@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,278 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { DndContext, DragOverlay, KeyboardSensor, MouseSensor, TouchSensor, closestCenter, pointerWithin, rectIntersection, useDroppable, useSensor, useSensors, } from '@dnd-kit/core';
3
+ import { SortableContext, rectSortingStrategy, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy, } from '@dnd-kit/sortable';
4
+ import { CSS } from '@dnd-kit/utilities';
5
+ import { useMemo, useRef, useState } from 'react';
6
+ import { PencilIcon } from '../PencilIcon.js';
7
+ import { PencilLine } from '../PencilLine.js';
8
+ import { PencilSurface } from '../PencilSurface.js';
9
+ import { PencilText } from '../PencilText.js';
10
+ import { cloneSortableContainers, findSortableLocation, projectSortableMove, sortableContainersEqual, } from './model.js';
11
+ const gripIcon = [
12
+ { d: 'M 8 7 L 8.01 7 M 16 7 L 16.01 7 M 8 12 L 8.01 12 M 16 12 L 16.01 12 M 8 17 L 8.01 17 M 16 17 L 16.01 17' },
13
+ ];
14
+ function engineItemId(id) {
15
+ return `inkra-sortable-item:${typeof id}:${String(id)}`;
16
+ }
17
+ function engineContainerId(id) {
18
+ return `inkra-sortable-container:${typeof id}:${String(id)}`;
19
+ }
20
+ function isInteractiveTarget(target) {
21
+ return target instanceof Element && Boolean(target.closest('button, a, input, select, textarea, [contenteditable="true"], [data-sortable-no-drag]'));
22
+ }
23
+ function filterItemActivatorProps(props) {
24
+ return {
25
+ ...props,
26
+ onKeyDown: (event) => {
27
+ if (!isInteractiveTarget(event.target))
28
+ props.onKeyDown?.(event);
29
+ },
30
+ onMouseDown: (event) => {
31
+ if (!isInteractiveTarget(event.target))
32
+ props.onMouseDown?.(event);
33
+ },
34
+ onTouchStart: (event) => {
35
+ if (!isInteractiveTarget(event.target))
36
+ props.onTouchStart?.(event);
37
+ },
38
+ };
39
+ }
40
+ const defaultLabels = {
41
+ handle: 'Drag item',
42
+ screenReaderInstructions: 'Press Space or Enter to pick up an item. Use the arrow keys to move it, Space or Enter to drop it, and Escape to cancel.',
43
+ pickedUp: (item, container, position, count) => `Picked up ${item}, item ${position} of ${count} in ${container}.`,
44
+ movedOver: (item, container, position, count) => `${item} is over position ${position} of ${count} in ${container}.`,
45
+ dropped: (item, container, position, count) => `Dropped ${item} at position ${position} of ${count} in ${container}.`,
46
+ cancelled: (item) => `Sorting cancelled. ${item} returned to its original position.`,
47
+ };
48
+ function getEngineData(value) {
49
+ const data = value?.data.current;
50
+ return data?.type === 'inkra-sortable-item' || data?.type === 'inkra-sortable-container' ? data : null;
51
+ }
52
+ function getCollisionEngineData(collision) {
53
+ return collision.data?.droppableContainer
54
+ ? getEngineData(collision.data.droppableContainer)
55
+ : null;
56
+ }
57
+ function getDropProjection(containers, event, getItemId) {
58
+ const activeData = getEngineData(event.active);
59
+ const overData = getEngineData(event.over);
60
+ if (activeData?.itemId === undefined || !overData || overData.disabled)
61
+ return cloneSortableContainers(containers);
62
+ const targetContainer = containers.find((container) => container.id === overData.containerId);
63
+ const translated = event.active.rect.current.translated;
64
+ const source = findSortableLocation(containers, activeData.itemId, getItemId);
65
+ const target = overData.itemId === undefined ? null : findSortableLocation(containers, overData.itemId, getItemId);
66
+ const keyboardDrag = typeof KeyboardEvent !== 'undefined' && event.activatorEvent instanceof KeyboardEvent;
67
+ const insertAfter = keyboardDrag
68
+ ? source !== null && target !== null && source.containerId === target.containerId && source.index < target.index
69
+ : overData.itemId !== undefined && translated !== null && targetContainer?.layout === 'grid'
70
+ ? translated.left + translated.width / 2 > event.over.rect.left + event.over.rect.width / 2
71
+ : overData.itemId !== undefined && translated !== null
72
+ && translated.top + translated.height / 2 > event.over.rect.top + event.over.rect.height / 2;
73
+ return projectSortableMove(containers, activeData.itemId, getItemId, {
74
+ overContainerId: overData.containerId,
75
+ overItemId: overData.itemId,
76
+ insertAfter,
77
+ });
78
+ }
79
+ const collisionDetection = (args) => {
80
+ const pointer = pointerWithin(args);
81
+ const pointerItems = pointer.filter((collision) => getCollisionEngineData(collision)?.type === 'inkra-sortable-item');
82
+ if (pointerItems.length > 0)
83
+ return pointerItems;
84
+ if (pointer.length > 0)
85
+ return pointer;
86
+ const intersections = rectIntersection(args);
87
+ const intersectingItems = intersections.filter((collision) => getCollisionEngineData(collision)?.type === 'inkra-sortable-item');
88
+ if (intersectingItems.length > 0)
89
+ return intersectingItems;
90
+ return intersections.length > 0 ? intersections : closestCenter(args);
91
+ };
92
+ function SortableContainer({ container, getItemId, renderItem, renderContainerHeader, handle, isItemDisabled, itemClassName, containerClassName, activeId, handleLabel, getItemLabel, }) {
93
+ const disabled = container.disabled === true;
94
+ const { isOver, setNodeRef } = useDroppable({
95
+ id: engineContainerId(container.id),
96
+ data: { type: 'inkra-sortable-container', containerId: container.id, disabled },
97
+ });
98
+ const ids = container.items.map((item) => engineItemId(getItemId(item)));
99
+ const layout = container.layout ?? 'list';
100
+ const acceptingOver = isOver && !disabled;
101
+ return _jsxs(PencilSurface, { as: "section", className: ['inkra-sortable__container', containerClassName].filter(Boolean).join(' '), "data-disabled": disabled || undefined, "data-layout": layout, "data-over": acceptingOver || undefined, "aria-disabled": disabled || undefined, "aria-label": container.label ?? String(container.id), ref: setNodeRef, seed: `sortable-container-${String(container.id)}`, variant: "paper", children: [acceptingOver && _jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-sortable__container-target", seed: `sortable-container-${String(container.id)}-target`, variant: "selection" }), (renderContainerHeader || container.label) && _jsxs("div", { className: "inkra-sortable__container-header", children: [_jsx("div", { className: "inkra-sortable__container-title", children: renderContainerHeader
102
+ ? renderContainerHeader({ container, isOver: acceptingOver, itemCount: container.items.length })
103
+ : container.label ? _jsx(PencilText, { children: container.label }) : null }), _jsx(PencilLine, { "aria-hidden": "true", className: "inkra-sortable__container-divider", seed: `sortable-container-${String(container.id)}-divider` })] }), _jsx(SortableContext, { items: ids, strategy: layout === 'grid' ? rectSortingStrategy : verticalListSortingStrategy, children: _jsxs("div", { className: "inkra-sortable__items", children: [container.items.map((item, index) => {
104
+ const id = getItemId(item);
105
+ return _jsx(SortableItem, { activeId: activeId, container: container, disabled: disabled || isItemDisabled?.(item, container) === true, handle: handle, handleLabel: `${handleLabel}: ${getItemLabel(item)}`, id: id, index: index, item: item, itemClassName: itemClassName, renderItem: renderItem }, engineItemId(id));
106
+ }), container.items.length === 0 && _jsx("div", { className: "inkra-sortable__empty", "aria-hidden": "true" })] }) })] });
107
+ }
108
+ function SortableItem({ activeId, container, disabled, handle, handleLabel, id, index, item, itemClassName, renderItem, }) {
109
+ const hasHandle = handle === true || typeof handle === 'function';
110
+ const { attributes, isDragging, listeners, setActivatorNodeRef, setNodeRef, transform, transition, } = useSortable({
111
+ id: engineItemId(id),
112
+ disabled: disabled ? { draggable: true, droppable: false } : false,
113
+ data: { type: 'inkra-sortable-item', containerId: container.id, itemId: id, disabled },
114
+ });
115
+ const state = {
116
+ item,
117
+ id,
118
+ containerId: container.id,
119
+ index,
120
+ disabled,
121
+ isDragging,
122
+ isOverlay: false,
123
+ };
124
+ const activatorProps = { ...attributes, ...listeners };
125
+ const itemActivatorProps = filterItemActivatorProps({ ...attributes, ...listeners });
126
+ const setItemRef = (element) => {
127
+ setNodeRef(element);
128
+ if (!hasHandle)
129
+ setActivatorNodeRef(element);
130
+ };
131
+ return _jsxs("div", { ...(!hasHandle ? itemActivatorProps : {}), "aria-disabled": disabled || undefined, className: ['inkra-sortable__item', itemClassName].filter(Boolean).join(' '), "data-disabled": disabled || undefined, "data-dragging": isDragging || undefined, "data-sortable-id": String(id), ref: setItemRef, style: { transform: CSS.Transform.toString(transform), transition }, children: [_jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-sortable__item-surface", seed: `sortable-item-${String(id)}`, variant: "paper" }), _jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-sortable__focus", seed: `sortable-focus-${String(id)}`, variant: "outline" }), activeId === id && _jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-sortable__placeholder", seed: `sortable-placeholder-${String(id)}`, variant: "selection" }), _jsx("div", { className: "inkra-sortable__item-content", children: renderItem(state) }), hasHandle && _jsx("div", { className: "inkra-sortable__handle-slot", children: typeof handle === 'function'
132
+ ? handle({ ...state, props: { ...activatorProps, 'aria-label': handleLabel, disabled, ref: setActivatorNodeRef } })
133
+ : _jsx("button", { ...activatorProps, "aria-label": handleLabel, className: "inkra-sortable__handle", "data-sortable-handle": "", disabled: disabled, ref: setActivatorNodeRef, type: "button", children: _jsx(PencilIcon, { "aria-hidden": "true", paths: gripIcon, size: 24, sourceSize: 24 }) }) })] });
134
+ }
135
+ export function Sortable({ autoScroll = true, className, containerClassName, containers, getContainerLabel = (container) => container.label ?? String(container.id), getItemId, getItemLabel = (item) => String(getItemId(item)), handle = false, isItemDisabled, itemClassName, labels: labelsProp, onChange, onMove, onReorder, renderContainerHeader, renderItem, renderOverlay, }) {
136
+ const labels = { ...defaultLabels, ...labelsProp };
137
+ const [activeId, setActiveId] = useState(null);
138
+ const [activeWidth, setActiveWidth] = useState(null);
139
+ const [projected, setProjected] = useState(null);
140
+ const initialRef = useRef([]);
141
+ const projectedRef = useRef([]);
142
+ const sensors = useSensors(useSensor(MouseSensor, { activationConstraint: { distance: 6 } }), useSensor(TouchSensor, { activationConstraint: { delay: 180, tolerance: 8 } }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }));
143
+ const visibleContainers = projected ?? cloneSortableContainers(containers);
144
+ const activeLocation = activeId === null ? null : findSortableLocation(visibleContainers, activeId, getItemId);
145
+ const activeContainer = activeLocation === null
146
+ ? null
147
+ : visibleContainers.find((container) => container.id === activeLocation.containerId) ?? null;
148
+ const activeItem = activeContainer && activeLocation
149
+ ? activeContainer.items[activeLocation.index]
150
+ : undefined;
151
+ const announcements = useMemo(() => ({
152
+ onDragStart({ active }) {
153
+ const data = getEngineData(active);
154
+ if (data?.itemId === undefined)
155
+ return undefined;
156
+ const location = findSortableLocation(containers, data.itemId, getItemId);
157
+ const container = location && containers.find((entry) => entry.id === location.containerId);
158
+ const item = container && location ? container.items[location.index] : undefined;
159
+ return container && location && item !== undefined
160
+ ? labels.pickedUp(getItemLabel(item), getContainerLabel(container), location.index + 1, container.items.length)
161
+ : undefined;
162
+ },
163
+ onDragOver({ active, over }) {
164
+ const data = getEngineData(active);
165
+ const overData = getEngineData(over);
166
+ if (data?.itemId === undefined || !overData || overData.disabled)
167
+ return undefined;
168
+ const current = projectedRef.current.length > 0 ? projectedRef.current : containers;
169
+ const location = findSortableLocation(current, data.itemId, getItemId);
170
+ const container = location && current.find((entry) => entry.id === location.containerId);
171
+ const item = container && location ? container.items[location.index] : undefined;
172
+ return container && location && item !== undefined
173
+ ? labels.movedOver(getItemLabel(item), getContainerLabel(container), location.index + 1, container.items.length)
174
+ : undefined;
175
+ },
176
+ onDragEnd({ active, over }) {
177
+ const data = getEngineData(active);
178
+ const overData = getEngineData(over);
179
+ if (data?.itemId === undefined || !over)
180
+ return undefined;
181
+ if (overData?.disabled) {
182
+ const location = findSortableLocation(initialRef.current, data.itemId, getItemId);
183
+ const container = location && initialRef.current.find((entry) => entry.id === location.containerId);
184
+ const item = container && location ? container.items[location.index] : undefined;
185
+ return item === undefined ? undefined : labels.cancelled(getItemLabel(item));
186
+ }
187
+ const current = projectedRef.current;
188
+ const location = findSortableLocation(current, data.itemId, getItemId);
189
+ const container = location && current.find((entry) => entry.id === location.containerId);
190
+ const item = container && location ? container.items[location.index] : undefined;
191
+ return container && location && item !== undefined
192
+ ? labels.dropped(getItemLabel(item), getContainerLabel(container), location.index + 1, container.items.length)
193
+ : undefined;
194
+ },
195
+ onDragCancel({ active }) {
196
+ const data = getEngineData(active);
197
+ if (data?.itemId === undefined)
198
+ return undefined;
199
+ const location = findSortableLocation(initialRef.current, data.itemId, getItemId);
200
+ const container = location && initialRef.current.find((entry) => entry.id === location.containerId);
201
+ const item = container && location ? container.items[location.index] : undefined;
202
+ return item === undefined ? undefined : labels.cancelled(getItemLabel(item));
203
+ },
204
+ }), [containers, getContainerLabel, getItemId, getItemLabel, labels]);
205
+ function resetDrag() {
206
+ setActiveId(null);
207
+ setActiveWidth(null);
208
+ setProjected(null);
209
+ projectedRef.current = [];
210
+ }
211
+ function handleDragStart(event) {
212
+ const data = getEngineData(event.active);
213
+ if (data?.itemId === undefined)
214
+ return;
215
+ const snapshot = cloneSortableContainers(containers);
216
+ initialRef.current = snapshot;
217
+ projectedRef.current = snapshot;
218
+ setProjected(snapshot);
219
+ setActiveId(data.itemId);
220
+ setActiveWidth(event.active.rect.current.initial?.width ?? null);
221
+ }
222
+ function handleDragOver(event) {
223
+ const overData = getEngineData(event.over);
224
+ if (!event.over || overData?.disabled) {
225
+ const restored = cloneSortableContainers(initialRef.current);
226
+ projectedRef.current = restored;
227
+ setProjected(restored);
228
+ return;
229
+ }
230
+ const next = getDropProjection(projectedRef.current, event, getItemId);
231
+ projectedRef.current = next;
232
+ setProjected(next);
233
+ }
234
+ function handleDragEnd(event) {
235
+ const data = getEngineData(event.active);
236
+ const overData = getEngineData(event.over);
237
+ if (data?.itemId === undefined || !event.over || overData?.disabled) {
238
+ resetDrag();
239
+ return;
240
+ }
241
+ const next = projectedRef.current;
242
+ const from = findSortableLocation(initialRef.current, data.itemId, getItemId);
243
+ const to = findSortableLocation(next, data.itemId, getItemId);
244
+ const sourceContainer = from && initialRef.current.find((container) => container.id === from.containerId);
245
+ const item = sourceContainer && from ? sourceContainer.items[from.index] : undefined;
246
+ if (from && to && item !== undefined && !sortableContainersEqual(initialRef.current, next, getItemId)) {
247
+ const details = {
248
+ activeId: data.itemId,
249
+ overId: overData?.itemId ?? null,
250
+ from,
251
+ to,
252
+ item,
253
+ type: from.containerId === to.containerId ? 'reorder' : 'move',
254
+ };
255
+ onChange(next, details);
256
+ if (details.type === 'reorder')
257
+ onReorder?.(details);
258
+ else
259
+ onMove?.(details);
260
+ }
261
+ resetDrag();
262
+ }
263
+ function handleDragCancel(_event) {
264
+ resetDrag();
265
+ }
266
+ return _jsxs(DndContext, { accessibility: {
267
+ announcements,
268
+ screenReaderInstructions: { draggable: labels.screenReaderInstructions },
269
+ }, autoScroll: autoScroll, collisionDetection: collisionDetection, onDragCancel: handleDragCancel, onDragEnd: handleDragEnd, onDragOver: handleDragOver, onDragStart: handleDragStart, sensors: sensors, children: [_jsx("div", { className: ['inkra-sortable', className].filter(Boolean).join(' '), "data-dragging": activeId !== null || undefined, children: visibleContainers.map((container) => _jsx(SortableContainer, { activeId: activeId, container: container, containerClassName: containerClassName, getItemId: getItemId, getItemLabel: getItemLabel, handle: handle, handleLabel: labels.handle, isItemDisabled: isItemDisabled, itemClassName: itemClassName, renderContainerHeader: renderContainerHeader, renderItem: renderItem }, container.id)) }), _jsx(DragOverlay, { dropAnimation: null, children: activeItem !== undefined && activeContainer && activeLocation ? _jsxs("div", { className: "inkra-sortable__overlay", style: activeWidth === null ? undefined : { '--inkra-sortable-overlay-width': `${activeWidth}px` }, children: [_jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-sortable__overlay-surface", seed: `sortable-overlay-${String(activeId)}`, variant: "paper" }), _jsx("div", { className: "inkra-sortable__item-content", children: (renderOverlay ?? renderItem)({
270
+ item: activeItem,
271
+ id: activeId,
272
+ containerId: activeContainer.id,
273
+ index: activeLocation.index,
274
+ disabled: false,
275
+ isDragging: true,
276
+ isOverlay: true,
277
+ }) })] }) : null })] });
278
+ }
@@ -0,0 +1,30 @@
1
+ export type SortableIdentifier = string | number;
2
+ export type SortableLayout = 'list' | 'grid';
3
+ export interface SortableContainerData<Item> {
4
+ id: SortableIdentifier;
5
+ items: readonly Item[];
6
+ label?: string;
7
+ disabled?: boolean;
8
+ layout?: SortableLayout;
9
+ }
10
+ export interface SortableLocation {
11
+ containerId: SortableIdentifier;
12
+ index: number;
13
+ }
14
+ export interface SortableChangeDetails<Item> {
15
+ activeId: SortableIdentifier;
16
+ overId: SortableIdentifier | null;
17
+ from: SortableLocation;
18
+ to: SortableLocation;
19
+ item: Item;
20
+ type: 'reorder' | 'move';
21
+ }
22
+ export interface SortableProjectionOptions {
23
+ overContainerId: SortableIdentifier;
24
+ overItemId?: SortableIdentifier;
25
+ insertAfter?: boolean;
26
+ }
27
+ export declare function cloneSortableContainers<Item>(containers: readonly SortableContainerData<Item>[]): SortableContainerData<Item>[];
28
+ export declare function findSortableLocation<Item>(containers: readonly SortableContainerData<Item>[], itemId: SortableIdentifier, getItemId: (item: Item) => SortableIdentifier): SortableLocation | null;
29
+ export declare function projectSortableMove<Item>(containers: readonly SortableContainerData<Item>[], activeId: SortableIdentifier, getItemId: (item: Item) => SortableIdentifier, options: SortableProjectionOptions): SortableContainerData<Item>[];
30
+ export declare function sortableContainersEqual<Item>(left: readonly SortableContainerData<Item>[], right: readonly SortableContainerData<Item>[], getItemId: (item: Item) => SortableIdentifier): boolean;
@@ -0,0 +1,64 @@
1
+ export function cloneSortableContainers(containers) {
2
+ return containers.map((container) => ({ ...container, items: [...container.items] }));
3
+ }
4
+ export function findSortableLocation(containers, itemId, getItemId) {
5
+ for (const container of containers) {
6
+ const index = container.items.findIndex((item) => getItemId(item) === itemId);
7
+ if (index >= 0)
8
+ return { containerId: container.id, index };
9
+ }
10
+ return null;
11
+ }
12
+ export function projectSortableMove(containers, activeId, getItemId, options) {
13
+ const source = findSortableLocation(containers, activeId, getItemId);
14
+ const targetContainerIndex = containers.findIndex((container) => container.id === options.overContainerId);
15
+ if (!source || targetContainerIndex < 0 || containers[targetContainerIndex]?.disabled) {
16
+ return cloneSortableContainers(containers);
17
+ }
18
+ if (options.overItemId === activeId)
19
+ return cloneSortableContainers(containers);
20
+ const sourceContainerIndex = containers.findIndex((container) => container.id === source.containerId);
21
+ const result = cloneSortableContainers(containers);
22
+ const sourceItems = [...result[sourceContainerIndex].items];
23
+ const [activeItem] = sourceItems.splice(source.index, 1);
24
+ if (activeItem === undefined)
25
+ return result;
26
+ if (sourceContainerIndex === targetContainerIndex) {
27
+ const originalTargetIndex = options.overItemId === undefined
28
+ ? sourceItems.length
29
+ : containers[targetContainerIndex].items.findIndex((item) => getItemId(item) === options.overItemId);
30
+ if (originalTargetIndex < 0)
31
+ return result;
32
+ let targetIndex = originalTargetIndex;
33
+ if (source.index < originalTargetIndex)
34
+ targetIndex -= 1;
35
+ if (options.insertAfter)
36
+ targetIndex += 1;
37
+ targetIndex = Math.max(0, Math.min(targetIndex, sourceItems.length));
38
+ sourceItems.splice(targetIndex, 0, activeItem);
39
+ result[sourceContainerIndex] = { ...result[sourceContainerIndex], items: sourceItems };
40
+ return result;
41
+ }
42
+ const targetItems = [...result[targetContainerIndex].items];
43
+ let targetIndex = options.overItemId === undefined
44
+ ? targetItems.length
45
+ : targetItems.findIndex((item) => getItemId(item) === options.overItemId);
46
+ if (targetIndex < 0)
47
+ targetIndex = targetItems.length;
48
+ if (options.insertAfter)
49
+ targetIndex += 1;
50
+ targetIndex = Math.max(0, Math.min(targetIndex, targetItems.length));
51
+ targetItems.splice(targetIndex, 0, activeItem);
52
+ result[sourceContainerIndex] = { ...result[sourceContainerIndex], items: sourceItems };
53
+ result[targetContainerIndex] = { ...result[targetContainerIndex], items: targetItems };
54
+ return result;
55
+ }
56
+ export function sortableContainersEqual(left, right, getItemId) {
57
+ return left.length === right.length && left.every((container, containerIndex) => {
58
+ const other = right[containerIndex];
59
+ return other !== undefined
60
+ && container.id === other.id
61
+ && container.items.length === other.items.length
62
+ && container.items.every((item, itemIndex) => getItemId(item) === getItemId(other.items[itemIndex]));
63
+ });
64
+ }
@@ -0,0 +1,19 @@
1
+ import type { HTMLAttributes } from 'react';
2
+ import type { SparklineDatum } from './model.js';
3
+ export type SparklineType = 'line' | 'bar';
4
+ export interface SparklineProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
5
+ data: readonly SparklineDatum[];
6
+ type?: SparklineType;
7
+ width?: number;
8
+ height?: number;
9
+ min?: number;
10
+ max?: number;
11
+ label?: string;
12
+ showPoints?: boolean;
13
+ showArea?: boolean;
14
+ showSummary?: boolean;
15
+ getLabel?: (value: number | null, index: number) => string;
16
+ }
17
+ export declare const Sparkline: import("react").ForwardRefExoticComponent<SparklineProps & import("react").RefAttributes<HTMLDivElement>>;
18
+ export { createSparklineGeometry, normalizeSparklineData, sparklineDomain } from './model.js';
19
+ export type { SparklineDatum, SparklinePoint } from './model.js';
@@ -0,0 +1,240 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, useMemo, useRef, useState } from 'react';
3
+ import { PencilText } from '../PencilText.js';
4
+ import { useBrowserLayoutEffect } from '../internal/useBrowserLayoutEffect.js';
5
+ import { effectiveDpr } from '../internal/cache.js';
6
+ import { observeCanvasRecovery } from '../internal/recovery.js';
7
+ import { seedToNumber } from '../internal/random.js';
8
+ import { pencilStroke } from '../internal/stroke.js';
9
+ import { drawPencilWash } from '../internal/wash.js';
10
+ import { pencilRenderDefaults, readRenderToken } from '../internal/renderTokens.js';
11
+ import { createSparklineGeometry, normalizeSparklineData, sparklineDomain } from './model.js';
12
+ function defaultLabel(value, index) {
13
+ return value === null ? `Point ${index + 1}: missing` : `Point ${index + 1}: ${value}`;
14
+ }
15
+ function resolveCssColor(host, style, token, fallback) {
16
+ const value = style.getPropertyValue(token).trim();
17
+ if (!value || !value.includes('var('))
18
+ return value || fallback;
19
+ const probe = document.createElement('span');
20
+ probe.style.color = `var(${token})`;
21
+ host.appendChild(probe);
22
+ const resolved = getComputedStyle(probe).color;
23
+ probe.remove();
24
+ return resolved || fallback;
25
+ }
26
+ export const Sparkline = forwardRef(function Sparkline({ data, type = 'line', width = 180, height = 56, min, max, label = 'Sparkline', showPoints = true, showArea = true, showSummary = true, getLabel = defaultLabel, className, ...props }, ref) {
27
+ const canvasRef = useRef(null);
28
+ const interactionCanvasRef = useRef(null);
29
+ const [pencilReady, setPencilReady] = useState(false);
30
+ const [interactionReady, setInteractionReady] = useState(false);
31
+ const points = useMemo(() => normalizeSparklineData(data), [data]);
32
+ const values = useMemo(() => points.flatMap(point => point.value === null ? [] : [point.value]), [points]);
33
+ const domain = useMemo(() => sparklineDomain(points), [points]);
34
+ const boundedPoints = useMemo(() => points.map(point => ({
35
+ ...point,
36
+ value: point.value === null ? null : Math.min(max ?? Infinity, Math.max(min ?? -Infinity, point.value)),
37
+ })), [max, min, points]);
38
+ const geometry = useMemo(() => createSparklineGeometry(boundedPoints, width, height), [boundedPoints, height, width]);
39
+ const [activeIndex, setActiveIndex] = useState(values.length ? [...points].reverse().find(point => point.value !== null)?.index ?? null : null);
40
+ const activePoint = activeIndex === null ? null : points[activeIndex] ?? null;
41
+ const effectiveShowPoints = showPoints || values.length === 1;
42
+ const summary = values.length === 0 ? 'No data' : `Current ${values[values.length - 1]}, min ${Math.min(...values)}, max ${Math.max(...values)}`;
43
+ const onKeyDown = (event) => {
44
+ if (!points.length || !['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key))
45
+ return;
46
+ event.preventDefault();
47
+ const current = activeIndex ?? 0;
48
+ const next = event.key === 'Home' ? 0 : event.key === 'End' ? points.length - 1 : Math.min(points.length - 1, Math.max(0, current + (event.key === 'ArrowRight' ? 1 : -1)));
49
+ setActiveIndex(next);
50
+ };
51
+ const classes = ['inkra-sparkline', `inkra-sparkline--${type}`, className].filter(Boolean).join(' ');
52
+ useBrowserLayoutEffect(() => {
53
+ const canvas = canvasRef.current;
54
+ if (!canvas || typeof window === 'undefined')
55
+ return undefined;
56
+ let frame = 0;
57
+ let disposed = false;
58
+ const paint = () => {
59
+ frame = 0;
60
+ if (disposed)
61
+ return;
62
+ const cssWidth = canvas.clientWidth;
63
+ const cssHeight = canvas.clientHeight;
64
+ const clear = () => { canvas.width = 1; canvas.height = 1; setPencilReady(false); };
65
+ if (!values.length || cssWidth < 4 || cssHeight < 4) {
66
+ clear();
67
+ return;
68
+ }
69
+ const dpr = effectiveDpr(2);
70
+ const context = canvas.getContext('2d');
71
+ if (!context || context.isContextLost?.()) {
72
+ clear();
73
+ return;
74
+ }
75
+ const style = getComputedStyle(canvas);
76
+ const lineColor = resolveCssColor(canvas, style, '--inkra-accent-strong', style.color);
77
+ const washColor = resolveCssColor(canvas, style, '--inkra-accent', lineColor);
78
+ const strokeWidth = readRenderToken(style, '--inkra-stroke-width', pencilRenderDefaults.strokeWidth, 0.3, 3);
79
+ const roughness = readRenderToken(style, '--inkra-stroke-amplitude', pencilRenderDefaults.strokeRoughness, 0, 4);
80
+ const washStrength = readRenderToken(style, '--inkra-wash-strength', pencilRenderDefaults.washStrength, 0, 1) / 0.48;
81
+ const washSpacing = readRenderToken(style, '--inkra-wash-spacing', pencilRenderDefaults.washSpacing, 1, 6);
82
+ const washRoughness = readRenderToken(style, '--inkra-wash-roughness', pencilRenderDefaults.washRoughness, 0, 6);
83
+ const washAngle = readRenderToken(style, '--inkra-wash-angle', pencilRenderDefaults.washAngle, -85, 85);
84
+ canvas.width = Math.ceil(cssWidth * dpr);
85
+ canvas.height = Math.ceil(cssHeight * dpr);
86
+ context.setTransform(dpr, 0, 0, dpr, 0, 0);
87
+ context.clearRect(0, 0, cssWidth, cssHeight);
88
+ const scaleX = cssWidth / width;
89
+ const scaleY = cssHeight / height;
90
+ const segments = [];
91
+ let segment = [];
92
+ boundedPoints.forEach(point => {
93
+ if (point.value === null) {
94
+ if (segment.length)
95
+ segments.push(segment);
96
+ segment = [];
97
+ return;
98
+ }
99
+ segment.push([geometry.x(point.index) * scaleX, geometry.y(point.value) * scaleY]);
100
+ });
101
+ if (segment.length)
102
+ segments.push(segment);
103
+ const seed = seedToNumber(`sparkline-${type}-${data.length}`);
104
+ if (type === 'line' && segments.some(points => points.length > 1)) {
105
+ if (showArea && typeof Path2D !== 'undefined' && geometry.areaPath) {
106
+ context.save();
107
+ context.scale(scaleX, scaleY);
108
+ context.clip(new Path2D(geometry.areaPath));
109
+ context.setTransform(dpr, 0, 0, dpr, 0, 0);
110
+ drawPencilWash(context, { x: 0, y: 0, width: cssWidth, height: cssHeight }, washColor, seed + 17, { strength: washStrength * 0.22, spacing: washSpacing, roughness: washRoughness, angle: washAngle, inset: 2, radius: 2, dpr });
111
+ context.restore();
112
+ }
113
+ segments.forEach((points, index) => {
114
+ if (points.length > 1)
115
+ pencilStroke(context, points, lineColor, strokeWidth, seed + index * 47, roughness, 2, false, { variation: 0.82, breaks: 0.25, grain: 0.62, gain: 2.1, step: 0.8 });
116
+ });
117
+ }
118
+ else if (type === 'bar') {
119
+ const baseline = geometry.y(0) * scaleY;
120
+ const barWidth = Math.max(2, cssWidth / Math.max(16, points.length * 2));
121
+ boundedPoints.forEach(point => {
122
+ if (point.value === null)
123
+ return;
124
+ const y = geometry.y(point.value) * scaleY;
125
+ drawPencilWash(context, { x: geometry.x(point.index) * scaleX - barWidth / 2, y: Math.min(y, baseline), width: barWidth, height: Math.max(2, Math.abs(baseline - y)) }, washColor, seed + point.index * 31, { strength: washStrength * 0.34, spacing: washSpacing, roughness: washRoughness, angle: washAngle, inset: 1, radius: 1, dpr });
126
+ pencilStroke(context, [[geometry.x(point.index) * scaleX - barWidth / 2, Math.min(y, baseline)], [geometry.x(point.index) * scaleX + barWidth / 2, Math.min(y, baseline)]], lineColor, strokeWidth * 0.55, seed + point.index * 43, roughness, 1, false, { variation: 0.8, breaks: 0.2, grain: 0.65, step: 0.8 });
127
+ });
128
+ }
129
+ if (!disposed)
130
+ setPencilReady(true);
131
+ };
132
+ const schedule = () => {
133
+ if (frame)
134
+ return;
135
+ frame = requestAnimationFrame(() => {
136
+ try {
137
+ paint();
138
+ }
139
+ catch {
140
+ canvas.width = 1;
141
+ canvas.height = 1;
142
+ setPencilReady(false);
143
+ }
144
+ });
145
+ };
146
+ const resize = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(schedule);
147
+ resize?.observe(canvas);
148
+ const media = window.matchMedia('(prefers-color-scheme: dark)');
149
+ media.addEventListener('change', schedule);
150
+ const inheritedStyle = new MutationObserver(schedule);
151
+ for (let element = canvas; element; element = element.parentElement)
152
+ inheritedStyle.observe(element, { attributes: true, attributeFilter: ['style', 'class', 'data-theme', 'data-inkra-theme'] });
153
+ const stopRecovery = observeCanvasRecovery(() => { setPencilReady(false); schedule(); });
154
+ try {
155
+ paint();
156
+ }
157
+ catch {
158
+ canvas.width = 1;
159
+ canvas.height = 1;
160
+ setPencilReady(false);
161
+ }
162
+ return () => { disposed = true; setPencilReady(false); resize?.disconnect(); inheritedStyle.disconnect(); stopRecovery(); media.removeEventListener('change', schedule); cancelAnimationFrame(frame); };
163
+ }, [boundedPoints, data.length, geometry, height, showArea, type, values.length, width]);
164
+ useBrowserLayoutEffect(() => {
165
+ const canvas = interactionCanvasRef.current;
166
+ if (!canvas || typeof window === 'undefined')
167
+ return undefined;
168
+ let frame = 0;
169
+ const paint = () => {
170
+ frame = 0;
171
+ const cssWidth = canvas.clientWidth;
172
+ const cssHeight = canvas.clientHeight;
173
+ const context = canvas.getContext('2d');
174
+ const clearInteraction = () => { canvas.width = 1; canvas.height = 1; setInteractionReady(false); };
175
+ if (!context || cssWidth < 4 || cssHeight < 4 || !values.length) {
176
+ clearInteraction();
177
+ return;
178
+ }
179
+ const dpr = effectiveDpr(2);
180
+ const style = getComputedStyle(canvas);
181
+ const lineColor = resolveCssColor(canvas, style, '--inkra-accent-strong', style.color);
182
+ const strokeWidth = readRenderToken(style, '--inkra-stroke-width', pencilRenderDefaults.strokeWidth, 0.3, 3);
183
+ const roughness = readRenderToken(style, '--inkra-stroke-amplitude', pencilRenderDefaults.strokeRoughness, 0, 4);
184
+ canvas.width = Math.ceil(cssWidth * dpr);
185
+ canvas.height = Math.ceil(cssHeight * dpr);
186
+ context.setTransform(dpr, 0, 0, dpr, 0, 0);
187
+ context.clearRect(0, 0, cssWidth, cssHeight);
188
+ const scaleX = cssWidth / width;
189
+ const scaleY = cssHeight / height;
190
+ const seed = seedToNumber(`sparkline-interaction-${type}-${data.length}`);
191
+ if (type === 'line' && effectiveShowPoints)
192
+ boundedPoints.forEach(point => {
193
+ if (point.value === null)
194
+ return;
195
+ const x = geometry.x(point.index) * scaleX;
196
+ const y = geometry.y(point.value) * scaleY;
197
+ pencilStroke(context, [[x - 2.8, y], [x, y - 2.8], [x + 2.8, y], [x, y + 2.8], [x - 2.8, y]], lineColor, strokeWidth * 0.7, seed + point.index * 61, roughness, 1, true, { variation: 0.75, breaks: 0.12, grain: 0.62, gain: 1.8, step: 0.8 });
198
+ });
199
+ if (activePoint && activePoint.value !== null) {
200
+ const x = geometry.x(activePoint.index) * scaleX;
201
+ pencilStroke(context, [[x, 2], [x, cssHeight - 2]], lineColor, strokeWidth * 0.18, seed + 401, roughness, 1, false, { variation: 0.55, breaks: 0.45, grain: 0.5, gain: 1.1, step: 1.2 });
202
+ }
203
+ setInteractionReady(true);
204
+ };
205
+ const schedule = () => { if (!frame)
206
+ frame = requestAnimationFrame(() => { try {
207
+ paint();
208
+ }
209
+ catch {
210
+ canvas.width = 1;
211
+ canvas.height = 1;
212
+ setInteractionReady(false);
213
+ } }); };
214
+ const resize = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(schedule);
215
+ resize?.observe(canvas);
216
+ const media = window.matchMedia('(prefers-color-scheme: dark)');
217
+ media.addEventListener('change', schedule);
218
+ const inheritedStyle = new MutationObserver(schedule);
219
+ for (let element = canvas; element; element = element.parentElement)
220
+ inheritedStyle.observe(element, { attributes: true, attributeFilter: ['style', 'class', 'data-theme', 'data-inkra-theme'] });
221
+ const stopRecovery = observeCanvasRecovery(() => { setInteractionReady(false); schedule(); });
222
+ try {
223
+ paint();
224
+ }
225
+ catch {
226
+ canvas.width = 1;
227
+ canvas.height = 1;
228
+ setInteractionReady(false);
229
+ }
230
+ return () => { setInteractionReady(false); resize?.disconnect(); inheritedStyle.disconnect(); stopRecovery(); media.removeEventListener('change', schedule); cancelAnimationFrame(frame); };
231
+ }, [activeIndex, activePoint, boundedPoints, data.length, effectiveShowPoints, geometry, height, type, values.length, width]);
232
+ return _jsxs("div", { ...props, ref: ref, className: `${classes}${pencilReady ? ' inkra-sparkline--pencil-ready' : ''}${interactionReady ? ' inkra-sparkline--interaction-ready' : ''}`, "data-empty": values.length === 0 || undefined, "data-show-points": effectiveShowPoints || undefined, children: [_jsxs("svg", { className: "inkra-sparkline__svg", viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": label, tabIndex: 0, onKeyDown: onKeyDown, children: [showArea && type === 'line' && geometry.areaPath && _jsx("path", { className: "inkra-sparkline__area", d: geometry.areaPath, "aria-hidden": "true" }), type === 'line' && geometry.linePath && _jsx("path", { className: "inkra-sparkline__line", d: geometry.linePath, "aria-hidden": "true" }), type === 'bar' && boundedPoints.map(point => {
233
+ if (point.value === null)
234
+ return null;
235
+ const baseline = geometry.y(0);
236
+ const valueY = geometry.y(point.value);
237
+ return _jsx("rect", { className: "inkra-sparkline__bar", x: geometry.x(point.index) - Math.max(2, width / Math.max(16, points.length * 2)) / 2, width: Math.max(2, width / Math.max(16, points.length * 2)), y: Math.min(baseline, valueY), height: Math.max(1, Math.abs(baseline - valueY)), "data-index": point.index, "data-active": activeIndex === point.index || undefined, onMouseEnter: () => setActiveIndex(point.index) }, point.index);
238
+ }), (showPoints || values.length === 1) && type === 'line' && boundedPoints.map(point => point.value === null ? null : _jsx("circle", { className: "inkra-sparkline__point", cx: geometry.x(point.index), cy: geometry.y(point.value), r: activeIndex === point.index ? 3.5 : 2, "data-active": activeIndex === point.index || undefined, onMouseEnter: () => setActiveIndex(point.index) }, point.index)), activePoint && activePoint.value !== null && _jsx("line", { className: "inkra-sparkline__guide", x1: geometry.x(activePoint.index), x2: geometry.x(activePoint.index), y1: 4, y2: height - 4, "aria-hidden": "true" })] }), _jsx("canvas", { ref: canvasRef, className: "inkra-sparkline__pencil inkra-sparkline__pencil--static", style: { aspectRatio: `${width} / ${height}` }, "aria-hidden": "true" }), _jsx("canvas", { ref: interactionCanvasRef, className: "inkra-sparkline__pencil inkra-sparkline__pencil--interaction", style: { aspectRatio: `${width} / ${height}` }, "aria-hidden": "true" }), activePoint && _jsx("div", { className: "inkra-sparkline__tooltip", "aria-hidden": "true", children: _jsx(PencilText, { children: getLabel(activePoint.value, activePoint.index) }) }), showSummary && _jsxs("p", { className: "inkra-sparkline__summary", children: [_jsxs("span", { className: "visually-hidden", children: [label, ": "] }), _jsx(PencilText, { seed: `sparkline-summary-${label}-${summary}`, children: summary })] }), _jsx("div", { className: "inkra-sparkline__data", "aria-label": `${label} data`, children: points.map(point => _jsx("span", { children: getLabel(point.value, point.index) }, point.index)) }), _jsxs("span", { className: "visually-hidden", children: ["Domain ", domain[0], " to ", domain[1]] })] });
239
+ });
240
+ export { createSparklineGeometry, normalizeSparklineData, sparklineDomain } from './model.js';