@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
|
@@ -4,8 +4,18 @@ import * as React from "react";
|
|
|
4
4
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
5
5
|
import { ChevronDown, ChevronLeft, ChevronRight, GripVertical } from "lucide-react";
|
|
6
6
|
import { Button } from "../general/button.js";
|
|
7
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "../feedback/tooltip.js";
|
|
8
|
+
import { CONTRAST_PIVOT, relativeLuminance } from "../../app/tenant-theme.js";
|
|
7
9
|
import { Text } from "../general/typography.js";
|
|
8
10
|
import { cn } from "../../lib/utils.js";
|
|
11
|
+
function inkOn(color) {
|
|
12
|
+
if (!color) return void 0;
|
|
13
|
+
const luminance = relativeLuminance(color);
|
|
14
|
+
if (luminance == null) return void 0;
|
|
15
|
+
return luminance > CONTRAST_PIVOT ? "black" : "white";
|
|
16
|
+
}
|
|
17
|
+
const LABEL_WIDTH_STEP = 8;
|
|
18
|
+
const LABEL_WIDTH_BIG_STEP = 32;
|
|
9
19
|
const RangeTimeline = React.forwardRef(
|
|
10
20
|
function RangeTimeline2({
|
|
11
21
|
label,
|
|
@@ -20,10 +30,30 @@ const RangeTimeline = React.forwardRef(
|
|
|
20
30
|
defaultExpandedValues,
|
|
21
31
|
onExpandedValuesChange,
|
|
22
32
|
sticky = false,
|
|
33
|
+
resizableLabel = false,
|
|
34
|
+
labelWidth,
|
|
35
|
+
defaultLabelWidth,
|
|
36
|
+
onLabelWidthChange,
|
|
37
|
+
busy = false,
|
|
23
38
|
className,
|
|
24
39
|
...props
|
|
25
40
|
}, ref) {
|
|
26
41
|
const { t } = useTranslation();
|
|
42
|
+
const resize = resizableLabel ? {
|
|
43
|
+
min: typeof resizableLabel === "object" && resizableLabel.min || 160,
|
|
44
|
+
max: typeof resizableLabel === "object" && resizableLabel.max || 640
|
|
45
|
+
} : null;
|
|
46
|
+
const [ownLabelWidth, setOwnLabelWidth] = React.useState(defaultLabelWidth);
|
|
47
|
+
const currentLabelWidth = labelWidth ?? ownLabelWidth;
|
|
48
|
+
const labelCell = React.useRef(null);
|
|
49
|
+
const labelDrag = React.useRef(null);
|
|
50
|
+
const setLabelWidth = (next) => {
|
|
51
|
+
if (!resize) return;
|
|
52
|
+
const bounded = Math.round(Math.min(resize.max, Math.max(resize.min, next)));
|
|
53
|
+
if (labelWidth === void 0) setOwnLabelWidth(bounded);
|
|
54
|
+
onLabelWidthChange?.(bounded);
|
|
55
|
+
};
|
|
56
|
+
const measuredLabelWidth = () => currentLabelWidth ?? Math.round(labelCell.current?.getBoundingClientRect().width ?? 0);
|
|
27
57
|
const reactId = React.useId();
|
|
28
58
|
const depthOf = (row) => Math.max(0, Math.floor(row.depth ?? 0));
|
|
29
59
|
const nested = rows.some((row) => depthOf(row) > 0);
|
|
@@ -85,7 +115,7 @@ const RangeTimeline = React.forwardRef(
|
|
|
85
115
|
const row = rows.find((row2) => row2.id === current.id);
|
|
86
116
|
const delta = deltaAt(event.clientX);
|
|
87
117
|
cancel();
|
|
88
|
-
if (!row) return;
|
|
118
|
+
if (!row || row.start === null || row.end === null) return;
|
|
89
119
|
const bounded = current.edge === "start" ? Math.min(delta, row.end - row.start) : Math.max(delta, row.start - row.end);
|
|
90
120
|
if (bounded) onRangeChange?.(row.id, current.edge, bounded);
|
|
91
121
|
};
|
|
@@ -107,7 +137,53 @@ const RangeTimeline = React.forwardRef(
|
|
|
107
137
|
)) })
|
|
108
138
|
] }),
|
|
109
139
|
/* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-header", children: [
|
|
110
|
-
/* @__PURE__ */
|
|
140
|
+
/* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-label", ref: labelCell, children: [
|
|
141
|
+
/* @__PURE__ */ jsx(Text, { weight: "bold", children: label }),
|
|
142
|
+
resize && /* @__PURE__ */ jsx(
|
|
143
|
+
"div",
|
|
144
|
+
{
|
|
145
|
+
role: "separator",
|
|
146
|
+
tabIndex: 0,
|
|
147
|
+
className: "ui-range-timeline-label-resizer",
|
|
148
|
+
"aria-orientation": "vertical",
|
|
149
|
+
"aria-label": t("rangeTimeline.resizeLabel"),
|
|
150
|
+
"aria-valuemin": resize.min,
|
|
151
|
+
"aria-valuemax": resize.max,
|
|
152
|
+
"aria-valuenow": currentLabelWidth ?? void 0,
|
|
153
|
+
onPointerDown: (event) => {
|
|
154
|
+
if (event.button !== 0) return;
|
|
155
|
+
event.preventDefault();
|
|
156
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
157
|
+
labelDrag.current = {
|
|
158
|
+
x: event.clientX,
|
|
159
|
+
width: measuredLabelWidth(),
|
|
160
|
+
direction: getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1
|
|
161
|
+
};
|
|
162
|
+
},
|
|
163
|
+
onPointerMove: (event) => {
|
|
164
|
+
const current = labelDrag.current;
|
|
165
|
+
if (current)
|
|
166
|
+
setLabelWidth(current.width + (event.clientX - current.x) * current.direction);
|
|
167
|
+
},
|
|
168
|
+
onPointerUp: () => labelDrag.current = null,
|
|
169
|
+
onPointerCancel: () => labelDrag.current = null,
|
|
170
|
+
onLostPointerCapture: () => labelDrag.current = null,
|
|
171
|
+
onKeyDown: (event) => {
|
|
172
|
+
const step = event.shiftKey ? LABEL_WIDTH_BIG_STEP : LABEL_WIDTH_STEP;
|
|
173
|
+
const direction = getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1;
|
|
174
|
+
let next = null;
|
|
175
|
+
if (event.key === "ArrowRight") next = measuredLabelWidth() + step * direction;
|
|
176
|
+
else if (event.key === "ArrowLeft")
|
|
177
|
+
next = measuredLabelWidth() - step * direction;
|
|
178
|
+
else if (event.key === "Home") next = resize.min;
|
|
179
|
+
else if (event.key === "End") next = resize.max;
|
|
180
|
+
if (next === null) return;
|
|
181
|
+
event.preventDefault();
|
|
182
|
+
setLabelWidth(next);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
] }),
|
|
111
187
|
/* @__PURE__ */ jsx("div", { className: "ui-range-timeline-columns", ref: track, children: columns.map((column, index) => /* @__PURE__ */ jsx(
|
|
112
188
|
"div",
|
|
113
189
|
{
|
|
@@ -117,7 +193,8 @@ const RangeTimeline = React.forwardRef(
|
|
|
117
193
|
},
|
|
118
194
|
index
|
|
119
195
|
)) })
|
|
120
|
-
] })
|
|
196
|
+
] }),
|
|
197
|
+
busy && /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-busy", "aria-hidden": "true" })
|
|
121
198
|
] });
|
|
122
199
|
const body = /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-body", role: nested ? "list" : void 0, children: [
|
|
123
200
|
(bordered || columns.some((column) => column.muted)) && // Decorative: the same unit tracks as the header columns, laid once behind every row so
|
|
@@ -136,10 +213,17 @@ const RangeTimeline = React.forwardRef(
|
|
|
136
213
|
] }),
|
|
137
214
|
visibleRows.map((row, index) => {
|
|
138
215
|
const idBase = `${reactId}-row-${rows.indexOf(row)}`;
|
|
216
|
+
const dated = row.start !== null && row.end !== null;
|
|
217
|
+
const rowStart = row.start ?? 0, rowEnd = row.end ?? 0;
|
|
139
218
|
const delta = preview?.id === row.id ? preview.delta : 0;
|
|
140
|
-
const start = Math.min(
|
|
141
|
-
const end = Math.max(
|
|
219
|
+
const start = Math.min(rowEnd, rowStart + (preview?.edge === "start" ? delta : 0));
|
|
220
|
+
const end = Math.max(rowStart, rowEnd + (preview?.edge === "end" ? delta : 0));
|
|
142
221
|
const left = Math.max(0, start), right = Math.min(units, end + 1);
|
|
222
|
+
const plan = dated && row.plan && row.plan.start !== null && row.plan.end !== null ? row.plan : null;
|
|
223
|
+
const planLeft = plan ? Math.max(0, plan.start) : 0, planRight = plan ? Math.min(units, plan.end + 1) : 0;
|
|
224
|
+
const overrun = plan !== null && end > plan.end;
|
|
225
|
+
const early = plan !== null && end < plan.end;
|
|
226
|
+
const overrunLeft = overrun ? Math.max(left, Math.min(units, plan.end + 1)) : 0;
|
|
143
227
|
return /* @__PURE__ */ jsxs(
|
|
144
228
|
"div",
|
|
145
229
|
{
|
|
@@ -182,7 +266,14 @@ const RangeTimeline = React.forwardRef(
|
|
|
182
266
|
/* @__PURE__ */ jsx("div", { id: `${idBase}-label`, className: "ui-range-timeline-label-content", children: row.label })
|
|
183
267
|
]
|
|
184
268
|
}
|
|
185
|
-
) : /* @__PURE__ */ jsx(
|
|
269
|
+
) : /* @__PURE__ */ jsx(
|
|
270
|
+
"div",
|
|
271
|
+
{
|
|
272
|
+
className: "ui-range-timeline-label",
|
|
273
|
+
id: row.tooltip != null ? `${idBase}-label` : void 0,
|
|
274
|
+
children: row.label
|
|
275
|
+
}
|
|
276
|
+
),
|
|
186
277
|
/* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-track", children: [
|
|
187
278
|
today != null && today >= 0 && today < units && /* @__PURE__ */ jsx(
|
|
188
279
|
"span",
|
|
@@ -192,71 +283,135 @@ const RangeTimeline = React.forwardRef(
|
|
|
192
283
|
style: { insetInlineStart: `${(today + 0.5) / units * 100}%` }
|
|
193
284
|
}
|
|
194
285
|
),
|
|
195
|
-
|
|
286
|
+
!dated && /* @__PURE__ */ jsx("span", { className: "ui-range-timeline-outside", "data-direction": "none", children: /* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", children: t("rangeTimeline.noDates") }) }),
|
|
287
|
+
dated && right <= left && (end < 0 ? /* @__PURE__ */ jsxs("span", { className: "ui-range-timeline-outside", "data-direction": "before", children: [
|
|
196
288
|
/* @__PURE__ */ jsx(ChevronLeft, { "aria-hidden": "true", className: "ui-range-timeline-outside-icon" }),
|
|
197
289
|
/* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", children: t("rangeTimeline.outsideBefore") })
|
|
198
290
|
] }) : /* @__PURE__ */ jsxs("span", { className: "ui-range-timeline-outside", "data-direction": "after", children: [
|
|
199
291
|
/* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", children: t("rangeTimeline.outsideAfter") }),
|
|
200
292
|
/* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true", className: "ui-range-timeline-outside-icon" })
|
|
201
293
|
] })),
|
|
202
|
-
|
|
294
|
+
plan && planRight > planLeft && /* @__PURE__ */ jsx(
|
|
295
|
+
"span",
|
|
296
|
+
{
|
|
297
|
+
"aria-hidden": "true",
|
|
298
|
+
className: "ui-range-timeline-plan",
|
|
299
|
+
style: {
|
|
300
|
+
insetInlineStart: `${planLeft / units * 100}%`,
|
|
301
|
+
inlineSize: `${(planRight - planLeft) / units * 100}%`
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
),
|
|
305
|
+
overrun && right > overrunLeft && /* @__PURE__ */ jsxs(
|
|
306
|
+
"span",
|
|
307
|
+
{
|
|
308
|
+
className: "ui-range-timeline-overrun",
|
|
309
|
+
style: {
|
|
310
|
+
insetInlineStart: `${overrunLeft / units * 100}%`,
|
|
311
|
+
inlineSize: `${(right - overrunLeft) / units * 100}%`
|
|
312
|
+
},
|
|
313
|
+
children: [
|
|
314
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: t("rangeTimeline.overrun") }),
|
|
315
|
+
row.varianceLabel !== false && /* @__PURE__ */ jsx("span", { className: "ui-range-timeline-variance", children: row.varianceLabel ?? t("rangeTimeline.lateBy", { n: String(end - plan.end) }) })
|
|
316
|
+
]
|
|
317
|
+
}
|
|
318
|
+
),
|
|
319
|
+
dated && !plan && row.planNote != null && right > left && /* @__PURE__ */ jsx(
|
|
320
|
+
"span",
|
|
321
|
+
{
|
|
322
|
+
className: "ui-range-timeline-plan-note",
|
|
323
|
+
style: { insetInlineStart: `${right / units * 100}%` },
|
|
324
|
+
children: row.planNote
|
|
325
|
+
}
|
|
326
|
+
),
|
|
327
|
+
early && right > left && right <= units && /* @__PURE__ */ jsx(
|
|
328
|
+
"span",
|
|
329
|
+
{
|
|
330
|
+
className: "ui-range-timeline-early",
|
|
331
|
+
style: { insetInlineStart: `${right / units * 100}%` },
|
|
332
|
+
children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: t("rangeTimeline.early") })
|
|
333
|
+
}
|
|
334
|
+
),
|
|
335
|
+
dated && right > left && /* @__PURE__ */ jsxs(
|
|
203
336
|
"div",
|
|
204
337
|
{
|
|
205
338
|
className: "ui-range-timeline-bar",
|
|
339
|
+
"data-muted": row.muted ? "true" : void 0,
|
|
340
|
+
"data-overdue": row.overdue ? "true" : void 0,
|
|
206
341
|
style: {
|
|
207
342
|
insetInlineStart: `${left / units * 100}%`,
|
|
208
|
-
inlineSize: `${(right - left) / units * 100}
|
|
343
|
+
inlineSize: `${(right - left) / units * 100}%`,
|
|
344
|
+
...row.color && {
|
|
345
|
+
"--range-timeline-bar-color": row.color,
|
|
346
|
+
"--range-timeline-bar-ink": inkOn(row.color)
|
|
347
|
+
}
|
|
209
348
|
},
|
|
210
|
-
children:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
"data-edge": edge,
|
|
219
|
-
"aria-label": edge === "start" ? row.startLabel : row.endLabel,
|
|
220
|
-
onPointerDown: (event) => {
|
|
221
|
-
const width = track.current?.getBoundingClientRect().width ?? 0;
|
|
222
|
-
if (!width || event.button !== 0) return;
|
|
223
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
224
|
-
drag.current = {
|
|
225
|
-
id: row.id,
|
|
226
|
-
edge,
|
|
227
|
-
x: event.clientX,
|
|
228
|
-
width,
|
|
229
|
-
direction: getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1
|
|
230
|
-
};
|
|
231
|
-
},
|
|
232
|
-
onPointerMove: (event) => {
|
|
233
|
-
if (drag.current)
|
|
234
|
-
setPreview({
|
|
235
|
-
id: drag.current.id,
|
|
236
|
-
edge: drag.current.edge,
|
|
237
|
-
delta: deltaAt(event.clientX)
|
|
238
|
-
});
|
|
239
|
-
},
|
|
240
|
-
onPointerUp: complete,
|
|
241
|
-
onPointerCancel: cancel,
|
|
242
|
-
onLostPointerCapture: cancel,
|
|
243
|
-
onKeyDown: (event) => {
|
|
244
|
-
if (event.key === "Escape") {
|
|
245
|
-
cancel();
|
|
246
|
-
return;
|
|
349
|
+
children: [
|
|
350
|
+
row.tooltip != null && /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
351
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
352
|
+
"span",
|
|
353
|
+
{
|
|
354
|
+
className: "ui-range-timeline-bar-hit ui-focus-ring",
|
|
355
|
+
tabIndex: 0,
|
|
356
|
+
"aria-labelledby": `${idBase}-label`
|
|
247
357
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
358
|
+
) }),
|
|
359
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: row.tooltip })
|
|
360
|
+
] }),
|
|
361
|
+
row.overdue && /* @__PURE__ */ jsx("span", { className: "sr-only", children: t("rangeTimeline.overdue") }),
|
|
362
|
+
onRangeChange && (right - left) * Math.max(1, columns.length) >= units && ["start", "end"].filter(
|
|
363
|
+
(edge) => edge === "start" ? start >= 0 && start < units : end >= 0 && end < units
|
|
364
|
+
).filter(
|
|
365
|
+
(edge) => row.editable === void 0 || row.editable === true ? true : row.editable === false ? false : row.editable[edge] !== false
|
|
366
|
+
).map((edge) => /* @__PURE__ */ jsx(
|
|
367
|
+
Button,
|
|
368
|
+
{
|
|
369
|
+
variant: "ghost",
|
|
370
|
+
size: "icon-xs",
|
|
371
|
+
className: "ui-range-timeline-handle",
|
|
372
|
+
"data-edge": edge,
|
|
373
|
+
"aria-label": edge === "start" ? row.startLabel : row.endLabel,
|
|
374
|
+
onPointerDown: (event) => {
|
|
375
|
+
const width = track.current?.getBoundingClientRect().width ?? 0;
|
|
376
|
+
if (!width || event.button !== 0) return;
|
|
377
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
378
|
+
drag.current = {
|
|
379
|
+
id: row.id,
|
|
380
|
+
edge,
|
|
381
|
+
x: event.clientX,
|
|
382
|
+
width,
|
|
383
|
+
direction: getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1
|
|
384
|
+
};
|
|
385
|
+
},
|
|
386
|
+
onPointerMove: (event) => {
|
|
387
|
+
if (drag.current)
|
|
388
|
+
setPreview({
|
|
389
|
+
id: drag.current.id,
|
|
390
|
+
edge: drag.current.edge,
|
|
391
|
+
delta: deltaAt(event.clientX)
|
|
392
|
+
});
|
|
393
|
+
},
|
|
394
|
+
onPointerUp: complete,
|
|
395
|
+
onPointerCancel: cancel,
|
|
396
|
+
onLostPointerCapture: cancel,
|
|
397
|
+
onKeyDown: (event) => {
|
|
398
|
+
if (event.key === "Escape") {
|
|
399
|
+
cancel();
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
const step = event.key === "ArrowRight" ? 1 : event.key === "ArrowLeft" ? -1 : 0;
|
|
403
|
+
if (!step) return;
|
|
404
|
+
event.preventDefault();
|
|
405
|
+
const direction = getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1;
|
|
406
|
+
const delta2 = step * direction;
|
|
407
|
+
if (edge === "start" ? rowStart + delta2 <= rowEnd : rowEnd + delta2 >= rowStart)
|
|
408
|
+
onRangeChange(row.id, edge, delta2);
|
|
409
|
+
},
|
|
410
|
+
children: /* @__PURE__ */ jsx(GripVertical, { "aria-hidden": "true" })
|
|
255
411
|
},
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
))
|
|
412
|
+
edge
|
|
413
|
+
))
|
|
414
|
+
]
|
|
260
415
|
}
|
|
261
416
|
)
|
|
262
417
|
] })
|
|
@@ -274,7 +429,14 @@ const RangeTimeline = React.forwardRef(
|
|
|
274
429
|
// Only a NON-default step scopes the unit-width knob, so a theme that narrows
|
|
275
430
|
// --range-timeline-unit-width globally still owns the default timeline (gh#730).
|
|
276
431
|
"data-density": density === "default" ? void 0 : density,
|
|
277
|
-
"
|
|
432
|
+
"data-busy": busy ? "true" : void 0,
|
|
433
|
+
"aria-busy": busy || void 0,
|
|
434
|
+
"aria-label": label,
|
|
435
|
+
// Only once a width exists does it override the token, so a theme's width stays the default.
|
|
436
|
+
style: currentLabelWidth !== void 0 ? {
|
|
437
|
+
...props.style,
|
|
438
|
+
"--range-timeline-label-width": `${currentLabelWidth}px`
|
|
439
|
+
} : props.style
|
|
278
440
|
};
|
|
279
441
|
if (!sticky) {
|
|
280
442
|
return /* @__PURE__ */ jsx("section", { ...sectionProps, tabIndex: 0, children: /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-canvas", style: canvasStyle, children: [
|
|
@@ -55,6 +55,8 @@ export { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, Command
|
|
|
55
55
|
export type { CommandProps } from "./command.js";
|
|
56
56
|
export { CommandPalette } from "./command-palette.js";
|
|
57
57
|
export { EmojiPicker } from "./emoji-picker.js";
|
|
58
|
+
export { SortableList } from "./sortable-list.js";
|
|
59
|
+
export type { SortableListItemProp, SortableListProp, SortableListProps } from "./sortable-list.js";
|
|
58
60
|
export type { EmojiPickerProp, EmojiPickerProps } from "./emoji-picker.js";
|
|
59
61
|
export type { CommandPaletteGroup, CommandPaletteItem, CommandPaletteLabels, CommandPaletteProps, CommandPaletteSelectModifiers, } from "./command-palette.js";
|
|
60
62
|
export { PasswordInput } from "./password-input.js";
|
|
@@ -54,6 +54,7 @@ import {
|
|
|
54
54
|
} from "./command.js";
|
|
55
55
|
import { CommandPalette } from "./command-palette.js";
|
|
56
56
|
import { EmojiPicker } from "./emoji-picker.js";
|
|
57
|
+
import { SortableList } from "./sortable-list.js";
|
|
57
58
|
import { PasswordInput } from "./password-input.js";
|
|
58
59
|
import { PasswordStrength, usePasswordStrength } from "./password-strength.js";
|
|
59
60
|
import { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from "./input-otp.js";
|
|
@@ -120,6 +121,7 @@ export {
|
|
|
120
121
|
SelectTrigger,
|
|
121
122
|
SelectValue,
|
|
122
123
|
Slider,
|
|
124
|
+
SortableList,
|
|
123
125
|
Switch,
|
|
124
126
|
TagInput,
|
|
125
127
|
Textarea,
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
declare const DEFAULT_PASSWORD_RULES: readonly ["length", "upper", "lower", "number", "symbol"];
|
|
2
2
|
export type PasswordRule = (typeof DEFAULT_PASSWORD_RULES)[number];
|
|
3
|
+
/**
|
|
4
|
+
* Every visible and screen-reader string, each optional (gh#1191). Unset entries come from the
|
|
5
|
+
* kit's own ja / en / vi catalogue for the active locale, so most apps pass nothing.
|
|
6
|
+
*/
|
|
3
7
|
export type PasswordStrengthLabels = {
|
|
4
|
-
weak
|
|
5
|
-
fair
|
|
6
|
-
strong
|
|
8
|
+
weak?: string;
|
|
9
|
+
fair?: string;
|
|
10
|
+
strong?: string;
|
|
11
|
+
/** Checklist line per rule. */
|
|
12
|
+
rules?: Partial<Record<PasswordRule, string>>;
|
|
13
|
+
/** Screen-reader prefix before a met rule (e.g. "Passed: "). */
|
|
14
|
+
passed?: string;
|
|
15
|
+
/** Screen-reader prefix before an unmet rule (e.g. "Not yet: "). */
|
|
16
|
+
failed?: string;
|
|
17
|
+
/** The polite live-region sentence, given the strength word. */
|
|
18
|
+
announcement?: (strength: string) => string;
|
|
7
19
|
};
|
|
8
20
|
export type PasswordStrengthProps = {
|
|
9
21
|
value: string;
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Check, X } from "lucide-react";
|
|
4
|
+
import { useTranslation } from "../../i18n/use-translation.js";
|
|
4
5
|
const DEFAULT_PASSWORD_RULES = ["length", "upper", "lower", "number", "symbol"];
|
|
5
|
-
const DEFAULT_LABELS = {
|
|
6
|
-
weak: "Weak",
|
|
7
|
-
fair: "Fair",
|
|
8
|
-
strong: "Strong"
|
|
9
|
-
};
|
|
10
6
|
function usePasswordStrength(value, rules = [...DEFAULT_PASSWORD_RULES]) {
|
|
11
7
|
const uniqueRules = [...new Set(rules)];
|
|
12
8
|
const checks = {
|
|
@@ -25,28 +21,33 @@ function scoreTone(score) {
|
|
|
25
21
|
if (score <= 3) return "warning";
|
|
26
22
|
return "success";
|
|
27
23
|
}
|
|
28
|
-
function
|
|
29
|
-
if (score <= 1) return
|
|
30
|
-
if (score <= 3) return
|
|
31
|
-
return
|
|
24
|
+
function scoreKey(score) {
|
|
25
|
+
if (score <= 1) return "weak";
|
|
26
|
+
if (score <= 3) return "fair";
|
|
27
|
+
return "strong";
|
|
32
28
|
}
|
|
33
29
|
function PasswordStrength({
|
|
34
30
|
value,
|
|
35
31
|
rules = [...DEFAULT_PASSWORD_RULES],
|
|
36
32
|
showChecklist = true,
|
|
37
|
-
labels =
|
|
33
|
+
labels = {}
|
|
38
34
|
}) {
|
|
35
|
+
const { t } = useTranslation();
|
|
39
36
|
const normalizedRules = [...new Set(rules)];
|
|
40
37
|
const { score, checks } = usePasswordStrength(value, normalizedRules);
|
|
41
38
|
const tone = scoreTone(score);
|
|
42
39
|
const segments = Array.from({ length: 5 });
|
|
40
|
+
const key = scoreKey(score);
|
|
41
|
+
const strength = labels[key] ?? t(`dataEntry.passwordStrength.${key}`);
|
|
42
|
+
const ruleLabel = (rule) => labels.rules?.[rule] ?? t(`dataEntry.passwordStrength.rules.${rule}`);
|
|
43
|
+
const announcement = labels.announcement ? labels.announcement(strength) : t("dataEntry.passwordStrength.announcement", { strength });
|
|
43
44
|
return /* @__PURE__ */ jsxs("div", { className: "ui-password-strength", children: [
|
|
44
45
|
/* @__PURE__ */ jsx(
|
|
45
46
|
"div",
|
|
46
47
|
{
|
|
47
48
|
className: "ui-password-strength-track",
|
|
48
49
|
role: "img",
|
|
49
|
-
"aria-label":
|
|
50
|
+
"aria-label": t("dataEntry.passwordStrength.meter", { score: String(score) }),
|
|
50
51
|
children: segments.map((_, index) => {
|
|
51
52
|
const filled = index < score + 1;
|
|
52
53
|
return /* @__PURE__ */ jsx(
|
|
@@ -63,7 +64,7 @@ function PasswordStrength({
|
|
|
63
64
|
}
|
|
64
65
|
),
|
|
65
66
|
/* @__PURE__ */ jsxs("div", { className: "ui-password-strength-meta", children: [
|
|
66
|
-
/* @__PURE__ */ jsx("span", { className: "ui-password-strength-label", children:
|
|
67
|
+
/* @__PURE__ */ jsx("span", { className: "ui-password-strength-label", children: strength }),
|
|
67
68
|
/* @__PURE__ */ jsxs("span", { className: "ui-password-strength-score", "aria-hidden": "true", children: [
|
|
68
69
|
score,
|
|
69
70
|
"/4"
|
|
@@ -76,34 +77,15 @@ function PasswordStrength({
|
|
|
76
77
|
"data-state": checks[rule] ? "passed" : "failed",
|
|
77
78
|
children: [
|
|
78
79
|
checks[rule] ? /* @__PURE__ */ jsx(Check, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(X, { "aria-hidden": "true" }),
|
|
79
|
-
/* @__PURE__ */ jsx("span", { className: "sr-only", children: checks[rule] ?
|
|
80
|
-
/* @__PURE__ */ jsx("span", { children:
|
|
80
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: checks[rule] ? labels.passed ?? t("dataEntry.passwordStrength.passed") : labels.failed ?? t("dataEntry.passwordStrength.failed") }),
|
|
81
|
+
/* @__PURE__ */ jsx("span", { children: ruleLabel(rule) })
|
|
81
82
|
]
|
|
82
83
|
},
|
|
83
84
|
rule
|
|
84
85
|
)) }) : null,
|
|
85
|
-
/* @__PURE__ */
|
|
86
|
-
scoreLabel(score, labels),
|
|
87
|
-
" password strength"
|
|
88
|
-
] })
|
|
86
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", "aria-live": "polite", children: announcement })
|
|
89
87
|
] });
|
|
90
88
|
}
|
|
91
|
-
function labelForRule(rule) {
|
|
92
|
-
switch (rule) {
|
|
93
|
-
case "length":
|
|
94
|
-
return "8+ characters";
|
|
95
|
-
case "upper":
|
|
96
|
-
return "Contains uppercase letter";
|
|
97
|
-
case "lower":
|
|
98
|
-
return "Contains lowercase letter";
|
|
99
|
-
case "number":
|
|
100
|
-
return "Contains number";
|
|
101
|
-
case "symbol":
|
|
102
|
-
return "Contains symbol";
|
|
103
|
-
default:
|
|
104
|
-
return rule;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
89
|
export {
|
|
108
90
|
PasswordStrength,
|
|
109
91
|
usePasswordStrength
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { SortableListProp } from "../../props/components/data-entry.prop.js";
|
|
3
|
+
export type { SortableListItemProp, SortableListProp, SortableListProp as SortableListProps, } from "../../props/components/data-entry.prop.js";
|
|
4
|
+
/**
|
|
5
|
+
* SortableList (gh#1173) — reorder a flat list or a grid of tiles by pointer drag or by keyboard
|
|
6
|
+
* on each item's grip: Space/Enter lifts, the arrows (and Home/End) move, Space/Enter drops, Esc
|
|
7
|
+
* cancels and blur cancels. Every step is spoken through a polite live region ("2 / 3"). The order
|
|
8
|
+
* is the value: `onValueChange` receives the item keys in their new order once, on drop.
|
|
9
|
+
*/
|
|
10
|
+
export declare const SortableList: React.ForwardRefExoticComponent<SortableListProp & React.RefAttributes<HTMLDivElement>>;
|