@godxjp/ui 30.1.0 → 30.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/START-HERE.md +1 -1
- package/agent/index.json +2 -2
- package/agent/llms.txt +3 -3
- package/dist/components/layout/topbar.d.ts +2 -1
- package/dist/components/layout/topbar.js +48 -5
- 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 +6 -1
- package/dist/styles/logo-layout.css +13 -0
- package/dist/styles/shell-layout.css +30 -0
- package/package.json +2 -2
package/agent/START-HERE.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
You are about to write code against a design system you did not author. This file is the whole
|
|
4
4
|
contract. Read it before you write JSX.
|
|
5
5
|
|
|
6
|
-
**This catalog describes `@godxjp/ui` 30.
|
|
6
|
+
**This catalog describes `@godxjp/ui` 30.2.0.** If the project you are editing has a different
|
|
7
7
|
version in its `package.json`, read the pinned catalog for THAT version instead
|
|
8
8
|
(`…/v<their-version>/agent/…`). A catalog newer than the installed package describes props that do
|
|
9
9
|
not exist yet; older, and it hides props that do. Neither failure announces itself.
|
package/agent/index.json
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"note": "Pin to the tag that matches the @godxjp/ui version you installed. A catalog newer than your package describes props you do not have; older, and it hides props you do.",
|
|
49
49
|
"read": {
|
|
50
50
|
"live": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json",
|
|
51
|
-
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v30.
|
|
51
|
+
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v30.2.0/agent/index.json"
|
|
52
52
|
},
|
|
53
53
|
"source": "mcp/src/data — the same data @godxjp/ui-mcp serves — plus the foundation and semantic token tiers, read from src/tokens/*.css",
|
|
54
54
|
"start": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md",
|
|
@@ -62,5 +62,5 @@
|
|
|
62
62
|
"foundation": "the seeds a consumer is invited to set — --primary, --background, --radius",
|
|
63
63
|
"semantic": "named roles that follow the seeds — --ring, --text-link, --overlay-background"
|
|
64
64
|
},
|
|
65
|
-
"version": "30.
|
|
65
|
+
"version": "30.2.0"
|
|
66
66
|
}
|
package/agent/llms.txt
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @godxjp/ui
|
|
2
2
|
|
|
3
3
|
> A Japanese-enterprise React design system: 171 components, 2071 design tokens,
|
|
4
|
-
> 50 cardinal rules. This file is the entry point for AI agents. Catalog version 30.
|
|
4
|
+
> 50 cardinal rules. This file is the entry point for AI agents. Catalog version 30.2.0.
|
|
5
5
|
|
|
6
6
|
If your client can run a process, do not read these files — run the MCP server instead
|
|
7
|
-
(`npx @godxjp/ui-mcp@30.
|
|
7
|
+
(`npx @godxjp/ui-mcp@30.2.0`). It is searchable and version-locked. These files exist for agents
|
|
8
8
|
that can only fetch URLs.
|
|
9
9
|
|
|
10
10
|
## Start
|
|
@@ -26,7 +26,7 @@ that can only fetch URLs.
|
|
|
26
26
|
## Pinning
|
|
27
27
|
|
|
28
28
|
Every URL above tracks `main`. To pin to the release a project actually installed, swap `main` for
|
|
29
|
-
the tag: `.../godx-jp/godxjp-ui/v30.
|
|
29
|
+
the tag: `.../godx-jp/godxjp-ui/v30.2.0/agent/...`. A catalog that does not match the installed
|
|
30
30
|
package describes props that are absent, or hides props that are present, and says nothing either way.
|
|
31
31
|
|
|
32
32
|
Pinned catalogs only exist for releases whose tag actually contains `agent/`. If `…/v<version>/agent/index.json` returns 404, that release predates this catalog: read `…/main/…` instead and compare `index.json` → `version` against the package you have, so you at least know which way it drifted.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import * as React from "react";
|
|
1
2
|
import type { TopbarProp } from "../../props/components/layout.prop.js";
|
|
2
3
|
export type { TopbarProp, TopbarProp as TopbarProps } from "../../props/components/layout.prop.js";
|
|
3
4
|
/**
|
|
4
5
|
* Topbar — a PURE SLOT bar. It positions three clusters (`start` / `center` / `end`) and owns the
|
|
5
6
|
* bar's flex layout; it does NOT bake any chrome.
|
|
6
7
|
*/
|
|
7
|
-
export declare function Topbar({ start, center, end, className, children, height, overflow, pad, style, ...props }: TopbarProp):
|
|
8
|
+
export declare function Topbar({ start, center, end, className, children, height, overflow, pad, style, ...props }: TopbarProp): React.JSX.Element;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { MoreHorizontal } from "lucide-react";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { useTranslation } from "../../i18n/use-translation.js";
|
|
2
6
|
import { padStyle } from "../../lib/variants.js";
|
|
3
7
|
import { cn } from "../../lib/utils.js";
|
|
8
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../data-display/popover.js";
|
|
9
|
+
import { TopbarItem } from "./topbar-item.js";
|
|
4
10
|
function Topbar({
|
|
5
11
|
start,
|
|
6
12
|
center,
|
|
@@ -13,23 +19,60 @@ function Topbar({
|
|
|
13
19
|
style,
|
|
14
20
|
...props
|
|
15
21
|
}) {
|
|
22
|
+
const barRef = React.useRef(null);
|
|
23
|
+
const foldable = overflow === "menu" && children == null;
|
|
24
|
+
const collapsed = useCollapsesToMenu(barRef, foldable);
|
|
25
|
+
const clusters = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
26
|
+
start != null ? /* @__PURE__ */ jsx("div", { "data-slot": "topbar-start", className: "ui-topbar-start", children: start }) : null,
|
|
27
|
+
center != null ? /* @__PURE__ */ jsx("div", { "data-slot": "topbar-center", className: "ui-topbar-center", children: center }) : null,
|
|
28
|
+
end != null ? /* @__PURE__ */ jsx("div", { "data-slot": "topbar-end", className: "ui-topbar-end", children: end }) : null
|
|
29
|
+
] });
|
|
16
30
|
return /* @__PURE__ */ jsx(
|
|
17
31
|
"div",
|
|
18
32
|
{
|
|
33
|
+
ref: barRef,
|
|
19
34
|
"data-height": height,
|
|
20
35
|
"data-overflow": overflow,
|
|
36
|
+
"data-collapsed": foldable ? String(collapsed) : void 0,
|
|
21
37
|
style: { ...style, ...padStyle(pad, void 0) },
|
|
22
38
|
"data-slot": "topbar",
|
|
23
39
|
className: cn("ui-topbar", className),
|
|
24
40
|
...props,
|
|
25
|
-
children: children ?? /* @__PURE__ */
|
|
26
|
-
start != null ? /* @__PURE__ */ jsx("div", { "data-slot": "topbar-start", className: "ui-topbar-start", children: start }) : null,
|
|
27
|
-
center != null ? /* @__PURE__ */ jsx("div", { "data-slot": "topbar-center", className: "ui-topbar-center", children: center }) : null,
|
|
28
|
-
end != null ? /* @__PURE__ */ jsx("div", { "data-slot": "topbar-end", className: "ui-topbar-end", children: end }) : null
|
|
29
|
-
] })
|
|
41
|
+
children: children ?? (collapsed ? /* @__PURE__ */ jsx(TopbarOverflowMenu, { children: clusters }) : clusters)
|
|
30
42
|
}
|
|
31
43
|
);
|
|
32
44
|
}
|
|
45
|
+
function TopbarOverflowMenu({ children }) {
|
|
46
|
+
const { t } = useTranslation();
|
|
47
|
+
return /* @__PURE__ */ jsxs(Popover, { children: [
|
|
48
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(TopbarItem, { "data-topbar-overflow-trigger": "", "aria-label": t("layout.topbar.more"), children: /* @__PURE__ */ jsx(MoreHorizontal, { "aria-hidden": "true" }) }) }),
|
|
49
|
+
/* @__PURE__ */ jsx(PopoverContent, { align: "end", width: "auto", children: /* @__PURE__ */ jsx("div", { "data-slot": "topbar-overflow", className: "ui-topbar-overflow", children }) })
|
|
50
|
+
] });
|
|
51
|
+
}
|
|
52
|
+
function useCollapsesToMenu(ref, enabled) {
|
|
53
|
+
const [collapsed, setCollapsed] = React.useState(false);
|
|
54
|
+
const needed = React.useRef(0);
|
|
55
|
+
React.useLayoutEffect(() => {
|
|
56
|
+
const bar = ref.current;
|
|
57
|
+
if (!enabled || !bar) return void 0;
|
|
58
|
+
const update = () => {
|
|
59
|
+
if (!collapsed) {
|
|
60
|
+
if (bar.clientWidth > 0 && bar.scrollWidth - bar.clientWidth > 1) {
|
|
61
|
+
needed.current = bar.scrollWidth;
|
|
62
|
+
setCollapsed(true);
|
|
63
|
+
}
|
|
64
|
+
} else if (bar.clientWidth >= needed.current) {
|
|
65
|
+
setCollapsed(false);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
update();
|
|
69
|
+
if (typeof ResizeObserver === "undefined") return void 0;
|
|
70
|
+
const observer = new ResizeObserver(update);
|
|
71
|
+
observer.observe(bar);
|
|
72
|
+
return () => observer.disconnect();
|
|
73
|
+
}, [ref, enabled, collapsed]);
|
|
74
|
+
return enabled && collapsed;
|
|
75
|
+
}
|
|
33
76
|
export {
|
|
34
77
|
Topbar
|
|
35
78
|
};
|
|
@@ -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": "30.
|
|
3
|
+
"version": "30.1.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,
|
|
@@ -1424,12 +1424,17 @@ export type TopbarProp = Omit<React.HTMLAttributes<HTMLDivElement>, "children">
|
|
|
1424
1424
|
* - `"clip"` — the pre-gh#728 behaviour: a cell past the cluster's edge is simply not painted.
|
|
1425
1425
|
* Still focusable, still announced, invisible and unreachable by pointer. Choose it only for a
|
|
1426
1426
|
* bar you have measured as never overflowing.
|
|
1427
|
+
* - `"menu"` — when the clusters do not fit, the bar shows ONE "more" cell and the clusters
|
|
1428
|
+
* move into its popover, where they wrap (gh#914). Nothing is off-screen and nothing is
|
|
1429
|
+
* duplicated: each control is rendered once, in the bar or in the popover. Use it for a bar
|
|
1430
|
+
* that must survive a narrow viewport with enlarged text, where a scrolling bar can shrink to
|
|
1431
|
+
* a window narrower than one cell. Ignored with `children`.
|
|
1427
1432
|
*
|
|
1428
1433
|
* Independent of `TopbarItem hideBelow`, which REMOVES a cell at a step: dropping a cell is the
|
|
1429
1434
|
* consumer saying it does not belong on a phone, and that remains the way to spend the budget
|
|
1430
1435
|
* deliberately. This prop is only about what happens once there is no budget left.
|
|
1431
1436
|
*/
|
|
1432
|
-
overflow?: "scroll" | "clip";
|
|
1437
|
+
overflow?: "scroll" | "clip" | "menu";
|
|
1433
1438
|
/** Escape hatch — render fully custom bar content instead of the three slots. */
|
|
1434
1439
|
children?: ReactNode;
|
|
1435
1440
|
};
|
|
@@ -141,6 +141,16 @@
|
|
|
141
141
|
width: auto;
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
.ui-logo[data-mark="godx-lockup"] {
|
|
145
|
+
flex-shrink: 1;
|
|
146
|
+
min-inline-size: 0;
|
|
147
|
+
max-inline-size: 100%;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.ui-logo[data-mark="godx-lockup"] [data-slot="logo-artwork"] {
|
|
151
|
+
max-inline-size: 100%;
|
|
152
|
+
}
|
|
153
|
+
|
|
144
154
|
.ui-logo[data-mark="godx"] [data-slot="logo-artwork"] {
|
|
145
155
|
display: block;
|
|
146
156
|
width: 100%;
|
|
@@ -149,8 +159,11 @@
|
|
|
149
159
|
|
|
150
160
|
.ui-logo-lockup {
|
|
151
161
|
display: inline-flex;
|
|
162
|
+
flex-wrap: wrap;
|
|
152
163
|
align-items: center;
|
|
153
164
|
gap: var(--logo-wordmark-gap);
|
|
165
|
+
min-inline-size: 0;
|
|
166
|
+
max-inline-size: 100%;
|
|
154
167
|
}
|
|
155
168
|
|
|
156
169
|
.ui-logo-lockup .ui-logo-wordmark {
|
|
@@ -2084,6 +2084,36 @@
|
|
|
2084
2084
|
min-inline-size: auto;
|
|
2085
2085
|
}
|
|
2086
2086
|
|
|
2087
|
+
.ui-topbar[data-overflow="menu"] {
|
|
2088
|
+
overflow: hidden;
|
|
2089
|
+
min-inline-size: var(--topbar-item-min-width);
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
.ui-topbar[data-overflow="menu"] > .ui-topbar-end {
|
|
2093
|
+
max-inline-size: none;
|
|
2094
|
+
min-inline-size: auto;
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
.ui-topbar[data-overflow="menu"] > [data-topbar-overflow-trigger] {
|
|
2098
|
+
margin-inline-start: auto;
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
.ui-topbar-overflow {
|
|
2102
|
+
display: flex;
|
|
2103
|
+
flex-wrap: wrap;
|
|
2104
|
+
align-items: center;
|
|
2105
|
+
gap: var(--topbar-gap);
|
|
2106
|
+
|
|
2107
|
+
max-inline-size: calc(100vi - 2 * var(--popover-space-inset) - var(--space-4));
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
.ui-topbar-overflow > :is(.ui-topbar-start, .ui-topbar-center, .ui-topbar-end) {
|
|
2111
|
+
flex-wrap: wrap;
|
|
2112
|
+
margin-inline-start: 0;
|
|
2113
|
+
min-block-size: var(--topbar-item-min-width);
|
|
2114
|
+
overflow: visible;
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2087
2117
|
.ui-topbar-item {
|
|
2088
2118
|
display: inline-flex;
|
|
2089
2119
|
min-width: var(--topbar-item-min-width);
|