panelui-web 0.9.0 → 0.10.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.
@@ -0,0 +1,278 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ /**
4
+ * XYPad — two numbers set with one drag: a point moved across a field.
5
+ *
6
+ * ```tsx
7
+ * <XYPad label="Framing" defaultValue={{ x: 0.2, y: -0.1 }}>
8
+ * <XYPad.Value />
9
+ * </XYPad>
10
+ * ```
11
+ *
12
+ * ## Two values that belong together
13
+ *
14
+ * A position, a pan, a balance between two pairs of things: values that the
15
+ * hand thinks of as one place are set as one place. Two sliders would make
16
+ * the reader find a point by turning two knobs in turn.
17
+ *
18
+ * ## The field reads like a chart
19
+ *
20
+ * A grid of dots marks the steps, two hairlines mark zero on each axis, and
21
+ * two fainter lines run through the handle to the edges, so where it stands
22
+ * can be read against both axes at once. While it is held, four brackets
23
+ * close round it.
24
+ *
25
+ * ## Joystick and trail
26
+ *
27
+ * `snapBack` makes it a joystick: it springs back to the centre when let go,
28
+ * for a value that only means something while it is held, such as a pan
29
+ * speed. `trail` draws the last moves as a fading line, for a value whose
30
+ * path matters as much as where it ends.
31
+ */
32
+ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from 'react';
33
+ import { tv } from 'tailwind-variants';
34
+ /** How many moves the trail remembers. */
35
+ const TRAIL = 28;
36
+ const xyPadVariants = tv({
37
+ slots: {
38
+ root: 'group/pad flex w-full flex-col gap-2 data-disabled:opacity-50',
39
+ field: [
40
+ 'relative w-full cursor-crosshair touch-none overflow-hidden rounded-2xl bg-muted outline-none select-none',
41
+ 'aspect-(--pad-aspect) ring-1 ring-inset ring-foreground/[0.04]',
42
+ 'group-data-disabled/pad:cursor-not-allowed',
43
+ ],
44
+ // Positions are laid out on a plane set in from the field's edge, so a
45
+ // point at the very end of a range still shows whole.
46
+ plane: 'absolute inset-3',
47
+ dots: 'pointer-events-none absolute inset-0 size-full overflow-visible text-foreground [&_circle]:transition-[r,fill-opacity] [&_circle]:duration-150 motion-reduce:[&_circle]:transition-none',
48
+ axis: 'pointer-events-none absolute bg-foreground/15',
49
+ guide: [
50
+ 'pointer-events-none absolute bg-(--pad-mark) opacity-20',
51
+ 'transition-[left,top] duration-[520ms] ease-[cubic-bezier(0.3,1.35,0.4,1)] group-data-dragging/pad:duration-0 motion-reduce:transition-none',
52
+ ],
53
+ trail: 'pointer-events-none absolute inset-0 size-full overflow-visible',
54
+ handle: [
55
+ 'absolute top-(--pad-y) left-(--pad-x) z-10 size-[18px] -translate-x-1/2 -translate-y-1/2 cursor-grab rounded-full outline-none',
56
+ 'border-[2.5px] border-(--pad-mark) bg-background shadow-[0_1px_4px_rgb(0_0_0/0.25)]',
57
+ 'transition-[left,top,scale] duration-[520ms] ease-[cubic-bezier(0.3,1.35,0.4,1)] group-data-dragging/pad:cursor-grabbing group-data-dragging/pad:duration-0',
58
+ 'group-data-dragging/pad:scale-110 group-data-disabled/pad:cursor-not-allowed motion-reduce:transition-none',
59
+ 'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-muted',
60
+ // The point itself, in the middle of the ring.
61
+ "after:absolute after:inset-[3px] after:rounded-full after:bg-(--pad-mark) after:content-['']",
62
+ ],
63
+ bracket: [
64
+ 'pointer-events-none absolute size-2 border-foreground/70 opacity-0 transition-[opacity,translate] duration-200',
65
+ 'group-data-dragging/pad:translate-x-0 group-data-dragging/pad:translate-y-0 group-data-dragging/pad:opacity-100',
66
+ 'motion-reduce:transition-none',
67
+ ],
68
+ value: 'flex items-center gap-3 text-xs font-medium tabular-nums text-muted-foreground',
69
+ axisName: 'me-1 text-foreground/50',
70
+ },
71
+ variants: {
72
+ color: {
73
+ primary: { root: '[--pad-mark:var(--primary)]' },
74
+ info: { root: '[--pad-mark:var(--info)]' },
75
+ success: { root: '[--pad-mark:var(--success)]' },
76
+ warning: { root: '[--pad-mark:var(--warning)]' },
77
+ destructive: { root: '[--pad-mark:var(--destructive)]' },
78
+ },
79
+ },
80
+ defaultVariants: { color: 'info' },
81
+ });
82
+ const PadContext = createContext(null);
83
+ const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
84
+ const snapTo = (value, step, min) => {
85
+ const decimals = (String(step).split('.')[1] ?? '').length;
86
+ return Number((Math.round((value - min) / step) * step + min).toFixed(Math.min(decimals + 2, 10)));
87
+ };
88
+ /** A field with a point in it, moved by a drag, a press or the arrow keys. */
89
+ function XYPadRoot({ value: valueProp, defaultValue, onValueChange, onValueCommitted, x: xRange = [-1, 1], y: yRange = [-1, 1], step = 0.01, grid = 8, snapToGrid = false, snapBack = false, trail = false, color, aspect = '16 / 10', label, format, disabled = false, name, className, style, children, ...props }) {
90
+ const slots = xyPadVariants({ color });
91
+ const [xMin, xMax] = xRange;
92
+ const [yMin, yMax] = yRange;
93
+ const centre = useMemo(() => ({ x: (xMin + xMax) / 2, y: (yMin + yMax) / 2 }), [xMin, xMax, yMin, yMax]);
94
+ const [inner, setInner] = useState(defaultValue ?? centre);
95
+ const value = valueProp ?? inner;
96
+ const [dragging, setDragging] = useState(false);
97
+ const [path, setPath] = useState([]);
98
+ const live = useRef({
99
+ value,
100
+ onValueChange,
101
+ onValueCommitted,
102
+ controlled: valueProp !== undefined,
103
+ });
104
+ live.current = {
105
+ value,
106
+ onValueChange,
107
+ onValueCommitted,
108
+ controlled: valueProp !== undefined,
109
+ };
110
+ const write = useCallback((axis, number) => format ? format(number, axis) : `${number < 0 ? '−' : ''}${Math.abs(number).toFixed(2)}`, [format]);
111
+ // Square cells: as many rows as the field's shape fits at the width of a column.
112
+ const [wide, tall] = aspect.split('/').map((part) => Number(part) || 1);
113
+ const rows = Math.max(1, Math.round((grid * (tall ?? 1)) / (wide ?? 1)));
114
+ const tidy = useCallback((point) => {
115
+ const xStep = snapToGrid ? (xMax - xMin) / grid : step;
116
+ const yStep = snapToGrid ? (yMax - yMin) / rows : step;
117
+ return {
118
+ x: clamp(snapTo(point.x, xStep, xMin), xMin, xMax),
119
+ y: clamp(snapTo(point.y, yStep, yMin), yMin, yMax),
120
+ };
121
+ }, [snapToGrid, grid, rows, step, xMin, xMax, yMin, yMax]);
122
+ const change = useCallback((next) => {
123
+ const { value: last, controlled } = live.current;
124
+ if (next.x === last.x && next.y === last.y)
125
+ return;
126
+ if (!controlled)
127
+ setInner(next);
128
+ live.current.onValueChange?.(next);
129
+ if (trail)
130
+ setPath((all) => [...all.slice(-(TRAIL - 1)), next]);
131
+ }, [trail]);
132
+ // The trail fades away once the point is left alone.
133
+ useEffect(() => {
134
+ if (!trail || dragging || path.length === 0)
135
+ return;
136
+ const timer = window.setInterval(() => {
137
+ setPath((all) => (all.length <= 1 ? [] : all.slice(Math.ceil(all.length / 6))));
138
+ }, 60);
139
+ return () => window.clearInterval(timer);
140
+ }, [trail, dragging, path.length]);
141
+ const field = useRef(null);
142
+ const plane = useRef(null);
143
+ // The plane's size in pixels, so the lens round the point is a circle.
144
+ const [size, setSize] = useState({ width: 0, height: 0 });
145
+ useEffect(() => {
146
+ const box = plane.current;
147
+ if (!box)
148
+ return;
149
+ const observer = new ResizeObserver(() => setSize({ width: box.clientWidth, height: box.clientHeight }));
150
+ observer.observe(box);
151
+ return () => observer.disconnect();
152
+ }, []);
153
+ const handle = useRef(null);
154
+ const pointAt = (clientX, clientY) => {
155
+ const box = plane.current.getBoundingClientRect();
156
+ const across = clamp((clientX - box.left) / box.width, 0, 1);
157
+ const down = clamp((clientY - box.top) / box.height, 0, 1);
158
+ return tidy({
159
+ x: xMin + across * (xMax - xMin),
160
+ y: yMax - down * (yMax - yMin),
161
+ });
162
+ };
163
+ const press = (event) => {
164
+ if (disabled || event.button !== 0)
165
+ return;
166
+ event.preventDefault();
167
+ try {
168
+ field.current?.setPointerCapture(event.pointerId);
169
+ }
170
+ catch {
171
+ // A pointer the browser no longer tracks; the drag still follows moves over the field.
172
+ }
173
+ // Focused for the arrow keys, without the ring a keyboard user would see.
174
+ handle.current?.focus({ preventScroll: true, focusVisible: false });
175
+ setDragging(true);
176
+ change(pointAt(event.clientX, event.clientY));
177
+ };
178
+ const move = (event) => {
179
+ if (!dragging)
180
+ return;
181
+ change(pointAt(event.clientX, event.clientY));
182
+ };
183
+ const release = () => {
184
+ if (!dragging)
185
+ return;
186
+ setDragging(false);
187
+ if (snapBack)
188
+ change(centre);
189
+ live.current.onValueCommitted?.(snapBack ? centre : live.current.value);
190
+ };
191
+ const keys = (event) => {
192
+ if (disabled)
193
+ return;
194
+ const by = (event.shiftKey ? 10 : 1) * (snapToGrid ? (xMax - xMin) / grid : step);
195
+ const byY = (event.shiftKey ? 10 : 1) * (snapToGrid ? (yMax - yMin) / rows : step);
196
+ const rtl = getComputedStyle(event.currentTarget).direction === 'rtl';
197
+ const moves = {
198
+ ArrowLeft: () => ({ ...value, x: value.x + (rtl ? by : -by) }),
199
+ ArrowRight: () => ({ ...value, x: value.x + (rtl ? -by : by) }),
200
+ ArrowUp: () => ({ ...value, y: value.y + byY }),
201
+ ArrowDown: () => ({ ...value, y: value.y - byY }),
202
+ Home: () => centre,
203
+ };
204
+ const next = moves[event.key];
205
+ if (!next)
206
+ return;
207
+ event.preventDefault();
208
+ const point = tidy(next());
209
+ change(point);
210
+ live.current.onValueCommitted?.(point);
211
+ };
212
+ const toX = (x) => ((x - xMin) / (xMax - xMin)) * 100;
213
+ const toY = (y) => ((yMax - y) / (yMax - yMin)) * 100;
214
+ const left = ((value.x - xMin) / (xMax - xMin)) * 100;
215
+ const down = ((yMax - value.y) / (yMax - yMin)) * 100;
216
+ const zeroX = xMin < 0 && xMax > 0 ? ((0 - xMin) / (xMax - xMin)) * 100 : null;
217
+ const zeroY = yMin < 0 && yMax > 0 ? ((yMax - 0) / (yMax - yMin)) * 100 : null;
218
+ const valueText = `${label ? `${label}: ` : ''}x ${write('x', value.x)}, y ${write('y', value.y)}`;
219
+ // Each bracket closes in from its own corner.
220
+ const brackets = [
221
+ 'border-s-[1.5px] border-t-[1.5px] -translate-x-1 -translate-y-1 left-[calc(var(--pad-x)-15px)] top-[calc(var(--pad-y)-15px)]',
222
+ 'border-e-[1.5px] border-t-[1.5px] translate-x-1 -translate-y-1 left-[calc(var(--pad-x)+7px)] top-[calc(var(--pad-y)-15px)]',
223
+ 'border-s-[1.5px] border-b-[1.5px] -translate-x-1 translate-y-1 left-[calc(var(--pad-x)-15px)] top-[calc(var(--pad-y)+7px)]',
224
+ 'border-e-[1.5px] border-b-[1.5px] translate-x-1 translate-y-1 left-[calc(var(--pad-x)+7px)] top-[calc(var(--pad-y)+7px)]',
225
+ ];
226
+ return (_jsx(PadContext.Provider, { value: useMemo(() => ({ value, write }), [value, write]), children: _jsxs("div", { "data-slot": "xy-pad", "data-dragging": dragging ? '' : undefined, "data-disabled": disabled ? '' : undefined, className: slots.root({ className }), style: {
227
+ ...style,
228
+ '--pad-aspect': aspect,
229
+ '--pad-x': `${left}%`,
230
+ '--pad-y': `${down}%`,
231
+ }, ...props, children: [_jsx("div", { ref: field, "data-slot": "xy-pad-field", className: slots.field(), onPointerDown: press, onPointerMove: move, onPointerUp: release, onPointerCancel: release, onLostPointerCapture: release, children: _jsxs("div", { ref: plane, "data-slot": "xy-pad-plane", className: slots.plane(), children: [_jsx(Dots, { columns: grid, rows: rows, size: size, at: { x: left / 100, y: down / 100 }, className: slots.dots() }), zeroX !== null ? (_jsx("span", { "aria-hidden": true, className: slots.axis({
232
+ className: '-inset-y-3 w-px -translate-x-1/2',
233
+ }), style: { left: `${zeroX}%` } })) : null, zeroY !== null ? (_jsx("span", { "aria-hidden": true, className: slots.axis({
234
+ className: '-inset-x-3 h-px -translate-y-1/2',
235
+ }), style: { top: `${zeroY}%` } })) : null, _jsx("span", { "aria-hidden": true, className: slots.guide({
236
+ className: '-inset-y-3 left-(--pad-x) w-px -translate-x-1/2',
237
+ }) }), _jsx("span", { "aria-hidden": true, className: slots.guide({
238
+ className: '-inset-x-3 top-(--pad-y) h-px -translate-y-1/2',
239
+ }) }), trail && path.length > 1 ? (_jsxs("svg", { "aria-hidden": true, className: slots.trail(), viewBox: "0 0 100 100", preserveAspectRatio: "none", children: [_jsx("polyline", { points: path.map((point) => `${toX(point.x)},${toY(point.y)}`).join(' '), fill: "none", stroke: "color-mix(in oklab, var(--pad-mark) 12%, var(--muted))", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", vectorEffect: "non-scaling-stroke" }), path.slice(1).map((point, at) => {
240
+ const from = path[at];
241
+ return (_jsx("line", { x1: toX(from.x), y1: toY(from.y), x2: toX(point.x), y2: toY(point.y), stroke: `color-mix(in oklab, var(--pad-mark) ${Math.round(12 + ((at + 1) / path.length) * 78)}%, var(--muted))`, strokeWidth: 2.5, strokeLinecap: "butt", vectorEffect: "non-scaling-stroke" }, at));
242
+ })] })) : null, brackets.map((place, at) => (_jsx("span", { "aria-hidden": true, className: slots.bracket({ className: place }) }, at))), _jsx("div", { ref: handle, role: "slider", "data-slot": "xy-pad-handle", tabIndex: disabled ? -1 : 0, "aria-label": label ?? 'Position', "aria-valuetext": valueText, "aria-valuenow": value.x, "aria-valuemin": xMin, "aria-valuemax": xMax, "aria-disabled": disabled || undefined, onKeyDown: keys, className: slots.handle() })] }) }), name ? (_jsxs(_Fragment, { children: [_jsx("input", { type: "hidden", name: `${name}.x`, value: value.x }), _jsx("input", { type: "hidden", name: `${name}.y`, value: value.y })] })) : null, children] }) }));
243
+ }
244
+ XYPadRoot.displayName = 'XYPad';
245
+ /** How far round the point the dots swell: this share of the field's shorter side, at most 72px. */
246
+ const LENS = 0.3;
247
+ /**
248
+ * The dot grid, one dot at each crossing including the edges. The dots
249
+ * within reach of the point swell and brighten, so the grid answers the
250
+ * point as it moves.
251
+ */
252
+ function Dots({ columns, rows, size, at, className, }) {
253
+ const dots = [];
254
+ for (let column = 0; column <= columns; column++) {
255
+ for (let row = 0; row <= rows; row++) {
256
+ const x = column / columns;
257
+ const y = row / rows;
258
+ const distance = Math.hypot((x - at.x) * size.width, (y - at.y) * size.height);
259
+ const reach = Math.min(Math.min(size.width, size.height) * LENS, 72);
260
+ const near = reach ? Math.max(0, 1 - distance / reach) : 0;
261
+ dots.push(_jsx("circle", { cx: `${x * 100}%`, cy: `${y * 100}%`, r: 1.25 + near * 1.25, fill: "currentColor", fillOpacity: 0.16 + near * 0.5 }, `${column}-${row}`));
262
+ }
263
+ }
264
+ return (_jsx("svg", { "aria-hidden": true, className: className, children: dots }));
265
+ }
266
+ /** The two values written out, under the field. */
267
+ function XYPadValue({ className, ...props }) {
268
+ const pad = useContext(PadContext);
269
+ if (!pad)
270
+ throw new Error('XYPad.Value must be used inside an <XYPad>.');
271
+ const slots = xyPadVariants();
272
+ return (_jsxs("div", { "aria-hidden": true, "data-slot": "xy-pad-value", className: slots.value({ className }), ...props, children: [_jsxs("span", { children: [_jsx("span", { className: slots.axisName(), children: "X" }), pad.write('x', pad.value.x)] }), _jsxs("span", { children: [_jsx("span", { className: slots.axisName(), children: "Y" }), pad.write('y', pad.value.y)] })] }));
273
+ }
274
+ XYPadValue.displayName = 'XYPad.Value';
275
+ export const XYPad = Object.assign(XYPadRoot, {
276
+ Value: XYPadValue,
277
+ });
278
+ export { XYPadValue, xyPadVariants };
package/dist/index.d.ts CHANGED
@@ -32,3 +32,10 @@ export { Alert, AlertIcon, AlertTitle, AlertDescription, AlertActions, AlertClos
32
32
  export { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogMedia, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, type AlertDialogProps, type AlertDialogTone, type AlertDialogTriggerProps, type AlertDialogContentProps, type AlertDialogMediaProps, type AlertDialogTitleProps, type AlertDialogDescriptionProps, type AlertDialogFooterProps, type AlertDialogCancelProps, type AlertDialogActionProps, } from './components/alert-dialog/index.js';
33
33
  export { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogBody, DialogFooter, DialogClose, DialogList, DialogListGroup, DialogListItem, type DialogProps, type DialogTriggerProps, type DialogContentProps, type DialogHeaderProps, type DialogTitleProps, type DialogDescriptionProps, type DialogBodyProps, type DialogFooterProps, type DialogCloseProps, type DialogListProps, type DialogListGroupProps, type DialogListItemProps, } from './components/dialog/index.js';
34
34
  export { Canvas, CanvasPattern, CanvasSpotlight, CanvasContent, type CanvasProps, type CanvasViewport, type CanvasPatternVariant, type CanvasFade, type CanvasPatternProps, type CanvasSpotlightProps, type CanvasContentProps, } from './components/canvas/index.js';
35
+ export { Slider, SliderStep, sliderVariants, type SliderProps, type SliderStepProps, type SliderVariant, type SliderSize, type SliderColor, } from './components/slider/index.js';
36
+ export { Toolbar, ToolbarGroup, ToolbarTool, ToolbarButton, ToolbarSeparator, ToolbarCaret, toolbarVariants, type ToolbarProps, type ToolbarVariant, type ToolbarSize, type ToolbarGroupProps, type ToolbarToolProps, type ToolbarButtonProps, type ToolbarSeparatorProps, type ToolbarCaretProps, } from './components/toolbar/index.js';
37
+ export { XYPad, XYPadValue, xyPadVariants, type XYPadProps, type XYPadValueProps, type XYPadPoint, type XYPadColor, } from './components/xy-pad/index.js';
38
+ export { ChoiceCards, ChoiceCardsItem, ChoiceCardsMedia, ChoiceCardsLabel, ChoiceCardsDescription, choiceCardsVariants, type ChoiceCardsProps, type ChoiceCardsColor, type ChoiceCardsItemProps, type ChoiceCardsMediaProps, type ChoiceCardsLabelProps, type ChoiceCardsDescriptionProps, } from './components/choice-cards/index.js';
39
+ export { Inspector, InspectorRail, InspectorTab, InspectorRailSeparator, InspectorPanel, InspectorPage, InspectorSection, InspectorSectionTitle, InspectorSectionAction, InspectorSectionContent, InspectorSeparator, inspectorVariants, type InspectorProps, type InspectorRailProps, type InspectorTabProps, type InspectorRailSeparatorProps, type InspectorPanelProps, type InspectorPageProps, type InspectorSectionProps, type InspectorSectionTitleProps, type InspectorSectionActionProps, type InspectorSectionContentProps, type InspectorSeparatorProps, } from './components/inspector/index.js';
40
+ export { Timeline, TimelineHeader, TimelineTime, TimelineZoom, TimelineViewport, TimelineRuler, TimelineTrack, TimelineClip, TimelineClipLabel, TimelineWaveform, TimelinePlayhead, timelineVariants, useTimeline, formatTime, rulerStep, type TimelineProps, type TimelineColor, type TimelineClipVariant, type TimelineTrackSize, type TimelineHeaderProps, type TimelineTimeProps, type TimelineZoomProps, type TimelineViewportProps, type TimelineRulerProps, type TimelineTrackProps, type TimelineClipProps, type TimelineClipLabelProps, type TimelineWaveformProps, type TimelinePlayheadProps, } from './components/timeline/index.js';
41
+ export { Workbench, WorkbenchBar, WorkbenchSidebar, WorkbenchCanvas, WorkbenchArtboard, WorkbenchInspector, WorkbenchInspectorTrigger, WorkbenchTimeline, workbenchVariants, useWorkbench, type WorkbenchProps, type WorkbenchBarProps, type WorkbenchSidebarProps, type WorkbenchCanvasProps, type WorkbenchArtboardProps, type WorkbenchInspectorProps, type WorkbenchInspectorTriggerProps, type WorkbenchTimelineProps, } from './components/workbench/index.js';
package/dist/index.js CHANGED
@@ -32,3 +32,10 @@ export { Alert, AlertIcon, AlertTitle, AlertDescription, AlertActions, AlertClos
32
32
  export { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogMedia, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, } from './components/alert-dialog/index.js';
33
33
  export { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogBody, DialogFooter, DialogClose, DialogList, DialogListGroup, DialogListItem, } from './components/dialog/index.js';
34
34
  export { Canvas, CanvasPattern, CanvasSpotlight, CanvasContent, } from './components/canvas/index.js';
35
+ export { Slider, SliderStep, sliderVariants, } from './components/slider/index.js';
36
+ export { Toolbar, ToolbarGroup, ToolbarTool, ToolbarButton, ToolbarSeparator, ToolbarCaret, toolbarVariants, } from './components/toolbar/index.js';
37
+ export { XYPad, XYPadValue, xyPadVariants, } from './components/xy-pad/index.js';
38
+ export { ChoiceCards, ChoiceCardsItem, ChoiceCardsMedia, ChoiceCardsLabel, ChoiceCardsDescription, choiceCardsVariants, } from './components/choice-cards/index.js';
39
+ export { Inspector, InspectorRail, InspectorTab, InspectorRailSeparator, InspectorPanel, InspectorPage, InspectorSection, InspectorSectionTitle, InspectorSectionAction, InspectorSectionContent, InspectorSeparator, inspectorVariants, } from './components/inspector/index.js';
40
+ export { Timeline, TimelineHeader, TimelineTime, TimelineZoom, TimelineViewport, TimelineRuler, TimelineTrack, TimelineClip, TimelineClipLabel, TimelineWaveform, TimelinePlayhead, timelineVariants, useTimeline, formatTime, rulerStep, } from './components/timeline/index.js';
41
+ export { Workbench, WorkbenchBar, WorkbenchSidebar, WorkbenchCanvas, WorkbenchArtboard, WorkbenchInspector, WorkbenchInspectorTrigger, WorkbenchTimeline, workbenchVariants, useWorkbench, } from './components/workbench/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "panelui-web",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "PanelUI for the web: animated, data-rich React components styled with Tailwind CSS on shadcn tokens.",
5
5
  "type": "module",
6
6
  "sideEffects": false,