@inkra/react 0.2.0 → 0.4.3
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 +101 -7
- 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.d.ts +1 -1
- package/dist/alert-dialog/index.js +18 -6
- package/dist/audio-player/index.d.ts +2 -0
- package/dist/audio-player/index.js +126 -31
- package/dist/calendar/index.d.ts +4 -1
- package/dist/calendar/index.js +31 -12
- package/dist/carousel/index.js +13 -6
- package/dist/choice-grid/index.d.ts +6 -1
- package/dist/choice-grid/index.js +61 -33
- package/dist/color-picker/GradientEditor.d.ts +39 -0
- package/dist/color-picker/GradientEditor.js +63 -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 +134 -32
- package/dist/color-swatch/index.d.ts +10 -0
- package/dist/color-swatch/index.js +9 -0
- package/dist/command/index.d.ts +24 -2
- package/dist/command/index.js +29 -6
- package/dist/content/index.d.ts +5 -0
- package/dist/content/index.js +12 -3
- package/dist/context-menu/index.d.ts +2 -2
- package/dist/context-menu/index.js +4 -3
- package/dist/data-table/index.d.ts +7 -1
- package/dist/data-table/index.js +64 -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 +10 -9
- package/dist/day-agenda/index.d.ts +6 -1
- package/dist/day-agenda/index.js +46 -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 +5 -5
- package/dist/drawer/index.d.ts +1 -1
- package/dist/drawer/index.js +9 -6
- package/dist/dropdown-menu/index.d.ts +1 -1
- package/dist/dropdown-menu/index.js +3 -2
- package/dist/editable/index.d.ts +24 -2
- package/dist/editable/index.js +142 -37
- 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/EditablePencilText.js +34 -0
- package/dist/form/Field.js +11 -10
- package/dist/form/Input.js +1 -1
- package/dist/form/Textarea.d.ts +3 -1
- package/dist/form/Textarea.js +6 -4
- package/dist/hotkey/index.d.ts +1 -0
- package/dist/hotkey/index.js +6 -4
- package/dist/hover-card/index.js +1 -1
- package/dist/image-cropper/index.js +4 -2
- package/dist/image-viewer/VideoResource.d.ts +21 -0
- package/dist/image-viewer/VideoResource.js +194 -0
- package/dist/image-viewer/index.d.ts +14 -0
- package/dist/image-viewer/index.js +118 -65
- package/dist/image-viewer/lucideGeometry.d.ts +3 -0
- package/dist/image-viewer/lucideGeometry.js +19 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/input-number/index.d.ts +6 -0
- package/dist/input-number/index.js +131 -15
- package/dist/input-number/model.d.ts +13 -0
- package/dist/input-number/model.js +50 -0
- 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 +2 -0
- package/dist/internal/textRenderer.js +3 -3
- package/dist/internal/usePencilSurface.js +17 -1
- package/dist/internal/wash.js +4 -3
- package/dist/journey-map/terrain.js +10 -5
- package/dist/layout/index.js +1 -1
- package/dist/log/index.js +29 -22
- 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 +175 -0
- package/dist/node-graph/index.d.ts +2 -0
- package/dist/node-graph/index.js +49 -25
- package/dist/number-ticker/index.d.ts +11 -9
- package/dist/number-ticker/index.js +14 -11
- package/dist/number-ticker/model.d.ts +38 -5
- package/dist/number-ticker/model.js +139 -10
- package/dist/number-ticker/precision.d.ts +7 -0
- package/dist/number-ticker/precision.js +141 -0
- package/dist/overflow-list/index.js +5 -2
- package/dist/overlay/Overlay.d.ts +1 -1
- package/dist/overlay/Overlay.js +5 -3
- package/dist/overlay/Popover.d.ts +1 -1
- package/dist/overlay/Popover.js +6 -5
- package/dist/overlay/themeBridge.d.ts +12 -1
- package/dist/overlay/themeBridge.js +41 -3
- package/dist/pagination/index.d.ts +10 -1
- package/dist/pagination/index.js +6 -4
- package/dist/pan-zoom/index.d.ts +2 -0
- package/dist/pan-zoom/index.js +7 -6
- package/dist/pencil.d.ts +1 -0
- package/dist/pencil.js +4 -4
- package/dist/radar/index.d.ts +4 -0
- package/dist/radar/index.js +41 -21
- package/dist/rating/index.d.ts +4 -0
- package/dist/rating/index.js +128 -24
- package/dist/resizable/index.js +1 -1
- 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 +61 -6
- package/dist/select/Select.d.ts +1 -0
- package/dist/select/Select.js +3 -1
- package/dist/select/StepperSelect.d.ts +29 -0
- package/dist/select/StepperSelect.js +119 -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 +15 -6
- package/dist/sparkline/index.js +17 -2
- package/dist/sparkline/model.js +11 -4
- 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 +557 -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 +2241 -443
- package/dist/tabs/index.d.ts +9 -0
- package/dist/tabs/index.js +66 -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 +70 -26
- package/dist/time-picker/index.js +38 -20
- package/dist/toast/index.d.ts +19 -11
- package/dist/toast/index.js +48 -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.d.ts +1 -1
- package/dist/tooltip/Tooltip.js +6 -5
- package/dist/transfer/index.d.ts +5 -0
- package/dist/transfer/index.js +93 -29
- 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 +5 -5
- package/dist/tree-select/index.js +67 -30
- 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 +30 -16
- package/dist/virtual-list/index.js +10 -7
- package/package.json +416 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useMemo, useRef } from 'react';
|
|
3
|
-
import { BoundedCache, PENCIL_RENDERER_VERSION, canvasByteCost, canvasIsUsable, effectiveDpr } from '../internal/cache.js';
|
|
3
|
+
import { BoundedCache, PENCIL_RENDERER_VERSION, boundedCanvasSize, canvasByteCost, canvasIsUsable, effectiveDpr } from '../internal/cache.js';
|
|
4
4
|
import { observeCanvasRecovery } from '../internal/recovery.js';
|
|
5
5
|
import { seedToNumber } from '../internal/random.js';
|
|
6
6
|
import { maxStrokeRoughness, pencilRenderDefaults, readRenderToken } from '../internal/renderTokens.js';
|
|
@@ -84,6 +84,7 @@ export function ProgressRing({ diameter, thickness, percent, seed }) {
|
|
|
84
84
|
const weight = readRenderToken(style, '--inkra-stroke-width', pencilRenderDefaults.strokeWidth, 0.3, 3);
|
|
85
85
|
const roughness = readRenderToken(style, '--inkra-stroke-amplitude', pencilRenderDefaults.strokeRoughness, 0, maxStrokeRoughness);
|
|
86
86
|
const dpr = effectiveDpr(2);
|
|
87
|
+
const size = boundedCanvasSize(width, width, dpr);
|
|
87
88
|
const key = JSON.stringify([PENCIL_RENDERER_VERSION, diameter, thickness, width, dpr, style.color, weight, roughness, seed]);
|
|
88
89
|
if (key === lastPaint && canvasIsUsable(canvas))
|
|
89
90
|
return;
|
|
@@ -94,7 +95,9 @@ export function ProgressRing({ diameter, thickness, percent, seed }) {
|
|
|
94
95
|
}
|
|
95
96
|
if (!image) {
|
|
96
97
|
image = document.createElement('canvas');
|
|
97
|
-
image.width =
|
|
98
|
+
image.width = size.width;
|
|
99
|
+
image.height = size.height;
|
|
100
|
+
image.addEventListener('contextlost', () => ringCache.delete(key), { once: true });
|
|
98
101
|
const context = image.getContext('2d');
|
|
99
102
|
if (!context)
|
|
100
103
|
throw new Error('Canvas unavailable');
|
|
@@ -116,6 +119,7 @@ export function ProgressRing({ diameter, thickness, percent, seed }) {
|
|
|
116
119
|
lastPaint = key;
|
|
117
120
|
}
|
|
118
121
|
catch {
|
|
122
|
+
canvas.width = canvas.height = 0;
|
|
119
123
|
delete canvas.dataset.ready;
|
|
120
124
|
lastPaint = '';
|
|
121
125
|
}
|
|
@@ -131,7 +135,7 @@ export function ProgressRing({ diameter, thickness, percent, seed }) {
|
|
|
131
135
|
const scheme = matchMedia('(prefers-color-scheme: dark)');
|
|
132
136
|
scheme.addEventListener('change', paint);
|
|
133
137
|
window.addEventListener('resize', paint);
|
|
134
|
-
const stopRecovery = observeCanvasRecovery(paint);
|
|
138
|
+
const stopRecovery = observeCanvasRecovery(() => { lastPaint = ''; paint(); });
|
|
135
139
|
paint();
|
|
136
140
|
return () => {
|
|
137
141
|
observer.disconnect();
|
package/dist/display/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HTMLAttributes, ReactNode } from 'react';
|
|
1
|
+
import type { CSSProperties, HTMLAttributes, ReactNode } from 'react';
|
|
2
2
|
import { type ProgressPartialSegment, type ProgressThreshold } from '../segmented-progress/SegmentedProgress.js';
|
|
3
3
|
export type { ProgressPartialSegment, ProgressThreshold } from '../segmented-progress/SegmentedProgress.js';
|
|
4
4
|
export type BadgeVariant = 'neutral' | 'accent' | 'success' | 'warning' | 'danger' | 'info';
|
|
@@ -22,6 +22,9 @@ export declare const Separator: import("react").ForwardRefExoticComponent<Separa
|
|
|
22
22
|
export interface SkeletonProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
23
23
|
seed?: string | number;
|
|
24
24
|
radius?: number;
|
|
25
|
+
width?: CSSProperties['width'];
|
|
26
|
+
height?: CSSProperties['height'];
|
|
27
|
+
animation?: 'none' | 'pulse';
|
|
25
28
|
}
|
|
26
29
|
export declare const Skeleton: import("react").ForwardRefExoticComponent<SkeletonProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
27
30
|
export interface ProgressRenderState {
|
package/dist/display/index.js
CHANGED
|
@@ -30,8 +30,9 @@ export const Separator = forwardRef(function Separator({ className, decorative =
|
|
|
30
30
|
: { 'aria-orientation': orientation, role: 'separator' };
|
|
31
31
|
return (_jsx("div", { ...props, ...semanticProps, className: ['inkra-separator', className].filter(Boolean).join(' '), "data-orientation": orientation, ref: ref, children: _jsx(PencilLine, { className: "inkra-separator__line", orientation: orientation, seed: seed ?? `inkra-separator-${orientation}`, weight: Number.isFinite(weight) ? Math.max(0.3, Math.min(2, weight)) : 0.9 }) }));
|
|
32
32
|
});
|
|
33
|
-
export const Skeleton = forwardRef(function Skeleton({ className, seed = 'inkra-skeleton', radius, ...props }, ref) {
|
|
34
|
-
|
|
33
|
+
export const Skeleton = forwardRef(function Skeleton({ className, seed = 'inkra-skeleton', radius = 7, width, height, animation = 'none', style, ...props }, ref) {
|
|
34
|
+
const resolvedRadius = Number.isFinite(radius) ? Math.max(0, Math.min(radius, 8)) : 7;
|
|
35
|
+
return (_jsx(PencilSurface, { ...props, "aria-hidden": "true", as: "div", className: ['inkra-skeleton', className].filter(Boolean).join(' '), "data-animation": animation, style: { width, height, borderRadius: resolvedRadius, ...style }, ref: ref, seed: seed, radius: resolvedRadius, variant: "selection" }));
|
|
35
36
|
});
|
|
36
37
|
function normalizeMax(max) {
|
|
37
38
|
return typeof max === 'number' && Number.isFinite(max) && max > 0 ? max : 100;
|
|
@@ -43,7 +43,7 @@ export const DockablePanelWorkspace = forwardRef(function DockablePanelWorkspace
|
|
|
43
43
|
return () => observer.disconnect();
|
|
44
44
|
}, []);
|
|
45
45
|
const activate = useCallback((id) => {
|
|
46
|
-
setOrder(current => promoteDockablePanel(current, id));
|
|
46
|
+
setOrder(current => current[current.length - 1] === id ? current : promoteDockablePanel(current, id));
|
|
47
47
|
if (activeId === undefined)
|
|
48
48
|
setUncontrolledActiveId(id);
|
|
49
49
|
if (resolvedActiveId !== id)
|
|
@@ -51,7 +51,7 @@ export const DockablePanelWorkspace = forwardRef(function DockablePanelWorkspace
|
|
|
51
51
|
}, [activeId, onActiveChange, resolvedActiveId]);
|
|
52
52
|
useEffect(() => {
|
|
53
53
|
if (activeId != null)
|
|
54
|
-
setOrder(current => promoteDockablePanel(current, activeId));
|
|
54
|
+
setOrder(current => current[current.length - 1] === activeId ? current : promoteDockablePanel(current, activeId));
|
|
55
55
|
}, [activeId]);
|
|
56
56
|
const register = useCallback((id) => {
|
|
57
57
|
setOrder(current => current.includes(id) ? current : [...current, id]);
|
|
@@ -72,18 +72,18 @@ export const DockablePanelWorkspace = forwardRef(function DockablePanelWorkspace
|
|
|
72
72
|
titleBarVisibility,
|
|
73
73
|
width: size.width,
|
|
74
74
|
}), [boundaryPadding, size.height, size.width, titleBarVisibility]);
|
|
75
|
+
const layers = useMemo(() => new Map(order.map((id, index) => [id, index])), [order]);
|
|
75
76
|
const context = useMemo(() => ({
|
|
76
77
|
activeId: resolvedActiveId,
|
|
77
78
|
activate,
|
|
78
79
|
bounds,
|
|
79
80
|
commitDrag,
|
|
80
81
|
layer(id) {
|
|
81
|
-
|
|
82
|
-
return baseZIndex + (resolvedActiveId === id ? order.length : Math.max(0, index));
|
|
82
|
+
return baseZIndex + (resolvedActiveId === id ? order.length : (layers.get(id) ?? 0));
|
|
83
83
|
},
|
|
84
84
|
register,
|
|
85
85
|
snapThreshold,
|
|
86
|
-
}), [activate, baseZIndex, bounds, commitDrag, order, register, resolvedActiveId, snapThreshold]);
|
|
86
|
+
}), [activate, baseZIndex, bounds, commitDrag, layers, order.length, register, resolvedActiveId, snapThreshold]);
|
|
87
87
|
function handleDragEnd(event) {
|
|
88
88
|
const id = String(event.active.id);
|
|
89
89
|
dragCallbacks.current.get(id)?.({ x: event.delta.x, y: event.delta.y });
|
package/dist/drawer/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export declare function DrawerRoot(props: DrawerRootProps): import("react").JSX.
|
|
|
8
8
|
export type DrawerTriggerProps = DialogPrimitive.DialogTriggerProps;
|
|
9
9
|
export declare const DrawerTrigger: import("react").ForwardRefExoticComponent<DialogPrimitive.DialogTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
10
10
|
export type DrawerPortalProps = DialogPrimitive.DialogPortalProps;
|
|
11
|
-
export declare function DrawerPortal({ children, ...props }: DrawerPortalProps):
|
|
11
|
+
export declare function DrawerPortal({ children, ...props }: DrawerPortalProps): ReactNode;
|
|
12
12
|
export type DrawerBackdropProps = DialogPrimitive.DialogOverlayProps;
|
|
13
13
|
export declare const DrawerBackdrop: import("react").ForwardRefExoticComponent<DialogPrimitive.DialogOverlayProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
14
14
|
export interface DrawerContentProps extends DialogPrimitive.DialogContentProps {
|
package/dist/drawer/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { PencilLine } from '../PencilLine.js';
|
|
|
8
8
|
import { PencilSurface } from '../PencilSurface.js';
|
|
9
9
|
import { PencilText } from '../PencilText.js';
|
|
10
10
|
import { Tooltip } from '../tooltip/Tooltip.js';
|
|
11
|
-
import {
|
|
11
|
+
import { mapPortalChildren, PortalThemeProvider, usePortalThemeProps, usePortalTriggerRef, } from '../overlay/themeBridge.js';
|
|
12
12
|
const classes = (...values) => values.filter(Boolean).join(' ');
|
|
13
13
|
const closePaths = closeIcon.node.map(([, attributes]) => ({ d: attributes.d }));
|
|
14
14
|
function drawerSize(size) {
|
|
@@ -29,16 +29,18 @@ export const DrawerTrigger = forwardRef(function DrawerTrigger(props, forwardedR
|
|
|
29
29
|
return _jsx(DialogPrimitive.Trigger, { ...props, ref: usePortalTriggerRef(forwardedRef) });
|
|
30
30
|
});
|
|
31
31
|
export function DrawerPortal({ children, ...props }) {
|
|
32
|
-
return _jsx(DialogPrimitive.Portal, { ...props, children:
|
|
32
|
+
return mapPortalChildren(children, child => _jsx(DialogPrimitive.Portal, { ...props, children: child }));
|
|
33
33
|
}
|
|
34
34
|
export const DrawerBackdrop = forwardRef(function DrawerBackdrop({ className, ...props }, ref) {
|
|
35
|
+
props = usePortalThemeProps(props);
|
|
35
36
|
return _jsx(DialogPrimitive.Overlay, { ...props, className: classes('inkra-drawer__backdrop', className), ref: ref });
|
|
36
37
|
});
|
|
37
38
|
export const DrawerContent = forwardRef(function DrawerContent({ children, className, direction = 'right', seed, size = 'md', style, ...props }, ref) {
|
|
38
39
|
const id = useId();
|
|
39
|
-
const
|
|
40
|
+
const themedProps = usePortalThemeProps({ ...props, style });
|
|
41
|
+
const mergedStyle = { ...themedProps.style, '--inkra-drawer-size': drawerSize(size) };
|
|
40
42
|
const edgeOrientation = direction === 'left' || direction === 'right' ? 'vertical' : 'horizontal';
|
|
41
|
-
return (
|
|
43
|
+
return (_jsxs(DialogPrimitive.Content, { ...themedProps, className: classes('inkra-drawer__content', className), "data-direction": direction, ref: ref, style: mergedStyle, children: [_jsx(PencilSurface, { "aria-hidden": "true", className: "inkra-drawer__focus-ring", radius: 0, seed: `drawer-focus-${id}`, variant: "outline" }), _jsxs(PencilSurface, { className: "inkra-drawer__surface", radius: 0, seed: seed ?? `inkra-drawer-${id}`, variant: "full", children: [_jsx(PencilLine, { className: "inkra-drawer__edge", orientation: edgeOrientation, seed: `drawer-edge-${id}` }), _jsx("div", { className: "inkra-drawer__layout", children: children })] })] }));
|
|
42
44
|
});
|
|
43
45
|
export const DrawerTitle = forwardRef(function DrawerTitle({ children, className, seed, ...props }, ref) {
|
|
44
46
|
const id = useId();
|
|
@@ -61,7 +63,8 @@ export const DrawerCloseButton = forwardRef(function DrawerCloseButton({ classNa
|
|
|
61
63
|
});
|
|
62
64
|
export const DrawerHeader = forwardRef(function DrawerHeader({ action, children, className, closeLabel = 'Close', divided = true, showClose = true, ...props }, ref) {
|
|
63
65
|
const id = useId();
|
|
64
|
-
|
|
66
|
+
const hasActions = Boolean(action || showClose);
|
|
67
|
+
return _jsxs("div", { ...props, className: classes('inkra-drawer__header', className), "data-actions": hasActions || undefined, "data-custom-action": action ? true : undefined, "data-divided": divided || undefined, ref: ref, children: [_jsx("div", { className: "inkra-drawer__heading", children: children }), hasActions ? _jsxs("div", { className: "inkra-drawer__header-actions", children: [action, showClose ? _jsx(DrawerCloseButton, { label: closeLabel }) : null] }) : null, divided ? _jsx(PencilLine, { className: "inkra-drawer__divider", seed: `drawer-header-${id}` }) : null] });
|
|
65
68
|
});
|
|
66
69
|
export const DrawerBody = forwardRef(function DrawerBody({ className, ...props }, ref) {
|
|
67
70
|
return _jsx("div", { ...props, className: classes('inkra-drawer__body', className), ref: ref });
|
|
@@ -70,7 +73,7 @@ export const DrawerFooter = forwardRef(function DrawerFooter({ align = 'end', ch
|
|
|
70
73
|
const id = useId();
|
|
71
74
|
return _jsxs("div", { ...props, className: classes('inkra-drawer__footer', className), "data-align": align, "data-divided": divided || undefined, ref: ref, children: [divided ? _jsx(PencilLine, { className: "inkra-drawer__divider", seed: `drawer-footer-${id}` }) : null, children] });
|
|
72
75
|
});
|
|
73
|
-
export const Drawer = Object.freeze({
|
|
76
|
+
export const Drawer = /* @__PURE__ */ Object.freeze({
|
|
74
77
|
Root: DrawerRoot,
|
|
75
78
|
Trigger: DrawerTrigger,
|
|
76
79
|
Portal: DrawerPortal,
|
|
@@ -4,7 +4,7 @@ export type DropdownMenuProps = Primitive.DropdownMenuProps;
|
|
|
4
4
|
declare function Root(props: DropdownMenuProps): import("react").JSX.Element;
|
|
5
5
|
export type DropdownMenuTriggerProps = Primitive.DropdownMenuTriggerProps;
|
|
6
6
|
export type DropdownMenuPortalProps = Primitive.DropdownMenuPortalProps;
|
|
7
|
-
declare function Portal({ children, ...props }: DropdownMenuPortalProps):
|
|
7
|
+
declare function Portal({ children, ...props }: DropdownMenuPortalProps): ReactNode;
|
|
8
8
|
export interface DropdownMenuContentProps extends Omit<Primitive.DropdownMenuContentProps, 'asChild'> {
|
|
9
9
|
seed?: string | number;
|
|
10
10
|
}
|
|
@@ -5,16 +5,17 @@ import { PencilSurface } from '../PencilSurface.js';
|
|
|
5
5
|
import { PencilText } from '../PencilText.js';
|
|
6
6
|
import { PencilIcon } from '../PencilIcon.js';
|
|
7
7
|
import { PencilLine } from '../PencilLine.js';
|
|
8
|
-
import {
|
|
8
|
+
import { mapPortalChildren, PortalThemeProvider, usePortalThemeProps, usePortalTriggerRef } from '../overlay/themeBridge.js';
|
|
9
9
|
const classes = (...values) => values.filter(Boolean).join(' ');
|
|
10
10
|
const copy = (children) => typeof children === 'string' ? _jsx(PencilText, { children: children }) : children;
|
|
11
11
|
function Root(props) { return _jsx(PortalThemeProvider, { children: _jsx(Primitive.Root, { ...props }) }); }
|
|
12
12
|
const Trigger = forwardRef(function Trigger(props, ref) {
|
|
13
13
|
return _jsx(Primitive.Trigger, { ...props, ref: usePortalTriggerRef(ref) });
|
|
14
14
|
});
|
|
15
|
-
function Portal({ children, ...props }) { return _jsx(Primitive.Portal, { ...props, children:
|
|
15
|
+
function Portal({ children, ...props }) { return mapPortalChildren(children, child => _jsx(Primitive.Portal, { ...props, children: child })); }
|
|
16
16
|
const Content = forwardRef(function Content({ className, children, seed, sideOffset = 6, collisionPadding = 8, ...props }, ref) {
|
|
17
17
|
const id = useId();
|
|
18
|
+
props = usePortalThemeProps(props);
|
|
18
19
|
return _jsx(Primitive.Content, { ...props, ref: ref, sideOffset: sideOffset, collisionPadding: collisionPadding, className: classes('inkra-menu', className), children: _jsx(PencilSurface, { variant: "paper", radius: 8, seed: seed ?? `menu-${id}`, className: "inkra-menu__paper", children: children }) });
|
|
19
20
|
});
|
|
20
21
|
function ItemBody({ children, icon }) {
|
package/dist/editable/index.d.ts
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
|
-
import type { HTMLAttributes, KeyboardEvent, ReactNode } from 'react';
|
|
1
|
+
import type { FocusEvent, HTMLAttributes, KeyboardEvent, ReactNode } from 'react';
|
|
2
|
+
import type { SearchableSelectOption } from '../select/index.js';
|
|
2
3
|
import type { InputProps } from '../form/Input.js';
|
|
3
4
|
import type { TextareaProps } from '../form/Textarea.js';
|
|
4
5
|
export type EditableBlurBehavior = 'ignore' | 'save' | 'cancel';
|
|
6
|
+
export type EditableEditorType = 'input' | 'textarea' | 'select';
|
|
7
|
+
export interface EditableSelectProps {
|
|
8
|
+
items: readonly SearchableSelectOption[];
|
|
9
|
+
mode?: 'dropdown' | 'searchable' | 'stepper';
|
|
10
|
+
size?: 'sm' | 'md' | 'lg';
|
|
11
|
+
dir?: 'ltr' | 'rtl';
|
|
12
|
+
searchPlaceholder?: string;
|
|
13
|
+
emptyContent?: ReactNode;
|
|
14
|
+
clearable?: boolean;
|
|
15
|
+
clearLabel?: string;
|
|
16
|
+
openLabel?: string;
|
|
17
|
+
previousLabel?: string;
|
|
18
|
+
nextLabel?: string;
|
|
19
|
+
loop?: boolean;
|
|
20
|
+
}
|
|
5
21
|
export type EditableSaveResult = boolean | string | void | null | undefined;
|
|
6
22
|
export type EditableSaveHandler = (value: string, previousValue: string) => EditableSaveResult | Promise<EditableSaveResult>;
|
|
7
23
|
export type EditableValidateHandler = (value: string, previousValue: string) => EditableSaveResult | Promise<EditableSaveResult>;
|
|
@@ -9,12 +25,16 @@ export interface EditableEditorProps {
|
|
|
9
25
|
value: string;
|
|
10
26
|
onValueChange: (value: string) => void;
|
|
11
27
|
onKeyDown: (event: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
12
|
-
onBlur: () => void;
|
|
28
|
+
onBlur: (event: FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
13
29
|
disabled?: boolean;
|
|
30
|
+
readOnly?: boolean;
|
|
14
31
|
invalid?: boolean;
|
|
15
32
|
error?: string;
|
|
16
33
|
autoFocus?: boolean;
|
|
17
34
|
'aria-label'?: string;
|
|
35
|
+
'aria-describedby'?: string;
|
|
36
|
+
'aria-errormessage'?: string;
|
|
37
|
+
'aria-invalid'?: boolean;
|
|
18
38
|
}
|
|
19
39
|
export type EditableEditor = ReactNode | ((props: EditableEditorProps) => ReactNode);
|
|
20
40
|
export interface EditableProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'onChange'> {
|
|
@@ -29,6 +49,8 @@ export interface EditableProps extends Omit<HTMLAttributes<HTMLDivElement>, 'chi
|
|
|
29
49
|
onCancel?: (value: string) => void;
|
|
30
50
|
display?: ReactNode | ((value: string) => ReactNode);
|
|
31
51
|
editor?: EditableEditor;
|
|
52
|
+
editorType?: EditableEditorType;
|
|
53
|
+
selectProps?: EditableSelectProps;
|
|
32
54
|
multiline?: boolean;
|
|
33
55
|
inputProps?: Omit<InputProps, 'value' | 'defaultValue' | 'onValueChange' | 'onChange'>;
|
|
34
56
|
textareaProps?: Omit<TextareaProps, 'value' | 'defaultValue' | 'onChange'>;
|
package/dist/editable/index.js
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef, useCallback, useEffect, useId, useImperativeHandle, useRef, useState, } from 'react';
|
|
3
3
|
import { Button } from '../Button.js';
|
|
4
|
+
import { PencilIcon } from '../PencilIcon.js';
|
|
5
|
+
import { PencilSurface } from '../PencilSurface.js';
|
|
6
|
+
import { PencilText } from '../PencilText.js';
|
|
4
7
|
import { Input } from '../form/Input.js';
|
|
5
8
|
import { Textarea } from '../form/Textarea.js';
|
|
9
|
+
import { Tooltip } from '../tooltip/Tooltip.js';
|
|
10
|
+
import { Select } from '../select/index.js';
|
|
6
11
|
const classes = (...values) => values.filter(Boolean).join(' ');
|
|
7
12
|
const interactiveSelector = 'button, a, input, textarea, select, option, [contenteditable="true"], [data-editable-ignore]';
|
|
13
|
+
const checkIcon = [{ d: 'm20 6-11 11-5-5' }];
|
|
14
|
+
const cancelIcon = [{ d: 'M18 6 6 18' }, { d: 'm6 6 12 12' }];
|
|
15
|
+
function mergeIds(...ids) {
|
|
16
|
+
return ids.filter(Boolean).join(' ') || undefined;
|
|
17
|
+
}
|
|
8
18
|
function resultMessage(result, fallback) {
|
|
9
19
|
if (typeof result === 'string')
|
|
10
20
|
return result || fallback;
|
|
@@ -15,11 +25,15 @@ function resultMessage(result, fallback) {
|
|
|
15
25
|
function isComposing(event) {
|
|
16
26
|
return event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229;
|
|
17
27
|
}
|
|
18
|
-
export const Editable = forwardRef(function Editable({ 'aria-label': ariaLabel, blurBehavior = 'ignore', className, defaultEditing = false, defaultValue = '', disabled = false, display, editor, editing, id, inputProps, invalid = false, multiline = false, onCancel, onEditingChange, onSave, onValueChange, placeholder = 'Edit value', readOnly = false, saveLabel = 'Save', cancelLabel = 'Cancel', startEditingLabel = 'Edit value', seed, submitOnEnter =
|
|
28
|
+
export const Editable = forwardRef(function Editable({ 'aria-label': ariaLabel, blurBehavior = 'ignore', className, defaultEditing = false, defaultValue = '', disabled = false, display, editor, editorType, editing, id, inputProps, invalid = false, multiline = false, onBlur: onRootBlur, onCancel, onEditingChange, onSave, onValueChange, placeholder = 'Edit value', readOnly = false, saveLabel = 'Save', cancelLabel = 'Cancel', startEditingLabel = 'Edit value', seed, selectProps, submitOnEnter = true, textareaProps, validate, value, ...props }, forwardedRef) {
|
|
19
29
|
const generatedId = useId();
|
|
20
30
|
const rootRef = useRef(null);
|
|
21
31
|
const editorRef = useRef(null);
|
|
22
|
-
const
|
|
32
|
+
const editButtonRef = useRef(null);
|
|
33
|
+
const blurFrameRef = useRef(undefined);
|
|
34
|
+
const savingRef = useRef(false);
|
|
35
|
+
const popupOpenRef = useRef(false);
|
|
36
|
+
const popupFrameRef = useRef(undefined);
|
|
23
37
|
const controlledValue = value !== undefined;
|
|
24
38
|
const controlledEditing = editing !== undefined;
|
|
25
39
|
const [localValue, setLocalValue] = useState(String(value ?? defaultValue));
|
|
@@ -31,6 +45,11 @@ export const Editable = forwardRef(function Editable({ 'aria-label': ariaLabel,
|
|
|
31
45
|
const isEditing = controlledEditing ? Boolean(editing) : localEditing;
|
|
32
46
|
const resolvedSeed = seed ?? `inkra-editable-${id ?? generatedId}`;
|
|
33
47
|
const resolvedId = id ?? `inkra-editable-${generatedId}`;
|
|
48
|
+
const resolvedEditorType = editorType ?? (multiline ? 'textarea' : 'input');
|
|
49
|
+
const isMultiline = resolvedEditorType === 'textarea';
|
|
50
|
+
const resolvedSize = resolvedEditorType === 'select' ? (selectProps?.size ?? 'md') : isMultiline ? (textareaProps?.size ?? 'md') : (inputProps?.size ?? 'md');
|
|
51
|
+
const actionSize = resolvedSize === 'sm' ? 'icon-sm' : resolvedSize === 'lg' ? 'icon-lg' : 'icon';
|
|
52
|
+
const actionIconSize = resolvedSize === 'sm' ? 18 : resolvedSize === 'lg' ? 24 : 20;
|
|
34
53
|
useEffect(() => {
|
|
35
54
|
if (controlledValue) {
|
|
36
55
|
const next = String(value ?? '');
|
|
@@ -43,9 +62,18 @@ export const Editable = forwardRef(function Editable({ 'aria-label': ariaLabel,
|
|
|
43
62
|
useEffect(() => {
|
|
44
63
|
if (!isEditing || disabled || readOnly)
|
|
45
64
|
return;
|
|
46
|
-
const frame = requestAnimationFrame(() =>
|
|
65
|
+
const frame = requestAnimationFrame(() => {
|
|
66
|
+
const control = editorRef.current ?? rootRef.current?.querySelector('[data-editable-editor] input:not([type="hidden"]), [data-editable-editor] textarea, [data-editable-editor] [role="combobox"], [data-editable-editor] [role="spinbutton"]');
|
|
67
|
+
control?.focus({ preventScroll: true });
|
|
68
|
+
});
|
|
47
69
|
return () => cancelAnimationFrame(frame);
|
|
48
70
|
}, [disabled, isEditing, readOnly]);
|
|
71
|
+
useEffect(() => () => {
|
|
72
|
+
if (blurFrameRef.current !== undefined)
|
|
73
|
+
cancelAnimationFrame(blurFrameRef.current);
|
|
74
|
+
if (popupFrameRef.current !== undefined)
|
|
75
|
+
cancelAnimationFrame(popupFrameRef.current);
|
|
76
|
+
}, []);
|
|
49
77
|
const setEditing = useCallback((next) => {
|
|
50
78
|
if (!controlledEditing)
|
|
51
79
|
setLocalEditing(next);
|
|
@@ -57,31 +85,41 @@ export const Editable = forwardRef(function Editable({ 'aria-label': ariaLabel,
|
|
|
57
85
|
onValueChange?.(next);
|
|
58
86
|
}, [controlledValue, onValueChange]);
|
|
59
87
|
const startEditing = useCallback(() => {
|
|
60
|
-
if (disabled || readOnly ||
|
|
88
|
+
if (disabled || readOnly || savingRef.current || isEditing)
|
|
61
89
|
return;
|
|
62
90
|
setError(undefined);
|
|
63
91
|
previousValueRef.current = currentValue;
|
|
64
92
|
setEditing(true);
|
|
65
|
-
}, [currentValue, disabled, isEditing, readOnly,
|
|
93
|
+
}, [currentValue, disabled, isEditing, readOnly, setEditing]);
|
|
66
94
|
const finish = useCallback((restoreFocus = true) => {
|
|
95
|
+
popupOpenRef.current = false;
|
|
67
96
|
setEditing(false);
|
|
68
97
|
if (restoreFocus)
|
|
69
|
-
requestAnimationFrame(() =>
|
|
98
|
+
requestAnimationFrame(() => editButtonRef.current?.focus({ preventScroll: true }));
|
|
70
99
|
}, [setEditing]);
|
|
71
|
-
const cancel = useCallback(() => {
|
|
72
|
-
if (
|
|
100
|
+
const cancel = useCallback((restoreFocus = true) => {
|
|
101
|
+
if (savingRef.current)
|
|
73
102
|
return;
|
|
103
|
+
if (blurFrameRef.current !== undefined) {
|
|
104
|
+
cancelAnimationFrame(blurFrameRef.current);
|
|
105
|
+
blurFrameRef.current = undefined;
|
|
106
|
+
}
|
|
74
107
|
const previous = previousValueRef.current;
|
|
75
108
|
updateValue(previous);
|
|
76
109
|
setError(undefined);
|
|
77
110
|
onCancel?.(previous);
|
|
78
|
-
finish();
|
|
79
|
-
}, [finish, onCancel,
|
|
80
|
-
const save = useCallback(async () => {
|
|
81
|
-
if (
|
|
111
|
+
finish(restoreFocus);
|
|
112
|
+
}, [finish, onCancel, updateValue]);
|
|
113
|
+
const save = useCallback(async (restoreFocus = true) => {
|
|
114
|
+
if (savingRef.current || disabled || readOnly)
|
|
82
115
|
return;
|
|
116
|
+
if (blurFrameRef.current !== undefined) {
|
|
117
|
+
cancelAnimationFrame(blurFrameRef.current);
|
|
118
|
+
blurFrameRef.current = undefined;
|
|
119
|
+
}
|
|
83
120
|
const next = currentValue;
|
|
84
121
|
const previous = previousValueRef.current;
|
|
122
|
+
savingRef.current = true;
|
|
85
123
|
setSaving(true);
|
|
86
124
|
setError(undefined);
|
|
87
125
|
try {
|
|
@@ -99,64 +137,131 @@ export const Editable = forwardRef(function Editable({ 'aria-label': ariaLabel,
|
|
|
99
137
|
}
|
|
100
138
|
previousValueRef.current = next;
|
|
101
139
|
updateValue(next);
|
|
102
|
-
finish();
|
|
140
|
+
finish(restoreFocus);
|
|
103
141
|
}
|
|
104
142
|
catch (caught) {
|
|
105
143
|
setError(caught instanceof Error ? caught.message : 'Could not save value');
|
|
106
144
|
}
|
|
107
145
|
finally {
|
|
146
|
+
savingRef.current = false;
|
|
108
147
|
setSaving(false);
|
|
109
148
|
}
|
|
110
|
-
}, [currentValue, disabled, finish, onSave, readOnly,
|
|
111
|
-
useImperativeHandle(forwardedRef, () => ({ focus: () =>
|
|
149
|
+
}, [currentValue, disabled, finish, onSave, readOnly, updateValue, validate]);
|
|
150
|
+
useImperativeHandle(forwardedRef, () => ({ focus: () => editButtonRef.current?.focus(), startEditing, save, cancel }), [cancel, save, startEditing]);
|
|
112
151
|
const handleDisplayClick = (event) => {
|
|
113
152
|
if (event.target.closest(interactiveSelector))
|
|
114
153
|
return;
|
|
115
154
|
startEditing();
|
|
116
155
|
};
|
|
117
|
-
const handleKeyDown = (event) => {
|
|
118
|
-
if (event.key === 'Enter' || event.key === ' ') {
|
|
119
|
-
event.preventDefault();
|
|
120
|
-
startEditing();
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
156
|
const handleEditorKeyDown = (event) => {
|
|
124
|
-
if (isComposing(event))
|
|
157
|
+
if (event.defaultPrevented || isComposing(event))
|
|
125
158
|
return;
|
|
126
159
|
if (event.key === 'Escape') {
|
|
127
160
|
event.preventDefault();
|
|
128
161
|
cancel();
|
|
129
162
|
return;
|
|
130
163
|
}
|
|
131
|
-
if (event.key === 'Enter' && submitOnEnter && (!
|
|
164
|
+
if (event.key === 'Enter' && submitOnEnter && (!isMultiline || event.ctrlKey || event.metaKey)) {
|
|
132
165
|
event.preventDefault();
|
|
133
166
|
void save();
|
|
134
167
|
}
|
|
135
168
|
};
|
|
136
|
-
const handleEditorBlur = () => {
|
|
137
|
-
if (
|
|
169
|
+
const handleEditorBlur = (event) => {
|
|
170
|
+
if (event.defaultPrevented || popupOpenRef.current || rootRef.current?.contains(event.relatedTarget))
|
|
138
171
|
return;
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
172
|
+
if (blurFrameRef.current !== undefined)
|
|
173
|
+
cancelAnimationFrame(blurFrameRef.current);
|
|
174
|
+
blurFrameRef.current = requestAnimationFrame(() => {
|
|
175
|
+
blurFrameRef.current = undefined;
|
|
176
|
+
if (popupOpenRef.current || rootRef.current?.contains(document.activeElement) || savingRef.current || blurBehavior === 'ignore')
|
|
177
|
+
return;
|
|
178
|
+
if (blurBehavior === 'cancel')
|
|
179
|
+
cancel(false);
|
|
180
|
+
else
|
|
181
|
+
void save(false);
|
|
182
|
+
});
|
|
143
183
|
};
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
:
|
|
184
|
+
const displayValue = resolvedEditorType === 'select' ? (selectProps?.items.find(item => item.value === currentValue)?.label ?? currentValue) : currentValue;
|
|
185
|
+
const displayContent = display == null
|
|
186
|
+
? _jsx(PencilText, { seed: `${resolvedSeed}-display-text`, children: displayValue || placeholder })
|
|
187
|
+
: typeof display === 'function' ? display(currentValue) : display;
|
|
147
188
|
const editorProps = {
|
|
148
189
|
value: currentValue,
|
|
149
190
|
onValueChange: updateValue,
|
|
150
191
|
onKeyDown: handleEditorKeyDown,
|
|
151
192
|
onBlur: handleEditorBlur,
|
|
152
193
|
disabled: disabled || saving,
|
|
194
|
+
readOnly,
|
|
153
195
|
invalid: invalid || Boolean(error),
|
|
154
196
|
error,
|
|
155
197
|
autoFocus: true,
|
|
156
198
|
'aria-label': ariaLabel,
|
|
199
|
+
'aria-describedby': error ? `${resolvedId}-error` : undefined,
|
|
200
|
+
'aria-errormessage': error ? `${resolvedId}-error` : undefined,
|
|
201
|
+
'aria-invalid': invalid || Boolean(error) || undefined,
|
|
202
|
+
};
|
|
203
|
+
const inputDescription = mergeIds(inputProps?.['aria-describedby'], error ? `${resolvedId}-error` : undefined);
|
|
204
|
+
const textareaDescription = mergeIds(textareaProps?.['aria-describedby'], error ? `${resolvedId}-error` : undefined);
|
|
205
|
+
const actions = _jsx(Tooltip.Provider, { children: _jsxs("span", { "aria-label": `${saveLabel}, ${cancelLabel}`, className: "inkra-editable__actions", role: "group", children: [_jsxs(Tooltip.Root, { children: [_jsx(Tooltip.Trigger, { asChild: true, children: _jsx(Button, { "aria-label": saveLabel, className: "inkra-editable__action", disabled: disabled || readOnly, loading: saving, onClick: () => void save(), size: actionSize, title: saveLabel, type: "button", variant: "ghost", children: _jsx(PencilIcon, { decorative: true, paths: checkIcon, seed: `${resolvedSeed}-save-icon`, size: actionIconSize, sourceSize: 24 }) }) }), _jsx(Tooltip.Portal, { children: _jsx(Tooltip.Content, { children: saveLabel }) })] }), _jsxs(Tooltip.Root, { children: [_jsx(Tooltip.Trigger, { asChild: true, children: _jsx(Button, { "aria-label": cancelLabel, className: "inkra-editable__action", disabled: disabled || saving, onClick: () => cancel(), size: actionSize, title: cancelLabel, type: "button", variant: "ghost", children: _jsx(PencilIcon, { decorative: true, paths: cancelIcon, seed: `${resolvedSeed}-cancel-icon`, size: actionIconSize, sourceSize: 24 }) }) }), _jsx(Tooltip.Portal, { children: _jsx(Tooltip.Content, { children: cancelLabel }) })] })] }) });
|
|
206
|
+
const changePopupOpen = (open) => {
|
|
207
|
+
if (popupFrameRef.current !== undefined)
|
|
208
|
+
cancelAnimationFrame(popupFrameRef.current);
|
|
209
|
+
if (open)
|
|
210
|
+
popupOpenRef.current = true;
|
|
211
|
+
else
|
|
212
|
+
popupFrameRef.current = requestAnimationFrame(() => {
|
|
213
|
+
popupOpenRef.current = false;
|
|
214
|
+
if (!rootRef.current || rootRef.current.contains(document.activeElement) || document.activeElement === document.body || savingRef.current)
|
|
215
|
+
return;
|
|
216
|
+
if (blurBehavior === 'cancel')
|
|
217
|
+
cancel(false);
|
|
218
|
+
else if (blurBehavior === 'save')
|
|
219
|
+
void save(false);
|
|
220
|
+
});
|
|
157
221
|
};
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
222
|
+
const items = selectProps?.items ?? [];
|
|
223
|
+
const selectState = {
|
|
224
|
+
value: currentValue,
|
|
225
|
+
onValueChange: (next) => updateValue(next ?? ''),
|
|
226
|
+
disabled: disabled || saving,
|
|
227
|
+
readOnly,
|
|
228
|
+
size: resolvedSize,
|
|
229
|
+
dir: selectProps?.dir,
|
|
230
|
+
placeholder,
|
|
231
|
+
'aria-label': ariaLabel ?? startEditingLabel,
|
|
232
|
+
'aria-describedby': error ? `${resolvedId}-error` : undefined,
|
|
233
|
+
'aria-errormessage': error ? `${resolvedId}-error` : undefined,
|
|
234
|
+
invalid: invalid || Boolean(error),
|
|
235
|
+
};
|
|
236
|
+
const selectEditor = _jsxs("div", { className: "inkra-editable__select-row", onKeyDown: event => {
|
|
237
|
+
if (event.defaultPrevented || popupOpenRef.current || event.target !== event.currentTarget.ownerDocument.activeElement)
|
|
238
|
+
return;
|
|
239
|
+
if (event.key === 'Escape' && !event.nativeEvent.isComposing) {
|
|
240
|
+
event.preventDefault();
|
|
241
|
+
cancel();
|
|
242
|
+
}
|
|
243
|
+
}, children: [selectProps?.mode === 'searchable' ? _jsx(Select.Searchable, { ...selectState, items: items, searchPlaceholder: selectProps.searchPlaceholder, emptyContent: selectProps.emptyContent, clearable: selectProps.clearable ?? false, clearLabel: selectProps.clearLabel, openLabel: selectProps.openLabel, onOpenChange: changePopupOpen })
|
|
244
|
+
: selectProps?.mode === 'stepper' ? _jsx(Select.Stepper, { ...selectState, items: items, loop: selectProps.loop, previousLabel: selectProps.previousLabel, nextLabel: selectProps.nextLabel })
|
|
245
|
+
: _jsxs(Select.Root, { value: currentValue, onValueChange: updateValue, disabled: disabled || saving, readOnly: readOnly, dir: selectProps?.dir, onOpenChange: changePopupOpen, children: [_jsx(Select.Trigger, { "aria-label": ariaLabel ?? startEditingLabel, "aria-describedby": selectState['aria-describedby'], "aria-errormessage": selectState['aria-errormessage'], invalid: selectState.invalid, size: resolvedSize, children: _jsx(Select.Value, { placeholder: placeholder }) }), _jsx(Select.Portal, { children: _jsx(Select.Content, { children: _jsx(Select.Viewport, { children: items.filter(item => item.value !== '').map(item => _jsxs(Select.Item, { value: item.value, disabled: item.disabled, children: [_jsx(Select.ItemText, { children: item.label }), _jsx(Select.ItemIndicator, {})] }, item.value)) }) }) })] }), actions] });
|
|
246
|
+
const defaultEditor = resolvedEditorType === 'select' ? selectEditor : isMultiline
|
|
247
|
+
? _jsx(Textarea, { variant: "underline", ...textareaProps, endAction: _jsxs(_Fragment, { children: [textareaProps?.endAction, actions] }), "aria-describedby": textareaDescription, "aria-errormessage": error ? `${resolvedId}-error` : textareaProps?.['aria-errormessage'], "aria-invalid": invalid || Boolean(error) || textareaProps?.['aria-invalid'], "aria-label": ariaLabel, autoFocus: true, disabled: disabled || saving, invalid: invalid || Boolean(error), onBlur: event => {
|
|
248
|
+
textareaProps?.onBlur?.(event);
|
|
249
|
+
handleEditorBlur(event);
|
|
250
|
+
}, onChange: event => updateValue(event.currentTarget.value), onKeyDown: event => {
|
|
251
|
+
textareaProps?.onKeyDown?.(event);
|
|
252
|
+
handleEditorKeyDown(event);
|
|
253
|
+
}, placeholder: placeholder, readOnly: readOnly, ref: editorRef, seed: `${resolvedSeed}-textarea`, value: currentValue })
|
|
254
|
+
: _jsx(Input, { variant: "underline", ...inputProps, endAction: _jsxs(_Fragment, { children: [inputProps?.endAction, actions] }), "aria-describedby": inputDescription, "aria-errormessage": error ? `${resolvedId}-error` : inputProps?.['aria-errormessage'], "aria-invalid": invalid || Boolean(error) || inputProps?.['aria-invalid'], "aria-label": ariaLabel, autoFocus: true, disabled: disabled || saving, invalid: invalid || Boolean(error), onBlur: event => {
|
|
255
|
+
inputProps?.onBlur?.(event);
|
|
256
|
+
handleEditorBlur(event);
|
|
257
|
+
}, onKeyDown: event => {
|
|
258
|
+
inputProps?.onKeyDown?.(event);
|
|
259
|
+
handleEditorKeyDown(event);
|
|
260
|
+
}, onValueChange: updateValue, placeholder: placeholder, readOnly: readOnly, ref: editorRef, seed: `${resolvedSeed}-input`, value: currentValue });
|
|
261
|
+
return _jsx("div", { ...props, className: classes('inkra-editable', className), "data-disabled": disabled || undefined, "data-editing": isEditing || undefined, "data-saving": saving || undefined, "data-invalid": Boolean(error) || invalid || undefined, "data-multiline": isMultiline || undefined, "data-editor-type": resolvedEditorType, "data-readonly": readOnly || undefined, "data-size": resolvedSize, onBlur: event => {
|
|
262
|
+
onRootBlur?.(event);
|
|
263
|
+
handleEditorBlur(event);
|
|
264
|
+
}, ref: rootRef, children: _jsx("div", { className: "inkra-editable__frame", children: isEditing ? _jsxs("div", { className: "inkra-editable__editor", "data-editable-editor": "true", children: [editor == null ? defaultEditor : _jsxs("div", { className: "inkra-editable__custom-row", children: [typeof editor === 'function' ? editor(editorProps) : editor, actions] }), error ? _jsx(PencilText, { as: "div", className: "inkra-editable__error", role: "alert", id: `${resolvedId}-error`, seed: `${resolvedSeed}-error`, children: error }) : null] }) : _jsxs("div", { className: "inkra-editable__display-shell", children: [_jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-editable__focus-ring", seed: `${resolvedSeed}-focus`, variant: "outline" }), display == null
|
|
265
|
+
? _jsx("button", { "aria-label": ariaLabel ?? startEditingLabel, className: "inkra-editable__display", "data-editable-display": "true", disabled: disabled || readOnly, onClick: startEditing, ref: editButtonRef, type: "button", children: displayContent })
|
|
266
|
+
: _jsxs(_Fragment, { children: [_jsx("div", { className: "inkra-editable__display", "data-editable-display": "true", onClick: handleDisplayClick, children: displayContent }), _jsx("button", { "aria-label": ariaLabel ?? startEditingLabel, className: "inkra-editable__custom-trigger", disabled: disabled || readOnly, onClick: startEditing, ref: editButtonRef, type: "button", children: startEditingLabel })] })] }) }) });
|
|
162
267
|
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PencilIconPath } from '../PencilIcon.js';
|
|
2
|
+
export type EmptyIllustration = 'inbox' | 'search' | 'folder' | 'documents' | 'messages' | 'image' | 'offline' | 'favorites';
|
|
3
|
+
type Illustration = {
|
|
4
|
+
ink: readonly PencilIconPath[];
|
|
5
|
+
accent: readonly PencilIconPath[];
|
|
6
|
+
};
|
|
7
|
+
export declare const emptyIllustrations: Record<EmptyIllustration, Illustration>;
|
|
8
|
+
export {};
|