@godxjp/ui 31.6.0 → 31.8.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 +4 -4
- package/agent/components/Breadcrumb.json +1 -1
- package/agent/components/ColorPicker.json +16 -8
- package/agent/components/PageContainer.json +1 -1
- package/agent/components/Progress.json +12 -1
- package/agent/components/Select.json +22 -0
- package/agent/components/Text.json +1 -1
- package/agent/components.json +53 -12
- package/agent/index.json +4 -4
- package/agent/llms.txt +5 -5
- package/agent/tokens.json +30 -0
- package/dist/components/data-display/progress.d.ts +16 -0
- package/dist/components/data-display/progress.js +17 -3
- package/dist/components/data-entry/chat-composer.js +11 -4
- package/dist/components/data-entry/chat-suggestion.js +2 -0
- package/dist/components/data-entry/color-picker.d.ts +2 -2
- package/dist/components/data-entry/color-picker.js +150 -37
- package/dist/components/data-entry/command-palette.js +2 -1
- package/dist/components/data-entry/date-picker.js +2 -0
- package/dist/components/data-entry/index.d.ts +1 -1
- package/dist/components/data-entry/number-input.js +2 -1
- package/dist/components/data-entry/search-select.js +55 -17
- package/dist/components/data-entry/select.js +1 -1
- package/dist/components/data-entry/time-picker.js +3 -0
- package/dist/components/feedback/non-modal-layer.js +2 -1
- package/dist/components/feedback/tooltip.d.ts +21 -0
- package/dist/components/feedback/tooltip.js +101 -0
- package/dist/components/general/typography.js +35 -12
- package/dist/components/layout/breadcrumb-ellipsis.d.ts +16 -0
- package/dist/components/layout/breadcrumb-ellipsis.js +28 -0
- package/dist/components/layout/breadcrumb.js +16 -7
- package/dist/components/layout/page-container.js +29 -20
- package/dist/components/navigation/pagination.js +2 -1
- package/dist/components/ui/tag-input.js +2 -1
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +6 -3
- package/dist/i18n/messages/ja.json +6 -3
- package/dist/i18n/messages/vi.json +6 -3
- package/dist/lib/ime.d.ts +12 -0
- package/dist/lib/ime.js +7 -0
- package/dist/props/components/data-entry.prop.d.ts +66 -1
- package/dist/props/components/index.d.ts +1 -1
- package/dist/props/registry.d.ts +20 -0
- package/dist/props/registry.js +22 -0
- package/dist/props/vocabulary/index.d.ts +1 -1
- package/dist/props/vocabulary/navigation.prop.d.ts +14 -0
- package/dist/styles/control.css +79 -0
- package/dist/styles/layers.json +3 -2
- package/dist/styles/layout.css +22 -0
- package/dist/styles/table-layout.css +8 -0
- package/dist/tokens/components/control.css +8 -0
- package/dist/tokens/components/navigation.css +2 -0
- package/docs/data-display/progress.tsx +24 -6
- package/docs/data-entry/color-picker.tsx +72 -0
- package/docs/data-entry/select.tsx +38 -0
- package/docs/general/typography.tsx +84 -1
- package/docs/i18n/messages/en.json +47 -1
- package/docs/i18n/messages/ja.json +47 -1
- package/docs/i18n/messages/vi.json +47 -1
- package/docs/navigation/breadcrumb.tsx +24 -0
- package/package.json +2 -2
|
@@ -33,6 +33,20 @@ export type BreadcrumbItemProp = {
|
|
|
33
33
|
to?: string;
|
|
34
34
|
/** Ant Design `menu` — a sibling dropdown on this segment. @see BreadcrumbItemMenuProp */
|
|
35
35
|
menu?: BreadcrumbItemMenuProp;
|
|
36
|
+
/**
|
|
37
|
+
* One line, a long label cut with "…" (gh#1046). antd's Breadcrumb has no per-item ellipsis;
|
|
38
|
+
* the name and shape are antd Typography's `ellipsis`. The full label shows in a tooltip on hover
|
|
39
|
+
* and on keyboard focus of the crumb link — `true` / `{}` use the label, `{ tooltip: node }`
|
|
40
|
+
* replaces it, `{ tooltip: false }` drops it. Applies to link and current crumbs, not to a
|
|
41
|
+
* `menu` segment or an `itemRender` body. The trail then stays on one line; a theme may cap
|
|
42
|
+
* each such crumb with `--breadcrumb-item-max-inline-size`.
|
|
43
|
+
* @see BreadcrumbItemEllipsisProp
|
|
44
|
+
*/
|
|
45
|
+
ellipsis?: BreadcrumbItemEllipsisProp;
|
|
46
|
+
};
|
|
47
|
+
/** `BreadcrumbItemProp.ellipsis` — on, or on with an explicit tooltip (gh#1046). */
|
|
48
|
+
export type BreadcrumbItemEllipsisProp = boolean | {
|
|
49
|
+
tooltip?: React.ReactNode;
|
|
36
50
|
};
|
|
37
51
|
/** Ordered breadcrumb trail above page title. */
|
|
38
52
|
export type BreadcrumbProp = BreadcrumbItemProp[];
|
package/dist/styles/control.css
CHANGED
|
@@ -738,6 +738,85 @@
|
|
|
738
738
|
text-transform: uppercase;
|
|
739
739
|
}
|
|
740
740
|
|
|
741
|
+
.ui-color-picker[data-panel] {
|
|
742
|
+
flex-direction: column;
|
|
743
|
+
align-items: stretch;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
.ui-color-picker-picker {
|
|
747
|
+
display: flex;
|
|
748
|
+
align-items: center;
|
|
749
|
+
gap: var(--control-gap);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
.ui-color-picker-presets {
|
|
753
|
+
display: flex;
|
|
754
|
+
flex-direction: column;
|
|
755
|
+
gap: var(--color-picker-presets-gap);
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
.ui-color-picker-presets-trigger {
|
|
759
|
+
display: inline-flex;
|
|
760
|
+
align-items: center;
|
|
761
|
+
gap: var(--space-1);
|
|
762
|
+
min-block-size: var(--touch-target-min);
|
|
763
|
+
color: hsl(var(--muted-foreground));
|
|
764
|
+
font-size: var(--color-picker-presets-font-size);
|
|
765
|
+
text-align: start;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
.ui-color-picker-presets-chevron {
|
|
769
|
+
width: var(--control-icon-size);
|
|
770
|
+
height: var(--control-icon-size);
|
|
771
|
+
flex-shrink: 0;
|
|
772
|
+
transition: rotate 150ms;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
.ui-color-picker-presets-trigger[data-state="closed"] .ui-color-picker-presets-chevron {
|
|
776
|
+
rotate: -90deg;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
.ui-color-picker-presets-trigger[data-state="closed"]:dir(rtl) .ui-color-picker-presets-chevron {
|
|
780
|
+
rotate: 90deg;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
.ui-color-picker-presets-items {
|
|
784
|
+
display: flex;
|
|
785
|
+
flex-wrap: wrap;
|
|
786
|
+
gap: var(--color-picker-preset-gap);
|
|
787
|
+
padding-block: var(--space-1);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
.ui-color-picker-presets-color {
|
|
791
|
+
display: inline-block;
|
|
792
|
+
flex-shrink: 0;
|
|
793
|
+
inline-size: var(--color-picker-preset-size);
|
|
794
|
+
block-size: var(--color-picker-preset-size);
|
|
795
|
+
border: var(--stroke-hairline) solid hsl(var(--input) / var(--input-alpha, 100%));
|
|
796
|
+
border-radius: var(--control-radius);
|
|
797
|
+
background-color: var(--color-picker-preset-color, transparent);
|
|
798
|
+
cursor: pointer;
|
|
799
|
+
forced-color-adjust: none;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
.ui-color-picker-presets-color[data-selected] {
|
|
803
|
+
box-shadow:
|
|
804
|
+
0 0 0 var(--stroke-md) hsl(var(--background)),
|
|
805
|
+
0 0 0 calc(var(--stroke-md) * 2) hsl(var(--foreground));
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
.ui-color-picker-presets-color[data-disabled] {
|
|
809
|
+
cursor: not-allowed;
|
|
810
|
+
opacity: var(--disabled-opacity);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
.ui-color-picker-presets-empty {
|
|
814
|
+
display: block;
|
|
815
|
+
padding-block: var(--space-1);
|
|
816
|
+
color: hsl(var(--muted-foreground));
|
|
817
|
+
font-size: var(--color-picker-presets-font-size);
|
|
818
|
+
}
|
|
819
|
+
|
|
741
820
|
.ui-query-refetch-icon[data-fetching="true"] {
|
|
742
821
|
animation: spin 1s linear infinite;
|
|
743
822
|
}
|
package/dist/styles/layers.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "31.
|
|
2
|
+
"version": "31.8.0",
|
|
3
3
|
"generatedBy": "scripts/gen-style-layers.mjs — do not edit by hand; run `pnpm gen:style-layers`",
|
|
4
4
|
"base": "base.css",
|
|
5
5
|
"fonts": "fonts.css",
|
|
@@ -702,7 +702,8 @@
|
|
|
702
702
|
},
|
|
703
703
|
"PageContainer": {
|
|
704
704
|
"layers": [
|
|
705
|
-
"layout.css"
|
|
705
|
+
"layout.css",
|
|
706
|
+
"dialog-layout.css"
|
|
706
707
|
]
|
|
707
708
|
},
|
|
708
709
|
"Pagination": {
|
package/dist/styles/layout.css
CHANGED
|
@@ -1036,6 +1036,28 @@
|
|
|
1036
1036
|
color: hsl(var(--foreground));
|
|
1037
1037
|
}
|
|
1038
1038
|
|
|
1039
|
+
.ui-breadcrumb-list[data-ellipsis] {
|
|
1040
|
+
flex-wrap: nowrap;
|
|
1041
|
+
}
|
|
1042
|
+
.ui-breadcrumb-list[data-ellipsis] > .ui-breadcrumb-item:not([data-ellipsis]) {
|
|
1043
|
+
flex-shrink: 0;
|
|
1044
|
+
white-space: nowrap;
|
|
1045
|
+
}
|
|
1046
|
+
.ui-breadcrumb-item[data-ellipsis] {
|
|
1047
|
+
min-inline-size: 0;
|
|
1048
|
+
max-inline-size: var(--breadcrumb-item-max-inline-size);
|
|
1049
|
+
}
|
|
1050
|
+
.ui-breadcrumb-item[data-ellipsis] > svg,
|
|
1051
|
+
.ui-breadcrumb-item[data-ellipsis] > .ui-breadcrumb-separator {
|
|
1052
|
+
flex-shrink: 0;
|
|
1053
|
+
}
|
|
1054
|
+
.ui-breadcrumb-ellipsis {
|
|
1055
|
+
min-inline-size: 0;
|
|
1056
|
+
overflow: hidden;
|
|
1057
|
+
text-overflow: ellipsis;
|
|
1058
|
+
white-space: nowrap;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1039
1061
|
.ui-empty-state {
|
|
1040
1062
|
display: flex;
|
|
1041
1063
|
flex-direction: column;
|
|
@@ -212,6 +212,9 @@
|
|
|
212
212
|
font: inherit;
|
|
213
213
|
cursor: pointer;
|
|
214
214
|
outline: none;
|
|
215
|
+
|
|
216
|
+
max-inline-size: 100%;
|
|
217
|
+
min-inline-size: 0;
|
|
215
218
|
}
|
|
216
219
|
|
|
217
220
|
.ui-data-table-sort-button::after {
|
|
@@ -334,6 +337,11 @@
|
|
|
334
337
|
display: inline-flex;
|
|
335
338
|
align-items: center;
|
|
336
339
|
gap: var(--space-inline-xs);
|
|
340
|
+
min-inline-size: 0;
|
|
341
|
+
max-inline-size: 100%;
|
|
342
|
+
}
|
|
343
|
+
.ui-data-table-sort-label > .ui-data-table-sort-icon {
|
|
344
|
+
flex-shrink: 0;
|
|
337
345
|
}
|
|
338
346
|
|
|
339
347
|
:is(th, td).text-center > .ui-data-table-sort-button > .ui-data-table-sort-label {
|
|
@@ -157,6 +157,10 @@
|
|
|
157
157
|
|
|
158
158
|
--color-picker-input-width: 6.5rem;
|
|
159
159
|
|
|
160
|
+
--color-picker-preset-size: var(--touch-target-min);
|
|
161
|
+
--color-picker-preset-gap: var(--space-2);
|
|
162
|
+
--color-picker-presets-gap: var(--space-1);
|
|
163
|
+
|
|
160
164
|
--command-list-max-height: min(300px, 50vh);
|
|
161
165
|
--command-input-padding-x: var(--space-3);
|
|
162
166
|
--command-group-padding: var(--space-1);
|
|
@@ -192,6 +196,10 @@
|
|
|
192
196
|
--font-size-xs,
|
|
193
197
|
calc(var(--font-size-base) / var(--font-size-ratio))
|
|
194
198
|
);
|
|
199
|
+
--color-picker-presets-font-size: var(
|
|
200
|
+
--font-size-xs,
|
|
201
|
+
calc(var(--font-size-base) / var(--font-size-ratio))
|
|
202
|
+
);
|
|
195
203
|
--command-group-heading-font-size: var(
|
|
196
204
|
--font-size-xs,
|
|
197
205
|
calc(var(--font-size-base) / var(--font-size-ratio))
|
|
@@ -46,6 +46,8 @@
|
|
|
46
46
|
--breadcrumb-font-size: var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)));
|
|
47
47
|
|
|
48
48
|
--breadcrumb-menu-trigger-gap: var(--space-inline-xs);
|
|
49
|
+
|
|
50
|
+
--breadcrumb-item-max-inline-size: none;
|
|
49
51
|
--menu-shortcut-font-size: var(
|
|
50
52
|
--font-size-xs,
|
|
51
53
|
calc(var(--font-size-base) / var(--font-size-ratio))
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
CardTitle,
|
|
7
7
|
Progress,
|
|
8
8
|
} from "@godxjp/ui/data-display";
|
|
9
|
+
import { useTranslation } from "@godxjp/ui/i18n";
|
|
9
10
|
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -13,6 +14,7 @@ import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
|
13
14
|
* Composed only from real @godxjp/ui components.
|
|
14
15
|
*/
|
|
15
16
|
export default function Demo() {
|
|
17
|
+
const { t, locale } = useTranslation();
|
|
16
18
|
return (
|
|
17
19
|
<PageContainer title="Progress" subtitle="0–100 bar · optional label + semantic tone">
|
|
18
20
|
<Flex direction="col" gap="lg">
|
|
@@ -37,11 +39,10 @@ export default function Demo() {
|
|
|
37
39
|
<CardHeader>
|
|
38
40
|
<CardTitle level={2}>shape="ring"</CardTitle>
|
|
39
41
|
<CardDescription>
|
|
40
|
-
同じメーターを弧で描きます。バーと同じ value / tone / size / ARIA
|
|
41
|
-
|
|
42
|
-
件」を見出しの横に出したいとき、バー+キャプションの 2
|
|
43
|
-
|
|
44
|
-
場所が正方形のときに選びます。
|
|
42
|
+
同じメーターを弧で描きます。バーと同じ value / tone / size / ARIA のまま、label
|
|
43
|
+
がリングの内側に入ります。狭いアプリバーで「18 / 42
|
|
44
|
+
件」を見出しの横に出したいとき、バー+キャプションの 2 段ではなく 1
|
|
45
|
+
マスで済むのが理由です。数値が重要なときではなく、 場所が正方形のときに選びます。
|
|
45
46
|
</CardDescription>
|
|
46
47
|
</CardHeader>
|
|
47
48
|
<CardContent>
|
|
@@ -68,7 +69,10 @@ export default function Demo() {
|
|
|
68
69
|
1 つの合計を状態ごとに分割します。割合ではなく実数を渡すと、各スライスの比率は
|
|
69
70
|
コンポーネントが計算します。メーターより背の高いトラックになるのは、0.5rem の pill
|
|
70
71
|
上に 3 色を並べると比率が読めなくなるためです。role="img"
|
|
71
|
-
として、全スライスを 1 つの名前で読み上げます。
|
|
72
|
+
として、全スライスを 1 つの名前で読み上げます。total を渡すと全体は合計ではなく total
|
|
73
|
+
になり、残りはトラックのまま「残り」として読み上げます(antd の percent +
|
|
74
|
+
success.percent と同じく、未塗りのトラックが残り。antd の全体は常に 100
|
|
75
|
+
ですが、ここは実数の単位で total を指定します)。
|
|
72
76
|
</CardDescription>
|
|
73
77
|
</CardHeader>
|
|
74
78
|
<CardContent>
|
|
@@ -89,6 +93,20 @@ export default function Demo() {
|
|
|
89
93
|
]}
|
|
90
94
|
label="みどり農産株式会社(0 件のスライスは幅 0)"
|
|
91
95
|
/>
|
|
96
|
+
{/* total を渡すと、スライスは合計ではなく total に対して描かれ、残りはトラックのまま。
|
|
97
|
+
読み上げには残り(remainderLabel)が Intl 形式の数値で入ります。 */}
|
|
98
|
+
<Progress
|
|
99
|
+
segments={[
|
|
100
|
+
{ value: 3, tone: "success", label: t("progressDocs.testRun.passed") },
|
|
101
|
+
{ value: 1, tone: "destructive", label: t("progressDocs.testRun.failed") },
|
|
102
|
+
{ value: 2, tone: "warning", label: t("progressDocs.testRun.blocked") },
|
|
103
|
+
]}
|
|
104
|
+
total={400}
|
|
105
|
+
remainderLabel={t("progressDocs.testRun.notRun")}
|
|
106
|
+
label={t("progressDocs.testRun.caption", {
|
|
107
|
+
total: new Intl.NumberFormat(locale).format(400),
|
|
108
|
+
})}
|
|
109
|
+
/>
|
|
92
110
|
</Flex>
|
|
93
111
|
</CardContent>
|
|
94
112
|
</Card>
|
|
@@ -3,19 +3,33 @@ import { useState } from "react";
|
|
|
3
3
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@godxjp/ui/data-display";
|
|
4
4
|
import { ColorPicker, FormField } from "@godxjp/ui/data-entry";
|
|
5
5
|
import { Text } from "@godxjp/ui/general";
|
|
6
|
+
import { useTranslation } from "@godxjp/ui/i18n";
|
|
6
7
|
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
7
8
|
|
|
9
|
+
/** A fixed tag palette (gh#1055): tags pick from it, never from free hex. */
|
|
10
|
+
const TAG_PALETTE = ["#dc2626", "#ea580c", "#ca8a04", "#16a34a", "#0891b2", "#2563eb", "#9333ea"];
|
|
11
|
+
|
|
8
12
|
/**
|
|
9
13
|
* ColorPicker — hex color swatch + optional editable hex input.
|
|
10
14
|
* Always initialize state to a valid 3- or 6-digit hex string.
|
|
11
15
|
* Use controlled mode (value + onValueChange); no uncontrolled path.
|
|
12
16
|
* Composed only from real @godxjp/ui components.
|
|
17
|
+
*
|
|
18
|
+
* `presets` / `panelRender` port antd ColorPicker (gh#1055). Deviations from antd, on purpose:
|
|
19
|
+
* - `colors` are hex strings only — the value is hex; antd also takes colour objects/gradients.
|
|
20
|
+
* - There is no popover: the picker is inline, so `panelRender` replaces the inline body. The
|
|
21
|
+
* presets-only recipe is antd's own: `panelRender={(_, { components: { Presets } }) => <Presets />}`.
|
|
22
|
+
* - Each swatch is a real radio (APG radio group, named by its hex, arrow keys select); antd's
|
|
23
|
+
* preset blocks are click-only divs.
|
|
13
24
|
*/
|
|
14
25
|
export default function Demo() {
|
|
15
26
|
const [brandColor, setBrandColor] = useState("#2563eb");
|
|
16
27
|
const [accentColor, setAccentColor] = useState("#16a34a");
|
|
17
28
|
const [categoryColor, setCategoryColor] = useState("#dc2626");
|
|
18
29
|
const [validatedColor, setValidatedColor] = useState("#9333ea");
|
|
30
|
+
const [labelColor, setLabelColor] = useState("#16a34a");
|
|
31
|
+
const [tagColor, setTagColor] = useState("#2563eb");
|
|
32
|
+
const { t } = useTranslation();
|
|
19
33
|
|
|
20
34
|
return (
|
|
21
35
|
<PageContainer title="ColorPicker" subtitle="カラーピッカー · スウォッチ+Hex入力">
|
|
@@ -75,6 +89,64 @@ export default function Demo() {
|
|
|
75
89
|
</CardContent>
|
|
76
90
|
</Card>
|
|
77
91
|
|
|
92
|
+
<Card>
|
|
93
|
+
<CardHeader>
|
|
94
|
+
<CardTitle level={2}>{t("showcase.colorPicker.presetsTitle")}</CardTitle>
|
|
95
|
+
<CardDescription>{t("showcase.colorPicker.presetsDescription")}</CardDescription>
|
|
96
|
+
</CardHeader>
|
|
97
|
+
<CardContent>
|
|
98
|
+
<FormField id="label-color" label={t("showcase.colorPicker.paletteLabel")}>
|
|
99
|
+
<ColorPicker
|
|
100
|
+
id="label-color"
|
|
101
|
+
value={labelColor}
|
|
102
|
+
onValueChange={setLabelColor}
|
|
103
|
+
presets={[
|
|
104
|
+
{
|
|
105
|
+
key: "recommended",
|
|
106
|
+
label: t("showcase.colorPicker.recommendedGroup"),
|
|
107
|
+
colors: TAG_PALETTE,
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
key: "recent",
|
|
111
|
+
label: t("showcase.colorPicker.recentGroup"),
|
|
112
|
+
colors: ["#2563eb", "#16a34a"],
|
|
113
|
+
defaultOpen: false,
|
|
114
|
+
},
|
|
115
|
+
]}
|
|
116
|
+
/>
|
|
117
|
+
</FormField>
|
|
118
|
+
</CardContent>
|
|
119
|
+
</Card>
|
|
120
|
+
|
|
121
|
+
<Card>
|
|
122
|
+
<CardHeader>
|
|
123
|
+
<CardTitle level={2}>{t("showcase.colorPicker.presetsOnlyTitle")}</CardTitle>
|
|
124
|
+
<CardDescription>{t("showcase.colorPicker.presetsOnlyDescription")}</CardDescription>
|
|
125
|
+
</CardHeader>
|
|
126
|
+
<CardContent>
|
|
127
|
+
<FormField
|
|
128
|
+
id="tag-color"
|
|
129
|
+
label={t("showcase.colorPicker.tagColorLabel")}
|
|
130
|
+
helper={t("showcase.colorPicker.tagColorHelper")}
|
|
131
|
+
>
|
|
132
|
+
<ColorPicker
|
|
133
|
+
id="tag-color"
|
|
134
|
+
name="tag_color"
|
|
135
|
+
value={tagColor}
|
|
136
|
+
onValueChange={setTagColor}
|
|
137
|
+
presets={[
|
|
138
|
+
{
|
|
139
|
+
key: "tags",
|
|
140
|
+
label: t("showcase.colorPicker.recommendedGroup"),
|
|
141
|
+
colors: TAG_PALETTE,
|
|
142
|
+
},
|
|
143
|
+
]}
|
|
144
|
+
panelRender={(_, { components: { Presets } }) => <Presets />}
|
|
145
|
+
/>
|
|
146
|
+
</FormField>
|
|
147
|
+
</CardContent>
|
|
148
|
+
</Card>
|
|
149
|
+
|
|
78
150
|
<Card>
|
|
79
151
|
<CardHeader>
|
|
80
152
|
<CardTitle level={2}>Hex バリデーションと確定動作</CardTitle>
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
SelectValue,
|
|
24
24
|
} from "@godxjp/ui/data-entry";
|
|
25
25
|
import { Button } from "@godxjp/ui/general";
|
|
26
|
+
import { useTranslation } from "@godxjp/ui/i18n";
|
|
26
27
|
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
27
28
|
import { X } from "lucide-react";
|
|
28
29
|
|
|
@@ -32,6 +33,7 @@ import { X } from "lucide-react";
|
|
|
32
33
|
* trigger. Never a raw <select>. Composed only from real @godxjp/ui components.
|
|
33
34
|
*/
|
|
34
35
|
export default function Demo() {
|
|
36
|
+
const { t, locale } = useTranslation();
|
|
35
37
|
const [status, setStatus] = useState("paid");
|
|
36
38
|
const [currency, setCurrency] = useState("JPY");
|
|
37
39
|
const [priority, setPriority] = useState("medium");
|
|
@@ -43,6 +45,8 @@ export default function Demo() {
|
|
|
43
45
|
const [reviewerLabel, setReviewerLabel] = useState("tanaka");
|
|
44
46
|
const [prefixed, setPrefixed] = useState("JPY");
|
|
45
47
|
const [tags, setTags] = useState<string[]>(["至急", "社内便"]);
|
|
48
|
+
const [labels, setLabels] = useState<string[]>([]);
|
|
49
|
+
const [created, setCreated] = useState<string[]>([]);
|
|
46
50
|
// antd `labelInValue`: the record arrives carrying its own label, before any option list loads.
|
|
47
51
|
const [assignedTo, setAssignedTo] = useState<
|
|
48
52
|
{ value: string; label: React.ReactNode } | undefined
|
|
@@ -481,6 +485,40 @@ export default function Demo() {
|
|
|
481
485
|
</CardContent>
|
|
482
486
|
</Card>
|
|
483
487
|
|
|
488
|
+
<Card>
|
|
489
|
+
<CardHeader>
|
|
490
|
+
<CardTitle level={2}>{t("showcase.select.createTitle")}</CardTitle>
|
|
491
|
+
<CardDescription>{t("showcase.select.createDescription")}</CardDescription>
|
|
492
|
+
</CardHeader>
|
|
493
|
+
<CardContent>
|
|
494
|
+
<FormField
|
|
495
|
+
id="issue-labels"
|
|
496
|
+
label={t("showcase.select.createField")}
|
|
497
|
+
helper={
|
|
498
|
+
created.length
|
|
499
|
+
? t("showcase.select.createdHelper", {
|
|
500
|
+
list: new Intl.ListFormat(locale).format(created),
|
|
501
|
+
})
|
|
502
|
+
: t("showcase.select.createdNone")
|
|
503
|
+
}
|
|
504
|
+
>
|
|
505
|
+
<Select
|
|
506
|
+
id="issue-labels"
|
|
507
|
+
mode="tags"
|
|
508
|
+
value={labels}
|
|
509
|
+
onValueChange={setLabels}
|
|
510
|
+
onCreate={(text) => setCreated((previous) => [...previous, text])}
|
|
511
|
+
allowCreate={(text) => text.length <= 12}
|
|
512
|
+
options={[
|
|
513
|
+
{ value: "bug", label: "Bug" },
|
|
514
|
+
{ value: "feature", label: "Feature" },
|
|
515
|
+
{ value: "docs", label: "Docs" },
|
|
516
|
+
]}
|
|
517
|
+
/>
|
|
518
|
+
</FormField>
|
|
519
|
+
</CardContent>
|
|
520
|
+
</Card>
|
|
521
|
+
|
|
484
522
|
<Card>
|
|
485
523
|
<CardHeader>
|
|
486
524
|
<CardTitle level={2}>labelInValue · 読み込み前でも名前が出る</CardTitle>
|
|
@@ -21,8 +21,10 @@ import {
|
|
|
21
21
|
TableHead,
|
|
22
22
|
TableHeader,
|
|
23
23
|
TableRow,
|
|
24
|
+
DataTable,
|
|
25
|
+
Tree,
|
|
24
26
|
} from "@godxjp/ui/data-display";
|
|
25
|
-
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
27
|
+
import { Breadcrumb, Flex, PageContainer, ResponsiveGrid } from "@godxjp/ui/layout";
|
|
26
28
|
|
|
27
29
|
/**
|
|
28
30
|
* Text + Heading — the typographic primitives. Use these INSTEAD of a hand-rolled
|
|
@@ -46,8 +48,15 @@ const headingTones = [
|
|
|
46
48
|
{ tone: "info", title: "システムメンテナンスのお知らせ" },
|
|
47
49
|
] as const;
|
|
48
50
|
|
|
51
|
+
type SuiteRow = { id: string; title: string };
|
|
52
|
+
|
|
49
53
|
export default function Demo() {
|
|
50
54
|
const { t } = useTranslation();
|
|
55
|
+
const longTitle = t("textExamples.ellipsisLongTitle");
|
|
56
|
+
const suiteRows: SuiteRow[] = [
|
|
57
|
+
{ id: "TS-0412", title: longTitle },
|
|
58
|
+
{ id: "TS-0413", title: t("textExamples.ellipsisShortTitle") },
|
|
59
|
+
];
|
|
51
60
|
return (
|
|
52
61
|
<PageContainer
|
|
53
62
|
title="Typography"
|
|
@@ -388,6 +397,80 @@ export default function Demo() {
|
|
|
388
397
|
</Flex>
|
|
389
398
|
</CardContent>
|
|
390
399
|
</Card>
|
|
400
|
+
<Card>
|
|
401
|
+
<CardHeader>
|
|
402
|
+
<CardTitle level={2}>{t("textExamples.ellipsisTitle")}</CardTitle>
|
|
403
|
+
<CardDescription>{t("textExamples.ellipsisDescription")}</CardDescription>
|
|
404
|
+
</CardHeader>
|
|
405
|
+
<CardContent>
|
|
406
|
+
<Flex direction="col" gap="md">
|
|
407
|
+
<ResponsiveGrid columns={{ sm: 2, lg: 3 }}>
|
|
408
|
+
<Flex direction="col" gap="xs">
|
|
409
|
+
<Text size="xs" tone="muted">
|
|
410
|
+
{t("textExamples.ellipsisPlain")}
|
|
411
|
+
</Text>
|
|
412
|
+
<Text ellipsis={{ tooltip: true }}>{longTitle}</Text>
|
|
413
|
+
</Flex>
|
|
414
|
+
<Flex direction="col" gap="xs">
|
|
415
|
+
<Text size="xs" tone="muted">
|
|
416
|
+
{t("textExamples.ellipsisLink")}
|
|
417
|
+
</Text>
|
|
418
|
+
<Text asChild link ellipsis={{ tooltip: true }}>
|
|
419
|
+
<a href="#typography">{longTitle}</a>
|
|
420
|
+
</Text>
|
|
421
|
+
</Flex>
|
|
422
|
+
<Flex direction="col" gap="xs">
|
|
423
|
+
<Text size="xs" tone="muted">
|
|
424
|
+
{t("textExamples.ellipsisTree")}
|
|
425
|
+
</Text>
|
|
426
|
+
<Tree
|
|
427
|
+
aria-label={t("textExamples.ellipsisTree")}
|
|
428
|
+
treeData={[
|
|
429
|
+
{
|
|
430
|
+
value: "suite",
|
|
431
|
+
label: longTitle,
|
|
432
|
+
children: [
|
|
433
|
+
{ value: "case-1", label: t("textExamples.ellipsisShortTitle") },
|
|
434
|
+
],
|
|
435
|
+
},
|
|
436
|
+
]}
|
|
437
|
+
defaultExpandedValues={["suite"]}
|
|
438
|
+
titleRender={(node) => <Text ellipsis={{ tooltip: true }}>{node.label}</Text>}
|
|
439
|
+
/>
|
|
440
|
+
</Flex>
|
|
441
|
+
</ResponsiveGrid>
|
|
442
|
+
<DataTable<SuiteRow>
|
|
443
|
+
label={t("textExamples.ellipsisTable")}
|
|
444
|
+
data={suiteRows}
|
|
445
|
+
getRowId={(row) => row.id}
|
|
446
|
+
columns={[
|
|
447
|
+
{ key: "id", header: "ID", width: "7rem", render: (row) => row.id },
|
|
448
|
+
{
|
|
449
|
+
key: "title",
|
|
450
|
+
header: (
|
|
451
|
+
<Text ellipsis={{ tooltip: true }}>
|
|
452
|
+
{t("textExamples.ellipsisLongHeader")}
|
|
453
|
+
</Text>
|
|
454
|
+
),
|
|
455
|
+
width: "12rem",
|
|
456
|
+
ellipsis: true,
|
|
457
|
+
sortable: true,
|
|
458
|
+
sorter: (a, b) => a.title.localeCompare(b.title),
|
|
459
|
+
render: (row) => <Text ellipsis={{ tooltip: true }}>{row.title}</Text>,
|
|
460
|
+
},
|
|
461
|
+
]}
|
|
462
|
+
/>
|
|
463
|
+
<Breadcrumb
|
|
464
|
+
ariaLabel={t("textExamples.ellipsisBreadcrumb")}
|
|
465
|
+
items={[
|
|
466
|
+
{ label: t("textExamples.ellipsisCrumbHome"), to: "#typography" },
|
|
467
|
+
{ label: longTitle, to: "#typography", ellipsis: true },
|
|
468
|
+
{ label: longTitle, ellipsis: true },
|
|
469
|
+
]}
|
|
470
|
+
/>
|
|
471
|
+
</Flex>
|
|
472
|
+
</CardContent>
|
|
473
|
+
</Card>
|
|
391
474
|
<Card>
|
|
392
475
|
<CardHeader>
|
|
393
476
|
<CardTitle level={2}>copyable · editable · 装飾</CardTitle>
|
|
@@ -6,7 +6,18 @@
|
|
|
6
6
|
"breakDescription": "An identifier with nowhere to break — an email address, a coupon code, a login ID — takes break=\"anywhere\", and the column stays inside the viewport even in a table cell. whitespace=\"pre-wrap\" is for newlines a person typed; it cannot wrap an identifier in a table cell.",
|
|
7
7
|
"breakColumnOwner": "Owner",
|
|
8
8
|
"breakColumnEmail": "Email address",
|
|
9
|
-
"breakSampleName": "Sato"
|
|
9
|
+
"breakSampleName": "Sato",
|
|
10
|
+
"ellipsisTitle": "ellipsis · the full text in a tooltip while it is cut",
|
|
11
|
+
"ellipsisDescription": "ellipsis={{ tooltip: true }} keeps one line and shows the whole text on hover and on keyboard focus of the control it sits in (the link, the tree item, the sort button). A title that fits shows no tooltip, and the Text never becomes a tab stop of its own.",
|
|
12
|
+
"ellipsisPlain": "Plain Text",
|
|
13
|
+
"ellipsisLink": "Text asChild · link",
|
|
14
|
+
"ellipsisTree": "Tree titleRender",
|
|
15
|
+
"ellipsisTable": "Test suites",
|
|
16
|
+
"ellipsisBreadcrumb": "Truncated breadcrumb",
|
|
17
|
+
"ellipsisCrumbHome": "Home",
|
|
18
|
+
"ellipsisLongTitle": "Q3 integration test · payment module · invoice re-issue scenarios and acceptance criteria review",
|
|
19
|
+
"ellipsisShortTitle": "Login smoke test",
|
|
20
|
+
"ellipsisLongHeader": "Latest run name (release candidate 2026-09)"
|
|
10
21
|
},
|
|
11
22
|
"themeShowcase": {
|
|
12
23
|
"page": {
|
|
@@ -532,6 +543,24 @@
|
|
|
532
543
|
"longIdTitle": "Long identifiers and +N",
|
|
533
544
|
"ledgerLabel": "Ledger ID",
|
|
534
545
|
"ledgerHelper": "A 71-character identifier still stays inside the control"
|
|
546
|
+
},
|
|
547
|
+
"select": {
|
|
548
|
+
"createTitle": "Tags: create row, onCreate and case-insensitive matching",
|
|
549
|
+
"createDescription": "Typed text that matches no option is offered as an explicit “Create” row. onCreate reports only invented text, never an option id. Typing “bug” finds “Bug” instead of creating a duplicate (caseSensitive restores exact matching). Unlike antd, the create row is labelled and text longer than 12 characters is refused through allowCreate.",
|
|
550
|
+
"createField": "Labels",
|
|
551
|
+
"createdHelper": "Created in this session: {list}",
|
|
552
|
+
"createdNone": "Nothing created yet"
|
|
553
|
+
},
|
|
554
|
+
"colorPicker": {
|
|
555
|
+
"presetsTitle": "Tag colour from a palette",
|
|
556
|
+
"presetsDescription": "presets — fixed swatch groups under the picker; each group collapses, and the free picker stays available.",
|
|
557
|
+
"paletteLabel": "Label colour",
|
|
558
|
+
"recommendedGroup": "Recommended",
|
|
559
|
+
"recentGroup": "Recently used",
|
|
560
|
+
"presetsOnlyTitle": "Palette only",
|
|
561
|
+
"presetsOnlyDescription": "panelRender returns only Presets — people pick from the palette and cannot type an arbitrary hex.",
|
|
562
|
+
"tagColorLabel": "Tag colour",
|
|
563
|
+
"tagColorHelper": "Arrow keys move between swatches; the selected one is announced."
|
|
535
564
|
}
|
|
536
565
|
},
|
|
537
566
|
"serviceLauncherShowcase": {
|
|
@@ -1469,5 +1498,22 @@
|
|
|
1469
1498
|
"other": "Load {count} more"
|
|
1470
1499
|
}
|
|
1471
1500
|
}
|
|
1501
|
+
},
|
|
1502
|
+
"progressDocs": {
|
|
1503
|
+
"testRun": {
|
|
1504
|
+
"passed": "Passed",
|
|
1505
|
+
"failed": "Failed",
|
|
1506
|
+
"blocked": "Blocked",
|
|
1507
|
+
"notRun": "Not run",
|
|
1508
|
+
"caption": "Regression suite — {total} cases"
|
|
1509
|
+
}
|
|
1510
|
+
},
|
|
1511
|
+
"breadcrumbExamples": {
|
|
1512
|
+
"ellipsisTitle": "ellipsis · a long segment on one line",
|
|
1513
|
+
"ellipsisDescription": "ellipsis on a segment keeps the trail on one line and cuts that label with \"…\"; the full label shows in a tooltip on hover and when the crumb link takes keyboard focus. antd Breadcrumb has no per-item ellipsis — the shape is Typography’s. PageContainer breadcrumb takes the same item field.",
|
|
1514
|
+
"ellipsisAria": "Truncated breadcrumb",
|
|
1515
|
+
"home": "Home",
|
|
1516
|
+
"longSuite": "Q3 integration test · payment module · invoice re-issue scenarios",
|
|
1517
|
+
"longSection": "Acceptance criteria review for the release candidate of September 2026"
|
|
1472
1518
|
}
|
|
1473
1519
|
}
|