@designa8/vibedesign-stripe-deepseek-85ea 0.2.0 → 0.2.2

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.
package/dist/index.js CHANGED
@@ -6858,6 +6858,19 @@ var Drawer = React35.forwardRef(
6858
6858
  }, [open, autoFocusNote]);
6859
6859
  const accessibleName = ariaLabel ?? (typeof title === "string" ? title : void 0);
6860
6860
  const noteIsDisabled = noteDisabled ?? actionDisabled;
6861
+ const body = children === void 0 ? null : children;
6862
+ const hasCustomBody = children !== void 0;
6863
+ const footerNode = footer === void 0 ? /* @__PURE__ */ jsx35(
6864
+ Button,
6865
+ {
6866
+ variant: "primary",
6867
+ size: "lg",
6868
+ fullWidth: true,
6869
+ disabled: actionDisabled,
6870
+ onClick: onAction,
6871
+ children: actionLabel
6872
+ }
6873
+ ) : footer;
6861
6874
  const panel = !mounted || typeof document === "undefined" ? null : ReactDOM5.createPortal(
6862
6875
  /* @__PURE__ */ jsxs32(
6863
6876
  "div",
@@ -6873,8 +6886,9 @@ var Drawer = React35.forwardRef(
6873
6886
  style: { zIndex: "var(--z-modal, 1200)" },
6874
6887
  className: cn28(
6875
6888
  "fixed inset-0 flex overflow-hidden",
6889
+ "transition-[visibility] duration-200 ease-out",
6876
6890
  side === "right" ? "justify-end" : "justify-start",
6877
- open ? "" : "pointer-events-none"
6891
+ open ? "visible" : "invisible pointer-events-none"
6878
6892
  ),
6879
6893
  ...rest,
6880
6894
  children: [
@@ -6886,7 +6900,7 @@ var Drawer = React35.forwardRef(
6886
6900
  className: cn28(
6887
6901
  "absolute inset-0 bg-scrim/40",
6888
6902
  "transition-opacity duration-200 ease-out",
6889
- "data-[state=closed]:opacity-0 data-[state=open]:opacity-100"
6903
+ open ? "opacity-100" : "opacity-0"
6890
6904
  )
6891
6905
  }
6892
6906
  ),
@@ -6897,8 +6911,11 @@ var Drawer = React35.forwardRef(
6897
6911
  "data-state": open ? "open" : "closed",
6898
6912
  className: cn28(
6899
6913
  "relative flex h-full w-full flex-col overflow-hidden bg-surface shadow-overlay",
6900
- "pointer-events-auto transition-transform duration-200 ease-out",
6901
- side === "right" ? "data-[state=closed]:translate-x-full sm:rounded-l-lg" : "data-[state=closed]:-translate-x-full sm:rounded-r-lg",
6914
+ "transition-transform duration-200 ease-out",
6915
+ open ? "translate-x-0" : "",
6916
+ !open && side === "right" ? "translate-x-full" : "",
6917
+ !open && side === "left" ? "-translate-x-full" : "",
6918
+ side === "right" ? "sm:rounded-l-lg" : "sm:rounded-r-lg",
6902
6919
  "sm:w-[var(--container-drawer,360px)]",
6903
6920
  className
6904
6921
  ),
@@ -6924,7 +6941,7 @@ var Drawer = React35.forwardRef(
6924
6941
  }
6925
6942
  )
6926
6943
  ] }),
