@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.
- package/README.md +17 -2
- package/dist/components/data-display/badge.d.ts +14 -1
- package/dist/components/data-display/badge.js +21 -1
- package/dist/components/data-display/data-table.d.ts +4 -2
- package/dist/components/data-display/data-table.js +14 -2
- package/dist/components/data-entry/date-picker.js +4 -16
- package/dist/components/layout/draggable-panel.d.ts +3 -2
- package/dist/components/layout/draggable-panel.js +11 -2
- package/dist/components/layout/index.d.ts +1 -1
- package/dist/components/navigation/filter-bar.js +11 -16
- package/dist/components/ui/segmented.d.ts +19 -1
- package/dist/components/ui/segmented.js +34 -2
- package/dist/props/components/data-display.prop.d.ts +5 -0
- package/dist/props/components/index.d.ts +1 -1
- package/dist/props/components/layout.prop.d.ts +13 -2
- package/dist/props/registry.d.ts +5 -1
- package/dist/props/registry.js +6 -1
- package/dist/props/vocabulary/data.prop.d.ts +11 -0
- package/dist/styles/badge-layout.css +25 -0
- package/dist/styles/control.css +37 -0
- package/dist/styles/core-with-fallbacks.css +3 -0
- package/dist/styles/focus-ring.css +2 -0
- package/dist/styles/font-fallbacks.css +83 -0
- package/dist/styles/fonts.css +1 -82
- package/dist/styles/layout.css +17 -5
- package/dist/tokens/components/badge.css +6 -0
- package/dist/tokens/components/draggable-panel.css +4 -0
- package/dist/tokens/components/segmented.css +8 -0
- package/docs/CONSUMER-RULES.md +1 -1
- package/docs/CUSTOMER-THEMING.md +16 -2
- package/docs/DESIGN-AUTHORITY.md +15 -0
- package/docs/data-entry/segmented-in-filter-row.tsx +2 -19
- package/docs/data-entry/segmented.tsx +2 -19
- package/package.json +4 -2
- package/scripts/_agent-setup.mjs +90 -17
- package/scripts/cli.mjs +6 -2
- package/scripts/consumer-rule.md +76 -18
- package/scripts/guinea-pig-skill.md +38 -9
- package/scripts/postinstall.mjs +1 -1
- 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
|
|
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` / `
|
|
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:
|
|
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:
|
|
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__ */
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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;
|
package/dist/props/registry.d.ts
CHANGED
|
@@ -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: {
|
package/dist/props/registry.js
CHANGED
|
@@ -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
|
}
|
package/dist/styles/control.css
CHANGED
|
@@ -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);
|
|
@@ -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,
|