@dreamtree-org/twreact-ui 1.3.11 → 2.0.1

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 (164) hide show
  1. package/README.md +40 -6
  2. package/ai-skills/dreamtree-ui.md +47 -9
  3. package/codemods/v2.cjs +198 -0
  4. package/dist/ai-schema.json +609 -33
  5. package/dist/components/blocks/AppShell.d.ts.map +1 -1
  6. package/dist/components/blocks/BottomActionBar.d.ts +6 -0
  7. package/dist/components/blocks/BottomActionBar.d.ts.map +1 -0
  8. package/dist/components/blocks/ConfirmDialog.d.ts.map +1 -1
  9. package/dist/components/blocks/PageHeader.d.ts.map +1 -1
  10. package/dist/components/core/Checkbox.d.ts.map +1 -1
  11. package/dist/components/core/DatePicker.d.ts.map +1 -1
  12. package/dist/components/core/DateRangePicker.d.ts.map +1 -1
  13. package/dist/components/core/Form.d.ts.map +1 -1
  14. package/dist/components/core/Input.d.ts.map +1 -1
  15. package/dist/components/core/Popover.d.ts.map +1 -1
  16. package/dist/components/core/ProgressBar.d.ts.map +1 -1
  17. package/dist/components/core/Rate.d.ts.map +1 -1
  18. package/dist/components/core/SearchField.d.ts +9 -0
  19. package/dist/components/core/SearchField.d.ts.map +1 -0
  20. package/dist/components/core/SegmentedControl.d.ts +8 -0
  21. package/dist/components/core/SegmentedControl.d.ts.map +1 -0
  22. package/dist/components/core/Select.d.ts.map +1 -1
  23. package/dist/components/core/SwipeableListItem.d.ts +4 -0
  24. package/dist/components/core/SwipeableListItem.d.ts.map +1 -0
  25. package/dist/components/core/SwipeableListItemGesture.d.ts +58 -0
  26. package/dist/components/core/SwipeableListItemGesture.d.ts.map +1 -0
  27. package/dist/components/core/Switch.d.ts.map +1 -1
  28. package/dist/components/core/Table/ActionMenu.d.ts +10 -3
  29. package/dist/components/core/Table/ActionMenu.d.ts.map +1 -1
  30. package/dist/components/core/Table/MobileCard.d.ts +10 -1
  31. package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
  32. package/dist/components/core/Table/MobileFilters.d.ts +8 -2
  33. package/dist/components/core/Table/MobileFilters.d.ts.map +1 -1
  34. package/dist/components/core/Table/Table.d.ts.map +1 -1
  35. package/dist/components/core/Table/TableRow.d.ts +2 -1
  36. package/dist/components/core/Table/TableRow.d.ts.map +1 -1
  37. package/dist/components/core/Tabs.d.ts +3 -3
  38. package/dist/components/core/Tabs.d.ts.map +1 -1
  39. package/dist/components/core/ThreeDotPopover.d.ts +10 -22
  40. package/dist/components/core/ThreeDotPopover.d.ts.map +1 -1
  41. package/dist/components/core/Tooltip.d.ts +2 -1
  42. package/dist/components/core/Tooltip.d.ts.map +1 -1
  43. package/dist/components/core/internal/Calendar.d.ts +77 -0
  44. package/dist/components/core/internal/Calendar.d.ts.map +1 -0
  45. package/dist/components/core/menu/ActionMenuSurface.d.ts +42 -0
  46. package/dist/components/core/menu/ActionMenuSurface.d.ts.map +1 -0
  47. package/dist/components/core/menu/ActionSheetMenu.d.ts +17 -0
  48. package/dist/components/core/menu/ActionSheetMenu.d.ts.map +1 -0
  49. package/dist/components/core/menu/MenuPopover.d.ts +21 -0
  50. package/dist/components/core/menu/MenuPopover.d.ts.map +1 -0
  51. package/dist/components/core/menu/menuItems.d.ts +21 -0
  52. package/dist/components/core/menu/menuItems.d.ts.map +1 -0
  53. package/dist/components/core/menu/menuKeyboard.d.ts +16 -0
  54. package/dist/components/core/menu/menuKeyboard.d.ts.map +1 -0
  55. package/dist/components/feedback/ActionSheet.d.ts +4 -0
  56. package/dist/components/feedback/ActionSheet.d.ts.map +1 -0
  57. package/dist/components/feedback/Alert.d.ts.map +1 -1
  58. package/dist/components/feedback/Dialog.d.ts.map +1 -1
  59. package/dist/components/feedback/Drawer.d.ts.map +1 -1
  60. package/dist/components/feedback/Sheet.d.ts +4 -0
  61. package/dist/components/feedback/Sheet.d.ts.map +1 -0
  62. package/dist/components/feedback/Toast.d.ts +4 -3
  63. package/dist/components/feedback/Toast.d.ts.map +1 -1
  64. package/dist/components/feedback/ToastItem.d.ts +47 -0
  65. package/dist/components/feedback/ToastItem.d.ts.map +1 -0
  66. package/dist/components/feedback/ToastStack.d.ts +20 -0
  67. package/dist/components/feedback/ToastStack.d.ts.map +1 -0
  68. package/dist/components/feedback/ToastSwipe.d.ts +22 -0
  69. package/dist/components/feedback/ToastSwipe.d.ts.map +1 -0
  70. package/dist/components/feedback/Tour.d.ts.map +1 -1
  71. package/dist/components/feedback/sheetCore.d.ts +30 -0
  72. package/dist/components/feedback/sheetCore.d.ts.map +1 -0
  73. package/dist/components/navigation/Navbar.d.ts.map +1 -1
  74. package/dist/components/navigation/Sidebar.d.ts +6 -0
  75. package/dist/components/navigation/Sidebar.d.ts.map +1 -1
  76. package/dist/components/rich-text/RichTextEditor.d.ts.map +1 -1
  77. package/dist/components/rich-text/RichTextToolbar.d.ts +6 -2
  78. package/dist/components/rich-text/RichTextToolbar.d.ts.map +1 -1
  79. package/dist/components/utility/PullToRefresh.d.ts +5 -0
  80. package/dist/components/utility/PullToRefresh.d.ts.map +1 -0
  81. package/dist/esm/components/blocks/AppShell.js +97 -90
  82. package/dist/esm/components/blocks/BottomActionBar.js +132 -0
  83. package/dist/esm/components/blocks/ConfirmDialog.js +40 -4
  84. package/dist/esm/components/blocks/PageHeader.js +16 -3
  85. package/dist/esm/components/core/Checkbox.js +13 -24
  86. package/dist/esm/components/core/DatePicker.js +117 -304
  87. package/dist/esm/components/core/DateRangePicker.js +260 -308
  88. package/dist/esm/components/core/Form.js +11 -2
  89. package/dist/esm/components/core/Input.js +13 -18
  90. package/dist/esm/components/core/Popover.js +59 -48
  91. package/dist/esm/components/core/ProgressBar.js +36 -64
  92. package/dist/esm/components/core/Rate.js +5 -10
  93. package/dist/esm/components/core/SearchField.js +311 -0
  94. package/dist/esm/components/core/SegmentedControl.js +189 -0
  95. package/dist/esm/components/core/Select.js +185 -190
  96. package/dist/esm/components/core/SwipeableListItem.js +286 -0
  97. package/dist/esm/components/core/SwipeableListItemGesture.js +219 -0
  98. package/dist/esm/components/core/Switch.js +11 -13
  99. package/dist/esm/components/core/Table/ActionMenu.js +45 -231
  100. package/dist/esm/components/core/Table/ColumnMenu.js +1 -1
  101. package/dist/esm/components/core/Table/MobileCard.js +66 -16
  102. package/dist/esm/components/core/Table/MobileFilters.js +181 -10
  103. package/dist/esm/components/core/Table/Table.js +149 -102
  104. package/dist/esm/components/core/Table/TableRow.js +10 -2
  105. package/dist/esm/components/core/Tabs.js +7 -7
  106. package/dist/esm/components/core/ThreeDotPopover.js +93 -99
  107. package/dist/esm/components/core/Tooltip.js +138 -145
  108. package/dist/esm/components/core/internal/Calendar.js +381 -0
  109. package/dist/esm/components/core/menu/ActionMenuSurface.js +110 -0
  110. package/dist/esm/components/core/menu/ActionSheetMenu.js +140 -0
  111. package/dist/esm/components/core/menu/MenuPopover.js +177 -0
  112. package/dist/esm/components/core/menu/menuItems.js +61 -0
  113. package/dist/esm/components/core/menu/menuKeyboard.js +54 -0
  114. package/dist/esm/components/feedback/ActionSheet.js +55 -0
  115. package/dist/esm/components/feedback/Alert.js +63 -53
  116. package/dist/esm/components/feedback/Dialog.js +141 -53
  117. package/dist/esm/components/feedback/Drawer.js +130 -132
  118. package/dist/esm/components/feedback/Sheet.js +125 -0
  119. package/dist/esm/components/feedback/Toast.js +21 -291
  120. package/dist/esm/components/feedback/ToastItem.js +348 -0
  121. package/dist/esm/components/feedback/ToastStack.js +130 -0
  122. package/dist/esm/components/feedback/ToastSwipe.js +52 -0
  123. package/dist/esm/components/feedback/Tour.js +107 -30
  124. package/dist/esm/components/feedback/sheetCore.js +494 -0
  125. package/dist/esm/components/navigation/Dropdown.js +1 -1
  126. package/dist/esm/components/navigation/Navbar.js +172 -37
  127. package/dist/esm/components/navigation/Sidebar.js +263 -111
  128. package/dist/esm/components/rich-text/RichTextEditor.js +9 -3
  129. package/dist/esm/components/rich-text/RichTextToolbar.js +29 -9
  130. package/dist/esm/components/utility/Portal.js +31 -0
  131. package/dist/esm/components/utility/PullToRefresh.js +229 -0
  132. package/dist/esm/hooks/useFloatingPosition.js +82 -0
  133. package/dist/esm/hooks/useHaptics.js +65 -0
  134. package/dist/esm/hooks/usePresence.js +58 -0
  135. package/dist/esm/hooks/usePresentation.js +21 -0
  136. package/dist/esm/hooks/useSheetDrag.js +220 -0
  137. package/dist/esm/index.js +13 -2
  138. package/dist/esm/utils/position.js +10 -63
  139. package/dist/hooks/useFloatingPosition.d.ts +8 -4
  140. package/dist/hooks/useFloatingPosition.d.ts.map +1 -1
  141. package/dist/hooks/useHaptics.d.ts +19 -0
  142. package/dist/hooks/useHaptics.d.ts.map +1 -0
  143. package/dist/hooks/useSheetDrag.d.ts +31 -0
  144. package/dist/hooks/useSheetDrag.d.ts.map +1 -0
  145. package/dist/index.css +1 -1
  146. package/dist/index.d.ts +9 -1
  147. package/dist/index.esm.css +1 -1
  148. package/dist/index.esm.js +8851 -3198
  149. package/dist/index.js +8856 -3195
  150. package/dist/rich-text/index.js +41 -11
  151. package/dist/types/blocks.d.ts +32 -2
  152. package/dist/types/blocks.d.ts.map +1 -1
  153. package/dist/types/index.d.ts +353 -19
  154. package/dist/types/index.d.ts.map +1 -1
  155. package/dist/types/rich-text.d.ts +5 -0
  156. package/dist/types/rich-text.d.ts.map +1 -1
  157. package/dist/utils/position.d.ts +0 -15
  158. package/dist/utils/position.d.ts.map +1 -1
  159. package/doc/README.md +15 -0
  160. package/mcp/catalog.snapshot.json +1398 -464
  161. package/package.json +7 -2
  162. package/dist/esm/hooks/useSwipeToClose.js +0 -66
  163. package/dist/hooks/useSwipeToClose.d.ts +0 -24
  164. package/dist/hooks/useSwipeToClose.d.ts.map +0 -1
