@godxjp/ui 32.8.0 → 32.10.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/DESIGN.md +11 -3
- package/README.md +5 -5
- package/agent/DESIGN.md +11 -3
- package/agent/START-HERE.md +9 -7
- package/agent/components/AppShell.json +1 -0
- package/agent/components/BlockEditor.json +1 -0
- package/agent/components/PageContainer.json +1 -0
- package/agent/components/Progress.json +3 -3
- package/agent/components/SearchInput.json +1 -0
- package/agent/components/Topbar.json +2 -0
- package/agent/components/TopbarItem.json +1 -0
- package/agent/components/TopbarSearch.json +49 -0
- package/agent/components/Tree.json +1 -0
- package/agent/components-index.json +5 -0
- package/agent/components.json +60 -3
- package/agent/index.json +7 -7
- package/agent/llms.txt +7 -7
- package/agent/tokens.json +39 -3
- package/dist/components/data-display/progress.d.ts +12 -6
- package/dist/components/data-display/progress.js +1 -1
- package/dist/components/data-display/tree.js +39 -0
- package/dist/components/layout/breadcrumb.js +2 -2
- package/dist/components/layout/index.d.ts +2 -0
- package/dist/components/layout/index.js +2 -0
- package/dist/components/layout/page-container.js +2 -2
- package/dist/components/layout/topbar-search.d.ts +12 -0
- package/dist/components/layout/topbar-search.js +87 -0
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +1 -0
- package/dist/i18n/messages/ja.json +1 -0
- package/dist/i18n/messages/vi.json +1 -0
- package/dist/props/components/layout.prop.d.ts +22 -0
- package/dist/props/registry.d.ts +9 -0
- package/dist/props/registry.js +16 -0
- package/dist/styles/card-layout.css +1 -1
- package/dist/styles/data-display-layout.css +37 -2
- package/dist/styles/dialog-layout.css +2 -0
- package/dist/styles/layers.json +7 -1
- package/dist/styles/navigation-layout.css +3 -0
- package/dist/styles/shell-layout.css +123 -2
- package/dist/styles.css +1 -1
- package/dist/tokens/components/card.css +3 -1
- package/dist/tokens/components/data-display.css +2 -0
- package/dist/tokens/components/shell.css +7 -0
- package/package.json +2 -2
- package/scripts/_agent-setup.mjs +10 -5
- package/scripts/cli.mjs +16 -7
- package/scripts/visual-audit.mjs +1412 -92
package/agent/tokens.json
CHANGED
|
@@ -2556,10 +2556,16 @@
|
|
|
2556
2556
|
"value": "var(--font-weight-medium)"
|
|
2557
2557
|
},
|
|
2558
2558
|
{
|
|
2559
|
-
"description": "
|
|
2559
|
+
"description": "gh#1305 (ADR C12): sentence case, no tracking by default; a theme opts into small caps.",
|
|
2560
2560
|
"name": "--stat-card-label-letter-spacing",
|
|
2561
2561
|
"tier": "component",
|
|
2562
|
-
"value": "
|
|
2562
|
+
"value": "normal"
|
|
2563
|
+
},
|
|
2564
|
+
{
|
|
2565
|
+
"description": "Card component tokens: card chrome derives from semantic layout tokens.",
|
|
2566
|
+
"name": "--stat-card-label-letter-case",
|
|
2567
|
+
"tier": "component",
|
|
2568
|
+
"value": "none"
|
|
2563
2569
|
},
|
|
2564
2570
|
{
|
|
2565
2571
|
"description": "Card component tokens: card chrome derives from semantic layout tokens.",
|
|
@@ -5387,6 +5393,12 @@
|
|
|
5387
5393
|
"tier": "component",
|
|
5388
5394
|
"value": "calc(2 * var(--control-height-xs) + var(--space-2))"
|
|
5389
5395
|
},
|
|
5396
|
+
{
|
|
5397
|
+
"description": "Below 40rem the gutter collapses to this (ADR C05: first line ≤24px from the inner edge) and the handle rises above the caret's block at its inline end instead of sitting beside it.",
|
|
5398
|
+
"name": "--block-editor-compact-gutter-inline-size",
|
|
5399
|
+
"tier": "component",
|
|
5400
|
+
"value": "var(--block-editor-frame-padding)"
|
|
5401
|
+
},
|
|
5390
5402
|
{
|
|
5391
5403
|
"description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
|
|
5392
5404
|
"name": "--block-editor-min-height",
|
|
@@ -5640,7 +5652,7 @@
|
|
|
5640
5652
|
"value": "initial"
|
|
5641
5653
|
},
|
|
5642
5654
|
{
|
|
5643
|
-
"description": "Progress track + fill — `initial` so the role defaults re-resolve under a scoped theme. Track reads --secondary, fill reads
|
|
5655
|
+
"description": "Progress track + fill — `initial` so the role defaults re-resolve under a scoped theme. Track reads --secondary, the default (`primary`) fill reads the brand mark; a service re-tones once. Defaults = hsl(var(--secondary)) track · hsl(var(--mark-primary, var(--primary))) fill (gh#1308 — it was the success mark; status tones are opt-in and do not read this knob).",
|
|
5644
5656
|
"name": "--progress-track-background",
|
|
5645
5657
|
"tier": "component",
|
|
5646
5658
|
"value": "initial"
|
|
@@ -10241,6 +10253,18 @@
|
|
|
10241
10253
|
"tier": "component",
|
|
10242
10254
|
"value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
|
|
10243
10255
|
},
|
|
10256
|
+
{
|
|
10257
|
+
"description": "Section label case and tracking (gh#1305, ADR C12): default sentence case, no tracking — tiny letter-spaced capitals (11px, 0.08em) are the classic \"AI dashboard\" eyebrow. A theme that wants small caps back sets both.",
|
|
10258
|
+
"name": "--sidebar-section-label-letter-case",
|
|
10259
|
+
"tier": "component",
|
|
10260
|
+
"value": "none"
|
|
10261
|
+
},
|
|
10262
|
+
{
|
|
10263
|
+
"description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
|
|
10264
|
+
"name": "--sidebar-section-label-letter-spacing",
|
|
10265
|
+
"tier": "component",
|
|
10266
|
+
"value": "normal"
|
|
10267
|
+
},
|
|
10244
10268
|
{
|
|
10245
10269
|
"description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
|
|
10246
10270
|
"name": "--sidebar-product-tenant-font-size",
|
|
@@ -10709,6 +10733,18 @@
|
|
|
10709
10733
|
"tier": "component",
|
|
10710
10734
|
"value": "none"
|
|
10711
10735
|
},
|
|
10736
|
+
{
|
|
10737
|
+
"description": "TopbarSearch (ADR C02): the inline field's TEXT AREA never shrinks below this — measured after the icon and clear/shortcut padding, in the field's own font. Below its `collapseBelow` step the field folds to a search cell instead of shrinking. 8ch is a repo-chosen policy, not a standard.",
|
|
10738
|
+
"name": "--topbar-search-min-text-inline-size",
|
|
10739
|
+
"tier": "component",
|
|
10740
|
+
"value": "8ch"
|
|
10741
|
+
},
|
|
10742
|
+
{
|
|
10743
|
+
"description": "The inline field's preferred width from the step up; it shrinks toward the floor above.",
|
|
10744
|
+
"name": "--topbar-search-inline-size",
|
|
10745
|
+
"tier": "component",
|
|
10746
|
+
"value": "16rem"
|
|
10747
|
+
},
|
|
10712
10748
|
{
|
|
10713
10749
|
"description": "TOPBAR BAR ITEM — the shape of an interactive cell IN the bar, as opposed to a control dropped into it. The bar's own chrome (Fluent's command bar, SLDS's global header, Atlassian's navigation, and the right-hand action slot of enterprise pro-layouts generally) draws a trigger as a full-height cell whose hover is the bar's surface; a `Button` in the same slot draws a --control-height pill with its own hover fill and its own ring, floating inside a taller strip. NO HEIGHT KNOB, DELIBERATELY. The cell's height IS the bar's, whatever the bar's is — `--app-shell-bar-height` inside AppShell, `--topbar-height` for a standalone Topbar, the coarse-pointer override on a touch device. A knob here would be a second answer that goes stale the moment either of those moves.",
|
|
10714
10750
|
"name": "--topbar-item-padding-inline",
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
export type ProgressTone = "success" | "warning" | "destructive";
|
|
3
2
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* Each paints exactly what the matching Legend swatch paints, so a key and its bar stay one.
|
|
3
|
+
* The METER's tone. `primary` (the default, gh#1308) is the brand role for ordinary progress — a
|
|
4
|
+
* reading position, an upload; the status tones are opt-in for a bar that reports that status
|
|
5
|
+
* (ADR C09). `primary` is the name `Badge` already gives its brand tone.
|
|
8
6
|
*/
|
|
9
|
-
export type
|
|
7
|
+
export type ProgressTone = "primary" | "success" | "warning" | "destructive";
|
|
8
|
+
/**
|
|
9
|
+
* A breakdown SLICE takes two more status tones than the meter (gh#1302): `info` and `neutral`, the
|
|
10
|
+
* same pair `Legend` already keys — a partition with four states (done · done-awaiting · in
|
|
11
|
+
* progress · not started) needs four distinguishable fills, and the meter's three made two of them
|
|
12
|
+
* identical. Each paints exactly what the matching Legend swatch paints, so a key and its bar stay
|
|
13
|
+
* one. No `primary`: a partition is states, and Legend keys no brand swatch.
|
|
14
|
+
*/
|
|
15
|
+
export type ProgressSegmentTone = Exclude<ProgressTone, "primary"> | "info" | "neutral";
|
|
10
16
|
/**
|
|
11
17
|
* One slice of a BREAKDOWN bar — how much of the total this state holds, in the SAME unit as every
|
|
12
18
|
* other slice (counts, bytes, yen). Never a percentage: the bar owns the ratio arithmetic, so the
|
|
@@ -73,7 +73,7 @@ function Progress(props) {
|
|
|
73
73
|
const meterValue = value ?? 0;
|
|
74
74
|
const isOver = over && meterValue > 100;
|
|
75
75
|
const boundedValue = Math.max(0, Math.min(100, meterValue));
|
|
76
|
-
const effectiveTone = tone ?? (isOver ? "destructive" : "
|
|
76
|
+
const effectiveTone = tone ?? (isOver ? "destructive" : "primary");
|
|
77
77
|
return /* @__PURE__ */ jsx(
|
|
78
78
|
"div",
|
|
79
79
|
{
|
|
@@ -5,6 +5,7 @@ import { mergeRefs } from "@react-aria/utils";
|
|
|
5
5
|
import { ChevronDown, ChevronRight, File as FileIcon, Folder, FolderOpen } from "lucide-react";
|
|
6
6
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
7
7
|
import { cn } from "../../lib/utils.js";
|
|
8
|
+
import { truncatedPart } from "../../lib/truncation.js";
|
|
8
9
|
import { CheckboxVisual } from "../data-entry/checkbox.js";
|
|
9
10
|
import { Skeleton } from "../feedback/skeleton.js";
|
|
10
11
|
import {
|
|
@@ -273,6 +274,44 @@ function TreeRoot({
|
|
|
273
274
|
const measured = firstRow?.offsetHeight ?? 0;
|
|
274
275
|
if (measured > 0 && measured !== rowHeight) setRowHeight(measured);
|
|
275
276
|
}, [isWindowed, rowHeight, size, visible.length]);
|
|
277
|
+
const markTruncatedLabels = React.useCallback(() => {
|
|
278
|
+
const tree = treeRef.current;
|
|
279
|
+
if (!tree) return;
|
|
280
|
+
for (const label of tree.querySelectorAll(".ui-tree-label")) {
|
|
281
|
+
if (label.dataset.truncated !== void 0 && label.parentElement === document.activeElement)
|
|
282
|
+
continue;
|
|
283
|
+
const ownTitle = label.dataset.truncatedTitle !== void 0;
|
|
284
|
+
const part = truncatedPart(label);
|
|
285
|
+
if (part) {
|
|
286
|
+
label.dataset.truncated = "";
|
|
287
|
+
if (!label.title || ownTitle) {
|
|
288
|
+
label.title = (label.textContent ?? "").replace(/\s+/g, " ").trim();
|
|
289
|
+
label.dataset.truncatedTitle = "";
|
|
290
|
+
}
|
|
291
|
+
} else if (label.dataset.truncated !== void 0) {
|
|
292
|
+
delete label.dataset.truncated;
|
|
293
|
+
if (ownTitle) {
|
|
294
|
+
label.removeAttribute("title");
|
|
295
|
+
delete label.dataset.truncatedTitle;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}, []);
|
|
300
|
+
React.useEffect(() => {
|
|
301
|
+
markTruncatedLabels();
|
|
302
|
+
});
|
|
303
|
+
React.useEffect(() => {
|
|
304
|
+
const tree = treeRef.current;
|
|
305
|
+
if (!tree || typeof ResizeObserver === "undefined") return;
|
|
306
|
+
const observer = new ResizeObserver(markTruncatedLabels);
|
|
307
|
+
observer.observe(tree);
|
|
308
|
+
const refold = () => requestAnimationFrame(markTruncatedLabels);
|
|
309
|
+
tree.addEventListener("focusout", refold);
|
|
310
|
+
return () => {
|
|
311
|
+
observer.disconnect();
|
|
312
|
+
tree.removeEventListener("focusout", refold);
|
|
313
|
+
};
|
|
314
|
+
}, [markTruncatedLabels]);
|
|
276
315
|
const nodeRefs = React.useRef(/* @__PURE__ */ new Map());
|
|
277
316
|
const pendingFocus = React.useRef(null);
|
|
278
317
|
React.useEffect(() => {
|
|
@@ -26,8 +26,8 @@ function Breadcrumb({
|
|
|
26
26
|
className: "ui-breadcrumb-item",
|
|
27
27
|
"data-ellipsis": item.ellipsis ? "" : void 0,
|
|
28
28
|
children: [
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
index > 0 ? /* @__PURE__ */ jsx("span", { className: "ui-breadcrumb-separator", "aria-hidden": "true", children: separatorNode }) : null,
|
|
30
|
+
renderBreadcrumbSegment({ item, index, isLast, items, itemRender, LinkComponent })
|
|
31
31
|
]
|
|
32
32
|
},
|
|
33
33
|
item.to ?? index
|
|
@@ -41,6 +41,8 @@ export { Topbar } from "./topbar.js";
|
|
|
41
41
|
export type { TopbarProp, TopbarProps } from "./topbar.js";
|
|
42
42
|
export { TopbarItem } from "./topbar-item.js";
|
|
43
43
|
export type { TopbarItemProp, TopbarItemProps } from "./topbar-item.js";
|
|
44
|
+
export { TopbarSearch } from "./topbar-search.js";
|
|
45
|
+
export type { TopbarSearchProp, TopbarSearchProps } from "./topbar-search.js";
|
|
44
46
|
export { ResponsiveGrid } from "./responsive-grid.js";
|
|
45
47
|
export type { ResponsiveGridProps } from "./responsive-grid.js";
|
|
46
48
|
export { MasterDetail } from "./master-detail.js";
|
|
@@ -18,6 +18,7 @@ import { Breadcrumb } from "./breadcrumb.js";
|
|
|
18
18
|
import { createSidebarLink, Sidebar, SidebarHeader, SidebarItem, SidebarSection } from "./sidebar.js";
|
|
19
19
|
import { Topbar } from "./topbar.js";
|
|
20
20
|
import { TopbarItem } from "./topbar-item.js";
|
|
21
|
+
import { TopbarSearch } from "./topbar-search.js";
|
|
21
22
|
import { ResponsiveGrid } from "./responsive-grid.js";
|
|
22
23
|
import { MasterDetail } from "./master-detail.js";
|
|
23
24
|
import { SplitPane } from "./split-pane.js";
|
|
@@ -59,6 +60,7 @@ export {
|
|
|
59
60
|
SplitPane,
|
|
60
61
|
Topbar,
|
|
61
62
|
TopbarItem,
|
|
63
|
+
TopbarSearch,
|
|
62
64
|
createSidebarLink,
|
|
63
65
|
useAppShellNavigationMode
|
|
64
66
|
};
|
|
@@ -123,6 +123,7 @@ function PageContainerRoot({
|
|
|
123
123
|
className: "ui-breadcrumb-item",
|
|
124
124
|
"data-ellipsis": item.ellipsis ? "" : void 0,
|
|
125
125
|
children: [
|
|
126
|
+
i > 0 ? /* @__PURE__ */ jsx("span", { className: "ui-breadcrumb-separator", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true" }) }) : null,
|
|
126
127
|
item.to && !isLast ? /* @__PURE__ */ jsx(BreadcrumbCrumbText, { item, children: /* @__PURE__ */ jsx(
|
|
127
128
|
LinkComponent,
|
|
128
129
|
{
|
|
@@ -138,8 +139,7 @@ function PageContainerRoot({
|
|
|
138
139
|
"aria-current": isLast ? "page" : void 0,
|
|
139
140
|
children: item.label
|
|
140
141
|
}
|
|
141
|
-
) })
|
|
142
|
-
!isLast && /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true" })
|
|
142
|
+
) })
|
|
143
143
|
]
|
|
144
144
|
},
|
|
145
145
|
i
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { TopbarSearchProp } from "../../props/components/layout.prop.js";
|
|
3
|
+
export type { TopbarSearchProp, TopbarSearchProp as TopbarSearchProps, } from "../../props/components/layout.prop.js";
|
|
4
|
+
/**
|
|
5
|
+
* TopbarSearch — the bar's search box, folded to a named search cell below `collapseBelow` (ADR C02).
|
|
6
|
+
*
|
|
7
|
+
* WAI-ARIA APG disclosure: the cell is a button with `aria-expanded` / `aria-controls`; the panel it
|
|
8
|
+
* shows holds the ONE `SearchInput` this component renders. Which of the two is on screen is decided
|
|
9
|
+
* by CSS at the step (`data-collapse-below`), not by a media-query hook, so SSR and the first client
|
|
10
|
+
* paint agree and the field keeps its value across a resize.
|
|
11
|
+
*/
|
|
12
|
+
export declare function TopbarSearch({ collapseBelow, className, ...props }: TopbarSearchProp): React.JSX.Element;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Search, X } from "lucide-react";
|
|
5
|
+
import { useTranslation } from "../../i18n/use-translation.js";
|
|
6
|
+
import { cn } from "../../lib/utils.js";
|
|
7
|
+
import { SearchInput } from "../data-entry/search-input.js";
|
|
8
|
+
import { TopbarItem } from "./topbar-item.js";
|
|
9
|
+
function TopbarSearch({ collapseBelow = "sm", className, ...props }) {
|
|
10
|
+
const { t } = useTranslation();
|
|
11
|
+
const [open, setOpen] = React.useState(false);
|
|
12
|
+
const triggerRef = React.useRef(null);
|
|
13
|
+
const panelRef = React.useRef(null);
|
|
14
|
+
const pressedInside = React.useRef(false);
|
|
15
|
+
const panelId = React.useId();
|
|
16
|
+
const name = props.ariaLabel ?? t("common.search");
|
|
17
|
+
React.useEffect(() => {
|
|
18
|
+
if (open) panelRef.current?.querySelector("input")?.focus();
|
|
19
|
+
}, [open]);
|
|
20
|
+
const close = (returnFocus) => {
|
|
21
|
+
setOpen(false);
|
|
22
|
+
if (returnFocus) triggerRef.current?.focus();
|
|
23
|
+
};
|
|
24
|
+
return /* @__PURE__ */ jsxs(
|
|
25
|
+
"div",
|
|
26
|
+
{
|
|
27
|
+
"data-slot": "topbar-search",
|
|
28
|
+
"data-collapse-below": collapseBelow,
|
|
29
|
+
"data-open": open ? "true" : void 0,
|
|
30
|
+
className: cn("ui-topbar-search", className),
|
|
31
|
+
children: [
|
|
32
|
+
/* @__PURE__ */ jsx(
|
|
33
|
+
TopbarItem,
|
|
34
|
+
{
|
|
35
|
+
ref: triggerRef,
|
|
36
|
+
className: "ui-topbar-search-trigger",
|
|
37
|
+
"aria-label": name,
|
|
38
|
+
"aria-expanded": open,
|
|
39
|
+
"aria-controls": panelId,
|
|
40
|
+
icon: /* @__PURE__ */ jsx(Search, { "aria-hidden": "true" }),
|
|
41
|
+
onClick: () => setOpen(true)
|
|
42
|
+
}
|
|
43
|
+
),
|
|
44
|
+
/* @__PURE__ */ jsxs(
|
|
45
|
+
"div",
|
|
46
|
+
{
|
|
47
|
+
ref: panelRef,
|
|
48
|
+
id: panelId,
|
|
49
|
+
className: "ui-topbar-search-panel",
|
|
50
|
+
onKeyDown: (event) => {
|
|
51
|
+
if (open && event.key === "Escape" && !event.nativeEvent.isComposing) {
|
|
52
|
+
event.preventDefault();
|
|
53
|
+
close(true);
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
onPointerDownCapture: () => {
|
|
57
|
+
pressedInside.current = true;
|
|
58
|
+
setTimeout(() => {
|
|
59
|
+
pressedInside.current = false;
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
onBlur: (event) => {
|
|
63
|
+
if (open && !pressedInside.current && !event.currentTarget.contains(event.relatedTarget)) {
|
|
64
|
+
close(false);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
children: [
|
|
68
|
+
/* @__PURE__ */ jsx(SearchInput, { ...props }),
|
|
69
|
+
/* @__PURE__ */ jsx(
|
|
70
|
+
TopbarItem,
|
|
71
|
+
{
|
|
72
|
+
className: "ui-topbar-search-close",
|
|
73
|
+
"aria-label": t("layout.topbar.closeSearch"),
|
|
74
|
+
icon: /* @__PURE__ */ jsx(X, { "aria-hidden": "true" }),
|
|
75
|
+
onClick: () => close(true)
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
export {
|
|
86
|
+
TopbarSearch
|
|
87
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "AUTO-GENERATED by scripts/gen-measurement-contract.mjs — do not edit. Read this instead of guessing: docs/MEASUREMENT-CONTRACT.md.",
|
|
3
|
-
"version": "32.
|
|
3
|
+
"version": "32.10.1",
|
|
4
4
|
"targetSize": {
|
|
5
5
|
"standard": "WCAG 2.2 SC 2.5.8 Target Size (Minimum), level AA — 24×24 CSS px",
|
|
6
6
|
"min": 24,
|
|
@@ -3,6 +3,7 @@ import type * as React from "react";
|
|
|
3
3
|
import type { ComponentType, ReactNode, SVGProps } from "react";
|
|
4
4
|
import type { BreadcrumbProp, TitleProp, SubtitleProp, StatusProp, ExtraProp, FooterProp, PageDensityProp, DensityProp, PageContainerVariantProp, CenteredShellWidthProp, CenteredShellAlignProp, CenteredShellPresetProp, ErrorSurfaceModeProp, ErrorSurfaceStatusProp, AuthShellPresetProp, MobileShellHeightProp, MobileShellWidthProp, OrientationProp, TextAlignProp, TextToneProp, BreakpointProp, GapProp, PadProp, PadRawProp, ClassNameProp, ChildrenProp, IdProp, DisabledProp, DescriptionProp, ActionProp, IconProp, HeadingLevelProp, ToneProp, WidthProp, SizeProp } from "../vocabulary/index.js";
|
|
5
5
|
import type { EmptyStateToneProp } from "./data-display.prop.js";
|
|
6
|
+
import type { SearchInputProp } from "./data-entry.prop.js";
|
|
6
7
|
/**
|
|
7
8
|
* Arrangement of the page header's title band and its `extra` slot below the 640px step.
|
|
8
9
|
* `responsive-inline` keeps `extra` beside the title band at the `--page-header-extra-measure`
|
|
@@ -1568,6 +1569,27 @@ export type TopbarProp = Omit<React.HTMLAttributes<HTMLDivElement>, "children">
|
|
|
1568
1569
|
/** Escape hatch — render fully custom bar content instead of the three slots. */
|
|
1569
1570
|
children?: ReactNode;
|
|
1570
1571
|
};
|
|
1572
|
+
/**
|
|
1573
|
+
* @see TopbarSearch — the bar's one search box, which folds to a named search cell on a narrow bar.
|
|
1574
|
+
*
|
|
1575
|
+
* A `SearchInput` dropped into a `Topbar` slot shrinks with its cluster: at 390px in a consumer bar
|
|
1576
|
+
* its text area held under 3ch, so neither a query nor the placeholder could be read (ADR C02).
|
|
1577
|
+
* Below `collapseBelow` this renders a `TopbarItem` named by `ariaLabel`; activating it opens the
|
|
1578
|
+
* field across the whole bar (Material 3 search bar → search view), focused, with a close cell.
|
|
1579
|
+
* Escape or the close cell folds it back and returns focus to the trigger; focus leaving the open
|
|
1580
|
+
* field folds it too. From the step up it is the inline field, whose text area never shrinks below
|
|
1581
|
+
* `--topbar-search-min-text-inline-size` (8ch).
|
|
1582
|
+
*
|
|
1583
|
+
* Every `SearchInput` prop passes through unchanged. ONE field is rendered at every width, so the
|
|
1584
|
+
* typed query survives a resize and the open/closed switch.
|
|
1585
|
+
*/
|
|
1586
|
+
export type TopbarSearchProp = SearchInputProp & {
|
|
1587
|
+
/**
|
|
1588
|
+
* The step below which the field folds to a search cell. Default `"sm"` (40rem) — the bar's own
|
|
1589
|
+
* compact step, shared with `TopbarItem labelHideBelow` and `AppShell logoCompactBelow`.
|
|
1590
|
+
*/
|
|
1591
|
+
collapseBelow?: BreakpointProp;
|
|
1592
|
+
};
|
|
1571
1593
|
/**
|
|
1572
1594
|
* @see TopbarItem — ONE interactive cell of a {@link TopbarProp} slot: the account button, a
|
|
1573
1595
|
* settings trigger, a notifications bell.
|
package/dist/props/registry.d.ts
CHANGED
|
@@ -1456,6 +1456,15 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
1456
1456
|
readonly reason: "Flex `hideBelow` scoped to the cell's label — icon-only below a breakpoint; visually hidden so the accessible name survives (gh#726).";
|
|
1457
1457
|
}];
|
|
1458
1458
|
};
|
|
1459
|
+
readonly TopbarSearchProp: {
|
|
1460
|
+
readonly group: "layout";
|
|
1461
|
+
readonly file: "components/layout.prop.ts";
|
|
1462
|
+
readonly vocabulary: readonly ["LabelProp", "PlaceholderProp", "DisabledProp", "ClassNameProp", "IdProp", {
|
|
1463
|
+
readonly field: "collapseBelow";
|
|
1464
|
+
readonly local: true;
|
|
1465
|
+
readonly reason: "Flex `hideBelow`'s breakpoint vocabulary, naming the step below which the bar's search folds to a search cell (ADR C02).";
|
|
1466
|
+
}];
|
|
1467
|
+
};
|
|
1459
1468
|
readonly NavListProp: {
|
|
1460
1469
|
readonly group: "layout";
|
|
1461
1470
|
readonly file: "components/layout.prop.ts";
|
package/dist/props/registry.js
CHANGED
|
@@ -1579,6 +1579,22 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
1579
1579
|
}
|
|
1580
1580
|
]
|
|
1581
1581
|
},
|
|
1582
|
+
TopbarSearchProp: {
|
|
1583
|
+
group: "layout",
|
|
1584
|
+
file: "components/layout.prop.ts",
|
|
1585
|
+
vocabulary: [
|
|
1586
|
+
"LabelProp",
|
|
1587
|
+
"PlaceholderProp",
|
|
1588
|
+
"DisabledProp",
|
|
1589
|
+
"ClassNameProp",
|
|
1590
|
+
"IdProp",
|
|
1591
|
+
{
|
|
1592
|
+
field: "collapseBelow",
|
|
1593
|
+
local: true,
|
|
1594
|
+
reason: "Flex `hideBelow`'s breakpoint vocabulary, naming the step below which the bar's search folds to a search cell (ADR C02)."
|
|
1595
|
+
}
|
|
1596
|
+
]
|
|
1597
|
+
},
|
|
1582
1598
|
NavListProp: {
|
|
1583
1599
|
group: "layout",
|
|
1584
1600
|
file: "components/layout.prop.ts",
|
|
@@ -501,7 +501,7 @@
|
|
|
501
501
|
font-weight: var(--stat-card-label-font-weight);
|
|
502
502
|
letter-spacing: var(--stat-card-label-letter-spacing);
|
|
503
503
|
line-height: var(--line-height-normal);
|
|
504
|
-
text-transform:
|
|
504
|
+
text-transform: var(--stat-card-label-letter-case);
|
|
505
505
|
}
|
|
506
506
|
|
|
507
507
|
[data-slot="stat-card-label"] svg {
|
|
@@ -189,7 +189,11 @@
|
|
|
189
189
|
.ui-progress-bar {
|
|
190
190
|
height: 100%;
|
|
191
191
|
border-radius: inherit;
|
|
192
|
-
background: var(--progress-fill-background, hsl(var(--mark-
|
|
192
|
+
background: var(--progress-fill-background, hsl(var(--mark-primary, var(--primary))));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.ui-progress[data-tone="success"] .ui-progress-bar {
|
|
196
|
+
background: hsl(var(--mark-success, var(--text-success)));
|
|
193
197
|
}
|
|
194
198
|
|
|
195
199
|
.ui-progress[data-tone="warning"] .ui-progress-bar {
|
|
@@ -291,11 +295,15 @@
|
|
|
291
295
|
}
|
|
292
296
|
|
|
293
297
|
.ui-progress-ring-indicator {
|
|
294
|
-
stroke: var(--progress-fill-background, hsl(var(--mark-
|
|
298
|
+
stroke: var(--progress-fill-background, hsl(var(--mark-primary, var(--primary))));
|
|
295
299
|
|
|
296
300
|
stroke-linecap: butt;
|
|
297
301
|
}
|
|
298
302
|
|
|
303
|
+
.ui-progress[data-tone="success"] .ui-progress-ring-indicator {
|
|
304
|
+
stroke: hsl(var(--mark-success, var(--text-success)));
|
|
305
|
+
}
|
|
306
|
+
|
|
299
307
|
.ui-progress[data-tone="warning"] .ui-progress-ring-indicator {
|
|
300
308
|
stroke: hsl(var(--mark-warning, var(--text-warning)));
|
|
301
309
|
}
|
|
@@ -1574,6 +1582,25 @@
|
|
|
1574
1582
|
gap: var(--space-1);
|
|
1575
1583
|
}
|
|
1576
1584
|
|
|
1585
|
+
@media (width < 40rem) {
|
|
1586
|
+
.ui-block-editor {
|
|
1587
|
+
padding-inline-start: var(--block-editor-compact-gutter-inline-size);
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
.ui-block-editor-handle {
|
|
1591
|
+
inset-inline: auto var(--block-editor-compact-gutter-inline-size);
|
|
1592
|
+
translate: 0 -100%;
|
|
1593
|
+
padding: var(--stroke-hairline);
|
|
1594
|
+
border: var(--stroke-hairline) solid hsl(var(--border));
|
|
1595
|
+
border-radius: var(--popover-radius, var(--radius));
|
|
1596
|
+
background-color: hsl(var(--popover) / var(--popover-alpha, 100%));
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
.ui-block-editor-handle[data-first-block] {
|
|
1600
|
+
translate: none;
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1577
1604
|
@media (hover: hover) {
|
|
1578
1605
|
.ui-block-editor:not(:hover):not(:focus-within) .ui-block-editor-handle {
|
|
1579
1606
|
opacity: 0;
|
|
@@ -2924,6 +2951,14 @@
|
|
|
2924
2951
|
white-space: nowrap;
|
|
2925
2952
|
}
|
|
2926
2953
|
|
|
2954
|
+
.ui-tree:not([data-virtual])
|
|
2955
|
+
.ui-tree-node:focus-visible
|
|
2956
|
+
> .ui-tree-label[data-truncated]:not(:has([data-ellipsis])) {
|
|
2957
|
+
overflow: visible;
|
|
2958
|
+
white-space: normal;
|
|
2959
|
+
overflow-wrap: anywhere;
|
|
2960
|
+
}
|
|
2961
|
+
|
|
2927
2962
|
.ui-tree-group {
|
|
2928
2963
|
display: flex;
|
|
2929
2964
|
flex-direction: column;
|
package/dist/styles/layers.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "32.
|
|
2
|
+
"version": "32.10.1",
|
|
3
3
|
"generatedBy": "scripts/gen-style-layers.mjs — do not edit by hand; run `pnpm gen:style-layers`",
|
|
4
4
|
"base": "base.css",
|
|
5
5
|
"fonts": "fonts.css",
|
|
@@ -1072,6 +1072,12 @@
|
|
|
1072
1072
|
"shell-layout.css"
|
|
1073
1073
|
]
|
|
1074
1074
|
},
|
|
1075
|
+
"TopbarSearch": {
|
|
1076
|
+
"layers": [
|
|
1077
|
+
"shell-layout.css",
|
|
1078
|
+
"control.css"
|
|
1079
|
+
]
|
|
1080
|
+
},
|
|
1075
1081
|
"Transfer": {
|
|
1076
1082
|
"layers": [
|
|
1077
1083
|
"layout.css",
|