@godxjp/ui 32.7.0 → 32.7.2
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 +2 -1
- package/README.md +1 -1
- package/agent/DESIGN.md +2 -1
- package/agent/START-HERE.md +1 -1
- package/agent/components/ListRow.json +1 -0
- package/agent/components.json +1 -0
- package/agent/index.json +3 -3
- package/agent/llms.txt +4 -4
- package/dist/components/data-display/data-table.js +2 -11
- package/dist/components/data-display/list-row.js +60 -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 +12 -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/scripts/_agent-setup.mjs +5 -3
- package/scripts/ui-audit.mjs +7 -3
package/DESIGN.md
CHANGED
|
@@ -148,7 +148,7 @@ Header: record name as title, status `Badge` beside it, actions in `extra` (one
|
|
|
148
148
|
|
|
149
149
|
### Editor
|
|
150
150
|
|
|
151
|
-
Edit (or create) one document or record. Header: record name as title, status `Badge` beside it, a subtitle only for a fact such as when it was last saved, and ONE primary Save in `extra` (`Button type="submit" form=<form id>`), Cancel `outline` before it. Body: one `Form` in a `SplitPane`: the main column holds the title field and a large body editor (`BlockEditor`, or `Textarea autoSize`); the aside holds metadata fields
|
|
151
|
+
Edit (or create) one document or record. Header: record name as title, status `Badge` beside it, a subtitle only for a fact such as when it was last saved, and ONE primary Save in `extra` (`Button type="submit" form=<form id>`), Cancel `outline` before it. Body: one `Form` in a `SplitPane`: the main column holds the title field and a large body editor (`BlockEditor`, or `Textarea autoSize`); the aside holds metadata fields and read-only facts in `Descriptions`. The change note goes either directly under the body (where the writer finishes) or last in the aside — pick one per app and keep it. Name each aside group with a `Heading level={2}` one step above its field labels. A part that is its own controlled component with its own `Form` (forms cannot nest) stays a separate form; the header Save then submits by handler (`onClick`) instead of `form=<id>`, still one Save. No Card per field group, no second Save at the bottom.
|
|
152
152
|
|
|
153
153
|
### Reader
|
|
154
154
|
|
|
@@ -208,3 +208,4 @@ A list whose rows are decisions. Show requester, target, reason, submitted time;
|
|
|
208
208
|
- `card-per-section` counts Cards per file, so a screen split across components can pass with a Card around every section.
|
|
209
209
|
- Exemplar previews deploy on release tags, so they can lag `main`. On GitHub Pages a showcase URL answers HTTP 404 and renders through `404.html`, so open it in a browser; a plain fetch sees the 404.
|
|
210
210
|
- Dark theme (`data-theme="dark"`) is supported; the exemplars are reviewed in light.
|
|
211
|
+
- On narrow screens the `PageContainer` title steps down (≈17.6px) while body h2 stays ≈15.7px — one step apart. A document page not built on `LegalDocumentShell` keeps only that step on phones; there is no intermediate page-title size yet.
|
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ static files straight from this public repo — no hosting, no deploy step:
|
|
|
51
51
|
| --- | --- | --- |
|
|
52
52
|
| [`agent/START-HERE.md`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md) | 11 KB | **read first** — self-contained: the four rules, the token override model, a page that passes review |
|
|
53
53
|
| [`agent/llms.txt`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/llms.txt) | 3 KB | the [llms.txt](https://llmstxt.org/) entry point |
|
|
54
|
-
| [`agent/DESIGN.md`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md) |
|
|
54
|
+
| [`agent/DESIGN.md`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md) | 14 KB | the visual spec: tokens, colour scarcity, admin screen anatomy, do/don't |
|
|
55
55
|
| [`agent/index.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json) | 3 KB | manifest: version, counts, every file's URL |
|
|
56
56
|
| [`agent/components-index.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json) | 47 KB | all 161 as name + group + tagline — **fetch this first** |
|
|
57
57
|
| [`agent/components/<Name>.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components/Select.json) | 1 KB–37 KB | one file per component, each with its `importPath` — **this is the route to take** |
|
package/agent/DESIGN.md
CHANGED
|
@@ -148,7 +148,7 @@ Header: record name as title, status `Badge` beside it, actions in `extra` (one
|
|
|
148
148
|
|
|
149
149
|
### Editor
|
|
150
150
|
|
|
151
|
-
Edit (or create) one document or record. Header: record name as title, status `Badge` beside it, a subtitle only for a fact such as when it was last saved, and ONE primary Save in `extra` (`Button type="submit" form=<form id>`), Cancel `outline` before it. Body: one `Form` in a `SplitPane`: the main column holds the title field and a large body editor (`BlockEditor`, or `Textarea autoSize`); the aside holds metadata fields
|
|
151
|
+
Edit (or create) one document or record. Header: record name as title, status `Badge` beside it, a subtitle only for a fact such as when it was last saved, and ONE primary Save in `extra` (`Button type="submit" form=<form id>`), Cancel `outline` before it. Body: one `Form` in a `SplitPane`: the main column holds the title field and a large body editor (`BlockEditor`, or `Textarea autoSize`); the aside holds metadata fields and read-only facts in `Descriptions`. The change note goes either directly under the body (where the writer finishes) or last in the aside — pick one per app and keep it. Name each aside group with a `Heading level={2}` one step above its field labels. A part that is its own controlled component with its own `Form` (forms cannot nest) stays a separate form; the header Save then submits by handler (`onClick`) instead of `form=<id>`, still one Save. No Card per field group, no second Save at the bottom.
|
|
152
152
|
|
|
153
153
|
### Reader
|
|
154
154
|
|
|
@@ -208,3 +208,4 @@ A list whose rows are decisions. Show requester, target, reason, submitted time;
|
|
|
208
208
|
- `card-per-section` counts Cards per file, so a screen split across components can pass with a Card around every section.
|
|
209
209
|
- Exemplar previews deploy on release tags, so they can lag `main`. On GitHub Pages a showcase URL answers HTTP 404 and renders through `404.html`, so open it in a browser; a plain fetch sees the 404.
|
|
210
210
|
- Dark theme (`data-theme="dark"`) is supported; the exemplars are reviewed in light.
|
|
211
|
+
- On narrow screens the `PageContainer` title steps down (≈17.6px) while body h2 stays ≈15.7px — one step apart. A document page not built on `LegalDocumentShell` keeps only that step on phones; there is no intermediate page-title size yet.
|
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.7.
|
|
6
|
+
**This catalog describes `@godxjp/ui` 32.7.2.** 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.",
|
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.",
|
package/agent/index.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"files": [
|
|
12
12
|
{
|
|
13
13
|
"file": "DESIGN.md",
|
|
14
|
-
"note": "
|
|
14
|
+
"note": "14 KB — the visual spec: tokens, colour scarcity, admin screen anatomy (list, detail, form, settings, dashboard), do/don't. Read before composing a screen.",
|
|
15
15
|
"url": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md"
|
|
16
16
|
},
|
|
17
17
|
{
|
|
@@ -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.7.
|
|
57
|
+
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v32.7.2/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.7.
|
|
71
|
+
"version": "32.7.2"
|
|
72
72
|
}
|
package/agent/llms.txt
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
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.7.
|
|
4
|
+
> 43 cardinal rules. This file is the entry point for AI agents. Catalog version 32.7.2.
|
|
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.
|
|
7
|
+
(`npx @godxjp/ui-mcp@32.7.2`). It is searchable and version-locked. These files exist for agents
|
|
8
8
|
that can only fetch URLs.
|
|
9
9
|
|
|
10
10
|
## Start
|
|
11
11
|
|
|
12
12
|
- [START-HERE.md](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md): the whole contract — the four rules, the token override model, a page that passes review. Read this first; it is self-contained.
|
|
13
13
|
- [index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json): version, counts, and the URL of every file.
|
|
14
|
-
- [DESIGN.md](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md):
|
|
14
|
+
- [DESIGN.md](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md): 14 KB — the visual spec: tokens, colour scarcity, admin screen anatomy (list, detail, form, settings, dashboard), do/don't. Read it before composing a screen.
|
|
15
15
|
|
|
16
16
|
## Catalog
|
|
17
17
|
|
|
@@ -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.7.
|
|
30
|
+
the tag: `.../godx-jp/godxjp-ui/v32.7.2/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) {
|
|
@@ -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,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.7.
|
|
3
|
+
"version": "32.7.2",
|
|
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
|
+
};
|
|
@@ -912,6 +912,18 @@
|
|
|
912
912
|
> [data-slot="list-row"] {
|
|
913
913
|
padding-inline: 0;
|
|
914
914
|
}
|
|
915
|
+
|
|
916
|
+
[data-slot="list-row"]:is(:focus-visible, :has(:focus-visible))
|
|
917
|
+
[data-slot="list-row-body"]
|
|
918
|
+
> [data-truncated],
|
|
919
|
+
[data-slot="list-row"]:is(:focus-visible, :has(:focus-visible))
|
|
920
|
+
[data-slot="list-row-body"]
|
|
921
|
+
> [data-truncated]
|
|
922
|
+
[data-truncate] {
|
|
923
|
+
overflow: visible;
|
|
924
|
+
white-space: normal;
|
|
925
|
+
overflow-wrap: anywhere;
|
|
926
|
+
}
|
|
915
927
|
[data-slot="list-row"][data-density="compact"] [data-slot="list-row-body"] {
|
|
916
928
|
min-inline-size: min(var(--list-row-compact-body-min-width, 6rem), 100%);
|
|
917
929
|
flex-basis: var(--list-row-compact-body-min-width, 6rem);
|
package/dist/styles/layers.json
CHANGED