@godxjp/ui 33.20.0 → 33.22.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/README.md +4 -4
- package/agent/START-HERE.md +7 -7
- package/agent/components/AppSettingPicker.json +0 -1
- package/agent/components/AppShell.json +11 -1
- package/agent/components/BlockEditor.json +6 -1
- package/agent/components/Button.json +1 -1
- package/agent/components/CardShowcase.json +44 -0
- package/agent/components/CatalogCard.json +83 -0
- package/agent/components/CatalogDetail.json +76 -0
- package/agent/components/CatalogDetailSection.json +52 -0
- package/agent/components/CatalogDetailTag.json +27 -0
- package/agent/components/EditorialArticle.json +53 -0
- package/agent/components/EditorialAuth.json +53 -0
- package/agent/components/EditorialAuthCard.json +52 -0
- package/agent/components/EditorialBanner.json +53 -0
- package/agent/components/EditorialBreadcrumb.json +38 -0
- package/agent/components/EditorialCard.json +70 -0
- package/agent/components/EditorialEmptyPanel.json +57 -0
- package/agent/components/EditorialFilterBar.json +51 -0
- package/agent/components/EditorialFilterField.json +39 -0
- package/agent/components/EditorialFilterPanel.json +46 -0
- package/agent/components/EditorialFooter.json +54 -0
- package/agent/components/EditorialFootnote.json +36 -0
- package/agent/components/EditorialHero.json +52 -0
- package/agent/components/EditorialInlineSearch.json +54 -0
- package/agent/components/EditorialMasthead.json +52 -0
- package/agent/components/EditorialMetaBar.json +37 -0
- package/agent/components/EditorialPageHeader.json +73 -0
- package/agent/components/EditorialPanel.json +48 -0
- package/agent/components/EditorialPillNav.json +41 -0
- package/agent/components/EditorialPrompt.json +54 -0
- package/agent/components/EditorialSearch.json +112 -0
- package/agent/components/EditorialSection.json +68 -0
- package/agent/components/EditorialSectionHead.json +62 -0
- package/agent/components/EditorialStats.json +32 -0
- package/agent/components/EditorialTextButton.json +47 -0
- package/agent/components/EditorialToggleGroup.json +52 -0
- package/agent/components/EditorialToolbar.json +45 -0
- package/agent/components/Eyebrow.json +39 -0
- package/agent/components/HoldingCard.json +69 -0
- package/agent/components/HoldingCardAction.json +51 -0
- package/agent/components/HoldingGrid.json +37 -0
- package/agent/components/Markdown.json +6 -0
- package/agent/components/NumberInput.json +5 -0
- package/agent/components/PriceSummary.json +32 -0
- package/agent/components/SettingsLayout.json +31 -0
- package/agent/components/SettingsPanel.json +53 -0
- package/agent/components/ThemePicker.json +54 -0
- package/agent/components/TopbarItem.json +5 -0
- package/agent/components-index.json +292 -98
- package/agent/components.json +2059 -4
- package/agent/index.json +7 -7
- package/agent/llms.txt +8 -8
- package/agent/tokens.json +5640 -132
- package/dist/components/data-display/badge.js +4 -2
- package/dist/components/data-display/image.js +6 -0
- package/dist/components/data-entry/form-field.js +2 -2
- package/dist/components/data-entry/number-input.d.ts +1 -0
- package/dist/components/data-entry/number-input.js +8 -0
- package/dist/components/data-entry/select.js +24 -2
- package/dist/components/general/button.js +14 -1
- package/dist/components/general/typography.d.ts +1 -1
- package/dist/components/layout/app-shell.d.ts +1 -1
- package/dist/components/layout/app-shell.js +28 -2
- package/dist/components/layout/centered-shell.js +4 -0
- package/dist/components/layout/editorial-account.d.ts +51 -0
- package/dist/components/layout/editorial-account.js +466 -0
- package/dist/components/layout/editorial-catalog.d.ts +18 -0
- package/dist/components/layout/editorial-catalog.js +164 -0
- package/dist/components/layout/editorial.d.ts +56 -0
- package/dist/components/layout/editorial.js +867 -0
- package/dist/components/layout/index.d.ts +6 -0
- package/dist/components/layout/index.js +98 -0
- package/dist/components/layout/mobile-shell.d.ts +2 -0
- package/dist/components/layout/mobile-shell.js +18 -11
- package/dist/components/layout/responsive-grid.js +9 -1
- package/dist/components/layout/topbar-item.d.ts +1 -0
- package/dist/components/layout/topbar-item.js +2 -0
- package/dist/contracts/measurement.json +1 -1
- package/dist/lab/legal-document-shell.js +61 -51
- package/dist/lib/toast-clearance.js +1 -1
- package/dist/props/components/data-display.prop.d.ts +2 -0
- package/dist/props/components/data-entry.prop.d.ts +9 -0
- package/dist/props/components/editorial-account.prop.d.ts +249 -0
- package/dist/props/components/editorial-account.prop.js +0 -0
- package/dist/props/components/general.prop.d.ts +6 -2
- package/dist/props/components/layout.prop.d.ts +602 -2
- package/dist/props/registry.d.ts +1124 -0
- package/dist/props/registry.js +792 -0
- package/dist/styles/badge-layout.css +2 -0
- package/dist/styles/control.css +60 -13
- package/dist/styles/core.css +1 -0
- package/dist/styles/data-display-layout.css +9 -3
- package/dist/styles/editorial-account-layout.css +1130 -0
- package/dist/styles/focus-ring.css +33 -10
- package/dist/styles/form-layout.css +8 -1
- package/dist/styles/index.css +1 -0
- package/dist/styles/layers.json +248 -1
- package/dist/styles/layout.css +2031 -0
- package/dist/styles/logo-layout.css +27 -0
- package/dist/styles/shell-layout.css +101 -3
- package/dist/styles/table-layout.css +25 -13
- package/dist/styles/text-layout.css +6 -0
- package/dist/styles.css +1 -1
- package/dist/tokens/base.css +2 -0
- package/dist/tokens/components/badge.css +3 -0
- package/dist/tokens/components/control.css +9 -0
- package/dist/tokens/components/editorial-account.css +393 -0
- package/dist/tokens/components/editorial.css +721 -0
- package/dist/tokens/components/form.css +4 -0
- package/dist/tokens/components/logo.css +2 -0
- package/dist/tokens/components/shell.css +23 -0
- package/dist/tokens/components/table.css +1 -1
- package/docs/TOKENS.md +26 -0
- package/package.json +2 -2
- package/scripts/ui-audit.mjs +3 -2
|
@@ -62,8 +62,10 @@ const badgeVariants = cva(
|
|
|
62
62
|
variant: {
|
|
63
63
|
default: "border-transparent bg-primary text-primary-foreground",
|
|
64
64
|
secondary: "border-transparent bg-secondary text-secondary-foreground",
|
|
65
|
-
outline
|
|
66
|
-
|
|
65
|
+
// gh#1439 — the outline / dashed ink is a role-mirror knob (default --foreground), so a
|
|
66
|
+
// brand whose plain chip reads muted sets it once instead of wrapping every label.
|
|
67
|
+
outline: "text-[color:var(--badge-outline-foreground,hsl(var(--foreground)))]",
|
|
68
|
+
dashed: "border-dashed text-[color:var(--badge-outline-foreground,hsl(var(--foreground)))]",
|
|
67
69
|
/* `color` mode. Deliberately empty and deliberately NOT in the public
|
|
68
70
|
* `BadgeVariant` union: every fill, border and text utility has to stay
|
|
69
71
|
* off the element so badge-layout.css's `[data-tinted]` rule is
|
|
@@ -429,6 +429,9 @@ const ImageRoot = React.forwardRef(function Image({
|
|
|
429
429
|
className,
|
|
430
430
|
onLoad,
|
|
431
431
|
onError,
|
|
432
|
+
fetchPriority,
|
|
433
|
+
loading = fetchPriority === "high" ? "eager" : "lazy",
|
|
434
|
+
decoding = "async",
|
|
432
435
|
...imgProps
|
|
433
436
|
}, ref) {
|
|
434
437
|
const { t } = useTranslation();
|
|
@@ -486,6 +489,9 @@ const ImageRoot = React.forwardRef(function Image({
|
|
|
486
489
|
"img",
|
|
487
490
|
{
|
|
488
491
|
...imgProps,
|
|
492
|
+
loading,
|
|
493
|
+
decoding,
|
|
494
|
+
fetchPriority,
|
|
489
495
|
width,
|
|
490
496
|
height,
|
|
491
497
|
ref: setImgRef,
|
|
@@ -54,7 +54,7 @@ function FormField({
|
|
|
54
54
|
const labelId = `${resolvedId}-label`;
|
|
55
55
|
const hasLabel = !(label === void 0 || label === null || label === false || label === "");
|
|
56
56
|
const helperId = helper ? `${resolvedId}-helper` : void 0;
|
|
57
|
-
const helperNode = helper ? /* @__PURE__ */ jsx("p", { id: helperId, className: "ui-form-field-note text-muted-foreground
|
|
57
|
+
const helperNode = helper ? /* @__PURE__ */ jsx("p", { id: helperId, className: "ui-form-field-note text-muted-foreground", children: helper }) : null;
|
|
58
58
|
const validationStatus = error ? "error" : validateStatus;
|
|
59
59
|
const feedbackId = hasFeedback && validationStatus ? `${resolvedId}-feedback` : void 0;
|
|
60
60
|
const FeedbackIcon = validationStatus === "validating" ? LoaderCircle : validationStatus === "error" ? CircleAlert : validationStatus === "warning" ? TriangleAlert : CheckCircle;
|
|
@@ -200,7 +200,7 @@ function FormField({
|
|
|
200
200
|
}
|
|
201
201
|
) : null,
|
|
202
202
|
helperPlacement === "after" ? helperNode : null,
|
|
203
|
-
error ? /* @__PURE__ */ jsx("p", { id: errorId, role: "alert", className: "ui-form-field-note text-error-strong
|
|
203
|
+
error ? /* @__PURE__ */ jsx("p", { id: errorId, role: "alert", className: "ui-form-field-note text-error-strong", children: error }) : null
|
|
204
204
|
] })
|
|
205
205
|
]
|
|
206
206
|
}
|
|
@@ -25,6 +25,7 @@ export declare const NumberInput: React.ForwardRefExoticComponent<import(".").Fi
|
|
|
25
25
|
placeholder?: import("../../props/index.js").PlaceholderProp;
|
|
26
26
|
prefix?: React.ReactNode;
|
|
27
27
|
suffix?: React.ReactNode;
|
|
28
|
+
width?: import("../../props/index.js").ControlWidthProp;
|
|
28
29
|
name?: import("../../props/index.js").NameProp;
|
|
29
30
|
id?: import("../../props/index.js").IdProp;
|
|
30
31
|
className?: import("../../props/index.js").ClassNameProp;
|
|
@@ -15,6 +15,7 @@ function decimalsOf(n) {
|
|
|
15
15
|
const dot = s.indexOf(".");
|
|
16
16
|
return dot === -1 ? 0 : s.length - dot - 1;
|
|
17
17
|
}
|
|
18
|
+
const AUTO_CHARS_UNBOUNDED = 6;
|
|
18
19
|
function clamp(n, min, max) {
|
|
19
20
|
let out = n;
|
|
20
21
|
if (min != null && out < min) out = min;
|
|
@@ -51,6 +52,7 @@ const NumberInput = React.forwardRef(
|
|
|
51
52
|
placeholder,
|
|
52
53
|
prefix,
|
|
53
54
|
suffix,
|
|
55
|
+
width = "full",
|
|
54
56
|
name,
|
|
55
57
|
id,
|
|
56
58
|
className,
|
|
@@ -182,6 +184,10 @@ const NumberInput = React.forwardRef(
|
|
|
182
184
|
if (!changeOnWheel || !interactive || !focused || event.deltaY === 0) return;
|
|
183
185
|
stepBy(event.deltaY < 0 ? 1 : -1);
|
|
184
186
|
};
|
|
187
|
+
const autoChars = width !== "auto" ? null : min == null && max == null ? AUTO_CHARS_UNBOUNDED : Math.max(
|
|
188
|
+
...[min, max].filter((bound) => bound != null && Number.isFinite(bound)).map((bound) => formatAtRest(bound).length),
|
|
189
|
+
1
|
|
190
|
+
);
|
|
185
191
|
return /* @__PURE__ */ jsxs(
|
|
186
192
|
"div",
|
|
187
193
|
{
|
|
@@ -190,7 +196,9 @@ const NumberInput = React.forwardRef(
|
|
|
190
196
|
"data-status": status,
|
|
191
197
|
"data-variant": variant,
|
|
192
198
|
"data-controls": controls ? void 0 : "off",
|
|
199
|
+
"data-width": width === "full" ? void 0 : width,
|
|
193
200
|
className: cn("ui-number-input", className),
|
|
201
|
+
style: autoChars == null ? void 0 : { "--number-input-chars": autoChars },
|
|
194
202
|
children: [
|
|
195
203
|
prefix != null ? /* @__PURE__ */ jsx(
|
|
196
204
|
"span",
|
|
@@ -319,6 +319,7 @@ const SelectTrigger = React.forwardRef(
|
|
|
319
319
|
},
|
|
320
320
|
[ref]
|
|
321
321
|
);
|
|
322
|
+
const openedWithPointer = React.useRef(false);
|
|
322
323
|
const wasOpen = React.useRef(false);
|
|
323
324
|
React.useEffect(() => {
|
|
324
325
|
if (!wasOpen.current || isOpen) {
|
|
@@ -354,6 +355,7 @@ const SelectTrigger = React.forwardRef(
|
|
|
354
355
|
ref: composedRef,
|
|
355
356
|
id,
|
|
356
357
|
onPointerDown: (event) => {
|
|
358
|
+
openedWithPointer.current = true;
|
|
357
359
|
event.currentTarget.focus();
|
|
358
360
|
},
|
|
359
361
|
...events,
|
|
@@ -384,6 +386,10 @@ const SelectTrigger = React.forwardRef(
|
|
|
384
386
|
"data-status": status,
|
|
385
387
|
"data-width": width,
|
|
386
388
|
"data-state": isOpen ? "open" : "closed",
|
|
389
|
+
"data-open-modality": isOpen ? openedWithPointer.current ? "pointer" : "keyboard" : void 0,
|
|
390
|
+
onKeyDownCapture: () => {
|
|
391
|
+
openedWithPointer.current = false;
|
|
392
|
+
},
|
|
387
393
|
"data-placeholder": hasValue ? void 0 : "",
|
|
388
394
|
"data-value": dataValue
|
|
389
395
|
}
|
|
@@ -600,6 +606,13 @@ function groupDataOptions(options) {
|
|
|
600
606
|
}
|
|
601
607
|
return order.map((key) => ({ heading: key || void 0, items: buckets.get(key) ?? [] }));
|
|
602
608
|
}
|
|
609
|
+
function withOptionIcon(option, label) {
|
|
610
|
+
if (!option.icon) return label;
|
|
611
|
+
return /* @__PURE__ */ jsxs("span", { className: "ui-select-option-body", children: [
|
|
612
|
+
/* @__PURE__ */ jsx("span", { className: "ui-select-option-icon", "aria-hidden": "true", children: option.icon }),
|
|
613
|
+
/* @__PURE__ */ jsx("span", { className: "ui-select-option-label", children: label })
|
|
614
|
+
] });
|
|
615
|
+
}
|
|
603
616
|
function DataSelectLabel({
|
|
604
617
|
labelRender,
|
|
605
618
|
options
|
|
@@ -716,7 +729,7 @@ function DataSelect(props) {
|
|
|
716
729
|
disabled: option.disabled,
|
|
717
730
|
"data-testid": optionTestId(option.value),
|
|
718
731
|
selectedIcon: menuItemSelectedIcon,
|
|
719
|
-
children: optionRender ? optionRender(option, { index }) : renderOption ? renderOption(option) : option.label
|
|
732
|
+
children: optionRender ? optionRender(option, { index }) : renderOption ? renderOption(option) : withOptionIcon(option, option.label)
|
|
720
733
|
},
|
|
721
734
|
option.value
|
|
722
735
|
);
|
|
@@ -771,7 +784,16 @@ function DataSelect(props) {
|
|
|
771
784
|
...ariaProps,
|
|
772
785
|
children: [
|
|
773
786
|
prefix === void 0 || prefix === null ? null : /* @__PURE__ */ jsx("span", { "data-slot": "select-prefix", className: "ui-select-prefix", children: prefix }),
|
|
774
|
-
/* @__PURE__ */ jsx(SelectValue, { placeholder: placeholder ?? t("dataEntry.searchSelect.placeholder"), children: labelRender ? /* @__PURE__ */ jsx(DataSelectLabel, { labelRender, options }) :
|
|
787
|
+
/* @__PURE__ */ jsx(SelectValue, { placeholder: placeholder ?? t("dataEntry.searchSelect.placeholder"), children: labelRender ? /* @__PURE__ */ jsx(DataSelectLabel, { labelRender, options }) : options.some((option) => option.icon) ? (
|
|
788
|
+
// gh#1444 — the selected option's icon leads the trigger too, as in the search panel.
|
|
789
|
+
/* @__PURE__ */ jsx(
|
|
790
|
+
DataSelectLabel,
|
|
791
|
+
{
|
|
792
|
+
labelRender: ({ label, option }) => option ? withOptionIcon(option, label) : label,
|
|
793
|
+
options
|
|
794
|
+
}
|
|
795
|
+
)
|
|
796
|
+
) : void 0 }),
|
|
775
797
|
suffixIcon === void 0 || suffixIcon === null || showClear || loading ? null : /* @__PURE__ */ jsx("span", { "data-slot": "select-suffix", className: "ui-select-suffix", "aria-hidden": "true", children: suffixIcon })
|
|
776
798
|
]
|
|
777
799
|
}
|
|
@@ -74,6 +74,11 @@ const buttonVariants = cva("ui-button", {
|
|
|
74
74
|
},
|
|
75
75
|
defaultVariants: { variant: "default", size: "default", shape: "default" }
|
|
76
76
|
});
|
|
77
|
+
function hasDirectText(children) {
|
|
78
|
+
return React.Children.toArray(children).some(
|
|
79
|
+
(child) => typeof child === "string" && child.trim() !== "" || typeof child === "number"
|
|
80
|
+
);
|
|
81
|
+
}
|
|
77
82
|
const Button = React.forwardRef(
|
|
78
83
|
({
|
|
79
84
|
className,
|
|
@@ -94,11 +99,15 @@ const Button = React.forwardRef(
|
|
|
94
99
|
disabled,
|
|
95
100
|
type,
|
|
96
101
|
children,
|
|
102
|
+
onClick,
|
|
97
103
|
...props
|
|
98
104
|
}, ref) => {
|
|
99
105
|
const { locale } = useTranslation();
|
|
100
106
|
const Comp = asChild ? Slot : "button";
|
|
101
107
|
const isLoading = !asChild && loading;
|
|
108
|
+
const handleClick = isLoading ? (event) => {
|
|
109
|
+
event.preventDefault();
|
|
110
|
+
} : onClick;
|
|
102
111
|
const content = isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
103
112
|
/* @__PURE__ */ jsx(Loader2, { className: "animate-spin", "aria-hidden": "true" }),
|
|
104
113
|
loadingText ?? children
|
|
@@ -108,6 +117,7 @@ const Button = React.forwardRef(
|
|
|
108
117
|
const spokenCount = countLabel ? `${countText} ${countLabel}` : countText;
|
|
109
118
|
const ariaLabel = props["aria-label"];
|
|
110
119
|
const foldedAriaLabel = showCount && ariaLabel != null ? { "aria-label": `${ariaLabel}, ${spokenCount}` } : null;
|
|
120
|
+
const labelled = asChild ? React.isValidElement(children) && hasDirectText(children.props.children) : hasDirectText(loadingText ?? children);
|
|
111
121
|
const countNode = showCount ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
112
122
|
/* @__PURE__ */ jsx("span", { "data-slot": "button-count", className: "ui-button-count", "aria-hidden": "true", children: countText }),
|
|
113
123
|
/* @__PURE__ */ jsx("span", { className: "sr-only", children: `, ${spokenCount}` })
|
|
@@ -124,8 +134,11 @@ const Button = React.forwardRef(
|
|
|
124
134
|
"data-wrap": wrap ? "" : void 0,
|
|
125
135
|
"data-align": align === "center" ? void 0 : align,
|
|
126
136
|
"data-loading": isLoading ? "" : void 0,
|
|
137
|
+
"data-label": labelled ? "" : void 0,
|
|
127
138
|
"aria-busy": isLoading || void 0,
|
|
128
|
-
disabled: isLoading ||
|
|
139
|
+
"aria-disabled": isLoading && !disabled || void 0,
|
|
140
|
+
disabled,
|
|
141
|
+
onClick: handleClick,
|
|
129
142
|
type: asChild ? void 0 : type ?? "button",
|
|
130
143
|
className: cn(
|
|
131
144
|
fullWidth && "w-full",
|
|
@@ -44,7 +44,7 @@ export declare const Text: React.ForwardRefExoticComponent<Omit<React.HTMLAttrib
|
|
|
44
44
|
as?: "span" | "p" | "div" | "a" | "label" | "strong" | "em" | "small" | "code" | "kbd" | "dt" | "dd" | "caption" | "abbr";
|
|
45
45
|
asChild?: import("../../props/index.js").AsChildProp;
|
|
46
46
|
link?: boolean;
|
|
47
|
-
size?: import("../../props/index.js").TextSizeProp;
|
|
47
|
+
size?: import("../../props/index.js").TextSizeProp | "inherit";
|
|
48
48
|
tone?: import("../../props/index.js").TextToneProp;
|
|
49
49
|
weight?: import("../../props/index.js").FontWeightProp;
|
|
50
50
|
align?: import("../../props/index.js").TextAlignProp;
|
|
@@ -3,4 +3,4 @@ import type { AppShellProp } from "../../props/components/layout.prop.js";
|
|
|
3
3
|
export type { AppShellProp, AppShellProp as AppShellProps, } from "../../props/components/layout.prop.js";
|
|
4
4
|
/** Same rail boundary as shell-layout.css; SSR starts in docked mode. */
|
|
5
5
|
export declare function useAppShellNavigationMode(): "drawer" | "docked";
|
|
6
|
-
export declare function AppShell({ sidebar, topbar, topbarLeft, topbarRight, logo, logoCompact, logoCompactBelow, breadcrumb, footer, children, sidebarCollapsed, responsiveNavigation, topbarSpan, navRail, navRailPosition, navRailEnd, navRailLabel, mobileNav, mobileNavLabel, mobileNavTriggerLabel, mobileNavOnCloseAutoFocus, mobileNavOpen, onMobileNavOpenChange, }: AppShellProp): React.JSX.Element;
|
|
6
|
+
export declare function AppShell({ sidebar, topbar, topbarLeft, topbarRight, logo, logoCompact, logoCompactBelow, breadcrumb, footer, children, sidebarCollapsed, responsiveNavigation, topbarSpan, navRail, navRailPosition, navRailEnd, navRailLabel, mobileTabBar, mobileTabBarLabel, mobileNav, mobileNavLabel, mobileNavTriggerLabel, mobileNavOnCloseAutoFocus, mobileNavOpen, onMobileNavOpenChange, }: AppShellProp): React.JSX.Element;
|
|
@@ -6,6 +6,8 @@ import { Menu } from "lucide-react";
|
|
|
6
6
|
import { useMediaQuery } from "../../lib/hooks.js";
|
|
7
7
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
8
8
|
import { Sheet, SheetBody, SheetContent, SheetHeader, SheetTrigger } from "../feedback/sheet.js";
|
|
9
|
+
import { ShellTabBar } from "./mobile-shell.js";
|
|
10
|
+
import { useToastStickyBarClearance } from "../../lib/toast-clearance.js";
|
|
9
11
|
import { NavSurfaceProvider } from "./nav-surface.js";
|
|
10
12
|
import { TopbarItem } from "./topbar-item.js";
|
|
11
13
|
import { isDevelopment } from "../../lib/dev.js";
|
|
@@ -30,6 +32,8 @@ function AppShell({
|
|
|
30
32
|
navRailPosition = "start",
|
|
31
33
|
navRailEnd,
|
|
32
34
|
navRailLabel,
|
|
35
|
+
mobileTabBar,
|
|
36
|
+
mobileTabBarLabel,
|
|
33
37
|
mobileNav,
|
|
34
38
|
mobileNavLabel,
|
|
35
39
|
mobileNavTriggerLabel,
|
|
@@ -39,6 +43,23 @@ function AppShell({
|
|
|
39
43
|
}) {
|
|
40
44
|
const { t } = useTranslation();
|
|
41
45
|
const navigationMode = useAppShellNavigationMode();
|
|
46
|
+
const rootRef = React.useRef(null);
|
|
47
|
+
const tabBarRef = React.useRef(null);
|
|
48
|
+
const showTabBar = responsiveNavigation === "drawer" && navigationMode === "drawer" && mobileTabBar != null && mobileTabBar !== false;
|
|
49
|
+
useToastStickyBarClearance(showTabBar ? [tabBarRef] : [], showTabBar);
|
|
50
|
+
React.useEffect(() => {
|
|
51
|
+
const root = rootRef.current;
|
|
52
|
+
const bar2 = tabBarRef.current;
|
|
53
|
+
if (!root || !bar2 || !showTabBar || typeof ResizeObserver === "undefined") return;
|
|
54
|
+
const publish = () => root.style.setProperty("--app-shell-mobile-tab-bar-block-size", `${bar2.offsetHeight}px`);
|
|
55
|
+
publish();
|
|
56
|
+
const observer = new ResizeObserver(publish);
|
|
57
|
+
observer.observe(bar2, { box: "border-box" });
|
|
58
|
+
return () => {
|
|
59
|
+
observer.disconnect();
|
|
60
|
+
root.style.removeProperty("--app-shell-mobile-tab-bar-block-size");
|
|
61
|
+
};
|
|
62
|
+
}, [showTabBar]);
|
|
42
63
|
const hasSidebar = sidebar !== void 0 && sidebar !== null && sidebar !== false;
|
|
43
64
|
const railContent = navRail === void 0 ? null : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
44
65
|
navRail,
|
|
@@ -146,10 +167,13 @@ function AppShell({
|
|
|
146
167
|
] }),
|
|
147
168
|
hasTopbarContent && resolvedTopbar
|
|
148
169
|
] });
|
|
170
|
+
const footerRegion = footer !== void 0 ? /* @__PURE__ */ jsx("footer", { className: "app-footer", "aria-label": t("layout.appShell.footerLabel"), children: footer }) : null;
|
|
149
171
|
return /* @__PURE__ */ jsxs(
|
|
150
172
|
"div",
|
|
151
173
|
{
|
|
174
|
+
ref: rootRef,
|
|
152
175
|
className: "app-root",
|
|
176
|
+
"data-mobile-tab-bar": showTabBar ? "" : void 0,
|
|
153
177
|
"data-collapsed": hasSidebar && sidebarCollapsed ? "true" : void 0,
|
|
154
178
|
"data-sidebar": hasSidebar ? void 0 : "none",
|
|
155
179
|
"data-responsive-navigation": responsiveNavigation,
|
|
@@ -177,11 +201,13 @@ function AppShell({
|
|
|
177
201
|
tabIndex: 0,
|
|
178
202
|
children: [
|
|
179
203
|
breadcrumb !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-breadcrumb", children: breadcrumb }),
|
|
180
|
-
children
|
|
204
|
+
children,
|
|
205
|
+
showTabBar && footerRegion
|
|
181
206
|
]
|
|
182
207
|
}
|
|
183
208
|
),
|
|
184
|
-
|
|
209
|
+
!showTabBar && footerRegion,
|
|
210
|
+
showTabBar && /* @__PURE__ */ jsx(ShellTabBar, { ref: tabBarRef, className: "app-mobile-tab-bar", "aria-label": mobileTabBarLabel, children: mobileTabBar })
|
|
185
211
|
]
|
|
186
212
|
}
|
|
187
213
|
);
|
|
@@ -15,6 +15,8 @@ function PageLayout({
|
|
|
15
15
|
width = "md",
|
|
16
16
|
align = "start",
|
|
17
17
|
preset = "default",
|
|
18
|
+
footerTone = "default",
|
|
19
|
+
flow = "column",
|
|
18
20
|
className
|
|
19
21
|
}) {
|
|
20
22
|
const { t } = useTranslation();
|
|
@@ -23,6 +25,7 @@ function PageLayout({
|
|
|
23
25
|
{
|
|
24
26
|
"data-slot": "centered-shell",
|
|
25
27
|
"data-preset": preset === "default" ? void 0 : preset,
|
|
28
|
+
"data-flow": flow === "sections" ? "sections" : void 0,
|
|
26
29
|
className: cn("ui-centered-shell", className),
|
|
27
30
|
children: [
|
|
28
31
|
topbar !== void 0 && /* @__PURE__ */ jsx(
|
|
@@ -39,6 +42,7 @@ function PageLayout({
|
|
|
39
42
|
{
|
|
40
43
|
className: "ui-centered-shell-footer",
|
|
41
44
|
"aria-label": t("layout.centeredShell.footerLabel"),
|
|
45
|
+
"data-tone": footerTone === "inverse" ? "inverse" : void 0,
|
|
42
46
|
children: footer
|
|
43
47
|
}
|
|
44
48
|
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { EditorialAuthCardProp, EditorialAuthProp, EditorialEmptyPanelProp, EditorialFootnoteProp, EditorialMetaBarProp, EditorialStatsProp, EditorialTextButtonProp, EditorialToggleGroupProp, EditorialToolbarProp, HoldingCardActionProp, HoldingCardProp, HoldingGridProp, SettingsLayoutProp, SettingsPanelProp, ThemePickerProp } from "../../props/components/editorial-account.prop.js";
|
|
3
|
+
export type { EditorialAuthCardProp, EditorialAuthCardProp as EditorialAuthCardProps, EditorialAuthProp, EditorialAuthProp as EditorialAuthProps, EditorialEmptyPanelProp, EditorialEmptyPanelProp as EditorialEmptyPanelProps, EditorialFootnoteProp, EditorialFootnoteProp as EditorialFootnoteProps, EditorialMetaBarProp, EditorialMetaBarProp as EditorialMetaBarProps, EditorialStatsItemProp, EditorialStatsProp, EditorialStatsProp as EditorialStatsProps, EditorialTextButtonProp, EditorialTextButtonProp as EditorialTextButtonProps, EditorialToggleGroupItemProp, EditorialToggleGroupProp, EditorialToggleGroupProp as EditorialToggleGroupProps, EditorialToolbarProp, EditorialToolbarProp as EditorialToolbarProps, HoldingCardActionProp, HoldingCardProp, HoldingCardProp as HoldingCardProps, HoldingGridProp, HoldingGridProp as HoldingGridProps, HoldingViewProp, SettingsLayoutProp, SettingsLayoutProp as SettingsLayoutProps, SettingsPanelProp, SettingsPanelProp as SettingsPanelProps, ThemePickerOptionProp, ThemePickerPreviewProp, ThemePickerProp, ThemePickerProp as ThemePickerProps, } from "../../props/components/editorial-account.prop.js";
|
|
4
|
+
/** A named group of `aria-pressed` buttons, one pressed at a time: text filter or icon switch. */
|
|
5
|
+
export declare function EditorialToggleGroup({ items, value, onValueChange, variant, className, ...rest }: EditorialToggleGroupProp): React.JSX.Element;
|
|
6
|
+
/** A hairline-ruled strip: a glyph and a line at the start, a badge at the end. */
|
|
7
|
+
export declare function EditorialMetaBar({ icon, start, end, className }: EditorialMetaBarProp): React.JSX.Element;
|
|
8
|
+
/** A centred signed-out (`guest`, with a card-stack illustration) or empty (`empty`) panel. */
|
|
9
|
+
export declare function EditorialEmptyPanel({ variant, eyebrow, title, level, description, actions, icon, className, }: EditorialEmptyPanelProp): React.JSX.Element;
|
|
10
|
+
/** A strip of figure tiles on unequal tracks; the first tile is the lead. */
|
|
11
|
+
export declare function EditorialStats({ items, className, ...rest }: EditorialStatsProp): React.JSX.Element;
|
|
12
|
+
/**
|
|
13
|
+
* The row above a collection: a summary (count + note) and / or a start cluster, an end cluster
|
|
14
|
+
* (order, view switch, primary action), optionally over a hairline. With a `summary` it is a
|
|
15
|
+
* listing row that keeps one line; without one it is a bar whose clusters may stack.
|
|
16
|
+
*/
|
|
17
|
+
export declare function EditorialToolbar({ summary, start, end, divider, className, }: EditorialToolbarProp): React.JSX.Element;
|
|
18
|
+
/** The track of HoldingCards; `view="list"` turns every card into a wide row. */
|
|
19
|
+
export declare function HoldingGrid({ view, children, className, ...rest }: HoldingGridProp): React.JSX.Element;
|
|
20
|
+
/** One owned item: picture ground, overline, title, meta, tags, purchase line, date, actions. */
|
|
21
|
+
export declare function HoldingCard({ media, overline, title, level, meta, tags, purchase, date, actions, className, }: HoldingCardProp): React.JSX.Element;
|
|
22
|
+
/** A quiet glyph + label action of a HoldingCard; `asChild` turns a router link into it. */
|
|
23
|
+
export declare function HoldingCardAction({ icon, children, asChild, onClick, disabled, className, ...rest }: HoldingCardActionProp): React.JSX.Element;
|
|
24
|
+
/** A settings page: a sticky rail beside the panels. */
|
|
25
|
+
export declare function SettingsLayout({ aside, children, className }: SettingsLayoutProp): React.JSX.Element;
|
|
26
|
+
/** One bordered settings section: number, title, description, then its fields. */
|
|
27
|
+
export declare function SettingsPanel({ number, title, level, description, children, titleId, className, }: SettingsPanelProp): React.JSX.Element;
|
|
28
|
+
/** An illustrated radio group for the colour theme (painted light / dark / system previews). */
|
|
29
|
+
export declare function ThemePicker({ legend, options, value, defaultValue, onValueChange, name, className, }: ThemePickerProp): React.JSX.Element;
|
|
30
|
+
/** A sign-in / sign-up page: the story column beside the form card. */
|
|
31
|
+
export declare function EditorialAuth({ eyebrow, title, description, art, benefits, children, className, }: EditorialAuthProp): React.JSX.Element;
|
|
32
|
+
/** The form card of EditorialAuth: badge, title, copy, the form and a ruled footer line. */
|
|
33
|
+
export declare function EditorialAuthCard({ badge, title, level, description, children, footer, className, }: EditorialAuthCardProp): React.JSX.Element;
|
|
34
|
+
/** An underlined text action in the primary tone; `asChild` turns a router link into it. */
|
|
35
|
+
export declare function EditorialTextButton({ children, icon, asChild, onClick, disabled, className, }: EditorialTextButtonProp): React.JSX.Element;
|
|
36
|
+
/**
|
|
37
|
+
* `EditorialSearch variant="inline"` (gh#1439) — internal: a collection's own search row, visible
|
|
38
|
+
* label, framed field with a glyph and a live count. Rendered by EditorialSearch; not exported.
|
|
39
|
+
*/
|
|
40
|
+
export declare function EditorialSearchInline({ label, id, placeholder, defaultValue, onSearch, debounce, count, className, }: {
|
|
41
|
+
label: string;
|
|
42
|
+
id?: string;
|
|
43
|
+
placeholder?: string;
|
|
44
|
+
defaultValue?: string;
|
|
45
|
+
onSearch?: (query: string) => void;
|
|
46
|
+
debounce?: number;
|
|
47
|
+
count?: React.ReactNode;
|
|
48
|
+
className?: string;
|
|
49
|
+
}): React.JSX.Element;
|
|
50
|
+
/** A quiet closing line: a note at the start, an optional action at the end. */
|
|
51
|
+
export declare function EditorialFootnote({ children, action, align, className, }: EditorialFootnoteProp): React.JSX.Element;
|