6927
- /* @__PURE__ */ jsx35("div", { className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-xl pb-xl", children: children ?? /* @__PURE__ */ jsxs32("div", { className: "flex flex-col gap-xl", children: [
6944
+ /* @__PURE__ */ jsx35("div", { className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-xl pb-xl", children: hasCustomBody ? body : /* @__PURE__ */ jsxs32("div", { className: "flex flex-col gap-xl", children: [
6928
6945
  /* @__PURE__ */ jsxs32("div", { className: "flex flex-col gap-lg", children: [
6929
6946
  status ? /* @__PURE__ */ jsx35(
6930
6947
  Badge,
@@ -6961,17 +6978,7 @@ var Drawer = React35.forwardRef(
6961
6978
  }
6962
6979
  ) : null
6963
6980
  ] }) }),
6964
- /* @__PURE__ */ jsx35("div", { className: "shrink-0 px-xl pt-md pb-xl", children: footer ?? /* @__PURE__ */ jsx35(
6965
- Button,
6966
- {
6967
- variant: "primary",
6968
- size: "lg",
6969
- fullWidth: true,
6970
- disabled: actionDisabled,
6971
- onClick: onAction,
6972
- children: actionLabel
6973
- }
6974
- ) })
6981
+ footerNode ? /* @__PURE__ */ jsx35("div", { className: "shrink-0 px-xl pt-md pb-xl", children: footerNode }) : null
6975
6982
  ]
6976
6983
  }
6977
6984
  )
@@ -9500,8 +9507,7 @@ var Modal = React50.forwardRef(
9500
9507
  contained ? "max-h-full" : placement === "top" ? "max-h-[calc(88dvh-1rem)]" : "max-h-[calc(100dvh-2rem)]",
9501
9508
  "rounded-lg border border-hairline bg-surface shadow-overlay",
9502
9509
  "transition duration-200 ease-out",
9503
- "data-[state=open]:translate-y-0 data-[state=open]:scale-100 data-[state=open]:opacity-100",
9504
- "data-[state=closed]:translate-y-2 data-[state=closed]:scale-[0.98] data-[state=closed]:opacity-0",
9510
+ isOpen ? "translate-y-0 scale-100 opacity-100" : "translate-y-2 opacity-0",
9505
9511
  className
9506
9512
  ),
9507
9513
  ...rest,
@@ -9608,7 +9614,7 @@ var Modal = React50.forwardRef(
9608
9614
  contained ? "absolute inset-0" : "fixed inset-0",
9609
9615
  placement === "top" ? "items-start px-base pt-[12dvh]" : "items-center p-base",
9610
9616
  "transition duration-200 ease-out",
9611
- "data-[state=closed]:pointer-events-none data-[state=closed]:invisible"
9617
+ isOpen ? "visible" : "invisible pointer-events-none"
9612
9618
  ),
9613
9619
  style: { zIndex: "var(--z-modal, 1200)" },
9614
9620
  children: [
@@ -9625,7 +9631,7 @@ var Modal = React50.forwardRef(
9625
9631
  style: scrimStyle(contained),
9626
9632
  className: cn41(
9627
9633
  "transition-opacity duration-200 ease-out",
9628
- "data-[state=open]:opacity-100 data-[state=closed]:opacity-0"
9634
+ isOpen ? "opacity-100" : "opacity-0"
9629
9635
  )
9630
9636
  }
9631
9637
  ),
@@ -14526,12 +14532,59 @@ var glyph3 = (name, size = 16, strokeWidth = 1.75) => /* @__PURE__ */ jsx74(
14526
14532
  style: { color: "inherit" }
14527
14533
  }
14528
14534
  );
