@tomny-dev/uzi 0.7.1 → 0.8.0-pr.85.286.1.ccec3e4

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 (51) hide show
  1. package/README.md +8 -0
  2. package/dist/components/ai-chat/AIChat.d.ts +164 -0
  3. package/dist/components/ai-chat/AIChat.d.ts.map +1 -0
  4. package/dist/components/ai-chat/AIChat.test.d.ts +2 -0
  5. package/dist/components/ai-chat/AIChat.test.d.ts.map +1 -0
  6. package/dist/components/ai-chat/AIChatDock.d.ts +33 -0
  7. package/dist/components/ai-chat/AIChatDock.d.ts.map +1 -0
  8. package/dist/components/floating-action-stack/FloatingActionStack.d.ts +19 -0
  9. package/dist/components/floating-action-stack/FloatingActionStack.d.ts.map +1 -0
  10. package/dist/components/floating-action-stack/FloatingActionStack.test.d.ts +2 -0
  11. package/dist/components/floating-action-stack/FloatingActionStack.test.d.ts.map +1 -0
  12. package/dist/components/multi-select/MultiSelect.d.ts +3 -0
  13. package/dist/components/multi-select/MultiSelect.d.ts.map +1 -1
  14. package/dist/index.cjs +9 -0
  15. package/dist/index.d.ts +7 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +4 -1
  18. package/dist/index26.js +6 -2
  19. package/dist/index26.js.map +1 -1
  20. package/dist/index27.cjs +7 -1
  21. package/dist/index27.cjs.map +1 -1
  22. package/dist/index27.js +40 -10
  23. package/dist/index27.js.map +1 -1
  24. package/dist/index28.cjs +40 -10
  25. package/dist/index28.cjs.map +1 -1
  26. package/dist/index75.js +91 -0
  27. package/dist/index75.js.map +1 -0
  28. package/dist/index76.cjs +133 -0
  29. package/dist/index76.cjs.map +1 -0
  30. package/dist/index76.js +667 -0
  31. package/dist/index76.js.map +1 -0
  32. package/dist/index77.cjs +669 -0
  33. package/dist/index77.cjs.map +1 -0
  34. package/dist/index77.js +35 -0
  35. package/dist/index77.js.map +1 -0
  36. package/dist/index78.cjs +49 -0
  37. package/dist/index78.cjs.map +1 -0
  38. package/dist/index78.js +231 -0
  39. package/dist/index78.js.map +1 -0
  40. package/dist/index79.cjs +231 -0
  41. package/dist/index79.cjs.map +1 -0
  42. package/dist/index79.js +19 -0
  43. package/dist/index79.js.map +1 -0
  44. package/dist/index80.cjs +25 -0
  45. package/dist/index80.cjs.map +1 -0
  46. package/dist/index80.js +36 -0
  47. package/dist/index80.js.map +1 -0
  48. package/dist/index81.cjs +37 -0
  49. package/dist/index81.cjs.map +1 -0
  50. package/dist/style.css +655 -0
  51. package/package.json +3 -1
