@flamingo-stack/openframe-frontend-core 0.0.459 → 0.0.460-snapshot.20260721124036

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 (92) hide show
  1. package/dist/{chunk-6XYHSDCL.cjs → chunk-2T5MXXTK.cjs} +31 -31
  2. package/dist/{chunk-6XYHSDCL.cjs.map → chunk-2T5MXXTK.cjs.map} +1 -1
  3. package/dist/{chunk-O5E7ZWHK.cjs → chunk-3H5XD5UD.cjs} +7 -7
  4. package/dist/{chunk-O5E7ZWHK.cjs.map → chunk-3H5XD5UD.cjs.map} +1 -1
  5. package/dist/{chunk-AS5B343N.js → chunk-4TKGFC7I.js} +2 -2
  6. package/dist/{chunk-DMU3BSPR.cjs → chunk-5D3UPZIM.cjs} +59 -59
  7. package/dist/{chunk-DMU3BSPR.cjs.map → chunk-5D3UPZIM.cjs.map} +1 -1
  8. package/dist/{chunk-XVHNAMAL.cjs → chunk-6IA5TD7O.cjs} +15 -15
  9. package/dist/{chunk-XVHNAMAL.cjs.map → chunk-6IA5TD7O.cjs.map} +1 -1
  10. package/dist/{chunk-MRKRE54X.js → chunk-7NUTHK3A.js} +4 -4
  11. package/dist/{chunk-WVC627C7.cjs → chunk-BFEMQ2XC.cjs} +26 -26
  12. package/dist/{chunk-WVC627C7.cjs.map → chunk-BFEMQ2XC.cjs.map} +1 -1
  13. package/dist/{chunk-GSKLTMIY.js → chunk-CDARBFPL.js} +2 -2
  14. package/dist/{chunk-JGSBLQLE.js → chunk-EXSLPPEY.js} +4 -4
  15. package/dist/{chunk-X5TAAOE7.cjs → chunk-FQKLIGV3.cjs} +62 -62
  16. package/dist/{chunk-X5TAAOE7.cjs.map → chunk-FQKLIGV3.cjs.map} +1 -1
  17. package/dist/{chunk-JWXOZRZ6.js → chunk-FYIX7RTZ.js} +4 -4
  18. package/dist/{chunk-CBNHSXTR.js → chunk-HHKLSJ5Y.js} +2 -2
  19. package/dist/{chunk-A2RF7ZG6.cjs → chunk-HWJWRQGV.cjs} +5 -5
  20. package/dist/{chunk-A2RF7ZG6.cjs.map → chunk-HWJWRQGV.cjs.map} +1 -1
  21. package/dist/{chunk-KW33TBQX.js → chunk-IQU6ZIZR.js} +2 -2
  22. package/dist/{chunk-TP5MVWQ2.js → chunk-KUVFE5WC.js} +665 -625
  23. package/dist/chunk-KUVFE5WC.js.map +1 -0
  24. package/dist/{chunk-IG4QVZSP.cjs → chunk-NFILBHXY.cjs} +9 -9
  25. package/dist/{chunk-IG4QVZSP.cjs.map → chunk-NFILBHXY.cjs.map} +1 -1
  26. package/dist/{chunk-EFGFAVOI.js → chunk-PLJSN3SR.js} +4 -4
  27. package/dist/{chunk-T2EBDVMZ.cjs → chunk-QLLXI554.cjs} +26 -26
  28. package/dist/{chunk-T2EBDVMZ.cjs.map → chunk-QLLXI554.cjs.map} +1 -1
  29. package/dist/{chunk-LDVQIOS7.js → chunk-RTLYVFFQ.js} +2 -2
  30. package/dist/{chunk-RTQ57HC5.js → chunk-S2KZZVJF.js} +2 -2
  31. package/dist/{chunk-YFPZLP63.cjs → chunk-TFVBIOSB.cjs} +771 -731
  32. package/dist/chunk-TFVBIOSB.cjs.map +1 -0
  33. package/dist/{chunk-OFPHMNRL.cjs → chunk-UNGRKZ65.cjs} +11 -11
  34. package/dist/{chunk-OFPHMNRL.cjs.map → chunk-UNGRKZ65.cjs.map} +1 -1
  35. package/dist/{chunk-OJ5ROJSS.cjs → chunk-WHXYDEAM.cjs} +37 -37
  36. package/dist/{chunk-OJ5ROJSS.cjs.map → chunk-WHXYDEAM.cjs.map} +1 -1
  37. package/dist/{chunk-Q74TSDZY.js → chunk-ZYHO7WAW.js} +2 -2
  38. package/dist/components/case-studies/index.cjs +8 -8
  39. package/dist/components/case-studies/index.js +2 -2
  40. package/dist/components/chat/guide-welcome.d.ts +5 -1
  41. package/dist/components/chat/guide-welcome.d.ts.map +1 -1
  42. package/dist/components/chat/index.cjs +2 -2
  43. package/dist/components/chat/index.js +1 -1
  44. package/dist/components/chat/mingo-welcome.d.ts +5 -1
  45. package/dist/components/chat/mingo-welcome.d.ts.map +1 -1
  46. package/dist/components/chat/quick-action-wall.d.ts +16 -6
  47. package/dist/components/chat/quick-action-wall.d.ts.map +1 -1
  48. package/dist/components/contact/index.cjs +3 -3
  49. package/dist/components/contact/index.js +2 -2
  50. package/dist/components/docs/index.cjs +5 -5
  51. package/dist/components/docs/index.js +4 -4
  52. package/dist/components/embeds/index.cjs +3 -3
  53. package/dist/components/embeds/index.js +2 -2
  54. package/dist/components/faq/index.cjs +3 -3
  55. package/dist/components/faq/index.js +2 -2
  56. package/dist/components/features/index.cjs +2 -2
  57. package/dist/components/features/index.js +1 -1
  58. package/dist/components/help-center-pages/index.cjs +20 -20
  59. package/dist/components/help-center-pages/index.js +11 -11
  60. package/dist/components/index.cjs +129 -129
  61. package/dist/components/index.js +9 -9
  62. package/dist/components/navigation/index.cjs +2 -2
  63. package/dist/components/navigation/index.js +1 -1
  64. package/dist/components/onboarding-guides/index.cjs +5 -5
  65. package/dist/components/onboarding-guides/index.js +4 -4
  66. package/dist/components/related-content/index.cjs +3 -3
  67. package/dist/components/related-content/index.js +2 -2
  68. package/dist/components/tickets/index.cjs +5 -5
  69. package/dist/components/tickets/index.js +4 -4
  70. package/dist/components/ui/index.cjs +2 -2
  71. package/dist/components/ui/index.js +1 -1
  72. package/dist/index.cjs +2 -2
  73. package/dist/index.js +1 -1
  74. package/package.json +1 -1
  75. package/src/components/chat/embeddable-chat.tsx +6 -0
  76. package/src/components/chat/guide-welcome.tsx +6 -0
  77. package/src/components/chat/mingo-welcome.tsx +6 -0
  78. package/src/components/chat/quick-action-wall.tsx +99 -11
  79. package/src/stories/QuickActionWall.stories.tsx +89 -0
  80. package/dist/chunk-TP5MVWQ2.js.map +0 -1
  81. package/dist/chunk-YFPZLP63.cjs.map +0 -1
  82. /package/dist/{chunk-AS5B343N.js.map → chunk-4TKGFC7I.js.map} +0 -0
  83. /package/dist/{chunk-MRKRE54X.js.map → chunk-7NUTHK3A.js.map} +0 -0
  84. /package/dist/{chunk-GSKLTMIY.js.map → chunk-CDARBFPL.js.map} +0 -0
  85. /package/dist/{chunk-JGSBLQLE.js.map → chunk-EXSLPPEY.js.map} +0 -0
  86. /package/dist/{chunk-JWXOZRZ6.js.map → chunk-FYIX7RTZ.js.map} +0 -0
  87. /package/dist/{chunk-CBNHSXTR.js.map → chunk-HHKLSJ5Y.js.map} +0 -0
  88. /package/dist/{chunk-KW33TBQX.js.map → chunk-IQU6ZIZR.js.map} +0 -0
  89. /package/dist/{chunk-EFGFAVOI.js.map → chunk-PLJSN3SR.js.map} +0 -0
  90. /package/dist/{chunk-LDVQIOS7.js.map → chunk-RTLYVFFQ.js.map} +0 -0
  91. /package/dist/{chunk-RTQ57HC5.js.map → chunk-S2KZZVJF.js.map} +0 -0
  92. /package/dist/{chunk-Q74TSDZY.js.map → chunk-ZYHO7WAW.js.map} +0 -0
