@godxjp/ui 27.6.0 → 27.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/dist/components/data-display/range-timeline.d.ts +24 -0
- package/dist/components/data-display/range-timeline.js +191 -92
- package/dist/components/layout/topbar-item.d.ts +2 -0
- package/dist/components/layout/topbar-item.js +34 -4
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +1 -0
- package/dist/i18n/messages/ja.json +1 -0
- package/dist/i18n/messages/vi.json +1 -0
- package/dist/props/components/layout.prop.d.ts +16 -0
- package/dist/props/registry.d.ts +21 -1
- package/dist/props/registry.js +28 -2
- package/dist/styles/data-display-layout.css +30 -0
- package/dist/styles/layout.css +60 -4
- package/dist/tokens/components/data-display.css +2 -0
- package/docs/DESIGN-AUTHORITY.md +17 -0
- package/docs/data-display/timeline.tsx +41 -0
- package/docs/layout/topbar-item.tsx +37 -0
- package/package.json +2 -2
|
@@ -6,6 +6,12 @@ export type RangeTimelineRow = {
|
|
|
6
6
|
end: number;
|
|
7
7
|
startLabel: string;
|
|
8
8
|
endLabel: string;
|
|
9
|
+
/**
|
|
10
|
+
* Nesting level, 0 for a top-level row. Rows arrive flat and depth-first (a parent, then its
|
|
11
|
+
* descendants); a row is a parent when the row after it is deeper. The component draws the
|
|
12
|
+
* indent (`--range-timeline-indent-width` per level) and the disclosure.
|
|
13
|
+
*/
|
|
14
|
+
depth?: number;
|
|
9
15
|
};
|
|
10
16
|
export type RangeTimelineProps = React.HTMLAttributes<HTMLElement> & {
|
|
11
17
|
label: string;
|
|
@@ -28,6 +34,15 @@ export type RangeTimelineProps = React.HTMLAttributes<HTMLElement> & {
|
|
|
28
34
|
* the header-only ruling. Colour `--range-timeline-grid-color`, weight `--range-timeline-grid-width`.
|
|
29
35
|
*/
|
|
30
36
|
bordered?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Controlled ids of the EXPANDED parent rows (same spelling as `Tree expandedValues`). A folded
|
|
39
|
+
* parent hides every descendant row — label and bar.
|
|
40
|
+
*/
|
|
41
|
+
expandedValues?: readonly string[];
|
|
42
|
+
/** Uncontrolled initial expanded parents. Omitted: every parent starts expanded. */
|
|
43
|
+
defaultExpandedValues?: readonly string[];
|
|
44
|
+
/** Fires with the next expanded parent ids, for controlled and uncontrolled timelines alike. */
|
|
45
|
+
onExpandedValuesChange?: (values: string[]) => void;
|
|
31
46
|
};
|
|
32
47
|
/** A horizontal range axis. Units and labels are data; the design system owns all geometry. */
|
|
33
48
|
export declare const RangeTimeline: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
|
|
@@ -51,4 +66,13 @@ export declare const RangeTimeline: React.ForwardRefExoticComponent<React.HTMLAt
|
|
|
51
66
|
* the header-only ruling. Colour `--range-timeline-grid-color`, weight `--range-timeline-grid-width`.
|
|
52
67
|
*/
|
|
53
68
|
bordered?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Controlled ids of the EXPANDED parent rows (same spelling as `Tree expandedValues`). A folded
|
|
71
|
+
* parent hides every descendant row — label and bar.
|
|
72
|
+
*/
|
|
73
|
+
expandedValues?: readonly string[];
|
|
74
|
+
/** Uncontrolled initial expanded parents. Omitted: every parent starts expanded. */
|
|
75
|
+
defaultExpandedValues?: readonly string[];
|
|
76
|
+
/** Fires with the next expanded parent ids, for controlled and uncontrolled timelines alike. */
|
|
77
|
+
onExpandedValuesChange?: (values: string[]) => void;
|
|
54
78
|
} & React.RefAttributes<HTMLElement>>;
|
|
@@ -2,13 +2,67 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
5
|
-
import { ChevronLeft, ChevronRight, GripVertical } from "lucide-react";
|
|
5
|
+
import { ChevronDown, ChevronLeft, ChevronRight, GripVertical } from "lucide-react";
|
|
6
6
|
import { Button } from "../general/button.js";
|
|
7
7
|
import { Text } from "../general/typography.js";
|
|
8
8
|
import { cn } from "../../lib/utils.js";
|
|
9
9
|
const RangeTimeline = React.forwardRef(
|
|
10
|
-
function RangeTimeline2({
|
|
10
|
+
function RangeTimeline2({
|
|
11
|
+
label,
|
|
12
|
+
columns,
|
|
13
|
+
bands,
|
|
14
|
+
rows,
|
|
15
|
+
today,
|
|
16
|
+
onRangeChange,
|
|
17
|
+
bordered = true,
|
|
18
|
+
expandedValues,
|
|
19
|
+
defaultExpandedValues,
|
|
20
|
+
onExpandedValuesChange,
|
|
21
|
+
className,
|
|
22
|
+
...props
|
|
23
|
+
}, ref) {
|
|
11
24
|
const { t } = useTranslation();
|
|
25
|
+
const reactId = React.useId();
|
|
26
|
+
const depthOf = (row) => Math.max(0, Math.floor(row.depth ?? 0));
|
|
27
|
+
const nested = rows.some((row) => depthOf(row) > 0);
|
|
28
|
+
const parents = rows.filter((row, index) => index + 1 < rows.length && depthOf(rows[index + 1]) > depthOf(row)).map((row) => row.id);
|
|
29
|
+
const [collapsed, setCollapsed] = React.useState(
|
|
30
|
+
() => new Set(
|
|
31
|
+
defaultExpandedValues ? parents.filter((id) => !defaultExpandedValues.includes(id)) : []
|
|
32
|
+
)
|
|
33
|
+
);
|
|
34
|
+
const isExpanded = (id) => expandedValues ? expandedValues.includes(id) : !collapsed.has(id);
|
|
35
|
+
const toggleRow = (id) => {
|
|
36
|
+
const open = !isExpanded(id);
|
|
37
|
+
if (!expandedValues) {
|
|
38
|
+
const next = new Set(collapsed);
|
|
39
|
+
if (open) next.delete(id);
|
|
40
|
+
else next.add(id);
|
|
41
|
+
setCollapsed(next);
|
|
42
|
+
}
|
|
43
|
+
onExpandedValuesChange?.(
|
|
44
|
+
parents.filter((parent) => parent === id ? open : isExpanded(parent))
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
let foldedAt = null;
|
|
48
|
+
const visibleRows = rows.filter((row) => {
|
|
49
|
+
const depth = depthOf(row);
|
|
50
|
+
if (foldedAt !== null && depth > foldedAt) return false;
|
|
51
|
+
foldedAt = parents.includes(row.id) && !isExpanded(row.id) ? depth : null;
|
|
52
|
+
return true;
|
|
53
|
+
});
|
|
54
|
+
const siblingsOf = (index) => {
|
|
55
|
+
const depth = depthOf(visibleRows[index]);
|
|
56
|
+
let first = index;
|
|
57
|
+
while (first > 0 && depthOf(visibleRows[first - 1]) >= depth) first -= 1;
|
|
58
|
+
let size = 0, position = 0;
|
|
59
|
+
for (let i = first; i < visibleRows.length && depthOf(visibleRows[i]) >= depth; i += 1) {
|
|
60
|
+
if (depthOf(visibleRows[i]) !== depth) continue;
|
|
61
|
+
size += 1;
|
|
62
|
+
if (i === index) position = size;
|
|
63
|
+
}
|
|
64
|
+
return { size, position };
|
|
65
|
+
};
|
|
12
66
|
const units = Math.max(
|
|
13
67
|
1,
|
|
14
68
|
columns.reduce((sum, column) => sum + column.units, 0)
|
|
@@ -73,7 +127,7 @@ const RangeTimeline = React.forwardRef(
|
|
|
73
127
|
index
|
|
74
128
|
)) })
|
|
75
129
|
] }),
|
|
76
|
-
/* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-body", children: [
|
|
130
|
+
/* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-body", role: nested ? "list" : void 0, children: [
|
|
77
131
|
(bordered || columns.some((column) => column.muted)) && // Decorative: the same unit tracks as the header columns, laid once behind every row so
|
|
78
132
|
// each vertical rule runs the full body height exactly under its header column.
|
|
79
133
|
/* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-grid", "aria-hidden": "true", children: [
|
|
@@ -88,103 +142,148 @@ const RangeTimeline = React.forwardRef(
|
|
|
88
142
|
index
|
|
89
143
|
)) })
|
|
90
144
|
] }),
|
|
91
|
-
|
|
145
|
+
visibleRows.map((row, index) => {
|
|
146
|
+
const idBase = `${reactId}-row-${rows.indexOf(row)}`;
|
|
92
147
|
const delta = preview?.id === row.id ? preview.delta : 0;
|
|
93
148
|
const start = Math.min(row.end, row.start + (preview?.edge === "start" ? delta : 0));
|
|
94
149
|
const end = Math.max(row.start, row.end + (preview?.edge === "end" ? delta : 0));
|
|
95
150
|
const left = Math.max(0, start), right = Math.min(units, end + 1);
|
|
96
|
-
return /* @__PURE__ */ jsxs(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
ChevronLeft,
|
|
110
|
-
{
|
|
111
|
-
"aria-hidden": "true",
|
|
112
|
-
className: "ui-range-timeline-outside-icon"
|
|
113
|
-
}
|
|
114
|
-
),
|
|
115
|
-
/* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", children: t("rangeTimeline.outsideBefore") })
|
|
116
|
-
] }) : /* @__PURE__ */ jsxs("span", { className: "ui-range-timeline-outside", "data-direction": "after", children: [
|
|
117
|
-
/* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", children: t("rangeTimeline.outsideAfter") }),
|
|
118
|
-
/* @__PURE__ */ jsx(
|
|
119
|
-
ChevronRight,
|
|
151
|
+
return /* @__PURE__ */ jsxs(
|
|
152
|
+
"div",
|
|
153
|
+
{
|
|
154
|
+
className: "ui-range-timeline-row",
|
|
155
|
+
...nested && {
|
|
156
|
+
role: "listitem",
|
|
157
|
+
"aria-level": depthOf(row) + 1,
|
|
158
|
+
"aria-setsize": siblingsOf(index).size,
|
|
159
|
+
"aria-posinset": siblingsOf(index).position
|
|
160
|
+
},
|
|
161
|
+
children: [
|
|
162
|
+
nested ? /* @__PURE__ */ jsxs(
|
|
163
|
+
"div",
|
|
120
164
|
{
|
|
121
|
-
|
|
122
|
-
|
|
165
|
+
className: "ui-range-timeline-label",
|
|
166
|
+
"data-nested": "true",
|
|
167
|
+
style: { "--range-timeline-depth": depthOf(row) },
|
|
168
|
+
children: [
|
|
169
|
+
parents.includes(row.id) ? /* @__PURE__ */ jsxs(
|
|
170
|
+
Button,
|
|
171
|
+
{
|
|
172
|
+
variant: "ghost",
|
|
173
|
+
size: "icon-xs",
|
|
174
|
+
className: "ui-range-timeline-disclosure",
|
|
175
|
+
"aria-expanded": isExpanded(row.id),
|
|
176
|
+
"aria-labelledby": `${idBase}-toggle ${idBase}-label`,
|
|
177
|
+
onClick: () => toggleRow(row.id),
|
|
178
|
+
children: [
|
|
179
|
+
/* @__PURE__ */ jsx("span", { id: `${idBase}-toggle`, hidden: true, children: t("rangeTimeline.childRows") }),
|
|
180
|
+
isExpanded(row.id) ? /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(
|
|
181
|
+
ChevronRight,
|
|
182
|
+
{
|
|
183
|
+
"aria-hidden": "true",
|
|
184
|
+
className: "ui-range-timeline-disclosure-collapsed"
|
|
185
|
+
}
|
|
186
|
+
)
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ui-range-timeline-disclosure-spacer" }),
|
|
190
|
+
/* @__PURE__ */ jsx("div", { id: `${idBase}-label`, className: "ui-range-timeline-label-content", children: row.label })
|
|
191
|
+
]
|
|
123
192
|
}
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
{
|
|
129
|
-
className: "ui-range-timeline-bar",
|
|
130
|
-
style: {
|
|
131
|
-
insetInlineStart: `${left / units * 100}%`,
|
|
132
|
-
inlineSize: `${(right - left) / units * 100}%`
|
|
133
|
-
},
|
|
134
|
-
children: onRangeChange && (right - left) * Math.max(1, columns.length) >= units && ["start", "end"].filter(
|
|
135
|
-
(edge) => edge === "start" ? start >= 0 && start < units : end >= 0 && end < units
|
|
136
|
-
).map((edge) => /* @__PURE__ */ jsx(
|
|
137
|
-
Button,
|
|
193
|
+
) : /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-label", children: row.label }),
|
|
194
|
+
/* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-track", children: [
|
|
195
|
+
today != null && today >= 0 && today < units && /* @__PURE__ */ jsx(
|
|
196
|
+
"span",
|
|
138
197
|
{
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
const step = event.key === "ArrowRight" ? 1 : event.key === "ArrowLeft" ? -1 : 0;
|
|
173
|
-
if (!step) return;
|
|
174
|
-
event.preventDefault();
|
|
175
|
-
const direction = getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1;
|
|
176
|
-
const delta2 = step * direction;
|
|
177
|
-
if (edge === "start" ? row.start + delta2 <= row.end : row.end + delta2 >= row.start)
|
|
178
|
-
onRangeChange(row.id, edge, delta2);
|
|
198
|
+
"aria-hidden": "true",
|
|
199
|
+
className: "ui-range-timeline-today",
|
|
200
|
+
style: { insetInlineStart: `${(today + 0.5) / units * 100}%` }
|
|
201
|
+
}
|
|
202
|
+
),
|
|
203
|
+
right <= left && (end < 0 ? /* @__PURE__ */ jsxs("span", { className: "ui-range-timeline-outside", "data-direction": "before", children: [
|
|
204
|
+
/* @__PURE__ */ jsx(
|
|
205
|
+
ChevronLeft,
|
|
206
|
+
{
|
|
207
|
+
"aria-hidden": "true",
|
|
208
|
+
className: "ui-range-timeline-outside-icon"
|
|
209
|
+
}
|
|
210
|
+
),
|
|
211
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", children: t("rangeTimeline.outsideBefore") })
|
|
212
|
+
] }) : /* @__PURE__ */ jsxs("span", { className: "ui-range-timeline-outside", "data-direction": "after", children: [
|
|
213
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", children: t("rangeTimeline.outsideAfter") }),
|
|
214
|
+
/* @__PURE__ */ jsx(
|
|
215
|
+
ChevronRight,
|
|
216
|
+
{
|
|
217
|
+
"aria-hidden": "true",
|
|
218
|
+
className: "ui-range-timeline-outside-icon"
|
|
219
|
+
}
|
|
220
|
+
)
|
|
221
|
+
] })),
|
|
222
|
+
right > left && /* @__PURE__ */ jsx(
|
|
223
|
+
"div",
|
|
224
|
+
{
|
|
225
|
+
className: "ui-range-timeline-bar",
|
|
226
|
+
style: {
|
|
227
|
+
insetInlineStart: `${left / units * 100}%`,
|
|
228
|
+
inlineSize: `${(right - left) / units * 100}%`
|
|
179
229
|
},
|
|
180
|
-
children:
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
230
|
+
children: onRangeChange && (right - left) * Math.max(1, columns.length) >= units && ["start", "end"].filter(
|
|
231
|
+
(edge) => edge === "start" ? start >= 0 && start < units : end >= 0 && end < units
|
|
232
|
+
).map((edge) => /* @__PURE__ */ jsx(
|
|
233
|
+
Button,
|
|
234
|
+
{
|
|
235
|
+
variant: "ghost",
|
|
236
|
+
size: "icon-xs",
|
|
237
|
+
className: "ui-range-timeline-handle",
|
|
238
|
+
"data-edge": edge,
|
|
239
|
+
"aria-label": edge === "start" ? row.startLabel : row.endLabel,
|
|
240
|
+
onPointerDown: (event) => {
|
|
241
|
+
const width = track.current?.getBoundingClientRect().width ?? 0;
|
|
242
|
+
if (!width || event.button !== 0) return;
|
|
243
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
244
|
+
drag.current = {
|
|
245
|
+
id: row.id,
|
|
246
|
+
edge,
|
|
247
|
+
x: event.clientX,
|
|
248
|
+
width,
|
|
249
|
+
direction: getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1
|
|
250
|
+
};
|
|
251
|
+
},
|
|
252
|
+
onPointerMove: (event) => {
|
|
253
|
+
if (drag.current)
|
|
254
|
+
setPreview({
|
|
255
|
+
id: drag.current.id,
|
|
256
|
+
edge: drag.current.edge,
|
|
257
|
+
delta: deltaAt(event.clientX)
|
|
258
|
+
});
|
|
259
|
+
},
|
|
260
|
+
onPointerUp: complete,
|
|
261
|
+
onPointerCancel: cancel,
|
|
262
|
+
onLostPointerCapture: cancel,
|
|
263
|
+
onKeyDown: (event) => {
|
|
264
|
+
if (event.key === "Escape") {
|
|
265
|
+
cancel();
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const step = event.key === "ArrowRight" ? 1 : event.key === "ArrowLeft" ? -1 : 0;
|
|
269
|
+
if (!step) return;
|
|
270
|
+
event.preventDefault();
|
|
271
|
+
const direction = getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1;
|
|
272
|
+
const delta2 = step * direction;
|
|
273
|
+
if (edge === "start" ? row.start + delta2 <= row.end : row.end + delta2 >= row.start)
|
|
274
|
+
onRangeChange(row.id, edge, delta2);
|
|
275
|
+
},
|
|
276
|
+
children: /* @__PURE__ */ jsx(GripVertical, { "aria-hidden": "true" })
|
|
277
|
+
},
|
|
278
|
+
edge
|
|
279
|
+
))
|
|
280
|
+
}
|
|
281
|
+
)
|
|
282
|
+
] })
|
|
283
|
+
]
|
|
284
|
+
},
|
|
285
|
+
row.id
|
|
286
|
+
);
|
|
188
287
|
})
|
|
189
288
|
] })
|
|
190
289
|
]
|
|
@@ -13,6 +13,8 @@ export type { TopbarItemProp, TopbarItemProp as TopbarItemProps, } from "../../p
|
|
|
13
13
|
export declare const TopbarItem: React.ForwardRefExoticComponent<Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "children"> & {
|
|
14
14
|
hideBelow?: import("../../props/index.js").BreakpointProp;
|
|
15
15
|
icon?: React.ReactNode;
|
|
16
|
+
iconHideFrom?: import("../../props/index.js").BreakpointProp;
|
|
17
|
+
labelHideBelow?: import("../../props/index.js").BreakpointProp;
|
|
16
18
|
badge?: React.ReactNode;
|
|
17
19
|
badgeTone?: import("../../props/components/layout.prop.js").SidebarBadgeToneProp;
|
|
18
20
|
asChild?: boolean;
|
|
@@ -2,10 +2,40 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { Slot } from "../../lib/slot.js";
|
|
4
4
|
import { cn } from "../../lib/utils.js";
|
|
5
|
-
const TopbarItem = React.forwardRef(function TopbarItem2({
|
|
5
|
+
const TopbarItem = React.forwardRef(function TopbarItem2({
|
|
6
|
+
asChild = false,
|
|
7
|
+
className,
|
|
8
|
+
type,
|
|
9
|
+
hideBelow,
|
|
10
|
+
icon,
|
|
11
|
+
iconHideFrom,
|
|
12
|
+
labelHideBelow,
|
|
13
|
+
badge,
|
|
14
|
+
badgeTone,
|
|
15
|
+
children,
|
|
16
|
+
...props
|
|
17
|
+
}, ref) {
|
|
6
18
|
const Comp = asChild ? Slot : "button";
|
|
7
19
|
const showBadge = !asChild && badge !== void 0 && badge !== "";
|
|
8
|
-
const iconNode =
|
|
20
|
+
const iconNode = icon !== void 0 && icon !== null && icon !== false ? /* @__PURE__ */ jsx(
|
|
21
|
+
"span",
|
|
22
|
+
{
|
|
23
|
+
"data-slot": "topbar-item-icon",
|
|
24
|
+
className: "ui-topbar-item-icon",
|
|
25
|
+
"data-hide-from": iconHideFrom,
|
|
26
|
+
children: icon
|
|
27
|
+
}
|
|
28
|
+
) : null;
|
|
29
|
+
const labelOf = (label) => labelHideBelow === void 0 || label === void 0 || label === null || label === false ? label : /* @__PURE__ */ jsx(
|
|
30
|
+
"span",
|
|
31
|
+
{
|
|
32
|
+
"data-slot": "topbar-item-label",
|
|
33
|
+
className: "ui-topbar-item-label",
|
|
34
|
+
"data-hide-below": labelHideBelow,
|
|
35
|
+
children: label
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
const slotted = asChild && (iconNode !== null || labelHideBelow !== void 0) && React.isValidElement(children) ? React.cloneElement(children, void 0, iconNode, labelOf(children.props.children)) : children;
|
|
9
39
|
const badgeNode = showBadge ? /* @__PURE__ */ jsx(
|
|
10
40
|
"span",
|
|
11
41
|
{
|
|
@@ -24,9 +54,9 @@ const TopbarItem = React.forwardRef(function TopbarItem2({ asChild = false, clas
|
|
|
24
54
|
className: cn("ui-topbar-item ui-focus-ring", className),
|
|
25
55
|
type: asChild ? void 0 : type ?? "button",
|
|
26
56
|
...props,
|
|
27
|
-
children: asChild ?
|
|
57
|
+
children: asChild ? slotted : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
28
58
|
iconNode,
|
|
29
|
-
children,
|
|
59
|
+
labelOf(children),
|
|
30
60
|
badgeNode
|
|
31
61
|
] })
|
|
32
62
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "AUTO-GENERATED by scripts/gen-measurement-contract.mjs — do not edit. Read this instead of guessing: docs/MEASUREMENT-CONTRACT.md.",
|
|
3
|
-
"version": "27.
|
|
3
|
+
"version": "27.8.0",
|
|
4
4
|
"targetSize": {
|
|
5
5
|
"standard": "WCAG 2.2 SC 2.5.8 Target Size (Minimum), level AA — 24×24 CSS px",
|
|
6
6
|
"min": 24,
|
|
@@ -1354,8 +1354,24 @@ export type TopbarItemProp = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
|
1354
1354
|
* visible label, not from the glyph. For a glyph that must carry a name, or one that needs a
|
|
1355
1355
|
* step other than the bar's, pass `<Icon as={…} size=… label=… />` — as this prop's value or as
|
|
1356
1356
|
* a child — and it keeps its own metric and its own semantics.
|
|
1357
|
+
*
|
|
1358
|
+
* Rendered under `asChild` too: the slot is inserted ahead of the child element's own children,
|
|
1359
|
+
* and the child element stays the cell (gh#726).
|
|
1357
1360
|
*/
|
|
1358
1361
|
icon?: ReactNode;
|
|
1362
|
+
/**
|
|
1363
|
+
* Drop the `icon` slot FROM a breakpoint step upwards — `Flex hideFrom`'s contract, scoped to
|
|
1364
|
+
* the cell's glyph, so a cell reads label-only on a wide bar without the consumer wrapping the
|
|
1365
|
+
* glyph (gh#726). Purely decorative: the accessible name is unaffected.
|
|
1366
|
+
*/
|
|
1367
|
+
iconHideFrom?: BreakpointProp;
|
|
1368
|
+
/**
|
|
1369
|
+
* Visually hide the cell's label BELOW a breakpoint step — `Flex hideBelow`'s contract, scoped to
|
|
1370
|
+
* the label — so the cell collapses to icon-only on a narrow bar (gh#726). The label stays in the
|
|
1371
|
+
* accessibility tree (visually hidden, not `display: none`), so the collapsed cell keeps its
|
|
1372
|
+
* accessible name. Under `asChild` the child element's own children are the label.
|
|
1373
|
+
*/
|
|
1374
|
+
labelHideBelow?: BreakpointProp;
|
|
1359
1375
|
/**
|
|
1360
1376
|
* Unread count OVERLAID on the cell's glyph — the notification-bell affordance the cell's own use
|
|
1361
1377
|
* cases name (gh#398). Pass the CONTENT ONLY, exactly like `SidebarItemProp.badge`: a number, a
|
package/dist/props/registry.d.ts
CHANGED
|
@@ -1187,6 +1187,14 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
1187
1187
|
readonly field: "asChild";
|
|
1188
1188
|
readonly local: true;
|
|
1189
1189
|
readonly reason: "Radix Slot passthrough — merges onto the child";
|
|
1190
|
+
}, "BreakpointProp", {
|
|
1191
|
+
readonly field: "iconHideFrom";
|
|
1192
|
+
readonly local: true;
|
|
1193
|
+
readonly reason: "Flex `hideFrom` scoped to the cell's icon slot — label-only from a breakpoint up without hand-wrapping the glyph (gh#726).";
|
|
1194
|
+
}, {
|
|
1195
|
+
readonly field: "labelHideBelow";
|
|
1196
|
+
readonly local: true;
|
|
1197
|
+
readonly reason: "Flex `hideBelow` scoped to the cell's label — icon-only below a breakpoint; visually hidden so the accessible name survives (gh#726).";
|
|
1190
1198
|
}];
|
|
1191
1199
|
};
|
|
1192
1200
|
readonly NavListProp: {
|
|
@@ -2950,7 +2958,7 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
2950
2958
|
}, {
|
|
2951
2959
|
readonly field: "rows";
|
|
2952
2960
|
readonly local: true;
|
|
2953
|
-
readonly reason: "Consumer-supplied interval records preserve true inclusive endpoints independently of clipping.";
|
|
2961
|
+
readonly reason: "Consumer-supplied interval records preserve true inclusive endpoints independently of clipping; optional `depth` nests them (flat, depth-first; a row is a parent when the next row is deeper).";
|
|
2954
2962
|
}, {
|
|
2955
2963
|
readonly field: "today";
|
|
2956
2964
|
readonly local: true;
|
|
@@ -2959,6 +2967,18 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
2959
2967
|
readonly field: "onRangeChange";
|
|
2960
2968
|
readonly local: true;
|
|
2961
2969
|
readonly reason: "An endpoint movement command, not an internally owned value; the consumer commits its row data.";
|
|
2970
|
+
}, {
|
|
2971
|
+
readonly field: "expandedValues";
|
|
2972
|
+
readonly local: true;
|
|
2973
|
+
readonly reason: "Controlled expanded parent row ids (gh#724) — the same spelling as `Tree expandedValues` (antd `expandedKeys` / Table `expandedRowKeys`), per docs/DESIGN-AUTHORITY.md.";
|
|
2974
|
+
}, {
|
|
2975
|
+
readonly field: "defaultExpandedValues";
|
|
2976
|
+
readonly local: true;
|
|
2977
|
+
readonly reason: "Uncontrolled initial expanded parents, same spelling as `Tree`; omitted, every parent starts expanded so adding `depth` never hides a row.";
|
|
2978
|
+
}, {
|
|
2979
|
+
readonly field: "onExpandedValuesChange";
|
|
2980
|
+
readonly local: true;
|
|
2981
|
+
readonly reason: "Next expanded parent ids, fired for controlled and uncontrolled timelines alike — the `Tree onExpandedValuesChange` callback.";
|
|
2962
2982
|
}];
|
|
2963
2983
|
};
|
|
2964
2984
|
readonly ResponsiveGridProp: {
|
package/dist/props/registry.js
CHANGED
|
@@ -1284,7 +1284,18 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
1284
1284
|
vocabulary: [
|
|
1285
1285
|
"ChildrenProp",
|
|
1286
1286
|
"ClassNameProp",
|
|
1287
|
-
{ field: "asChild", local: true, reason: "Radix Slot passthrough \u2014 merges onto the child" }
|
|
1287
|
+
{ field: "asChild", local: true, reason: "Radix Slot passthrough \u2014 merges onto the child" },
|
|
1288
|
+
"BreakpointProp",
|
|
1289
|
+
{
|
|
1290
|
+
field: "iconHideFrom",
|
|
1291
|
+
local: true,
|
|
1292
|
+
reason: "Flex `hideFrom` scoped to the cell's icon slot \u2014 label-only from a breakpoint up without hand-wrapping the glyph (gh#726)."
|
|
1293
|
+
},
|
|
1294
|
+
{
|
|
1295
|
+
field: "labelHideBelow",
|
|
1296
|
+
local: true,
|
|
1297
|
+
reason: "Flex `hideBelow` scoped to the cell's label \u2014 icon-only below a breakpoint; visually hidden so the accessible name survives (gh#726)."
|
|
1298
|
+
}
|
|
1288
1299
|
]
|
|
1289
1300
|
},
|
|
1290
1301
|
NavListProp: {
|
|
@@ -3460,7 +3471,7 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
3460
3471
|
{
|
|
3461
3472
|
field: "rows",
|
|
3462
3473
|
local: true,
|
|
3463
|
-
reason: "Consumer-supplied interval records preserve true inclusive endpoints independently of clipping."
|
|
3474
|
+
reason: "Consumer-supplied interval records preserve true inclusive endpoints independently of clipping; optional `depth` nests them (flat, depth-first; a row is a parent when the next row is deeper)."
|
|
3464
3475
|
},
|
|
3465
3476
|
{
|
|
3466
3477
|
field: "today",
|
|
@@ -3471,6 +3482,21 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
3471
3482
|
field: "onRangeChange",
|
|
3472
3483
|
local: true,
|
|
3473
3484
|
reason: "An endpoint movement command, not an internally owned value; the consumer commits its row data."
|
|
3485
|
+
},
|
|
3486
|
+
{
|
|
3487
|
+
field: "expandedValues",
|
|
3488
|
+
local: true,
|
|
3489
|
+
reason: "Controlled expanded parent row ids (gh#724) \u2014 the same spelling as `Tree expandedValues` (antd `expandedKeys` / Table `expandedRowKeys`), per docs/DESIGN-AUTHORITY.md."
|
|
3490
|
+
},
|
|
3491
|
+
{
|
|
3492
|
+
field: "defaultExpandedValues",
|
|
3493
|
+
local: true,
|
|
3494
|
+
reason: "Uncontrolled initial expanded parents, same spelling as `Tree`; omitted, every parent starts expanded so adding `depth` never hides a row."
|
|
3495
|
+
},
|
|
3496
|
+
{
|
|
3497
|
+
field: "onExpandedValuesChange",
|
|
3498
|
+
local: true,
|
|
3499
|
+
reason: "Next expanded parent ids, fired for controlled and uncontrolled timelines alike \u2014 the `Tree onExpandedValuesChange` callback."
|
|
3474
3500
|
}
|
|
3475
3501
|
]
|
|
3476
3502
|
},
|
|
@@ -1454,6 +1454,36 @@
|
|
|
1454
1454
|
inset-block: 0;
|
|
1455
1455
|
border-inline-start: 1px solid hsl(var(--primary));
|
|
1456
1456
|
}
|
|
1457
|
+
|
|
1458
|
+
.ui-range-timeline-label[data-nested="true"] {
|
|
1459
|
+
display: flex;
|
|
1460
|
+
align-items: center;
|
|
1461
|
+
gap: var(--space-1);
|
|
1462
|
+
padding-inline-start: calc(
|
|
1463
|
+
var(--space-2) + var(--range-timeline-depth, 0) * var(--range-timeline-indent-width)
|
|
1464
|
+
);
|
|
1465
|
+
}
|
|
1466
|
+
.ui-range-timeline-label-content {
|
|
1467
|
+
flex: 1;
|
|
1468
|
+
min-inline-size: 0;
|
|
1469
|
+
}
|
|
1470
|
+
.ui-range-timeline-disclosure,
|
|
1471
|
+
.ui-range-timeline-disclosure-spacer {
|
|
1472
|
+
flex-shrink: 0;
|
|
1473
|
+
}
|
|
1474
|
+
.ui-range-timeline-disclosure-spacer {
|
|
1475
|
+
inline-size: var(--control-height-xs);
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
@media (pointer: coarse) {
|
|
1479
|
+
.ui-range-timeline-disclosure-spacer {
|
|
1480
|
+
inline-size: var(--control-height-default);
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
[dir="rtl"] .ui-range-timeline-disclosure-collapsed {
|
|
1485
|
+
transform: scaleX(-1);
|
|
1486
|
+
}
|
|
1457
1487
|
}
|
|
1458
1488
|
|
|
1459
1489
|
@layer components {
|
package/dist/styles/layout.css
CHANGED
|
@@ -1485,28 +1485,84 @@
|
|
|
1485
1485
|
}
|
|
1486
1486
|
|
|
1487
1487
|
@media (width >= 40rem) {
|
|
1488
|
-
.ui-flex[data-hide-from="sm"]
|
|
1488
|
+
.ui-flex[data-hide-from="sm"],
|
|
1489
|
+
.ui-topbar-item-icon[data-hide-from="sm"] {
|
|
1489
1490
|
display: none;
|
|
1490
1491
|
}
|
|
1491
1492
|
}
|
|
1492
1493
|
|
|
1493
1494
|
@media (width >= 48rem) {
|
|
1494
|
-
.ui-flex[data-hide-from="md"]
|
|
1495
|
+
.ui-flex[data-hide-from="md"],
|
|
1496
|
+
.ui-topbar-item-icon[data-hide-from="md"] {
|
|
1495
1497
|
display: none;
|
|
1496
1498
|
}
|
|
1497
1499
|
}
|
|
1498
1500
|
|
|
1499
1501
|
@media (width >= 64rem) {
|
|
1500
|
-
.ui-flex[data-hide-from="lg"]
|
|
1502
|
+
.ui-flex[data-hide-from="lg"],
|
|
1503
|
+
.ui-topbar-item-icon[data-hide-from="lg"] {
|
|
1501
1504
|
display: none;
|
|
1502
1505
|
}
|
|
1503
1506
|
}
|
|
1504
1507
|
|
|
1505
1508
|
@media (width >= 80rem) {
|
|
1506
|
-
.ui-flex[data-hide-from="xl"]
|
|
1509
|
+
.ui-flex[data-hide-from="xl"],
|
|
1510
|
+
.ui-topbar-item-icon[data-hide-from="xl"] {
|
|
1507
1511
|
display: none;
|
|
1508
1512
|
}
|
|
1509
1513
|
}
|
|
1514
|
+
|
|
1515
|
+
@media (width < 40rem) {
|
|
1516
|
+
.ui-topbar-item-label[data-hide-below="sm"] {
|
|
1517
|
+
position: absolute;
|
|
1518
|
+
inset-block-start: 0;
|
|
1519
|
+
inset-inline-start: 0;
|
|
1520
|
+
inline-size: var(--stroke-hairline);
|
|
1521
|
+
block-size: var(--stroke-hairline);
|
|
1522
|
+
overflow: hidden;
|
|
1523
|
+
clip-path: inset(50%);
|
|
1524
|
+
white-space: nowrap;
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
@media (width < 48rem) {
|
|
1529
|
+
.ui-topbar-item-label[data-hide-below="md"] {
|
|
1530
|
+
position: absolute;
|
|
1531
|
+
inset-block-start: 0;
|
|
1532
|
+
inset-inline-start: 0;
|
|
1533
|
+
inline-size: var(--stroke-hairline);
|
|
1534
|
+
block-size: var(--stroke-hairline);
|
|
1535
|
+
overflow: hidden;
|
|
1536
|
+
clip-path: inset(50%);
|
|
1537
|
+
white-space: nowrap;
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
@media (width < 64rem) {
|
|
1542
|
+
.ui-topbar-item-label[data-hide-below="lg"] {
|
|
1543
|
+
position: absolute;
|
|
1544
|
+
inset-block-start: 0;
|
|
1545
|
+
inset-inline-start: 0;
|
|
1546
|
+
inline-size: var(--stroke-hairline);
|
|
1547
|
+
block-size: var(--stroke-hairline);
|
|
1548
|
+
overflow: hidden;
|
|
1549
|
+
clip-path: inset(50%);
|
|
1550
|
+
white-space: nowrap;
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
@media (width < 80rem) {
|
|
1555
|
+
.ui-topbar-item-label[data-hide-below="xl"] {
|
|
1556
|
+
position: absolute;
|
|
1557
|
+
inset-block-start: 0;
|
|
1558
|
+
inset-inline-start: 0;
|
|
1559
|
+
inline-size: var(--stroke-hairline);
|
|
1560
|
+
block-size: var(--stroke-hairline);
|
|
1561
|
+
overflow: hidden;
|
|
1562
|
+
clip-path: inset(50%);
|
|
1563
|
+
white-space: nowrap;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1510
1566
|
}
|
|
1511
1567
|
|
|
1512
1568
|
@layer components {
|
package/docs/DESIGN-AUTHORITY.md
CHANGED
|
@@ -298,6 +298,23 @@ bottomEnd | none` (`TablePaginationPositionProp`, default `['bottomEnd']`), the
|
|
|
298
298
|
purpose: omitted, `flow="columns"` keeps `start` and `flow="rows"` keeps the grid's stretch, so
|
|
299
299
|
no existing grid moves; antd's `Row` default is `top` in every case.
|
|
300
300
|
|
|
301
|
+
- **`RangeTimeline` nested rows take `Tree`'s spelling, not antd's (gh#724).** antd has no Gantt;
|
|
302
|
+
the nearest names are `Tree expandedKeys` / `defaultExpandedKeys` / `onExpand` and `Table
|
|
303
|
+
expandable.expandedRowKeys` / `onExpandedRowsChange`. This library already mapped the Tree ones
|
|
304
|
+
onto its controlled vocabulary as `expandedValues` / `defaultExpandedValues` /
|
|
305
|
+
`onExpandedValuesChange`, and a second spelling of the same axis is what
|
|
306
|
+
`check:prop-vocabulary` exists to prevent — so `RangeTimeline` reuses those three names exactly
|
|
307
|
+
(the values are row `id`s). The shape is also `Tree`'s: flat rows plus `depth`, the component
|
|
308
|
+
owns the indent (`--range-timeline-indent-width`) and the disclosure. Two deliberate differences
|
|
309
|
+
from `Tree`: (1) a row is a parent when the NEXT row is deeper — derived from the depth-first list,
|
|
310
|
+
never from a `hasChildren` flag, so a disclosure can never promise children that are not there;
|
|
311
|
+
(2) omitted `defaultExpandedValues` starts every parent EXPANDED (a `Tree` starts closed), so
|
|
312
|
+
adding `depth` to an existing schedule never hides a row. The disclosure is a real `Button`
|
|
313
|
+
(the row is not a focusable tree item, so APG's one-tab-stop rule does not apply), and the rows
|
|
314
|
+
are a `list` of `listitem`s with `aria-level` / `aria-setsize` / `aria-posinset` — the lightest
|
|
315
|
+
role that carries a level without promising the `tree` / `treegrid` arrow-key model. A timeline
|
|
316
|
+
with no `depth > 0` keeps its pre-#724 markup byte for byte.
|
|
317
|
+
|
|
301
318
|
**A knob that only a fork could reach is not parity either.** antd's `components`,
|
|
302
319
|
`filterDropdown`, `classNames`/`styles` semantic maps and `prefixCls` all exist to let a consumer
|
|
303
320
|
replace the rendered markup. This library answers that layer with tokens (cardinal rule #45), so
|
|
@@ -293,6 +293,47 @@ export default function Demo() {
|
|
|
293
293
|
/>
|
|
294
294
|
</CardContent>
|
|
295
295
|
</Card>
|
|
296
|
+
|
|
297
|
+
<Card>
|
|
298
|
+
<CardHeader>
|
|
299
|
+
<CardTitle level={2}>親子のある作業(depth と折りたたみ)</CardTitle>
|
|
300
|
+
<CardDescription>
|
|
301
|
+
行を深さ優先の順に並べ、depth
|
|
302
|
+
を渡すと、ラベルの列の中で段ごとに字下げされます。次の行が
|
|
303
|
+
より深い行は親になり、開閉ボタンが付きます。「実装」は defaultExpandedValues
|
|
304
|
+
に含まれていないため折りたたまれており、子の行もそのバーも表示されません。
|
|
305
|
+
</CardDescription>
|
|
306
|
+
</CardHeader>
|
|
307
|
+
<CardContent>
|
|
308
|
+
<RangeTimeline
|
|
309
|
+
label={t("rangeTimeline.schedule")}
|
|
310
|
+
today={4}
|
|
311
|
+
columns={Array.from({ length: 14 }, (_, index) => {
|
|
312
|
+
const weekday = new Date(Date.UTC(2026, 8, index + 1)).getUTCDay();
|
|
313
|
+
return {
|
|
314
|
+
label: new Intl.NumberFormat(locale).format(index + 1),
|
|
315
|
+
units: 1,
|
|
316
|
+
muted: weekday === 0 || weekday === 6,
|
|
317
|
+
};
|
|
318
|
+
})}
|
|
319
|
+
defaultExpandedValues={["design", "api"]}
|
|
320
|
+
rows={[
|
|
321
|
+
{ id: "design", label: "設計", depth: 0, start: 0, end: 5 },
|
|
322
|
+
{ id: "screens", label: "画面設計", depth: 1, start: 0, end: 2 },
|
|
323
|
+
{ id: "api", label: "API設計", depth: 1, start: 2, end: 5 },
|
|
324
|
+
{ id: "endpoints", label: "エンドポイント定義", depth: 2, start: 2, end: 3 },
|
|
325
|
+
{ id: "build", label: "実装", depth: 0, start: 6, end: 12 },
|
|
326
|
+
{ id: "frontend", label: "フロントエンド", depth: 1, start: 6, end: 10 },
|
|
327
|
+
{ id: "backend", label: "バックエンド", depth: 1, start: 6, end: 12 },
|
|
328
|
+
{ id: "release", label: "リリース", depth: 0, start: 13, end: 13 },
|
|
329
|
+
].map((row) => ({
|
|
330
|
+
...row,
|
|
331
|
+
startLabel: dayLabel(row.start + 1),
|
|
332
|
+
endLabel: dayLabel(row.end + 1),
|
|
333
|
+
}))}
|
|
334
|
+
/>
|
|
335
|
+
</CardContent>
|
|
336
|
+
</Card>
|
|
296
337
|
</Flex>
|
|
297
338
|
</PageContainer>
|
|
298
339
|
);
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
PanelLeftClose,
|
|
30
30
|
PanelLeftOpen,
|
|
31
31
|
Settings,
|
|
32
|
+
Target,
|
|
32
33
|
Users,
|
|
33
34
|
} from "lucide-react";
|
|
34
35
|
|
|
@@ -178,6 +179,42 @@ export default function Demo() {
|
|
|
178
179
|
/>
|
|
179
180
|
</CardContent>
|
|
180
181
|
</Card>
|
|
182
|
+
|
|
183
|
+
<Card>
|
|
184
|
+
<CardHeader>
|
|
185
|
+
<CardTitle level={2}>リンクのセルと、幅で畳むセル</CardTitle>
|
|
186
|
+
<CardDescription>
|
|
187
|
+
`asChild` でもセルは `icon`
|
|
188
|
+
スロットを子要素の中に差し込み、リンクそのものがセルです。 `labelHideBelow`
|
|
189
|
+
はその幅未満でラベルを視覚的にだけ隠すので、アイコンだけになっても
|
|
190
|
+
ラベルがアクセシブルネームとして残ります。`iconHideFrom`
|
|
191
|
+
はその幅以上でアイコンを外します。 ビューポートを 640px
|
|
192
|
+
の前後に動かして確認してください。
|
|
193
|
+
</CardDescription>
|
|
194
|
+
</CardHeader>
|
|
195
|
+
<CardContent>
|
|
196
|
+
<Topbar
|
|
197
|
+
start={
|
|
198
|
+
<>
|
|
199
|
+
<TopbarItem asChild icon={<Target aria-hidden="true" />}>
|
|
200
|
+
<a href="#topbar-item-goals">目標</a>
|
|
201
|
+
</TopbarItem>
|
|
202
|
+
<TopbarItem
|
|
203
|
+
asChild
|
|
204
|
+
icon={<Target aria-hidden="true" />}
|
|
205
|
+
labelHideBelow="sm"
|
|
206
|
+
iconHideFrom="sm"
|
|
207
|
+
>
|
|
208
|
+
<a href="#topbar-item-goals-responsive">今期の目標</a>
|
|
209
|
+
</TopbarItem>
|
|
210
|
+
<TopbarItem icon={<Building2 aria-hidden="true" />} labelHideBelow="md">
|
|
211
|
+
東京本社
|
|
212
|
+
</TopbarItem>
|
|
213
|
+
</>
|
|
214
|
+
}
|
|
215
|
+
/>
|
|
216
|
+
</CardContent>
|
|
217
|
+
</Card>
|
|
181
218
|
</Flex>
|
|
182
219
|
</PageContainer>
|
|
183
220
|
</AppShell>
|