@godxjp/ui 18.15.4 → 19.0.0

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 (145) hide show
  1. package/dist/app/date-format-labels.d.ts +1 -1
  2. package/dist/app/time-format-labels.d.ts +1 -1
  3. package/dist/components/data-display/badge.d.ts +1 -1
  4. package/dist/components/data-display/card.d.ts +4 -13
  5. package/dist/components/data-display/card.js +2 -15
  6. package/dist/components/data-display/data-table.d.ts +3 -8
  7. package/dist/components/data-display/data-table.js +106 -68
  8. package/dist/components/data-display/descriptions.js +34 -5
  9. package/dist/components/data-display/empty-state.js +1 -1
  10. package/dist/components/data-display/permission-matrix.js +7 -7
  11. package/dist/components/data-display/popover.js +2 -9
  12. package/dist/components/data-display/qr-code.d.ts +1 -1
  13. package/dist/components/data-display/scroll-area.d.ts +3 -1
  14. package/dist/components/data-display/scroll-area.js +150 -16
  15. package/dist/components/data-display/table.js +12 -3
  16. package/dist/components/data-entry/branch-scope-picker.js +4 -4
  17. package/dist/components/data-entry/calendar.js +15 -24
  18. package/dist/components/data-entry/cascader.js +67 -71
  19. package/dist/components/data-entry/checkbox.js +9 -1
  20. package/dist/components/data-entry/command.d.ts +6 -6
  21. package/dist/components/data-entry/date-picker.js +28 -15
  22. package/dist/components/data-entry/date-range-picker.js +10 -10
  23. package/dist/components/data-entry/form-field.js +7 -3
  24. package/dist/components/data-entry/index.d.ts +2 -1
  25. package/dist/components/data-entry/input.js +8 -19
  26. package/dist/components/data-entry/label.js +4 -2
  27. package/dist/components/data-entry/month-picker.js +16 -15
  28. package/dist/components/data-entry/month-range-picker.js +17 -16
  29. package/dist/components/data-entry/radio.js +6 -1
  30. package/dist/components/data-entry/search-select.js +29 -29
  31. package/dist/components/data-entry/select.js +15 -18
  32. package/dist/components/data-entry/switch.js +7 -1
  33. package/dist/components/data-entry/textarea.d.ts +56 -0
  34. package/dist/components/data-entry/textarea.js +103 -40
  35. package/dist/components/data-entry/time-picker.js +52 -52
  36. package/dist/components/data-entry/toggle-group.d.ts +1 -0
  37. package/dist/components/data-entry/toggle.d.ts +1 -1
  38. package/dist/components/data-entry/transfer.js +14 -15
  39. package/dist/components/data-entry/tree-select.js +16 -22
  40. package/dist/components/data-entry/upload-crop-dialog.js +4 -4
  41. package/dist/components/data-entry/upload.d.ts +1 -1
  42. package/dist/components/data-entry/upload.js +46 -46
  43. package/dist/components/feedback/alert.js +7 -14
  44. package/dist/components/feedback/dialog.d.ts +23 -32
  45. package/dist/components/feedback/dialog.js +16 -13
  46. package/dist/components/feedback/sheet.d.ts +1 -1
  47. package/dist/components/feedback/sheet.js +14 -14
  48. package/dist/components/feedback/skeleton.js +13 -10
  49. package/dist/components/feedback/sonner.d.ts +1 -1
  50. package/dist/components/feedback/sonner.js +17 -8
  51. package/dist/components/feedback/tooltip.js +1 -1
  52. package/dist/components/general/activity.d.ts +44 -0
  53. package/dist/components/general/activity.js +65 -0
  54. package/dist/components/general/button.d.ts +2 -2
  55. package/dist/components/general/button.js +11 -24
  56. package/dist/components/general/index.d.ts +2 -0
  57. package/dist/components/general/index.js +2 -0
  58. package/dist/components/layout/app-shell.js +5 -3
  59. package/dist/components/layout/auth-divider.d.ts +9 -2
  60. package/dist/components/layout/auth-divider.js +7 -11
  61. package/dist/components/layout/index.d.ts +1 -0
  62. package/dist/components/layout/page-container.d.ts +1 -1
  63. package/dist/components/layout/page-container.js +32 -20
  64. package/dist/components/layout/resizable.d.ts +12 -12
  65. package/dist/components/layout/separator.d.ts +1 -0
  66. package/dist/components/layout/service-role-panel.js +47 -42
  67. package/dist/components/layout/sidebar.js +13 -1
  68. package/dist/components/layout/split-pane.d.ts +12 -1
  69. package/dist/components/layout/split-pane.js +13 -4
  70. package/dist/components/navigation/app-setting-picker.js +5 -14
  71. package/dist/components/navigation/dropdown-menu.js +10 -16
  72. package/dist/components/navigation/menubar.d.ts +3 -6
  73. package/dist/components/navigation/pagination-utils.d.ts +15 -2
  74. package/dist/components/navigation/pagination-utils.js +27 -21
  75. package/dist/components/navigation/pagination.d.ts +4 -4
  76. package/dist/components/navigation/pagination.js +2 -2
  77. package/dist/components/navigation/steps.js +31 -67
  78. package/dist/components/navigation/tabs.js +17 -5
  79. package/dist/components/query/infinite-query-state.js +2 -2
  80. package/dist/components/ui/accordion.d.ts +1 -1
  81. package/dist/components/ui/avatar.d.ts +1 -1
  82. package/dist/components/ui/avatar.js +29 -10
  83. package/dist/components/ui/input-otp.d.ts +8 -6
  84. package/dist/components/ui/rating.js +1 -1
  85. package/dist/components/ui/separator.d.ts +27 -2
  86. package/dist/components/ui/separator.js +42 -11
  87. package/dist/components/ui/toggle-group.d.ts +15 -5
  88. package/dist/components/ui/toggle-group.js +43 -18
  89. package/dist/components/ui/toggle.d.ts +66 -5
  90. package/dist/components/ui/toggle.js +64 -9
  91. package/dist/i18n/messages/en.json +8 -0
  92. package/dist/i18n/messages/ja.json +8 -0
  93. package/dist/i18n/messages/vi.json +8 -0
  94. package/dist/lib/control-styles.d.ts +14 -0
  95. package/dist/lib/control-styles.js +2 -0
  96. package/dist/props/components/data-display.prop.d.ts +85 -3
  97. package/dist/props/components/data-entry.prop.d.ts +17 -0
  98. package/dist/props/components/general.prop.d.ts +52 -1
  99. package/dist/props/components/layout.prop.d.ts +137 -2
  100. package/dist/props/registry.d.ts +116 -5
  101. package/dist/props/registry.js +165 -4
  102. package/dist/props/vocabulary/index.d.ts +2 -2
  103. package/dist/props/vocabulary/interaction.prop.d.ts +15 -0
  104. package/dist/props/vocabulary/layout.prop.d.ts +8 -0
  105. package/dist/styles/alert-layout.css +69 -3
  106. package/dist/styles/badge-layout.css +2 -2
  107. package/dist/styles/base.css +6 -0
  108. package/dist/styles/card-layout.css +25 -8
  109. package/dist/styles/control.css +1150 -29
  110. package/dist/styles/data-display-layout.css +185 -11
  111. package/dist/styles/data-entry-layout.css +352 -1
  112. package/dist/styles/density.css +2 -2
  113. package/dist/styles/dialog-layout.css +203 -4
  114. package/dist/styles/focus-ring.css +155 -0
  115. package/dist/styles/form-layout.css +50 -5
  116. package/dist/styles/index.css +1 -0
  117. package/dist/styles/layout.css +412 -23
  118. package/dist/styles/motion.css +178 -0
  119. package/dist/styles/navigation-layout.css +398 -22
  120. package/dist/styles/shell-layout.css +137 -39
  121. package/dist/styles/table-layout.css +153 -22
  122. package/dist/styles/toggle.css +59 -0
  123. package/dist/tokens/base.css +5 -0
  124. package/dist/tokens/components/activity.css +64 -0
  125. package/dist/tokens/components/badge.css +7 -0
  126. package/dist/tokens/components/card.css +14 -10
  127. package/dist/tokens/components/chart.css +1 -1
  128. package/dist/tokens/components/control.css +358 -8
  129. package/dist/tokens/components/data-display.css +75 -0
  130. package/dist/tokens/components/data-entry.css +25 -0
  131. package/dist/tokens/components/descriptions.css +22 -0
  132. package/dist/tokens/components/feedback.css +143 -4
  133. package/dist/tokens/components/form.css +16 -0
  134. package/dist/tokens/components/legal-document.css +5 -1
  135. package/dist/tokens/components/navigation.css +109 -0
  136. package/dist/tokens/components/scroll-area.css +21 -0
  137. package/dist/tokens/components/separator.css +52 -0
  138. package/dist/tokens/components/shell.css +132 -20
  139. package/dist/tokens/components/table.css +52 -3
  140. package/dist/tokens/components/toggle.css +82 -0
  141. package/dist/tokens/components/upload.css +107 -0
  142. package/dist/tokens/foundation.css +171 -10
  143. package/dist/tokens/semantic/layout.css +120 -1
  144. package/package.json +84 -68
  145. package/scripts/ui-audit.mjs +51 -2
