@dreamtree-org/twreact-ui 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/README.md +48 -4
  2. package/ai-skills/dreamtree-ui.md +20 -3
  3. package/dist/_shared/{cn-DPPQUJu1.js → cn-TMJ-_w1a.js} +14 -1
  4. package/dist/_shared/useLatestRef-CdtlnPUz.js +21 -0
  5. package/dist/_shared/useReducedMotion-B_PMM5ER.js +77 -0
  6. package/dist/ai-schema.json +513 -0
  7. package/dist/charts/index.js +6 -76
  8. package/dist/components/core/Table/Table.d.ts.map +1 -1
  9. package/dist/components/motion/BentoExpandGrid.d.ts +10 -0
  10. package/dist/components/motion/BentoExpandGrid.d.ts.map +1 -0
  11. package/dist/components/motion/CountUp.d.ts +9 -0
  12. package/dist/components/motion/CountUp.d.ts.map +1 -0
  13. package/dist/components/motion/DeviceFrame.d.ts +8 -0
  14. package/dist/components/motion/DeviceFrame.d.ts.map +1 -0
  15. package/dist/components/motion/DeviceMorphHero.d.ts +11 -0
  16. package/dist/components/motion/DeviceMorphHero.d.ts.map +1 -0
  17. package/dist/components/motion/LogoMarquee.d.ts +9 -0
  18. package/dist/components/motion/LogoMarquee.d.ts.map +1 -0
  19. package/dist/components/motion/PhotoCollage.d.ts +9 -0
  20. package/dist/components/motion/PhotoCollage.d.ts.map +1 -0
  21. package/dist/components/motion/Reveal.d.ts +9 -0
  22. package/dist/components/motion/Reveal.d.ts.map +1 -0
  23. package/dist/components/motion/RevealGroup.d.ts +5 -0
  24. package/dist/components/motion/RevealGroup.d.ts.map +1 -0
  25. package/dist/components/motion/RotatingBadge.d.ts +9 -0
  26. package/dist/components/motion/RotatingBadge.d.ts.map +1 -0
  27. package/dist/components/motion/ScrollStage.d.ts +11 -0
  28. package/dist/components/motion/ScrollStage.d.ts.map +1 -0
  29. package/dist/components/motion/SmoothScrollProvider.d.ts +18 -0
  30. package/dist/components/motion/SmoothScrollProvider.d.ts.map +1 -0
  31. package/dist/components/motion/StackedCards.d.ts +10 -0
  32. package/dist/components/motion/StackedCards.d.ts.map +1 -0
  33. package/dist/components/motion/StatStrip.d.ts +8 -0
  34. package/dist/components/motion/StatStrip.d.ts.map +1 -0
  35. package/dist/components/motion/TestimonialSpotlight.d.ts +10 -0
  36. package/dist/components/motion/TestimonialSpotlight.d.ts.map +1 -0
  37. package/dist/components/motion/storyData.d.ts +52 -0
  38. package/dist/components/motion/storyData.d.ts.map +1 -0
  39. package/dist/components/navigation/Navbar.d.ts.map +1 -1
  40. package/dist/esm/components/core/Table/MobileCard.js +2 -2
  41. package/dist/esm/components/core/Table/MobileFilters.js +1 -1
  42. package/dist/esm/components/core/Table/Table.js +28 -26
  43. package/dist/esm/components/motion/BentoExpandGrid.js +144 -0
  44. package/dist/esm/components/motion/CountUp.js +97 -0
  45. package/dist/esm/components/motion/DeviceFrame.js +102 -0
  46. package/dist/esm/components/motion/DeviceMorphHero.js +228 -0
  47. package/dist/esm/components/motion/LogoMarquee.js +144 -0
  48. package/dist/esm/components/motion/PhotoCollage.js +92 -0
  49. package/dist/esm/components/motion/Reveal.js +115 -0
  50. package/dist/esm/components/motion/RevealGroup.js +43 -0
  51. package/dist/esm/components/motion/RotatingBadge.js +66 -0
  52. package/dist/esm/components/motion/ScrollStage.js +62 -0
  53. package/dist/esm/components/motion/SmoothScrollProvider.js +63 -0
  54. package/dist/esm/components/motion/StackedCards.js +166 -0
  55. package/dist/esm/components/motion/StatStrip.js +58 -0
  56. package/dist/esm/components/motion/TestimonialSpotlight.js +209 -0
  57. package/dist/esm/components/navigation/Navbar.js +5 -2
  58. package/dist/esm/hooks/useScrollProgress.js +107 -0
  59. package/dist/esm/hooks/useSmoothScroll.js +33 -0
  60. package/dist/esm/motion/engine/inView.js +54 -0
  61. package/dist/esm/motion/engine/progress.js +45 -0
  62. package/dist/esm/motion/engine/scheduler.js +67 -0
  63. package/dist/esm/motion/engine/useHydrated.js +17 -0
  64. package/dist/esm/motion/engine/useIsomorphicLayoutEffect.js +7 -0
  65. package/dist/esm/motion/engine/useMergedRef.js +12 -0
  66. package/dist/esm/motion/index.js +16 -0
  67. package/dist/esm/motion/tokens.js +10 -0
  68. package/dist/hooks/useScrollProgress.d.ts +17 -0
  69. package/dist/hooks/useScrollProgress.d.ts.map +1 -0
  70. package/dist/hooks/useSmoothScroll.d.ts +11 -0
  71. package/dist/hooks/useSmoothScroll.d.ts.map +1 -0
  72. package/dist/index.css +1 -1
  73. package/dist/index.esm.css +1 -1
  74. package/dist/index.esm.js +36 -31
  75. package/dist/index.js +36 -31
  76. package/dist/motion/engine/inView.d.ts +5 -0
  77. package/dist/motion/engine/inView.d.ts.map +1 -0
  78. package/dist/motion/engine/progress.d.ts +18 -0
  79. package/dist/motion/engine/progress.d.ts.map +1 -0
  80. package/dist/motion/engine/scheduler.d.ts +10 -0
  81. package/dist/motion/engine/scheduler.d.ts.map +1 -0
  82. package/dist/motion/engine/useHydrated.d.ts +3 -0
  83. package/dist/motion/engine/useHydrated.d.ts.map +1 -0
  84. package/dist/motion/engine/useIsomorphicLayoutEffect.d.ts +4 -0
  85. package/dist/motion/engine/useIsomorphicLayoutEffect.d.ts.map +1 -0
  86. package/dist/motion/engine/useMergedRef.d.ts +3 -0
  87. package/dist/motion/engine/useMergedRef.d.ts.map +1 -0
  88. package/dist/motion/index.d.ts +20 -0
  89. package/dist/motion/index.d.ts.map +1 -0
  90. package/dist/motion/index.js +1813 -0
  91. package/dist/motion/tokens.d.ts +6 -0
  92. package/dist/motion/tokens.d.ts.map +1 -0
  93. package/dist/rich-text/index.js +3 -18
  94. package/dist/tokens/tokens.json +21 -0
  95. package/dist/types/motion.d.ts +290 -0
  96. package/dist/types/motion.d.ts.map +1 -0
  97. package/doc/README.md +17 -1
  98. package/mcp/catalog.snapshot.json +959 -12
  99. package/motion/package.json +5 -0
  100. package/package.json +14 -3
  101. package/tokens/tokens.json +6 -0
