@inkra/react 0.0.0-stage → 0.1.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 +213 -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 +212 -0
- package/dist/PencilLine.d.ts +10 -0
- package/dist/PencilLine.js +85 -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 +205 -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/assets/ui-hand-yozai.woff2 +0 -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/content/index.d.ts +106 -0
- package/dist/content/index.js +80 -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/index.d.ts +32 -0
- package/dist/display/index.js +59 -0
- package/dist/dropdown-menu/index.d.ts +34 -0
- package/dist/dropdown-menu/index.js +40 -0
- package/dist/form/EditablePencilText.d.ts +13 -0
- package/dist/form/EditablePencilText.js +312 -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 +5 -0
- package/dist/form/Textarea.js +23 -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/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 +28 -0
- package/dist/index.js +22 -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/stroke.d.ts +24 -0
- package/dist/internal/stroke.js +144 -0
- package/dist/internal/surfaceRenderer.d.ts +33 -0
- package/dist/internal/surfaceRenderer.js +175 -0
- package/dist/internal/textQueue.d.ts +1 -0
- package/dist/internal/textQueue.js +37 -0
- package/dist/internal/textRenderer.d.ts +27 -0
- package/dist/internal/textRenderer.js +213 -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 +108 -0
- package/dist/internal/useSelectionDrawing.d.ts +2 -0
- package/dist/internal/useSelectionDrawing.js +86 -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 +52 -0
- package/dist/journey-map/index.d.ts +39 -0
- package/dist/journey-map/index.js +195 -0
- package/dist/journey-map/terrain.d.ts +8 -0
- package/dist/journey-map/terrain.js +127 -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/pencil.d.ts +10 -0
- package/dist/pencil.js +39 -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/styles.css +3663 -0
- package/dist/tabs/index.d.ts +22 -0
- package/dist/tabs/index.js +42 -0
- package/dist/tokens.css +355 -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/package.json +100 -4
|
@@ -0,0 +1,212 @@
|
|
|
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
|
+
const geometryCache = new BoundedCache(256, 180000);
|
|
8
|
+
const imageCache = new BoundedCache(128, 24 * 1024 * 1024);
|
|
9
|
+
function cachedPathParts(data) {
|
|
10
|
+
const key = `${PENCIL_RENDERER_VERSION}:${data}`;
|
|
11
|
+
const cached = geometryCache.get(key);
|
|
12
|
+
if (cached)
|
|
13
|
+
return cached;
|
|
14
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
15
|
+
path.setAttribute('d', data);
|
|
16
|
+
const length = path.getTotalLength();
|
|
17
|
+
const count = Math.max(1, Math.ceil(length / 0.25));
|
|
18
|
+
const parts = [[]];
|
|
19
|
+
for (let index = 0; index <= count; index += 1) {
|
|
20
|
+
const point = path.getPointAtLength(length * index / count);
|
|
21
|
+
const activePart = parts[parts.length - 1];
|
|
22
|
+
const previous = activePart[activePart.length - 1];
|
|
23
|
+
if (previous && Math.hypot(point.x - previous[0], point.y - previous[1]) > 0.5)
|
|
24
|
+
parts.push([]);
|
|
25
|
+
parts[parts.length - 1].push([point.x, point.y]);
|
|
26
|
+
}
|
|
27
|
+
return geometryCache.set(key, parts, parts.reduce((total, part) => total + part.length, 0));
|
|
28
|
+
}
|
|
29
|
+
function drawFallbackPath(context, data, color, mode, weightScale = 1) {
|
|
30
|
+
try {
|
|
31
|
+
const path = new Path2D(data);
|
|
32
|
+
context.save();
|
|
33
|
+
context.strokeStyle = color;
|
|
34
|
+
context.lineCap = 'round';
|
|
35
|
+
context.lineJoin = 'round';
|
|
36
|
+
context.lineWidth = (mode === 'scuff' ? 0.65 : 1.4) * weightScale;
|
|
37
|
+
context.globalAlpha = mode === 'scuff' ? 0.6 : 0.9;
|
|
38
|
+
context.stroke(path);
|
|
39
|
+
context.restore();
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Semantic controls remain usable even when a path cannot be painted.
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function renderIcon(paths, options) {
|
|
46
|
+
const { seed, size, sourceSize, active, color, dpr } = options;
|
|
47
|
+
const weightScale = options.weightScale ?? 1;
|
|
48
|
+
const canvas = document.createElement('canvas');
|
|
49
|
+
canvas.width = Math.round(size * dpr);
|
|
50
|
+
canvas.height = Math.round(size * dpr);
|
|
51
|
+
const context = canvas.getContext('2d');
|
|
52
|
+
if (!context)
|
|
53
|
+
return canvas;
|
|
54
|
+
const coordinateScale = size / 40;
|
|
55
|
+
context.scale(dpr * coordinateScale, dpr * coordinateScale);
|
|
56
|
+
const offset = (40 - sourceSize) / 2;
|
|
57
|
+
context.translate(offset, offset);
|
|
58
|
+
paths.forEach((path, index) => {
|
|
59
|
+
const mode = path.mode ?? 'stroke';
|
|
60
|
+
const pathSeed = seed + index * 137;
|
|
61
|
+
if (mode === 'wash') {
|
|
62
|
+
try {
|
|
63
|
+
context.save();
|
|
64
|
+
context.clip(new Path2D(path.d));
|
|
65
|
+
context.globalAlpha = active ? 0.76 : 0.34;
|
|
66
|
+
for (let y = sourceSize * 0.18; y < sourceSize; y += 1.6) {
|
|
67
|
+
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 });
|
|
68
|
+
}
|
|
69
|
+
context.restore();
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
drawFallbackPath(context, path.d, color, mode, weightScale);
|
|
73
|
+
}
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const parts = cachedPathParts(path.d);
|
|
78
|
+
for (const points of parts) {
|
|
79
|
+
pencilStroke(context, points, color, (mode === 'scuff' ? 0.55 : 1.65) * weightScale, pathSeed, 0.3, mode === 'scuff' ? 1 : 3, false, {
|
|
80
|
+
variation: 0.82,
|
|
81
|
+
breaks: 0.18,
|
|
82
|
+
grain: 0.68,
|
|
83
|
+
gain: mode === 'scuff' ? 1.5 : 3,
|
|
84
|
+
step: 0.35,
|
|
85
|
+
taperLength: 0.65,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
drawFallbackPath(context, path.d, color, mode, weightScale);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
if (active) {
|
|
94
|
+
pencilStroke(context, [[sourceSize * 0.2, sourceSize - 2], [sourceSize * 0.5, sourceSize - 1.5], [sourceSize * 0.8, sourceSize - 2.2]], color, 1.1, seed + 977, 0.25, 3, false, { variation: 0.8, breaks: 0.25, grain: 0.7, gain: 2.8, step: 0.35 });
|
|
95
|
+
}
|
|
96
|
+
if (options.badge?.paths.length) {
|
|
97
|
+
const badge = options.badge;
|
|
98
|
+
const scale = Number.isFinite(badge.scale) ? Math.min(0.65, Math.max(0.35, badge.scale)) : 0.55;
|
|
99
|
+
const badgeSourceSize = Number.isFinite(badge.sourceSize) ? Math.min(32, Math.max(1, badge.sourceSize)) : 24;
|
|
100
|
+
const position = badge.position ?? 'bottom-end';
|
|
101
|
+
const onLeft = position.endsWith('start') !== Boolean(options.rtl);
|
|
102
|
+
const extent = 40 * scale;
|
|
103
|
+
const x = onLeft ? 0 : 40 - extent;
|
|
104
|
+
const y = position.startsWith('top') ? 0 : 40 - extent;
|
|
105
|
+
const badgeImage = renderIcon(badge.paths, {
|
|
106
|
+
seed: seed + 1543, size: size * scale, sourceSize: badgeSourceSize, active: false, color, dpr,
|
|
107
|
+
weightScale: 1 / scale,
|
|
108
|
+
});
|
|
109
|
+
const mask = document.createElement('canvas');
|
|
110
|
+
mask.width = badgeImage.width;
|
|
111
|
+
mask.height = badgeImage.height;
|
|
112
|
+
const maskContext = mask.getContext('2d');
|
|
113
|
+
if (maskContext) {
|
|
114
|
+
maskContext.drawImage(badgeImage, 0, 0);
|
|
115
|
+
const pixels = maskContext.getImageData(0, 0, mask.width, mask.height);
|
|
116
|
+
for (let index = 3; index < pixels.data.length; index += 4) {
|
|
117
|
+
pixels.data[index] = pixels.data[index] ? 255 : 0;
|
|
118
|
+
}
|
|
119
|
+
maskContext.putImageData(pixels, 0, 0);
|
|
120
|
+
}
|
|
121
|
+
context.save();
|
|
122
|
+
context.setTransform(dpr * coordinateScale, 0, 0, dpr * coordinateScale, 0, 0);
|
|
123
|
+
// A narrow contour halo separates the strokes without cutting a disk out of the base icon.
|
|
124
|
+
context.globalCompositeOperation = 'destination-out';
|
|
125
|
+
for (let step = 0; step < 8; step += 1) {
|
|
126
|
+
const angle = step * Math.PI / 4;
|
|
127
|
+
context.drawImage(mask, x + Math.cos(angle) * 1.25, y + Math.sin(angle) * 1.25, extent, extent);
|
|
128
|
+
}
|
|
129
|
+
context.drawImage(mask, x, y, extent, extent);
|
|
130
|
+
context.globalCompositeOperation = 'source-over';
|
|
131
|
+
context.drawImage(badgeImage, x, y, extent, extent);
|
|
132
|
+
context.restore();
|
|
133
|
+
}
|
|
134
|
+
return canvas;
|
|
135
|
+
}
|
|
136
|
+
export const PencilIcon = forwardRef(function PencilIcon({ active = false, badge, className = '', decorative = true, paths, seed, size = 40, sourceSize = 32, ...props }, forwardedRef) {
|
|
137
|
+
const canvasRef = useRef(null);
|
|
138
|
+
useImperativeHandle(forwardedRef, () => canvasRef.current);
|
|
139
|
+
const geometryKey = useMemo(() => JSON.stringify(paths), [paths]);
|
|
140
|
+
const badgeKey = useMemo(() => badge ? JSON.stringify(badge) : '', [badge]);
|
|
141
|
+
const resolvedSeed = seedToNumber(seed ?? geometryKey);
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
const canvas = canvasRef.current;
|
|
144
|
+
if (!canvas)
|
|
145
|
+
return undefined;
|
|
146
|
+
let disposed = false;
|
|
147
|
+
let lastPaint = '';
|
|
148
|
+
const paint = () => {
|
|
149
|
+
if (disposed)
|
|
150
|
+
return;
|
|
151
|
+
const dpr = effectiveDpr(3);
|
|
152
|
+
const computed = getComputedStyle(canvas);
|
|
153
|
+
const color = computed.color;
|
|
154
|
+
const rtl = computed.direction === 'rtl';
|
|
155
|
+
const key = JSON.stringify([
|
|
156
|
+
PENCIL_RENDERER_VERSION,
|
|
157
|
+
geometryKey,
|
|
158
|
+
badgeKey,
|
|
159
|
+
rtl,
|
|
160
|
+
resolvedSeed,
|
|
161
|
+
size,
|
|
162
|
+
sourceSize,
|
|
163
|
+
active,
|
|
164
|
+
color,
|
|
165
|
+
dpr,
|
|
166
|
+
]);
|
|
167
|
+
if (key === lastPaint && canvasIsUsable(canvas))
|
|
168
|
+
return;
|
|
169
|
+
let image = imageCache.get(key);
|
|
170
|
+
if (image && !canvasIsUsable(image)) {
|
|
171
|
+
imageCache.delete(key);
|
|
172
|
+
image = undefined;
|
|
173
|
+
}
|
|
174
|
+
if (!image) {
|
|
175
|
+
image = renderIcon(paths, { seed: resolvedSeed, size, sourceSize, active, color, dpr, badge, rtl });
|
|
176
|
+
imageCache.set(key, image, canvasByteCost(image));
|
|
177
|
+
}
|
|
178
|
+
canvas.width = image.width;
|
|
179
|
+
canvas.height = image.height;
|
|
180
|
+
const context = canvas.getContext('2d');
|
|
181
|
+
if (!context || context.isContextLost?.())
|
|
182
|
+
return;
|
|
183
|
+
context.drawImage(image, 0, 0);
|
|
184
|
+
lastPaint = key;
|
|
185
|
+
};
|
|
186
|
+
const appearance = new MutationObserver(paint);
|
|
187
|
+
appearance.observe(document.documentElement, {
|
|
188
|
+
attributes: true,
|
|
189
|
+
subtree: true,
|
|
190
|
+
attributeFilter: ['data-theme', 'data-inkra-theme'],
|
|
191
|
+
});
|
|
192
|
+
const inheritedColor = new MutationObserver(paint);
|
|
193
|
+
for (let element = canvas; element; element = element.parentElement) {
|
|
194
|
+
inheritedColor.observe(element, { attributes: true, attributeFilter: ['style', 'class', 'dir'] });
|
|
195
|
+
}
|
|
196
|
+
const colorScheme = window.matchMedia('(prefers-color-scheme: dark)');
|
|
197
|
+
colorScheme.addEventListener('change', paint);
|
|
198
|
+
const stopRecovery = observeCanvasRecovery(() => { lastPaint = ''; paint(); });
|
|
199
|
+
paint();
|
|
200
|
+
return () => {
|
|
201
|
+
disposed = true;
|
|
202
|
+
stopRecovery();
|
|
203
|
+
appearance.disconnect();
|
|
204
|
+
inheritedColor.disconnect();
|
|
205
|
+
colorScheme.removeEventListener('change', paint);
|
|
206
|
+
};
|
|
207
|
+
}, [active, badge, badgeKey, geometryKey, paths, resolvedSeed, size, sourceSize]);
|
|
208
|
+
const accessibilityProps = decorative
|
|
209
|
+
? { 'aria-hidden': true }
|
|
210
|
+
: { role: props.role ?? 'img' };
|
|
211
|
+
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 } }));
|
|
212
|
+
});
|
|
@@ -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,85 @@
|
|
|
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
|
+
const lineCache = new BoundedCache(96, 12 * 1024 * 1024);
|
|
9
|
+
function renderLine(width, height, color, seed, weight, roughness, orientation, dpr) {
|
|
10
|
+
const canvas = document.createElement('canvas');
|
|
11
|
+
canvas.width = Math.ceil(width * dpr);
|
|
12
|
+
canvas.height = Math.ceil(height * dpr);
|
|
13
|
+
const context = canvas.getContext('2d');
|
|
14
|
+
if (!context)
|
|
15
|
+
return canvas;
|
|
16
|
+
context.scale(dpr, dpr);
|
|
17
|
+
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 });
|
|
18
|
+
return canvas;
|
|
19
|
+
}
|
|
20
|
+
export const PencilLine = forwardRef(function PencilLine({ className = '', orientation = 'horizontal', roughness = 0.6, seed = 'inkra-pencil-line', weight = 1.2, ...props }, forwardedRef) {
|
|
21
|
+
const canvasRef = useRef(null);
|
|
22
|
+
useImperativeHandle(forwardedRef, () => canvasRef.current);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const canvas = canvasRef.current;
|
|
25
|
+
if (!canvas)
|
|
26
|
+
return undefined;
|
|
27
|
+
let frame = 0;
|
|
28
|
+
let disposed = false;
|
|
29
|
+
const paint = () => {
|
|
30
|
+
frame = 0;
|
|
31
|
+
if (disposed)
|
|
32
|
+
return;
|
|
33
|
+
const width = canvas.clientWidth;
|
|
34
|
+
const height = canvas.clientHeight;
|
|
35
|
+
if (!pencilLineHasDrawableSize(width, height, orientation))
|
|
36
|
+
return;
|
|
37
|
+
const dpr = effectiveDpr(2);
|
|
38
|
+
const color = getComputedStyle(canvas).color;
|
|
39
|
+
const numericSeed = seedToNumber(seed);
|
|
40
|
+
const key = JSON.stringify([
|
|
41
|
+
PENCIL_RENDERER_VERSION, orientation, width, height, color, numericSeed, weight, roughness, dpr,
|
|
42
|
+
]);
|
|
43
|
+
let image = lineCache.get(key);
|
|
44
|
+
if (image && !canvasIsUsable(image)) {
|
|
45
|
+
lineCache.delete(key);
|
|
46
|
+
image = undefined;
|
|
47
|
+
}
|
|
48
|
+
if (!image) {
|
|
49
|
+
image = renderLine(width, height, color, numericSeed, weight, roughness, orientation, dpr);
|
|
50
|
+
lineCache.set(key, image, canvasByteCost(image));
|
|
51
|
+
}
|
|
52
|
+
canvas.width = image.width;
|
|
53
|
+
canvas.height = image.height;
|
|
54
|
+
const context = canvas.getContext('2d');
|
|
55
|
+
if (!context || context.isContextLost?.())
|
|
56
|
+
return;
|
|
57
|
+
context.drawImage(image, 0, 0);
|
|
58
|
+
};
|
|
59
|
+
const schedule = () => {
|
|
60
|
+
if (!frame)
|
|
61
|
+
frame = requestAnimationFrame(paint);
|
|
62
|
+
};
|
|
63
|
+
const resize = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(schedule);
|
|
64
|
+
resize?.observe(canvas);
|
|
65
|
+
const appearance = new MutationObserver(schedule);
|
|
66
|
+
appearance.observe(document.documentElement, {
|
|
67
|
+
attributes: true,
|
|
68
|
+
subtree: true,
|
|
69
|
+
attributeFilter: ['data-theme', 'data-inkra-theme'],
|
|
70
|
+
});
|
|
71
|
+
const colorScheme = window.matchMedia('(prefers-color-scheme: dark)');
|
|
72
|
+
colorScheme.addEventListener('change', schedule);
|
|
73
|
+
const stopRecovery = observeCanvasRecovery(schedule);
|
|
74
|
+
paint();
|
|
75
|
+
return () => {
|
|
76
|
+
disposed = true;
|
|
77
|
+
stopRecovery();
|
|
78
|
+
resize?.disconnect();
|
|
79
|
+
appearance.disconnect();
|
|
80
|
+
colorScheme.removeEventListener('change', schedule);
|
|
81
|
+
cancelAnimationFrame(frame);
|
|
82
|
+
};
|
|
83
|
+
}, [orientation, roughness, seed, weight]);
|
|
84
|
+
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 }));
|
|
85
|
+
});
|
|
@@ -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 {};
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
|
3
|
+
import { useBrowserLayoutEffect } from './internal/useBrowserLayoutEffect.js';
|
|
4
|
+
import { effectiveDpr } from './internal/cache.js';
|
|
5
|
+
import { observeCanvasRecovery } from './internal/recovery.js';
|
|
6
|
+
import { seedToNumber } from './internal/random.js';
|
|
7
|
+
import { renderPencilText } from './internal/textRenderer.js';
|
|
8
|
+
import { queueTextPaint } from './internal/textQueue.js';
|
|
9
|
+
function textSeed(text) {
|
|
10
|
+
return Array.from(text).reduce((seed, character) => Math.imul(seed ^ character.codePointAt(0), 16777619), 71) >>> 0;
|
|
11
|
+
}
|
|
12
|
+
function paintText(element, source, canvas, text, seed) {
|
|
13
|
+
const box = element.getBoundingClientRect();
|
|
14
|
+
if (!box.width || !box.height || text.length > 4096 || !source.firstChild)
|
|
15
|
+
return false;
|
|
16
|
+
const style = getComputedStyle(element);
|
|
17
|
+
const size = Number.parseFloat(style.fontSize);
|
|
18
|
+
const context = canvas.getContext('2d');
|
|
19
|
+
const padding = 5;
|
|
20
|
+
const width = box.width + padding * 2;
|
|
21
|
+
const height = box.height + padding * 2;
|
|
22
|
+
const dpr = effectiveDpr(2);
|
|
23
|
+
if (width * height * dpr ** 2 > 2 * 1024 * 1024 || !context || context.isContextLost?.())
|
|
24
|
+
return false;
|
|
25
|
+
canvas.width = Math.ceil(width * dpr);
|
|
26
|
+
canvas.height = Math.ceil(height * dpr);
|
|
27
|
+
Object.assign(canvas.style, {
|
|
28
|
+
left: `-${padding}px`,
|
|
29
|
+
top: `-${padding}px`,
|
|
30
|
+
right: 'auto',
|
|
31
|
+
bottom: 'auto',
|
|
32
|
+
width: `${width}px`,
|
|
33
|
+
height: `${height}px`,
|
|
34
|
+
});
|
|
35
|
+
context.scale(dpr, dpr);
|
|
36
|
+
context.font = `400 ${size}px ${style.fontFamily}`;
|
|
37
|
+
context.fontKerning = 'none';
|
|
38
|
+
const ascent = context.measureText(text).fontBoundingBoxAscent ?? size;
|
|
39
|
+
const range = document.createRange();
|
|
40
|
+
const lines = [];
|
|
41
|
+
let offset = 0;
|
|
42
|
+
for (const character of text) {
|
|
43
|
+
range.setStart(source.firstChild, offset);
|
|
44
|
+
offset += character.length;
|
|
45
|
+
range.setEnd(source.firstChild, offset);
|
|
46
|
+
const rectangle = range.getBoundingClientRect();
|
|
47
|
+
let line = lines[lines.length - 1];
|
|
48
|
+
if (!line || Math.abs(line.top - rectangle.top) > 1) {
|
|
49
|
+
line = { text: '', left: rectangle.left, top: rectangle.top };
|
|
50
|
+
lines.push(line);
|
|
51
|
+
}
|
|
52
|
+
line.text += character;
|
|
53
|
+
}
|
|
54
|
+
for (const line of lines) {
|
|
55
|
+
const lineText = line.text.trimEnd();
|
|
56
|
+
if (!lineText)
|
|
57
|
+
continue;
|
|
58
|
+
const sprite = renderPencilText(lineText, {
|
|
59
|
+
size,
|
|
60
|
+
seed: seedToNumber(seed) ^ textSeed(line.text),
|
|
61
|
+
color: style.color,
|
|
62
|
+
family: style.fontFamily,
|
|
63
|
+
dpr,
|
|
64
|
+
});
|
|
65
|
+
if (sprite.ink.getContext('2d')?.isContextLost?.())
|
|
66
|
+
return false;
|
|
67
|
+
context.drawImage(sprite.ink, padding + line.left - box.left - sprite.padding, padding + line.top - box.top + ascent - sprite.ascent - sprite.padding, sprite.width, sprite.height);
|
|
68
|
+
}
|
|
69
|
+
canvas.dataset.lines = String(lines.length);
|
|
70
|
+
element.dataset.pencilReady = 'true';
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
const PencilTextImplementation = forwardRef(function PencilText({ as: Element = 'span', children, seed, ellipsis = false, className = '', ...props }, forwardedRef) {
|
|
74
|
+
const [text, setText] = useState(children);
|
|
75
|
+
const elementRef = useRef(null);
|
|
76
|
+
const sourceRef = useRef(null);
|
|
77
|
+
const canvasRef = useRef(null);
|
|
78
|
+
const resolvedSeed = seed ?? children;
|
|
79
|
+
useImperativeHandle(forwardedRef, () => elementRef.current);
|
|
80
|
+
useBrowserLayoutEffect(() => {
|
|
81
|
+
if (!ellipsis) {
|
|
82
|
+
setText(children);
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
const node = elementRef.current;
|
|
86
|
+
const canvas = canvasRef.current;
|
|
87
|
+
if (!node || !canvas)
|
|
88
|
+
return undefined;
|
|
89
|
+
let disposed = false;
|
|
90
|
+
const fit = () => {
|
|
91
|
+
const width = node.clientWidth - 8;
|
|
92
|
+
if (width <= 0)
|
|
93
|
+
return;
|
|
94
|
+
const style = getComputedStyle(node);
|
|
95
|
+
const context = canvas.getContext('2d');
|
|
96
|
+
if (!context || context.isContextLost?.())
|
|
97
|
+
return;
|
|
98
|
+
context.font = `400 ${style.fontSize} ${style.fontFamily}`;
|
|
99
|
+
context.fontKerning = 'none';
|
|
100
|
+
const measure = (value) => context.measureText(value).width;
|
|
101
|
+
if (measure(children) <= width) {
|
|
102
|
+
setText(previous => previous === children ? previous : children);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const characters = Array.from(children);
|
|
106
|
+
let low = 0;
|
|
107
|
+
let high = characters.length;
|
|
108
|
+
while (low < high) {
|
|
109
|
+
const middle = Math.ceil((low + high) / 2);
|
|
110
|
+
if (measure(`${characters.slice(0, middle).join('')}…`) <= width)
|
|
111
|
+
low = middle;
|
|
112
|
+
else
|
|
113
|
+
high = middle - 1;
|
|
114
|
+
}
|
|
115
|
+
const clipped = `${characters.slice(0, low).join('').trimEnd()}…`;
|
|
116
|
+
setText(previous => previous === clipped ? previous : clipped);
|
|
117
|
+
};
|
|
118
|
+
const resize = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(fit);
|
|
119
|
+
resize?.observe(node);
|
|
120
|
+
document.fonts?.ready.then(() => { if (!disposed)
|
|
121
|
+
fit(); });
|
|
122
|
+
fit();
|
|
123
|
+
return () => {
|
|
124
|
+
disposed = true;
|
|
125
|
+
resize?.disconnect();
|
|
126
|
+
};
|
|
127
|
+
}, [children, ellipsis]);
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
const node = elementRef.current;
|
|
130
|
+
const source = sourceRef.current;
|
|
131
|
+
const canvas = canvasRef.current;
|
|
132
|
+
if (!node || !source || !canvas)
|
|
133
|
+
return undefined;
|
|
134
|
+
delete node.dataset.pencilReady;
|
|
135
|
+
let disposed = false;
|
|
136
|
+
let visible = typeof IntersectionObserver === 'undefined';
|
|
137
|
+
let pending = null;
|
|
138
|
+
let dirty = true;
|
|
139
|
+
const schedule = () => {
|
|
140
|
+
if (!visible || !dirty || pending || disposed)
|
|
141
|
+
return;
|
|
142
|
+
pending = queueTextPaint(() => {
|
|
143
|
+
pending = null;
|
|
144
|
+
if (!disposed && visible && dirty) {
|
|
145
|
+
try {
|
|
146
|
+
paintText(node, source, canvas, text, resolvedSeed);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
delete node.dataset.pencilReady;
|
|
150
|
+
}
|
|
151
|
+
dirty = false;
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
const markDirty = () => {
|
|
156
|
+
dirty = true;
|
|
157
|
+
delete node.dataset.pencilReady;
|
|
158
|
+
schedule();
|
|
159
|
+
};
|
|
160
|
+
const resize = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(markDirty);
|
|
161
|
+
resize?.observe(node);
|
|
162
|
+
const appearance = new MutationObserver(markDirty);
|
|
163
|
+
appearance.observe(document.documentElement, {
|
|
164
|
+
attributes: true,
|
|
165
|
+
subtree: true,
|
|
166
|
+
attributeFilter: ['data-theme', 'data-inkra-theme'],
|
|
167
|
+
});
|
|
168
|
+
const colorScheme = window.matchMedia('(prefers-color-scheme: dark)');
|
|
169
|
+
colorScheme.addEventListener('change', markDirty);
|
|
170
|
+
const intersection = typeof IntersectionObserver === 'undefined' ? null : new IntersectionObserver(entries => {
|
|
171
|
+
visible = entries[entries.length - 1]?.isIntersecting ?? false;
|
|
172
|
+
schedule();
|
|
173
|
+
}, { rootMargin: '80px' });
|
|
174
|
+
intersection?.observe(node);
|
|
175
|
+
const fonts = document.fonts;
|
|
176
|
+
fonts?.addEventListener('loading', markDirty);
|
|
177
|
+
fonts?.addEventListener('loadingdone', markDirty);
|
|
178
|
+
fonts?.addEventListener('loadingerror', markDirty);
|
|
179
|
+
fonts?.ready.then(() => { if (!disposed)
|
|
180
|
+
markDirty(); });
|
|
181
|
+
const stopRecovery = observeCanvasRecovery(() => {
|
|
182
|
+
pending?.();
|
|
183
|
+
pending = null;
|
|
184
|
+
markDirty();
|
|
185
|
+
});
|
|
186
|
+
schedule();
|
|
187
|
+
return () => {
|
|
188
|
+
disposed = true;
|
|
189
|
+
stopRecovery();
|
|
190
|
+
pending?.();
|
|
191
|
+
resize?.disconnect();
|
|
192
|
+
intersection?.disconnect();
|
|
193
|
+
appearance.disconnect();
|
|
194
|
+
colorScheme.removeEventListener('change', markDirty);
|
|
195
|
+
fonts?.removeEventListener('loading', markDirty);
|
|
196
|
+
fonts?.removeEventListener('loadingdone', markDirty);
|
|
197
|
+
fonts?.removeEventListener('loadingerror', markDirty);
|
|
198
|
+
};
|
|
199
|
+
}, [text, resolvedSeed]);
|
|
200
|
+
const classes = ['inkra-pencil-text', ellipsis && 'inkra-pencil-text--ellipsis', className]
|
|
201
|
+
.filter(Boolean).join(' ');
|
|
202
|
+
const title = props.title ?? (ellipsis ? children : undefined);
|
|
203
|
+
return (_jsxs(Element, { ...props, className: classes, ref: elementRef, title: title, children: [_jsx("span", { className: "inkra-pencil-text__source", ref: sourceRef, children: children }), _jsx("canvas", { "aria-hidden": "true", "data-renderer": "inkra-pencil-lettering-c", ref: canvasRef })] }));
|
|
204
|
+
});
|
|
205
|
+
export const PencilText = PencilTextImplementation;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
export type AccordionRootProps = AccordionPrimitive.AccordionSingleProps | AccordionPrimitive.AccordionMultipleProps;
|
|
4
|
+
export declare const AccordionRoot: import("react").ForwardRefExoticComponent<AccordionRootProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
5
|
+
export interface AccordionItemProps extends AccordionPrimitive.AccordionItemProps {
|
|
6
|
+
dividerSeed?: string | number;
|
|
7
|
+
showDivider?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare const AccordionItem: import("react").ForwardRefExoticComponent<AccordionItemProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
10
|
+
export type AccordionHeaderProps = AccordionPrimitive.AccordionHeaderProps;
|
|
11
|
+
export declare const AccordionHeader: import("react").ForwardRefExoticComponent<AccordionPrimitive.AccordionHeaderProps & import("react").RefAttributes<HTMLHeadingElement>>;
|
|
12
|
+
export interface AccordionTriggerProps extends AccordionPrimitive.AccordionTriggerProps {
|
|
13
|
+
icon?: ReactNode;
|
|
14
|
+
seed?: string | number;
|
|
15
|
+
}
|
|
16
|
+
export declare const AccordionTrigger: import("react").ForwardRefExoticComponent<AccordionTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
17
|
+
export interface AccordionContentProps extends AccordionPrimitive.AccordionContentProps {
|
|
18
|
+
contentClassName?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare const AccordionContent: import("react").ForwardRefExoticComponent<AccordionContentProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
21
|
+
export declare const Accordion: Readonly<{
|
|
22
|
+
Root: import("react").ForwardRefExoticComponent<AccordionRootProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
23
|
+
Item: import("react").ForwardRefExoticComponent<AccordionItemProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
24
|
+
Header: import("react").ForwardRefExoticComponent<AccordionPrimitive.AccordionHeaderProps & import("react").RefAttributes<HTMLHeadingElement>>;
|
|
25
|
+
Trigger: import("react").ForwardRefExoticComponent<AccordionTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
26
|
+
Content: import("react").ForwardRefExoticComponent<AccordionContentProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
27
|
+
}>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
|
3
|
+
import { createContext, forwardRef, useContext, useId } from 'react';
|
|
4
|
+
import { PencilIcon } from '../PencilIcon.js';
|
|
5
|
+
import { PencilLine } from '../PencilLine.js';
|
|
6
|
+
import { PencilSurface } from '../PencilSurface.js';
|
|
7
|
+
import { PencilText } from '../PencilText.js';
|
|
8
|
+
const chevronDownPaths = [
|
|
9
|
+
{ d: 'M6 9L12 15L18 9' },
|
|
10
|
+
];
|
|
11
|
+
const AccordionOrientationContext = createContext('vertical');
|
|
12
|
+
function classes(...values) {
|
|
13
|
+
return values.filter(Boolean).join(' ');
|
|
14
|
+
}
|
|
15
|
+
export const AccordionRoot = forwardRef(function AccordionRoot({ className, orientation = 'vertical', ...props }, ref) {
|
|
16
|
+
return (_jsx(AccordionOrientationContext.Provider, { value: orientation, children: _jsx(AccordionPrimitive.Root, { ...props, className: classes('inkra-accordion', className), orientation: orientation, ref: ref }) }));
|
|
17
|
+
});
|
|
18
|
+
export const AccordionItem = forwardRef(function AccordionItem({ children, className, dividerSeed, showDivider = true, value, ...props }, ref) {
|
|
19
|
+
const orientation = useContext(AccordionOrientationContext);
|
|
20
|
+
return (_jsxs(AccordionPrimitive.Item, { ...props, className: classes('inkra-accordion__item', className), ref: ref, value: value, children: [children, showDivider ? (_jsx(PencilLine, { className: "inkra-accordion__divider", orientation: orientation === 'horizontal' ? 'vertical' : 'horizontal', seed: dividerSeed ?? `inkra-accordion-divider-${value}`, weight: 0.8 })) : null] }));
|
|
21
|
+
});
|
|
22
|
+
export const AccordionHeader = forwardRef(function AccordionHeader({ className, ...props }, ref) {
|
|
23
|
+
return (_jsx(AccordionPrimitive.Header, { ...props, className: classes('inkra-accordion__header', className), ref: ref }));
|
|
24
|
+
});
|
|
25
|
+
export const AccordionTrigger = forwardRef(function AccordionTrigger({ children, className, icon, seed, ...props }, ref) {
|
|
26
|
+
const generatedId = useId();
|
|
27
|
+
const resolvedSeed = seed ?? `inkra-accordion-trigger-${generatedId}`;
|
|
28
|
+
const triggerIcon = icon === undefined ? (_jsx(PencilIcon, { className: "inkra-accordion__trigger-glyph", paths: chevronDownPaths, seed: `${resolvedSeed}-chevron`, size: 16, sourceSize: 24 })) : icon;
|
|
29
|
+
return (_jsxs(AccordionPrimitive.Trigger, { ...props, className: classes('inkra-accordion__trigger', className), ref: ref, children: [_jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-accordion__focus-ring", radius: 6, seed: `${resolvedSeed}-focus`, variant: "outline" }), _jsx("span", { className: "inkra-accordion__trigger-label", children: typeof children === 'string' ? (_jsx(PencilText, { seed: `${resolvedSeed}-text`, children: children })) : children }), triggerIcon == null ? null : (_jsx("span", { "aria-hidden": "true", className: "inkra-accordion__trigger-icon", children: triggerIcon }))] }));
|
|
30
|
+
});
|
|
31
|
+
export const AccordionContent = forwardRef(function AccordionContent({ children, className, contentClassName, ...props }, ref) {
|
|
32
|
+
return (_jsx(AccordionPrimitive.Content, { ...props, className: classes('inkra-accordion__content', className), ref: ref, children: _jsx("div", { className: classes('inkra-accordion__content-body', contentClassName), children: children }) }));
|
|
33
|
+
});
|
|
34
|
+
export const Accordion = Object.freeze({
|
|
35
|
+
Root: AccordionRoot,
|
|
36
|
+
Item: AccordionItem,
|
|
37
|
+
Header: AccordionHeader,
|
|
38
|
+
Trigger: AccordionTrigger,
|
|
39
|
+
Content: AccordionContent,
|
|
40
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Accordion, AccordionContent, AccordionHeader, AccordionItem, AccordionRoot, AccordionTrigger, } from './Accordion.js';
|
|
Binary file
|