@godxjp/ui 23.4.1 → 23.4.3

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 (40) hide show
  1. package/README.md +17 -2
  2. package/dist/components/data-display/badge.d.ts +14 -1
  3. package/dist/components/data-display/badge.js +21 -1
  4. package/dist/components/data-display/data-table.d.ts +4 -2
  5. package/dist/components/data-display/data-table.js +14 -2
  6. package/dist/components/data-entry/date-picker.js +4 -16
  7. package/dist/components/layout/draggable-panel.d.ts +3 -2
  8. package/dist/components/layout/draggable-panel.js +11 -2
  9. package/dist/components/layout/index.d.ts +1 -1
  10. package/dist/components/navigation/filter-bar.js +11 -16
  11. package/dist/components/ui/segmented.d.ts +19 -1
  12. package/dist/components/ui/segmented.js +34 -2
  13. package/dist/props/components/data-display.prop.d.ts +5 -0
  14. package/dist/props/components/index.d.ts +1 -1
  15. package/dist/props/components/layout.prop.d.ts +13 -2
  16. package/dist/props/registry.d.ts +5 -1
  17. package/dist/props/registry.js +6 -1
  18. package/dist/props/vocabulary/data.prop.d.ts +11 -0
  19. package/dist/styles/badge-layout.css +25 -0
  20. package/dist/styles/control.css +37 -0
  21. package/dist/styles/core-with-fallbacks.css +3 -0
  22. package/dist/styles/focus-ring.css +2 -0
  23. package/dist/styles/font-fallbacks.css +83 -0
  24. package/dist/styles/fonts.css +1 -82
  25. package/dist/styles/layout.css +17 -5
  26. package/dist/tokens/components/badge.css +6 -0
  27. package/dist/tokens/components/draggable-panel.css +4 -0
  28. package/dist/tokens/components/segmented.css +8 -0
  29. package/docs/CONSUMER-RULES.md +1 -1
  30. package/docs/CUSTOMER-THEMING.md +16 -2
  31. package/docs/DESIGN-AUTHORITY.md +15 -0
  32. package/docs/data-entry/segmented-in-filter-row.tsx +2 -19
  33. package/docs/data-entry/segmented.tsx +2 -19
  34. package/package.json +4 -2
  35. package/scripts/_agent-setup.mjs +90 -17
  36. package/scripts/cli.mjs +6 -2
  37. package/scripts/consumer-rule.md +76 -18
  38. package/scripts/guinea-pig-skill.md +38 -9
  39. package/scripts/postinstall.mjs +1 -1
  40. package/scripts/ui-audit.mjs +1 -1
package/README.md CHANGED
@@ -110,11 +110,26 @@ The framework ships colors, the type scale, the wa-iro palette, and (opt-in) bun
110
110
  @import "@godxjp/ui/styles/core"; /* every component layer, no @font-face */
