@stackone/malachite 2.64.0 → 2.66.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/COMPONENTS.md +4 -4
- package/dist/components/Avatar.js +10 -10
- package/dist/components/Avatar.js.map +1 -1
- package/dist/components/Button.js +103 -89
- package/dist/components/Button.js.map +1 -1
- package/dist/components/NavItem.js +140 -101
- package/dist/components/NavItem.js.map +1 -1
- package/dist/components/Popover.js +157 -149
- package/dist/components/Popover.js.map +1 -1
- package/dist/components/Typography/PathText.js +158 -0
- package/dist/components/Typography/PathText.js.map +1 -0
- package/dist/components/Typography/index.js +15 -13
- package/dist/components/Typography/index.js.map +1 -1
- package/dist/components/Typography/pathTextFit.js +42 -0
- package/dist/components/Typography/pathTextFit.js.map +1 -0
- package/dist/components/Typography/pathTextMeasure.js +67 -0
- package/dist/components/Typography/pathTextMeasure.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/tailwind.css.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { jsx as f, jsxs as P } from "react/jsx-runtime";
|
|
2
|
+
import D, { useRef as w, useState as H, useEffect as R } from "react";
|
|
3
|
+
import U from "../Tooltip.js";
|
|
4
|
+
import { DEFAULT_MIN_CHARS as L, fitPath as q } from "./pathTextFit.js";
|
|
5
|
+
import { observePath as K, scheduleRemeasure as _, measurerFor as j, fontOf as V } from "./pathTextMeasure.js";
|
|
6
|
+
import { getFontSize as Y, getFontWeight as Z } from "./textStyles.js";
|
|
7
|
+
const k = {
|
|
8
|
+
display: "grid",
|
|
9
|
+
gridTemplateColumns: "minmax(0, 1fr)",
|
|
10
|
+
minWidth: 0,
|
|
11
|
+
maxWidth: "100%"
|
|
12
|
+
}, $ = {
|
|
13
|
+
gridArea: "1 / 1",
|
|
14
|
+
height: 0,
|
|
15
|
+
overflow: "hidden",
|
|
16
|
+
visibility: "hidden",
|
|
17
|
+
whiteSpace: "pre"
|
|
18
|
+
}, z = {
|
|
19
|
+
gridArea: "1 / 1",
|
|
20
|
+
display: "flex",
|
|
21
|
+
minWidth: 0,
|
|
22
|
+
overflow: "hidden",
|
|
23
|
+
whiteSpace: "nowrap"
|
|
24
|
+
}, B = {
|
|
25
|
+
position: "absolute",
|
|
26
|
+
width: 1,
|
|
27
|
+
height: 1,
|
|
28
|
+
margin: -1,
|
|
29
|
+
overflow: "hidden",
|
|
30
|
+
clipPath: "inset(50%)",
|
|
31
|
+
whiteSpace: "nowrap"
|
|
32
|
+
}, v = {
|
|
33
|
+
default: {},
|
|
34
|
+
secondary: {
|
|
35
|
+
color: "var(--malachite-text-secondary, rgb(123, 123, 123))",
|
|
36
|
+
fontWeight: Z("normal")
|
|
37
|
+
}
|
|
38
|
+
}, G = { ...v.secondary, flexShrink: 0, whiteSpace: "pre" }, p = (t) => t.tone ?? "default", J = (t, r) => t !== null && t.width === r.width && t.fonts.default === r.fonts.default && t.fonts.secondary === r.fonts.secondary, Q = (t, r, d) => {
|
|
39
|
+
if (!t || t.width <= 0)
|
|
40
|
+
return null;
|
|
41
|
+
const m = [];
|
|
42
|
+
for (const h of r) {
|
|
43
|
+
const y = j(t.fonts[p(h)] ?? "");
|
|
44
|
+
if (!y)
|
|
45
|
+
return null;
|
|
46
|
+
m.push({
|
|
47
|
+
text: h.text,
|
|
48
|
+
minChars: h.minChars ?? L,
|
|
49
|
+
measure: y
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const c = j(t.fonts.secondary ?? "");
|
|
53
|
+
return r.length > 1 && !c ? null : q({
|
|
54
|
+
available: t.width,
|
|
55
|
+
segments: m,
|
|
56
|
+
separatorWidth: (c == null ? void 0 : c(d)) ?? 0
|
|
57
|
+
});
|
|
58
|
+
}, st = ({
|
|
59
|
+
segments: t,
|
|
60
|
+
separator: r = " / ",
|
|
61
|
+
size: d,
|
|
62
|
+
tooltip: m,
|
|
63
|
+
tooltipPlacement: c = "top",
|
|
64
|
+
tooltipSuppressed: h = !1,
|
|
65
|
+
className: y
|
|
66
|
+
}) => {
|
|
67
|
+
const u = w(null), A = w(null), T = w(null), [a, M] = H(null), S = w(null), W = t.length === 0;
|
|
68
|
+
R(() => {
|
|
69
|
+
const e = u.current;
|
|
70
|
+
if (e)
|
|
71
|
+
return K(e, (n, o) => {
|
|
72
|
+
const i = A.current;
|
|
73
|
+
if (!i)
|
|
74
|
+
return;
|
|
75
|
+
if (o || !S.current) {
|
|
76
|
+
const l = {};
|
|
77
|
+
for (const I of i.querySelectorAll("[data-tone]")) {
|
|
78
|
+
const g = I.dataset.tone;
|
|
79
|
+
l[g] ?? (l[g] = V(I));
|
|
80
|
+
}
|
|
81
|
+
S.current = l;
|
|
82
|
+
}
|
|
83
|
+
const F = { width: n, fonts: S.current };
|
|
84
|
+
M((l) => J(l, F) ? l : F);
|
|
85
|
+
});
|
|
86
|
+
}, [W]);
|
|
87
|
+
const C = new Set(t.map(p));
|
|
88
|
+
t.length > 1 && C.add("secondary");
|
|
89
|
+
const O = [...C].sort().join(" ");
|
|
90
|
+
if (R(() => {
|
|
91
|
+
const e = u.current, n = O.split(" ").some((o) => !(a != null && a.fonts[o]));
|
|
92
|
+
e && a && n && _(e);
|
|
93
|
+
}, [O, a]), R(() => {
|
|
94
|
+
u.current && _(u.current);
|
|
95
|
+
}, [d]), W)
|
|
96
|
+
return null;
|
|
97
|
+
const s = Q(a, t, r), x = t.length - 1, E = t.map((e) => e.text).join(r), N = (e, n) => {
|
|
98
|
+
const o = e.minChars ?? L, i = !s && n < x && e.text.length > o + 1;
|
|
99
|
+
return {
|
|
100
|
+
...v[p(e)],
|
|
101
|
+
minWidth: i ? `${o + 1}ch` : 0,
|
|
102
|
+
overflow: "hidden",
|
|
103
|
+
// Fitted text already carries its ellipsis; a sub-pixel overflow must not add one.
|
|
104
|
+
textOverflow: s ? "clip" : "ellipsis",
|
|
105
|
+
flexShrink: n < x ? 1e3 * (x - n) : 1
|
|
106
|
+
};
|
|
107
|
+
}, b = (e, n) => t.map((o, i) => (
|
|
108
|
+
// Positional: an index is a level of the path, and texts repeat ("Acme / Acme").
|
|
109
|
+
/* @__PURE__ */ P(D.Fragment, { children: [
|
|
110
|
+
i > 0 && /* @__PURE__ */ f("span", { "data-tone": n ? "secondary" : void 0, style: G, children: r }),
|
|
111
|
+
/* @__PURE__ */ f(
|
|
112
|
+
"span",
|
|
113
|
+
{
|
|
114
|
+
"data-tone": n ? p(o) : void 0,
|
|
115
|
+
style: n ? v[p(o)] : N(o, i),
|
|
116
|
+
children: e[i]
|
|
117
|
+
}
|
|
118
|
+
)
|
|
119
|
+
] }, i)
|
|
120
|
+
));
|
|
121
|
+
return /* @__PURE__ */ f(
|
|
122
|
+
U,
|
|
123
|
+
{
|
|
124
|
+
text: m ?? E,
|
|
125
|
+
placement: c,
|
|
126
|
+
triggerAs: "span",
|
|
127
|
+
describesTrigger: !1,
|
|
128
|
+
suppressed: h,
|
|
129
|
+
isShrinkable: !0,
|
|
130
|
+
shouldShow: () => {
|
|
131
|
+
if (s)
|
|
132
|
+
return s.truncated;
|
|
133
|
+
const e = T.current;
|
|
134
|
+
return !!e && [...e.children].some((n) => n.scrollWidth > n.clientWidth);
|
|
135
|
+
},
|
|
136
|
+
children: /* @__PURE__ */ P(
|
|
137
|
+
"span",
|
|
138
|
+
{
|
|
139
|
+
ref: u,
|
|
140
|
+
className: y,
|
|
141
|
+
style: d ? { ...k, fontSize: Y(d) } : k,
|
|
142
|
+
children: [
|
|
143
|
+
/* @__PURE__ */ f("span", { ref: A, "aria-hidden": "true", style: $, children: b(
|
|
144
|
+
t.map((e) => e.text),
|
|
145
|
+
!0
|
|
146
|
+
) }),
|
|
147
|
+
/* @__PURE__ */ f("span", { ref: T, "aria-hidden": "true", style: z, children: b((s == null ? void 0 : s.texts) ?? t.map((e) => e.text), !1) }),
|
|
148
|
+
/* @__PURE__ */ f("span", { style: B, children: E })
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
};
|
|
155
|
+
export {
|
|
156
|
+
st as default
|
|
157
|
+
};
|
|
158
|
+
//# sourceMappingURL=PathText.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PathText.js","sources":["../../../src/components/Typography/PathText.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport Tooltip from '../Tooltip';\nimport { DEFAULT_MIN_CHARS, type FitSegment, type PathFit, fitPath } from './pathTextFit';\nimport { fontOf, measurerFor, observePath, scheduleRemeasure } from './pathTextMeasure';\nimport { type FontSize, getFontSize, getFontWeight } from './textStyles';\n\n/** `default` takes the surrounding colour and weight; `secondary` recedes, as an ancestor should. */\nexport type PathTextTone = 'default' | 'secondary';\n\nexport interface PathTextSegment {\n text: string;\n tone?: PathTextTone;\n /** Kept when cut, before the next segment gives way. Defaults to 2; ignored on the last. */\n minChars?: number;\n}\n\nexport interface PathTextProps {\n /** Root first, leaf last; segments give way in that order, so the leaf stays whole longest. */\n segments: PathTextSegment[];\n /** Drawn between segments, never cut. Defaults to `' / '`. */\n separator?: string;\n /** Inherits the surrounding size when unset. */\n size?: FontSize;\n /** Shown when anything is cut. Defaults to the whole path; pass a node to wrap it. */\n tooltip?: React.ReactNode;\n tooltipPlacement?: 'top' | 'bottom' | 'left' | 'right';\n /** Holds the tooltip back, e.g. while the menu this path labels is open. */\n tooltipSuppressed?: boolean;\n className?: string;\n}\n\ninterface Measured {\n width: number;\n fonts: Partial<Record<PathTextTone, string>>;\n}\n\n// Inline styles, not classes: a path can sit in a menu portaled out of the shadow root.\n// SIZER keeps the uncut width, or a cut path would shrink its own box and be cut again.\nconst ROOT: React.CSSProperties = {\n display: 'grid',\n gridTemplateColumns: 'minmax(0, 1fr)',\n minWidth: 0,\n maxWidth: '100%',\n};\nconst SIZER: React.CSSProperties = {\n gridArea: '1 / 1',\n height: 0,\n overflow: 'hidden',\n visibility: 'hidden',\n whiteSpace: 'pre',\n};\nconst LINE: React.CSSProperties = {\n gridArea: '1 / 1',\n display: 'flex',\n minWidth: 0,\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n};\nconst VISUALLY_HIDDEN: React.CSSProperties = {\n position: 'absolute',\n width: 1,\n height: 1,\n margin: -1,\n overflow: 'hidden',\n clipPath: 'inset(50%)',\n whiteSpace: 'nowrap',\n};\nconst TONE: Record<PathTextTone, React.CSSProperties> = {\n default: {},\n secondary: {\n color: 'var(--malachite-text-secondary, rgb(123, 123, 123))',\n fontWeight: getFontWeight('normal'),\n },\n};\nconst SEPARATOR: React.CSSProperties = { ...TONE.secondary, flexShrink: 0, whiteSpace: 'pre' };\n\nconst toneOf = (segment: PathTextSegment): PathTextTone => segment.tone ?? 'default';\n\nconst sameMeasured = (a: Measured | null, b: Measured): boolean =>\n a !== null &&\n a.width === b.width &&\n a.fonts.default === b.fonts.default &&\n a.fonts.secondary === b.fonts.secondary;\n\nconst fitOf = (\n measured: Measured | null,\n segments: PathTextSegment[],\n separator: string,\n): PathFit | null => {\n if (!measured || measured.width <= 0) {\n return null;\n }\n const fitSegments: FitSegment[] = [];\n for (const segment of segments) {\n const measure = measurerFor(measured.fonts[toneOf(segment)] ?? '');\n if (!measure) {\n return null;\n }\n fitSegments.push({\n text: segment.text,\n minChars: segment.minChars ?? DEFAULT_MIN_CHARS,\n measure,\n });\n }\n const measureSeparator = measurerFor(measured.fonts.secondary ?? '');\n if (segments.length > 1 && !measureSeparator) {\n return null;\n }\n return fitPath({\n available: measured.width,\n segments: fitSegments,\n separatorWidth: measureSeparator?.(separator) ?? 0,\n });\n};\n\n/**\n * Canvas-measured, not `text-overflow`, which leaves a space before the ellipsis and cannot hold\n * a minimum length. Unmeasured (no canvas yet), `flex-shrink` gives the same priority.\n */\nconst PathText: React.FC<PathTextProps> = ({\n segments,\n separator = ' / ',\n size,\n tooltip,\n tooltipPlacement = 'top',\n tooltipSuppressed = false,\n className,\n}) => {\n const rootRef = useRef<HTMLSpanElement>(null);\n const sizerRef = useRef<HTMLSpanElement>(null);\n const lineRef = useRef<HTMLSpanElement>(null);\n const [measured, setMeasured] = useState<Measured | null>(null);\n // Fonts are read on first measure and on refresh only: a resize must not force a style read.\n const fontsRef = useRef<Measured['fonts'] | null>(null);\n const empty = segments.length === 0;\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: the root only exists once there are segments\n useEffect(() => {\n const root = rootRef.current;\n if (!root) {\n return;\n }\n return observePath(root, (width, refreshFonts) => {\n const sizer = sizerRef.current;\n if (!sizer) {\n return;\n }\n if (refreshFonts || !fontsRef.current) {\n const read: Measured['fonts'] = {};\n for (const node of sizer.querySelectorAll<HTMLElement>('[data-tone]')) {\n const tone = node.dataset.tone as PathTextTone;\n read[tone] ??= fontOf(node);\n }\n fontsRef.current = read;\n }\n const next = { width, fonts: fontsRef.current };\n setMeasured((previous) => (sameMeasured(previous, next) ? previous : next));\n });\n }, [empty]);\n\n const tones = new Set<PathTextTone>(segments.map(toneOf));\n if (segments.length > 1) {\n tones.add('secondary');\n }\n const toneKey = [...tones].sort().join(' ');\n useEffect(() => {\n const root = rootRef.current;\n const missing = toneKey.split(' ').some((tone) => !measured?.fonts[tone as PathTextTone]);\n if (root && measured && missing) {\n scheduleRemeasure(root);\n }\n }, [toneKey, measured]);\n\n // A new size keeps a cut path's box the same width, so the observer would not refire.\n // biome-ignore lint/correctness/useExhaustiveDependencies: re-reads the fonts when `size` changes\n useEffect(() => {\n if (rootRef.current) {\n scheduleRemeasure(rootRef.current);\n }\n }, [size]);\n\n if (empty) {\n return null;\n }\n\n const fit = fitOf(measured, segments, separator);\n const last = segments.length - 1;\n const fullText = segments.map((segment) => segment.text).join(separator);\n\n const segmentStyle = (segment: PathTextSegment, index: number): React.CSSProperties => {\n const minChars = segment.minChars ?? DEFAULT_MIN_CHARS;\n const keepsMinimum = !fit && index < last && segment.text.length > minChars + 1;\n return {\n ...TONE[toneOf(segment)],\n minWidth: keepsMinimum ? `${minChars + 1}ch` : 0,\n overflow: 'hidden',\n // Fitted text already carries its ellipsis; a sub-pixel overflow must not add one.\n textOverflow: fit ? 'clip' : 'ellipsis',\n flexShrink: index < last ? 1000 * (last - index) : 1,\n };\n };\n\n const renderSegments = (texts: string[], forSizer: boolean) =>\n segments.map((segment, index) => (\n // Positional: an index is a level of the path, and texts repeat (\"Acme / Acme\").\n <React.Fragment key={index}>\n {index > 0 && (\n <span data-tone={forSizer ? 'secondary' : undefined} style={SEPARATOR}>\n {separator}\n </span>\n )}\n <span\n data-tone={forSizer ? toneOf(segment) : undefined}\n style={forSizer ? TONE[toneOf(segment)] : segmentStyle(segment, index)}\n >\n {texts[index]}\n </span>\n </React.Fragment>\n ));\n\n const isCut = (): boolean => {\n if (fit) {\n return fit.truncated;\n }\n const line = lineRef.current;\n return !!line && [...line.children].some((child) => child.scrollWidth > child.clientWidth);\n };\n\n return (\n <Tooltip\n text={tooltip ?? fullText}\n placement={tooltipPlacement}\n triggerAs=\"span\"\n describesTrigger={false}\n suppressed={tooltipSuppressed}\n isShrinkable\n shouldShow={isCut}\n >\n <span\n ref={rootRef}\n className={className}\n style={size ? { ...ROOT, fontSize: getFontSize(size) } : ROOT}\n >\n <span ref={sizerRef} aria-hidden=\"true\" style={SIZER}>\n {renderSegments(\n segments.map((segment) => segment.text),\n true,\n )}\n </span>\n <span ref={lineRef} aria-hidden=\"true\" style={LINE}>\n {renderSegments(fit?.texts ?? segments.map((segment) => segment.text), false)}\n </span>\n <span style={VISUALLY_HIDDEN}>{fullText}</span>\n </span>\n </Tooltip>\n );\n};\n\nexport default PathText;\n"],"names":["ROOT","SIZER","LINE","VISUALLY_HIDDEN","TONE","getFontWeight","SEPARATOR","toneOf","segment","sameMeasured","a","b","fitOf","measured","segments","separator","fitSegments","measure","measurerFor","DEFAULT_MIN_CHARS","measureSeparator","fitPath","PathText","size","tooltip","tooltipPlacement","tooltipSuppressed","className","rootRef","useRef","sizerRef","lineRef","setMeasured","useState","fontsRef","empty","useEffect","root","observePath","width","refreshFonts","sizer","read","node","tone","fontOf","next","previous","tones","toneKey","missing","scheduleRemeasure","fit","last","fullText","segmentStyle","index","minChars","keepsMinimum","renderSegments","texts","forSizer","jsxs","React","jsx","Tooltip","line","child","getFontSize"],"mappings":"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"}
|
|
@@ -4,28 +4,30 @@ import r from "./FormSectionTitle.js";
|
|
|
4
4
|
import m from "./LinkText.js";
|
|
5
5
|
import i from "./MarkdownBlock.js";
|
|
6
6
|
import e from "./PageTitle.js";
|
|
7
|
-
import p from "./
|
|
8
|
-
import f from "./
|
|
9
|
-
import a from "./
|
|
10
|
-
import T from "./
|
|
11
|
-
import l from "./
|
|
7
|
+
import p from "./PathText.js";
|
|
8
|
+
import f from "./SecondaryText.js";
|
|
9
|
+
import a from "./SectionTitle.js";
|
|
10
|
+
import T from "./StatisticLabel.js";
|
|
11
|
+
import l from "./StatisticValue.js";
|
|
12
|
+
import x from "./TerminalText.js";
|
|
12
13
|
import c from "./Text.js";
|
|
13
|
-
const
|
|
14
|
+
const B = {
|
|
14
15
|
CodeText: o,
|
|
15
16
|
EllipsisText: t,
|
|
16
17
|
FormSectionTitle: r,
|
|
17
18
|
LinkText: m,
|
|
18
19
|
MarkdownBlock: i,
|
|
19
20
|
PageTitle: e,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
PathText: p,
|
|
22
|
+
SecondaryText: f,
|
|
23
|
+
SectionTitle: a,
|
|
24
|
+
StatisticLabel: T,
|
|
25
|
+
StatisticValue: l,
|
|
26
|
+
TerminalText: x,
|
|
25
27
|
Text: c
|
|
26
28
|
};
|
|
27
29
|
export {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
B as Typography,
|
|
31
|
+
B as default
|
|
30
32
|
};
|
|
31
33
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/components/Typography/index.tsx"],"sourcesContent":["import { default as CodeText } from './CodeText';\nimport { default as EllipsisText } from './EllipsisText';\nimport { default as FormSectionTitle } from './FormSectionTitle';\nimport { default as LinkText } from './LinkText';\nimport { default as MarkdownBlock } from './MarkdownBlock';\nimport { default as PageTitle } from './PageTitle';\nimport { default as SecondaryText } from './SecondaryText';\nimport { default as SectionTitle } from './SectionTitle';\nimport { default as StatisticLabel } from './StatisticLabel';\nimport { default as StatisticValue } from './StatisticValue';\nimport { default as TerminalText } from './TerminalText';\nimport { default as Text } from './Text';\n\nexport type { CodeTextProps, CodeTextVariant } from './CodeText';\nexport type { MarkdownLinks, MarkdownProps, MarkdownVariant } from './MarkdownBlock';\nexport type { FontSize, FontWeight, TextColor, TextElement, TextProps } from './Text';\n\nexport const Typography = {\n CodeText,\n EllipsisText,\n FormSectionTitle,\n LinkText,\n MarkdownBlock,\n PageTitle,\n SecondaryText,\n SectionTitle,\n StatisticLabel,\n StatisticValue,\n TerminalText,\n Text,\n};\n\nexport default Typography;\n"],"names":["Typography","CodeText","EllipsisText","FormSectionTitle","LinkText","MarkdownBlock","PageTitle","SecondaryText","SectionTitle","StatisticLabel","StatisticValue","TerminalText","Text"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/components/Typography/index.tsx"],"sourcesContent":["import { default as CodeText } from './CodeText';\nimport { default as EllipsisText } from './EllipsisText';\nimport { default as FormSectionTitle } from './FormSectionTitle';\nimport { default as LinkText } from './LinkText';\nimport { default as MarkdownBlock } from './MarkdownBlock';\nimport { default as PageTitle } from './PageTitle';\nimport { default as PathText } from './PathText';\nimport { default as SecondaryText } from './SecondaryText';\nimport { default as SectionTitle } from './SectionTitle';\nimport { default as StatisticLabel } from './StatisticLabel';\nimport { default as StatisticValue } from './StatisticValue';\nimport { default as TerminalText } from './TerminalText';\nimport { default as Text } from './Text';\n\nexport type { CodeTextProps, CodeTextVariant } from './CodeText';\nexport type { MarkdownLinks, MarkdownProps, MarkdownVariant } from './MarkdownBlock';\nexport type { PathTextProps, PathTextSegment, PathTextTone } from './PathText';\nexport type { FontSize, FontWeight, TextColor, TextElement, TextProps } from './Text';\n\nexport const Typography = {\n CodeText,\n EllipsisText,\n FormSectionTitle,\n LinkText,\n MarkdownBlock,\n PageTitle,\n PathText,\n SecondaryText,\n SectionTitle,\n StatisticLabel,\n StatisticValue,\n TerminalText,\n Text,\n};\n\nexport default Typography;\n"],"names":["Typography","CodeText","EllipsisText","FormSectionTitle","LinkText","MarkdownBlock","PageTitle","PathText","SecondaryText","SectionTitle","StatisticLabel","StatisticValue","TerminalText","Text"],"mappings":";;;;;;;;;;;;;AAmBO,MAAMA,IAAa;AAAA,EACtB,UAAAC;AAAA,EACA,cAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,UAAAC;AAAA,EACA,eAAAC;AAAA,EACA,WAAAC;AAAA,EACA,UAAAC;AAAA,EACA,eAAAC;AAAA,EACA,cAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,cAAAC;AAAA,EACA,MAAAC;AACJ;"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const p = "…", A = 2;
|
|
2
|
+
let a;
|
|
3
|
+
const S = (e) => {
|
|
4
|
+
if (a === void 0) {
|
|
5
|
+
const t = typeof Intl > "u" ? void 0 : Intl.Segmenter;
|
|
6
|
+
a = t ? new t(void 0, { granularity: "grapheme" }) : null;
|
|
7
|
+
}
|
|
8
|
+
return a ? Array.from(a.segment(e), (t) => t.segment) : Array.from(e);
|
|
9
|
+
}, f = (e, t) => `${e.slice(0, t).join("").trimEnd()}…`, L = (e, t, s) => {
|
|
10
|
+
if (s(e) <= t + 0.25)
|
|
11
|
+
return e;
|
|
12
|
+
const o = S(e);
|
|
13
|
+
let r = 0, h = o.length - 1;
|
|
14
|
+
for (; r < h; ) {
|
|
15
|
+
const c = Math.ceil((r + h) / 2);
|
|
16
|
+
s(f(o, c)) <= t ? r = c : h = c - 1;
|
|
17
|
+
}
|
|
18
|
+
return r === 0 ? "…" : f(o, r);
|
|
19
|
+
}, I = ({ text: e, minChars: t }) => {
|
|
20
|
+
const s = S(e);
|
|
21
|
+
return s.length > t + 1 ? f(s, t) : e;
|
|
22
|
+
}, P = ({ available: e, segments: t, separatorWidth: s }) => {
|
|
23
|
+
const o = t.map((n) => n.text), r = t.map((n) => n.measure(n.text)), h = s * Math.max(t.length - 1, 0), c = (n) => n.reduce((u, l) => u + l, h);
|
|
24
|
+
if (c(r) <= e + 0.25)
|
|
25
|
+
return { texts: o, truncated: !1 };
|
|
26
|
+
const i = t.length - 1;
|
|
27
|
+
for (let n = 0; n < i; n += 1) {
|
|
28
|
+
const u = t[n], l = I(u), m = u.measure(l), E = c(r) - r[n];
|
|
29
|
+
if (E + m <= e)
|
|
30
|
+
return o[n] = L(u.text, e - E, u.measure), { texts: o, truncated: !0 };
|
|
31
|
+
o[n] = l, r[n] = m;
|
|
32
|
+
}
|
|
33
|
+
const d = t[i], g = e - (c(r) - r[i]);
|
|
34
|
+
return o[i] = L(d.text, g, d.measure), { texts: o, truncated: !0 };
|
|
35
|
+
};
|
|
36
|
+
export {
|
|
37
|
+
A as DEFAULT_MIN_CHARS,
|
|
38
|
+
p as ELLIPSIS,
|
|
39
|
+
P as fitPath,
|
|
40
|
+
L as fitText
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=pathTextFit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathTextFit.js","sources":["../../../src/components/Typography/pathTextFit.ts"],"sourcesContent":["export type MeasureText = (text: string) => number;\n\nexport interface FitSegment {\n text: string;\n minChars: number;\n measure: MeasureText;\n}\n\nexport interface PathFitInput {\n available: number;\n segments: FitSegment[];\n separatorWidth: number;\n}\n\nexport interface PathFit {\n texts: string[];\n truncated: boolean;\n}\n\nexport const ELLIPSIS = '…';\nexport const DEFAULT_MIN_CHARS = 2;\n\n// Canvas and layout widths differ by rounding; a path that exactly fills its box stays whole.\nconst TOLERANCE_PX = 0.25;\n\n// Declared locally: the configured lib predates `Intl.Segmenter`, which every target browser has.\ninterface GraphemeSegmenter {\n segment(text: string): Iterable<{ segment: string }>;\n}\ntype SegmenterConstructor = new (\n locale: undefined,\n options: { granularity: 'grapheme' },\n) => GraphemeSegmenter;\n\nlet segmenter: GraphemeSegmenter | null | undefined;\n\nconst graphemesOf = (text: string): string[] => {\n if (segmenter === undefined) {\n const Segmenter =\n typeof Intl === 'undefined'\n ? undefined\n : (Intl as unknown as { Segmenter?: SegmenterConstructor }).Segmenter;\n segmenter = Segmenter ? new Segmenter(undefined, { granularity: 'grapheme' }) : null;\n }\n return segmenter\n ? Array.from(segmenter.segment(text), (part) => part.segment)\n : Array.from(text);\n};\n\nconst cut = (chars: string[], length: number): string =>\n `${chars.slice(0, length).join('').trimEnd()}${ELLIPSIS}`;\n\nexport const fitText = (text: string, width: number, measure: MeasureText): string => {\n if (measure(text) <= width + TOLERANCE_PX) {\n return text;\n }\n const chars = graphemesOf(text);\n let low = 0;\n let high = chars.length - 1;\n while (low < high) {\n const middle = Math.ceil((low + high) / 2);\n if (measure(cut(chars, middle)) <= width) {\n low = middle;\n } else {\n high = middle - 1;\n }\n }\n return low === 0 ? ELLIPSIS : cut(chars, low);\n};\n\n// `+ 1`: an ellipsis is about as wide as the one character it would replace.\nconst shortestOf = ({ text, minChars }: FitSegment): string => {\n const chars = graphemesOf(text);\n return chars.length > minChars + 1 ? cut(chars, minChars) : text;\n};\n\nexport const fitPath = ({ available, segments, separatorWidth }: PathFitInput): PathFit => {\n const texts = segments.map((segment) => segment.text);\n const widths = segments.map((segment) => segment.measure(segment.text));\n const separators = separatorWidth * Math.max(segments.length - 1, 0);\n const total = (values: number[]) => values.reduce((sum, value) => sum + value, separators);\n\n if (total(widths) <= available + TOLERANCE_PX) {\n return { texts, truncated: false };\n }\n\n const last = segments.length - 1;\n for (let index = 0; index < last; index += 1) {\n const segment = segments[index];\n const shortest = shortestOf(segment);\n const shortestWidth = segment.measure(shortest);\n const others = total(widths) - widths[index];\n if (others + shortestWidth <= available) {\n texts[index] = fitText(segment.text, available - others, segment.measure);\n return { texts, truncated: true };\n }\n texts[index] = shortest;\n widths[index] = shortestWidth;\n }\n\n const lastSegment = segments[last];\n const room = available - (total(widths) - widths[last]);\n texts[last] = fitText(lastSegment.text, room, lastSegment.measure);\n return { texts, truncated: true };\n};\n"],"names":["ELLIPSIS","DEFAULT_MIN_CHARS","segmenter","graphemesOf","text","Segmenter","part","cut","chars","length","fitText","width","measure","low","high","middle","shortestOf","minChars","fitPath","available","segments","separatorWidth","texts","segment","widths","separators","total","values","sum","value","last","index","shortest","shortestWidth","others","lastSegment","room"],"mappings":"AAmBO,MAAMA,IAAW,KACXC,IAAoB;AAcjC,IAAIC;AAEJ,MAAMC,IAAc,CAACC,MAA2B;AAC5C,MAAIF,MAAc,QAAW;AACzB,UAAMG,IACF,OAAO,OAAS,MACV,SACC,KAAyD;AACpE,IAAAH,IAAYG,IAAY,IAAIA,EAAU,QAAW,EAAE,aAAa,WAAA,CAAY,IAAI;AAAA,EACpF;AACA,SAAOH,IACD,MAAM,KAAKA,EAAU,QAAQE,CAAI,GAAG,CAACE,MAASA,EAAK,OAAO,IAC1D,MAAM,KAAKF,CAAI;AACzB,GAEMG,IAAM,CAACC,GAAiBC,MAC1B,GAAGD,EAAM,MAAM,GAAGC,CAAM,EAAE,KAAK,EAAE,EAAE,QAAA,CAAS,KAEnCC,IAAU,CAACN,GAAcO,GAAeC,MAAiC;AAClF,MAAIA,EAAQR,CAAI,KAAKO,IAAQ;AACzB,WAAOP;AAEX,QAAMI,IAAQL,EAAYC,CAAI;AAC9B,MAAIS,IAAM,GACNC,IAAON,EAAM,SAAS;AAC1B,SAAOK,IAAMC,KAAM;AACf,UAAMC,IAAS,KAAK,MAAMF,IAAMC,KAAQ,CAAC;AACzC,IAAIF,EAAQL,EAAIC,GAAOO,CAAM,CAAC,KAAKJ,IAC/BE,IAAME,IAEND,IAAOC,IAAS;AAAA,EAExB;AACA,SAAOF,MAAQ,IAAI,MAAWN,EAAIC,GAAOK,CAAG;AAChD,GAGMG,IAAa,CAAC,EAAE,MAAAZ,GAAM,UAAAa,QAAmC;AAC3D,QAAMT,IAAQL,EAAYC,CAAI;AAC9B,SAAOI,EAAM,SAASS,IAAW,IAAIV,EAAIC,GAAOS,CAAQ,IAAIb;AAChE,GAEac,IAAU,CAAC,EAAE,WAAAC,GAAW,UAAAC,GAAU,gBAAAC,QAA4C;AACvF,QAAMC,IAAQF,EAAS,IAAI,CAACG,MAAYA,EAAQ,IAAI,GAC9CC,IAASJ,EAAS,IAAI,CAACG,MAAYA,EAAQ,QAAQA,EAAQ,IAAI,CAAC,GAChEE,IAAaJ,IAAiB,KAAK,IAAID,EAAS,SAAS,GAAG,CAAC,GAC7DM,IAAQ,CAACC,MAAqBA,EAAO,OAAO,CAACC,GAAKC,MAAUD,IAAMC,GAAOJ,CAAU;AAEzF,MAAIC,EAAMF,CAAM,KAAKL,IAAY;AAC7B,WAAO,EAAE,OAAAG,GAAO,WAAW,GAAA;AAG/B,QAAMQ,IAAOV,EAAS,SAAS;AAC/B,WAASW,IAAQ,GAAGA,IAAQD,GAAMC,KAAS,GAAG;AAC1C,UAAMR,IAAUH,EAASW,CAAK,GACxBC,IAAWhB,EAAWO,CAAO,GAC7BU,IAAgBV,EAAQ,QAAQS,CAAQ,GACxCE,IAASR,EAAMF,CAAM,IAAIA,EAAOO,CAAK;AAC3C,QAAIG,IAASD,KAAiBd;AAC1B,aAAAG,EAAMS,CAAK,IAAIrB,EAAQa,EAAQ,MAAMJ,IAAYe,GAAQX,EAAQ,OAAO,GACjE,EAAE,OAAAD,GAAO,WAAW,GAAA;AAE/B,IAAAA,EAAMS,CAAK,IAAIC,GACfR,EAAOO,CAAK,IAAIE;AAAA,EACpB;AAEA,QAAME,IAAcf,EAASU,CAAI,GAC3BM,IAAOjB,KAAaO,EAAMF,CAAM,IAAIA,EAAOM,CAAI;AACrD,SAAAR,EAAMQ,CAAI,IAAIpB,EAAQyB,EAAY,MAAMC,GAAMD,EAAY,OAAO,GAC1D,EAAE,OAAAb,GAAO,WAAW,GAAA;AAC/B;"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const s = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Set();
|
|
2
|
+
let c = null, i = null, h = !1, a;
|
|
3
|
+
const l = /* @__PURE__ */ new Map(), S = 2e3, F = () => {
|
|
4
|
+
if (a === void 0)
|
|
5
|
+
try {
|
|
6
|
+
a = document.createElement("canvas").getContext("2d");
|
|
7
|
+
} catch {
|
|
8
|
+
a = null;
|
|
9
|
+
}
|
|
10
|
+
return a;
|
|
11
|
+
}, w = "", R = (e) => {
|
|
12
|
+
const t = F();
|
|
13
|
+
if (!t || !e)
|
|
14
|
+
return null;
|
|
15
|
+
const [n, o = "0px"] = e.split(w);
|
|
16
|
+
return (r) => {
|
|
17
|
+
const u = `${e}\0${r}`, g = l.get(u);
|
|
18
|
+
if (g !== void 0)
|
|
19
|
+
return g;
|
|
20
|
+
t.font !== n && (t.font = n), "letterSpacing" in t && t.letterSpacing !== o && (t.letterSpacing = o);
|
|
21
|
+
const m = t.measureText(r).width;
|
|
22
|
+
return l.size >= S && l.clear(), l.set(u, m), m;
|
|
23
|
+
};
|
|
24
|
+
}, z = (e) => {
|
|
25
|
+
const t = getComputedStyle(e), n = t.font || `${t.fontStyle} ${t.fontWeight} ${t.fontSize} ${t.fontFamily}`.trim(), o = t.letterSpacing === "normal" ? "0px" : t.letterSpacing;
|
|
26
|
+
return `${n}${w}${o}`;
|
|
27
|
+
}, $ = () => {
|
|
28
|
+
i = null;
|
|
29
|
+
const e = [...f];
|
|
30
|
+
f.clear();
|
|
31
|
+
for (const t of e) {
|
|
32
|
+
const n = s.get(t);
|
|
33
|
+
n && n.width !== null && n.remeasure(n.width, !0);
|
|
34
|
+
}
|
|
35
|
+
}, y = (e) => {
|
|
36
|
+
f.add(e), i === null && (i = requestAnimationFrame($));
|
|
37
|
+
}, p = () => {
|
|
38
|
+
var e;
|
|
39
|
+
l.clear();
|
|
40
|
+
for (const t of s.keys())
|
|
41
|
+
y(t);
|
|
42
|
+
((e = document.fonts) == null ? void 0 : e.status) === "loaded" && d(!1);
|
|
43
|
+
};
|
|
44
|
+
function d(e) {
|
|
45
|
+
var t, n, o, r;
|
|
46
|
+
e !== h && (h = e, e ? (n = (t = document.fonts) == null ? void 0 : t.addEventListener) == null || n.call(t, "loadingdone", p) : (r = (o = document.fonts) == null ? void 0 : o.removeEventListener) == null || r.call(o, "loadingdone", p));
|
|
47
|
+
}
|
|
48
|
+
const v = () => {
|
|
49
|
+
var e;
|
|
50
|
+
((e = document.fonts) == null ? void 0 : e.status) === "loading" && d(!0);
|
|
51
|
+
}, x = (e) => {
|
|
52
|
+
v();
|
|
53
|
+
for (const { target: t, contentRect: n } of e) {
|
|
54
|
+
const o = s.get(t);
|
|
55
|
+
o && (o.width = n.width, o.remeasure(n.width, !1));
|
|
56
|
+
}
|
|
57
|
+
}, C = (e, t) => typeof ResizeObserver > "u" ? () => {
|
|
58
|
+
} : (v(), c ?? (c = new ResizeObserver(x)), s.set(e, { remeasure: t, width: null }), c.observe(e), () => {
|
|
59
|
+
c == null || c.unobserve(e), s.delete(e), f.delete(e), s.size === 0 && (d(!1), i !== null && (cancelAnimationFrame(i), i = null));
|
|
60
|
+
});
|
|
61
|
+
export {
|
|
62
|
+
z as fontOf,
|
|
63
|
+
R as measurerFor,
|
|
64
|
+
C as observePath,
|
|
65
|
+
y as scheduleRemeasure
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=pathTextMeasure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathTextMeasure.js","sources":["../../../src/components/Typography/pathTextMeasure.ts"],"sourcesContent":["import type { MeasureText } from './pathTextFit';\n\ntype Remeasure = (width: number, refreshFonts: boolean) => void;\n\ninterface Entry {\n remeasure: Remeasure;\n width: number | null;\n}\n\nconst entries = new Map<Element, Entry>();\nconst pending = new Set<Element>();\nlet observer: ResizeObserver | null = null;\nlet frame: number | null = null;\nlet listeningForFonts = false;\nlet context: CanvasRenderingContext2D | null | undefined;\nconst widthCache = new Map<string, number>();\nconst WIDTH_CACHE_LIMIT = 2000;\n\nconst getContext = (): CanvasRenderingContext2D | null => {\n if (context === undefined) {\n try {\n context = document.createElement('canvas').getContext('2d');\n } catch {\n context = null;\n }\n }\n return context;\n};\n\nconst KEY_SEPARATOR = '\\u0001';\n\nexport const measurerFor = (fontKey: string): MeasureText | null => {\n const ctx = getContext();\n if (!ctx || !fontKey) {\n return null;\n }\n const [font, letterSpacing = '0px'] = fontKey.split(KEY_SEPARATOR);\n return (text) => {\n const key = `${fontKey}\\u0000${text}`;\n const cached = widthCache.get(key);\n if (cached !== undefined) {\n return cached;\n }\n if (ctx.font !== font) {\n ctx.font = font;\n }\n // Canvas ignores inherited `tracking-*`; set it, or tracked text measures narrow.\n if ('letterSpacing' in ctx && ctx.letterSpacing !== letterSpacing) {\n ctx.letterSpacing = letterSpacing;\n }\n const width = ctx.measureText(text).width;\n if (widthCache.size >= WIDTH_CACHE_LIMIT) {\n widthCache.clear();\n }\n widthCache.set(key, width);\n return width;\n };\n};\n\nexport const fontOf = (element: Element): string => {\n const style = getComputedStyle(element);\n // `font` can come back empty for a shorthand some longhand cannot express.\n const font =\n style.font ||\n `${style.fontStyle} ${style.fontWeight} ${style.fontSize} ${style.fontFamily}`.trim();\n const spacing = style.letterSpacing === 'normal' ? '0px' : style.letterSpacing;\n return `${font}${KEY_SEPARATOR}${spacing}`;\n};\n\nconst flush = () => {\n frame = null;\n const batch = [...pending];\n pending.clear();\n for (const element of batch) {\n const entry = entries.get(element);\n if (entry && entry.width !== null) {\n entry.remeasure(entry.width, true);\n }\n }\n};\n\nexport const scheduleRemeasure = (element: Element): void => {\n pending.add(element);\n if (frame === null) {\n frame = requestAnimationFrame(flush);\n }\n};\n\n// A webfont landing changes widths without resizing boxes. Listened for only while a load is in\n// flight, so nothing global is attached at rest.\nconst onFontsLoaded = () => {\n widthCache.clear();\n for (const element of entries.keys()) {\n scheduleRemeasure(element);\n }\n if (document.fonts?.status === 'loaded') {\n listenForFonts(false);\n }\n};\n\nfunction listenForFonts(on: boolean): void {\n if (on === listeningForFonts) {\n return;\n }\n listeningForFonts = on;\n if (on) {\n document.fonts?.addEventListener?.('loadingdone', onFontsLoaded);\n } else {\n document.fonts?.removeEventListener?.('loadingdone', onFontsLoaded);\n }\n}\n\nconst listenWhileFontsLoad = () => {\n if (document.fonts?.status === 'loading') {\n listenForFonts(true);\n }\n};\n\n// One observer for every path: a mount batch is one callback, not one per instance.\nconst onResize: ResizeObserverCallback = (resized) => {\n listenWhileFontsLoad();\n for (const { target, contentRect } of resized) {\n const entry = entries.get(target);\n if (entry) {\n entry.width = contentRect.width;\n entry.remeasure(contentRect.width, false);\n }\n }\n};\n\nexport const observePath = (element: Element, remeasure: Remeasure): (() => void) => {\n if (typeof ResizeObserver === 'undefined') {\n return () => undefined;\n }\n listenWhileFontsLoad();\n observer ??= new ResizeObserver(onResize);\n entries.set(element, { remeasure, width: null });\n observer.observe(element);\n return () => {\n observer?.unobserve(element);\n entries.delete(element);\n pending.delete(element);\n if (entries.size === 0) {\n listenForFonts(false);\n if (frame !== null) {\n cancelAnimationFrame(frame);\n frame = null;\n }\n }\n };\n};\n"],"names":["entries","pending","observer","frame","listeningForFonts","context","widthCache","WIDTH_CACHE_LIMIT","getContext","KEY_SEPARATOR","measurerFor","fontKey","ctx","font","letterSpacing","text","key","cached","width","fontOf","element","style","spacing","flush","batch","entry","scheduleRemeasure","onFontsLoaded","_a","listenForFonts","on","_b","_c","_d","listenWhileFontsLoad","onResize","resized","target","contentRect","observePath","remeasure"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -373,6 +373,11 @@ declare interface ButtonProps extends default_2.ButtonHTMLAttributes<HTMLButtonE
|
|
|
373
373
|
disabled?: boolean;
|
|
374
374
|
icon?: default_2.ReactNode;
|
|
375
375
|
iconPosition?: 'start' | 'end';
|
|
376
|
+
/** Before the label at its own size, never squeezed (an avatar); pairs with an end `icon`. */
|
|
377
|
+
leading?: default_2.ReactNode;
|
|
378
|
+
/** `start` aligns the label to the leading edge and pins an end `icon` to the far edge. */
|
|
379
|
+
contentAlign?: 'center' | 'start';
|
|
380
|
+
/** Fills the container's width. */
|
|
376
381
|
flexGrow?: boolean;
|
|
377
382
|
fill?: boolean;
|
|
378
383
|
tooltip?: string;
|
|
@@ -3672,6 +3677,8 @@ export declare const NavItem: default_2.ForwardRefExoticComponent<NavItemProps &
|
|
|
3672
3677
|
export declare interface NavItemAsChildProps extends NavItemBaseProps {
|
|
3673
3678
|
asChild: true;
|
|
3674
3679
|
children: default_2.ReactElement;
|
|
3680
|
+
disabled?: never;
|
|
3681
|
+
disabledReason?: never;
|
|
3675
3682
|
href?: never;
|
|
3676
3683
|
target?: never;
|
|
3677
3684
|
rel?: never;
|
|
@@ -3699,6 +3706,10 @@ declare interface NavItemBaseProps extends NativeProps {
|
|
|
3699
3706
|
|
|
3700
3707
|
export declare interface NavItemLinkProps extends NavItemBaseProps {
|
|
3701
3708
|
asChild?: false;
|
|
3709
|
+
/** Leaves the row focusable but inert: `aria-disabled`, no hover, no click or navigation. */
|
|
3710
|
+
disabled?: boolean;
|
|
3711
|
+
/** Why a `disabled` row is unavailable: its tooltip and its accessible description. */
|
|
3712
|
+
disabledReason?: string;
|
|
3702
3713
|
href?: string;
|
|
3703
3714
|
target?: string;
|
|
3704
3715
|
rel?: string;
|
|
@@ -3855,6 +3866,31 @@ export declare interface PartialMalachiteTheme {
|
|
|
3855
3866
|
};
|
|
3856
3867
|
}
|
|
3857
3868
|
|
|
3869
|
+
export declare interface PathTextProps {
|
|
3870
|
+
/** Root first, leaf last; segments give way in that order, so the leaf stays whole longest. */
|
|
3871
|
+
segments: PathTextSegment[];
|
|
3872
|
+
/** Drawn between segments, never cut. Defaults to `' / '`. */
|
|
3873
|
+
separator?: string;
|
|
3874
|
+
/** Inherits the surrounding size when unset. */
|
|
3875
|
+
size?: FontSize;
|
|
3876
|
+
/** Shown when anything is cut. Defaults to the whole path; pass a node to wrap it. */
|
|
3877
|
+
tooltip?: default_2.ReactNode;
|
|
3878
|
+
tooltipPlacement?: 'top' | 'bottom' | 'left' | 'right';
|
|
3879
|
+
/** Holds the tooltip back, e.g. while the menu this path labels is open. */
|
|
3880
|
+
tooltipSuppressed?: boolean;
|
|
3881
|
+
className?: string;
|
|
3882
|
+
}
|
|
3883
|
+
|
|
3884
|
+
export declare interface PathTextSegment {
|
|
3885
|
+
text: string;
|
|
3886
|
+
tone?: PathTextTone;
|
|
3887
|
+
/** Kept when cut, before the next segment gives way. Defaults to 2; ignored on the last. */
|
|
3888
|
+
minChars?: number;
|
|
3889
|
+
}
|
|
3890
|
+
|
|
3891
|
+
/** `default` takes the surrounding colour and weight; `secondary` recedes, as an ancestor should. */
|
|
3892
|
+
export declare type PathTextTone = 'default' | 'secondary';
|
|
3893
|
+
|
|
3858
3894
|
declare type PhraseLabel = string | {
|
|
3859
3895
|
prefix: string;
|
|
3860
3896
|
suffix?: string;
|
|
@@ -3942,6 +3978,8 @@ declare interface PopoverBaseProps {
|
|
|
3942
3978
|
offset?: FloatingOffset;
|
|
3943
3979
|
elevation?: 'default' | 'raised';
|
|
3944
3980
|
initialFocusRef?: default_2.RefObject<HTMLElement | null>;
|
|
3981
|
+
/** A click panel also opens, focus inside, on the arrow key its placement points at. */
|
|
3982
|
+
openOnArrowKey?: boolean;
|
|
3945
3983
|
role?: 'dialog' | 'menu' | 'listbox';
|
|
3946
3984
|
className?: string;
|
|
3947
3985
|
}
|
|
@@ -5395,6 +5433,7 @@ export declare const Typography: {
|
|
|
5395
5433
|
LinkText: FC<LinkProps_2>;
|
|
5396
5434
|
MarkdownBlock: NamedExoticComponent<MarkdownProps>;
|
|
5397
5435
|
PageTitle: FC<PageTitleProps>;
|
|
5436
|
+
PathText: FC<PathTextProps>;
|
|
5398
5437
|
SecondaryText: FC<SecondaryTextProps>;
|
|
5399
5438
|
SectionTitle: FC<SectionTitleProps>;
|
|
5400
5439
|
StatisticLabel: FC<StatisticLabelProps>;
|