@godxjp/ui 31.29.0 → 31.30.1
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 +4 -4
- package/agent/components/Legend.json +1 -1
- package/agent/components/PasswordStrength.json +8 -2
- package/agent/components/RangeTimeline.json +28 -1
- package/agent/components.json +37 -4
- package/agent/index.json +4 -4
- package/agent/llms.txt +5 -5
- package/agent/tokens.json +48 -0
- 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/password-strength.d.ts +22 -5
- package/dist/components/data-entry/password-strength.js +20 -37
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +23 -1
- package/dist/i18n/messages/ja.json +23 -1
- package/dist/i18n/messages/vi.json +23 -1
- package/dist/props/components/data-display.prop.d.ts +9 -0
- package/dist/styles/data-display-layout.css +135 -2
- package/dist/styles/layers.json +1 -1
- package/dist/tokens/components/data-display.css +12 -0
- package/docs/FRAME-COVERAGE-REPORT.md +1 -1
- package/docs/data-display/timeline.tsx +84 -1
- package/docs/i18n/messages/en.json +11 -0
- package/docs/i18n/messages/ja.json +11 -0
- package/docs/i18n/messages/vi.json +11 -0
- package/package.json +2 -2
|
@@ -353,6 +353,10 @@
|
|
|
353
353
|
border-radius: var(--legend-swatch-radius);
|
|
354
354
|
}
|
|
355
355
|
|
|
356
|
+
.ui-legend-swatch[data-color="true"] {
|
|
357
|
+
background: var(--legend-swatch-color, hsl(var(--muted-foreground)));
|
|
358
|
+
}
|
|
359
|
+
|
|
356
360
|
.ui-legend-swatch[data-tone="default"] {
|
|
357
361
|
background: hsl(
|
|
358
362
|
var(
|
|
@@ -2008,6 +2012,50 @@
|
|
|
2008
2012
|
.ui-range-timeline-header {
|
|
2009
2013
|
background: hsl(var(--muted));
|
|
2010
2014
|
}
|
|
2015
|
+
|
|
2016
|
+
.ui-range-timeline-label-resizer {
|
|
2017
|
+
position: absolute;
|
|
2018
|
+
inset-block: 0;
|
|
2019
|
+
inset-inline-end: calc(var(--range-timeline-resizer-inline-size) / -2);
|
|
2020
|
+
z-index: 2;
|
|
2021
|
+
inline-size: var(--range-timeline-resizer-inline-size);
|
|
2022
|
+
cursor: col-resize;
|
|
2023
|
+
touch-action: none;
|
|
2024
|
+
}
|
|
2025
|
+
.ui-range-timeline-label-resizer::after {
|
|
2026
|
+
content: "";
|
|
2027
|
+
position: absolute;
|
|
2028
|
+
inset-block: 0;
|
|
2029
|
+
inset-inline-start: 50%;
|
|
2030
|
+
inline-size: var(--range-timeline-resizer-active-width);
|
|
2031
|
+
translate: -50% 0;
|
|
2032
|
+
background: transparent;
|
|
2033
|
+
}
|
|
2034
|
+
.ui-range-timeline-label-resizer:hover::after,
|
|
2035
|
+
.ui-range-timeline-label-resizer:focus-visible::after {
|
|
2036
|
+
background: hsl(var(--primary));
|
|
2037
|
+
}
|
|
2038
|
+
.ui-range-timeline-label-resizer:focus-visible {
|
|
2039
|
+
outline: none;
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
.ui-range-timeline[data-busy="true"] .ui-range-timeline-body {
|
|
2043
|
+
opacity: var(--range-timeline-busy-body-alpha);
|
|
2044
|
+
}
|
|
2045
|
+
.ui-range-timeline-busy {
|
|
2046
|
+
position: relative;
|
|
2047
|
+
overflow: hidden;
|
|
2048
|
+
block-size: var(--range-timeline-busy-line-block-size);
|
|
2049
|
+
background: hsl(var(--primary) / 0.2);
|
|
2050
|
+
}
|
|
2051
|
+
.ui-range-timeline-busy::before {
|
|
2052
|
+
content: "";
|
|
2053
|
+
position: absolute;
|
|
2054
|
+
inset-block: 0;
|
|
2055
|
+
inline-size: 30%;
|
|
2056
|
+
background: hsl(var(--primary));
|
|
2057
|
+
animation: ui-range-timeline-busy var(--duration-slow, 1.2s) ease-in-out infinite;
|
|
2058
|
+
}
|
|
2011
2059
|
.ui-range-timeline-label {
|
|
2012
2060
|
position: sticky;
|
|
2013
2061
|
inset-inline-start: 0;
|
|
@@ -2109,10 +2157,77 @@
|
|
|
2109
2157
|
--radius-sm,
|
|
2110
2158
|
calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))
|
|
2111
2159
|
);
|
|
2112
|
-
background: hsl(var(--primary));
|
|
2113
|
-
color: hsl(var(--primary-foreground));
|
|
2160
|
+
background: var(--range-timeline-bar-color, hsl(var(--primary)));
|
|
2161
|
+
color: var(--range-timeline-bar-ink, hsl(var(--primary-foreground)));
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
.ui-range-timeline-plan,
|
|
2165
|
+
.ui-range-timeline-overrun,
|
|
2166
|
+
.ui-range-timeline-early {
|
|
2167
|
+
position: absolute;
|
|
2168
|
+
inset-block-start: 50%;
|
|
2169
|
+
transform: translateY(-50%);
|
|
2170
|
+
block-size: var(--range-timeline-bar-height);
|
|
2171
|
+
}
|
|
2172
|
+
.ui-range-timeline-plan {
|
|
2173
|
+
border: var(--range-timeline-plan-border-width) dashed hsl(var(--foreground) / 0.45);
|
|
2174
|
+
border-radius: var(
|
|
2175
|
+
--radius-sm,
|
|
2176
|
+
calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))
|
|
2177
|
+
);
|
|
2178
|
+
}
|
|
2179
|
+
.ui-range-timeline-overrun {
|
|
2180
|
+
z-index: 1;
|
|
2181
|
+
display: flex;
|
|
2182
|
+
align-items: center;
|
|
2183
|
+
justify-content: flex-end;
|
|
2184
|
+
overflow: visible;
|
|
2185
|
+
background: hsl(var(--destructive));
|
|
2186
|
+
color: hsl(var(--destructive-foreground));
|
|
2187
|
+
pointer-events: none;
|
|
2188
|
+
}
|
|
2189
|
+
.ui-range-timeline-variance {
|
|
2190
|
+
position: absolute;
|
|
2191
|
+
inset-inline-start: 100%;
|
|
2192
|
+
padding-inline: var(--space-1);
|
|
2193
|
+
color: hsl(var(--text-error));
|
|
2194
|
+
font-size: var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)));
|
|
2195
|
+
font-weight: var(--font-weight-medium);
|
|
2196
|
+
white-space: nowrap;
|
|
2197
|
+
}
|
|
2198
|
+
.ui-range-timeline-plan-note {
|
|
2199
|
+
position: absolute;
|
|
2200
|
+
inset-block-start: 50%;
|
|
2201
|
+
transform: translateY(-50%);
|
|
2202
|
+
padding-inline: var(--space-1);
|
|
2203
|
+
color: hsl(var(--muted-foreground));
|
|
2204
|
+
font-size: var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)));
|
|
2205
|
+
white-space: nowrap;
|
|
2206
|
+
pointer-events: none;
|
|
2207
|
+
}
|
|
2208
|
+
.ui-range-timeline-early {
|
|
2209
|
+
z-index: 1;
|
|
2210
|
+
inline-size: var(--range-timeline-early-marker-inline-size);
|
|
2211
|
+
background: hsl(var(--success));
|
|
2212
|
+
pointer-events: none;
|
|
2213
|
+
}
|
|
2214
|
+
.ui-range-timeline-bar[data-muted="true"] {
|
|
2215
|
+
opacity: var(--range-timeline-bar-muted-alpha);
|
|
2216
|
+
}
|
|
2217
|
+
.ui-range-timeline-bar[data-overdue="true"] {
|
|
2218
|
+
box-shadow: inset calc(-1 * var(--range-timeline-bar-overdue-width)) 0 0 hsl(var(--destructive));
|
|
2219
|
+
}
|
|
2220
|
+
[dir="rtl"] .ui-range-timeline-bar[data-overdue="true"] {
|
|
2221
|
+
box-shadow: inset var(--range-timeline-bar-overdue-width) 0 0 hsl(var(--destructive));
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
.ui-range-timeline-bar-hit {
|
|
2225
|
+
position: absolute;
|
|
2226
|
+
inset: 0;
|
|
2227
|
+
border-radius: inherit;
|
|
2114
2228
|
}
|
|
2115
2229
|
.ui-range-timeline-handle {
|
|
2230
|
+
z-index: 1;
|
|
2116
2231
|
position: absolute;
|
|
2117
2232
|
inset-block: 0;
|
|
2118
2233
|
min-inline-size: 0;
|
|
@@ -3372,3 +3487,21 @@
|
|
|
3372
3487
|
display: contents;
|
|
3373
3488
|
}
|
|
3374
3489
|
}
|
|
3490
|
+
|
|
3491
|
+
@keyframes ui-range-timeline-busy {
|
|
3492
|
+
from {
|
|
3493
|
+
inset-inline-start: -30%;
|
|
3494
|
+
}
|
|
3495
|
+
to {
|
|
3496
|
+
inset-inline-start: 100%;
|
|
3497
|
+
}
|
|
3498
|
+
}
|
|
3499
|
+
|
|
3500
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3501
|
+
.ui-range-timeline-busy::before {
|
|
3502
|
+
animation: none;
|
|
3503
|
+
inset-inline-start: 0;
|
|
3504
|
+
inline-size: 100%;
|
|
3505
|
+
opacity: 0.6;
|
|
3506
|
+
}
|
|
3507
|
+
}
|
package/dist/styles/layers.json
CHANGED
|
@@ -250,6 +250,12 @@
|
|
|
250
250
|
:root {
|
|
251
251
|
--range-timeline-label-width: var(--app-shell-sidebar-width);
|
|
252
252
|
|
|
253
|
+
--range-timeline-resizer-inline-size: var(--space-6);
|
|
254
|
+
--range-timeline-resizer-active-width: var(--stroke-md, 2px);
|
|
255
|
+
|
|
256
|
+
--range-timeline-busy-body-alpha: 0.55;
|
|
257
|
+
--range-timeline-busy-line-block-size: var(--stroke-md, 2px);
|
|
258
|
+
|
|
253
259
|
--range-timeline-unit-width: var(--range-timeline-unit-width-default);
|
|
254
260
|
|
|
255
261
|
--range-timeline-unit-width-compact: calc(var(--control-height-sm) * 1.5);
|
|
@@ -258,6 +264,12 @@
|
|
|
258
264
|
--range-timeline-row-height: var(--control-height-lg);
|
|
259
265
|
--range-timeline-bar-height: var(--control-height-sm);
|
|
260
266
|
|
|
267
|
+
--range-timeline-bar-muted-alpha: 0.45;
|
|
268
|
+
--range-timeline-bar-overdue-width: var(--stroke-md);
|
|
269
|
+
|
|
270
|
+
--range-timeline-plan-border-width: var(--stroke-hairline);
|
|
271
|
+
--range-timeline-early-marker-inline-size: var(--stroke-md);
|
|
272
|
+
|
|
261
273
|
--range-timeline-border-color: var(--border);
|
|
262
274
|
|
|
263
275
|
--range-timeline-grid-color: initial;
|
|
@@ -48,7 +48,7 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
|
|
|
48
48
|
| CardBar | **✗** | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
49
49
|
| TimeRangePicker | ✓ | · | · | · | · | · | · | · | · | · |
|
|
50
50
|
| VisuallyHidden | **✗** | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
51
|
-
| RangeTimeline | **✗** | · |
|
|
51
|
+
| RangeTimeline | **✗** | · | · | N/A | · | · | · | · | · | · |
|
|
52
52
|
| PageContainer | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
|
|
53
53
|
| PageCover | ✓ | · | N/A | N/A | · | · | · | · | · | · |
|
|
54
54
|
| Flex | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { useState, type CSSProperties } from "react";
|
|
2
2
|
|
|
3
3
|
import { useTranslation } from "@godxjp/ui/i18n";
|
|
4
4
|
import {
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
RangeTimeline,
|
|
12
12
|
type TimelineItem,
|
|
13
13
|
} from "@godxjp/ui/data-display";
|
|
14
|
+
import { Switch } from "@godxjp/ui/data-entry";
|
|
14
15
|
import { Text } from "@godxjp/ui/general";
|
|
15
16
|
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
16
17
|
import { ArrowRightLeft, MessageSquare } from "lucide-react";
|
|
@@ -90,6 +91,7 @@ const richItems: TimelineItem[] = [
|
|
|
90
91
|
|
|
91
92
|
export default function Demo() {
|
|
92
93
|
const { t, locale } = useTranslation();
|
|
94
|
+
const [gantt, setGantt] = useState({ width: 280, busy: false });
|
|
93
95
|
// An activity log (gh#1092): every row already happened, so none is "done" or "upcoming" —
|
|
94
96
|
// `status: "log"` keeps the neutral dot and adds no screen-reader status prefix.
|
|
95
97
|
const logItems: TimelineItem[] = [
|
|
@@ -270,6 +272,87 @@ export default function Demo() {
|
|
|
270
272
|
/>
|
|
271
273
|
</CardContent>
|
|
272
274
|
</Card>
|
|
275
|
+
<Card>
|
|
276
|
+
<CardHeader>
|
|
277
|
+
<CardTitle level={2}>{t("rangeTimelineDocs.resizeTitle")}</CardTitle>
|
|
278
|
+
<CardDescription>{t("rangeTimelineDocs.resizeDescription")}</CardDescription>
|
|
279
|
+
</CardHeader>
|
|
280
|
+
<CardContent>
|
|
281
|
+
<Flex direction="col" gap="sm">
|
|
282
|
+
<Switch
|
|
283
|
+
checked={gantt.busy}
|
|
284
|
+
onCheckedChange={(busy) => setGantt((state) => ({ ...state, busy }))}
|
|
285
|
+
aria-label={t("rangeTimelineDocs.busyToggle")}
|
|
286
|
+
/>
|
|
287
|
+
<RangeTimeline
|
|
288
|
+
label={t("rangeTimeline.schedule")}
|
|
289
|
+
columns={Array.from({ length: 14 }, (_, index) => ({
|
|
290
|
+
label: new Intl.NumberFormat(locale).format(index + 1),
|
|
291
|
+
units: 1,
|
|
292
|
+
}))}
|
|
293
|
+
rows={[
|
|
294
|
+
{
|
|
295
|
+
id: "r1",
|
|
296
|
+
label: t("rangeTimelineDocs.longTask"),
|
|
297
|
+
start: 1,
|
|
298
|
+
end: 6,
|
|
299
|
+
startLabel: "",
|
|
300
|
+
endLabel: "",
|
|
301
|
+
color: "#2563eb",
|
|
302
|
+
tooltip: t("rangeTimelineDocs.longTask"),
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
id: "r3",
|
|
306
|
+
label: t("rangeTimelineDocs.doneTask"),
|
|
307
|
+
start: 0,
|
|
308
|
+
end: 2,
|
|
309
|
+
startLabel: "",
|
|
310
|
+
endLabel: "",
|
|
311
|
+
color: "#16a34a",
|
|
312
|
+
muted: true,
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
id: "r4",
|
|
316
|
+
label: t("rangeTimelineDocs.lateTask"),
|
|
317
|
+
start: 3,
|
|
318
|
+
end: 8,
|
|
319
|
+
startLabel: "",
|
|
320
|
+
endLabel: "",
|
|
321
|
+
color: "#f59e0b",
|
|
322
|
+
overdue: true,
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
id: "r5",
|
|
326
|
+
label: t("rangeTimelineDocs.plannedTask"),
|
|
327
|
+
start: 2,
|
|
328
|
+
end: 9,
|
|
329
|
+
startLabel: "",
|
|
330
|
+
endLabel: "",
|
|
331
|
+
color: "#7c3aed",
|
|
332
|
+
plan: { start: 2, end: 6 },
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
id: "r2",
|
|
336
|
+
label: t("rangeTimelineDocs.undatedTask"),
|
|
337
|
+
start: null,
|
|
338
|
+
end: null,
|
|
339
|
+
startLabel: "",
|
|
340
|
+
endLabel: "",
|
|
341
|
+
},
|
|
342
|
+
]}
|
|
343
|
+
resizableLabel={{ min: 180, max: 520 }}
|
|
344
|
+
labelWidth={gantt.width}
|
|
345
|
+
onLabelWidthChange={(width) => setGantt((state) => ({ ...state, width }))}
|
|
346
|
+
busy={gantt.busy}
|
|
347
|
+
/>
|
|
348
|
+
<Text size="sm" tone="muted">
|
|
349
|
+
{t("rangeTimelineDocs.width", {
|
|
350
|
+
width: new Intl.NumberFormat(locale).format(gantt.width),
|
|
351
|
+
})}
|
|
352
|
+
</Text>
|
|
353
|
+
</Flex>
|
|
354
|
+
</CardContent>
|
|
355
|
+
</Card>
|
|
273
356
|
|
|
274
357
|
{/* sticky sits OUTSIDE a Card on purpose: Card clips (`overflow: hidden`), and a clipping
|
|
275
358
|
ancestor becomes the box the header sticks to — the same limit as antd Table sticky. */}
|
|
@@ -1689,5 +1689,16 @@
|
|
|
1689
1689
|
},
|
|
1690
1690
|
"sidebarDocs": {
|
|
1691
1691
|
"newEntry": "New journal entry"
|
|
1692
|
+
},
|
|
1693
|
+
"rangeTimelineDocs": {
|
|
1694
|
+
"resizeTitle": "Resizable label column, loading, undated rows",
|
|
1695
|
+
"resizeDescription": "Drag the divider in the header (or focus it and use the arrow keys, Shift for bigger steps, Home/End) to widen the label column. The width is controlled, so an app can remember it per user. The switch marks a range as loading; a row without dates shows a hint instead of a bar.",
|
|
1696
|
+
"busyToggle": "Loading a new range",
|
|
1697
|
+
"longTask": "EXSELI-81 Rebuild the contact form and its confirmation email",
|
|
1698
|
+
"undatedTask": "EXSELI-82 Not scheduled yet",
|
|
1699
|
+
"width": "Label column: {width}px",
|
|
1700
|
+
"doneTask": "EXSELI-79 Release notes (done)",
|
|
1701
|
+
"lateTask": "EXSELI-80 Data migration (overdue)",
|
|
1702
|
+
"plannedTask": "EXSELI-84 Payment API (plan 3–7, actual 3–10)"
|
|
1692
1703
|
}
|
|
1693
1704
|
}
|
|
@@ -1682,5 +1682,16 @@
|
|
|
1682
1682
|
},
|
|
1683
1683
|
"sidebarDocs": {
|
|
1684
1684
|
"newEntry": "仕訳を追加"
|
|
1685
|
+
},
|
|
1686
|
+
"rangeTimelineDocs": {
|
|
1687
|
+
"resizeTitle": "ラベル列の幅変更・読み込み中・日付なしの行",
|
|
1688
|
+
"resizeDescription": "ヘッダーの区切りをドラッグ(またはフォーカスして矢印キー、Shiftで大きく、Home/End)するとラベル列の幅が変わります。幅は制御プロパティなので、アプリ側でユーザーごとに保存できます。スイッチは新しい期間の読み込み中を示し、日付のない行はバーの代わりに案内を表示します。",
|
|
1689
|
+
"busyToggle": "新しい期間を読み込み中",
|
|
1690
|
+
"longTask": "EXSELI-81 問い合わせフォームと確認メールの改修",
|
|
1691
|
+
"undatedTask": "EXSELI-82 まだ日程未定",
|
|
1692
|
+
"width": "ラベル列: {width}px",
|
|
1693
|
+
"doneTask": "EXSELI-79 リリースノート(完了)",
|
|
1694
|
+
"lateTask": "EXSELI-80 データ移行(期限超過)",
|
|
1695
|
+
"plannedTask": "EXSELI-84 決済API(予定 3–7、実績 3–10)"
|
|
1685
1696
|
}
|
|
1686
1697
|
}
|
|
@@ -1682,5 +1682,16 @@
|
|
|
1682
1682
|
},
|
|
1683
1683
|
"sidebarDocs": {
|
|
1684
1684
|
"newEntry": "Thêm bút toán"
|
|
1685
|
+
},
|
|
1686
|
+
"rangeTimelineDocs": {
|
|
1687
|
+
"resizeTitle": "Cột nhãn đổi độ rộng, đang tải, hàng chưa có ngày",
|
|
1688
|
+
"resizeDescription": "Kéo vạch ngăn ở header (hoặc focus rồi dùng phím mũi tên, Shift để bước lớn, Home/End) để mở rộng cột nhãn. Độ rộng là prop controlled nên app có thể lưu theo từng người dùng. Công tắc đánh dấu đang tải khoảng mới; hàng chưa có ngày hiện gợi ý thay cho thanh.",
|
|
1689
|
+
"busyToggle": "Đang tải khoảng mới",
|
|
1690
|
+
"longTask": "EXSELI-81 Làm lại form liên hệ và email xác nhận",
|
|
1691
|
+
"undatedTask": "EXSELI-82 Chưa lên lịch",
|
|
1692
|
+
"width": "Cột nhãn: {width}px",
|
|
1693
|
+
"doneTask": "EXSELI-79 Ghi chú phát hành (xong)",
|
|
1694
|
+
"lateTask": "EXSELI-80 Chuyển dữ liệu (quá hạn)",
|
|
1695
|
+
"plannedTask": "EXSELI-84 API thanh toán (kế hoạch 3–7, thực tế 3–10)"
|
|
1685
1696
|
}
|
|
1686
1697
|
}
|