@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.
Files changed (267) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +316 -2
  3. package/THIRD_PARTY_NOTICES.md +39 -0
  4. package/Yozai-OFL.txt +94 -0
  5. package/dist/Button.d.ts +36 -0
  6. package/dist/Button.js +89 -0
  7. package/dist/PencilIcon.d.ts +22 -0
  8. package/dist/PencilIcon.js +210 -0
  9. package/dist/PencilLine.d.ts +10 -0
  10. package/dist/PencilLine.js +91 -0
  11. package/dist/PencilSurface.d.ts +19 -0
  12. package/dist/PencilSurface.js +19 -0
  13. package/dist/PencilText.d.ts +16 -0
  14. package/dist/PencilText.js +338 -0
  15. package/dist/accordion/Accordion.d.ts +27 -0
  16. package/dist/accordion/Accordion.js +40 -0
  17. package/dist/accordion/index.d.ts +2 -0
  18. package/dist/accordion/index.js +1 -0
  19. package/dist/alert-dialog/index.d.ts +64 -0
  20. package/dist/alert-dialog/index.js +109 -0
  21. package/dist/assets/ui-hand-yozai.woff2 +0 -0
  22. package/dist/audio-player/index.d.ts +60 -0
  23. package/dist/audio-player/index.js +101 -0
  24. package/dist/breadcrumb/index.d.ts +16 -0
  25. package/dist/breadcrumb/index.js +25 -0
  26. package/dist/calendar/index.d.ts +21 -0
  27. package/dist/calendar/index.js +41 -0
  28. package/dist/carousel/index.d.ts +51 -0
  29. package/dist/carousel/index.js +290 -0
  30. package/dist/choice-grid/index.d.ts +38 -0
  31. package/dist/choice-grid/index.js +85 -0
  32. package/dist/color-picker/color.d.ts +15 -0
  33. package/dist/color-picker/color.js +55 -0
  34. package/dist/color-picker/index.d.ts +31 -0
  35. package/dist/color-picker/index.js +69 -0
  36. package/dist/command/index.d.ts +23 -0
  37. package/dist/command/index.js +39 -0
  38. package/dist/content/index.d.ts +106 -0
  39. package/dist/content/index.js +80 -0
  40. package/dist/context-menu/index.d.ts +76 -0
  41. package/dist/context-menu/index.js +240 -0
  42. package/dist/data-table/index.d.ts +47 -0
  43. package/dist/data-table/index.js +91 -0
  44. package/dist/date-picker/index.d.ts +50 -0
  45. package/dist/date-picker/index.js +180 -0
  46. package/dist/day-agenda/index.d.ts +43 -0
  47. package/dist/day-agenda/index.js +47 -0
  48. package/dist/day-agenda/layout.d.ts +20 -0
  49. package/dist/day-agenda/layout.js +60 -0
  50. package/dist/display/ProgressRing.d.ts +6 -0
  51. package/dist/display/ProgressRing.js +146 -0
  52. package/dist/display/index.d.ts +59 -0
  53. package/dist/display/index.js +75 -0
  54. package/dist/dockable-panel/index.d.ts +41 -0
  55. package/dist/dockable-panel/index.js +253 -0
  56. package/dist/dockable-panel/model.d.ts +21 -0
  57. package/dist/dockable-panel/model.js +61 -0
  58. package/dist/drawer/index.d.ts +63 -0
  59. package/dist/drawer/index.js +86 -0
  60. package/dist/dropdown-menu/index.d.ts +34 -0
  61. package/dist/dropdown-menu/index.js +40 -0
  62. package/dist/editable/index.d.ts +53 -0
  63. package/dist/editable/index.js +162 -0
  64. package/dist/empty/index.d.ts +21 -0
  65. package/dist/empty/index.js +23 -0
  66. package/dist/flip/index.d.ts +49 -0
  67. package/dist/flip/index.js +138 -0
  68. package/dist/form/EditablePencilText.d.ts +13 -0
  69. package/dist/form/EditablePencilText.js +323 -0
  70. package/dist/form/Field.d.ts +13 -0
  71. package/dist/form/Field.js +26 -0
  72. package/dist/form/Input.d.ts +27 -0
  73. package/dist/form/Input.js +97 -0
  74. package/dist/form/InputAction.d.ts +7 -0
  75. package/dist/form/InputAction.js +24 -0
  76. package/dist/form/Textarea.d.ts +17 -0
  77. package/dist/form/Textarea.js +102 -0
  78. package/dist/form/context.d.ts +12 -0
  79. package/dist/form/context.js +10 -0
  80. package/dist/form/controlProps.d.ts +23 -0
  81. package/dist/form/controlProps.js +20 -0
  82. package/dist/form/index.d.ts +7 -0
  83. package/dist/form/index.js +3 -0
  84. package/dist/form/types.d.ts +6 -0
  85. package/dist/form/types.js +1 -0
  86. package/dist/heatmap/index.d.ts +59 -0
  87. package/dist/heatmap/index.js +248 -0
  88. package/dist/hotkey/index.d.ts +37 -0
  89. package/dist/hotkey/index.js +130 -0
  90. package/dist/hotkey/model.d.ts +27 -0
  91. package/dist/hotkey/model.js +97 -0
  92. package/dist/hover-card/index.d.ts +33 -0
  93. package/dist/hover-card/index.js +141 -0
  94. package/dist/image-cropper/index.d.ts +82 -0
  95. package/dist/image-cropper/index.js +261 -0
  96. package/dist/image-cropper/model.d.ts +42 -0
  97. package/dist/image-cropper/model.js +94 -0
  98. package/dist/image-viewer/index.d.ts +79 -0
  99. package/dist/image-viewer/index.js +220 -0
  100. package/dist/image-viewer/model.d.ts +9 -0
  101. package/dist/image-viewer/model.js +18 -0
  102. package/dist/images/layers-2x.png +0 -0
  103. package/dist/images/layers.png +0 -0
  104. package/dist/images/marker-icon.png +0 -0
  105. package/dist/index.d.ts +75 -0
  106. package/dist/index.js +69 -0
  107. package/dist/input-number/index.d.ts +16 -0
  108. package/dist/input-number/index.js +77 -0
  109. package/dist/internal/InputActionContext.d.ts +1 -0
  110. package/dist/internal/InputActionContext.js +3 -0
  111. package/dist/internal/cache.d.ts +14 -0
  112. package/dist/internal/cache.js +54 -0
  113. package/dist/internal/line.d.ts +4 -0
  114. package/dist/internal/line.js +21 -0
  115. package/dist/internal/paper.d.ts +1 -0
  116. package/dist/internal/paper.js +65 -0
  117. package/dist/internal/random.d.ts +3 -0
  118. package/dist/internal/random.js +30 -0
  119. package/dist/internal/recovery.d.ts +1 -0
  120. package/dist/internal/recovery.js +52 -0
  121. package/dist/internal/renderTokens.d.ts +10 -0
  122. package/dist/internal/renderTokens.js +13 -0
  123. package/dist/internal/stroke.d.ts +24 -0
  124. package/dist/internal/stroke.js +144 -0
  125. package/dist/internal/surfaceRenderer.d.ts +41 -0
  126. package/dist/internal/surfaceRenderer.js +178 -0
  127. package/dist/internal/textQueue.d.ts +1 -0
  128. package/dist/internal/textQueue.js +37 -0
  129. package/dist/internal/textRenderer.d.ts +28 -0
  130. package/dist/internal/textRenderer.js +239 -0
  131. package/dist/internal/travelIcons.d.ts +24 -0
  132. package/dist/internal/travelIcons.js +14 -0
  133. package/dist/internal/useBrowserLayoutEffect.d.ts +2 -0
  134. package/dist/internal/useBrowserLayoutEffect.js +3 -0
  135. package/dist/internal/usePencilSurface.d.ts +3 -0
  136. package/dist/internal/usePencilSurface.js +116 -0
  137. package/dist/internal/useSelectionDrawing.d.ts +2 -0
  138. package/dist/internal/useSelectionDrawing.js +90 -0
  139. package/dist/internal/wash.d.ts +16 -0
  140. package/dist/internal/wash.js +149 -0
  141. package/dist/journey-map/MapScale.d.ts +4 -0
  142. package/dist/journey-map/MapScale.js +54 -0
  143. package/dist/journey-map/index.d.ts +39 -0
  144. package/dist/journey-map/index.js +197 -0
  145. package/dist/journey-map/terrain.d.ts +8 -0
  146. package/dist/journey-map/terrain.js +127 -0
  147. package/dist/keypad/index.d.ts +23 -0
  148. package/dist/keypad/index.js +63 -0
  149. package/dist/keypad/model.d.ts +20 -0
  150. package/dist/keypad/model.js +33 -0
  151. package/dist/layout/index.d.ts +63 -0
  152. package/dist/layout/index.js +62 -0
  153. package/dist/log/index.d.ts +45 -0
  154. package/dist/log/index.js +159 -0
  155. package/dist/log/model.d.ts +16 -0
  156. package/dist/log/model.js +13 -0
  157. package/dist/node-graph/index.d.ts +123 -0
  158. package/dist/node-graph/index.js +304 -0
  159. package/dist/number-ticker/index.d.ts +29 -0
  160. package/dist/number-ticker/index.js +132 -0
  161. package/dist/number-ticker/model.d.ts +8 -0
  162. package/dist/number-ticker/model.js +34 -0
  163. package/dist/overflow-list/index.d.ts +39 -0
  164. package/dist/overflow-list/index.js +230 -0
  165. package/dist/overflow-list/layout.d.ts +19 -0
  166. package/dist/overflow-list/layout.js +44 -0
  167. package/dist/overlay/Overlay.d.ts +65 -0
  168. package/dist/overlay/Overlay.js +77 -0
  169. package/dist/overlay/Popover.d.ts +43 -0
  170. package/dist/overlay/Popover.js +45 -0
  171. package/dist/overlay/index.d.ts +4 -0
  172. package/dist/overlay/index.js +2 -0
  173. package/dist/overlay/themeBridge.d.ts +8 -0
  174. package/dist/overlay/themeBridge.js +98 -0
  175. package/dist/pagination/index.d.ts +23 -0
  176. package/dist/pagination/index.js +41 -0
  177. package/dist/pagination/model.d.ts +4 -0
  178. package/dist/pagination/model.js +42 -0
  179. package/dist/pan-zoom/index.d.ts +71 -0
  180. package/dist/pan-zoom/index.js +175 -0
  181. package/dist/pencil.d.ts +10 -0
  182. package/dist/pencil.js +39 -0
  183. package/dist/radar/index.d.ts +54 -0
  184. package/dist/radar/index.js +220 -0
  185. package/dist/range-slider/index.d.ts +16 -0
  186. package/dist/range-slider/index.js +22 -0
  187. package/dist/rating/index.d.ts +28 -0
  188. package/dist/rating/index.js +127 -0
  189. package/dist/resizable/index.d.ts +32 -0
  190. package/dist/resizable/index.js +50 -0
  191. package/dist/scroll-area/index.d.ts +36 -0
  192. package/dist/scroll-area/index.js +44 -0
  193. package/dist/segmented-progress/SegmentedProgress.d.ts +17 -0
  194. package/dist/segmented-progress/SegmentedProgress.js +42 -0
  195. package/dist/select/MultipleSelect.d.ts +44 -0
  196. package/dist/select/MultipleSelect.js +124 -0
  197. package/dist/select/SearchableSelect.d.ts +45 -0
  198. package/dist/select/SearchableSelect.js +50 -0
  199. package/dist/select/Select.d.ts +109 -0
  200. package/dist/select/Select.js +205 -0
  201. package/dist/select/index.d.ts +4 -0
  202. package/dist/select/index.js +2 -0
  203. package/dist/selection/Checkbox.d.ts +9 -0
  204. package/dist/selection/Checkbox.js +37 -0
  205. package/dist/selection/RadioGroup.d.ts +23 -0
  206. package/dist/selection/RadioGroup.js +82 -0
  207. package/dist/selection/Switch.d.ts +8 -0
  208. package/dist/selection/Switch.js +36 -0
  209. package/dist/selection/index.d.ts +6 -0
  210. package/dist/selection/index.js +3 -0
  211. package/dist/selection/useNativeChecked.d.ts +13 -0
  212. package/dist/selection/useNativeChecked.js +27 -0
  213. package/dist/slider/index.d.ts +11 -0
  214. package/dist/slider/index.js +45 -0
  215. package/dist/slot/index.d.ts +24 -0
  216. package/dist/slot/index.js +29 -0
  217. package/dist/sortable/index.d.ts +50 -0
  218. package/dist/sortable/index.js +278 -0
  219. package/dist/sortable/model.d.ts +30 -0
  220. package/dist/sortable/model.js +64 -0
  221. package/dist/sparkline/index.d.ts +19 -0
  222. package/dist/sparkline/index.js +240 -0
  223. package/dist/sparkline/model.d.ts +16 -0
  224. package/dist/sparkline/model.js +28 -0
  225. package/dist/steps/index.d.ts +16 -0
  226. package/dist/steps/index.js +37 -0
  227. package/dist/styles.css +8226 -0
  228. package/dist/tabs/index.d.ts +22 -0
  229. package/dist/tabs/index.js +42 -0
  230. package/dist/tag-input/index.d.ts +69 -0
  231. package/dist/tag-input/index.js +325 -0
  232. package/dist/tag-input/model.d.ts +14 -0
  233. package/dist/tag-input/model.js +38 -0
  234. package/dist/time-picker/index.d.ts +15 -0
  235. package/dist/time-picker/index.js +168 -0
  236. package/dist/timeline/index.d.ts +14 -0
  237. package/dist/timeline/index.js +16 -0
  238. package/dist/toast/index.d.ts +27 -0
  239. package/dist/toast/index.js +36 -0
  240. package/dist/toggle-group/index.d.ts +17 -0
  241. package/dist/toggle-group/index.js +26 -0
  242. package/dist/tokens.css +356 -0
  243. package/dist/tooltip/Tooltip.d.ts +24 -0
  244. package/dist/tooltip/Tooltip.js +32 -0
  245. package/dist/tooltip/index.d.ts +2 -0
  246. package/dist/tooltip/index.js +1 -0
  247. package/dist/transfer/index.d.ts +64 -0
  248. package/dist/transfer/index.js +174 -0
  249. package/dist/transfer/model.d.ts +12 -0
  250. package/dist/transfer/model.js +33 -0
  251. package/dist/tree/index.d.ts +39 -0
  252. package/dist/tree/index.js +36 -0
  253. package/dist/tree-select/index.d.ts +59 -0
  254. package/dist/tree-select/index.js +142 -0
  255. package/dist/tree-select/model.d.ts +31 -0
  256. package/dist/tree-select/model.js +135 -0
  257. package/dist/typewriter/index.d.ts +21 -0
  258. package/dist/typewriter/index.js +101 -0
  259. package/dist/typewriter/model.d.ts +7 -0
  260. package/dist/typewriter/model.js +45 -0
  261. package/dist/upload/index.d.ts +59 -0
  262. package/dist/upload/index.js +230 -0
  263. package/dist/virtual-list/index.d.ts +44 -0
  264. package/dist/virtual-list/index.js +128 -0
  265. package/dist/virtual-list/model.d.ts +7 -0
  266. package/dist/virtual-list/model.js +27 -0
  267. package/package.json +119 -4
