@flamingo-stack/openframe-frontend-core 0.0.449-snapshot.20260718143201 → 0.0.449

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 (142) hide show
  1. package/dist/{chunk-DQ5U6DCR.cjs → chunk-47AMTR2S.cjs} +18 -18
  2. package/dist/{chunk-DQ5U6DCR.cjs.map → chunk-47AMTR2S.cjs.map} +1 -1
  3. package/dist/{chunk-PCW2TRZ4.js → chunk-4IMXFDRI.js} +3 -3
  4. package/dist/{chunk-XITG5ICQ.cjs → chunk-4S4RR7XC.cjs} +40 -40
  5. package/dist/{chunk-XITG5ICQ.cjs.map → chunk-4S4RR7XC.cjs.map} +1 -1
  6. package/dist/{chunk-HXCQHMS5.js → chunk-5SJGFLL2.js} +6032 -6386
  7. package/dist/chunk-5SJGFLL2.js.map +1 -0
  8. package/dist/{chunk-6RA4NRBA.cjs → chunk-6TS4AIDX.cjs} +15 -15
  9. package/dist/{chunk-6RA4NRBA.cjs.map → chunk-6TS4AIDX.cjs.map} +1 -1
  10. package/dist/{chunk-QF3NQW7C.cjs → chunk-AN7MCJTV.cjs} +29 -122
  11. package/dist/chunk-AN7MCJTV.cjs.map +1 -0
  12. package/dist/{chunk-J5BYYZVM.cjs → chunk-AZKVNRZP.cjs} +32 -32
  13. package/dist/{chunk-J5BYYZVM.cjs.map → chunk-AZKVNRZP.cjs.map} +1 -1
  14. package/dist/{chunk-VUDZOCPW.js → chunk-BSBWBQ7M.js} +6 -6
  15. package/dist/{chunk-26JSJMMZ.cjs → chunk-DJP5HYFG.cjs} +7 -7
  16. package/dist/{chunk-26JSJMMZ.cjs.map → chunk-DJP5HYFG.cjs.map} +1 -1
  17. package/dist/{chunk-5HW5HMNF.cjs → chunk-DRKQNXSZ.cjs} +5 -5
  18. package/dist/{chunk-5HW5HMNF.cjs.map → chunk-DRKQNXSZ.cjs.map} +1 -1
  19. package/dist/{chunk-ROBGJH52.cjs → chunk-EOFENGSZ.cjs} +12 -12
  20. package/dist/{chunk-ROBGJH52.cjs.map → chunk-EOFENGSZ.cjs.map} +1 -1
  21. package/dist/{chunk-N5M72LJX.cjs → chunk-H56AEHFC.cjs} +1266 -1620
  22. package/dist/chunk-H56AEHFC.cjs.map +1 -0
  23. package/dist/{chunk-RQHHACP2.js → chunk-HQ7S6JG5.js} +3 -3
  24. package/dist/{chunk-K3GXIGN6.js → chunk-JAASDJOF.js} +5 -5
  25. package/dist/{chunk-5OY7HYII.cjs → chunk-KKJRBMG3.cjs} +73 -73
  26. package/dist/{chunk-5OY7HYII.cjs.map → chunk-KKJRBMG3.cjs.map} +1 -1
  27. package/dist/{chunk-VLDZ4363.cjs → chunk-LQTX7EJS.cjs} +29 -29
  28. package/dist/{chunk-VLDZ4363.cjs.map → chunk-LQTX7EJS.cjs.map} +1 -1
  29. package/dist/{chunk-4VSTLJDO.js → chunk-LWT6G75Q.js} +2 -2
  30. package/dist/{chunk-4SZDO3TE.js → chunk-MWRFPLNB.js} +3 -3
  31. package/dist/{chunk-3ITY2LBM.js → chunk-NPBTNWRA.js} +4 -4
  32. package/dist/{chunk-UPRY4I63.cjs → chunk-ROCJMSJI.cjs} +3 -3
  33. package/dist/{chunk-UPRY4I63.cjs.map → chunk-ROCJMSJI.cjs.map} +1 -1
  34. package/dist/{chunk-MLFFBQ5B.js → chunk-TKGCTDQY.js} +87 -180
  35. package/dist/chunk-TKGCTDQY.js.map +1 -0
  36. package/dist/{chunk-M3AKWFAO.js → chunk-UNQVTGVG.js} +2 -2
  37. package/dist/{chunk-HYIHXXF3.js → chunk-VSWFYFIG.js} +5 -5
  38. package/dist/{chunk-6GJKSYM2.cjs → chunk-WYPROXL4.cjs} +73 -73
  39. package/dist/{chunk-6GJKSYM2.cjs.map → chunk-WYPROXL4.cjs.map} +1 -1
  40. package/dist/{chunk-76EN3GEH.cjs → chunk-X754WDWO.cjs} +40 -40
  41. package/dist/{chunk-76EN3GEH.cjs.map → chunk-X754WDWO.cjs.map} +1 -1
  42. package/dist/{chunk-N53FC732.js → chunk-XLFAFH2B.js} +2 -2
  43. package/dist/{chunk-EQWE64RJ.js → chunk-YHNBJ3F3.js} +2 -2
  44. package/dist/{chunk-CM5XKHHS.js → chunk-YSNMV53O.js} +6 -6
  45. package/dist/components/case-studies/index.cjs +9 -9
  46. package/dist/components/case-studies/index.js +3 -3
  47. package/dist/components/chat/chat-quick-action-row.d.ts +1 -26
  48. package/dist/components/chat/chat-quick-action-row.d.ts.map +1 -1
  49. package/dist/components/chat/index.cjs +3 -15
  50. package/dist/components/chat/index.cjs.map +1 -1
  51. package/dist/components/chat/index.d.ts +0 -1
  52. package/dist/components/chat/index.d.ts.map +1 -1
  53. package/dist/components/chat/index.js +2 -14
  54. package/dist/components/chat/quick-action-chip.d.ts +4 -45
  55. package/dist/components/chat/quick-action-chip.d.ts.map +1 -1
  56. package/dist/components/chat/quick-action-marquee.d.ts +9 -24
  57. package/dist/components/chat/quick-action-marquee.d.ts.map +1 -1
  58. package/dist/components/contact/index.cjs +4 -4
  59. package/dist/components/contact/index.js +3 -3
  60. package/dist/components/content-loading-container.d.ts +1 -1
  61. package/dist/components/docs/index.cjs +6 -6
  62. package/dist/components/docs/index.js +5 -5
  63. package/dist/components/embeds/index.cjs +4 -4
  64. package/dist/components/embeds/index.js +3 -3
  65. package/dist/components/faq/index.cjs +5 -5
  66. package/dist/components/faq/index.js +4 -4
  67. package/dist/components/features/cards-strip.d.ts.map +1 -1
  68. package/dist/components/features/index.cjs +3 -3
  69. package/dist/components/features/index.js +2 -2
  70. package/dist/components/form.d.ts +1 -1
  71. package/dist/components/form.d.ts.map +1 -1
  72. package/dist/components/help-center-pages/index.cjs +22 -22
  73. package/dist/components/help-center-pages/index.js +13 -13
  74. package/dist/components/index.cjs +135 -159
  75. package/dist/components/index.cjs.map +1 -1
  76. package/dist/components/index.js +11 -35
  77. package/dist/components/index.js.map +1 -1
  78. package/dist/components/navigation/index.cjs +3 -3
  79. package/dist/components/navigation/index.js +2 -2
  80. package/dist/components/onboarding-guides/index.cjs +7 -7
  81. package/dist/components/onboarding-guides/index.js +6 -6
  82. package/dist/components/related-content/index.cjs +5 -5
  83. package/dist/components/related-content/index.js +4 -4
  84. package/dist/components/tickets/index.cjs +6 -6
  85. package/dist/components/tickets/index.js +5 -5
  86. package/dist/components/ui/index.cjs +3 -27
  87. package/dist/components/ui/index.cjs.map +1 -1
  88. package/dist/components/ui/index.d.ts +0 -1
  89. package/dist/components/ui/index.d.ts.map +1 -1
  90. package/dist/components/ui/index.js +2 -26
  91. package/dist/hooks/index.cjs +2 -6
  92. package/dist/hooks/index.cjs.map +1 -1
  93. package/dist/hooks/index.js +1 -5
  94. package/dist/hooks/ui/index.d.ts +0 -2
  95. package/dist/hooks/ui/index.d.ts.map +1 -1
  96. package/dist/index.cjs +3 -31
  97. package/dist/index.cjs.map +1 -1
  98. package/dist/index.js +2 -30
  99. package/dist/tailwind.config.cjs +8 -1
  100. package/dist/tailwind.config.cjs.map +1 -1
  101. package/dist/tailwind.config.js +8 -1
  102. package/dist/tailwind.config.js.map +1 -1
  103. package/package.json +1 -1
  104. package/src/components/chat/chat-quick-action-row.tsx +3 -47
  105. package/src/components/chat/index.ts +0 -1
  106. package/src/components/chat/quick-action-chip.tsx +13 -81
  107. package/src/components/chat/quick-action-marquee.tsx +47 -54
  108. package/src/components/features/cards-strip.tsx +158 -88
  109. package/src/components/ui/index.ts +0 -1
  110. package/src/hooks/ui/index.ts +0 -2
  111. package/src/stories/QuickActionMarquee.stories.tsx +7 -8
  112. package/tailwind.config.ts +7 -0
  113. package/dist/chunk-HXCQHMS5.js.map +0 -1
  114. package/dist/chunk-MLFFBQ5B.js.map +0 -1
  115. package/dist/chunk-N5M72LJX.cjs.map +0 -1
  116. package/dist/chunk-QF3NQW7C.cjs.map +0 -1
  117. package/dist/components/chat/quick-action-wall.d.ts +0 -96
  118. package/dist/components/chat/quick-action-wall.d.ts.map +0 -1
  119. package/dist/components/ui/marquee-wall.d.ts +0 -159
  120. package/dist/components/ui/marquee-wall.d.ts.map +0 -1
  121. package/dist/hooks/ui/use-marquee-engine.d.ts +0 -73
  122. package/dist/hooks/ui/use-marquee-engine.d.ts.map +0 -1
  123. package/dist/hooks/ui/use-suppress-clone-focus.d.ts +0 -24
  124. package/dist/hooks/ui/use-suppress-clone-focus.d.ts.map +0 -1
  125. package/src/components/chat/quick-action-wall.tsx +0 -247
  126. package/src/components/ui/marquee-wall.tsx +0 -522
  127. package/src/hooks/ui/use-marquee-engine.ts +0 -158
  128. package/src/hooks/ui/use-suppress-clone-focus.ts +0 -61
  129. package/src/stories/MarqueeWall.stories.tsx +0 -132
  130. package/src/stories/QuickActionWall.stories.tsx +0 -116
  131. /package/dist/{chunk-PCW2TRZ4.js.map → chunk-4IMXFDRI.js.map} +0 -0
  132. /package/dist/{chunk-VUDZOCPW.js.map → chunk-BSBWBQ7M.js.map} +0 -0
  133. /package/dist/{chunk-RQHHACP2.js.map → chunk-HQ7S6JG5.js.map} +0 -0
  134. /package/dist/{chunk-K3GXIGN6.js.map → chunk-JAASDJOF.js.map} +0 -0
  135. /package/dist/{chunk-4VSTLJDO.js.map → chunk-LWT6G75Q.js.map} +0 -0
  136. /package/dist/{chunk-4SZDO3TE.js.map → chunk-MWRFPLNB.js.map} +0 -0
  137. /package/dist/{chunk-3ITY2LBM.js.map → chunk-NPBTNWRA.js.map} +0 -0
  138. /package/dist/{chunk-M3AKWFAO.js.map → chunk-UNQVTGVG.js.map} +0 -0
  139. /package/dist/{chunk-HYIHXXF3.js.map → chunk-VSWFYFIG.js.map} +0 -0
  140. /package/dist/{chunk-N53FC732.js.map → chunk-XLFAFH2B.js.map} +0 -0
  141. /package/dist/{chunk-EQWE64RJ.js.map → chunk-YHNBJ3F3.js.map} +0 -0
  142. /package/dist/{chunk-CM5XKHHS.js.map → chunk-YSNMV53O.js.map} +0 -0