@@ -38,10 +38,30 @@ export function interleave<T>(a: ReadonlyArray<T>, b: ReadonlyArray<T>): T[] {
38
38
  return out
39
39
  }
40
40
 
41
- // Brick-mode padding default: ~14 columns of chips per row (~3200px) — one
42
- // row copy overflows any sensible container, so the loop always engages.
41
+ // Brick-mode padding fallback: ~14 columns of chips per row (~3200px) — one
42
+ // row copy overflows any sensible container, so the loop always engages. Used
43
+ // as the row-count reference and until the container width has been measured;
44
+ // once measured, the per-row pad target adapts to that width (see MIN_CHIP_PX).
43
45
  const DEFAULT_MIN_CHIPS_PER_ROW = 14
44
46
 
47
+ // Conservative floor for one chip's on-track footprint in px (icon + a short
48
+ // mono label + Tag padding + the copy gap). The adaptive pad target divides the
49
+ // measured container width by this, so it must stay AT OR BELOW the narrowest
50
+ // real chip — an over-estimate would under-pad and the row could stop scrolling
51
+ // on a wide surface. Realistic quick-action labels are far wider, so the padded
52
+ // copy overflows comfortably; the `+ADAPTIVE_PAD_MARGIN` covers the worst case.
53
+ const MIN_CHIP_PX = 72
54
+ const ADAPTIVE_PAD_MARGIN = 2
55
+ // The adaptive target is clamped to [MIN_ADAPTIVE_PAD, DEFAULT_MIN_CHIPS_PER_ROW]:
56
+ // it only ever REDUCES padding below the fixed default (for narrow composers) —
57
+ // never above it, so no wide surface pads more than it does today.
58
+ const MIN_ADAPTIVE_PAD = 4
59
+
60
+ // Chat-agent walls (fae/mingo) cap the brick stack at 2 rows so the quick
61
+ // actions never crowd the composer; every other surface keeps the caller's
62
+ // `rows` as its cap.
63
+ const AGENT_MAX_ROWS = 2
64
+
45
65
  // =============================================================================
