@dreamtree-org/twreact-ui 1.3.4 → 1.3.6

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 (36) hide show
  1. package/README.md +37 -20
  2. package/ai-skills/dreamtree-ui.md +5 -1
  3. package/dist/ai-schema.json +44 -2
  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/feedback/Dialog.d.ts.map +1 -1
  8. package/dist/components/feedback/Drawer.d.ts.map +1 -1
  9. package/dist/components/navigation/FootNav.d.ts.map +1 -1
  10. package/dist/components/utility/Badge.d.ts.map +1 -1
  11. package/dist/components/utility/Stepper.d.ts.map +1 -1
  12. package/dist/esm/components/blocks/StatusPill.js +1 -1
  13. package/dist/esm/components/core/Button.js +23 -6
  14. package/dist/esm/components/core/Radio.js +3 -2
  15. package/dist/esm/components/core/Select.js +12 -2
  16. package/dist/esm/components/feedback/Dialog.js +4 -2
  17. package/dist/esm/components/feedback/Drawer.js +39 -10
  18. package/dist/esm/components/navigation/FootNav.js +41 -14
  19. package/dist/esm/components/utility/Badge.js +1 -0
  20. package/dist/esm/components/utility/Stepper.js +5 -2
  21. package/dist/esm/hooks/useSwipeToClose.js +66 -0
  22. package/dist/esm/utils/touchTarget.js +6 -0
  23. package/dist/hooks/useSwipeToClose.d.ts +24 -0
  24. package/dist/hooks/useSwipeToClose.d.ts.map +1 -0
  25. package/dist/index.css +1 -1
  26. package/dist/index.esm.css +1 -1
  27. package/dist/index.esm.js +191 -38
  28. package/dist/index.js +191 -38
  29. package/dist/types/index.d.ts +28 -2
  30. package/dist/types/index.d.ts.map +1 -1
  31. package/dist/utils/touchTarget.d.ts +2 -0
  32. package/dist/utils/touchTarget.d.ts.map +1 -0
  33. package/doc/README.md +1 -1
  34. package/mcp/README.md +1 -1
  35. package/mcp/catalog.snapshot.json +51 -21
  36. package/package.json +6 -6
package/dist/index.esm.js CHANGED
@@ -3429,7 +3429,7 @@ var Input = /*#__PURE__*/forwardRef(function (props, forwardedRef) {
3429
3429
  });
3430
3430
  Input.displayName = "Input";
3431
3431
 
