@a11y-core/react 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +252 -0
  2. package/dist/chunk-3WBTHTVK.js +41 -0
  3. package/dist/chunk-3WBTHTVK.js.map +1 -0
  4. package/dist/chunk-47MFBHV6.js +85 -0
  5. package/dist/chunk-47MFBHV6.js.map +1 -0
  6. package/dist/chunk-7A3IDIUB.cjs +89 -0
  7. package/dist/chunk-7A3IDIUB.cjs.map +1 -0
  8. package/dist/chunk-AZFZWGI6.cjs +383 -0
  9. package/dist/chunk-AZFZWGI6.cjs.map +1 -0
  10. package/dist/chunk-CTW5D77X.cjs +220 -0
  11. package/dist/chunk-CTW5D77X.cjs.map +1 -0
  12. package/dist/chunk-EY73HQNR.js +380 -0
  13. package/dist/chunk-EY73HQNR.js.map +1 -0
  14. package/dist/chunk-FJABCNFE.js +215 -0
  15. package/dist/chunk-FJABCNFE.js.map +1 -0
  16. package/dist/chunk-FTZ5KCOO.js +326 -0
  17. package/dist/chunk-FTZ5KCOO.js.map +1 -0
  18. package/dist/chunk-GS3H4T2O.cjs +106 -0
  19. package/dist/chunk-GS3H4T2O.cjs.map +1 -0
  20. package/dist/chunk-N6L4GLFC.cjs +45 -0
  21. package/dist/chunk-N6L4GLFC.cjs.map +1 -0
  22. package/dist/chunk-N774QCHE.js +234 -0
  23. package/dist/chunk-N774QCHE.js.map +1 -0
  24. package/dist/chunk-OSHIYZCZ.cjs +386 -0
  25. package/dist/chunk-OSHIYZCZ.cjs.map +1 -0
  26. package/dist/chunk-SRJSGDIA.js +373 -0
  27. package/dist/chunk-SRJSGDIA.js.map +1 -0
  28. package/dist/chunk-THB5U7YC.cjs +338 -0
  29. package/dist/chunk-THB5U7YC.cjs.map +1 -0
  30. package/dist/chunk-U6DUSMEA.js +99 -0
  31. package/dist/chunk-U6DUSMEA.js.map +1 -0
  32. package/dist/chunk-WDCYEMBO.cjs +245 -0
  33. package/dist/chunk-WDCYEMBO.cjs.map +1 -0
  34. package/dist/components/combobox/index.cjs +31 -0
  35. package/dist/components/combobox/index.cjs.map +1 -0
  36. package/dist/components/combobox/index.d.cts +55 -0
  37. package/dist/components/combobox/index.d.ts +55 -0
  38. package/dist/components/combobox/index.js +6 -0
  39. package/dist/components/combobox/index.js.map +1 -0
  40. package/dist/components/dialog/index.cjs +46 -0
  41. package/dist/components/dialog/index.cjs.map +1 -0
  42. package/dist/components/dialog/index.d.cts +84 -0
  43. package/dist/components/dialog/index.d.ts +84 -0
  44. package/dist/components/dialog/index.js +5 -0
  45. package/dist/components/dialog/index.js.map +1 -0
  46. package/dist/components/menu/index.cjs +46 -0
  47. package/dist/components/menu/index.cjs.map +1 -0
  48. package/dist/components/menu/index.d.cts +80 -0
  49. package/dist/components/menu/index.d.ts +80 -0
  50. package/dist/components/menu/index.js +5 -0
  51. package/dist/components/menu/index.js.map +1 -0
  52. package/dist/components/tabs/index.cjs +35 -0
  53. package/dist/components/tabs/index.cjs.map +1 -0
  54. package/dist/components/tabs/index.d.cts +65 -0
  55. package/dist/components/tabs/index.d.ts +65 -0
  56. package/dist/components/tabs/index.js +6 -0
  57. package/dist/components/tabs/index.js.map +1 -0
  58. package/dist/components/toast/index.cjs +24 -0
  59. package/dist/components/toast/index.cjs.map +1 -0
  60. package/dist/components/toast/index.d.cts +49 -0
  61. package/dist/components/toast/index.d.ts +49 -0
  62. package/dist/components/toast/index.js +3 -0
  63. package/dist/components/toast/index.js.map +1 -0
  64. package/dist/index.cjs +698 -0
  65. package/dist/index.cjs.map +1 -0
  66. package/dist/index.d.cts +402 -0
  67. package/dist/index.d.ts +402 -0
  68. package/dist/index.js +426 -0
  69. package/dist/index.js.map +1 -0
  70. package/package.json +89 -0
