@godxjp/ui 27.3.1 → 27.5.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/data-entry/upload-file-kind.d.ts +25 -0
- package/dist/components/data-entry/upload-file-kind.js +88 -0
- package/dist/components/data-entry/upload.d.ts +2 -2
- package/dist/components/data-entry/upload.js +10 -6
- package/dist/components/general/icon.d.ts +31 -0
- package/dist/components/general/icon.js +23 -0
- package/dist/components/general/index.d.ts +2 -0
- package/dist/components/general/index.js +2 -0
- package/dist/components/layout/flex.d.ts +2 -2
- package/dist/components/layout/flex.js +7 -1
- package/dist/components/layout/topbar-item.d.ts +1 -0
- package/dist/components/layout/topbar-item.js +3 -1
- package/dist/components/ui/avatar.d.ts +1 -1
- package/dist/components/ui/avatar.js +2 -0
- package/dist/components/ui/segmented.d.ts +7 -2
- package/dist/components/ui/toggle.d.ts +2 -2
- package/dist/components/ui/toggle.js +4 -0
- package/dist/contracts/measurement.json +1 -1
- package/dist/props/components/data-display.prop.d.ts +14 -0
- package/dist/props/components/data-entry.prop.d.ts +25 -0
- package/dist/props/components/general.prop.d.ts +42 -1
- package/dist/props/components/layout.prop.d.ts +42 -0
- package/dist/props/registry.d.ts +37 -1
- package/dist/props/registry.js +43 -1
- package/dist/props/vocabulary/index.d.ts +1 -1
- package/dist/props/vocabulary/interaction.prop.d.ts +11 -0
- package/dist/styles/control.css +12 -0
- package/dist/styles/core.css +2 -0
- package/dist/styles/data-display-layout.css +35 -5
- package/dist/styles/data-entry-layout.css +22 -0
- package/dist/styles/icon-layout.css +37 -0
- package/dist/styles/index.css +2 -0
- package/dist/styles/shell-layout.css +10 -0
- package/dist/styles/text-layout.css +16 -8
- package/dist/tokens/components/control.css +1 -0
- package/dist/tokens/components/data-display.css +26 -0
- package/dist/tokens/components/segmented.css +4 -0
- package/dist/tokens/components/upload.css +4 -0
- package/docs/CONSUMER-RULES.md +2 -2
- package/docs/CUSTOMER-THEMING.md +26 -0
- package/docs/FRAME-COVERAGE-REPORT.md +3 -2
- package/docs/data-display/avatar.tsx +128 -11
- package/docs/data-display/prose.tsx +64 -0
- package/docs/data-entry/segmented.tsx +55 -5
- package/docs/data-entry/toggle-group.tsx +15 -3
- package/docs/data-entry/toggle.tsx +39 -1
- package/docs/data-entry/upload.tsx +38 -0
- package/docs/general/icon.tsx +215 -0
- package/docs/layout/flex.tsx +59 -0
- package/docs/layout/topbar-item.tsx +29 -1
- package/package.json +2 -2
- package/scripts/consumer-rule.md +18 -17
- package/scripts/ui-audit.mjs +128 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a listed file IS, at the coarseness a row can actually draw (gh#720).
|
|
3
|
+
*
|
|
4
|
+
* A picture list shows a thumbnail for an image and a glyph for everything else, so the buckets
|
|
5
|
+
* are exactly the marks we have: five, not one per MIME type. The kind is also written onto the
|
|
6
|
+
* row as `data-file-kind`, so a service can retint a bucket without forking the component.
|
|
7
|
+
*/
|
|
8
|
+
export type UploadFileKind = "image" | "pdf" | "archive" | "text" | "file";
|
|
9
|
+
/** The kind of one listed file, from its MIME type when it has one and its extension otherwise. */
|
|
10
|
+
export declare function uploadFileKind(item: {
|
|
11
|
+
name?: string;
|
|
12
|
+
mimeType?: string;
|
|
13
|
+
}): UploadFileKind;
|
|
14
|
+
/**
|
|
15
|
+
* The mark per kind. PDF takes the prose-lines document (`FileText`) because lucide ships no PDF
|
|
16
|
+
* glyph, which is also why plain/structured text takes the `</>` mark rather than the same one: a
|
|
17
|
+
* `.pdf` and a `.json` on adjacent rows must not draw identically.
|
|
18
|
+
*/
|
|
19
|
+
export declare const UPLOAD_FILE_KIND_GLYPHS: {
|
|
20
|
+
readonly image: import("react").ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
|
|
21
|
+
readonly pdf: import("react").ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
|
|
22
|
+
readonly archive: import("react").ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
|
|
23
|
+
readonly text: import("react").ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
|
|
24
|
+
readonly file: import("react").ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
|
|
25
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { File as FileGlyph, FileArchive, FileCode, FileImage, FileText } from "lucide-react";
|
|
2
|
+
const MIME_KINDS = {
|
|
3
|
+
"application/pdf": "pdf",
|
|
4
|
+
"application/x-pdf": "pdf",
|
|
5
|
+
"application/zip": "archive",
|
|
6
|
+
"application/x-zip-compressed": "archive",
|
|
7
|
+
"application/x-7z-compressed": "archive",
|
|
8
|
+
"application/vnd.rar": "archive",
|
|
9
|
+
"application/x-rar-compressed": "archive",
|
|
10
|
+
"application/gzip": "archive",
|
|
11
|
+
"application/x-tar": "archive",
|
|
12
|
+
"application/x-bzip": "archive",
|
|
13
|
+
"application/x-bzip2": "archive",
|
|
14
|
+
"application/json": "text",
|
|
15
|
+
"application/ld+json": "text",
|
|
16
|
+
"application/xml": "text",
|
|
17
|
+
"application/yaml": "text",
|
|
18
|
+
"application/x-yaml": "text"
|
|
19
|
+
};
|
|
20
|
+
const EXTENSION_KINDS = {
|
|
21
|
+
png: "image",
|
|
22
|
+
jpg: "image",
|
|
23
|
+
jpeg: "image",
|
|
24
|
+
gif: "image",
|
|
25
|
+
webp: "image",
|
|
26
|
+
avif: "image",
|
|
27
|
+
svg: "image",
|
|
28
|
+
bmp: "image",
|
|
29
|
+
ico: "image",
|
|
30
|
+
heic: "image",
|
|
31
|
+
heif: "image",
|
|
32
|
+
tif: "image",
|
|
33
|
+
tiff: "image",
|
|
34
|
+
pdf: "pdf",
|
|
35
|
+
zip: "archive",
|
|
36
|
+
tar: "archive",
|
|
37
|
+
gz: "archive",
|
|
38
|
+
tgz: "archive",
|
|
39
|
+
rar: "archive",
|
|
40
|
+
"7z": "archive",
|
|
41
|
+
bz2: "archive",
|
|
42
|
+
xz: "archive",
|
|
43
|
+
zst: "archive",
|
|
44
|
+
txt: "text",
|
|
45
|
+
md: "text",
|
|
46
|
+
markdown: "text",
|
|
47
|
+
json: "text",
|
|
48
|
+
jsonl: "text",
|
|
49
|
+
csv: "text",
|
|
50
|
+
tsv: "text",
|
|
51
|
+
log: "text",
|
|
52
|
+
xml: "text",
|
|
53
|
+
yml: "text",
|
|
54
|
+
yaml: "text",
|
|
55
|
+
html: "text",
|
|
56
|
+
htm: "text",
|
|
57
|
+
css: "text",
|
|
58
|
+
js: "text",
|
|
59
|
+
ts: "text"
|
|
60
|
+
};
|
|
61
|
+
function uploadFileKind(item) {
|
|
62
|
+
const mime = item.mimeType?.trim().toLowerCase();
|
|
63
|
+
if (mime) {
|
|
64
|
+
if (mime.startsWith("image/")) return "image";
|
|
65
|
+
if (mime.startsWith("text/")) return "text";
|
|
66
|
+
const known = MIME_KINDS[mime];
|
|
67
|
+
if (known) return known;
|
|
68
|
+
}
|
|
69
|
+
const name = item.name ?? "";
|
|
70
|
+
const dot = name.lastIndexOf(".");
|
|
71
|
+
if (dot > 0) {
|
|
72
|
+
const extension = name.slice(dot + 1).toLowerCase();
|
|
73
|
+
const known = EXTENSION_KINDS[extension];
|
|
74
|
+
if (known) return known;
|
|
75
|
+
}
|
|
76
|
+
return "file";
|
|
77
|
+
}
|
|
78
|
+
const UPLOAD_FILE_KIND_GLYPHS = {
|
|
79
|
+
image: FileImage,
|
|
80
|
+
pdf: FileText,
|
|
81
|
+
archive: FileArchive,
|
|
82
|
+
text: FileCode,
|
|
83
|
+
file: FileGlyph
|
|
84
|
+
};
|
|
85
|
+
export {
|
|
86
|
+
UPLOAD_FILE_KIND_GLYPHS,
|
|
87
|
+
uploadFileKind
|
|
88
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import type { UploadProp } from "../../props/components/data-entry.prop.js";
|
|
3
|
-
export type { UploadProp, UploadProp as UploadProps, UploadFileItemProp, UploadVariantProp, } from "../../props/components/data-entry.prop.js";
|
|
3
|
+
export type { UploadProp, UploadProp as UploadProps, UploadFileItemProp, UploadVariantProp, UploadListTypeProp, } from "../../props/components/data-entry.prop.js";
|
|
4
4
|
export type { UploadFileItem, UploadVariant, UploadCommitAction } from "./upload-types.js";
|
|
5
5
|
export { collectUploadCommitActions, createUploadItem, UPLOAD_LIST_IGNORE } from "./upload-types.js";
|
|
6
6
|
export { useUploadDraft } from "./use-upload-draft.js";
|
|
7
|
-
export declare function Upload({ variant, triggerSize, triggerVariant, value, defaultValue, onValueChange, accept: acceptProp, multiple: multipleProp, maxCount: maxCountProp, maxSizeBytes, disabled: disabledProp, readOnly, directory, pastable, openFileDialogOnClick, name, action, method, headers, data, withCredentials, beforeUpload, onReject, onRemove, onPreview, onDownload, previewFile, onDrop, showUploadList, itemRender, removable, onUpload, id, className, children, ...ariaProps }: UploadProp): React.JSX.Element;
|
|
7
|
+
export declare function Upload({ variant, listType, triggerSize, triggerVariant, value, defaultValue, onValueChange, accept: acceptProp, multiple: multipleProp, maxCount: maxCountProp, maxSizeBytes, disabled: disabledProp, readOnly, directory, pastable, openFileDialogOnClick, name, action, method, headers, data, withCredentials, beforeUpload, onReject, onRemove, onPreview, onDownload, previewFile, onDrop, showUploadList, itemRender, removable, onUpload, id, className, children, ...ariaProps }: UploadProp): React.JSX.Element;
|
|
@@ -15,9 +15,10 @@ import { useTranslation } from "../../i18n/use-translation.js";
|
|
|
15
15
|
import { formatBytes } from "../../lib/format.js";
|
|
16
16
|
import { cn } from "../../lib/utils.js";
|
|
17
17
|
import { resolveFieldA11y } from "../../lib/field-a11y.js";
|
|
18
|
-
import { controlIconClass } from "../../lib/control-styles.js";
|
|
19
18
|
import { Button } from "../general/button.js";
|
|
19
|
+
import { Icon } from "../general/icon.js";
|
|
20
20
|
import { UploadCropDialog } from "./upload-crop-dialog.js";
|
|
21
|
+
import { UPLOAD_FILE_KIND_GLYPHS, uploadFileKind } from "./upload-file-kind.js";
|
|
21
22
|
import {
|
|
22
23
|
UPLOAD_LIST_IGNORE,
|
|
23
24
|
createUploadItem,
|
|
@@ -66,6 +67,7 @@ function useUploadList(controlled, defaultValue, onValueChange) {
|
|
|
66
67
|
}
|
|
67
68
|
function Upload({
|
|
68
69
|
variant = "dropzone",
|
|
70
|
+
listType,
|
|
69
71
|
triggerSize,
|
|
70
72
|
triggerVariant = "outline",
|
|
71
73
|
value,
|
|
@@ -109,6 +111,7 @@ function Upload({
|
|
|
109
111
|
triggerOwnsAriaLabel ? { ...ariaProps, "aria-label": void 0 } : ariaProps,
|
|
110
112
|
t("dataEntry.upload.inputLabel")
|
|
111
113
|
);
|
|
114
|
+
const resolvedListType = listType ?? (variant === "picture" ? "picture" : "text");
|
|
112
115
|
const accept = acceptProp ?? defaultAcceptForVariant(variant);
|
|
113
116
|
const maxCount = maxCountProp ?? defaultMaxCount(variant);
|
|
114
117
|
const multiple = multipleProp ?? (maxCount === 1 ? false : true);
|
|
@@ -380,7 +383,7 @@ function Upload({
|
|
|
380
383
|
hasCustomPreview: Boolean(onPreview),
|
|
381
384
|
onDownload,
|
|
382
385
|
itemRender,
|
|
383
|
-
|
|
386
|
+
listType: resolvedListType
|
|
384
387
|
}
|
|
385
388
|
) : null;
|
|
386
389
|
const hiddenInput = /* @__PURE__ */ jsx(
|
|
@@ -571,7 +574,7 @@ function Upload({
|
|
|
571
574
|
onClick: openPicker,
|
|
572
575
|
className: "ui-upload-picture-empty",
|
|
573
576
|
children: [
|
|
574
|
-
/* @__PURE__ */ jsx(ImagePlus, { className:
|
|
577
|
+
/* @__PURE__ */ jsx(ImagePlus, { className: "ui-upload-picture-empty-icon", "aria-hidden": "true" }),
|
|
575
578
|
/* @__PURE__ */ jsx("span", { className: "ui-upload-picture-empty-label", children: t("dataEntry.upload.addImage") })
|
|
576
579
|
]
|
|
577
580
|
}
|
|
@@ -621,7 +624,7 @@ function Upload({
|
|
|
621
624
|
className: "ui-upload-avatar ui-focus-ring",
|
|
622
625
|
"aria-label": t("dataEntry.upload.avatarLabel"),
|
|
623
626
|
children: [
|
|
624
|
-
!showPlaceholder && item?.previewUrl ? /* @__PURE__ */ jsx("img", { src: item.previewUrl, alt: "", className: "ui-upload-avatar-image" }) : /* @__PURE__ */ jsx("span", { className: "ui-upload-avatar-placeholder", children: /* @__PURE__ */ jsx(Camera, { className:
|
|
627
|
+
!showPlaceholder && item?.previewUrl ? /* @__PURE__ */ jsx("img", { src: item.previewUrl, alt: "", className: "ui-upload-avatar-image" }) : /* @__PURE__ */ jsx("span", { className: "ui-upload-avatar-placeholder", children: /* @__PURE__ */ jsx(Camera, { className: "ui-upload-avatar-icon", "aria-hidden": "true" }) }),
|
|
625
628
|
!disabled && /* @__PURE__ */ jsx("span", { className: "ui-upload-avatar-change", children: t("dataEntry.upload.change") })
|
|
626
629
|
]
|
|
627
630
|
}
|
|
@@ -750,12 +753,13 @@ function UploadFileList({
|
|
|
750
753
|
hasCustomPreview,
|
|
751
754
|
onDownload,
|
|
752
755
|
itemRender,
|
|
753
|
-
|
|
756
|
+
listType
|
|
754
757
|
}) {
|
|
755
758
|
const { t } = useTranslation();
|
|
756
759
|
return /* @__PURE__ */ jsx("ul", { className: "ui-stack-xs", children: items.map((item) => {
|
|
760
|
+
const kind = uploadFileKind(item);
|
|
757
761
|
const node = /* @__PURE__ */ jsxs("div", { className: "ui-upload-row", children: [
|
|
758
|
-
|
|
762
|
+
listType === "picture" && (item.previewUrl ? /* @__PURE__ */ jsx("img", { src: item.previewUrl, alt: "", className: "ui-upload-list-thumb" }) : /* @__PURE__ */ jsx("span", { className: "ui-upload-list-glyph", "data-file-kind": kind, children: /* @__PURE__ */ jsx(Icon, { as: UPLOAD_FILE_KIND_GLYPHS[kind], size: "lg" }) })),
|
|
759
763
|
/* @__PURE__ */ jsxs("div", { className: "ui-upload-row-main", children: [
|
|
760
764
|
/* @__PURE__ */ jsx("div", { className: "truncate font-medium", children: item.name }),
|
|
761
765
|
/* @__PURE__ */ jsxs("div", { className: "text-muted-foreground text-xs", children: [
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type { IconGlyphProp, IconGlyphProp as IconProps, } from "../../props/components/general.prop.js";
|
|
3
|
+
/**
|
|
4
|
+
* Icon — a glyph on the `--icon-size-*` scale, and the only supported way to draw a standalone one.
|
|
5
|
+
*
|
|
6
|
+
* WHY THIS EXISTS (gh#712). A lucide component ships `width="24" height="24"`, and exactly four
|
|
7
|
+
* rules in this library ever override that: `.ui-button svg`, `.ui-dropdown-menu-item > svg`,
|
|
8
|
+
* `.ui-topbar-item > svg` and `[data-slot="list-row-leading"] > svg`. Anywhere else — in a `Text`,
|
|
9
|
+
* in a table cell, in an `<a>` — the glyph draws at 24px beside 14px type, 1.71× the text it
|
|
10
|
+
* annotates. A consumer cannot fix that themselves: `size-4` and `w-[16px]` are what
|
|
11
|
+
* docs/CONSUMER-RULES.md §3/§8 forbid, and `size={16}` hard-codes a number the theme owns. One
|
|
12
|
+
* consumer measured 38 such glyphs in a single app.
|
|
13
|
+
*
|
|
14
|
+
* RENDERS ONTO THE GLYPH, NOT AROUND IT. `as={Lock}` is invoked with the class, the size and the
|
|
15
|
+
* a11y wiring, so the element that carries the metric IS the `<svg>`. A wrapper `<span>` would add
|
|
16
|
+
* a box to every flex row that holds an icon, and would break `Button`'s own `svg` rule by putting
|
|
17
|
+
* an element between the two.
|
|
18
|
+
*
|
|
19
|
+
* DECORATIVE BY DEFAULT. Without `label` the glyph is `aria-hidden` — a glyph beside a visible
|
|
20
|
+
* label is decoration, and announcing it twice is the usual defect (WCAG 2.2 SC 1.1.1). Pass
|
|
21
|
+
* `label` only when the glyph is the ONLY thing saying what it says; it then renders as
|
|
22
|
+
* `role="img"` + that name, which is how a graphic gets a name in WAI-ARIA 1.2. The string is the
|
|
23
|
+
* consumer's to localize — the library ships no copy for it.
|
|
24
|
+
*/
|
|
25
|
+
export declare const Icon: React.ForwardRefExoticComponent<Omit<React.SVGProps<SVGSVGElement>, "children" | "ref"> & {
|
|
26
|
+
as: React.ComponentType<React.SVGProps<SVGSVGElement> & React.RefAttributes<SVGSVGElement>>;
|
|
27
|
+
size?: import("../../props/index.js").IconSizeProp;
|
|
28
|
+
tone?: import("../../props/index.js").TextToneProp;
|
|
29
|
+
label?: string;
|
|
30
|
+
className?: import("../../props/index.js").ClassNameProp;
|
|
31
|
+
} & React.RefAttributes<SVGSVGElement>>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
|
+
const Icon = React.forwardRef(function Icon2({ as: Glyph, size = "md", tone, label, className, ...props }, ref) {
|
|
5
|
+
const named = label !== void 0 && label !== "";
|
|
6
|
+
return /* @__PURE__ */ jsx(
|
|
7
|
+
Glyph,
|
|
8
|
+
{
|
|
9
|
+
ref,
|
|
10
|
+
"data-slot": "icon",
|
|
11
|
+
"data-size": size,
|
|
12
|
+
"data-tone": tone,
|
|
13
|
+
className: cn("ui-icon", className),
|
|
14
|
+
role: named ? "img" : void 0,
|
|
15
|
+
"aria-label": named ? label : void 0,
|
|
16
|
+
"aria-hidden": named ? void 0 : true,
|
|
17
|
+
...props
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
export {
|
|
22
|
+
Icon
|
|
23
|
+
};
|
|
@@ -2,6 +2,8 @@ export { Button, buttonVariants } from "./button.js";
|
|
|
2
2
|
export type { ButtonProps } from "./button.js";
|
|
3
3
|
export { Text, Heading, Typography, Title, Paragraph, Link } from "./typography.js";
|
|
4
4
|
export type { TextProps, HeadingProps, TextProp, HeadingProp, TypographyProp, TypographyProps, TypographyBlockProp, TypographyTitleProp, TitleProps, ParagraphProp, ParagraphProps, LinkProp, LinkProps, } from "./typography.js";
|
|
5
|
+
export { Icon } from "./icon.js";
|
|
6
|
+
export type { IconGlyphProp, IconProps } from "./icon.js";
|
|
5
7
|
export { Logo } from "./logo.js";
|
|
6
8
|
export type { LogoMark, LogoProps, LogoSize, LogoTone } from "./logo.js";
|
|
7
9
|
export { Reveal } from "./reveal.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Button, buttonVariants } from "./button.js";
|
|
2
2
|
import { Text, Heading, Typography, Title, Paragraph, Link } from "./typography.js";
|
|
3
|
+
import { Icon } from "./icon.js";
|
|
3
4
|
import { Logo } from "./logo.js";
|
|
4
5
|
import { Reveal } from "./reveal.js";
|
|
5
6
|
import { FloatButton } from "./float-button.js";
|
|
@@ -15,6 +16,7 @@ export {
|
|
|
15
16
|
Button,
|
|
16
17
|
FloatButton,
|
|
17
18
|
Heading,
|
|
19
|
+
Icon,
|
|
18
20
|
Link,
|
|
19
21
|
Logo,
|
|
20
22
|
Paragraph,
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { FlexProp } from "../../props/components/layout.prop.js";
|
|
2
|
-
export type { FlexAlignProp, FlexDirectionProp, FlexJustifyProp, FlexProp, FlexProp as FlexProps, } from "../../props/components/layout.prop.js";
|
|
3
|
-
export declare function Flex({ as: Element, direction, grow, shrink, surface, bleed, reveal, gap, gapRaw, pad, padRaw, align, justify, wrap, hideBelow, hideFrom, hideBelowRaw, hideFromRaw, fill, width, className, style, children, ...props }: FlexProp): import("react").JSX.Element;
|
|
2
|
+
export type { FlexAlignProp, FlexDirectionProp, FlexJustifyProp, FlexMarkerProp, FlexProp, FlexProp as FlexProps, } from "../../props/components/layout.prop.js";
|
|
3
|
+
export declare function Flex({ as: Element, direction, marker, grow, shrink, surface, bleed, reveal, gap, gapRaw, pad, padRaw, align, justify, wrap, hideBelow, hideFrom, hideBelowRaw, hideFromRaw, fill, width, className, style, children, ...props }: FlexProp): import("react").JSX.Element;
|
|
@@ -6,9 +6,15 @@ import { flexGapClass, padStyle, padStepToken } from "../../lib/variants.js";
|
|
|
6
6
|
const toCssLength = (value) => typeof value === "number" ? `${value}px` : value;
|
|
7
7
|
const rawBreakpoint = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
8
8
|
const rawBreakpointRule = (axis, px) => `@media (width ${axis === "below" ? "<" : ">="} ${px}px){.ui-flex[data-hide-${axis}-raw="${px}"]{display:none}}`;
|
|
9
|
+
const listMarker = (element, marker) => {
|
|
10
|
+
if (element !== "ul" && element !== "ol") return void 0;
|
|
11
|
+
const resolved = marker ?? (element === "ul" ? "disc" : "decimal");
|
|
12
|
+
return resolved === "none" ? void 0 : resolved;
|
|
13
|
+
};
|
|
9
14
|
function Flex({
|
|
10
15
|
as: Element = "div",
|
|
11
16
|
direction = "row",
|
|
17
|
+
marker,
|
|
12
18
|
grow,
|
|
13
19
|
shrink,
|
|
14
20
|
surface,
|
|
@@ -65,7 +71,7 @@ function Flex({
|
|
|
65
71
|
"data-shrink": shrink === false ? "false" : void 0,
|
|
66
72
|
"data-surface": surface,
|
|
67
73
|
"data-reveal": reveal,
|
|
68
|
-
"data-list": Element
|
|
74
|
+
"data-list": listMarker(Element, marker),
|
|
69
75
|
"data-align": align,
|
|
70
76
|
"data-justify": justify,
|
|
71
77
|
"data-wrap": wrap ? "true" : void 0,
|
|
@@ -12,6 +12,7 @@ export type { TopbarItemProp, TopbarItemProp as TopbarItemProps, } from "../../p
|
|
|
12
12
|
*/
|
|
13
13
|
export declare const TopbarItem: React.ForwardRefExoticComponent<Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "children"> & {
|
|
14
14
|
hideBelow?: import("../../props/index.js").BreakpointProp;
|
|
15
|
+
icon?: React.ReactNode;
|
|
15
16
|
badge?: React.ReactNode;
|
|
16
17
|
badgeTone?: import("../../props/components/layout.prop.js").SidebarBadgeToneProp;
|
|
17
18
|
asChild?: boolean;
|
|
@@ -2,9 +2,10 @@ 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({ asChild = false, className, type, hideBelow, badge, badgeTone, children, ...props }, ref) {
|
|
5
|
+
const TopbarItem = React.forwardRef(function TopbarItem2({ asChild = false, className, type, hideBelow, icon, badge, badgeTone, children, ...props }, ref) {
|
|
6
6
|
const Comp = asChild ? Slot : "button";
|
|
7
7
|
const showBadge = !asChild && badge !== void 0 && badge !== "";
|
|
8
|
+
const iconNode = !asChild && icon !== void 0 && icon !== null && icon !== false ? /* @__PURE__ */ jsx("span", { "data-slot": "topbar-item-icon", className: "ui-topbar-item-icon", children: icon }) : null;
|
|
8
9
|
const badgeNode = showBadge ? /* @__PURE__ */ jsx(
|
|
9
10
|
"span",
|
|
10
11
|
{
|
|
@@ -24,6 +25,7 @@ const TopbarItem = React.forwardRef(function TopbarItem2({ asChild = false, clas
|
|
|
24
25
|
type: asChild ? void 0 : type ?? "button",
|
|
25
26
|
...props,
|
|
26
27
|
children: asChild ? children : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
28
|
+
iconNode,
|
|
27
29
|
children,
|
|
28
30
|
badgeNode
|
|
29
31
|
] })
|
|
@@ -19,7 +19,7 @@ import type { AvatarProp } from "../../props/components/data-display.prop.js";
|
|
|
19
19
|
type ImageLoadingStatus = "idle" | "loading" | "loaded" | "error";
|
|
20
20
|
export declare const Avatar: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & {
|
|
21
21
|
asChild?: boolean;
|
|
22
|
-
} & Pick<AvatarProp, "appearance" | "presence" | "presenceLabel" | "shape"> & React.RefAttributes<HTMLSpanElement>>;
|
|
22
|
+
} & Pick<AvatarProp, "appearance" | "presence" | "presenceLabel" | "shape" | "size"> & React.RefAttributes<HTMLSpanElement>>;
|
|
23
23
|
export declare const AvatarImage: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, "ref"> & {
|
|
24
24
|
asChild?: boolean;
|
|
25
25
|
onLoadingStatusChange?: (status: ImageLoadingStatus) => void;
|
|
@@ -53,6 +53,7 @@ const Avatar = React.forwardRef(
|
|
|
53
53
|
({
|
|
54
54
|
className,
|
|
55
55
|
shape = "circle",
|
|
56
|
+
size = "md",
|
|
56
57
|
appearance = "default",
|
|
57
58
|
presence,
|
|
58
59
|
presenceLabel,
|
|
@@ -73,6 +74,7 @@ const Avatar = React.forwardRef(
|
|
|
73
74
|
ref,
|
|
74
75
|
"data-slot": "avatar",
|
|
75
76
|
"data-shape": shape === "square" ? "square" : void 0,
|
|
77
|
+
"data-size": size === "md" ? void 0 : size,
|
|
76
78
|
"data-appearance": appearance === "tinted" ? "tinted" : void 0,
|
|
77
79
|
"data-presence": presence,
|
|
78
80
|
className: cn("ui-avatar", className),
|
|
@@ -42,8 +42,13 @@ export type SegmentedProp = {
|
|
|
42
42
|
block?: boolean;
|
|
43
43
|
/** antd `vertical` — stack the choices in a column. Arrow keys follow the axis. */
|
|
44
44
|
vertical?: boolean;
|
|
45
|
-
/**
|
|
46
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Control height tier: `md` (default), `xs`, `sm` or `lg` — the same `--control-height-*` tier
|
|
47
|
+
* every other control reads. `xs` is the fourth step (gh#719, the one Toggle/ToggleGroup took in
|
|
48
|
+
* gh#716): a 24px-dense row can carry a real segmented control instead of a hand-rolled row of
|
|
49
|
+
* Buttons.
|
|
50
|
+
*/
|
|
51
|
+
size?: "xs" | "sm" | "md" | "lg";
|
|
47
52
|
/** Disable the whole group. */
|
|
48
53
|
disabled?: boolean;
|
|
49
54
|
/** Form field name — submits the selected value with the form. */
|
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
3
|
declare const toggleVariants: (props?: ({
|
|
4
4
|
variant?: "default" | "outline" | null | undefined;
|
|
5
|
-
size?: "lg" | "md" | "sm" | null | undefined;
|
|
5
|
+
size?: "lg" | "md" | "sm" | "xs" | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
7
|
/**
|
|
8
8
|
* Not exported on its own — it is folded into `ToggleProp` and `ToggleGroupItemProp` so there is
|
|
@@ -69,7 +69,7 @@ export type ToggleProp = React.ComponentPropsWithoutRef<"button"> & TogglePresse
|
|
|
69
69
|
export type ToggleProps = ToggleProp;
|
|
70
70
|
export declare const Toggle: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & TogglePressedFields & VariantProps<(props?: ({
|
|
71
71
|
variant?: "default" | "outline" | null | undefined;
|
|
72
|
-
size?: "lg" | "md" | "sm" | null | undefined;
|
|
72
|
+
size?: "lg" | "md" | "sm" | "xs" | null | undefined;
|
|
73
73
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string> & ToggleCountFields & React.RefAttributes<HTMLButtonElement>>;
|
|
74
74
|
export { toggleVariants, useCounterPill, restoreDomProps };
|
|
75
75
|
export type { ToggleCountFields, TogglePressedFields };
|
|
@@ -13,6 +13,10 @@ const toggleVariants = cva("ui-toggle", {
|
|
|
13
13
|
outline: "ui-toggle-outline"
|
|
14
14
|
},
|
|
15
15
|
size: {
|
|
16
|
+
// The fourth step of the shared control ladder (gh#716): 24px, `--control-height-xs`, the
|
|
17
|
+
// same tier `Button size="xs"` reads — so a 24px-dense row can carry a segmented control
|
|
18
|
+
// instead of someone hand-rolling one out of Buttons.
|
|
19
|
+
xs: "ui-toggle-xs",
|
|
16
20
|
sm: "ui-toggle-sm",
|
|
17
21
|
md: "ui-toggle-default-size",
|
|
18
22
|
lg: "ui-toggle-lg"
|
|
@@ -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.5.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,
|
|
@@ -208,6 +208,20 @@ export type DescriptionsItemProp = {
|
|
|
208
208
|
*/
|
|
209
209
|
export type AvatarProp = React.ComponentPropsWithoutRef<"span"> & {
|
|
210
210
|
shape?: AvatarShapeProp;
|
|
211
|
+
/**
|
|
212
|
+
* Box size on the shared control ladder — `md` (default) is `--control-height`, and `xs`/`sm`/
|
|
213
|
+
* `lg` are `--control-height-xs/-sm/-lg`, the SAME tier Button and Input read. State it when the
|
|
214
|
+
* mark has to sit in a row the row's height already decided: inside an `icon-sm` trigger, in a
|
|
215
|
+
* 24px dense table row, beside a `size="sm"` Button. Before gh#716 the box was welded to
|
|
216
|
+
* `--control-height`, so a 32px mark inside a 28px trigger overflowed it and the only legal move
|
|
217
|
+
* left was raising the whole row.
|
|
218
|
+
*
|
|
219
|
+
* The initials' type step and a glyph's box move with the box — one step of the type scale and
|
|
220
|
+
* one step of the `--icon-size-*` scale per step — so a small mark is small, not clipped.
|
|
221
|
+
* `shape="square"` rides the identical ladder. Beyond the ladder (a 96px profile mark) is a
|
|
222
|
+
* `className` size utility, exactly as before; the ladder is for the control row.
|
|
223
|
+
*/
|
|
224
|
+
size?: SizeProp;
|
|
211
225
|
appearance?: AvatarAppearanceProp;
|
|
212
226
|
/**
|
|
213
227
|
* Presence — WHO is reachable right now, drawn as an indicator at the block-end/inline-end
|
|
@@ -1464,9 +1464,34 @@ export type SelectDataProp = SearchSelectBaseProp & {
|
|
|
1464
1464
|
export type UploadFileItemProp = UploadFileItem;
|
|
1465
1465
|
/** @see Upload */
|
|
1466
1466
|
export type UploadVariantProp = "dropzone" | "button" | "picture-card" | "picture" | "avatar" | "avatar-crop";
|
|
1467
|
+
/**
|
|
1468
|
+
* Upload `listType` — HOW THE CHOSEN FILES ARE LISTED, ported from antd (gh#720).
|
|
1469
|
+
*
|
|
1470
|
+
* antd separates two axes and this component had only one: `variant` says how a file is PICKED
|
|
1471
|
+
* (drag area, button, tile grid, avatar), `listType` says how the picked ones are DRAWN. Welding
|
|
1472
|
+
* the second onto the first meant a `variant="dropzone"` could not show a thumbnail even for an
|
|
1473
|
+
* item that already carried a `previewUrl`, and its rows carried no per-type mark at all — a
|
|
1474
|
+
* drawer listing a `.png` beside a `.json` and a `.txt` could draw only three identical
|
|
1475
|
+
* name-and-size rows.
|
|
1476
|
+
*
|
|
1477
|
+
* - `text` — name, size, actions. The row every dropzone/button list has always drawn.
|
|
1478
|
+
* - `picture` — a leading box on every row: the thumbnail when the item has a `previewUrl`, and
|
|
1479
|
+
* otherwise the glyph for its file kind (image / pdf / archive / text / generic). Both boxes are
|
|
1480
|
+
* the same size, so a mixed list keeps one row height.
|
|
1481
|
+
*
|
|
1482
|
+
* antd's third value, `picture-card`, is `variant="picture-card"` here: in that variant the tile
|
|
1483
|
+
* grid IS the picker (the add tile sits inside the grid), so it is not a listing that can be put
|
|
1484
|
+
* under a different trigger. It is deliberately not offered as a `listType`.
|
|
1485
|
+
*/
|
|
1486
|
+
export type UploadListTypeProp = "text" | "picture";
|
|
1467
1487
|
/** @see Upload — presentational; wire `onUpload` to media-service in app api.ts */
|
|
1468
1488
|
export type UploadProp = FieldA11yProps & {
|
|
1469
1489
|
variant?: UploadVariantProp;
|
|
1490
|
+
/**
|
|
1491
|
+
* @see UploadListTypeProp — an axis of its own, independent of `variant`. Defaults to the
|
|
1492
|
+
* listing each variant already drew: `picture` for `variant="picture"`, `text` everywhere else.
|
|
1493
|
+
*/
|
|
1494
|
+
listType?: UploadListTypeProp;
|
|
1470
1495
|
value?: ValueProp<UploadFileItemProp[]>;
|
|
1471
1496
|
defaultValue?: DefaultValueProp<UploadFileItemProp[]>;
|
|
1472
1497
|
onValueChange?: OnValueChangeProp<UploadFileItemProp[]>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Foundation component prop types — @see docs/COMPONENTS.md#foundation */
|
|
2
2
|
import type * as React from "react";
|
|
3
|
-
import type { ActivityAnnounceProp, ActivityVariantProp, AsChildProp, ButtonSizeProp, ButtonVariantProp, ChildrenProp, ClassNameProp, DescriptionProp, DisabledProp, FontWeightProp, HeadingLevelProp, IdProp, LabelProp, OnClickProp, OnOpenChangeProp, OpenProp, PendingProp, RevealDelayProp, ShapeProp, SizeProp, TextAlignProp, TextSizeProp, TextToneProp, TextWhitespaceProp, TitleLevelProp, TypographyActionsConfigProp, TypographyCopyConfigProp, TypographyEditConfigProp, TypographyEllipsisConfigProp, TypographyTypeProp } from "../vocabulary/index.js";
|
|
3
|
+
import type { ActivityAnnounceProp, ActivityVariantProp, AsChildProp, ButtonSizeProp, ButtonVariantProp, ChildrenProp, ClassNameProp, DescriptionProp, DisabledProp, FontWeightProp, HeadingLevelProp, IconSizeProp, IdProp, LabelProp, OnClickProp, OnOpenChangeProp, OpenProp, PendingProp, RevealDelayProp, ShapeProp, SizeProp, TextAlignProp, TextSizeProp, TextToneProp, TextWhitespaceProp, TitleLevelProp, TypographyActionsConfigProp, TypographyCopyConfigProp, TypographyEditConfigProp, TypographyEllipsisConfigProp, TypographyTypeProp } from "../vocabulary/index.js";
|
|
4
4
|
/**
|
|
5
5
|
* @see Text — typographic primitive; replaces hand-rolled `<span className="text-[13px] …">`.
|
|
6
6
|
*
|
|
@@ -336,6 +336,47 @@ export type ActivityProp = Omit<React.HTMLAttributes<HTMLSpanElement>, "color">
|
|
|
336
336
|
announce?: ActivityAnnounceProp;
|
|
337
337
|
className?: ClassNameProp;
|
|
338
338
|
};
|
|
339
|
+
/**
|
|
340
|
+
* @see Icon — the ONE supported way to put a standalone glyph on the `--icon-size-*` scale.
|
|
341
|
+
*
|
|
342
|
+
* A lucide component carries `width="24" height="24"` of its own, and only four rules in this
|
|
343
|
+
* library ever re-size a glyph (`.ui-button svg`, the menu row, the topbar cell, the ListRow
|
|
344
|
+
* leading slot) — three of them direct-child rules. Outside those four a glyph renders at 24px
|
|
345
|
+
* beside 14px text, and a consumer has no supported way to fix it: `docs/CONSUMER-RULES.md` §8
|
|
346
|
+
* forbids `size-4`/`w-[16px]`, and `size={16}` re-derives a scale the theme owns. Measured in a
|
|
347
|
+
* consumer at 38 such glyphs (gh#712).
|
|
348
|
+
*
|
|
349
|
+
* Icon renders ONTO the glyph rather than wrapping it — the sized element IS the `<svg>` — so it
|
|
350
|
+
* composes anywhere a bare glyph does (inside `Text`, in a `Button`, in a table cell, in an `<a>`)
|
|
351
|
+
* and adds no box to the layout.
|
|
352
|
+
*/
|
|
353
|
+
export type IconGlyphProp = Omit<React.SVGProps<SVGSVGElement>, "ref" | "children"> & {
|
|
354
|
+
/**
|
|
355
|
+
* The glyph COMPONENT — `as={Lock}`, not `<Lock />`. Any component that forwards SVG props and a
|
|
356
|
+
* ref qualifies (every `lucide-react` icon does); Icon hands it the class, the size attributes
|
|
357
|
+
* and the a11y wiring.
|
|
358
|
+
*/
|
|
359
|
+
as: React.ComponentType<React.SVGProps<SVGSVGElement> & React.RefAttributes<SVGSVGElement>>;
|
|
360
|
+
/**
|
|
361
|
+
* Step of the nine-step icon scale. Default `md` (16px — "the default icon step" in
|
|
362
|
+
* docs/TOKENS.md). A glyph beside `Text size="sm"` wants `sm`; an empty-state mark wants `4xl`.
|
|
363
|
+
*/
|
|
364
|
+
size?: IconSizeProp;
|
|
365
|
+
/**
|
|
366
|
+
* Semantic colour intent, the same vocabulary `Text` uses. Omitted by default, and that default
|
|
367
|
+
* is load-bearing: a glyph inherits `currentColor`, so an Icon inside a Button, a Badge or a
|
|
368
|
+
* toned `Text` paints in that surface's own ink without being told.
|
|
369
|
+
*/
|
|
370
|
+
tone?: TextToneProp;
|
|
371
|
+
/**
|
|
372
|
+
* Accessible NAME, when the glyph carries meaning nothing else on screen says (a lock in a
|
|
373
|
+
* status cell with no text beside it). Localized by the consumer — the library ships no copy.
|
|
374
|
+
* Supplying it switches the glyph from `aria-hidden` to `role="img"` + that name; leave it off
|
|
375
|
+
* (the default) for a decorative glyph beside a visible label, which is the common case.
|
|
376
|
+
*/
|
|
377
|
+
label?: string;
|
|
378
|
+
className?: ClassNameProp;
|
|
379
|
+
};
|
|
339
380
|
/**
|
|
340
381
|
* FloatButton `type` — the two fills Ant Design gives the corner mark.
|
|
341
382
|
*
|
|
@@ -100,6 +100,11 @@ export type PageContainerProp = {
|
|
|
100
100
|
className?: ClassNameProp;
|
|
101
101
|
};
|
|
102
102
|
export type FlexDirectionProp = "row" | "col";
|
|
103
|
+
/**
|
|
104
|
+
* List marker for `as="ul"`/`as="ol"` — the CSS `list-style-type` keywords the layer implements,
|
|
105
|
+
* plus `none` for a list that is SEMANTIC ONLY (gh#714).
|
|
106
|
+
*/
|
|
107
|
+
export type FlexMarkerProp = "disc" | "decimal" | "none";
|
|
103
108
|
export type FlexAlignProp = "start" | "center" | "end" | "stretch" | "baseline";
|
|
104
109
|
export type FlexJustifyProp = "start" | "center" | "end" | "between" | "around" | "evenly";
|
|
105
110
|
/** @see Flex */
|
|
@@ -112,6 +117,26 @@ export type FlexProp = React.HTMLAttributes<HTMLElement> & {
|
|
|
112
117
|
* `.ui-flex` rules carry `display: flex`, so the box is identical either way.
|
|
113
118
|
*/
|
|
114
119
|
as?: "div" | "span" | "ul" | "ol" | "li";
|
|
120
|
+
/**
|
|
121
|
+
* Marker for a LIST element (`as="ul"` → `disc`, `as="ol"` → `decimal` by default); ignored by
|
|
122
|
+
* every other tag.
|
|
123
|
+
*
|
|
124
|
+
* `marker="none"` emits no `data-list` at all, so the list keeps its element, its `<li>`
|
|
125
|
+
* semantics and its `gap`, and loses the bullet AND the `--space-5` indent that come with it.
|
|
126
|
+
*
|
|
127
|
+
* ## Why the axis exists
|
|
128
|
+
*
|
|
129
|
+
* The bullet was unconditional, and the catalog's own idiom — `<ListRow as="li">` inside a list
|
|
130
|
+
* — could not live with it: `.ui-flex[data-list] > li { display: list-item }` outranks
|
|
131
|
+
* `[data-slot="list-row"] { display: flex }`, so every row fell out of flex layout (measured on
|
|
132
|
+
* this page: row height 94.58px → 41.2px once the attribute is gone). The only move left was a
|
|
133
|
+
* RAW `<ul>`, which carries no gap token and which the consumer rules forbid in spirit — one
|
|
134
|
+
* consumer kept three `Flex role="list"` divs for exactly that reason (gh#714).
|
|
135
|
+
*
|
|
136
|
+
* `disc`/`decimal` stay available so an `<ol>` can be bulleted (or a `<ul>` numbered) without a
|
|
137
|
+
* `list-style-type` in a className.
|
|
138
|
+
*/
|
|
139
|
+
marker?: FlexMarkerProp;
|
|
115
140
|
/** Lightweight surfaces for rows and notices; no Card elevation by default. */
|
|
116
141
|
surface?: "muted" | "popover" | "warning";
|
|
117
142
|
/** Negative inline inset, using the same spacing scale as pad. */
|
|
@@ -1314,6 +1339,23 @@ export type TopbarItemProp = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
|
1314
1339
|
*/
|
|
1315
1340
|
/** Hide below a shared responsive breakpoint, without changing cell height. */
|
|
1316
1341
|
hideBelow?: BreakpointProp;
|
|
1342
|
+
/**
|
|
1343
|
+
* The cell's leading glyph, placed in a slot the CELL sizes (`--topbar-icon-size`).
|
|
1344
|
+
*
|
|
1345
|
+
* Passing the glyph as a child works too — but only while it stays a DIRECT child, because
|
|
1346
|
+
* `.ui-topbar-item > svg` is the rule that sizes it. The moment a cell wraps its glyph (a
|
|
1347
|
+
* `<Flex hideBelow>` so the icon drops at narrow widths) the rule can no longer reach it and the
|
|
1348
|
+
* glyph renders at lucide's intrinsic 24px: measured at 390px on an org-switcher cell, 1.5x the
|
|
1349
|
+
* cell's own step (gh#712). This slot survives that, because the wrapper is the one the cell
|
|
1350
|
+
* placed. The alternative — widening the rule to a descendant — was measured to shrink or grow
|
|
1351
|
+
* OTHER components' glyphs inside the cell (a Badge's 12px glyph became 16px), so it is not one.
|
|
1352
|
+
*
|
|
1353
|
+
* Decorative by convention: the cell's accessible name comes from its own `aria-label` or its
|
|
1354
|
+
* visible label, not from the glyph. For a glyph that must carry a name, or one that needs a
|
|
1355
|
+
* step other than the bar's, pass `<Icon as={…} size=… label=… />` — as this prop's value or as
|
|
1356
|
+
* a child — and it keeps its own metric and its own semantics.
|
|
1357
|
+
*/
|
|
1358
|
+
icon?: ReactNode;
|
|
1317
1359
|
/**
|
|
1318
1360
|
* Unread count OVERLAID on the cell's glyph — the notification-bell affordance the cell's own use
|
|
1319
1361
|
* cases name (gh#398). Pass the CONTENT ONLY, exactly like `SidebarItemProp.badge`: a number, a
|