@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.
- package/dist/{chunk-DQ5U6DCR.cjs → chunk-47AMTR2S.cjs} +18 -18
- package/dist/{chunk-DQ5U6DCR.cjs.map → chunk-47AMTR2S.cjs.map} +1 -1
- package/dist/{chunk-PCW2TRZ4.js → chunk-4IMXFDRI.js} +3 -3
- package/dist/{chunk-XITG5ICQ.cjs → chunk-4S4RR7XC.cjs} +40 -40
- package/dist/{chunk-XITG5ICQ.cjs.map → chunk-4S4RR7XC.cjs.map} +1 -1
- package/dist/{chunk-HXCQHMS5.js → chunk-5SJGFLL2.js} +6032 -6386
- package/dist/chunk-5SJGFLL2.js.map +1 -0
- package/dist/{chunk-6RA4NRBA.cjs → chunk-6TS4AIDX.cjs} +15 -15
- package/dist/{chunk-6RA4NRBA.cjs.map → chunk-6TS4AIDX.cjs.map} +1 -1
- package/dist/{chunk-QF3NQW7C.cjs → chunk-AN7MCJTV.cjs} +29 -122
- package/dist/chunk-AN7MCJTV.cjs.map +1 -0
- package/dist/{chunk-J5BYYZVM.cjs → chunk-AZKVNRZP.cjs} +32 -32
- package/dist/{chunk-J5BYYZVM.cjs.map → chunk-AZKVNRZP.cjs.map} +1 -1
- package/dist/{chunk-VUDZOCPW.js → chunk-BSBWBQ7M.js} +6 -6
- package/dist/{chunk-26JSJMMZ.cjs → chunk-DJP5HYFG.cjs} +7 -7
- package/dist/{chunk-26JSJMMZ.cjs.map → chunk-DJP5HYFG.cjs.map} +1 -1
- package/dist/{chunk-5HW5HMNF.cjs → chunk-DRKQNXSZ.cjs} +5 -5
- package/dist/{chunk-5HW5HMNF.cjs.map → chunk-DRKQNXSZ.cjs.map} +1 -1
- package/dist/{chunk-ROBGJH52.cjs → chunk-EOFENGSZ.cjs} +12 -12
- package/dist/{chunk-ROBGJH52.cjs.map → chunk-EOFENGSZ.cjs.map} +1 -1
- package/dist/{chunk-N5M72LJX.cjs → chunk-H56AEHFC.cjs} +1266 -1620
- package/dist/chunk-H56AEHFC.cjs.map +1 -0
- package/dist/{chunk-RQHHACP2.js → chunk-HQ7S6JG5.js} +3 -3
- package/dist/{chunk-K3GXIGN6.js → chunk-JAASDJOF.js} +5 -5
- package/dist/{chunk-5OY7HYII.cjs → chunk-KKJRBMG3.cjs} +73 -73
- package/dist/{chunk-5OY7HYII.cjs.map → chunk-KKJRBMG3.cjs.map} +1 -1
- package/dist/{chunk-VLDZ4363.cjs → chunk-LQTX7EJS.cjs} +29 -29
- package/dist/{chunk-VLDZ4363.cjs.map → chunk-LQTX7EJS.cjs.map} +1 -1
- package/dist/{chunk-4VSTLJDO.js → chunk-LWT6G75Q.js} +2 -2
- package/dist/{chunk-4SZDO3TE.js → chunk-MWRFPLNB.js} +3 -3
- package/dist/{chunk-3ITY2LBM.js → chunk-NPBTNWRA.js} +4 -4
- package/dist/{chunk-UPRY4I63.cjs → chunk-ROCJMSJI.cjs} +3 -3
- package/dist/{chunk-UPRY4I63.cjs.map → chunk-ROCJMSJI.cjs.map} +1 -1
- package/dist/{chunk-MLFFBQ5B.js → chunk-TKGCTDQY.js} +87 -180
- package/dist/chunk-TKGCTDQY.js.map +1 -0
- package/dist/{chunk-M3AKWFAO.js → chunk-UNQVTGVG.js} +2 -2
- package/dist/{chunk-HYIHXXF3.js → chunk-VSWFYFIG.js} +5 -5
- package/dist/{chunk-6GJKSYM2.cjs → chunk-WYPROXL4.cjs} +73 -73
- package/dist/{chunk-6GJKSYM2.cjs.map → chunk-WYPROXL4.cjs.map} +1 -1
- package/dist/{chunk-76EN3GEH.cjs → chunk-X754WDWO.cjs} +40 -40
- package/dist/{chunk-76EN3GEH.cjs.map → chunk-X754WDWO.cjs.map} +1 -1
- package/dist/{chunk-N53FC732.js → chunk-XLFAFH2B.js} +2 -2
- package/dist/{chunk-EQWE64RJ.js → chunk-YHNBJ3F3.js} +2 -2
- package/dist/{chunk-CM5XKHHS.js → chunk-YSNMV53O.js} +6 -6
- package/dist/components/case-studies/index.cjs +9 -9
- package/dist/components/case-studies/index.js +3 -3
- package/dist/components/chat/chat-quick-action-row.d.ts +1 -26
- package/dist/components/chat/chat-quick-action-row.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +3 -15
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.d.ts +0 -1
- package/dist/components/chat/index.d.ts.map +1 -1
- package/dist/components/chat/index.js +2 -14
- package/dist/components/chat/quick-action-chip.d.ts +4 -45
- package/dist/components/chat/quick-action-chip.d.ts.map +1 -1
- package/dist/components/chat/quick-action-marquee.d.ts +9 -24
- package/dist/components/chat/quick-action-marquee.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +4 -4
- package/dist/components/contact/index.js +3 -3
- package/dist/components/content-loading-container.d.ts +1 -1
- package/dist/components/docs/index.cjs +6 -6
- package/dist/components/docs/index.js +5 -5
- package/dist/components/embeds/index.cjs +4 -4
- package/dist/components/embeds/index.js +3 -3
- package/dist/components/faq/index.cjs +5 -5
- package/dist/components/faq/index.js +4 -4
- package/dist/components/features/cards-strip.d.ts.map +1 -1
- package/dist/components/features/index.cjs +3 -3
- package/dist/components/features/index.js +2 -2
- package/dist/components/form.d.ts +1 -1
- package/dist/components/form.d.ts.map +1 -1
- package/dist/components/help-center-pages/index.cjs +22 -22
- package/dist/components/help-center-pages/index.js +13 -13
- package/dist/components/index.cjs +135 -159
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +11 -35
- package/dist/components/index.js.map +1 -1
- package/dist/components/navigation/index.cjs +3 -3
- package/dist/components/navigation/index.js +2 -2
- package/dist/components/onboarding-guides/index.cjs +7 -7
- package/dist/components/onboarding-guides/index.js +6 -6
- package/dist/components/related-content/index.cjs +5 -5
- package/dist/components/related-content/index.js +4 -4
- package/dist/components/tickets/index.cjs +6 -6
- package/dist/components/tickets/index.js +5 -5
- package/dist/components/ui/index.cjs +3 -27
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.d.ts +0 -1
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +2 -26
- package/dist/hooks/index.cjs +2 -6
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.js +1 -5
- package/dist/hooks/ui/index.d.ts +0 -2
- package/dist/hooks/ui/index.d.ts.map +1 -1
- package/dist/index.cjs +3 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -30
- package/dist/tailwind.config.cjs +8 -1
- package/dist/tailwind.config.cjs.map +1 -1
- package/dist/tailwind.config.js +8 -1
- package/dist/tailwind.config.js.map +1 -1
- package/package.json +1 -1
- package/src/components/chat/chat-quick-action-row.tsx +3 -47
- package/src/components/chat/index.ts +0 -1
- package/src/components/chat/quick-action-chip.tsx +13 -81
- package/src/components/chat/quick-action-marquee.tsx +47 -54
- package/src/components/features/cards-strip.tsx +158 -88
- package/src/components/ui/index.ts +0 -1
- package/src/hooks/ui/index.ts +0 -2
- package/src/stories/QuickActionMarquee.stories.tsx +7 -8
- package/tailwind.config.ts +7 -0
- package/dist/chunk-HXCQHMS5.js.map +0 -1
- package/dist/chunk-MLFFBQ5B.js.map +0 -1
- package/dist/chunk-N5M72LJX.cjs.map +0 -1
- package/dist/chunk-QF3NQW7C.cjs.map +0 -1
- package/dist/components/chat/quick-action-wall.d.ts +0 -96
- package/dist/components/chat/quick-action-wall.d.ts.map +0 -1
- package/dist/components/ui/marquee-wall.d.ts +0 -159
- package/dist/components/ui/marquee-wall.d.ts.map +0 -1
- package/dist/hooks/ui/use-marquee-engine.d.ts +0 -73
- package/dist/hooks/ui/use-marquee-engine.d.ts.map +0 -1
- package/dist/hooks/ui/use-suppress-clone-focus.d.ts +0 -24
- package/dist/hooks/ui/use-suppress-clone-focus.d.ts.map +0 -1
- package/src/components/chat/quick-action-wall.tsx +0 -247
- package/src/components/ui/marquee-wall.tsx +0 -522
- package/src/hooks/ui/use-marquee-engine.ts +0 -158
- package/src/hooks/ui/use-suppress-clone-focus.ts +0 -61
- package/src/stories/MarqueeWall.stories.tsx +0 -132
- package/src/stories/QuickActionWall.stories.tsx +0 -116
- /package/dist/{chunk-PCW2TRZ4.js.map → chunk-4IMXFDRI.js.map} +0 -0
- /package/dist/{chunk-VUDZOCPW.js.map → chunk-BSBWBQ7M.js.map} +0 -0
- /package/dist/{chunk-RQHHACP2.js.map → chunk-HQ7S6JG5.js.map} +0 -0
- /package/dist/{chunk-K3GXIGN6.js.map → chunk-JAASDJOF.js.map} +0 -0
- /package/dist/{chunk-4VSTLJDO.js.map → chunk-LWT6G75Q.js.map} +0 -0
- /package/dist/{chunk-4SZDO3TE.js.map → chunk-MWRFPLNB.js.map} +0 -0
- /package/dist/{chunk-3ITY2LBM.js.map → chunk-NPBTNWRA.js.map} +0 -0
- /package/dist/{chunk-M3AKWFAO.js.map → chunk-UNQVTGVG.js.map} +0 -0
- /package/dist/{chunk-HYIHXXF3.js.map → chunk-VSWFYFIG.js.map} +0 -0
- /package/dist/{chunk-N53FC732.js.map → chunk-XLFAFH2B.js.map} +0 -0
- /package/dist/{chunk-EQWE64RJ.js.map → chunk-YHNBJ3F3.js.map} +0 -0
- /package/dist/{chunk-CM5XKHHS.js.map → chunk-YSNMV53O.js.map} +0 -0
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useEffect, useRef } from 'react'
|
|
4
|
-
|
|
5
|
-
// Every focusable a clone might contain — matched so it can be pulled out of the
|
|
6
|
-
// keyboard tab order (see useSuppressCloneFocus). `[contenteditable]:not(
|
|
7
|
-
// [contenteditable="false"])` catches the empty/`"true"`/`"plaintext-only"`
|
|
8
|
-
// editable forms; `summary` is focusable inside a <details>.
|
|
9
|
-
const CLONE_FOCUSABLE_SELECTOR =
|
|
10
|
-
'a[href],button,input,select,textarea,iframe,summary,audio[controls],video[controls],[tabindex],[contenteditable]:not([contenteditable="false"])'
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Keep a marquee clone's content pointer-CLICKABLE while taking it out of the
|
|
14
|
-
* accessibility tree and the keyboard tab order. Shared by every endless-loop
|
|
15
|
-
* surface that renders a second track copy (<CardsStrip> managed cells,
|
|
16
|
-
* <MarqueeWall> clone copies).
|
|
17
|
-
*
|
|
18
|
-
* `inert` (the previous approach) does all three at once: a11y-hidden,
|
|
19
|
-
* un-focusable AND un-clickable. That third effect was the "news marquee stops
|
|
20
|
-
* being clickable after you scroll it for a while" bug — the 2-copy endless
|
|
21
|
-
* loop ALWAYS paints clone cards inside the viewport near the copy seam, so a
|
|
22
|
-
* user who manually scrolls and parks there is looking at real-looking cards
|
|
23
|
-
* that silently swallow every click. Clones must therefore stay clickable (a
|
|
24
|
-
* click on ANY visible card must open its link — mouse, ⌘-click, middle-click
|
|
25
|
-
* and context-menu all handled natively by the clone's own anchor).
|
|
26
|
-
*
|
|
27
|
-
* The a11y contract is still met without `inert`: the caller keeps
|
|
28
|
-
* `aria-hidden` on the clone wrapper (out of the a11y tree) and this hook
|
|
29
|
-
* forces every focusable descendant to `tabindex="-1"` (out of the tab order →
|
|
30
|
-
* no duplicate tab stops, no aria-hidden-focus violation). Re-applied on
|
|
31
|
-
* subtree mutation. This is the standard loop-clone treatment used by
|
|
32
|
-
* Swiper/Splide.
|
|
33
|
-
*/
|
|
34
|
-
export function useSuppressCloneFocus(active: boolean) {
|
|
35
|
-
const ref = useRef<HTMLDivElement | null>(null)
|
|
36
|
-
useEffect(() => {
|
|
37
|
-
const root = ref.current
|
|
38
|
-
if (!root || !active) return
|
|
39
|
-
const suppress = () => {
|
|
40
|
-
root.querySelectorAll<HTMLElement>(CLONE_FOCUSABLE_SELECTOR).forEach(el => {
|
|
41
|
-
// Only stamp the ones not already stamped — avoids touching the DOM (and
|
|
42
|
-
// clobbering an intentional tabindex) on every mutation.
|
|
43
|
-
if (el.getAttribute('tabindex') !== '-1') el.setAttribute('tabindex', '-1')
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
suppress()
|
|
47
|
-
// Watch structure AND the attributes that can turn a descendant tabbable
|
|
48
|
-
// (an anchor gaining `href`, React restoring `tabindex="0"`, an element
|
|
49
|
-
// becoming editable, media gaining `controls`). The `!== '-1'` guard above
|
|
50
|
-
// makes our own tabindex writes a no-op, so the observer never loops.
|
|
51
|
-
const mo = new MutationObserver(suppress)
|
|
52
|
-
mo.observe(root, {
|
|
53
|
-
childList: true,
|
|
54
|
-
subtree: true,
|
|
55
|
-
attributes: true,
|
|
56
|
-
attributeFilter: ['href', 'tabindex', 'contenteditable', 'controls'],
|
|
57
|
-
})
|
|
58
|
-
return () => mo.disconnect()
|
|
59
|
-
}, [active])
|
|
60
|
-
return ref
|
|
61
|
-
}
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
|
|
2
|
-
import { MarqueeWall, useMarqueeSync } from '../components/ui/marquee-wall'
|
|
3
|
-
|
|
4
|
-
// Arbitrary-children demo content: simple lockup tiles (the wall is
|
|
5
|
-
// content-agnostic — chips, logos, feed rows all ride the same engine).
|
|
6
|
-
const TILES = [
|
|
7
|
-
'Datto RMM',
|
|
8
|
-
'ConnectWise',
|
|
9
|
-
'HaloPSA',
|
|
10
|
-
'SentinelOne',
|
|
11
|
-
'Proofpoint',
|
|
12
|
-
'Veeam',
|
|
13
|
-
'Auvik',
|
|
14
|
-
'IT Glue',
|
|
15
|
-
]
|
|
16
|
-
|
|
17
|
-
function Tile({ label }: { label: string }) {
|
|
18
|
-
return (
|
|
19
|
-
<div className="flex h-16 w-48 shrink-0 items-center justify-center rounded-md border border-ods-border bg-ods-card text-h6 text-ods-text-secondary">
|
|
20
|
-
{label}
|
|
21
|
-
</div>
|
|
22
|
-
)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const meta: Meta<typeof MarqueeWall> = {
|
|
26
|
-
title: 'UI/MarqueeWall',
|
|
27
|
-
component: MarqueeWall,
|
|
28
|
-
parameters: {
|
|
29
|
-
layout: 'padded',
|
|
30
|
-
docs: {
|
|
31
|
-
description: {
|
|
32
|
-
component:
|
|
33
|
-
'THE endless-scroll wall container — a clipped area whose content loops as a marquee along either axis, fading where the clip cuts. Transform-driven on the shared `useMarqueeEngine` core (no inner scroller). Auto-static when the content fits or under `prefers-reduced-motion`. `useMarqueeSync` pins multiple walls to one position driver; `trackId` publishes live offsets for FLIP-morph coordination.',
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
decorators: [
|
|
38
|
-
(Story) => (
|
|
39
|
-
<div className="bg-ods-bg p-[var(--spacing-system-xl)]">
|
|
40
|
-
<Story />
|
|
41
|
-
</div>
|
|
42
|
-
),
|
|
43
|
-
],
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export default meta
|
|
47
|
-
type Story = StoryObj<typeof MarqueeWall>
|
|
48
|
-
|
|
49
|
-
/** Horizontal loop of arbitrary children with the default right fade. */
|
|
50
|
-
export const Horizontal: Story = {
|
|
51
|
-
render: () => (
|
|
52
|
-
<MarqueeWall fade="right" copyGap="var(--spacing-system-mf)" className="w-full" contentClassName="flex items-center gap-[var(--spacing-system-mf)]">
|
|
53
|
-
{TILES.map(t => (
|
|
54
|
-
<Tile key={t} label={t} />
|
|
55
|
-
))}
|
|
56
|
-
</MarqueeWall>
|
|
57
|
-
),
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/** Vertical loop (bottom fade → bottom→top travel) inside a height cap. */
|
|
61
|
-
export const Vertical: Story = {
|
|
62
|
-
render: () => (
|
|
63
|
-
<div className="w-64 rounded-md border border-ods-border bg-ods-card p-[var(--spacing-system-mf)]">
|
|
64
|
-
<MarqueeWall
|
|
65
|
-
fade="bottom"
|
|
66
|
-
fadeColor="var(--color-bg-card)"
|
|
67
|
-
copyGap="var(--spacing-system-mf)"
|
|
68
|
-
className="max-h-[240px]"
|
|
69
|
-
contentClassName="flex flex-col gap-[var(--spacing-system-mf)]"
|
|
70
|
-
>
|
|
71
|
-
{TILES.map(t => (
|
|
72
|
-
<Tile key={t} label={t} />
|
|
73
|
-
))}
|
|
74
|
-
</MarqueeWall>
|
|
75
|
-
</div>
|
|
76
|
-
),
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** Two walls pinned to ONE position driver via `useMarqueeSync` — scroll
|
|
80
|
-
* stays pixel-locked (the FreeTrialCTA resolve-strip mechanism). */
|
|
81
|
-
export const SyncedPair: Story = {
|
|
82
|
-
render: function SyncedPairStory() {
|
|
83
|
-
const sync = useMarqueeSync()
|
|
84
|
-
return (
|
|
85
|
-
<div className="flex flex-col gap-[var(--spacing-system-mf)]">
|
|
86
|
-
{[0, 1].map(row => (
|
|
87
|
-
<MarqueeWall
|
|
88
|
-
key={row}
|
|
89
|
-
sync={sync}
|
|
90
|
-
axis="x"
|
|
91
|
-
copyGap="var(--spacing-system-mf)"
|
|
92
|
-
className="w-full"
|
|
93
|
-
contentClassName="flex items-center gap-[var(--spacing-system-mf)]"
|
|
94
|
-
>
|
|
95
|
-
{TILES.map(t => (
|
|
96
|
-
<Tile key={t} label={t} />
|
|
97
|
-
))}
|
|
98
|
-
</MarqueeWall>
|
|
99
|
-
))}
|
|
100
|
-
</div>
|
|
101
|
-
)
|
|
102
|
-
},
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/** Plain mode — the consumer's opt-out: same wall, no motion, no fades. */
|
|
106
|
-
export const Plain: Story = {
|
|
107
|
-
render: () => (
|
|
108
|
-
<MarqueeWall mode="plain" className="w-full" contentClassName="flex items-center gap-[var(--spacing-system-mf)]">
|
|
109
|
-
{TILES.map(t => (
|
|
110
|
-
<Tile key={t} label={t} />
|
|
111
|
-
))}
|
|
112
|
-
</MarqueeWall>
|
|
113
|
-
),
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** Reverse travel (content moves right) with a custom-size leading fade. */
|
|
117
|
-
export const Reversed: Story = {
|
|
118
|
-
render: () => (
|
|
119
|
-
<MarqueeWall
|
|
120
|
-
reverse
|
|
121
|
-
fade={['left', 'right']}
|
|
122
|
-
fadeSize={{ left: 48 }}
|
|
123
|
-
copyGap="var(--spacing-system-mf)"
|
|
124
|
-
className="w-full"
|
|
125
|
-
contentClassName="flex items-center gap-[var(--spacing-system-mf)]"
|
|
126
|
-
>
|
|
127
|
-
{TILES.map(t => (
|
|
128
|
-
<Tile key={t} label={t} />
|
|
129
|
-
))}
|
|
130
|
-
</MarqueeWall>
|
|
131
|
-
),
|
|
132
|
-
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
|
|
2
|
-
import { QuickActionWall, interleave } from '../components/chat/quick-action-wall'
|
|
3
|
-
import type { QuickActionChip } from '../components/chat/chat-quick-action-row'
|
|
4
|
-
|
|
5
|
-
// A mixed IT/SEC stream (per-chip themes + lozenges) and a fae wall — the two
|
|
6
|
-
// wall registers: category-classified deck panels vs agent-themed hero walls.
|
|
7
|
-
const IT_ACTIONS: ReadonlyArray<QuickActionChip> = [
|
|
8
|
-
{ id: 'reset-password', label: 'Reset a password', icon: { name: 'key' }, theme: 'it' },
|
|
9
|
-
{ id: 'new-laptop', label: 'Provision a new laptop', icon: { name: 'laptop' }, theme: 'it' },
|
|
10
|
-
{ id: 'printer', label: 'Fix the printer', icon: { name: 'printer' }, theme: 'it' },
|
|
11
|
-
{ id: 'vpn', label: 'VPN will not connect', icon: { name: 'globe' }, theme: 'it' },
|
|
12
|
-
{ id: 'disk-full', label: 'Disk almost full', icon: { name: 'hard-drive' }, theme: 'it' },
|
|
13
|
-
{ id: 'onboard', label: 'Onboard a new hire', icon: { name: 'user-plus' }, theme: 'it' },
|
|
14
|
-
]
|
|
15
|
-
|
|
16
|
-
const SEC_ACTIONS: ReadonlyArray<QuickActionChip> = [
|
|
17
|
-
{ id: 'phishing', label: 'Phishing report triage', icon: { name: 'fish' }, theme: 'sec' },
|
|
18
|
-
{ id: 'mfa', label: 'Enforce MFA', icon: { name: 'shield-check' }, theme: 'sec' },
|
|
19
|
-
{ id: 'patch', label: 'Patch the CVE', icon: { name: 'bug' }, theme: 'sec' },
|
|
20
|
-
{ id: 'offboard', label: 'Revoke access on exit', icon: { name: 'user-minus' }, theme: 'sec' },
|
|
21
|
-
{ id: 'edr-alert', label: 'EDR alert review', icon: { name: 'radar' }, theme: 'sec' },
|
|
22
|
-
]
|
|
23
|
-
|
|
24
|
-
const FAE_ACTIONS: ReadonlyArray<QuickActionChip> = [
|
|
25
|
-
{ id: 'how-to-start', label: 'How to start', icon: { name: 'fae' } },
|
|
26
|
-
{ id: 'connect-device', label: 'Connect device', icon: { name: 'search' }, theme: 'fae' },
|
|
27
|
-
{ id: 'find-device', label: 'Find device', icon: { name: 'compass' }, theme: 'fae' },
|
|
28
|
-
{ id: 'remote-connection', label: 'Remote connection', icon: { name: 'rocket' }, theme: 'fae' },
|
|
29
|
-
{ id: 'run-scripts', label: 'Run scripts', icon: { name: 'bracket-curly' }, theme: 'fae' },
|
|
30
|
-
{ id: 'device-software', label: 'Device software', icon: { name: 'package' }, theme: 'fae' },
|
|
31
|
-
]
|
|
32
|
-
|
|
33
|
-
const meta: Meta<typeof QuickActionWall> = {
|
|
34
|
-
title: 'Chat/QuickActionWall',
|
|
35
|
-
component: QuickActionWall,
|
|
36
|
-
parameters: {
|
|
37
|
-
layout: 'padded',
|
|
38
|
-
docs: {
|
|
39
|
-
description: {
|
|
40
|
-
component:
|
|
41
|
-
'THE quick-action chip wall: a themed pile of the shared chip on the shared `<MarqueeWall>` engine. Static-with-fade when content fits (or `prefers-reduced-motion`); an endless marquee when it overflows — the axis follows the fade (`bottom` fade → content travels bottom→top; `right` fade → right→left). Themes: `fae`/`mingo` (agent identities) and `it`/`sec` (classification pair, with lozenges). Interactive chips pause the track on hover; clone-copy chips stay clickable with wrapper-level a11y. `rows` renders the brick-wall mode (stacked independent row marquees).',
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
decorators: [
|
|
46
|
-
(Story) => (
|
|
47
|
-
<div className="bg-ods-bg p-[var(--spacing-system-xl)]">
|
|
48
|
-
<Story />
|
|
49
|
-
</div>
|
|
50
|
-
),
|
|
51
|
-
],
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export default meta
|
|
55
|
-
type Story = StoryObj<typeof QuickActionWall>
|
|
56
|
-
|
|
57
|
-
/** Vertical wall (bottom fade → bottom→top marquee): the deck-panel register —
|
|
58
|
-
* mixed IT/SEC stream with lozenges, decorative chips. */
|
|
59
|
-
export const VerticalMixedStream: Story = {
|
|
60
|
-
render: () => (
|
|
61
|
-
<div className="rounded-md border border-ods-border bg-ods-card p-[var(--spacing-system-mf)]">
|
|
62
|
-
<QuickActionWall
|
|
63
|
-
chips={interleave(IT_ACTIONS, SEC_ACTIONS)}
|
|
64
|
-
lozenges
|
|
65
|
-
fade="bottom"
|
|
66
|
-
fadeColor="var(--color-bg-card)"
|
|
67
|
-
className="max-h-[180px]"
|
|
68
|
-
/>
|
|
69
|
-
</div>
|
|
70
|
-
),
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** Horizontal wall (right fade): the hero-tab register — a wide fae wall
|
|
74
|
-
* drifting right→left, interactive chips (hover pauses the track). */
|
|
75
|
-
export const HorizontalInteractive: Story = {
|
|
76
|
-
render: () => (
|
|
77
|
-
<QuickActionWall
|
|
78
|
-
chips={FAE_ACTIONS.map((c, i) => ({ ...c, selected: i === 0, selectedAccent: 'pink', onSelect: () => console.log(c.id) }))}
|
|
79
|
-
fade="right"
|
|
80
|
-
className="w-full"
|
|
81
|
-
contentClassName="w-[1400px]"
|
|
82
|
-
/>
|
|
83
|
-
),
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/** Plain mode — the consumer's opt-out: same chips and layout, no marquee,
|
|
87
|
-
* no blur. */
|
|
88
|
-
export const Plain: Story = {
|
|
89
|
-
render: () => (
|
|
90
|
-
<div className="rounded-md border border-ods-border bg-ods-card p-[var(--spacing-system-mf)]">
|
|
91
|
-
<QuickActionWall
|
|
92
|
-
chips={interleave(IT_ACTIONS, SEC_ACTIONS)}
|
|
93
|
-
mode="plain"
|
|
94
|
-
lozenges
|
|
95
|
-
className="max-h-[180px]"
|
|
96
|
-
/>
|
|
97
|
-
</div>
|
|
98
|
-
),
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/** Loading: skeleton chips (1:1 geometry, lozenge slots reserved) — static
|
|
102
|
-
* until real chips land. */
|
|
103
|
-
export const Loading: Story = {
|
|
104
|
-
render: () => (
|
|
105
|
-
<div className="rounded-md border border-ods-border bg-ods-card p-[var(--spacing-system-mf)]">
|
|
106
|
-
<QuickActionWall
|
|
107
|
-
chips={[]}
|
|
108
|
-
loading
|
|
109
|
-
lozenges
|
|
110
|
-
fade="bottom"
|
|
111
|
-
fadeColor="var(--color-bg-card)"
|
|
112
|
-
className="max-h-[180px]"
|
|
113
|
-
/>
|
|
114
|
-
</div>
|
|
115
|
-
),
|
|
116
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|