@@ -0,0 +1,286 @@
1
+ 'use client';
2
+ import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, typeof as _typeof, toConsumableArray as _toConsumableArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+ import React, { useMemo, useRef, useState, useCallback } from 'react';
5
+ import { MoreHorizontal } from 'lucide-react';
6
+ import { cn } from '../../utils/cn.js';
7
+ import { setRefs } from '../../utils/position.js';
8
+ import { useControllableState } from '../../hooks/useControllableState.js';
9
+ import { useClickOutside } from '../../hooks/useClickOutside.js';
10
+ import ActionMenuSurface from './menu/ActionMenuSurface.js';
11
+ import { renderIcon } from './menu/menuItems.js';
12
+ import { useSwipeGesture, restingOffset } from './SwipeableListItemGesture.js';
13
+
14
+ var _excluded = ["as", "children", "leadingActions", "trailingActions", "fullSwipe", "fullSwipeThreshold", "actionWidth", "open", "defaultOpen", "onOpenChange", "disabled", "moreActions", "moreActionsLabel", "menuPresentation", "contentClassName", "className", "onKeyDown"];
15
+ // The iOS Mail / Gmail row: swipe horizontally to reveal actions, swipe all
16
+ // the way to commit the first one. Every action is also reachable without a
17
+ // gesture through the "More actions" button (a menu, or an action sheet on
18
+ // phones).
19
+ var TONE_CLASSES = {
20
+ "default": "bg-secondary-600 text-secondary-50",
21
+ primary: "bg-primary-600 text-primary-50",
22
+ secondary: "bg-secondary-600 text-secondary-50",
23
+ success: "bg-success-600 text-success-50",
24
+ warning: "bg-warning-600 text-warning-50",
25
+ info: "bg-info-600 text-info-50",
26
+ error: "bg-error-600 text-error-50",
27
+ destructive: "bg-error-600 text-error-50"
28
+ };
29
+ var MOTION = "duration-base ease-standard motion-reduce:transition-none";
30
+ var toneClass = function toneClass(tone) {
31
+ return TONE_CLASSES[tone] || TONE_CLASSES["default"];
32
+ };
33
+ var isMenuDestructive = function isMenuDestructive(tone) {
34
+ return tone === "destructive" || tone === "error";
35
+ };
36
+ function ActionPanel(_ref) {
37
+ var side = _ref.side,
38
+ actions = _ref.actions,
39
+ width = _ref.width,
40
+ open = _ref.open,
41
+ armed = _ref.armed,
42
+ dragging = _ref.dragging,
43
+ onSelect = _ref.onSelect;
44
+ // The first action sits at the outer edge, so trailing actions render reversed.
45
+ var ordered = side === "trailing" ? _toConsumableArray(actions).reverse() : actions;
46
+ var first = actions[0];
47
+ return jsx("div", {
48
+ "data-swipe-actions": side,
49
+ "aria-hidden": open ? undefined : true,
50
+ className: cn("absolute inset-y-0 flex overflow-hidden", side === "leading" ? "left-0" : "right-0 flex-row", !dragging && cn("transition-[width]", MOTION)),
51
+ style: {
52
+ width: width
53
+ },
54
+ children: ordered.map(function (action, idx) {
55
+ var _action$key;
56
+ var grow = armed && action === first;
57
+ var collapsed = armed && action !== first;
58
+ return jsxs("button", {
59
+ type: "button",
60
+ tabIndex: open ? 0 : -1,
61
+ disabled: action.disabled || undefined,
62
+ "data-tone": action.tone || "default",
63
+ className: cn("flex min-w-0 flex-col items-center justify-center gap-1 overflow-hidden px-2 text-xs font-medium outline-none", "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-50", "disabled:cursor-not-allowed disabled:opacity-60", toneClass(action.tone), grow ? "flex-[1_0_auto]" : collapsed ? "w-0 flex-none px-0" : "flex-1", !dragging && cn("transition-[flex-grow,width]", MOTION)),
64
+ onClick: function onClick(e) {
65
+ e.stopPropagation();
66
+ onSelect(action, "button");
67
+ },
68
+ children: [action.icon != null && jsx("span", {
69
+ className: "inline-flex shrink-0",
70
+ "aria-hidden": "true",
71
+ children: renderIcon(action.icon, "h-5 w-5")
72
+ }), jsx("span", {
73
+ className: "max-w-full truncate",
74
+ children: action.label
75
+ })]
76
+ }, (_action$key = action.key) !== null && _action$key !== void 0 ? _action$key : "".concat(side, "-").concat(idx));
77
+ })
78
+ });
79
+ }
80
+ var SwipeableListItem = /*#__PURE__*/React.forwardRef(function SwipeableListItem(_ref2, _ref4) {
81
+ var _ref2$as = _ref2.as,
82
+ Component = _ref2$as === void 0 ? "div" : _ref2$as,
83
+ children = _ref2.children,
84
+ _ref2$leadingActions = _ref2.leadingActions,
85
+ leadingActions = _ref2$leadingActions === void 0 ? [] : _ref2$leadingActions,
86
+ _ref2$trailingActions = _ref2.trailingActions,
87
+ trailingActions = _ref2$trailingActions === void 0 ? [] : _ref2$trailingActions,
88
+ _ref2$fullSwipe = _ref2.fullSwipe,
89
+ fullSwipe = _ref2$fullSwipe === void 0 ? true : _ref2$fullSwipe,
90
+ _ref2$fullSwipeThresh = _ref2.fullSwipeThreshold,
91
+ fullSwipeThreshold = _ref2$fullSwipeThresh === void 0 ? 0.6 : _ref2$fullSwipeThresh,
92
+ _ref2$actionWidth = _ref2.actionWidth,
93
+ actionWidth = _ref2$actionWidth === void 0 ? 80 : _ref2$actionWidth,
94
+ open = _ref2.open,
95
+ _ref2$defaultOpen = _ref2.defaultOpen,
96
+ defaultOpen = _ref2$defaultOpen === void 0 ? null : _ref2$defaultOpen,
97
+ onOpenChange = _ref2.onOpenChange,
98
+ _ref2$disabled = _ref2.disabled,
99
+ disabled = _ref2$disabled === void 0 ? false : _ref2$disabled,
100
+ _ref2$moreActions = _ref2.moreActions,
101
+ moreActions = _ref2$moreActions === void 0 ? "focus" : _ref2$moreActions,
102
+ _ref2$moreActionsLabe = _ref2.moreActionsLabel,
103
+ moreActionsLabel = _ref2$moreActionsLabe === void 0 ? "More actions" : _ref2$moreActionsLabe,
104
+ _ref2$menuPresentatio = _ref2.menuPresentation,
105
+ menuPresentation = _ref2$menuPresentatio === void 0 ? "auto" : _ref2$menuPresentatio,
106
+ contentClassName = _ref2.contentClassName,
107
+ className = _ref2.className,
108
+ onKeyDown = _ref2.onKeyDown,
109
+ rest = _objectWithoutProperties(_ref2, _excluded);
110
+ var leading = useMemo(function () {
111
+ return Array.isArray(leadingActions) ? leadingActions : [];
112
+ }, [leadingActions]);
113
+ var trailing = useMemo(function () {
114
+ return Array.isArray(trailingActions) ? trailingActions : [];
115
+ }, [trailingActions]);
116
+ var widths = useMemo(function () {
117
+ return {
118
+ leading: leading.length * actionWidth,
119
+ trailing: trailing.length * actionWidth
120
+ };
121
+ }, [leading.length, trailing.length, actionWidth]);
122
+ var _useControllableState = useControllableState({
123
+ value: open,
124
+ defaultValue: defaultOpen,
125
+ onChange: onOpenChange
126
+ }),
127
+ _useControllableState2 = _slicedToArray(_useControllableState, 2),
128
+ rawOpenSide = _useControllableState2[0],
129
+ setOpenSide = _useControllableState2[1];
130
+ // A side without actions can't be open.
131
+ var openSide = rawOpenSide && widths[rawOpenSide] > 0 ? rawOpenSide : null;
132
+ var rootRef = useRef(null);
133
+ var _useState = useState(null),
134
+ _useState2 = _slicedToArray(_useState, 2),
135
+ moreButtonEl = _useState2[0],
136
+ setMoreButtonEl = _useState2[1];
137
+ var _useState3 = useState(false),
138
+ _useState4 = _slicedToArray(_useState3, 2),
139
+ menuOpen = _useState4[0],
140
+ setMenuOpen = _useState4[1];
141
+ var close = useCallback(function () {
142
+ if (openSide != null) setOpenSide(null);
143
+ }, [openSide, setOpenSide]);
144
+ var runAction = useCallback(function (action, source) {
145
+ var _action$onSelect;
146
+ if (!action || action.disabled) return;
147
+ (_action$onSelect = action.onSelect) === null || _action$onSelect === void 0 || _action$onSelect.call(action, {
148
+ action: action,
149
+ source: source
150
+ });
151
+ setOpenSide(null);
152
+ }, [setOpenSide]);
153
+ var allowFull = _typeof(fullSwipe) === "object" && fullSwipe !== null ? {
154
+ leading: fullSwipe.leading !== false,
155
+ trailing: fullSwipe.trailing !== false
156
+ } : {
157
+ leading: Boolean(fullSwipe),
158
+ trailing: Boolean(fullSwipe)
159
+ };
160
+ var onSettle = function onSettle(_ref3) {
161
+ var side = _ref3.side,
162
+ commit = _ref3.commit;
163
+ if (commit) {
164
+ runAction((side === "leading" ? leading : trailing)[0], "full-swipe");
165
+ return;
166
+ }
167
+ if (side !== openSide) setOpenSide(side);
168
+ };
169
+ var enabled = !disabled && (widths.leading > 0 || widths.trailing > 0);
170
+ var _useSwipeGesture = useSwipeGesture({
171
+ enabled: enabled,
172
+ widths: widths,
173
+ openSide: openSide,
174
+ fullSwipe: allowFull,
175
+ fullSwipeThreshold: fullSwipeThreshold,
176
+ onSettle: onSettle
177
+ }),
178
+ offset = _useSwipeGesture.offset,
179
+ dragging = _useSwipeGesture.dragging,
180
+ armed = _useSwipeGesture.armed,
181
+ handlers = _useSwipeGesture.handlers,
182
+ consumeClick = _useSwipeGesture.consumeClick;
183
+ useClickOutside([rootRef], close, {
184
+ enabled: openSide != null
185
+ });
186
+ var x = offset !== null && offset !== void 0 ? offset : restingOffset(openSide, widths);
187
+ var menuItems = useMemo(function () {
188
+ return [].concat(_toConsumableArray(leading), _toConsumableArray(trailing)).map(function (action, idx) {
189
+ var _action$key2;
190
+ return {
191
+ key: (_action$key2 = action.key) !== null && _action$key2 !== void 0 ? _action$key2 : "action-".concat(idx),
192
+ label: action.label,
193
+ icon: action.icon != null ? renderIcon(action.icon, "h-4 w-4") : null,
194
+ disabled: Boolean(action.disabled),
195
+ tone: isMenuDestructive(action.tone) ? "destructive" : "default",
196
+ onSelect: function onSelect() {
197
+ return runAction(action, "menu");
198
+ }
199
+ };
200
+ });
201
+ }, [leading, trailing, runAction]);
202
+ var hasActions = menuItems.length > 0;
203
+ var showMore = hasActions && moreActions !== false && !disabled;
204
+ var handleKeyDown = function handleKeyDown(e) {
205
+ onKeyDown === null || onKeyDown === void 0 || onKeyDown(e);
206
+ if (e.defaultPrevented) return;
207
+ if (e.key === "Escape" && openSide != null) {
208
+ e.stopPropagation();
209
+ setOpenSide(null);
210
+ }
211
+ };
212
+ return jsxs(Component, _objectSpread2(_objectSpread2({
213
+ ref: function ref(node) {
214
+ return setRefs(node, rootRef, _ref4);
215
+ },
216
+ "data-swipe-open": openSide !== null && openSide !== void 0 ? openSide : undefined,
217
+ "data-swiping": dragging || undefined,
218
+ className: cn("group/swipe relative isolate overflow-hidden", className),
219
+ onKeyDown: handleKeyDown
220
+ }, rest), {}, {
221
+ children: [widths.leading > 0 && jsx(ActionPanel, {
222
+ side: "leading",
223
+ actions: leading,
224
+ width: Math.max(0, x),
225
+ open: openSide === "leading",
226
+ armed: armed === "leading",
227
+ dragging: dragging,
228
+ onSelect: runAction
229
+ }), widths.trailing > 0 && jsx(ActionPanel, {
230
+ side: "trailing",
231
+ actions: trailing,
232
+ width: Math.max(0, -x),
233
+ open: openSide === "trailing",
234
+ armed: armed === "trailing",
235
+ dragging: dragging,
236
+ onSelect: runAction
237
+ }), jsx("div", _objectSpread2(_objectSpread2({
238
+ "data-swipe-content": "",
239
+ className: cn("relative bg-surface touch-pan-y", dragging ? "select-none" : cn("transition-transform", MOTION), contentClassName),
240
+ style: x ? {
241
+ transform: "translate3d(".concat(x, "px, 0, 0)")
242
+ } : undefined
243
+ }, handlers), {}, {
244
+ onClickCapture: function onClickCapture(e) {
245
+ // The click that ends a swipe, or a tap on an open row, only closes.
246
+ var endedSwipe = consumeClick();
247
+ if (!endedSwipe && openSide == null) return;
248
+ e.stopPropagation();
249
+ e.preventDefault();
250
+ if (!endedSwipe) close();
251
+ },
252
+ children: children
253
+ })), showMore && jsx("button", {
254
+ ref: setMoreButtonEl,
255
+ type: "button",
256
+ "aria-label": moreActionsLabel,
257
+ "aria-haspopup": "menu",
258
+ "aria-expanded": menuOpen,
259
+ "data-swipe-more": "",
260
+ className: cn("absolute right-2 top-1/2 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full", "border border-line bg-surface text-foreground shadow-sm outline-none", "focus-visible:ring-2 focus-visible:ring-primary-500 transition-opacity duration-fast motion-reduce:transition-none", moreActions === "focus" && !menuOpen && "pointer-events-none opacity-0 focus-visible:pointer-events-auto focus-visible:opacity-100 [@media(hover:hover)]:group-hover/swipe:pointer-events-auto [@media(hover:hover)]:group-hover/swipe:opacity-100", openSide != null && "hidden"),
261
+ onClick: function onClick(e) {
262
+ e.stopPropagation();
263
+ setMenuOpen(function (v) {
264
+ return !v;
265
+ });
266
+ },
267
+ children: jsx(MoreHorizontal, {
268
+ className: "h-5 w-5",
269
+ "aria-hidden": "true"
270
+ })
271
+ }), showMore && jsx(ActionMenuSurface, {
272
+ open: menuOpen,
273
+ onClose: function onClose() {
274
+ return setMenuOpen(false);
275
+ },
276
+ anchorEl: moreButtonEl,
277
+ items: menuItems,
278
+ presentation: menuPresentation,
279
+ placement: "bottom-end",
280
+ label: moreActionsLabel
281
+ })]
282
+ }));
283
+ });
284
+ SwipeableListItem.displayName = "SwipeableListItem";
285
+
286
+ export { SwipeableListItem as default };
@@ -0,0 +1,219 @@
1
+ 'use client';
2
+ import { slicedToArray as _slicedToArray } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { useState, useRef, useCallback } from 'react';
4
+ import { useLatestRef } from '../../hooks/useLatestRef.js';
5
+ import { rubberBand, FLICK_VELOCITY } from '../../hooks/useSheetDrag.js';
6
+
7
+ // Internal (not exported). The horizontal swipe gesture behind
8
+ // SwipeableListItem. Offsets are in px; positive moves the content right
9
+ // (revealing the leading actions), negative moves it left (trailing).
10
+ //
11
+ // The gesture only starts once horizontal movement dominates, so a vertical
12
+ // pan scrolls the page as usual (pair with `touch-action: pan-y`). Past the
13
+ // revealed actions the content rubber-bands, unless a full swipe is possible,
14
+ // in which case it follows the finger up to the row width.
15
+ var SLOP = 6; // px before a press becomes a swipe (or a scroll)
16
+ var VELOCITY_WINDOW = 100; // ms of recent samples used for release velocity
17
+ var FULL_SWIPE_MARGIN = 24; // px a full swipe must travel past the revealed actions
18
+ var FALLBACK_WIDTH = 320; // px, when the row has no layout (jsdom, hidden)
19
+ var now = function now() {
20
+ return Date.now();
21
+ };
22
+ var sideOf = function sideOf(offset) {
23
+ return offset > 0 ? "leading" : offset < 0 ? "trailing" : null;
24
+ };
25
+ /**
26
+ * Where the content rests for an open side.
27
+ * @param {'leading'|'trailing'|null} side
28
+ * @param {{ leading: number, trailing: number }} widths - revealed widths in px.
29
+ */
30
+ function restingOffset(side, widths) {
31
+ if (side === "leading") return widths.leading;
32
+ if (side === "trailing") return -widths.trailing;
33
+ return 0;
34
+ }
35
+ /** Distance (px) past which releasing commits the side's first action. */
36
+ function fullSwipeDistance(reveal, width, threshold) {
37
+ return Math.max(reveal + FULL_SWIPE_MARGIN, width * threshold);
38
+ }
39
+ /**
40
+ * Maps a raw finger offset to the displayed offset for one side.
41
+ * @param {number} raw - px, signed.
42
+ * @param {{ reveal: number, fullSwipe: boolean, width: number }} opts
43
+ */
44
+ function constrainOffset(raw, _ref) {
45
+ var reveal = _ref.reveal,
46
+ fullSwipe = _ref.fullSwipe,
47
+ width = _ref.width;
48
+ var sign = Math.sign(raw);
49
+ var distance = Math.abs(raw);
50
+ var limit = reveal > 0 && fullSwipe ? width : reveal;
51
+ if (distance <= limit) return raw;
52
+ return sign * (limit + rubberBand(distance - limit, width));
53
+ }
54
+ /**
55
+ * @param {{
56
+ * enabled: boolean,
57
+ * widths: { leading: number, trailing: number },
58
+ * openSide: 'leading'|'trailing'|null,
59
+ * fullSwipe: { leading: boolean, trailing: boolean },
60
+ * fullSwipeThreshold: number,
61
+ * onSettle: (r: { side: 'leading'|'trailing'|null, commit: boolean }) => void,
62
+ * }} options
63
+ * @returns {{ offset: number|null, dragging: boolean, armed: 'leading'|'trailing'|null,
64
+ * handlers: object, consumeClick: () => boolean }}
65
+ */
66
+ function useSwipeGesture(_ref2) {
67
+ var enabled = _ref2.enabled,
68
+ widths = _ref2.widths,
69
+ openSide = _ref2.openSide,
70
+ fullSwipe = _ref2.fullSwipe,
71
+ fullSwipeThreshold = _ref2.fullSwipeThreshold,
72
+ onSettle = _ref2.onSettle;
73
+ // `{ offset, width }` while a swipe is in progress, else null.
74
+ var _useState = useState(null),
75
+ _useState2 = _slicedToArray(_useState, 2),
76
+ drag = _useState2[0],
77
+ setDrag = _useState2[1];
78
+ var gesture = useRef(null);
79
+ var swallowClick = useRef(false);
80
+ var latest = useLatestRef({
81
+ widths: widths,
82
+ openSide: openSide,
83
+ fullSwipe: fullSwipe,
84
+ fullSwipeThreshold: fullSwipeThreshold,
85
+ onSettle: onSettle
86
+ });
87
+ var reset = useCallback(function () {
88
+ gesture.current = null;
89
+ setDrag(null);
90
+ }, []);
91
+ var onPointerDown = useCallback(function (e) {
92
+ var _el$getBoundingClient;
93
+ if (!enabled || e.button !== undefined && e.button !== 0) return;
94
+ var el = e.currentTarget;
95
+ var width = ((_el$getBoundingClient = el.getBoundingClientRect) === null || _el$getBoundingClient === void 0 ? void 0 : _el$getBoundingClient.call(el).width) || el.offsetWidth || FALLBACK_WIDTH;
96
+ var start = restingOffset(latest.current.openSide, latest.current.widths);
97
+ gesture.current = {
98
+ x: e.clientX,
99
+ y: e.clientY,
100
+ start: start,
101
+ width: width,
102
+ el: el,
103
+ pointerId: e.pointerId,
104
+ active: false,
105
+ current: start,
106
+ samples: [{
107
+ o: start,
108
+ t: now()
109
+ }]
110
+ };
111
+ swallowClick.current = false;
112
+ }, [enabled, latest]);
113
+ var onPointerMove = useCallback(function (e) {
114
+ var g = gesture.current;
115
+ if (!g) return;
116
+ var dx = e.clientX - g.x;
117
+ var dy = e.clientY - g.y;
118
+ if (!g.active) {
119
+ if (Math.max(Math.abs(dx), Math.abs(dy)) < SLOP) return;
120
+ if (Math.abs(dy) >= Math.abs(dx)) {
121
+ gesture.current = null; // a vertical pan: let the page scroll
122
+ return;
123
+ }
124
+ g.active = true;
125
+ swallowClick.current = true;
126
+ try {
127
+ var _g$el, _g$el$setPointerCaptu;
128
+ (_g$el = g.el) === null || _g$el === void 0 || (_g$el$setPointerCaptu = _g$el.setPointerCapture) === null || _g$el$setPointerCaptu === void 0 || _g$el$setPointerCaptu.call(_g$el, g.pointerId);
129
+ } catch (_unused) {
130
+ // The pointer may already be gone (synthetic events, fast lifts).
131
+ }
132
+ }
133
+ var raw = g.start + dx;
134
+ var side = sideOf(raw);
135
+ var _latest$current = latest.current,
136
+ w = _latest$current.widths,
137
+ fs = _latest$current.fullSwipe;
138
+ var next = side ? constrainOffset(raw, {
139
+ reveal: w[side],
140
+ fullSwipe: fs[side],
141
+ width: g.width
142
+ }) : 0;
143
+ g.current = next;
144
+ var t = now();
145
+ g.samples.push({
146
+ o: next,
147
+ t: t
148
+ });
149
+ while (g.samples.length > 2 && t - g.samples[0].t > VELOCITY_WINDOW) g.samples.shift();
150
+ setDrag({
151
+ offset: next,
152
+ width: g.width
153
+ });
154
+ }, [latest]);
155
+ var onPointerUp = useCallback(function () {
156
+ var g = gesture.current;
157
+ if (!g) return;
158
+ gesture.current = null;
159
+ if (!g.active) return;
160
+ var _latest$current2 = latest.current,
161
+ w = _latest$current2.widths,
162
+ fs = _latest$current2.fullSwipe,
163
+ t = _latest$current2.fullSwipeThreshold,
164
+ settle = _latest$current2.onSettle;
165
+ var value = g.current;
166
+ var side = sideOf(value);
167
+ var first = g.samples[0];
168
+ var velocity = (value - first.o) / Math.max(1, now() - first.t);
169
+ setDrag(null);
170
+ if (!side || w[side] === 0) {
171
+ settle({
172
+ side: null,
173
+ commit: false
174
+ });
175
+ return;
176
+ }
177
+ if (fs[side] && Math.abs(value) >= fullSwipeDistance(w[side], g.width, t)) {
178
+ settle({
179
+ side: side,
180
+ commit: true
181
+ });
182
+ return;
183
+ }
184
+ // A flick decides by direction; otherwise past half the actions opens.
185
+ var towardOpen = side === "leading" ? velocity > 0 : velocity < 0;
186
+ var flick = Math.abs(velocity) >= FLICK_VELOCITY;
187
+ var open = flick ? towardOpen : Math.abs(value) >= w[side] / 2;
188
+ settle({
189
+ side: open ? side : null,
190
+ commit: false
191
+ });
192
+ }, [latest]);
193
+ var onPointerCancel = useCallback(function () {
194
+ swallowClick.current = false;
195
+ reset();
196
+ }, [reset]);
197
+ // The click that ends a swipe must not activate the row.
198
+ var consumeClick = useCallback(function () {
199
+ if (!swallowClick.current) return false;
200
+ swallowClick.current = false;
201
+ return true;
202
+ }, []);
203
+ var dragSide = drag ? sideOf(drag.offset) : null;
204
+ var armed = dragSide && fullSwipe[dragSide] && widths[dragSide] > 0 && Math.abs(drag.offset) >= fullSwipeDistance(widths[dragSide], drag.width, fullSwipeThreshold) ? dragSide : null;
205
+ return {
206
+ offset: drag ? drag.offset : null,
207
+ dragging: drag != null,
208
+ armed: armed,
209
+ consumeClick: consumeClick,
210
+ handlers: enabled ? {
211
+ onPointerDown: onPointerDown,
212
+ onPointerMove: onPointerMove,
213
+ onPointerUp: onPointerUp,
214
+ onPointerCancel: onPointerCancel
215
+ } : {}
216
+ };
217
+ }
218
+
219
+ export { FALLBACK_WIDTH, constrainOffset, fullSwipeDistance, restingOffset, useSwipeGesture };
@@ -3,8 +3,9 @@ import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
4
  import { forwardRef, useState, useId, useEffect, useRef } from 'react';