@@ -1,96 +0,0 @@
1
- import * as React from 'react';
2
- import { type MarqueeSyncController, type MarqueeWallFadeEdge, type MarqueeWallProps } from '../ui/marquee-wall';
3
- import type { QuickActionTheme, QuickActionThemeAccents } from './quick-action-chip';
4
- import type { QuickActionChip } from './chat-quick-action-row';
5
- /** Skeleton label widths (ch) — realistic spread, cycled. THE wall-skeleton
6
- * spread, shared with the company-hub deck's ChipWall: sized so a 24-item
7
- * wall overflows typical caps at any viewport width (same fill + fade as
8
- * the loaded state — zero height jump when data lands). */
9
- export declare const WALL_SKELETON_LABEL_CH: number[];
10
- /** Deterministic index-alternating merge — the mixed "one stream" pile
11
- * (deck slide 3's IT+SEC blend and its Storybook mirror). Input order
12
- * stable → the blend never reshuffles across renders or consumers. */
13
- export declare function interleave<T>(a: ReadonlyArray<T>, b: ReadonlyArray<T>): T[];
14
- export interface QuickActionWallProps {
15
- /** The wall's chips — the shared {@link QuickActionChip} shape (same as the
16
- * chat rows), including per-chip `theme`/`lozenge` for mixed IT/SEC
17
- * streams. Chips with `onSelect` render as buttons; without, as tags. */
18
- chips: ReadonlyArray<QuickActionChip>;
19
- /** Wall-default theme (fae/mingo/it/sec) for chips without their own. */
20
- theme?: QuickActionTheme;
21
- /** Server-configured per-theme accent overrides
22
- * ({@link QuickActionThemeAccents}) — inject the agents' configured colors
23
- * (resolve via `accentFromIdentityIcon`); the built-in theme accents are
24
- * fallback-only. Per-chip `themeAccent` still wins. */
25
- themeAccents?: QuickActionThemeAccents;
26
- /** `'animated'` (default): marquee + overflow fades. `'plain'`: no motion,
27
- * no blur — the consumer's per-surface opt-out (forwarded to
28
- * {@link MarqueeWall}; in brick mode the rows render static and the
29
- * stack-level fades are skipped). */
30
- mode?: 'animated' | 'plain';
31
- /** Render every chip's theme lozenge (classification walls). Per-chip
32
- * `lozenge` values still win. */
33
- lozenges?: boolean;
34
- /** Marquee axis — defaults to where `fade` sits (see {@link MarqueeWall}). */
35
- axis?: MarqueeWallProps['axis'];
36
- reverse?: boolean;
37
- /** px/s. Default 40 (MarqueeWall default). */
38
- speed?: number;
39
- /** Marquee on/off (auto-off when content fits / reduced motion / loading). */
40
- animate?: boolean;
41
- pauseOnHover?: boolean;
42
- fade?: MarqueeWallFadeEdge | ReadonlyArray<MarqueeWallFadeEdge>;
43
- /** Color behind the wall — the fades blend into it. */
44
- fadeColor?: string;
45
- fadeSize?: MarqueeWallProps['fadeSize'];
46
- /** THE wall pitch — one value drives the chip gap, the clone-seam gap, and
47
- * (in brick mode) the row-stack gap, so the courses read as a uniform wall
48
- * and the seam is invisible by construction. Default
49
- * `var(--spacing-system-xsf)`. */
50
- copyGap?: number | string;
51
- /** Pad the track by REPEATING the chips up to this count (suffixed keys) so
52
- * one copy always overflows the container and the loop engages — without
53
- * it a wall whose content roughly fits its box goes static (the marquee
54
- * only loops what overflows). Defaults to `rows × 14` in brick mode;
55
- * unset otherwise (capped walls that always overflow, and FLIP-tracked
56
- * walls where repeats would duplicate flip ids, need no padding). */
57
- minChips?: number;
58
- /**
59
- * BRICK-WALL mode: render this many stacked independent single-row
60
- * marquees (chips distributed round-robin) instead of one track. Rows pack
61
- * their chips edge-to-edge like bricks — a grid would column-align chips
62
- * of different widths and leave holes — and each row loops on its own
63
- * wrap, so the courses stagger organically. Horizontal only; the fades
64
- * draw ONCE over the whole stack.
65
- */
66
- rows?: number;
67
- /** Draw skeleton chips instead of `chips` (the shared
68
- * {@link QuickActionChipSkeleton} — 1:1 geometry with loaded chips).
69
- * Callers own the policy (`loading` flag vs skeleton-when-empty). */
70
- loading?: boolean;
71
- skeletonCount?: number;
72
- /** Outer container (sizing: height cap for vertical walls). */
73
- className?: string;
74
- /** Per-copy layout — default a wrapping chip wall. Override for single-row
75
- * marquee strips (`flex-nowrap`). */
76
- contentClassName?: string;
77
- /** Pair with sibling walls under one position driver (resolve strips). */
78
- sync?: MarqueeSyncController;
79
- }
80
- /**
81
- * <QuickActionWall> — THE quick-action chip wall: a themed pile of the shared
82
- * chip on the shared {@link MarqueeWall} engine. One component for every
83
- * surface that shows "the work the agents do" — homepage hero tabs, deck
84
- * panels, marketing strips — whether static-with-fade or endlessly scrolling
85
- * (axis follows the fade), interactive or decorative.
86
- *
87
- * Clone-copy chips stay INTERACTIVE (pointer cursor + working click) — the
88
- * loop paints clones inside the viewport (reverse walls even START on the
89
- * clone copy), and a visible chip that ignores clicks reads as broken. A11y
90
- * holds via the clone wrapper: aria-hidden + focus suppression (the standard
91
- * Swiper/Splide loop-clone treatment, same as CardsStrip). `pauseOnHover`
92
- * (default on) freezes the track under a pointing cursor so chips never
93
- * dodge a click.
94
- */
95
- export declare function QuickActionWall({ chips, theme, themeAccents, mode, lozenges, axis, reverse, speed, animate, pauseOnHover, fade, fadeColor, fadeSize, copyGap, minChips, rows, loading, skeletonCount, className, contentClassName, sync, }: QuickActionWallProps): React.JSX.Element;
96
- //# sourceMappingURL=quick-action-wall.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"quick-action-wall.d.ts","sourceRoot":"","sources":["../../../src/components/chat/quick-action-wall.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAA;AAE3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAEpF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAM9D;;;4DAG4D;AAC5D,eAAO,MAAM,sBAAsB,UAAmD,CAAA;AAEtF;;uEAEuE;AACvE,wBAAgB,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAO3E;AAUD,MAAM,WAAW,oBAAoB;IACnC;;8EAE0E;IAC1E,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,CAAA;IACrC,yEAAyE;IACzE,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB;;;4DAGwD;IACxD,YAAY,CAAC,EAAE,uBAAuB,CAAA;IACtC;;;0CAGsC;IACtC,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAA;IAC3B;sCACkC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,IAAI,CAAC,EAAE,mBAAmB,GAAG,aAAa,CAAC,mBAAmB,CAAC,CAAA;IAC/D,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAA;IACvC;;;uCAGmC;IACnC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB;;;;;0EAKsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;0EAEsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;0CACsC;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,qBAAqB,CAAA;CAC7B;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,KAAK,EACL,YAAY,EACZ,IAAiB,EACjB,QAAgB,EAChB,IAAI,EACJ,OAAO,EACP,KAAK,EACL,OAAc,EACd,YAAY,EACZ,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,IAAI,EACJ,OAAe,EACf,aAAkB,EAClB,SAAS,EACT,gBAAgB,EAChB,IAAI,GACL,EAAE,oBAAoB,qBA4FtB"}
@@ -1,159 +0,0 @@
1
- import * as React from 'react';
2
- export type MarqueeWallFadeEdge = 'top' | 'bottom' | 'left' | 'right';
3
- /** @internal per-instance sync membership (transform writer + driver-role
4
- * promotion callback, so a surviving member can be re-elected). */
5
- interface MarqueeSyncMember {
6
- apply: (pos: number) => void;
7
- makeDriver: () => void;
8
- }
9
- /**
10
- * Pairs two (or more) <MarqueeWall> instances to ONE position driver so their
11
- * tracks stay pixel-locked (the FreeTrialCTA resolve strips: a pending and a
12
- * resolved copy of the same chips, clip-path'd at the avatar line). The first
13
- * mounted instance claims the driver role and runs the shared rAF; the others
14
- * only register their `apply` transforms. If the driver unmounts while
15
- * members survive, the next member is promoted — the pair must merely be
16
- * geometry-identical while mounted together.
17
- */
18
- export interface MarqueeSyncController {
19
- /** @internal registered members in mount order. */
20
- members: Set<MarqueeSyncMember>;
21
- /** @internal current driver member. */
22
- driver: MarqueeSyncMember | null;
23
- /** @internal last driver-written position — a promoted driver's engine
24
- * seeds from it, so re-election never snaps the pair back to 0. */
25
- position: number;
26
- }
27
- export declare function useMarqueeSync(): MarqueeSyncController;
28
- export interface MarqueeTrackOffset {
29
- /** Applied translation (px) along each axis. */
30
- x: number;
31
- y: number;
32
- /** Loop wrap size (single copy + seam gap) along each axis; 0 on the
33
- * non-scroll axis. Lets morph engines treat a chip and its loop clone as
34
- * ONE identity `wrap` apart (the Swiper loop-clone model) and fly the
35
- * copy the viewer actually sees. */
36
- wrapX: number;
37
- wrapY: number;
38
- }
39
- /** Last known translation + wrap of the wall registered under `trackId`
40
- * (live or already unmounted). Zeros for unknown ids / static walls. */
41
- export declare function getMarqueeTrackOffset(trackId: string): MarqueeTrackOffset;
42
- /**
43
- * The translation ACTUALLY applied to a wall's track right now, read from the
44
- * DOM of the `data-marquee-track` container. Morph engines use this on the
45
- * CAPTURE side (never the registry): a same-id wall freshly remounted in the
46
- * current commit has not applied any transform yet, while the registry still
47
- * holds its predecessor's final drift for the flight-side lookup.
48
- */
49
- export declare function getMarqueeAppliedOffset(trackContainer: Element): {
50
- x: number;
51
- y: number;
52
- };
53
- /**
54
- * The loop-clone twin of an element inside a wall's PRIMARY copy (same index
55
- * in the `data-marquee-copy="clone"` copy), or null when there is no clone /
56
- * the element isn't in the primary copy. Owns the wall's internal DOM shape
57
- * so morph engines don't hardcode it; `selector` scopes which descendants
58
- * count as items (default: direct structure-preserving lookup by class is the
59
- * caller's job — pass the item selector, e.g. `'.flipchip'`).
60
- */
61
- export declare function getMarqueeCloneTwin(trackContainer: Element, el: Element, selector: string): HTMLElement | null;
62
- export interface MarqueeWallProps {
63
- /**
64
- * Presentation mode — the consumer's one switch for "do I want the
65
- * blur + marquee here at all":
66
- * - `'animated'` (default): endless marquee when content overflows, with
67
- * the overflow fades.
68
- * - `'plain'`: no motion, no fades — a plain clipped wall. All marquee
69
- * machinery (engine, clone copy, fades) is skipped entirely.
70
- */
71
- mode?: 'animated' | 'plain';
72
- /**
73
- * Marquee axis. Defaults to where the fade sits — the animation's job is to
74
- * reveal what the fade hides: a `bottom`/`top` fade clips rows → vertical
75
- * (content travels bottom→top); a `left`/`right`-only fade clips columns →
76
- * horizontal (content travels right→left). No fade → horizontal.
77
- */
78
- axis?: 'x' | 'y';
79
- /** Reverse travel: `x` reversed moves content right, `y` reversed moves it
80
- * down. Default false (left / up). */
81
- reverse?: boolean;
82
- /** Scroll speed in px/s (the CardsStrip unit — one speed language across
83
- * every marquee). Default 40: calm chip-wall drift, slower than the 60 the
84
- * card strips cruise at. */
85
- speed?: number;
86
- /** Master switch. Even when true the marquee auto-disables while the content
87
- * fits the container and under `prefers-reduced-motion` (static wall). */
88
- animate?: boolean;
89
- /** Freeze while a hover-capable pointer is anywhere over the wall — content
90
- * must never move under a pointing cursor (required for interactive chip
91
- * walls). Default true. */
92
- pauseOnHover?: boolean;
93
- /** Edge fade(s) — the "there's more" affordance. ONE spelling of the
94
- * clip-and-fade across every wall surface. */
95
- fade?: MarqueeWallFadeEdge | ReadonlyArray<MarqueeWallFadeEdge>;
96
- /** The color the fades blend INTO — must match the surface behind the wall
97
- * or the gradient paints a visible box. Default the page background. */
98
- fadeColor?: string;
99
- /** Fade thickness: one value for all edges or a per-edge map. Defaults:
100
- * 40px vertical edges, 112px horizontal edges (the shipped hero-wall
101
- * geometry). */
102
- fadeSize?: number | string | Partial<Record<MarqueeWallFadeEdge, number | string>>;
103
- /** Gap between the two track copies — match the content's own item gap so
104
- * the seam is invisible. A CSS length string (e.g. `var(--tlcl-chipgap)`)
105
- * lets responsive CSS own the value; the true seam distance is MEASURED
106
- * from the rendered copies either way. Default 8. */
107
- copyGap?: number | string;
108
- /** Outer container class — sizing lives here (height cap for `y`, width for
109
- * `x`). The container is always `relative overflow-hidden`. */
110
- className?: string;
111
- /** Class on EACH track copy — the wall's own layout (e.g. a wrapping chip
112
- * row `flex flex-wrap gap-2`, or a fixed-width grid). */
113
- contentClassName?: string;
114
- /** Inline style on EACH track copy — for values classes can't carry (e.g.
115
- * an item gap driven by the same variable as `copyGap`, so chip pitch and
116
- * seam pitch stay one value by construction). */
117
- contentStyle?: React.CSSProperties;
118
- /**
119
- * Wall content — ONE copy; the wall clones it for the endless loop (clone
120
- * `aria-hidden` + focus-suppressed but still clickable). Pass a render
121
- * callback to vary the clone copy (e.g. omit `data-flip-id`s / render
122
- * decorative chips). Children must be clone-safe: ref-free, unique-DOM-id-
123
- * free, mount-effect-free (same contract as <CardsStrip> children mode).
124
- */
125
- children: React.ReactNode | ((ctx: {
126
- isClone: boolean;
127
- }) => React.ReactNode);
128
- /** Pair this wall with sibling walls under one shared position driver. */
129
- sync?: MarqueeSyncController;
130
- /** Stable id for FLIP coordination: publishes the wall's live offset via
131
- * {@link getMarqueeTrackOffset} and stamps `data-marquee-track` on the
132
- * container so morph engines can drift-correct captured positions. */
133
- trackId?: string;
134
- }
135
- /** The wall's edge-fade overlays — exported so composite walls (stacked row
136
- * marquees) can draw ONE set of fades over the whole stack instead of
137
- * per-row copies. Parent must be `relative`. Overlays sit at z-1, ABOVE
138
- * FLIP flight ghosts (z-0 by contract): an in-flight chip dissolves under
139
- * the blur exactly like a resting chip. */
140
- export declare function MarqueeWallFades({ fade, fadeColor, fadeSize, }: {
141
- fade?: MarqueeWallFadeEdge | ReadonlyArray<MarqueeWallFadeEdge>;
142
- fadeColor?: string;
143
- fadeSize?: MarqueeWallProps['fadeSize'];
144
- }): React.JSX.Element;
145
- /**
146
- * <MarqueeWall> — THE endless-scroll wall container: a clipped area whose
147
- * content loops as a marquee along either axis, fading out where the clip
148
- * cuts. Built on the same `useMarqueeEngine` core as <CardsStrip> (the news /
149
- * logo / bites strips) with a TRANSFORM driver instead of a scroller — no
150
- * inner scrollable area is created, so it is safe inside surfaces that forbid
151
- * nested scrollers (the deck's mobile single-fold panels).
152
- *
153
- * Static by circumstance, not by variant: when the content fits the container
154
- * (or `prefers-reduced-motion`) the wall renders a single static copy with
155
- * its fades — byte-identical to the old non-animated walls.
156
- */
157
- export declare function MarqueeWall({ mode, axis: axisProp, reverse, speed, animate, pauseOnHover, fade, fadeColor, fadeSize, copyGap, className, contentClassName, contentStyle, children, sync, trackId, }: MarqueeWallProps): React.JSX.Element;
158
- export {};
159
- //# sourceMappingURL=marquee-wall.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"marquee-wall.d.ts","sourceRoot":"","sources":["../../../src/components/ui/marquee-wall.tsx"],"names":[],"mappings":"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"}
@@ -1,73 +0,0 @@
1
- import { type MutableRefObject } from 'react';
2
- /**
3
- * THE marquee animation core (single source of truth) — extracted verbatim
4
- * from <CardsStrip> so every endless-scroll surface (card strips, logo strips,
5
- * quick-action walls, chip marquees) shares ONE rAF position engine ("unify
6
- * means delete variations").
7
- *
8
- * The engine is axis- and driver-agnostic: it owns a FLOAT position ref, a
9
- * velocity envelope, seam wrapping, and an optional chevron-style glide; the
10
- * caller decides what a position "means" via `apply` — writing
11
- * `scroller.scrollLeft` (CardsStrip: a real scroller the user can also drag)
12
- * or a `translate` transform (MarqueeWall: decorative tracks, incl. vertical —
13
- * mandatory inside surfaces that forbid inner scrollers, e.g. the deck's
14
- * mobile single-fold panels).
15
- *
16
- * Engine semantics (do not "simplify"):
17
- * - Position lives in a FLOAT ref, never read-modify-write from the DOM:
18
- * scrollLeft reads back rounded values, so sub-pixel increments
19
- * (speed/fps < 1px) get eaten by rounding — stutter + measurably slower
20
- * than the configured speed.
21
- * - Velocity envelope (~250ms time constant) eases between 0 and `speed`
22
- * instead of binary stop/start — pause decelerates, resume accelerates from
23
- * the current position (GSAP-marquee behavior; hard cuts read as jank).
24
- * - Glide consumes a signed remaining-distance, wrapping modulo the copy size
25
- * each frame, so seam warps are invisible to it (browser smooth-scroll
26
- * animates toward an ABSOLUTE target and lunges after a warp).
27
- * - `isPaused` is evaluated every frame — the caller owns the pause-reason
28
- * set (hover, viewport, tab visibility, suppress windows); the engine only
29
- * turns it into a smooth velocity target.
30
- */
31
- export interface MarqueeEngineOptions {
32
- /** Master switch — the rAF runs only while true. On (re)activation the
33
- * position resyncs from `readBack` when provided. */
34
- active: boolean;
35
- /** Cruise speed in px/s. */
36
- speed: number;
37
- /** Per-frame pause verdict (caller-owned reason set). `now` is the rAF
38
- * timestamp, for suppress-until comparisons. */
39
- isPaused: (now: number) => boolean;
40
- /** Single-copy size in px (the wrap modulus). Return <= 0 to disable
41
- * wrapping (position advances unwrapped — callers should size tracks so
42
- * this never happens while active). */
43
- getWrapSize: () => number;
44
- /** Lower bound of the wrap range: positions stay in
45
- * [wrapMin, wrapMin + wrapSize). Default 0. Scroller drivers with USER
46
- * scrolling pass their seam-warp buffer here so engine-written positions
47
- * never enter the re-center zones — an exact-edge warp check is racy
48
- * against the rAF (the engine nudges the scroller off the edge before the
49
- * scroll handler samples it → "stuck at the left edge"). */
50
- getWrapMin?: () => number;
51
- /** Write the position to the DOM (scrollLeft assignment or transform). */
52
- apply: (pos: number) => void;
53
- /** Read the externally-mutated position back (real scrollers: user drag /
54
- * native smooth scroll move scrollLeft under the engine). Omit for
55
- * transform drivers — nothing external can move them. */
56
- readBack?: () => number;
57
- /** Called at the end of every frame (e.g. hover re-resolution after the
58
- * track moved under a stationary pointer). */
59
- onAfterFrame?: () => void;
60
- }
61
- export interface MarqueeEngineHandle {
62
- /** The engine's float position (px along the axis, 0 ≤ pos < wrap while
63
- * wrapping). Callers may write it together with their own DOM write (seam
64
- * warp on manual scroll). */
65
- posRef: MutableRefObject<number>;
66
- /** Accumulate a signed glide distance (chevron navigation). Runs through
67
- * the engine's own tween — never native smooth scroll while wrapping. */
68
- glideBy: (px: number) => void;
69
- /** Wrap an arbitrary position into [0, wrapSize). */
70
- wrap: (pos: number) => number;
71
- }
72
- export declare function useMarqueeEngine(options: MarqueeEngineOptions): MarqueeEngineHandle;
73
- //# sourceMappingURL=use-marquee-engine.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-marquee-engine.d.ts","sourceRoot":"","sources":["../../../src/hooks/ui/use-marquee-engine.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkC,KAAK,gBAAgB,EAAE,MAAM,OAAO,CAAA;AAE7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,WAAW,oBAAoB;IACnC;0DACsD;IACtD,MAAM,EAAE,OAAO,CAAA;IACf,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb;qDACiD;IACjD,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;IAClC;;4CAEwC;IACxC,WAAW,EAAE,MAAM,MAAM,CAAA;IACzB;;;;;iEAK6D;IAC7D,UAAU,CAAC,EAAE,MAAM,MAAM,CAAA;IACzB,0EAA0E;IAC1E,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IAC5B;;8DAE0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,MAAM,CAAA;IACvB;mDAC+C;IAC/C,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC;;kCAE8B;IAC9B,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IAChC;8EAC0E;IAC1E,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7B,qDAAqD;IACrD,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;CAC9B;AAKD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,oBAAoB,GAAG,mBAAmB,CA8EnF"}
@@ -1,24 +0,0 @@
1
- /**
2
- * Keep a marquee clone's content pointer-CLICKABLE while taking it out of the
3
- * accessibility tree and the keyboard tab order. Shared by every endless-loop
4
- * surface that renders a second track copy (<CardsStrip> managed cells,
5
- * <MarqueeWall> clone copies).
6
- *
7
- * `inert` (the previous approach) does all three at once: a11y-hidden,
8
- * un-focusable AND un-clickable. That third effect was the "news marquee stops
9
- * being clickable after you scroll it for a while" bug — the 2-copy endless
10
- * loop ALWAYS paints clone cards inside the viewport near the copy seam, so a
11
- * user who manually scrolls and parks there is looking at real-looking cards
12
- * that silently swallow every click. Clones must therefore stay clickable (a
13
- * click on ANY visible card must open its link — mouse, ⌘-click, middle-click
14
- * and context-menu all handled natively by the clone's own anchor).
15
- *
16
- * The a11y contract is still met without `inert`: the caller keeps
17
- * `aria-hidden` on the clone wrapper (out of the a11y tree) and this hook
18
- * forces every focusable descendant to `tabindex="-1"` (out of the tab order →
19
- * no duplicate tab stops, no aria-hidden-focus violation). Re-applied on
20
- * subtree mutation. This is the standard loop-clone treatment used by
21
- * Swiper/Splide.
22
- */
23
- export declare function useSuppressCloneFocus(active: boolean): import("react").RefObject<HTMLDivElement | null>;
24
- //# sourceMappingURL=use-suppress-clone-focus.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-suppress-clone-focus.d.ts","sourceRoot":"","sources":["../../../src/hooks/ui/use-suppress-clone-focus.ts"],"names":[],"mappings":"AAWA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,oDA2BpD"}
@@ -1,247 +0,0 @@
1
- 'use client'
2
-
3
- import * as React from 'react'
4
- import { cn } from '../../utils/cn'
5
- import {
6
- MarqueeWall,
7
- MarqueeWallFades,
8
- type MarqueeSyncController,
9
- type MarqueeWallFadeEdge,
10
- type MarqueeWallProps,
11
- } from '../ui/marquee-wall'
12
- import { QuickActionChipSkeleton } from './quick-action-chip'
13
- import type { QuickActionTheme, QuickActionThemeAccents } from './quick-action-chip'
14
- import { QuickActionChipFromData } from './chat-quick-action-row'
15
- import type { QuickActionChip } from './chat-quick-action-row'
16
-
17
- // =============================================================================
18
- // Shared wall constants
19
- // =============================================================================
20
-
21
- /** Skeleton label widths (ch) — realistic spread, cycled. THE wall-skeleton
22
- * spread, shared with the company-hub deck's ChipWall: sized so a 24-item
23
- * wall overflows typical caps at any viewport width (same fill + fade as
24
- * the loaded state — zero height jump when data lands). */
25
- export const WALL_SKELETON_LABEL_CH = [17, 24, 14, 20, 15, 25, 12, 21, 16, 19, 13, 23]
26
-
27
- /** Deterministic index-alternating merge — the mixed "one stream" pile
28
- * (deck slide 3's IT+SEC blend and its Storybook mirror). Input order
29
- * stable → the blend never reshuffles across renders or consumers. */
30
- export function interleave<T>(a: ReadonlyArray<T>, b: ReadonlyArray<T>): T[] {
31
- const out: T[] = []
32
- for (let i = 0; i < Math.max(a.length, b.length); i++) {
33
- if (a[i] !== undefined) out.push(a[i])
34
- if (b[i] !== undefined) out.push(b[i])
35
- }
36
- return out
37
- }
38
-
39
- // Brick-mode padding default: ~14 columns of chips per row (~3200px) — one
40
- // row copy overflows any sensible container, so the loop always engages.
41
- const DEFAULT_MIN_CHIPS_PER_ROW = 14
42
-
43
- // =============================================================================
44
- // Types
45
- // =============================================================================
46
-
47
- export interface QuickActionWallProps {
48
- /** The wall's chips — the shared {@link QuickActionChip} shape (same as the
49
- * chat rows), including per-chip `theme`/`lozenge` for mixed IT/SEC
50
- * streams. Chips with `onSelect` render as buttons; without, as tags. */
51
- chips: ReadonlyArray<QuickActionChip>
52
- /** Wall-default theme (fae/mingo/it/sec) for chips without their own. */
53
- theme?: QuickActionTheme
54
- /** Server-configured per-theme accent overrides
55
- * ({@link QuickActionThemeAccents}) — inject the agents' configured colors
56
- * (resolve via `accentFromIdentityIcon`); the built-in theme accents are
57
- * fallback-only. Per-chip `themeAccent` still wins. */
58
- themeAccents?: QuickActionThemeAccents
59
- /** `'animated'` (default): marquee + overflow fades. `'plain'`: no motion,
60
- * no blur — the consumer's per-surface opt-out (forwarded to
61
- * {@link MarqueeWall}; in brick mode the rows render static and the
62
- * stack-level fades are skipped). */
63
- mode?: 'animated' | 'plain'
64
- /** Render every chip's theme lozenge (classification walls). Per-chip
65
- * `lozenge` values still win. */
66
- lozenges?: boolean
67
- /** Marquee axis — defaults to where `fade` sits (see {@link MarqueeWall}). */
68
- axis?: MarqueeWallProps['axis']
69
- reverse?: boolean
70
- /** px/s. Default 40 (MarqueeWall default). */
71
- speed?: number
72
- /** Marquee on/off (auto-off when content fits / reduced motion / loading). */
73
- animate?: boolean
74
- pauseOnHover?: boolean
75
- fade?: MarqueeWallFadeEdge | ReadonlyArray<MarqueeWallFadeEdge>
76
- /** Color behind the wall — the fades blend into it. */
77
- fadeColor?: string
78
- fadeSize?: MarqueeWallProps['fadeSize']
79
- /** THE wall pitch — one value drives the chip gap, the clone-seam gap, and
80
- * (in brick mode) the row-stack gap, so the courses read as a uniform wall
81
- * and the seam is invisible by construction. Default
82
- * `var(--spacing-system-xsf)`. */
83
- copyGap?: number | string
84
- /** Pad the track by REPEATING the chips up to this count (suffixed keys) so
85
- * one copy always overflows the container and the loop engages — without
86
- * it a wall whose content roughly fits its box goes static (the marquee
87
- * only loops what overflows). Defaults to `rows × 14` in brick mode;
88
- * unset otherwise (capped walls that always overflow, and FLIP-tracked
89
- * walls where repeats would duplicate flip ids, need no padding). */
90
- minChips?: number
91
- /**
92
- * BRICK-WALL mode: render this many stacked independent single-row
93
- * marquees (chips distributed round-robin) instead of one track. Rows pack
94
- * their chips edge-to-edge like bricks — a grid would column-align chips
95
- * of different widths and leave holes — and each row loops on its own
96
- * wrap, so the courses stagger organically. Horizontal only; the fades
97
- * draw ONCE over the whole stack.
98
- */
99
- rows?: number
100
- /** Draw skeleton chips instead of `chips` (the shared
101
- * {@link QuickActionChipSkeleton} — 1:1 geometry with loaded chips).
102
- * Callers own the policy (`loading` flag vs skeleton-when-empty). */
103
- loading?: boolean
104
- skeletonCount?: number
105
- /** Outer container (sizing: height cap for vertical walls). */
106
- className?: string
107
- /** Per-copy layout — default a wrapping chip wall. Override for single-row
108
- * marquee strips (`flex-nowrap`). */
109
- contentClassName?: string
110
- /** Pair with sibling walls under one position driver (resolve strips). */
111
- sync?: MarqueeSyncController
112
- }
113
-
114
- // =============================================================================
115
- // Component
116
- // =============================================================================
117
-
118
- /**
119
- * <QuickActionWall> — THE quick-action chip wall: a themed pile of the shared
120
- * chip on the shared {@link MarqueeWall} engine. One component for every
121
- * surface that shows "the work the agents do" — homepage hero tabs, deck
122
- * panels, marketing strips — whether static-with-fade or endlessly scrolling
123
- * (axis follows the fade), interactive or decorative.
124
- *
125
- * Clone-copy chips stay INTERACTIVE (pointer cursor + working click) — the
126
- * loop paints clones inside the viewport (reverse walls even START on the
127
- * clone copy), and a visible chip that ignores clicks reads as broken. A11y
128
- * holds via the clone wrapper: aria-hidden + focus suppression (the standard
129
- * Swiper/Splide loop-clone treatment, same as CardsStrip). `pauseOnHover`
130
- * (default on) freezes the track under a pointing cursor so chips never
131
- * dodge a click.
132
- */
133
- export function QuickActionWall({
134
- chips,
135
- theme,
136
- themeAccents,
137
- mode = 'animated',
138
- lozenges = false,
139
- axis,
140
- reverse,
141
- speed,
142
- animate = true,
143
- pauseOnHover,
144
- fade,
145
- fadeColor,
146
- fadeSize,
147
- copyGap,
148
- minChips,
149
- rows,
150
- loading = false,
151
- skeletonCount = 24,
152
- className,
153
- contentClassName,
154
- sync,
155
- }: QuickActionWallProps) {
156
- // Repeat-pad the track (stable suffixed keys; repeats keep the full chip —
157
- // identical selected/interactive state, so every visible instance behaves
158
- // the same and the clone copy stays geometry-identical by construction).
159
- const padTarget = minChips ?? (rows ? rows * DEFAULT_MIN_CHIPS_PER_ROW : undefined)
160
- const track = React.useMemo(() => {
161
- if (!padTarget || chips.length === 0 || chips.length >= padTarget) return chips
162
- const repeats = Math.ceil(padTarget / chips.length)
163
- return Array.from({ length: repeats }, (_, r) =>
164
- r === 0 ? chips : chips.map(chip => ({ ...chip, id: `${chip.id}__r${r}` })),
165
- ).flat()
166
- }, [chips, padTarget])
167
-
168
- const renderSkeletons = (count: number, offset = 0) =>
169
- Array.from({ length: count }, (_, i) => (
170
- <QuickActionChipSkeleton
171
- key={i}
172
- lozenge={lozenges}
173
- labelCh={WALL_SKELETON_LABEL_CH[(offset + i) % WALL_SKELETON_LABEL_CH.length]}
174
- />
175
- ))
176
-
177
- const renderChipNodes = (list: ReadonlyArray<QuickActionChip>) =>
178
- list.map(chip => (
179
- <QuickActionChipFromData
180
- key={chip.id}
181
- chip={chip}
182
- defaultTheme={theme}
183
- themeAccents={themeAccents}
184
- defaultLozenge={lozenges}
185
- interactive={!!chip.onSelect}
186
- className="max-w-full"
187
- />
188
- ))
189
-
190
- const renderChips = () => (loading ? renderSkeletons(skeletonCount) : renderChipNodes(track))
191
-
192
- // ONE pitch for chips, clone seams, and (brick mode) the row stack — a
193
- // custom `copyGap` moves all three together, so no seam can ever disagree
194
- // with the chip gap.
195
- const gap = copyGap ?? 'var(--spacing-system-xsf)'
196
-
197
- // ---- BRICK-WALL mode: stacked independent row marquees ---------------------
198
- if (rows && rows > 0) {
199
- const rowLists = Array.from({ length: rows }, (_, r) => track.filter((_, i) => i % rows === r))
200
- const skelPerRow = Math.ceil(skeletonCount / rows)
201
- return (
202
- <div className={cn('relative flex flex-col overflow-hidden', className)} style={{ gap }}>
203
- {rowLists.map((list, r) => (
204
- <MarqueeWall
205
- key={r}
206
- mode={mode}
207
- axis="x"
208
- reverse={reverse}
209
- speed={speed}
210
- animate={animate && !loading}
211
- pauseOnHover={pauseOnHover}
212
- copyGap={gap}
213
- contentClassName={cn('flex items-center', contentClassName)}
214
- contentStyle={{ gap }}
215
- >
216
- {loading ? renderSkeletons(skelPerRow, r * 3) : renderChipNodes(list)}
217
- </MarqueeWall>
218
- ))}
219
- {mode === 'animated' && (
220
- <MarqueeWallFades fade={fade} fadeColor={fadeColor} fadeSize={fadeSize} />
221
- )}
222
- </div>
223
- )
224
- }
225
-
226
- return (
227
- <MarqueeWall
228
- mode={mode}
229
- axis={axis}
230
- reverse={reverse}
231
- speed={speed}
232
- // Skeleton walls stay put — the marquee starts when real chips land.
233
- animate={animate && !loading}
234
- pauseOnHover={pauseOnHover}
235
- fade={fade}
236
- fadeColor={fadeColor}
237
- fadeSize={fadeSize}
238
- copyGap={gap}
239
- className={className}
240
- contentClassName={cn('flex flex-wrap content-start items-start', contentClassName)}
241
- contentStyle={{ gap }}
242
- sync={sync}
243
- >
244
- {renderChips()}
245
- </MarqueeWall>
246
- )
247
- }