@@ -0,0 +1,10 @@
1
+ export default BentoExpandGrid;
2
+ /**
3
+ * A photo grid whose active tile grows (its row and column tracks widen) while the
4
+ * neighbours shrink. Hover, keyboard focus and — with `trigger="click"` — tap expand a
5
+ * tile, and arrow keys move between tiles, so it never depends on a mouse. Below `md` it
6
+ * becomes a horizontal snap scroller. Under reduced motion the resize is instant.
7
+ */
8
+ declare const BentoExpandGrid: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
9
+ import React from "react";
10
+ //# sourceMappingURL=BentoExpandGrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BentoExpandGrid.d.ts","sourceRoot":"","sources":["../../../src/components/motion/BentoExpandGrid.jsx"],"names":[],"mappings":";AASA;;;;;GAKG;AACH,yFA+FE;kBA9GsC,OAAO"}
@@ -0,0 +1,9 @@
1
+ export default CountUp;
2
+ /**
3
+ * A number that counts up when it scrolls into view. The server (and reduced motion)
4
+ * renders the real final value, so crawlers and no-JS readers never see "0". Screen readers
5
+ * read the final value once from a visually hidden copy; the animating digits are hidden.
6
+ */
7
+ declare const CountUp: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
8
+ import React from "react";
9
+ //# sourceMappingURL=CountUp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CountUp.d.ts","sourceRoot":"","sources":["../../../src/components/motion/CountUp.jsx"],"names":[],"mappings":";AAaA;;;;GAIG;AACH,iFA8DE;kBAhFgD,OAAO"}
@@ -0,0 +1,8 @@
1
+ export default DeviceFrame;
2
+ /**
3
+ * A CSS-only device mock-up (phone, tablet, laptop or browser window) around any
4
+ * screen content. Purely presentational: no motion, works anywhere.
5
+ */
6
+ declare const DeviceFrame: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
7
+ import React from "react";
8
+ //# sourceMappingURL=DeviceFrame.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeviceFrame.d.ts","sourceRoot":"","sources":["../../../src/components/motion/DeviceFrame.jsx"],"names":[],"mappings":";AA+CA;;;GAGG;AACH,qFAuBE;kBA1EgB,OAAO"}
@@ -0,0 +1,11 @@
1
+ export default DeviceMorphHero;
2
+ /**
3
+ * The signature scroll hero: full-bleed media shrinks into a device frame, the bezel fades
4
+ * in, then the device slides aside while the copy (`content`) fades in beside it. The
5
+ * timeline maps the scene's scroll progress: 0–45 % morph, 40–60 % bezel, 60–90 % slide.
6
+ * The server, no-JS readers and reduced-motion users get the final layout (copy beside the
7
+ * device) with no pinning. Below `md` the device rises and shrinks and the copy appears under it.
8
+ */
9
+ declare const DeviceMorphHero: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
10
+ import React from "react";
11
+ //# sourceMappingURL=DeviceMorphHero.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeviceMorphHero.d.ts","sourceRoot":"","sources":["../../../src/components/motion/DeviceMorphHero.jsx"],"names":[],"mappings":";AAuCA;;;;;;GAMG;AACH,yFAmLE;kBAjOoD,OAAO"}
@@ -0,0 +1,9 @@
1
+ export default LogoMarquee;
2
+ /**
3
+ * An endless strip of logos or names. The second copy of the list (needed for a seamless
4
+ * loop) is `aria-hidden`, so screen readers read each item once. Pauses on hover, while
5
+ * focus is inside and while off screen; under reduced motion it is a static, wrapped row.
6
+ */
7
+ declare const LogoMarquee: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
8
+ import React from "react";
9
+ //# sourceMappingURL=LogoMarquee.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LogoMarquee.d.ts","sourceRoot":"","sources":["../../../src/components/motion/LogoMarquee.jsx"],"names":[],"mappings":";AA6CA;;;;GAIG;AACH,qFA2EE;kBA7HiD,OAAO"}
@@ -0,0 +1,9 @@
1
+ export default PhotoCollage;
2
+ /**
3
+ * Overlapping, offset photos with floating stat chips and an optional badge. On scroll the
4
+ * photos drift at different depths (parallax), driven by a CSS variable — no re-renders.
5
+ * Under reduced motion (or `parallax={0}`) they stay put.
6
+ */
7
+ declare const PhotoCollage: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
8
+ import React from "react";
9
+ //# sourceMappingURL=PhotoCollage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PhotoCollage.d.ts","sourceRoot":"","sources":["../../../src/components/motion/PhotoCollage.jsx"],"names":[],"mappings":";AAmBA;;;;GAIG;AACH,sFA2CE;kBAnE4B,OAAO"}
@@ -0,0 +1,9 @@
1
+ export default Reveal;
2
+ /**
3
+ * Plays an entrance when the element scrolls into view. The server, no-JS readers and
4
+ * reduced-motion users get the content as-is; elements already on screen at load are not
5
+ * hidden (no flash, no LCP delay). Only content below the fold animates.
6
+ */
7
+ declare const Reveal: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
8
+ import React from "react";
9
+ //# sourceMappingURL=Reveal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Reveal.d.ts","sourceRoot":"","sources":["../../../src/components/motion/Reveal.jsx"],"names":[],"mappings":";AAoBA;;;;GAIG;AACH,gFAyEE;kBAlGsC,OAAO"}
@@ -0,0 +1,5 @@
1
+ export default RevealGroup;
2
+ /** Reveals each child in turn: child `i` waits `delay + i * stagger` ms. */
3
+ declare const RevealGroup: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
4
+ import React from "react";
5
+ //# sourceMappingURL=RevealGroup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RevealGroup.d.ts","sourceRoot":"","sources":["../../../src/components/motion/RevealGroup.jsx"],"names":[],"mappings":";AAGA,4EAA4E;AAC5E,qFAoBE;kBAxBgB,OAAO"}
@@ -0,0 +1,9 @@
1
+ export default RotatingBadge;
2
+ /**
3
+ * A circular badge with text set around its edge, slowly turning (SVG `textPath`). The
4
+ * text is spread to fill the circle exactly. Exposed as one image named by `text`
5
+ * (override with `aria-label`); it stops turning under reduced motion.
6
+ */
7
+ declare const RotatingBadge: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
8
+ import React from "react";
9
+ //# sourceMappingURL=RotatingBadge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RotatingBadge.d.ts","sourceRoot":"","sources":["../../../src/components/motion/RotatingBadge.jsx"],"names":[],"mappings":";AAMA;;;;GAIG;AACH,uFAiCG;kBA5C0B,OAAO"}
@@ -0,0 +1,11 @@
1
+ export default ScrollStage;
2
+ /**
3
+ * A pinned scroll scene: a tall section whose content sticks to the viewport while the
4
+ * user scrolls through `length` vh. Progress (0–1) is written to `--dt-p` on the root, so
5
+ * children animate with CSS (`opacity: var(--dt-p, 1)`), and passed to `children(progress)`
6
+ * and `onProgress`. Under reduced motion, or with `pin={false}`, it renders in normal flow
7
+ * at its final state.
8
+ */
9
+ declare const ScrollStage: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
10
+ import React from "react";
11
+ //# sourceMappingURL=ScrollStage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScrollStage.d.ts","sourceRoot":"","sources":["../../../src/components/motion/ScrollStage.jsx"],"names":[],"mappings":";AAQA;;;;;;GAMG;AACH,qFAsCE;kBArD4B,OAAO"}
@@ -0,0 +1,18 @@
1
+ export default SmoothScrollProvider;
2
+ /**
3
+ * Opt-in smooth (inertial) scrolling with Lenis. Lenis is an optional peer dependency
4
+ * and is never imported by this package: install it and pass the class —
5
+ * `<SmoothScrollProvider lenis={Lenis}>`. Without `lenis`, with `enabled={false}` or when
6
+ * the user prefers reduced motion, the page keeps native scrolling. Lenis runs on the same
7
+ * frame loop as the other motion components.
8
+ */
9
+ declare function SmoothScrollProvider({ lenis: LenisClass, options, enabled, children }: {
10
+ lenis: any;
11
+ options: any;
12
+ enabled?: boolean | undefined;
13
+ children: any;
14
+ }): import("react/jsx-runtime").JSX.Element;
15
+ declare namespace SmoothScrollProvider {
16
+ let displayName: string;
17
+ }
18
+ //# sourceMappingURL=SmoothScrollProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SmoothScrollProvider.d.ts","sourceRoot":"","sources":["../../../src/components/motion/SmoothScrollProvider.jsx"],"names":[],"mappings":";AAKA;;;;;;GAMG;AACH;;;;;4CA2BC"}
@@ -0,0 +1,10 @@
1
+ export default StackedCards;
2
+ /**
3
+ * Cards that stick one over another as the page scrolls (sticky stacking). Cards
4
+ * underneath shrink and dim as the next one covers them, and each has a slight
5
+ * alternating tilt so the stack looks hand-placed. Tilt is off below `md` and under
6
+ * reduced motion; the scale/dim effect is off under reduced motion.
7
+ */
8
+ declare const StackedCards: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
9
+ import React from "react";
10
+ //# sourceMappingURL=StackedCards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StackedCards.d.ts","sourceRoot":"","sources":["../../../src/components/motion/StackedCards.jsx"],"names":[],"mappings":";AAqDA;;;;;GAKG;AACH,sFA6EE;kBAxIuC,OAAO"}
@@ -0,0 +1,8 @@
1
+ export default StatStrip;
2
+ /**
3
+ * A row of headline numbers that count up on view — as bordered cards or one band with
4
+ * dividers. A description list: each label is a `<dt>`, each number its `<dd>`.
5
+ */
6
+ declare const StatStrip: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
7
+ import React from "react";
8
+ //# sourceMappingURL=StatStrip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatStrip.d.ts","sourceRoot":"","sources":["../../../src/components/motion/StatStrip.jsx"],"names":[],"mappings":";AAMA;;;GAGG;AACH,mFAsCG;kBAhDe,OAAO"}
@@ -0,0 +1,10 @@
1
+ export default TestimonialSpotlight;
2
+ /**
3
+ * Client quotes with a 3×3 tile grid of logos: the active client's logo sits in the centre
4
+ * tile and the quote beside it. Dots are a tab list (arrow keys, Home/End). Autoplay pauses
5
+ * on hover, while focus is inside, while off screen and under reduced motion, and has a
6
+ * visible pause button (WCAG 2.2.2).
7
+ */
8
+ declare const TestimonialSpotlight: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
9
+ import React from "react";
10
+ //# sourceMappingURL=TestimonialSpotlight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestimonialSpotlight.d.ts","sourceRoot":"","sources":["../../../src/components/motion/TestimonialSpotlight.jsx"],"names":[],"mappings":";AAgBA;;;;;GAKG;AACH,8FAgIE;kBAtJwD,OAAO"}
@@ -0,0 +1,52 @@
1
+ /** A token-coloured placeholder screen for device mock-ups. */
2
+ export function Screen({ label }: {
3
+ label?: string | undefined;
4
+ }): import("react/jsx-runtime").JSX.Element;
5
+ export function photo(seed: any, w?: number, h?: number): string;
6
+ export const clients: string[];
7
+ export const stats: ({
8
+ value: number;
9
+ suffix: string;
10
+ label: string;
11
+ prefix?: undefined;
12
+ } | {
13
+ value: number;
14
+ label: string;
15
+ suffix?: undefined;
16
+ prefix?: undefined;
17
+ } | {
18
+ value: number;
19
+ prefix: string;
20
+ label: string;
21
+ suffix?: undefined;
22
+ })[];
23
+ export const pillars: {
24
+ kicker: string;
25
+ title: string;
26
+ body: string;
27
+ bullets: string[];
28
+ metric: {
29
+ value: string;
30
+ label: string;
31
+ };
32
+ media: {
33
+ src: string;
34
+ alt: string;
35
+ };
36
+ }[];
37
+ export const projects: {
38
+ title: string;
39
+ tag: string;
40
+ client: string;
41
+ media: {
42
+ src: string;
43
+ alt: string;
44
+ };
45
+ }[];
46
+ export const testimonials: {
47
+ quote: string;
48
+ name: string;
49
+ role: string;
50
+ logo: string;
51
+ }[];
52
+ //# sourceMappingURL=storyData.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storyData.d.ts","sourceRoot":"","sources":["../../../src/components/motion/storyData.js"],"names":[],"mappings":"AA8DA,+DAA+D;AAC/D;;4CAQC;AAtEM,iEAAwF;AAE/F,+BAAoH;AAEpH;;;;;;;;;;;;;;;KAKE;AAEF;;;;;;;;;;;;;IAiCE;AAEF;;;;;;;;IAOE;AAEF;;;;;IAIE"}
@@ -1 +1 @@
1
- {"version":3,"file":"Navbar.d.ts","sourceRoot":"","sources":["../../../src/components/navigation/Navbar.jsx"],"names":[],"mappings":"AAmQA,+EAkZG;;kBAppBmF,OAAO"}
1
+ {"version":3,"file":"Navbar.d.ts","sourceRoot":"","sources":["../../../src/components/navigation/Navbar.jsx"],"names":[],"mappings":"AAmQA,+EAqZG;;kBAvpBmF,OAAO"}
@@ -201,10 +201,10 @@ function MobileCard(_ref) {
201
201
  return jsxs("div", {
202
202
  className: cn("flex justify-between items-center flex-row py-2 border-b last:border-b-0", safeExtraCellClass),
203
203
  children: [jsx("div", {
204
- className: "text-xs font-medium text-primary-700 uppercase tracking-wide mb-1 sm:mb-0 sm:w-1/3 sm:pr-2",
204
+ className: "text-xs font-medium text-primary-700 dark:text-primary-300 uppercase tracking-wide mb-1 sm:mb-0 sm:w-1/3 sm:pr-2",
205
205
  children: column.label
206
206
  }), jsx("div", {
207
- className: "text-sm text-primary-900 sm:w-2/3 sm:pl-2 break-words",
207
+ className: "text-sm text-primary-900 dark:text-foreground sm:w-2/3 sm:pl-2 break-words",
208
208
  children: renderCell(column, row, globalIndex)
209
209
  })]
210
210
  }, column.key);
@@ -205,7 +205,7 @@ function MobileFilters(_ref5) {
205
205
  });
