@godxjp/ui 27.7.0 → 27.8.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/dist/components/layout/topbar-item.d.ts +2 -0
- package/dist/components/layout/topbar-item.js +34 -4
- package/dist/contracts/measurement.json +1 -1
- package/dist/props/components/layout.prop.d.ts +16 -0
- package/dist/props/registry.d.ts +8 -0
- package/dist/props/registry.js +12 -1
- package/dist/styles/layout.css +60 -4
- package/docs/layout/topbar-item.tsx +37 -0
- package/package.json +2 -2
|
@@ -13,6 +13,8 @@ export type { TopbarItemProp, TopbarItemProp as TopbarItemProps, } from "../../p
|
|
|
13
13
|
export declare const TopbarItem: React.ForwardRefExoticComponent<Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "children"> & {
|
|
14
14
|
hideBelow?: import("../../props/index.js").BreakpointProp;
|
|
15
15
|
icon?: React.ReactNode;
|
|
16
|
+
iconHideFrom?: import("../../props/index.js").BreakpointProp;
|
|
17
|
+
labelHideBelow?: import("../../props/index.js").BreakpointProp;
|
|
16
18
|
badge?: React.ReactNode;
|
|
17
19
|
badgeTone?: import("../../props/components/layout.prop.js").SidebarBadgeToneProp;
|
|
18
20
|
asChild?: boolean;
|
|
@@ -2,10 +2,40 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { Slot } from "../../lib/slot.js";
|
|
4
4
|
import { cn } from "../../lib/utils.js";
|
|
5
|
-
const TopbarItem = React.forwardRef(function TopbarItem2({
|
|
5
|
+
const TopbarItem = React.forwardRef(function TopbarItem2({
|
|
6
|
+
asChild = false,
|
|
7
|
+
className,
|
|
8
|
+
type,
|
|
9
|
+
hideBelow,
|
|
10
|
+
icon,
|
|
11
|
+
iconHideFrom,
|
|
12
|
+
labelHideBelow,
|
|
13
|
+
badge,
|
|
14
|
+
badgeTone,
|
|
15
|
+
children,
|
|
16
|
+
...props
|
|
17
|
+
}, ref) {
|
|
6
18
|
const Comp = asChild ? Slot : "button";
|
|
7
19
|
const showBadge = !asChild && badge !== void 0 && badge !== "";
|
|
8
|
-
const iconNode =
|
|
20
|
+
const iconNode = icon !== void 0 && icon !== null && icon !== false ? /* @__PURE__ */ jsx(
|
|
21
|
+
"span",
|
|
22
|
+
{
|
|
23
|
+
"data-slot": "topbar-item-icon",
|
|
24
|
+
className: "ui-topbar-item-icon",
|
|
25
|
+
"data-hide-from": iconHideFrom,
|
|
26
|
+
children: icon
|
|
27
|
+
}
|
|
28
|
+
) : null;
|
|
29
|
+
const labelOf = (label) => labelHideBelow === void 0 || label === void 0 || label === null || label === false ? label : /* @__PURE__ */ jsx(
|
|
30
|
+
"span",
|
|
31
|
+
{
|
|
32
|
+
"data-slot": "topbar-item-label",
|
|
33
|
+
className: "ui-topbar-item-label",
|
|
34
|
+
"data-hide-below": labelHideBelow,
|
|
35
|
+
children: label
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
const slotted = asChild && (iconNode !== null || labelHideBelow !== void 0) && React.isValidElement(children) ? React.cloneElement(children, void 0, iconNode, labelOf(children.props.children)) : children;
|
|
9
39
|
const badgeNode = showBadge ? /* @__PURE__ */ jsx(
|
|
10
40
|
"span",
|
|
11
41
|
{
|
|
@@ -24,9 +54,9 @@ const TopbarItem = React.forwardRef(function TopbarItem2({ asChild = false, clas
|
|
|
24
54
|
className: cn("ui-topbar-item ui-focus-ring", className),
|
|
25
55
|
type: asChild ? void 0 : type ?? "button",
|
|
26
56
|
...props,
|
|
27
|
-
children: asChild ?
|
|
57
|
+
children: asChild ? slotted : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
28
58
|
iconNode,
|
|
29
|
-
children,
|
|
59
|
+
labelOf(children),
|
|
30
60
|
badgeNode
|
|
31
61
|
] })
|
|
32
62
|
}
|
|
@@ -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": "27.
|
|
3
|
+
"version": "27.8.0",
|
|
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,
|
|
@@ -1354,8 +1354,24 @@ export type TopbarItemProp = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
|
1354
1354
|
* visible label, not from the glyph. For a glyph that must carry a name, or one that needs a
|
|
1355
1355
|
* step other than the bar's, pass `<Icon as={…} size=… label=… />` — as this prop's value or as
|
|
1356
1356
|
* a child — and it keeps its own metric and its own semantics.
|
|
1357
|
+
*
|
|
1358
|
+
* Rendered under `asChild` too: the slot is inserted ahead of the child element's own children,
|
|
1359
|
+
* and the child element stays the cell (gh#726).
|
|
1357
1360
|
*/
|
|
1358
1361
|
icon?: ReactNode;
|
|
1362
|
+
/**
|
|
1363
|
+
* Drop the `icon` slot FROM a breakpoint step upwards — `Flex hideFrom`'s contract, scoped to
|
|
1364
|
+
* the cell's glyph, so a cell reads label-only on a wide bar without the consumer wrapping the
|
|
1365
|
+
* glyph (gh#726). Purely decorative: the accessible name is unaffected.
|
|
1366
|
+
*/
|
|
1367
|
+
iconHideFrom?: BreakpointProp;
|
|
1368
|
+
/**
|
|
1369
|
+
* Visually hide the cell's label BELOW a breakpoint step — `Flex hideBelow`'s contract, scoped to
|
|
1370
|
+
* the label — so the cell collapses to icon-only on a narrow bar (gh#726). The label stays in the
|
|
1371
|
+
* accessibility tree (visually hidden, not `display: none`), so the collapsed cell keeps its
|
|
1372
|
+
* accessible name. Under `asChild` the child element's own children are the label.
|
|
1373
|
+
*/
|
|
1374
|
+
labelHideBelow?: BreakpointProp;
|
|
1359
1375
|
/**
|
|
1360
1376
|
* Unread count OVERLAID on the cell's glyph — the notification-bell affordance the cell's own use
|
|
1361
1377
|
* cases name (gh#398). Pass the CONTENT ONLY, exactly like `SidebarItemProp.badge`: a number, a
|
package/dist/props/registry.d.ts
CHANGED
|
@@ -1187,6 +1187,14 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
1187
1187
|
readonly field: "asChild";
|
|
1188
1188
|
readonly local: true;
|
|
1189
1189
|
readonly reason: "Radix Slot passthrough — merges onto the child";
|
|
1190
|
+
}, "BreakpointProp", {
|
|
1191
|
+
readonly field: "iconHideFrom";
|
|
1192
|
+
readonly local: true;
|
|
1193
|
+
readonly reason: "Flex `hideFrom` scoped to the cell's icon slot — label-only from a breakpoint up without hand-wrapping the glyph (gh#726).";
|
|
1194
|
+
}, {
|
|
1195
|
+
readonly field: "labelHideBelow";
|
|
1196
|
+
readonly local: true;
|
|
1197
|
+
readonly reason: "Flex `hideBelow` scoped to the cell's label — icon-only below a breakpoint; visually hidden so the accessible name survives (gh#726).";
|
|
1190
1198
|
}];
|
|
1191
1199
|
};
|
|
1192
1200
|
readonly NavListProp: {
|
package/dist/props/registry.js
CHANGED
|
@@ -1284,7 +1284,18 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
1284
1284
|
vocabulary: [
|
|
1285
1285
|
"ChildrenProp",
|
|
1286
1286
|
"ClassNameProp",
|
|
1287
|
-
{ field: "asChild", local: true, reason: "Radix Slot passthrough \u2014 merges onto the child" }
|
|
1287
|
+
{ field: "asChild", local: true, reason: "Radix Slot passthrough \u2014 merges onto the child" },
|
|
1288
|
+
"BreakpointProp",
|
|
1289
|
+
{
|
|
1290
|
+
field: "iconHideFrom",
|
|
1291
|
+
local: true,
|
|
1292
|
+
reason: "Flex `hideFrom` scoped to the cell's icon slot \u2014 label-only from a breakpoint up without hand-wrapping the glyph (gh#726)."
|
|
1293
|
+
},
|
|
1294
|
+
{
|
|
1295
|
+
field: "labelHideBelow",
|
|
1296
|
+
local: true,
|
|
1297
|
+
reason: "Flex `hideBelow` scoped to the cell's label \u2014 icon-only below a breakpoint; visually hidden so the accessible name survives (gh#726)."
|
|
1298
|
+
}
|
|
1288
1299
|
]
|
|
1289
1300
|
},
|
|
1290
1301
|
NavListProp: {
|
package/dist/styles/layout.css
CHANGED
|
@@ -1485,28 +1485,84 @@
|
|
|
1485
1485
|
}
|
|
1486
1486
|
|
|
1487
1487
|
@media (width >= 40rem) {
|
|
1488
|
-
.ui-flex[data-hide-from="sm"]
|
|
1488
|
+
.ui-flex[data-hide-from="sm"],
|
|
1489
|
+
.ui-topbar-item-icon[data-hide-from="sm"] {
|
|
1489
1490
|
display: none;
|
|
1490
1491
|
}
|
|
1491
1492
|
}
|
|
1492
1493
|
|
|
1493
1494
|
@media (width >= 48rem) {
|
|
1494
|
-
.ui-flex[data-hide-from="md"]
|
|
1495
|
+
.ui-flex[data-hide-from="md"],
|
|
1496
|
+
.ui-topbar-item-icon[data-hide-from="md"] {
|
|
1495
1497
|
display: none;
|
|
1496
1498
|
}
|
|
1497
1499
|
}
|
|
1498
1500
|
|
|
1499
1501
|
@media (width >= 64rem) {
|
|
1500
|
-
.ui-flex[data-hide-from="lg"]
|
|
1502
|
+
.ui-flex[data-hide-from="lg"],
|
|
1503
|
+
.ui-topbar-item-icon[data-hide-from="lg"] {
|
|
1501
1504
|
display: none;
|
|
1502
1505
|
}
|
|
1503
1506
|
}
|
|
1504
1507
|
|
|
1505
1508
|
@media (width >= 80rem) {
|
|
1506
|
-
.ui-flex[data-hide-from="xl"]
|
|
1509
|
+
.ui-flex[data-hide-from="xl"],
|
|
1510
|
+
.ui-topbar-item-icon[data-hide-from="xl"] {
|
|
1507
1511
|
display: none;
|
|
1508
1512
|
}
|
|
1509
1513
|
}
|
|
1514
|
+
|
|
1515
|
+
@media (width < 40rem) {
|
|
1516
|
+
.ui-topbar-item-label[data-hide-below="sm"] {
|
|
1517
|
+
position: absolute;
|
|
1518
|
+
inset-block-start: 0;
|
|
1519
|
+
inset-inline-start: 0;
|
|
1520
|
+
inline-size: var(--stroke-hairline);
|
|
1521
|
+
block-size: var(--stroke-hairline);
|
|
1522
|
+
overflow: hidden;
|
|
1523
|
+
clip-path: inset(50%);
|
|
1524
|
+
white-space: nowrap;
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
@media (width < 48rem) {
|
|
1529
|
+
.ui-topbar-item-label[data-hide-below="md"] {
|
|
1530
|
+
position: absolute;
|
|
1531
|
+
inset-block-start: 0;
|
|
1532
|
+
inset-inline-start: 0;
|
|
1533
|
+
inline-size: var(--stroke-hairline);
|
|
1534
|
+
block-size: var(--stroke-hairline);
|
|
1535
|
+
overflow: hidden;
|
|
1536
|
+
clip-path: inset(50%);
|
|
1537
|
+
white-space: nowrap;
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
@media (width < 64rem) {
|
|
1542
|
+
.ui-topbar-item-label[data-hide-below="lg"] {
|
|
1543
|
+
position: absolute;
|
|
1544
|
+
inset-block-start: 0;
|
|
1545
|
+
inset-inline-start: 0;
|
|
1546
|
+
inline-size: var(--stroke-hairline);
|
|
1547
|
+
block-size: var(--stroke-hairline);
|
|
1548
|
+
overflow: hidden;
|
|
1549
|
+
clip-path: inset(50%);
|
|
1550
|
+
white-space: nowrap;
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
@media (width < 80rem) {
|
|
1555
|
+
.ui-topbar-item-label[data-hide-below="xl"] {
|
|
1556
|
+
position: absolute;
|
|
1557
|
+
inset-block-start: 0;
|
|
1558
|
+
inset-inline-start: 0;
|
|
1559
|
+
inline-size: var(--stroke-hairline);
|
|
1560
|
+
block-size: var(--stroke-hairline);
|
|
1561
|
+
overflow: hidden;
|
|
1562
|
+
clip-path: inset(50%);
|
|
1563
|
+
white-space: nowrap;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1510
1566
|
}
|
|
1511
1567
|
|
|
1512
1568
|
@layer components {
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
PanelLeftClose,
|
|
30
30
|
PanelLeftOpen,
|
|
31
31
|
Settings,
|
|
32
|
+
Target,
|
|
32
33
|
Users,
|
|
33
34
|
} from "lucide-react";
|
|
34
35
|
|
|
@@ -178,6 +179,42 @@ export default function Demo() {
|
|
|
178
179
|
/>
|
|
179
180
|
</CardContent>
|
|
180
181
|
</Card>
|
|
182
|
+
|
|
183
|
+
<Card>
|
|
184
|
+
<CardHeader>
|
|
185
|
+
<CardTitle level={2}>リンクのセルと、幅で畳むセル</CardTitle>
|
|
186
|
+
<CardDescription>
|
|
187
|
+
`asChild` でもセルは `icon`
|
|
188
|
+
スロットを子要素の中に差し込み、リンクそのものがセルです。 `labelHideBelow`
|
|
189
|
+
はその幅未満でラベルを視覚的にだけ隠すので、アイコンだけになっても
|
|
190
|
+
ラベルがアクセシブルネームとして残ります。`iconHideFrom`
|
|
191
|
+
はその幅以上でアイコンを外します。 ビューポートを 640px
|
|
192
|
+
の前後に動かして確認してください。
|
|
193
|
+
</CardDescription>
|
|
194
|
+
</CardHeader>
|
|
195
|
+
<CardContent>
|
|
196
|
+
<Topbar
|
|
197
|
+
start={
|
|
198
|
+
<>
|
|
199
|
+
<TopbarItem asChild icon={<Target aria-hidden="true" />}>
|
|
200
|
+
<a href="#topbar-item-goals">目標</a>
|
|
201
|
+
</TopbarItem>
|
|
202
|
+
<TopbarItem
|
|
203
|
+
asChild
|
|
204
|
+
icon={<Target aria-hidden="true" />}
|
|
205
|
+
labelHideBelow="sm"
|
|
206
|
+
iconHideFrom="sm"
|
|
207
|
+
>
|
|
208
|
+
<a href="#topbar-item-goals-responsive">今期の目標</a>
|
|
209
|
+
</TopbarItem>
|
|
210
|
+
<TopbarItem icon={<Building2 aria-hidden="true" />} labelHideBelow="md">
|
|
211
|
+
東京本社
|
|
212
|
+
</TopbarItem>
|
|
213
|
+
</>
|
|
214
|
+
}
|
|
215
|
+
/>
|
|
216
|
+
</CardContent>
|
|
217
|
+
</Card>
|
|
181
218
|
</Flex>
|
|
182
219
|
</PageContainer>
|
|
183
220
|
</AppShell>
|