@inkra/react 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +316 -2
- package/THIRD_PARTY_NOTICES.md +39 -0
- package/Yozai-OFL.txt +94 -0
- package/dist/Button.d.ts +36 -0
- package/dist/Button.js +89 -0
- package/dist/PencilIcon.d.ts +22 -0
- package/dist/PencilIcon.js +210 -0
- package/dist/PencilLine.d.ts +10 -0
- package/dist/PencilLine.js +91 -0
- package/dist/PencilSurface.d.ts +19 -0
- package/dist/PencilSurface.js +19 -0
- package/dist/PencilText.d.ts +16 -0
- package/dist/PencilText.js +338 -0
- package/dist/accordion/Accordion.d.ts +27 -0
- package/dist/accordion/Accordion.js +40 -0
- package/dist/accordion/index.d.ts +2 -0
- package/dist/accordion/index.js +1 -0
- package/dist/alert-dialog/index.d.ts +64 -0
- package/dist/alert-dialog/index.js +109 -0
- package/dist/assets/ui-hand-yozai.woff2 +0 -0
- package/dist/audio-player/index.d.ts +60 -0
- package/dist/audio-player/index.js +101 -0
- package/dist/breadcrumb/index.d.ts +16 -0
- package/dist/breadcrumb/index.js +25 -0
- package/dist/calendar/index.d.ts +21 -0
- package/dist/calendar/index.js +41 -0
- package/dist/carousel/index.d.ts +51 -0
- package/dist/carousel/index.js +290 -0
- package/dist/choice-grid/index.d.ts +38 -0
- package/dist/choice-grid/index.js +85 -0
- package/dist/color-picker/color.d.ts +15 -0
- package/dist/color-picker/color.js +55 -0
- package/dist/color-picker/index.d.ts +31 -0
- package/dist/color-picker/index.js +69 -0
- package/dist/command/index.d.ts +23 -0
- package/dist/command/index.js +39 -0
- package/dist/content/index.d.ts +106 -0
- package/dist/content/index.js +80 -0
- package/dist/context-menu/index.d.ts +76 -0
- package/dist/context-menu/index.js +240 -0
- package/dist/data-table/index.d.ts +47 -0
- package/dist/data-table/index.js +91 -0
- package/dist/date-picker/index.d.ts +50 -0
- package/dist/date-picker/index.js +180 -0
- package/dist/day-agenda/index.d.ts +43 -0
- package/dist/day-agenda/index.js +47 -0
- package/dist/day-agenda/layout.d.ts +20 -0
- package/dist/day-agenda/layout.js +60 -0
- package/dist/display/ProgressRing.d.ts +6 -0
- package/dist/display/ProgressRing.js +146 -0
- package/dist/display/index.d.ts +59 -0
- package/dist/display/index.js +75 -0
- package/dist/dockable-panel/index.d.ts +41 -0
- package/dist/dockable-panel/index.js +253 -0
- package/dist/dockable-panel/model.d.ts +21 -0
- package/dist/dockable-panel/model.js +61 -0
- package/dist/drawer/index.d.ts +63 -0
- package/dist/drawer/index.js +86 -0
- package/dist/dropdown-menu/index.d.ts +34 -0
- package/dist/dropdown-menu/index.js +40 -0
- package/dist/editable/index.d.ts +53 -0
- package/dist/editable/index.js +162 -0
- package/dist/empty/index.d.ts +21 -0
- package/dist/empty/index.js +23 -0
- package/dist/flip/index.d.ts +49 -0
- package/dist/flip/index.js +138 -0
- package/dist/form/EditablePencilText.d.ts +13 -0
- package/dist/form/EditablePencilText.js +323 -0
- package/dist/form/Field.d.ts +13 -0
- package/dist/form/Field.js +26 -0
- package/dist/form/Input.d.ts +27 -0
- package/dist/form/Input.js +97 -0
- package/dist/form/InputAction.d.ts +7 -0
- package/dist/form/InputAction.js +24 -0
- package/dist/form/Textarea.d.ts +17 -0
- package/dist/form/Textarea.js +102 -0
- package/dist/form/context.d.ts +12 -0
- package/dist/form/context.js +10 -0
- package/dist/form/controlProps.d.ts +23 -0
- package/dist/form/controlProps.js +20 -0
- package/dist/form/index.d.ts +7 -0
- package/dist/form/index.js +3 -0
- package/dist/form/types.d.ts +6 -0
- package/dist/form/types.js +1 -0
- package/dist/heatmap/index.d.ts +59 -0
- package/dist/heatmap/index.js +248 -0
- package/dist/hotkey/index.d.ts +37 -0
- package/dist/hotkey/index.js +130 -0
- package/dist/hotkey/model.d.ts +27 -0
- package/dist/hotkey/model.js +97 -0
- package/dist/hover-card/index.d.ts +33 -0
- package/dist/hover-card/index.js +141 -0
- package/dist/image-cropper/index.d.ts +82 -0
- package/dist/image-cropper/index.js +261 -0
- package/dist/image-cropper/model.d.ts +42 -0
- package/dist/image-cropper/model.js +94 -0
- package/dist/image-viewer/index.d.ts +79 -0
- package/dist/image-viewer/index.js +220 -0
- package/dist/image-viewer/model.d.ts +9 -0
- package/dist/image-viewer/model.js +18 -0
- package/dist/images/layers-2x.png +0 -0
- package/dist/images/layers.png +0 -0
- package/dist/images/marker-icon.png +0 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.js +69 -0
- package/dist/input-number/index.d.ts +16 -0
- package/dist/input-number/index.js +77 -0
- package/dist/internal/InputActionContext.d.ts +1 -0
- package/dist/internal/InputActionContext.js +3 -0
- package/dist/internal/cache.d.ts +14 -0
- package/dist/internal/cache.js +54 -0
- package/dist/internal/line.d.ts +4 -0
- package/dist/internal/line.js +21 -0
- package/dist/internal/paper.d.ts +1 -0
- package/dist/internal/paper.js +65 -0
- package/dist/internal/random.d.ts +3 -0
- package/dist/internal/random.js +30 -0
- package/dist/internal/recovery.d.ts +1 -0
- package/dist/internal/recovery.js +52 -0
- package/dist/internal/renderTokens.d.ts +10 -0
- package/dist/internal/renderTokens.js +13 -0
- package/dist/internal/stroke.d.ts +24 -0
- package/dist/internal/stroke.js +144 -0
- package/dist/internal/surfaceRenderer.d.ts +41 -0
- package/dist/internal/surfaceRenderer.js +178 -0
- package/dist/internal/textQueue.d.ts +1 -0
- package/dist/internal/textQueue.js +37 -0
- package/dist/internal/textRenderer.d.ts +28 -0
- package/dist/internal/textRenderer.js +239 -0
- package/dist/internal/travelIcons.d.ts +24 -0
- package/dist/internal/travelIcons.js +14 -0
- package/dist/internal/useBrowserLayoutEffect.d.ts +2 -0
- package/dist/internal/useBrowserLayoutEffect.js +3 -0
- package/dist/internal/usePencilSurface.d.ts +3 -0
- package/dist/internal/usePencilSurface.js +116 -0
- package/dist/internal/useSelectionDrawing.d.ts +2 -0
- package/dist/internal/useSelectionDrawing.js +90 -0
- package/dist/internal/wash.d.ts +16 -0
- package/dist/internal/wash.js +149 -0
- package/dist/journey-map/MapScale.d.ts +4 -0
- package/dist/journey-map/MapScale.js +54 -0
- package/dist/journey-map/index.d.ts +39 -0
- package/dist/journey-map/index.js +197 -0
- package/dist/journey-map/terrain.d.ts +8 -0
- package/dist/journey-map/terrain.js +127 -0
- package/dist/keypad/index.d.ts +23 -0
- package/dist/keypad/index.js +63 -0
- package/dist/keypad/model.d.ts +20 -0
- package/dist/keypad/model.js +33 -0
- package/dist/layout/index.d.ts +63 -0
- package/dist/layout/index.js +62 -0
- package/dist/log/index.d.ts +45 -0
- package/dist/log/index.js +159 -0
- package/dist/log/model.d.ts +16 -0
- package/dist/log/model.js +13 -0
- package/dist/node-graph/index.d.ts +123 -0
- package/dist/node-graph/index.js +304 -0
- package/dist/number-ticker/index.d.ts +29 -0
- package/dist/number-ticker/index.js +132 -0
- package/dist/number-ticker/model.d.ts +8 -0
- package/dist/number-ticker/model.js +34 -0
- package/dist/overflow-list/index.d.ts +39 -0
- package/dist/overflow-list/index.js +230 -0
- package/dist/overflow-list/layout.d.ts +19 -0
- package/dist/overflow-list/layout.js +44 -0
- package/dist/overlay/Overlay.d.ts +65 -0
- package/dist/overlay/Overlay.js +77 -0
- package/dist/overlay/Popover.d.ts +43 -0
- package/dist/overlay/Popover.js +45 -0
- package/dist/overlay/index.d.ts +4 -0
- package/dist/overlay/index.js +2 -0
- package/dist/overlay/themeBridge.d.ts +8 -0
- package/dist/overlay/themeBridge.js +98 -0
- package/dist/pagination/index.d.ts +23 -0
- package/dist/pagination/index.js +41 -0
- package/dist/pagination/model.d.ts +4 -0
- package/dist/pagination/model.js +42 -0
- package/dist/pan-zoom/index.d.ts +71 -0
- package/dist/pan-zoom/index.js +175 -0
- package/dist/pencil.d.ts +10 -0
- package/dist/pencil.js +39 -0
- package/dist/radar/index.d.ts +54 -0
- package/dist/radar/index.js +220 -0
- package/dist/range-slider/index.d.ts +16 -0
- package/dist/range-slider/index.js +22 -0
- package/dist/rating/index.d.ts +28 -0
- package/dist/rating/index.js +127 -0
- package/dist/resizable/index.d.ts +32 -0
- package/dist/resizable/index.js +50 -0
- package/dist/scroll-area/index.d.ts +36 -0
- package/dist/scroll-area/index.js +44 -0
- package/dist/segmented-progress/SegmentedProgress.d.ts +17 -0
- package/dist/segmented-progress/SegmentedProgress.js +42 -0
- package/dist/select/MultipleSelect.d.ts +44 -0
- package/dist/select/MultipleSelect.js +124 -0
- package/dist/select/SearchableSelect.d.ts +45 -0
- package/dist/select/SearchableSelect.js +50 -0
- package/dist/select/Select.d.ts +109 -0
- package/dist/select/Select.js +205 -0
- package/dist/select/index.d.ts +4 -0
- package/dist/select/index.js +2 -0
- package/dist/selection/Checkbox.d.ts +9 -0
- package/dist/selection/Checkbox.js +37 -0
- package/dist/selection/RadioGroup.d.ts +23 -0
- package/dist/selection/RadioGroup.js +82 -0
- package/dist/selection/Switch.d.ts +8 -0
- package/dist/selection/Switch.js +36 -0
- package/dist/selection/index.d.ts +6 -0
- package/dist/selection/index.js +3 -0
- package/dist/selection/useNativeChecked.d.ts +13 -0
- package/dist/selection/useNativeChecked.js +27 -0
- package/dist/slider/index.d.ts +11 -0
- package/dist/slider/index.js +45 -0
- package/dist/slot/index.d.ts +24 -0
- package/dist/slot/index.js +29 -0
- package/dist/sortable/index.d.ts +50 -0
- package/dist/sortable/index.js +278 -0
- package/dist/sortable/model.d.ts +30 -0
- package/dist/sortable/model.js +64 -0
- package/dist/sparkline/index.d.ts +19 -0
- package/dist/sparkline/index.js +240 -0
- package/dist/sparkline/model.d.ts +16 -0
- package/dist/sparkline/model.js +28 -0
- package/dist/steps/index.d.ts +16 -0
- package/dist/steps/index.js +37 -0
- package/dist/styles.css +8226 -0
- package/dist/tabs/index.d.ts +22 -0
- package/dist/tabs/index.js +42 -0
- package/dist/tag-input/index.d.ts +69 -0
- package/dist/tag-input/index.js +325 -0
- package/dist/tag-input/model.d.ts +14 -0
- package/dist/tag-input/model.js +38 -0
- package/dist/time-picker/index.d.ts +15 -0
- package/dist/time-picker/index.js +168 -0
- package/dist/timeline/index.d.ts +14 -0
- package/dist/timeline/index.js +16 -0
- package/dist/toast/index.d.ts +27 -0
- package/dist/toast/index.js +36 -0
- package/dist/toggle-group/index.d.ts +17 -0
- package/dist/toggle-group/index.js +26 -0
- package/dist/tokens.css +356 -0
- package/dist/tooltip/Tooltip.d.ts +24 -0
- package/dist/tooltip/Tooltip.js +32 -0
- package/dist/tooltip/index.d.ts +2 -0
- package/dist/tooltip/index.js +1 -0
- package/dist/transfer/index.d.ts +64 -0
- package/dist/transfer/index.js +174 -0
- package/dist/transfer/model.d.ts +12 -0
- package/dist/transfer/model.js +33 -0
- package/dist/tree/index.d.ts +39 -0
- package/dist/tree/index.js +36 -0
- package/dist/tree-select/index.d.ts +59 -0
- package/dist/tree-select/index.js +142 -0
- package/dist/tree-select/model.d.ts +31 -0
- package/dist/tree-select/model.js +135 -0
- package/dist/typewriter/index.d.ts +21 -0
- package/dist/typewriter/index.js +101 -0
- package/dist/typewriter/model.d.ts +7 -0
- package/dist/typewriter/model.js +45 -0
- package/dist/upload/index.d.ts +59 -0
- package/dist/upload/index.js +230 -0
- package/dist/virtual-list/index.d.ts +44 -0
- package/dist/virtual-list/index.js +128 -0
- package/dist/virtual-list/model.d.ts +7 -0
- package/dist/virtual-list/model.js +27 -0
- package/package.json +119 -4
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
|
|
3
|
+
import { BoundedCache, PENCIL_RENDERER_VERSION, canvasByteCost, canvasIsUsable, effectiveDpr, } from './internal/cache.js';
|
|
4
|
+
import { observeCanvasRecovery } from './internal/recovery.js';
|
|
5
|
+
import { seedToNumber } from './internal/random.js';
|
|
6
|
+
import { pencilStroke } from './internal/stroke.js';
|
|
7
|
+
import { maxStrokeRoughness, pencilRenderDefaults, readRenderToken } from './internal/renderTokens.js';
|
|
8
|
+
const geometryCache = new BoundedCache(256, 180000);
|
|
9
|
+
const imageCache = new BoundedCache(128, 24 * 1024 * 1024);
|
|
10
|
+
function cachedPathParts(data) {
|
|
11
|
+
const key = `${PENCIL_RENDERER_VERSION}:${data}`;
|
|
12
|
+
const cached = geometryCache.get(key);
|
|
13
|
+
if (cached)
|
|
14
|
+
return cached;
|
|
15
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
16
|
+
path.setAttribute('d', data);
|
|
17
|
+
const length = path.getTotalLength();
|
|
18
|
+
const count = Math.max(1, Math.ceil(length / 0.25));
|
|
19
|
+
const parts = [[]];
|
|
20
|
+
for (let index = 0; index <= count; index += 1) {
|
|
21
|
+
const point = path.getPointAtLength(length * index / count);
|
|
22
|
+
const activePart = parts[parts.length - 1];
|
|
23
|
+
const previous = activePart[activePart.length - 1];
|
|
24
|
+
if (previous && Math.hypot(point.x - previous[0], point.y - previous[1]) > 0.5)
|
|
25
|
+
parts.push([]);
|
|
26
|
+
parts[parts.length - 1].push([point.x, point.y]);
|
|
27
|
+
}
|
|
28
|
+
return geometryCache.set(key, parts, parts.reduce((total, part) => total + part.length, 0));
|
|
29
|
+
}
|
|
30
|
+
function drawFallbackPath(context, data, color, mode, weightScale = 1) {
|
|
31
|
+
try {
|
|
32
|
+
const path = new Path2D(data);
|
|
33
|
+
context.save();
|
|
34
|
+
context.strokeStyle = color;
|
|
35
|
+
context.lineCap = 'round';
|
|
36
|
+
context.lineJoin = 'round';
|
|
37
|
+
context.lineWidth = (mode === 'scuff' ? 0.65 : 1.4) * weightScale;
|
|
38
|
+
context.globalAlpha = mode === 'scuff' ? 0.6 : 0.9;
|
|
39
|
+
context.stroke(path);
|
|
40
|
+
context.restore();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Semantic controls remain usable even when a path cannot be painted.
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function renderIcon(paths, options) {
|
|
47
|
+
const { seed, size, sourceSize, active, color, dpr } = options;
|
|
48
|
+
const weightScale = options.weightScale ?? 1;
|
|
49
|
+
const roughnessScale = options.roughnessScale ?? 1;
|
|
50
|
+
const canvas = document.createElement('canvas');
|
|
51
|
+
canvas.width = Math.round(size * dpr);
|
|
52
|
+
canvas.height = Math.round(size * dpr);
|
|
53
|
+
const context = canvas.getContext('2d');
|
|
54
|
+
if (!context)
|
|
55
|
+
return canvas;
|
|
56
|
+
const coordinateScale = size / 40;
|
|
57
|
+
context.scale(dpr * coordinateScale, dpr * coordinateScale);
|
|
58
|
+
const offset = (40 - sourceSize) / 2;
|
|
59
|
+
context.translate(offset, offset);
|
|
60
|
+
paths.forEach((path, index) => {
|
|
61
|
+
const mode = path.mode ?? 'stroke';
|
|
62
|
+
const pathSeed = seed + index * 137;
|
|
63
|
+
if (mode === 'wash') {
|
|
64
|
+
try {
|
|
65
|
+
context.save();
|
|
66
|
+
context.clip(new Path2D(path.d));
|
|
67
|
+
context.globalAlpha = active ? 0.76 : 0.34;
|
|
68
|
+
for (let y = sourceSize * 0.18; y < sourceSize; y += 1.6) {
|
|
69
|
+
pencilStroke(context, [[sourceSize * 0.15, y + 3], [sourceSize * 0.85, y - 3]], color, 1.1, pathSeed + Math.round(y * 17), 0.25, 2, false, { variation: 0.85, breaks: 0.25, grain: 0.7, gain: 2.2, step: 0.35 });
|
|
70
|
+
}
|
|
71
|
+
context.restore();
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
drawFallbackPath(context, path.d, color, mode, weightScale);
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const parts = cachedPathParts(path.d);
|
|
80
|
+
for (const points of parts) {
|
|
81
|
+
pencilStroke(context, points, color, (mode === 'scuff' ? 0.55 : 1.65) * weightScale, pathSeed, 0.3 * roughnessScale, mode === 'scuff' ? 1 : 3, false, {
|
|
82
|
+
variation: 0.82,
|
|
83
|
+
breaks: 0.18,
|
|
84
|
+
grain: 0.68,
|
|
85
|
+
gain: mode === 'scuff' ? 1.5 : 3,
|
|
86
|
+
step: 0.35,
|
|
87
|
+
taperLength: 0.65,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
drawFallbackPath(context, path.d, color, mode, weightScale);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
if (active) {
|
|
96
|
+
pencilStroke(context, [[sourceSize * 0.2, sourceSize - 2], [sourceSize * 0.5, sourceSize - 1.5], [sourceSize * 0.8, sourceSize - 2.2]], color, 1.1 * weightScale, seed + 977, 0.25 * roughnessScale, 3, false, { variation: 0.8, breaks: 0.25, grain: 0.7, gain: 2.8, step: 0.35 });
|
|
97
|
+
}
|
|
98
|
+
if (options.badge?.paths.length) {
|
|
99
|
+
const badge = options.badge;
|
|
100
|
+
const scale = Number.isFinite(badge.scale) ? Math.min(0.65, Math.max(0.35, badge.scale)) : 0.55;
|
|
101
|
+
const badgeSourceSize = Number.isFinite(badge.sourceSize) ? Math.min(32, Math.max(1, badge.sourceSize)) : 24;
|
|
102
|
+
const position = badge.position ?? 'bottom-end';
|
|
103
|
+
const onLeft = position.endsWith('start') !== Boolean(options.rtl);
|
|
104
|
+
const extent = 40 * scale;
|
|
105
|
+
const x = onLeft ? 0 : 40 - extent;
|
|
106
|
+
const y = position.startsWith('top') ? 0 : 40 - extent;
|
|
107
|
+
const badgeImage = renderIcon(badge.paths, {
|
|
108
|
+
seed: seed + 1543, size: size * scale, sourceSize: badgeSourceSize, active: false, color, dpr,
|
|
109
|
+
weightScale: weightScale / scale, roughnessScale,
|
|
110
|
+
});
|
|
111
|
+
const mask = document.createElement('canvas');
|
|
112
|
+
mask.width = badgeImage.width;
|
|
113
|
+
mask.height = badgeImage.height;
|
|
114
|
+
const maskContext = mask.getContext('2d');
|
|
115
|
+
if (maskContext) {
|
|
116
|
+
maskContext.drawImage(badgeImage, 0, 0);
|
|
117
|
+
const pixels = maskContext.getImageData(0, 0, mask.width, mask.height);
|
|
118
|
+
for (let index = 3; index < pixels.data.length; index += 4) {
|
|
119
|
+
pixels.data[index] = pixels.data[index] ? 255 : 0;
|
|
120
|
+
}
|
|
121
|
+
maskContext.putImageData(pixels, 0, 0);
|
|
122
|
+
}
|
|
123
|
+
context.save();
|
|
124
|
+
context.setTransform(dpr * coordinateScale, 0, 0, dpr * coordinateScale, 0, 0);
|
|
125
|
+
// A narrow contour halo separates the strokes without cutting a disk out of the base icon.
|
|
126
|
+
context.globalCompositeOperation = 'destination-out';
|
|
127
|
+
for (let step = 0; step < 8; step += 1) {
|
|
128
|
+
const angle = step * Math.PI / 4;
|
|
129
|
+
context.drawImage(mask, x + Math.cos(angle) * 1.25, y + Math.sin(angle) * 1.25, extent, extent);
|
|
130
|
+
}
|
|
131
|
+
context.drawImage(mask, x, y, extent, extent);
|
|
132
|
+
context.globalCompositeOperation = 'source-over';
|
|
133
|
+
context.drawImage(badgeImage, x, y, extent, extent);
|
|
134
|
+
context.restore();
|
|
135
|
+
}
|
|
136
|
+
return canvas;
|
|
137
|
+
}
|
|
138
|
+
export const PencilIcon = forwardRef(function PencilIcon({ active = false, badge, className = '', decorative = true, paths, seed, size = 40, sourceSize = 32, ...props }, forwardedRef) {
|
|
139
|
+
const canvasRef = useRef(null);
|
|
140
|
+
const lastPaintRef = useRef('');
|
|
141
|
+
useImperativeHandle(forwardedRef, () => canvasRef.current);
|
|
142
|
+
const geometryKey = useMemo(() => JSON.stringify(paths), [paths]);
|
|
143
|
+
const badgeKey = useMemo(() => badge ? JSON.stringify(badge) : '', [badge]);
|
|
144
|
+
const resolvedSeed = seedToNumber(seed ?? geometryKey);
|
|
145
|
+
useEffect(() => {
|
|
146
|
+
const canvas = canvasRef.current;
|
|
147
|
+
if (!canvas)
|
|
148
|
+
return undefined;
|
|
149
|
+
let disposed = false;
|
|
150
|
+
const paint = () => {
|
|
151
|
+
if (disposed)
|
|
152
|
+
return;
|
|
153
|
+
const dpr = effectiveDpr(3);
|
|
154
|
+
const computed = getComputedStyle(canvas);
|
|
155
|
+
const color = computed.color;
|
|
156
|
+
const rtl = computed.direction === 'rtl';
|
|
157
|
+
const weightScale = readRenderToken(computed, '--inkra-stroke-width', pencilRenderDefaults.strokeWidth, 0.3, 3) / 1.2;
|
|
158
|
+
const roughnessScale = readRenderToken(computed, '--inkra-stroke-amplitude', pencilRenderDefaults.strokeRoughness, 0, maxStrokeRoughness) / 0.6;
|
|
159
|
+
const key = JSON.stringify([
|
|
160
|
+
PENCIL_RENDERER_VERSION,
|
|
161
|
+
geometryKey,
|
|
162
|
+
badgeKey,
|
|
163
|
+
rtl,
|
|
164
|
+
resolvedSeed,
|
|
165
|
+
size,
|
|
166
|
+
sourceSize,
|
|
167
|
+
active,
|
|
168
|
+
color,
|
|
169
|
+
dpr,
|
|
170
|
+
weightScale, roughnessScale,
|
|
171
|
+
]);
|
|
172
|
+
if (key === lastPaintRef.current && canvasIsUsable(canvas))
|
|
173
|
+
return;
|
|
174
|
+
let image = imageCache.get(key);
|
|
175
|
+
if (image && !canvasIsUsable(image)) {
|
|
176
|
+
imageCache.delete(key);
|
|
177
|
+
image = undefined;
|
|
178
|
+
}
|
|
179
|
+
if (!image) {
|
|
180
|
+
image = renderIcon(paths, { seed: resolvedSeed, size, sourceSize, active, color, dpr, badge, rtl, weightScale, roughnessScale });
|
|
181
|
+
imageCache.set(key, image, canvasByteCost(image));
|
|
182
|
+
}
|
|
183
|
+
canvas.width = image.width;
|
|
184
|
+
canvas.height = image.height;
|
|
185
|
+
const context = canvas.getContext('2d');
|
|
186
|
+
if (!context || context.isContextLost?.())
|
|
187
|
+
return;
|
|
188
|
+
context.drawImage(image, 0, 0);
|
|
189
|
+
lastPaintRef.current = key;
|
|
190
|
+
};
|
|
191
|
+
const inheritedColor = new MutationObserver(paint);
|
|
192
|
+
for (let element = canvas; element; element = element.parentElement) {
|
|
193
|
+
inheritedColor.observe(element, { attributes: true, attributeFilter: ['style', 'class', 'dir', 'data-theme', 'data-inkra-theme'] });
|
|
194
|
+
}
|
|
195
|
+
const colorScheme = window.matchMedia('(prefers-color-scheme: dark)');
|
|
196
|
+
colorScheme.addEventListener('change', paint);
|
|
197
|
+
const stopRecovery = observeCanvasRecovery(() => { lastPaintRef.current = ''; paint(); });
|
|
198
|
+
paint();
|
|
199
|
+
return () => {
|
|
200
|
+
disposed = true;
|
|
201
|
+
stopRecovery();
|
|
202
|
+
inheritedColor.disconnect();
|
|
203
|
+
colorScheme.removeEventListener('change', paint);
|
|
204
|
+
};
|
|
205
|
+
}, [active, badge, badgeKey, geometryKey, paths, resolvedSeed, size, sourceSize]);
|
|
206
|
+
const accessibilityProps = decorative
|
|
207
|
+
? { 'aria-hidden': true }
|
|
208
|
+
: { role: props.role ?? 'img' };
|
|
209
|
+
return (_jsx("canvas", { ...props, ...accessibilityProps, className: ['inkra-pencil-icon', className].filter(Boolean).join(' '), "data-active": active || undefined, "data-composite": Boolean(badge?.paths.length) || undefined, "data-renderer": "inkra-pressure-pencil", ref: canvasRef, style: { width: size, height: size, ...props.style } }));
|
|
210
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CanvasHTMLAttributes } from 'react';
|
|
2
|
+
import type { PencilLineOrientation } from './internal/line.js';
|
|
3
|
+
export interface PencilLineProps extends Omit<CanvasHTMLAttributes<HTMLCanvasElement>, 'children'> {
|
|
4
|
+
seed?: string | number;
|
|
5
|
+
weight?: number;
|
|
6
|
+
roughness?: number;
|
|
7
|
+
orientation?: PencilLineOrientation;
|
|
8
|
+
}
|
|
9
|
+
export declare const PencilLine: import("react").ForwardRefExoticComponent<PencilLineProps & import("react").RefAttributes<HTMLCanvasElement>>;
|
|
10
|
+
export type { PencilLineOrientation };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react';
|
|
3
|
+
import { BoundedCache, PENCIL_RENDERER_VERSION, canvasByteCost, canvasIsUsable, effectiveDpr, } from './internal/cache.js';
|
|
4
|
+
import { observeCanvasRecovery } from './internal/recovery.js';
|
|
5
|
+
import { seedToNumber } from './internal/random.js';
|
|
6
|
+
import { createPencilLinePoints, pencilLineHasDrawableSize } from './internal/line.js';
|
|
7
|
+
import { pencilStroke } from './internal/stroke.js';
|
|
8
|
+
import { maxStrokeRoughness, pencilRenderDefaults, readRenderToken } from './internal/renderTokens.js';
|
|
9
|
+
const lineCache = new BoundedCache(96, 12 * 1024 * 1024);
|
|
10
|
+
function renderLine(width, height, color, seed, weight, roughness, orientation, dpr) {
|
|
11
|
+
const canvas = document.createElement('canvas');
|
|
12
|
+
canvas.width = Math.ceil(width * dpr);
|
|
13
|
+
canvas.height = Math.ceil(height * dpr);
|
|
14
|
+
const context = canvas.getContext('2d');
|
|
15
|
+
if (!context)
|
|
16
|
+
return canvas;
|
|
17
|
+
context.scale(dpr, dpr);
|
|
18
|
+
pencilStroke(context, createPencilLinePoints(width, height, orientation, roughness), color, weight, seed, roughness, 3, false, { variation: 0.82, breaks: 0.18, grain: 0.68, gain: 2.6, step: 0.5, taperLength: 1.4 });
|
|
19
|
+
return canvas;
|
|
20
|
+
}
|
|
21
|
+
export const PencilLine = forwardRef(function PencilLine({ className = '', orientation = 'horizontal', roughness, seed = 'inkra-pencil-line', weight, ...props }, forwardedRef) {
|
|
22
|
+
const canvasRef = useRef(null);
|
|
23
|
+
useImperativeHandle(forwardedRef, () => canvasRef.current);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
const canvas = canvasRef.current;
|
|
26
|
+
if (!canvas)
|
|
27
|
+
return undefined;
|
|
28
|
+
let frame = 0;
|
|
29
|
+
let disposed = false;
|
|
30
|
+
let lastPaint = '';
|
|
31
|
+
const paint = () => {
|
|
32
|
+
frame = 0;
|
|
33
|
+
if (disposed)
|
|
34
|
+
return;
|
|
35
|
+
const width = canvas.clientWidth;
|
|
36
|
+
const height = canvas.clientHeight;
|
|
37
|
+
if (!pencilLineHasDrawableSize(width, height, orientation))
|
|
38
|
+
return;
|
|
39
|
+
const dpr = effectiveDpr(2);
|
|
40
|
+
const style = getComputedStyle(canvas);
|
|
41
|
+
const color = style.color;
|
|
42
|
+
const resolvedWeight = weight ?? readRenderToken(style, '--inkra-stroke-width', pencilRenderDefaults.strokeWidth, 0.3, 3);
|
|
43
|
+
const resolvedRoughness = roughness ?? readRenderToken(style, '--inkra-stroke-amplitude', pencilRenderDefaults.strokeRoughness, 0, maxStrokeRoughness);
|
|
44
|
+
const numericSeed = seedToNumber(seed);
|
|
45
|
+
const key = JSON.stringify([
|
|
46
|
+
PENCIL_RENDERER_VERSION, orientation, width, height, color, numericSeed, resolvedWeight, resolvedRoughness, dpr,
|
|
47
|
+
]);
|
|
48
|
+
if (key === lastPaint && canvasIsUsable(canvas))
|
|
49
|
+
return;
|
|
50
|
+
let image = lineCache.get(key);
|
|
51
|
+
if (image && !canvasIsUsable(image)) {
|
|
52
|
+
lineCache.delete(key);
|
|
53
|
+
image = undefined;
|
|
54
|
+
}
|
|
55
|
+
if (!image) {
|
|
56
|
+
image = renderLine(width, height, color, numericSeed, resolvedWeight, resolvedRoughness, orientation, dpr);
|
|
57
|
+
lineCache.set(key, image, canvasByteCost(image));
|
|
58
|
+
}
|
|
59
|
+
canvas.width = image.width;
|
|
60
|
+
canvas.height = image.height;
|
|
61
|
+
const context = canvas.getContext('2d');
|
|
62
|
+
if (!context || context.isContextLost?.())
|
|
63
|
+
return;
|
|
64
|
+
context.drawImage(image, 0, 0);
|
|
65
|
+
lastPaint = key;
|
|
66
|
+
};
|
|
67
|
+
const schedule = () => {
|
|
68
|
+
if (!frame)
|
|
69
|
+
frame = requestAnimationFrame(paint);
|
|
70
|
+
};
|
|
71
|
+
const resize = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(schedule);
|
|
72
|
+
resize?.observe(canvas);
|
|
73
|
+
const colorScheme = window.matchMedia('(prefers-color-scheme: dark)');
|
|
74
|
+
const inheritedStyle = new MutationObserver(schedule);
|
|
75
|
+
for (let element = canvas; element; element = element.parentElement) {
|
|
76
|
+
inheritedStyle.observe(element, { attributes: true, attributeFilter: ['style', 'class', 'data-theme', 'data-inkra-theme'] });
|
|
77
|
+
}
|
|
78
|
+
colorScheme.addEventListener('change', schedule);
|
|
79
|
+
const stopRecovery = observeCanvasRecovery(() => { lastPaint = ''; schedule(); });
|
|
80
|
+
paint();
|
|
81
|
+
return () => {
|
|
82
|
+
disposed = true;
|
|
83
|
+
stopRecovery();
|
|
84
|
+
resize?.disconnect();
|
|
85
|
+
inheritedStyle.disconnect();
|
|
86
|
+
colorScheme.removeEventListener('change', schedule);
|
|
87
|
+
cancelAnimationFrame(frame);
|
|
88
|
+
};
|
|
89
|
+
}, [orientation, roughness, seed, weight]);
|
|
90
|
+
return (_jsx("canvas", { ...props, "aria-hidden": "true", className: ['inkra-pencil-line', className].filter(Boolean).join(' '), "data-orientation": orientation, "data-renderer": "inkra-pressure-pencil", ref: canvasRef }));
|
|
91
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef, ComponentPropsWithRef, ElementType, ReactElement, ReactNode } from 'react';
|
|
2
|
+
import type { PencilSurfaceVariant } from './internal/surfaceRenderer.js';
|
|
3
|
+
interface PencilSurfaceBaseProps {
|
|
4
|
+
variant?: PencilSurfaceVariant;
|
|
5
|
+
seed?: string | number;
|
|
6
|
+
clipContent?: boolean;
|
|
7
|
+
radius?: number;
|
|
8
|
+
className?: string;
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
type PencilSurfaceOwnProps<Element extends ElementType> = PencilSurfaceBaseProps & {
|
|
12
|
+
as?: Element;
|
|
13
|
+
};
|
|
14
|
+
export type PencilSurfaceProps<Element extends ElementType = 'div'> = PencilSurfaceOwnProps<Element> & Omit<ComponentPropsWithoutRef<Element>, keyof PencilSurfaceOwnProps<Element>>;
|
|
15
|
+
type PencilSurfaceComponent = <Element extends ElementType = 'div'>(props: PencilSurfaceProps<Element> & {
|
|
16
|
+
ref?: ComponentPropsWithRef<Element>['ref'];
|
|
17
|
+
}) => ReactElement | null;
|
|
18
|
+
export declare const PencilSurface: PencilSurfaceComponent;
|
|
19
|
+
export type { PencilSurfaceVariant };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useImperativeHandle, useRef } from 'react';
|
|
3
|
+
import { usePencilSurface } from './internal/usePencilSurface.js';
|
|
4
|
+
const PencilSurfaceImplementation = forwardRef(function PencilSurface({ as: Element = 'div', variant = 'paper', seed = 23, className = '', clipContent = false, radius, children, ...props }, forwardedRef) {
|
|
5
|
+
const rootRef = useRef(null);
|
|
6
|
+
const canvasRef = useRef(null);
|
|
7
|
+
const borderRef = useRef(null);
|
|
8
|
+
useImperativeHandle(forwardedRef, () => rootRef.current);
|
|
9
|
+
usePencilSurface(rootRef, canvasRef, borderRef, variant, seed, clipContent, radius);
|
|
10
|
+
const classes = [
|
|
11
|
+
'inkra-pencil-surface',
|
|
12
|
+
`inkra-pencil-surface--${variant}`,
|
|
13
|
+
clipContent && 'inkra-pencil-surface--clipped',
|
|
14
|
+
className,
|
|
15
|
+
].filter(Boolean).join(' ');
|
|
16
|
+
const nativeProps = Element === 'button' ? { type: 'button', ...props } : props;
|
|
17
|
+
return (_jsxs(Element, { ...nativeProps, className: classes, ref: rootRef, children: [_jsx("canvas", { "aria-hidden": "true", className: "inkra-pencil-surface__ink", ref: canvasRef }), clipContent ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "inkra-pencil-surface__content", children: children }), _jsx("canvas", { "aria-hidden": "true", className: "inkra-pencil-surface__border", ref: borderRef })] })) : children] }));
|
|
18
|
+
});
|
|
19
|
+
export const PencilSurface = PencilSurfaceImplementation;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef, ComponentPropsWithRef, ElementType, ReactElement } from 'react';
|
|
2
|
+
interface PencilTextBaseProps {
|
|
3
|
+
children: string;
|
|
4
|
+
seed?: string | number;
|
|
5
|
+
ellipsis?: boolean;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
type PencilTextOwnProps<Element extends ElementType> = PencilTextBaseProps & {
|
|
9
|
+
as?: Element;
|
|
10
|
+
};
|
|
11
|
+
export type PencilTextProps<Element extends ElementType = 'span'> = PencilTextOwnProps<Element> & Omit<ComponentPropsWithoutRef<Element>, keyof PencilTextOwnProps<Element>>;
|
|
12
|
+
type PencilTextComponent = <Element extends ElementType = 'span'>(props: PencilTextProps<Element> & {
|
|
13
|
+
ref?: ComponentPropsWithRef<Element>['ref'];
|
|
14
|
+
}) => ReactElement | null;
|
|
15
|
+
export declare const PencilText: PencilTextComponent;
|
|
16
|
+
export {};
|