@godxjp/ui 20.0.0 → 20.1.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/README.md +8 -2
- package/dist/app/theme-axes.d.ts +2 -0
- package/dist/app/theme-axes.js +45 -0
- package/dist/components/charts/chart-cartesian.d.ts +2 -1
- package/dist/components/charts/chart-cartesian.js +52 -3
- package/dist/components/charts/chart-category-axis.d.ts +55 -0
- package/dist/components/charts/chart-category-axis.js +93 -0
- package/dist/components/charts/chart-frame.d.ts +10 -1
- package/dist/components/charts/chart-frame.js +19 -3
- package/dist/components/charts/compact-bar-trend.d.ts +1 -1
- package/dist/components/charts/compact-bar-trend.js +2 -0
- package/dist/components/charts/pie-chart.d.ts +1 -1
- package/dist/components/charts/pie-chart.js +12 -1
- package/dist/components/charts/recharts-peer.d.ts +49 -0
- package/dist/components/charts/recharts-peer.js +45 -0
- package/dist/components/data-display/card.d.ts +12 -1
- package/dist/components/data-display/card.js +22 -4
- package/dist/components/data-display/code-block.js +6 -2
- package/dist/components/data-display/data-table.d.ts +39 -4
- package/dist/components/data-display/data-table.js +802 -270
- package/dist/components/data-display/descriptions.d.ts +27 -6
- package/dist/components/data-display/descriptions.js +58 -17
- package/dist/components/data-display/index.d.ts +2 -0
- package/dist/components/data-display/index.js +2 -0
- package/dist/components/data-display/list-row.d.ts +10 -1
- package/dist/components/data-display/list-row.js +7 -1
- package/dist/components/data-display/popover.d.ts +2 -2
- package/dist/components/data-display/popover.js +61 -11
- package/dist/components/data-display/range-timeline.d.ts +38 -0
- package/dist/components/data-display/range-timeline.js +161 -0
- package/dist/components/data-display/scroll-area.js +13 -2
- package/dist/components/data-display/service-launcher-card.js +10 -10
- package/dist/components/data-display/table.d.ts +11 -3
- package/dist/components/data-display/table.js +48 -18
- package/dist/components/data-display/tree-list.js +4 -9
- package/dist/components/data-entry/calendar.d.ts +2 -2
- package/dist/components/data-entry/calendar.js +12 -1
- package/dist/components/data-entry/cascader.d.ts +1 -1
- package/dist/components/data-entry/cascader.js +188 -24
- package/dist/components/data-entry/color-picker.d.ts +1 -1
- package/dist/components/data-entry/color-picker.js +17 -5
- package/dist/components/data-entry/control-appearance.d.ts +64 -0
- package/dist/components/data-entry/control-appearance.js +39 -0
- package/dist/components/data-entry/control-surface.d.ts +61 -0
- package/dist/components/data-entry/control-surface.js +39 -0
- package/dist/components/data-entry/date-picker.d.ts +1 -1
- package/dist/components/data-entry/date-picker.js +344 -113
- package/dist/components/data-entry/date-range-picker.d.ts +1 -1
- package/dist/components/data-entry/date-range-picker.js +278 -140
- package/dist/components/data-entry/form-field.d.ts +1 -1
- package/dist/components/data-entry/form-field.js +39 -4
- package/dist/components/data-entry/form.d.ts +4 -0
- package/dist/components/data-entry/form.js +4 -2
- package/dist/components/data-entry/index.d.ts +7 -3
- package/dist/components/data-entry/index.js +10 -1
- package/dist/components/data-entry/input-otp.d.ts +1 -1
- package/dist/components/data-entry/input.d.ts +12 -34
- package/dist/components/data-entry/input.js +92 -24
- package/dist/components/data-entry/month-picker.d.ts +1 -1
- package/dist/components/data-entry/month-picker.js +47 -10
- package/dist/components/data-entry/month-range-picker.d.ts +1 -1
- package/dist/components/data-entry/month-range-picker.js +51 -11
- package/dist/components/data-entry/number-input.d.ts +7 -0
- package/dist/components/data-entry/number-input.js +147 -98
- package/dist/components/data-entry/password-input.d.ts +1 -1
- package/dist/components/data-entry/radio.d.ts +1 -1
- package/dist/components/data-entry/radio.js +61 -13
- package/dist/components/data-entry/search-input.d.ts +1 -1
- package/dist/components/data-entry/search-input.js +16 -2
- package/dist/components/data-entry/search-select.d.ts +2 -2
- package/dist/components/data-entry/search-select.js +209 -78
- package/dist/components/data-entry/select.d.ts +22 -4
- package/dist/components/data-entry/select.js +215 -163
- package/dist/components/data-entry/slider.d.ts +9 -1
- package/dist/components/data-entry/slider.js +87 -9
- package/dist/components/data-entry/switch.d.ts +3 -0
- package/dist/components/data-entry/switch.js +29 -3
- package/dist/components/data-entry/textarea.d.ts +14 -56
- package/dist/components/data-entry/textarea.js +80 -33
- package/dist/components/data-entry/time-picker.d.ts +2 -2
- package/dist/components/data-entry/time-picker.js +333 -109
- package/dist/components/data-entry/time-range-picker.d.ts +5 -0
- package/dist/components/data-entry/time-range-picker.js +89 -0
- package/dist/components/data-entry/transfer.d.ts +1 -1
- package/dist/components/data-entry/transfer.js +86 -28
- package/dist/components/data-entry/tree-select.d.ts +1 -1
- package/dist/components/data-entry/tree-select.js +201 -113
- package/dist/components/data-entry/tree-utils.js +7 -14
- package/dist/components/data-entry/upload-files.d.ts +2 -0
- package/dist/components/data-entry/upload-files.js +31 -0
- package/dist/components/data-entry/upload-request.d.ts +4 -0
- package/dist/components/data-entry/upload-request.js +53 -0
- package/dist/components/data-entry/upload-types.d.ts +28 -0
- package/dist/components/data-entry/upload-types.js +2 -0
- package/dist/components/data-entry/upload.d.ts +2 -2
- package/dist/components/data-entry/upload.js +475 -115
- package/dist/components/feedback/dialog.js +16 -19
- package/dist/components/general/button.d.ts +1 -1
- package/dist/components/general/button.js +5 -1
- package/dist/components/general/index.d.ts +1 -0
- package/dist/components/general/index.js +2 -0
- package/dist/components/general/typography.d.ts +3 -0
- package/dist/components/general/typography.js +15 -1
- package/dist/components/general/visually-hidden.d.ts +3 -0
- package/dist/components/general/visually-hidden.js +9 -0
- package/dist/components/layout/app-launcher.d.ts +34 -0
- package/dist/components/layout/app-launcher.js +228 -0
- package/dist/components/layout/app-shell.d.ts +2 -0
- package/dist/components/layout/app-shell.js +20 -7
- package/dist/components/layout/breadcrumb.d.ts +14 -2
- package/dist/components/layout/breadcrumb.js +46 -4
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +23 -2
- package/dist/components/layout/index.d.ts +3 -0
- package/dist/components/layout/index.js +5 -1
- package/dist/components/layout/org-switcher.js +20 -1
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +5 -3
- package/dist/components/layout/responsive-grid.d.ts +16 -2
- package/dist/components/layout/responsive-grid.js +29 -2
- package/dist/components/layout/topbar-item.d.ts +3 -0
- package/dist/components/layout/topbar-item.js +18 -3
- package/dist/components/layout/topbar.d.ts +1 -1
- package/dist/components/layout/topbar.js +27 -6
- package/dist/components/navigation/dropdown-menu.d.ts +30 -2
- package/dist/components/navigation/dropdown-menu.js +68 -11
- package/dist/components/navigation/pagination.d.ts +2 -2
- package/dist/components/navigation/pagination.js +155 -83
- package/dist/components/navigation/steps.d.ts +2 -2
- package/dist/components/navigation/steps.js +29 -4
- package/dist/components/navigation/tabs.d.ts +5 -33
- package/dist/components/navigation/tabs.js +232 -64
- package/dist/components/ui/input-otp.d.ts +26 -28
- package/dist/components/ui/input-otp.js +50 -7
- package/dist/components/ui/password-input.d.ts +36 -2
- package/dist/components/ui/password-input.js +27 -7
- package/dist/components/ui/rating.d.ts +25 -0
- package/dist/components/ui/rating.js +67 -27
- package/dist/components/ui/segmented.d.ts +9 -0
- package/dist/components/ui/segmented.js +17 -2
- package/dist/components/ui/separator.d.ts +4 -0
- package/dist/components/ui/separator.js +13 -0
- package/dist/components/ui/tag-input.d.ts +45 -0
- package/dist/components/ui/tag-input.js +109 -27
- package/dist/form/form-context.d.ts +29 -0
- package/dist/form/form-context.js +44 -4
- package/dist/form/form-field-array.d.ts +22 -0
- package/dist/form/form-field-array.js +50 -0
- package/dist/form/form-field-control.d.ts +2 -1
- package/dist/form/form-field-control.js +116 -40
- package/dist/form/form-root.d.ts +2 -1
- package/dist/form/form-root.js +142 -23
- package/dist/form/index.d.ts +3 -1
- package/dist/form/index.js +12 -1
- package/dist/i18n/messages/en.json +56 -5
- package/dist/i18n/messages/ja.json +56 -5
- package/dist/i18n/messages/vi.json +56 -5
- package/dist/inertia/index.d.ts +20 -0
- package/dist/inertia/index.js +60 -1
- package/dist/lib/control-styles.d.ts +25 -3
- package/dist/lib/control-styles.js +9 -3
- package/dist/lib/datetime/picker-format.d.ts +8 -0
- package/dist/lib/datetime/picker-format.js +54 -0
- package/dist/props/components/charts.prop.d.ts +21 -0
- package/dist/props/components/data-display.prop.d.ts +55 -4
- package/dist/props/components/data-entry.prop.d.ts +687 -43
- package/dist/props/components/form.prop.d.ts +142 -4
- package/dist/props/components/general.prop.d.ts +17 -1
- package/dist/props/components/index.d.ts +2 -2
- package/dist/props/components/layout.prop.d.ts +163 -6
- package/dist/props/components/navigation.prop.d.ts +113 -3
- package/dist/props/registry.d.ts +376 -10
- package/dist/props/registry.js +493 -9
- package/dist/props/vocabulary/data.prop.d.ts +179 -1
- package/dist/props/vocabulary/index.d.ts +4 -4
- package/dist/props/vocabulary/interaction.prop.d.ts +51 -2
- package/dist/props/vocabulary/navigation.prop.d.ts +40 -0
- package/dist/props/vocabulary/shared.prop.d.ts +33 -0
- package/dist/styles/badge-layout.css +2 -1
- package/dist/styles/card-layout.css +26 -4
- package/dist/styles/chart-layout.css +15 -0
- package/dist/styles/control.css +515 -14
- package/dist/styles/data-display-layout.css +241 -6
- package/dist/styles/data-entry-layout.css +13 -0
- package/dist/styles/layout.css +221 -4
- package/dist/styles/navigation-layout.css +227 -0
- package/dist/styles/shell-layout.css +229 -5
- package/dist/styles/table-layout.css +95 -6
- package/dist/styles/text-layout.css +5 -0
- package/dist/tokens/base.css +1 -0
- package/dist/tokens/components/badge.css +1 -0
- package/dist/tokens/components/chart.css +6 -0
- package/dist/tokens/components/control.css +79 -2
- package/dist/tokens/components/data-display.css +9 -0
- package/dist/tokens/components/descriptions.css +11 -0
- package/dist/tokens/components/flex.css +8 -0
- package/dist/tokens/components/navigation.css +55 -0
- package/dist/tokens/components/shell.css +50 -2
- package/dist/tokens/components/table.css +14 -0
- package/dist/tokens/semantic/layout.css +9 -0
- package/docs/CONSUMER-RULES.md +13 -0
- package/docs/DESIGN-AUTHORITY.md +43 -6
- package/docs/DEVELOPMENT.md +4 -3
- package/docs/FORMS.md +151 -6
- package/docs/FRAME-COVERAGE-REPORT.md +29 -16
- package/docs/README.md +1 -1
- package/docs/STANDARDS-vocabulary-tokens.md +1 -1
- package/docs/TESTING.md +15 -6
- package/docs/charts/cjk-category-axis.tsx +81 -0
- package/docs/data-display/card/index.tsx +22 -0
- package/docs/data-display/data-table/examples/antd-parity.tsx +257 -0
- package/docs/data-display/data-table/index.tsx +23 -0
- package/docs/data-display/descriptions.tsx +41 -0
- package/docs/data-display/scroll-area.tsx +31 -25
- package/docs/data-display/table.tsx +104 -45
- package/docs/data-display/timeline.tsx +41 -0
- package/docs/data-entry/date-picker.tsx +85 -0
- package/docs/data-entry/date-range-picker.tsx +26 -0
- package/docs/data-entry/form-dynamic-fields.tsx +199 -0
- package/docs/data-entry/form.tsx +74 -4
- package/docs/data-entry/input-otp.tsx +24 -0
- package/docs/data-entry/input.tsx +46 -1
- package/docs/data-entry/month-range-picker.tsx +1 -1
- package/docs/data-entry/select.tsx +27 -0
- package/docs/data-entry/switch.tsx +41 -0
- package/docs/data-entry/textarea.tsx +38 -0
- package/docs/data-entry/time-picker.tsx +85 -1
- package/docs/data-entry/time-range-picker.tsx +55 -0
- package/docs/data-entry/transfer.tsx +17 -0
- package/docs/data-entry/upload.tsx +56 -12
- package/docs/feedback/tooltip.tsx +1 -1
- package/docs/general/activity.tsx +2 -2
- package/docs/general/button/index.tsx +14 -1
- package/docs/general/typography.tsx +14 -1
- package/docs/layout/app-launcher.tsx +151 -0
- package/docs/layout/app-shell.tsx +11 -0
- package/docs/layout/flex.tsx +50 -0
- package/docs/layout/responsive-grid.tsx +21 -1
- package/docs/layout/topbar.tsx +5 -9
- package/docs/navigation/app-setting-picker.tsx +11 -0
- package/docs/navigation/breadcrumb.tsx +48 -0
- package/docs/navigation/dropdown-menu.tsx +21 -0
- package/docs/navigation/pagination.tsx +52 -0
- package/docs/navigation/steps.tsx +37 -0
- package/docs/navigation/tabs.tsx +97 -1
- package/docs/query/button-refetch.tsx +1 -0
- package/package.json +19 -2
- package/scripts/_agent-setup.mjs +19 -2
- package/scripts/init-guinea-pig.mjs +26 -4
- package/scripts/ui-audit.mjs +243 -30
|
@@ -12,7 +12,7 @@ import { buttonVariants } from "../general/button.js";
|
|
|
12
12
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
13
13
|
import { Button } from "../general/button.js";
|
|
14
14
|
import { Input } from "../data-entry/input.js";
|
|
15
|
-
import {
|
|
15
|
+
import { FormField } from "../data-entry/form-field.js";
|
|
16
16
|
function useOverlayOpenState({ open, defaultOpen, onOpenChange }) {
|
|
17
17
|
const [uncontrolled, setUncontrolled] = React.useState(defaultOpen ?? false);
|
|
18
18
|
const isOpen = open ?? uncontrolled;
|
|
@@ -407,24 +407,21 @@ function AlertDialog({
|
|
|
407
407
|
/* @__PURE__ */ jsx(AlertDialogTitle, { children: title }),
|
|
408
408
|
description ? /* @__PURE__ */ jsx(AlertDialogDescription, { children: description }) : null
|
|
409
409
|
] }),
|
|
410
|
-
needsPhrase && /* @__PURE__ */
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
value
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
}
|
|
426
|
-
)
|
|
427
|
-
] }),
|
|
410
|
+
needsPhrase && /* @__PURE__ */ jsx(FormField, { id: inputId, label: t("common.typeToConfirm", { phrase }), children: /* @__PURE__ */ jsx(
|
|
411
|
+
Input,
|
|
412
|
+
{
|
|
413
|
+
id: inputId,
|
|
414
|
+
value: typed,
|
|
415
|
+
onChange: (e) => {
|
|
416
|
+
setTyped(e.target.value);
|
|
417
|
+
},
|
|
418
|
+
autoComplete: "off",
|
|
419
|
+
spellCheck: false,
|
|
420
|
+
placeholder: phrase,
|
|
421
|
+
"aria-required": "true",
|
|
422
|
+
disabled: busy
|
|
423
|
+
}
|
|
424
|
+
) }),
|
|
428
425
|
stepUpFailed && /* @__PURE__ */ jsx("p", { id: stepErrorId, role: "alert", className: "ui-dialog-step-up-error", children: t("feedback.alert.stepUpFailed") }),
|
|
429
426
|
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
430
427
|
/* @__PURE__ */ jsx(DialogCancel, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", disabled: busy, children: resolvedCancel }) }),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
declare const buttonVariants: (props?: ({
|
|
3
|
-
variant?: "dashed" | "default" | "destructive" | "ghost" | "link" | "outline" | "secondary" | null | undefined;
|
|
3
|
+
variant?: "bare" | "dashed" | "default" | "destructive" | "ghost" | "link" | "outline" | "secondary" | null | undefined;
|
|
4
4
|
size?: "default" | "icon" | "icon-lg" | "icon-sm" | "icon-xs" | "lg" | "md" | "sm" | "xs" | null | undefined;
|
|
5
5
|
shape?: "default" | "pill" | "sharp" | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
@@ -20,7 +20,11 @@ const buttonVariants = cva("ui-button", {
|
|
|
20
20
|
dashed: "ui-button--dashed border border-dashed bg-background hover:bg-accent hover:text-accent-foreground",
|
|
21
21
|
secondary: "ui-button--secondary bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
22
22
|
ghost: "ui-button--ghost hover:bg-accent hover:text-accent-foreground",
|
|
23
|
-
link: "ui-button--link text-primary underline-offset-4 hover:underline"
|
|
23
|
+
link: "ui-button--link text-primary underline-offset-4 hover:underline",
|
|
24
|
+
// NO utilities, deliberately: `bare` is the absence of geometry, and every property it has
|
|
25
|
+
// to unset (the size tier's height and inline inset) is declared in the components layer.
|
|
26
|
+
// A utility here would be the only thing that could out-rank it. See `.ui-button--bare`.
|
|
27
|
+
bare: "ui-button--bare"
|
|
24
28
|
},
|
|
25
29
|
size: {
|
|
26
30
|
default: "ui-button--default-size",
|
|
@@ -3,6 +3,7 @@ import { Text, Heading } from "./typography.js";
|
|
|
3
3
|
import { Logo } from "./logo.js";
|
|
4
4
|
import { Reveal } from "./reveal.js";
|
|
5
5
|
import { Activity } from "./activity.js";
|
|
6
|
+
import { VisuallyHidden } from "./visually-hidden.js";
|
|
6
7
|
export {
|
|
7
8
|
Activity,
|
|
8
9
|
Button,
|
|
@@ -10,5 +11,6 @@ export {
|
|
|
10
11
|
Logo,
|
|
11
12
|
Reveal,
|
|
12
13
|
Text,
|
|
14
|
+
VisuallyHidden,
|
|
13
15
|
buttonVariants
|
|
14
16
|
};
|
|
@@ -14,7 +14,10 @@ export declare const Text: React.ForwardRefExoticComponent<Omit<React.HTMLAttrib
|
|
|
14
14
|
align?: import("../../props/index.js").TextAlignProp;
|
|
15
15
|
truncate?: boolean;
|
|
16
16
|
clamp?: number;
|
|
17
|
+
whitespace?: import("../../props/index.js").TextWhitespaceProp;
|
|
17
18
|
tabular?: boolean;
|
|
19
|
+
decoration?: "none" | "underline" | "line-through";
|
|
20
|
+
chip?: boolean;
|
|
18
21
|
mono?: boolean;
|
|
19
22
|
htmlFor?: string;
|
|
20
23
|
href?: string;
|
|
@@ -12,7 +12,10 @@ const Text = React.forwardRef(
|
|
|
12
12
|
align,
|
|
13
13
|
truncate,
|
|
14
14
|
clamp,
|
|
15
|
+
whitespace,
|
|
15
16
|
tabular,
|
|
17
|
+
decoration,
|
|
18
|
+
chip,
|
|
16
19
|
mono,
|
|
17
20
|
link,
|
|
18
21
|
className,
|
|
@@ -21,6 +24,7 @@ const Text = React.forwardRef(
|
|
|
21
24
|
...props
|
|
22
25
|
}, ref) => {
|
|
23
26
|
const clampLines = typeof clamp === "number" && Number.isFinite(clamp) && clamp >= 1 ? Math.floor(clamp) : void 0;
|
|
27
|
+
const truncating = truncate === true && clampLines === void 0;
|
|
24
28
|
if (typeof process !== "undefined" && process.env?.NODE_ENV !== "production") {
|
|
25
29
|
if (clamp !== void 0 && clampLines === void 0) {
|
|
26
30
|
console.warn(
|
|
@@ -32,6 +36,11 @@ const Text = React.forwardRef(
|
|
|
32
36
|
"Text: `truncate` and `clamp` are mutually exclusive \u2014 `clamp` takes precedence; drop `truncate`."
|
|
33
37
|
);
|
|
34
38
|
}
|
|
39
|
+
if (whitespace === "pre-wrap" && truncating) {
|
|
40
|
+
console.warn(
|
|
41
|
+
'Text: `truncate` and `whitespace="pre-wrap"` are mutually exclusive \u2014 `truncate` takes precedence (one line, one ellipsis); use `clamp` to keep preserved line breaks and still bound the height.'
|
|
42
|
+
);
|
|
43
|
+
}
|
|
35
44
|
}
|
|
36
45
|
const typography = {
|
|
37
46
|
"data-slot": "text",
|
|
@@ -40,10 +49,15 @@ const Text = React.forwardRef(
|
|
|
40
49
|
"data-link": link ? "" : void 0,
|
|
41
50
|
"data-weight": weight,
|
|
42
51
|
"data-align": align,
|
|
43
|
-
"data-truncate":
|
|
52
|
+
"data-truncate": truncating ? "" : void 0,
|
|
44
53
|
"data-clamp": clampLines !== void 0 ? "" : void 0,
|
|
54
|
+
// Inert default: `normal` is CSS's own behaviour, so it emits no attribute and there is no
|
|
55
|
+
// `[data-whitespace="normal"]` rule to lose a specificity argument with anything.
|
|
56
|
+
"data-whitespace": whitespace === "pre-wrap" && !truncating ? "pre-wrap" : void 0,
|
|
45
57
|
style: clampLines !== void 0 ? { ...style, "--text-clamp": clampLines } : style,
|
|
46
58
|
"data-tabular": tabular ? "" : void 0,
|
|
59
|
+
"data-decoration": decoration,
|
|
60
|
+
"data-chip": chip ? "" : void 0,
|
|
47
61
|
"data-mono": mono ? "" : void 0,
|
|
48
62
|
className: cn("ui-text", className),
|
|
49
63
|
...props
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
|
+
const VisuallyHidden = React.forwardRef(function VisuallyHidden2({ className, ...props }, ref) {
|
|
5
|
+
return /* @__PURE__ */ jsx("span", { ...props, ref, className: cn("sr-only", className) });
|
|
6
|
+
});
|
|
7
|
+
export {
|
|
8
|
+
VisuallyHidden
|
|
9
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { AppLauncherProp } from "../../props/components/layout.prop.js";
|
|
3
|
+
export type { AppLauncherApp, AppLauncherGroup, AppLauncherLabels, AppLauncherProp, AppLauncherProp as AppLauncherProps, } from "../../props/components/layout.prop.js";
|
|
4
|
+
/** Arbitrary `data-*` hooks — the one escape hatch this closed component keeps open. */
|
|
5
|
+
type DataAttributes = {
|
|
6
|
+
[key: `data-${string}`]: string | number | boolean | undefined;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* AppLauncher — the nine-dot app grid in the topbar: the platform's standard way to change app.
|
|
10
|
+
*
|
|
11
|
+
* THE TRIGGER IS A `TopbarItem`, NOT A `Button`. A bar cell is as tall as the bar, its hover IS the
|
|
12
|
+
* bar's surface, and its focus mark is hosted inside it; a `Button variant="ghost"` in the same slot
|
|
13
|
+
* draws a `--control-height` pill floating in a taller strip, with its own hover fill and its own
|
|
14
|
+
* ring drawn around that pill. That was the 20.0.0 correction, and it is why nothing here emits a
|
|
15
|
+
* height: the cell stretches to whatever the bar's height happens to be (`--app-shell-bar-height`,
|
|
16
|
+
* `--topbar-height`, or the coarse-pointer override), so it names none of them.
|
|
17
|
+
*
|
|
18
|
+
* The panel is the SAME responsive contract as `OrgSwitcher`: a desktop popover above
|
|
19
|
+
* `--sheet-responsive-breakpoint-width` and a focus-trapped bottom Sheet at/below it, through the
|
|
20
|
+
* shared `useSheetResponsiveMode()` hook rather than a component-local media query.
|
|
21
|
+
*
|
|
22
|
+
* ## Related — two components this is repeatedly confused with
|
|
23
|
+
*
|
|
24
|
+
* - `ServiceLauncherCard` (data-display) is a launcher tile too, but a PAGE-SIZED one: status,
|
|
25
|
+
* hostname, plan, an action button, a reason it is locked. It belongs on a service-catalogue page,
|
|
26
|
+
* where choosing is a considered act. The tile here is bar-sized — mark plus name, the whole tile
|
|
27
|
+
* one link — because changing app is a reflex. Neither is built out of the other, and a grid of
|
|
28
|
+
* `ServiceLauncherCard`s inside a popover is the wrong component, not a smaller version of this.
|
|
29
|
+
* - `AppShellProp.navRail` says the SAME platform scope as a docked column. Pick ONE: the launcher
|
|
30
|
+
* for a platform with MANY apps where switching is occasional (Google Workspace), the rail for a
|
|
31
|
+
* single product where switching workspace is constant enough to be worth permanent screen width
|
|
32
|
+
* (Slack). Shipping both puts one scope in two places and makes neither authoritative.
|
|
33
|
+
*/
|
|
34
|
+
export declare function AppLauncher({ apps, groups, labels, columns, linkComponent, loading, error, onRetry, responsive, open, onOpenChange, className, ...rest }: AppLauncherProp & Pick<React.ComponentPropsWithoutRef<"button">, "id"> & DataAttributes): React.JSX.Element;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Grip, Loader2, RotateCcw } from "lucide-react";
|
|
5
|
+
import { cn } from "../../lib/utils.js";
|
|
6
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../data-display/popover.js";
|
|
7
|
+
import {
|
|
8
|
+
Sheet,
|
|
9
|
+
SheetBody,
|
|
10
|
+
SheetContent,
|
|
11
|
+
SheetHeader,
|
|
12
|
+
SheetTrigger,
|
|
13
|
+
useSheetResponsiveMode
|
|
14
|
+
} from "../feedback/sheet.js";
|
|
15
|
+
import { Button } from "../general/button.js";
|
|
16
|
+
import { TopbarItem } from "./topbar-item.js";
|
|
17
|
+
function AppMark({ app }) {
|
|
18
|
+
return /* @__PURE__ */ jsx("span", { className: "ui-app-launcher-mark", "aria-hidden": "true", children: app.icon ?? app.name.trim().charAt(0).toUpperCase() });
|
|
19
|
+
}
|
|
20
|
+
function AppLauncherTile({
|
|
21
|
+
app,
|
|
22
|
+
linkComponent: Link,
|
|
23
|
+
externalHint,
|
|
24
|
+
close
|
|
25
|
+
}) {
|
|
26
|
+
const children = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
27
|
+
/* @__PURE__ */ jsx(AppMark, { app }),
|
|
28
|
+
/* @__PURE__ */ jsx("span", { className: "ui-app-launcher-name", children: app.name }),
|
|
29
|
+
app.external && externalHint != null ? /* @__PURE__ */ jsx("span", { className: "sr-only", children: externalHint }) : null
|
|
30
|
+
] });
|
|
31
|
+
const linkProps = {
|
|
32
|
+
href: app.href,
|
|
33
|
+
className: "ui-app-launcher-tile ui-focus-ring",
|
|
34
|
+
"data-active": app.current ? "true" : void 0,
|
|
35
|
+
"aria-current": app.current ? "page" : void 0,
|
|
36
|
+
onClick: close,
|
|
37
|
+
children
|
|
38
|
+
};
|
|
39
|
+
return /* @__PURE__ */ jsx("li", { className: "ui-app-launcher-cell", "data-app": app.id, children: app.external || Link == null ? /* @__PURE__ */ jsx(
|
|
40
|
+
"a",
|
|
41
|
+
{
|
|
42
|
+
...linkProps,
|
|
43
|
+
target: app.external ? "_blank" : void 0,
|
|
44
|
+
rel: app.external ? "noreferrer noopener" : void 0
|
|
45
|
+
}
|
|
46
|
+
) : /* @__PURE__ */ jsx(Link, { ...linkProps }) });
|
|
47
|
+
}
|
|
48
|
+
function AppLauncherGrid({
|
|
49
|
+
apps,
|
|
50
|
+
linkComponent,
|
|
51
|
+
externalHint,
|
|
52
|
+
close,
|
|
53
|
+
...props
|
|
54
|
+
}) {
|
|
55
|
+
return /* @__PURE__ */ jsx("ul", { className: "ui-app-launcher-grid", ...props, children: apps.map((app) => /* @__PURE__ */ jsx(
|
|
56
|
+
AppLauncherTile,
|
|
57
|
+
{
|
|
58
|
+
app,
|
|
59
|
+
linkComponent,
|
|
60
|
+
externalHint,
|
|
61
|
+
close
|
|
62
|
+
},
|
|
63
|
+
app.id
|
|
64
|
+
)) });
|
|
65
|
+
}
|
|
66
|
+
function AppLauncherSection({
|
|
67
|
+
label,
|
|
68
|
+
apps,
|
|
69
|
+
linkComponent,
|
|
70
|
+
externalHint,
|
|
71
|
+
close
|
|
72
|
+
}) {
|
|
73
|
+
const labelId = React.useId();
|
|
74
|
+
return /* @__PURE__ */ jsxs("div", { role: "group", "aria-labelledby": labelId, className: "ui-app-launcher-group", children: [
|
|
75
|
+
/* @__PURE__ */ jsx("span", { id: labelId, className: "ui-app-launcher-group-label", children: label }),
|
|
76
|
+
/* @__PURE__ */ jsx(
|
|
77
|
+
AppLauncherGrid,
|
|
78
|
+
{
|
|
79
|
+
apps,
|
|
80
|
+
linkComponent,
|
|
81
|
+
externalHint,
|
|
82
|
+
close
|
|
83
|
+
}
|
|
84
|
+
)
|
|
85
|
+
] });
|
|
86
|
+
}
|
|
87
|
+
function AppLauncherPanel({
|
|
88
|
+
apps,
|
|
89
|
+
groups,
|
|
90
|
+
labels,
|
|
91
|
+
columns,
|
|
92
|
+
linkComponent,
|
|
93
|
+
loading,
|
|
94
|
+
error,
|
|
95
|
+
onRetry,
|
|
96
|
+
close
|
|
97
|
+
}) {
|
|
98
|
+
if (loading) {
|
|
99
|
+
return /* @__PURE__ */ jsxs("div", { className: "ui-app-launcher-state", role: "status", children: [
|
|
100
|
+
/* @__PURE__ */ jsx(Loader2, { className: "ui-app-launcher-spinner", "aria-hidden": "true" }),
|
|
101
|
+
/* @__PURE__ */ jsx("span", { children: labels.loading })
|
|
102
|
+
] });
|
|
103
|
+
}
|
|
104
|
+
if (error != null) {
|
|
105
|
+
return /* @__PURE__ */ jsxs("div", { className: "ui-app-launcher-state", role: "alert", children: [
|
|
106
|
+
/* @__PURE__ */ jsx("span", { children: error }),
|
|
107
|
+
onRetry != null ? /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: onRetry, children: [
|
|
108
|
+
/* @__PURE__ */ jsx(RotateCcw, { "aria-hidden": "true" }),
|
|
109
|
+
labels.retry
|
|
110
|
+
] }) : null
|
|
111
|
+
] });
|
|
112
|
+
}
|
|
113
|
+
if (!apps.length && (groups ?? []).every((group) => !group.apps.length)) {
|
|
114
|
+
return /* @__PURE__ */ jsx("div", { className: "ui-app-launcher-state", role: "status", children: /* @__PURE__ */ jsx("span", { children: labels.empty }) });
|
|
115
|
+
}
|
|
116
|
+
return /* @__PURE__ */ jsxs(
|
|
117
|
+
"div",
|
|
118
|
+
{
|
|
119
|
+
className: "ui-app-launcher-panel",
|
|
120
|
+
style: columns == null ? void 0 : { "--app-launcher-columns": String(columns) },
|
|
121
|
+
children: [
|
|
122
|
+
apps.length ? /* @__PURE__ */ jsx(
|
|
123
|
+
AppLauncherGrid,
|
|
124
|
+
{
|
|
125
|
+
apps,
|
|
126
|
+
linkComponent,
|
|
127
|
+
externalHint: labels.externalHint,
|
|
128
|
+
close,
|
|
129
|
+
"aria-label": labels.title
|
|
130
|
+
}
|
|
131
|
+
) : null,
|
|
132
|
+
groups?.map((group) => /* @__PURE__ */ jsx(
|
|
133
|
+
AppLauncherSection,
|
|
134
|
+
{
|
|
135
|
+
label: group.label,
|
|
136
|
+
apps: group.apps,
|
|
137
|
+
linkComponent,
|
|
138
|
+
externalHint: labels.externalHint,
|
|
139
|
+
close
|
|
140
|
+
},
|
|
141
|
+
group.label
|
|
142
|
+
))
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
function AppLauncher({
|
|
148
|
+
apps,
|
|
149
|
+
groups,
|
|
150
|
+
labels,
|
|
151
|
+
columns,
|
|
152
|
+
linkComponent,
|
|
153
|
+
loading = false,
|
|
154
|
+
error,
|
|
155
|
+
onRetry,
|
|
156
|
+
responsive = "auto",
|
|
157
|
+
open,
|
|
158
|
+
onOpenChange,
|
|
159
|
+
className,
|
|
160
|
+
...rest
|
|
161
|
+
}) {
|
|
162
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false);
|
|
163
|
+
const controlled = open !== void 0;
|
|
164
|
+
const resolvedOpen = controlled ? open : uncontrolledOpen;
|
|
165
|
+
const setOpen = React.useCallback(
|
|
166
|
+
(nextOpen) => {
|
|
167
|
+
if (!controlled) {
|
|
168
|
+
setUncontrolledOpen(nextOpen);
|
|
169
|
+
}
|
|
170
|
+
onOpenChange?.(nextOpen);
|
|
171
|
+
},
|
|
172
|
+
[controlled, onOpenChange]
|
|
173
|
+
);
|
|
174
|
+
const compactViewport = useSheetResponsiveMode("auto") === "bottom";
|
|
175
|
+
const sheet = responsive === "sheet" || responsive === "auto" && compactViewport;
|
|
176
|
+
const close = React.useCallback(() => {
|
|
177
|
+
setOpen(false);
|
|
178
|
+
}, [setOpen]);
|
|
179
|
+
const trigger = /* @__PURE__ */ jsx(
|
|
180
|
+
TopbarItem,
|
|
181
|
+
{
|
|
182
|
+
className: cn("ui-app-launcher-trigger", className),
|
|
183
|
+
"aria-label": labels.trigger,
|
|
184
|
+
...rest,
|
|
185
|
+
children: /* @__PURE__ */ jsx(Grip, { "aria-hidden": "true" })
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
const panel = /* @__PURE__ */ jsx(
|
|
189
|
+
AppLauncherPanel,
|
|
190
|
+
{
|
|
191
|
+
apps,
|
|
192
|
+
groups,
|
|
193
|
+
labels,
|
|
194
|
+
columns,
|
|
195
|
+
linkComponent,
|
|
196
|
+
loading,
|
|
197
|
+
error,
|
|
198
|
+
onRetry,
|
|
199
|
+
close
|
|
200
|
+
}
|
|
201
|
+
);
|
|
202
|
+
if (sheet) {
|
|
203
|
+
return /* @__PURE__ */ jsxs(Sheet, { open: resolvedOpen, onOpenChange: setOpen, children: [
|
|
204
|
+
/* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: trigger }),
|
|
205
|
+
/* @__PURE__ */ jsxs(
|
|
206
|
+
SheetContent,
|
|
207
|
+
{
|
|
208
|
+
responsive: "bottom",
|
|
209
|
+
className: "ui-app-launcher-sheet",
|
|
210
|
+
style: {
|
|
211
|
+
"--sheet-bottom-max-height": "var(--app-launcher-sheet-max-height)"
|
|
212
|
+
},
|
|
213
|
+
children: [
|
|
214
|
+
/* @__PURE__ */ jsx(SheetHeader, { title: labels.title }),
|
|
215
|
+
/* @__PURE__ */ jsx(SheetBody, { children: panel })
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
)
|
|
219
|
+
] });
|
|
220
|
+
}
|
|
221
|
+
return /* @__PURE__ */ jsxs(Popover, { open: resolvedOpen, onOpenChange: setOpen, children: [
|
|
222
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: trigger }),
|
|
223
|
+
/* @__PURE__ */ jsx(PopoverContent, { align: "end", className: "ui-app-launcher-popover", "aria-label": labels.title, children: panel })
|
|
224
|
+
] });
|
|
225
|
+
}
|
|
226
|
+
export {
|
|
227
|
+
AppLauncher
|
|
228
|
+
};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import type { AppShellProp } from "../../props/components/layout.prop.js";
|
|
3
3
|
export type { AppShellProp, AppShellProp as AppShellProps, } from "../../props/components/layout.prop.js";
|
|
4
|
+
/** Same rail boundary as shell-layout.css; SSR starts in docked mode. */
|
|
5
|
+
export declare function useAppShellNavigationMode(): "drawer" | "docked";
|
|
4
6
|
export declare function AppShell({ sidebar, topbar, topbarLeft, topbarRight, logo, breadcrumb, footer, children, sidebarCollapsed, responsiveNavigation, topbarSpan, navRail, navRailLabel, mobileNav, mobileNavLabel, mobileNavOpen, onMobileNavOpenChange, }: AppShellProp): React.JSX.Element;
|
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Menu } from "lucide-react";
|
|
5
|
+
import { useMediaQuery } from "../../lib/hooks.js";
|
|
5
6
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
6
7
|
import { Button } from "../general/button.js";
|
|
7
8
|
import { Sheet, SheetBody, SheetContent, SheetHeader, SheetTrigger } from "../feedback/sheet.js";
|
|
8
9
|
import { NavSurfaceProvider } from "./nav-surface.js";
|
|
10
|
+
function useAppShellNavigationMode() {
|
|
11
|
+
return useMediaQuery("(width <= 56.25rem)") ? "drawer" : "docked";
|
|
12
|
+
}
|
|
9
13
|
function AppShell({
|
|
10
14
|
sidebar,
|
|
11
15
|
topbar,
|
|
@@ -26,11 +30,13 @@ function AppShell({
|
|
|
26
30
|
onMobileNavOpenChange
|
|
27
31
|
}) {
|
|
28
32
|
const { t } = useTranslation();
|
|
33
|
+
const navigationMode = useAppShellNavigationMode();
|
|
34
|
+
const hasSidebar = sidebar !== void 0 && sidebar !== null && sidebar !== false;
|
|
29
35
|
const drawerNav = mobileNav !== void 0 ? mobileNav : navRail !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
30
36
|
navRail,
|
|
31
37
|
sidebar
|
|
32
38
|
] }) : sidebar;
|
|
33
|
-
const hasDrawer = responsiveNavigation === "drawer" && drawerNav != null;
|
|
39
|
+
const hasDrawer = responsiveNavigation === "drawer" && drawerNav != null && drawerNav !== false;
|
|
34
40
|
const railInDrawer = mobileNav === void 0 && navRail !== void 0;
|
|
35
41
|
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false);
|
|
36
42
|
const drawerOpen = mobileNavOpen ?? uncontrolledOpen;
|
|
@@ -38,7 +44,11 @@ function AppShell({
|
|
|
38
44
|
const handleDrawerClick = (event) => {
|
|
39
45
|
const target = event.target;
|
|
40
46
|
const hit = target.closest("a[href], button, [role='menuitem']");
|
|
41
|
-
if (
|
|
47
|
+
if (!hit) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const opensSomething = hit.hasAttribute("aria-expanded") || hit.hasAttribute("aria-haspopup") || hit.classList.contains("sb-nav-group-trigger");
|
|
51
|
+
if (!opensSomething) {
|
|
42
52
|
setDrawerOpen(false);
|
|
43
53
|
}
|
|
44
54
|
};
|
|
@@ -54,7 +64,7 @@ function AppShell({
|
|
|
54
64
|
);
|
|
55
65
|
}
|
|
56
66
|
}
|
|
57
|
-
const logoInRail = logo !== void 0 && topbarSpan !== "full";
|
|
67
|
+
const logoInRail = hasSidebar && logo !== void 0 && topbarSpan !== "full";
|
|
58
68
|
const resolvedTopbar = topbar !== void 0 ? /* @__PURE__ */ jsxs("div", { className: "app-topbar-rail", children: [
|
|
59
69
|
!logoInRail && logo !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-logo", children: logo }),
|
|
60
70
|
/* @__PURE__ */ jsx("div", { className: "app-topbar-custom", children: topbar })
|
|
@@ -64,10 +74,10 @@ function AppShell({
|
|
|
64
74
|
/* @__PURE__ */ jsx("div", { className: "app-topbar-spacer" }),
|
|
65
75
|
topbarRight !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-right", children: topbarRight })
|
|
66
76
|
] });
|
|
67
|
-
const rail = /* @__PURE__ */ jsxs("aside", { className: "app-sidebar", "aria-label": t("layout.appShell.sidebarLabel"), children: [
|
|
77
|
+
const rail = hasSidebar ? /* @__PURE__ */ jsxs("aside", { className: "app-sidebar", "aria-label": t("layout.appShell.sidebarLabel"), children: [
|
|
68
78
|
logoInRail && /* @__PURE__ */ jsx("div", { className: "app-sidebar-logo", children: logo }),
|
|
69
79
|
sidebar
|
|
70
|
-
] });
|
|
80
|
+
] }) : null;
|
|
71
81
|
const navRailRegion = navRail === void 0 ? null : /* @__PURE__ */ jsx(
|
|
72
82
|
"aside",
|
|
73
83
|
{
|
|
@@ -120,8 +130,10 @@ function AppShell({
|
|
|
120
130
|
"div",
|
|
121
131
|
{
|
|
122
132
|
className: "app-root",
|
|
123
|
-
"data-collapsed": sidebarCollapsed ? "true" : void 0,
|
|
133
|
+
"data-collapsed": hasSidebar && sidebarCollapsed ? "true" : void 0,
|
|
134
|
+
"data-sidebar": hasSidebar ? void 0 : "none",
|
|
124
135
|
"data-responsive-navigation": responsiveNavigation,
|
|
136
|
+
"data-navigation": navigationMode,
|
|
125
137
|
"data-topbar": hasTopbarContent ? void 0 : "none",
|
|
126
138
|
"data-topbar-span": topbarSpan === "full" ? "full" : void 0,
|
|
127
139
|
"data-nav-rail": navRail !== void 0 ? "" : void 0,
|
|
@@ -145,5 +157,6 @@ function AppShell({
|
|
|
145
157
|
);
|
|
146
158
|
}
|
|
147
159
|
export {
|
|
148
|
-
AppShell
|
|
160
|
+
AppShell,
|
|
161
|
+
useAppShellNavigationMode
|
|
149
162
|
};
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
import type { ElementType } from "react";
|
|
2
|
-
import type { BreadcrumbProp } from "../../props/vocabulary/navigation.prop.js";
|
|
2
|
+
import type { BreadcrumbItemRenderProp, BreadcrumbProp, BreadcrumbSeparatorProp } from "../../props/vocabulary/navigation.prop.js";
|
|
3
3
|
export type BreadcrumbProps = {
|
|
4
4
|
items: BreadcrumbProp;
|
|
5
5
|
linkComponent?: ElementType;
|
|
6
6
|
/** Override the `<nav>` landmark's accessible name. Defaults to a localized "Breadcrumb". */
|
|
7
7
|
ariaLabel?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Ant Design `separator`. Defaults to the chevron glyph. A string (`"/"`) or any node replaces
|
|
10
|
+
* it; `""` removes it. It is always `aria-hidden` — the trail's structure is carried by the
|
|
11
|
+
* `<ol>`/`<li>`, never by the glyph, so a screen reader never hears "slash" between segments.
|
|
12
|
+
*/
|
|
13
|
+
separator?: BreadcrumbSeparatorProp;
|
|
14
|
+
/**
|
|
15
|
+
* Ant Design `itemRender`. Replaces the anchor/text of ONE segment while this component keeps
|
|
16
|
+
* owning the `<nav>`, the `<ol>`/`<li>`, the separators and `aria-current` — the parts that make
|
|
17
|
+
* the trail a landmark. Use it to hand the trail a router `<Link>` (Inertia, react-router).
|
|
18
|
+
*/
|
|
19
|
+
itemRender?: BreadcrumbItemRenderProp;
|
|
8
20
|
};
|
|
9
|
-
export declare function Breadcrumb({ items, linkComponent: LinkComponent, ariaLabel, }: BreadcrumbProps): import("react").JSX.Element;
|
|
21
|
+
export declare function Breadcrumb({ items, linkComponent: LinkComponent, ariaLabel, separator, itemRender, }: BreadcrumbProps): import("react").JSX.Element;
|
|
@@ -1,21 +1,63 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { ChevronRight } from "lucide-react";
|
|
3
|
+
import { ChevronDown, ChevronRight } from "lucide-react";
|
|
4
4
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
5
|
+
import {
|
|
6
|
+
DropdownMenu,
|
|
7
|
+
DropdownMenuContent,
|
|
8
|
+
DropdownMenuItem,
|
|
9
|
+
DropdownMenuTrigger
|
|
10
|
+
} from "../navigation/dropdown-menu.js";
|
|
5
11
|
function Breadcrumb({
|
|
6
12
|
items,
|
|
7
13
|
linkComponent: LinkComponent = "a",
|
|
8
|
-
ariaLabel
|
|
14
|
+
ariaLabel,
|
|
15
|
+
separator,
|
|
16
|
+
itemRender
|
|
9
17
|
}) {
|
|
10
18
|
const { t } = useTranslation();
|
|
19
|
+
const separatorNode = separator === void 0 ? /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true" }) : separator;
|
|
11
20
|
return /* @__PURE__ */ jsx("nav", { "aria-label": ariaLabel ?? t("navigation.breadcrumb.ariaLabel"), className: "ui-breadcrumb", children: /* @__PURE__ */ jsx("ol", { className: "ui-breadcrumb-list", children: items.map((item, index) => {
|
|
12
21
|
const isLast = index === items.length - 1;
|
|
13
22
|
return /* @__PURE__ */ jsxs("li", { className: "ui-breadcrumb-item", children: [
|
|
14
|
-
|
|
15
|
-
!isLast ? /* @__PURE__ */ jsx(
|
|
23
|
+
renderBreadcrumbSegment({ item, index, isLast, items, itemRender, LinkComponent }),
|
|
24
|
+
!isLast ? /* @__PURE__ */ jsx("span", { className: "ui-breadcrumb-separator", "aria-hidden": "true", children: separatorNode }) : null
|
|
16
25
|
] }, item.to ?? index);
|
|
17
26
|
}) }) });
|
|
18
27
|
}
|
|
28
|
+
function renderBreadcrumbSegment({
|
|
29
|
+
item,
|
|
30
|
+
index,
|
|
31
|
+
isLast,
|
|
32
|
+
items,
|
|
33
|
+
itemRender,
|
|
34
|
+
LinkComponent
|
|
35
|
+
}) {
|
|
36
|
+
if (itemRender) return itemRender(item, { index, isLast, items });
|
|
37
|
+
if (item.menu) {
|
|
38
|
+
const { items: menuItems, onSelect } = item.menu;
|
|
39
|
+
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
40
|
+
/* @__PURE__ */ jsxs(DropdownMenuTrigger, { className: "ui-breadcrumb-menu-trigger ui-focus-ring", children: [
|
|
41
|
+
item.label,
|
|
42
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: "ui-breadcrumb-menu-icon", "aria-hidden": "true" })
|
|
43
|
+
] }),
|
|
44
|
+
/* @__PURE__ */ jsx(DropdownMenuContent, { placement: "bottomStart", children: menuItems.map((entry) => /* @__PURE__ */ jsx(
|
|
45
|
+
DropdownMenuItem,
|
|
46
|
+
{
|
|
47
|
+
disabled: entry.disabled,
|
|
48
|
+
onSelect: onSelect ? () => onSelect(entry.value) : void 0,
|
|
49
|
+
asChild: entry.to !== void 0,
|
|
50
|
+
children: entry.to !== void 0 ? /* @__PURE__ */ jsx(LinkComponent, { href: entry.to, to: entry.to, children: entry.label }) : entry.label
|
|
51
|
+
},
|
|
52
|
+
entry.value
|
|
53
|
+
)) })
|
|
54
|
+
] });
|
|
55
|
+
}
|
|
56
|
+
if (item.to && !isLast) {
|
|
57
|
+
return /* @__PURE__ */ jsx(LinkComponent, { href: item.to, to: item.to, className: "ui-breadcrumb-link", children: item.label });
|
|
58
|
+
}
|
|
59
|
+
return /* @__PURE__ */ jsx("span", { className: "ui-breadcrumb-current", "aria-current": isLast ? "page" : void 0, children: item.label });
|
|
60
|
+
}
|
|
19
61
|
export {
|
|
20
62
|
Breadcrumb
|
|
21
63
|
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { FlexProp } from "../../props/components/layout.prop.js";
|
|
2
2
|
export type { FlexAlignProp, FlexDirectionProp, FlexJustifyProp, FlexProp, FlexProp as FlexProps, } from "../../props/components/layout.prop.js";
|
|
3
|
-
export declare function Flex({ as: Element, direction, gap, gapRaw, pad, padRaw, align, justify, wrap, hideBelow, hideFrom, fill, width, className, style, children, ...props }: FlexProp): import("react").JSX.Element;
|
|
3
|
+
export declare function Flex({ as: Element, direction, grow, shrink, surface, bleed, reveal, gap, gapRaw, pad, padRaw, align, justify, wrap, hideBelow, hideFrom, fill, width, className, style, children, ...props }: FlexProp): import("react").JSX.Element;
|