206
206
  },
207
207
  "aria-expanded": !!showMobileFilters,
208
- className: "text-xs font-medium text-primary-700",
208
+ className: "text-xs font-medium text-primary-700 dark:text-primary-300",
209
209
  children: showMobileFilters ? "Hide" : "Show"
210
210
  })]
211
211
  }), showMobileFilters && jsxs("div", {
@@ -178,6 +178,12 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
178
178
  _useState14 = _slicedToArray(_useState13, 2),
179
179
  filters = _useState14[0],
180
180
  setFilters = _useState14[1];
181
+ // The handlers below read and advance these refs synchronously, so they can
182
+ // call onSort / onFilter after setting state instead of inside a setState
183
+ // updater (updaters must be pure; React runs them during render and twice
184
+ // in StrictMode, #194). They are the only writers of sortConfig / filters.
185
+ var sortConfigRef = useRef(sortConfig);
186
+ var filtersRef = useRef(filters);
181
187
  var _useState15 = useState(""),
182
188
  _useState16 = _slicedToArray(_useState15, 2),
183
189
  searchInput = _useState16[0],
@@ -932,34 +938,30 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
932
938
  }, []);
933
939
  var handleSort = useCallback(function (key) {
934
940
  if (!sortable) return;
935
- setSortConfig(function (prev) {
936
- var direction = prev.key === key && prev.direction === "asc" ? "desc" : "asc";
937
- onSort === null || onSort === void 0 || onSort(key, direction);
938
- return {
939
- key: key,
940
- direction: direction
941
- };
942
- });
941
+ var prev = sortConfigRef.current;
942
+ var direction = prev.key === key && prev.direction === "asc" ? "desc" : "asc";
943
+ var next = {
944
+ key: key,
945
+ direction: direction
946
+ };
947
+ sortConfigRef.current = next;
948
+ setSortConfig(next);
949
+ onSort === null || onSort === void 0 || onSort(key, direction);
943
950
  }, [sortable, onSort]);