@@ -0,0 +1,253 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { DndContext, MouseSensor, TouchSensor, useDraggable, useSensor, useSensors, } from '@dnd-kit/core';
3
+ import { createContext, forwardRef, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, } from 'react';
4
+ import { Button } from '../Button.js';
5
+ import { PencilIcon } from '../PencilIcon.js';
6
+ import { PencilLine } from '../PencilLine.js';
7
+ import { PencilSurface } from '../PencilSurface.js';
8
+ import { PencilText } from '../PencilText.js';
9
+ import { useBrowserLayoutEffect } from '../internal/useBrowserLayoutEffect.js';
10
+ import { clampDockablePanelPosition, placeDockablePanel, promoteDockablePanel, } from './model.js';
11
+ const WorkspaceContext = createContext(null);
12
+ function classes(...values) {
13
+ return values.filter(Boolean).join(' ');
14
+ }
15
+ export const DockablePanelWorkspace = forwardRef(function DockablePanelWorkspace({ activeId, baseZIndex = 0, boundaryPadding = 8, children, className, defaultActiveId = null, onActiveChange, snapThreshold = 12, titleBarVisibility = 56, ...props }, forwardedRef) {
16
+ const rootRef = useRef(null);
17
+ const dragCallbacks = useRef(new Map());
18
+ const [order, setOrder] = useState([]);
19
+ const [uncontrolledActiveId, setUncontrolledActiveId] = useState(defaultActiveId);
20
+ const resolvedActiveId = activeId === undefined ? uncontrolledActiveId : activeId;
21
+ const [size, setSize] = useState({ width: 0, height: 0 });
22
+ const sensors = useSensors(useSensor(MouseSensor, { activationConstraint: { distance: 4 } }), useSensor(TouchSensor, { activationConstraint: { delay: 180, tolerance: 8 } }));
23
+ const setRoot = useCallback((node) => {
24
+ rootRef.current = node;
25
+ if (typeof forwardedRef === 'function')
26
+ forwardedRef(node);
27
+ else if (forwardedRef)
28
+ forwardedRef.current = node;
29
+ }, [forwardedRef]);
30
+ useBrowserLayoutEffect(() => {
31
+ const root = rootRef.current;
32
+ if (!root)
33
+ return undefined;
34
+ const update = () => setSize(current => {
35
+ const next = { width: root.clientWidth, height: root.clientHeight };
36
+ return current.width === next.width && current.height === next.height ? current : next;
37
+ });
38
+ update();
39
+ if (typeof ResizeObserver === 'undefined')
40
+ return undefined;
41
+ const observer = new ResizeObserver(update);
42
+ observer.observe(root);
43
+ return () => observer.disconnect();
44
+ }, []);
45
+ const activate = useCallback((id) => {
46
+ setOrder(current => promoteDockablePanel(current, id));
47
+ if (activeId === undefined)
48
+ setUncontrolledActiveId(id);
49
+ if (resolvedActiveId !== id)
50
+ onActiveChange?.(id);
51
+ }, [activeId, onActiveChange, resolvedActiveId]);
52
+ useEffect(() => {
53
+ if (activeId != null)
54
+ setOrder(current => promoteDockablePanel(current, activeId));
55
+ }, [activeId]);
56
+ const register = useCallback((id) => {
57
+ setOrder(current => current.includes(id) ? current : [...current, id]);
58
+ return () => {
59
+ dragCallbacks.current.delete(id);
60
+ setOrder(current => current.filter(value => value !== id));
61
+ };
62
+ }, []);
63
+ const commitDrag = useCallback((id, callback) => {
64
+ if (callback)
65
+ dragCallbacks.current.set(id, callback);
66
+ else
67
+ dragCallbacks.current.delete(id);
68
+ }, []);
69
+ const bounds = useMemo(() => ({
70
+ height: size.height,
71
+ padding: boundaryPadding,
72
+ titleBarVisibility,
73
+ width: size.width,
74
+ }), [boundaryPadding, size.height, size.width, titleBarVisibility]);
75
+ const context = useMemo(() => ({
76
+ activeId: resolvedActiveId,
77
+ activate,
78
+ bounds,
79
+ commitDrag,
80
+ layer(id) {
81
+ const index = order.indexOf(id);
82
+ return baseZIndex + (resolvedActiveId === id ? order.length : Math.max(0, index));
83
+ },
84
+ register,
85
+ snapThreshold,
86
+ }), [activate, baseZIndex, bounds, commitDrag, order, register, resolvedActiveId, snapThreshold]);
87
+ function handleDragEnd(event) {
88
+ const id = String(event.active.id);
89
+ dragCallbacks.current.get(id)?.({ x: event.delta.x, y: event.delta.y });
90
+ }
91
+ return _jsx(WorkspaceContext.Provider, { value: context, children: _jsx(DndContext, { sensors: sensors, onDragStart: (event) => activate(String(event.active.id)), onDragEnd: handleDragEnd, children: _jsx("div", { ...props, className: classes('inkra-dockable-panel-workspace', className), ref: setRoot, children: children }) }) });
92
+ });
93
+ const collapsePaths = [{ d: 'M6 12h12' }];
94
+ const expandPaths = [{ d: 'M6 9h12M12 3v12' }];
95
+ const resetPaths = [
96
+ { d: 'M4 12a8 8 0 1 0 2.34-5.66L4 8.68' },
97
+ { d: 'M4 4v4.68h4.68' },
98
+ ];
99
+ const defaultLabels = {
100
+ move: 'Move panel',
101
+ collapse: 'Collapse panel',
102
+ expand: 'Expand panel',
103
+ reset: 'Restore panel position',
104
+ keyboardInstructions: 'Use the arrow keys to move this panel. Hold Shift for larger steps. Press Home to restore its position.',
105
+ };
106
+ function renderTitle(title) {
107
+ return typeof title === 'string' ? _jsx(PencilText, { children: title }) : title;
108
+ }
109
+ function isInteractiveTarget(target) {
110
+ return target instanceof Element && Boolean(target.closest('button, a, input, select, textarea, [contenteditable="true"], [data-dockable-panel-no-drag]'));
111
+ }
112
+ export const DockablePanel = forwardRef(function DockablePanel({ children, className, collapsed, collapsible = true, defaultCollapsed = false, defaultPosition = { x: 8, y: 8 }, headerActions, id, keyboardStep = 8, labels: labelOverrides, movable = true, onCollapsedChange, onFocusCapture, onPointerDown, onPositionChange, position, style, title, ...props }, forwardedRef) {
113
+ const workspace = useContext(WorkspaceContext);
114
+ if (!workspace)
115
+ throw new Error('DockablePanel must be rendered inside DockablePanelWorkspace.');
116
+ const generatedId = useId();
117
+ const titleId = `${generatedId}-title`;
118
+ const instructionsId = `${generatedId}-instructions`;
119
+ const panelRef = useRef(null);
120
+ const titleBarRef = useRef(null);
121
+ const [uncontrolledPosition, setUncontrolledPosition] = useState(defaultPosition);
122
+ const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState(defaultCollapsed);
123
+ const [panelSize, setPanelSize] = useState({ width: 0, height: 0, titleBarHeight: 44 });
124
+ const resolvedPosition = position ?? uncontrolledPosition;
125
+ const resolvedCollapsed = collapsed ?? uncontrolledCollapsed;
126
+ const positionRef = useRef(resolvedPosition);
127
+ positionRef.current = resolvedPosition;
128
+ const labels = { ...defaultLabels, ...labelOverrides };
129
+ const { activate, bounds, commitDrag, layer, register, snapThreshold, } = workspace;
130
+ const { attributes, isDragging, listeners, setActivatorNodeRef, setNodeRef, transform } = useDraggable({
131
+ id,
132
+ disabled: !movable,
133
+ attributes: { role: 'button', roleDescription: labels.move, tabIndex: 0 },
134
+ });
135
+ const setPanelRef = useCallback((node) => {
136
+ panelRef.current = node;
137
+ setNodeRef(node);
138
+ if (typeof forwardedRef === 'function')
139
+ forwardedRef(node);
140
+ else if (forwardedRef)
141
+ forwardedRef.current = node;
142
+ }, [forwardedRef, setNodeRef]);
143
+ const changePosition = useCallback((next, reason, snap) => {
144
+ const panel = panelRef.current;
145
+ const titleBar = titleBarRef.current;
146
+ if (!panel || !titleBar || bounds.width <= 0 || bounds.height <= 0)
147
+ return;
148
+ const measuredBounds = { ...bounds, titleBarHeight: titleBar.offsetHeight };
149
+ const placement = snap
150
+ ? placeDockablePanel(next, { width: panel.offsetWidth, height: panel.offsetHeight }, measuredBounds, snapThreshold)
151
+ : { position: clampDockablePanelPosition(next, { width: panel.offsetWidth, height: panel.offsetHeight }, measuredBounds), snappedEdges: [] };
152
+ if (placement.position.x === positionRef.current.x && placement.position.y === positionRef.current.y)
153
+ return;
154
+ if (position === undefined)
155
+ setUncontrolledPosition(placement.position);
156
+ positionRef.current = placement.position;
157
+ onPositionChange?.(placement.position, { reason, snappedEdges: placement.snappedEdges });
158
+ }, [bounds, onPositionChange, position, snapThreshold]);
159
+ useEffect(() => register(id), [id, register]);
160
+ useEffect(() => {
161
+ commitDrag(id, delta => changePosition({
162
+ x: positionRef.current.x + delta.x,
163
+ y: positionRef.current.y + delta.y,
164
+ }, 'drag', true));
165
+ return () => commitDrag(id, null);
166
+ }, [changePosition, commitDrag, id]);
167
+ useBrowserLayoutEffect(() => {
168
+ const panel = panelRef.current;
169
+ if (!panel || typeof ResizeObserver === 'undefined')
170
+ return undefined;
171
+ const update = () => {
172
+ const titleBarHeight = titleBarRef.current?.offsetHeight ?? 44;
173
+ const next = { width: panel.offsetWidth, height: panel.offsetHeight, titleBarHeight };
174
+ setPanelSize(current => current.width === next.width
175
+ && current.height === next.height
176
+ && current.titleBarHeight === next.titleBarHeight ? current : next);
177
+ changePosition(positionRef.current, 'viewport', false);
178
+ };
179
+ update();
180
+ const observer = new ResizeObserver(update);
181
+ observer.observe(panel);
182
+ return () => observer.disconnect();
183
+ }, [changePosition]);
184
+ useBrowserLayoutEffect(() => {
185
+ changePosition(positionRef.current, 'viewport', false);
186
+ }, [bounds.height, bounds.width, changePosition, resolvedPosition.x, resolvedPosition.y]);
187
+ function resetPosition() {
188
+ activate(id);
189
+ changePosition(defaultPosition, 'reset', false);
190
+ titleBarRef.current?.focus();
191
+ }
192
+ function changeCollapsed(next) {
193
+ if (collapsed === undefined)
194
+ setUncontrolledCollapsed(next);
195
+ onCollapsedChange?.(next);
196
+ }
197
+ function handleTitleKeyDown(event) {
198
+ if (!movable || event.defaultPrevented || isInteractiveTarget(event.target))
199
+ return;
200
+ if (event.key === 'Home') {
201
+ event.preventDefault();
202
+ resetPosition();
203
+ return;
204
+ }
205
+ const direction = {
206
+ ArrowLeft: { x: -1, y: 0 },
207
+ ArrowRight: { x: 1, y: 0 },
208
+ ArrowUp: { x: 0, y: -1 },
209
+ ArrowDown: { x: 0, y: 1 },
210
+ }[event.key];
211
+ if (!direction)
212
+ return;
213
+ event.preventDefault();
214
+ activate(id);
215
+ const step = Math.max(1, keyboardStep) * (event.shiftKey ? 4 : 1);
216
+ changePosition({
217
+ x: positionRef.current.x + direction.x * step,
218
+ y: positionRef.current.y + direction.y * step,
219
+ }, 'keyboard', false);
220
+ }
221
+ const nativeListeners = movable ? listeners : undefined;
222
+ const translatedPosition = {
223
+ x: resolvedPosition.x + (transform?.x ?? 0),
224
+ y: resolvedPosition.y + (transform?.y ?? 0),
225
+ };
226
+ const visualPosition = panelSize.width > 0 && panelSize.height > 0 && bounds.width > 0 && bounds.height > 0
227
+ ? clampDockablePanelPosition(translatedPosition, panelSize, { ...bounds, titleBarHeight: panelSize.titleBarHeight })
228
+ : translatedPosition;
229
+ const panelStyle = {
230
+ ...style,
231
+ '--inkra-dockable-panel-x': `${visualPosition.x}px`,
232
+ '--inkra-dockable-panel-y': `${visualPosition.y}px`,
233
+ zIndex: layer(id),
234
+ };
235
+ return _jsxs(PencilSurface, { ...props, as: "section", "aria-labelledby": titleId, className: classes('inkra-dockable-panel', className), "data-active": workspace.activeId === id || undefined, "data-collapsed": resolvedCollapsed || undefined, "data-dragging": isDragging || undefined, onFocusCapture: event => {
236
+ onFocusCapture?.(event);
237
+ if (!event.defaultPrevented)
238
+ activate(id);
239
+ }, onPointerDown: event => {
240
+ onPointerDown?.(event);
241
+ if (!event.defaultPrevented)
242
+ activate(id);
243
+ }, ref: setPanelRef, style: panelStyle, variant: "paper", children: [_jsxs("div", { className: "inkra-dockable-panel__header", children: [_jsx("div", { ...attributes, ...nativeListeners, "aria-describedby": movable ? instructionsId : undefined, "aria-label": labels.move, className: "inkra-dockable-panel__handle", "data-dockable-panel-handle": true, onKeyDown: handleTitleKeyDown, onMouseDown: event => {
244
+ if (!isInteractiveTarget(event.target))
245
+ nativeListeners?.onMouseDown?.(event);
246
+ }, onTouchStart: event => {
247
+ if (!isInteractiveTarget(event.target))
248
+ nativeListeners?.onTouchStart?.(event);
249
+ }, ref: node => {
250
+ titleBarRef.current = node;
251
+ setActivatorNodeRef(node);
252
+ }, children: _jsx("span", { className: "inkra-dockable-panel__title", id: titleId, children: renderTitle(title) }) }), _jsxs("div", { className: "inkra-dockable-panel__actions", "data-dockable-panel-no-drag": true, children: [headerActions, movable && _jsx(Button, { "aria-label": labels.reset, "data-dockable-panel-reset": true, size: "icon-xs", variant: "ghost", onClick: resetPosition, children: _jsx(PencilIcon, { decorative: true, paths: resetPaths, size: 18, sourceSize: 24 }) }), collapsible && _jsx(Button, { "aria-expanded": !resolvedCollapsed, "aria-label": resolvedCollapsed ? labels.expand : labels.collapse, "data-dockable-panel-collapse": true, size: "icon-xs", variant: "ghost", onClick: () => changeCollapsed(!resolvedCollapsed), children: _jsx(PencilIcon, { decorative: true, paths: resolvedCollapsed ? expandPaths : collapsePaths, size: 18, sourceSize: 24 }) })] })] }), _jsx(PencilLine, { className: "inkra-dockable-panel__divider" }), !resolvedCollapsed && _jsx("div", { className: "inkra-dockable-panel__body", children: children }), movable && _jsx("span", { className: "inkra-visually-hidden", id: instructionsId, children: labels.keyboardInstructions })] });
253
+ });
@@ -0,0 +1,21 @@
1
+ export interface DockablePanelPosition {
2
+ x: number;
3
+ y: number;
4
+ }
5
+ export interface DockablePanelSize {
6
+ width: number;
7
+ height: number;
8
+ }
9
+ export interface DockablePanelBounds extends DockablePanelSize {
10
+ padding: number;
11
+ titleBarHeight: number;
12
+ titleBarVisibility: number;
13
+ }
14
+ export type DockablePanelSnapEdge = 'top' | 'right' | 'bottom' | 'left';
15
+ export interface DockablePanelPlacement {
16
+ position: DockablePanelPosition;
17
+ snappedEdges: DockablePanelSnapEdge[];
18
+ }
19
+ export declare function clampDockablePanelPosition(position: DockablePanelPosition, panel: DockablePanelSize, bounds: DockablePanelBounds): DockablePanelPosition;
20
+ export declare function placeDockablePanel(position: DockablePanelPosition, panel: DockablePanelSize, bounds: DockablePanelBounds, snapThreshold?: number): DockablePanelPlacement;
21
+ export declare function promoteDockablePanel(order: readonly string[], id: string): string[];
@@ -0,0 +1,61 @@
1
+ function finite(value, fallback = 0) {
2
+ return Number.isFinite(value) ? value : fallback;
3
+ }
4
+ function range(minimum, maximum, value) {
5
+ return Math.min(Math.max(value, minimum), Math.max(minimum, maximum));
6
+ }
7
+ export function clampDockablePanelPosition(position, panel, bounds) {
8
+ const padding = Math.max(0, finite(bounds.padding));
9
+ const viewportWidth = Math.max(0, finite(bounds.width));
10
+ const viewportHeight = Math.max(0, finite(bounds.height));
11
+ const panelWidth = Math.max(0, finite(panel.width));
12
+ const panelHeight = Math.max(0, finite(panel.height));
13
+ const titleBarHeight = Math.max(1, finite(bounds.titleBarHeight, 44));
14
+ const titleBarVisibility = Math.max(1, finite(bounds.titleBarVisibility, 56));
15
+ const availableWidth = Math.max(0, viewportWidth - padding * 2);
16
+ const availableHeight = Math.max(0, viewportHeight - padding * 2);
17
+ const visibleTitleWidth = Math.min(panelWidth, titleBarVisibility);
18
+ const minimumX = panelWidth <= availableWidth
19
+ ? padding
20
+ : padding + visibleTitleWidth - panelWidth;
21
+ const maximumX = panelWidth <= availableWidth
22
+ ? viewportWidth - padding - panelWidth
23
+ : Math.max(minimumX, viewportWidth - padding - visibleTitleWidth);
24
+ const minimumY = padding;
25
+ const maximumY = panelHeight <= availableHeight
26
+ ? viewportHeight - padding - panelHeight
27
+ : Math.max(minimumY, viewportHeight - padding - Math.min(panelHeight, titleBarHeight));
28
+ return {
29
+ x: range(minimumX, maximumX, finite(position.x)),
30
+ y: range(minimumY, maximumY, finite(position.y)),
31
+ };
32
+ }
33
+ export function placeDockablePanel(position, panel, bounds, snapThreshold = 12) {
34
+ const clamped = clampDockablePanelPosition(position, panel, bounds);
35
+ const padding = Math.max(0, finite(bounds.padding));
36
+ const threshold = Math.max(0, finite(snapThreshold));
37
+ const maximumX = Math.max(padding, bounds.width - padding - panel.width);
38
+ const maximumY = Math.max(padding, bounds.height - padding - panel.height);
39
+ const snappedEdges = [];
40
+ let { x, y } = clamped;
41
+ if (Math.abs(x - padding) <= threshold) {
42
+ x = padding;
43
+ snappedEdges.push('left');
44
+ }
45
+ else if (panel.width <= bounds.width - padding * 2 && Math.abs(x - maximumX) <= threshold) {
46
+ x = maximumX;
47
+ snappedEdges.push('right');
48
+ }
49
+ if (Math.abs(y - padding) <= threshold) {
50
+ y = padding;
51
+ snappedEdges.push('top');
52
+ }
53
+ else if (panel.height <= bounds.height - padding * 2 && Math.abs(y - maximumY) <= threshold) {
54
+ y = maximumY;
55
+ snappedEdges.push('bottom');
56
+ }
57
+ return { position: { x, y }, snappedEdges };
58
+ }
59
+ export function promoteDockablePanel(order, id) {
60
+ return [...order.filter(value => value !== id), id];
61
+ }
@@ -0,0 +1,63 @@
1
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
2
+ import type { ComponentPropsWithoutRef, ReactNode } from 'react';
3
+ import type { ButtonProps } from '../Button.js';
4
+ export type DrawerDirection = 'top' | 'right' | 'bottom' | 'left';
5
+ export type DrawerSize = 'sm' | 'md' | 'lg' | number | string;
6
+ export type DrawerRootProps = DialogPrimitive.DialogProps;
7
+ export declare function DrawerRoot(props: DrawerRootProps): import("react").JSX.Element;
8
+ export type DrawerTriggerProps = DialogPrimitive.DialogTriggerProps;
9
+ export declare const DrawerTrigger: import("react").ForwardRefExoticComponent<DialogPrimitive.DialogTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
10
+ export type DrawerPortalProps = DialogPrimitive.DialogPortalProps;
11
+ export declare function DrawerPortal({ children, ...props }: DrawerPortalProps): import("react").JSX.Element;
12
+ export type DrawerBackdropProps = DialogPrimitive.DialogOverlayProps;
13
+ export declare const DrawerBackdrop: import("react").ForwardRefExoticComponent<DialogPrimitive.DialogOverlayProps & import("react").RefAttributes<HTMLDivElement>>;
14
+ export interface DrawerContentProps extends DialogPrimitive.DialogContentProps {
15
+ direction?: DrawerDirection;
16
+ seed?: string | number;
17
+ size?: DrawerSize;
18
+ }
19
+ export declare const DrawerContent: import("react").ForwardRefExoticComponent<DrawerContentProps & import("react").RefAttributes<HTMLDivElement>>;
20
+ export interface DrawerTitleProps extends Omit<ComponentPropsWithoutRef<typeof DialogPrimitive.Title>, 'children'> {
21
+ children: string;
22
+ seed?: string | number;
23
+ }
24
+ export declare const DrawerTitle: import("react").ForwardRefExoticComponent<DrawerTitleProps & import("react").RefAttributes<HTMLHeadingElement>>;
25
+ export interface DrawerDescriptionProps extends Omit<ComponentPropsWithoutRef<typeof DialogPrimitive.Description>, 'children'> {
26
+ children: string;
27
+ seed?: string | number;
28
+ }
29
+ export declare const DrawerDescription: import("react").ForwardRefExoticComponent<DrawerDescriptionProps & import("react").RefAttributes<HTMLParagraphElement>>;
30
+ export type DrawerCloseProps = ComponentPropsWithoutRef<typeof DialogPrimitive.Close>;
31
+ export declare const DrawerClose: import("react").ForwardRefExoticComponent<Omit<DialogPrimitive.DialogCloseProps & import("react").RefAttributes<HTMLButtonElement>, "ref"> & import("react").RefAttributes<HTMLButtonElement>>;
32
+ export interface DrawerCloseButtonProps extends Omit<ButtonProps, 'aria-label' | 'children' | 'loading' | 'size' | 'type' | 'variant'> {
33
+ label?: string;
34
+ }
35
+ export declare const DrawerCloseButton: import("react").ForwardRefExoticComponent<DrawerCloseButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
36
+ export interface DrawerHeaderProps extends ComponentPropsWithoutRef<'div'> {
37
+ action?: ReactNode;
38
+ closeLabel?: string;
39
+ divided?: boolean;
40
+ showClose?: boolean;
41
+ }
42
+ export declare const DrawerHeader: import("react").ForwardRefExoticComponent<DrawerHeaderProps & import("react").RefAttributes<HTMLDivElement>>;
43
+ export type DrawerBodyProps = ComponentPropsWithoutRef<'div'>;
44
+ export declare const DrawerBody: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
45
+ export interface DrawerFooterProps extends ComponentPropsWithoutRef<'div'> {
46
+ align?: 'start' | 'center' | 'end';
47
+ divided?: boolean;
48
+ }
49
+ export declare const DrawerFooter: import("react").ForwardRefExoticComponent<DrawerFooterProps & import("react").RefAttributes<HTMLDivElement>>;
50
+ export declare const Drawer: Readonly<{
51
+ Root: typeof DrawerRoot;
52
+ Trigger: import("react").ForwardRefExoticComponent<DialogPrimitive.DialogTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
53
+ Portal: typeof DrawerPortal;
54
+ Backdrop: import("react").ForwardRefExoticComponent<DialogPrimitive.DialogOverlayProps & import("react").RefAttributes<HTMLDivElement>>;
55
+ Content: import("react").ForwardRefExoticComponent<DrawerContentProps & import("react").RefAttributes<HTMLDivElement>>;
56
+ Header: import("react").ForwardRefExoticComponent<DrawerHeaderProps & import("react").RefAttributes<HTMLDivElement>>;
57
+ Body: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
58
+ Footer: import("react").ForwardRefExoticComponent<DrawerFooterProps & import("react").RefAttributes<HTMLDivElement>>;
59
+ Title: import("react").ForwardRefExoticComponent<DrawerTitleProps & import("react").RefAttributes<HTMLHeadingElement>>;
60
+ Description: import("react").ForwardRefExoticComponent<DrawerDescriptionProps & import("react").RefAttributes<HTMLParagraphElement>>;
61
+ Close: import("react").ForwardRefExoticComponent<Omit<DialogPrimitive.DialogCloseProps & import("react").RefAttributes<HTMLButtonElement>, "ref"> & import("react").RefAttributes<HTMLButtonElement>>;
62
+ CloseButton: import("react").ForwardRefExoticComponent<DrawerCloseButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
63
+ }>;
@@ -0,0 +1,86 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
3
+ import { forwardRef, useId } from 'react';
4
+ import { __iconData as closeIcon } from 'lucide-react/dist/esm/icons/x.mjs';
5
+ import { Button } from '../Button.js';
6
+ import { PencilIcon } from '../PencilIcon.js';
7
+ import { PencilLine } from '../PencilLine.js';
8
+ import { PencilSurface } from '../PencilSurface.js';
9
+ import { PencilText } from '../PencilText.js';
10
+ import { Tooltip } from '../tooltip/Tooltip.js';
11
+ import { PortalThemeBridge, PortalThemeProvider, usePortalTriggerRef, } from '../overlay/themeBridge.js';
12
+ const classes = (...values) => values.filter(Boolean).join(' ');
13
+ const closePaths = closeIcon.node.map(([, attributes]) => ({ d: attributes.d }));
14
+ function drawerSize(size) {
15
+ if (typeof size === 'number')
16
+ return `${size}px`;
17
+ if (size === 'sm')
18
+ return '20rem';
19
+ if (size === 'md')
20
+ return '28rem';
21
+ if (size === 'lg')
22
+ return '36rem';
23
+ return size;
24
+ }
25
+ export function DrawerRoot(props) {
26
+ return _jsx(PortalThemeProvider, { children: _jsx(DialogPrimitive.Root, { ...props }) });
27
+ }
28
+ export const DrawerTrigger = forwardRef(function DrawerTrigger(props, forwardedRef) {
29
+ return _jsx(DialogPrimitive.Trigger, { ...props, ref: usePortalTriggerRef(forwardedRef) });
30
+ });
31
+ export function DrawerPortal({ children, ...props }) {
32
+ return _jsx(DialogPrimitive.Portal, { ...props, children: _jsx(PortalThemeBridge, { children: children }) });
33
+ }
34
+ export const DrawerBackdrop = forwardRef(function DrawerBackdrop({ className, ...props }, ref) {
35
+ return _jsx(DialogPrimitive.Overlay, { ...props, className: classes('inkra-drawer__backdrop', className), ref: ref });
36
+ });
37
+ export const DrawerContent = forwardRef(function DrawerContent({ children, className, direction = 'right', seed, size = 'md', style, ...props }, ref) {
38
+ const id = useId();
39
+ const mergedStyle = { ...style, '--inkra-drawer-size': drawerSize(size) };
40
+ const edgeOrientation = direction === 'left' || direction === 'right' ? 'vertical' : 'horizontal';
41
+ return (_jsx(DialogPrimitive.Content, { ...props, className: classes('inkra-drawer__content', className), "data-direction": direction, ref: ref, style: mergedStyle, children: _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
+ });
43
+ export const DrawerTitle = forwardRef(function DrawerTitle({ children, className, seed, ...props }, ref) {
44
+ const id = useId();
45
+ return _jsx(DialogPrimitive.Title, { ...props, className: classes('inkra-drawer__title', className), ref: ref, children: _jsx(PencilText, { seed: seed ?? `inkra-drawer-title-${id}`, children: children }) });
46
+ });
47
+ export const DrawerDescription = forwardRef(function DrawerDescription({ children, className, seed, ...props }, ref) {
48
+ const id = useId();
49
+ return _jsx(DialogPrimitive.Description, { ...props, className: classes('inkra-drawer__description', className), ref: ref, children: _jsx(PencilText, { seed: seed ?? `inkra-drawer-description-${id}`, children: children }) });
50
+ });
51
+ export const DrawerClose = forwardRef(function DrawerClose(props, ref) {
52
+ return _jsx(DialogPrimitive.Close, { ...props, ref: ref });
53
+ });
54
+ export const DrawerCloseButton = forwardRef(function DrawerCloseButton({ className, label = 'Close', onFocus, ...props }, ref) {
55
+ return _jsx(Tooltip.Provider, { children: _jsxs(Tooltip.Root, { children: [_jsx(Tooltip.Trigger, { asChild: true, children: _jsx(DialogPrimitive.Close, { asChild: true, children: _jsx(Button, { ...props, "aria-label": label, className: classes('inkra-drawer__close-button', className), ref: ref, size: "icon", type: "button", variant: "outline", onFocus: event => {
56
+ onFocus?.(event);
57
+ const dialog = event.currentTarget.closest('[role="dialog"]');
58
+ if (dialog && (!event.relatedTarget || !dialog.contains(event.relatedTarget)))
59
+ event.preventDefault();
60
+ }, children: _jsx(PencilIcon, { decorative: true, paths: closePaths, size: 30, sourceSize: 24 }) }) }) }), _jsx(Tooltip.Portal, { children: _jsx(Tooltip.Content, { align: "end", side: "bottom", children: label }) })] }) });
61
+ });
62
+ export const DrawerHeader = forwardRef(function DrawerHeader({ action, children, className, closeLabel = 'Close', divided = true, showClose = true, ...props }, ref) {
63
+ const id = useId();
64
+ return _jsxs("div", { ...props, className: classes('inkra-drawer__header', className), "data-divided": divided || undefined, ref: ref, children: [_jsx("div", { className: "inkra-drawer__heading", children: children }), (action || showClose) ? _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
+ });
66
+ export const DrawerBody = forwardRef(function DrawerBody({ className, ...props }, ref) {
67
+ return _jsx("div", { ...props, className: classes('inkra-drawer__body', className), ref: ref });
68
+ });
69
+ export const DrawerFooter = forwardRef(function DrawerFooter({ align = 'end', children, className, divided = true, ...props }, ref) {
70
+ const id = useId();
71
+ 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
+ });
73
+ export const Drawer = Object.freeze({
74
+ Root: DrawerRoot,
75
+ Trigger: DrawerTrigger,
76
+ Portal: DrawerPortal,
77
+ Backdrop: DrawerBackdrop,
78
+ Content: DrawerContent,
79
+ Header: DrawerHeader,
80
+ Body: DrawerBody,
81
+ Footer: DrawerFooter,
82
+ Title: DrawerTitle,
83
+ Description: DrawerDescription,
84
+ Close: DrawerClose,
85
+ CloseButton: DrawerCloseButton,
86
+ });
@@ -0,0 +1,34 @@
1
+ import * as Primitive from '@radix-ui/react-dropdown-menu';
2
+ import { type ReactNode } from 'react';
3
+ export type DropdownMenuProps = Primitive.DropdownMenuProps;
4
+ declare function Root(props: DropdownMenuProps): import("react").JSX.Element;
5
+ export type DropdownMenuTriggerProps = Primitive.DropdownMenuTriggerProps;
6
+ export type DropdownMenuPortalProps = Primitive.DropdownMenuPortalProps;
7
+ declare function Portal({ children, ...props }: DropdownMenuPortalProps): import("react").JSX.Element;
8
+ export interface DropdownMenuContentProps extends Omit<Primitive.DropdownMenuContentProps, 'asChild'> {
9
+ seed?: string | number;
10
+ }
11
+ export interface DropdownMenuItemProps extends Omit<Primitive.DropdownMenuItemProps, 'asChild'> {
12
+ destructive?: boolean;
13
+ icon?: ReactNode;
14
+ }
15
+ export type DropdownMenuCheckboxItemProps = Omit<Primitive.DropdownMenuCheckboxItemProps, 'asChild'>;
16
+ export type DropdownMenuRadioItemProps = Omit<Primitive.DropdownMenuRadioItemProps, 'asChild'>;
17
+ export type DropdownMenuLabelProps = Omit<Primitive.DropdownMenuLabelProps, 'asChild'>;
18
+ export type DropdownMenuSeparatorProps = Omit<Primitive.DropdownMenuSeparatorProps, 'asChild' | 'children'>;
19
+ export type DropdownMenuGroupProps = Primitive.DropdownMenuGroupProps;
20
+ export type DropdownMenuRadioGroupProps = Primitive.DropdownMenuRadioGroupProps;
21
+ export declare const DropdownMenu: {
22
+ Root: typeof Root;
23
+ Trigger: import("react").ForwardRefExoticComponent<Primitive.DropdownMenuTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
24
+ Portal: typeof Portal;
25
+ Content: import("react").ForwardRefExoticComponent<DropdownMenuContentProps & import("react").RefAttributes<HTMLDivElement>>;
26
+ Item: import("react").ForwardRefExoticComponent<DropdownMenuItemProps & import("react").RefAttributes<HTMLDivElement>>;
27
+ CheckboxItem: import("react").ForwardRefExoticComponent<DropdownMenuCheckboxItemProps & import("react").RefAttributes<HTMLDivElement>>;
28
+ RadioItem: import("react").ForwardRefExoticComponent<DropdownMenuRadioItemProps & import("react").RefAttributes<HTMLDivElement>>;
29
+ Label: import("react").ForwardRefExoticComponent<DropdownMenuLabelProps & import("react").RefAttributes<HTMLDivElement>>;
30
+ Separator: import("react").ForwardRefExoticComponent<DropdownMenuSeparatorProps & import("react").RefAttributes<HTMLDivElement>>;
31
+ Group: import("react").ForwardRefExoticComponent<Primitive.DropdownMenuGroupProps & import("react").RefAttributes<HTMLDivElement>>;
32
+ RadioGroup: import("react").ForwardRefExoticComponent<Primitive.DropdownMenuRadioGroupProps & import("react").RefAttributes<HTMLDivElement>>;
33
+ };
34
+ export {};
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as Primitive from '@radix-ui/react-dropdown-menu';
3
+ import { forwardRef, useId } from 'react';
4
+ import { PencilSurface } from '../PencilSurface.js';
5
+ import { PencilText } from '../PencilText.js';
6
+ import { PencilIcon } from '../PencilIcon.js';
7
+ import { PencilLine } from '../PencilLine.js';
8
+ import { PortalThemeBridge, PortalThemeProvider, usePortalTriggerRef } from '../overlay/themeBridge.js';
9
+ const classes = (...values) => values.filter(Boolean).join(' ');
10
+ const copy = (children) => typeof children === 'string' ? _jsx(PencilText, { children: children }) : children;
11
+ function Root(props) { return _jsx(PortalThemeProvider, { children: _jsx(Primitive.Root, { ...props }) }); }
12
+ const Trigger = forwardRef(function Trigger(props, ref) {
13
+ return _jsx(Primitive.Trigger, { ...props, ref: usePortalTriggerRef(ref) });
14
+ });
15
+ function Portal({ children, ...props }) { return _jsx(Primitive.Portal, { ...props, children: _jsx(PortalThemeBridge, { children: children }) }); }
16
+ const Content = forwardRef(function Content({ className, children, seed, sideOffset = 6, collisionPadding = 8, ...props }, ref) {
17
+ const id = useId();
18
+ 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
+ function ItemBody({ children, icon }) {
21
+ return _jsxs(_Fragment, { children: [_jsx(PencilSurface, { as: "span", "aria-hidden": "true", variant: "selection", className: "inkra-menu__highlight" }), _jsx("span", { className: "inkra-menu__icon", "aria-hidden": "true", children: icon }), _jsx("span", { className: "inkra-menu__label", children: copy(children) })] });
22
+ }
23
+ const Item = forwardRef(function Item({ className, children, destructive = false, icon, ...props }, ref) {
24
+ return _jsx(Primitive.Item, { ...props, ref: ref, "data-destructive": destructive || undefined, className: classes('inkra-menu__item', className), children: _jsx(ItemBody, { icon: icon, children: children }) });
25
+ });
26
+ const CheckboxItem = forwardRef(function CheckboxItem({ className, children, checked, ...props }, ref) {
27
+ const indicator = _jsx(Primitive.ItemIndicator, { children: _jsx(PencilIcon, { size: 16, sourceSize: 24, paths: [{ d: checked === 'indeterminate' ? 'M5 12h14' : 'M5 12.5L10 17L19 7' }] }) });
28
+ return _jsx(Primitive.CheckboxItem, { ...props, checked: checked, ref: ref, className: classes('inkra-menu__item', className), children: _jsx(ItemBody, { icon: indicator, children: children }) });
29
+ });
30
+ const RadioItem = forwardRef(function RadioItem({ className, children, ...props }, ref) {
31
+ const indicator = _jsx(Primitive.ItemIndicator, { children: _jsx(PencilIcon, { size: 16, sourceSize: 24, paths: [{ d: 'M5 12.5L10 17L19 7' }] }) });
32
+ return _jsx(Primitive.RadioItem, { ...props, ref: ref, className: classes('inkra-menu__item', className), children: _jsx(ItemBody, { icon: indicator, children: children }) });
33
+ });
34
+ const Label = forwardRef(function Label({ className, children, ...props }, ref) {
35
+ return _jsx(Primitive.Label, { ...props, ref: ref, className: classes('inkra-menu__group-label', className), children: copy(children) });
36
+ });
37
+ const Separator = forwardRef(function Separator({ className, ...props }, ref) {
38
+ return _jsx(Primitive.Separator, { ...props, ref: ref, className: classes('inkra-menu__separator', className), children: _jsx(PencilLine, {}) });
39
+ });
40
+ export const DropdownMenu = { Root, Trigger, Portal, Content, Item, CheckboxItem, RadioItem, Label, Separator, Group: Primitive.Group, RadioGroup: Primitive.RadioGroup };
@@ -0,0 +1,53 @@
1
+ import type { HTMLAttributes, KeyboardEvent, ReactNode } from 'react';
2
+ import type { InputProps } from '../form/Input.js';
3
+ import type { TextareaProps } from '../form/Textarea.js';
4
+ export type EditableBlurBehavior = 'ignore' | 'save' | 'cancel';
5
+ export type EditableSaveResult = boolean | string | void | null | undefined;
6
+ export type EditableSaveHandler = (value: string, previousValue: string) => EditableSaveResult | Promise<EditableSaveResult>;
7
+ export type EditableValidateHandler = (value: string, previousValue: string) => EditableSaveResult | Promise<EditableSaveResult>;
8
+ export interface EditableEditorProps {
9
+ value: string;
10
+ onValueChange: (value: string) => void;
11
+ onKeyDown: (event: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
12
+ onBlur: () => void;
13
+ disabled?: boolean;
14
+ invalid?: boolean;
15
+ error?: string;
16
+ autoFocus?: boolean;
17
+ 'aria-label'?: string;
18
+ }
19
+ export type EditableEditor = ReactNode | ((props: EditableEditorProps) => ReactNode);
20
+ export interface EditableProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'onChange'> {
21
+ value?: string;
22
+ defaultValue?: string;
23
+ editing?: boolean;
24
+ defaultEditing?: boolean;
25
+ onValueChange?: (value: string) => void;
26
+ onEditingChange?: (editing: boolean) => void;
27
+ onSave?: EditableSaveHandler;
28
+ validate?: EditableValidateHandler;
29
+ onCancel?: (value: string) => void;
30
+ display?: ReactNode | ((value: string) => ReactNode);
31
+ editor?: EditableEditor;
32
+ multiline?: boolean;
33
+ inputProps?: Omit<InputProps, 'value' | 'defaultValue' | 'onValueChange' | 'onChange'>;
34
+ textareaProps?: Omit<TextareaProps, 'value' | 'defaultValue' | 'onChange'>;
35
+ placeholder?: string;
36
+ startEditingLabel?: string;
37
+ saveLabel?: string;
38
+ cancelLabel?: string;
39
+ blurBehavior?: EditableBlurBehavior;
40
+ submitOnEnter?: boolean;
41
+ disabled?: boolean;
42
+ readOnly?: boolean;
43
+ invalid?: boolean;
44
+ seed?: string | number;
45
+ }
46
+ export interface EditableHandle {
47
+ focus: () => void;
48
+ startEditing: () => void;
49
+ save: () => void;
50
+ cancel: () => void;
51
+ }
52
+ export declare const Editable: import("react").ForwardRefExoticComponent<EditableProps & import("react").RefAttributes<EditableHandle>>;
53
+ export type { InputProps, TextareaProps };