@inkra/react 0.3.0 → 0.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/README.md +113 -3
- package/dist/Button.js +3 -2
- package/dist/PencilIcon.d.ts +10 -0
- package/dist/PencilIcon.js +83 -39
- package/dist/PencilLine.js +9 -1
- package/dist/PencilText.js +15 -9
- package/dist/accordion/Accordion.js +65 -5
- package/dist/alert-dialog/index.js +14 -4
- package/dist/audio-player/index.d.ts +2 -0
- package/dist/audio-player/index.js +131 -34
- package/dist/breadcrumb/index.js +4 -1
- package/dist/calendar/index.d.ts +4 -1
- package/dist/calendar/index.js +37 -12
- package/dist/calendar/locales.d.ts +7 -0
- package/dist/calendar/locales.js +2 -0
- package/dist/carousel/index.js +20 -10
- package/dist/choice-grid/index.d.ts +6 -1
- package/dist/choice-grid/index.js +63 -33
- package/dist/color-picker/GradientEditor.d.ts +40 -0
- package/dist/color-picker/GradientEditor.js +64 -0
- package/dist/color-picker/gradient.d.ts +25 -0
- package/dist/color-picker/gradient.js +60 -0
- package/dist/color-picker/index.d.ts +27 -7
- package/dist/color-picker/index.js +144 -40
- package/dist/color-swatch/index.d.ts +10 -0
- package/dist/color-swatch/index.js +9 -0
- package/dist/command/index.js +27 -4
- package/dist/content/index.d.ts +5 -0
- package/dist/content/index.js +15 -3
- package/dist/context-menu/index.js +1 -1
- package/dist/data-table/index.d.ts +7 -1
- package/dist/data-table/index.js +67 -16
- package/dist/data-table/model.d.ts +2 -0
- package/dist/data-table/model.js +7 -0
- package/dist/date-picker/index.d.ts +2 -0
- package/dist/date-picker/index.js +20 -21
- package/dist/day-agenda/index.d.ts +6 -1
- package/dist/day-agenda/index.js +49 -21
- package/dist/day-agenda/layout.js +65 -9
- package/dist/display/ProgressRing.js +7 -3
- package/dist/display/index.d.ts +4 -1
- package/dist/display/index.js +3 -2
- package/dist/dockable-panel/index.js +15 -13
- package/dist/drawer/index.js +11 -5
- package/dist/editable/index.d.ts +24 -2
- package/dist/editable/index.js +148 -40
- package/dist/empty/illustrations.d.ts +8 -0
- package/dist/empty/illustrations.js +78 -0
- package/dist/empty/index.d.ts +6 -1
- package/dist/empty/index.js +11 -3
- package/dist/flip/index.js +28 -8
- package/dist/form/Field.js +11 -10
- package/dist/form/Input.js +4 -1
- package/dist/form/Textarea.d.ts +3 -1
- package/dist/form/Textarea.js +9 -5
- package/dist/heatmap/index.js +4 -1
- package/dist/hotkey/index.d.ts +1 -0
- package/dist/hotkey/index.js +9 -4
- package/dist/hover-card/index.js +1 -1
- package/dist/i18n/catalog.d.ts +5 -0
- package/dist/i18n/catalog.js +289 -0
- package/dist/i18n/index.d.ts +23 -0
- package/dist/i18n/index.js +50 -0
- package/dist/image-cropper/index.js +21 -17
- package/dist/image-viewer/VideoResource.d.ts +21 -0
- package/dist/image-viewer/VideoResource.js +196 -0
- package/dist/image-viewer/index.d.ts +14 -0
- package/dist/image-viewer/index.js +141 -86
- package/dist/image-viewer/lucideGeometry.d.ts +3 -0
- package/dist/image-viewer/lucideGeometry.js +19 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/input-number/index.js +13 -5
- package/dist/internal/cache.d.ts +4 -0
- package/dist/internal/cache.js +18 -1
- package/dist/internal/iconGeometry.d.ts +2 -0
- package/dist/internal/iconGeometry.js +32 -0
- package/dist/internal/renderTokens.d.ts +4 -0
- package/dist/internal/renderTokens.js +4 -0
- package/dist/internal/stroke.d.ts +7 -0
- package/dist/internal/stroke.js +63 -7
- package/dist/internal/surfaceBudget.d.ts +20 -0
- package/dist/internal/surfaceBudget.js +69 -0
- package/dist/internal/surfaceRenderer.js +87 -28
- package/dist/internal/surfaceVisibility.d.ts +3 -0
- package/dist/internal/surfaceVisibility.js +60 -0
- package/dist/internal/textRenderer.d.ts +3 -0
- package/dist/internal/textRenderer.js +13 -5
- package/dist/internal/usePencilSurface.js +17 -1
- package/dist/internal/wash.js +4 -3
- package/dist/journey-map/index.d.ts +1 -1
- package/dist/journey-map/index.js +6 -3
- package/dist/journey-map/terrain.js +10 -5
- package/dist/keypad/index.js +4 -1
- package/dist/layout/index.js +1 -1
- package/dist/log/index.js +42 -33
- package/dist/markdown/CodeBlock.d.ts +19 -0
- package/dist/markdown/CodeBlock.js +86 -0
- package/dist/markdown/Deletion.d.ts +2 -0
- package/dist/markdown/Deletion.js +69 -0
- package/dist/markdown/icons.d.ts +14 -0
- package/dist/markdown/icons.js +16 -0
- package/dist/markdown/index.d.ts +17 -0
- package/dist/markdown/index.js +177 -0
- package/dist/node-graph/index.d.ts +3 -1
- package/dist/node-graph/index.js +63 -28
- package/dist/number-ticker/index.js +4 -1
- package/dist/number-ticker/precision.js +9 -2
- package/dist/overflow-list/index.js +9 -6
- package/dist/overlay/Overlay.js +8 -3
- package/dist/overlay/Popover.js +3 -3
- package/dist/overlay/themeBridge.js +14 -2
- package/dist/pagination/index.d.ts +10 -1
- package/dist/pagination/index.js +13 -9
- package/dist/pan-zoom/index.d.ts +2 -0
- package/dist/pan-zoom/index.js +12 -8
- package/dist/pencil.d.ts +1 -0
- package/dist/pencil.js +4 -4
- package/dist/radar/index.d.ts +2 -0
- package/dist/radar/index.js +44 -21
- package/dist/range-slider/index.js +4 -3
- package/dist/rating/index.d.ts +4 -0
- package/dist/rating/index.js +131 -24
- package/dist/resizable/index.d.ts +1 -1
- package/dist/resizable/index.js +5 -2
- package/dist/scroll-area/index.d.ts +1 -1
- package/dist/scroll-area/index.js +5 -2
- package/dist/select/MultipleSelect.js +5 -4
- package/dist/select/SearchableSelect.js +64 -7
- package/dist/select/Select.d.ts +1 -0
- package/dist/select/Select.js +6 -2
- package/dist/select/StepperSelect.d.ts +29 -0
- package/dist/select/StepperSelect.js +122 -0
- package/dist/select/index.d.ts +2 -0
- package/dist/select/index.js +1 -0
- package/dist/select/stepperModel.d.ts +7 -0
- package/dist/select/stepperModel.js +29 -0
- package/dist/selection/Checkbox.js +4 -3
- package/dist/selection/RadioGroup.js +29 -13
- package/dist/selection/Switch.js +4 -3
- package/dist/selection/useNativeChecked.d.ts +2 -1
- package/dist/selection/useNativeChecked.js +26 -8
- package/dist/slider/index.js +50 -6
- package/dist/sortable/index.js +17 -11
- package/dist/sparkline/index.js +21 -6
- package/dist/sparkline/model.js +11 -4
- package/dist/steps/index.js +4 -1
- package/dist/styles/accordion.css +228 -0
- package/dist/styles/alert-dialog.css +139 -0
- package/dist/styles/audio-player.css +22 -0
- package/dist/styles/base.css +638 -0
- package/dist/styles/breadcrumb.css +7 -0
- package/dist/styles/calendar.css +62 -0
- package/dist/styles/carousel.css +173 -0
- package/dist/styles/choice-grid.css +226 -0
- package/dist/styles/color-picker.css +281 -0
- package/dist/styles/color-swatch.css +47 -0
- package/dist/styles/command.css +52 -0
- package/dist/styles/content.css +79 -0
- package/dist/styles/context-menu.css +35 -0
- package/dist/styles/data-table.css +31 -0
- package/dist/styles/date-picker.css +107 -0
- package/dist/styles/day-agenda.css +30 -0
- package/dist/styles/display.css +304 -0
- package/dist/styles/dockable-panel.css +110 -0
- package/dist/styles/drawer.css +133 -0
- package/dist/styles/dropdown-menu.css +68 -0
- package/dist/styles/editable.css +145 -0
- package/dist/styles/empty.css +108 -0
- package/dist/styles/flip.css +101 -0
- package/dist/styles/form.css +634 -0
- package/dist/styles/heatmap.css +256 -0
- package/dist/styles/hotkey.css +189 -0
- package/dist/styles/hover-card.css +27 -0
- package/dist/styles/image-cropper.css +205 -0
- package/dist/styles/image-viewer.css +422 -0
- package/dist/styles/input-number.css +21 -0
- package/dist/styles/journey-map.css +19 -0
- package/dist/styles/keypad.css +92 -0
- package/dist/styles/layout.css +72 -0
- package/dist/styles/leaflet.css +661 -0
- package/dist/styles/log.css +203 -0
- package/dist/styles/markdown.css +379 -0
- package/dist/styles/node-graph.css +142 -0
- package/dist/styles/number-ticker.css +83 -0
- package/dist/styles/overflow-list.css +51 -0
- package/dist/styles/overlay.css +284 -0
- package/dist/styles/pagination.css +21 -0
- package/dist/styles/pan-zoom.css +136 -0
- package/dist/styles/radar.css +1 -0
- package/dist/styles/rating.css +121 -0
- package/dist/styles/resizable.css +108 -0
- package/dist/styles/scroll-area.css +122 -0
- package/dist/styles/select.css +554 -0
- package/dist/styles/selection.css +264 -0
- package/dist/styles/slider.css +145 -0
- package/dist/styles/slot.css +109 -0
- package/dist/styles/sortable.css +159 -0
- package/dist/styles/sparkline.css +24 -0
- package/dist/styles/steps.css +27 -0
- package/dist/styles/tabs.css +79 -0
- package/dist/styles/tag-input.css +213 -0
- package/dist/styles/time-picker.css +66 -0
- package/dist/styles/timeline.css +24 -0
- package/dist/styles/toast.css +160 -0
- package/dist/styles/toggle-group.css +107 -0
- package/dist/styles/tooltip.css +78 -0
- package/dist/styles/transfer.css +148 -0
- package/dist/styles/tree-select.css +131 -0
- package/dist/styles/tree.css +59 -0
- package/dist/styles/typewriter.css +62 -0
- package/dist/styles/upload.css +60 -0
- package/dist/styles/virtual-list.css +112 -0
- package/dist/styles.css +2091 -421
- package/dist/tabs/index.d.ts +9 -0
- package/dist/tabs/index.js +69 -16
- package/dist/tabs/useOverflow.d.ts +20 -0
- package/dist/tabs/useOverflow.js +145 -0
- package/dist/tag-input/index.d.ts +7 -2
- package/dist/tag-input/index.js +81 -42
- package/dist/theme/index.d.ts +11 -0
- package/dist/theme/index.js +23 -0
- package/dist/time-picker/index.js +45 -27
- package/dist/timeline/index.js +4 -1
- package/dist/toast/index.d.ts +19 -11
- package/dist/toast/index.js +51 -8
- package/dist/toast/manager.d.ts +42 -0
- package/dist/toast/manager.js +85 -0
- package/dist/toast/useToastNavigation.d.ts +3 -0
- package/dist/toast/useToastNavigation.js +75 -0
- package/dist/tokens.css +4 -0
- package/dist/tooltip/Tooltip.js +3 -3
- package/dist/transfer/index.d.ts +5 -0
- package/dist/transfer/index.js +120 -53
- package/dist/transfer/model.d.ts +4 -0
- package/dist/transfer/model.js +37 -11
- package/dist/tree/index.d.ts +5 -1
- package/dist/tree/index.js +11 -6
- package/dist/tree-select/index.js +70 -31
- package/dist/tree-select/model.d.ts +11 -5
- package/dist/tree-select/model.js +111 -83
- package/dist/typewriter/index.js +10 -10
- package/dist/upload/index.js +50 -33
- package/dist/virtual-list/index.js +11 -6
- package/package.json +423 -3
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale } from '../i18n/index.js';
|
|
3
|
+
import ReactMarkdown from 'react-markdown';
|
|
4
|
+
import remarkGfm from 'remark-gfm';
|
|
5
|
+
import { Children, cloneElement, createContext, forwardRef, isValidElement, useCallback, useContext, useMemo, } from 'react';
|
|
6
|
+
import { PencilIcon } from '../PencilIcon.js';
|
|
7
|
+
import { PencilLine } from '../PencilLine.js';
|
|
8
|
+
import { PencilSurface } from '../PencilSurface.js';
|
|
9
|
+
import { PencilText } from '../PencilText.js';
|
|
10
|
+
import { Table } from '../content/index.js';
|
|
11
|
+
import { Checkbox } from '../selection/Checkbox.js';
|
|
12
|
+
import { MarkdownCodeBlock } from './CodeBlock.js';
|
|
13
|
+
import { Deletion } from './Deletion.js';
|
|
14
|
+
const listContext = createContext('unordered');
|
|
15
|
+
const codeContext = createContext('inline');
|
|
16
|
+
const bulletPaths = [{ d: 'M12 4.5a7.5 7.5 0 1 0 0 15a7.5 7.5 0 1 0 0-15' }];
|
|
17
|
+
const markdownPlugins = [remarkGfm];
|
|
18
|
+
function classes(...values) {
|
|
19
|
+
return values.filter(Boolean).join(' ');
|
|
20
|
+
}
|
|
21
|
+
function pencilChildren(children, seed) {
|
|
22
|
+
return Children.map(children, (child, index) => {
|
|
23
|
+
if (typeof child !== 'string' && typeof child !== 'number')
|
|
24
|
+
return child;
|
|
25
|
+
const value = String(child);
|
|
26
|
+
if (!/\S/.test(value))
|
|
27
|
+
return value;
|
|
28
|
+
const [, leading, text, trailing] = /^(\s*)([\s\S]*?)(\s*)$/.exec(value);
|
|
29
|
+
return _jsxs(_Fragment, { children: [leading, _jsx(PencilText, { seed: `${seed}-${index}`, children: text }), trailing] });
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function taskContent(children) {
|
|
33
|
+
let checkbox;
|
|
34
|
+
const extract = (content) => Children.map(content, child => {
|
|
35
|
+
if (!isValidElement(child))
|
|
36
|
+
return child;
|
|
37
|
+
if (!checkbox && child.props.node?.tagName === 'input' && child.props.type === 'checkbox') {
|
|
38
|
+
checkbox = child;
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
if (!checkbox && child.props.node?.tagName === 'p')
|
|
42
|
+
return cloneElement(child, {}, extract(child.props.children));
|
|
43
|
+
return child;
|
|
44
|
+
});
|
|
45
|
+
const content = extract(children);
|
|
46
|
+
return { checkbox, content };
|
|
47
|
+
}
|
|
48
|
+
function textChildren(children) {
|
|
49
|
+
let value = '';
|
|
50
|
+
Children.forEach(children, child => {
|
|
51
|
+
if (typeof child === 'string' || typeof child === 'number')
|
|
52
|
+
value += String(child);
|
|
53
|
+
});
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
function codeBlockContent(children) {
|
|
57
|
+
if (isValidElement(children)) {
|
|
58
|
+
return {
|
|
59
|
+
className: children.props.className,
|
|
60
|
+
code: textChildren(children.props.children),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return { className: undefined, code: textChildren(children) };
|
|
64
|
+
}
|
|
65
|
+
function safeUrl(url, kind) {
|
|
66
|
+
const trimmed = url.trim();
|
|
67
|
+
if (!trimmed)
|
|
68
|
+
return null;
|
|
69
|
+
if (/^(?:[#/?]|\.\.?\/)/.test(trimmed))
|
|
70
|
+
return trimmed;
|
|
71
|
+
const scheme = /^([a-z][a-z\d+.-]*):/i.exec(trimmed.replace(/[\u0000-\u001f\u007f]/g, ''))?.[1]?.toLowerCase();
|
|
72
|
+
if (!scheme)
|
|
73
|
+
return trimmed;
|
|
74
|
+
if (scheme === 'http' || scheme === 'https')
|
|
75
|
+
return trimmed;
|
|
76
|
+
if (kind === 'link' && (scheme === 'mailto' || scheme === 'tel'))
|
|
77
|
+
return trimmed;
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
function headingTag(level, offset) {
|
|
81
|
+
return `h${Math.max(1, Math.min(6, level + offset))}`;
|
|
82
|
+
}
|
|
83
|
+
function MarkdownTaskCheckbox({ checked = false, className, label, ...props }) {
|
|
84
|
+
const selected = Boolean(checked);
|
|
85
|
+
return _jsx(Checkbox, { ...props, "aria-label": props['aria-label'] ?? label, checked: selected, className: classes('inkra-markdown__task-checkbox', className), disabled: true, label: _jsx("span", { "aria-hidden": "true" }), seed: `markdown-task-${selected ? 'checked' : 'unchecked'}` });
|
|
86
|
+
}
|
|
87
|
+
function createMarkdownComponents(headingLevelOffset, labels) {
|
|
88
|
+
const heading = (level) => {
|
|
89
|
+
const Heading = headingTag(level, headingLevelOffset);
|
|
90
|
+
return ({ node: _node, children, className, ...props }) => (_jsx(Heading, { ...props, className: classes('inkra-markdown__heading', className), children: pencilChildren(children, `markdown-heading-${level}`) }));
|
|
91
|
+
};
|
|
92
|
+
return {
|
|
93
|
+
h1: heading(1),
|
|
94
|
+
h2: heading(2),
|
|
95
|
+
h3: heading(3),
|
|
96
|
+
h4: heading(4),
|
|
97
|
+
h5: heading(5),
|
|
98
|
+
h6: heading(6),
|
|
99
|
+
p: ({ node: _node, children, className, ...props }) => (_jsx("p", { ...props, className: classes('inkra-markdown__paragraph', className), children: pencilChildren(children, 'markdown-paragraph') })),
|
|
100
|
+
strong: ({ node: _node, children, ...props }) => _jsx("strong", { ...props, children: pencilChildren(children, 'markdown-strong') }),
|
|
101
|
+
em: ({ node: _node, children, ...props }) => _jsx("em", { ...props, children: pencilChildren(children, 'markdown-emphasis') }),
|
|
102
|
+
del: ({ node: _node, children, ...props }) => _jsx(Deletion, { ...props, children: pencilChildren(children, 'markdown-deleted') }),
|
|
103
|
+
a: ({ node: _node, children, className, href, ...props }) => href ? (_jsxs("a", { ...props, className: classes('inkra-markdown__link', className), href: href, children: [_jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-markdown__link-focus", radius: 3, seed: `markdown-link-focus-${href}`, variant: "outline" }), _jsx("span", { children: pencilChildren(children, 'markdown-link') }), _jsx(PencilLine, { className: "inkra-markdown__link-line", seed: `markdown-link-${href}` })] })) : _jsx("span", { className: classes('inkra-markdown__link-text', className), children: pencilChildren(children, 'markdown-link-text') }),
|
|
104
|
+
blockquote: ({ node: _node, children, className, ...props }) => (_jsxs("blockquote", { ...props, className: classes('inkra-markdown__quote', className), children: [_jsx(PencilLine, { className: "inkra-markdown__quote-line", orientation: "vertical", seed: "markdown-quote" }), _jsx("div", { children: children })] })),
|
|
105
|
+
hr: ({ node: _node, className, ...props }) => (_jsx("div", { ...props, className: classes('inkra-markdown__divider', className), role: "separator", children: _jsx(PencilLine, { seed: "markdown-divider" }) })),
|
|
106
|
+
pre: ({ node: _node, children, ...props }) => {
|
|
107
|
+
const block = codeBlockContent(children);
|
|
108
|
+
return _jsx(codeContext.Provider, { value: "block", children: _jsx(MarkdownCodeBlock, { ...props, "aria-label": labels.code, labels: labels, code: block.code, codeClassName: block.className }) });
|
|
109
|
+
},
|
|
110
|
+
code: ({ node: _node, children, className, ...props }) => {
|
|
111
|
+
const kind = useContext(codeContext);
|
|
112
|
+
const value = textChildren(children);
|
|
113
|
+
return _jsx("code", { ...props, className: classes('inkra-markdown__code', className), "data-inline": kind === 'inline' || undefined, children: kind === 'inline'
|
|
114
|
+
? _jsxs(_Fragment, { children: [_jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-markdown__code-wash", radius: 3, seed: `markdown-inline-code-wash-${value}`, variant: "wash" }), _jsx(PencilText, { className: "inkra-markdown__code-text", seed: `markdown-inline-code-${value}`, children: value })] })
|
|
115
|
+
: children });
|
|
116
|
+
},
|
|
117
|
+
ul: ({ node: _node, children, className, ...props }) => (_jsx(listContext.Provider, { value: "unordered", children: _jsx("ul", { ...props, className: classes('inkra-markdown__list', 'inkra-markdown__list--unordered', className), children: children }) })),
|
|
118
|
+
ol: ({ node: _node, children, className, start, style, ...props }) => {
|
|
119
|
+
const first = typeof start === 'number' && Number.isFinite(start) ? Math.trunc(start) : 1;
|
|
120
|
+
let itemIndex = 0;
|
|
121
|
+
const numberedChildren = Children.map(children, child => {
|
|
122
|
+
if (!isValidElement(child))
|
|
123
|
+
return child;
|
|
124
|
+
const marker = first + itemIndex;
|
|
125
|
+
itemIndex += 1;
|
|
126
|
+
return cloneElement(child, { 'data-inkra-ordered-index': marker });
|
|
127
|
+
});
|
|
128
|
+
const last = first + Math.max(0, itemIndex - 1);
|
|
129
|
+
const markerCharacters = Math.max(`${first}.`.length, `${last}.`.length);
|
|
130
|
+
const listStyle = {
|
|
131
|
+
...style,
|
|
132
|
+
'--inkra-markdown-ordered-marker-width': `max(1.75rem, ${markerCharacters}ch)`,
|
|
133
|
+
};
|
|
134
|
+
return _jsx(listContext.Provider, { value: "ordered", children: _jsx("ol", { ...props, className: classes('inkra-markdown__list', 'inkra-markdown__list--ordered', className), start: first, style: listStyle, children: numberedChildren }) });
|
|
135
|
+
},
|
|
136
|
+
li: ({ node: _node, children, className, 'data-inkra-ordered-index': orderedIndex, ...props }) => {
|
|
137
|
+
const kind = useContext(listContext);
|
|
138
|
+
const task = className?.split(/\s+/).includes('task-list-item');
|
|
139
|
+
const extracted = task ? taskContent(children) : undefined;
|
|
140
|
+
return _jsxs("li", { ...props, className: classes('inkra-markdown__list-item', className), "data-inkra-list-kind": kind, children: [kind === 'unordered' && !task && _jsx(PencilIcon, { className: "inkra-markdown__bullet", paths: bulletPaths, size: 12, sourceSize: 24, strokeWidth: 1.2, intensity: 0.78 }), kind === 'ordered' && orderedIndex != null && _jsx(PencilText, { "aria-hidden": "true", className: "inkra-markdown__ordered-marker", seed: `markdown-order-${orderedIndex}`, children: `${orderedIndex}.` }), _jsx("div", { className: "inkra-markdown__list-content", children: extracted?.checkbox
|
|
141
|
+
? _jsxs("div", { className: "inkra-markdown__task-row", children: [extracted.checkbox, _jsx("div", { className: "inkra-markdown__task-content", children: pencilChildren(extracted.content, 'markdown-list-item') })] })
|
|
142
|
+
: pencilChildren(children, 'markdown-list-item') })] });
|
|
143
|
+
},
|
|
144
|
+
input: ({ node: _node, checked, type, ...props }) => type === 'checkbox'
|
|
145
|
+
? _jsx(MarkdownTaskCheckbox, { ...props, checked: checked, label: checked ? labels.taskChecked : labels.taskUnchecked })
|
|
146
|
+
: _jsx("input", { ...props, checked: checked, type: type }),
|
|
147
|
+
table: ({ node: _node, children, className, ...props }) => (_jsxs("div", { className: "inkra-markdown__table-frame", children: [_jsx(Table.Container, { "aria-label": labels.table, className: "inkra-markdown__table", role: "region", children: _jsx(Table.Root, { ...props, className: className, children: children }) }), _jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-markdown__table-focus", radius: 6, seed: "markdown-table-focus", variant: "outline" })] })),
|
|
148
|
+
thead: ({ node: _node, ...props }) => _jsx(Table.Header, { ...props }),
|
|
149
|
+
tbody: ({ node: _node, ...props }) => _jsx(Table.Body, { ...props }),
|
|
150
|
+
tr: ({ node: _node, ...props }) => _jsx(Table.Row, { ...props }),
|
|
151
|
+
th: ({ node: _node, children, align, ...props }) => _jsx(Table.Head, { ...props, align: align, children: pencilChildren(children, 'markdown-table-heading') }),
|
|
152
|
+
td: ({ node: _node, children, align, ...props }) => _jsx(Table.Cell, { ...props, align: align, verticalAlign: "top", children: pencilChildren(children, 'markdown-table-cell') }),
|
|
153
|
+
img: ({ node: _node, className, alt = '', ...props }) => props.src ? (_jsx(PencilSurface, { as: "span", className: "inkra-markdown__image-frame", radius: 6, seed: `markdown-image-${props.src ?? ''}`, variant: "outline", children: _jsx("img", { ...props, alt: alt, className: classes('inkra-markdown__image', className), decoding: "async", loading: "lazy" }) })) : _jsx("span", { className: classes('inkra-markdown__image-alt', className), children: pencilChildren(alt, 'markdown-image-alt') }),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
export const Markdown = forwardRef(function Markdown({ children, className, components, headingLevelOffset = 0, labels, transformUrl, ...props }, ref) {
|
|
157
|
+
const { t } = useInkraLocale();
|
|
158
|
+
const offset = Number.isFinite(headingLevelOffset) ? Math.trunc(headingLevelOffset) : 0;
|
|
159
|
+
const resolvedLabels = useMemo(() => ({
|
|
160
|
+
code: labels?.code ?? t('markdown.code'),
|
|
161
|
+
plainText: labels?.plainText ?? t('markdown.plain'),
|
|
162
|
+
copy: labels?.copy ?? t('markdown.copy'),
|
|
163
|
+
copied: labels?.copied ?? t('markdown.copied'),
|
|
164
|
+
copyFailed: labels?.copyFailed ?? t('markdown.copyFailed'),
|
|
165
|
+
table: labels?.table ?? t('markdown.table'),
|
|
166
|
+
taskChecked: labels?.taskChecked ?? t('markdown.checked'),
|
|
167
|
+
taskUnchecked: labels?.taskUnchecked ?? t('markdown.unchecked'),
|
|
168
|
+
}), [t, labels?.code, labels?.plainText, labels?.copy, labels?.copied, labels?.copyFailed, labels?.table, labels?.taskChecked, labels?.taskUnchecked]);
|
|
169
|
+
const builtIns = useMemo(() => createMarkdownComponents(offset, resolvedLabels), [offset, resolvedLabels]);
|
|
170
|
+
const resolvedComponents = useMemo(() => ({ ...builtIns, ...components }), [builtIns, components]);
|
|
171
|
+
const urlTransform = useCallback((url, key) => {
|
|
172
|
+
const kind = key === 'src' ? 'image' : 'link';
|
|
173
|
+
const transformed = transformUrl ? transformUrl(url, kind) : url;
|
|
174
|
+
return transformed == null ? null : safeUrl(transformed, kind);
|
|
175
|
+
}, [transformUrl]);
|
|
176
|
+
return _jsx("div", { ...props, ref: ref, className: classes('inkra-markdown', className), children: _jsx(ReactMarkdown, { components: resolvedComponents, remarkPlugins: markdownPlugins, skipHtml: true, urlTransform: urlTransform, children: children }) });
|
|
177
|
+
});
|
|
@@ -50,7 +50,9 @@ export interface NodeGraphControlLabels {
|
|
|
50
50
|
fitView: string;
|
|
51
51
|
}
|
|
52
52
|
export interface NodeGraphRootProps<NodeType extends NodeGraphNode = NodeGraphNode, EdgeType extends NodeGraphEdge = NodeGraphEdge> extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'onError'> {
|
|
53
|
+
/** Immutable snapshots: replace the array and each changed node (including changed nested data). */
|
|
53
54
|
nodes: NodeType[];
|
|
55
|
+
/** Immutable snapshots: replace the array and each changed edge (including changed nested data). */
|
|
54
56
|
edges: EdgeType[];
|
|
55
57
|
onNodesChange?: (changes: NodeGraphNodeChange<NodeType>[]) => void;
|
|
56
58
|
onEdgesChange?: (changes: NodeGraphEdgeChange<EdgeType>[]) => void;
|
|
@@ -109,7 +111,7 @@ export interface NodeGraphControlsProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
109
111
|
zoomOutLabel?: string;
|
|
110
112
|
fitViewLabel?: string;
|
|
111
113
|
}
|
|
112
|
-
declare function NodeGraphControls(
|
|
114
|
+
declare function NodeGraphControls(inkraProps: NodeGraphControlsProps): import("react").JSX.Element;
|
|
113
115
|
export declare function applyNodeGraphNodeChanges<NodeType extends NodeGraphNode>(changes: NodeGraphNodeChange<NodeType>[], nodes: NodeType[]): NodeType[];
|
|
114
116
|
export declare function applyNodeGraphEdgeChanges<EdgeType extends NodeGraphEdge>(changes: NodeGraphEdgeChange<EdgeType>[], edges: EdgeType[]): EdgeType[];
|
|
115
117
|
export declare function addNodeGraphEdge<EdgeType extends NodeGraphEdge>(connection: NodeGraphConnection | EdgeType, edges: EdgeType[]): EdgeType[];
|
package/dist/node-graph/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale } from '../i18n/index.js';
|
|
2
3
|
import { EdgeLabelRenderer, Handle, Panel, Position, ReactFlow, ReactFlowProvider, addEdge as addFlowEdge, applyEdgeChanges as applyFlowEdgeChanges, applyNodeChanges as applyFlowNodeChanges, getBezierPath, useReactFlow, useViewport, } from '@xyflow/react';
|
|
3
4
|
import { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, } from 'react';
|
|
4
5
|
import { PencilIcon } from '../PencilIcon.js';
|
|
@@ -132,9 +133,6 @@ function PencilEdgeCanvas({ id, path, className, selected = false }) {
|
|
|
132
133
|
if (disposed)
|
|
133
134
|
return;
|
|
134
135
|
try {
|
|
135
|
-
const points = sampleSvgPath(pathElement, bounds);
|
|
136
|
-
if (points.length < 2)
|
|
137
|
-
throw new Error('NodeGraph edge has no drawable path');
|
|
138
136
|
const style = getComputedStyle(canvas);
|
|
139
137
|
const width = readRenderToken(style, '--inkra-stroke-width', pencilRenderDefaults.strokeWidth, 0.3, 3);
|
|
140
138
|
const roughness = readRenderToken(style, '--inkra-stroke-amplitude', pencilRenderDefaults.strokeRoughness, 0, maxStrokeRoughness);
|
|
@@ -150,6 +148,9 @@ function PencilEdgeCanvas({ id, path, className, selected = false }) {
|
|
|
150
148
|
image = undefined;
|
|
151
149
|
}
|
|
152
150
|
if (!image) {
|
|
151
|
+
const points = sampleSvgPath(pathElement, bounds);
|
|
152
|
+
if (points.length < 2)
|
|
153
|
+
throw new Error('NodeGraph edge has no drawable path');
|
|
153
154
|
image = document.createElement('canvas');
|
|
154
155
|
image.width = budget.width;
|
|
155
156
|
image.height = budget.height;
|
|
@@ -238,7 +239,9 @@ function NodeGraphConnectionLine({ fromX, fromY, toX, toY, fromPosition, toPosit
|
|
|
238
239
|
});
|
|
239
240
|
return _jsx(PencilEdgeCanvas, { id: "connection-preview", path: path, className: "inkra-node-graph__connection-line" });
|
|
240
241
|
}
|
|
241
|
-
function NodeGraphControls(
|
|
242
|
+
function NodeGraphControls(inkraProps) {
|
|
243
|
+
const { t } = useInkraLocale();
|
|
244
|
+
const { className, fitViewOptions, zoomInLabel = t('common.zoomIn'), zoomOutLabel = t('common.zoomOut'), fitViewLabel = t('graph.fit'), ...props } = inkraProps;
|
|
242
245
|
const flow = useReactFlow();
|
|
243
246
|
const actions = [
|
|
244
247
|
{ label: zoomInLabel, paths: zoomInPaths, run: () => flow.zoomIn() },
|
|
@@ -250,7 +253,9 @@ function NodeGraphControls({ className, fitViewOptions, zoomInLabel = 'Zoom in',
|
|
|
250
253
|
function SsrFallback({ nodes, emptyState, label, }) {
|
|
251
254
|
return _jsx("div", { className: "inkra-node-graph__ssr", role: "group", "aria-label": label, children: nodes.length === 0 ? _jsx("div", { className: "inkra-node-graph__empty", children: emptyState }) : _jsx("ul", { children: nodes.map(node => _jsx("li", { children: readableLabel(node.data.label, node.id) }, node.id)) }) });
|
|
252
255
|
}
|
|
253
|
-
function NodeGraphRootInner(
|
|
256
|
+
function NodeGraphRootInner(inkraProps, forwardedRef) {
|
|
257
|
+
const { t } = useInkraLocale();
|
|
258
|
+
const { nodes, edges, onNodesChange, onEdgesChange, onConnect, isValidConnection, renderNode, renderEdge, renderEdgeLabel, readOnly = false, emptyState = t('graph.empty'), controls = true, controlLabels, fitView = false, fitViewOptions, defaultViewport = { x: 0, y: 0, zoom: 1 }, viewport, onViewportChange, minZoom = 0.25, maxZoom = 2, panOnDrag = true, zoomOnScroll = true, zoomOnPinch = true, connectOnClick = true, onlyRenderVisibleElements = false, className, style, 'aria-label': ariaLabel = t('graph.label'), ...props } = inkraProps;
|
|
254
259
|
const [mounted, setMounted] = useState(false);
|
|
255
260
|
const instanceRef = useRef(null);
|
|
256
261
|
useEffect(() => setMounted(true), []);
|
|
@@ -260,30 +265,60 @@ function NodeGraphRootInner({ nodes, edges, onNodesChange, onEdgesChange, onConn
|
|
|
260
265
|
zoomOut: () => instanceRef.current?.zoomOut() ?? Promise.resolve(false),
|
|
261
266
|
getViewport: () => instanceRef.current?.getViewport() ?? defaultViewport,
|
|
262
267
|
}), [defaultViewport]);
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
}
|
|
284
|
-
}
|
|
268
|
+
// Immutable node/edge updates should invalidate only the changed records. Weak
|
|
269
|
+
// keys release removed records and changing render configuration resets the cache.
|
|
270
|
+
const adaptNode = useMemo(() => {
|
|
271
|
+
const cache = new WeakMap();
|
|
272
|
+
return (node) => {
|
|
273
|
+
const cached = cache.get(node);
|
|
274
|
+
if (cached)
|
|
275
|
+
return cached;
|
|
276
|
+
const adapted = {
|
|
277
|
+
...node,
|
|
278
|
+
type: 'inkra',
|
|
279
|
+
ariaLabel: node.ariaLabel ?? readableLabel(node.data.label, node.id),
|
|
280
|
+
data: {
|
|
281
|
+
__inkraRenderNode: renderNode,
|
|
282
|
+
__inkraReadOnly: readOnly,
|
|
283
|
+
__inkraData: node.data,
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
cache.set(node, adapted);
|
|
287
|
+
return adapted;
|
|
288
|
+
};
|
|
289
|
+
}, [readOnly, renderNode]);
|
|
290
|
+
const adaptEdge = useMemo(() => {
|
|
291
|
+
const cache = new WeakMap();
|
|
292
|
+
return (edge) => {
|
|
293
|
+
const cached = cache.get(edge);
|
|
294
|
+
if (cached)
|
|
295
|
+
return cached;
|
|
296
|
+
const adapted = {
|
|
297
|
+
...edge,
|
|
298
|
+
type: 'inkra',
|
|
299
|
+
ariaLabel: edge.ariaLabel ?? `Edge from ${edge.source} to ${edge.target}`,
|
|
300
|
+
label: undefined,
|
|
301
|
+
data: {
|
|
302
|
+
...edge.data,
|
|
303
|
+
__inkraEdge: edge,
|
|
304
|
+
__inkraRenderEdge: renderEdge,
|
|
305
|
+
__inkraRenderEdgeLabel: renderEdgeLabel,
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
cache.set(edge, adapted);
|
|
309
|
+
return adapted;
|
|
310
|
+
};
|
|
311
|
+
}, [renderEdge, renderEdgeLabel]);
|
|
312
|
+
const internalNodes = useMemo(() => nodes.map(adaptNode), [nodes, adaptNode]);
|
|
313
|
+
const internalEdges = useMemo(() => edges.map(adaptEdge), [edges, adaptEdge]);
|
|
285
314
|
const rootStyle = { minHeight: 320, ...style };
|
|
286
|
-
return _jsx("div", { ...props, "aria-label": ariaLabel, className: ['inkra-node-graph', className].filter(Boolean).join(' '), "data-empty": nodes.length === 0 || undefined, "data-read-only": readOnly || undefined, style: rootStyle, children: !mounted ? _jsx(SsrFallback, { nodes: nodes, emptyState: emptyState, label: ariaLabel }) : _jsxs(ReactFlowProvider, { children: [_jsx(ReactFlow, { "aria-label": ariaLabel,
|
|
315
|
+
return _jsx("div", { ...props, "aria-label": ariaLabel, className: ['inkra-node-graph', className].filter(Boolean).join(' '), "data-empty": nodes.length === 0 || undefined, "data-read-only": readOnly || undefined, style: rootStyle, children: !mounted ? _jsx(SsrFallback, { nodes: nodes, emptyState: emptyState, label: ariaLabel }) : _jsxs(ReactFlowProvider, { children: [_jsx(ReactFlow, { "aria-label": ariaLabel, ariaLabelConfig: {
|
|
316
|
+
'node.a11yDescription.default': t('graph.nodeInstructions'),
|
|
317
|
+
'node.a11yDescription.keyboardDisabled': t('graph.nodeMoveInstructions'),
|
|
318
|
+
'node.a11yDescription.ariaLiveMessage': ({ x, y }) => t('graph.nodeMoved', { x, y }),
|
|
319
|
+
'edge.a11yDescription.default': t('graph.edgeInstructions'),
|
|
320
|
+
'handle.ariaLabel': t('graph.handle'),
|
|
321
|
+
}, nodes: internalNodes, edges: internalEdges, nodeTypes: nodeTypes, edgeTypes: edgeTypes, onInit: instance => { instanceRef.current = instance; }, onNodesChange: changes => onNodesChange?.(changes), onEdgesChange: changes => onEdgesChange?.(changes), onConnect: readOnly ? undefined : onConnect, isValidConnection: isValidConnection, nodesDraggable: !readOnly, nodesConnectable: !readOnly, elementsSelectable: !readOnly, edgesReconnectable: !readOnly, nodesFocusable: true, edgesFocusable: true, deleteKeyCode: readOnly ? null : ['Backspace', 'Delete'], fitView: fitView, fitViewOptions: fitViewOptions, defaultViewport: defaultViewport, viewport: viewport, onViewportChange: onViewportChange, minZoom: minZoom, maxZoom: maxZoom, panOnDrag: panOnDrag, zoomOnScroll: zoomOnScroll, zoomOnPinch: zoomOnPinch, connectOnClick: connectOnClick && !readOnly, connectionLineComponent: NodeGraphConnectionLine, onlyRenderVisibleElements: onlyRenderVisibleElements, noDragClassName: "nodrag", noPanClassName: "nopan", children: controls && _jsx(Panel, { position: "bottom-left", children: _jsx(NodeGraphControls, { fitViewLabel: controlLabels?.fitView, fitViewOptions: fitViewOptions, zoomInLabel: controlLabels?.zoomIn, zoomOutLabel: controlLabels?.zoomOut }) }) }), nodes.length === 0 && _jsx("div", { className: "inkra-node-graph__empty", role: "status", children: emptyState })] }) });
|
|
287
322
|
}
|
|
288
323
|
const NodeGraphRoot = forwardRef(NodeGraphRootInner);
|
|
289
324
|
export function applyNodeGraphNodeChanges(changes, nodes) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale } from '../i18n/index.js';
|
|
2
3
|
import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
|
|
3
4
|
import { PencilText } from '../PencilText.js';
|
|
4
5
|
import { useBrowserLayoutEffect } from '../internal/useBrowserLayoutEffect.js';
|
|
@@ -23,7 +24,9 @@ function lettering(content, seed) {
|
|
|
23
24
|
function accessibleAffix(content) {
|
|
24
25
|
return typeof content === 'string' || typeof content === 'number' ? String(content) : '';
|
|
25
26
|
}
|
|
26
|
-
export const NumberTicker = forwardRef(function NumberTicker({ animate = true, className, compact = false, compactOptions, deltaDuration = 1600, deltaFormatOptions, duration = 420, easing = easeOutCubic, formatOptions, getValueLabel, locale, prefix, renderDelta, renderValue, showDelta = false, suffix, value, ...props }, forwardedRef) {
|
|
27
|
+
export const NumberTicker = forwardRef(function NumberTicker({ animate = true, className, compact = false, compactOptions, deltaDuration = 1600, deltaFormatOptions, duration = 420, easing = easeOutCubic, formatOptions, getValueLabel, locale: localeProp, prefix, renderDelta, renderValue, showDelta = false, suffix, value, ...props }, forwardedRef) {
|
|
28
|
+
const { locale: inheritedLocale } = useInkraLocale();
|
|
29
|
+
const locale = localeProp ?? inheritedLocale;
|
|
27
30
|
const rootRef = useRef(null);
|
|
28
31
|
const frameRef = useRef(null);
|
|
29
32
|
const deltaTimerRef = useRef(null);
|
|
@@ -46,6 +46,14 @@ function roundedDecimal(value, options) {
|
|
|
46
46
|
: options.minimumFractionDigits ?? 0;
|
|
47
47
|
return { value: rounded, decimals };
|
|
48
48
|
}
|
|
49
|
+
let exactDecimalStringsSupported;
|
|
50
|
+
function supportsExactDecimalStrings() {
|
|
51
|
+
if (exactDecimalStringsSupported === undefined) {
|
|
52
|
+
const probe = new Intl.NumberFormat('en-US', { useGrouping: false });
|
|
53
|
+
exactDecimalStringsSupported = probe.format('9007199254740993') === '9007199254740993';
|
|
54
|
+
}
|
|
55
|
+
return exactDecimalStringsSupported;
|
|
56
|
+
}
|
|
49
57
|
// Intl accepts exact decimal strings in modern engines, but some engines still
|
|
50
58
|
// turn strings beyond Number.MAX_VALUE into Infinity. BigInt bypasses that path.
|
|
51
59
|
export function formatExactParts(formatter, value) {
|
|
@@ -60,8 +68,7 @@ export function formatExactParts(formatter, value) {
|
|
|
60
68
|
return formatter.formatToParts(BigInt(decimal.toFixed(0)));
|
|
61
69
|
if (decimal.e < 308) {
|
|
62
70
|
const exactFormat = formatter.formatToParts;
|
|
63
|
-
|
|
64
|
-
if (probe.format('9007199254740993') !== '9007199254740993') {
|
|
71
|
+
if (!supportsExactDecimalStrings()) {
|
|
65
72
|
throw new RangeError('NumberTicker decimal strings require exact Intl.NumberFormat string support');
|
|
66
73
|
}
|
|
67
74
|
return exactFormat.call(formatter, decimal.toString());
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale } from '../i18n/index.js';
|
|
2
3
|
import { forwardRef, useCallback, useEffect, useId, useMemo, useRef, useState, } from 'react';
|
|
3
4
|
import { Button } from '../Button.js';
|
|
4
5
|
import { DropdownMenu } from '../dropdown-menu/index.js';
|
|
@@ -27,10 +28,9 @@ function assignRef(ref, value) {
|
|
|
27
28
|
else if (ref)
|
|
28
29
|
ref.current = value;
|
|
29
30
|
}
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
function OverflowListInner({ 'aria-label': ariaLabel, className, gap, getOverflowItemIcon, items, measurementKey = '', onOverflowChange, onOverflowItemSelect, overflowButtonProps, overflowLabel = defaultOverflowLabel, renderItem, renderOverflow, renderOverflowItem, role, strategy = 'end', style, ...props }, forwardedRef) {
|
|
31
|
+
function OverflowListInner({ 'aria-label': ariaLabel, className, gap, getOverflowItemIcon, items, measurementKey = '', onOverflowChange, onOverflowItemSelect, overflowButtonProps, overflowLabel: overflowLabelProp, renderItem, renderOverflow, renderOverflowItem, role, strategy = 'end', style, ...props }, forwardedRef) {
|
|
32
|
+
const { t } = useInkraLocale();
|
|
33
|
+
const overflowLabel = overflowLabelProp ?? ((count) => t('overflow.more', { count }));
|
|
34
34
|
const generatedId = useId();
|
|
35
35
|
const rootRef = useRef(null);
|
|
36
36
|
const triggerRef = useRef(null);
|
|
@@ -157,6 +157,9 @@ function OverflowListInner({ 'aria-label': ariaLabel, className, gap, getOverflo
|
|
|
157
157
|
widthCache.current.clear();
|
|
158
158
|
setLayout({ signature, visibleKeys: new Set(allKeys), needsOverflow: false, measuring: true });
|
|
159
159
|
}, [allKeys, layout.signature, signature]);
|
|
160
|
+
// Keep observer targets in sync when a resize reveals or hides items without
|
|
161
|
+
// changing whether an overflow trigger is needed. Memoized visibleEntries
|
|
162
|
+
// leaves the observer intact during unrelated parent updates.
|
|
160
163
|
useEffect(() => {
|
|
161
164
|
const root = rootRef.current;
|
|
162
165
|
if (!root)
|
|
@@ -177,7 +180,7 @@ function OverflowListInner({ 'aria-label': ariaLabel, className, gap, getOverflo
|
|
|
177
180
|
frameRef.current = null;
|
|
178
181
|
}
|
|
179
182
|
};
|
|
180
|
-
}, [effectiveLayout.measuring, effectiveLayout.needsOverflow, scheduleLayout, signature]);
|
|
183
|
+
}, [effectiveLayout.measuring, effectiveLayout.needsOverflow, scheduleLayout, signature, visibleEntries]);
|
|
181
184
|
useEffect(() => {
|
|
182
185
|
const fonts = typeof document === 'undefined' ? undefined : document.fonts;
|
|
183
186
|
if (!fonts?.addEventListener)
|
|
@@ -198,7 +201,7 @@ function OverflowListInner({ 'aria-label': ariaLabel, className, gap, getOverflo
|
|
|
198
201
|
useEffect(() => {
|
|
199
202
|
if (effectiveLayout.measuring)
|
|
200
203
|
return;
|
|
201
|
-
const changeKey =
|
|
204
|
+
const changeKey = JSON.stringify([signature, visibleEntries.map(entry => entry.key)]);
|
|
202
205
|
if (lastChangeRef.current === changeKey)
|
|
203
206
|
return;
|
|
204
207
|
lastChangeRef.current = changeKey;
|
package/dist/overlay/Overlay.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale } from '../i18n/index.js';
|
|
2
3
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
3
4
|
import { forwardRef, useId } from 'react';
|
|
4
5
|
import { __iconData as closeIcon } from 'lucide-react/dist/esm/icons/x.mjs';
|
|
@@ -43,7 +44,9 @@ export const OverlayClose = forwardRef(function OverlayClose(props, ref) {
|
|
|
43
44
|
return _jsx(DialogPrimitive.Close, { ...props, ref: ref });
|
|
44
45
|
});
|
|
45
46
|
const closePaths = closeIcon.node.map(([, attributes]) => ({ d: attributes.d }));
|
|
46
|
-
export const OverlayCloseButton = forwardRef(function OverlayCloseButton(
|
|
47
|
+
export const OverlayCloseButton = forwardRef(function OverlayCloseButton(inkraProps, ref) {
|
|
48
|
+
const { t } = useInkraLocale();
|
|
49
|
+
const { label = t('common.close'), className, onFocus, ...props } = inkraProps;
|
|
47
50
|
return _jsx(Tooltip.Provider, { children: _jsxs(Tooltip.Root, { children: [_jsx(Tooltip.Trigger, { asChild: true, children: _jsx(DialogPrimitive.Close, { asChild: true, children: _jsx(Button, { ...props, ref: ref, type: "button", size: "icon", variant: "ghost", className: classes('inkra-overlay__close-button', className), "aria-label": label, onFocus: event => {
|
|
48
51
|
onFocus?.(event);
|
|
49
52
|
const dialog = event.currentTarget.closest('[role="dialog"]');
|
|
@@ -52,7 +55,9 @@ export const OverlayCloseButton = forwardRef(function OverlayCloseButton({ label
|
|
|
52
55
|
event.preventDefault();
|
|
53
56
|
}, children: _jsx(PencilIcon, { paths: closePaths, size: 30, sourceSize: 24, decorative: true }) }) }) }), _jsx(Tooltip.Portal, { children: _jsx(Tooltip.Content, { side: "bottom", align: "end", children: label }) })] }) });
|
|
54
57
|
});
|
|
55
|
-
export const OverlayHeader = forwardRef(function OverlayHeader(
|
|
58
|
+
export const OverlayHeader = forwardRef(function OverlayHeader(inkraProps, ref) {
|
|
59
|
+
const { t } = useInkraLocale();
|
|
60
|
+
const { children, className, divided = true, showClose = true, closeLabel = t('common.close'), action, ...props } = inkraProps;
|
|
56
61
|
const id = useId();
|
|
57
62
|
return _jsxs("div", { ...props, ref: ref, className: classes('inkra-overlay__header', className), "data-divided": divided || undefined, children: [_jsx("div", { className: "inkra-overlay__heading", children: children }), (action || showClose) && _jsxs("div", { className: "inkra-overlay__header-actions", children: [action, showClose && _jsx(OverlayCloseButton, { label: closeLabel })] }), divided && _jsx(PencilLine, { className: "inkra-overlay__section-divider", seed: `overlay-header-${id}` })] });
|
|
58
63
|
});
|
|
@@ -63,7 +68,7 @@ export const OverlayFooter = forwardRef(function OverlayFooter({ children, class
|
|
|
63
68
|
const id = useId();
|
|
64
69
|
return _jsxs("div", { ...props, ref: ref, className: classes('inkra-overlay__footer', className), "data-divided": divided || undefined, "data-align": align, children: [divided && _jsx(PencilLine, { className: "inkra-overlay__section-divider", seed: `overlay-footer-${id}` }), children] });
|
|
65
70
|
});
|
|
66
|
-
export const Overlay = Object.freeze({
|
|
71
|
+
export const Overlay = /* @__PURE__ */ Object.freeze({
|
|
67
72
|
Root: OverlayRoot,
|
|
68
73
|
Trigger: OverlayTrigger,
|
|
69
74
|
Portal: OverlayPortal,
|
package/dist/overlay/Popover.js
CHANGED
|
@@ -18,10 +18,10 @@ export const PopoverTrigger = forwardRef(function PopoverTrigger(props, forwarde
|
|
|
18
18
|
export function PopoverPortal({ children, ...props }) {
|
|
19
19
|
return mapPortalChildren(children, child => _jsx(PopoverPrimitive.Portal, { ...props, children: child }));
|
|
20
20
|
}
|
|
21
|
-
export const PopoverContent = forwardRef(function PopoverContent({ arrowProps, children, className, seed, showArrow = false, surfaceClassName, surfaceRadius = 8, surfaceVariant = 'paper', ...props }, ref) {
|
|
21
|
+
export const PopoverContent = forwardRef(function PopoverContent({ arrowProps, children, className, collisionPadding = 12, seed, showArrow = false, surfaceClassName, surfaceRadius = 8, surfaceVariant = 'paper', ...props }, ref) {
|
|
22
22
|
const id = useId();
|
|
23
23
|
props = usePortalThemeProps(props);
|
|
24
|
-
return (_jsxs(PopoverPrimitive.Content, { ...props, className: classes('inkra-popover__content', className), ref: ref, children: [_jsx(PencilSurface, { className: classes('inkra-popover__surface', surfaceClassName), radius: surfaceRadius, seed: seed ?? `inkra-popover-${id}`, variant: surfaceVariant, children: _jsx("div", { className: "inkra-popover__content-body", children: children }) }), showArrow ? (_jsx(PopoverPrimitive.Arrow, { ...arrowProps, className: classes('inkra-popover__arrow', arrowProps?.className) })) : null] }));
|
|
24
|
+
return (_jsxs(PopoverPrimitive.Content, { ...props, className: classes('inkra-popover__content', className), collisionPadding: collisionPadding, ref: ref, children: [_jsx(PencilSurface, { className: classes('inkra-popover__surface', surfaceClassName), radius: surfaceRadius, seed: seed ?? `inkra-popover-${id}`, variant: surfaceVariant, children: _jsx("div", { className: "inkra-popover__content-body", children: children }) }), showArrow ? (_jsx(PopoverPrimitive.Arrow, { ...arrowProps, className: classes('inkra-popover__arrow', arrowProps?.className) })) : null] }));
|
|
25
25
|
});
|
|
26
26
|
export const PopoverTitle = forwardRef(function PopoverTitle({ children, className, seed, ...props }, ref) {
|
|
27
27
|
const id = useId();
|
|
@@ -34,7 +34,7 @@ export const PopoverDescription = forwardRef(function PopoverDescription({ child
|
|
|
34
34
|
export const PopoverClose = forwardRef(function PopoverClose(props, ref) {
|
|
35
35
|
return _jsx(PopoverPrimitive.Close, { ...props, ref: ref });
|
|
36
36
|
});
|
|
37
|
-
export const Popover = Object.freeze({
|
|
37
|
+
export const Popover = /* @__PURE__ */ Object.freeze({
|
|
38
38
|
Root: PopoverRoot,
|
|
39
39
|
Anchor: PopoverAnchor,
|
|
40
40
|
Trigger: PopoverTrigger,
|
|
@@ -45,6 +45,14 @@ function readThemeSnapshot(node, forcedColors = isForcedColorsActive()) {
|
|
|
45
45
|
style,
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
+
function sameThemeSnapshot(left, right) {
|
|
49
|
+
if (left.theme !== right.theme || left.inkraTheme !== right.inkraTheme
|
|
50
|
+
|| left.direction !== right.direction || left.language !== right.language)
|
|
51
|
+
return false;
|
|
52
|
+
const entries = Object.entries(left.style);
|
|
53
|
+
return entries.length === Object.keys(right.style).length
|
|
54
|
+
&& entries.every(([property, value]) => right.style[property] === value);
|
|
55
|
+
}
|
|
48
56
|
export function PortalThemeProvider({ children }) {
|
|
49
57
|
const parentDepth = useContext(PortalLayerDepthContext);
|
|
50
58
|
const depth = parentDepth + 1;
|
|
@@ -52,12 +60,16 @@ export function PortalThemeProvider({ children }) {
|
|
|
52
60
|
const [snapshot, setSnapshot] = useState(emptySnapshot);
|
|
53
61
|
const captureTrigger = useCallback((node) => {
|
|
54
62
|
setTrigger(node);
|
|
55
|
-
|
|
63
|
+
const next = readThemeSnapshot(node);
|
|
64
|
+
setSnapshot(current => sameThemeSnapshot(current, next) ? current : next);
|
|
56
65
|
}, []);
|
|
57
66
|
useEffect(() => {
|
|
58
67
|
if (!trigger || typeof MutationObserver === 'undefined')
|
|
59
68
|
return undefined;
|
|
60
|
-
const refresh = () =>
|
|
69
|
+
const refresh = () => {
|
|
70
|
+
const next = readThemeSnapshot(trigger);
|
|
71
|
+
setSnapshot(current => sameThemeSnapshot(current, next) ? current : next);
|
|
72
|
+
};
|
|
61
73
|
const observer = new MutationObserver(refresh);
|
|
62
74
|
for (let target = trigger; target; target = target.parentElement) {
|
|
63
75
|
observer.observe(target, {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HTMLAttributes } from 'react';
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
2
|
export interface PaginationLabels {
|
|
3
3
|
nav: string;
|
|
4
4
|
first: string;
|
|
@@ -16,6 +16,15 @@ export interface PaginationProps extends Omit<HTMLAttributes<HTMLElement>, 'chil
|
|
|
16
16
|
siblingCount?: number;
|
|
17
17
|
boundaryCount?: number;
|
|
18
18
|
showFirstLast?: boolean;
|
|
19
|
+
showPreviousNext?: boolean;
|
|
20
|
+
hideOnSinglePage?: boolean;
|
|
21
|
+
simple?: boolean;
|
|
22
|
+
/** Non-interactive content inside each numbered page button. */
|
|
23
|
+
renderPage?: (page: number, state: {
|
|
24
|
+
isCurrent: boolean;
|
|
25
|
+
}) => ReactNode;
|
|
26
|
+
/** Non-interactive current/total content in simple mode. */
|
|
27
|
+
renderSummary?: (page: number, totalPages: number) => ReactNode;
|
|
19
28
|
disabled?: boolean;
|
|
20
29
|
size?: 'sm' | 'md' | 'lg';
|
|
21
30
|
labels?: Partial<PaginationLabels>;
|
package/dist/pagination/index.js
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale } from '../i18n/index.js';
|
|
2
3
|
import { forwardRef, useEffect, useState } from 'react';
|
|
3
4
|
import { Button } from '../Button.js';
|
|
4
5
|
import { PencilIcon } from '../PencilIcon.js';
|
|
5
6
|
import { PencilSurface } from '../PencilSurface.js';
|
|
6
7
|
import { PencilText } from '../PencilText.js';
|
|
7
8
|
import { clampPage, getPaginationEntries, normalizeTotal } from './model.js';
|
|
8
|
-
const defaultLabels = {
|
|
9
|
-
nav: '
|
|
10
|
-
page: page =>
|
|
11
|
-
};
|
|
12
|
-
export const Pagination = forwardRef(function Pagination({ totalPages, page, defaultPage = 1, onPageChange, siblingCount = 1, boundaryCount = 1, showFirstLast = false, disabled = false, size = 'md', labels, className, ...props }, ref) {
|
|
9
|
+
const defaultLabels = (t) => ({
|
|
10
|
+
nav: t('pagination.nav'), first: t('pagination.first'), previous: t('common.previousPage'), next: t('common.nextPage'), last: t('pagination.last'),
|
|
11
|
+
page: page => t('pagination.page', { page }), ellipsis: t('pagination.more'),
|
|
12
|
+
});
|
|
13
|
+
export const Pagination = forwardRef(function Pagination({ totalPages, page, defaultPage = 1, onPageChange, siblingCount = 1, boundaryCount = 1, showFirstLast = false, showPreviousNext = true, hideOnSinglePage = false, simple = false, renderPage, renderSummary, disabled = false, size = 'md', labels, className, ...props }, ref) {
|
|
14
|
+
const { t } = useInkraLocale();
|
|
13
15
|
const total = normalizeTotal(totalPages);
|
|
14
16
|
const [internalPage, setInternalPage] = useState(() => clampPage(defaultPage, total));
|
|
15
17
|
const current = clampPage(page ?? internalPage, total);
|
|
16
|
-
const text = { ...defaultLabels, ...labels };
|
|
18
|
+
const text = { ...defaultLabels(t), ...labels };
|
|
17
19
|
useEffect(() => {
|
|
18
20
|
if (page === undefined)
|
|
19
21
|
setInternalPage(value => clampPage(value, total));
|
|
@@ -35,7 +37,9 @@ export const Pagination = forwardRef(function Pagination({ totalPages, page, def
|
|
|
35
37
|
paths.push({ d: 'M19 6v12' });
|
|
36
38
|
return _jsx("li", { children: _jsx(Button, { variant: "ghost", size: size === 'md' ? 'icon' : `icon-${size}`, "aria-label": text[kind], title: text[kind], disabled: disabled || unavailable, onClick: () => select(target), children: _jsx(PencilIcon, { className: "inkra-pagination__arrow", paths: paths, size: 20, sourceSize: 24 }) }) }, kind);
|
|
37
39
|
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
if (hideOnSinglePage && total <= 1)
|
|
41
|
+
return null;
|
|
42
|
+
return _jsx("nav", { "aria-label": text.nav, ...props, ref: ref, className: ['inkra-pagination', className].filter(Boolean).join(' '), "data-empty": !total || undefined, "data-simple": simple || undefined, children: _jsxs("ul", { className: "inkra-pagination__list", children: [showFirstLast && arrow('first', 1, current <= 1), showPreviousNext && arrow('previous', current - 1, current <= 1), simple ? _jsx("li", { className: "inkra-pagination__summary", "aria-live": "polite", "aria-atomic": "true", children: renderSummary ? renderSummary(current, total) : _jsx(PencilText, { children: `${current} / ${total}` }) }) : getPaginationEntries(total, current, siblingCount, boundaryCount).map(entry => typeof entry === 'number'
|
|
43
|
+
? _jsx("li", { className: "inkra-pagination__page-item", children: _jsxs(Button, { size: size, variant: "ghost", className: "inkra-pagination__page", "aria-label": text.page(entry), "aria-current": entry === current ? 'page' : undefined, disabled: disabled, onClick: () => select(entry), children: [entry === current && _jsx(PencilSurface, { as: "span", "aria-hidden": "true", variant: "selection", className: "inkra-pagination__selection", seed: `page-${entry}` }), renderPage ? renderPage(entry, { isCurrent: entry === current }) : _jsx(PencilText, { children: String(entry) })] }) }, entry)
|
|
44
|
+
: _jsxs("li", { className: "inkra-pagination__ellipsis", children: [_jsx("span", { className: "inkra-pagination__sr-only", children: text.ellipsis }), _jsx(PencilText, { "aria-hidden": "true", children: "..." })] }, entry)), showPreviousNext && arrow('next', current + 1, !total || current >= total), showFirstLast && arrow('last', total, !total || current >= total)] }) });
|
|
41
45
|
});
|
package/dist/pan-zoom/index.d.ts
CHANGED
|
@@ -48,6 +48,8 @@ export interface PanZoomProps extends Omit<HTMLAttributes<HTMLDivElement>, 'chil
|
|
|
48
48
|
minScale?: number;
|
|
49
49
|
maxScale?: number;
|
|
50
50
|
wheel?: PanZoomWheelMode;
|
|
51
|
+
/** Scale increment per wheel delta unit. Must be finite and positive. */
|
|
52
|
+
wheelStep?: number;
|
|
51
53
|
pinch?: boolean;
|
|
52
54
|
pan?: boolean;
|
|
53
55
|
keyboard?: boolean;
|