@dreamtree-org/twreact-ui 1.3.9 → 1.3.10

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 (62) hide show
  1. package/README.md +2 -0
  2. package/dist/ai-schema.json +19 -8
  3. package/dist/components/blocks/AppShell.d.ts.map +1 -1
  4. package/dist/components/core/Accordion.d.ts.map +1 -1
  5. package/dist/components/core/ColorPicker.d.ts.map +1 -1
  6. package/dist/components/core/DatePicker.d.ts.map +1 -1
  7. package/dist/components/core/Form.d.ts.map +1 -1
  8. package/dist/components/core/Input.d.ts.map +1 -1
  9. package/dist/components/core/PriceRangePicker.d.ts +0 -29
  10. package/dist/components/core/PriceRangePicker.d.ts.map +1 -1
  11. package/dist/components/core/Radio.d.ts.map +1 -1
  12. package/dist/components/core/Rate.d.ts.map +1 -1
  13. package/dist/components/core/RoundedTag.d.ts.map +1 -1
  14. package/dist/components/core/Table/ColumnMenu.d.ts.map +1 -1
  15. package/dist/components/core/Table/Pagination.d.ts.map +1 -1
  16. package/dist/components/core/Table/TableRow.d.ts.map +1 -1
  17. package/dist/components/core/Table/helpers.d.ts +2 -0
  18. package/dist/components/core/Table/helpers.d.ts.map +1 -1
  19. package/dist/components/core/Tabs.d.ts.map +1 -1
  20. package/dist/components/core/TextToSpeech.d.ts +2 -7
  21. package/dist/components/core/TextToSpeech.d.ts.map +1 -1
  22. package/dist/components/core/Tooltip.d.ts.map +1 -1
  23. package/dist/components/feedback/Alert.d.ts.map +1 -1
  24. package/dist/components/feedback/Dialog.d.ts.map +1 -1
  25. package/dist/components/feedback/Toast.d.ts.map +1 -1
  26. package/dist/components/navigation/Sidebar.d.ts.map +1 -1
  27. package/dist/components/utility/Avatar.d.ts.map +1 -1
  28. package/dist/components/utility/Carousel.d.ts.map +1 -1
  29. package/dist/esm/components/blocks/AppShell.js +24 -18
  30. package/dist/esm/components/core/Accordion.js +40 -9
  31. package/dist/esm/components/core/ColorPicker.js +19 -7
  32. package/dist/esm/components/core/DatePicker.js +97 -58
  33. package/dist/esm/components/core/Form.js +35 -8
  34. package/dist/esm/components/core/Input.js +3 -1
  35. package/dist/esm/components/core/PriceRangePicker.js +205 -218
  36. package/dist/esm/components/core/Radio.js +36 -6
  37. package/dist/esm/components/core/Rate.js +41 -50
  38. package/dist/esm/components/core/RoundedTag.js +25 -8
  39. package/dist/esm/components/core/Table/ColumnMenu.js +2 -4
  40. package/dist/esm/components/core/Table/Pagination.js +15 -18
  41. package/dist/esm/components/core/Table/TableRow.js +2 -2
  42. package/dist/esm/components/core/Table/helpers.js +33 -1
  43. package/dist/esm/components/core/Tabs.js +6 -5
  44. package/dist/esm/components/core/TextToSpeech.js +121 -28
  45. package/dist/esm/components/core/Tooltip.js +100 -28
  46. package/dist/esm/components/feedback/Alert.js +21 -11
  47. package/dist/esm/components/feedback/Dialog.js +44 -100
  48. package/dist/esm/components/feedback/Toast.js +24 -5
  49. package/dist/esm/components/navigation/Sidebar.js +13 -61
  50. package/dist/esm/components/utility/Avatar.js +23 -10
  51. package/dist/esm/components/utility/Carousel.js +34 -17
  52. package/dist/esm/components/utility/Pagination.js +2 -2
  53. package/dist/esm/hooks/useFocusTrap.js +10 -2
  54. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  55. package/dist/index.css +1 -1
  56. package/dist/index.esm.css +1 -1
  57. package/dist/index.esm.js +1760 -1350
  58. package/dist/index.js +1759 -1349
  59. package/dist/types/index.d.ts +8 -2
  60. package/dist/types/index.d.ts.map +1 -1
  61. package/mcp/catalog.snapshot.json +82 -52
  62. package/package.json +1 -1