944
- var handleFilter = useCallback(function (key, value) {
945
- setFilters(function (prev) {
946
- var newFilters = _objectSpread2(_objectSpread2({}, prev), {}, _defineProperty({}, key, value));
947
- onFilter === null || onFilter === void 0 || onFilter(newFilters);
948
- onFilterChange === null || onFilterChange === void 0 || onFilterChange(newFilters);
949
- return newFilters;
950
- });
951
+ var commitFilters = useCallback(function (newFilters) {
952
+ filtersRef.current = newFilters;
953
+ setFilters(newFilters);
951
954
  setCurrentPage(1);
955
+ onFilter === null || onFilter === void 0 || onFilter(newFilters);
956
+ onFilterChange === null || onFilterChange === void 0 || onFilterChange(newFilters);
952
957
  }, [onFilter, onFilterChange]);
958
+ var handleFilter = useCallback(function (key, value) {
959
+ return commitFilters(_objectSpread2(_objectSpread2({}, filtersRef.current), {}, _defineProperty({}, key, value)));
960
+ }, [commitFilters]);
953
961
  // Commits several filters at once (the phone filter sheet's Apply).
954
962
  var applyFilters = useCallback(function (patch) {
955
- setFilters(function (prev) {
956
- var newFilters = _objectSpread2(_objectSpread2({}, prev), patch);
957
- onFilter === null || onFilter === void 0 || onFilter(newFilters);
958
- onFilterChange === null || onFilterChange === void 0 || onFilterChange(newFilters);
959
- return newFilters;
960
- });
961
- setCurrentPage(1);
962
- }, [onFilter, onFilterChange]);
963
+ return commitFilters(_objectSpread2(_objectSpread2({}, filtersRef.current), patch));
964
+ }, [commitFilters]);
963
965
  // One open swipe row at a time: `{ key, side }`.
