@dreamtree-org/twreact-ui 1.3.3 → 1.3.5

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 (53) hide show
  1. package/README.md +13 -6
  2. package/ai-skills/dreamtree-ui.md +5 -1
  3. package/dist/ai-schema.json +46 -3
  4. package/dist/components/core/Button.d.ts.map +1 -1
  5. package/dist/components/core/Radio.d.ts.map +1 -1
  6. package/dist/components/core/Select.d.ts.map +1 -1
  7. package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
  8. package/dist/components/core/Table/TableRow.d.ts.map +1 -1
  9. package/dist/components/core/Table/helpers.d.ts +12 -0
  10. package/dist/components/core/Table/helpers.d.ts.map +1 -1
  11. package/dist/components/feedback/Dialog.d.ts.map +1 -1
  12. package/dist/components/feedback/Drawer.d.ts.map +1 -1
  13. package/dist/components/navigation/FootNav.d.ts.map +1 -1
  14. package/dist/components/utility/Badge.d.ts.map +1 -1
  15. package/dist/components/utility/Stepper.d.ts.map +1 -1
  16. package/dist/esm/components/blocks/StatusPill.js +1 -1
  17. package/dist/esm/components/core/Button.js +23 -6
  18. package/dist/esm/components/core/Radio.js +3 -2
  19. package/dist/esm/components/core/Select.js +12 -2
  20. package/dist/esm/components/core/Table/ActionMenu.js +5 -5
  21. package/dist/esm/components/core/Table/ColumnMenu.js +1 -1
  22. package/dist/esm/components/core/Table/FieldInput.js +5 -5
  23. package/dist/esm/components/core/Table/MobileCard.js +9 -10
  24. package/dist/esm/components/core/Table/MobileFilters.js +1 -1
  25. package/dist/esm/components/core/Table/Pagination.js +1 -1
  26. package/dist/esm/components/core/Table/Table.js +12 -12
  27. package/dist/esm/components/core/Table/TableRow.js +10 -11
  28. package/dist/esm/components/core/Table/helpers.js +16 -1
  29. package/dist/esm/components/feedback/Dialog.js +4 -2
  30. package/dist/esm/components/feedback/Drawer.js +39 -10
  31. package/dist/esm/components/navigation/Dropdown.js +1 -1
  32. package/dist/esm/components/navigation/FootNav.js +41 -14
  33. package/dist/esm/components/navigation/Navbar.js +21 -21
  34. package/dist/esm/components/navigation/Sidebar.js +12 -12
  35. package/dist/esm/components/utility/Badge.js +1 -0
  36. package/dist/esm/components/utility/Card.js +5 -5
  37. package/dist/esm/components/utility/Stepper.js +5 -2
  38. package/dist/esm/hooks/useSwipeToClose.js +66 -0
  39. package/dist/esm/utils/touchTarget.js +6 -0
  40. package/dist/hooks/useSwipeToClose.d.ts +24 -0
  41. package/dist/hooks/useSwipeToClose.d.ts.map +1 -0
  42. package/dist/index.css +1 -1
  43. package/dist/index.esm.css +1 -1
  44. package/dist/index.esm.js +287 -121
  45. package/dist/index.js +287 -121
  46. package/dist/types/index.d.ts +29 -2
  47. package/dist/types/index.d.ts.map +1 -1
  48. package/dist/utils/touchTarget.d.ts +2 -0
  49. package/dist/utils/touchTarget.d.ts.map +1 -0
  50. package/doc/README.md +1 -1
  51. package/mcp/README.md +1 -1
  52. package/mcp/catalog.snapshot.json +60 -30
  53. package/package.json +4 -4