package/README.md CHANGED
@@ -913,6 +913,8 @@ function App() {
913
913
 
914
914
  Surfaces such as `Card`, `Sidebar`, `Navbar`, `Table`, `FootNav` and `Dropdown` use the semantic `bg-surface` / `bg-background` / `border-line` / `text-foreground` / `text-muted` tokens, which switch under `.dark` (or `[data-theme="dark"]`). Re-theme them by overriding the `--dt-surface`, `--dt-background`, `--dt-line`, … variables.
915
915
 
916
+ > **Accessibility fixes (1.4.x):** Radio groups keep a single selection when uncontrolled, Rate and DatePicker use one tab stop with arrow-key focus, Dialog/Sidebar/AppShell drawers share one focus trap and scroll lock, Toast announces via `role="status"`, Alert's dismiss button is labelled, and Input shows a visible focus ring in its default state. No props changed.
917
+
916
918
  ## Examples
917
919
 
918
920
  ### Complete Form Example
@@ -728,7 +728,8 @@
728
728
  },
729
729
  "label": {
730
730
  "type": "string",
731
- "required": false
731
+ "required": false,
732
+ "default": "\"Pick a color\""
732
733
  }
733
734
  }
734
735
  },
@@ -1195,7 +1196,8 @@
1195
1196
  },
1196
1197
  "onSubmit": {
1197
1198
  "type": "(data: any) => void",
1198
- "required": false
1199
+ "required": false,
1200
+ "default": "Promise<void>"
1199
1201
  },