14535
+ var hasBadge = (badge) => {
14536
+ if (badge === void 0 || badge === null) {
14537
+ return false;
14538
+ }
14539
+ if (typeof badge === "number") {
14540
+ return Number.isFinite(badge) && badge !== 0;
14541
+ }
14542
+ const trimmed = badge.trim();
14543
+ return trimmed.length > 0 && trimmed !== "0";
14544
+ };
14545
+ var badgeText = (badge) => typeof badge === "number" ? badge > 99 ? "99+" : String(badge) : badge.trim();
14546
+ var rowAccessibleName = (label, badge) => {
14547
+ if (!hasBadge(badge)) {
14548
+ return label;
14549
+ }
14550
+ return typeof badge === "number" ? `${label}, ${badge} pending` : `${label}, ${badgeText(badge)}`;
14551
+ };
14552
+ var RailBadge = ({
14553
+ badge,
14554
+ active
14555
+ }) => /* @__PURE__ */ jsx74(
14556
+ "span",
14557
+ {
14558
+ "aria-hidden": "true",
14559
+ "data-active": active || void 0,
14560
+ className: cn65(
14561
+ "ml-auto flex h-4 min-w-4 shrink-0 items-center justify-center rounded-full",
14562
+ "bg-primary px-xxs text-caption text-on-primary",
14563
+ "data-[active=true]:bg-on-primary data-[active=true]:text-primary"
14564
+ ),
14565
+ children: badgeText(badge)
14566
+ }
14567
+ );
14568
+ var railGlyph = (item, folded) => /* @__PURE__ */ jsxs71("span", { className: "relative inline-flex shrink-0 items-center", children: [
14569
+ glyph3(item.icon, 16, 1.75),
14570
+ folded && hasBadge(item.badge) ? /* @__PURE__ */ jsx74(
14571
+ "span",
14572
+ {
14573
+ "aria-hidden": "true",
14574
+ className: cn65(
14575
+ "pointer-events-none absolute -right-xxs -top-xxs size-2 rounded-full",
14576
+ "bg-primary",
14577
+ "group-data-[active=true]:bg-on-primary"
14578
+ )
14579
+ }
14580
+ ) : null
14581
+ ] });
14529
14582
  var RowLabel = ({
14530
14583
  folded,
14531
14584
  children
14532
14585
  }) => folded ? /* @__PURE__ */ jsx74("span", { className: "sr-only", children }) : /* @__PURE__ */ jsx74("span", { className: "truncate", children });
