@godxjp/ui 19.3.1 → 19.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/data-display/badge.d.ts +9 -1
- package/dist/components/data-display/badge.js +3 -2
- package/dist/components/data-display/index.d.ts +2 -0
- package/dist/components/data-display/index.js +2 -0
- package/dist/components/data-display/popover.d.ts +13 -1
- package/dist/components/data-display/popover.js +3 -1
- package/dist/components/data-display/table.d.ts +19 -2
- package/dist/components/data-display/table.js +4 -1
- package/dist/components/data-display/timeline-grid.d.ts +18 -0
- package/dist/components/data-display/timeline-grid.js +222 -0
- package/dist/components/data-entry/cascader.js +4 -6
- package/dist/components/data-entry/checkbox.js +1 -1
- package/dist/components/data-entry/search-select.js +5 -7
- package/dist/components/data-entry/select.js +32 -28
- package/dist/components/data-entry/tree-select.js +4 -6
- package/dist/components/general/inert-background.d.ts +5 -0
- package/dist/components/general/inert-background.js +48 -0
- package/dist/components/layout/auth-shell.d.ts +4 -2
- package/dist/components/layout/auth-shell.js +7 -1
- package/dist/components/layout/centered-shell.d.ts +2 -2
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +2 -1
- package/dist/components/layout/index.d.ts +3 -0
- package/dist/components/layout/index.js +2 -0
- package/dist/components/layout/mobile-shell.d.ts +21 -0
- package/dist/components/layout/mobile-shell.js +43 -0
- package/dist/components/layout/sidebar-link.d.ts +1 -1
- package/dist/components/navigation/context-menu.js +13 -9
- package/dist/components/navigation/dropdown-menu.js +17 -13
- package/dist/inertia/index.d.ts +1 -1
- package/dist/lib/variants.d.ts +3 -3
- package/dist/lib/variants.js +1 -0
- package/dist/props/components/data-display.prop.d.ts +65 -0
- package/dist/props/components/data-entry.prop.d.ts +1 -1
- package/dist/props/components/layout.prop.d.ts +93 -6
- package/dist/props/registry.d.ts +109 -2
- package/dist/props/registry.js +143 -0
- package/dist/props/vocabulary/data.prop.d.ts +6 -0
- package/dist/props/vocabulary/index.d.ts +3 -3
- package/dist/props/vocabulary/layout.prop.d.ts +17 -2
- package/dist/props/vocabulary/shared.prop.d.ts +7 -0
- package/dist/styles/control.css +18 -1
- package/dist/styles/data-display-layout.css +167 -0
- package/dist/styles/layout.css +7 -0
- package/dist/styles/shell-layout.css +148 -0
- package/dist/styles/table-layout.css +23 -4
- package/dist/tokens/components/control.css +1 -0
- package/dist/tokens/components/data-display.css +20 -0
- package/dist/tokens/components/shell.css +22 -0
- package/dist/tokens/components/table.css +2 -0
- package/docs/FRAME-A11Y-CI.md +99 -17
- package/docs/FRAME-COVERAGE-REPORT.md +4 -2
- package/docs/SPACING.md +19 -6
- package/docs/charts/compact-bar-trend.tsx +5 -6
- package/docs/data-display/avatar.tsx +7 -9
- package/docs/data-display/badge.tsx +1 -1
- package/docs/data-display/card/index.tsx +6 -4
- package/docs/data-display/data-table/examples/approval-queue.tsx +1 -1
- package/docs/data-display/data-table/index.tsx +1 -1
- package/docs/data-display/permission-matrix.tsx +2 -2
- package/docs/data-display/popover.tsx +4 -1
- package/docs/data-display/scroll-area.tsx +1 -1
- package/docs/data-display/table.tsx +1 -1
- package/docs/data-display/timeline-grid.tsx +119 -0
- package/docs/data-entry/branch-scope-picker.tsx +1 -1
- package/docs/data-entry/date-picker.tsx +2 -1
- package/docs/data-entry/form-field/index.tsx +2 -2
- package/docs/data-entry/input-otp.tsx +1 -1
- package/docs/data-entry/select-matrix.tsx +2 -1
- package/docs/data-entry/select.tsx +3 -1
- package/docs/data-entry/textarea.tsx +1 -1
- package/docs/data-entry/toggle-count.tsx +1 -1
- package/docs/feedback/alert.tsx +1 -1
- package/docs/feedback/banner.tsx +1 -1
- package/docs/feedback/dialog.tsx +2 -1
- package/docs/feedback/sheet.tsx +2 -1
- package/docs/foundation/email-tokens.tsx +1 -1
- package/docs/general/activity.tsx +1 -1
- package/docs/layout/app-shell.tsx +4 -4
- package/docs/layout/auth-account-summary.tsx +1 -1
- package/docs/layout/auth-recovery/examples/mobile-390.tsx +1 -1
- package/docs/layout/auth-recovery/examples/password-recovery.tsx +0 -2
- package/docs/layout/auth-shell-context.tsx +1 -1
- package/docs/layout/auth-shell-device.tsx +2 -2
- package/docs/layout/auth-shell-registration.tsx +1 -1
- package/docs/layout/auth-shell.tsx +1 -1
- package/docs/layout/master-detail.tsx +2 -2
- package/docs/layout/mobile-shell.tsx +101 -0
- package/docs/layout/page-container.tsx +6 -6
- package/docs/layout/responsive-grid.tsx +5 -5
- package/docs/layout/separator.tsx +2 -2
- package/docs/layout/service-role-panel.tsx +1 -1
- package/docs/layout/sidebar.tsx +9 -9
- package/docs/layout/split-pane.tsx +5 -6
- package/docs/layout/topbar.tsx +2 -8
- package/docs/navigation/context-menu.tsx +6 -1
- package/docs/navigation/dropdown-menu.tsx +2 -1
- package/docs/navigation/filter-bar.tsx +2 -2
- package/docs/navigation/pagination.tsx +2 -2
- package/docs/navigation/steps.tsx +1 -1
- package/docs/navigation/tabs.tsx +3 -3
- package/docs/showcase/acme-portal.tsx +11 -12
- package/docs/showcase/acme-website.tsx +7 -7
- package/docs/showcase/case1-warehouse-dashboard.tsx +11 -12
- package/docs/showcase/case2-employee-me.tsx +10 -16
- package/docs/showcase/case4-login.tsx +144 -156
- package/docs/showcase/case5-shift-calendar.tsx +181 -280
- package/docs/showcase/case6-agency-handy.tsx +446 -443
- package/docs/showcase/futurelastic-web.tsx +9 -8
- package/docs/showcase/org-switcher.tsx +18 -11
- package/docs/showcase/permission-matrix.tsx +13 -13
- package/docs/showcase/public-landing.tsx +1 -1
- package/docs/showcase/settings-account-sections.tsx +4 -4
- package/docs/showcase/settings-security-mfa.tsx +3 -3
- package/docs/showcase/table-approval-queue.tsx +1 -1
- package/docs/showcase/table-bulk-actions.tsx +49 -52
- package/docs/showcase/table-conditional-format.tsx +1 -1
- package/docs/showcase/table-crud-list.tsx +1 -1
- package/docs/showcase/table-expandable-rows.tsx +101 -98
- package/docs/showcase/table-filter-chips.tsx +78 -66
- package/docs/showcase/table-footer-totals.tsx +23 -19
- package/docs/showcase/table-grouped-subtotals.tsx +7 -4
- package/docs/showcase/table-master-detail.tsx +13 -15
- package/docs/showcase/table-states.tsx +34 -29
- package/docs/showcase/table-sticky-columns.tsx +3 -2
- package/docs/showcase/table-tree-rows.tsx +22 -15
- package/docs/showcase/table-view-tabs.tsx +12 -14
- package/package.json +7 -6
|
@@ -83,6 +83,7 @@ const THEME = `
|
|
|
83
83
|
[data-tenant="futurelastic"] .fl-lead { font-size: 1.25rem; line-height: 1.65; color: hsl(var(--muted-foreground)); max-width: 620px; }
|
|
84
84
|
[data-tenant="futurelastic"] .fl-note { font-size: 0.9375rem; color: hsl(var(--muted-foreground)); margin-top: 2.5rem; }
|
|
85
85
|
[data-tenant="futurelastic"] .fl-head { max-width: 640px; margin-inline: auto; text-align: center; }
|
|
86
|
+
[data-tenant="futurelastic"] .fl-hero-actions { margin-top: 1.75rem; }
|
|
86
87
|
[data-tenant="futurelastic"] .fl-cta-inner { position: relative; max-width: 680px; margin-inline: auto; }
|
|
87
88
|
[data-tenant="futurelastic"] .fl-footer-tagline { max-width: 260px; }
|
|
88
89
|
[data-tenant="futurelastic"] .fl-logocloud { display: flex; flex-wrap: wrap; justify-content: center; gap: 1rem 2.5rem; }
|
|
@@ -121,7 +122,7 @@ function Navbar() {
|
|
|
121
122
|
<span className="fl-brand">
|
|
122
123
|
futur<span className="fl-gold">elastic</span>
|
|
123
124
|
</span>
|
|
124
|
-
<Flex direction="row" gap="xs" align="center"
|
|
125
|
+
<Flex direction="row" gap="xs" align="center">
|
|
125
126
|
{links.map((l, i) => (
|
|
126
127
|
<Button key={l} variant="ghost" size="sm" aria-current={i === 0 ? "page" : undefined}>
|
|
127
128
|
{l}
|
|
@@ -154,7 +155,7 @@ function Hero() {
|
|
|
154
155
|
Futurelastic là pháp nhân holding của nhóm công ty công nghệ & AI vận hành xuyên Nhật
|
|
155
156
|
Bản và Việt Nam, từ logistics, fintech đến F&B và thương mại.
|
|
156
157
|
</p>
|
|
157
|
-
<Flex direction="row" gap="md" className="
|
|
158
|
+
<Flex direction="row" gap="md" className="fl-hero-actions">
|
|
158
159
|
<Button size="lg">Khám phá hệ sinh thái</Button>
|
|
159
160
|
<Button variant="outline" size="lg">
|
|
160
161
|
Liên hệ hợp tác
|
|
@@ -176,8 +177,8 @@ function LogoCloud() {
|
|
|
176
177
|
];
|
|
177
178
|
return (
|
|
178
179
|
<section className="fl-section-tint">
|
|
179
|
-
<
|
|
180
|
-
<Text as="p" size="xs" tone="muted" className="
|
|
180
|
+
<Flex direction="col" gap="lg" className={SHELL}>
|
|
181
|
+
<Text as="p" size="xs" tone="muted" className="text-center tracking-widest uppercase">
|
|
181
182
|
Các pháp nhân vận hành dưới Futurelastic
|
|
182
183
|
</Text>
|
|
183
184
|
<div className="fl-logocloud">
|
|
@@ -187,7 +188,7 @@ function LogoCloud() {
|
|
|
187
188
|
</span>
|
|
188
189
|
))}
|
|
189
190
|
</div>
|
|
190
|
-
</
|
|
191
|
+
</Flex>
|
|
191
192
|
</section>
|
|
192
193
|
);
|
|
193
194
|
}
|
|
@@ -235,8 +236,8 @@ function Bento() {
|
|
|
235
236
|
];
|
|
236
237
|
return (
|
|
237
238
|
<section className="fl-section" id="ventures">
|
|
238
|
-
<
|
|
239
|
-
<div className="fl-head
|
|
239
|
+
<Flex direction="col" gap="xl" className={SHELL}>
|
|
240
|
+
<div className="fl-head">
|
|
240
241
|
<div className="fl-eyebrow">Hệ sinh thái</div>
|
|
241
242
|
<h2 className="fl-h2">Một mái nhà, nhiều mũi nhọn</h2>
|
|
242
243
|
<p className="fl-lead mx-auto">
|
|
@@ -260,7 +261,7 @@ function Bento() {
|
|
|
260
261
|
</Card>
|
|
261
262
|
))}
|
|
262
263
|
</div>
|
|
263
|
-
</
|
|
264
|
+
</Flex>
|
|
264
265
|
</section>
|
|
265
266
|
);
|
|
266
267
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Showcase · OrgSwitcher — sidebar organization/tenant switcher (Slack/Linear pattern)
|
|
3
3
|
*
|
|
4
|
-
* Requested by dxs-platform
|
|
4
|
+
* Requested by dxs-platform as a "first-class OrgSwitcher component".
|
|
5
5
|
* GATE 0 — Framework-Component Test verdict: **COMPOSITION PATTERN**, not a framework
|
|
6
6
|
* component. It owns NO new behaviour — search/keyboard/filtering come from `Command`
|
|
7
7
|
* (cmdk), open/focus-trap/dismiss from `Popover`, the trigger from `Button` + `Avatar`.
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
AppShell,
|
|
45
45
|
Flex,
|
|
46
46
|
PageContainer,
|
|
47
|
+
Separator,
|
|
47
48
|
Sidebar,
|
|
48
49
|
type SidebarSectionProp,
|
|
49
50
|
Topbar,
|
|
@@ -116,25 +117,29 @@ function OrgSwitcher({ organizations, currentId, onSelect, onCreate, onJoin }: O
|
|
|
116
117
|
type="button"
|
|
117
118
|
variant="ghost"
|
|
118
119
|
aria-label={`Tổ chức hiện tại: ${current.name}. Nhấn để đổi tổ chức`}
|
|
119
|
-
className="w-full justify-between
|
|
120
|
+
className="w-full justify-between"
|
|
120
121
|
>
|
|
121
|
-
<
|
|
122
|
+
{/* Inside a Button, i.e. inside a <button>, whose content model is phrasing content
|
|
123
|
+
only — so every Flex on this branch renders as a <span>. */}
|
|
124
|
+
<Flex as="span" align="center" gap="sm" className="min-w-0">
|
|
122
125
|
<Avatar className="size-7 rounded-md">
|
|
123
126
|
<AvatarFallback>{monogram(current.name)}</AvatarFallback>
|
|
124
127
|
</Avatar>
|
|
125
|
-
<span className="
|
|
128
|
+
<Flex as="span" direction="col" gap="none" className="min-w-0 text-start">
|
|
126
129
|
<Text as="span" size="sm" weight="medium" truncate>
|
|
127
130
|
{current.name}
|
|
128
131
|
</Text>
|
|
129
132
|
<Text as="span" size="xs" tone="muted" truncate>
|
|
130
133
|
{current.role}
|
|
131
134
|
</Text>
|
|
132
|
-
</
|
|
135
|
+
</Flex>
|
|
133
136
|
</Flex>
|
|
134
137
|
<ChevronsUpDown aria-hidden className="size-4 shrink-0 opacity-60" />
|
|
135
138
|
</Button>
|
|
136
139
|
</PopoverTrigger>
|
|
137
|
-
|
|
140
|
+
{/* `flush` — the Command list owns its own inset, so its rows and separators run edge to
|
|
141
|
+
edge inside the popover instead of being indented by the panel padding. */}
|
|
142
|
+
<PopoverContent flush align="start" sideOffset={6} className="w-64">
|
|
138
143
|
<Command label="Chọn tổ chức">
|
|
139
144
|
<CommandInput
|
|
140
145
|
placeholder="Tìm tổ chức…"
|
|
@@ -154,18 +159,18 @@ function OrgSwitcher({ organizations, currentId, onSelect, onCreate, onJoin }: O
|
|
|
154
159
|
keywords={[org.id]}
|
|
155
160
|
onSelect={() => choose(org.id)}
|
|
156
161
|
>
|
|
157
|
-
<Flex align="center" gap="sm" className="w-full min-w-0">
|
|
162
|
+
<Flex as="span" align="center" gap="sm" className="w-full min-w-0">
|
|
158
163
|
<Avatar className="size-6 rounded">
|
|
159
164
|
<AvatarFallback>{monogram(org.name)}</AvatarFallback>
|
|
160
165
|
</Avatar>
|
|
161
|
-
<span className="
|
|
166
|
+
<Flex as="span" direction="col" gap="none" className="min-w-0 text-start">
|
|
162
167
|
<Text as="span" size="sm" truncate>
|
|
163
168
|
{org.name}
|
|
164
169
|
</Text>
|
|
165
170
|
<Text as="span" size="xs" tone="muted" truncate>
|
|
166
171
|
{org.role}
|
|
167
172
|
</Text>
|
|
168
|
-
</
|
|
173
|
+
</Flex>
|
|
169
174
|
{active ? (
|
|
170
175
|
<Check aria-hidden className="text-primary ms-auto size-4 shrink-0" />
|
|
171
176
|
) : null}
|
|
@@ -176,7 +181,9 @@ function OrgSwitcher({ organizations, currentId, onSelect, onCreate, onJoin }: O
|
|
|
176
181
|
})}
|
|
177
182
|
</CommandGroup>
|
|
178
183
|
</CommandList>
|
|
179
|
-
<
|
|
184
|
+
<Separator />
|
|
185
|
+
{/* Menu-style footer: the two actions read as one list, so no seam between them. */}
|
|
186
|
+
<Flex direction="col" gap="none">
|
|
180
187
|
<Button
|
|
181
188
|
type="button"
|
|
182
189
|
variant="ghost"
|
|
@@ -203,7 +210,7 @@ function OrgSwitcher({ organizations, currentId, onSelect, onCreate, onJoin }: O
|
|
|
203
210
|
<TicketPlus aria-hidden className="size-4" />
|
|
204
211
|
Tham gia bằng mã mời
|
|
205
212
|
</Button>
|
|
206
|
-
</
|
|
213
|
+
</Flex>
|
|
207
214
|
</Command>
|
|
208
215
|
</PopoverContent>
|
|
209
216
|
</Popover>
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
* A role × permission matrix with a STICKY first column (権限), ✓/— cells, a
|
|
5
5
|
* two-role COMPARE mode, and a 差分のみ (differences-only) filter — the pattern
|
|
6
6
|
* DXS role tabs (SCR-203) and the org role editor (SCR-111b) each hand-rolled
|
|
7
|
-
|
|
7
|
+
*. Read-only by default.
|
|
8
8
|
*
|
|
9
|
-
* SINCE
|
|
9
|
+
* SINCE the grid itself IS a package export — `PermissionMatrix` from
|
|
10
10
|
* `@godxjp/ui/data-display` (see docs/data-display/permission-matrix.tsx). The
|
|
11
11
|
* original Gate-0 "composition pattern" verdict was OUTCOME-corrected the same
|
|
12
|
-
* way ErrorSurface was
|
|
12
|
+
* way ErrorSurface was: a consumer cannot import a docs page, so the
|
|
13
13
|
* canonical grid needed an importable home. Prefer the export in app code.
|
|
14
14
|
*
|
|
15
15
|
* This showcase remains as the COMPOSED form of the same screen — the full
|
|
@@ -129,10 +129,10 @@ function GrantCell({ granted }: { granted: boolean }) {
|
|
|
129
129
|
<span className="sr-only">許可</span>
|
|
130
130
|
</Badge>
|
|
131
131
|
) : (
|
|
132
|
-
<
|
|
132
|
+
<Flex align="center" justify="center" gap="none" className="text-muted-foreground">
|
|
133
133
|
<Minus aria-hidden="true" className="size-4" />
|
|
134
134
|
<span className="sr-only">不許可</span>
|
|
135
|
-
</
|
|
135
|
+
</Flex>
|
|
136
136
|
);
|
|
137
137
|
}
|
|
138
138
|
|
|
@@ -240,19 +240,19 @@ export default function Demo() {
|
|
|
240
240
|
className={cn("text-center", isCompared && "bg-primary/[0.06]")}
|
|
241
241
|
aria-label={isCompared ? `${role.name}(比較対象)` : role.name}
|
|
242
242
|
>
|
|
243
|
-
<
|
|
244
|
-
<
|
|
243
|
+
<Flex direction="col" align="center" gap="none" className="leading-tight">
|
|
244
|
+
<Flex align="center" gap="xs">
|
|
245
245
|
<Text weight="medium">{role.name}</Text>
|
|
246
246
|
{isCompared && (
|
|
247
247
|
<Badge tone="primary" variant="outline">
|
|
248
248
|
{role.id === compareA ? "A" : "B"}
|
|
249
249
|
</Badge>
|
|
250
250
|
)}
|
|
251
|
-
</
|
|
251
|
+
</Flex>
|
|
252
252
|
<Text size="2xs" tone="muted">
|
|
253
253
|
{role.hint} · {countGrants(PERMISSIONS, GRANTS, role.id)}件
|
|
254
254
|
</Text>
|
|
255
|
-
</
|
|
255
|
+
</Flex>
|
|
256
256
|
</TableHead>
|
|
257
257
|
);
|
|
258
258
|
})}
|
|
@@ -270,14 +270,14 @@ export default function Demo() {
|
|
|
270
270
|
>
|
|
271
271
|
<TableCell className={cn(PIN_START, "w-64 min-w-64 align-middle")}>
|
|
272
272
|
<Flex direction="col" className="leading-tight">
|
|
273
|
-
<
|
|
273
|
+
<Flex align="center" gap="xs">
|
|
274
274
|
<Text weight="medium">{perm.name}</Text>
|
|
275
275
|
{isDiffRow && (
|
|
276
276
|
<Badge tone="warning" variant="outline">
|
|
277
277
|
差分
|
|
278
278
|
</Badge>
|
|
279
279
|
)}
|
|
280
|
-
</
|
|
280
|
+
</Flex>
|
|
281
281
|
<Text size="2xs" tone="muted">
|
|
282
282
|
{perm.category} · {perm.description}
|
|
283
283
|
</Text>
|
|
@@ -322,9 +322,9 @@ export default function Demo() {
|
|
|
322
322
|
</Text>
|
|
323
323
|
</Flex>
|
|
324
324
|
<Flex direction="row" align="center" gap="xs">
|
|
325
|
-
<
|
|
325
|
+
<Flex align="center" gap="none" className="text-muted-foreground">
|
|
326
326
|
<Minus aria-hidden="true" className="size-4" />
|
|
327
|
-
</
|
|
327
|
+
</Flex>
|
|
328
328
|
<Text size="xs" tone="muted">
|
|
329
329
|
不許可
|
|
330
330
|
</Text>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Showcase · Public landing
|
|
2
|
+
* Showcase · Public landing — the PUBLIC marketing/product landing page composed from
|
|
3
3
|
* real @godxjp/ui primitives with **zero page-local CSS**.
|
|
4
4
|
*
|
|
5
5
|
* Gate 0 (docs/COMPOSITION-VS-COMPONENT.md): a landing header / hero / section grid / legal footer
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Showcase · settings-account-sections — the canonical SETTINGS SECTION / ROW composition
|
|
2
|
+
* Showcase · settings-account-sections — the canonical SETTINGS SECTION / ROW composition
|
|
3
3
|
*
|
|
4
4
|
* ── Gate 0 verdict: COMPOSITION PATTERN, not a framework component ────────────────────────────
|
|
5
5
|
* A "SettingsSection" / "SettingsRow" / "DangerZone" fails the Framework-Component Test
|
|
@@ -61,7 +61,7 @@ import { AlertDialog } from "@godxjp/ui/feedback";
|
|
|
61
61
|
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
62
62
|
|
|
63
63
|
// ── Label bundles: the SAME screen at its longest JA / EN / VI wording ────────────────────────
|
|
64
|
-
// Long-label stress is a first-class acceptance criterion
|
|
64
|
+
// Long-label stress is a first-class acceptance criterion, so the bundle intentionally
|
|
65
65
|
// carries the verbose form of each label instead of the tidy demo form.
|
|
66
66
|
|
|
67
67
|
type LabelBundle = {
|
|
@@ -348,7 +348,7 @@ export default function SettingsAccountSectionsShowcase() {
|
|
|
348
348
|
title={b.pageTitle}
|
|
349
349
|
subtitle={b.pageSubtitle}
|
|
350
350
|
breadcrumb={[{ label: b.pageTitle }]}
|
|
351
|
-
// PageHeader action composition
|
|
351
|
+
// PageHeader action composition: the header owns the page-level actions through
|
|
352
352
|
// `extra`. It wraps at 390 instead of overflowing, so no page-local header geometry.
|
|
353
353
|
extra={
|
|
354
354
|
<Flex direction="row" align="end" gap="sm" wrap>
|
|
@@ -477,7 +477,7 @@ export default function SettingsAccountSectionsShowcase() {
|
|
|
477
477
|
</Descriptions>
|
|
478
478
|
</CardContent>
|
|
479
479
|
<CardFooter separated>
|
|
480
|
-
<Flex direction="col" gap="
|
|
480
|
+
<Flex direction="col" gap="md" className="sm:flex-row sm:items-center">
|
|
481
481
|
<Button variant="outline" asChild>
|
|
482
482
|
<a href="https://billing.example.com/portal" target="_blank" rel="noreferrer">
|
|
483
483
|
<ExternalLink aria-hidden="true" />
|
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
* ✗ wrong (hand-rolled) ✓ here (rule)
|
|
8
8
|
* ─────────────────────────────────────────────────────────────────────────────────────────
|
|
9
9
|
* factor row = a centered <div> with the ListRow — leading icon · title/description ·
|
|
10
|
-
* title duplicated as its own description
|
|
10
|
+
* title duplicated as its own description trailing action (no redundant copy)
|
|
11
11
|
* "Xoá" rendered as plain black text destructive-toned ghost button — delete is a
|
|
12
12
|
* destructive action, color carries intent
|
|
13
13
|
* every action a full-width stacked bar right-aligned, auto-width actions; ONE primary
|
|
14
14
|
* (rule 217 explicitly forbids this) per card, secondary = outline (rule 217)
|
|
15
15
|
* 📱 / ✉️ emoji as "icons" lucide icons (no emoji in product UI) (anti-tell)
|
|
16
|
-
* brand glyph = a styled <span> (size/radius
|
|
16
|
+
* brand glyph = a styled <span> (size/radius Avatar primitive — real brand mark
|
|
17
17
|
* baked as literals)
|
|
18
18
|
*
|
|
19
19
|
* Built ENTIRELY from real @godxjp/ui primitives. reference-design DNA: small headings, 14/1.7 body,
|
|
@@ -130,7 +130,7 @@ export default function SecurityMfaShowcase() {
|
|
|
130
130
|
</Text>
|
|
131
131
|
</Flex>
|
|
132
132
|
</CardContent>
|
|
133
|
-
<CardFooter separated className="justify-end
|
|
133
|
+
<CardFooter separated className="justify-end">
|
|
134
134
|
<Button variant="ghost" size="sm">
|
|
135
135
|
Tải xuống
|
|
136
136
|
</Button>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Showcase · アクセス承認キュー / Access approval queue
|
|
2
|
+
* Showcase · アクセス承認キュー / Access approval queue — the canonical five-column
|
|
3
3
|
* approval collection at 1440 · 1024 · 390 using ONLY public API.
|
|
4
4
|
*
|
|
5
5
|
* The whole responsive contract is `Table preset="action-collection"` plus a `priority` on each
|
|
@@ -202,61 +202,58 @@ function BulkActionBar({
|
|
|
202
202
|
}) {
|
|
203
203
|
const effective = spanAll ? total : count;
|
|
204
204
|
return (
|
|
205
|
-
<
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
>
|
|
213
|
-
{/* left: count + cross-page select-all escalation + safe batch actions */}
|
|
214
|
-
<Flex direction="row" align="center" gap="sm" className="min-w-0 flex-1">
|
|
215
|
-
<Text tone="primary" weight="medium" tabular className="whitespace-nowrap">
|
|
216
|
-
{effective}件を選択中
|
|
217
|
-
</Text>
|
|
218
|
-
|
|
219
|
-
{/* cross-page select-all: only offered once the whole page is selected */}
|
|
220
|
-
{pageAllSelected &&
|
|
221
|
-
(spanAll ? (
|
|
222
|
-
<Text size="xs" tone="muted">
|
|
223
|
-
フィルタ条件の全{" "}
|
|
224
|
-
<Text as="span" tabular>
|
|
225
|
-
{total}
|
|
226
|
-
</Text>{" "}
|
|
227
|
-
件を選択しました
|
|
205
|
+
<Card className="bg-primary/5 border-primary/30">
|
|
206
|
+
<CardContent solo>
|
|
207
|
+
<Flex role="region" aria-label="一括操作" wrap align="center" gap="md">
|
|
208
|
+
{/* left: count + cross-page select-all escalation + safe batch actions */}
|
|
209
|
+
<Flex direction="row" align="center" gap="sm" className="min-w-0 flex-1">
|
|
210
|
+
<Text tone="primary" weight="medium" tabular className="whitespace-nowrap">
|
|
211
|
+
{effective}件を選択中
|
|
228
212
|
</Text>
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
213
|
+
|
|
214
|
+
{/* cross-page select-all: only offered once the whole page is selected */}
|
|
215
|
+
{pageAllSelected &&
|
|
216
|
+
(spanAll ? (
|
|
217
|
+
<Text size="xs" tone="muted">
|
|
218
|
+
フィルタ条件の全{" "}
|
|
219
|
+
<Text as="span" tabular>
|
|
220
|
+
{total}
|
|
221
|
+
</Text>{" "}
|
|
222
|
+
件を選択しました
|
|
223
|
+
</Text>
|
|
224
|
+
) : (
|
|
225
|
+
<Button variant="link" size="sm" onClick={onSelectSpanAll}>
|
|
226
|
+
全 <span className="tabular-nums">{total}</span> 件を選択
|
|
227
|
+
</Button>
|
|
228
|
+
))}
|
|
229
|
+
|
|
230
|
+
<span className="bg-border h-4 w-px" aria-hidden="true" />
|
|
231
|
+
|
|
232
|
+
<Button variant="outline" size="sm" onClick={onApprove}>
|
|
233
|
+
<CheckCheck aria-hidden="true" />
|
|
234
|
+
一括承認
|
|
232
235
|
</Button>
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
<CheckCheck aria-hidden="true" />
|
|
239
|
-
一括承認
|
|
240
|
-
</Button>
|
|
241
|
-
<Button variant="outline" size="sm" onClick={onExport}>
|
|
242
|
-
<Download aria-hidden="true" />
|
|
243
|
-
CSV出力
|
|
244
|
-
</Button>
|
|
245
|
-
</Flex>
|
|
236
|
+
<Button variant="outline" size="sm" onClick={onExport}>
|
|
237
|
+
<Download aria-hidden="true" />
|
|
238
|
+
CSV出力
|
|
239
|
+
</Button>
|
|
240
|
+
</Flex>
|
|
246
241
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
242
|
+
{/* right: ISOLATED destructive action, kept apart from the safe ones */}
|
|
243
|
+
<Flex direction="row" align="center" gap="sm">
|
|
244
|
+
<Button variant="destructive" size="sm" onClick={onDelete}>
|
|
245
|
+
<Trash2 aria-hidden="true" />
|
|
246
|
+
一括削除
|
|
247
|
+
</Button>
|
|
248
|
+
<span className="bg-border h-4 w-px" aria-hidden="true" />
|
|
249
|
+
<Button variant="ghost" size="sm" onClick={onClear} aria-label="選択を解除">
|
|
250
|
+
<X aria-hidden="true" />
|
|
251
|
+
解除
|
|
252
|
+
</Button>
|
|
253
|
+
</Flex>
|
|
254
|
+
</Flex>
|
|
255
|
+
</CardContent>
|
|
256
|
+
</Card>
|
|
260
257
|
);
|
|
261
258
|
}
|
|
262
259
|
|
|
@@ -247,7 +247,7 @@ export default function Demo() {
|
|
|
247
247
|
<Flex direction="col" gap="lg">
|
|
248
248
|
{/* ── 行レベル + セルレベルの条件付き書式(実 Table primitive で合成) ── */}
|
|
249
249
|
<Card>
|
|
250
|
-
<CardHeader
|
|
250
|
+
<CardHeader>
|
|
251
251
|
<Flex direction="row" wrap align="center" justify="between" gap="sm">
|
|
252
252
|
<CardTitle level={2}>勤怠サマリ · 製造部(当月締め)</CardTitle>
|
|
253
253
|
<Text size="xs" tone="muted" tabular>
|
|
@@ -497,7 +497,7 @@ export default function Demo() {
|
|
|
497
497
|
</CardContent>
|
|
498
498
|
|
|
499
499
|
{/* Footer totals — composed from CardFooter + Badge, not a hand-rolled bar. */}
|
|
500
|
-
<CardFooter className="flex-wrap justify-between
|
|
500
|
+
<CardFooter className="flex-wrap justify-between">
|
|
501
501
|
<Flex direction="row" gap="md" align="center" wrap>
|
|
502
502
|
<Text size="xs" tone="muted">
|
|
503
503
|
選択中{" "}
|