@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
package/dist/styles/layout.css
CHANGED
|
@@ -138,7 +138,10 @@
|
|
|
138
138
|
min-inline-size: 0;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
.ui-space-compact[data-orientation="horizontal"][data-full-width="true"]
|
|
141
|
+
.ui-space-compact[data-orientation="horizontal"][data-full-width="true"]
|
|
142
|
+
> [data-slot="space-compact-item"]:not(
|
|
143
|
+
:has(.ui-control, .ui-control-multiline, .ui-tag-input)
|
|
144
|
+
) {
|
|
142
145
|
flex: none;
|
|
143
146
|
}
|
|
144
147
|
|
|
@@ -146,16 +149,21 @@
|
|
|
146
149
|
flex-direction: column;
|
|
147
150
|
}
|
|
148
151
|
|
|
149
|
-
.ui-space-compact[data-orientation="vertical"][data-full-width="true"]
|
|
152
|
+
.ui-space-compact[data-orientation="vertical"][data-full-width="true"]
|
|
153
|
+
> [data-slot="space-compact-item"] {
|
|
150
154
|
min-inline-size: auto;
|
|
151
155
|
min-block-size: 0;
|
|
152
156
|
}
|
|
153
157
|
|
|
154
|
-
.ui-space-compact[data-orientation="horizontal"]
|
|
158
|
+
.ui-space-compact[data-orientation="horizontal"]
|
|
159
|
+
> [data-slot="space-compact-item"]
|
|
160
|
+
+ [data-slot="space-compact-item"] {
|
|
155
161
|
margin-inline-start: calc(var(--control-border-width, var(--stroke-hairline)) * -1);
|
|
156
162
|
}
|
|
157
163
|
|
|
158
|
-
.ui-space-compact[data-orientation="vertical"]
|
|
164
|
+
.ui-space-compact[data-orientation="vertical"]
|
|
165
|
+
> [data-slot="space-compact-item"]
|
|
166
|
+
+ [data-slot="space-compact-item"] {
|
|
159
167
|
margin-block-start: calc(var(--control-border-width, var(--stroke-hairline)) * -1);
|
|
160
168
|
}
|
|
161
169
|
|
|
@@ -175,12 +183,14 @@
|
|
|
175
183
|
z-index: 1;
|
|
176
184
|
}
|
|
177
185
|
|
|
178
|
-
.ui-space-compact[data-orientation="horizontal"]
|
|
186
|
+
.ui-space-compact[data-orientation="horizontal"]
|
|
187
|
+
> [data-slot="space-compact-item"]:not(:first-child) {
|
|
179
188
|
--input-radius-start: 0;
|
|
180
189
|
--control-trigger-radius-start: 0;
|
|
181
190
|
}
|
|
182
191
|
|
|
183
|
-
.ui-space-compact[data-orientation="horizontal"]
|
|
192
|
+
.ui-space-compact[data-orientation="horizontal"]
|
|
193
|
+
> [data-slot="space-compact-item"]:not(:last-child) {
|
|
184
194
|
--input-radius-end: 0;
|
|
185
195
|
--control-trigger-radius-end: 0;
|
|
186
196
|
}
|
|
@@ -410,6 +420,10 @@
|
|
|
410
420
|
align-items: start;
|
|
411
421
|
}
|
|
412
422
|
|
|
423
|
+
.ui-responsive-grid[data-dense] {
|
|
424
|
+
grid-auto-flow: row dense;
|
|
425
|
+
}
|
|
426
|
+
|
|
413
427
|
.ui-responsive-grid[data-align="start"] {
|
|
414
428
|
align-items: start;
|
|
415
429
|
}
|
|
@@ -926,7 +940,10 @@
|
|
|
926
940
|
|
|
927
941
|
.ui-page-container[data-header-scale="display"] .ui-page-title,
|
|
928
942
|
.ui-page-container[data-header-scale="display"] .ui-page-header .ui-page-title {
|
|
929
|
-
font-size: var(
|
|
943
|
+
font-size: var(
|
|
944
|
+
--page-title-font-size-display,
|
|
945
|
+
var(--font-size-4xl, calc(var(--font-size-display) / var(--font-size-display-ratio)))
|
|
946
|
+
);
|
|
930
947
|
font-weight: var(--font-weight-semibold);
|
|
931
948
|
line-height: var(--page-title-line-height-display);
|
|
932
949
|
text-wrap: balance;
|
|
@@ -1966,22 +1983,27 @@
|
|
|
1966
1983
|
.ui-master-detail[data-rail-width="wide"] {
|
|
1967
1984
|
--master-detail-rail-size: var(--master-detail-rail-wide);
|
|
1968
1985
|
}
|
|
1986
|
+
|
|
1969
1987
|
.ui-responsive-grid-item {
|
|
1970
1988
|
grid-column: span min(var(--responsive-grid-base, 1), var(--responsive-grid-item-base, 1));
|
|
1989
|
+
grid-row: span var(--responsive-grid-item-row-base, 1);
|
|
1971
1990
|
}
|
|
1972
1991
|
@container responsive-grid (min-width: 40rem) {
|
|
1973
1992
|
.ui-responsive-grid-item {
|
|
1974
1993
|
grid-column: span min(var(--responsive-grid-sm, 1), var(--responsive-grid-item-sm, 1));
|
|
1994
|
+
grid-row: span var(--responsive-grid-item-row-sm, 1);
|
|
1975
1995
|
}
|
|
1976
1996
|
}
|
|
1977
1997
|
@container responsive-grid (min-width: 48rem) {
|
|
1978
1998
|
.ui-responsive-grid-item {
|
|
1979
1999
|
grid-column: span min(var(--responsive-grid-md, 1), var(--responsive-grid-item-md, 1));
|
|
2000
|
+
grid-row: span var(--responsive-grid-item-row-md, 1);
|
|
1980
2001
|
}
|
|
1981
2002
|
}
|
|
1982
2003
|
@container responsive-grid (min-width: 64rem) {
|
|
1983
2004
|
.ui-responsive-grid-item {
|
|
1984
2005
|
grid-column: span min(var(--responsive-grid-lg, 1), var(--responsive-grid-item-lg, 1));
|
|
2006
|
+
grid-row: span var(--responsive-grid-item-row-lg, 1);
|
|
1985
2007
|
}
|
|
1986
2008
|
}
|
|
1987
2009
|
.ui-separator[data-label-size="2xs"] .ui-separator-label {
|
|
@@ -1504,6 +1504,21 @@
|
|
|
1504
1504
|
font-weight: var(--font-weight-medium);
|
|
1505
1505
|
}
|
|
1506
1506
|
|
|
1507
|
+
.ui-app-launcher-footer {
|
|
1508
|
+
display: flex;
|
|
1509
|
+
flex-wrap: wrap;
|
|
1510
|
+
align-items: center;
|
|
1511
|
+
gap: var(--app-launcher-footer-gap);
|
|
1512
|
+
margin-block-start: var(--app-launcher-footer-space-block);
|
|
1513
|
+
padding-block-start: var(--app-launcher-footer-space-block);
|
|
1514
|
+
border-block-start: var(--stroke-hairline) solid hsl(var(--border));
|
|
1515
|
+
font-size: var(--app-launcher-footer-font-size);
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
.ui-app-launcher-launchpad .ui-app-launcher-footer {
|
|
1519
|
+
justify-content: center;
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1507
1522
|
.ui-app-launcher-state {
|
|
1508
1523
|
display: flex;
|
|
1509
1524
|
min-height: var(--app-launcher-state-min-height);
|
|
@@ -1606,6 +1621,17 @@
|
|
|
1606
1621
|
height: var(--sidebar-product-caret-icon-size);
|
|
1607
1622
|
}
|
|
1608
1623
|
|
|
1624
|
+
.sb-action {
|
|
1625
|
+
display: flex;
|
|
1626
|
+
flex-shrink: 0;
|
|
1627
|
+
flex-direction: column;
|
|
1628
|
+
padding: var(--sidebar-action-padding);
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
.sb-root[data-collapsed="true"] .sb-action {
|
|
1632
|
+
align-items: center;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1609
1635
|
.sb-nav-scroll {
|
|
1610
1636
|
flex: 1;
|
|
1611
1637
|
min-height: 0;
|
|
@@ -470,6 +470,11 @@
|
|
|
470
470
|
);
|
|
471
471
|
--emoji-picker-glyph-size: var(--icon-size-lg);
|
|
472
472
|
--emoji-picker-grid-max-block-size: 16rem;
|
|
473
|
+
|
|
474
|
+
--sortable-list-gap: var(--space-2);
|
|
475
|
+
--sortable-list-item-padding: var(--space-2);
|
|
476
|
+
--sortable-list-item-radius: var(--control-radius);
|
|
477
|
+
--sortable-list-grid-item-min-inline-size: 12rem;
|
|
473
478
|
}
|
|
474
479
|
|
|
475
480
|
@media (pointer: coarse) {
|
|
@@ -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;
|
|
@@ -29,6 +29,12 @@
|
|
|
29
29
|
--sheet-close-rest-alpha: 0.7;
|
|
30
30
|
--sheet-header-close-space-inline-end: var(--space-8);
|
|
31
31
|
--dialog-width-default: 32rem;
|
|
32
|
+
|
|
33
|
+
--dialog-width: initial;
|
|
34
|
+
|
|
35
|
+
--dialog-motion-duration: initial;
|
|
36
|
+
--sheet-enter-duration: initial;
|
|
37
|
+
--sheet-exit-duration: initial;
|
|
32
38
|
--dialog-viewport-inset: 1.5rem;
|
|
33
39
|
--dialog-overlay-background: initial;
|
|
34
40
|
|
|
@@ -139,6 +139,8 @@
|
|
|
139
139
|
|
|
140
140
|
--sidebar-nav-item-radius: initial;
|
|
141
141
|
--sidebar-nav-scroll-padding: var(--space-3) var(--space-2);
|
|
142
|
+
|
|
143
|
+
--sidebar-action-padding: var(--space-3) var(--space-2) 0;
|
|
142
144
|
--sidebar-section-gap: var(--space-4);
|
|
143
145
|
--sidebar-section-label-padding-x: var(--space-2);
|
|
144
146
|
--sidebar-section-label-padding-bottom: var(--space-1);
|
|
@@ -240,6 +242,10 @@
|
|
|
240
242
|
--app-launcher-group-label-color: initial;
|
|
241
243
|
--app-launcher-state-min-height: 8rem;
|
|
242
244
|
|
|
245
|
+
--app-launcher-footer-space-block: var(--space-2);
|
|
246
|
+
--app-launcher-footer-gap: var(--space-3);
|
|
247
|
+
--app-launcher-footer-font-size: var(--font-size-sm, var(--font-size-base));
|
|
248
|
+
|
|
243
249
|
--app-launcher-launchpad-backdrop-background: initial;
|
|
244
250
|
--app-launcher-launchpad-backdrop-blur-size: var(--blur-lg);
|
|
245
251
|
--app-launcher-launchpad-backdrop-alpha: 55%;
|
|
@@ -91,10 +91,7 @@
|
|
|
91
91
|
|
|
92
92
|
--page-title-font-size-chrome: var(--heading-h3, var(--font-size-base));
|
|
93
93
|
|
|
94
|
-
--page-title-font-size-display:
|
|
95
|
-
--font-size-4xl,
|
|
96
|
-
calc(var(--font-size-display) / var(--font-size-display-ratio))
|
|
97
|
-
);
|
|
94
|
+
--page-title-font-size-display: initial;
|
|
98
95
|
--page-title-line-height-display: 1.4;
|
|
99
96
|
|
|
100
97
|
--page-icon-size: var(--icon-size-4xl);
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
> Generated by `scripts/frame-coverage.mjs` (issue #163). Do not edit by hand — run `pnpm check:frame-coverage`.
|
|
4
4
|
> Standard: [FRAME-COVERAGE-STANDARD.md](./FRAME-COVERAGE-STANDARD.md). A missing dimension is **UNTESTED**, never a pass.
|
|
5
5
|
|
|
6
|
-
- Public components: **
|
|
7
|
-
- With ≥1 frame: **
|
|
6
|
+
- Public components: **185**
|
|
7
|
+
- With ≥1 frame: **161** · zero-frame: **24**
|
|
8
8
|
- Fully covered (every contract axis declared): **0**
|
|
9
9
|
|
|
10
10
|
## UNTESTED — no `/frame/**` route
|
|
@@ -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 | · | · | · | · | · | · |
|
|
@@ -195,6 +195,7 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
|
|
|
195
195
|
| PieChart | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
|
|
196
196
|
| CommandPalette | ✓ | N/A | · | · | · | · | · | · | · | · |
|
|
197
197
|
| EmojiPicker | ✓ | · | · | · | · | · | · | · | · | · |
|
|
198
|
+
| SortableList | ✓ | N/A | · | · | · | · | · | · | · | · |
|
|
198
199
|
| TwoFactorSetup | ✓ | N/A | · | · | · | · | · | · | · | · |
|
|
199
200
|
| AuthDivider | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
200
201
|
| AuthFooter | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
@@ -11,9 +11,11 @@ import {
|
|
|
11
11
|
} from "@godxjp/ui/data-display";
|
|
12
12
|
import { Button, Text } from "@godxjp/ui/general";
|
|
13
13
|
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
14
|
+
import { useTranslation } from "@godxjp/ui/i18n";
|
|
14
15
|
import { Building2, KeyRound, ShieldCheck, Sparkles } from "lucide-react";
|
|
15
16
|
|
|
16
17
|
import portraitAmber from "../assets/portrait-amber.svg";
|
|
18
|
+
import shotLandscape from "../assets/shot-landscape.svg";
|
|
17
19
|
import portraitClay from "../assets/portrait-clay.svg";
|
|
18
20
|
import portraitIndigo from "../assets/portrait-indigo.svg";
|
|
19
21
|
import portraitIris from "../assets/portrait-iris.svg";
|
|
@@ -39,9 +41,39 @@ import portraitSlate from "../assets/portrait-slate.svg";
|
|
|
39
41
|
* Composed only from real @godxjp/ui components.
|
|
40
42
|
*/
|
|
41
43
|
export default function Demo() {
|
|
44
|
+
const { t } = useTranslation();
|
|
42
45
|
return (
|
|
43
46
|
<PageContainer title="Avatar" subtitle="Identity image with a readable fallback">
|
|
44
47
|
<Flex direction="col" gap="lg">
|
|
48
|
+
<Card>
|
|
49
|
+
<CardHeader>
|
|
50
|
+
<CardTitle level={2}>{t("avatarDocs.fitTitle")}</CardTitle>
|
|
51
|
+
<CardDescription>{t("avatarDocs.fitDescription")}</CardDescription>
|
|
52
|
+
</CardHeader>
|
|
53
|
+
<CardContent>
|
|
54
|
+
{/* gh#1176: a wide logo — cover crops it, contain shows it whole. */}
|
|
55
|
+
<Flex direction="row" wrap align="center" gap="md">
|
|
56
|
+
<Flex direction="col" align="center" gap="xs">
|
|
57
|
+
<Avatar shape="square" size="lg">
|
|
58
|
+
<AvatarImage src={shotLandscape} alt={t("avatarDocs.logo")} />
|
|
59
|
+
<AvatarFallback>AC</AvatarFallback>
|
|
60
|
+
</Avatar>
|
|
61
|
+
<Text size="sm" tone="muted">
|
|
62
|
+
cover
|
|
63
|
+
</Text>
|
|
64
|
+
</Flex>
|
|
65
|
+
<Flex direction="col" align="center" gap="xs">
|
|
66
|
+
<Avatar shape="square" size="lg">
|
|
67
|
+
<AvatarImage src={shotLandscape} alt={t("avatarDocs.logo")} fit="contain" />
|
|
68
|
+
<AvatarFallback>AC</AvatarFallback>
|
|
69
|
+
</Avatar>
|
|
70
|
+
<Text size="sm" tone="muted">
|
|
71
|
+
contain
|
|
72
|
+
</Text>
|
|
73
|
+
</Flex>
|
|
74
|
+
</Flex>
|
|
75
|
+
</CardContent>
|
|
76
|
+
</Card>
|
|
45
77
|
<Card>
|
|
46
78
|
<CardHeader>
|
|
47
79
|
<CardTitle level={2}>Image + fallback</CardTitle>
|
|
@@ -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. */}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@godxjp/ui/data-display";
|
|
3
|
+
import { SortableList } from "@godxjp/ui/data-entry";
|
|
4
|
+
import { Text } from "@godxjp/ui/general";
|
|
5
|
+
import { useTranslation } from "@godxjp/ui/i18n";
|
|
6
|
+
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* SortableList (gh#1173) — a desktop editor's widget order (tiles) and a settings list of tabs,
|
|
10
|
+
* reordered by dragging a grip or by the keyboard, every step announced.
|
|
11
|
+
*/
|
|
12
|
+
export default function Demo() {
|
|
13
|
+
const { t, locale } = useTranslation();
|
|
14
|
+
const list = new Intl.ListFormat(locale, { style: "narrow", type: "unit" });
|
|
15
|
+
const ordinal = new Intl.NumberFormat(locale);
|
|
16
|
+
const widgets = [
|
|
17
|
+
{ value: "calendar", label: t("sortableListDocs.calendar") },
|
|
18
|
+
{ value: "mail", label: t("sortableListDocs.mail") },
|
|
19
|
+
{ value: "tasks", label: t("sortableListDocs.tasks") },
|
|
20
|
+
{ value: "notes", label: t("sortableListDocs.notes") },
|
|
21
|
+
];
|
|
22
|
+
const tabs = [
|
|
23
|
+
{ value: "overview", label: t("sortableListDocs.overview") },
|
|
24
|
+
{ value: "members", label: t("sortableListDocs.members") },
|
|
25
|
+
{ value: "billing", label: t("sortableListDocs.billing"), disabled: true },
|
|
26
|
+
{ value: "audit", label: t("sortableListDocs.audit") },
|
|
27
|
+
];
|
|
28
|
+
const [order, setOrder] = React.useState(widgets.map((w) => w.value));
|
|
29
|
+
return (
|
|
30
|
+
<PageContainer title="SortableList" subtitle={t("sortableListDocs.subtitle")}>
|
|
31
|
+
<Flex direction="col" gap="lg">
|
|
32
|
+
<Card>
|
|
33
|
+
<CardHeader>
|
|
34
|
+
<CardTitle level={2}>{t("sortableListDocs.widgetsTitle")}</CardTitle>
|
|
35
|
+
<CardDescription>{t("sortableListDocs.widgetsDescription")}</CardDescription>
|
|
36
|
+
</CardHeader>
|
|
37
|
+
<CardContent>
|
|
38
|
+
<Flex direction="col" gap="sm">
|
|
39
|
+
<SortableList
|
|
40
|
+
aria-label={t("sortableListDocs.widgetsTitle")}
|
|
41
|
+
layout="grid"
|
|
42
|
+
items={widgets}
|
|
43
|
+
value={order}
|
|
44
|
+
onValueChange={setOrder}
|
|
45
|
+
renderItem={(item, { index }) => (
|
|
46
|
+
<Flex direction="col" gap="xs">
|
|
47
|
+
<Text weight="medium">{item.label}</Text>
|
|
48
|
+
<Text size="sm" tone="muted">
|
|
49
|
+
{t("sortableListDocs.slot", { position: ordinal.format(index + 1) })}
|
|
50
|
+
</Text>
|
|
51
|
+
</Flex>
|
|
52
|
+
)}
|
|
53
|
+
/>
|
|
54
|
+
<Text size="sm" tone="muted">
|
|
55
|
+
{t("sortableListDocs.saved", {
|
|
56
|
+
order: list.format(
|
|
57
|
+
order.map((key) => widgets.find((w) => w.value === key)?.label ?? key),
|
|
58
|
+
),
|
|
59
|
+
})}
|
|
60
|
+
</Text>
|
|
61
|
+
</Flex>
|
|
62
|
+
</CardContent>
|
|
63
|
+
</Card>
|
|
64
|
+
<Card>
|
|
65
|
+
<CardHeader>
|
|
66
|
+
<CardTitle level={2}>{t("sortableListDocs.tabsTitle")}</CardTitle>
|
|
67
|
+
<CardDescription>{t("sortableListDocs.tabsDescription")}</CardDescription>
|
|
68
|
+
</CardHeader>
|
|
69
|
+
<CardContent>
|
|
70
|
+
<SortableList aria-label={t("sortableListDocs.tabsTitle")} items={tabs} />
|
|
71
|
+
</CardContent>
|
|
72
|
+
</Card>
|
|
73
|
+
</Flex>
|
|
74
|
+
</PageContainer>
|
|
75
|
+
);
|
|
76
|
+
}
|
package/docs/feedback/dialog.tsx
CHANGED
|
@@ -21,7 +21,8 @@ import {
|
|
|
21
21
|
CardTitle,
|
|
22
22
|
} from "@godxjp/ui/data-display";
|
|
23
23
|
import { Button, Text } from "@godxjp/ui/general";
|
|
24
|
-
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
24
|
+
import { Flex, PageContainer, ResponsiveGrid } from "@godxjp/ui/layout";
|
|
25
|
+
import { useTranslation } from "@godxjp/ui/i18n";
|
|
25
26
|
|
|
26
27
|
/** Every branch of DialogHeader's `tone`, in the order the vocabulary declares them. */
|
|
27
28
|
const headerTones = [
|
|
@@ -49,6 +50,8 @@ const yen = new Intl.NumberFormat("ja-JP", { style: "currency", currency: "JPY"
|
|
|
49
50
|
* Use DialogFooter for primary/cancel actions.
|
|
50
51
|
*/
|
|
51
52
|
export default function Demo() {
|
|
53
|
+
const { t } = useTranslation();
|
|
54
|
+
const [wideOpen, setWideOpen] = useState(false);
|
|
52
55
|
const [createOpen, setCreateOpen] = useState(true);
|
|
53
56
|
const [detailOpen, setDetailOpen] = useState(false);
|
|
54
57
|
const [toneOpen, setToneOpen] = useState(false);
|
|
@@ -128,6 +131,39 @@ export default function Demo() {
|
|
|
128
131
|
</CardContent>
|
|
129
132
|
</Card>
|
|
130
133
|
|
|
134
|
+
<Card>
|
|
135
|
+
<CardHeader>
|
|
136
|
+
<CardTitle level={2}>{t("dialogWidthDocs.title")}</CardTitle>
|
|
137
|
+
<CardDescription>{t("dialogWidthDocs.description")}</CardDescription>
|
|
138
|
+
</CardHeader>
|
|
139
|
+
<CardContent>
|
|
140
|
+
<Dialog open={wideOpen} onOpenChange={setWideOpen}>
|
|
141
|
+
<DialogTrigger asChild>
|
|
142
|
+
<Button variant="outline" size="sm">
|
|
143
|
+
{t("dialogWidthDocs.open")}
|
|
144
|
+
</Button>
|
|
145
|
+
</DialogTrigger>
|
|
146
|
+
<DialogContent width="60rem">
|
|
147
|
+
<DialogHeader>
|
|
148
|
+
<DialogTitle>{t("dialogWidthDocs.dialogTitle")}</DialogTitle>
|
|
149
|
+
<DialogDescription>{t("dialogWidthDocs.dialogDescription")}</DialogDescription>
|
|
150
|
+
</DialogHeader>
|
|
151
|
+
<DialogBody>
|
|
152
|
+
<ResponsiveGrid columns={{ base: 1, sm: 3 }}>
|
|
153
|
+
{[1, 2, 3, 4, 5, 6].map((n) => (
|
|
154
|
+
<Card key={n}>
|
|
155
|
+
<CardContent>
|
|
156
|
+
<Text>{t("dialogWidthDocs.desktop", { n: String(n) })}</Text>
|
|
157
|
+
</CardContent>
|
|
158
|
+
</Card>
|
|
159
|
+
))}
|
|
160
|
+
</ResponsiveGrid>
|
|
161
|
+
</DialogBody>
|
|
162
|
+
</DialogContent>
|
|
163
|
+
</Dialog>
|
|
164
|
+
</CardContent>
|
|
165
|
+
</Card>
|
|
166
|
+
|
|
131
167
|
<Card>
|
|
132
168
|
<CardHeader>
|
|
133
169
|
<CardTitle level={2}>Read-only detail pop-up</CardTitle>
|
|
@@ -1638,5 +1638,67 @@
|
|
|
1638
1638
|
"label": "Icon",
|
|
1639
1639
|
"chosen": "Chosen: {icon}",
|
|
1640
1640
|
"none": "No icon"
|
|
1641
|
+
},
|
|
1642
|
+
"dialogWidthDocs": {
|
|
1643
|
+
"title": "Wide dialog (width)",
|
|
1644
|
+
"description": "DialogContent width sizes the panel for an overview grid; it is capped at the viewport minus the inset, so it still fits a phone.",
|
|
1645
|
+
"open": "Open the overview",
|
|
1646
|
+
"dialogTitle": "All desktops",
|
|
1647
|
+
"dialogDescription": "A 60rem dialog holding a three-column grid.",
|
|
1648
|
+
"desktop": "Desktop {n}"
|
|
1649
|
+
},
|
|
1650
|
+
"sortableListDocs": {
|
|
1651
|
+
"subtitle": "Drag a grip, or Space · arrows · Space · Esc — every move is announced",
|
|
1652
|
+
"widgetsTitle": "Home widgets",
|
|
1653
|
+
"widgetsDescription": "Order the tiles on your desktop. The order is saved once, when you drop.",
|
|
1654
|
+
"calendar": "Calendar",
|
|
1655
|
+
"mail": "Mail",
|
|
1656
|
+
"tasks": "Tasks",
|
|
1657
|
+
"notes": "Notes",
|
|
1658
|
+
"slot": "Slot {position}",
|
|
1659
|
+
"saved": "Saved order: {order}",
|
|
1660
|
+
"tabsTitle": "Project tabs",
|
|
1661
|
+
"tabsDescription": "A list layout. Billing is locked by your plan, so it cannot be picked up — the others still move past it.",
|
|
1662
|
+
"overview": "Overview",
|
|
1663
|
+
"members": "Members",
|
|
1664
|
+
"billing": "Billing",
|
|
1665
|
+
"audit": "Audit log"
|
|
1666
|
+
},
|
|
1667
|
+
"topbarItemDocs": {
|
|
1668
|
+
"notifications": "Notifications",
|
|
1669
|
+
"notificationsUnread": "Notifications, {count} unread"
|
|
1670
|
+
},
|
|
1671
|
+
"appLauncherDocs": {
|
|
1672
|
+
"requestAccess": "Request access",
|
|
1673
|
+
"allApps": "All apps"
|
|
1674
|
+
},
|
|
1675
|
+
"responsiveGridDocs": {
|
|
1676
|
+
"boardTitle": "Widget board (rowSpan + dense)",
|
|
1677
|
+
"boardDescription": "A 2×1 cell, a tall 1×2 cell (ResponsiveGrid.Item rowSpan={2}) and 1×1 cells. dense lets the small cells fill the space beside the wide and tall ones.",
|
|
1678
|
+
"revenue": "Monthly revenue",
|
|
1679
|
+
"tasks": "Open tasks",
|
|
1680
|
+
"members": "Members",
|
|
1681
|
+
"invoices": "Invoices",
|
|
1682
|
+
"services": "Services",
|
|
1683
|
+
"invitations": "Invitations"
|
|
1684
|
+
},
|
|
1685
|
+
"avatarDocs": {
|
|
1686
|
+
"fitTitle": "Logos: fit=\"contain\"",
|
|
1687
|
+
"fitDescription": "cover (the default) crops to fill — right for a face. contain shows a wide or transparent logo whole.",
|
|
1688
|
+
"logo": "Acme logo"
|
|
1689
|
+
},
|
|
1690
|
+
"sidebarDocs": {
|
|
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)"
|
|
1641
1703
|
}
|
|
1642
1704
|
}
|