@inkra/react 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +316 -2
- package/THIRD_PARTY_NOTICES.md +39 -0
- package/Yozai-OFL.txt +94 -0
- package/dist/Button.d.ts +36 -0
- package/dist/Button.js +89 -0
- package/dist/PencilIcon.d.ts +22 -0
- package/dist/PencilIcon.js +210 -0
- package/dist/PencilLine.d.ts +10 -0
- package/dist/PencilLine.js +91 -0
- package/dist/PencilSurface.d.ts +19 -0
- package/dist/PencilSurface.js +19 -0
- package/dist/PencilText.d.ts +16 -0
- package/dist/PencilText.js +338 -0
- package/dist/accordion/Accordion.d.ts +27 -0
- package/dist/accordion/Accordion.js +40 -0
- package/dist/accordion/index.d.ts +2 -0
- package/dist/accordion/index.js +1 -0
- package/dist/alert-dialog/index.d.ts +64 -0
- package/dist/alert-dialog/index.js +109 -0
- package/dist/assets/ui-hand-yozai.woff2 +0 -0
- package/dist/audio-player/index.d.ts +60 -0
- package/dist/audio-player/index.js +101 -0
- package/dist/breadcrumb/index.d.ts +16 -0
- package/dist/breadcrumb/index.js +25 -0
- package/dist/calendar/index.d.ts +21 -0
- package/dist/calendar/index.js +41 -0
- package/dist/carousel/index.d.ts +51 -0
- package/dist/carousel/index.js +290 -0
- package/dist/choice-grid/index.d.ts +38 -0
- package/dist/choice-grid/index.js +85 -0
- package/dist/color-picker/color.d.ts +15 -0
- package/dist/color-picker/color.js +55 -0
- package/dist/color-picker/index.d.ts +31 -0
- package/dist/color-picker/index.js +69 -0
- package/dist/command/index.d.ts +23 -0
- package/dist/command/index.js +39 -0
- package/dist/content/index.d.ts +106 -0
- package/dist/content/index.js +80 -0
- package/dist/context-menu/index.d.ts +76 -0
- package/dist/context-menu/index.js +240 -0
- package/dist/data-table/index.d.ts +47 -0
- package/dist/data-table/index.js +91 -0
- package/dist/date-picker/index.d.ts +50 -0
- package/dist/date-picker/index.js +180 -0
- package/dist/day-agenda/index.d.ts +43 -0
- package/dist/day-agenda/index.js +47 -0
- package/dist/day-agenda/layout.d.ts +20 -0
- package/dist/day-agenda/layout.js +60 -0
- package/dist/display/ProgressRing.d.ts +6 -0
- package/dist/display/ProgressRing.js +146 -0
- package/dist/display/index.d.ts +59 -0
- package/dist/display/index.js +75 -0
- package/dist/dockable-panel/index.d.ts +41 -0
- package/dist/dockable-panel/index.js +253 -0
- package/dist/dockable-panel/model.d.ts +21 -0
- package/dist/dockable-panel/model.js +61 -0
- package/dist/drawer/index.d.ts +63 -0
- package/dist/drawer/index.js +86 -0
- package/dist/dropdown-menu/index.d.ts +34 -0
- package/dist/dropdown-menu/index.js +40 -0
- package/dist/editable/index.d.ts +53 -0
- package/dist/editable/index.js +162 -0
- package/dist/empty/index.d.ts +21 -0
- package/dist/empty/index.js +23 -0
- package/dist/flip/index.d.ts +49 -0
- package/dist/flip/index.js +138 -0
- package/dist/form/EditablePencilText.d.ts +13 -0
- package/dist/form/EditablePencilText.js +323 -0
- package/dist/form/Field.d.ts +13 -0
- package/dist/form/Field.js +26 -0
- package/dist/form/Input.d.ts +27 -0
- package/dist/form/Input.js +97 -0
- package/dist/form/InputAction.d.ts +7 -0
- package/dist/form/InputAction.js +24 -0
- package/dist/form/Textarea.d.ts +17 -0
- package/dist/form/Textarea.js +102 -0
- package/dist/form/context.d.ts +12 -0
- package/dist/form/context.js +10 -0
- package/dist/form/controlProps.d.ts +23 -0
- package/dist/form/controlProps.js +20 -0
- package/dist/form/index.d.ts +7 -0
- package/dist/form/index.js +3 -0
- package/dist/form/types.d.ts +6 -0
- package/dist/form/types.js +1 -0
- package/dist/heatmap/index.d.ts +59 -0
- package/dist/heatmap/index.js +248 -0
- package/dist/hotkey/index.d.ts +37 -0
- package/dist/hotkey/index.js +130 -0
- package/dist/hotkey/model.d.ts +27 -0
- package/dist/hotkey/model.js +97 -0
- package/dist/hover-card/index.d.ts +33 -0
- package/dist/hover-card/index.js +141 -0
- package/dist/image-cropper/index.d.ts +82 -0
- package/dist/image-cropper/index.js +261 -0
- package/dist/image-cropper/model.d.ts +42 -0
- package/dist/image-cropper/model.js +94 -0
- package/dist/image-viewer/index.d.ts +79 -0
- package/dist/image-viewer/index.js +220 -0
- package/dist/image-viewer/model.d.ts +9 -0
- package/dist/image-viewer/model.js +18 -0
- package/dist/images/layers-2x.png +0 -0
- package/dist/images/layers.png +0 -0
- package/dist/images/marker-icon.png +0 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.js +69 -0
- package/dist/input-number/index.d.ts +16 -0
- package/dist/input-number/index.js +77 -0
- package/dist/internal/InputActionContext.d.ts +1 -0
- package/dist/internal/InputActionContext.js +3 -0
- package/dist/internal/cache.d.ts +14 -0
- package/dist/internal/cache.js +54 -0
- package/dist/internal/line.d.ts +4 -0
- package/dist/internal/line.js +21 -0
- package/dist/internal/paper.d.ts +1 -0
- package/dist/internal/paper.js +65 -0
- package/dist/internal/random.d.ts +3 -0
- package/dist/internal/random.js +30 -0
- package/dist/internal/recovery.d.ts +1 -0
- package/dist/internal/recovery.js +52 -0
- package/dist/internal/renderTokens.d.ts +10 -0
- package/dist/internal/renderTokens.js +13 -0
- package/dist/internal/stroke.d.ts +24 -0
- package/dist/internal/stroke.js +144 -0
- package/dist/internal/surfaceRenderer.d.ts +41 -0
- package/dist/internal/surfaceRenderer.js +178 -0
- package/dist/internal/textQueue.d.ts +1 -0
- package/dist/internal/textQueue.js +37 -0
- package/dist/internal/textRenderer.d.ts +28 -0
- package/dist/internal/textRenderer.js +239 -0
- package/dist/internal/travelIcons.d.ts +24 -0
- package/dist/internal/travelIcons.js +14 -0
- package/dist/internal/useBrowserLayoutEffect.d.ts +2 -0
- package/dist/internal/useBrowserLayoutEffect.js +3 -0
- package/dist/internal/usePencilSurface.d.ts +3 -0
- package/dist/internal/usePencilSurface.js +116 -0
- package/dist/internal/useSelectionDrawing.d.ts +2 -0
- package/dist/internal/useSelectionDrawing.js +90 -0
- package/dist/internal/wash.d.ts +16 -0
- package/dist/internal/wash.js +149 -0
- package/dist/journey-map/MapScale.d.ts +4 -0
- package/dist/journey-map/MapScale.js +54 -0
- package/dist/journey-map/index.d.ts +39 -0
- package/dist/journey-map/index.js +197 -0
- package/dist/journey-map/terrain.d.ts +8 -0
- package/dist/journey-map/terrain.js +127 -0
- package/dist/keypad/index.d.ts +23 -0
- package/dist/keypad/index.js +63 -0
- package/dist/keypad/model.d.ts +20 -0
- package/dist/keypad/model.js +33 -0
- package/dist/layout/index.d.ts +63 -0
- package/dist/layout/index.js +62 -0
- package/dist/log/index.d.ts +45 -0
- package/dist/log/index.js +159 -0
- package/dist/log/model.d.ts +16 -0
- package/dist/log/model.js +13 -0
- package/dist/node-graph/index.d.ts +123 -0
- package/dist/node-graph/index.js +304 -0
- package/dist/number-ticker/index.d.ts +29 -0
- package/dist/number-ticker/index.js +132 -0
- package/dist/number-ticker/model.d.ts +8 -0
- package/dist/number-ticker/model.js +34 -0
- package/dist/overflow-list/index.d.ts +39 -0
- package/dist/overflow-list/index.js +230 -0
- package/dist/overflow-list/layout.d.ts +19 -0
- package/dist/overflow-list/layout.js +44 -0
- package/dist/overlay/Overlay.d.ts +65 -0
- package/dist/overlay/Overlay.js +77 -0
- package/dist/overlay/Popover.d.ts +43 -0
- package/dist/overlay/Popover.js +45 -0
- package/dist/overlay/index.d.ts +4 -0
- package/dist/overlay/index.js +2 -0
- package/dist/overlay/themeBridge.d.ts +8 -0
- package/dist/overlay/themeBridge.js +98 -0
- package/dist/pagination/index.d.ts +23 -0
- package/dist/pagination/index.js +41 -0
- package/dist/pagination/model.d.ts +4 -0
- package/dist/pagination/model.js +42 -0
- package/dist/pan-zoom/index.d.ts +71 -0
- package/dist/pan-zoom/index.js +175 -0
- package/dist/pencil.d.ts +10 -0
- package/dist/pencil.js +39 -0
- package/dist/radar/index.d.ts +54 -0
- package/dist/radar/index.js +220 -0
- package/dist/range-slider/index.d.ts +16 -0
- package/dist/range-slider/index.js +22 -0
- package/dist/rating/index.d.ts +28 -0
- package/dist/rating/index.js +127 -0
- package/dist/resizable/index.d.ts +32 -0
- package/dist/resizable/index.js +50 -0
- package/dist/scroll-area/index.d.ts +36 -0
- package/dist/scroll-area/index.js +44 -0
- package/dist/segmented-progress/SegmentedProgress.d.ts +17 -0
- package/dist/segmented-progress/SegmentedProgress.js +42 -0
- package/dist/select/MultipleSelect.d.ts +44 -0
- package/dist/select/MultipleSelect.js +124 -0
- package/dist/select/SearchableSelect.d.ts +45 -0
- package/dist/select/SearchableSelect.js +50 -0
- package/dist/select/Select.d.ts +109 -0
- package/dist/select/Select.js +205 -0
- package/dist/select/index.d.ts +4 -0
- package/dist/select/index.js +2 -0
- package/dist/selection/Checkbox.d.ts +9 -0
- package/dist/selection/Checkbox.js +37 -0
- package/dist/selection/RadioGroup.d.ts +23 -0
- package/dist/selection/RadioGroup.js +82 -0
- package/dist/selection/Switch.d.ts +8 -0
- package/dist/selection/Switch.js +36 -0
- package/dist/selection/index.d.ts +6 -0
- package/dist/selection/index.js +3 -0
- package/dist/selection/useNativeChecked.d.ts +13 -0
- package/dist/selection/useNativeChecked.js +27 -0
- package/dist/slider/index.d.ts +11 -0
- package/dist/slider/index.js +45 -0
- package/dist/slot/index.d.ts +24 -0
- package/dist/slot/index.js +29 -0
- package/dist/sortable/index.d.ts +50 -0
- package/dist/sortable/index.js +278 -0
- package/dist/sortable/model.d.ts +30 -0
- package/dist/sortable/model.js +64 -0
- package/dist/sparkline/index.d.ts +19 -0
- package/dist/sparkline/index.js +240 -0
- package/dist/sparkline/model.d.ts +16 -0
- package/dist/sparkline/model.js +28 -0
- package/dist/steps/index.d.ts +16 -0
- package/dist/steps/index.js +37 -0
- package/dist/styles.css +8226 -0
- package/dist/tabs/index.d.ts +22 -0
- package/dist/tabs/index.js +42 -0
- package/dist/tag-input/index.d.ts +69 -0
- package/dist/tag-input/index.js +325 -0
- package/dist/tag-input/model.d.ts +14 -0
- package/dist/tag-input/model.js +38 -0
- package/dist/time-picker/index.d.ts +15 -0
- package/dist/time-picker/index.js +168 -0
- package/dist/timeline/index.d.ts +14 -0
- package/dist/timeline/index.js +16 -0
- package/dist/toast/index.d.ts +27 -0
- package/dist/toast/index.js +36 -0
- package/dist/toggle-group/index.d.ts +17 -0
- package/dist/toggle-group/index.js +26 -0
- package/dist/tokens.css +356 -0
- package/dist/tooltip/Tooltip.d.ts +24 -0
- package/dist/tooltip/Tooltip.js +32 -0
- package/dist/tooltip/index.d.ts +2 -0
- package/dist/tooltip/index.js +1 -0
- package/dist/transfer/index.d.ts +64 -0
- package/dist/transfer/index.js +174 -0
- package/dist/transfer/model.d.ts +12 -0
- package/dist/transfer/model.js +33 -0
- package/dist/tree/index.d.ts +39 -0
- package/dist/tree/index.js +36 -0
- package/dist/tree-select/index.d.ts +59 -0
- package/dist/tree-select/index.js +142 -0
- package/dist/tree-select/model.d.ts +31 -0
- package/dist/tree-select/model.js +135 -0
- package/dist/typewriter/index.d.ts +21 -0
- package/dist/typewriter/index.js +101 -0
- package/dist/typewriter/model.d.ts +7 -0
- package/dist/typewriter/model.js +45 -0
- package/dist/upload/index.d.ts +59 -0
- package/dist/upload/index.js +230 -0
- package/dist/virtual-list/index.d.ts +44 -0
- package/dist/virtual-list/index.js +128 -0
- package/dist/virtual-list/model.d.ts +7 -0
- package/dist/virtual-list/model.js +27 -0
- package/package.json +119 -4
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useCallback, useEffect, useId, useImperativeHandle, useRef, useState, } from 'react';
|
|
3
|
+
import { Button } from '../Button.js';
|
|
4
|
+
import { Input } from '../form/Input.js';
|
|
5
|
+
import { Textarea } from '../form/Textarea.js';
|
|
6
|
+
const classes = (...values) => values.filter(Boolean).join(' ');
|
|
7
|
+
const interactiveSelector = 'button, a, input, textarea, select, option, [contenteditable="true"], [data-editable-ignore]';
|
|
8
|
+
function resultMessage(result, fallback) {
|
|
9
|
+
if (typeof result === 'string')
|
|
10
|
+
return result || fallback;
|
|
11
|
+
if (result === false)
|
|
12
|
+
return fallback;
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
function isComposing(event) {
|
|
16
|
+
return event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229;
|
|
17
|
+
}
|
|
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 = !multiline, textareaProps, validate, value, ...props }, forwardedRef) {
|
|
19
|
+
const generatedId = useId();
|
|
20
|
+
const rootRef = useRef(null);
|
|
21
|
+
const editorRef = useRef(null);
|
|
22
|
+
const displayRef = useRef(null);
|
|
23
|
+
const controlledValue = value !== undefined;
|
|
24
|
+
const controlledEditing = editing !== undefined;
|
|
25
|
+
const [localValue, setLocalValue] = useState(String(value ?? defaultValue));
|
|
26
|
+
const [localEditing, setLocalEditing] = useState(defaultEditing);
|
|
27
|
+
const [error, setError] = useState();
|
|
28
|
+
const [saving, setSaving] = useState(false);
|
|
29
|
+
const previousValueRef = useRef(String(value ?? defaultValue));
|
|
30
|
+
const currentValue = controlledValue ? String(value ?? '') : localValue;
|
|
31
|
+
const isEditing = controlledEditing ? Boolean(editing) : localEditing;
|
|
32
|
+
const resolvedSeed = seed ?? `inkra-editable-${id ?? generatedId}`;
|
|
33
|
+
const resolvedId = id ?? `inkra-editable-${generatedId}`;
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (controlledValue) {
|
|
36
|
+
const next = String(value ?? '');
|
|
37
|
+
if (!isEditing) {
|
|
38
|
+
previousValueRef.current = next;
|
|
39
|
+
setLocalValue(next);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}, [controlledValue, isEditing, value]);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (!isEditing || disabled || readOnly)
|
|
45
|
+
return;
|
|
46
|
+
const frame = requestAnimationFrame(() => editorRef.current?.focus({ preventScroll: true }));
|
|
47
|
+
return () => cancelAnimationFrame(frame);
|
|
48
|
+
}, [disabled, isEditing, readOnly]);
|
|
49
|
+
const setEditing = useCallback((next) => {
|
|
50
|
+
if (!controlledEditing)
|
|
51
|
+
setLocalEditing(next);
|
|
52
|
+
onEditingChange?.(next);
|
|
53
|
+
}, [controlledEditing, onEditingChange]);
|
|
54
|
+
const updateValue = useCallback((next) => {
|
|
55
|
+
if (!controlledValue)
|
|
56
|
+
setLocalValue(next);
|
|
57
|
+
onValueChange?.(next);
|
|
58
|
+
}, [controlledValue, onValueChange]);
|
|
59
|
+
const startEditing = useCallback(() => {
|
|
60
|
+
if (disabled || readOnly || saving || isEditing)
|
|
61
|
+
return;
|
|
62
|
+
setError(undefined);
|
|
63
|
+
previousValueRef.current = currentValue;
|
|
64
|
+
setEditing(true);
|
|
65
|
+
}, [currentValue, disabled, isEditing, readOnly, saving, setEditing]);
|
|
66
|
+
const finish = useCallback((restoreFocus = true) => {
|
|
67
|
+
setEditing(false);
|
|
68
|
+
if (restoreFocus)
|
|
69
|
+
requestAnimationFrame(() => displayRef.current?.focus({ preventScroll: true }));
|
|
70
|
+
}, [setEditing]);
|
|
71
|
+
const cancel = useCallback(() => {
|
|
72
|
+
if (saving)
|
|
73
|
+
return;
|
|
74
|
+
const previous = previousValueRef.current;
|
|
75
|
+
updateValue(previous);
|
|
76
|
+
setError(undefined);
|
|
77
|
+
onCancel?.(previous);
|
|
78
|
+
finish();
|
|
79
|
+
}, [finish, onCancel, saving, updateValue]);
|
|
80
|
+
const save = useCallback(async () => {
|
|
81
|
+
if (saving || disabled || readOnly)
|
|
82
|
+
return;
|
|
83
|
+
const next = currentValue;
|
|
84
|
+
const previous = previousValueRef.current;
|
|
85
|
+
setSaving(true);
|
|
86
|
+
setError(undefined);
|
|
87
|
+
try {
|
|
88
|
+
const validation = validate ? await validate(next, previous) : undefined;
|
|
89
|
+
const validationMessage = resultMessage(validation, 'Value is invalid');
|
|
90
|
+
if (validationMessage) {
|
|
91
|
+
setError(validationMessage);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const saved = onSave ? await onSave(next, previous) : undefined;
|
|
95
|
+
const saveMessage = resultMessage(saved, 'Could not save value');
|
|
96
|
+
if (saveMessage) {
|
|
97
|
+
setError(saveMessage);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
previousValueRef.current = next;
|
|
101
|
+
updateValue(next);
|
|
102
|
+
finish();
|
|
103
|
+
}
|
|
104
|
+
catch (caught) {
|
|
105
|
+
setError(caught instanceof Error ? caught.message : 'Could not save value');
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
setSaving(false);
|
|
109
|
+
}
|
|
110
|
+
}, [currentValue, disabled, finish, onSave, readOnly, saving, updateValue, validate]);
|
|
111
|
+
useImperativeHandle(forwardedRef, () => ({ focus: () => displayRef.current?.focus(), startEditing, save, cancel }), [cancel, save, startEditing]);
|
|
112
|
+
const handleDisplayClick = (event) => {
|
|
113
|
+
if (event.target.closest(interactiveSelector))
|
|
114
|
+
return;
|
|
115
|
+
startEditing();
|
|
116
|
+
};
|
|
117
|
+
const handleKeyDown = (event) => {
|
|
118
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
119
|
+
event.preventDefault();
|
|
120
|
+
startEditing();
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
const handleEditorKeyDown = (event) => {
|
|
124
|
+
if (isComposing(event))
|
|
125
|
+
return;
|
|
126
|
+
if (event.key === 'Escape') {
|
|
127
|
+
event.preventDefault();
|
|
128
|
+
cancel();
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (event.key === 'Enter' && submitOnEnter && (!multiline || event.ctrlKey || event.metaKey)) {
|
|
132
|
+
event.preventDefault();
|
|
133
|
+
void save();
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
const handleEditorBlur = () => {
|
|
137
|
+
if (saving || blurBehavior === 'ignore')
|
|
138
|
+
return;
|
|
139
|
+
if (blurBehavior === 'cancel')
|
|
140
|
+
cancel();
|
|
141
|
+
else
|
|
142
|
+
void save();
|
|
143
|
+
};
|
|
144
|
+
const displayContent = typeof display === 'function'
|
|
145
|
+
? display(currentValue)
|
|
146
|
+
: (display ?? currentValue) || placeholder;
|
|
147
|
+
const editorProps = {
|
|
148
|
+
value: currentValue,
|
|
149
|
+
onValueChange: updateValue,
|
|
150
|
+
onKeyDown: handleEditorKeyDown,
|
|
151
|
+
onBlur: handleEditorBlur,
|
|
152
|
+
disabled: disabled || saving,
|
|
153
|
+
invalid: invalid || Boolean(error),
|
|
154
|
+
error,
|
|
155
|
+
autoFocus: true,
|
|
156
|
+
'aria-label': ariaLabel,
|
|
157
|
+
};
|
|
158
|
+
const defaultEditor = multiline
|
|
159
|
+
? _jsx(Textarea, { ...textareaProps, "aria-label": ariaLabel, autoFocus: true, ref: editorRef, value: currentValue, onChange: event => updateValue(event.currentTarget.value), onKeyDown: handleEditorKeyDown, onBlur: handleEditorBlur, disabled: disabled || saving, invalid: invalid || Boolean(error), placeholder: placeholder, seed: `${resolvedSeed}-textarea` })
|
|
160
|
+
: _jsx(Input, { ...inputProps, "aria-label": ariaLabel, autoFocus: true, ref: editorRef, value: currentValue, onValueChange: updateValue, onKeyDown: handleEditorKeyDown, onBlur: handleEditorBlur, disabled: disabled || saving, invalid: invalid || Boolean(error), placeholder: placeholder, seed: `${resolvedSeed}-input` });
|
|
161
|
+
return _jsx("div", { ...props, className: classes('inkra-editable', className), "data-editing": isEditing || undefined, "data-saving": saving || undefined, "data-invalid": Boolean(error) || invalid || undefined, "data-multiline": multiline || undefined, ref: rootRef, children: isEditing ? _jsxs("div", { className: "inkra-editable__editor", "data-editable-editor": "true", children: [editor == null ? defaultEditor : typeof editor === 'function' ? editor(editorProps) : editor, _jsxs("div", { className: "inkra-editable__actions", children: [_jsx(Button, { type: "button", size: "sm", variant: "primary", loading: saving, onClick: () => void save(), "aria-label": saveLabel, children: saveLabel }), _jsx(Button, { type: "button", size: "sm", variant: "ghost", disabled: saving, onClick: cancel, "aria-label": cancelLabel, children: cancelLabel })] }), error ? _jsx("div", { className: "inkra-editable__error", role: "alert", id: `${resolvedId}-error`, children: error }) : null] }) : _jsx("div", { "aria-label": ariaLabel ?? startEditingLabel, className: "inkra-editable__display", "data-editable-display": "true", onClick: handleDisplayClick, onKeyDown: handleKeyDown, ref: displayRef, role: "button", tabIndex: disabled || readOnly ? -1 : 0, "aria-disabled": disabled || readOnly || undefined, children: displayContent }) });
|
|
162
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef, ElementType, HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export interface EmptyRootProps extends HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
size?: 'sm' | 'md' | 'lg';
|
|
4
|
+
align?: 'start' | 'center';
|
|
5
|
+
}
|
|
6
|
+
export interface EmptyIconProps extends HTMLAttributes<HTMLDivElement> {
|
|
7
|
+
decorative?: boolean;
|
|
8
|
+
}
|
|
9
|
+
type EmptyTitleProps<Element extends ElementType = 'h3'> = {
|
|
10
|
+
as?: Element;
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
} & Omit<ComponentPropsWithoutRef<Element>, 'as' | 'children'>;
|
|
13
|
+
declare function Title<Element extends ElementType = 'h3'>({ as, children, className, ...props }: EmptyTitleProps<Element>): import("react").JSX.Element;
|
|
14
|
+
export declare const Empty: {
|
|
15
|
+
Root: import("react").ForwardRefExoticComponent<EmptyRootProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
16
|
+
Icon: import("react").ForwardRefExoticComponent<EmptyIconProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
17
|
+
Title: typeof Title;
|
|
18
|
+
Description: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & import("react").RefAttributes<HTMLParagraphElement>>;
|
|
19
|
+
Actions: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & import("react").RefAttributes<HTMLDivElement>>;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
import { PencilText } from '../PencilText.js';
|
|
4
|
+
function classes(base, className) {
|
|
5
|
+
return [base, className].filter(Boolean).join(' ');
|
|
6
|
+
}
|
|
7
|
+
const Root = forwardRef(function EmptyRoot({ align = 'center', className, size = 'md', ...props }, ref) {
|
|
8
|
+
return (_jsx("div", { ...props, className: classes('inkra-empty', className), "data-align": align, "data-size": size, ref: ref }));
|
|
9
|
+
});
|
|
10
|
+
const Icon = forwardRef(function EmptyIcon({ className, decorative = true, ...props }, ref) {
|
|
11
|
+
return (_jsx("div", { ...props, "aria-hidden": decorative || undefined, className: classes('inkra-empty__icon', className), ref: ref }));
|
|
12
|
+
});
|
|
13
|
+
function Title({ as, children, className, ...props }) {
|
|
14
|
+
const Element = as ?? 'h3';
|
|
15
|
+
return (_jsx(Element, { ...props, className: classes('inkra-empty__title', className), children: typeof children === 'string' ? _jsx(PencilText, { children: children }) : children }));
|
|
16
|
+
}
|
|
17
|
+
const Description = forwardRef(function EmptyDescription({ children, className, ...props }, ref) {
|
|
18
|
+
return (_jsx("p", { ...props, className: classes('inkra-empty__description', className), ref: ref, children: typeof children === 'string' ? _jsx(PencilText, { children: children }) : children }));
|
|
19
|
+
});
|
|
20
|
+
const Actions = forwardRef(function EmptyActions({ className, ...props }, ref) {
|
|
21
|
+
return _jsx("div", { ...props, className: classes('inkra-empty__actions', className), ref: ref });
|
|
22
|
+
});
|
|
23
|
+
export const Empty = { Root, Icon, Title, Description, Actions };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { HTMLAttributes, PointerEvent as ReactPointerEvent, ReactNode } from 'react';
|
|
2
|
+
import type { ButtonProps } from '../Button.js';
|
|
3
|
+
export type TiltAxis = 'both' | 'x' | 'y';
|
|
4
|
+
export interface TiltRotation {
|
|
5
|
+
rotateX: number;
|
|
6
|
+
rotateY: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function calculateTiltRotation(clientX: number, clientY: number, bounds: Pick<DOMRect, 'left' | 'top' | 'width' | 'height'>, maxAngle: number, axis?: TiltAxis): TiltRotation;
|
|
9
|
+
export interface TiltProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onPointerMove'> {
|
|
10
|
+
/** Rotation axes that respond to the mouse position. */
|
|
11
|
+
axis?: TiltAxis;
|
|
12
|
+
/** Disables pointer tracking and returns the content to its resting position. */
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
/** Maximum rotation in degrees at each edge. */
|
|
15
|
+
maxAngle?: number;
|
|
16
|
+
/** Transform response time while following the mouse, in milliseconds. */
|
|
17
|
+
response?: number;
|
|
18
|
+
/** Transform duration used when the mouse leaves, in milliseconds. */
|
|
19
|
+
resetDuration?: number;
|
|
20
|
+
onPointerMove?: (event: ReactPointerEvent<HTMLDivElement>) => void;
|
|
21
|
+
}
|
|
22
|
+
export declare const Tilt: import("react").ForwardRefExoticComponent<TiltProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
23
|
+
export interface FlipProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'onChange'> {
|
|
24
|
+
/** Content shown in the initial orientation. */
|
|
25
|
+
front: ReactNode;
|
|
26
|
+
/** Content shown after flipping. */
|
|
27
|
+
back: ReactNode;
|
|
28
|
+
/** Controlled flipped state. */
|
|
29
|
+
flipped?: boolean;
|
|
30
|
+
/** Initial state when Flip is uncontrolled. */
|
|
31
|
+
defaultFlipped?: boolean;
|
|
32
|
+
/** Enables state changes without disabling content inside either face. */
|
|
33
|
+
flipEnabled?: boolean;
|
|
34
|
+
onFlippedChange?: (flipped: boolean) => void;
|
|
35
|
+
/** Enables mouse tilt independently from flipping. */
|
|
36
|
+
tilt?: boolean;
|
|
37
|
+
tiltAxis?: TiltAxis;
|
|
38
|
+
tiltMaxAngle?: number;
|
|
39
|
+
tiltResponse?: number;
|
|
40
|
+
tiltResetDuration?: number;
|
|
41
|
+
/** Flip transition duration in milliseconds. */
|
|
42
|
+
duration?: number;
|
|
43
|
+
}
|
|
44
|
+
export declare const Flip: import("react").ForwardRefExoticComponent<FlipProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
45
|
+
export interface FlipToggleProps extends ButtonProps {
|
|
46
|
+
/** Explicit next state; omit to toggle the current state. */
|
|
47
|
+
flipped?: boolean;
|
|
48
|
+
}
|
|
49
|
+
export declare const FlipToggle: import("react").ForwardRefExoticComponent<FlipToggleProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, forwardRef, useContext, useImperativeHandle, useRef, useState, } from 'react';
|
|
3
|
+
import { Button } from '../Button.js';
|
|
4
|
+
import { useBrowserLayoutEffect } from '../internal/useBrowserLayoutEffect.js';
|
|
5
|
+
const classes = (...values) => values.filter(Boolean).join(' ');
|
|
6
|
+
const clamp = (value, minimum, maximum) => Math.min(maximum, Math.max(minimum, value));
|
|
7
|
+
export function calculateTiltRotation(clientX, clientY, bounds, maxAngle, axis = 'both') {
|
|
8
|
+
if (bounds.width <= 0 || bounds.height <= 0)
|
|
9
|
+
return { rotateX: 0, rotateY: 0 };
|
|
10
|
+
const horizontal = clamp(((clientX - bounds.left) / bounds.width) * 2 - 1, -1, 1);
|
|
11
|
+
const vertical = clamp(((clientY - bounds.top) / bounds.height) * 2 - 1, -1, 1);
|
|
12
|
+
const angle = Math.max(0, Math.abs(maxAngle));
|
|
13
|
+
const rotateX = axis === 'y' ? 0 : vertical * angle;
|
|
14
|
+
const rotateY = axis === 'x' ? 0 : -horizontal * angle;
|
|
15
|
+
return {
|
|
16
|
+
rotateX: rotateX === 0 ? 0 : rotateX,
|
|
17
|
+
rotateY: rotateY === 0 ? 0 : rotateY,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function useReducedMotion(onReduce) {
|
|
21
|
+
const reducedRef = useRef(false);
|
|
22
|
+
useBrowserLayoutEffect(() => {
|
|
23
|
+
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function')
|
|
24
|
+
return undefined;
|
|
25
|
+
const query = window.matchMedia('(prefers-reduced-motion: reduce)');
|
|
26
|
+
const update = () => {
|
|
27
|
+
reducedRef.current = query.matches;
|
|
28
|
+
if (query.matches)
|
|
29
|
+
onReduce();
|
|
30
|
+
};
|
|
31
|
+
update();
|
|
32
|
+
query.addEventListener('change', update);
|
|
33
|
+
return () => query.removeEventListener('change', update);
|
|
34
|
+
}, [onReduce]);
|
|
35
|
+
return reducedRef;
|
|
36
|
+
}
|
|
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
|
+
const rootRef = useRef(null);
|
|
39
|
+
const reset = () => {
|
|
40
|
+
const root = rootRef.current;
|
|
41
|
+
if (!root)
|
|
42
|
+
return;
|
|
43
|
+
root.style.setProperty('--inkra-tilt-rotate-x', '0deg');
|
|
44
|
+
root.style.setProperty('--inkra-tilt-rotate-y', '0deg');
|
|
45
|
+
root.removeAttribute('data-tilting');
|
|
46
|
+
};
|
|
47
|
+
const reducedMotion = useReducedMotion(reset);
|
|
48
|
+
useImperativeHandle(forwardedRef, () => rootRef.current);
|
|
49
|
+
useBrowserLayoutEffect(() => {
|
|
50
|
+
if (disabled)
|
|
51
|
+
reset();
|
|
52
|
+
}, [disabled]);
|
|
53
|
+
const canTrack = (event) => (!disabled && !reducedMotion.current && event.pointerType === 'mouse' && event.isPrimary);
|
|
54
|
+
const handlePointerEnter = (event) => {
|
|
55
|
+
onPointerEnter?.(event);
|
|
56
|
+
if (event.defaultPrevented || !canTrack(event))
|
|
57
|
+
return;
|
|
58
|
+
event.currentTarget.setAttribute('data-tilting', 'true');
|
|
59
|
+
};
|
|
60
|
+
const handlePointerMove = (event) => {
|
|
61
|
+
onPointerMove?.(event);
|
|
62
|
+
if (event.defaultPrevented || !canTrack(event))
|
|
63
|
+
return;
|
|
64
|
+
const { rotateX, rotateY } = calculateTiltRotation(event.clientX, event.clientY, event.currentTarget.getBoundingClientRect(), maxAngle, axis);
|
|
65
|
+
event.currentTarget.style.setProperty('--inkra-tilt-rotate-x', `${rotateX}deg`);
|
|
66
|
+
event.currentTarget.style.setProperty('--inkra-tilt-rotate-y', `${rotateY}deg`);
|
|
67
|
+
event.currentTarget.setAttribute('data-tilting', 'true');
|
|
68
|
+
};
|
|
69
|
+
const handlePointerLeave = (event) => {
|
|
70
|
+
onPointerLeave?.(event);
|
|
71
|
+
reset();
|
|
72
|
+
};
|
|
73
|
+
const handlePointerCancel = (event) => {
|
|
74
|
+
onPointerCancel?.(event);
|
|
75
|
+
reset();
|
|
76
|
+
};
|
|
77
|
+
const tiltStyle = {
|
|
78
|
+
'--inkra-tilt-max-angle': `${Math.max(0, Math.abs(maxAngle))}deg`,
|
|
79
|
+
'--inkra-tilt-response': `${Math.max(0, response)}ms`,
|
|
80
|
+
'--inkra-tilt-reset-duration': `${Math.max(0, resetDuration)}ms`,
|
|
81
|
+
'--inkra-tilt-rotate-x': '0deg',
|
|
82
|
+
'--inkra-tilt-rotate-y': '0deg',
|
|
83
|
+
...style,
|
|
84
|
+
};
|
|
85
|
+
return _jsx("div", { ...props, className: classes('inkra-tilt', className), "data-axis": axis, "data-disabled": disabled || undefined, onPointerCancel: handlePointerCancel, onPointerEnter: handlePointerEnter, onPointerLeave: handlePointerLeave, onPointerMove: handlePointerMove, ref: rootRef, style: tiltStyle, children: children });
|
|
86
|
+
});
|
|
87
|
+
const FlipContext = createContext(null);
|
|
88
|
+
const focusableSelector = [
|
|
89
|
+
'a[href]',
|
|
90
|
+
'button:not(:disabled)',
|
|
91
|
+
'input:not(:disabled)',
|
|
92
|
+
'select:not(:disabled)',
|
|
93
|
+
'textarea:not(:disabled)',
|
|
94
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
95
|
+
].join(',');
|
|
96
|
+
export const Flip = forwardRef(function Flip({ back, className, defaultFlipped = false, duration = 420, flipEnabled = true, flipped: controlledFlipped, front, onFlippedChange, style, tabIndex, tilt = false, tiltAxis = 'both', tiltMaxAngle = 8, tiltResetDuration = 180, tiltResponse = 120, ...props }, forwardedRef) {
|
|
97
|
+
const rootRef = useRef(null);
|
|
98
|
+
const frontRef = useRef(null);
|
|
99
|
+
const backRef = useRef(null);
|
|
100
|
+
const previousFlipped = useRef(controlledFlipped ?? defaultFlipped);
|
|
101
|
+
const [uncontrolledFlipped, setUncontrolledFlipped] = useState(defaultFlipped);
|
|
102
|
+
const flipped = controlledFlipped ?? uncontrolledFlipped;
|
|
103
|
+
useImperativeHandle(forwardedRef, () => rootRef.current);
|
|
104
|
+
const setFlipped = (next) => {
|
|
105
|
+
if (!flipEnabled || next === flipped)
|
|
106
|
+
return;
|
|
107
|
+
if (controlledFlipped === undefined)
|
|
108
|
+
setUncontrolledFlipped(next);
|
|
109
|
+
onFlippedChange?.(next);
|
|
110
|
+
};
|
|
111
|
+
useBrowserLayoutEffect(() => {
|
|
112
|
+
if (previousFlipped.current === flipped)
|
|
113
|
+
return;
|
|
114
|
+
previousFlipped.current = flipped;
|
|
115
|
+
const outgoing = flipped ? frontRef.current : backRef.current;
|
|
116
|
+
if (!outgoing?.contains(document.activeElement))
|
|
117
|
+
return;
|
|
118
|
+
const incoming = flipped ? backRef.current : frontRef.current;
|
|
119
|
+
const nextFocus = incoming?.querySelector(focusableSelector);
|
|
120
|
+
(nextFocus ?? rootRef.current)?.focus({ preventScroll: true });
|
|
121
|
+
}, [flipped]);
|
|
122
|
+
const context = { enabled: flipEnabled, flipped, setFlipped };
|
|
123
|
+
const flipStyle = {
|
|
124
|
+
'--inkra-flip-duration': `${Math.max(0, duration)}ms`,
|
|
125
|
+
...style,
|
|
126
|
+
};
|
|
127
|
+
return _jsx(FlipContext.Provider, { value: context, children: _jsx(Tilt, { ...props, axis: tiltAxis, className: classes('inkra-flip', className), "data-flipped": flipped || undefined, disabled: !tilt, maxAngle: tiltMaxAngle, ref: rootRef, resetDuration: tiltResetDuration, response: tiltResponse, style: flipStyle, tabIndex: tabIndex ?? -1, children: _jsxs("div", { className: "inkra-flip__scene", children: [_jsx("div", { "aria-hidden": flipped || undefined, className: "inkra-flip__face inkra-flip__face--front", "data-active": !flipped || undefined, inert: flipped || undefined, ref: frontRef, children: front }), _jsx("div", { "aria-hidden": !flipped || undefined, className: "inkra-flip__face inkra-flip__face--back", "data-active": flipped || undefined, inert: !flipped || undefined, ref: backRef, children: back })] }) }) });
|
|
128
|
+
});
|
|
129
|
+
export const FlipToggle = forwardRef(function FlipToggle({ children, className, disabled, flipped: nextFlipped, onClick, type = 'button', ...props }, ref) {
|
|
130
|
+
const context = useContext(FlipContext);
|
|
131
|
+
if (!context)
|
|
132
|
+
throw new Error('FlipToggle must be rendered inside Flip.');
|
|
133
|
+
return _jsx(Button, { ...props, "aria-pressed": context.flipped, className: classes('inkra-flip-toggle', className), disabled: disabled || !context.enabled, onClick: event => {
|
|
134
|
+
onClick?.(event);
|
|
135
|
+
if (!event.defaultPrevented)
|
|
136
|
+
context.setFlipped(nextFlipped ?? !context.flipped);
|
|
137
|
+
}, ref: ref, type: type, children: children });
|
|
138
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
type EditableControl = HTMLInputElement | HTMLTextAreaElement;
|
|
3
|
+
interface EditablePencilTextProps {
|
|
4
|
+
controlRef: RefObject<EditableControl | null>;
|
|
5
|
+
defaultValue?: string | number | readonly string[];
|
|
6
|
+
multiline?: boolean;
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
seed: string | number;
|
|
9
|
+
value?: string | number | readonly string[];
|
|
10
|
+
wrap?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function EditablePencilText({ controlRef, defaultValue, multiline, placeholder, seed, value, }: EditablePencilTextProps): import("react").JSX.Element;
|
|
13
|
+
export {};
|