964
966
  var _useState37 = useState(null),
965
967
  _useState38 = _slicedToArray(_useState37, 2),
@@ -1196,7 +1198,7 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
1196
1198
  className: "bg-primary-50/40 hover:bg-primary-100/70 active:bg-primary-100 transition-colors border-t-2 border-b-2 border-dashed border-primary-300 cursor-pointer group",
1197
1199
  children: jsx("td", {
1198
1200
  colSpan: visibleCount,
1199
- className: "px-6 py-3.5 text-left text-sm font-semibold text-primary-700 group-hover:text-primary-800",
1201
+ className: "px-6 py-3.5 text-left text-sm font-semibold text-primary-700 group-hover:text-primary-800 dark:text-primary-300 dark:group-hover:text-primary-200",
1200
1202
  children: jsxs("div", {
1201
1203
  className: "flex items-center justify-start gap-2",
1202
1204
  children: [jsx(Plus, {
@@ -1376,7 +1378,7 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
1376
1378
  children: [hasDetailsColumn && jsx("th", {
1377
1379
  className: "w-8 px-4 py-3"
1378
1380
  }), showSerial && jsx("th", {
1379
- className: "w-8 px-4 py-3 text-left text-xs font-medium text-primary-700 uppercase tracking-wider",
1381
+ className: "w-8 px-4 py-3 text-left text-xs font-medium text-primary-700 dark:text-primary-300 uppercase tracking-wider",
1380
1382
  children: "#"
1381
1383
  }), selectable && jsx("th", {
1382
1384
  className: "w-12 px-6 py-3",
@@ -1403,7 +1405,7 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
1403
1405
  return jsx("th", {
1404
1406
  scope: "col",
1405
1407
  "aria-sort": ariaSort,
1406
- className: cn("px-6 py-3 text-left text-xs font-medium text-primary-700 uppercase tracking-wider", isSortable && "p-0"),
1408
+ className: cn("px-6 py-3 text-left text-xs font-medium text-primary-700 dark:text-primary-300 uppercase tracking-wider", isSortable && "p-0"),
1407
1409
  children: isSortable ? jsxs("button", {
1408
1410
  type: "button",
1409
1411
  onClick: function onClick() {
@@ -0,0 +1,144 @@
1
+ 'use client';
2
+ import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2, typeof as _typeof } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsx, jsxs } from 'react/jsx-runtime';
4
+ import React, { useRef, useState } from 'react';
5
+ import { cn } from '../../utils/cn.js';
6
+ import { useMergedRef } from '../../motion/engine/useMergedRef.js';
7
+
8
+ var _excluded = ["items", "cols", "expand", "trigger", "label", "className", "style", "onMouseLeave"];
9
+ var isImage = function isImage(media) {
10
+ return media && _typeof(media) === "object" && ! /*#__PURE__*/React.isValidElement(media) && "src" in media;
11
+ };
12
+ var tracks = function tracks(count, active, expand) {
13
+ return Array.from({
14
+ length: count
15
+ }, function (_, i) {
16
+ return i === active ? "".concat(expand, "fr") : "1fr";
17
+ }).join(" ");
18
+ };
19
+ /**
20
+ * A photo grid whose active tile grows (its row and column tracks widen) while the
21
+ * neighbours shrink. Hover, keyboard focus and — with `trigger="click"` — tap expand a
22
+ * tile, and arrow keys move between tiles, so it never depends on a mouse. Below `md` it
23
+ * becomes a horizontal snap scroller. Under reduced motion the resize is instant.
24
+ */
25
+ var BentoExpandGrid = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
26
+ var _ref$items = _ref.items,
27
+ items = _ref$items === void 0 ? [] : _ref$items,
28
+ _ref$cols = _ref.cols,
29
+ cols = _ref$cols === void 0 ? 3 : _ref$cols,
30
+ _ref$expand = _ref.expand,
31
+ expand = _ref$expand === void 0 ? 2 : _ref$expand,
32
+ _ref$trigger = _ref.trigger,
33
+ trigger = _ref$trigger === void 0 ? "hover" : _ref$trigger,
34
+ label = _ref.label,
35
+ className = _ref.className,
36
+ style = _ref.style,
37
+ _onMouseLeave = _ref.onMouseLeave,
38
+ rest = _objectWithoutProperties(_ref, _excluded);
39
+ var local = useRef(null);
40
+ var setRef = useMergedRef(ref, local);
41
+ var _useState = useState(null),
42
+ _useState2 = _slicedToArray(_useState, 2),
43
+ active = _useState2[0],
44
+ setActive = _useState2[1];
45
+ var rows = Math.max(1, Math.ceil(items.length / cols));
46
+ var activeCol = active == null ? -1 : active % cols;
47
+ var activeRow = active == null ? -1 : Math.floor(active / cols);
48
+ var focusTile = function focusTile(index) {
49
+ var tiles = local.current ? local.current.querySelectorAll("[data-bento-tile]") : [];
50
+ if (tiles[index]) tiles[index].focus();
51
+ };
52
+ var _onKeyDown = function onKeyDown(event, index) {
53
+ var step = {
54
+ ArrowRight: 1,
55
+ ArrowLeft: -1,
56
+ ArrowDown: cols,
57
+ ArrowUp: -cols
58
+ }[event.key];
59
+ if (step === undefined) {
60
+ if (event.key === "Home") focusTile(0);else if (event.key === "End") focusTile(items.length - 1);else return;
61
+ event.preventDefault();
62
+ return;
63
+ }
64
+ var next = index + step;
65
+ if (next >= 0 && next < items.length) {
66
+ event.preventDefault();
67
+ focusTile(next);
68
+ }
69
+ };
70
+ return jsx("ul", _objectSpread2(_objectSpread2({
71
+ ref: setRef,
72
+ "aria-label": label,
73
+ className: cn("flex snap-x snap-mandatory gap-4 overflow-x-auto pb-2", "md:grid md:h-[min(80vh,720px)] md:snap-none md:overflow-visible md:pb-0", "md:transition-[grid-template-columns,grid-template-rows] md:duration-500 md:ease-emphasized motion-reduce:transition-none", className),
74
+ style: _objectSpread2({
75
+ gridTemplateColumns: tracks(cols, activeCol, expand),
76
+ gridTemplateRows: tracks(rows, activeRow, expand)
77
+ }, style),
78
+ onMouseLeave: function onMouseLeave(e) {
79
+ if (trigger === "hover") setActive(null);
80
+ if (_onMouseLeave) _onMouseLeave(e);
81
+ }
82
+ }, rest), {}, {
83
+ children: items.map(function (item, i) {
84
+ var _item$id;
85
+ var Tag = item.href ? "a" : trigger === "click" ? "button" : "div";
86
+ var expanded = active === i;
87
+ var interactive = {
88
+ "data-bento-tile": "",
89
+ onKeyDown: function onKeyDown(e) {
90
+ return _onKeyDown(e, i);
91
+ },
92
+ onFocus: trigger !== "click" ? function () {
93
+ return setActive(i);
94
+ } : undefined,
95
+ onMouseEnter: trigger === "hover" ? function () {
96
+ return setActive(i);
97
+ } : undefined,
98
+ onClick: trigger === "click" ? function () {
99
+ return setActive(expanded ? null : i);
100
+ } : undefined
101
+ };
102
+ if (Tag === "a") interactive.href = item.href;
103
+ if (Tag === "button") {
104
+ interactive.type = "button";
105
+ interactive["aria-pressed"] = expanded;
106
+ }
107
+ if (Tag === "div") interactive.tabIndex = 0;
108
+ return jsx("li", {
109
+ className: "w-[80%] shrink-0 snap-start sm:w-[45%] md:w-auto md:min-h-0 md:min-w-0",
110
+ children: jsxs(Tag, _objectSpread2(_objectSpread2({}, interactive), {}, {
111
+ "data-active": expanded ? "" : undefined,
112
+ className: "group relative block h-72 w-full overflow-hidden rounded-card text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-2 md:h-full",
113
+ children: [isImage(item.media) ? jsx("img", {
114
+ src: item.media.src,
115
+ alt: item.media.alt,
116
+ loading: "lazy",
117
+ className: "absolute inset-0 h-full w-full object-cover transition-transform duration-700 ease-emphasized group-hover:scale-105 group-data-[active]:scale-105 motion-reduce:transition-none motion-reduce:group-hover:scale-100"
118
+ }) : jsx("span", {
119
+ className: "absolute inset-0",
120
+ children: item.media
121
+ }), jsx("span", {
122
+ "aria-hidden": "true",
123
+ className: "absolute inset-0 bg-gradient-to-t from-gray-950/80 via-gray-950/20 to-transparent"
124
+ }), jsxs("span", {
125
+ className: "absolute inset-x-0 bottom-0 flex flex-col gap-1 p-4 text-primary-foreground",
126
+ children: [item.tag ? jsx("span", {
127
+ className: "w-max rounded-pill bg-primary-foreground/20 px-2.5 py-0.5 text-micro uppercase tracking-wider backdrop-blur",
128
+ children: item.tag
129
+ }) : null, item.client ? jsx("span", {
130
+ className: "text-caption text-primary-foreground/80",
131
+ children: item.client
132
+ }) : null, jsx("span", {
133
+ className: "text-body font-semibold",
134
+ children: item.title
135
+ })]
136
+ })]
137
+ }))
138
+ }, (_item$id = item.id) !== null && _item$id !== void 0 ? _item$id : i);
139
+ })
140
+ }));
141
+ });
142
+ BentoExpandGrid.displayName = "BentoExpandGrid";
143
+
144
+ export { BentoExpandGrid as default };
@@ -0,0 +1,97 @@
1
+ 'use client';
2
+ import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+ import React, { useRef, useMemo, useEffect } from 'react';
5
+ import { cn } from '../../utils/cn.js';
6
+ import { useReducedMotion } from '../../hooks/useReducedMotion.js';
7
+ import { observe } from '../../motion/engine/inView.js';
8
+ import { subscribe } from '../../motion/engine/scheduler.js';
9
+ import { easeOut } from '../../motion/engine/progress.js';
10
+
11
+ var _excluded = ["value", "from", "prefix", "suffix", "duration", "decimals", "locale", "format", "className"];
12
+ var decimalsOf = function decimalsOf(n) {
13
+ var s = String(n);
14
+ var dot = s.indexOf(".");
15
+ return dot === -1 ? 0 : s.length - dot - 1;
16
+ };
17
+ /**
18
+ * A number that counts up when it scrolls into view. The server (and reduced motion)
19
+ * renders the real final value, so crawlers and no-JS readers never see "0". Screen readers
20
+ * read the final value once from a visually hidden copy; the animating digits are hidden.
21
+ */
22
+ var CountUp = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
23
+ var value = _ref.value,
24
+ _ref$from = _ref.from,
25
+ from = _ref$from === void 0 ? 0 : _ref$from,
26
+ prefix = _ref.prefix,
27
+ suffix = _ref.suffix,
28
+ _ref$duration = _ref.duration,
29
+ duration = _ref$duration === void 0 ? 1600 : _ref$duration,
30
+ decimals = _ref.decimals,
31
+ _ref$locale = _ref.locale,
32
+ locale = _ref$locale === void 0 ? "en-IN" : _ref$locale,
33
+ format = _ref.format,
34
+ className = _ref.className,
35
+ rest = _objectWithoutProperties(_ref, _excluded);
36
+ var live = useRef(null);
37
+ var reduced = useReducedMotion();
38
+ var digits = decimals !== null && decimals !== void 0 ? decimals : decimalsOf(value);
39
+ var fmt = useMemo(function () {
40
+ if (format) return format;
41
+ var nf = new Intl.NumberFormat(locale, {
42
+ minimumFractionDigits: digits,
43
+ maximumFractionDigits: digits
44
+ });
45
+ return function (n) {
46
+ return nf.format(n);
47
+ };
48
+ }, [format, locale, digits]);
49
+ var finalText = fmt(value);
50
+ useEffect(function () {
51
+ var el = live.current;
52
+ if (!el || reduced || duration <= 0) return undefined;
53
+ // Below the fold: show the start value until it scrolls in. On screen: count right away.
54
+ if (el.getBoundingClientRect().top > innerHeight) el.textContent = fmt(from);
55
+ var unsubscribe = null;
56
+ var stop = function stop() {};
57
+ stop = observe(el, function (inView) {
58
+ if (!inView || unsubscribe) return;
59
+ stop();
60
+ var t0 = null;
61
+ unsubscribe = subscribe({
62
+ loop: true,
63
+ write: function write(_, now) {
64
+ if (t0 === null) t0 = now;
65
+ var t = Math.min(1, (now - t0) / duration);
66
+ el.textContent = t < 1 ? fmt(from + (value - from) * easeOut(t)) : fmt(value);
67
+ if (t >= 1) unsubscribe();
68
+ }
69
+ });
70
+ }, {
71
+ threshold: 0.4
72
+ });
73
+ return function () {
74
+ stop();
75
+ if (unsubscribe) unsubscribe();
76
+ el.textContent = fmt(value);
77
+ };
78
+ }, [value, from, duration, fmt, reduced]);
79
+ return jsxs("span", _objectSpread2(_objectSpread2({
80
+ ref: ref,
81
+ className: cn("tabular-nums", className)
82
+ }, rest), {}, {
83
+ children: [jsxs("span", {
84
+ "aria-hidden": "true",
85
+ children: [prefix, jsx("span", {
86
+ ref: live,
87
+ children: finalText
88
+ }), suffix]
89
+ }), jsxs("span", {
90
+ className: "sr-only",
91
+ children: [prefix, finalText, suffix]
92
+ })]
93
+ }));
94
+ });
95
+ CountUp.displayName = "CountUp";
96
+
97
+ export { CountUp as default };