@godxjp/ui 31.28.4 → 31.30.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.
- package/agent/START-HERE.md +5 -5
- package/agent/components/AppLauncher.json +5 -0
- package/agent/components/Avatar.json +1 -0
- package/agent/components/Dialog.json +3 -1
- package/agent/components/Legend.json +1 -1
- package/agent/components/PasswordStrength.json +2 -2
- package/agent/components/RangeTimeline.json +28 -1
- package/agent/components/ResponsiveGrid.json +7 -0
- package/agent/components/Sidebar.json +5 -0
- package/agent/components/SortableList.json +78 -0
- package/agent/components/TopbarItem.json +1 -1
- package/agent/components-index.json +5 -0
- package/agent/components.json +131 -6
- package/agent/index.json +6 -6
- package/agent/llms.txt +6 -6
- package/agent/tokens.json +122 -2
- package/dist/components/data-display/legend.d.ts +3 -2
- package/dist/components/data-display/legend.js +10 -1
- package/dist/components/data-display/range-timeline.d.ts +93 -2
- package/dist/components/data-display/range-timeline.js +220 -58
- package/dist/components/data-entry/index.d.ts +2 -0
- package/dist/components/data-entry/index.js +2 -0
- package/dist/components/data-entry/password-strength.d.ts +15 -3
- package/dist/components/data-entry/password-strength.js +16 -34
- package/dist/components/data-entry/sortable-list.d.ts +10 -0
- package/dist/components/data-entry/sortable-list.js +237 -0
- package/dist/components/feedback/dialog.d.ts +8 -2
- package/dist/components/feedback/dialog.js +8 -1
- package/dist/components/feedback/sheet.js +1 -1
- package/dist/components/layout/app-launcher.d.ts +1 -1
- package/dist/components/layout/app-launcher.js +18 -14
- package/dist/components/layout/responsive-grid.d.ts +17 -2
- package/dist/components/layout/responsive-grid.js +17 -4
- package/dist/components/layout/sidebar.d.ts +1 -1
- package/dist/components/layout/sidebar.js +3 -0
- package/dist/components/layout/topbar-item.js +8 -2
- package/dist/components/ui/avatar.d.ts +3 -1
- package/dist/components/ui/avatar.js +2 -1
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +31 -1
- package/dist/i18n/messages/ja.json +31 -1
- package/dist/i18n/messages/vi.json +31 -1
- package/dist/props/components/data-display.prop.d.ts +18 -0
- package/dist/props/components/data-entry.prop.d.ts +34 -0
- package/dist/props/components/feedback.prop.d.ts +6 -1
- package/dist/props/components/layout.prop.d.ts +22 -0
- package/dist/props/registry.d.ts +33 -2
- package/dist/props/registry.js +44 -1
- package/dist/styles/control.css +50 -0
- package/dist/styles/data-display-layout.css +139 -2
- package/dist/styles/dialog-layout.css +14 -1
- package/dist/styles/layers.json +6 -1
- package/dist/styles/layout.css +29 -7
- package/dist/styles/shell-layout.css +26 -0
- package/dist/tokens/components/control.css +5 -0
- package/dist/tokens/components/data-display.css +12 -0
- package/dist/tokens/components/feedback.css +6 -0
- package/dist/tokens/components/shell.css +6 -0
- package/dist/tokens/semantic/layout.css +1 -4
- package/docs/FRAME-COVERAGE-REPORT.md +4 -3
- package/docs/data-display/avatar.tsx +32 -0
- package/docs/data-display/timeline.tsx +84 -1
- package/docs/data-entry/sortable-list.tsx +76 -0
- package/docs/feedback/dialog.tsx +37 -1
- package/docs/i18n/messages/en.json +62 -0
- package/docs/i18n/messages/ja.json +62 -0
- package/docs/i18n/messages/vi.json +62 -0
- package/docs/layout/app-launcher.tsx +17 -1
- package/docs/layout/responsive-grid.tsx +23 -0
- package/docs/layout/sidebar.tsx +24 -0
- package/docs/layout/topbar-item.tsx +11 -0
- package/package.json +2 -2
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { GripVertical } from "lucide-react";
|
|
5
|
+
import { useTranslation } from "../../i18n/use-translation.js";
|
|
6
|
+
import { cn } from "../../lib/utils.js";
|
|
7
|
+
import { Button } from "../general/button.js";
|
|
8
|
+
const DRAG_THRESHOLD = 4;
|
|
9
|
+
function move(list, from, to) {
|
|
10
|
+
const next = list.slice();
|
|
11
|
+
const [item] = next.splice(from, 1);
|
|
12
|
+
next.splice(to, 0, item);
|
|
13
|
+
return next;
|
|
14
|
+
}
|
|
15
|
+
function reconcile(order, items) {
|
|
16
|
+
const known = new Set(items.map((item) => item.value));
|
|
17
|
+
const kept = order.filter((key) => known.has(key));
|
|
18
|
+
const seen = new Set(kept);
|
|
19
|
+
return [...kept, ...items.map((item) => item.value).filter((key) => !seen.has(key))];
|
|
20
|
+
}
|
|
21
|
+
const SortableList = React.forwardRef(
|
|
22
|
+
function SortableList2({
|
|
23
|
+
items,
|
|
24
|
+
value: valueProp,
|
|
25
|
+
defaultValue,
|
|
26
|
+
onValueChange,
|
|
27
|
+
renderItem,
|
|
28
|
+
layout = "list",
|
|
29
|
+
disabled = false,
|
|
30
|
+
"aria-label": ariaLabel,
|
|
31
|
+
id,
|
|
32
|
+
className
|
|
33
|
+
}, ref) {
|
|
34
|
+
const { t, locale } = useTranslation();
|
|
35
|
+
const hintId = React.useId();
|
|
36
|
+
const [inner, setInner] = React.useState(
|
|
37
|
+
() => defaultValue ?? items.map((item) => item.value)
|
|
38
|
+
);
|
|
39
|
+
const committed = reconcile(valueProp ?? inner, items);
|
|
40
|
+
const [preview, setPreview] = React.useState(null);
|
|
41
|
+
const [held, setHeld] = React.useState(
|
|
42
|
+
null
|
|
43
|
+
);
|
|
44
|
+
const [announcement, setAnnouncement] = React.useState("");
|
|
45
|
+
const order = preview ?? committed;
|
|
46
|
+
const byKey = React.useMemo(() => new Map(items.map((item) => [item.value, item])), [items]);
|
|
47
|
+
const listRef = React.useRef(null);
|
|
48
|
+
const number = React.useMemo(() => new Intl.NumberFormat(locale), [locale]);
|
|
49
|
+
const position = (keys, key) => ({
|
|
50
|
+
label: byKey.get(key)?.label ?? key,
|
|
51
|
+
position: number.format(keys.indexOf(key) + 1),
|
|
52
|
+
count: number.format(keys.length)
|
|
53
|
+
});
|
|
54
|
+
const commit = (keys) => {
|
|
55
|
+
if (keys.join("\0") !== committed.join("\0")) {
|
|
56
|
+
if (valueProp === void 0) setInner(keys);
|
|
57
|
+
onValueChange?.(keys);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const lift = (key, via) => {
|
|
61
|
+
setHeld({ key, via });
|
|
62
|
+
setPreview(committed);
|
|
63
|
+
setAnnouncement(t("dataEntry.sortableList.lifted", position(committed, key)));
|
|
64
|
+
};
|
|
65
|
+
const drop = () => {
|
|
66
|
+
if (!held || !preview) return;
|
|
67
|
+
commit(preview);
|
|
68
|
+
setAnnouncement(t("dataEntry.sortableList.dropped", position(preview, held.key)));
|
|
69
|
+
setHeld(null);
|
|
70
|
+
setPreview(null);
|
|
71
|
+
};
|
|
72
|
+
const cancel = () => {
|
|
73
|
+
if (!held) return;
|
|
74
|
+
setAnnouncement(t("dataEntry.sortableList.cancelled", position(committed, held.key)));
|
|
75
|
+
setHeld(null);
|
|
76
|
+
setPreview(null);
|
|
77
|
+
};
|
|
78
|
+
const moveTo = (key, target) => {
|
|
79
|
+
setPreview((current) => {
|
|
80
|
+
const keys = current ?? committed;
|
|
81
|
+
const from = keys.indexOf(key);
|
|
82
|
+
const to = Math.max(0, Math.min(keys.length - 1, target));
|
|
83
|
+
if (from < 0 || from === to) return keys;
|
|
84
|
+
const next = move(keys, from, to);
|
|
85
|
+
setAnnouncement(t("dataEntry.sortableList.moved", position(next, key)));
|
|
86
|
+
return next;
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
const onKeyDown = (key) => (event) => {
|
|
90
|
+
if (event.key === " " || event.key === "Enter") {
|
|
91
|
+
event.preventDefault();
|
|
92
|
+
if (held?.key === key) drop();
|
|
93
|
+
else if (!held) lift(key, "keyboard");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (held?.key !== key) return;
|
|
97
|
+
const index = order.indexOf(key);
|
|
98
|
+
const step = {
|
|
99
|
+
ArrowUp: -1,
|
|
100
|
+
ArrowLeft: -1,
|
|
101
|
+
ArrowDown: 1,
|
|
102
|
+
ArrowRight: 1
|
|
103
|
+
};
|
|
104
|
+
if (event.key in step) {
|
|
105
|
+
event.preventDefault();
|
|
106
|
+
moveTo(key, index + (step[event.key] ?? 0));
|
|
107
|
+
} else if (event.key === "Home") {
|
|
108
|
+
event.preventDefault();
|
|
109
|
+
moveTo(key, 0);
|
|
110
|
+
} else if (event.key === "End") {
|
|
111
|
+
event.preventDefault();
|
|
112
|
+
moveTo(key, order.length - 1);
|
|
113
|
+
} else if (event.key === "Escape") {
|
|
114
|
+
event.preventDefault();
|
|
115
|
+
cancel();
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
const indexAt = (x, y) => {
|
|
119
|
+
const nodes = Array.from(
|
|
120
|
+
listRef.current?.querySelectorAll("[data-sortable-value]") ?? []
|
|
121
|
+
);
|
|
122
|
+
let best = -1;
|
|
123
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
124
|
+
nodes.forEach((node, index) => {
|
|
125
|
+
const box = node.getBoundingClientRect();
|
|
126
|
+
if (x >= box.left && x <= box.right && y >= box.top && y <= box.bottom) {
|
|
127
|
+
best = index;
|
|
128
|
+
bestDistance = -1;
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (bestDistance < 0) return;
|
|
132
|
+
const distance = Math.hypot(x - (box.left + box.width / 2), y - (box.top + box.height / 2));
|
|
133
|
+
if (distance < bestDistance) {
|
|
134
|
+
bestDistance = distance;
|
|
135
|
+
best = index;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
return best;
|
|
139
|
+
};
|
|
140
|
+
const press = React.useRef(
|
|
141
|
+
null
|
|
142
|
+
);
|
|
143
|
+
const latest = React.useRef({ lift, moveTo, drop, cancel, indexAt });
|
|
144
|
+
latest.current = { lift, moveTo, drop, cancel, indexAt };
|
|
145
|
+
const onPointerDown = (key) => (event) => {
|
|
146
|
+
if (event.button !== 0 || held) return;
|
|
147
|
+
press.current = { key, x: event.clientX, y: event.clientY, dragging: false };
|
|
148
|
+
const onMove = (move2) => {
|
|
149
|
+
const current = press.current;
|
|
150
|
+
if (!current) return;
|
|
151
|
+
if (!current.dragging) {
|
|
152
|
+
if (Math.hypot(move2.clientX - current.x, move2.clientY - current.y) < DRAG_THRESHOLD)
|
|
153
|
+
return;
|
|
154
|
+
current.dragging = true;
|
|
155
|
+
latest.current.lift(current.key, "pointer");
|
|
156
|
+
}
|
|
157
|
+
const target = latest.current.indexAt(move2.clientX, move2.clientY);
|
|
158
|
+
if (target >= 0) latest.current.moveTo(current.key, target);
|
|
159
|
+
};
|
|
160
|
+
const end = (cancelled) => () => {
|
|
161
|
+
window.removeEventListener("pointermove", onMove);
|
|
162
|
+
window.removeEventListener("pointerup", onUp);
|
|
163
|
+
window.removeEventListener("pointercancel", onCancel);
|
|
164
|
+
window.removeEventListener("keydown", onKey);
|
|
165
|
+
const current = press.current;
|
|
166
|
+
press.current = null;
|
|
167
|
+
if (!current?.dragging) return;
|
|
168
|
+
if (cancelled) latest.current.cancel();
|
|
169
|
+
else latest.current.drop();
|
|
170
|
+
};
|
|
171
|
+
const onUp = end(false);
|
|
172
|
+
const onCancel = end(true);
|
|
173
|
+
const onKey = (key2) => {
|
|
174
|
+
if (key2.key === "Escape" && press.current?.dragging) end(true)();
|
|
175
|
+
};
|
|
176
|
+
window.addEventListener("pointermove", onMove);
|
|
177
|
+
window.addEventListener("pointerup", onUp);
|
|
178
|
+
window.addEventListener("pointercancel", onCancel);
|
|
179
|
+
window.addEventListener("keydown", onKey);
|
|
180
|
+
};
|
|
181
|
+
return /* @__PURE__ */ jsxs(
|
|
182
|
+
"div",
|
|
183
|
+
{
|
|
184
|
+
ref,
|
|
185
|
+
id,
|
|
186
|
+
className: cn("ui-sortable-list", className),
|
|
187
|
+
"data-layout": layout,
|
|
188
|
+
"data-disabled": disabled || void 0,
|
|
189
|
+
children: [
|
|
190
|
+
/* @__PURE__ */ jsx("ul", { ref: listRef, className: "ui-sortable-list-items", "aria-label": ariaLabel, children: order.map((key, index) => {
|
|
191
|
+
const item = byKey.get(key);
|
|
192
|
+
if (!item) return null;
|
|
193
|
+
const dragging = held?.key === key;
|
|
194
|
+
const itemDisabled = disabled || item.disabled;
|
|
195
|
+
return /* @__PURE__ */ jsxs(
|
|
196
|
+
"li",
|
|
197
|
+
{
|
|
198
|
+
className: "ui-sortable-list-item",
|
|
199
|
+
"data-sortable-value": key,
|
|
200
|
+
"data-dragging": dragging || void 0,
|
|
201
|
+
"data-disabled": itemDisabled || void 0,
|
|
202
|
+
children: [
|
|
203
|
+
/* @__PURE__ */ jsx(
|
|
204
|
+
Button,
|
|
205
|
+
{
|
|
206
|
+
type: "button",
|
|
207
|
+
variant: "ghost",
|
|
208
|
+
size: "icon-sm",
|
|
209
|
+
className: "ui-sortable-list-handle",
|
|
210
|
+
disabled: itemDisabled,
|
|
211
|
+
"aria-label": t("dataEntry.sortableList.handle", { label: item.label }),
|
|
212
|
+
"aria-describedby": hintId,
|
|
213
|
+
"aria-pressed": dragging,
|
|
214
|
+
onKeyDown: onKeyDown(key),
|
|
215
|
+
onBlur: () => {
|
|
216
|
+
if (held?.key === key && held.via === "keyboard") cancel();
|
|
217
|
+
},
|
|
218
|
+
onPointerDown: onPointerDown(key),
|
|
219
|
+
children: /* @__PURE__ */ jsx(GripVertical, { "aria-hidden": "true" })
|
|
220
|
+
}
|
|
221
|
+
),
|
|
222
|
+
/* @__PURE__ */ jsx("div", { className: "ui-sortable-list-content", children: renderItem ? renderItem(item, { index, dragging }) : item.label })
|
|
223
|
+
]
|
|
224
|
+
},
|
|
225
|
+
key
|
|
226
|
+
);
|
|
227
|
+
}) }),
|
|
228
|
+
/* @__PURE__ */ jsx("span", { id: hintId, className: "sr-only", children: t("dataEntry.sortableList.hint") }),
|
|
229
|
+
/* @__PURE__ */ jsx("span", { role: "status", "aria-live": "polite", className: "sr-only", children: announcement })
|
|
230
|
+
]
|
|
231
|
+
}
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
);
|
|
235
|
+
export {
|
|
236
|
+
SortableList
|
|
237
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import type { ToneProp } from "../../props/vocabulary/index.js";
|
|
2
|
+
import type { ToneProp, WidthProp } from "../../props/vocabulary/index.js";
|
|
3
3
|
import type { AlertDialogProp, DialogContentProp, DialogProp } from "../../props/components/feedback.prop.js";
|
|
4
4
|
export type { AlertDialogProp, AlertDialogProp as AlertDialogProps, DialogProp, DialogProp as DialogProps, DialogContentProp, DialogContentProp as DialogContentProps, } from "../../props/components/feedback.prop.js";
|
|
5
5
|
interface OverlayOpenProps {
|
|
@@ -57,8 +57,14 @@ interface DialogContentProps extends Omit<React.ComponentPropsWithRef<"section">
|
|
|
57
57
|
forceMount?: true;
|
|
58
58
|
/** Giữ tên prop của Radix — xem `useCloseAutoFocus`. */
|
|
59
59
|
onCloseAutoFocus?: (event: Event) => void;
|
|
60
|
+
/**
|
|
61
|
+
* Panel width (antd Modal `width`, the same vocabulary as SheetContent `width`). A number is px;
|
|
62
|
+
* a string is any CSS length. Capped at the viewport minus `--dialog-viewport-inset`, so a wide
|
|
63
|
+
* dialog never leaves a phone screen. Omit to keep `--dialog-width-default` (32rem).
|
|
64
|
+
*/
|
|
65
|
+
width?: WidthProp;
|
|
60
66
|
}
|
|
61
|
-
declare function DialogContent({ className, children, showClose, showCloseButton: showCloseButtonProp, overlayClassName, variant: variantProp, forceMount: _forceMount, ...props }: DialogContentProps): React.JSX.Element;
|
|
67
|
+
declare function DialogContent({ className, children, showClose, showCloseButton: showCloseButtonProp, overlayClassName, variant: variantProp, forceMount: _forceMount, width, style, ...props }: DialogContentProps): React.JSX.Element;
|
|
62
68
|
declare namespace DialogContent {
|
|
63
69
|
var displayName: string;
|
|
64
70
|
}
|
|
@@ -45,7 +45,7 @@ const DialogLabelContext = React.createContext(null);
|
|
|
45
45
|
const DialogVariantContext = React.createContext("default");
|
|
46
46
|
const DialogModalContext = React.createContext(true);
|
|
47
47
|
const OVERLAY_CLASS = "ui-dialog-overlay data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0";
|
|
48
|
-
const CONTENT_CLASS = "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95
|
|
48
|
+
const CONTENT_CLASS = "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 outline-none";
|
|
49
49
|
function DialogShell({
|
|
50
50
|
role = "dialog",
|
|
51
51
|
className,
|
|
@@ -177,6 +177,8 @@ function DialogContent({
|
|
|
177
177
|
overlayClassName,
|
|
178
178
|
variant: variantProp,
|
|
179
179
|
forceMount: _forceMount,
|
|
180
|
+
width,
|
|
181
|
+
style,
|
|
180
182
|
...props
|
|
181
183
|
}) {
|
|
182
184
|
const { t } = useTranslation();
|
|
@@ -184,6 +186,10 @@ function DialogContent({
|
|
|
184
186
|
const variant = variantProp ?? inheritedVariant;
|
|
185
187
|
const isDestructive = variant === "destructive";
|
|
186
188
|
const showCloseButton = showCloseButtonProp ?? showClose ?? !isDestructive;
|
|
189
|
+
const mergedStyle = width == null ? style : {
|
|
190
|
+
...style,
|
|
191
|
+
["--dialog-width"]: typeof width === "number" ? `${width}px` : width
|
|
192
|
+
};
|
|
187
193
|
return /* @__PURE__ */ jsx(DialogVariantContext.Provider, { value: variant, children: /* @__PURE__ */ jsxs(
|
|
188
194
|
DialogShell,
|
|
189
195
|
{
|
|
@@ -192,6 +198,7 @@ function DialogContent({
|
|
|
192
198
|
"data-variant": variant,
|
|
193
199
|
className,
|
|
194
200
|
overlayClassName,
|
|
201
|
+
style: mergedStyle,
|
|
195
202
|
...props,
|
|
196
203
|
children: [
|
|
197
204
|
children,
|
|
@@ -91,7 +91,7 @@ function SheetOverlay(_props) {
|
|
|
91
91
|
SheetOverlay.displayName = "SheetOverlay";
|
|
92
92
|
const SHEET_OVERLAY_CLASS = "ui-sheet-overlay data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 fixed";
|
|
93
93
|
const sheetVariants = cva(
|
|
94
|
-
"ui-sheet-panel fixed flex flex-col gap-[var(--space-chrome-gap)] text-foreground px-[var(--sheet-pad-x)] py-[var(--sheet-pad-y)] transition ease-in-out data-[state=closed]:animate-out data-[state=
|
|
94
|
+
"ui-sheet-panel fixed flex flex-col gap-[var(--space-chrome-gap)] text-foreground px-[var(--sheet-pad-x)] py-[var(--sheet-pad-y)] transition ease-in-out data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
95
95
|
{
|
|
96
96
|
variants: {
|
|
97
97
|
// `side` is a deliberately PHYSICAL API (left/right/top/bottom) — a sheet
|
|
@@ -31,4 +31,4 @@ type DataAttributes = {
|
|
|
31
31
|
* single product where switching workspace is constant enough to be worth permanent screen width
|
|
32
32
|
* (Slack). Shipping both puts one scope in two places and makes neither authoritative.
|
|
33
33
|
*/
|
|
34
|
-
export declare function AppLauncher({ apps, groups, labels, columns, linkComponent, loading, error, onRetry, responsive, appearance, side, align, open, onOpenChange, className, ...rest }: AppLauncherProp & Pick<React.ComponentPropsWithoutRef<"button">, "id"> & DataAttributes): React.JSX.Element;
|
|
34
|
+
export declare function AppLauncher({ apps, groups, labels, columns, linkComponent, loading, error, onRetry, responsive, appearance, side, align, footer, open, onOpenChange, className, ...rest }: AppLauncherProp & Pick<React.ComponentPropsWithoutRef<"button">, "id"> & DataAttributes): React.JSX.Element;
|
|
@@ -165,6 +165,7 @@ function AppLauncher({
|
|
|
165
165
|
appearance = "bar",
|
|
166
166
|
side,
|
|
167
167
|
align,
|
|
168
|
+
footer,
|
|
168
169
|
open,
|
|
169
170
|
onOpenChange,
|
|
170
171
|
className,
|
|
@@ -194,20 +195,23 @@ function AppLauncher({
|
|
|
194
195
|
...rest
|
|
195
196
|
};
|
|
196
197
|
const trigger = appearance === "bar" ? /* @__PURE__ */ jsx(TopbarItem, { ...triggerProps, children: /* @__PURE__ */ jsx(Grip, { "aria-hidden": "true" }) }) : /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", ...triggerProps, children: /* @__PURE__ */ jsx(Grip, { "aria-hidden": "true" }) });
|
|
197
|
-
const panel = /* @__PURE__ */
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
198
|
+
const panel = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
199
|
+
/* @__PURE__ */ jsx(
|
|
200
|
+
AppLauncherPanel,
|
|
201
|
+
{
|
|
202
|
+
apps,
|
|
203
|
+
groups,
|
|
204
|
+
labels,
|
|
205
|
+
columns,
|
|
206
|
+
linkComponent,
|
|
207
|
+
loading,
|
|
208
|
+
error,
|
|
209
|
+
onRetry,
|
|
210
|
+
close
|
|
211
|
+
}
|
|
212
|
+
),
|
|
213
|
+
footer != null && footer !== false ? /* @__PURE__ */ jsx("div", { "data-slot": "app-launcher-footer", className: "ui-app-launcher-footer", children: footer }) : null
|
|
214
|
+
] });
|
|
211
215
|
if (launchpad) {
|
|
212
216
|
return /* @__PURE__ */ jsxs(Dialog, { open: resolvedOpen, onOpenChange: setOpen, children: [
|
|
213
217
|
/* @__PURE__ */ jsx(DialogTrigger, { asChild: true, children: trigger }),
|
|
@@ -24,15 +24,30 @@ export type ResponsiveGridProps = {
|
|
|
24
24
|
* to strip its old `columns` prop.
|
|
25
25
|
*/
|
|
26
26
|
preset?: ResponsiveGridPresetProp;
|
|
27
|
+
/**
|
|
28
|
+
* Dense packing (`grid-auto-flow: row dense`): a later, smaller cell back-fills the hole a wide
|
|
29
|
+
* or tall cell left earlier in the row — a widget board of 1×1 / 2×1 / 1×2 cells without gaps
|
|
30
|
+
* (gh#1175). It changes VISUAL order only; DOM and focus order stay as written, so use it where
|
|
31
|
+
* the cells are independent (widgets, tiles), not where reading order matters. Ignored under
|
|
32
|
+
* `flow="columns"`, whose sequence is the point.
|
|
33
|
+
*/
|
|
34
|
+
dense?: boolean;
|
|
27
35
|
children: ReactNode;
|
|
28
36
|
};
|
|
29
|
-
export declare function ResponsiveGrid({ columns, flow, align, gap, pad, padRaw, preset, className, children, }: ResponsiveGridProps): import("react").JSX.Element;
|
|
37
|
+
export declare function ResponsiveGrid({ columns, flow, align, gap, pad, padRaw, preset, dense, className, children, }: ResponsiveGridProps): import("react").JSX.Element;
|
|
30
38
|
export declare namespace ResponsiveGrid {
|
|
31
39
|
export { ResponsiveGridItem as Item };
|
|
32
40
|
}
|
|
33
41
|
/** A grid item owns its responsive span; no extra implicit columns on a narrow container. */
|
|
34
|
-
export declare function ResponsiveGridItem({ span, children, className, }: {
|
|
42
|
+
export declare function ResponsiveGridItem({ span, rowSpan, children, className, }: {
|
|
35
43
|
span?: ResponsiveGridColumnsProp;
|
|
44
|
+
/**
|
|
45
|
+
* Rows the cell spans — the tall (1×2) widget of a board (gh#1175). Same shape as `span`: a
|
|
46
|
+
* number spans that many rows from the `sm` step up and one row at `base`, where the grid is a
|
|
47
|
+
* single stacked column and a tall cell would only stretch; an object sets each step. Pair with
|
|
48
|
+
* `ResponsiveGrid dense` so the cells after it fill the space beside it.
|
|
49
|
+
*/
|
|
50
|
+
rowSpan?: ResponsiveGridColumnsProp;
|
|
36
51
|
children?: ReactNode;
|
|
37
52
|
className?: string;
|
|
38
53
|
}): import("react").JSX.Element;
|
|
@@ -36,6 +36,7 @@ function ResponsiveGrid({
|
|
|
36
36
|
pad,
|
|
37
37
|
padRaw,
|
|
38
38
|
preset,
|
|
39
|
+
dense = false,
|
|
39
40
|
className,
|
|
40
41
|
children
|
|
41
42
|
}) {
|
|
@@ -47,21 +48,33 @@ function ResponsiveGrid({
|
|
|
47
48
|
"data-gap": gap,
|
|
48
49
|
"data-flow": flow === "columns" ? "columns" : void 0,
|
|
49
50
|
"data-align": align,
|
|
51
|
+
"data-dense": dense && flow !== "columns" ? "" : void 0,
|
|
50
52
|
style: { ...toStyle(resolved), ...padStyle(pad, padRaw) },
|
|
51
53
|
"data-pad-raw": padRaw === void 0 ? void 0 : "",
|
|
52
54
|
children
|
|
53
55
|
}
|
|
54
56
|
) });
|
|
55
57
|
}
|
|
58
|
+
function resolveSpan(span) {
|
|
59
|
+
return typeof span === "number" ? { base: 1, sm: span, md: span, lg: span } : resolveColumns(span);
|
|
60
|
+
}
|
|
56
61
|
function ResponsiveGridItem({
|
|
57
62
|
span = 1,
|
|
63
|
+
rowSpan,
|
|
58
64
|
children,
|
|
59
65
|
className
|
|
60
66
|
}) {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
const style = Object.fromEntries([
|
|
68
|
+
...Object.entries(resolveSpan(span)).map(([step, value]) => [
|
|
69
|
+
`--responsive-grid-item-${step}`,
|
|
70
|
+
value
|
|
71
|
+
]),
|
|
72
|
+
// Only when asked: an item without `rowSpan` renders the style it always had.
|
|
73
|
+
...rowSpan === void 0 ? [] : Object.entries(resolveSpan(rowSpan)).map(([step, value]) => [
|
|
74
|
+
`--responsive-grid-item-row-${step}`,
|
|
75
|
+
value
|
|
76
|
+
])
|
|
77
|
+
]);
|
|
65
78
|
return /* @__PURE__ */ jsx("div", { className: cn("ui-responsive-grid-item", className), style, children });
|
|
66
79
|
}
|
|
67
80
|
ResponsiveGrid.Item = ResponsiveGridItem;
|
|
@@ -47,4 +47,4 @@ export { createSidebarLink } from "./sidebar-link.js";
|
|
|
47
47
|
* Sidebar — data-driven vertical nav rail. Use {@link createSidebarLink} to adapt a router `Link`,
|
|
48
48
|
* or `SidebarItem asChild` when composing rows by hand.
|
|
49
49
|
*/
|
|
50
|
-
export declare function Sidebar({ ariaLabel: ariaLabelCamel, scrollRef, activeId, onSelect, sections, product, onProductClick, brand, collapsed, children, linkComponent, renderItem, footer, "aria-label": ariaLabel, }: SidebarProp): React.JSX.Element;
|
|
50
|
+
export declare function Sidebar({ ariaLabel: ariaLabelCamel, scrollRef, activeId, onSelect, sections, product, onProductClick, brand, action, collapsed, children, linkComponent, renderItem, footer, "aria-label": ariaLabel, }: SidebarProp): React.JSX.Element;
|
|
@@ -301,6 +301,7 @@ function Sidebar({
|
|
|
301
301
|
product,
|
|
302
302
|
onProductClick,
|
|
303
303
|
brand,
|
|
304
|
+
action,
|
|
304
305
|
collapsed = false,
|
|
305
306
|
children,
|
|
306
307
|
linkComponent,
|
|
@@ -314,6 +315,7 @@ function Sidebar({
|
|
|
314
315
|
collapsed = surface === "drawer" ? false : collapsed;
|
|
315
316
|
const brandNode = typeof brand === "function" ? brand(collapsed) : brand;
|
|
316
317
|
const footerNode = typeof footer === "function" ? footer(collapsed) : footer;
|
|
318
|
+
const actionNode = typeof action === "function" ? action(collapsed) : action;
|
|
317
319
|
return /* @__PURE__ */ jsxs("div", { className: "sb-root", "data-collapsed": collapsed ? "true" : void 0, children: [
|
|
318
320
|
brand !== void 0 ? /* @__PURE__ */ jsx(SidebarHeader, { children: brandNode }) : product ? (() => {
|
|
319
321
|
const interactive = onProductClick != null;
|
|
@@ -352,6 +354,7 @@ function Sidebar({
|
|
|
352
354
|
meta
|
|
353
355
|
] });
|
|
354
356
|
})() : null,
|
|
357
|
+
actionNode ? /* @__PURE__ */ jsx("div", { className: "sb-action", "data-slot": "sidebar-action", children: actionNode }) : null,
|
|
355
358
|
/* @__PURE__ */ jsx(
|
|
356
359
|
"nav",
|
|
357
360
|
{
|
|
@@ -16,7 +16,7 @@ const TopbarItem = React.forwardRef(function TopbarItem2({
|
|
|
16
16
|
...props
|
|
17
17
|
}, ref) {
|
|
18
18
|
const Comp = asChild ? Slot : "button";
|
|
19
|
-
const showBadge =
|
|
19
|
+
const showBadge = badge !== void 0 && badge !== "";
|
|
20
20
|
const iconNode = icon !== void 0 && icon !== null && icon !== false ? /* @__PURE__ */ jsx(
|
|
21
21
|
"span",
|
|
22
22
|
{
|
|
@@ -35,7 +35,6 @@ const TopbarItem = React.forwardRef(function TopbarItem2({
|
|
|
35
35
|
children: label
|
|
36
36
|
}
|
|
37
37
|
);
|
|
38
|
-
const slotted = asChild && (iconNode !== null || labelHideBelow !== void 0) && React.isValidElement(children) ? React.cloneElement(children, void 0, iconNode, labelOf(children.props.children)) : children;
|
|
39
38
|
const badgeNode = showBadge ? /* @__PURE__ */ jsx(
|
|
40
39
|
"span",
|
|
41
40
|
{
|
|
@@ -45,6 +44,13 @@ const TopbarItem = React.forwardRef(function TopbarItem2({
|
|
|
45
44
|
children: badge
|
|
46
45
|
}
|
|
47
46
|
) : null;
|
|
47
|
+
const slotted = asChild && (iconNode !== null || labelHideBelow !== void 0 || badgeNode !== null) && React.isValidElement(children) ? React.cloneElement(
|
|
48
|
+
children,
|
|
49
|
+
void 0,
|
|
50
|
+
iconNode,
|
|
51
|
+
labelOf(children.props.children),
|
|
52
|
+
badgeNode
|
|
53
|
+
) : children;
|
|
48
54
|
return /* @__PURE__ */ jsx(
|
|
49
55
|
Comp,
|
|
50
56
|
{
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type ImageLoadingStatus } from "../../lib/image-loading-status.js";
|
|
3
|
-
import type { AvatarProp } from "../../props/components/data-display.prop.js";
|
|
3
|
+
import type { AvatarImageFitProp, AvatarProp } from "../../props/components/data-display.prop.js";
|
|
4
4
|
export declare const Avatar: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & {
|
|
5
5
|
asChild?: boolean;
|
|
6
6
|
} & Pick<AvatarProp, "appearance" | "presence" | "presenceLabel" | "shape" | "size"> & React.RefAttributes<HTMLSpanElement>>;
|
|
7
7
|
export declare const AvatarImage: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, "ref"> & {
|
|
8
8
|
asChild?: boolean;
|
|
9
9
|
onLoadingStatusChange?: (status: ImageLoadingStatus) => void;
|
|
10
|
+
/** `cover` (default) crops to fill; `contain` shows a logo or app icon whole (gh#1176). */
|
|
11
|
+
fit?: AvatarImageFitProp;
|
|
10
12
|
} & React.RefAttributes<HTMLImageElement>>;
|
|
11
13
|
export declare const AvatarFallback: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & {
|
|
12
14
|
asChild?: boolean;
|
|
@@ -53,7 +53,7 @@ const Avatar = React.forwardRef(
|
|
|
53
53
|
}
|
|
54
54
|
);
|
|
55
55
|
Avatar.displayName = "Avatar";
|
|
56
|
-
const AvatarImage = React.forwardRef(({ className, src, onLoadingStatusChange, asChild = false, ...props }, ref) => {
|
|
56
|
+
const AvatarImage = React.forwardRef(({ className, src, onLoadingStatusChange, asChild = false, fit, ...props }, ref) => {
|
|
57
57
|
const { imageLoadingStatus, setImageLoadingStatus } = useAvatarContext("AvatarImage");
|
|
58
58
|
const status = useImageLoadingStatus(src, {
|
|
59
59
|
referrerPolicy: props.referrerPolicy,
|
|
@@ -78,6 +78,7 @@ const AvatarImage = React.forwardRef(({ className, src, onLoadingStatusChange, a
|
|
|
78
78
|
{
|
|
79
79
|
ref,
|
|
80
80
|
"data-slot": "avatar-image",
|
|
81
|
+
"data-fit": fit === "contain" ? "contain" : void 0,
|
|
81
82
|
className: cn("ui-avatar-image", className),
|
|
82
83
|
...props,
|
|
83
84
|
src
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "AUTO-GENERATED by scripts/gen-measurement-contract.mjs — do not edit. Read this instead of guessing: docs/MEASUREMENT-CONTRACT.md.",
|
|
3
|
-
"version": "31.
|
|
3
|
+
"version": "31.30.0",
|
|
4
4
|
"targetSize": {
|
|
5
5
|
"standard": "WCAG 2.2 SC 2.5.8 Target Size (Minimum), level AA — 24×24 CSS px",
|
|
6
6
|
"min": 24,
|
|
@@ -232,6 +232,30 @@
|
|
|
232
232
|
"symbols": "Symbols",
|
|
233
233
|
"flags": "Flags"
|
|
234
234
|
}
|
|
235
|
+
},
|
|
236
|
+
"sortableList": {
|
|
237
|
+
"handle": "Reorder {label}",
|
|
238
|
+
"hint": "Press Space to pick up, the arrow keys to move, Space to drop, Escape to cancel.",
|
|
239
|
+
"lifted": "Picked up {label}. Position {position} of {count}.",
|
|
240
|
+
"moved": "{label}: position {position} of {count}.",
|
|
241
|
+
"dropped": "Dropped {label} at position {position} of {count}.",
|
|
242
|
+
"cancelled": "Move cancelled. {label} is back at position {position} of {count}."
|
|
243
|
+
},
|
|
244
|
+
"passwordStrength": {
|
|
245
|
+
"weak": "Weak",
|
|
246
|
+
"fair": "Fair",
|
|
247
|
+
"strong": "Strong",
|
|
248
|
+
"meter": "Password strength {score} of 4",
|
|
249
|
+
"passed": "Passed: ",
|
|
250
|
+
"failed": "Not yet: ",
|
|
251
|
+
"announcement": "Password strength: {strength}",
|
|
252
|
+
"rules": {
|
|
253
|
+
"length": "8+ characters",
|
|
254
|
+
"upper": "Contains uppercase letter",
|
|
255
|
+
"lower": "Contains lowercase letter",
|
|
256
|
+
"number": "Contains number",
|
|
257
|
+
"symbol": "Contains symbol"
|
|
258
|
+
}
|
|
235
259
|
}
|
|
236
260
|
},
|
|
237
261
|
"feedback": {
|
|
@@ -741,7 +765,13 @@
|
|
|
741
765
|
"childRows": "Child rows",
|
|
742
766
|
"outsideAfter": "After the visible range",
|
|
743
767
|
"outsideBefore": "Before the visible range",
|
|
744
|
-
"schedule": "Schedule"
|
|
768
|
+
"schedule": "Schedule",
|
|
769
|
+
"noDates": "No dates",
|
|
770
|
+
"resizeLabel": "Resize the label column",
|
|
771
|
+
"overdue": "Overdue",
|
|
772
|
+
"overrun": "Over the plan",
|
|
773
|
+
"early": "Ahead of the plan",
|
|
774
|
+
"lateBy": "+{n}d"
|
|
745
775
|
},
|
|
746
776
|
"chat": {
|
|
747
777
|
"bubble": {
|
|
@@ -228,6 +228,30 @@
|
|
|
228
228
|
"symbols": "記号",
|
|
229
229
|
"flags": "旗"
|
|
230
230
|
}
|
|
231
|
+
},
|
|
232
|
+
"sortableList": {
|
|
233
|
+
"handle": "{label} を並べ替え",
|
|
234
|
+
"hint": "Space で持ち上げ、矢印キーで移動、Space で確定、Esc で取り消します。",
|
|
235
|
+
"lifted": "{label} を持ち上げました。{count} 件中 {position} 番目です。",
|
|
236
|
+
"moved": "{label}: {count} 件中 {position} 番目。",
|
|
237
|
+
"dropped": "{label} を {count} 件中 {position} 番目に置きました。",
|
|
238
|
+
"cancelled": "移動を取り消しました。{label} は {count} 件中 {position} 番目に戻りました。"
|
|
239
|
+
},
|
|
240
|
+
"passwordStrength": {
|
|
241
|
+
"weak": "弱い",
|
|
242
|
+
"fair": "普通",
|
|
243
|
+
"strong": "強い",
|
|
244
|
+
"meter": "パスワードの強度 4 段階中 {score}",
|
|
245
|
+
"passed": "達成: ",
|
|
246
|
+
"failed": "未達成: ",
|
|
247
|
+
"announcement": "パスワードの強度: {strength}",
|
|
248
|
+
"rules": {
|
|
249
|
+
"length": "8 文字以上",
|
|
250
|
+
"upper": "大文字を含む",
|
|
251
|
+
"lower": "小文字を含む",
|
|
252
|
+
"number": "数字を含む",
|
|
253
|
+
"symbol": "記号を含む"
|
|
254
|
+
}
|
|
231
255
|
}
|
|
232
256
|
},
|
|
233
257
|
"feedback": {
|
|
@@ -716,7 +740,13 @@
|
|
|
716
740
|
"childRows": "子の行",
|
|
717
741
|
"outsideAfter": "表示範囲より後",
|
|
718
742
|
"outsideBefore": "表示範囲より前",
|
|
719
|
-
"schedule": "スケジュール"
|
|
743
|
+
"schedule": "スケジュール",
|
|
744
|
+
"noDates": "日付なし",
|
|
745
|
+
"resizeLabel": "ラベル列の幅を変更",
|
|
746
|
+
"overdue": "期限超過",
|
|
747
|
+
"overrun": "予定超過",
|
|
748
|
+
"early": "予定より早く完了",
|
|
749
|
+
"lateBy": "+{n}日"
|
|
720
750
|
},
|
|
721
751
|
"chat": {
|
|
722
752
|
"bubble": {
|