@@ -0,0 +1,383 @@
1
+ 'use strict';
2
+
3
+ var chunkGS3H4T2O_cjs = require('./chunk-GS3H4T2O.cjs');
4
+ var chunkN6L4GLFC_cjs = require('./chunk-N6L4GLFC.cjs');
5
+ var react = require('react');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+
8
+ var ActionMenuContext = react.createContext(null);
9
+ function useActionMenuContext() {
10
+ const context = react.useContext(ActionMenuContext);
11
+ if (!context) {
12
+ throw new Error(
13
+ "ActionMenu compound components must be used within an ActionMenu component"
14
+ );
15
+ }
16
+ return context;
17
+ }
18
+ var ActionMenuProvider = ActionMenuContext.Provider;
19
+ function ActionMenu({
20
+ defaultOpen = false,
21
+ open: controlledOpen,
22
+ onOpenChange,
23
+ children,
24
+ unstyled = false
25
+ }) {
26
+ const [uncontrolledOpen, setUncontrolledOpen] = react.useState(defaultOpen);
27
+ const isOpen = controlledOpen ?? uncontrolledOpen;
28
+ const [highlightedIndex, setHighlightedIndex] = react.useState(-1);
29
+ const itemsRef = react.useRef([]);
30
+ const onSelectRef = react.useRef(null);
31
+ const menuId = chunkN6L4GLFC_cjs.useId("action-menu");
32
+ const triggerId = chunkN6L4GLFC_cjs.useId("action-menu-trigger");
33
+ const setOpen = react.useCallback(
34
+ (value) => {
35
+ if (controlledOpen === void 0) {
36
+ setUncontrolledOpen(value);
37
+ }
38
+ onOpenChange?.(value);
39
+ if (!value) {
40
+ setHighlightedIndex(-1);
41
+ }
42
+ },
43
+ [controlledOpen, onOpenChange]
44
+ );
45
+ const open = react.useCallback(() => setOpen(true), [setOpen]);
46
+ const close = react.useCallback(() => setOpen(false), [setOpen]);
47
+ const toggle = react.useCallback(() => setOpen(!isOpen), [setOpen, isOpen]);
48
+ const registerItem = react.useCallback((id) => {
49
+ const index = itemsRef.current.length;
50
+ itemsRef.current.push(id);
51
+ return index;
52
+ }, []);
53
+ const unregisterItem = react.useCallback((id) => {
54
+ const index = itemsRef.current.indexOf(id);
55
+ if (index > -1) {
56
+ itemsRef.current.splice(index, 1);
57
+ }
58
+ }, []);
59
+ const getItemCount = react.useCallback(() => itemsRef.current.length, []);
60
+ const selectItem = react.useCallback(
61
+ (index) => {
62
+ onSelectRef.current?.(index);
63
+ close();
64
+ },
65
+ [close]
66
+ );
67
+ const contextValue = {
68
+ isOpen,
69
+ open,
70
+ close,
71
+ toggle,
72
+ highlightedIndex,
73
+ setHighlightedIndex,
74
+ menuId,
75
+ triggerId,
76
+ registerItem,
77
+ unregisterItem,
78
+ getItemCount,
79
+ selectItem,
80
+ unstyled
81
+ };
82
+ return /* @__PURE__ */ jsxRuntime.jsx(ActionMenuProvider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
83
+ "div",
84
+ {
85
+ style: { position: "relative", display: "inline-block" },
86
+ "data-a11y-core-action-menu": true,
87
+ children
88
+ }
89
+ ) });
90
+ }
91
+ var ActionMenuTrigger = react.forwardRef(function ActionMenuTrigger2({ children, onClick, onKeyDown, ...props }, ref) {
92
+ const {
93
+ isOpen,
94
+ toggle,
95
+ open,
96
+ close,
97
+ triggerId,
98
+ menuId,
99
+ setHighlightedIndex,
100
+ getItemCount
101
+ } = useActionMenuContext();
102
+ const handleClick = (event) => {
103
+ onClick?.(event);
104
+ if (!event.defaultPrevented) {
105
+ toggle();
106
+ }
107
+ };
108
+ const keyboardProps = chunkGS3H4T2O_cjs.useKeyboard(
109
+ {
110
+ ArrowDown: () => {
111
+ if (!isOpen) {
112
+ open();
113
+ }
114
+ setHighlightedIndex(0);
115
+ },
116
+ ArrowUp: () => {
117
+ if (!isOpen) {
118
+ open();
119
+ }
120
+ setHighlightedIndex(getItemCount() - 1);
121
+ },
122
+ Enter: () => toggle(),
123
+ Space: () => toggle(),
124
+ Escape: () => close()
125
+ },
126
+ { preventDefault: true }
127
+ );
128
+ const handleKeyDown = (event) => {
129
+ onKeyDown?.(event);
130
+ if (!event.defaultPrevented) {
131
+ keyboardProps.onKeyDown(event);
132
+ }
133
+ };
134
+ return /* @__PURE__ */ jsxRuntime.jsx(
135
+ "button",
136
+ {
137
+ ref,
138
+ id: triggerId,
139
+ type: "button",
140
+ tabIndex: 0,
141
+ "aria-haspopup": "menu",
142
+ "aria-expanded": isOpen,
143
+ "aria-controls": isOpen ? menuId : void 0,
144
+ onClick: handleClick,
145
+ onKeyDown: handleKeyDown,
146
+ "data-a11y-core-action-menu-trigger": true,
147
+ ...props,
148
+ children
149
+ }
150
+ );
151
+ });
152
+ var ActionMenuContent = react.forwardRef(function ActionMenuContent2({ children, onKeyDown, style, ...props }, ref) {
153
+ const {
154
+ isOpen,
155
+ close,
156
+ menuId,
157
+ triggerId,
158
+ highlightedIndex,
159
+ setHighlightedIndex,
160
+ getItemCount,
161
+ unstyled
162
+ } = useActionMenuContext();
163
+ const menuRef = react.useRef(null);
164
+ const clickHighlightedItem = () => {
165
+ if (highlightedIndex >= 0 && menuRef.current) {
166
+ const items = menuRef.current.querySelectorAll('[role="menuitem"]');
167
+ const item = items[highlightedIndex];
168
+ if (item && item.getAttribute("aria-disabled") !== "true") {
169
+ item.click();
170
+ }
171
+ }
172
+ };
173
+ const keyboardProps = chunkGS3H4T2O_cjs.useKeyboard(
174
+ {
175
+ ArrowDown: () => {
176
+ const count = getItemCount();
177
+ setHighlightedIndex((highlightedIndex + 1) % count);
178
+ },
179
+ ArrowUp: () => {
180
+ const count = getItemCount();
181
+ setHighlightedIndex((highlightedIndex - 1 + count) % count);
182
+ },
183
+ Home: () => setHighlightedIndex(0),
184
+ End: () => setHighlightedIndex(getItemCount() - 1),
185
+ Enter: () => clickHighlightedItem(),
186
+ Space: () => clickHighlightedItem(),
187
+ Escape: () => close(),
188
+ Tab: () => {
189
+ close();
190
+ return false;
191
+ }
192
+ },
193
+ { preventDefault: true }
194
+ );
195
+ const handleKeyDown = (event) => {
196
+ onKeyDown?.(event);
197
+ if (!event.defaultPrevented) {
198
+ keyboardProps.onKeyDown(event);
199
+ }
200
+ };
201
+ react.useEffect(() => {
202
+ if (isOpen && menuRef.current) {
203
+ menuRef.current.focus();
204
+ }
205
+ }, [isOpen]);
206
+ react.useEffect(() => {
207
+ if (!isOpen) return;
208
+ const handleClick = (event) => {
209
+ const target = event.target;
210
+ const menu = menuRef.current;
211
+ const trigger = document.getElementById(triggerId);
212
+ if (menu && !menu.contains(target) && trigger && !trigger.contains(target)) {
213
+ close();
214
+ }
215
+ };
216
+ document.addEventListener("mousedown", handleClick);
217
+ return () => document.removeEventListener("mousedown", handleClick);
218
+ }, [isOpen, close, triggerId]);
219
+ if (!isOpen) {
220
+ return null;
221
+ }
222
+ const contentStructuralStyles = {
223
+ position: "absolute",
224
+ top: "100%",
225
+ left: 0,
226
+ marginTop: "4px",
227
+ zIndex: 1e3
228
+ };
229
+ const contentVisualStyles = unstyled ? {} : {
230
+ minWidth: "160px",
231
+ backgroundColor: "white",
232
+ border: "1px solid #e0e0e0",
233
+ borderRadius: "4px",
234
+ boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
235
+ padding: "4px 0"
236
+ };
237
+ const contentStyles = {
238
+ ...contentStructuralStyles,
239
+ ...contentVisualStyles
240
+ };
241
+ return /* @__PURE__ */ jsxRuntime.jsx(
242
+ "div",
243
+ {
244
+ ref: (node) => {
245
+ menuRef.current = node;
246
+ if (typeof ref === "function") {
247
+ ref(node);
248
+ } else if (ref) {
249
+ ref.current = node;
250
+ }
251
+ },
252
+ id: menuId,
253
+ role: "menu",
254
+ "aria-labelledby": triggerId,
255
+ tabIndex: -1,
256
+ onKeyDown: handleKeyDown,
257
+ style: { ...contentStyles, ...style },
258
+ "data-a11y-core-action-menu-content": true,
259
+ ...props,
260
+ children
261
+ }
262
+ );
263
+ });
264
+ var ActionMenuItem = react.forwardRef(
265
+ function ActionMenuItem2({
266
+ children,
267
+ disabled = false,
268
+ onSelect,
269
+ onClick,
270
+ onMouseEnter,
271
+ style,
272
+ ...props
273
+ }, ref) {
274
+ const {
275
+ registerItem,
276
+ unregisterItem,
277
+ highlightedIndex,
278
+ setHighlightedIndex,
279
+ close,
280
+ unstyled
281
+ } = useActionMenuContext();
282
+ const itemId = chunkN6L4GLFC_cjs.useId("action-menu-item");
283
+ const indexRef = react.useRef(-1);
284
+ react.useEffect(() => {
285
+ if (!disabled) {
286
+ indexRef.current = registerItem(itemId);
287
+ }
288
+ return () => {
289
+ if (!disabled) {
290
+ unregisterItem(itemId);
291
+ }
292
+ };
293
+ }, [itemId, disabled, registerItem, unregisterItem]);
294
+ const isHighlighted = indexRef.current === highlightedIndex;
295
+ const handleClick = (event) => {
296
+ onClick?.(event);
297
+ if (!event.defaultPrevented && !disabled) {
298
+ onSelect?.();
299
+ close();
300
+ }
301
+ };
302
+ const handleMouseEnter = (event) => {
303
+ onMouseEnter?.(event);
304
+ if (!disabled) {
305
+ setHighlightedIndex(indexRef.current);
306
+ }
307
+ };
308
+ const itemBehaviorStyles = {
309
+ cursor: disabled ? "not-allowed" : "pointer",
310
+ opacity: disabled ? 0.5 : 1
311
+ };
312
+ const itemVisualStyles = unstyled ? {} : {
313
+ padding: "8px 16px",
314
+ backgroundColor: isHighlighted ? "#f0f0f0" : "transparent"
315
+ };
316
+ const itemStyles = {
317
+ ...itemBehaviorStyles,
318
+ ...itemVisualStyles
319
+ };
320
+ return /* @__PURE__ */ jsxRuntime.jsx(
321
+ "div",
322
+ {
323
+ ref,
324
+ id: itemId,
325
+ role: "menuitem",
326
+ tabIndex: -1,
327
+ "aria-disabled": disabled,
328
+ "data-highlighted": isHighlighted,
329
+ "data-disabled": disabled,
330
+ onClick: handleClick,
331
+ onMouseEnter: handleMouseEnter,
332
+ style: { ...itemStyles, ...style },
333
+ "data-a11y-core-action-menu-item": true,
334
+ ...props,
335
+ children
336
+ }
337
+ );
338
+ }
339
+ );
340
+ var ActionMenuSeparator = react.forwardRef(function ActionMenuSeparator2(props, ref) {
341
+ return /* @__PURE__ */ jsxRuntime.jsx(
342
+ "div",
343
+ {
344
+ ref,
345
+ role: "separator",
346
+ "data-a11y-core-action-menu-separator": true,
347
+ ...props
348
+ }
349
+ );
350
+ });
351
+ var ActionMenuLabel = react.forwardRef(
352
+ function ActionMenuLabel2({ children, ...props }, ref) {
353
+ return /* @__PURE__ */ jsxRuntime.jsx(
354
+ "div",
355
+ {
356
+ ref,
357
+ role: "presentation",
358
+ "data-a11y-core-action-menu-label": true,
359
+ ...props,
360
+ children
361
+ }
362
+ );
363
+ }
364
+ );
365
+ var ActionMenuCompound = Object.assign(ActionMenu, {
366
+ Trigger: ActionMenuTrigger,
367
+ Content: ActionMenuContent,
368
+ Item: ActionMenuItem,
369
+ Separator: ActionMenuSeparator,
370
+ Label: ActionMenuLabel
371
+ });
372
+
373
+ exports.ActionMenu = ActionMenu;
374
+ exports.ActionMenuCompound = ActionMenuCompound;
375
+ exports.ActionMenuContent = ActionMenuContent;
376
+ exports.ActionMenuItem = ActionMenuItem;
377
+ exports.ActionMenuLabel = ActionMenuLabel;
378
+ exports.ActionMenuProvider = ActionMenuProvider;
379
+ exports.ActionMenuSeparator = ActionMenuSeparator;
380
+ exports.ActionMenuTrigger = ActionMenuTrigger;
381
+ exports.useActionMenuContext = useActionMenuContext;
382
+ //# sourceMappingURL=chunk-AZFZWGI6.cjs.map
383
+ //# sourceMappingURL=chunk-AZFZWGI6.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/menu/menu-context.ts","../src/components/menu/menu.tsx"],"names":["createContext","useContext","useState","useRef","useId","useCallback","jsx","forwardRef","ActionMenuTrigger","useKeyboard","ActionMenuContent","useEffect","ActionMenuItem","ActionMenuSeparator","ActionMenuLabel"],"mappings":"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","file":"chunk-AZFZWGI6.cjs","sourcesContent":["import { createContext, useContext } from 'react';\n\nexport interface ActionMenuContextValue {\n /** Whether the menu is open */\n isOpen: boolean;\n /** Open the menu */\n open: () => void;\n /** Close the menu */\n close: () => void;\n /** Toggle the menu */\n toggle: () => void;\n /** Currently highlighted item index */\n highlightedIndex: number;\n /** Set highlighted item */\n setHighlightedIndex: (index: number) => void;\n /** ID for the menu element */\n menuId: string;\n /** ID for the trigger element */\n triggerId: string;\n /** Register a menu item */\n registerItem: (id: string) => number;\n /** Unregister a menu item */\n unregisterItem: (id: string) => void;\n /** Get item count */\n getItemCount: () => number;\n /** Select an item */\n selectItem: (index: number) => void;\n /** Whether default styles are disabled */\n unstyled: boolean;\n}\n\nconst ActionMenuContext = createContext<ActionMenuContextValue | null>(null);\n\nexport function useActionMenuContext(): ActionMenuContextValue {\n const context = useContext(ActionMenuContext);\n if (!context) {\n throw new Error(\n 'ActionMenu compound components must be used within an ActionMenu component'\n );\n }\n return context;\n}\n\nexport const ActionMenuProvider = ActionMenuContext.Provider;\n","import React, {\n forwardRef,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { useId } from '../../hooks/use-id';\nimport { useKeyboard } from '../../hooks/use-keyboard';\nimport {\n ActionMenuProvider,\n useActionMenuContext,\n type ActionMenuContextValue,\n} from './menu-context';\n\n// ============================================================================\n// ActionMenu Root\n// ============================================================================\n\nexport interface ActionMenuProps {\n /** Whether the menu is initially open */\n defaultOpen?: boolean;\n /** Controlled open state */\n open?: boolean;\n /** Called when open state changes */\n onOpenChange?: (open: boolean) => void;\n /** Menu content */\n children: React.ReactNode;\n /** Remove default styles to allow full customization via className */\n unstyled?: boolean;\n}\n\nexport function ActionMenu({\n defaultOpen = false,\n open: controlledOpen,\n onOpenChange,\n children,\n unstyled = false,\n}: ActionMenuProps) {\n const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n const isOpen = controlledOpen ?? uncontrolledOpen;\n\n const [highlightedIndex, setHighlightedIndex] = useState(-1);\n const itemsRef = useRef<string[]>([]);\n const onSelectRef = useRef<((index: number) => void) | null>(null);\n\n const menuId = useId('action-menu');\n const triggerId = useId('action-menu-trigger');\n\n const setOpen = useCallback(\n (value: boolean) => {\n if (controlledOpen === undefined) {\n setUncontrolledOpen(value);\n }\n onOpenChange?.(value);\n\n if (!value) {\n setHighlightedIndex(-1);\n }\n },\n [controlledOpen, onOpenChange]\n );\n\n const open = useCallback(() => setOpen(true), [setOpen]);\n const close = useCallback(() => setOpen(false), [setOpen]);\n const toggle = useCallback(() => setOpen(!isOpen), [setOpen, isOpen]);\n\n const registerItem = useCallback((id: string) => {\n const index = itemsRef.current.length;\n itemsRef.current.push(id);\n return index;\n }, []);\n\n const unregisterItem = useCallback((id: string) => {\n const index = itemsRef.current.indexOf(id);\n if (index > -1) {\n itemsRef.current.splice(index, 1);\n }\n }, []);\n\n const getItemCount = useCallback(() => itemsRef.current.length, []);\n\n const selectItem = useCallback(\n (index: number) => {\n onSelectRef.current?.(index);\n close();\n },\n [close]\n );\n\n const contextValue: ActionMenuContextValue = {\n isOpen,\n open,\n close,\n toggle,\n highlightedIndex,\n setHighlightedIndex,\n menuId,\n triggerId,\n registerItem,\n unregisterItem,\n getItemCount,\n selectItem,\n unstyled,\n };\n\n return (\n <ActionMenuProvider value={contextValue}>\n <div\n style={{ position: 'relative', display: 'inline-block' }}\n data-a11y-core-action-menu\n >\n {children}\n </div>\n </ActionMenuProvider>\n );\n}\n\nexport interface ActionMenuTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n children: React.ReactNode;\n}\n\nexport const ActionMenuTrigger = forwardRef<\n HTMLButtonElement,\n ActionMenuTriggerProps\n>(function ActionMenuTrigger({ children, onClick, onKeyDown, ...props }, ref) {\n const {\n isOpen,\n toggle,\n open,\n close,\n triggerId,\n menuId,\n setHighlightedIndex,\n getItemCount,\n } = useActionMenuContext();\n\n const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n if (!event.defaultPrevented) {\n toggle();\n }\n };\n\n const keyboardProps = useKeyboard(\n {\n ArrowDown: () => {\n if (!isOpen) {\n open();\n }\n setHighlightedIndex(0);\n },\n ArrowUp: () => {\n if (!isOpen) {\n open();\n }\n setHighlightedIndex(getItemCount() - 1);\n },\n Enter: () => toggle(),\n Space: () => toggle(),\n Escape: () => close(),\n },\n { preventDefault: true }\n );\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {\n onKeyDown?.(event);\n if (!event.defaultPrevented) {\n keyboardProps.onKeyDown(event);\n }\n };\n\n return (\n <button\n ref={ref}\n id={triggerId}\n type=\"button\"\n // Safari fix: Ensure button is in tab order (Safari skips buttons by default)\n tabIndex={0}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? menuId : undefined}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n data-a11y-core-action-menu-trigger\n {...props}\n >\n {children}\n </button>\n );\n});\n\nexport interface ActionMenuContentProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode;\n}\n\nexport const ActionMenuContent = forwardRef<\n HTMLDivElement,\n ActionMenuContentProps\n>(function ActionMenuContent({ children, onKeyDown, style, ...props }, ref) {\n const {\n isOpen,\n close,\n menuId,\n triggerId,\n highlightedIndex,\n setHighlightedIndex,\n getItemCount,\n unstyled,\n } = useActionMenuContext();\n const menuRef = useRef<HTMLDivElement>(null);\n\n const clickHighlightedItem = () => {\n if (highlightedIndex >= 0 && menuRef.current) {\n const items = menuRef.current.querySelectorAll('[role=\"menuitem\"]');\n const item = items[highlightedIndex] as HTMLElement;\n if (item && item.getAttribute('aria-disabled') !== 'true') {\n item.click();\n }\n }\n };\n\n const keyboardProps = useKeyboard(\n {\n ArrowDown: () => {\n const count = getItemCount();\n setHighlightedIndex((highlightedIndex + 1) % count);\n },\n ArrowUp: () => {\n const count = getItemCount();\n setHighlightedIndex((highlightedIndex - 1 + count) % count);\n },\n Home: () => setHighlightedIndex(0),\n End: () => setHighlightedIndex(getItemCount() - 1),\n Enter: () => clickHighlightedItem(),\n Space: () => clickHighlightedItem(),\n Escape: () => close(),\n Tab: () => {\n close();\n return false; // Allow default tab behavior\n },\n },\n { preventDefault: true }\n );\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n if (!event.defaultPrevented) {\n keyboardProps.onKeyDown(event);\n }\n };\n\n useEffect(() => {\n if (isOpen && menuRef.current) {\n menuRef.current.focus();\n }\n }, [isOpen]);\n\n useEffect(() => {\n if (!isOpen) return;\n\n const handleClick = (event: MouseEvent) => {\n const target = event.target as Node;\n const menu = menuRef.current;\n const trigger = document.getElementById(triggerId);\n\n if (\n menu &&\n !menu.contains(target) &&\n trigger &&\n !trigger.contains(target)\n ) {\n close();\n }\n };\n\n document.addEventListener('mousedown', handleClick);\n return () => document.removeEventListener('mousedown', handleClick);\n }, [isOpen, close, triggerId]);\n\n if (!isOpen) {\n return null;\n }\n\n // Structural styles - always applied, required for dropdown positioning\n const contentStructuralStyles: React.CSSProperties = {\n position: 'absolute',\n top: '100%',\n left: 0,\n marginTop: '4px',\n zIndex: 1000,\n };\n\n // Visual styles - only applied when not unstyled\n const contentVisualStyles: React.CSSProperties = unstyled\n ? {}\n : {\n minWidth: '160px',\n backgroundColor: 'white',\n border: '1px solid #e0e0e0',\n borderRadius: '4px',\n boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',\n padding: '4px 0',\n };\n\n const contentStyles: React.CSSProperties = {\n ...contentStructuralStyles,\n ...contentVisualStyles,\n };\n\n return (\n <div\n ref={(node) => {\n (menuRef as React.MutableRefObject<HTMLDivElement | null>).current =\n node;\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n ref.current = node;\n }\n }}\n id={menuId}\n role=\"menu\"\n aria-labelledby={triggerId}\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n style={{ ...contentStyles, ...style }}\n data-a11y-core-action-menu-content\n {...props}\n >\n {children}\n </div>\n );\n});\n\nexport interface ActionMenuItemProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Whether the item is disabled */\n disabled?: boolean;\n /** Called when item is selected */\n onSelect?: () => void;\n children: React.ReactNode;\n}\n\nexport const ActionMenuItem = forwardRef<HTMLDivElement, ActionMenuItemProps>(\n function ActionMenuItem(\n {\n children,\n disabled = false,\n onSelect,\n onClick,\n onMouseEnter,\n style,\n ...props\n },\n ref\n ) {\n const {\n registerItem,\n unregisterItem,\n highlightedIndex,\n setHighlightedIndex,\n close,\n unstyled,\n } = useActionMenuContext();\n const itemId = useId('action-menu-item');\n const indexRef = useRef(-1);\n\n useEffect(() => {\n if (!disabled) {\n indexRef.current = registerItem(itemId);\n }\n return () => {\n if (!disabled) {\n unregisterItem(itemId);\n }\n };\n }, [itemId, disabled, registerItem, unregisterItem]);\n\n const isHighlighted = indexRef.current === highlightedIndex;\n\n const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {\n onClick?.(event);\n if (!event.defaultPrevented && !disabled) {\n onSelect?.();\n close();\n }\n };\n\n const handleMouseEnter = (event: React.MouseEvent<HTMLDivElement>) => {\n onMouseEnter?.(event);\n if (!disabled) {\n setHighlightedIndex(indexRef.current);\n }\n };\n\n // Behavioral styles - always applied for correct UX\n const itemBehaviorStyles: React.CSSProperties = {\n cursor: disabled ? 'not-allowed' : 'pointer',\n opacity: disabled ? 0.5 : 1,\n };\n\n // Visual styles - only applied when not unstyled\n const itemVisualStyles: React.CSSProperties = unstyled\n ? {}\n : {\n padding: '8px 16px',\n backgroundColor: isHighlighted ? '#f0f0f0' : 'transparent',\n };\n\n const itemStyles: React.CSSProperties = {\n ...itemBehaviorStyles,\n ...itemVisualStyles,\n };\n\n return (\n <div\n ref={ref}\n id={itemId}\n role=\"menuitem\"\n tabIndex={-1}\n aria-disabled={disabled}\n data-highlighted={isHighlighted}\n data-disabled={disabled}\n onClick={handleClick}\n onMouseEnter={handleMouseEnter}\n style={{ ...itemStyles, ...style }}\n data-a11y-core-action-menu-item\n {...props}\n >\n {children}\n </div>\n );\n }\n);\n\nexport interface ActionMenuSeparatorProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const ActionMenuSeparator = forwardRef<\n HTMLDivElement,\n ActionMenuSeparatorProps\n>(function ActionMenuSeparator(props, ref) {\n return (\n <div\n ref={ref}\n role=\"separator\"\n data-a11y-core-action-menu-separator\n {...props}\n />\n );\n});\n\nexport interface ActionMenuLabelProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode;\n}\n\nexport const ActionMenuLabel = forwardRef<HTMLDivElement, ActionMenuLabelProps>(\n function ActionMenuLabel({ children, ...props }, ref) {\n return (\n <div\n ref={ref}\n role=\"presentation\"\n data-a11y-core-action-menu-label\n {...props}\n >\n {children}\n </div>\n );\n }\n);\n\nexport const ActionMenuCompound = Object.assign(ActionMenu, {\n Trigger: ActionMenuTrigger,\n Content: ActionMenuContent,\n Item: ActionMenuItem,\n Separator: ActionMenuSeparator,\n Label: ActionMenuLabel,\n});\n"]}
@@ -0,0 +1,220 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var reactDom = require('react-dom');
5
+ var core = require('@a11y-core/core');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+
8
+ // src/components/toast/toast.tsx
9
+ var ToastContext = react.createContext(null);
10
+ function useToast() {
11
+ const context = react.useContext(ToastContext);
12
+ if (!context) {
13
+ throw new Error("useToast must be used within a ToastProvider");
14
+ }
15
+ return context;
16
+ }
17
+ function ToastProvider({
18
+ children,
19
+ duration = 5e3,
20
+ maxToasts = 5
21
+ }) {
22
+ const [toasts, setToasts] = react.useState([]);
23
+ const toastIdCounter = react.useRef(0);
24
+ const addToast = react.useCallback(
25
+ (toast) => {
26
+ const id = `toast-${++toastIdCounter.current}`;
27
+ const newToast = {
28
+ ...toast,
29
+ id,
30
+ duration: toast.duration ?? duration
31
+ };
32
+ setToasts((prev) => {
33
+ const updated = [...prev, newToast];
34
+ return updated.slice(-maxToasts);
35
+ });
36
+ const message = toast.title ? `${toast.title}. ${toast.description || ""}` : toast.description || "";
37
+ if (toast.type === "error") {
38
+ core.announceAssertive(message);
39
+ } else {
40
+ core.announce(message, { politeness: "polite" });
41
+ }
42
+ return id;
43
+ },
44
+ [duration, maxToasts]
45
+ );
46
+ const removeToast = react.useCallback((id) => {
47
+ setToasts((prev) => prev.filter((t) => t.id !== id));
48
+ }, []);
49
+ const updateToast = react.useCallback(
50
+ (id, updates) => {
51
+ setToasts(
52
+ (prev) => prev.map((t) => t.id === id ? { ...t, ...updates } : t)
53
+ );
54
+ },
55
+ []
56
+ );
57
+ return /* @__PURE__ */ jsxRuntime.jsx(
58
+ ToastContext.Provider,
59
+ {
60
+ value: { toasts, addToast, removeToast, updateToast },
61
+ children
62
+ }
63
+ );
64
+ }
65
+ var positionStyles = {
66
+ "top-left": { top: 0, left: 0 },
67
+ "top-center": { top: 0, left: "50%", transform: "translateX(-50%)" },
68
+ "top-right": { top: 0, right: 0 },
69
+ "bottom-left": { bottom: 0, left: 0 },
70
+ "bottom-center": { bottom: 0, left: "50%", transform: "translateX(-50%)" },
71
+ "bottom-right": { bottom: 0, right: 0 }
72
+ };
73
+ var ToastViewport = react.forwardRef(
74
+ function ToastViewport2({
75
+ position = "bottom-right",
76
+ label = "Notifications",
77
+ style,
78
+ children,
79
+ ...props
80
+ }, ref) {
81
+ const { toasts, removeToast } = useToast();
82
+ const viewport = /* @__PURE__ */ jsxRuntime.jsxs(
83
+ "div",
84
+ {
85
+ ref,
86
+ role: "region",
87
+ "aria-label": label,
88
+ "aria-live": "polite",
89
+ "aria-relevant": "additions removals",
90
+ tabIndex: -1,
91
+ style: {
92
+ position: "fixed",
93
+ zIndex: 9999,
94
+ padding: "1rem",
95
+ display: "flex",
96
+ flexDirection: "column",
97
+ gap: "0.5rem",
98
+ ...positionStyles[position],
99
+ ...style
100
+ },
101
+ "data-a11y-core-toast-viewport": true,
102
+ "data-position": position,
103
+ ...props,
104
+ children: [
105
+ toasts.map((toast) => /* @__PURE__ */ jsxRuntime.jsx(
106
+ ToastItem,
107
+ {
108
+ toast,
109
+ onClose: () => removeToast(toast.id)
110
+ },
111
+ toast.id
112
+ )),
113
+ children
114
+ ]
115
+ }
116
+ );
117
+ return reactDom.createPortal(viewport, document.body);
118
+ }
119
+ );
120
+ function ToastItem({ toast, onClose }) {
121
+ const [isVisible, setIsVisible] = react.useState(true);
122
+ const [, setIsPaused] = react.useState(false);
123
+ const timerRef = react.useRef(null);
124
+ const remainingRef = react.useRef(toast.duration || 5e3);
125
+ const startTimeRef = react.useRef(Date.now());
126
+ const startTimer = react.useCallback(() => {
127
+ if (toast.duration === 0) return;
128
+ startTimeRef.current = Date.now();
129
+ timerRef.current = setTimeout(() => {
130
+ setIsVisible(false);
131
+ setTimeout(onClose, 200);
132
+ }, remainingRef.current);
133
+ }, [toast.duration, onClose]);
134
+ const pauseTimer = react.useCallback(() => {
135
+ if (timerRef.current) {
136
+ clearTimeout(timerRef.current);
137
+ remainingRef.current -= Date.now() - startTimeRef.current;
138
+ }
139
+ }, []);
140
+ react.useEffect(() => {
141
+ startTimer();
142
+ return () => {
143
+ if (timerRef.current) {
144
+ clearTimeout(timerRef.current);
145
+ }
146
+ };
147
+ }, [startTimer]);
148
+ const handleMouseEnter = () => {
149
+ setIsPaused(true);
150
+ pauseTimer();
151
+ };
152
+ const handleMouseLeave = () => {
153
+ setIsPaused(false);
154
+ startTimer();
155
+ };
156
+ const handleKeyDown = (event) => {
157
+ if (event.key === "Escape") {
158
+ onClose();
159
+ }
160
+ };
161
+ return /* @__PURE__ */ jsxRuntime.jsxs(
162
+ "div",
163
+ {
164
+ role: "alert",
165
+ "aria-atomic": "true",
166
+ tabIndex: 0,
167
+ onMouseEnter: handleMouseEnter,
168
+ onMouseLeave: handleMouseLeave,
169
+ onKeyDown: handleKeyDown,
170
+ "data-type": toast.type,
171
+ "data-visible": isVisible,
172
+ "data-a11y-core-toast": true,
173
+ children: [
174
+ toast.title && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-a11y-core-toast-title": true, children: toast.title }),
175
+ toast.description && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-a11y-core-toast-description": true, children: toast.description }),
176
+ toast.action && /* @__PURE__ */ jsxRuntime.jsx(
177
+ "button",
178
+ {
179
+ type: "button",
180
+ tabIndex: 0,
181
+ onClick: () => {
182
+ toast.action?.onClick();
183
+ onClose();
184
+ },
185
+ "data-a11y-core-toast-action": true,
186
+ children: toast.action.label
187
+ }
188
+ ),
189
+ /* @__PURE__ */ jsxRuntime.jsx(
190
+ "button",
191
+ {
192
+ type: "button",
193
+ tabIndex: 0,
194
+ "aria-label": "Dismiss",
195
+ onClick: onClose,
196
+ "data-a11y-core-toast-close": true,
197
+ children: "\xD7"
198
+ }
199
+ )
200
+ ]
201
+ }
202
+ );
203
+ }
204
+ function useToastHelpers() {
205
+ const { addToast } = useToast();
206
+ return {
207
+ toast: addToast,
208
+ success: (title, description) => addToast({ type: "success", title, description }),
209
+ error: (title, description) => addToast({ type: "error", title, description }),
210
+ warning: (title, description) => addToast({ type: "warning", title, description }),
211
+ info: (title, description) => addToast({ type: "info", title, description })
212
+ };
213
+ }
214
+
215
+ exports.ToastProvider = ToastProvider;
216
+ exports.ToastViewport = ToastViewport;
217
+ exports.useToast = useToast;
218
+ exports.useToastHelpers = useToastHelpers;
219
+ //# sourceMappingURL=chunk-CTW5D77X.cjs.map
220
+ //# sourceMappingURL=chunk-CTW5D77X.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/toast/toast.tsx"],"names":["createContext","useContext","useState","useRef","useCallback","announceAssertive","announce","jsx","forwardRef","ToastViewport","jsxs","createPortal","useEffect"],"mappings":"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","file":"chunk-CTW5D77X.cjs","sourcesContent":["import React, {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { announce, announceAssertive } from '@a11y-core/core';\nexport type ToastType = 'info' | 'success' | 'warning' | 'error';\n\nexport interface Toast {\n id: string;\n title?: string;\n description?: string;\n type: ToastType;\n duration?: number;\n action?: {\n label: string;\n onClick: () => void;\n };\n}\n\ninterface ToastContextValue {\n toasts: Toast[];\n addToast: (toast: Omit<Toast, 'id'>) => string;\n removeToast: (id: string) => void;\n updateToast: (id: string, toast: Partial<Omit<Toast, 'id'>>) => void;\n}\n\nconst ToastContext = createContext<ToastContextValue | null>(null);\n\nexport function useToast() {\n const context = useContext(ToastContext);\n if (!context) {\n throw new Error('useToast must be used within a ToastProvider');\n }\n return context;\n}\n\nexport interface ToastProviderProps {\n children: React.ReactNode;\n /** Default duration for toasts in ms */\n duration?: number;\n /** Maximum number of visible toasts */\n maxToasts?: number;\n}\n\nexport function ToastProvider({\n children,\n duration = 5000,\n maxToasts = 5,\n}: ToastProviderProps) {\n const [toasts, setToasts] = useState<Toast[]>([]);\n const toastIdCounter = useRef(0);\n\n const addToast = useCallback(\n (toast: Omit<Toast, 'id'>): string => {\n const id = `toast-${++toastIdCounter.current}`;\n const newToast: Toast = {\n ...toast,\n id,\n duration: toast.duration ?? duration,\n };\n\n setToasts((prev) => {\n const updated = [...prev, newToast];\n // Limit visible toasts\n return updated.slice(-maxToasts);\n });\n\n // Announce to screen readers\n const message = toast.title\n ? `${toast.title}. ${toast.description || ''}`\n : toast.description || '';\n\n if (toast.type === 'error') {\n announceAssertive(message);\n } else {\n announce(message, { politeness: 'polite' });\n }\n\n return id;\n },\n [duration, maxToasts]\n );\n\n const removeToast = useCallback((id: string) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, []);\n\n const updateToast = useCallback(\n (id: string, updates: Partial<Omit<Toast, 'id'>>) => {\n setToasts((prev) =>\n prev.map((t) => (t.id === id ? { ...t, ...updates } : t))\n );\n },\n []\n );\n\n return (\n <ToastContext.Provider\n value={{ toasts, addToast, removeToast, updateToast }}\n >\n {children}\n </ToastContext.Provider>\n );\n}\n\nexport interface ToastViewportProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Position of the toast container */\n position?:\n | 'top-left'\n | 'top-center'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-center'\n | 'bottom-right';\n /** Label for screen readers */\n label?: string;\n}\n\nconst positionStyles: Record<string, React.CSSProperties> = {\n 'top-left': { top: 0, left: 0 },\n 'top-center': { top: 0, left: '50%', transform: 'translateX(-50%)' },\n 'top-right': { top: 0, right: 0 },\n 'bottom-left': { bottom: 0, left: 0 },\n 'bottom-center': { bottom: 0, left: '50%', transform: 'translateX(-50%)' },\n 'bottom-right': { bottom: 0, right: 0 },\n};\n\nexport const ToastViewport = forwardRef<HTMLDivElement, ToastViewportProps>(\n function ToastViewport(\n {\n position = 'bottom-right',\n label = 'Notifications',\n style,\n children,\n ...props\n },\n ref\n ) {\n const { toasts, removeToast } = useToast();\n\n const viewport = (\n <div\n ref={ref}\n role=\"region\"\n aria-label={label}\n aria-live=\"polite\"\n aria-relevant=\"additions removals\"\n tabIndex={-1}\n style={{\n position: 'fixed',\n zIndex: 9999,\n padding: '1rem',\n display: 'flex',\n flexDirection: 'column',\n gap: '0.5rem',\n ...positionStyles[position],\n ...style,\n }}\n data-a11y-core-toast-viewport\n data-position={position}\n {...props}\n >\n {toasts.map((toast) => (\n <ToastItem\n key={toast.id}\n toast={toast}\n onClose={() => removeToast(toast.id)}\n />\n ))}\n {children}\n </div>\n );\n\n return createPortal(viewport, document.body);\n }\n);\n\ninterface ToastItemProps {\n toast: Toast;\n onClose: () => void;\n}\n\nfunction ToastItem({ toast, onClose }: ToastItemProps) {\n const [isVisible, setIsVisible] = useState(true);\n const [, setIsPaused] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const remainingRef = useRef(toast.duration || 5000);\n const startTimeRef = useRef(Date.now());\n\n const startTimer = useCallback(() => {\n if (toast.duration === 0) return; // Infinite duration\n\n startTimeRef.current = Date.now();\n timerRef.current = setTimeout(() => {\n setIsVisible(false);\n setTimeout(onClose, 200); // Allow exit animation\n }, remainingRef.current);\n }, [toast.duration, onClose]);\n\n const pauseTimer = useCallback(() => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n remainingRef.current -= Date.now() - startTimeRef.current;\n }\n }, []);\n\n useEffect(() => {\n startTimer();\n return () => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n }\n };\n }, [startTimer]);\n\n const handleMouseEnter = () => {\n setIsPaused(true);\n pauseTimer();\n };\n\n const handleMouseLeave = () => {\n setIsPaused(false);\n startTimer();\n };\n\n const handleKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === 'Escape') {\n onClose();\n }\n };\n\n return (\n <div\n role=\"alert\"\n aria-atomic=\"true\"\n tabIndex={0}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onKeyDown={handleKeyDown}\n data-type={toast.type}\n data-visible={isVisible}\n data-a11y-core-toast\n >\n {toast.title && <div data-a11y-core-toast-title>{toast.title}</div>}\n {toast.description && (\n <div data-a11y-core-toast-description>{toast.description}</div>\n )}\n {toast.action && (\n <button\n type=\"button\"\n // Safari fix: Ensure button is in tab order\n tabIndex={0}\n onClick={() => {\n toast.action?.onClick();\n onClose();\n }}\n data-a11y-core-toast-action\n >\n {toast.action.label}\n </button>\n )}\n <button\n type=\"button\"\n // Safari fix: Ensure button is in tab order\n tabIndex={0}\n aria-label=\"Dismiss\"\n onClick={onClose}\n data-a11y-core-toast-close\n >\n ×\n </button>\n </div>\n );\n}\n\n/**\n * Hook for common toast patterns\n */\nexport function useToastHelpers() {\n const { addToast } = useToast();\n\n return {\n toast: addToast,\n success: (title: string, description?: string) =>\n addToast({ type: 'success', title, description }),\n error: (title: string, description?: string) =>\n addToast({ type: 'error', title, description }),\n warning: (title: string, description?: string) =>\n addToast({ type: 'warning', title, description }),\n info: (title: string, description?: string) =>\n addToast({ type: 'info', title, description }),\n };\n}\n"]}