46
66
  // Types
47
67
  // =============================================================================
@@ -92,14 +112,24 @@ export interface QuickActionWallProps {
92
112
  * walls where repeats would duplicate flip ids, need no padding). */
93
113
  minChips?: number
94
114
  /**
95
- * BRICK-WALL mode: render this many stacked independent single-row
96
- * marquees (chips distributed round-robin) instead of one track. Rows pack
97
- * their chips edge-to-edge like bricks — a grid would column-align chips
98
- * of different widths and leave holes — and each row loops on its own
99
- * wrap, so the courses stagger organically. Horizontal only; the fades
115
+ * BRICK-WALL mode: the MAXIMUM number of stacked single-row marquees. The
116
+ * actual row count grows with the chip supply — `ceil(chips / 14)` capped at
117
+ * `rows` — so a short action set fills one row (padded with its own repeats)
118
+ * instead of spreading one chip per row. The originals are split evenly
119
+ * ACROSS the active rows first, THEN each row pads to a full course, so no
120
+ * row is ever all-duplicates while another holds the unique chips. Rows pack
121
+ * edge-to-edge like bricks (a grid would column-align mismatched widths and
122
+ * leave holes) and each loops on its own wrap. Horizontal only; the fades
100
123
  * draw ONCE over the whole stack.
101
124
  */
102
125
  rows?: number
126
+ /**
127
+ * Chat agent this wall belongs to (`'fae'` / `'mingo'`). When set to a
128
+ * built-in agent it caps the brick stack at {@link AGENT_MAX_ROWS} (2) so the
129
+ * actions stay compact above the composer; any other value (or unset) leaves
130
+ * the cap at `rows`. Optional — decorative/marketing walls omit it.
131
+ */
132
+ agentSlug?: string
103
133
  /** Draw skeleton chips instead of `chips` (the shared
104
134
  * {@link QuickActionChipSkeleton} — 1:1 geometry with loaded chips).
105
135
  * Callers own the policy (`loading` flag vs skeleton-when-empty). */
