@godxjp/ui 32.7.1 → 32.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/agent/START-HERE.md +1 -1
- package/agent/components/ListRow.json +1 -0
- package/agent/components/Progress.json +2 -2
- package/agent/components.json +3 -2
- package/agent/index.json +2 -2
- package/agent/llms.txt +3 -3
- package/dist/components/data-display/data-table.js +2 -11
- package/dist/components/data-display/index.d.ts +1 -1
- package/dist/components/data-display/list-row.js +60 -1
- package/dist/components/data-display/progress.d.ts +8 -1
- package/dist/contracts/measurement.json +1 -1
- package/dist/lib/truncation.d.ts +14 -0
- package/dist/lib/truncation.js +14 -0
- package/dist/styles/data-display-layout.css +20 -0
- package/dist/styles/focus-ring.css +1 -0
- package/dist/styles/layers.json +1 -1
- package/dist/styles.css +1 -1
- 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` 32.
|
|
6
|
+
**This catalog describes `@godxjp/ui` 32.8.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.
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
"storyPath": "data-display/list-row.tsx",
|
|
74
74
|
"tagline": "Single-line entity row (leading · title/description · trailing action) for SHORT lists inside a Card — sessions, API tokens, linked accounts, passkeys, MFA factors, invitations.",
|
|
75
75
|
"usage": [
|
|
76
|
+
"DO rely on ListRow for a cut title (gh#1298): a title or description that is actually truncated gets a `title` with its text (a `Text ellipsis` inside it, never a badge beside it) and unfolds while the row holds keyboard focus; when nothing in the row takes focus, the cut line gets its own tab stop. Do not add a hand-rolled Tooltip for that.",
|
|
76
77
|
"DO use ListRow for a SHORT (≈2–8 item) list of entities inside a Card where each row is one line with an action — account sessions, API keys, linked identities, passkeys. Stack rows in a `<Card><CardContent flush>` so the rows draw their own quiet dividers edge-to-edge.",
|
|
77
78
|
"DON'T reach for DataTable here — it carries sorting/selection/pagination chrome that a 3-item list doesn't need. DON'T nest a Card per row either (card-in-card). ListRow is the in-between surface.",
|
|
78
79
|
"DO host ListRow in a DataTable column when the list needs ROW SELECTION (a mail/notification inbox with bulk actions) — DataTable is the only primitive that selects rows. Mark that column `flush: true` so the cell drops its own padding and the ListRow owns the inset (gh#1016); without it the cell padding stacks on the row's (a 32px dead gap after the checkbox, taller rows) and the unread band stops at the checkbox cell. DON'T zero the cell with a className.",
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
"type": "number"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
|
-
"description": "BREAKDOWN mode: one total split into slices. Pass ABSOLUTE amounts in one unit (counts, bytes, yen) — the bar computes each share, so three numbers never have to be rounded into 100. Renders role=\"img\" named from every slice (a partition is not three progressbars), on a taller track (--progress-breakdown-block-size 1.375rem, --progress-breakdown-radius var(--radius)) because three abutting fills on the meter's 0.5rem pill read as a coloured hairline. `label` on each slice is REQUIRED — colour alone never carries meaning (WCAG 1.4.1). Mutually exclusive with value/tone/over.",
|
|
14
|
+
"description": "BREAKDOWN mode: one total split into slices. Pass ABSOLUTE amounts in one unit (counts, bytes, yen) — the bar computes each share, so three numbers never have to be rounded into 100. Renders role=\"img\" named from every slice (a partition is not three progressbars), on a taller track (--progress-breakdown-block-size 1.375rem, --progress-breakdown-radius var(--radius)) because three abutting fills on the meter's 0.5rem pill read as a coloured hairline. `label` on each slice is REQUIRED — colour alone never carries meaning (WCAG 1.4.1). Mutually exclusive with value/tone/over. Slice tones add `info` and `neutral` to the three meter tones (gh#1302) — the same fills as the matching `Legend` swatches, so a four-state partition (done · awaiting · in progress · not started) stays distinguishable and keys one-to-one.",
|
|
15
15
|
"name": "segments",
|
|
16
|
-
"type": "{ value: number; tone: \"success\" | \"warning\" | \"destructive\"; label: string }[]"
|
|
16
|
+
"type": "{ value: number; tone: \"success\" | \"warning\" | \"destructive\" | \"info\" | \"neutral\"; label: string }[]"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"description": "BREAKDOWN mode: the WHOLE the slices are drawn against, in the same unit as their values. Omit it and the whole is the sum of the slices (the bar is always full). Pass it when part of the whole has no state yet — 3 passed of 400 test cases — and the rest stays the neutral TRACK, the antd `percent` model where the unfilled track is the remainder. The remainder is spoken in the role=\"img\" name, Intl-formatted in the active locale. A total below the slice sum is ignored (the sum wins), so slices never overflow.",
|
package/agent/components.json
CHANGED
|
@@ -4352,6 +4352,7 @@
|
|
|
4352
4352
|
"storyPath": "data-display/list-row.tsx",
|
|
4353
4353
|
"tagline": "Single-line entity row (leading · title/description · trailing action) for SHORT lists inside a Card — sessions, API tokens, linked accounts, passkeys, MFA factors, invitations.",
|
|
4354
4354
|
"usage": [
|
|
4355
|
+
"DO rely on ListRow for a cut title (gh#1298): a title or description that is actually truncated gets a `title` with its text (a `Text ellipsis` inside it, never a badge beside it) and unfolds while the row holds keyboard focus; when nothing in the row takes focus, the cut line gets its own tab stop. Do not add a hand-rolled Tooltip for that.",
|
|
4355
4356
|
"DO use ListRow for a SHORT (≈2–8 item) list of entities inside a Card where each row is one line with an action — account sessions, API keys, linked identities, passkeys. Stack rows in a `<Card><CardContent flush>` so the rows draw their own quiet dividers edge-to-edge.",
|
|
4356
4357
|
"DON'T reach for DataTable here — it carries sorting/selection/pagination chrome that a 3-item list doesn't need. DON'T nest a Card per row either (card-in-card). ListRow is the in-between surface.",
|
|
4357
4358
|
"DO host ListRow in a DataTable column when the list needs ROW SELECTION (a mail/notification inbox with bulk actions) — DataTable is the only primitive that selects rows. Mark that column `flush: true` so the cell drops its own padding and the ListRow owns the inset (gh#1016); without it the cell padding stacks on the row's (a 32px dead gap after the checkbox, taller rows) and the unread band stops at the checkbox cell. DON'T zero the cell with a className.",
|
|
@@ -4717,9 +4718,9 @@
|
|
|
4717
4718
|
"type": "number"
|
|
4718
4719
|
},
|
|
4719
4720
|
{
|
|
4720
|
-
"description": "BREAKDOWN mode: one total split into slices. Pass ABSOLUTE amounts in one unit (counts, bytes, yen) — the bar computes each share, so three numbers never have to be rounded into 100. Renders role=\"img\" named from every slice (a partition is not three progressbars), on a taller track (--progress-breakdown-block-size 1.375rem, --progress-breakdown-radius var(--radius)) because three abutting fills on the meter's 0.5rem pill read as a coloured hairline. `label` on each slice is REQUIRED — colour alone never carries meaning (WCAG 1.4.1). Mutually exclusive with value/tone/over.",
|
|
4721
|
+
"description": "BREAKDOWN mode: one total split into slices. Pass ABSOLUTE amounts in one unit (counts, bytes, yen) — the bar computes each share, so three numbers never have to be rounded into 100. Renders role=\"img\" named from every slice (a partition is not three progressbars), on a taller track (--progress-breakdown-block-size 1.375rem, --progress-breakdown-radius var(--radius)) because three abutting fills on the meter's 0.5rem pill read as a coloured hairline. `label` on each slice is REQUIRED — colour alone never carries meaning (WCAG 1.4.1). Mutually exclusive with value/tone/over. Slice tones add `info` and `neutral` to the three meter tones (gh#1302) — the same fills as the matching `Legend` swatches, so a four-state partition (done · awaiting · in progress · not started) stays distinguishable and keys one-to-one.",
|
|
4721
4722
|
"name": "segments",
|
|
4722
|
-
"type": "{ value: number; tone: \"success\" | \"warning\" | \"destructive\"; label: string }[]"
|
|
4723
|
+
"type": "{ value: number; tone: \"success\" | \"warning\" | \"destructive\" | \"info\" | \"neutral\"; label: string }[]"
|
|
4723
4724
|
},
|
|
4724
4725
|
{
|
|
4725
4726
|
"description": "BREAKDOWN mode: the WHOLE the slices are drawn against, in the same unit as their values. Omit it and the whole is the sum of the slices (the bar is always full). Pass it when part of the whole has no state yet — 3 passed of 400 test cases — and the rest stays the neutral TRACK, the antd `percent` model where the unfilled track is the remainder. The remainder is spoken in the role=\"img\" name, Intl-formatted in the active locale. A total below the slice sum is ignored (the sum wins), so slices never overflow.",
|
package/agent/index.json
CHANGED
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"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.",
|
|
55
55
|
"read": {
|
|
56
56
|
"live": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json",
|
|
57
|
-
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v32.
|
|
57
|
+
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v32.8.0/agent/index.json"
|
|
58
58
|
},
|
|
59
59
|
"source": "mcp/src/data — the same data @godxjp/ui-mcp serves — plus the foundation and semantic token tiers, read from src/tokens/*.css",
|
|
60
60
|
"start": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md",
|
|
@@ -68,5 +68,5 @@
|
|
|
68
68
|
"foundation": "the seeds a consumer is invited to set — --primary, --background, --radius",
|
|
69
69
|
"semantic": "named roles that follow the seeds — --ring, --text-link, --overlay-background"
|
|
70
70
|
},
|
|
71
|
-
"version": "32.
|
|
71
|
+
"version": "32.8.0"
|
|
72
72
|
}
|
package/agent/llms.txt
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @godxjp/ui
|
|
2
2
|
|
|
3
3
|
> A Japanese-enterprise React design system: 161 components, 2197 design tokens,
|
|
4
|
-
> 43 cardinal rules. This file is the entry point for AI agents. Catalog version 32.
|
|
4
|
+
> 43 cardinal rules. This file is the entry point for AI agents. Catalog version 32.8.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@32.
|
|
7
|
+
(`npx @godxjp/ui-mcp@32.8.0`). It is searchable and version-locked. These files exist for agents
|
|
8
8
|
that can only fetch URLs.
|
|
9
9
|
|
|
10
10
|
## Start
|
|
@@ -27,7 +27,7 @@ that can only fetch URLs.
|
|
|
27
27
|
## Pinning
|
|
28
28
|
|
|
29
29
|
Every URL above tracks `main`. To pin to the release a project actually installed, swap `main` for
|
|
30
|
-
the tag: `.../godx-jp/godxjp-ui/v32.
|
|
30
|
+
the tag: `.../godx-jp/godxjp-ui/v32.8.0/agent/...`. A catalog that does not match the installed
|
|
31
31
|
package describes props that are absent, or hides props that are present, and says nothing either way.
|
|
32
32
|
|
|
33
33
|
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.
|
|
@@ -71,6 +71,7 @@ import {
|
|
|
71
71
|
import { cn } from "../../lib/utils.js";
|
|
72
72
|
import { useScrollsHorizontally } from "../../lib/hooks.js";
|
|
73
73
|
import { densityClass } from "../../lib/variants.js";
|
|
74
|
+
import { TRUNCATION_FOCUSABLE, truncatedPart } from "../../lib/truncation.js";
|
|
74
75
|
import {
|
|
75
76
|
controlIconSmClass,
|
|
76
77
|
tableCellPaddingClass,
|
|
@@ -728,16 +729,6 @@ DataTable.DensityToggle.displayName = "DataTable.DensityToggle";
|
|
|
728
729
|
function fixedEdge(col) {
|
|
729
730
|
return col.fixed ?? (col.pin === "end" ? "end" : void 0);
|
|
730
731
|
}
|
|
731
|
-
const TRUNCATED_CELL_FOCUSABLE = 'a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"]), [contenteditable="true"]';
|
|
732
|
-
function truncatedPart(cell) {
|
|
733
|
-
if (cell.scrollWidth - cell.clientWidth > 1) return cell;
|
|
734
|
-
for (const el of cell.querySelectorAll("*")) {
|
|
735
|
-
if (el.scrollWidth - el.clientWidth > 1 && getComputedStyle(el).textOverflow === "ellipsis") {
|
|
736
|
-
return el;
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
return null;
|
|
740
|
-
}
|
|
741
732
|
function sameOffsets(a, b) {
|
|
742
733
|
const keys = Object.keys(a);
|
|
743
734
|
if (keys.length !== Object.keys(b).length) return false;
|
|
@@ -934,7 +925,7 @@ DataTable.Content = function DataTableContent() {
|
|
|
934
925
|
cell.title = (part.textContent ?? "").replace(/\s+/g, " ").trim();
|
|
935
926
|
cell.dataset.truncatedTitle = "";
|
|
936
927
|
}
|
|
937
|
-
if (!cell.querySelector(
|
|
928
|
+
if (!cell.querySelector(TRUNCATION_FOCUSABLE)) cell.tabIndex = 0;
|
|
938
929
|
} else if (cell.dataset.truncated !== void 0) {
|
|
939
930
|
delete cell.dataset.truncated;
|
|
940
931
|
if (ownTitle) {
|
|
@@ -29,7 +29,7 @@ export { CodeBlock } from "./code-block.js";
|
|
|
29
29
|
export type { CodeBlockProp, CodeBlockProps } from "./code-block.js";
|
|
30
30
|
export { Prose } from "./prose.js";
|
|
31
31
|
export type { ProseProp, ProseProps } from "./prose.js";
|
|
32
|
-
export type { ProgressProps, ProgressSegment, ProgressTone } from "./progress.js";
|
|
32
|
+
export type { ProgressProps, ProgressSegment, ProgressSegmentTone, ProgressTone } from "./progress.js";
|
|
33
33
|
export { Timeline } from "./timeline.js";
|
|
34
34
|
export type { TimelineItem, TimelineProps } from "./timeline.js";
|
|
35
35
|
export { Popover, PopoverAnchor, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, } from "./popover.js";
|
|
@@ -4,7 +4,56 @@ import * as React from "react";
|
|
|
4
4
|
import { Slot } from "../../lib/slot.js";
|
|
5
5
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
6
6
|
import { cn } from "../../lib/utils.js";
|
|
7
|
+
import { TRUNCATION_FOCUSABLE, truncatedPart } from "../../lib/truncation.js";
|
|
7
8
|
import { Text } from "../general/typography.js";
|
|
9
|
+
function useTruncatedLines(rowRef, enabled) {
|
|
10
|
+
const mark = React.useCallback(() => {
|
|
11
|
+
const row = rowRef.current;
|
|
12
|
+
if (!row) return;
|
|
13
|
+
const rowFocusable = row.matches(TRUNCATION_FOCUSABLE) || row.querySelector(TRUNCATION_FOCUSABLE) !== null;
|
|
14
|
+
for (const line of row.querySelectorAll('[data-slot="list-row-body"] > *')) {
|
|
15
|
+
if (row.contains(document.activeElement) && line.dataset.truncated !== void 0) continue;
|
|
16
|
+
const ownTitle = line.dataset.truncatedTitle !== void 0;
|
|
17
|
+
const part = truncatedPart(line);
|
|
18
|
+
if (part) {
|
|
19
|
+
line.dataset.truncated = "";
|
|
20
|
+
if ((!line.title || ownTitle) && (part === line || !part.title)) {
|
|
21
|
+
line.title = (part.textContent ?? "").replace(/\s+/g, " ").trim();
|
|
22
|
+
line.dataset.truncatedTitle = "";
|
|
23
|
+
}
|
|
24
|
+
if (!rowFocusable || line.dataset.truncatedStop !== void 0) {
|
|
25
|
+
line.tabIndex = 0;
|
|
26
|
+
line.dataset.truncatedStop = "";
|
|
27
|
+
}
|
|
28
|
+
} else if (line.dataset.truncated !== void 0) {
|
|
29
|
+
delete line.dataset.truncated;
|
|
30
|
+
if (ownTitle) {
|
|
31
|
+
line.removeAttribute("title");
|
|
32
|
+
delete line.dataset.truncatedTitle;
|
|
33
|
+
}
|
|
34
|
+
if (line.dataset.truncatedStop !== void 0) {
|
|
35
|
+
line.removeAttribute("tabindex");
|
|
36
|
+
delete line.dataset.truncatedStop;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}, [rowRef]);
|
|
41
|
+
React.useEffect(() => {
|
|
42
|
+
if (enabled) mark();
|
|
43
|
+
});
|
|
44
|
+
React.useEffect(() => {
|
|
45
|
+
const row = rowRef.current;
|
|
46
|
+
if (!enabled || !row || typeof ResizeObserver === "undefined") return;
|
|
47
|
+
const observer = new ResizeObserver(mark);
|
|
48
|
+
observer.observe(row);
|
|
49
|
+
const refold = () => requestAnimationFrame(mark);
|
|
50
|
+
row.addEventListener("focusout", refold);
|
|
51
|
+
return () => {
|
|
52
|
+
observer.disconnect();
|
|
53
|
+
row.removeEventListener("focusout", refold);
|
|
54
|
+
};
|
|
55
|
+
}, [enabled, mark, rowRef]);
|
|
56
|
+
}
|
|
8
57
|
const ListRow = React.forwardRef(
|
|
9
58
|
({
|
|
10
59
|
as = "div",
|
|
@@ -22,6 +71,16 @@ const ListRow = React.forwardRef(
|
|
|
22
71
|
...props
|
|
23
72
|
}, ref) => {
|
|
24
73
|
const { t } = useTranslation();
|
|
74
|
+
const rowRef = React.useRef(null);
|
|
75
|
+
const setRef = React.useCallback(
|
|
76
|
+
(node) => {
|
|
77
|
+
rowRef.current = node;
|
|
78
|
+
if (typeof ref === "function") ref(node);
|
|
79
|
+
else if (ref) ref.current = node;
|
|
80
|
+
},
|
|
81
|
+
[ref]
|
|
82
|
+
);
|
|
83
|
+
useTruncatedLines(rowRef, overflow !== "wrap");
|
|
25
84
|
const item = asChild && as !== "div" ? as : null;
|
|
26
85
|
const Comp = asChild ? Slot : as;
|
|
27
86
|
const truncate = overflow !== "wrap";
|
|
@@ -37,7 +96,7 @@ const ListRow = React.forwardRef(
|
|
|
37
96
|
const row = /* @__PURE__ */ jsx(
|
|
38
97
|
Comp,
|
|
39
98
|
{
|
|
40
|
-
ref,
|
|
99
|
+
ref: setRef,
|
|
41
100
|
"data-slot": "list-row",
|
|
42
101
|
"data-align": align === "start" ? "start" : void 0,
|
|
43
102
|
"data-overflow": overflow === "wrap" ? "wrap" : void 0,
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
export type ProgressTone = "success" | "warning" | "destructive";
|
|
3
|
+
/**
|
|
4
|
+
* A breakdown SLICE takes two more tones than the meter (gh#1302): `info` and `neutral`, the same
|
|
5
|
+
* pair `Legend` already keys — a partition with four states (done · done-awaiting · in progress ·
|
|
6
|
+
* not started) needs four distinguishable fills, and the meter's three made two of them identical.
|
|
7
|
+
* Each paints exactly what the matching Legend swatch paints, so a key and its bar stay one.
|
|
8
|
+
*/
|
|
9
|
+
export type ProgressSegmentTone = ProgressTone | "info" | "neutral";
|
|
3
10
|
/**
|
|
4
11
|
* One slice of a BREAKDOWN bar — how much of the total this state holds, in the SAME unit as every
|
|
5
12
|
* other slice (counts, bytes, yen). Never a percentage: the bar owns the ratio arithmetic, so the
|
|
@@ -10,7 +17,7 @@ export type ProgressTone = "success" | "warning" | "destructive";
|
|
|
10
17
|
*/
|
|
11
18
|
export type ProgressSegment = {
|
|
12
19
|
value: number;
|
|
13
|
-
tone:
|
|
20
|
+
tone: ProgressSegmentTone;
|
|
14
21
|
label: string;
|
|
15
22
|
};
|
|
16
23
|
type ProgressBase = Omit<React.HTMLAttributes<HTMLDivElement>, "role" | "children" | "aria-valuenow" | "aria-valuemin" | "aria-valuemax" | "aria-valuetext"> & {
|
|
@@ -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.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,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What is actually CUT inside a truncating box, shared by DataTable `ellipsis` cells (gh#1262,
|
|
3
|
+
* gh#1269) and ListRow titles (gh#1298).
|
|
4
|
+
*
|
|
5
|
+
* Internal: reachable from no published subpath.
|
|
6
|
+
*/
|
|
7
|
+
/** Something that already takes focus — a box holding one needs no tab stop of its own. */
|
|
8
|
+
export declare const TRUNCATION_FOCUSABLE = "a[href], button, input, select, textarea, [tabindex]:not([tabindex=\"-1\"]), [contenteditable=\"true\"]";
|
|
9
|
+
/**
|
|
10
|
+
* The box itself when it overflows, else the first descendant that ends in an ellipsis
|
|
11
|
+
* (`text-overflow: ellipsis`) and overflows — a `Text truncate` link beside a badge or an avatar
|
|
12
|
+
* is cut while its container fits. `null` when nothing is cut.
|
|
13
|
+
*/
|
|
14
|
+
export declare function truncatedPart(box: HTMLElement): HTMLElement | null;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const TRUNCATION_FOCUSABLE = 'a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"]), [contenteditable="true"]';
|
|
2
|
+
function truncatedPart(box) {
|
|
3
|
+
if (box.scrollWidth - box.clientWidth > 1) return box;
|
|
4
|
+
for (const el of box.querySelectorAll("*")) {
|
|
5
|
+
if (el.scrollWidth - el.clientWidth > 1 && getComputedStyle(el).textOverflow === "ellipsis") {
|
|
6
|
+
return el;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
TRUNCATION_FOCUSABLE,
|
|
13
|
+
truncatedPart
|
|
14
|
+
};
|
|
@@ -241,6 +241,14 @@
|
|
|
241
241
|
background: hsl(var(--mark-destructive, var(--text-error)));
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
+
.ui-progress-segment[data-tone="info"] {
|
|
245
|
+
background: hsl(var(--mark-info, var(--text-info)));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.ui-progress-segment[data-tone="neutral"] {
|
|
249
|
+
background: hsl(var(--muted-foreground));
|
|
250
|
+
}
|
|
251
|
+
|
|
244
252
|
.ui-progress-label {
|
|
245
253
|
color: hsl(var(--muted-foreground));
|
|
246
254
|
font-size: var(--progress-label-font-size);
|
|
@@ -912,6 +920,18 @@
|
|
|
912
920
|
> [data-slot="list-row"] {
|
|
913
921
|
padding-inline: 0;
|
|
914
922
|
}
|
|
923
|
+
|
|
924
|
+
[data-slot="list-row"]:is(:focus-visible, :has(:focus-visible))
|
|
925
|
+
[data-slot="list-row-body"]
|
|
926
|
+
> [data-truncated],
|
|
927
|
+
[data-slot="list-row"]:is(:focus-visible, :has(:focus-visible))
|
|
928
|
+
[data-slot="list-row-body"]
|
|
929
|
+
> [data-truncated]
|
|
930
|
+
[data-truncate] {
|
|
931
|
+
overflow: visible;
|
|
932
|
+
white-space: normal;
|
|
933
|
+
overflow-wrap: anywhere;
|
|
934
|
+
}
|
|
915
935
|
[data-slot="list-row"][data-density="compact"] [data-slot="list-row-body"] {
|
|
916
936
|
min-inline-size: min(var(--list-row-compact-body-min-width, 6rem), 100%);
|
|
917
937
|
flex-basis: var(--list-row-compact-body-min-width, 6rem);
|
package/dist/styles/layers.json
CHANGED