@godxjp/ui 23.1.0 → 23.2.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/card.d.ts +45 -2
- package/dist/components/data-display/card.js +4 -2
- package/dist/components/data-display/feature-list.d.ts +26 -0
- package/dist/components/data-display/feature-list.js +29 -0
- package/dist/components/data-display/index.d.ts +6 -0
- package/dist/components/data-display/index.js +6 -0
- package/dist/components/data-display/swatch.d.ts +24 -0
- package/dist/components/data-display/swatch.js +19 -0
- package/dist/components/data-display/thumbnail.d.ts +37 -0
- package/dist/components/data-display/thumbnail.js +20 -0
- package/dist/components/feedback/index.d.ts +2 -2
- package/dist/components/feedback/index.js +19 -1
- package/dist/components/feedback/skeleton.d.ts +33 -3
- package/dist/components/feedback/skeleton.js +154 -3
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +17 -5
- package/dist/components/layout/sidebar.js +9 -2
- package/dist/components/navigation/tabs-scroll.d.ts +27 -0
- package/dist/components/navigation/tabs-scroll.js +36 -1
- package/dist/components/navigation/tabs.d.ts +2 -2
- package/dist/components/navigation/tabs.js +44 -12
- package/dist/i18n/messages/en.json +5 -0
- package/dist/i18n/messages/ja.json +5 -0
- package/dist/i18n/messages/vi.json +5 -0
- package/dist/props/components/data-display.prop.d.ts +93 -0
- package/dist/props/components/feedback.prop.d.ts +85 -1
- package/dist/props/components/layout.prop.d.ts +72 -1
- package/dist/props/components/navigation.prop.d.ts +72 -1
- package/dist/props/registry.d.ts +118 -0
- package/dist/props/registry.js +134 -0
- package/dist/styles/alert-layout.css +139 -0
- package/dist/styles/card-layout.css +48 -0
- package/dist/styles/data-display-layout.css +88 -0
- package/dist/styles/navigation-layout.css +76 -3
- package/dist/styles/shell-layout.css +18 -0
- package/dist/tokens/components/card.css +2 -0
- package/dist/tokens/components/data-display.css +23 -0
- package/dist/tokens/components/feedback.css +18 -0
- package/dist/tokens/components/navigation.css +2 -0
- package/dist/tokens/foundation.css +18 -16
- package/docs/CONSUMER-RULES.md +1 -1
- package/docs/DESIGN-AUTHORITY.md +2 -1
- package/docs/FRAME-COVERAGE-REPORT.md +29 -3
- package/docs/assets/shot-landscape.svg +12 -0
- package/docs/assets/shot-portrait.svg +10 -0
- package/docs/data-display/card/index.tsx +40 -0
- package/docs/data-display/feature-list.tsx +159 -0
- package/docs/data-display/swatch.tsx +107 -0
- package/docs/data-display/thumbnail.tsx +128 -0
- package/docs/feedback/skeleton.tsx +57 -0
- package/docs/layout/flex.tsx +29 -0
- package/docs/layout/sidebar.tsx +66 -10
- package/docs/navigation/tabs.tsx +59 -0
- package/package.json +4 -7
- package/scripts/_agent-setup.mjs +164 -28
- package/scripts/consumer-rule.md +16 -0
- package/scripts/postinstall.mjs +9 -0
- package/scripts/ui-audit.mjs +70 -28
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { mergeAriaIds } from "../../lib/field-a11y.js";
|
|
4
4
|
import { cn } from "../../lib/utils.js";
|
|
5
5
|
import { flexGapClass, padStyle, padStepToken } from "../../lib/variants.js";
|
|
6
6
|
const toCssLength = (value) => typeof value === "number" ? `${value}px` : value;
|
|
7
|
+
const rawBreakpoint = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
8
|
+
const rawBreakpointRule = (axis, px) => `@media (width ${axis === "below" ? "<" : ">="} ${px}px){.ui-flex[data-hide-${axis}-raw="${px}"]{display:none}}`;
|
|
7
9
|
function Flex({
|
|
8
10
|
as: Element = "div",
|
|
9
11
|
direction = "row",
|
|
@@ -21,6 +23,8 @@ function Flex({
|
|
|
21
23
|
wrap = false,
|
|
22
24
|
hideBelow,
|
|
23
25
|
hideFrom,
|
|
26
|
+
hideBelowRaw,
|
|
27
|
+
hideFromRaw,
|
|
24
28
|
fill = false,
|
|
25
29
|
width,
|
|
26
30
|
className,
|
|
@@ -42,6 +46,8 @@ function Flex({
|
|
|
42
46
|
"aria-describedby": mergeAriaIds(props["aria-describedby"], ariaErrorMessage)
|
|
43
47
|
};
|
|
44
48
|
}
|
|
49
|
+
const belowRaw = rawBreakpoint(hideBelowRaw);
|
|
50
|
+
const fromRaw = rawBreakpoint(hideFromRaw);
|
|
45
51
|
const responsive = typeof direction === "object";
|
|
46
52
|
const axes = responsive ? direction : { base: direction };
|
|
47
53
|
const cssDirection = (axis) => axis === "col" ? "column" : axis;
|
|
@@ -51,7 +57,7 @@ function Flex({
|
|
|
51
57
|
cssDirection(axis)
|
|
52
58
|
])
|
|
53
59
|
) : {};
|
|
54
|
-
return /* @__PURE__ */
|
|
60
|
+
return /* @__PURE__ */ jsxs(
|
|
55
61
|
Element,
|
|
56
62
|
{
|
|
57
63
|
"data-direction": responsive ? "responsive" : direction,
|
|
@@ -63,8 +69,10 @@ function Flex({
|
|
|
63
69
|
"data-align": align,
|
|
64
70
|
"data-justify": justify,
|
|
65
71
|
"data-wrap": wrap ? "true" : void 0,
|
|
66
|
-
"data-hide-below": hideBelow,
|
|
67
|
-
"data-hide-from": hideFrom,
|
|
72
|
+
"data-hide-below": belowRaw === void 0 ? hideBelow : void 0,
|
|
73
|
+
"data-hide-from": fromRaw === void 0 ? hideFrom : void 0,
|
|
74
|
+
"data-hide-below-raw": belowRaw,
|
|
75
|
+
"data-hide-from-raw": fromRaw,
|
|
68
76
|
"data-fill": fill ? "" : void 0,
|
|
69
77
|
"data-width-raw": width === void 0 ? void 0 : "",
|
|
70
78
|
"data-gap-raw": gapRaw,
|
|
@@ -79,7 +87,11 @@ function Flex({
|
|
|
79
87
|
...padStyle(pad, padRaw)
|
|
80
88
|
},
|
|
81
89
|
...domProps,
|
|
82
|
-
children
|
|
90
|
+
children: [
|
|
91
|
+
belowRaw === void 0 ? null : /* @__PURE__ */ jsx("style", { href: `ui-flex-hide-below-raw-${belowRaw}`, precedence: "ui-flex-raw-breakpoint", children: rawBreakpointRule("below", belowRaw) }),
|
|
92
|
+
fromRaw === void 0 ? null : /* @__PURE__ */ jsx("style", { href: `ui-flex-hide-from-raw-${fromRaw}`, precedence: "ui-flex-raw-breakpoint", children: rawBreakpointRule("from", fromRaw) }),
|
|
93
|
+
children
|
|
94
|
+
]
|
|
83
95
|
}
|
|
84
96
|
);
|
|
85
97
|
}
|
|
@@ -27,6 +27,11 @@ function SidebarSection({
|
|
|
27
27
|
function SidebarIcon({ icon: Icon }) {
|
|
28
28
|
return /* @__PURE__ */ jsx("span", { className: "sb-icon", children: Icon ? /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true" }) : null });
|
|
29
29
|
}
|
|
30
|
+
function SidebarTrailingIcon({
|
|
31
|
+
icon: Icon
|
|
32
|
+
}) {
|
|
33
|
+
return /* @__PURE__ */ jsx("span", { className: "sb-trailing-icon", children: /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true" }) });
|
|
34
|
+
}
|
|
30
35
|
function SidebarRowContent({
|
|
31
36
|
item,
|
|
32
37
|
sub = false,
|
|
@@ -48,7 +53,8 @@ function SidebarRowContent({
|
|
|
48
53
|
children: item.badge
|
|
49
54
|
}
|
|
50
55
|
)
|
|
51
|
-
) : null
|
|
56
|
+
) : null,
|
|
57
|
+
item.trailingIcon ? /* @__PURE__ */ jsx(SidebarTrailingIcon, { icon: item.trailingIcon }) : null
|
|
52
58
|
] });
|
|
53
59
|
}
|
|
54
60
|
function SidebarItem({
|
|
@@ -305,6 +311,7 @@ function Sidebar({
|
|
|
305
311
|
const surface = useNavSurface();
|
|
306
312
|
collapsed = surface === "drawer" ? false : collapsed;
|
|
307
313
|
const brandNode = typeof brand === "function" ? brand(collapsed) : brand;
|
|
314
|
+
const footerNode = typeof footer === "function" ? footer(collapsed) : footer;
|
|
308
315
|
return /* @__PURE__ */ jsxs("div", { className: "sb-root", "data-collapsed": collapsed ? "true" : void 0, children: [
|
|
309
316
|
brand !== void 0 ? /* @__PURE__ */ jsx(SidebarHeader, { children: brandNode }) : product ? (() => {
|
|
310
317
|
const interactive = onProductClick != null;
|
|
@@ -385,7 +392,7 @@ function Sidebar({
|
|
|
385
392
|
))
|
|
386
393
|
}
|
|
387
394
|
),
|
|
388
|
-
|
|
395
|
+
footerNode ? /* @__PURE__ */ jsx("div", { className: "sb-footer", children: footerNode }) : null
|
|
389
396
|
] });
|
|
390
397
|
}
|
|
391
398
|
export {
|
|
@@ -47,6 +47,33 @@ export declare function useKeepActiveTabVisible(listRef: React.RefObject<HTMLEle
|
|
|
47
47
|
* it are the ones that hand it real geometry.
|
|
48
48
|
*/
|
|
49
49
|
export declare function resolveHiddenTabValues(list: HTMLElement, values: readonly string[]): string[];
|
|
50
|
+
/**
|
|
51
|
+
* The LOGICAL scroll offset of a strip: how far it has moved from its own start edge, growing
|
|
52
|
+
* towards `end` on whichever axis the strip is on and in whichever direction it is written.
|
|
53
|
+
*
|
|
54
|
+
* `scrollLeft` cannot be read raw. Per CSSOM-View an RTL scroller reports `0` at its START edge
|
|
55
|
+
* (the right one) and goes NEGATIVE towards the end, so "scrollLeft went up" means opposite things
|
|
56
|
+
* in the two directions — exactly the bug `start`/`end` exist to prevent, and it would have been
|
|
57
|
+
* invisible in an LTR test suite.
|
|
58
|
+
*/
|
|
59
|
+
export declare function readTabsScrollOffset(list: HTMLElement, vertical: boolean): number;
|
|
60
|
+
/**
|
|
61
|
+
* Ant Design `onTabScroll`'s one piece of logic: which edge a movement of the scroll offset went
|
|
62
|
+
* towards. `null` when the offset did not move, so a scroll event that reports the same position
|
|
63
|
+
* (momentum settling, a programmatic re-pin that was already in place) reports nothing.
|
|
64
|
+
*/
|
|
65
|
+
export declare function resolveTabsScrollDirection(previous: number, next: number): "start" | "end" | null;
|
|
66
|
+
/**
|
|
67
|
+
* Reports every real movement of the strip's own scrollport to `onScroll` — Ant Design
|
|
68
|
+
* `onTabScroll`. The handler is held in a ref so a consumer's inline arrow function does not
|
|
69
|
+
* re-arm the listener on every render (same contract as `useTabsOverflowValues` above).
|
|
70
|
+
*
|
|
71
|
+
* It reports a `scrollIntoView` re-pin too, and deliberately: antd's does the same, and "the strip
|
|
72
|
+
* moved" is the fact a consumer is subscribing to — not "the user moved it".
|
|
73
|
+
*/
|
|
74
|
+
export declare function useTabsScrollReporter(listRef: React.RefObject<HTMLElement | null>, vertical: boolean, onScroll: ((info: {
|
|
75
|
+
direction: "start" | "end";
|
|
76
|
+
}) => void) | undefined): void;
|
|
50
77
|
/**
|
|
51
78
|
* Keeps `onChange` fed with the values currently out of the scrollport, recomputing on the two
|
|
52
79
|
* things that can move them: the strip resizing (a viewport change, a font swap, a tab added or
|
|
@@ -78,6 +78,38 @@ function resolveHiddenTabValues(list, values) {
|
|
|
78
78
|
});
|
|
79
79
|
return hidden;
|
|
80
80
|
}
|
|
81
|
+
function readTabsScrollOffset(list, vertical) {
|
|
82
|
+
if (vertical) return list.scrollTop;
|
|
83
|
+
const rtl = list.ownerDocument?.defaultView?.getComputedStyle(list).direction === "rtl" || list.closest("[dir]")?.getAttribute("dir") === "rtl";
|
|
84
|
+
return rtl ? -list.scrollLeft : list.scrollLeft;
|
|
85
|
+
}
|
|
86
|
+
function resolveTabsScrollDirection(previous, next) {
|
|
87
|
+
if (next === previous) return null;
|
|
88
|
+
return next > previous ? "end" : "start";
|
|
89
|
+
}
|
|
90
|
+
function useTabsScrollReporter(listRef, vertical, onScroll) {
|
|
91
|
+
const onScrollRef = React.useRef(onScroll);
|
|
92
|
+
React.useEffect(() => {
|
|
93
|
+
onScrollRef.current = onScroll;
|
|
94
|
+
});
|
|
95
|
+
const armed = onScroll !== void 0;
|
|
96
|
+
React.useEffect(() => {
|
|
97
|
+
if (!armed) return void 0;
|
|
98
|
+
const list = listRef.current;
|
|
99
|
+
if (!list) return void 0;
|
|
100
|
+
let last = readTabsScrollOffset(list, vertical);
|
|
101
|
+
const report = () => {
|
|
102
|
+
const next = readTabsScrollOffset(list, vertical);
|
|
103
|
+
const direction = resolveTabsScrollDirection(last, next);
|
|
104
|
+
last = next;
|
|
105
|
+
if (direction) onScrollRef.current?.({ direction });
|
|
106
|
+
};
|
|
107
|
+
list.addEventListener("scroll", report, { passive: true });
|
|
108
|
+
return () => {
|
|
109
|
+
list.removeEventListener("scroll", report);
|
|
110
|
+
};
|
|
111
|
+
}, [armed, listRef, vertical]);
|
|
112
|
+
}
|
|
81
113
|
function useTabsOverflowValues(listRef, values, onChange) {
|
|
82
114
|
const onChangeRef = React.useRef(onChange);
|
|
83
115
|
React.useEffect(() => {
|
|
@@ -119,9 +151,12 @@ function useTabsOverflowValues(listRef, values, onChange) {
|
|
|
119
151
|
export {
|
|
120
152
|
isTabFullyVisible,
|
|
121
153
|
prefersReducedMotion,
|
|
154
|
+
readTabsScrollOffset,
|
|
122
155
|
resolveHiddenTabValues,
|
|
123
156
|
resolveTabScrollTarget,
|
|
157
|
+
resolveTabsScrollDirection,
|
|
124
158
|
syncActiveTabIntoView,
|
|
125
159
|
useKeepActiveTabVisible,
|
|
126
|
-
useTabsOverflowValues
|
|
160
|
+
useTabsOverflowValues,
|
|
161
|
+
useTabsScrollReporter
|
|
127
162
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import type { TabItemProp, TabsProp } from "../../props/components/navigation.prop.js";
|
|
3
|
-
export type { TabItemProp, TabsProp, TabsVariantProp, TabsPlacementProp, TabsExtraProp, TabsOverflowProp, } from "../../props/components/navigation.prop.js";
|
|
3
|
+
export type { TabItemProp, TabsProp, TabsVariantProp, TabsPlacementProp, TabsExtraProp, TabsOverflowProp, TabsAnimatedProp, TabsIndicatorProp, TabsIndicatorSizeProp, TabsScrollDirectionProp, TabsOnScrollProp, } from "../../props/components/navigation.prop.js";
|
|
4
4
|
export type TabsOrientation = "vertical" | "horizontal";
|
|
5
5
|
export type TabsItem = TabItemProp;
|
|
6
6
|
export type TabsProps = Omit<React.ComponentPropsWithoutRef<"div">, "defaultValue" | "dir"> & TabsProp & {
|
|
@@ -8,7 +8,7 @@ export type TabsProps = Omit<React.ComponentPropsWithoutRef<"div">, "defaultValu
|
|
|
8
8
|
dir?: "ltr" | "rtl";
|
|
9
9
|
activationMode?: "manual" | "automatic";
|
|
10
10
|
};
|
|
11
|
-
export declare function Tabs({ className, orientation, items, value, defaultValue, onValueChange, activationMode, dir, variant, tabPlacement, size, centered, extra, destroyOnHidden, onEdit, addIcon, hideAdd, closeIcon, onTabClick, overflow, listClassName, contentClassName, children, ...props }: TabsProps): React.JSX.Element;
|
|
11
|
+
export declare function Tabs({ className, orientation, items, value, defaultValue, onValueChange, activationMode, dir, variant, tabPlacement, size, centered, extra, destroyOnHidden, onEdit, addIcon, hideAdd, closeIcon, onTabClick, overflow, animated, indicator, moreIcon, onTabScroll, listClassName, contentClassName, children, ...props }: TabsProps): React.JSX.Element;
|
|
12
12
|
export declare const TabsList: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
13
13
|
variant?: "default" | "line";
|
|
14
14
|
/**
|
|
@@ -17,10 +17,22 @@ import {
|
|
|
17
17
|
DropdownMenuItem,
|
|
18
18
|
DropdownMenuTrigger
|
|
19
19
|
} from "./dropdown-menu.js";
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
useKeepActiveTabVisible,
|
|
22
|
+
useTabsOverflowValues,
|
|
23
|
+
useTabsScrollReporter
|
|
24
|
+
} from "./tabs-scroll.js";
|
|
25
|
+
function triggerSizeClassName(size) {
|
|
26
|
+
return cn(
|
|
27
|
+
size === "sm" && "min-h-[var(--tabs-trigger-height-sm)] px-[var(--tabs-trigger-padding-x-sm)] text-[length:var(--tabs-trigger-font-size-sm)]",
|
|
28
|
+
size === "md" && "min-h-[var(--tabs-trigger-height-md)] px-[var(--tabs-trigger-padding-x-md)] text-[length:var(--tabs-trigger-font-size-md)]",
|
|
29
|
+
size === "lg" && "min-h-[var(--tabs-trigger-height-lg)] px-[var(--tabs-trigger-padding-x-lg)] text-[length:var(--tabs-trigger-font-size-lg)]"
|
|
30
|
+
);
|
|
31
|
+
}
|
|
21
32
|
const TabsFrameContext = React.createContext({
|
|
22
33
|
orientation: "horizontal",
|
|
23
|
-
selectionSuppressed: false
|
|
34
|
+
selectionSuppressed: false,
|
|
35
|
+
size: "md"
|
|
24
36
|
});
|
|
25
37
|
function resolveFallbackTabValue(items, requested) {
|
|
26
38
|
if (!items || items.length === 0) return requested;
|
|
@@ -46,6 +58,12 @@ function resolveTabsExtra(extra) {
|
|
|
46
58
|
if (isSlotMap) return extra;
|
|
47
59
|
return { end: extra };
|
|
48
60
|
}
|
|
61
|
+
function resolveTabsAnimated(animated) {
|
|
62
|
+
if (animated === false) return { inkBar: false, tabPane: false };
|
|
63
|
+
if (animated === true) return { inkBar: true, tabPane: true };
|
|
64
|
+
if (animated === void 0) return { inkBar: true, tabPane: false };
|
|
65
|
+
return { inkBar: animated.inkBar ?? true, tabPane: animated.tabPane ?? false };
|
|
66
|
+
}
|
|
49
67
|
function resolveTabsAxis(tabPlacement, orientation) {
|
|
50
68
|
if (tabPlacement) {
|
|
51
69
|
return {
|
|
@@ -86,12 +104,19 @@ function Tabs({
|
|
|
86
104
|
closeIcon,
|
|
87
105
|
onTabClick,
|
|
88
106
|
overflow = "scroll",
|
|
107
|
+
animated,
|
|
108
|
+
indicator,
|
|
109
|
+
moreIcon,
|
|
110
|
+
onTabScroll,
|
|
89
111
|
listClassName,
|
|
90
112
|
contentClassName,
|
|
91
113
|
children,
|
|
92
114
|
...props
|
|
93
115
|
}) {
|
|
94
116
|
const { t } = useTranslation();
|
|
117
|
+
const motion = resolveTabsAnimated(animated);
|
|
118
|
+
const indicatorSize = indicator?.size ?? "full";
|
|
119
|
+
const indicatorAlign = indicator?.align ?? "center";
|
|
95
120
|
const resolvedDefault = resolveFallbackTabValue(items, defaultValue);
|
|
96
121
|
const narrow = useMaxWidthBreakpoint(
|
|
97
122
|
TABS_PLACEMENT_BREAKPOINT_TOKEN,
|
|
@@ -103,8 +128,8 @@ function Tabs({
|
|
|
103
128
|
);
|
|
104
129
|
const selectionSuppressed = value === void 0 && items != null && items.length > 0 && resolvedDefault === void 0;
|
|
105
130
|
const frame = React.useMemo(
|
|
106
|
-
() => ({ orientation: resolvedOrientation, selectionSuppressed }),
|
|
107
|
-
[resolvedOrientation, selectionSuppressed]
|
|
131
|
+
() => ({ orientation: resolvedOrientation, selectionSuppressed, size }),
|
|
132
|
+
[resolvedOrientation, selectionSuppressed, size]
|
|
108
133
|
);
|
|
109
134
|
const editable = variant === "editable-card";
|
|
110
135
|
const collapsible = items != null && overflow === "menu";
|
|
@@ -120,6 +145,7 @@ function Tabs({
|
|
|
120
145
|
);
|
|
121
146
|
}, []);
|
|
122
147
|
useTabsOverflowValues(listRef, itemValues, handleHiddenChange);
|
|
148
|
+
useTabsScrollReporter(listRef, resolvedOrientation === "vertical", onTabScroll);
|
|
123
149
|
const [mirroredValue, setMirroredValue] = React.useState(
|
|
124
150
|
value ?? resolvedDefault
|
|
125
151
|
);
|
|
@@ -139,11 +165,7 @@ function Tabs({
|
|
|
139
165
|
const showAdd = editable && !hideAdd && Boolean(onEdit);
|
|
140
166
|
const needsBar = Boolean(extraStart || extraEnd || showAdd || collapsible);
|
|
141
167
|
const card = variant === "card" || variant === "editable-card";
|
|
142
|
-
const sizeTriggerClassName =
|
|
143
|
-
size === "sm" && "min-h-[var(--tabs-trigger-height-sm)] px-[var(--tabs-trigger-padding-x-sm)] text-[length:var(--tabs-trigger-font-size-sm)]",
|
|
144
|
-
size === "md" && "min-h-[var(--tabs-trigger-height-md)] px-[var(--tabs-trigger-padding-x-md)] text-[length:var(--tabs-trigger-font-size-md)]",
|
|
145
|
-
size === "lg" && "min-h-[var(--tabs-trigger-height-lg)] px-[var(--tabs-trigger-padding-x-lg)] text-[length:var(--tabs-trigger-font-size-lg)]"
|
|
146
|
-
);
|
|
168
|
+
const sizeTriggerClassName = triggerSizeClassName(size);
|
|
147
169
|
const list = items ? /* @__PURE__ */ jsx(
|
|
148
170
|
TabsList,
|
|
149
171
|
{
|
|
@@ -283,6 +305,10 @@ function Tabs({
|
|
|
283
305
|
"data-placement": placement,
|
|
284
306
|
"data-size": size,
|
|
285
307
|
"data-centered": centered ? "true" : void 0,
|
|
308
|
+
"data-animated-ink-bar": motion.inkBar ? "true" : "false",
|
|
309
|
+
"data-animated-tab-pane": motion.tabPane ? "true" : "false",
|
|
310
|
+
"data-indicator-size": indicatorSize,
|
|
311
|
+
"data-indicator-align": indicatorAlign,
|
|
286
312
|
orientation: resolvedOrientation,
|
|
287
313
|
keyboardActivation: activationMode,
|
|
288
314
|
selectedKey: value ?? (collapsible ? mirroredValue : void 0),
|
|
@@ -307,7 +333,11 @@ function Tabs({
|
|
|
307
333
|
"data-variant": variant,
|
|
308
334
|
"data-placement": placement,
|
|
309
335
|
"data-size": size,
|
|
310
|
-
"data-centered": centered ? "true" : void 0
|
|
336
|
+
"data-centered": centered ? "true" : void 0,
|
|
337
|
+
"data-animated-ink-bar": motion.inkBar ? "true" : "false",
|
|
338
|
+
"data-animated-tab-pane": motion.tabPane ? "true" : "false",
|
|
339
|
+
"data-indicator-size": indicatorSize,
|
|
340
|
+
"data-indicator-align": indicatorAlign
|
|
311
341
|
}),
|
|
312
342
|
children: items ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
313
343
|
needsBar ? /* @__PURE__ */ jsxs("div", { "data-slot": "tabs-bar", className: "ui-tabs-bar", children: [
|
|
@@ -330,7 +360,7 @@ function Tabs({
|
|
|
330
360
|
{
|
|
331
361
|
className: "ui-tabs-overflow",
|
|
332
362
|
"aria-label": t("navigation.tabs.moreTabs"),
|
|
333
|
-
children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "ui-tabs-overflow-icon", "aria-hidden": "true" })
|
|
363
|
+
children: moreIcon ?? /* @__PURE__ */ jsx(MoreHorizontal, { className: "ui-tabs-overflow-icon", "aria-hidden": "true" })
|
|
334
364
|
}
|
|
335
365
|
),
|
|
336
366
|
/* @__PURE__ */ jsx(DropdownMenuContent, { placement: "bottomEnd", children: overflowItems.map((item) => /* @__PURE__ */ jsx(
|
|
@@ -407,7 +437,7 @@ const TabsList = React.forwardRef(
|
|
|
407
437
|
TabsList.displayName = "TabsList";
|
|
408
438
|
const TabsTrigger = React.forwardRef(
|
|
409
439
|
({ className, value, disabled, children, onKeyDown, onClick, ...props }, ref) => {
|
|
410
|
-
const { orientation, selectionSuppressed } = React.useContext(TabsFrameContext);
|
|
440
|
+
const { orientation, selectionSuppressed, size } = React.useContext(TabsFrameContext);
|
|
411
441
|
return /* @__PURE__ */ jsx(
|
|
412
442
|
AriaTab,
|
|
413
443
|
{
|
|
@@ -434,6 +464,8 @@ const TabsTrigger = React.forwardRef(
|
|
|
434
464
|
// Selected and focused stay visually distinct (WCAG 2.4.7): selected is a 1px hairline in the
|
|
435
465
|
// border, focused is the 2px ring plus its halo outside it.
|
|
436
466
|
"text-muted-foreground ring-offset-background hover:text-foreground ui-focus-ring data-[state=active]:bg-background data-[state=active]:text-foreground group-data-[variant=default]/tabs-list:data-[state=active]:border-primary/25 relative inline-flex flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-3 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:flex-none group-data-[orientation=vertical]/tabs:justify-start group-data-[variant=line]/tabs-list:border-e-0 group-data-[variant=line]/tabs-list:border-b-0 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none",
|
|
467
|
+
// The tier the root was given. Without this the compound form ignored `size` outright.
|
|
468
|
+
triggerSizeClassName(size),
|
|
437
469
|
className
|
|
438
470
|
),
|
|
439
471
|
render: (domProps, renderProps) => withDomProps("button", "tabs-trigger", { type: "button", ...props }, domProps, {
|
|
@@ -283,6 +283,11 @@
|
|
|
283
283
|
"dotsLabel": "Choose slide",
|
|
284
284
|
"goToSlide": "Go to slide {index}"
|
|
285
285
|
},
|
|
286
|
+
"featureList": {
|
|
287
|
+
"included": "Included",
|
|
288
|
+
"excluded": "Not included",
|
|
289
|
+
"limited": "Limited"
|
|
290
|
+
},
|
|
286
291
|
"listRow": {
|
|
287
292
|
"unread": "Unread",
|
|
288
293
|
"read": "Read"
|
|
@@ -47,6 +47,99 @@ export type LegendProp = Omit<React.HTMLAttributes<HTMLUListElement>, "children"
|
|
|
47
47
|
items: LegendItemProp[];
|
|
48
48
|
className?: ClassNameProp;
|
|
49
49
|
};
|
|
50
|
+
/**
|
|
51
|
+
* @see Swatch — a READ-ONLY sample of ONE colour a person chose.
|
|
52
|
+
*
|
|
53
|
+
* ## Why it is not a Legend, a ColorPicker or a Badge
|
|
54
|
+
*
|
|
55
|
+
* `Legend` is a KEY: a closed set of semantic TONES, each with required words beside it, because
|
|
56
|
+
* there the colour stands FOR something. Here the colour IS the content — a brand's
|
|
57
|
+
* `primary_color`, a calendar category, a label a user tinted — so there is no tone it maps to and
|
|
58
|
+
* no second thing for a word to name. `ColorPicker` is the INPUT for the same value, and rendering
|
|
59
|
+
* a disabled input to display one reads as a control that broke. `Badge` is a chip: tinted fill,
|
|
60
|
+
* border, clickable affordance — not a sample of the exact colour.
|
|
61
|
+
*
|
|
62
|
+
* Its mark is the same square Legend draws, one type step larger, because it stands beside a name
|
|
63
|
+
* rather than inside an 11px key.
|
|
64
|
+
*/
|
|
65
|
+
export type SwatchProp = Omit<React.HTMLAttributes<HTMLSpanElement>, "children" | "color"> & {
|
|
66
|
+
/**
|
|
67
|
+
* The colour to show, as a CSS colour VALUE — `#7C3AED`, `rgb(…)`, `oklch(…)`. It is DATA the
|
|
68
|
+
* same way `Badge`'s `color` is: a value a person picked in a settings screen, so it arrives as
|
|
69
|
+
* a prop and is never written into a stylesheet. Passing a semantic token's own colour here is
|
|
70
|
+
* the one thing to avoid — a tone that MEANS something belongs on a component that names the
|
|
71
|
+
* meaning (`Badge tone`, `Legend`), not on a sample.
|
|
72
|
+
*/
|
|
73
|
+
color: string;
|
|
74
|
+
/**
|
|
75
|
+
* The accessible NAME of the sample, and the reason this component can exist without a visible
|
|
76
|
+
* label. Say what the colour is FOR and what it is: `aria-label={`${t.primaryColor}: ${hex}`}`.
|
|
77
|
+
*
|
|
78
|
+
* With it, the swatch is a `role="img"` that announces that sentence. Without it the swatch is
|
|
79
|
+
* `aria-hidden` — correct, and the only correct option, when a visible line beside it already
|
|
80
|
+
* states the colour. Either way colour is never the sole carrier of the meaning (WCAG 1.4.1);
|
|
81
|
+
* what is NOT offered is a third path where it is.
|
|
82
|
+
*/
|
|
83
|
+
"aria-label"?: string;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Whether a `FeatureList` line is in, out, or in with a limit.
|
|
87
|
+
*
|
|
88
|
+
* Three members and no fourth: the axis is INCLUSION, and a list that also carried "coming soon",
|
|
89
|
+
* "beta" or "deprecated" would be encoding a roadmap on the same glyph column as a fact about
|
|
90
|
+
* today. Those are a `Badge` beside the label, which is content the screen already owns.
|
|
91
|
+
*/
|
|
92
|
+
export type FeatureStateProp = "included" | "excluded" | "limited";
|
|
93
|
+
/**
|
|
94
|
+
* One line of a `FeatureList`: what state it is in, what it is called, and — optionally — a
|
|
95
|
+
* sentence about it that WRAPS.
|
|
96
|
+
*
|
|
97
|
+
* There is deliberately no field for a quantity ("10,000 req/mo"). Composing it into `label` as
|
|
98
|
+
* `<>API calls <Text tone="muted" tabular>10,000 req/mo</Text></>` is already legal and already
|
|
99
|
+
* audit-clean, so a prop for it would fail question 1 of docs/WHAT-BELONGS-HERE.md — the consumer
|
|
100
|
+
* has a move. What the consumer did NOT have a move for is the glyph column and its alignment,
|
|
101
|
+
* which is what this component owns.
|
|
102
|
+
*/
|
|
103
|
+
export type FeatureItemProp = {
|
|
104
|
+
/** In, out, or in with a limit. Drives the glyph, its mark colour and the `sr-only` prefix. */
|
|
105
|
+
state: FeatureStateProp;
|
|
106
|
+
/** What the line is about. Wraps. */
|
|
107
|
+
label: LabelProp;
|
|
108
|
+
/** An optional muted sentence under the label. Wraps; long unbroken tokens break. */
|
|
109
|
+
description?: DescriptionProp;
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* @see FeatureList — a list of statements, each with a leading state glyph: what a plan includes,
|
|
113
|
+
* what a tier supports, which requirements a submission met.
|
|
114
|
+
*/
|
|
115
|
+
export type FeatureListProp = Omit<React.HTMLAttributes<HTMLUListElement>, "children"> & {
|
|
116
|
+
items: FeatureItemProp[];
|
|
117
|
+
className?: ClassNameProp;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Fixed BLOCK size of a `Thumbnail`; the inline size stays intrinsic.
|
|
121
|
+
*
|
|
122
|
+
* A subset of the shared `SizeProp` ladder — `xs` is off the bottom because a 48px frame with a
|
|
123
|
+
* 1px hairline is a favicon, not a thumbnail, and nothing in the reported cases wanted one.
|
|
124
|
+
*/
|
|
125
|
+
export type ThumbnailSizeProp = Extract<SizeProp, "sm" | "md" | "lg">;
|
|
126
|
+
/**
|
|
127
|
+
* @see Thumbnail — a framed image at a FIXED HEIGHT and its own intrinsic width, for a wrapping
|
|
128
|
+
* row of pictures whose aspect ratios differ.
|
|
129
|
+
*/
|
|
130
|
+
export type ThumbnailProp = Omit<React.ImgHTMLAttributes<HTMLImageElement>, "alt"> & {
|
|
131
|
+
/** Image URL. */
|
|
132
|
+
src: string;
|
|
133
|
+
/**
|
|
134
|
+
* Required, with no way to omit it. Pass `""` for a picture that carries no information the
|
|
135
|
+
* page does not already say — the empty string is a DECISION the author has to make, where a
|
|
136
|
+
* missing attribute is an omission nobody notices (WCAG 1.1.1).
|
|
137
|
+
*/
|
|
138
|
+
alt: string;
|
|
139
|
+
/** Frame height. Default `md`. The width follows the picture's own ratio. */
|
|
140
|
+
size?: ThumbnailSizeProp;
|
|
141
|
+
className?: ClassNameProp;
|
|
142
|
+
};
|
|
50
143
|
/** @see EmptyState */
|
|
51
144
|
/**
|
|
52
145
|
* Semantic intent of the EmptyState icon medallion — a subset of the shared `ToneProp` vocabulary
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Feedback component prop types — @see docs/COMPONENTS.md#feedback */
|
|
2
2
|
import type * as React from "react";
|
|
3
3
|
import type { QueryErrorCategory } from "../../lib/query-error.js";
|
|
4
|
-
import type { AlertVariantProp, CancelLabelProp, ChildrenProp, ClassNameProp, ConfirmLabelProp, ConfirmVariantProp, DescriptionProp, HandlerProp, IconProp, OpenProp, OnOpenChangeProp, PendingProp, ToneProp, TitleProp } from "../vocabulary/index.js";
|
|
4
|
+
import type { AlertVariantProp, AvatarShapeProp, CancelLabelProp, ChildrenProp, ClassNameProp, ConfirmLabelProp, ConfirmVariantProp, DescriptionProp, HandlerProp, IconProp, OpenProp, OnOpenChangeProp, PendingProp, ShapeProp, SizeProp, ToneProp, TitleProp } from "../vocabulary/index.js";
|
|
5
5
|
/** @see AlertDialog */
|
|
6
6
|
export type AlertDialogProp = {
|
|
7
7
|
open: OpenProp;
|
|
@@ -83,3 +83,87 @@ export type SkeletonRowsProp = {
|
|
|
83
83
|
rows?: number;
|
|
84
84
|
columns?: number;
|
|
85
85
|
};
|
|
86
|
+
/**
|
|
87
|
+
* A skeleton line's MEASURE. `number` is read as pixels, matching antd's
|
|
88
|
+
* `SkeletonParagraphProps["width"]` (components/skeleton/Paragraph.tsx); a string is any CSS length
|
|
89
|
+
* or percentage. It reaches the DOM as the `--skeleton-line-width` custom property rather than a
|
|
90
|
+
* raw `width`, so the line still resolves its own block size and radius from the token tier.
|
|
91
|
+
*/
|
|
92
|
+
export type SkeletonWidth = number | string;
|
|
93
|
+
/**
|
|
94
|
+
* @see Skeleton — the placeholder BLOCK. Both fields are antd's, ported onto the block this
|
|
95
|
+
* library already shipped rather than onto a second component beside it.
|
|
96
|
+
*/
|
|
97
|
+
export type SkeletonProp = React.HTMLAttributes<HTMLDivElement> & {
|
|
98
|
+
/**
|
|
99
|
+
* Swap the resting pulse for the travelling SHEEN (antd's `active`). antd's non-active skeleton
|
|
100
|
+
* is fully static; this library's block has always pulsed, so the default is left alone and
|
|
101
|
+
* `active` selects the louder of the two motions instead of turning motion on.
|
|
102
|
+
*/
|
|
103
|
+
active?: boolean;
|
|
104
|
+
/**
|
|
105
|
+
* `false` renders `children` in place of the placeholder. An OMITTED `loading` still renders the
|
|
106
|
+
* placeholder — antd's `loading || !("loading" in props)`.
|
|
107
|
+
*/
|
|
108
|
+
loading?: boolean;
|
|
109
|
+
};
|
|
110
|
+
/** @see SkeletonAvatar */
|
|
111
|
+
export type SkeletonAvatarProp = {
|
|
112
|
+
/** Box, from the `--control-height` tier — the same tier the real `Avatar` sizes from. */
|
|
113
|
+
size?: SizeProp;
|
|
114
|
+
shape?: AvatarShapeProp;
|
|
115
|
+
active?: boolean;
|
|
116
|
+
className?: ClassNameProp;
|
|
117
|
+
};
|
|
118
|
+
/** @see SkeletonButton */
|
|
119
|
+
export type SkeletonButtonProp = {
|
|
120
|
+
size?: SizeProp;
|
|
121
|
+
/** Corner, in `Button`'s own vocabulary: `pill` is antd's `shape="round"`. */
|
|
122
|
+
shape?: ShapeProp;
|
|
123
|
+
/** Fill the inline axis, for a button that spans its column (antd's `block`). */
|
|
124
|
+
block?: boolean;
|
|
125
|
+
active?: boolean;
|
|
126
|
+
className?: ClassNameProp;
|
|
127
|
+
};
|
|
128
|
+
/** @see SkeletonInput */
|
|
129
|
+
export type SkeletonInputProp = {
|
|
130
|
+
size?: SizeProp;
|
|
131
|
+
block?: boolean;
|
|
132
|
+
active?: boolean;
|
|
133
|
+
className?: ClassNameProp;
|
|
134
|
+
};
|
|
135
|
+
/** @see SkeletonNode — a square standing in for a media/custom slot; `children` centres in it. */
|
|
136
|
+
export type SkeletonNodeProp = {
|
|
137
|
+
active?: boolean;
|
|
138
|
+
children?: ChildrenProp;
|
|
139
|
+
className?: ClassNameProp;
|
|
140
|
+
};
|
|
141
|
+
/** @see SkeletonImage */
|
|
142
|
+
export type SkeletonImageProp = {
|
|
143
|
+
active?: boolean;
|
|
144
|
+
className?: ClassNameProp;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* @see SkeletonArticle — antd's own `<Skeleton>` shape (avatar + title + paragraph). It is a
|
|
148
|
+
* SIBLING of `Skeleton`, not a replacement: `Skeleton` here is the block antd spells
|
|
149
|
+
* `Skeleton.Node`, and re-pointing it at the article would change what every existing call site
|
|
150
|
+
* renders.
|
|
151
|
+
*/
|
|
152
|
+
export type SkeletonArticleProp = {
|
|
153
|
+
avatar?: boolean | Pick<SkeletonAvatarProp, "size" | "shape">;
|
|
154
|
+
/** The heading line. NOT a string title — `false` drops the line, `{ width }` re-measures it. */
|
|
155
|
+
title?: boolean | {
|
|
156
|
+
width?: SkeletonWidth;
|
|
157
|
+
};
|
|
158
|
+
/** `width` as an array measures each row; as a single value it measures the LAST row. */
|
|
159
|
+
paragraph?: boolean | {
|
|
160
|
+
rows?: number;
|
|
161
|
+
width?: SkeletonWidth | SkeletonWidth[];
|
|
162
|
+
};
|
|
163
|
+
/** Pill corners on every line (antd's `round`, whose capsule radius is `--radius-pill` here). */
|
|
164
|
+
round?: boolean;
|
|
165
|
+
active?: boolean;
|
|
166
|
+
loading?: boolean;
|
|
167
|
+
children?: ChildrenProp;
|
|
168
|
+
className?: ClassNameProp;
|
|
169
|
+
};
|