5
5
  import { cn } from '../../utils/cn.js';
6
+ import { useHaptics } from '../../hooks/useHaptics.js';
6
7
 
7
- var _excluded = ["id", "name", "checked", "defaultChecked", "onChange", "disabled", "size", "color", "trackClass", "thumbClass", "className", "topLabel", "bottomLabel", "rightLabel", "leftLabel", "ariaLabel", "onPointerDown", "onPointerMove", "onPointerUp", "onPointerCancel"];
8
+ var _excluded = ["id", "name", "checked", "defaultChecked", "onChange", "disabled", "size", "color", "trackClass", "thumbClass", "className", "topLabel", "bottomLabel", "rightLabel", "leftLabel", "ariaLabel", "onPointerDown", "onPointerMove", "onPointerUp", "onPointerCancel", "haptics"];
8
9
  /**
9
10
  * Switch.jsx
10
11
  * - Plain JSX (no TypeScript)
@@ -40,6 +41,8 @@ var SIZE_MAP = {
40
41
  };
41
42
  // Horizontal travel (px) before a press becomes a drag.
42
43
  var DRAG_THRESHOLD = 4;
44
+ // Token presets only: the raw-palette presets (blue / indigo / purple) were
45
+ // removed in 2.0.0 (DTUI-65).
43
46
  var COLOR_PRESETS = {
44
47
  primary: {
45
48
  bg: "bg-primary-600",
@@ -72,18 +75,6 @@ var COLOR_PRESETS = {
72
75
  warning: {
73
76
  bg: "bg-warning-600",
74
77
  ring: "focus-visible:ring-warning-300"
75
- },
76
- blue: {
77
- bg: "bg-blue-600",
78
- ring: "focus-visible:ring-blue-300"
79
- },
80
- indigo: {
81
- bg: "bg-indigo-600",
82
- ring: "focus-visible:ring-indigo-300"
83
- },
84
- purple: {
85
- bg: "bg-purple-600",
86
- ring: "focus-visible:ring-purple-300"
87
78
  }
88
79
  };
89
80
  var Switch = /*#__PURE__*/forwardRef(function Switch(props, ref) {
@@ -112,6 +103,8 @@ var Switch = /*#__PURE__*/forwardRef(function Switch(props, ref) {
112
103
  onPointerMove = props.onPointerMove,
113
104
  onPointerUp = props.onPointerUp,
114
105
  onPointerCancel = props.onPointerCancel,
106
+ _props$haptics = props.haptics,
107
+ haptics = _props$haptics === void 0 ? false : _props$haptics,
115
108
  rest = _objectWithoutProperties(props, _excluded);
116
109
  var isControlled = typeof checked === "boolean";
117
110
  var _useState = useState(defaultChecked),
@@ -132,9 +125,14 @@ var Switch = /*#__PURE__*/forwardRef(function Switch(props, ref) {
132
125
  _useState4 = _slicedToArray(_useState3, 2),
133
126
  dragPreview = _useState4[0],
134
127
  setDragPreview = _useState4[1];
128
+ var _useHaptics = useHaptics({
129
+ enabled: haptics
130
+ }),
131
+ haptic = _useHaptics.trigger;
135
132
  var setOn = function setOn(next) {
136
133
  if (disabled || next === isOn) return;
137
134
  if (!isControlled) setInternalChecked(next);
135
+ haptic("selection");
138
136
  onChange && onChange(next);
139
137
  };
140
138
  var toggle = function toggle() {