@@ -150,16 +180,36 @@ export function QuickActionWall({
150
180
  copyGap,
151
181
  minChips,
152
182
  rows,
183
+ agentSlug,
153
184
  loading = false,
154
185
  skeletonCount = 24,
155
186
  className,
156
187
  contentClassName,
157
188
  sync,
158
189
  }: QuickActionWallProps) {
190
+ // Measure the brick container so the per-row pad target can adapt to its
191
+ // width (see MIN_CHIP_PX): a narrow chat composer needs only a handful of
192
+ // repeats to overflow, a wide wall needs many. Pre-measure / SSR falls back
193
+ // to the fixed default, which always overflows. Only used in brick mode.
194
+ const brickRef = React.useRef<HTMLDivElement>(null)
195
+ const [brickWidth, setBrickWidth] = React.useState(0)
196
+ React.useEffect(() => {
197
+ const el = brickRef.current
198
+ if (!el || typeof ResizeObserver === 'undefined') return
199
+ const ro = new ResizeObserver(entries => {
200
+ const w = entries[0]?.contentRect.width ?? 0
201
+ if (w > 0) setBrickWidth(w)
202
+ })
203
+ ro.observe(el)
204
+ return () => ro.disconnect()
205
+ }, [])
206
+
159
207
  // Repeat-pad the track (stable suffixed keys; repeats keep the full chip —
160
208
  // identical selected/interactive state, so every visible instance behaves
161
209
  // the same and the clone copy stays geometry-identical by construction).
162
- const padTarget = minChips ?? (rows ? rows * DEFAULT_MIN_CHIPS_PER_ROW : undefined)
210
+ // Brick mode does its own per-row padding below, so this pads only the
211
+ // single-track (wrap / vertical) walls.
212
+ const padTarget = rows ? undefined : minChips
163
213
  const track = React.useMemo(() => {
164
214
  if (!padTarget || chips.length === 0 || chips.length >= padTarget) return chips
165
215
  const repeats = Math.ceil(padTarget / chips.length)
@@ -198,10 +248,48 @@ export function QuickActionWall({
198
248
 
199
249
  // ---- BRICK-WALL mode: stacked independent row marquees ---------------------
200
250
  if (rows && rows > 0) {
201
- const rowLists = Array.from({ length: rows }, (_, r) => track.filter((_, i) => i % rows === r))
202
- const skelPerRow = Math.ceil(skeletonCount / rows)
251
+ // Chat-agent walls (fae/mingo) grow the stack with the chip supply and cap
252
+ // it at AGENT_MAX_ROWS (2) so the actions stay compact above the composer.
253
+ // Every other surface keeps exactly `rows` rows (marketing/onboarding walls
254
+ // are sized for their design and carry far fewer than a full course/row).
255
+ const agentCapped = agentSlug === 'fae' || agentSlug === 'mingo'
256
+ const rowCap = agentCapped ? Math.min(rows, AGENT_MAX_ROWS) : rows
257
+ const dataRows = agentCapped
258
+ ? Math.min(Math.max(1, Math.ceil(chips.length / DEFAULT_MIN_CHIPS_PER_ROW)), rowCap)
259
+ : rows
260
+ // Skeletons hold the cap so the row count never jumps when real chips land.
261
+ const stackRows = loading ? rowCap : dataRows
262
+ // Per-row overflow target — how many chips one copy must hold to overflow
263
+ // the container (so the marquee loop engages). Priority: an explicit
264
+ // `minChips` budget wins; otherwise adapt to the MEASURED width (just enough
265
+ // repeats to overflow — no more, so a narrow composer isn't flooded with
266
+ // duplicates); before the first measure (or SSR) fall back to the fixed
267
+ // default, which overflows any width.
268
+ const adaptivePerRow =
269
+ brickWidth > 0
270
+ ? Math.min(
271
+ Math.max(Math.ceil(brickWidth / MIN_CHIP_PX) + ADAPTIVE_PAD_MARGIN, MIN_ADAPTIVE_PAD),
272
+ DEFAULT_MIN_CHIPS_PER_ROW,
273
+ )
274
+ : DEFAULT_MIN_CHIPS_PER_ROW
275
+ const perRowTarget = minChips ? Math.ceil(minChips / stackRows) : adaptivePerRow
276
+
277
+ // Split the ORIGINAL chips evenly across the rows FIRST (each row holds
278
+ // distinct actions), THEN pad each row to a full course with repeats of its
279
+ // OWN chips — so a row is never all-duplicates while another carries the
280
+ // unique ones (the old pad-then-slice split did exactly that when the chip
281
+ // count lined up with the row count).
282
+ const rowLists = Array.from({ length: stackRows }, (_, r) => {
283
+ const base = chips.filter((_, i) => i % stackRows === r)
284
+ if (base.length === 0 || base.length >= perRowTarget) return base
285
+ const repeats = Math.ceil(perRowTarget / base.length)
286
+ return Array.from({ length: repeats }, (_, rep) =>
287
+ rep === 0 ? base : base.map(chip => ({ ...chip, id: `${chip.id}__r${rep}` })),
288
+ ).flat()
289
+ })
290
+ const skelPerRow = Math.ceil(skeletonCount / stackRows)
203
291
  return (
204
- <div className={cn('relative flex flex-col overflow-hidden', className)} style={{ gap }}>
292
+ <div ref={brickRef} className={cn('relative flex flex-col overflow-hidden', className)} style={{ gap }}>
205
293
  {rowLists.map((list, r) => (
206
294
  <MarqueeWall
207
295
  key={r}
@@ -127,3 +127,92 @@ export const Loading: Story = {
127
127
  </div>
128
128
  ),
129
129
  }
130
+
131
+ // Brick-mode chip set: enough distinct actions to fill more than two full
132
+ // courses, so the agent cap and the even split are both visible.
133
+ const BRICK_ACTIONS: ReadonlyArray<QuickActionChip> = [
134
+ ...IT_ACTIONS,
135
+ ...SEC_ACTIONS,
136
+ ...FAE_ACTIONS.map((c) => ({ ...c, theme: FAE_THEME })),
137
+ ].map((c) => ({ ...c, onSelect: () => console.log(c.id) }))
138
+
139
+ /** Brick, chat agent (`agentSlug="mingo"`): the stack grows with the chip
140
+ * supply but caps at 2 rows. Originals are split evenly across the two rows
141
+ * first, then each row pads to a full course — no row is all-duplicates. */
142
+ export const BrickAgentCapped: Story = {
143
+ render: () => (
144
+ <QuickActionWall
145
+ chips={BRICK_ACTIONS}
146
+ agentSlug="mingo"
147
+ rows={4}
148
+ pauseOnHover
149
+ dragScroll
150
+ fade={['left', 'right']}
151
+ fadeSize={{ left: 32 }}
152
+ fadeColor="var(--color-bg)"
153
+ copyGap="var(--spacing-system-xxs)"
154
+ className="max-h-44"
155
+ />
156
+ ),
157
+ }
158
+
159
+ /** Brick, few actions (`agentSlug="fae"`, 3 chips): fewer than one course, so
160
+ * the stack collapses to a SINGLE row padded with its own repeats instead of
161
+ * spreading one chip per row. */
162
+ export const BrickFewActions: Story = {
163
+ render: () => (
164
+ <QuickActionWall
165
+ chips={FAE_ACTIONS.slice(0, 3).map((c) => ({ ...c, theme: FAE_THEME, onSelect: () => console.log(c.id) }))}
166
+ agentSlug="fae"
167
+ rows={4}
168
+ pauseOnHover
169
+ dragScroll
170
+ fade={['left', 'right']}
171
+ fadeSize={{ left: 32 }}
172
+ fadeColor="var(--color-bg)"
173
+ copyGap="var(--spacing-system-xxs)"
174
+ className="max-h-44"
175
+ />
176
+ ),
177
+ }
178
+
179
+ /** Brick, narrow composer: the per-row pad target adapts to the measured
180
+ * container width, so a chat-composer-width wall repeats each action only as
181
+ * many times as it takes to overflow (far fewer duplicates than the fixed
182
+ * 14), while a wide wall keeps the full course. Constrained to ~420px here to
183
+ * show the reduced duplication. */
184
+ export const BrickNarrowComposer: Story = {
185
+ render: () => (
186
+ <div className="w-[420px] max-w-full rounded-md border border-ods-border bg-ods-card p-[var(--spacing-system-mf)]">
187
+ <QuickActionWall
188
+ chips={FAE_ACTIONS.slice(0, 3).map((c) => ({ ...c, theme: FAE_THEME, onSelect: () => console.log(c.id) }))}
189
+ agentSlug="fae"
190
+ rows={4}
191
+ pauseOnHover
192
+ dragScroll
193
+ fade={['left', 'right']}
194
+ fadeSize={{ left: 32 }}
195
+ fadeColor="var(--color-bg-card)"
196
+ copyGap="var(--spacing-system-xxs)"
197
+ className="max-h-44"
198
+ />
199
+ </div>
200
+ ),
201
+ }
202
+
203
+ /** Brick, non-agent (no `agentSlug`): keeps exactly `rows` rows (marketing /
204
+ * onboarding walls are sized for their design), still getting the even split
205
+ * so a row is never filled with only one repeated chip. */
206
+ export const BrickNonAgent: Story = {
207
+ render: () => (
208
+ <QuickActionWall
209
+ chips={BRICK_ACTIONS}
210
+ rows={4}
211
+ fade={['left', 'right']}
212
+ fadeSize={{ left: 32 }}
213
+ fadeColor="var(--color-bg)"
214
+ copyGap="var(--spacing-system-xxs)"
215
+ className="max-h-56"
216
+ />
217
+ ),
218
+ }