@@ -21,11 +21,11 @@ var _excluded = ["data", "columns", "sortable", "filterable", "selectable", "pag
21
21
  var DEFAULT_DATA = [];
22
22
  var DEFAULT_COLUMNS = [];
23
23
  var DEFAULT_THEME = {
24
- stripedColors: ["bg-[#ffffff]", "bg-[#f7fafc]"],
25
- rowHover: "bg-gray-50",
26
- accentColor: "bg-gray-50",
27
- menuBg: "bg-white",
28
- menuItemHover: "hover:bg-gray-50"
24
+ stripedColors: ["bg-surface", "bg-background"],
25
+ rowHover: "bg-background",
26
+ accentColor: "bg-background",
27
+ menuBg: "bg-surface",
28
+ menuItemHover: "hover:bg-background"
29
29
  };
30
30
  var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
31
31
  var _validationErrors$;
@@ -1239,7 +1239,7 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
1239
1239
  onClick: handleClearChanges,
1240
1240
  disabled: isSaving,
1241
1241
  title: "Discard all pending modifications",
1242
- className: "px-4 py-2 font-medium rounded-lg text-sm flex items-center gap-2 transition-all border border-primary-300 text-primary-700 bg-white hover:bg-primary-50 active:bg-primary-100 cursor-pointer shadow-sm disabled:opacity-50",
1242
+ className: "px-4 py-2 font-medium rounded-lg text-sm flex items-center gap-2 transition-all border border-primary-300 text-primary-700 bg-surface hover:bg-primary-50 dark:text-primary-300 dark:border-primary-700 dark:hover:bg-primary-900/40 active:bg-primary-100 cursor-pointer shadow-sm disabled:opacity-50",
1243
1243
  children: [jsx(X, {
1244
1244
  className: "w-4 h-4 text-primary-600"
1245
1245
  }), jsx("span", {
@@ -1283,7 +1283,7 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
1283
1283
  onKeyDown: onGlobalKeyDown
1284
1284
  }), jsx("button", {
1285
1285
  onClick: applyGlobalSearch,
1286
- className: "absolute right-2 top-1/2 transform -translate-y-1/2 p-2 rounded-lg hover:bg-gray-100",
1286
+ className: "absolute right-2 top-1/2 transform -translate-y-1/2 p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800",
1287
1287
  title: "Search",
1288
1288
  children: jsx(Search, {
1289
1289
  className: "h-4 w-4 text-primary-400"
@@ -1294,7 +1294,7 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
1294
1294
  setSearchInput("");
1295
1295
  handleFilter("global", "");
1296
1296
  },
1297
- className: "whitespace-nowrap rounded-lg md:rounded-md border border-gray-300 px-4 py-3 md:py-2 text-sm hover:bg-gray-100 w-full sm:w-auto",
1297
+ className: "whitespace-nowrap rounded-lg md:rounded-md border border-gray-300 px-4 py-3 md:py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-800 w-full sm:w-auto",
1298
1298
  children: "Clear"
1299
1299
  })]
1300
1300
  })