@@ -0,0 +1,231 @@
1
+ "use client";
2
+ const require_ai_chat_dock_module = require("./index78.cjs");
3
+ let react = require("react");
4
+ let react_jsx_runtime = require("react/jsx-runtime");
5
+ //#region src/components/ai-chat/AIChatDock.tsx
6
+ /**
7
+ * Shared chat navigation chrome. Children remain mounted while closed to retain
8
+ * the consumer's active AI SDK conversation, pending approvals and attachments.
9
+ * The dock never creates a second chat runtime or reads application messages.
10
+ * Desktop is deliberately non-modal: Tab can move back into the page.
11
+ * On mobile the full-screen modal sheet traps sequential keyboard focus.
12
+ */
13
+ function AIChatDock({ title, description, launcherLabel, showLauncher = true, panelId: controlledPanelId, externalLauncherId, children, open, defaultOpen = false, onOpenChange, expanded, defaultExpanded = false, onExpandedChange, className }) {
14
+ const autoId = (0, react.useId)();
15
+ const panelId = controlledPanelId ?? `uzi-ai-dock-${autoId}`;
16
+ const [internalOpen, setInternalOpen] = (0, react.useState)(defaultOpen);
17
+ const [internalExpanded, setInternalExpanded] = (0, react.useState)(defaultExpanded);
18
+ const isOpen = open ?? internalOpen;
19
+ const isExpanded = expanded ?? internalExpanded;
20
+ const [mobile, setMobile] = (0, react.useState)(false);
21
+ const launcherRef = (0, react.useRef)(null);
22
+ const panelRef = (0, react.useRef)(null);
23
+ const openerRef = (0, react.useRef)(null);
24
+ const wasOpen = (0, react.useRef)(false);
25
+ const changeOpen = (next) => {
26
+ if (open === void 0) setInternalOpen(next);
27
+ onOpenChange?.(next);
28
+ };
29
+ const changeExpanded = (next) => {
30
+ if (expanded === void 0) setInternalExpanded(next);
31
+ onExpandedChange?.(next);
32
+ if (next && !isOpen) changeOpen(true);
33
+ };
34
+ (0, react.useEffect)(() => {
35
+ if (typeof window.matchMedia !== "function") return;
36
+ const media = window.matchMedia("(max-width: 640px)");
37
+ const update = () => setMobile(media.matches);
38
+ update();
39
+ media.addEventListener("change", update);
40
+ return () => media.removeEventListener("change", update);
41
+ }, []);
42
+ (0, react.useEffect)(() => {
43
+ if (isOpen && !wasOpen.current) {
44
+ openerRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
45
+ panelRef.current?.focus();
46
+ } else if (!isOpen && wasOpen.current) {
47
+ const previous = openerRef.current;
48
+ if (previous?.isConnected && previous !== panelRef.current) previous.focus();
49
+ else if (externalLauncherId) document.getElementById(externalLauncherId)?.focus();
50
+ else launcherRef.current?.focus();
51
+ }
52
+ wasOpen.current = isOpen;
53
+ }, [isOpen, externalLauncherId]);
54
+ (0, react.useEffect)(() => {
55
+ if (!isOpen || !mobile) return;
56
+ const previous = document.body.style.overflow;
57
+ document.body.style.overflow = "hidden";
58
+ return () => {
59
+ document.body.style.overflow = previous;
60
+ };
61
+ }, [isOpen, mobile]);
62
+ (0, react.useEffect)(() => {
63
+ if (!isOpen) return;
64
+ const keydown = (event) => {
65
+ if (event.key === "Escape") {
66
+ event.preventDefault();
67
+ changeOpen(false);
68
+ return;
69
+ }
70
+ if (event.key !== "Tab" || !mobile) return;
71
+ const focusable = Array.from(panelRef.current?.querySelectorAll("a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])") ?? []).filter((item) => item.tabIndex >= 0 && item.getClientRects().length > 0);
72
+ if (!focusable.length) {
73
+ event.preventDefault();
74
+ panelRef.current?.focus();
75
+ return;
76
+ }
77
+ const first = focusable[0], last = focusable[focusable.length - 1];
78
+ if (event.shiftKey && (document.activeElement === first || !panelRef.current?.contains(document.activeElement))) {
79
+ event.preventDefault();
80
+ last?.focus();
81
+ } else if (!event.shiftKey && (document.activeElement === last || !panelRef.current?.contains(document.activeElement))) {
82
+ event.preventDefault();
83
+ first?.focus();
84
+ }
85
+ };
86
+ document.addEventListener("keydown", keydown);
87
+ return () => document.removeEventListener("keydown", keydown);
88
+ }, [
89
+ isOpen,
90
+ mobile,
91
+ onOpenChange,
92
+ open
93
+ ]);
94
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
95
+ className: [require_ai_chat_dock_module.default.dock, className].filter(Boolean).join(" "),
96
+ children: [
97
+ showLauncher && !isOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
98
+ ref: launcherRef,
99
+ type: "button",
100
+ className: require_ai_chat_dock_module.default.launcher,
101
+ "aria-controls": panelId,
102
+ "aria-expanded": false,
103
+ "aria-label": launcherLabel ?? `Open ${title}`,
104
+ onClick: () => changeOpen(true),
105
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
106
+ "aria-hidden": "true",
107
+ width: "23",
108
+ height: "23",
109
+ viewBox: "0 0 24 24",
110
+ fill: "none",
111
+ stroke: "currentColor",
112
+ strokeWidth: "1.8",
113
+ strokeLinecap: "round",
114
+ strokeLinejoin: "round",
115
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M21 11.5a8.5 8.5 0 0 1-8.5 8.5 9.1 9.1 0 0 1-4-.9L3 21l1.9-5.5a9.1 9.1 0 0 1-.9-4 8.5 8.5 0 0 1 8.5-8.5h.5A8.5 8.5 0 0 1 21 11.5Z" })
116
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
117
+ className: require_ai_chat_dock_module.default.launcherText,
118
+ children: title
119
+ })]
120
+ }),
121
+ isOpen && mobile && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
122
+ className: require_ai_chat_dock_module.default.backdrop,
123
+ "aria-hidden": "true",
124
+ onClick: () => changeOpen(false)
125
+ }),
126
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
127
+ ref: panelRef,
128
+ id: panelId,
129
+ role: "dialog",
130
+ "aria-modal": mobile && isOpen,
131
+ "aria-label": title,
132
+ tabIndex: -1,
133
+ className: require_ai_chat_dock_module.default.panel,
134
+ "data-expanded": isExpanded,
135
+ hidden: !isOpen,
136
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
137
+ className: require_ai_chat_dock_module.default.header,
138
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
139
+ className: require_ai_chat_dock_module.default.identity,
140
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
141
+ className: require_ai_chat_dock_module.default.avatar,
142
+ "aria-hidden": "true",
143
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
144
+ width: "18",
145
+ height: "18",
146
+ viewBox: "0 0 24 24",
147
+ fill: "none",
148
+ stroke: "currentColor",
149
+ strokeWidth: "1.8",
150
+ strokeLinecap: "round",
151
+ strokeLinejoin: "round",
152
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
153
+ x: "4",
154
+ y: "6",
155
+ width: "16",
156
+ height: "14",
157
+ rx: "4"
158
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M12 3v3M9 13h.01M15 13h.01M9 17h6" })]
159
+ })
160
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
161
+ className: require_ai_chat_dock_module.default.titles,
162
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
163
+ className: require_ai_chat_dock_module.default.title,
164
+ children: title
165
+ }), description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
166
+ className: require_ai_chat_dock_module.default.description,
167
+ children: description
168
+ })]
169
+ })]
170
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
171
+ className: require_ai_chat_dock_module.default.actions,
172
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
173
+ type: "button",
174
+ className: require_ai_chat_dock_module.default.iconButton,
175
+ "aria-label": isExpanded ? `Collapse ${title}` : `Expand ${title}`,
176
+ title: isExpanded ? "Collapse" : "Expand",
177
+ onClick: () => changeExpanded(!isExpanded),
178
+ children: isExpanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
179
+ width: "17",
180
+ height: "17",
181
+ viewBox: "0 0 24 24",
182
+ fill: "none",
183
+ stroke: "currentColor",
184
+ strokeWidth: "2",
185
+ strokeLinecap: "round",
186
+ strokeLinejoin: "round",
187
+ "aria-hidden": "true",
188
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M9 3v6H3M15 21v-6h6M3 9l6-6M21 15l-6 6" })
189
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
190
+ width: "17",
191
+ height: "17",
192
+ viewBox: "0 0 24 24",
193
+ fill: "none",
194
+ stroke: "currentColor",
195
+ strokeWidth: "2",
196
+ strokeLinecap: "round",
197
+ strokeLinejoin: "round",
198
+ "aria-hidden": "true",
199
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 3H3v5M16 21h5v-5M3 3l7 7M21 21l-7-7" })
200
+ })
201
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
202
+ type: "button",
203
+ className: require_ai_chat_dock_module.default.iconButton,
204
+ "aria-label": `Close ${title}`,
205
+ title: "Close",
206
+ onClick: () => changeOpen(false),
207
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
208
+ width: "18",
209
+ height: "18",
210
+ viewBox: "0 0 24 24",
211
+ fill: "none",
212
+ stroke: "currentColor",
213
+ strokeWidth: "2",
214
+ strokeLinecap: "round",
215
+ "aria-hidden": "true",
216
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M18 6 6 18M6 6l12 12" })
217
+ })
218
+ })]
219
+ })]
220
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
221
+ className: require_ai_chat_dock_module.default.content,
222
+ children
223
+ })]
224
+ })
225
+ ]
226
+ });
227
+ }
228
+ //#endregion
229
+ exports.AIChatDock = AIChatDock;
230
+
231
+ //# sourceMappingURL=index79.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index79.cjs","names":[],"sources":["../src/components/ai-chat/AIChatDock.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useId, useRef, useState, type ReactNode } from 'react';\n\nimport styles from './ai-chat-dock.module.css';\n\nexport interface AIChatDockProps {\n /** Visible assistant name, e.g. \"Betty\" or \"Ask Tultr\". */\n readonly title: string;\n readonly description?: string;\n /** Accessible name for the floating action button. Defaults to \"Open {title}\". */\n readonly launcherLabel?: string;\n /** Turn off the built-in FAB when a parent FloatingActionStack owns the launcher. */\n readonly showLauncher?: boolean;\n /** Optional stable panel ID for an external button's aria-controls. */\n readonly panelId?: string;\n /** ID of the external launch button to restore keyboard focus after close. */\n readonly externalLauncherId?: string;\n readonly children: ReactNode;\n /** Controlled visibility; when omitted, the dock manages its own state. */\n readonly open?: boolean;\n readonly defaultOpen?: boolean;\n readonly onOpenChange?: (open: boolean) => void;\n /** Controlled expansion; apps may synchronize this with a dedicated route. */\n readonly expanded?: boolean;\n readonly defaultExpanded?: boolean;\n readonly onExpandedChange?: (expanded: boolean) => void;\n readonly className?: string;\n}\n\n/**\n * Shared chat navigation chrome. Children remain mounted while closed to retain\n * the consumer's active AI SDK conversation, pending approvals and attachments.\n * The dock never creates a second chat runtime or reads application messages.\n * Desktop is deliberately non-modal: Tab can move back into the page.\n * On mobile the full-screen modal sheet traps sequential keyboard focus.\n */\nexport function AIChatDock({\n title,\n description,\n launcherLabel,\n showLauncher = true,\n panelId: controlledPanelId,\n externalLauncherId,\n children,\n open,\n defaultOpen = false,\n onOpenChange,\n expanded,\n defaultExpanded = false,\n onExpandedChange,\n className,\n}: AIChatDockProps) {\n const autoId = useId();\n const panelId = controlledPanelId ?? `uzi-ai-dock-${autoId}`;\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);\n const isOpen = open ?? internalOpen;\n const isExpanded = expanded ?? internalExpanded;\n const [mobile, setMobile] = useState(false);\n const launcherRef = useRef<HTMLButtonElement>(null);\n const panelRef = useRef<HTMLElement>(null);\n const openerRef = useRef<HTMLElement | null>(null);\n const wasOpen = useRef(false);\n\n const changeOpen = (next: boolean) => {\n if (open === undefined) setInternalOpen(next);\n onOpenChange?.(next);\n };\n\n const changeExpanded = (next: boolean) => {\n if (expanded === undefined) setInternalExpanded(next);\n onExpandedChange?.(next);\n if (next && !isOpen) changeOpen(true);\n };\n\n useEffect(() => {\n if (typeof window.matchMedia !== 'function') return;\n const media = window.matchMedia('(max-width: 640px)');\n const update = () => setMobile(media.matches);\n update();\n media.addEventListener('change', update);\n return () => media.removeEventListener('change', update);\n }, []);\n\n useEffect(() => {\n if (isOpen && !wasOpen.current) {\n openerRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n panelRef.current?.focus();\n } else if (!isOpen && wasOpen.current) {\n const previous = openerRef.current;\n if (previous?.isConnected && previous !== panelRef.current) previous.focus();\n else if (externalLauncherId) document.getElementById(externalLauncherId)?.focus();\n else launcherRef.current?.focus();\n }\n wasOpen.current = isOpen;\n }, [isOpen, externalLauncherId]);\n\n useEffect(() => {\n if (!isOpen || !mobile) return;\n const previous = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n return () => { document.body.style.overflow = previous; };\n }, [isOpen, mobile]);\n\n useEffect(() => {\n if (!isOpen) return;\n const keydown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n changeOpen(false);\n return;\n }\n // On desktop the panel is non-modal; only the mobile sheet traps focus.\n if (event.key !== 'Tab' || !mobile) return;\n const focusable = Array.from(panelRef.current?.querySelectorAll<HTMLElement>(\n 'a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n ) ?? []).filter((item) => item.tabIndex >= 0 && item.getClientRects().length > 0);\n if (!focusable.length) { event.preventDefault(); panelRef.current?.focus(); return; }\n const first = focusable[0], last = focusable[focusable.length - 1];\n if (event.shiftKey && (document.activeElement === first || !panelRef.current?.contains(document.activeElement))) {\n event.preventDefault();\n last?.focus();\n } else if (!event.shiftKey && (document.activeElement === last || !panelRef.current?.contains(document.activeElement))) {\n event.preventDefault();\n first?.focus();\n }\n };\n document.addEventListener('keydown', keydown);\n return () => document.removeEventListener('keydown', keydown);\n }, [isOpen, mobile, onOpenChange, open]);\n\n return (\n <div className={[styles.dock, className].filter(Boolean).join(' ')}>\n {showLauncher && !isOpen && (\n <button\n ref={launcherRef}\n type=\"button\"\n className={styles.launcher}\n aria-controls={panelId}\n aria-expanded={false}\n aria-label={launcherLabel ?? `Open ${title}`}\n onClick={() => changeOpen(true)}\n >\n <svg aria-hidden=\"true\" width=\"23\" height=\"23\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 11.5a8.5 8.5 0 0 1-8.5 8.5 9.1 9.1 0 0 1-4-.9L3 21l1.9-5.5a9.1 9.1 0 0 1-.9-4 8.5 8.5 0 0 1 8.5-8.5h.5A8.5 8.5 0 0 1 21 11.5Z\" />\n </svg>\n <span className={styles.launcherText}>{title}</span>\n </button>\n )}\n {isOpen && mobile && <div className={styles.backdrop} aria-hidden=\"true\" onClick={() => changeOpen(false)} />}\n <section\n ref={panelRef}\n id={panelId}\n role=\"dialog\"\n aria-modal={mobile && isOpen}\n aria-label={title}\n tabIndex={-1}\n className={styles.panel}\n data-expanded={isExpanded}\n hidden={!isOpen}\n >\n <header className={styles.header}>\n <div className={styles.identity}>\n <div className={styles.avatar} aria-hidden=\"true\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"4\" y=\"6\" width=\"16\" height=\"14\" rx=\"4\" />\n <path d=\"M12 3v3M9 13h.01M15 13h.01M9 17h6\" />\n </svg>\n </div>\n <div className={styles.titles}>\n <strong className={styles.title}>{title}</strong>\n {description && <span className={styles.description}>{description}</span>}\n </div>\n </div>\n <div className={styles.actions}>\n <button type=\"button\" className={styles.iconButton}\n aria-label={isExpanded ? `Collapse ${title}` : `Expand ${title}`}\n title={isExpanded ? 'Collapse' : 'Expand'}\n onClick={() => changeExpanded(!isExpanded)}>\n {isExpanded ? (\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"\n strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\"><path d=\"M9 3v6H3M15 21v-6h6M3 9l6-6M21 15l-6 6\" /></svg>\n ) : (\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"\n strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\"><path d=\"M8 3H3v5M16 21h5v-5M3 3l7 7M21 21l-7-7\" /></svg>\n )}\n </button>\n <button type=\"button\" className={styles.iconButton}\n aria-label={`Close ${title}`} title=\"Close\"\n onClick={() => changeOpen(false)}>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden=\"true\"><path d=\"M18 6 6 18M6 6l12 12\" /></svg>\n </button>\n </div>\n </header>\n <div className={styles.content}>{children}</div>\n </section>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ //#region src/components/floating-action-stack/floating-action-stack.module.css
2
+ var stack = "uzi-floating-action-stack-module__stack__5UH0U";
3
+ var action = "uzi-floating-action-stack-module__action__07atd";
4
+ var primary = "uzi-floating-action-stack-module__primary__xoV0q";
5
+ var secondary = "uzi-floating-action-stack-module__secondary__g5tf3";
6
+ var icon = "uzi-floating-action-stack-module__icon__XZoM5";
7
+ var label = "uzi-floating-action-stack-module__label__Rb4A0";
8
+ var floating_action_stack_module_default = {
9
+ stack,
10
+ action,
11
+ primary,
12
+ secondary,
13
+ icon,
14
+ label
15
+ };
16
+ //#endregion
17
+ export { action, floating_action_stack_module_default as default, icon, label, primary, secondary, stack };
18
+
19
+ //# sourceMappingURL=index79.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index79.js","names":[],"sources":["../src/components/floating-action-stack/floating-action-stack.module.css"],"sourcesContent":["/* One fixed positioning and safe-area system for any number of actions. */\n.stack {\n position: fixed;\n z-index: 60;\n right: max(1.25rem, env(safe-area-inset-right));\n bottom: calc(1.25rem + env(safe-area-inset-bottom));\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 0.625rem;\n pointer-events: none;\n}\n.stack > * { pointer-events: auto; }\n\n.action {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.625rem;\n min-height: 3.5rem;\n padding: 0.7rem 1.1rem;\n border: 1px solid var(--border);\n border-radius: 999px;\n box-shadow: 0 6px 24px color-mix(in srgb, var(--foreground) 20%, transparent);\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n}\n.primary { color: var(--primary-foreground); background: var(--primary); }\n.secondary { color: var(--foreground); background: var(--background); }\n.action:hover { filter: brightness(0.95); }\n.action:focus-visible { outline: 2px solid var(--ring, var(--primary)); outline-offset: 2px; }\n.action:disabled { opacity: 0.5; cursor: not-allowed; }\n.icon { display: flex; flex: none; align-items: center; justify-content: center; }\n.label { white-space: nowrap; }\n\n@media (max-width: 640px) {\n .stack {\n right: max(1rem, env(safe-area-inset-right));\n bottom: calc(1rem + env(safe-area-inset-bottom));\n }\n .action { width: 3.5rem; height: 3.5rem; min-width: 3.5rem; padding: 0; }\n .label { display: none; }\n}\n"],"mappings":""}
@@ -0,0 +1,25 @@
1
+ //#region src/components/floating-action-stack/floating-action-stack.module.css
2
+ var stack = "uzi-floating-action-stack-module__stack__5UH0U";
3
+ var action = "uzi-floating-action-stack-module__action__07atd";
4
+ var primary = "uzi-floating-action-stack-module__primary__xoV0q";
5
+ var secondary = "uzi-floating-action-stack-module__secondary__g5tf3";
6
+ var icon = "uzi-floating-action-stack-module__icon__XZoM5";
7
+ var label = "uzi-floating-action-stack-module__label__Rb4A0";
8
+ var floating_action_stack_module_default = {
9
+ stack,
10
+ action,
11
+ primary,
12
+ secondary,
13
+ icon,
14
+ label
15
+ };
16
+ //#endregion
17
+ exports.action = action;
18
+ exports.default = floating_action_stack_module_default;
19
+ exports.icon = icon;
20
+ exports.label = label;
21
+ exports.primary = primary;
22
+ exports.secondary = secondary;
23
+ exports.stack = stack;
24
+
25
+ //# sourceMappingURL=index80.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index80.cjs","names":[],"sources":["../src/components/floating-action-stack/floating-action-stack.module.css"],"sourcesContent":["/* One fixed positioning and safe-area system for any number of actions. */\n.stack {\n position: fixed;\n z-index: 60;\n right: max(1.25rem, env(safe-area-inset-right));\n bottom: calc(1.25rem + env(safe-area-inset-bottom));\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 0.625rem;\n pointer-events: none;\n}\n.stack > * { pointer-events: auto; }\n\n.action {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.625rem;\n min-height: 3.5rem;\n padding: 0.7rem 1.1rem;\n border: 1px solid var(--border);\n border-radius: 999px;\n box-shadow: 0 6px 24px color-mix(in srgb, var(--foreground) 20%, transparent);\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n}\n.primary { color: var(--primary-foreground); background: var(--primary); }\n.secondary { color: var(--foreground); background: var(--background); }\n.action:hover { filter: brightness(0.95); }\n.action:focus-visible { outline: 2px solid var(--ring, var(--primary)); outline-offset: 2px; }\n.action:disabled { opacity: 0.5; cursor: not-allowed; }\n.icon { display: flex; flex: none; align-items: center; justify-content: center; }\n.label { white-space: nowrap; }\n\n@media (max-width: 640px) {\n .stack {\n right: max(1rem, env(safe-area-inset-right));\n bottom: calc(1rem + env(safe-area-inset-bottom));\n }\n .action { width: 3.5rem; height: 3.5rem; min-width: 3.5rem; padding: 0; }\n .label { display: none; }\n}\n"],"mappings":""}
@@ -0,0 +1,36 @@
1
+ "use client";
2
+ import floating_action_stack_module_default from "./index79.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ //#region src/components/floating-action-stack/FloatingActionStack.tsx
5
+ function FloatingActionStack({ children, className, label = "Quick actions" }) {
6
+ return /* @__PURE__ */ jsx("nav", {
7
+ "aria-label": label,
8
+ className: [floating_action_stack_module_default.stack, className].filter(Boolean).join(" "),
9
+ children
10
+ });
11
+ }
12
+ /** A directly accessible action, not a speed-dial menu or nested overlay. */
13
+ function FloatingActionButton({ label, icon, children, variant = "primary", className, ...buttonProps }) {
14
+ return /* @__PURE__ */ jsxs("button", {
15
+ ...buttonProps,
16
+ type: "button",
17
+ "aria-label": label,
18
+ className: [
19
+ floating_action_stack_module_default.action,
20
+ variant === "secondary" ? floating_action_stack_module_default.secondary : floating_action_stack_module_default.primary,
21
+ className
22
+ ].filter(Boolean).join(" "),
23
+ children: [/* @__PURE__ */ jsx("span", {
24
+ className: floating_action_stack_module_default.icon,
25
+ "aria-hidden": "true",
26
+ children: icon
27
+ }), /* @__PURE__ */ jsx("span", {
28
+ className: floating_action_stack_module_default.label,
29
+ children: children ?? label
30
+ })]
31
+ });
32
+ }
33
+ //#endregion
34
+ export { FloatingActionButton, FloatingActionStack };
35
+
36
+ //# sourceMappingURL=index80.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index80.js","names":[],"sources":["../src/components/floating-action-stack/FloatingActionStack.tsx"],"sourcesContent":["'use client';\n\nimport type { ButtonHTMLAttributes, ReactNode } from 'react';\n\nimport styles from './floating-action-stack.module.css';\n\n/** A single screen-edge action rail shared by unrelated application features. */\nexport interface FloatingActionStackProps {\n readonly children: ReactNode;\n readonly className?: string;\n readonly label?: string;\n}\n\nexport function FloatingActionStack({ children, className, label = 'Quick actions' }: FloatingActionStackProps) {\n return (\n <nav\n aria-label={label}\n className={[styles.stack, className].filter(Boolean).join(' ')}\n >\n {children}\n </nav>\n );\n}\n\nexport interface FloatingActionButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'type'> {\n /** Stable accessible name, including when the mobile label is hidden. */\n readonly label: string;\n readonly icon: ReactNode;\n readonly children?: ReactNode;\n /** Use secondary styling for contextual actions above the primary launcher. */\n readonly variant?: 'primary' | 'secondary';\n}\n\n/** A directly accessible action, not a speed-dial menu or nested overlay. */\nexport function FloatingActionButton({\n label,\n icon,\n children,\n variant = 'primary',\n className,\n ...buttonProps\n}: FloatingActionButtonProps) {\n return (\n <button\n {...buttonProps}\n type=\"button\"\n aria-label={label}\n className={[styles.action, variant === 'secondary' ? styles.secondary : styles.primary, className]\n .filter(Boolean).join(' ')}\n >\n <span className={styles.icon} aria-hidden=\"true\">{icon}</span>\n <span className={styles.label}>{children ?? label}</span>\n </button>\n );\n}\n"],"mappings":";;;;AAaA,SAAgB,oBAAoB,EAAE,UAAU,WAAW,QAAQ,mBAA6C;CAC9G,OACE,oBAAC,OAAD;EACE,cAAY;EACZ,WAAW,CAAC,qCAAO,OAAO,SAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;EAE5D;CACE,CAAA;AAET;;AAYA,SAAgB,qBAAqB,EACnC,OACA,MACA,UACA,UAAU,WACV,WACA,GAAG,eACyB;CAC5B,OACE,qBAAC,UAAD;EACE,GAAI;EACJ,MAAK;EACL,cAAY;EACZ,WAAW;GAAC,qCAAO;GAAQ,YAAY,cAAc,qCAAO,YAAY,qCAAO;GAAS;EAAS,CAAC,CAC/F,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;YAL7B,CAOE,oBAAC,QAAD;GAAM,WAAW,qCAAO;GAAM,eAAY;aAAQ;EAAW,CAAA,GAC7D,oBAAC,QAAD;GAAM,WAAW,qCAAO;aAAQ,YAAY;EAAY,CAAA,CAClD;;AAEZ"}
@@ -0,0 +1,37 @@
1
+ "use client";
2
+ const require_floating_action_stack_module = require("./index80.cjs");
3
+ let react_jsx_runtime = require("react/jsx-runtime");
4
+ //#region src/components/floating-action-stack/FloatingActionStack.tsx
5
+ function FloatingActionStack({ children, className, label = "Quick actions" }) {
6
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("nav", {
7
+ "aria-label": label,
8
+ className: [require_floating_action_stack_module.default.stack, className].filter(Boolean).join(" "),
9
+ children
10
+ });
11
+ }
12
+ /** A directly accessible action, not a speed-dial menu or nested overlay. */
13
+ function FloatingActionButton({ label, icon, children, variant = "primary", className, ...buttonProps }) {
14
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
15
+ ...buttonProps,
16
+ type: "button",
17
+ "aria-label": label,
18
+ className: [
19
+ require_floating_action_stack_module.default.action,
20
+ variant === "secondary" ? require_floating_action_stack_module.default.secondary : require_floating_action_stack_module.default.primary,
21
+ className
22
+ ].filter(Boolean).join(" "),
23
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
24
+ className: require_floating_action_stack_module.default.icon,
25
+ "aria-hidden": "true",
26
+ children: icon
27
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
28
+ className: require_floating_action_stack_module.default.label,
29
+ children: children ?? label
30
+ })]
31
+ });
32
+ }
33
+ //#endregion
34
+ exports.FloatingActionButton = FloatingActionButton;
35
+ exports.FloatingActionStack = FloatingActionStack;
36
+
37
+ //# sourceMappingURL=index81.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index81.cjs","names":[],"sources":["../src/components/floating-action-stack/FloatingActionStack.tsx"],"sourcesContent":["'use client';\n\nimport type { ButtonHTMLAttributes, ReactNode } from 'react';\n\nimport styles from './floating-action-stack.module.css';\n\n/** A single screen-edge action rail shared by unrelated application features. */\nexport interface FloatingActionStackProps {\n readonly children: ReactNode;\n readonly className?: string;\n readonly label?: string;\n}\n\nexport function FloatingActionStack({ children, className, label = 'Quick actions' }: FloatingActionStackProps) {\n return (\n <nav\n aria-label={label}\n className={[styles.stack, className].filter(Boolean).join(' ')}\n >\n {children}\n </nav>\n );\n}\n\nexport interface FloatingActionButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'type'> {\n /** Stable accessible name, including when the mobile label is hidden. */\n readonly label: string;\n readonly icon: ReactNode;\n readonly children?: ReactNode;\n /** Use secondary styling for contextual actions above the primary launcher. */\n readonly variant?: 'primary' | 'secondary';\n}\n\n/** A directly accessible action, not a speed-dial menu or nested overlay. */\nexport function FloatingActionButton({\n label,\n icon,\n children,\n variant = 'primary',\n className,\n ...buttonProps\n}: FloatingActionButtonProps) {\n return (\n <button\n {...buttonProps}\n type=\"button\"\n aria-label={label}\n className={[styles.action, variant === 'secondary' ? styles.secondary : styles.primary, className]\n .filter(Boolean).join(' ')}\n >\n <span className={styles.icon} aria-hidden=\"true\">{icon}</span>\n <span className={styles.label}>{children ?? label}</span>\n </button>\n );\n}\n"],"mappings":";;;;AAaA,SAAgB,oBAAoB,EAAE,UAAU,WAAW,QAAQ,mBAA6C;CAC9G,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EACE,cAAY;EACZ,WAAW,CAAC,qCAAA,QAAO,OAAO,SAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;EAE5D;CACE,CAAA;AAET;;AAYA,SAAgB,qBAAqB,EACnC,OACA,MACA,UACA,UAAU,WACV,WACA,GAAG,eACyB;CAC5B,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;EACE,GAAI;EACJ,MAAK;EACL,cAAY;EACZ,WAAW;GAAC,qCAAA,QAAO;GAAQ,YAAY,cAAc,qCAAA,QAAO,YAAY,qCAAA,QAAO;GAAS;EAAS,CAAC,CAC/F,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;YAL7B,CAOE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;GAAM,WAAW,qCAAA,QAAO;GAAM,eAAY;aAAQ;EAAW,CAAA,GAC7D,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;GAAM,WAAW,qCAAA,QAAO;aAAQ,YAAY;EAAY,CAAA,CAClD;;AAEZ"}