@@ -18,36 +18,18 @@ function StepIcon({
18
18
  if (icon)
19
19
  return /* @__PURE__ */ jsx("span", { className: cn("flex items-center justify-center", controlIconClass), children: icon });
20
20
  if (type === "dot") {
21
- return /* @__PURE__ */ jsx("span", { className: cn("flex items-center justify-center", controlIconClass), children: /* @__PURE__ */ jsx(
22
- "span",
23
- {
24
- className: cn(
25
- "block size-2.5 rounded-full",
26
- status === "finish" && "bg-primary",
27
- status === "process" && "bg-primary ring-primary/20 ring-4",
28
- status === "error" && "bg-destructive",
29
- status === "wait" && "bg-muted-foreground/30"
30
- )
31
- }
32
- ) });
21
+ return /* @__PURE__ */ jsx("span", { className: cn("flex items-center justify-center", controlIconClass), children: /* @__PURE__ */ jsx("span", { className: "ui-steps-dot", "data-status": status }) });
33
22
  }
34
23
  return /* @__PURE__ */ jsxs(
35
24
  "span",
36
25
  {
37
- className: cn(
38
- "flex items-center justify-center",
39
- controlIconClass,
40
- "rounded-full border-2 text-sm font-medium",
41
- status === "finish" && "border-primary bg-primary text-primary-foreground",
42
- status === "process" && "border-primary text-primary",
43
- status === "error" && "border-destructive bg-destructive text-destructive-foreground",
44
- status === "wait" && "border-muted-foreground/30 text-muted-foreground"
45
- ),
26
+ "data-status": status,
27
+ className: cn("flex items-center justify-center", controlIconClass, "ui-steps-marker"),
46
28
  children: [
47
- status === "finish" && /* @__PURE__ */ jsx(Check, { className: "size-4", "aria-hidden": "true" }),
48
- status === "process" && /* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": "true" }),
49
- status === "error" && /* @__PURE__ */ jsx(X, { className: "size-4", "aria-hidden": "true" }),
50
- status === "wait" && /* @__PURE__ */ jsx(Circle, { className: "size-3 fill-current", "aria-hidden": "true" })
29
+ status === "finish" && /* @__PURE__ */ jsx(Check, { className: "ui-steps-marker-icon", "aria-hidden": "true" }),
30
+ status === "process" && /* @__PURE__ */ jsx(Loader2, { className: "ui-steps-marker-icon animate-spin", "aria-hidden": "true" }),
31
+ status === "error" && /* @__PURE__ */ jsx(X, { className: "ui-steps-marker-icon", "aria-hidden": "true" }),
32
+ status === "wait" && /* @__PURE__ */ jsx(Circle, { className: "ui-steps-wait-icon", "aria-hidden": "true" })
51
33
  ]
52
34
  }
53
35
  );
@@ -74,11 +56,8 @@ function Steps({
74
56
  return /* @__PURE__ */ jsx(
75
57
  "ol",
76
58
  {
77
- className: cn(
78
- "flex w-full",
79
- inline ? "ui-steps-inline" : isVertical ? "flex-col gap-0" : "flex-row items-start",
80
- className
81
- ),
59
+ "data-direction": inline ? void 0 : isVertical ? "vertical" : "horizontal",
60
+ className: cn("flex w-full", inline ? "ui-steps-inline" : "ui-steps-list", className),
82
61
  "aria-label": t("navigation.steps.ariaLabel"),
83
62
  children: items.map((item, index) => {
84
63
  const absoluteIndex = base + index;
@@ -90,9 +69,10 @@ function Steps({
90
69
  const statusLabel = t(
91
70
  stepStatus === "finish" ? "navigation.steps.status.finish" : stepStatus === "process" ? "navigation.steps.status.process" : stepStatus === "error" ? "navigation.steps.status.error" : "navigation.steps.status.wait"
92
71
  );
72
+ const stepDirection = inline ? void 0 : isVertical ? "vertical" : "horizontal";
93
73
  const stepClassName = cn(
94
- "group flex min-w-0",
95
- inline ? "ui-steps-inline-control" : isVertical ? "flex-row items-start gap-3" : "flex-col items-center",
74
+ "group",
75
+ inline ? "ui-steps-inline-control" : "ui-steps-control",
96
76
  clickable ? "cursor-pointer" : "cursor-default"
97
77
  );
98
78
  const stepInner = inline ? /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -101,45 +81,28 @@ function Steps({
101
81
  /* @__PURE__ */ jsx("span", { className: "sr-only", children: statusLabel })
102
82
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
103
83
  /* @__PURE__ */ jsx(StepIcon, { status: stepStatus, icon: item.icon, type }),
104
- /* @__PURE__ */ jsxs(
105
- "div",
106
- {
107
- className: cn(
108
- "min-w-0",
109
- isVertical ? "pt-1 text-start" : "mt-2 px-2",
110
- titlePlacement === "vertical" && !isVertical && "mt-1"
111
- ),
112
- children: [
113
- /* @__PURE__ */ jsx(
114
- "div",
115
- {
116
- className: cn(
117
- "font-medium",
118
- compact ? "text-xs" : "text-sm",
119
- stepStatus === "process" && "text-foreground",
120
- stepStatus === "wait" && "text-muted-foreground",
121
- stepStatus === "error" && "text-destructive"
122
- ),
123
- children: item.title
124
- }
125
- ),
126
- item.subtitle && /* @__PURE__ */ jsx("div", { className: "text-muted-foreground text-xs", children: item.subtitle }),
127
- description && /* @__PURE__ */ jsx("div", { className: cn("text-muted-foreground", compact ? "text-xs" : "text-sm"), children: description })
128
- ]
129
- }
130
- )
84
+ /* @__PURE__ */ jsxs("div", { className: "ui-steps-text", children: [
85
+ /* @__PURE__ */ jsx(
86
+ "div",
87
+ {
88
+ className: "ui-steps-title",
89
+ "data-status": stepStatus,
90
+ "data-compact": compact ? "" : void 0,
91
+ children: item.title
92
+ }
93
+ ),
94
+ item.subtitle && /* @__PURE__ */ jsx("div", { className: "ui-steps-subtitle", children: item.subtitle }),
95
+ description && /* @__PURE__ */ jsx("div", { className: "ui-steps-description", "data-compact": compact ? "" : void 0, children: description })
96
+ ] })
131
97
  ] });
132
98
  return /* @__PURE__ */ jsxs(
133
99
  "li",
134
100
  {
135
101
  "aria-current": isCurrent ? "step" : void 0,
136
- className: cn(
137
- "relative flex min-w-0",
138
- !inline && "flex-1",
139
- inline ? "ui-steps-inline-item" : isVertical ? "flex-row gap-3 pb-8 last:pb-0" : "flex-col items-center text-center",
140
- !isVertical && !inline && index < items.length - 1 && "after:bg-border after:absolute after:top-4 after:h-px",
141
- !isVertical && !inline && index < items.length - 1 && "after:left-[calc(50%+1.25rem)] after:w-[calc(100%-2.5rem)]"
142
- ),
102
+ "data-direction": inline ? void 0 : isVertical ? "vertical" : "horizontal",
103
+ "data-title-placement": titlePlacement,
104
+ "data-connector": !isVertical && !inline && index < items.length - 1 ? "" : void 0,
105
+ className: cn(!inline && "flex-1", inline ? "ui-steps-inline-item" : "ui-steps-item"),
143
106
  "data-status": stepStatus,
144
107
  children: [
145
108
  interactive ? /* @__PURE__ */ jsx(
@@ -148,10 +111,11 @@ function Steps({
148
111
  type: "button",
149
112
  disabled: !clickable,
150
113
  onClick: clickable ? () => onValueChange?.(absoluteIndex) : void 0,
114
+ "data-direction": stepDirection,
151
115
  className: stepClassName,
152
116
  children: stepInner
153
117
  }
154
- ) : /* @__PURE__ */ jsx("span", { className: stepClassName, children: stepInner }),
118
+ ) : /* @__PURE__ */ jsx("span", { "data-direction": stepDirection, className: stepClassName, children: stepInner }),
155
119
  inline && index < items.length - 1 ? /* @__PURE__ */ jsx(
156
120
  SeparatorIcon,
157
121
  {
@@ -29,11 +29,15 @@ function Tabs({
29
29
  {
30
30
  "data-slot": "tabs",
31
31
  "data-orientation": orientation,
32
+ "data-variant": variant,
32
33
  orientation,
33
34
  value,
34
35
  defaultValue: value === void 0 ? resolvedDefault : void 0,
35
36
  className: cn(
36
- "group/tabs flex min-w-0 gap-2 data-[orientation=horizontal]:flex-col",
37
+ // Structure only. The shrink floor (`min-inline-size: 0`, gh#175) and the strip↔panel gap
38
+ // live in src/styles/navigation-layout.css so the gap reads --tabs-root-gap and a service
39
+ // can retune the tab rhythm without forking this file (#319).
40
+ "group/tabs flex data-[orientation=horizontal]:flex-col",
37
41
  className
38
42
  ),
39
43
  ...props,
@@ -44,7 +48,10 @@ function Tabs({
44
48
  "data-slot": "tabs-list",
45
49
  variant: variant === "line" ? "line" : "default",
46
50
  className: cn(
47
- variant === "line" && "h-auto w-full justify-start border-b p-0",
51
+ // The padding override is an arbitrary value reading the knob (never `p-0`): it must
52
+ // stay a UTILITY so tailwind-merge still drops the strip's own padding step, and a
53
+ // components-layer rule could not beat that utility anyway (#319).
54
+ variant === "line" && "h-auto w-full justify-start border-b p-[var(--tabs-list-line-space-inset)]",
48
55
  variant === "card" && "w-full justify-start",
49
56
  listClassName
50
57
  ),
@@ -56,8 +63,13 @@ function Tabs({
56
63
  className: cn(
57
64
  // Geometry only — the active underline is the token-owned `::after` bar the
58
65
  // line variant already owns (never a second, hand-rolled border-b indicator).
59
- variant === "line" && "rounded-none px-4 py-2",
60
- variant === "card" && "data-[state=active]:shadow-sm"
66
+ // Token-reading arbitrary values, not Tailwind steps (#319): they have to stay
67
+ // utilities so tailwind-merge keeps dropping the pill trigger's own radius /
68
+ // padding steps from the base class list.
69
+ // `card` adds NOTHING here — its list is forwarded as data-variant="default", so
70
+ // the active lift already comes from the base trigger's
71
+ // `group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm`.
72
+ variant === "line" && "rounded-[var(--tabs-trigger-line-radius)] px-[var(--tabs-trigger-line-padding-x)] py-[var(--tabs-trigger-line-padding-y)]"
61
73
  ),
62
74
  children: item.label
63
75
  },
@@ -70,7 +82,7 @@ function Tabs({
70
82
  {
71
83
  value: item.value,
72
84
  "data-slot": "tabs-panel",
73
- className: cn(variant === "line" && "mt-0", contentClassName),
85
+ className: contentClassName,
74
86
  children: item.content
75
87
  },
76
88
  item.value
@@ -56,7 +56,7 @@ function InfiniteQueryState({
56
56
  if (!data) return /* @__PURE__ */ jsx(Fragment, { children: skeleton });
57
57
  const flat = flatten(data);
58
58
  if (empty && isEmpty(flat)) return /* @__PURE__ */ jsx(Fragment, { children: empty });
59
- const footer = showLoadMore && query.hasNextPage ? loadMore ?? /* @__PURE__ */ jsx("div", { className: "flex justify-center pt-4", children: /* @__PURE__ */ jsx(
59
+ const footer = showLoadMore && query.hasNextPage ? loadMore ?? /* @__PURE__ */ jsx("div", { className: "flex justify-center pt-[var(--query-load-more-space-block-start)]", children: /* @__PURE__ */ jsx(
60
60
  Button,
61
61
  {
62
62
  type: "button",
@@ -73,7 +73,7 @@ function InfiniteQueryState({
73
73
  hasNextPage: !!query.hasNextPage,
74
74
  isFetchingNextPage: query.isFetchingNextPage
75
75
  }),
76
- query.isFetchingNextPage && (loadingMore ?? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground pt-2 text-center text-xs", children: t("common.working") })),
76
+ query.isFetchingNextPage && (loadingMore ?? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground pt-[var(--query-loading-more-space-block-start)] text-center text-xs", children: t("common.working") })),
77
77
  footer
78
78
  ] });
79
79
  }
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import * as AccordionPrimitive from "@radix-ui/react-accordion";
3
- export declare const Accordion: React.ForwardRefExoticComponent<(AccordionPrimitive.AccordionSingleProps | AccordionPrimitive.AccordionMultipleProps) & React.RefAttributes<HTMLDivElement>>;
3
+ export declare const Accordion: React.ForwardRefExoticComponent<(AccordionPrimitive.AccordionMultipleProps | AccordionPrimitive.AccordionSingleProps) & React.RefAttributes<HTMLDivElement>>;
4
4
  export declare const AccordionItem: React.ForwardRefExoticComponent<Omit<AccordionPrimitive.AccordionItemProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
5
5
  export declare const AccordionTrigger: React.ForwardRefExoticComponent<Omit<AccordionPrimitive.AccordionTriggerProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
6
6
  export declare const AccordionContent: React.ForwardRefExoticComponent<Omit<AccordionPrimitive.AccordionContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import * as AvatarPrimitive from "@radix-ui/react-avatar";
3
3
  import type { AvatarProp } from "../../props/components/data-display.prop.js";
4
- export declare const Avatar: React.ForwardRefExoticComponent<Omit<AvatarPrimitive.AvatarProps & React.RefAttributes<HTMLSpanElement>, "ref"> & Pick<AvatarProp, "shape" | "appearance"> & React.RefAttributes<HTMLSpanElement>>;
4
+ export declare const Avatar: React.ForwardRefExoticComponent<Omit<AvatarPrimitive.AvatarProps & React.RefAttributes<HTMLSpanElement>, "ref"> & Pick<AvatarProp, "appearance" | "presence" | "presenceLabel" | "shape"> & React.RefAttributes<HTMLSpanElement>>;
5
5
  export declare const AvatarImage: React.ForwardRefExoticComponent<Omit<AvatarPrimitive.AvatarImageProps & React.RefAttributes<HTMLImageElement>, "ref"> & React.RefAttributes<HTMLImageElement>>;
6
6
  export declare const AvatarFallback: React.ForwardRefExoticComponent<Omit<AvatarPrimitive.AvatarFallbackProps & React.RefAttributes<HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
@@ -1,19 +1,38 @@
1
1
  "use client";
2
- import { jsx } from "react/jsx-runtime";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import * as AvatarPrimitive from "@radix-ui/react-avatar";
5
+ import { useTranslation } from "../../i18n/use-translation.js";
5
6
  import { cn } from "../../lib/utils.js";
6
- const Avatar = React.forwardRef(({ className, shape = "circle", appearance = "default", ...props }, ref) => /* @__PURE__ */ jsx(
7
- AvatarPrimitive.Root,
8
- {
9
- ref,
10
- "data-slot": "avatar",
11
- "data-shape": shape === "square" ? "square" : void 0,
12
- "data-appearance": appearance === "tinted" ? "tinted" : void 0,
13
- className: cn("ui-avatar", className),
7
+ const Avatar = React.forwardRef(
8
+ ({
9
+ className,
10
+ shape = "circle",
11
+ appearance = "default",
12
+ presence,
13
+ presenceLabel,
14
+ children,
14
15
  ...props
16
+ }, ref) => {
17
+ const { t } = useTranslation();
18
+ return /* @__PURE__ */ jsxs(
19
+ AvatarPrimitive.Root,
20
+ {
21
+ ref,
22
+ "data-slot": "avatar",
23
+ "data-shape": shape === "square" ? "square" : void 0,
24
+ "data-appearance": appearance === "tinted" ? "tinted" : void 0,
25
+ "data-presence": presence,
26
+ className: cn("ui-avatar", className),
27
+ ...props,
28
+ children: [
29
+ children,
30
+ presence !== void 0 ? /* @__PURE__ */ jsx("span", { "data-slot": "avatar-presence", "data-presence": presence, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: presenceLabel ?? t(`dataDisplay.avatar.presence.${presence}`) }) }) : null
31
+ ]
32
+ }
33
+ );
15
34
  }
16
- ));
35
+ );
17
36
  Avatar.displayName = AvatarPrimitive.Root.displayName;
18
37
  const AvatarImage = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
19
38
  AvatarPrimitive.Image,
@@ -9,29 +9,31 @@ import type { InputOTPAlignProp } from "../../props/components/data-entry.prop.j
9
9
  * through `:has()`, exactly as it already does for the invalid and disabled states. A service that
10
10
  * wants every code field centred sets `--otp-container-align` once instead.
11
11
  */
12
- export declare const InputOTP: React.ForwardRefExoticComponent<((Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "onChange" | "value" | "maxLength" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
12
+ export declare const InputOTP: React.ForwardRefExoticComponent<((Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "containerClassName" | "maxLength" | "noScriptCSSFallback" | "nonce" | "onChange" | "onComplete" | "pasteTransformer" | "pushPasswordManagerStrategy" | "textAlign" | "value"> & {
13
13
  value?: string;
14
14
  onChange?: (newValue: string) => unknown;
15
15
  maxLength: number;
16
- textAlign?: "left" | "center" | "right";
16
+ textAlign?: 'left' | 'center' | 'right';
17
17
  onComplete?: (...args: any[]) => unknown;
18
- pushPasswordManagerStrategy?: "increase-width" | "none";
18
+ pushPasswordManagerStrategy?: 'increase-width' | 'none';
19
19
  pasteTransformer?: (pasted: string) => string;
20
20
  containerClassName?: string;
21
21
  noScriptCSSFallback?: string | null;
22
+ nonce?: string;
22
23
  } & {
23
24
  render: (props: import("input-otp").RenderProps) => React.ReactNode;
24
25
  children?: never;
25
- } & React.RefAttributes<HTMLInputElement>, "ref"> | Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "onChange" | "value" | "maxLength" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
26
+ } & React.RefAttributes<HTMLInputElement>, "ref"> | Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "containerClassName" | "maxLength" | "noScriptCSSFallback" | "nonce" | "onChange" | "onComplete" | "pasteTransformer" | "pushPasswordManagerStrategy" | "textAlign" | "value"> & {
26
27
  value?: string;
27
28
  onChange?: (newValue: string) => unknown;
28
29
  maxLength: number;
29
- textAlign?: "left" | "center" | "right";
30
+ textAlign?: 'left' | 'center' | 'right';
30
31
  onComplete?: (...args: any[]) => unknown;
31
- pushPasswordManagerStrategy?: "increase-width" | "none";
32
+ pushPasswordManagerStrategy?: 'increase-width' | 'none';
32
33
  pasteTransformer?: (pasted: string) => string;
33
34
  containerClassName?: string;
34
35
  noScriptCSSFallback?: string | null;
36
+ nonce?: string;
35
37
  } & {
36
38
  render?: never;
37
39
  children: React.ReactNode;
@@ -30,7 +30,7 @@ const Rating = React.forwardRef(
30
30
  const focusableStar = current > 0 ? current : 1;
31
31
  const onKeyDown = (e, star) => {
32
32
  if (!interactive) return;
33
- let next = null;
33
+ let next;
34
34
  switch (e.key) {
35
35
  case "ArrowRight":
36
36
  case "ArrowUp":
@@ -1,3 +1,28 @@
1
1
  import * as React from "react";
2
- import * as SeparatorPrimitive from "@radix-ui/react-separator";
3
- export declare const Separator: React.ForwardRefExoticComponent<Omit<SeparatorPrimitive.SeparatorProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
2
+ export type { SeparatorProp, SeparatorProp as SeparatorProps, } from "../../props/components/layout.prop.js";
3
+ /**
4
+ * Separator — a tokenized horizontal/vertical rule, optionally INTERRUPTED by a localized label
5
+ * (gh#308): a message stream's day divider, a "new messages" unread watermark, an auth
6
+ * conjunction. Before #308 the only labelled rule in the library was the auth-scoped
7
+ * `AuthDivider`, so a chat stream had to either misuse it (inheriting the `--auth-shell-divider-*`
8
+ * type ramp) or hand-roll a `<div>` grid; `AuthDivider` is now a thin preset over this.
9
+ *
10
+ * ACCESSIBILITY — the whole point of the labelled form is that the label is ANNOUNCED, exactly
11
+ * ONCE. Without a label the rule stays `decorative` (Radix emits `role="none"`), which is right:
12
+ * a section rule carries no information. With a label the default flips to `decorative={false}`,
13
+ * so Radix emits a real `role="separator"` (plus `aria-orientation` when vertical, which is what
14
+ * the ARIA default already implies for horizontal), the label string becomes the separator's
15
+ * accessible NAME via `aria-label`, and the visible label node is `aria-hidden` — otherwise the
16
+ * same string would be announced twice, once as the name and again as the content. A consumer who
17
+ * explicitly passes `decorative` still wins; when they force `decorative` on a labelled rule the
18
+ * name is dropped (a `role="none"` element may not carry one) and the visible text is left in the
19
+ * tree instead, so it is still read once and never as a nameless blank rule.
20
+ */
21
+ export declare const Separator: React.ForwardRefExoticComponent<Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & {
22
+ orientation?: import("../../props/index.js").OrientationProp;
23
+ label?: string;
24
+ labelAlign?: import("../../props/index.js").TextAlignProp;
25
+ tone?: import("../../props/index.js").TextToneProp;
26
+ decorative?: boolean;
27
+ className?: import("../../props/index.js").ClassNameProp;
28
+ } & React.RefAttributes<HTMLDivElement>>;
@@ -1,21 +1,52 @@
1
1
  "use client";
2
- import { jsx } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import * as SeparatorPrimitive from "@radix-ui/react-separator";
5
5
  import { cn } from "../../lib/utils.js";
6
- const Separator = React.forwardRef(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => /* @__PURE__ */ jsx(
7
- SeparatorPrimitive.Root,
8
- {
9
- ref,
10
- "data-slot": "separator",
11
- "data-orientation": orientation,
12
- orientation,
6
+ const Separator = React.forwardRef(
7
+ ({
8
+ className,
9
+ orientation = "horizontal",
13
10
  decorative,
14
- className: cn("ui-separator", className),
11
+ label,
12
+ labelAlign = "center",
13
+ tone = "default",
15
14
  ...props
15
+ }, ref) => {
16
+ const hasLabel = typeof label === "string" && label.trim() !== "";
17
+ const labelled = hasLabel && orientation === "horizontal";
18
+ if (typeof process !== "undefined" && process.env?.NODE_ENV !== "production") {
19
+ if (hasLabel && orientation === "vertical") {
20
+ console.warn(
21
+ 'Separator: `label` is rendered on orientation="horizontal" only; it was ignored. Use a horizontal rule for a day divider / unread watermark.'
22
+ );
23
+ }
24
+ }
25
+ const isDecorative = decorative ?? !labelled;
26
+ return /* @__PURE__ */ jsx(
27
+ SeparatorPrimitive.Root,
28
+ {
29
+ ref,
30
+ "data-slot": "separator",
31
+ "data-orientation": orientation,
32
+ "data-tone": tone,
33
+ "data-labelled": labelled ? "" : void 0,
34
+ "data-label-align": labelled ? labelAlign : void 0,
35
+ orientation,
36
+ decorative: isDecorative,
37
+ "aria-label": labelled && !isDecorative ? label : void 0,
38
+ className: cn("ui-separator", className),
39
+ ...props,
40
+ children: labelled ? /* @__PURE__ */ jsxs(Fragment, { children: [
41
+ /* @__PURE__ */ jsx("span", { className: "ui-separator-rule", "aria-hidden": "true" }),
42
+ /* @__PURE__ */ jsx("span", { className: "ui-separator-label", "aria-hidden": isDecorative ? void 0 : true, children: label }),
43
+ /* @__PURE__ */ jsx("span", { className: "ui-separator-rule", "aria-hidden": "true" })
44
+ ] }) : null
45
+ }
46
+ );
16
47
  }
17
- ));
18
- Separator.displayName = SeparatorPrimitive.Root.displayName;
48
+ );
49
+ Separator.displayName = "Separator";
19
50
  export {
20
51
  Separator
21
52
  };
@@ -1,13 +1,23 @@
1
1
  import * as React from "react";
2
2
  import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
3
- import { type ToggleProps } from "./toggle.js";
4
- type ToggleGroupVariant = ToggleProps["variant"];
5
- type ToggleGroupSize = ToggleProps["size"];
6
- export declare const ToggleGroup: React.ForwardRefExoticComponent<((Omit<ToggleGroupPrimitive.ToggleGroupSingleProps & React.RefAttributes<HTMLDivElement>, "ref"> | Omit<ToggleGroupPrimitive.ToggleGroupMultipleProps & React.RefAttributes<HTMLDivElement>, "ref">) & {
3
+ import { type ToggleCountFields, type ToggleProp } from "./toggle.js";
4
+ type ToggleGroupVariant = ToggleProp["variant"];
5
+ type ToggleGroupSize = ToggleProp["size"];
6
+ export declare const ToggleGroup: React.ForwardRefExoticComponent<((Omit<ToggleGroupPrimitive.ToggleGroupMultipleProps & React.RefAttributes<HTMLDivElement>, "ref"> | Omit<ToggleGroupPrimitive.ToggleGroupSingleProps & React.RefAttributes<HTMLDivElement>, "ref">) & {
7
7
  variant?: ToggleGroupVariant;
8
8
  size?: ToggleGroupSize;
9
9
  }) & React.RefAttributes<HTMLDivElement>>;
10
- export declare const ToggleGroupItem: React.ForwardRefExoticComponent<Omit<ToggleGroupPrimitive.ToggleGroupItemProps & React.RefAttributes<HTMLButtonElement>, "ref"> & {
10
+ /**
11
+ * `variant`/`size` come from the group through context; the COUNT stays per item, because the
12
+ * number is per-item data (gh#312). Same vocabulary as `Toggle` and `Button` — one counter pill
13
+ * for the whole library.
14
+ */
15
+ export type ToggleGroupItemProp = React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> & ToggleCountFields & {
16
+ variant?: ToggleGroupVariant;
17
+ size?: ToggleGroupSize;
18
+ };
19
+ export type ToggleGroupItemProps = ToggleGroupItemProp;
20
+ export declare const ToggleGroupItem: React.ForwardRefExoticComponent<Omit<ToggleGroupPrimitive.ToggleGroupItemProps & React.RefAttributes<HTMLButtonElement>, "ref"> & ToggleCountFields & {
11
21
  variant?: ToggleGroupVariant;
12
22
  size?: ToggleGroupSize;
13
23
  } & React.RefAttributes<HTMLButtonElement>>;
@@ -1,9 +1,9 @@
1
1
  "use client";
2
- import { jsx } from "react/jsx-runtime";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
5
5
  import { cn } from "../../lib/utils.js";
6
- import { toggleVariants } from "./toggle.js";
6
+ import { toggleVariants, useCounterPill } from "./toggle.js";
7
7
  const ToggleGroupContext = React.createContext({});
8
8
  const ToggleGroup = React.forwardRef(({ className, variant, size, children, ...props }, ref) => {
9
9
  const context = React.useMemo(() => ({ variant, size }), [variant, size]);
@@ -21,22 +21,47 @@ const ToggleGroup = React.forwardRef(({ className, variant, size, children, ...p
21
21
  );
22
22
  });
23
23
  ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
24
- const ToggleGroupItem = React.forwardRef(({ className, variant, size, ...props }, ref) => {
25
- const context = React.useContext(ToggleGroupContext);
26
- const resolvedVariant = variant ?? context.variant;
27
- const resolvedSize = size ?? context.size;
28
- return /* @__PURE__ */ jsx(
29
- ToggleGroupPrimitive.Item,
30
- {
31
- ref,
32
- "data-slot": "toggle-group-item",
33
- "data-variant": resolvedVariant,
34
- "data-size": resolvedSize,
35
- className: cn(toggleVariants({ variant: resolvedVariant, size: resolvedSize }), className),
36
- ...props
37
- }
38
- );
39
- });
24
+ const ToggleGroupItem = React.forwardRef(
25
+ ({
26
+ className,
27
+ variant,
28
+ size,
29
+ count,
30
+ overflowCount,
31
+ showZero,
32
+ countLabel,
33
+ children,
34
+ "aria-label": ariaLabel,
35
+ ...props
36
+ }, ref) => {
37
+ const context = React.useContext(ToggleGroupContext);
38
+ const resolvedVariant = variant ?? context.variant;
39
+ const resolvedSize = size ?? context.size;
40
+ const { pill, resolvedAriaLabel } = useCounterPill({
41
+ count,
42
+ overflowCount,
43
+ showZero,
44
+ countLabel,
45
+ ariaLabel
46
+ });
47
+ return /* @__PURE__ */ jsxs(
48
+ ToggleGroupPrimitive.Item,
49
+ {
50
+ ref,
51
+ "data-slot": "toggle-group-item",
52
+ "data-variant": resolvedVariant,
53
+ "data-size": resolvedSize,
54
+ "aria-label": resolvedAriaLabel,
55
+ className: cn(toggleVariants({ variant: resolvedVariant, size: resolvedSize }), className),
56
+ ...props,
57
+ children: [
58
+ children,
59
+ pill
60
+ ]
61
+ }
62
+ );
63
+ }
64
+ );
40
65
  ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
41
66
  export {
42
67
  ToggleGroup,
@@ -3,11 +3,72 @@ import * as TogglePrimitive from "@radix-ui/react-toggle";
3
3
  import { type VariantProps } from "class-variance-authority";
4
4
  declare const toggleVariants: (props?: ({
5
5
  variant?: "default" | "outline" | null | undefined;
6
- size?: "sm" | "md" | "lg" | null | undefined;
6
+ size?: "lg" | "md" | "sm" | null | undefined;
7
7
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
- export type ToggleProps = React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> & VariantProps<typeof toggleVariants>;
8
+ /**
9
+ * The counter-pill vocabulary, lifted VERBATIM from `Button` (`count` / `overflowCount` /
10
+ * `showZero`) so a counted filter tab and a counted, pressed filter chip are one vocabulary rather
11
+ * than two that drift (gh#312). Not exported on its own — it is folded into `ToggleProp` and
12
+ * `ToggleGroupItemProp` so there is one public name per component.
13
+ */
14
+ type ToggleCountFields = {
15
+ /**
16
+ * Optional numeric count rendered as a borderless counter pill after the label — the SAME
17
+ * vocabulary `Button` already defines, so a counted segmented toggle and a counted filter tab
18
+ * read identically. Formatted with `Intl.NumberFormat` in the active locale (never `String(n)`,
19
+ * never a hand-rolled thousands separator). Never nest a `Badge` inside a Toggle for this: a
20
+ * Badge is a status chip with its own surface, so it double-borders the chip and puts two boxes
21
+ * where there is one control. The pill takes its colour from the toggle's OWN pressed state, so
22
+ * pressed and unpressed chips differ without reading the number.
23
+ */
24
+ count?: number;
25
+ /** Cap for `count` — beyond it the pill shows `{overflowCount}+` (e.g. `99+`). Default `99`. */
26
+ overflowCount?: number;
27
+ /** Render the pill when `count` is 0. Default `true`, matching Button. */
28
+ showZero?: boolean;
29
+ /**
30
+ * Localized description of what the count MEANS, folded into the accessible name so the control
31
+ * never announces as a bare number ("👍 3" → "thumbs up, 3 reactions"). Supply it whenever the
32
+ * visible label is an icon or an emoji; with a text label the label itself already carries the
33
+ * meaning. Pass a `t()`-resolved string — the library does not own this wording.
34
+ */
35
+ countLabel?: string;
36
+ };
37
+ /**
38
+ * Counter pill shared by `Toggle` and `ToggleGroupItem`.
39
+ *
40
+ * ACCESSIBLE NAME. The digits live INSIDE the same `button[aria-pressed]` — one tab stop, one
41
+ * focus ring, one name. The name always comes out as "<label>, <count> <unit>" ("Unread, 12",
42
+ * "Thích, 3 lượt"), by one of two routes:
43
+ *
44
+ * • Name from CONTENTS (the usual text chip). The visible digits are `aria-hidden`, and an
45
+ * `sr-only` sibling carries ", 12 unit". The separator is explicit on purpose: the accessible
46
+ * name is a CONCATENATION of descendant text, and whether a browser inserts a space between
47
+ * two inline boxes is a layout detail no test can rely on — without it the control can
48
+ * announce "Unread12".
49
+ * • Name from `aria-label` (an icon or emoji chip). Contents are ignored for the name, so the
50
+ * same ", 12 unit" tail is folded into the label instead.
51
+ *
52
+ * Either way the count is announced exactly ONCE — the visible digits are hidden from the a11y
53
+ * tree precisely so they cannot be counted twice — and there is deliberately no `aria-live`: a
54
+ * count that ticks up as other people react is not this control's status, and a live region here
55
+ * would fire on every socket message. A product that wants the change announced owns its own
56
+ * live region.
57
+ */
58
+ declare function useCounterPill({ count, overflowCount, showZero, countLabel, ariaLabel, }: ToggleCountFields & {
59
+ ariaLabel?: string;
60
+ }): {
61
+ pill: null;
62
+ resolvedAriaLabel: string | undefined;
63
+ } | {
64
+ pill: React.JSX.Element;
65
+ resolvedAriaLabel: string | undefined;
66
+ };
67
+ export type ToggleProp = React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> & VariantProps<typeof toggleVariants> & ToggleCountFields;
68
+ export type ToggleProps = ToggleProp;
9
69
  export declare const Toggle: React.ForwardRefExoticComponent<Omit<TogglePrimitive.ToggleProps & React.RefAttributes<HTMLButtonElement>, "ref"> & VariantProps<(props?: ({
10
70
  variant?: "default" | "outline" | null | undefined;
11
- size?: "sm" | "md" | "lg" | null | undefined;
12
- } & import("class-variance-authority/types").ClassProp) | undefined) => string> & React.RefAttributes<HTMLButtonElement>>;
13
- export { toggleVariants };
71
+ size?: "lg" | "md" | "sm" | null | undefined;
72
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string> & ToggleCountFields & React.RefAttributes<HTMLButtonElement>>;
73
+ export { toggleVariants, useCounterPill };
74
+ export type { ToggleCountFields };