3432
- var _excluded$N = ["className", "variant", "size", "disabled", "loading", "children", "leftIcon", "rightIcon", "fullWidth"];
3432
+ var _excluded$N = ["className", "variant", "size", "disabled", "loading", "children", "leftIcon", "rightIcon", "fullWidth", "as", "onClick"];
3433
3433
  function ownKeys$T(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3434
3434
  function _objectSpread$T(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$T(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$T(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
3435
3435
  var Button = /*#__PURE__*/forwardRef(function (_ref, ref) {
@@ -3444,12 +3444,19 @@ var Button = /*#__PURE__*/forwardRef(function (_ref, ref) {
3444
3444
  leftIcon = _ref.leftIcon,
3445
3445
  rightIcon = _ref.rightIcon,
3446
3446
  fullWidth = _ref.fullWidth,
3447
+ as = _ref.as,
3448
+ onClick = _ref.onClick,
3447
3449
  props = _objectWithoutProperties$1(_ref, _excluded$N);
3448
- var baseClasses = cn$1('inline-flex items-center justify-center rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none', {
3450
+ // `as` renders any element or component (an <a>, a router Link) with the
3451
+ // Button's look; a bare `href` implies an <a>.
3452
+ var Component = as || (props.href !== undefined ? 'a' : 'button');
3453
+ var isNativeButton = Component === 'button';
3454
+ var isDisabled = disabled || loading;
3455
+ var baseClasses = cn$1('inline-flex items-center justify-center rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none aria-disabled:opacity-50 aria-disabled:pointer-events-none', {
3449
3456
  // Variants
3450
3457
  'bg-primary-600 text-white hover:bg-primary-700 focus:ring-primary-500': variant === 'primary',
3451
3458
  'bg-secondary-100 text-secondary-900 hover:bg-secondary-200 focus:ring-secondary-500': variant === 'secondary',
3452
- 'bg-transparent border border-gray-300 hover:bg-gray-50 focus:ring-primary-500': variant === 'outline',
3459
+ 'bg-transparent border border-gray-300 hover:bg-gray-50 focus:ring-primary-500 dark:border-gray-600 dark:text-gray-100 dark:hover:bg-gray-800 dark:focus:ring-offset-gray-900': variant === 'outline',
3453
3460
  'bg-transparent text-primary-600 hover:bg-primary-50 focus:ring-primary-500': variant === 'ghost',
3454
3461
  'bg-error-600 text-white hover:bg-error-700 focus:ring-error-500': variant === 'destructive',
3455
3462
  'bg-success-600 text-white hover:bg-success-700 focus:ring-success-500': variant === 'success',
@@ -3464,10 +3471,20 @@ var Button = /*#__PURE__*/forwardRef(function (_ref, ref) {
3464
3471
  // Full width
3465
3472
  'w-full': fullWidth
3466
3473
  }, className);
3467
- return jsxs("button", _objectSpread$T(_objectSpread$T({
3474
+ return jsxs(Component, _objectSpread$T(_objectSpread$T(_objectSpread$T({
3468
3475
  ref: ref,
3469
- className: baseClasses,
3470
- disabled: disabled || loading
3476
+ className: baseClasses
3477
+ }, isNativeButton ? {
3478
+ disabled: isDisabled
3479
+ }
3480
+ // Links can't be `disabled`: announce it and swallow the click instead.
3481
+ : isDisabled && {
3482
+ 'aria-disabled': true,
3483
+ tabIndex: -1
3484
+ }), {}, {
3485
+ onClick: !isNativeButton && isDisabled ? function (e) {
3486
+ return e.preventDefault();
3487
+ } : onClick
3471
3488
  }, props), {}, {
3472
3489
  children: [loading && jsx(Loader2, {
3473
3490
  className: "mr-2 h-4 w-4 animate-spin"
@@ -3514,7 +3531,7 @@ function useLatestRef(value) {
3514
3531
  return ref;
3515
3532
  }
3516
3533
 
3517
- var _excluded$M = ["options", "value", "onChange", "placeholder", "label", "error", "helperText", "disabled", "required", "multiSelect", "searchable", "grouped", "onMenuItemRender", "className", "allowClear", "creatable", "onCreateOption", "onSearch", "loading", "selectAllOption", "closeOnSelect", "maxTagCount", "renderGroupLabel", "name"];
3534
+ var _excluded$M = ["options", "value", "onChange", "placeholder", "label", "error", "helperText", "disabled", "required", "multiSelect", "searchable", "grouped", "onMenuItemRender", "className", "allowClear", "creatable", "onCreateOption", "onSearch", "loading", "selectAllOption", "closeOnSelect", "maxTagCount", "renderGroupLabel", "name", "size"];
3518
3535
  function ownKeys$S(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3519
3536
  function _objectSpread$S(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$S(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$S(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
3520
3537
  /**
@@ -3615,6 +3632,14 @@ var highlight = function highlight() {
3615
3632
  }), label.slice(idx + term.length)]
3616
3633
  });
3617
3634
  };
3635
+ // Trigger sizes. min-h (not h) so multi-select tags can wrap. `md` keeps its
3636
+ // desktop look but grows to the 44px touch target on coarse pointers; `lg` is
3637
+ // 44px everywhere.
3638
+ var SIZE_CLASSES$1 = {
3639
+ sm: "min-h-8 px-2.5 py-1 text-xs",
3640
+ md: "min-h-[38px] px-3 py-2 text-sm [@media(pointer:coarse)]:min-h-11",
3641
+ lg: "min-h-11 px-4 py-2.5 text-base"
3642
+ };
3618
3643
  var Select = /*#__PURE__*/React__default.forwardRef(function (_ref, forwardedRef) {
3619
3644
  var _ref$options = _ref.options,
3620
3645
  options = _ref$options === void 0 ? [] : _ref$options,
@@ -3651,6 +3676,8 @@ var Select = /*#__PURE__*/React__default.forwardRef(function (_ref, forwardedRef
3651
3676
  maxTagCount = _ref$maxTagCount === void 0 ? 3 : _ref$maxTagCount,
3652
3677
  renderGroupLabel = _ref.renderGroupLabel,
3653
3678
  name = _ref.name,
3679
+ _ref$size = _ref.size,
3680
+ size = _ref$size === void 0 ? "md" : _ref$size,
3654
3681
  props = _objectWithoutProperties$1(_ref, _excluded$M);
3655
3682
  var _useState = useState(false),
3656
3683
  _useState2 = _slicedToArray(_useState, 2),
@@ -4221,7 +4248,7 @@ var Select = /*#__PURE__*/React__default.forwardRef(function (_ref, forwardedRef
4221
4248
  "aria-labelledby": label ? "".concat(labelId, " ").concat(valueId) : valueId,
4222
4249
  "aria-describedby": describedBy,
4223
4250
  "aria-invalid": error ? true : undefined,
4224
- className: cn$1("flex w-full items-center justify-between rounded-md border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent disabled:cursor-not-allowed disabled:opacity-50", {
4251
+ className: cn$1("flex w-full items-center justify-between rounded-md border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent disabled:cursor-not-allowed disabled:opacity-50", SIZE_CLASSES$1[size] || SIZE_CLASSES$1.md, {
4225
4252
  "border-error-500 focus:ring-error-500": error,
4226
4253
  "text-primary-500": !selectedOptions.length,
4227
4254
  "pr-14": showClearButton
@@ -17218,7 +17245,8 @@ var Radio = /*#__PURE__*/forwardRef(function Radio(_ref, ref) {
17218
17245
  props = _objectWithoutProperties$1(_ref, _excluded$A);
17219
17246
  var autoId = useId();
17220
17247
  var inputId = id || "".concat(autoId, "-radio");
17221
- var accentColor = radioColor || "blue";
17248
+ // Default to the brand's primary token so the radio follows theming.
17249
+ var accentColor = radioColor || "rgb(var(--dt-primary-600))";
17222
17250
  var _useState = useState(!!defaultChecked),
17223
17251
  _useState2 = _slicedToArray(_useState, 2),
17224
17252
  internalChecked = _useState2[0],
@@ -17276,7 +17304,7 @@ var Radio = /*#__PURE__*/forwardRef(function Radio(_ref, ref) {
17276
17304
  "--radio-accent": accentColor
17277
17305
  },
17278
17306
  children: jsx("span", {
17279
- className: cn("flex items-center justify-center rounded-full border transition-colors duration-150 ease-in-out border-slate-300", sizeClasses.outer, disabled ? "bg-slate-100" : "bg-white", isChecked ? "shadow-inner" : ""),
17307
+ className: cn("flex items-center justify-center rounded-full border transition-colors duration-150 ease-in-out border-slate-300 dark:border-gray-600", sizeClasses.outer, disabled ? "bg-slate-100 dark:bg-gray-800" : "bg-white dark:bg-gray-900", isChecked ? "shadow-inner" : ""),
17280
17308
  children: jsx("span", {
17281
17309
  "aria-hidden": true,
17282
17310
  className: cn("rounded-full transform transition-all duration-200 ease-out", sizeClasses.dot),
@@ -20847,11 +20875,28 @@ function _objectSpread$o(e) { for (var r = 1; r < arguments.length; r++) { var t
20847
20875
  var hasBadge = function hasBadge(badge) {
20848
20876
  return badge === 0 || Boolean(badge);
20849
20877
  };
20850
- var FootNav = /*#__PURE__*/React__default.forwardRef(function (_ref, ref) {
20851
- var _ref$items = _ref.items,
20852
- items = _ref$items === void 0 ? [] : _ref$items,
20853
- className = _ref.className,
20854
- props = _objectWithoutProperties$1(_ref, _excluded$k);
20878
+ // Only aria-* and data-* item keys reach the DOM (e.g. aria-haspopup="dialog"
20879
+ // on an item that opens a sheet); the rest of the item is data, not attributes.
20880
+ var passthrough = function passthrough(item) {
20881
+ return Object.fromEntries(Object.entries(item).filter(function (_ref) {
20882
+ var _ref2 = _slicedToArray(_ref, 1),
20883
+ key = _ref2[0];
20884
+ return /^(aria|data)-/.test(key);
20885
+ }));
20886
+ };
20887
+ var Badge$1 = function Badge(_ref3) {
20888
+ var badge = _ref3.badge;
20889
+ return jsx("span", {
20890
+ 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",
20891
+ "data-slot": "badge",
20892
+ children: badge
20893
+ });
20894
+ };
20895
+ var FootNav = /*#__PURE__*/React__default.forwardRef(function (_ref4, ref) {
20896
+ var _ref4$items = _ref4.items,
20897
+ items = _ref4$items === void 0 ? [] : _ref4$items,
20898
+ className = _ref4.className,
20899
+ props = _objectWithoutProperties$1(_ref4, _excluded$k);
20855
20900
  return jsx("nav", _objectSpread$o(_objectSpread$o({
20856
20901
  ref: ref,
20857
20902
  className: cn$1('fixed bottom-0 left-0 right-0 bg-surface border-t border-line px-2 py-2 md:hidden', className)
@@ -20860,27 +20905,37 @@ var FootNav = /*#__PURE__*/React__default.forwardRef(function (_ref, ref) {
20860
20905
  className: "flex items-stretch justify-around gap-1",
20861
20906
  children: items.map(function (item, index) {
20862
20907
  var _item$id;
20863
- return jsxs("button", {
20908
+ var isAction = item.variant === 'action';
20909
+ return jsxs("button", _objectSpread$o(_objectSpread$o({
20864
20910
  type: "button",
20865
20911
  "aria-current": item.active ? 'page' : undefined,
20866
- className: cn$1('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'),
20912
+ "data-variant": isAction ? 'action' : undefined
20913
+ }, passthrough(item)), {}, {
20914
+ className: cn$1('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'),
20867
20915
  onClick: function onClick() {
20868
20916
  var _item$onClick;
20869
20917
  return (_item$onClick = item.onClick) === null || _item$onClick === void 0 ? void 0 : _item$onClick.call(item, item);
20870
20918
  },
20871
- children: [jsxs("span", {
20919
+ children: [isAction ?
20920
+ // Raised primary circle (FAB): 56px, lifted above the bar and
20921
+ // ringed in the surface colour so it reads as cut out of the bar.
20922
+ jsxs("span", {
20923
+ 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",
20924
+ "data-slot": "icon",
20925
+ children: [item.icon, hasBadge(item.badge) && jsx(Badge$1, {
20926
+ badge: item.badge
20927
+ })]
20928
+ }) : jsxs("span", {
20872
20929
  className: "relative inline-flex text-lg",
20873
20930
  "data-slot": "icon",
20874
- children: [item.icon, hasBadge(item.badge) && jsx("span", {
20875
- 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",
20876
- "data-slot": "badge",
20877
- children: item.badge
20931
+ children: [item.icon, hasBadge(item.badge) && jsx(Badge$1, {
20932
+ badge: item.badge
20878
20933
  })]
20879
20934
  }), jsx("span", {
20880
20935
  className: "block max-w-full truncate",
20881
20936
  children: item.label
20882
20937
  })]
20883
- }, (_item$id = item.id) !== null && _item$id !== void 0 ? _item$id : index);
20938
+ }), (_item$id = item.id) !== null && _item$id !== void 0 ? _item$id : index);
20884
20939
  })
20885
20940
  })
20886
20941
  }));
@@ -20956,6 +21011,11 @@ var Breadcrumbs = /*#__PURE__*/React__default.forwardRef(function (_ref2, ref) {
20956
21011
  });
20957
21012
  Breadcrumbs.displayName = 'Breadcrumbs';
20958
21013
 
21014
+ // Internal (not exported). Grows an icon-only control to the 44×44 px minimum
21015
+ // touch target (WCAG 2.5.5, Apple HIG) on coarse pointers only, so desktop
21016
+ // layouts keep their compact size. Pair with inline-flex centering.
21017
+ var TOUCH_TARGET = "[@media(pointer:coarse)]:min-h-11 [@media(pointer:coarse)]:min-w-11";
21018
+
20959
21019
  var _excluded$i = ["isOpen", "onClose", "title", "children", "size", "dismissible", "showCloseButton", "footer", "className", "onOpen"],
20960
21020
  _excluded2$2 = ["children", "className"],
20961
21021
  _excluded3$2 = ["children", "className"],
@@ -21092,11 +21152,12 @@ var Dialog = /*#__PURE__*/React__default.forwardRef(function (_ref, _ref3) {
21092
21152
  children: title
21093
21153
  }), showCloseButton && jsx("button", {
21094
21154
  type: "button",
21095
- className: "rounded-md p-1 text-primary-400 hover:text-primary-600 hover:bg-gray-100",
21155
+ className: cn$1('inline-flex items-center justify-center rounded-md p-1 text-primary-400 hover:text-primary-600 hover:bg-gray-100', TOUCH_TARGET),
21096
21156
  onClick: onClose,
21097
21157
  "aria-label": "Close dialog",
21098
21158
  children: jsx(X, {
21099
- className: "h-5 w-5"
21159
+ className: "h-5 w-5",
21160
+ "aria-hidden": "true"
21100
21161
  })
21101
21162
  })]
21102
21163
  }), jsx("div", {
@@ -21615,7 +21676,68 @@ function useScrollLock(active) {
21615
21676
  }, [active]);
21616
21677
  }
21617
21678
 
21618
- var _excluded$f = ["isOpen", "onClose", "title", "description", "children", "placement", "size", "dismissible", "showCloseButton", "footer", "initialFocusRef", "className"],
21679
+ // Internal (not exported). Drag-down-to-dismiss for a bottom sheet. Spread
21680
+ // `dragProps` on the grab zone (handle + header), not the scrolling body, so a
21681
+ // swipe never fights the content's own scroll. Past `threshold` px (or a quick
21682
+ // flick) the drag calls onClose; otherwise the sheet snaps back.
21683
+ var FLICK_VELOCITY = 0.5; // px per ms
21684
+ function useSwipeToClose(_ref) {
21685
+ var enabled = _ref.enabled,
21686
+ onClose = _ref.onClose,
21687
+ _ref$threshold = _ref.threshold,
21688
+ threshold = _ref$threshold === void 0 ? 80 : _ref$threshold;
21689
+ var _useState = useState(0),
21690
+ _useState2 = _slicedToArray(_useState, 2),
21691
+ offset = _useState2[0],
21692
+ setOffset = _useState2[1];
21693
+ var _useState3 = useState(false),
21694
+ _useState4 = _slicedToArray(_useState3, 2),
21695
+ dragging = _useState4[0],
21696
+ setDragging = _useState4[1];
21697
+ var start = useRef(null);
21698
+ var end = useCallback(function (e) {
21699
+ if (!start.current) return;
21700
+ var dy = Math.max(0, e.clientY - start.current.y);
21701
+ var elapsed = Math.max(1, Date.now() - start.current.t);
21702
+ start.current = null;
21703
+ setDragging(false);
21704
+ setOffset(0);
21705
+ if (dy >= threshold || dy > 16 && dy / elapsed >= FLICK_VELOCITY) onClose === null || onClose === void 0 || onClose();
21706
+ }, [onClose, threshold]);
21707
+ if (!enabled) return {
21708
+ dragProps: {},
21709
+ offset: 0,
21710
+ dragging: false
21711
+ };
21712
+ return {
21713
+ offset: offset,
21714
+ dragging: dragging,
21715
+ dragProps: {
21716
+ onPointerDown: function onPointerDown(e) {
21717
+ var _e$currentTarget$setP, _e$currentTarget;
21718
+ if (e.button !== undefined && e.button !== 0) return;
21719
+ start.current = {
21720
+ y: e.clientY,
21721
+ t: Date.now()
21722
+ };
21723
+ setDragging(true);
21724
+ (_e$currentTarget$setP = (_e$currentTarget = e.currentTarget).setPointerCapture) === null || _e$currentTarget$setP === void 0 || _e$currentTarget$setP.call(_e$currentTarget, e.pointerId);
21725
+ },
21726
+ onPointerMove: function onPointerMove(e) {
21727
+ if (!start.current) return;
21728
+ setOffset(Math.max(0, e.clientY - start.current.y));
21729
+ },
21730
+ onPointerUp: end,
21731
+ onPointerCancel: function onPointerCancel() {
21732
+ start.current = null;
21733
+ setDragging(false);
21734
+ setOffset(0);
21735
+ }
21736
+ }
21737
+ };
21738
+ }
21739
+
21740
+ var _excluded$f = ["isOpen", "onClose", "title", "description", "children", "placement", "size", "dismissible", "showCloseButton", "footer", "initialFocusRef", "handle", "swipeToClose", "className", "style"],
21619
21741
  _excluded2$1 = ["className"],
21620
21742
  _excluded3$1 = ["className"],
21621
21743
  _excluded4$1 = ["className"];
@@ -21625,7 +21747,8 @@ var PLACEMENT_CLASSES = {
21625
21747
  right: "inset-y-0 right-0 h-full w-full border-l",
21626
21748
  left: "inset-y-0 left-0 h-full w-full border-r",
21627
21749
  top: "inset-x-0 top-0 w-full border-b",
21628
- bottom: "inset-x-0 bottom-0 w-full border-t"
21750
+ // Bottom sheet: rounded top and room for the home indicator (safe area).
21751
+ bottom: "inset-x-0 bottom-0 w-full overflow-hidden rounded-t-2xl border-t pb-[env(safe-area-inset-bottom)]"
21629
21752
  };
21630
21753
  var SIDE_SIZES = {
21631
21754
  sm: "max-w-xs",
@@ -21648,7 +21771,7 @@ var CloseButton = function CloseButton(_ref) {
21648
21771
  type: "button",
21649
21772
  onClick: onClose,
21650
21773
  "aria-label": "Close drawer",
21651
- className: cn$1("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),
21774
+ className: cn$1("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),
21652
21775
  children: jsx(X, {
21653
21776
  className: "h-5 w-5",
21654
21777
  "aria-hidden": "true"
@@ -21671,7 +21794,11 @@ var Drawer = /*#__PURE__*/React__default.forwardRef(function (_ref2, _ref3) {
21671
21794
  showCloseButton = _ref2$showCloseButton === void 0 ? true : _ref2$showCloseButton,
21672
21795
  footer = _ref2.footer,
21673
21796
  initialFocusRef = _ref2.initialFocusRef,
21797
+ handle = _ref2.handle,
21798
+ _ref2$swipeToClose = _ref2.swipeToClose,
21799
+ swipeToClose = _ref2$swipeToClose === void 0 ? false : _ref2$swipeToClose,
21674
21800
  className = _ref2.className,
21801
+ style = _ref2.style,
21675
21802
  props = _objectWithoutProperties$1(_ref2, _excluded$f);
21676
21803
  var panelRef = useRef(null);
21677
21804
  var titleId = "drawer-title-".concat(useId());
@@ -21681,6 +21808,17 @@ var Drawer = /*#__PURE__*/React__default.forwardRef(function (_ref2, _ref3) {
21681
21808
  // Without title/description/footer the children are the panel content, so
21682
21809
  // Drawer.Header / Drawer.Body / Drawer.Footer compose without double padding.
21683
21810
  var composed = !title && !description && !footer;
21811
+ var showHandle = handle !== null && handle !== void 0 ? handle : side === "bottom";
21812
+ var swipe = useSwipeToClose({
21813
+ enabled: swipeToClose && side === "bottom" && dismissible,
21814
+ onClose: onClose
21815
+ });
21816
+ // The grab zone (handle + header) starts a swipe; the scrolling body never does.
21817
+ var grabProps = swipeToClose && side === "bottom" && dismissible ? _objectSpread$j(_objectSpread$j({}, swipe.dragProps), {}, {
21818
+ className: "touch-none cursor-grab"
21819
+ }) : {
21820
+ className: ""
21821
+ };
21684
21822
  useScrollLock(isOpen);
21685
21823
  useFocusTrap(panelRef, {
21686
21824
  active: isOpen,
@@ -21699,7 +21837,7 @@ var Drawer = /*#__PURE__*/React__default.forwardRef(function (_ref2, _ref3) {
21699
21837
  onClick: function onClick() {
21700
21838
  return dismissible && (onClose === null || onClose === void 0 ? void 0 : onClose());
21701
21839
  }
21702
- }), jsx("div", _objectSpread$j(_objectSpread$j({
21840
+ }), jsxs("div", _objectSpread$j(_objectSpread$j({
21703
21841
  ref: function ref(node) {
21704
21842
  return setRefs$1(node, panelRef, _ref3);
21705
21843
  },
@@ -21709,16 +21847,27 @@ var Drawer = /*#__PURE__*/React__default.forwardRef(function (_ref2, _ref3) {
21709
21847
  "aria-describedby": description ? descriptionId : undefined,
21710
21848
  tabIndex: -1,
21711
21849
  "data-placement": side,
21712
- className: cn$1("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)
21850
+ className: cn$1("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),
21851
+ style: swipe.offset ? _objectSpread$j(_objectSpread$j({}, style), {}, {
21852
+ transform: "translateY(".concat(swipe.offset, "px)")
21853
+ }) : style
21713
21854
  }, props), {}, {
21714
- children: composed ? jsxs(Fragment, {
21855
+ children: [showHandle && jsx("div", _objectSpread$j(_objectSpread$j({
21856
+ "aria-hidden": "true",
21857
+ "data-testid": "drawer-handle"
21858
+ }, grabProps), {}, {
21859
+ className: cn$1("flex shrink-0 justify-center pb-1 pt-3", grabProps.className),
21860
+ children: jsx("span", {
21861
+ className: "h-1.5 w-10 rounded-full bg-gray-300 dark:bg-gray-600"
21862
+ })
21863
+ })), composed ? jsxs(Fragment, {
21715
21864
  children: [showCloseButton && jsx(CloseButton, {
21716
21865
  onClose: onClose,
21717
21866
  className: "absolute right-3 top-3"
21718
21867
  }), children]
21719
21868
  }) : jsxs(Fragment, {
21720
- children: [jsxs("div", {
21721
- className: "flex items-start justify-between gap-4 border-b border-gray-200 px-6 py-4 dark:border-gray-700",
21869
+ children: [jsxs("div", _objectSpread$j(_objectSpread$j({}, grabProps), {}, {
21870
+ className: cn$1("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),
21722
21871
  children: [jsxs("div", {
21723
21872
  className: "min-w-0",
21724
21873
  children: [title && jsx("h2", {
@@ -21733,14 +21882,14 @@ var Drawer = /*#__PURE__*/React__default.forwardRef(function (_ref2, _ref3) {
21733
21882
  }), showCloseButton && jsx(CloseButton, {
21734
21883
  onClose: onClose
21735
21884
  })]
21736
- }), jsx("div", {
21885
+ })), jsx("div", {
21737
21886
  className: "min-h-0 flex-1 overflow-y-auto px-6 py-4",
21738
21887
  children: children
21739
21888
  }), footer && jsx("div", {
21740
21889
  className: "flex items-center justify-end gap-3 border-t border-gray-200 px-6 py-4 dark:border-gray-700",
21741
21890
  children: footer
21742
21891
  })]
21743
- })
21892
+ })]
21744
21893
  }))]
21745
21894
  }), document.body);
21746
21895
  });
@@ -22148,6 +22297,7 @@ var Badge = /*#__PURE__*/React__default.forwardRef(function (_ref, ref) {
22148
22297
  success: 'bg-success-100 text-success-800',
22149
22298
  warning: 'bg-warning-100 text-warning-800',
22150
22299
  error: 'bg-error-100 text-error-800',
22300
+ info: 'bg-info-100 text-info-800',
22151
22301
  outline: 'border border-gray-300'
22152
22302
  };
22153
22303
  var sizes = {
@@ -22400,9 +22550,12 @@ var Stepper = /*#__PURE__*/React__default.forwardRef(function (_ref, ref) {
22400
22550
  "aria-label": "Progress"
22401
22551
  }, props), {}, {
22402
22552
  children: steps.map(function (step, stepIndex) {
22553
+ var _step$title;
22403
22554
  var status = getStepStatus(stepIndex);
22404
22555
  var isLast = stepIndex === steps.length - 1;
22405
22556
  var colors = statusColors[status];
22557
+ // `label` is accepted as an alias for `title` (the docs used `label`).
22558
+ var stepTitle = (_step$title = step.title) !== null && _step$title !== void 0 ? _step$title : step.label;
22406
22559
  return jsxs("div", {
22407
22560
  className: cn$1('flex items-center', {
22408
22561
  'flex-col': orientation === 'horizontal',
@@ -22422,7 +22575,7 @@ var Stepper = /*#__PURE__*/React__default.forwardRef(function (_ref, ref) {
22422
22575
  },
22423
22576
  disabled: !onStepClick || stepIndex > currentStep,
22424
22577
  "aria-current": status === 'current' ? 'step' : undefined,
22425
- "aria-label": "Step ".concat(stepIndex + 1).concat(step.title ? ": ".concat(step.title) : '').concat(status === 'completed' ? ' (completed)' : ''),
22578
+ "aria-label": "Step ".concat(stepIndex + 1).concat(stepTitle ? ": ".concat(stepTitle) : '').concat(status === 'completed' ? ' (completed)' : ''),
22426
22579
  children: status === 'completed' ? jsx(Check, {
22427
22580
  className: "h-4 w-4",
22428
22581
  "aria-hidden": "true"
@@ -22440,7 +22593,7 @@ var Stepper = /*#__PURE__*/React__default.forwardRef(function (_ref, ref) {
22440
22593
  }),
22441
22594
  children: [jsx("span", {
22442
22595
  className: cn$1('text-sm font-medium', colors.text),
22443
- children: step.title
22596
+ children: stepTitle
22444
22597
  }), step.description && jsx("span", {
22445
22598
  className: "text-xs text-muted",
22446
22599
  children: step.description
@@ -23540,7 +23693,7 @@ function _objectSpread$7(e) { for (var r = 1; r < arguments.length; r++) { var t
23540
23693
  // One map from domain state to tone + human label; unknown states are humanized, never shown raw.
23541
23694
  var TONE_TO_VARIANT = {
23542
23695
  neutral: 'secondary',
23543
- info: 'primary',
23696
+ info: 'info',
23544
23697
  success: 'success',
23545
23698
  warning: 'warning',
23546
23699
  danger: 'error',