1200
1202
  "defaultValues": {
1201
1203
  "type": "Record",
@@ -1800,7 +1802,7 @@
1800
1802
  "colorClass": {
1801
1803
  "type": "string",
1802
1804
  "required": false,
1803
- "default": "\"bg-pink-500\""
1805
+ "default": "\"bg-primary-600\""
1804
1806
  },
1805
1807
  "ariaLabel": {
1806
1808
  "type": "string",
@@ -2164,8 +2166,7 @@
2164
2166
  },
2165
2167
  "ariaLabel": {
2166
2168
  "type": "string",
2167
- "required": false,
2168
- "default": "\"tag\""
2169
+ "required": false
2169
2170
  },
2170
2171
  "avatarPosition": {
2171
2172
  "type": "enum",
@@ -3118,7 +3119,7 @@
3118
3119
  "TextToSpeech": {
3119
3120
  "group": "core",
3120
3121
  "import": "@dreamtree-org/twreact-ui",
3121
- "forwardRef": false,
3122
+ "forwardRef": true,
3122
3123
  "props": {
3123
3124
  "text": {
3124
3125
  "type": "string",
@@ -3140,6 +3141,16 @@
3140
3141
  "required": false,
3141
3142
  "default": "() => {}"
3142
3143
  },
3144
+ "onError": {
3145
+ "type": "(error: Error) => void",
3146
+ "required": false,
3147
+ "default": "() => {}"
3148
+ },
3149
+ "disabled": {
3150
+ "type": "boolean",
3151
+ "required": false,
3152
+ "default": "false"
3153
+ },
3143
3154
  "renderButton": {
3144
3155
  "type": "(state: TextToSpeechState) => ReactNode",
3145
3156
  "required": false
@@ -3347,12 +3358,12 @@
3347
3358
  "textClass": {
3348
3359
  "type": "string",
3349
3360
  "required": false,
3350
- "default": "\"text-black\""
3361
+ "default": "\"text-foreground\""
3351
3362
  },
3352
3363
  "bgClass": {
3353
3364
  "type": "string",
3354
3365
  "required": false,
3355
- "default": "\"bg-white\""
3366
+ "default": "\"bg-surface\""
3356
3367
  },
3357
3368
  "portal": {
3358
3369
  "type": "boolean",
@@ -1 +1 @@
1
- {"version":3,"file":"AppShell.d.ts","sourceRoot":"","sources":["../../../src/components/blocks/AppShell.jsx"],"names":[],"mappings":";AAmDA,kFAgEG;kBAnH6D,OAAO"}
1
+ {"version":3,"file":"AppShell.d.ts","sourceRoot":"","sources":["../../../src/components/blocks/AppShell.jsx"],"names":[],"mappings":";AAqDA,kFA+EG;kBApIkD,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"Accordion.d.ts","sourceRoot":"","sources":["../../../src/components/core/Accordion.jsx"],"names":[],"mappings":";AAIA;;;;GAIG;AAEH,mFA+OG;kBAzP8E,OAAO"}
1
+ {"version":3,"file":"Accordion.d.ts","sourceRoot":"","sources":["../../../src/components/core/Accordion.jsx"],"names":[],"mappings":";AAKA;;;;GAIG;AAEH,mFA+QG;kBA1RqF,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"ColorPicker.d.ts","sourceRoot":"","sources":["../../../src/components/core/ColorPicker.jsx"],"names":[],"mappings":";AA0FA,qFAkKG;kBA5PkD,OAAO"}
1
+ {"version":3,"file":"ColorPicker.d.ts","sourceRoot":"","sources":["../../../src/components/core/ColorPicker.jsx"],"names":[],"mappings":";AA0FA,qFAiLG;kBA3QyD,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"DatePicker.d.ts","sourceRoot":"","sources":["../../../src/components/core/DatePicker.jsx"],"names":[],"mappings":";AA8BA,oFA+dE;kBArfK,OAAO"}
1
+ {"version":3,"file":"DatePicker.d.ts","sourceRoot":"","sources":["../../../src/components/core/DatePicker.jsx"],"names":[],"mappings":";AAgCA,oFAqhBE;kBA7iBK,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"Form.d.ts","sourceRoot":"","sources":["../../../src/components/core/Form.jsx"],"names":[],"mappings":";AAwCA,8EA2hBG;kBAnkB6D,OAAO"}
1
+ {"version":3,"file":"Form.d.ts","sourceRoot":"","sources":["../../../src/components/core/Form.jsx"],"names":[],"mappings":";AAuDA,8EAyiBG;kBAhmB6D,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../../src/components/core/Input.jsx"],"names":[],"mappings":";AAIA,+EA+NG;kBAnOqE,OAAO"}
1
+ {"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../../src/components/core/Input.jsx"],"names":[],"mappings":";AAIA,+EAmOG;kBAvOqE,OAAO"}
@@ -1,33 +1,4 @@
1
1
  export default PriceRangePicker;
2
- /**
3
- * PriceRangeSlider - UI library component (Tailwind)
4
- *
5
- * Props
6
- * - min: number (default 0)
7
- * - max: number (default 1000)
8
- * - step: number (default 1)
9
- * - minGap: number (minimum distance between thumbs, default 5)
10
- * - value: { min: number, max: number } | null (controlled)
11
- * - defaultValue: { min: number, max: number } (uncontrolled initial)
12
- * - onChange: (value) => void
13
- * - onFinalChange: (value) => void // called on mouseup/touchend or Enter in inputs
14
- * - showInputs: boolean (default true)
15
- * - showTooltips: boolean (default true)
16
- * - disabled: boolean
17
- * - presets: Array<{ id: string|number, label: string, value: {min:number,max:number} }>
18
- * - formatValue: (n) => string (formatting callback, default: n => n)
19
- * - className: string (container custom classes)
20
- * - size: 'sm' | 'md' | 'lg' (affects thumb size & spacing)
21
- * - colorClass: Tailwind class for active track/thumb, default 'bg-pink-500'
22
- * - ariaLabel: string
23
- *
24
- * Usage notes
25
- * - Controlled mode: pass `value` and handle updates via onChange.
26
- * - Uncontrolled mode: omit `value` and use `defaultValue`.
27
- *
28
- * Accessibility
29
- * - Inputs are labelled and thumbs are keyboard-focusable
30
- */
31
2
  declare const PriceRangePicker: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
32
3
  import React from "react";
33
4
  //# sourceMappingURL=PriceRangePicker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PriceRangePicker.d.ts","sourceRoot":"","sources":["../../../src/components/core/PriceRangePicker.jsx"],"names":[],"mappings":";AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,0FA8TG;kBA/V6D,OAAO"}
1
+ {"version":3,"file":"PriceRangePicker.d.ts","sourceRoot":"","sources":["../../../src/components/core/PriceRangePicker.jsx"],"names":[],"mappings":";AAqCA,0FAoQG;kBAzSqE,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"Radio.d.ts","sourceRoot":"","sources":["../../../src/components/core/Radio.jsx"],"names":[],"mappings":";AAYA,+EAsIG;kBAjJgD,OAAO"}
1
+ {"version":3,"file":"Radio.d.ts","sourceRoot":"","sources":["../../../src/components/core/Radio.jsx"],"names":[],"mappings":";AAmBA,+EAwKG;kBAnLI,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"Rate.d.ts","sourceRoot":"","sources":["../../../src/components/core/Rate.jsx"],"names":[],"mappings":";AA0CA,8EAuJG;kBAhMyC,OAAO"}
1
+ {"version":3,"file":"Rate.d.ts","sourceRoot":"","sources":["../../../src/components/core/Rate.jsx"],"names":[],"mappings":";AA2CA,8EAyJG;kBAnMiD,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"RoundedTag.d.ts","sourceRoot":"","sources":["../../../src/components/core/RoundedTag.jsx"],"names":[],"mappings":";AAGA,oFAoIG;kBAvI+B,OAAO"}
1
+ {"version":3,"file":"RoundedTag.d.ts","sourceRoot":"","sources":["../../../src/components/core/RoundedTag.jsx"],"names":[],"mappings":";AAIA,oFAgKG;kBApK+B,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"ColumnMenu.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/ColumnMenu.jsx"],"names":[],"mappings":";AAKA;;GAEG;AACH;;;;;;4CAmCC"}
1
+ {"version":3,"file":"ColumnMenu.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/ColumnMenu.jsx"],"names":[],"mappings":";AAMA;;GAEG;AACH;;;;;;4CAmCC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Pagination.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/Pagination.jsx"],"names":[],"mappings":"AAiBA;;;;;4CAkDC;AAGD;;;;;;4CA4HC"}
1
+ {"version":3,"file":"Pagination.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/Pagination.jsx"],"names":[],"mappings":"AAoBA;;;;;4CAkDC;AAGD;;;;;;4CAmIC"}
@@ -1 +1 @@
1
- {"version":3,"file":"TableRow.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/TableRow.jsx"],"names":[],"mappings":";AAYA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4CA+RC"}
1
+ {"version":3,"file":"TableRow.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/TableRow.jsx"],"names":[],"mappings":";AAaA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4CA+RC"}
@@ -18,4 +18,6 @@ export function resolveActions(actions: any[] | Function, row: object, index: nu
18
18
  inlineActions: any[];
19
19
  menuActions: any[];
20
20
  };
21
+ export const DEFAULT_HOVER_CLASS: string;
22
+ export function getHoverClass(rowHover: any): any;
21
23
  //# sourceMappingURL=helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/helpers.js"],"names":[],"mappings":"AAGO,8DAMN;AAOM;;;;;;;;;;;EAKN;AAaM,8EACqE;AAMrE,qDAGG;AAcH,8EAmBN;AAuBM,wCALI,gBAAc,OACd,MAAM,SACN,MAAM,GACJ;IAAE,aAAa,QAAQ;IAAC,WAAW,QAAO;CAAE,CAyBxD"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/helpers.js"],"names":[],"mappings":"AAGO,8DAMN;AAOM;;;;;;;;;;;EAKN;AAaM,8EACqE;AAMrE,qDAGG;AAcH,8EAmBN;AAuBM,wCALI,gBAAc,OACd,MAAM,SACN,MAAM,GACJ;IAAE,aAAa,QAAQ;IAAC,WAAW,QAAO;CAAE,CAyBxD;AAgBD,yCAAqE;AAU9D,kDAUN"}
@@ -1 +1 @@
1
- {"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../src/components/core/Tabs.jsx"],"names":[],"mappings":"AA0GA;;;4CAuBC;AAGD;;;;;;;;4CAkHC;AAGD;;;4CAcC;AAED;;;;;mDA8BC;;AAnPD,8EAiDG;kBA7FI,OAAO"}
1
+ {"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../src/components/core/Tabs.jsx"],"names":[],"mappings":"AA0GA;;;4CAuBC;AAGD;;;;;;;;4CAmHC;AAGD;;;4CAcC;AAED;;;;;mDAyBC;;AA/OD,8EAiDG;kBA7FI,OAAO"}
@@ -1,9 +1,4 @@
1
1
  export default TextToSpeech;
2
- declare function TextToSpeech({ text, rate, pitch, onSpeak, renderButton, }: {
3
- text?: string | undefined;
4
- rate?: number | undefined;
5
- pitch?: number | undefined;
6
- onSpeak?: (() => void) | undefined;
7
- renderButton: any;
8
- }): import("react/jsx-runtime").JSX.Element;
2
+ declare const TextToSpeech: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
3
+ import React from "react";
9
4
  //# sourceMappingURL=TextToSpeech.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextToSpeech.d.ts","sourceRoot":"","sources":["../../../src/components/core/TextToSpeech.jsx"],"names":[],"mappings":";AAEA;;;;;;4CA4CC"}
1
+ {"version":3,"file":"TextToSpeech.d.ts","sourceRoot":"","sources":["../../../src/components/core/TextToSpeech.jsx"],"names":[],"mappings":";AAgBA,sFA6IE;kBA7J0E,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../../src/components/core/Tooltip.jsx"],"names":[],"mappings":";AAoCA;;;;;;;;;;;;;;;;GAgBG;AACH,iFAqVG;kBAjYI,OAAO"}
1
+ {"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../../src/components/core/Tooltip.jsx"],"names":[],"mappings":";AAwDA;;;;;;;;;;;;;;;;GAgBG;AACH,iFAwZG;kBAxdI,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"Alert.d.ts","sourceRoot":"","sources":["../../../src/components/feedback/Alert.jsx"],"names":[],"mappings":";AAIA,+EAwFG;kBA5Fe,OAAO"}
1
+ {"version":3,"file":"Alert.d.ts","sourceRoot":"","sources":["../../../src/components/feedback/Alert.jsx"],"names":[],"mappings":";AASA,+EA0FG;kBAnGe,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../../../src/components/feedback/Dialog.jsx"],"names":[],"mappings":";AAoCA,gFA0JG;kBA9LsC,OAAO"}
1
+ {"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../../../src/components/feedback/Dialog.jsx"],"names":[],"mappings":";AAUA,gFA6GG;kBAvH6C,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"Toast.d.ts","sourceRoot":"","sources":["../../../src/components/feedback/Toast.jsx"],"names":[],"mappings":";AAmDA,8EA4NG;AA6CH,2FAOC;AA6CD;;;;4CAkBC;;;;AAMD;;;;;;;;;;;;EAIC;kBA5Y+G,OAAO"}
1
+ {"version":3,"file":"Toast.d.ts","sourceRoot":"","sources":["../../../src/components/feedback/Toast.jsx"],"names":[],"mappings":";AA4DA,8EAgOG;AA+CH,2FAOC;AA6CD;;;;4CAkBC;;;;AAMD;;;;;;;;;;;;EAIC;kBA3Z+G,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"Sidebar.d.ts","sourceRoot":"","sources":["../../../src/components/navigation/Sidebar.jsx"],"names":[],"mappings":";AAiGA;;;;;;;;;;;;;;;;;GAiBG;AACH,iFA2kBG;kBAtrBI,OAAO"}
1
+ {"version":3,"file":"Sidebar.d.ts","sourceRoot":"","sources":["../../../src/components/navigation/Sidebar.jsx"],"names":[],"mappings":";AAkFA;;;;;;;;;;;;;;;;;GAiBG;AACH,iFAohBG;kBAhnBI,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../../../src/components/utility/Avatar.jsx"],"names":[],"mappings":";AAIA,gFA6GG;kBAjHe,OAAO"}
1
+ {"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../../../src/components/utility/Avatar.jsx"],"names":[],"mappings":";AAIA,gFAoHG;kBAxHe,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"Carousel.d.ts","sourceRoot":"","sources":["../../../src/components/utility/Carousel.jsx"],"names":[],"mappings":"AAIA,iFAsFE;;kBA1FgB,OAAO"}
1
+ {"version":3,"file":"Carousel.d.ts","sourceRoot":"","sources":["../../../src/components/utility/Carousel.jsx"],"names":[],"mappings":"AAUA,iFAoGE;;kBA9GgB,OAAO"}
@@ -1,9 +1,11 @@
1
1
  'use client';
2
2
  import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2, createForOfIteratorHelper as _createForOfIteratorHelper } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
3
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
4
- import React, { useState, useRef, useCallback, useEffect } from 'react';
4
+ import React, { useState, useRef, useCallback } from 'react';
5
5
  import { X, Menu } from 'lucide-react';
6
6
  import { cn } from '../../utils/cn.js';
7
+ import { useFocusTrap } from '../../hooks/useFocusTrap.js';
8
+ import { useScrollLock } from '../../hooks/useScrollLock.js';
7
9
 
8
10
  var _excluded = ["brand", "nav", "sidebarFooter", "topbar", "pageTitle", "linkAs", "children", "className"];
9
11
  // Extracted from procurementpro/components/app-shell.tsx (12 of 13 products hand-roll a shell).
@@ -105,23 +107,22 @@ var AppShell = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
105
107
  open = _useState2[0],
106
108
  setOpen = _useState2[1];
107
109
  var menuButton = useRef(null);
110
+ var drawer = useRef(null);
108
111
  var close = useCallback(function () {
109
112
  return setOpen(false);
110
113
  }, []);
111
- useEffect(function () {
112
- if (!open) return undefined;
113
- var onKey = function onKey(e) {
114
- if (e.key === 'Escape') {
115
- var _menuButton$current;
116
- setOpen(false);
117
- (_menuButton$current = menuButton.current) === null || _menuButton$current === void 0 || _menuButton$current.focus();
118
- }
119
- };
120
- document.addEventListener('keydown', onKey);
121
- return function () {
122
- return document.removeEventListener('keydown', onKey);
123
- };
124
- }, [open]);
114
+ // Mobile drawer is a modal dialog: focus moves in, Tab is trapped, Escape
115
+ // closes, focus returns to the menu button, and the page behind is locked.
116
+ useScrollLock(open);
117
+ useFocusTrap(drawer, {
118
+ active: open,
119
+ onEscape: function onEscape() {
120
+ var _menuButton$current;
121
+ close();
122
+ // Some browsers (Safari) don't focus a clicked button, so the opener may be <body>.
123
+ (_menuButton$current = menuButton.current) === null || _menuButton$current === void 0 || _menuButton$current.focus();
124
+ }
125
+ });
125
126
  var sidebar = jsxs(Fragment, {
126
127
  children: [jsxs("div", {
127
128
  className: "flex items-center justify-between px-5 pb-4 pt-5 text-white",
@@ -134,7 +135,8 @@ var AppShell = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
134
135
  onClick: close,
135
136
  "aria-label": "Close navigation",
136
137
  children: jsx(X, {
137
- className: "h-5 w-5"
138
+ className: "h-5 w-5",
139
+ "aria-hidden": "true"
138
140
  })
139
141
  })]
140
142
  }), jsx(NavList, {
@@ -165,8 +167,12 @@ var AppShell = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
165
167
  onClick: close,
166
168
  "aria-hidden": "true"
167
169
  }), jsx("aside", {
168
- className: "absolute inset-y-0 left-0 flex w-72 max-w-[85%] flex-col bg-shell",
169
- "aria-label": "Sidebar",
170
+ ref: drawer,
171
+ role: "dialog",
172
+ "aria-modal": "true",
173
+ "aria-label": "Navigation",
174
+ tabIndex: -1,
175
+ className: "absolute inset-y-0 left-0 flex w-72 max-w-[85%] flex-col bg-shell focus:outline-none",
170
176
  children: sidebar
171
177
  })]
172
178
  }), jsxs("div", {
@@ -1,9 +1,10 @@
1
1
  'use client';
2
2
  import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2, toConsumableArray as _toConsumableArray } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
3
  import { jsx, jsxs } from 'react/jsx-runtime';
4
- import { forwardRef, useState, useRef, useEffect, useLayoutEffect } from 'react';
4
+ import { forwardRef, useState, useRef, useEffect, useId, useLayoutEffect } from 'react';
5
5
  import { cn } from '../../utils/cn.js';
6
6
  import { useLatestRef } from '../../hooks/useLatestRef.js';
7
+ import { useReducedMotion } from '../../hooks/useReducedMotion.js';
7
8
 
8
9
  var _excluded = ["items", "allowMultiple", "defaultOpenIndexes", "onChange", "className", "headerClassName", "contentClassName", "chevronPosition", "chevronIcon", "bordered", "rounded", "size", "transitionDuration"];
9
10
  /**
@@ -65,15 +66,45 @@ var Accordion = /*#__PURE__*/forwardRef(function Accordion(_ref, ref) {
65
66
  useEffect(function () {
66
67
  if (typeof onChangeRef.current === "function") onChangeRef.current(openIndexes);
67
68
  }, [openIndexes, onChangeRef]);
68
- // Size panels from their measured content before paint. Done imperatively
69
- // (not via the style prop) so render never reads refs / the DOM.
69
+ // Unique per instance so two accordions on one page never share ids.
70
+ var uid = useId();
71
+ var reducedMotion = useReducedMotion();
72
+ var duration = reducedMotion ? 0 : transitionDuration;
73
+ // Which panels were open on the previous layout pass (null = first mount).
74
+ var prevOpenRef = useRef(null);
75
+ // Size panels imperatively (not via the style prop) so render never reads
76
+ // refs / the DOM. An open panel settles on `max-height: none` so content
77
+ // that grows after opening is never clipped; closed panels are `inert` so
78
+ // Tab cannot land inside collapsed content.
70
79
  useLayoutEffect(function () {
80
+ var prevOpen = prevOpenRef.current;
81
+ var timers = [];
71
82
  panelRefs.current.forEach(function (panelEl, idx) {
72
83
  if (!panelEl) return;
73
84
  var open = openIndexes.includes(idx);
74
- panelEl.style.maxHeight = open ? panelEl.scrollHeight + "px" : "0px";
85
+ var wasOpen = prevOpen ? prevOpen.includes(idx) : open;
86
+ if (open) panelEl.removeAttribute("inert");else panelEl.setAttribute("inert", "");
87
+ if (open === wasOpen || duration === 0) {
88
+ panelEl.style.maxHeight = open ? "none" : "0px";
89
+ return;
90
+ }
91
+ if (open) {
92
+ panelEl.style.maxHeight = panelEl.scrollHeight + "px";
93
+ timers.push(setTimeout(function () {
94
+ if (panelEl.getAttribute("inert") === null) panelEl.style.maxHeight = "none";
95
+ }, duration));
96
+ } else {
97
+ // Collapse from a concrete height; `none` -> 0 cannot be transitioned.
98
+ panelEl.style.maxHeight = panelEl.scrollHeight + "px";
99
+ void panelEl.offsetHeight; // force reflow so the transition starts
100
+ panelEl.style.maxHeight = "0px";
101
+ }
75
102
  });
76
- }, [openIndexes, items]);
103
+ prevOpenRef.current = openIndexes;
104
+ return function () {
105
+ return timers.forEach(clearTimeout);
106
+ };
107
+ }, [openIndexes, items, duration]);
77
108
  var isOpen = function isOpen(index) {
78
109
  return openIndexes.includes(index);
79
110
  };
@@ -166,8 +197,8 @@ var Accordion = /*#__PURE__*/forwardRef(function Accordion(_ref, ref) {
166
197
  var _item$id;
167
198
  var id = (_item$id = item.id) !== null && _item$id !== void 0 ? _item$id : index;
168
199
  var open = isOpen(index);
169
- var headerId = "accordion-header-".concat(id);
170
- var panelId = "accordion-panel-".concat(id);
200
+ var headerId = "".concat(uid, "accordion-header-").concat(id);
201
+ var panelId = "".concat(uid, "accordion-panel-").concat(id);
171
202
  var leftIconEl = renderLeftIcon(item, index);
172
203
  return jsxs("div", {
173
204
  className: "bg-white",
@@ -187,7 +218,7 @@ var Accordion = /*#__PURE__*/forwardRef(function Accordion(_ref, ref) {
187
218
  return handleHeaderKeyDown(e, index);
188
219
  },
189
220
  type: "button",
190
- className: "w-full flex items-center ".concat(sizeMap[size].header, " justify-between focus:outline-none focus:ring-2 focus:ring-indigo-500 ").concat(headerClassName, " ").concat(item.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"),
221
+ className: "w-full flex items-center ".concat(sizeMap[size].header, " justify-between focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 ").concat(headerClassName, " ").concat(item.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"),
191
222
  children: jsxs("div", {
192
223
  className: "flex items-center gap-3 w-full",
193
224
  children: [chevronPosition === "left" ? jsx("span", {
@@ -242,7 +273,7 @@ var Accordion = /*#__PURE__*/forwardRef(function Accordion(_ref, ref) {
242
273
  return panelRefs.current[index] = el;
243
274
  },
244
275
  style: {
245
- transition: "max-height ".concat(transitionDuration, "ms ease"),
276
+ transition: duration ? "max-height ".concat(duration, "ms ease") : "none",
246
277
  overflow: "hidden"
247
278
  },
248
279
  className: "".concat(contentClassName, " ").concat(sizeMap[size].content),
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
- import { forwardRef, useMemo, useState } from 'react';
4
+ import { forwardRef, useId, useMemo, useState } from 'react';
5
5
  import { cn } from '../../utils/cn.js';
6
6
 
7
7
  var _excluded = ["value", "defaultValue", "onChange", "swatches", "showAlpha", "size", "disabled", "className", "label", "id"];
@@ -150,6 +150,12 @@ var ColorPicker = /*#__PURE__*/forwardRef(function ColorPicker(props, ref) {
150
150
  label = _props$label === void 0 ? "Pick a color" : _props$label,
151
151
  id = props.id,
152
152
  rest = _objectWithoutProperties(props, _excluded);
153
+ // The visible <label> must point at a real control: the text value input
154
+ // takes the caller's `id` (or a generated one).
155
+ var autoId = useId();
156
+ var inputId = id !== null && id !== void 0 ? id : "".concat(autoId, "color-input");
157
+ var labelId = "".concat(inputId, "-label");
158
+ var valueLabelId = "".concat(inputId, "-value-label");
153
159
  var parsedControlled = useMemo(function () {
154
160
  return parseColor(value !== null && value !== void 0 ? value : null);
155
161
  }, [value]);
@@ -212,8 +218,9 @@ var ColorPicker = /*#__PURE__*/forwardRef(function ColorPicker(props, ref) {
212
218
  className: cn("inline-block", className)
213
219
  }, rest), {}, {
214
220
  children: [jsx("label", {
221
+ id: labelId,
215
222
  className: "block mb-2 ".concat(sizeMap.font),
216
- htmlFor: id,
223
+ htmlFor: inputId,
217
224
  children: label
218
225
  }), jsxs("div", {
219
226
  className: "flex ".concat(sizeMap.gap, " items-start flex-col"),
@@ -234,7 +241,7 @@ var ColorPicker = /*#__PURE__*/forwardRef(function ColorPicker(props, ref) {
234
241
  onClick: function onClick() {
235
242
  return pushChange(c);
236
243
  },
237
- className: "rounded-md border border-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-indigo-500 ".concat(sizeMap.swatch, " overflow-hidden"),
244
+ className: "rounded-md border border-gray-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-primary-500 ".concat(sizeMap.swatch, " overflow-hidden"),
238
245
  style: {
239
246
  background: "rgba(".concat(c.r, ",").concat(c.g, ",").concat(c.b, ",").concat(c.a, ")")
240
247
  },
@@ -274,9 +281,14 @@ var ColorPicker = /*#__PURE__*/forwardRef(function ColorPicker(props, ref) {
274
281
  },
275
282
  className: "w-10 h-10 p-0 border-none bg-transparent",
276
283
  "aria-label": "Native color input"
277
- }), jsx("div", {
284
+ }), jsxs("div", {
278
285
  className: "flex-1",
279
- children: jsx("input", {
286
+ children: [jsx("span", {
287
+ id: valueLabelId,
288
+ className: "sr-only",
289
+ children: "Color value"
290
+ }), jsx("input", {
291
+ id: inputId,
280
292
  type: "text",
281
293
  disabled: disabled,
282
294
  value: showAlpha ? rgbaToString(internal) : rgbaToHex(internal, showAlpha),
@@ -292,8 +304,8 @@ var ColorPicker = /*#__PURE__*/forwardRef(function ColorPicker(props, ref) {
292
304
  }
293
305
  },
294
306
  className: "w-full rounded-md border border-gray-200 px-2 py-1 font-mono",
295
- "aria-label": "Color value"
296
- })
307
+ "aria-labelledby": "".concat(labelId, " ").concat(valueLabelId)
308
+ })]
297
309
  })]
298
310
  }), jsx("div", {
299
311
  className: "mt-3 space-y-2",