111
111
  ```
112
112
 
113
+ Supplying Noto Sans JP yourself and want the cold-visit swap not to reflow the page? Take the
114
+ third entry instead — the same layers plus the six metric-matched fallback faces, whose `src` is
115
+ `local()`-only, so it costs **zero network bytes** over `core`:
116
+
117
+ ```css
118
+ @import "@godxjp/ui/styles/core-with-fallbacks"; /* core + 6 local()-only faces */
119
+ ```
120
+
121
+ Then name the family directly after your own face:
122
+ `--font-sans-base: "Noto Sans JP", "Noto Sans JP Fallback", system-ui, sans-serif;`
123
+
124
+ `core` stays at **zero** `@font-face` on purpose — `grep -c '@font-face'
125
+ node_modules/@godxjp/ui/dist/styles/core.css` → `0` is the promise, so the fallbacks got their own
126
+ entry rather than being folded in.
127
+
113
128
  > **Do not cherry-pick `*-layout.css` files.** Layers depend on each other (a
114
129
  > Select's rows, a menu's surface, a form's rhythm live in shared rules) and a
115
130
  > missing layer fails silently: menus render with no background, rows with no
116
- > height. `styles` and `styles/core` are the two supported entries; the runtime
117
- > `visual-audit` flags a page whose layers are incomplete (`css-layers-missing`).
131
+ > height. `styles`, `styles/core` and `styles/core-with-fallbacks` are the three supported entries;
132
+ > the runtime `visual-audit` flags a page whose layers are incomplete (`css-layers-missing`).
118
133
 
119
134
  ## Golden ratio (φ ≈ 1.618)
120
135
 
@@ -73,8 +73,21 @@ export interface BadgeProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "
73
73
  */
74
74
  tabular?: boolean;
75
75
  children?: React.ReactNode;
76
+ /**
77
+ * antd `Tag` `closable` + `onClose` — one callback when the user activates the × the chip draws.
78
+ * Named `onRemove` (not `onClose`) because this DS already uses `onClose` on overlays and
79
+ * `onValueChange` on fields; the chip remover is not a dismiss surface. Omitting it is antd
80
+ * `closable={false}`: no × is rendered.
81
+ *
82
+ * The × accessible name is built from the visible label (`children`, or the resolved `status`
83
+ * label) via `navigation.filterBar.removeFilter` — pass a string `children` (or plain text
84
+ * label) so the name quotes the chip, e.g. `getByRole('button', { name: /期限: 今週/ })`.
85
+ */
86
+ onRemove?: () => void;
87
+ /** Disables only the × when `onRemove` is set (FilterBar bar/chip disabled). Label stays visible. */
88
+ removeDisabled?: boolean;
76
89
  }
77
- export declare function Badge({ as: Element, className, variant, shape, tone, color, icon, status, tabular, style, children, ...props }: BadgeProps): React.JSX.Element;
90
+ export declare function Badge({ as: Element, className, variant, shape, tone, color, icon, status, tabular, style, children, onRemove, removeDisabled, ...props }: BadgeProps): React.JSX.Element;
78
91
  /**
79
92
  * Status-aware badge with the shared domain-status-to-tone mapping. `Badge` remains the
80
93
  * general-purpose primitive.
@@ -9,6 +9,7 @@ import {
9
9
  Pause,
10
10
  Play,
11
11
  Trash2,
12
+ X,
12
13
  XCircle
13
14
  } from "lucide-react";
14
15
  import { useTranslation } from "../../i18n/use-translation.js";
@@ -100,6 +101,8 @@ function Badge({
100
101
  tabular,
101
102
  style,
102
103
  children,
104
+ onRemove,
105
+ removeDisabled,
103
106
  ...props
104
107
  }) {
105
108
  const { t } = useTranslation();
@@ -108,6 +111,7 @@ function Badge({
108
111
  const ResolvedIcon = icon === void 0 ? statusDef?.icon : icon;
109
112
  const resolvedChildren = children ?? (status ? status in STATUS_MAP ? t(`status.${status}`) : status : void 0);
110
113
  const tinted = color != null && color !== "";
114
+ const removeLabel = typeof children === "string" ? children : typeof resolvedChildren === "string" ? resolvedChildren : void 0;
111
115
  return /* @__PURE__ */ jsxs(
112
116
  Element,
113
117
  {
@@ -116,6 +120,7 @@ function Badge({
116
120
  "data-tinted": tinted ? "" : void 0,
117
121
  "data-shape": shape ?? "default",
118
122
  "data-tabular": tabular ? "" : void 0,
123
+ "data-removable": onRemove ? "" : void 0,
119
124
  className: cn(
120
125
  badgeVariants({
121
126
  variant: tinted ? "tinted" : variant ?? "default",
@@ -128,7 +133,22 @@ function Badge({
128
133
  ...props,
129
134
  children: [
130
135
  ResolvedIcon ? /* @__PURE__ */ jsx(ResolvedIcon, { "data-slot": "badge-icon", "aria-hidden": "true" }) : null,
131
- resolvedChildren != null ? /* @__PURE__ */ jsx("span", { "data-slot": "badge-label", children: resolvedChildren }) : null
136
+ resolvedChildren != null ? /* @__PURE__ */ jsx("span", { "data-slot": "badge-label", children: resolvedChildren }) : null,
137
+ onRemove ? /* @__PURE__ */ jsx(
138
+ "button",
139
+ {
140
+ type: "button",
141
+ "data-slot": "badge-remove",
142
+ className: "ui-control-inline-affix-action ui-badge-remove",
143
+ "aria-label": removeLabel != null ? t("navigation.filterBar.removeFilter", { label: removeLabel }) : t("common.delete"),
144
+ onClick: (event) => {
145
+ event.stopPropagation();
146
+ onRemove();
147
+ },
148
+ disabled: removeDisabled,
149
+ children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true" })
150
+ }
151
+ ) : null
132
152
  ]
133
153
  }
134
154
  );
@@ -4,10 +4,12 @@ import type { BreakpointProp, ColumnDefProp, DensityProp, OnColumnFilterChangePr
4
4
  export type Density = DensityProp;
5
5
  /**
6
6
  * Lean column definition — the simple, common-case column API. `render` shapes a cell; `sortable`
7
- * opts the column into the sort cycle; `align` / `width` / `pin` / `hiddenOnMobile` / `priority`
8
- * tune layout; `enableHiding` (default true) lists the column in DataTable.ViewOptions.
7
+ * opts the column into the sort cycle; `align` / `width` / `pin` / `hideBelow` / `hiddenOnMobile` /
8
+ * `priority` tune layout; `enableHiding` (default true) lists the column in DataTable.ViewOptions.
9
9
  */
10
10
  export type ColumnDef<T> = ColumnDefProp<T>;
11
+ /** Same resolution DataTable stamps as `data-hide-below` — `hiddenOnMobile: true` → `md`. */
12
+ export declare function resolveColumnHideBelow(col: Pick<ColumnDef<unknown>, "hideBelow" | "hiddenOnMobile">): BreakpointProp | undefined;
11
13
  interface DataTableProps<T> {
12
14
  data: T[];
13
15
  columns: ColumnDef<T>[];
@@ -73,6 +73,15 @@ import {
73
73
  tableCellPaddingClass,
74
74
  tableRowHeightClass
75
75
  } from "../../lib/control-styles.js";
76
+ function resolveColumnHideBelow(col) {
77
+ if (col.hideBelow) return col.hideBelow;
78
+ if (col.hiddenOnMobile) return "md";
79
+ return void 0;
80
+ }
81
+ function columnHideBelowProps(col) {
82
+ const step = resolveColumnHideBelow(col);
83
+ return step ? { "data-hide-below": step } : {};
84
+ }
76
85
  function dataTableFeatures() {
77
86
  return tableFeatures({
78
87
  rowSortingFeature,
@@ -861,7 +870,6 @@ DataTable.Content = function DataTableContent() {
861
870
  columnWidth(col.width).className,
862
871
  col.align === "right" && "text-end",
863
872
  col.align === "center" && "text-center",
864
- col.hiddenOnMobile && "hidden md:table-cell",
865
873
  col.ellipsis && "ui-data-table-ellipsis",
866
874
  edge === "end" && "ui-data-table-pin-end",
867
875
  edge === "start" && "ui-data-table-pin-start"
@@ -991,6 +999,7 @@ DataTable.Content = function DataTableContent() {
991
999
  "data-align": col.headerAlign ?? col.align,
992
1000
  "aria-sort": isSortable ? activeDirection ? activeDirection === "asc" ? "ascending" : "descending" : "none" : void 0,
993
1001
  ...fixedCellProps(col.key, fixedEdge(col)),
1002
+ ...columnHideBelowProps(col),
994
1003
  style: columnCellStyle(col),
995
1004
  className: cn(
996
1005
  columnCellClass(col),
@@ -1029,6 +1038,7 @@ DataTable.Content = function DataTableContent() {
1029
1038
  {
1030
1039
  priority: col.priority,
1031
1040
  "data-align": col.align,
1041
+ ...columnHideBelowProps(col),
1032
1042
  style: columnCellStyle(col),
1033
1043
  className: cn(cellPadding, columnCellClass(col)),
1034
1044
  children: /* @__PURE__ */ jsx(
@@ -1252,6 +1262,7 @@ DataTable.Content = function DataTableContent() {
1252
1262
  "data-align": col.align,
1253
1263
  title,
1254
1264
  ...fixedCellProps(col.key, fixedEdge(col)),
1265
+ ...columnHideBelowProps(col),
1255
1266
  style: columnCellStyle(col),
1256
1267
  className: cn(cellPadding, columnCellClass(col)),
1257
1268
  children: rendered
@@ -1410,5 +1421,6 @@ DataTable.RowActions = function DataTableRowActions({ ariaLabel, children }) {
1410
1421
  DataTable.RowActions.displayName = "DataTable.RowActions";
1411
1422
  export {
1412
1423
  DataTable,
1413
- flexRender
1424
+ flexRender,
1425
+ resolveColumnHideBelow
1414
1426
  };
@@ -441,14 +441,8 @@ function DatePicker(props) {
441
441
  event.currentTarget.closest("div")?.querySelector("input:not([type=hidden])")?.focus();
442
442
  clear();
443
443
  },
444
- className: range ? "text-muted-foreground hover:text-foreground shrink-0" : "ui-control-inline-affix-action",
445
- children: clearControl.clearIcon ?? /* @__PURE__ */ jsx(
446
- X,
447
- {
448
- className: range ? "ui-month-picker-icon" : "ui-control-inline-affix-icon",
449
- "aria-hidden": "true"
450
- }
451
- )
444
+ className: "ui-control-inline-affix-action",
445
+ children: clearControl.clearIcon ?? /* @__PURE__ */ jsx(X, { className: "ui-control-inline-affix-icon", "aria-hidden": "true" })
452
446
  }
453
447
  ) : /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
454
448
  "button",
@@ -457,14 +451,8 @@ function DatePicker(props) {
457
451
  disabled: allDisabled,
458
452
  tabIndex: -1,
459
453
  "aria-label": triggerLabel ?? (isPeriod ? t("dataEntry.monthPicker.openGrid") : range ? t("dataEntry.dateRangePicker.openCalendar") : t("dataEntry.datePicker.openCalendar")) ?? "Open calendar",
460
- className: range ? "text-muted-foreground hover:text-foreground shrink-0" : "ui-control-inline-affix-action",
461
- children: /* @__PURE__ */ jsx(
462
- CalendarIcon,
463
- {
464
- className: range ? "ui-month-picker-icon" : "ui-control-inline-affix-icon",
465
- "aria-hidden": "true"
466
- }
467
- )
454
+ className: "ui-control-inline-affix-action",
455
+ children: /* @__PURE__ */ jsx(CalendarIcon, { className: "ui-control-inline-affix-icon", "aria-hidden": "true" })
468
456
  }
469
457
  ) });
470
458
  const panel = /* @__PURE__ */ jsxs(
@@ -1,18 +1,19 @@
1
1
  import * as React from "react";
2
2
  import type { DragAxisProp, DraggablePanelPositionProp } from "../../props/components/layout.prop.js";
3
- export type { DraggablePanelProp, DraggablePanelProp as DraggablePanelProps, DraggablePanelPlacementProp, DraggablePanelPositionProp, DragAxisProp, DragBoundsProp, } from "../../props/components/layout.prop.js";
3
+ export type { DraggablePanelProp, DraggablePanelProp as DraggablePanelProps, DraggablePanelPlacementProp, DraggablePanelPositionProp, DraggablePanelLabels, DragAxisProp, DragBoundsProp, } from "../../props/components/layout.prop.js";
4
4
  export declare const DraggablePanel: React.ForwardRefExoticComponent<Omit<React.HTMLAttributes<HTMLElement>, "children" | "onDrag" | "title"> & {
5
5
  title: import("../../props/index.js").TitleProp;
6
6
  children?: import("../../props/index.js").ChildrenProp;
7
7
  extra?: import("../../props/index.js").ExtraProp;
8
8
  placement?: import("./draggable-panel.js").DraggablePanelPlacementProp;
9
- width?: Extract<import("../../props/index.js").SizeProp, "sm" | "md" | "lg">;
9
+ width?: Extract<import("../../props/index.js").SizeProp, "sm" | "md" | "lg"> | "xl";
10
10
  axis?: DragAxisProp;
11
11
  bounds?: import("./draggable-panel.js").DragBoundsProp;
12
12
  position?: DraggablePanelPositionProp;
13
13
  defaultPosition?: DraggablePanelPositionProp;
14
14
  onPositionChange?: (position: DraggablePanelPositionProp) => void;
15
15
  onClose?: () => void;
16
+ labels?: import("./draggable-panel.js").DraggablePanelLabels;
16
17
  disabled?: import("../../props/index.js").DisabledProp;
17
18
  className?: import("../../props/index.js").ClassNameProp;
18
19
  } & React.RefAttributes<HTMLElement>>;
@@ -51,6 +51,7 @@ const DraggablePanel = React.forwardRef(
51
51
  defaultPosition,
52
52
  onPositionChange,
53
53
  onClose,
54
+ labels,
54
55
  disabled = false,
55
56
  className,
56
57
  ...props
@@ -73,6 +74,14 @@ const DraggablePanel = React.forwardRef(
73
74
  [bounds, onPositionChange, position]
74
75
  );
75
76
  React.useEffect(() => () => stopDrag.current?.(), []);
77
+ React.useEffect(() => {
78
+ if (bounds !== "viewport" || typeof window === "undefined") return;
79
+ const onResize = () => {
80
+ commit(currentRef.current);
81
+ };
82
+ window.addEventListener("resize", onResize);
83
+ return () => window.removeEventListener("resize", onResize);
84
+ }, [bounds, commit]);
76
85
  const setPanel = React.useCallback(
77
86
  (node) => {
78
87
  panelRef.current = node;
@@ -156,7 +165,7 @@ const DraggablePanel = React.forwardRef(
156
165
  type: "button",
157
166
  "data-slot": "draggable-panel-handle",
158
167
  className: "ui-draggable-panel-handle ui-focus-ring",
159
- "aria-label": t("layout.draggablePanel.moveLabel"),
168
+ "aria-label": labels?.move ?? t("layout.draggablePanel.moveLabel"),
160
169
  "aria-disabled": movable ? void 0 : "true",
161
170
  onPointerDown: handlePointerDown,
162
171
  onKeyDown: handleKeyDown,
@@ -171,7 +180,7 @@ const DraggablePanel = React.forwardRef(
171
180
  type: "button",
172
181
  "data-slot": "draggable-panel-close",
173
182
  className: "ui-draggable-panel-close ui-focus-ring",
174
- "aria-label": t("feedback.alert.dismiss"),
183
+ "aria-label": labels?.close ?? t("feedback.alert.dismiss"),
175
184
  onClick: onClose,
176
185
  children: /* @__PURE__ */ jsx(X, { className: "ui-draggable-panel-close-icon", "aria-hidden": "true" })
177
186
  }
@@ -50,7 +50,7 @@ export type { MasterDetailProps } from "./master-detail.js";
50
50
  export { SplitPane } from "./split-pane.js";
51
51
  export type { SplitPaneProps } from "./split-pane.js";
52
52
  export { DraggablePanel } from "./draggable-panel.js";
53
- export type { DraggablePanelProp, DraggablePanelProps, DraggablePanelPlacementProp, DraggablePanelPositionProp, DragAxisProp, DragBoundsProp, } from "./draggable-panel.js";
53
+ export type { DraggablePanelProp, DraggablePanelProps, DraggablePanelPlacementProp, DraggablePanelPositionProp, DraggablePanelLabels, DragAxisProp, DragBoundsProp, } from "./draggable-panel.js";
54
54
  export { Separator } from "./separator.js";
55
55
  export type { SeparatorProp, SeparatorProps } from "./separator.js";
56
56
  export { AspectRatio } from "./aspect-ratio.js";
@@ -131,22 +131,17 @@ function Toolbar({
131
131
  role: "group",
132
132
  "aria-label": t("navigation.filterBar.appliedFilters"),
133
133
  className: "ui-filter-bar-chips",
134
- children: chips.map((chip) => /* @__PURE__ */ jsxs("span", { className: "ui-filter-bar-chip", children: [
135
- /* @__PURE__ */ jsx(Badge, { variant: "outline", children: chip.label }),
136
- onChipRemove && /* @__PURE__ */ jsx(
137
- Button,
138
- {
139
- variant: "ghost",
140
- size: "icon-sm",
141
- disabled: disabled || chip.disabled,
142
- "aria-label": t("navigation.filterBar.removeFilter", {
143
- label: typeof chip.label === "string" ? chip.label : chip.value
144
- }),
145
- onClick: () => onChipRemove(chip.value),
146
- children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true" })
147
- }
148
- )
149
- ] }, chip.value))
134
+ children: chips.map((chip) => /* @__PURE__ */ jsx(
135
+ Badge,
136
+ {
137
+ variant: "outline",
138
+ className: "ui-filter-bar-chip",
139
+ onRemove: onChipRemove ? () => onChipRemove(chip.value) : void 0,
140
+ removeDisabled: Boolean(disabled || chip.disabled),
141
+ children: typeof chip.label === "string" ? chip.label : chip.value
142
+ },
143
+ chip.value
144
+ ))
150
145
  }
151
146
  ),
152
147
  showMeta && /* @__PURE__ */ jsx("div", { className: "ui-filter-bar-meta", children: error != null ? /* @__PURE__ */ jsx("p", { role: "alert", className: "ui-filter-bar-error", children: error }) : /* @__PURE__ */ jsx("p", { role: "status", className: "ui-filter-bar-count", children: t("navigation.filterBar.resultCount", { count: resultCount }) }) })
@@ -1,6 +1,23 @@
1
1
  import * as React from "react";
2
+ /** Counter pill fields on {@link SegmentedOption} — same vocabulary as `Button` / `Toggle`. */
3
+ type SegmentedCountFields = {
4
+ /**
5
+ * Optional count rendered as a borderless pill after the label — do not nest `Badge` in `label`
6
+ * for this (gh#602): `Badge` `secondary` is `--muted`, which matches the Segmented track.
7
+ */
8
+ count?: number | string;
9
+ /** Cap for numeric `count` — beyond it the pill shows `{overflowCount}+` (e.g. `99+`). */
10
+ overflowCount?: number;
11
+ /** Render the pill when numeric `count` is 0. Default `true`. */
12
+ showZero?: boolean;
13
+ /**
14
+ * Localized description of what the count means, folded into the accessible name
15
+ * (`全件, 54 件` when supplied).
16
+ */
17
+ countLabel?: string;
18
+ };
2
19
  /** One choice in a {@link Segmented}. */
3
- export type SegmentedOption = {
20
+ export type SegmentedOption = SegmentedCountFields & {
4
21
  /** Wire value — what `onValueChange` reports and what a form submits. */
5
22
  value: string;
6
23
  /** Visible label. It is also the item's accessible name, so it is required. */
@@ -69,3 +86,4 @@ export type SegmentedProps = SegmentedProp;
69
86
  * row each of them means.
70
87
  */
71
88
  export declare const Segmented: React.ForwardRefExoticComponent<SegmentedProp & React.RefAttributes<HTMLDivElement>>;
89
+ export {};
@@ -1,9 +1,32 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { Radio as AriaRadio, RadioGroup as AriaRadioGroup } from "react-aria-components";
5
5
  import { withOwnHitTarget } from "../data-entry/choice-hit-target.js";
6
6
  import { cn } from "../../lib/utils.js";
7
+ import { useTranslation } from "../../i18n/use-translation.js";
8
+ import { numberFormat } from "../../lib/intl-cache.js";
9
+ function SegmentedCountPill({
10
+ count,
11
+ overflowCount = 99,
12
+ showZero = true,
13
+ countLabel
14
+ }) {
15
+ const { locale } = useTranslation();
16
+ const visible = count != null && count !== "" && (typeof count !== "number" || count !== 0 || showZero);
17
+ const formatted = React.useMemo(() => {
18
+ if (count == null || count === "") return "";
19
+ if (typeof count === "string") return count;
20
+ const format = numberFormat(locale);
21
+ return count > overflowCount ? `${format.format(overflowCount)}+` : format.format(count);
22
+ }, [count, locale, overflowCount]);
23
+ if (!visible) return null;
24
+ const spoken = countLabel ? `${formatted} ${countLabel}` : formatted;
25
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
26
+ /* @__PURE__ */ jsx("span", { "data-slot": "segmented-count", className: "ui-segmented-count", "aria-hidden": "true", children: formatted }),
27
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: `, ${spoken}` })
28
+ ] });
29
+ }
7
30
  const Segmented = React.forwardRef(function Segmented2({
8
31
  options,
9
32
  value,
@@ -59,7 +82,16 @@ const Segmented = React.forwardRef(function Segmented2({
59
82
  children: option.icon
60
83
  }
61
84
  ),
62
- /* @__PURE__ */ jsx("span", { "data-slot": "segmented-item-label", className: "ui-segmented-item-label", children: option.label })
85
+ /* @__PURE__ */ jsx("span", { "data-slot": "segmented-item-label", className: "ui-segmented-item-label", children: option.label }),
86
+ /* @__PURE__ */ jsx(
87
+ SegmentedCountPill,
88
+ {
89
+ count: option.count,
90
+ overflowCount: option.overflowCount,
91
+ showZero: option.showZero,
92
+ countLabel: option.countLabel
93
+ }
94
+ )
63
95
  ]
64
96
  },
65
97
  option.value
@@ -289,6 +289,11 @@ export type BadgeProp = {
289
289
  tabular?: boolean;
290
290
  className?: ClassNameProp;
291
291
  children?: ChildrenProp;
292
+ /**
293
+ * antd `Tag` `closable` + `onClose` — omit for a plain chip; set to draw a × that calls this once.
294
+ * Port name `onRemove` (not `onClose`) — see {@link Badge} JSDoc and `docs/DESIGN-AUTHORITY.md`.
295
+ */
296
+ onRemove?: () => void;
292
297
  };
293
298
  /** @see CredentialReveal */
294
299
  /**
@@ -1,4 +1,4 @@
1
- export type { AppLauncherApp, AppLauncherGroup, AppLauncherLabels, AppLauncherProp, AppShellProp, AuthFooterProp, AuthIdentityProp, OrgSwitcherLabels, OrgSwitcherOrganization, OrgSwitcherProp, DragAxisProp, DragBoundsProp, DraggablePanelPlacementProp, DraggablePanelPositionProp, DraggablePanelProp, PageContainerProp, PageInsetProp, SidebarItemProp, SidebarProductProp, SidebarProp, SidebarSectionProp, TopbarProp, } from "./layout.prop.js";
1
+ export type { AppLauncherApp, AppLauncherGroup, AppLauncherLabels, AppLauncherProp, AppShellProp, AuthFooterProp, AuthIdentityProp, OrgSwitcherLabels, OrgSwitcherOrganization, OrgSwitcherProp, DragAxisProp, DragBoundsProp, DraggablePanelLabels, DraggablePanelPlacementProp, DraggablePanelPositionProp, DraggablePanelProp, PageContainerProp, PageInsetProp, SidebarItemProp, SidebarProductProp, SidebarProp, SidebarSectionProp, TopbarProp, } from "./layout.prop.js";
2
2
  export type { ButtonProp } from "./general.prop.js";
3
3
  export type { InputProp, TextareaProp, FormFieldProp, SearchInputProp, CheckboxProp, CheckboxGroupProp, ChoiceOptionProp, RadioProp, RadioGroupProp, SwitchProp, SliderProp, CalendarProp, DatePickerProp, TimePickerProp, ColorPickerProp, UploadProp, UploadFileItemProp, UploadVariantProp, TreeOptionProp, TreeFieldNamesProp, CascaderProp, TreeSelectProp, ShowCheckedStrategyProp, TransferProp, TransferItemProp, } from "./data-entry.prop.js";
4
4
  export type { AvatarProp, EmptyStateProp, DescriptionsProp, DescriptionsItemProp, BadgeProp, DataTableProp, QrCodeProp, } from "./data-display.prop.js";
@@ -1442,6 +1442,11 @@ export type DraggablePanelPositionProp = {
1442
1442
  x: number;
1443
1443
  y: number;
1444
1444
  };
1445
+ /** Optional overrides for title-bar control labels when `AppProvider` is not in scope (gh#606). */
1446
+ export type DraggablePanelLabels = {
1447
+ close?: string;
1448
+ move?: string;
1449
+ };
1445
1450
  /**
1446
1451
  * @see DraggablePanel — a floating surface the person using it can MOVE, so a docked assistant
1447
1452
  * stops covering the thing they are asking about.
@@ -1458,8 +1463,8 @@ export type DraggablePanelProp = Omit<React.HTMLAttributes<HTMLElement>, "title"
1458
1463
  extra?: ExtraProp;
1459
1464
  /** Resting corner before any movement. Default `bottom-end`. */
1460
1465
  placement?: DraggablePanelPlacementProp;
1461
- /** Panel width, from the token scale. Default `md`. */
1462
- width?: Extract<SizeProp, "sm" | "md" | "lg">;
1466
+ /** Panel width, from the token scale (`sm`–`xl`). Default `md`. */
1467
+ width?: Extract<SizeProp, "sm" | "md" | "lg"> | "xl";
1463
1468
  /** react-draggable `axis`. Default `both`. */
1464
1469
  axis?: DragAxisProp;
1465
1470
  /** react-draggable `bounds`. Default `viewport`. */
@@ -1476,6 +1481,12 @@ export type DraggablePanelProp = Omit<React.HTMLAttributes<HTMLElement>, "title"
1476
1481
  onPositionChange?: (position: DraggablePanelPositionProp) => void;
1477
1482
  /** Presence renders the close control in the title bar (antd Modal's `onCancel`). */
1478
1483
  onClose?: () => void;
1484
+ /**
1485
+ * Localized strings for the close and move controls. Each key wins over `t()` when set; omit to
1486
+ * keep the framework default. For script-injected embeds that cannot mount `AppProvider` without
1487
+ * restyling the host page — a scoped provider subtree is the long-term fix (gh#606).
1488
+ */
1489
+ labels?: DraggablePanelLabels;
1479
1490
  /** react-draggable `disabled` — the panel stays, the handle stops moving it. */
1480
1491
  disabled?: DisabledProp;
1481
1492
  className?: ClassNameProp;
@@ -627,7 +627,7 @@ export declare const VOCABULARY_REGISTRY: {
627
627
  readonly ColumnDefProp: {
628
628
  readonly file: "vocabulary/data.prop.ts";
629
629
  readonly category: "data";
630
- readonly description: 'DataTable column definition — key/header/render/sortable/align/width/pin/hiddenOnMobile/enableHiding/ariaLabel plus `priority` (TableColumnPriorityProp), read by DataTable preset="action-collection"';
630
+ readonly description: 'DataTable column definition — key/header/render/sortable/align/width/pin/hideBelow/hiddenOnMobile/enableHiding/ariaLabel plus `priority` (TableColumnPriorityProp), read by DataTable preset="action-collection"';
631
631
  };
632
632
  readonly SelectedIdsProp: {
633
633
  readonly file: "vocabulary/data.prop.ts";
@@ -2536,6 +2536,10 @@ export declare const COMPONENT_PROP_REGISTRY: {
2536
2536
  readonly field: "onClose";
2537
2537
  readonly local: true;
2538
2538
  readonly reason: "Presence renders the title-bar close control — antd Modal's onCancel.";
2539
+ }, {
2540
+ readonly field: "labels";
2541
+ readonly local: true;
2542
+ readonly reason: "Optional close/move strings for embeds that cannot mount AppProvider without restyling the host page (gh#606).";
2539
2543
  }];
2540
2544
  };
2541
2545
  readonly ThumbnailSizeProp: {
@@ -628,7 +628,7 @@ const VOCABULARY_REGISTRY = {
628
628
  ColumnDefProp: {
629
629
  file: "vocabulary/data.prop.ts",
630
630
  category: "data",
631
- description: 'DataTable column definition \u2014 key/header/render/sortable/align/width/pin/hiddenOnMobile/enableHiding/ariaLabel plus `priority` (TableColumnPriorityProp), read by DataTable preset="action-collection"'
631
+ description: 'DataTable column definition \u2014 key/header/render/sortable/align/width/pin/hideBelow/hiddenOnMobile/enableHiding/ariaLabel plus `priority` (TableColumnPriorityProp), read by DataTable preset="action-collection"'
632
632
  },
633
633
  SelectedIdsProp: {
634
634
  file: "vocabulary/data.prop.ts",
@@ -2953,6 +2953,11 @@ const COMPONENT_PROP_REGISTRY = {
2953
2953
  field: "onClose",
2954
2954
  local: true,
2955
2955
  reason: "Presence renders the title-bar close control \u2014 antd Modal's onCancel."
2956
+ },
2957
+ {
2958
+ field: "labels",
2959
+ local: true,
2960
+ reason: "Optional close/move strings for embeds that cannot mount AppProvider without restyling the host page (gh#606)."
2956
2961
  }
2957
2962
  ]
2958
2963
  },
@@ -38,6 +38,17 @@ export type ColumnDefProp<T> = {
38
38
  * usual case.
39
39
  */
40
40
  headerAlign?: ColumnAlignProp;
41
+ /**
42
+ * Hide this column below a canonical viewport step — the SAME contract as `Flex hideBelow`
43
+ * (sm 40rem · md 48rem · lg 64rem · xl 80rem). Stamped on both `<th>` and `<td>` as
44
+ * `data-hide-below`; a media query cannot read a `var()`, so the step values are the tokenized
45
+ * scale written out in the stylesheet. Wins over `hiddenOnMobile` when both are set.
46
+ */
47
+ hideBelow?: BreakpointProp;
48
+ /**
49
+ * @deprecated Prefer `hideBelow: 'md'`. When `hideBelow` is omitted, `true` is an alias for
50
+ * `hideBelow: 'md'`.
51
+ */
41
52
  hiddenOnMobile?: boolean;
42
53
  /**
43
54
  * List this column in DataTable.ViewOptions (the column show/hide "set view"
@@ -50,4 +50,29 @@
50
50
  height: var(--badge-icon-size);
51
51
  flex-shrink: 0;
52
52
  }
53
+
54
+ [data-slot="badge"][data-removable] {
55
+ padding-inline-end: var(--badge-space-x-removable);
56
+ }
57
+
58
+ [data-slot="badge-remove"] {
59
+ flex-shrink: 0;
60
+ margin-inline-end: var(--badge-remove-offset-inline-end);
61
+ color: inherit;
62
+ opacity: var(--badge-remove-rest-alpha);
63
+ border: 0;
64
+ padding: 0;
65
+ cursor: pointer;
66
+ background: transparent;
67
+ }
68
+
69
+ [data-slot="badge-remove"]:hover,
70
+ [data-slot="badge-remove"]:focus-visible {
71
+ opacity: var(--badge-remove-hover-alpha);
72
+ }
73
+
74
+ [data-slot="badge-remove"] svg {
75
+ width: var(--badge-remove-icon-size);
76
+ height: var(--badge-remove-icon-size);
77
+ }
53
78
  }
@@ -1136,6 +1136,22 @@
1136
1136
  vertical-align: middle;
1137
1137
  }
1138
1138
 
1139
+ .ui-segmented-count {
1140
+ display: inline-flex;
1141
+ flex: 0 0 auto;
1142
+ align-items: center;
1143
+ justify-content: center;
1144
+ min-inline-size: var(--segmented-count-min-width);
1145
+ margin-inline-start: var(--segmented-count-gap);
1146
+ border-radius: var(--segmented-count-radius);
1147
+ padding-inline: var(--segmented-count-space-inline);
1148
+ background: var(--segmented-count-background, hsl(var(--primary)));
1149
+ color: var(--segmented-count-color, hsl(var(--primary-foreground)));
1150
+ font-size: var(--segmented-count-font-size);
1151
+ line-height: 1;
1152
+ font-variant-numeric: tabular-nums;
1153
+ }
1154
+
1139
1155
  .ui-tag-input {
1140
1156
  display: flex;
1141
1157
  flex-wrap: wrap;
@@ -1339,6 +1355,27 @@
1339
1355
  block-size: 0.75rem;
1340
1356
  }
1341
1357
 
1358
+ .ui-number-input-step {
1359
+ position: relative;
1360
+ }
1361
+
1362
+ .ui-number-input-step::after {
1363
+ content: "";
1364
+ position: absolute;
1365
+ inset-inline-start: 50%;
1366
+ translate: -50% 0;
1367
+ inline-size: var(--touch-target-min);
1368
+ block-size: var(--touch-target-min);
1369
+ }
1370
+
1371
+ .ui-number-input-step-up::after {
1372
+ inset-block-end: 0;
1373
+ }
1374
+
1375
+ .ui-number-input-step-down::after {
1376
+ inset-block-start: 0;
1377
+ }
1378
+
1342
1379
  @media (pointer: coarse) {
1343
1380
  .ui-number-input:not([data-size="xs"]):not([data-size="sm"]) {
1344
1381
  --control-height: var(--number-input-touch-height);
@@ -0,0 +1,3 @@
1
+
2
+ @import "./core.css";
3
+ @import "./font-fallbacks.css";
@@ -18,6 +18,7 @@
18
18
  .ui-control-inline-affix-action,
19
19
  .ui-search-input-clear,
20
20
  .ui-tag-input-remove,
21
+ .ui-badge-remove,
21
22
  .ui-color-picker-input,
22
23
  .ui-upload-tile-add,
23
24
  .ui-upload-picture-empty,
@@ -78,6 +79,7 @@
78
79
  .ui-control-inline-affix-action,
79
80
  .ui-search-input-clear,
80
81
  .ui-tag-input-remove,
82
+ .ui-badge-remove,
81
83
  .ui-color-picker-input,
82
84
  .ui-upload-tile-add,
83
85
  .ui-upload-picture-empty,