@@ -1318,7 +1318,7 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
1318
1318
  }), !isMobileView && jsx("div", {
1319
1319
  className: "overflow-x-auto overflow-y-visible",
1320
1320
  children: jsxs("table", _objectSpread2(_objectSpread2({
1321
- className: cn("min-w-full divide-y divide-gray-200", className)
1321
+ className: cn("min-w-full divide-y divide-line", className)
1322
1322
  }, props), {}, {
1323
1323
  children: [jsxs("thead", {
1324
1324
  className: safeTheme.accentColor,
@@ -1340,7 +1340,7 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
1340
1340
  var _column$rules;
1341
1341
  return jsx("th", {
1342
1342
  className: cn("px-6 py-3 text-left text-xs font-medium text-primary-700 uppercase tracking-wider", {
1343
- "cursor-pointer hover:bg-gray-100": sortable && column.sortable !== false
1343
+ "cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800": sortable && column.sortable !== false
1344
1344
  }),
1345
1345
  onClick: function onClick() {
1346
1346
  return column.sortable !== false && handleSort(column.key);
@@ -1384,7 +1384,7 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
1384
1384
  return !s;
1385
1385
  });
1386
1386
  },
1387
- className: "p-1 rounded hover:bg-gray-100",
1387
+ className: "p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-800",
1388
1388
  children: jsx(MoreVertical, {
1389
1389
  className: "h-4 w-4"
1390
1390
  })
@@ -1420,7 +1420,7 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
1420
1420
  })]
1421
1421
  })]
1422
1422
  }), jsx("tbody", {
1423
- className: "divide-y divide-gray-200",
1423
+ className: "divide-y divide-line",
1424
1424
  children: loading ? jsx("tr", {
1425
1425
  children: jsx("td", {
1426
1426
  colSpan: visibleCount,
@@ -5,7 +5,7 @@ import React from 'react';
5
5
  import { cn } from '../../../utils/cn.js';
6
6
  import { Trash2, MoreVertical } from 'lucide-react';
7
7
  import ActionMenu from './ActionMenu.js';
8
- import { getRowKey, resolveActions, rowHasDetails, getActionLabelText } from './helpers.js';
8
+ import { getRowKey, resolveActions, rowHasDetails, getActionLabelText, getStripeProps } from './helpers.js';
9
9
 
10
10
  /**
11
11
  * Desktop table row component
@@ -86,6 +86,7 @@ function TableRow(_ref) {
86
86
  var safeExtraRowClass = typeof extraRowClass === "string" ? extraRowClass.trim() : "";
87
87
  var stripeColors = theme === null || theme === void 0 ? void 0 : theme.stripedColors;
88
88
  var stripeBg = stripedRows && !isSelected && Array.isArray(stripeColors) && stripeColors.length > 0 ? stripeColors[globalIndex % stripeColors.length] : undefined;
89
+ var stripeProps = getStripeProps(stripeBg);
89
90
  var rowKey = isNewRow ? row._key : key;
90
91
  var isRowActive = interactive && (activeCell === null || activeCell === void 0 ? void 0 : activeCell.rowKey) === rowKey;
91
92
  var effectiveRow = React.useMemo(function () {
@@ -94,10 +95,8 @@ function TableRow(_ref) {
94
95
  }, [interactive, pendingEdits, rowKey, row]);
95
96
  return jsxs(React.Fragment, {
96
97
  children: [jsxs("tr", {
97
- style: stripeBg ? {
98
- backgroundColor: stripeBg
99
- } : undefined,
100
- className: cn(theme !== null && theme !== void 0 && theme.rowHover ? ["hover:" + theme.rowHover] : [], {
98
+ style: stripeProps.style,
99
+ className: cn(stripeProps.className, theme !== null && theme !== void 0 && theme.rowHover ? ["hover:" + theme.rowHover] : [], {
101
100
  "cursor-pointer": !!onRowClick,
102
101
  "bg-primary-50": isSelected,
103
102
  "bg-primary-50/20": isRowActive && !isSelected,
@@ -116,7 +115,7 @@ function TableRow(_ref) {
116
115
  },
117
116
  "aria-expanded": isExpanded,
118
117
  "aria-label": isExpanded ? "Collapse row details" : "Expand row details",
119
- className: "p-1 rounded hover:bg-gray-100",
118
+ className: "p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-800",
120
119
  children: isExpanded ? "▾" : "▸"
121
120
  })
122
121
  }), showSerial && jsx("td", {
@@ -152,9 +151,9 @@ function TableRow(_ref) {
152
151
  title: isCellInvalid ? "Field \"".concat(column.label || column.key, "\" is required or invalid") : undefined,
153
152
  className: cn("px-6 py-4 text-sm transition-all", wrapCell ? "whitespace-normal break-words" : "whitespace-nowrap", {
154
153
  "ring-2 ring-error-500 ring-inset bg-error-50/40 relative z-10": isCellInvalid && !isCellEditing,
155
- "ring-2 ring-error-600 ring-inset bg-white p-1 z-20 relative": isCellEditing && isCellInvalid,
154
+ "ring-2 ring-error-600 ring-inset bg-surface p-1 z-20 relative": isCellEditing && isCellInvalid,
156
155
  "ring-2 ring-primary-500 ring-inset bg-primary-50/50 relative z-10": isCellActive && !isCellEditing && !isCellInvalid,
157
- "ring-2 ring-primary-600 ring-inset bg-white p-1 z-20 relative": isCellEditing && !isCellInvalid
156
+ "ring-2 ring-primary-600 ring-inset bg-surface p-1 z-20 relative": isCellEditing && !isCellInvalid
158
157
  }, safeExtraCellClass),
159
158
  onClick: function onClick() {
160
159
  if (interactive && onCellClick) {
@@ -201,7 +200,7 @@ function TableRow(_ref) {
201
200
  if (action.disabled) return;
202
201
  handleOnAction(action, row);
203
202
  },
204
- className: cn("p-1 rounded", action.disabled ? "opacity-50 cursor-not-allowed" : "hover:bg-gray-100"),
203
+ className: cn("p-1 rounded", action.disabled ? "opacity-50 cursor-not-allowed" : "hover:bg-gray-100 dark:hover:bg-gray-800"),
205
204
  children: action.render ? action.render(row) : (_action$icon = action.icon) !== null && _action$icon !== void 0 ? _action$icon : jsx("span", {
206
205
  className: "text-xs",
207
206
  children: actionLabel
@@ -217,7 +216,7 @@ function TableRow(_ref) {
217
216
  return toggleActions(e, actionCellKey, row);
218
217
  },
219
218
  "aria-expanded": activeActionRowKey === actionCellKey,
220
- className: "p-1 rounded hover:bg-gray-100",
219
+ className: "p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-800",
221
220
  title: "Actions",
222
221
  children: jsx(MoreVertical, {
223
222
  className: "h-4 w-4"
@@ -241,7 +240,7 @@ function TableRow(_ref) {
241
240
  colSpan: visibleCount,
242
241
  className: cn(_defineProperty(_defineProperty({
243
242
  "px-6 py-4": true
244
- }, (_theme$accentColor = theme === null || theme === void 0 ? void 0 : theme.accentColor) !== null && _theme$accentColor !== void 0 ? _theme$accentColor : "bg-gray-50", true), (_theme$rowHover = theme === null || theme === void 0 ? void 0 : theme.rowHover) !== null && _theme$rowHover !== void 0 ? _theme$rowHover : "bg-gray-50", true)),
243
+ }, (_theme$accentColor = theme === null || theme === void 0 ? void 0 : theme.accentColor) !== null && _theme$accentColor !== void 0 ? _theme$accentColor : "bg-background", true), (_theme$rowHover = theme === null || theme === void 0 ? void 0 : theme.rowHover) !== null && _theme$rowHover !== void 0 ? _theme$rowHover : "bg-background", true)),
245
244
  children: jsx(DetailsComponent, {
246
245
  row: row,
247
246
  index: globalIndex
@@ -10,6 +10,21 @@ var getRowKey = function getRowKey(row, globalIndex) {
10
10
  if (row._id !== undefined && row._id !== null) return String(row._id);
11
11
  return String(globalIndex);
12
12
  };
13
+ /**
14
+ * A `stripedColors` entry is either a CSS colour ("#f7fafc", "rgb(...)") applied as an
15
+ * inline background, or a Tailwind class ("bg-surface", "dark:bg-gray-900") applied as a
16
+ * className. Returns the props to spread onto the striped element.
17
+ */
18
+ var getStripeProps = function getStripeProps(stripe) {
19
+ if (!stripe) return {};
20
+ return /(^|[\s:])bg-/.test(stripe) ? {
21
+ className: stripe
22
+ } : {
23
+ style: {
24
+ backgroundColor: stripe
25
+ }
26
+ };
27
+ };
13
28
  /**
14
29
  * Resolve a value that may be supplied directly or as a per-row producer.
15
30
  * Used for an action's `label`, `icon`, `hidden` and `disabled`.
@@ -121,4 +136,4 @@ var resolveActions = function resolveActions(actions, row, index) {
121
136
  };
122
137
  };
123
138
 
124
- export { getActionLabelText, getRowKey, mergeDefaultActions, resolveActions, rowHasDetails };
139
+ export { getActionLabelText, getRowKey, getStripeProps, mergeDefaultActions, resolveActions, rowHasDetails };
@@ -6,6 +6,7 @@ import { createPortal } from 'react-dom';
6
6
  import { cn } from '../../utils/cn.js';
7
7
  import { X } from 'lucide-react';
8
8
  import { useLatestRef } from '../../hooks/useLatestRef.js';
9
+ import { TOUCH_TARGET } from '../../utils/touchTarget.js';
9
10
 
10
11
  var _excluded = ["isOpen", "onClose", "title", "children", "size", "dismissible", "showCloseButton", "footer", "className", "onOpen"],
11
12
  _excluded2 = ["children", "className"],
@@ -141,11 +142,12 @@ var Dialog = /*#__PURE__*/React.forwardRef(function (_ref, _ref3) {
141
142
  children: title
142
143
  }), showCloseButton && jsx("button", {
143
144
  type: "button",
144
- className: "rounded-md p-1 text-primary-400 hover:text-primary-600 hover:bg-gray-100",
145
+ className: cn('inline-flex items-center justify-center rounded-md p-1 text-primary-400 hover:text-primary-600 hover:bg-gray-100', TOUCH_TARGET),
145
146
  onClick: onClose,
146
147
  "aria-label": "Close dialog",
147
148
  children: jsx(X, {
148
- className: "h-5 w-5"
149
+ className: "h-5 w-5",
150
+ "aria-hidden": "true"
149
151
  })
150
152
  })]
151
153
  }), jsx("div", {
@@ -8,8 +8,10 @@ import { cn } from '../../utils/cn.js';
8
8
  import { setRefs } from '../../utils/position.js';
9
9
  import { useFocusTrap } from '../../hooks/useFocusTrap.js';
10
10
  import { useScrollLock } from '../../hooks/useScrollLock.js';
11
+ import { useSwipeToClose } from '../../hooks/useSwipeToClose.js';
12
+ import { TOUCH_TARGET } from '../../utils/touchTarget.js';
11
13
 
12
- var _excluded = ["isOpen", "onClose", "title", "description", "children", "placement", "size", "dismissible", "showCloseButton", "footer", "initialFocusRef", "className"],
14
+ var _excluded = ["isOpen", "onClose", "title", "description", "children", "placement", "size", "dismissible", "showCloseButton", "footer", "initialFocusRef", "handle", "swipeToClose", "className", "style"],
13
15
  _excluded2 = ["className"],
14
16
  _excluded3 = ["className"],
15
17
  _excluded4 = ["className"];
@@ -17,7 +19,8 @@ var PLACEMENT_CLASSES = {
17
19
  right: "inset-y-0 right-0 h-full w-full border-l",
18
20
  left: "inset-y-0 left-0 h-full w-full border-r",
19
21
  top: "inset-x-0 top-0 w-full border-b",
20
- bottom: "inset-x-0 bottom-0 w-full border-t"
22
+ // Bottom sheet: rounded top and room for the home indicator (safe area).
23
+ bottom: "inset-x-0 bottom-0 w-full overflow-hidden rounded-t-2xl border-t pb-[env(safe-area-inset-bottom)]"
21
24
  };
22
25
  var SIDE_SIZES = {
23
26
  sm: "max-w-xs",
@@ -40,7 +43,7 @@ var CloseButton = function CloseButton(_ref) {
40
43
  type: "button",
41
44
  onClick: onClose,
42
45
  "aria-label": "Close drawer",
43
- className: cn("rounded-md p-1 text-gray-500 hover:bg-gray-100 hover:text-gray-700 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2", "dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-200 dark:focus:ring-offset-gray-900", className),
46
+ className: cn("inline-flex items-center justify-center rounded-md p-1 text-gray-500 hover:bg-gray-100 hover:text-gray-700 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2", "dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-200 dark:focus:ring-offset-gray-900", TOUCH_TARGET, className),
44
47
  children: jsx(X, {
45
48
  className: "h-5 w-5",
46
49
  "aria-hidden": "true"
@@ -63,7 +66,11 @@ var Drawer = /*#__PURE__*/React.forwardRef(function (_ref2, _ref3) {
63
66
  showCloseButton = _ref2$showCloseButton === void 0 ? true : _ref2$showCloseButton,
64
67
  footer = _ref2.footer,
65
68
  initialFocusRef = _ref2.initialFocusRef,
69
+ handle = _ref2.handle,
70
+ _ref2$swipeToClose = _ref2.swipeToClose,
71
+ swipeToClose = _ref2$swipeToClose === void 0 ? false : _ref2$swipeToClose,
66
72
  className = _ref2.className,
73
+ style = _ref2.style,
67
74
  props = _objectWithoutProperties(_ref2, _excluded);
68
75
  var panelRef = useRef(null);
69
76
  var titleId = "drawer-title-".concat(useId());
@@ -73,6 +80,17 @@ var Drawer = /*#__PURE__*/React.forwardRef(function (_ref2, _ref3) {
73
80
  // Without title/description/footer the children are the panel content, so
74
81
  // Drawer.Header / Drawer.Body / Drawer.Footer compose without double padding.
75
82
  var composed = !title && !description && !footer;
83
+ var showHandle = handle !== null && handle !== void 0 ? handle : side === "bottom";
84
+ var swipe = useSwipeToClose({
85
+ enabled: swipeToClose && side === "bottom" && dismissible,
86
+ onClose: onClose
87
+ });
88
+ // The grab zone (handle + header) starts a swipe; the scrolling body never does.
89
+ var grabProps = swipeToClose && side === "bottom" && dismissible ? _objectSpread2(_objectSpread2({}, swipe.dragProps), {}, {
90
+ className: "touch-none cursor-grab"
91
+ }) : {
92
+ className: ""
93
+ };
76
94
  useScrollLock(isOpen);
77
95
  useFocusTrap(panelRef, {
78
96
  active: isOpen,
@@ -91,7 +109,7 @@ var Drawer = /*#__PURE__*/React.forwardRef(function (_ref2, _ref3) {
91
109
  onClick: function onClick() {
92
110
  return dismissible && (onClose === null || onClose === void 0 ? void 0 : onClose());
93
111
  }
94
- }), jsx("div", _objectSpread2(_objectSpread2({
112
+ }), jsxs("div", _objectSpread2(_objectSpread2({
95
113
  ref: function ref(node) {
96
114
  return setRefs(node, panelRef, _ref3);
97
115
  },
@@ -101,16 +119,27 @@ var Drawer = /*#__PURE__*/React.forwardRef(function (_ref2, _ref3) {
101
119
  "aria-describedby": description ? descriptionId : undefined,
102
120
  tabIndex: -1,
103
121
  "data-placement": side,
104
- className: cn("absolute flex flex-col border-gray-200 bg-white text-gray-900 shadow-xl focus:outline-none", "dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100", "animate-fade-in motion-reduce:animate-none", PLACEMENT_CLASSES[side], (isEdge ? EDGE_SIZES : SIDE_SIZES)[size] || (isEdge ? EDGE_SIZES.md : SIDE_SIZES.md), className)
122
+ className: cn("absolute flex flex-col border-gray-200 bg-white text-gray-900 shadow-xl focus:outline-none", "dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100", "animate-fade-in motion-reduce:animate-none", PLACEMENT_CLASSES[side], (isEdge ? EDGE_SIZES : SIDE_SIZES)[size] || (isEdge ? EDGE_SIZES.md : SIDE_SIZES.md), !swipe.dragging && "transition-transform duration-200 ease-out motion-reduce:transition-none", className),
123
+ style: swipe.offset ? _objectSpread2(_objectSpread2({}, style), {}, {
124
+ transform: "translateY(".concat(swipe.offset, "px)")
125
+ }) : style
105
126
  }, props), {}, {
106
- children: composed ? jsxs(Fragment, {
127
+ children: [showHandle && jsx("div", _objectSpread2(_objectSpread2({
128
+ "aria-hidden": "true",
129
+ "data-testid": "drawer-handle"
130
+ }, grabProps), {}, {
131
+ className: cn("flex shrink-0 justify-center pb-1 pt-3", grabProps.className),
132
+ children: jsx("span", {
133
+ className: "h-1.5 w-10 rounded-full bg-gray-300 dark:bg-gray-600"
134
+ })
135
+ })), composed ? jsxs(Fragment, {
107
136
  children: [showCloseButton && jsx(CloseButton, {
108
137
  onClose: onClose,
109
138
  className: "absolute right-3 top-3"
110
139
  }), children]
111
140
  }) : jsxs(Fragment, {
112
- children: [jsxs("div", {
113
- className: "flex items-start justify-between gap-4 border-b border-gray-200 px-6 py-4 dark:border-gray-700",
141
+ children: [jsxs("div", _objectSpread2(_objectSpread2({}, grabProps), {}, {
142
+ className: cn("flex items-start justify-between gap-4 border-b border-gray-200 px-6 py-4 dark:border-gray-700", showHandle && "pt-2", grabProps.className),
114
143
  children: [jsxs("div", {
115
144
  className: "min-w-0",
116
145
  children: [title && jsx("h2", {
@@ -125,14 +154,14 @@ var Drawer = /*#__PURE__*/React.forwardRef(function (_ref2, _ref3) {
125
154
  }), showCloseButton && jsx(CloseButton, {
126
155
  onClose: onClose
127
156
  })]
128
- }), jsx("div", {
157
+ })), jsx("div", {
129
158
  className: "min-h-0 flex-1 overflow-y-auto px-6 py-4",
130
159
  children: children
131
160
  }), footer && jsx("div", {
132
161
  className: "flex items-center justify-end gap-3 border-t border-gray-200 px-6 py-4 dark:border-gray-700",
133
162
  children: footer
134
163
  })]
135
- })
164
+ })]
136
165
  }))]
137
166
  }), document.body);
138
167
  });
@@ -44,7 +44,7 @@ var Dropdown = function Dropdown(_ref) {
44
44
  },
45
45
  children: trigger
46
46
  }), isOpen && jsx("div", {
47
- className: "absolute z-50 bg-white border border-gray-200 rounded-md shadow-lg ".concat(placementClasses[placement], " min-w-48"),
47
+ className: "absolute z-50 bg-surface text-foreground border border-line rounded-md shadow-lg ".concat(placementClasses[placement], " min-w-48"),
48
48
  children: children
49
49
  })]
50
50
  }));
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
2
+ import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2, slicedToArray as _slicedToArray } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
3
  import { jsx, jsxs } from 'react/jsx-runtime';
4
4
  import React from 'react';
5
5
  import { cn } from '../../utils/cn.js';
@@ -8,11 +8,28 @@ var _excluded = ["items", "className"];
8
8
  var hasBadge = function hasBadge(badge) {
9
9
  return badge === 0 || Boolean(badge);
10
10
  };
11
- var FootNav = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
12
- var _ref$items = _ref.items,
13
- items = _ref$items === void 0 ? [] : _ref$items,
14
- className = _ref.className,
15
- props = _objectWithoutProperties(_ref, _excluded);
11
+ // Only aria-* and data-* item keys reach the DOM (e.g. aria-haspopup="dialog"
12
+ // on an item that opens a sheet); the rest of the item is data, not attributes.
13
+ var passthrough = function passthrough(item) {
14
+ return Object.fromEntries(Object.entries(item).filter(function (_ref) {
15
+ var _ref2 = _slicedToArray(_ref, 1),
16
+ key = _ref2[0];
17
+ return /^(aria|data)-/.test(key);
18
+ }));
19
+ };
20
+ var Badge = function Badge(_ref3) {
21
+ var badge = _ref3.badge;
22
+ return jsx("span", {
23
+ className: "absolute -top-1.5 left-full -ml-2 flex h-4 min-w-4 items-center justify-center rounded-full bg-error-600 px-1 text-micro font-semibold text-white",
24
+ "data-slot": "badge",
25
+ children: badge
26
+ });
27
+ };
28
+ var FootNav = /*#__PURE__*/React.forwardRef(function (_ref4, ref) {
29
+ var _ref4$items = _ref4.items,
30
+ items = _ref4$items === void 0 ? [] : _ref4$items,
31
+ className = _ref4.className,
32
+ props = _objectWithoutProperties(_ref4, _excluded);
16
33
  return jsx("nav", _objectSpread2(_objectSpread2({
17
34
  ref: ref,
18
35
  className: cn('fixed bottom-0 left-0 right-0 bg-surface border-t border-line px-2 py-2 md:hidden', className)
@@ -21,27 +38,37 @@ var FootNav = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
21
38
  className: "flex items-stretch justify-around gap-1",
22
39
  children: items.map(function (item, index) {
23
40
  var _item$id;
24
- return jsxs("button", {
41
+ var isAction = item.variant === 'action';
42
+ return jsxs("button", _objectSpread2(_objectSpread2({
25
43
  type: "button",
26
44
  "aria-current": item.active ? 'page' : undefined,
27
- className: cn('relative flex min-w-0 flex-1 flex-col items-center gap-1 rounded-md px-1 py-2 text-xs transition-colors', 'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-1 motion-reduce:transition-none', item.active ? 'bg-primary-50 font-semibold text-primary-700 dark:bg-primary-900/40 dark:text-primary-300' : 'font-medium text-muted hover:bg-gray-100 hover:text-foreground dark:hover:bg-gray-800'),
45
+ "data-variant": isAction ? 'action' : undefined
46
+ }, passthrough(item)), {}, {
47
+ className: cn('relative flex min-w-0 flex-1 flex-col items-center gap-1 rounded-md px-1 py-2 text-xs transition-colors', 'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-1 motion-reduce:transition-none', isAction ? 'group justify-start py-0 font-medium text-muted' : item.active ? 'bg-primary-50 font-semibold text-primary-700 dark:bg-primary-900/40 dark:text-primary-300' : 'font-medium text-muted hover:bg-gray-100 hover:text-foreground dark:hover:bg-gray-800'),
28
48
  onClick: function onClick() {
29
49
  var _item$onClick;
30
50
  return (_item$onClick = item.onClick) === null || _item$onClick === void 0 ? void 0 : _item$onClick.call(item, item);
31
51
  },
32
- children: [jsxs("span", {
52
+ children: [isAction ?
53
+ // Raised primary circle (FAB): 56px, lifted above the bar and
54
+ // ringed in the surface colour so it reads as cut out of the bar.
55
+ jsxs("span", {
56
+ className: "relative -mt-7 inline-flex h-14 w-14 items-center justify-center rounded-full bg-primary-600 text-2xl text-white shadow-lg ring-4 ring-surface transition-colors group-hover:bg-primary-700 motion-reduce:transition-none",
57
+ "data-slot": "icon",
58
+ children: [item.icon, hasBadge(item.badge) && jsx(Badge, {
59
+ badge: item.badge
60
+ })]
61
+ }) : jsxs("span", {
33
62
  className: "relative inline-flex text-lg",
34
63
  "data-slot": "icon",
35
- children: [item.icon, hasBadge(item.badge) && jsx("span", {
36
- className: "absolute -top-1.5 left-full -ml-2 flex h-4 min-w-4 items-center justify-center rounded-full bg-error-600 px-1 text-micro font-semibold text-white",
37
- "data-slot": "badge",
38
- children: item.badge
64
+ children: [item.icon, hasBadge(item.badge) && jsx(Badge, {
65
+ badge: item.badge
39
66
  })]
40
67
  }), jsx("span", {
41
68
  className: "block max-w-full truncate",
42
69
  children: item.label
43
70
  })]
44
- }, (_item$id = item.id) !== null && _item$id !== void 0 ? _item$id : index);
71
+ }), (_item$id = item.id) !== null && _item$id !== void 0 ? _item$id : index);
45
72
  })
46
73
  })
47
74
  }));
@@ -67,7 +67,7 @@ var NotificationsDropdown = function NotificationsDropdown(_ref) {
67
67
  // For simplicity, shows notifications in the dropdown, can be expanded
68
68
  return jsx(Dropdown, {
69
69
  trigger: jsxs("button", {
70
- className: "relative rounded-md p-2 text-primary-400 hover:text-primary-500 hover:bg-gray-100",
70
+ className: "relative rounded-md p-2 text-primary-400 hover:text-primary-500 hover:bg-gray-100 dark:hover:bg-gray-800",
71
71
  "aria-label": "notifications",
72
72
  children: [jsx(Bell, {
73
73
  className: "h-5 w-5"
@@ -80,9 +80,9 @@ var NotificationsDropdown = function NotificationsDropdown(_ref) {
80
80
  children: jsxs("div", {
81
81
  className: "py-2 min-w-56 max-h-80 overflow-y-auto",
82
82
  children: [jsxs("div", {
83
- className: "px-4 py-2 border-b border-gray-100 flex items-center justify-between",
83
+ className: "px-4 py-2 border-b border-line flex items-center justify-between",
84
84
  children: [jsx("span", {
85
- className: "font-medium text-primary-800 text-sm",
85
+ className: "font-medium text-primary-800 dark:text-primary-100 text-sm",
86
86
  children: "Notifications"
87
87
  }), jsx("button", {
88
88
  className: "text-xs text-primary-400 hover:text-error-600",
@@ -98,16 +98,16 @@ var NotificationsDropdown = function NotificationsDropdown(_ref) {
98
98
  children: "No notifications"
99
99
  }) : notifications.map(function (n) {
100
100
  return jsxs("div", {
101
- className: cn("flex items-start gap-3 px-4 py-2 hover:bg-gray-50 cursor-pointer group", !n.read ? "bg-primary-50" : ""),
101
+ className: cn("flex items-start gap-3 px-4 py-2 hover:bg-gray-50 dark:hover:bg-gray-800 cursor-pointer group", !n.read ? "bg-primary-50 dark:bg-primary-900/40" : ""),
102
102
  onClick: function onClick() {
103
103
  return onView();
104
104
  },
105
105
  children: [jsx("span", {
106
- className: cn("h-2 w-2 mt-2 rounded-full", !n.read ? "bg-primary-500" : "bg-gray-300")
106
+ className: cn("h-2 w-2 mt-2 rounded-full", !n.read ? "bg-primary-500" : "bg-gray-300 dark:bg-gray-600")
107
107
  }), jsxs("div", {
108
108
  className: "flex-1",
109
109
  children: [jsx("div", {
110
- className: "text-sm text-primary-800",
110
+ className: "text-sm text-primary-800 dark:text-primary-100",
111
111
  children: n.title
112
112
  }), n.message && jsx("div", {
113
113
  className: "text-xs text-primary-500",
@@ -159,10 +159,10 @@ var RightMenuContent = function RightMenuContent(_ref2) {
159
159
  });
160
160
  };
161
161
  var styledClassNames = {
162
- button: "rounded-md p-2 text-primary-400 hover:text-primary-500 hover:bg-gray-100",
162
+ button: "rounded-md p-2 text-primary-400 hover:text-primary-500 hover:bg-gray-100 dark:hover:bg-gray-800",
163
163
  mobileItem: "md:hidden",
164
164
  icon: "h-6 w-6",
165
- dropdown: "w-56 rounded-md border border-gray-200 bg-white py-1 shadow-lg"
165
+ dropdown: "w-56 rounded-md border border-line bg-surface py-1 shadow-lg"
166
166
  };
167
167
  var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
168
168
  var emitter = _ref3.emitter,
@@ -247,7 +247,7 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
247
247
  },
248
248
  className: cn("block w-full text-left px-4 py-2 text-sm", {
249
249
  "text-primary-600": item.active,
250
- "hover:bg-gray-50": !item.active
250
+ "hover:bg-gray-50 dark:hover:bg-gray-800": !item.active
251
251
  }),
252
252
  children: item.label
253
253
  }, item.id);
@@ -262,7 +262,7 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
262
262
  };
263
263
  return jsxs("nav", _objectSpread2(_objectSpread2({
264
264
  ref: ref,
265
- className: cn("bg-white border-b border-gray-200 px-4 sm:px-6 lg:px-8", className)
265
+ className: cn("bg-surface text-foreground border-b border-line px-4 sm:px-6 lg:px-8", className)
266
266
  }, props), {}, {
267
267
  children: [jsxs("div", {
268
268
  className: "flex h-16 min-w-0 items-center justify-between gap-2 sm:gap-4",
@@ -275,7 +275,7 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
275
275
  className: "flex min-w-0 items-center",
276
276
  children: [leftIcon !== false && jsx("button", {
277
277
  onClick: onLeftIconClick,
278
- className: "shrink-0 md:hidden rounded-md p-2 text-primary-400 hover:text-primary-500 hover:bg-gray-100",
278
+ className: "shrink-0 md:hidden rounded-md p-2 text-primary-400 hover:text-primary-500 hover:bg-gray-100 dark:hover:bg-gray-800",
279
279
  "aria-label": "back",
280
280
  children: leftIcon
281
281
  }), logo && jsx("div", {
@@ -302,7 +302,7 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
302
302
  }), jsx("input", {
303
303
  type: "text",
304
304
  placeholder: "Search...",
305
- className: "w-64 rounded-md border border-gray-300 bg-white pl-10 pr-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent",
305
+ className: "w-64 rounded-md border border-gray-300 bg-surface text-foreground dark:border-gray-700 pl-10 pr-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent",
306
306
  value: searchTerm,
307
307
  onChange: function onChange(e) {
308
308
  return setSearchTerm(e.target.value);
@@ -365,9 +365,9 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
365
365
  children: jsxs("div", {
366
366
  className: styledClassNames.dropdown,
367
367
  children: [jsxs("div", {
368
- className: "px-4 py-2 border-b border-gray-200",
368
+ className: "px-4 py-2 border-b border-line",
369
369
  children: [jsx("p", {
370
- className: "text-sm font-medium text-primary-900",
370
+ className: "text-sm font-medium text-primary-900 dark:text-primary-100",
371
371
  children: user.name
372
372
  }), jsx("p", {
373
373
  className: "text-xs text-primary-500",
@@ -377,23 +377,23 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
377
377
  className: "py-1",
378
378
  children: renderNavItems(true)
379
379
  }), user.menuItems && user.menuItems.length > 0 && jsx("div", {
380
- className: "border-t border-gray-100",
380
+ className: "border-t border-line",
381
381
  children: user.menuItems.map(function (mi) {
382
382
  return jsx("button", {
383
383
  onClick: function onClick(e) {
384
384
  var _mi$onClick;
385
385
  return mi === null || mi === void 0 || (_mi$onClick = mi.onClick) === null || _mi$onClick === void 0 ? void 0 : _mi$onClick.call(mi, e);
386
386
  },
387
- className: "block w-full px-4 py-2 text-left text-sm hover:bg-gray-100",
387
+ className: "block w-full px-4 py-2 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-800",
388
388
  children: mi.label
389
389
  }, mi.id);
390
390
  })
391
391
  }), jsx("div", {
392
- className: "border-t border-gray-100 sm:hidden",
392
+ className: "border-t border-line sm:hidden",
393
393
  children: jsxs("button", {
394
394
  type: "button",
395
395
  onClick: handleLogoutClick,
396
- className: "flex w-full items-center gap-2 px-4 py-2 text-left text-sm hover:bg-gray-100",
396
+ className: "flex w-full items-center gap-2 px-4 py-2 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-800",
397
397
  children: [jsx(LogOut, {
398
398
  className: "h-4 w-4",
399
399
  "aria-hidden": "true"
@@ -407,13 +407,13 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
407
407
  }), isMobileMenuOpen && !user && jsx("div", {
408
408
  className: "md:hidden h-full",
409
409
  children: jsx("div", {
410
- className: "space-y-1 border-t border-gray-200 px-2 pt-4 pb-3",
410
+ className: "space-y-1 border-t border-line px-2 pt-4 pb-3",
411
411
  children: items.map(function (item) {
412
412
  return jsx("a", {
413
413
  href: item.href,
414
414
  className: cn("block rounded-md px-3 py-2 text-base font-medium", {
415
- "bg-primary-50 text-primary-700": item.active,
416
- "hover:bg-gray-50": !item.active
415
+ "bg-primary-50 text-primary-700 dark:bg-primary-900/40 dark:text-primary-300": item.active,
416
+ "hover:bg-gray-50 dark:hover:bg-gray-800": !item.active
417
417
  }),
418
418
  children: item.label
419
419
  }, item.id);