Releases: gfazioli/mantine-marquee
v4.0.1
What's Changed
Toolchain: ESLint → oxlint
- Replaced ESLint with oxlint (^1.58.0) for significantly faster linting
- Removed
eslint,eslint-config-mantine,eslint-plugin-jsx-a11y,eslint-plugin-react,typescript-eslint - Added
oxlint.config.tswith react, typescript, jsx-a11y, and jest plugins - Removed unused
@mantinex/shikifrom docs dependencies - Updated
docs/tsconfig.json:jsx: "preserve"→"react-jsx"
This is a patch release — no changes to the component API, runtime behavior, or published bundle.
4.0.0
Caution
This is a major release with breaking changes. Mantine 9, React 19, and TypeScript 6 are now required. See the Migration Guide below.
Breaking Changes
1. Mantine 9 required
@mantine/core and @mantine/hooks have been upgraded from v8 to v9. Mantine 9 includes breaking changes in its own API — consult the Mantine 9 changelog for details.
The peer dependency range remains >=7.0.0, but v4.0.0 of this package is built and tested against Mantine 9.
2. React 19 required
React has been upgraded to 19.2.4. React 19 introduces native ref forwarding — components no longer use React.forwardRef. The peer dependency allows both ^18.x || ^19.x, but React 19 is recommended.
3. TypeScript 6 required
TypeScript has been upgraded from 5.9.x to 6.0.2. TypeScript 6 deprecates moduleResolution: "node" in favor of "bundler". If your project uses TypeScript 5.x, you may encounter type-level incompatibilities.
4. Ref forwarding changes (internal)
Marquee no longer accepts ref as a second argument in the factory callback. This follows Mantine 9's updated pattern where ref forwarding is handled internally via React 19's native mechanism.
Note
This change is transparent to consumers — ref props on <Marquee ref={myRef} /> continue to work as expected. No changes are needed in your application code.
Bug Fixes
1. repeat prop now safely handles undefined
The repeat prop could cause a TypeScript 6 compile error when undefined (its type allows it). Now properly guarded with ?? 2 fallback in the Array.from call.
Improvements
1. Storybook upgraded to v10
Storybook has been upgraded from v8 to v10. The new version includes built-in support for controls, actions, and docs. Dark mode toggling is now handled via the toolbar using @storybook/addon-themes.
2. Prettier replaced by oxfmt
The code formatter has been switched from Prettier to oxfmt, a Rust-based formatter. Formatting commands have changed:
| Before | After |
|---|---|
yarn prettier:check |
yarn format:test |
yarn prettier:write |
yarn format:write |
Other Changes
- CI workflow updated for the new toolchain
tsconfig.build.jsonupdated with explicitrootDirand narrowedincludefor TypeScript 6 compatibilitydocs/tsconfig.jsonupdated tomoduleResolution: "bundler"andtarget: "es2015"- Documentation site dependencies updated: Next.js 15.5.14,
@mantine/code-highlight9.0.0 - Shell and Footer documentation components refreshed from the base template
Migration Guide
Step 1: Update dependencies
npm install @gfazioli/mantine-marquee@4
npm install @mantine/core@9 @mantine/hooks@9 react@19 react-dom@19Step 2: Follow the Mantine 9 migration guide
Consult the Mantine 9 changelog for any breaking changes that affect your usage of Mantine components.
Step 3: Update TypeScript (if applicable)
If you're on TypeScript 5.x, upgrade to TypeScript 6:
npm install typescript@6Update your tsconfig.json to use "moduleResolution": "bundler" instead of "node".
Step 4: No component API changes
The Marquee component retains the same props and behavior. No changes to your JSX are required. Ref forwarding continues to work transparently.
Summary
@gfazioli/mantine-marquee v4.0.0 is a major infrastructure upgrade — Mantine 9, React 19, TypeScript 6, Storybook 10, and oxfmt replace the previous toolchain. The component API is unchanged; all 13 tests pass. The only action required from consumers is updating peer dependencies.
What's Changed
Full Changelog: 3.0.0...4.0.0
3.0.0
🚀 Breaking Changes
1. Removed fadeEdgesColor prop
The fadeEdgesColor prop (type MantineColor) has been completely removed from MarqueeBaseProps, the varsResolver, and the CSS module. The previous implementation used overlay <div> elements with colored linear-gradient backgrounds to simulate edge fading; the new implementation uses CSS mask-image for true alpha compositing that is entirely independent of background color.
Affected files: package/src/Marquee.tsx, package/src/Marquee.module.css
2. fadeEdges prop type changed from boolean to a union
The fadeEdges prop has been broadened from boolean to MarqueeFadeEdges:
// New type (exported from the package)
type MarqueeFadeEdges = boolean | 'linear' | 'ellipse' | 'rect';trueand'linear'are equivalent -- linear gradient mask on leading/trailing scroll edges.'ellipse'-- radial elliptical mask that fades all edges (vignette effect).'rect'-- four one-sided linear gradients (left, right, top, bottom) composited withmask-composite: intersect.falseor omitted -- no mask.
The resolved string value is exposed as data-fade-edges="linear|ellipse|rect" on the .root element. Passing true still works and maps to "linear", so existing code that uses fadeEdges={true} or fadeEdges (boolean shorthand) continues to work without changes.
Affected files: package/src/Marquee.tsx, package/src/Marquee.module.css
3. fadeEdgesSize prop now accepts an [x, y] tuple
The fadeEdgesSize prop has been broadened to MarqueeFadeEdgesSize:
// New type (exported from the package)
type MarqueeFadeEdgesSize =
| MantineSize
| (string & {})
| [MantineSize | (string & {}), MantineSize | (string & {})];When a tuple [x, y] is provided, x controls the left/right fade extent and y controls the top/bottom fade extent. This is primarily useful with fadeEdges="rect". Two new CSS custom properties have been introduced: --marquee-fade-edge-size-x and --marquee-fade-edge-size-y. For a single (non-tuple) value, all three variables (--marquee-fade-edge-size, -x, -y) resolve identically.
Affected files: package/src/Marquee.tsx, package/src/Marquee.module.css, docs/styles-api/Marquee.styles-api.ts
4. vertical prop is now responsive
The vertical prop has been broadened from boolean to MarqueeVertical:
// New type (exported from the package)
type MarqueeVertical = boolean | Partial<Record<MantineBreakpoint, boolean>>;It accepts a responsive breakpoint object (e.g. { base: true, md: false }) resolved internally by Mantine's useMatches hook. The component now emits data-vertical on .root when the resolved value is true.
As a consequence, the CSS variable --marquee-direction has been moved from varsResolver to an inline style on .root, because varsResolver cannot call React hooks. It is no longer part of MarqueeCssVariables.
Affected files: package/src/Marquee.tsx, docs/styles-api/Marquee.styles-api.ts
5. gap prop is now responsive
The gap prop has been broadened from MantineSize | (string & {}) to MarqueeGap:
// New type (exported from the package)
type MarqueeGap =
| MantineSize
| (string & {})
| Partial<Record<MantineBreakpoint, MantineSize | (string & {})>>;Same useMatches pattern as vertical. The CSS variable --marquee-gap has been moved from varsResolver to an inline style on .root and is no longer part of MarqueeCssVariables.
Affected files: package/src/Marquee.tsx, docs/styles-api/Marquee.styles-api.ts
6. CSS custom properties removed from the Styles API
The following variables have been removed from MarqueeCssVariables and from the varsResolver:
| Variable | Reason |
|---|---|
--marquee-direction |
Moved to inline style (depends on useMatches) |
--marquee-gap |
Moved to inline style (depends on useMatches) |
--marquee-fade-edge-color |
Removed entirely (no longer needed with mask-image) |
The following variables have been added to MarqueeCssVariables and to the varsResolver:
| Variable | Purpose |
|---|---|
--marquee-fade-edge-size-x |
Horizontal fade extent for rect mode (resolves from first tuple value) |
--marquee-fade-edge-size-y |
Vertical fade extent for rect mode (resolves from second tuple value) |
Affected files: package/src/Marquee.tsx, docs/styles-api/Marquee.styles-api.ts
7. Internal CSS class selectors removed
The following class selectors, which rendered overlay <div> elements, have been removed from the CSS module and are no longer emitted to the DOM:
.marqueeFadeEdgeLeft.marqueeFadeEdgeRight.marqueeFadeEdgeTop.marqueeFadeEdgeBottom
These were not part of MarqueeStylesNames but could have been targeted via plain CSS overrides. They no longer exist.
Affected files: package/src/Marquee.module.css, package/src/Marquee.tsx
✨ New Features
CSS mask-image based fade edges system
The entire edge fade mechanism has been rewritten to use CSS mask-image instead of overlay <div> elements. This provides true alpha compositing that is fully independent of the background color and removes 2-4 DOM elements from the render tree.
The technique uses one-sided gradients (one gradient per edge) composited with mask-composite: intersect / -webkit-mask-composite: source-in. This avoids the gradient stop overlap problem that occurs with double-sided gradients when the fade size exceeds 50%. Each gradient goes from transparent to black over the configured size, with intermediate stops (0.1, 0.35, 0.65, 0.9) for a smooth perceptual curve.
isolation: isolate is applied to the masked .root element to prevent Safari compositing glitches when will-change: transform children are present. Both standard (mask-image, mask-composite) and WebKit-prefixed (-webkit-mask-image, -webkit-mask-composite) properties are always written explicitly because postcss-preset-mantine does not include autoprefixer.
Affected files: package/src/Marquee.module.css, package/src/Marquee.tsx
fadeEdges="ellipse" -- radial mask mode
Applies radial-gradient(ellipse closest-side at center, ...) to create a vignette effect around all edges. closest-side ensures the ellipse is sized so that 100% reaches the center of each edge (not the corner), which is important for rectangular containers. The * 2 multiplier on --marquee-fade-edge-size makes the visual fade extent comparable to "linear" mode. No [data-vertical] variant is needed because radial gradients are orientation-independent.
When applied to a square element (width equals height), it naturally produces a circular mask -- no additional props are required.
Affected files: package/src/Marquee.module.css
fadeEdges="rect" -- four-edge independent mask mode
Applies 4 one-sided linear gradients (left, right, top, bottom) via mask-composite: intersect. Supports independent axis sizing through the fadeEdgesSize={['lg', 'xs']} tuple, where the first value controls left/right and the second controls top/bottom. At corners the alpha values multiply naturally (e.g. 0.5 x 0.5 = 0.25). No [data-vertical] variant is needed because all four edges are always masked.
Affected files: package/src/Marquee.module.css
Responsive vertical prop
The vertical prop now accepts a responsive breakpoint object, allowing the marquee to switch between vertical and horizontal layouts at different viewport widths:
<Marquee vertical={{ base: true, md: false }}>{children}</Marquee>Affected files: package/src/Marquee.tsx
Responsive gap prop
The gap prop now accepts a responsive breakpoint object, allowing different gap sizes at different viewport widths:
<Marquee gap={{ base: 'xs', md: 'xl' }}>{children}</Marquee>Affected files: package/src/Marquee.tsx
New exported TypeScript types
Four new types are now exported from the package entry point (package/src/index.ts):
MarqueeFadeEdges-- union type for thefadeEdgespropMarqueeFadeEdgesSize-- union type (with tuple) for thefadeEdgesSizepropMarqueeVertical-- union type for the responsiveverticalpropMarqueeGap-- union type for the responsivegapprop
Affected files: package/src/Marquee.tsx, package/src/index.ts
🐛 Bug Fixes
-
Fixed triple-dash CSS variable reference in
.root-- the fallback for--marquee-gapwasvar(---marquee-gap-xl, 16px)(three dashes); corrected tovar(--marquee-gap-xl, 16px). This caused the gap to always fall through to the16pxfallback instead of resolving the token. (package/src/Marquee.module.css) -
Fixed
justify-contentin.marqueeContent-- changed fromspace-aroundtoflex-start. The previous value distributed extra space between cloned child elements, which broke the seamless loop geometry (clones must be packed tightly so each translates by exactly-100% - gap). (package/src/Marquee.module.css) -
Fixed missing
useMemodependencies inrenderContent-- addedgap(nowresolvedGap) anddurationto the dependency array. Previously, changing these props at runtime would not regenerate the clone keys, leading to stale React keys and potential animation glitches. (package/src/Marquee.tsx) -
Fixed
libraryValuemismatches in the configurator demo -- alignedlibraryValuefields to actualdefaultProps:repeatcorrected from4to2,durationfrom10to20,gapfrom'sm'to'xl'. IncorrectlibraryValuecauses the configurator to show i...