14533
14586
  var railRowClass = (active, folded) => cn65(
14534
- "flex w-full cursor-pointer items-center rounded-lg border-0 bg-transparent",
14587
+ "group flex w-full cursor-pointer items-center rounded-lg border-0 bg-transparent",
14535
14588
  "text-body-md transition duration-150 ease-out",
14536
14589
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-blue",
14537
14590
  "focus-visible:ring-inset",
@@ -14867,6 +14920,7 @@ var SidebarDesktop = React74.forwardRef(
14867
14920
  className: "flex flex-col gap-xxs",
14868
14921
  children: navItems.map((item) => {
14869
14922
  const active = item.id === activeId;
14923
+ const badged = hasBadge(item.badge);
14870
14924
  if (!item.children?.length) {
14871
14925
  return /* @__PURE__ */ jsxs71(
14872
14926
  "a",
@@ -14874,11 +14928,13 @@ var SidebarDesktop = React74.forwardRef(
14874
14928
  href: item.href ?? `#${item.id}`,
14875
14929
  onClick: navigate({ id: item.id, href: item.href }),
14876
14930
  "aria-current": active ? "page" : void 0,
14877
- "aria-label": isFolded ? item.label : void 0,
14931
+ "data-active": active,
14932
+ "aria-label": isFolded || badged ? rowAccessibleName(item.label, item.badge) : void 0,
14878
14933
  className: railRowClass(active, isFolded),
14879
14934
  children: [
14880
- glyph3(item.icon, 16, 1.75),
14881
- /* @__PURE__ */ jsx74(RowLabel, { folded: isFolded, children: item.label })
14935
+ railGlyph(item, isFolded),
14936
+ /* @__PURE__ */ jsx74(RowLabel, { folded: isFolded, children: item.label }),
14937
+ !isFolded && badged ? /* @__PURE__ */ jsx74(RailBadge, { badge: item.badge, active }) : null
14882
14938
  ]
14883
14939
  },
14884
14940
  item.id
@@ -14894,22 +14950,32 @@ var SidebarDesktop = React74.forwardRef(
14894
14950
  size: "rail",
14895
14951
  "aria-expanded": expanded,
14896
14952
  "aria-controls": subId,
14897
- "aria-label": isFolded ? item.label : void 0,
14953
+ "aria-label": isFolded || badged ? rowAccessibleName(item.label, item.badge) : void 0,
14898
14954
  "data-active": active,
14899
14955
  "data-folded": isFolded,
14900
14956
  onClick: () => toggleExpanded(item.id),
14901
- leadingIcon: glyph3(item.icon, 16, 1.75),
14902
- trailingIcon: isFolded ? void 0 : /* @__PURE__ */ jsx74(
14903
- "span",
14904
- {
14905
- "aria-hidden": "true",
14906
- className: cn65(
14907
- "flex shrink-0 items-center transition-transform duration-200 ease-out",
14908
- expanded ? "rotate-180" : "rotate-0"
14909
- ),
14910
- children: glyph3("chevron-down", 16, 2)
14911
- }
14912
- ),
14957
+ className: "group",
14958
+ leadingIcon: railGlyph(item, isFolded),
14959
+ trailingIcon: isFolded ? void 0 : /* @__PURE__ */ jsxs71("span", { className: "flex items-center gap-xs", children: [
14960
+ badged ? /* @__PURE__ */ jsx74(
14961
+ RailBadge,
14962
+ {
14963
+ badge: item.badge,
14964
+ active
14965
+ }
14966
+ ) : null,
14967
+ /* @__PURE__ */ jsx74(
14968
+ "span",
14969
+ {
14970
+ "aria-hidden": "true",
14971
+ className: cn65(
14972
+ "flex shrink-0 items-center transition-transform duration-200 ease-out",
14973
+ expanded ? "rotate-180" : "rotate-0"
14974
+ ),
14975
+ children: glyph3("chevron-down", 16, 2)
14976
+ }
14977
+ )
14978
+ ] }),
14913
14979
  children: /* @__PURE__ */ jsx74(RowLabel, { folded: isFolded, children: item.label })
14914
14980
  }
14915
14981
  ),
@@ -14962,17 +15028,20 @@ var SidebarDesktop = React74.forwardRef(
14962
15028
  ),
14963
15029
  /* @__PURE__ */ jsx74("nav", { "aria-label": "Secondary", className: "mt-lg flex flex-col gap-xxs", children: secondaryNav.map((item) => {
14964
15030
  const active = item.id === secondaryActiveId;
15031
+ const badged = hasBadge(item.badge);
14965
15032
  return /* @__PURE__ */ jsxs71(
14966
15033
  "a",
14967
15034
  {
14968
15035
  href: item.href ?? `#${item.id}`,
14969
15036
  onClick: navigate({ id: item.id, href: item.href }),
14970
15037
  "aria-current": active ? "page" : void 0,
14971
- "aria-label": isFolded ? item.label : void 0,
15038
+ "data-active": active,
15039
+ "aria-label": isFolded || badged ? rowAccessibleName(item.label, item.badge) : void 0,
14972
15040
  className: railRowClass(active, isFolded),
14973
15041
  children: [
14974
- glyph3(item.icon, 16, 1.75),
14975
- /* @__PURE__ */ jsx74(RowLabel, { folded: isFolded, children: item.label })
15042
+ railGlyph(item, isFolded),
15043
+ /* @__PURE__ */ jsx74(RowLabel, { folded: isFolded, children: item.label }),
15044
+ !isFolded && badged ? /* @__PURE__ */ jsx74(RailBadge, { badge: item.badge, active }) : null
14976
15045
  ]
14977
15046
  },
14978
15047
  item.id
@@ -15099,6 +15168,39 @@ var SAMPLE_SECONDARY2 = [
15099
15168
  ];
15100
15169
  var SAMPLE_PLAN2 = { name: "Pro", price: "$2,400.00 / month", href: "#plan" };
15101
15170
  var glyph4 = (name, size = 18, strokeWidth = 1.75) => /* @__PURE__ */ jsx75(Icon, { name, size, strokeWidth, style: { color: "inherit" } });
15171
+ var hasBadge2 = (badge) => {
15172
+ if (badge === void 0 || badge === null) {
15173
+ return false;
15174
+ }
15175
+ if (typeof badge === "number") {
15176
+ return Number.isFinite(badge) && badge !== 0;
15177
+ }
15178
+ const trimmed = badge.trim();
15179
+ return trimmed.length > 0 && trimmed !== "0";
15180
+ };
15181
+ var badgeText2 = (badge) => typeof badge === "number" ? badge > 99 ? "99+" : String(badge) : badge.trim();
15182
+ var rowAccessibleName2 = (label, badge) => {
15183
+ if (!hasBadge2(badge)) {
15184
+ return label;
15185
+ }
15186
+ return typeof badge === "number" ? `${label}, ${badge} pending` : `${label}, ${badgeText2(badge)}`;
15187
+ };
15188
+ var NavBadge = ({
15189
+ badge,
15190
+ active
15191
+ }) => /* @__PURE__ */ jsx75(
15192
+ "span",
15193
+ {
15194
+ "aria-hidden": "true",
15195
+ "data-active": active || void 0,
15196
+ className: cn66(
15197
+ "ml-auto flex h-4 min-w-4 shrink-0 items-center justify-center rounded-full",
15198
+ "bg-primary px-xxs text-caption text-on-primary",
15199
+ "data-[active=true]:bg-on-primary data-[active=true]:text-primary"
15200
+ ),
15201
+ children: badgeText2(badge)
15202
+ }
15203
+ );
15102
15204
  var rowClass = (active) => cn66(
15103
15205
  "flex min-h-10 w-full cursor-pointer items-center gap-md rounded-lg px-md py-sm",
15104
15206
  "text-body-md transition duration-150 ease-out",
@@ -15411,6 +15513,7 @@ var SidebarMobile = React75.forwardRef(
15411
15513
  ] }),
15412
15514
  /* @__PURE__ */ jsx75("nav", { "aria-label": "Primary", className: "mt-md flex flex-col gap-xxs", children: navItems.map((item) => {
15413
15515
  const active = item.id === activeId;
15516
+ const badged = hasBadge2(item.badge);
15414
15517
  if (!item.children?.length) {
15415
15518
  return /* @__PURE__ */ jsxs72(
15416
15519
  "a",
@@ -15418,10 +15521,18 @@ var SidebarMobile = React75.forwardRef(
15418
15521
  href: item.href ?? `#${item.id}`,
15419
15522
  onClick: navigate({ id: item.id, href: item.href }),
15420
15523
  "aria-current": active ? "page" : void 0,
15524
+ "aria-label": badged ? rowAccessibleName2(item.label, item.badge) : void 0,
15421
15525
  className: rowClass(active),
15422
15526
  children: [
15423
15527
  glyph4(item.icon, 18, 1.75),
15424
- /* @__PURE__ */ jsx75("span", { className: "truncate", children: item.label })
15528
+ /* @__PURE__ */ jsx75("span", { className: "truncate", children: item.label }),
15529
+ badged ? /* @__PURE__ */ jsx75(
15530
+ NavBadge,
15531
+ {
15532
+ badge: item.badge,
15533
+ active
15534
+ }
15535
+ ) : null
15425
15536
  ]
15426
15537
  },
15427
15538
  item.id
@@ -15437,20 +15548,31 @@ var SidebarMobile = React75.forwardRef(
15437
15548
  size: "rail",
15438
15549
  "aria-expanded": expanded,
15439
15550
  "aria-controls": subId,
15551
+ "aria-label": badged ? rowAccessibleName2(item.label, item.badge) : void 0,
15440
15552
  "data-active": active,
15441
15553
  onClick: () => toggleExpanded(item.id),
15442
15554
  className: "px-md",
15443
15555
  leadingIcon: glyph4(item.icon, 18, 1.75),
15444
- trailingIcon: /* @__PURE__ */ jsx75(
15445
- "span",
15446
- {
15447
- className: cn66(
15448
- "flex shrink-0 items-center transition-transform duration-200 ease-out",
15449
- expanded ? "rotate-180" : "rotate-0"
15450
- ),
15451
- children: glyph4("chevron-down", 18, 2)
15452
- }
15453
- ),
15556
+ trailingIcon: /* @__PURE__ */ jsxs72("span", { className: "flex items-center gap-xs", children: [
15557
+ badged ? /* @__PURE__ */ jsx75(
15558
+ NavBadge,
15559
+ {
15560
+ badge: item.badge,
15561
+ active
15562
+ }
15563
+ ) : null,
15564
+ /* @__PURE__ */ jsx75(
15565
+ "span",
15566
+ {
15567
+ "aria-hidden": "true",
15568
+ className: cn66(
15569
+ "flex shrink-0 items-center transition-transform duration-200 ease-out",
15570
+ expanded ? "rotate-180" : "rotate-0"
15571
+ ),
15572
+ children: glyph4("chevron-down", 18, 2)
15573
+ }
15574
+ )
15575
+ ] }),
15454
15576
  children: /* @__PURE__ */ jsx75("span", { className: "truncate text-left", children: item.label })
15455
15577
  }
15456
15578
  ),
@@ -15506,16 +15628,25 @@ var SidebarMobile = React75.forwardRef(
15506
15628
  /* @__PURE__ */ jsx75(Divider, { className: "my-md" }),
15507
15629
  /* @__PURE__ */ jsx75("nav", { "aria-label": "Secondary", className: "flex flex-col gap-xxs", children: secondaryNav.map((item) => {
15508
15630
  const active = item.id === secondaryActiveId;
15631
+ const badged = hasBadge2(item.badge);
15509
15632
  return /* @__PURE__ */ jsxs72(
15510
15633
  "a",
15511
15634
  {
15512
15635
  href: item.href ?? `#${item.id}`,
15513
15636
  onClick: navigate({ id: item.id, href: item.href }),
15514
15637
  "aria-current": active ? "page" : void 0,
15638
+ "aria-label": badged ? rowAccessibleName2(item.label, item.badge) : void 0,
15515
15639
  className: rowClass(active),
15516
15640
  children: [
15517
15641
  glyph4(item.icon, 18, 1.75),
15518
- /* @__PURE__ */ jsx75("span", { className: "truncate", children: item.label })
15642
+ /* @__PURE__ */ jsx75("span", { className: "truncate", children: item.label }),
15643
+ badged ? /* @__PURE__ */ jsx75(
15644
+ NavBadge,
15645
+ {
15646
+ badge: item.badge,
15647
+ active
15648
+ }
15649
+ ) : null
15519
15650
  ]
15520
15651
  },
15521
15652
  item.id
package/dist/styles.css CHANGED
@@ -1114,6 +1114,10 @@
1114
1114
  --tw-translate-y: calc(1 / 2 * 100%);
1115
1115
  translate: var(--tw-translate-x) var(--tw-translate-y);
1116
1116
  }
1117
+ .translate-y-2 {
1118
+ --tw-translate-y: calc(var(--spacing) * 2);
1119
+ translate: var(--tw-translate-x) var(--tw-translate-y);
1120
+ }
1117
1121
  .translate-y-px {
1118
1122
  --tw-translate-y: 1px;
1119
1123
  translate: var(--tw-translate-x) var(--tw-translate-y);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@designa8/vibedesign-stripe-deepseek-85ea",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Complete design system \"My Project stripe-deepseek\" generated by Atoms Design.",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",
@@ -62,9 +62,15 @@ export interface DrawerProps
62
62
  actionDisabled?: boolean;
63
63
  /** Fires when the primary action is pressed. */
64
64
  onAction?: () => void;
65
- /** Replaces the pinned action footer. */
65
+ /**
66
+ * Replaces the pinned action footer. Pass `null` to render no footer at all;
67
+ * the default action only appears when the prop is left `undefined`.
68
+ */
66
69
  footer?: React.ReactNode;
67
- /** Replaces the default payment body. */
70
+ /**
71
+ * Replaces the default payment body. Pass `null` to render an empty body;
72
+ * the default fixture only appears when the prop is left `undefined`.
73
+ */
68
74
  children?: React.ReactNode;
69
75
  /** Accessible name of the close control. */
70
76
  closeLabel?: string;
@@ -77,6 +83,11 @@ export interface DrawerProps
77
83
  * `translate-x`, and only the body between the pinned heading and footer
78
84
  * scrolls.
79
85
  *
86
+ * The closed state is expressed with plain utilities (`invisible`,
87
+ * `pointer-events-none`, the travel offset) rather than `data-[state=closed]:*`
88
+ * variants, so the panel is never painted, never focusable, and never swallows
89
+ * pointer events even in a build that emits no data-state rules.
90
+ *
80
91
  * The `role="dialog"` element is the full-viewport stage, not the travelling
81
92
  * surface: the box the user reads stays put while the sheet inside it slides, so
82
93
  * a closed drawer never parks itself outside the viewport.
@@ -157,6 +168,24 @@ export const Drawer = React.forwardRef<HTMLDivElement, DrawerProps>(
157
168
  ariaLabel ?? (typeof title === "string" ? title : undefined);
158
169
  const noteIsDisabled = noteDisabled ?? actionDisabled;
159
170
 
171
+ /* `undefined` means "not supplied" — `null` is an explicit "render nothing". */
172
+ const body = children === undefined ? null : children;
173
+ const hasCustomBody = children !== undefined;
174
+ const footerNode =
175
+ footer === undefined ? (
176
+ <Button
177
+ variant="primary"
178
+ size="lg"
179
+ fullWidth
180
+ disabled={actionDisabled}
181
+ onClick={onAction}
182
+ >
183
+ {actionLabel}
184
+ </Button>
185
+ ) : (
186
+ footer
187
+ );
188
+
160
189
  const panel =
161
190
  !mounted || typeof document === "undefined"
162
191
  ? null
@@ -173,8 +202,9 @@ export const Drawer = React.forwardRef<HTMLDivElement, DrawerProps>(
173
202
  style={{ zIndex: "var(--z-modal, 1200)" }}
174
203
  className={cn(
175
204
  "fixed inset-0 flex overflow-hidden",
205
+ "transition-[visibility] duration-200 ease-out",
176
206
  side === "right" ? "justify-end" : "justify-start",
177
- open ? "" : "pointer-events-none",
207
+ open ? "visible" : "invisible pointer-events-none",
178
208
  )}
179
209
  {...rest}
180
210
  >
@@ -186,7 +216,7 @@ export const Drawer = React.forwardRef<HTMLDivElement, DrawerProps>(
186
216
  className={cn(
187
217
  "absolute inset-0 bg-scrim/40",
188
218
  "transition-opacity duration-200 ease-out",
189
- "data-[state=closed]:opacity-0 data-[state=open]:opacity-100",
219
+ open ? "opacity-100" : "opacity-0",
190
220
  )}
191
221
  />
192
222
 
@@ -195,10 +225,11 @@ export const Drawer = React.forwardRef<HTMLDivElement, DrawerProps>(
195
225
  data-state={open ? "open" : "closed"}
196
226
  className={cn(
197
227
  "relative flex h-full w-full flex-col overflow-hidden bg-surface shadow-overlay",
198
- "pointer-events-auto transition-transform duration-200 ease-out",
199
- side === "right"
200
- ? "data-[state=closed]:translate-x-full sm:rounded-l-lg"
201
- : "data-[state=closed]:-translate-x-full sm:rounded-r-lg",
228
+ "transition-transform duration-200 ease-out",
229
+ open ? "translate-x-0" : "",
230
+ !open && side === "right" ? "translate-x-full" : "",
231
+ !open && side === "left" ? "-translate-x-full" : "",
232
+ side === "right" ? "sm:rounded-l-lg" : "sm:rounded-r-lg",
202
233
  "sm:w-[var(--container-drawer,360px)]",
203
234
  className,
204
235
  )}
@@ -221,7 +252,9 @@ export const Drawer = React.forwardRef<HTMLDivElement, DrawerProps>(
221
252
  </div>
222
253
 
223
254
  <div className="min-h-0 flex-1 overflow-y-auto overscroll-contain px-xl pb-xl">
224
- {children ?? (
255
+ {hasCustomBody ? (
256
+ body
257
+ ) : (
225
258
  <div className="flex flex-col gap-xl">
226
259
  <div className="flex flex-col gap-lg">
227
260
  {status ? (
@@ -269,19 +302,9 @@ export const Drawer = React.forwardRef<HTMLDivElement, DrawerProps>(
269
302
  )}
270
303
  </div>
271
304
 
272
- <div className="shrink-0 px-xl pt-md pb-xl">
273
- {footer ?? (
274
- <Button
275
- variant="primary"
276
- size="lg"
277
- fullWidth
278
- disabled={actionDisabled}
279
- onClick={onAction}
280
- >
281
- {actionLabel}
282
- </Button>
283
- )}
284
- </div>
305
+ {footerNode ? (
306
+ <div className="shrink-0 px-xl pt-md pb-xl">{footerNode}</div>
307
+ ) : null}
285
308
  </div>
286
309
  </div>,
287
310
  document.body,
@@ -150,6 +150,12 @@ export interface ModalProps
150
150
  * the body portals its listbox to `document.body` at `--z-popover`, above this
151
151
  * dialog's `--z-modal`, so opening it can never grow the panel or paint
152
152
  * underneath it.
153
+ *
154
+ * The closed state is expressed with plain utilities (`invisible`,
155
+ * `pointer-events-none`, `opacity-0`, the resting offset) instead of
156
+ * `data-[state=closed]:*` variants, so the dialog is hidden, unfocusable, and
157
+ * click-through even in a build that emits no data-state rules. `data-state`
158
+ * is still published for consumers that style it.
153
159
  */
154
160
  export const Modal = React.forwardRef<HTMLDivElement, ModalProps>(
155
161
  (
@@ -387,8 +393,9 @@ export const Modal = React.forwardRef<HTMLDivElement, ModalProps>(
387
393
  : "max-h-[calc(100dvh-2rem)]",
388
394
  "rounded-lg border border-hairline bg-surface shadow-overlay",
389
395
  "transition duration-200 ease-out",
390
- "data-[state=open]:translate-y-0 data-[state=open]:scale-100 data-[state=open]:opacity-100",
391
- "data-[state=closed]:translate-y-2 data-[state=closed]:scale-[0.98] data-[state=closed]:opacity-0",
396
+ isOpen
397
+ ? "translate-y-0 scale-100 opacity-100"
398
+ : "translate-y-2 opacity-0",
392
399
  className,
393
400
  )}
394
401
  {...rest}
@@ -510,7 +517,7 @@ export const Modal = React.forwardRef<HTMLDivElement, ModalProps>(
510
517
  ? "items-start px-base pt-[12dvh]"
511
518
  : "items-center p-base",
512
519
  "transition duration-200 ease-out",
513
- "data-[state=closed]:pointer-events-none data-[state=closed]:invisible",
520
+ isOpen ? "visible" : "invisible pointer-events-none",
514
521
  )}
515
522
  style={{ zIndex: "var(--z-modal, 1200)" }}
516
523
  >
@@ -526,7 +533,7 @@ export const Modal = React.forwardRef<HTMLDivElement, ModalProps>(
526
533
  style={scrimStyle(contained)}
527
534
  className={cn(
528
535
  "transition-opacity duration-200 ease-out",
529
- "data-[state=open]:opacity-100 data-[state=closed]:opacity-0",
536
+ isOpen ? "opacity-100" : "opacity-0",
530
537
  )}
531
538
  />
532
539