@inkra/react 0.3.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 +15 -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 +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.js +27 -4
- package/dist/content/index.d.ts +5 -0
- package/dist/content/index.js +12 -3
- package/dist/context-menu/index.js +1 -1
- 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.js +4 -3
- 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/Field.js +11 -10
- 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.js +9 -4
- 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/precision.js +9 -2
- package/dist/overflow-list/index.js +5 -2
- package/dist/overlay/Overlay.js +1 -1
- 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 +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 +2 -0
- package/dist/radar/index.js +40 -20
- 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 +6 -2
- 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 +2094 -421
- 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.js +3 -3
- 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 +7 -5
- package/package.json +413 -3
package/dist/drawer/index.js
CHANGED
|
@@ -40,7 +40,7 @@ export const DrawerContent = forwardRef(function DrawerContent({ children, class
|
|
|
40
40
|
const themedProps = usePortalThemeProps({ ...props, style });
|
|
41
41
|
const mergedStyle = { ...themedProps.style, '--inkra-drawer-size': drawerSize(size) };
|
|
42
42
|
const edgeOrientation = direction === 'left' || direction === 'right' ? 'vertical' : 'horizontal';
|
|
43
|
-
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 })] })] }));
|
|
44
44
|
});
|
|
45
45
|
export const DrawerTitle = forwardRef(function DrawerTitle({ children, className, seed, ...props }, ref) {
|
|
46
46
|
const id = useId();
|
|
@@ -63,7 +63,8 @@ export const DrawerCloseButton = forwardRef(function DrawerCloseButton({ classNa
|
|
|
63
63
|
});
|
|
64
64
|
export const DrawerHeader = forwardRef(function DrawerHeader({ action, children, className, closeLabel = 'Close', divided = true, showClose = true, ...props }, ref) {
|
|
65
65
|
const id = useId();
|
|
66
|
-
|
|
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] });
|
|
67
68
|
});
|
|
68
69
|
export const DrawerBody = forwardRef(function DrawerBody({ className, ...props }, ref) {
|
|
69
70
|
return _jsx("div", { ...props, className: classes('inkra-drawer__body', className), ref: ref });
|
|
@@ -72,7 +73,7 @@ export const DrawerFooter = forwardRef(function DrawerFooter({ align = 'end', ch
|
|
|
72
73
|
const id = useId();
|
|
73
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] });
|
|
74
75
|
});
|
|
75
|
-
export const Drawer = Object.freeze({
|
|
76
|
+
export const Drawer = /* @__PURE__ */ Object.freeze({
|
|
76
77
|
Root: DrawerRoot,
|
|
77
78
|
Trigger: DrawerTrigger,
|
|
78
79
|
Portal: DrawerPortal,
|
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 {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const line = (d) => ({ d, mode: 'scuff' });
|
|
2
|
+
const wash = (d) => ({ d, mode: 'wash' });
|
|
3
|
+
// Geometry lives in a 40-unit square. Fine strokes keep large illustrations airy.
|
|
4
|
+
export const emptyIllustrations = {
|
|
5
|
+
inbox: {
|
|
6
|
+
ink: [
|
|
7
|
+
line('M7 21 12 15H28L33 21V31H7Z'),
|
|
8
|
+
line('M7 21H15L17 25H23L25 21H33'),
|
|
9
|
+
line('M14 19V9H24L28 13V19'),
|
|
10
|
+
line('M24 9V13H28'), line('M17 13H21 M17 16H24'),
|
|
11
|
+
line('M10 28H14 M26 28H30'), line('M5 34Q19 35 35 33'),
|
|
12
|
+
line('M8 12 6 10 M32 14 35 12 M19 5V3'),
|
|
13
|
+
],
|
|
14
|
+
accent: [wash('M8 23H14L17 27H23L26 23H32V30H8Z'), line('M17 19H24'), line('M30 7H34 M32 5V9')],
|
|
15
|
+
},
|
|
16
|
+
search: {
|
|
17
|
+
ink: [
|
|
18
|
+
line('M23 29H8V8H24L28 12V17'), line('M24 8V12H28'),
|
|
19
|
+
line('M12 13H20 M12 17H17 M12 21H15 M12 25H18'),
|
|
20
|
+
line('M31 23A7 7 0 1 1 17 23A7 7 0 1 1 31 23'),
|
|
21
|
+
line('M29 28 35 34 33 36 27 30'), line('M20 23Q20 20 23 19'),
|
|
22
|
+
line('M5 33H20 M4 17V20'),
|
|
23
|
+
],
|
|
24
|
+
accent: [wash('M11 9H22V16H11Z'), line('M22 24H26'), line('M32 10H36 M34 8V12')],
|
|
25
|
+
},
|
|
26
|
+
folder: {
|
|
27
|
+
ink: [
|
|
28
|
+
line('M6 29V12H16L19 15H31V19'),
|
|
29
|
+
line('M7 31 11 20H35L30 31Z'), line('M14 18V9L26 7 28 17'),
|
|
30
|
+
line('M17 12 23 11 M17 15 24 14'), line('M14 24H22'),
|
|
31
|
+
line('M5 34Q20 35 34 33'), line('M4 20 2 19 M32 10 34 8'),
|
|
32
|
+
],
|
|
33
|
+
accent: [wash('M12 22H33L29 30H9Z'), line('M7 12H15'), line('M8 5V8 M6.5 6.5H9.5')],
|
|
34
|
+
},
|
|
35
|
+
documents: {
|
|
36
|
+
ink: [
|
|
37
|
+
line('M10 28 7 10 21 7'), line('M13 31 11 8 28 6 29 12'),
|
|
38
|
+
line('M16 12H27L33 18V33H16Z'), line('M27 12V18H33'),
|
|
39
|
+
line('M20 21H28 M20 25H28 M20 29H25'),
|
|
40
|
+
line('M7 35H30 M5 25V28'),
|
|
41
|
+
],
|
|
42
|
+
accent: [wash('M12 9 25 7 26 10 14 10 14 29 13 29Z'), line('M20 17H23'), line('M33 6V10 M31 8H35')],
|
|
43
|
+
},
|
|
44
|
+
messages: {
|
|
45
|
+
ink: [
|
|
46
|
+
line('M7 9H27Q29 9 29 11V22Q29 24 27 24H16L10 29V24H7Q5 24 5 22V11Q5 9 7 9Z'),
|
|
47
|
+
line('M32 16H33Q35 16 35 18V29Q35 31 33 31H30V35L25 31H19Q17 31 17 29V27'),
|
|
48
|
+
line('M10 14H23 M10 18H19'), line('M5 33H10'),
|
|
49
|
+
],
|
|
50
|
+
accent: [wash('M20 26H27Q31 26 31 22V18H33V29H29V31L26 29H20Z'), line('M22 19H24'), line('M31 4V8 M29 6H33')],
|
|
51
|
+
},
|
|
52
|
+
image: {
|
|
53
|
+
ink: [
|
|
54
|
+
line('M7 27 5 10 29 7 30 11'), line('M10 13H34V31H10Z'),
|
|
55
|
+
line('M11 27 18 20 24 26 28 22 33 27'),
|
|
56
|
+
line('M29 18A2 2 0 1 1 25 18A2 2 0 1 1 29 18'),
|
|
57
|
+
line('M7 35Q21 36 34 34'), line('M4 23V26'),
|
|
58
|
+
],
|
|
59
|
+
accent: [wash('M12 28 18 22 24 28 28 24 33 29H12Z'), line('M10 8 23 6'), line('M34 5V9 M32 7H36')],
|
|
60
|
+
},
|
|
61
|
+
offline: {
|
|
62
|
+
ink: [
|
|
63
|
+
line('M14 24H10A5 5 0 0 1 9 14A8 8 0 0 1 24 12A6 6 0 0 1 32 24H26'),
|
|
64
|
+
line('M18 21 15 25H20L17 30 M23 22 20 27H25L22 32'),
|
|
65
|
+
line('M7 32H12 M28 31H33'), line('M13 12Q15 9 18 10'),
|
|
66
|
+
line('M3 10 5 11 M30 7 32 5'),
|
|
67
|
+
],
|
|
68
|
+
accent: [wash('M8 19Q16 22 32 19V23H25L23 20H17L15 23H10Q7 23 8 19Z'), line('M16 35H22'), line('M24 5V3')],
|
|
69
|
+
},
|
|
70
|
+
favorites: {
|
|
71
|
+
ink: [
|
|
72
|
+
line('M11 8H28V33L20 28 11 33Z'), line('M8 26V5H25'),
|
|
73
|
+
line('M20 12 22 16 27 17 23.5 20.5 24.5 25 20 22.5 15.5 25 16.5 20.5 13 17 18 16Z'),
|
|
74
|
+
line('M7 36H31 M32 26V29'),
|
|
75
|
+
],
|
|
76
|
+
accent: [wash('M20 14 21.5 17.5 25 18 22 20 23 23 20 21 17 23 18 20 15 18 18.5 17.5Z'), line('M32 10V14 M30 12H34')],
|
|
77
|
+
},
|
|
78
|
+
};
|
package/dist/empty/index.d.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import type { ComponentPropsWithoutRef, ElementType, HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import type { EmptyIllustration } from './illustrations.js';
|
|
3
|
+
export type { EmptyIllustration } from './illustrations.js';
|
|
2
4
|
export interface EmptyRootProps extends HTMLAttributes<HTMLDivElement> {
|
|
3
5
|
size?: 'sm' | 'md' | 'lg';
|
|
4
6
|
align?: 'start' | 'center';
|
|
5
7
|
}
|
|
6
8
|
export interface EmptyIconProps extends HTMLAttributes<HTMLDivElement> {
|
|
7
9
|
decorative?: boolean;
|
|
10
|
+
/** Built-in illustration used when children are omitted. */
|
|
11
|
+
illustration?: EmptyIllustration;
|
|
12
|
+
/** Illustration size in CSS pixels; constrained by available width. */
|
|
13
|
+
size?: number;
|
|
8
14
|
}
|
|
9
15
|
type EmptyTitleProps<Element extends ElementType = 'h3'> = {
|
|
10
16
|
as?: Element;
|
|
@@ -18,4 +24,3 @@ export declare const Empty: {
|
|
|
18
24
|
Description: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & import("react").RefAttributes<HTMLParagraphElement>>;
|
|
19
25
|
Actions: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & import("react").RefAttributes<HTMLDivElement>>;
|
|
20
26
|
};
|
|
21
|
-
export {};
|
package/dist/empty/index.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef } from 'react';
|
|
3
3
|
import { PencilText } from '../PencilText.js';
|
|
4
|
+
import { PencilIcon } from '../PencilIcon.js';
|
|
5
|
+
import { emptyIllustrations } from './illustrations.js';
|
|
4
6
|
function classes(base, className) {
|
|
5
7
|
return [base, className].filter(Boolean).join(' ');
|
|
6
8
|
}
|
|
7
9
|
const Root = forwardRef(function EmptyRoot({ align = 'center', className, size = 'md', ...props }, ref) {
|
|
8
10
|
return (_jsx("div", { ...props, className: classes('inkra-empty', className), "data-align": align, "data-size": size, ref: ref }));
|
|
9
11
|
});
|
|
10
|
-
|
|
11
|
-
return (
|
|
12
|
+
function IllustrationLayer({ paths, accent }) {
|
|
13
|
+
return _jsxs("span", { className: classes('inkra-empty__illustration-layer', accent ? 'inkra-empty__illustration-layer--accent' : undefined), children: [_jsx(PencilIcon, { paths: paths, size: 192, sourceSize: 40, decorative: true }), _jsx("svg", { "aria-hidden": "true", focusable: "false", viewBox: "0 0 40 40", className: "inkra-empty__illustration-fallback", children: paths.map((path, index) => _jsx("path", { d: path.d, fill: path.mode === 'wash' ? 'currentColor' : 'none', fillOpacity: 0.12, stroke: path.mode === 'wash' ? 'none' : 'currentColor', strokeWidth: 0.5, strokeLinecap: "round", strokeLinejoin: "round" }, index)) })] });
|
|
14
|
+
}
|
|
15
|
+
const Icon = forwardRef(function EmptyIcon({ children, className, decorative = true, illustration = 'inbox', size, style, ...props }, ref) {
|
|
16
|
+
const builtIn = children === undefined;
|
|
17
|
+
const drawing = emptyIllustrations[illustration] ?? emptyIllustrations.inbox;
|
|
18
|
+
const resolvedSize = typeof size === 'number' && Number.isFinite(size) && size > 0 ? size : undefined;
|
|
19
|
+
return (_jsx("div", { ...props, "aria-hidden": decorative || undefined, role: props.role ?? (!decorative && builtIn ? 'img' : undefined), className: classes('inkra-empty__icon', className), "data-illustration": builtIn ? illustration : undefined, ref: ref, style: { '--inkra-empty-icon-size': resolvedSize === undefined ? undefined : `${resolvedSize}px`, ...style }, children: builtIn ? _jsxs("span", { className: "inkra-empty__illustration", "aria-hidden": "true", children: [_jsx(IllustrationLayer, { paths: drawing.accent, accent: true }), _jsx(IllustrationLayer, { paths: drawing.ink })] }) : children }));
|
|
12
20
|
});
|
|
13
21
|
function Title({ as, children, className, ...props }) {
|
|
14
22
|
const Element = as ?? 'h3';
|
package/dist/flip/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { createContext, forwardRef, useContext, useImperativeHandle, useRef, useState, } from 'react';
|
|
2
|
+
import { createContext, forwardRef, useCallback, useContext, useImperativeHandle, useRef, useState, } from 'react';
|
|
3
3
|
import { Button } from '../Button.js';
|
|
4
4
|
import { useBrowserLayoutEffect } from '../internal/useBrowserLayoutEffect.js';
|
|
5
5
|
const classes = (...values) => values.filter(Boolean).join(' ');
|
|
@@ -36,20 +36,30 @@ function useReducedMotion(onReduce) {
|
|
|
36
36
|
}
|
|
37
37
|
export const Tilt = forwardRef(function Tilt({ axis = 'both', children, className, disabled = false, maxAngle = 8, onPointerCancel, onPointerEnter, onPointerLeave, onPointerMove, resetDuration = 180, response = 120, style, ...props }, forwardedRef) {
|
|
38
38
|
const rootRef = useRef(null);
|
|
39
|
-
const
|
|
39
|
+
const frameRef = useRef(null);
|
|
40
|
+
const pointerRef = useRef(null);
|
|
41
|
+
const cancelFrame = useCallback(() => {
|
|
42
|
+
if (frameRef.current !== null)
|
|
43
|
+
cancelAnimationFrame(frameRef.current);
|
|
44
|
+
frameRef.current = null;
|
|
45
|
+
pointerRef.current = null;
|
|
46
|
+
}, []);
|
|
47
|
+
const reset = useCallback(() => {
|
|
48
|
+
cancelFrame();
|
|
40
49
|
const root = rootRef.current;
|
|
41
50
|
if (!root)
|
|
42
51
|
return;
|
|
43
52
|
root.style.setProperty('--inkra-tilt-rotate-x', '0deg');
|
|
44
53
|
root.style.setProperty('--inkra-tilt-rotate-y', '0deg');
|
|
45
54
|
root.removeAttribute('data-tilting');
|
|
46
|
-
};
|
|
55
|
+
}, [cancelFrame]);
|
|
47
56
|
const reducedMotion = useReducedMotion(reset);
|
|
48
57
|
useImperativeHandle(forwardedRef, () => rootRef.current);
|
|
49
58
|
useBrowserLayoutEffect(() => {
|
|
50
59
|
if (disabled)
|
|
51
60
|
reset();
|
|
52
|
-
}, [disabled]);
|
|
61
|
+
}, [disabled, reset]);
|
|
62
|
+
useBrowserLayoutEffect(() => cancelFrame, [cancelFrame]);
|
|
53
63
|
const canTrack = (event) => (!disabled && !reducedMotion.current && event.pointerType === 'mouse' && event.isPrimary);
|
|
54
64
|
const handlePointerEnter = (event) => {
|
|
55
65
|
onPointerEnter?.(event);
|
|
@@ -61,10 +71,20 @@ export const Tilt = forwardRef(function Tilt({ axis = 'both', children, classNam
|
|
|
61
71
|
onPointerMove?.(event);
|
|
62
72
|
if (event.defaultPrevented || !canTrack(event))
|
|
63
73
|
return;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
pointerRef.current = { root: event.currentTarget, clientX: event.clientX, clientY: event.clientY, maxAngle, axis };
|
|
75
|
+
if (frameRef.current !== null)
|
|
76
|
+
return;
|
|
77
|
+
frameRef.current = requestAnimationFrame(() => {
|
|
78
|
+
frameRef.current = null;
|
|
79
|
+
const pointer = pointerRef.current;
|
|
80
|
+
pointerRef.current = null;
|
|
81
|
+
if (!pointer)
|
|
82
|
+
return;
|
|
83
|
+
const { rotateX, rotateY } = calculateTiltRotation(pointer.clientX, pointer.clientY, pointer.root.getBoundingClientRect(), pointer.maxAngle, pointer.axis);
|
|
84
|
+
pointer.root.style.setProperty('--inkra-tilt-rotate-x', `${rotateX}deg`);
|
|
85
|
+
pointer.root.style.setProperty('--inkra-tilt-rotate-y', `${rotateY}deg`);
|
|
86
|
+
pointer.root.setAttribute('data-tilting', 'true');
|
|
87
|
+
});
|
|
68
88
|
};
|
|
69
89
|
const handlePointerLeave = (event) => {
|
|
70
90
|
onPointerLeave?.(event);
|
package/dist/form/Field.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useId } from 'react';
|
|
2
|
+
import { useId, useMemo } from 'react';
|
|
3
3
|
import { PencilText } from '../PencilText.js';
|
|
4
4
|
import { FieldContext } from './context.js';
|
|
5
5
|
function fieldCopy(value, seed) {
|
|
@@ -14,13 +14,14 @@ export function Field({ children, className, description, disabled = false, erro
|
|
|
14
14
|
const descriptionId = hasDescription ? `${controlId}-description` : undefined;
|
|
15
15
|
const errorId = hasError ? `${controlId}-error` : undefined;
|
|
16
16
|
const classes = ['inkra-field', className].filter(Boolean).join(' ');
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
const context = useMemo(() => ({
|
|
18
|
+
controlId,
|
|
19
|
+
descriptionId,
|
|
20
|
+
errorId,
|
|
21
|
+
required,
|
|
22
|
+
invalid: resolvedInvalid,
|
|
23
|
+
disabled,
|
|
24
|
+
readOnly,
|
|
25
|
+
}), [controlId, descriptionId, errorId, required, resolvedInvalid, disabled, readOnly]);
|
|
26
|
+
return (_jsx(FieldContext.Provider, { value: context, children: _jsxs("div", { ...props, className: classes, "data-disabled": disabled || undefined, "data-invalid": resolvedInvalid || undefined, "data-readonly": readOnly || undefined, "data-required": required || undefined, children: [_jsxs("label", { className: "inkra-field__label", htmlFor: controlId, children: [_jsx("span", { children: fieldCopy(label, `${controlId}-label`) }), required ? _jsx("span", { "aria-hidden": "true", className: "inkra-field__required", children: "*" }) : null] }), _jsx("div", { className: "inkra-field__control", children: children }), hasDescription ? (_jsx("div", { className: "inkra-field__description", id: descriptionId, children: fieldCopy(description, `${controlId}-description`) })) : null, hasError ? (_jsx("div", { className: "inkra-field__error", id: errorId, children: fieldCopy(error, `${controlId}-error`) })) : null] }) }));
|
|
26
27
|
}
|
package/dist/form/Textarea.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TextareaHTMLAttributes } from 'react';
|
|
1
|
+
import type { ReactNode, TextareaHTMLAttributes } from 'react';
|
|
2
2
|
import type { FieldControlStateProps } from './types.js';
|
|
3
3
|
export interface TextareaCountDetails {
|
|
4
4
|
count: number;
|
|
@@ -6,6 +6,8 @@ export interface TextareaCountDetails {
|
|
|
6
6
|
remaining: number;
|
|
7
7
|
}
|
|
8
8
|
export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement>, FieldControlStateProps {
|
|
9
|
+
variant?: 'outline' | 'underline';
|
|
10
|
+
endAction?: ReactNode;
|
|
9
11
|
countMode?: 'remaining' | 'fraction' | 'progress' | 'none';
|
|
10
12
|
countDisplay?: 'auto' | 'always';
|
|
11
13
|
/** Ratio of maxLength at which the automatic counter appears. */
|