@brett_lamy/docstream 1.12.0 → 1.13.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/README.md CHANGED
@@ -246,7 +246,11 @@ setMethod(code, song.tracks[1].chain, "room", formatNumber(0.5)) // exact edit,
246
246
  mixCode(song, { solo: new Set([0]) }) // the code with other tracks silenced
247
247
  ```
248
248
 
249
- `StrudelRack`, `StepGrid`, `Knob` and `Fader` are exported for custom studios. The parser
249
+ The master strip's **Rack | Grid** switch puts the modules on a masonry grid: drag a module's
250
+ title to move it, drag its corner to resize it (arrow keys work on both handles).
251
+ `<StrudelRack layout="grid" persistKey="my-song" />` starts there and remembers the arrangement.
252
+
253
+ `StrudelRack`, `RackGrid`, `StepGrid`, `Knob` and `Fader` are exported for custom studios. The parser
250
254
  (acorn) loads only when a rack opens.
251
255
 
252
256
  ## GitBook Syntax
@@ -0,0 +1,23 @@
1
+ import { type ReactNode } from "react";
2
+ export interface GridItem {
3
+ key: string;
4
+ label: string;
5
+ node: ReactNode;
6
+ /** Default width in twelfths of the grid (12 = full width). */
7
+ span?: number;
8
+ }
9
+ export interface GridLayout {
10
+ order: string[];
11
+ /** Width in twelfths, and an optional minimum height in px, per item key. */
12
+ sizes: Record<string, {
13
+ w: number;
14
+ h?: number;
15
+ }>;
16
+ }
17
+ export interface RackGridProps {
18
+ items: GridItem[];
19
+ layout: GridLayout;
20
+ onLayoutChange: (layout: GridLayout) => void;
21
+ }
22
+ export declare function RackGrid({ items, layout, onLayoutChange }: RackGridProps): import("react").JSX.Element;
23
+ //# sourceMappingURL=RackGrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RackGrid.d.ts","sourceRoot":"","sources":["../../src/strudel/RackGrid.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAuF,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAE3H,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,SAAS,CAAA;IACf,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACjD;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,QAAQ,EAAE,CAAA;IACjB,MAAM,EAAE,UAAU,CAAA;IAClB,cAAc,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAA;CAC7C;AAaD,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,aAAa,+BAiMxE"}
@@ -0,0 +1,182 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /* A masonry grid of modules you can rearrange and resize. Columns follow the container's width; every module spans
3
+ some of them and as many 8px rows as its content (or the height you dragged it to) needs, and `dense` flow packs
4
+ the gaps. Drag a module's grip to move it (others reflow under the pointer); drag its corner to resize. Both
5
+ handles are keyboard-operable: arrows move or resize, Home/End move to the ends. */
6
+ import { useEffect, useLayoutEffect, useRef, useState } from "react";
7
+ const ROW = 8;
8
+ const GAP = 10;
9
+ /** Items in layout order: known keys first, new ones appended. */
10
+ function ordered(items, order) {
11
+ const byKey = new Map(items.map((i) => [i.key, i]));
12
+ const out = order.map((k) => byKey.get(k)).filter((i) => !!i);
13
+ for (const i of items)
14
+ if (!order.includes(i.key))
15
+ out.push(i);
16
+ return out;
17
+ }
18
+ export function RackGrid({ items, layout, onLayoutChange }) {
19
+ const gridRef = useRef(null);
20
+ const [cols, setCols] = useState(12);
21
+ const [heights, setHeights] = useState({});
22
+ const [dragging, setDragging] = useState(null);
23
+ const drag = useRef(null);
24
+ const elements = useRef(new Map());
25
+ const list = ordered(items, layout.order);
26
+ const keys = list.map((i) => i.key);
27
+ const layoutRef = useRef(layout);
28
+ layoutRef.current = layout;
29
+ // Columns: one per ~84px of width, at most 12 — spans are stored in twelfths and scaled.
30
+ useLayoutEffect(() => {
31
+ const grid = gridRef.current;
32
+ if (!grid)
33
+ return;
34
+ const measure = () => setCols(Math.max(2, Math.min(12, Math.floor((grid.clientWidth + GAP) / 84))));
35
+ measure();
36
+ const ro = new ResizeObserver(measure);
37
+ ro.observe(grid);
38
+ return () => ro.disconnect();
39
+ }, []);
40
+ // Masonry: each module spans as many rows as its content is tall.
41
+ useEffect(() => {
42
+ const ro = new ResizeObserver((entries) => {
43
+ setHeights((prev) => {
44
+ let next = prev;
45
+ for (const e of entries) {
46
+ const key = e.target.dataset.content;
47
+ const h = Math.ceil(e.target.offsetHeight);
48
+ if (prev[key] !== h)
49
+ next = { ...next, [key]: h };
50
+ }
51
+ return next;
52
+ });
53
+ });
54
+ elements.current.forEach((el) => {
55
+ const content = el.querySelector("[data-content]");
56
+ if (content)
57
+ ro.observe(content);
58
+ });
59
+ return () => ro.disconnect();
60
+ }, [keys.join("|")]);
61
+ const span = (item) => {
62
+ const w = layout.sizes[item.key]?.w ?? item.span ?? 6;
63
+ return Math.max(1, Math.min(cols, Math.round((w / 12) * cols)));
64
+ };
65
+ const rows = (item) => {
66
+ const h = Math.max(heights[item.key] ?? 120, layout.sizes[item.key]?.h ?? 0);
67
+ return Math.ceil((h + GAP) / (ROW + GAP));
68
+ };
69
+ const setSize = (key, size) => {
70
+ const cur = layoutRef.current;
71
+ onLayoutChange({ order: keys, sizes: { ...cur.sizes, [key]: { ...cur.sizes[key], w: cur.sizes[key]?.w ?? 6, ...size } } });
72
+ };
73
+ const move = (key, to) => {
74
+ const from = keys.indexOf(key);
75
+ const next = keys.filter((k) => k !== key);
76
+ next.splice(Math.max(0, Math.min(next.length, to)), 0, key);
77
+ if (from !== next.indexOf(key))
78
+ onLayoutChange({ ...layoutRef.current, order: next });
79
+ };
80
+ // Moving: the module follows the pointer; hovering another module takes its place.
81
+ const place = (key, x, y) => {
82
+ const el = elements.current.get(key);
83
+ const grid = gridRef.current;
84
+ const d = drag.current;
85
+ if (!el || !grid || !d)
86
+ return;
87
+ const box = grid.getBoundingClientRect();
88
+ el.style.transform = `translate(${x - d.dx - box.left - el.offsetLeft}px, ${y - d.dy - box.top - el.offsetTop}px)`;
89
+ };
90
+ const onGripDown = (key) => (e) => {
91
+ if (e.button !== 0)
92
+ return;
93
+ const el = elements.current.get(key);
94
+ const r = el.getBoundingClientRect();
95
+ e.currentTarget.setPointerCapture(e.pointerId);
96
+ drag.current = { key, dx: e.clientX - r.left, dy: e.clientY - r.top, x: e.clientX, y: e.clientY };
97
+ setDragging(key);
98
+ };
99
+ const onGripMove = (e) => {
100
+ const d = drag.current;
101
+ if (!d)
102
+ return;
103
+ d.x = e.clientX;
104
+ d.y = e.clientY;
105
+ place(d.key, e.clientX, e.clientY);
106
+ const dragged = elements.current.get(d.key);
107
+ dragged.style.pointerEvents = "none";
108
+ const under = document.elementFromPoint(e.clientX, e.clientY)?.closest("[data-grid-key]");
109
+ dragged.style.pointerEvents = "";
110
+ const target = under?.dataset.gridKey;
111
+ if (target && target !== d.key)
112
+ move(d.key, keys.indexOf(target));
113
+ };
114
+ const onGripUp = () => {
115
+ const d = drag.current;
116
+ if (!d)
117
+ return;
118
+ const el = elements.current.get(d.key);
119
+ if (el)
120
+ el.style.transform = "";
121
+ drag.current = null;
122
+ setDragging(null);
123
+ };
124
+ // After a reorder the module's slot moved: keep it under the pointer.
125
+ useLayoutEffect(() => {
126
+ const d = drag.current;
127
+ if (d)
128
+ place(d.key, d.x, d.y);
129
+ });
130
+ const onGripKey = (key) => (e) => {
131
+ const i = keys.indexOf(key);
132
+ const to = { ArrowLeft: i - 1, ArrowUp: i - 1, ArrowRight: i + 1, ArrowDown: i + 1, Home: 0, End: keys.length - 1 }[e.key];
133
+ if (to === undefined)
134
+ return;
135
+ e.preventDefault();
136
+ move(key, to);
137
+ };
138
+ // Resizing: the corner sets the width in columns and a minimum height.
139
+ const resize = useRef(null);
140
+ const onCornerDown = (key) => (e) => {
141
+ const r = elements.current.get(key).getBoundingClientRect();
142
+ e.currentTarget.setPointerCapture(e.pointerId);
143
+ resize.current = { key, left: r.left, top: r.top };
144
+ };
145
+ const onCornerMove = (e) => {
146
+ const r = resize.current;
147
+ const grid = gridRef.current;
148
+ if (!r || !grid)
149
+ return;
150
+ const colWidth = (grid.clientWidth - GAP * (cols - 1)) / cols;
151
+ const c = Math.max(1, Math.min(cols, Math.round((e.clientX - r.left + GAP) / (colWidth + GAP))));
152
+ setSize(r.key, { w: Math.round((c / cols) * 12 * 100) / 100, h: Math.max(60, Math.round(e.clientY - r.top)) });
153
+ };
154
+ const onCornerUp = () => {
155
+ resize.current = null;
156
+ };
157
+ const onCornerKey = (item) => (e) => {
158
+ const w = layout.sizes[item.key]?.w ?? item.span ?? 6;
159
+ const h = layout.sizes[item.key]?.h ?? heights[item.key] ?? 120;
160
+ const step = 12 / cols;
161
+ const next = {
162
+ ArrowRight: { w: Math.min(12, w + step) },
163
+ ArrowLeft: { w: Math.max(step, w - step) },
164
+ ArrowDown: { h: h + 24 },
165
+ ArrowUp: { h: Math.max(0, h - 24) },
166
+ }[e.key];
167
+ if (!next)
168
+ return;
169
+ e.preventDefault();
170
+ setSize(item.key, next);
171
+ };
172
+ return (_jsx("div", { ref: gridRef, className: "strudel-grid", style: { gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`, gridAutoRows: ROW, rowGap: GAP, columnGap: GAP }, children: list.map((item) => {
173
+ const h = layout.sizes[item.key]?.h;
174
+ return (_jsxs("div", { ref: (el) => {
175
+ if (el)
176
+ elements.current.set(item.key, el);
177
+ else
178
+ elements.current.delete(item.key);
179
+ }, className: "strudel-grid__item", "data-grid-key": item.key, "data-dragging": dragging === item.key || undefined, style: { gridColumn: `span ${span(item)}`, gridRow: `span ${rows(item)}` }, children: [_jsx("div", { "data-content": item.key, className: "strudel-grid__content", style: h ? { minHeight: h } : undefined, children: item.node }), _jsx("button", { type: "button", className: "strudel-grid__grip", "aria-label": `Move ${item.label}`, title: "Drag to move (arrow keys too)", onPointerDown: onGripDown(item.key), onPointerMove: onGripMove, onPointerUp: onGripUp, onPointerCancel: onGripUp, onKeyDown: onGripKey(item.key) }), _jsx("button", { type: "button", className: "strudel-grid__corner", "aria-label": `Resize ${item.label}`, title: "Drag to resize (arrow keys too)", onPointerDown: onCornerDown(item.key), onPointerMove: onCornerMove, onPointerUp: onCornerUp, onPointerCancel: onCornerUp, onKeyDown: onCornerKey(item) })] }, item.key));
180
+ }) }));
181
+ }
182
+ //# sourceMappingURL=RackGrid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RackGrid.js","sourceRoot":"","sources":["../../src/strudel/RackGrid.tsx"],"names":[],"mappings":"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"}
@@ -5,6 +5,10 @@ export interface StrudelRackProps {
5
5
  /** The code to play for the current mute/solo mix (the written code with silenced tracks). */
6
6
  onPlayableChange?: (code: string) => void;
7
7
  className?: string;
8
+ /** "rack": modules stacked full width. "grid": a masonry grid you drag and resize. Defaults to "rack". */
9
+ layout?: "rack" | "grid";
10
+ /** Remember the layout (mode, order and sizes) in localStorage under this key. */
11
+ persistKey?: string;
8
12
  }
9
13
  interface Param {
10
14
  label: string;
@@ -19,6 +23,6 @@ export declare const STRUDEL_PARAMS: Record<string, Param>;
19
23
  /** A name for a track: its label, the sounds of a drum row, or its role and synth. */
20
24
  export declare function trackName(track: StrudelTrack): string;
21
25
  /** Equipment generated from Strudel code. Controlled: `code` in, edited code out through `onChange`. */
22
- export declare function StrudelRack({ code, onChange, onPlayableChange, className }: StrudelRackProps): import("react").JSX.Element;
26
+ export declare function StrudelRack({ code, onChange, onPlayableChange, className, layout, persistKey }: StrudelRackProps): import("react").JSX.Element;
23
27
  export default StrudelRack;
24
28
  //# sourceMappingURL=StrudelRack.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StrudelRack.d.ts","sourceRoot":"","sources":["../../src/strudel/StrudelRack.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAmG,KAAK,YAAY,EAAE,MAAM,eAAe,CAAA;AAKlJ,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACzC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,UAAU,KAAK;IACb,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CAC/B;AAKD,uGAAuG;AACvG,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAsBhD,CAAA;AAcD,sFAAsF;AACtF,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAarD;AAoJD,wGAAwG;AACxG,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,SAAS,EAAE,EAAE,gBAAgB,+BAuF5F;AAED,eAAe,WAAW,CAAA"}
1
+ {"version":3,"file":"StrudelRack.d.ts","sourceRoot":"","sources":["../../src/strudel/StrudelRack.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAmG,KAAK,YAAY,EAAE,MAAM,eAAe,CAAA;AAMlJ,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACzC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0GAA0G;IAC1G,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACxB,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAgBD,UAAU,KAAK;IACb,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CAC/B;AAKD,uGAAuG;AACvG,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAsBhD,CAAA;AAcD,sFAAsF;AACtF,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAarD;AAoJD,wGAAwG;AACxG,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAe,EAAE,UAAU,EAAE,EAAE,gBAAgB,+BA0HzH;AAED,eAAe,WAAW,CAAA"}
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  /* The rack: equipment generated from a Strudel song's syntax tree. Every track becomes a device — mute/solo,
3
3
  a gain fader, its sound and scale, a step grid for its pattern, and a knob for each effect it uses (plus any
4
4
  you add) — and the song gets a master strip with the tempo. Every control edits the code in place (edit.ts),
@@ -10,6 +10,17 @@ import { findCall, parseStrudel, StrudelSyntaxError } from "./ast/program.js";
10
10
  import { formatNumber, isAudible, mixCode, removeMethod, setMethod, setMiniAtom, setMiniSource, setTempo } from "./ast/edit.js";
11
11
  import { Fader, Knob, defaultFormat } from "./controls.js";
12
12
  import { StepGrid } from "./StepGrid.js";
13
+ import { RackGrid } from "./RackGrid.js";
14
+ function load(key) {
15
+ if (!key)
16
+ return {};
17
+ try {
18
+ return JSON.parse(localStorage.getItem(`strudel-rack:${key}`) ?? "{}");
19
+ }
20
+ catch {
21
+ return {};
22
+ }
23
+ }
13
24
  const hz = (v) => (v >= 1000 ? `${+(v / 1000).toFixed(1)}k` : v.toFixed(0));
14
25
  const pct = (v) => `${Math.round(v * 100)}`;
15
26
  /** Effects the rack knows how to draw, in display order. Others still parse; they just get no knob. */
@@ -88,7 +99,20 @@ function Device({ song, track, mix, onMix, onChange, }) {
88
99
  }), missing.length > 0 && (_jsxs("label", { className: "strudel-device__add", title: "Add an effect", children: [_jsx(Plus, { size: 14, "aria-hidden": "true" }), _jsxs("select", { "aria-label": `Add an effect to ${name}`, value: "", onChange: (e) => e.target.value && set(e.target.value, STRUDEL_PARAMS[e.target.value].default), children: [_jsx("option", { value: "", children: "Add\u2026" }), missing.map((p) => (_jsxs("option", { value: p, children: [STRUDEL_PARAMS[p].label, " (", p, ")"] }, p)))] })] }))] })] })] })] }));
89
100
  }
90
101
  /** Equipment generated from Strudel code. Controlled: `code` in, edited code out through `onChange`. */
91
- export function StrudelRack({ code, onChange, onPlayableChange, className }) {
102
+ export function StrudelRack({ code, onChange, onPlayableChange, className, layout = "rack", persistKey }) {
103
+ const [saved] = useState(() => load(persistKey));
104
+ const [mode, setMode] = useState(saved.mode ?? layout);
105
+ const [grid, setGrid] = useState(saved.grid ?? { order: [], sizes: {} });
106
+ useEffect(() => {
107
+ if (!persistKey)
108
+ return;
109
+ try {
110
+ localStorage.setItem(`strudel-rack:${persistKey}`, JSON.stringify({ mode, grid }));
111
+ }
112
+ catch {
113
+ // Storage unavailable (private mode): the layout just isn't remembered.
114
+ }
115
+ }, [persistKey, mode, grid]);
92
116
  const parsed = useMemo(() => {
93
117
  try {
94
118
  return { song: parseStrudel(code) };
@@ -117,7 +141,14 @@ export function StrudelRack({ code, onChange, onPlayableChange, className }) {
117
141
  const cps = song.tempo?.cps;
118
142
  const master = song.masterChain;
119
143
  const postgain = master ? firstNumber(findCall(master, "postgain")) : null;
120
- return (_jsxs("div", { className: `strudel-rack ${className ?? ""}`.trim(), children: [_jsxs("div", { className: "strudel-rack__master", role: "group", "aria-label": "Master", children: [_jsxs("span", { className: "strudel-rack__title", children: ["Master", _jsx("small", { children: "Strudel" })] }), _jsxs("output", { className: "strudel-lcd strudel-lcd--bpm", "aria-label": "Tempo", children: [Math.round((cps && Number.isFinite(cps) ? cps : 0.5) * 2400) / 10, _jsx("small", { children: "BPM" })] }), _jsx(Knob, { size: "lg", label: "Tempo", value: cps && Number.isFinite(cps) ? cps : 0.5, min: 0.1, max: 2, defaultValue: 0.5, format: (v) => `${Math.round(v * 240)} bpm`, onChange: (v) => onChange(setTempo(song, v)) }), master && (_jsx(Knob, { size: "lg", label: "Output", value: postgain ?? 1, min: 0, max: 2, defaultValue: 1, format: pct, onChange: (v) => onChange(setMethod(code, master, "postgain", formatNumber(v))) })), _jsxs("span", { className: "strudel-rack__summary", children: [song.tracks.length, " track", song.tracks.length === 1 ? "" : "s", song.layout === "stack" ? " · stack" : song.layout === "labels" ? " · $:" : ""] })] }), song.tracks.length === 0 && _jsx("p", { className: "strudel-rack__error", children: "No pattern found." }), song.tracks.map((t) => (_jsx(Device, { song: song, track: t, mix: mix, onChange: onChange, onMix: (kind) => (kind === "mute" ? setMuted(toggle(muted, t.index)) : setSolo(toggle(solo, t.index))) }, t.index)))] }));
144
+ const masterStrip = (_jsxs("div", { className: "strudel-rack__master", role: "group", "aria-label": "Master", children: [_jsxs("span", { className: "strudel-rack__title", children: ["Master", _jsx("small", { children: "Strudel" })] }), _jsxs("output", { className: "strudel-lcd strudel-lcd--bpm", "aria-label": "Tempo", children: [Math.round((cps && Number.isFinite(cps) ? cps : 0.5) * 2400) / 10, _jsx("small", { children: "BPM" })] }), _jsx(Knob, { size: "lg", label: "Tempo", value: cps && Number.isFinite(cps) ? cps : 0.5, min: 0.1, max: 2, defaultValue: 0.5, format: (v) => `${Math.round(v * 240)} bpm`, onChange: (v) => onChange(setTempo(song, v)) }), master && (_jsx(Knob, { size: "lg", label: "Output", value: postgain ?? 1, min: 0, max: 2, defaultValue: 1, format: pct, onChange: (v) => onChange(setMethod(code, master, "postgain", formatNumber(v))) })), _jsxs("span", { className: "strudel-rack__summary", children: [song.tracks.length, " track", song.tracks.length === 1 ? "" : "s", song.layout === "stack" ? " · stack" : song.layout === "labels" ? " · $:" : ""] }), _jsx("div", { className: "strudel-rack__mode", role: "radiogroup", "aria-label": "Layout", children: ["rack", "grid"].map((m) => (_jsx("button", { type: "button", role: "radio", "aria-checked": mode === m, onClick: () => setMode(m), children: m }, m))) })] }));
145
+ const devices = song.tracks.map((t) => ({
146
+ key: `track-${t.index}`,
147
+ label: trackName(t),
148
+ span: 6,
149
+ node: (_jsx(Device, { song: song, track: t, mix: mix, onChange: onChange, onMix: (kind) => (kind === "mute" ? setMuted(toggle(muted, t.index)) : setSolo(toggle(solo, t.index))) })),
150
+ }));
151
+ return (_jsxs("div", { className: `strudel-rack ${className ?? ""}`.trim(), "data-mode": mode, children: [mode === "grid" ? (_jsx(RackGrid, { items: [{ key: "master", label: "Master", span: 12, node: masterStrip }, ...devices], layout: grid, onLayoutChange: setGrid })) : (_jsxs(_Fragment, { children: [masterStrip, devices.map((d) => (_jsx("div", { children: d.node }, d.key)))] })), song.tracks.length === 0 && _jsx("p", { className: "strudel-rack__error", children: "No pattern found." })] }));
121
152
  }
122
153
  export default StrudelRack;
123
154
  //# sourceMappingURL=StrudelRack.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"StrudelRack.js","sourceRoot":"","sources":["../../src/strudel/StrudelRack.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"StrudelRack.js","sourceRoot":"","sources":["../../src/strudel/StrudelRack.tsx"],"names":[],"mappings":";AAAA;;;oFAGoF;AACpF,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,cAAc,CAAA;AAC1E,OAAO,EAAE,SAAS,EAAiB,MAAM,YAAY,CAAA;AACrD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,kBAAkB,EAA0E,MAAM,eAAe,CAAA;AAClJ,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAmB,MAAM,YAAY,CAAA;AAC7I,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,QAAQ,EAAmB,MAAM,YAAY,CAAA;AAmBtD,SAAS,IAAI,CAAC,GAAuB;IACnC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAA;IACnB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,gBAAgB,GAAG,EAAE,CAAC,IAAI,IAAI,CAAmB,CAAA;IAC1F,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC;AAWD,MAAM,EAAE,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;AACnF,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,CAAA;AAEnD,uGAAuG;AACvG,MAAM,CAAC,MAAM,cAAc,GAA0B;IACnD,GAAG,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;IACnF,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;IACtF,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE;IACnD,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;IAClF,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE;IAC1D,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE;IACvD,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;IACxE,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE;IAC3D,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE;IACtD,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE;IAC5D,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;IACpE,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE;IACzD,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE;IACtD,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE;IACxD,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;IACtD,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,EAAE;IACtL,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;IACpE,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;IACnD,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;IACpE,SAAS,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE;IACzE,aAAa,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;CACnF,CAAA;AAED,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;AACxG,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,CAAA;AAC7G,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,OAAO,CAAC,CAAA;AAInN,MAAM,WAAW,GAAG,CAAC,IAAwB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;AAChH,MAAM,UAAU,GAAG,CAAC,IAAwB,EAAe,EAAE;IAC3D,MAAM,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;IACvB,OAAO,CAAC,EAAE,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAChD,CAAC,CAAA;AAED,sFAAsF;AACtF,MAAM,UAAU,SAAS,CAAC,KAAmB;IAC3C,IAAI,KAAK,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC,KAAK,CAAA;IACnC,MAAM,IAAI,GAAG,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;IACjE,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAA;QACrF,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAK,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QACvI,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;IAC/D,CAAC;IACD,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAA;IACxD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAA;IACnE,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;IACrD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,IAAI,IAAI,EAAE,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAA;IAC7I,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AACxD,CAAC;AAED,SAAS,MAAM,CAAC,EACd,IAAI,EACJ,KAAK,EACL,GAAG,EACH,KAAK,EACL,QAAQ,GAOT;IACC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAA;IACrB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;IACzB,MAAM,IAAI,GAAG,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;IACrD,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE,IAAI,SAAS,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;IAC1J,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IAClE,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC,CAAA;IACnC,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,IAAK,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACtE,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IACtG,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAA;IAClD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,6BAA6B,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAClF,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IACxC,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAA;IAClC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;IAC7E,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,CAAA;IACjG,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IACrC,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA;IAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,CAAA;IAErG,MAAM,GAAG,GAAG,CAAC,MAAc,EAAE,KAAa,EAAE,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAC5G,MAAM,OAAO,GAAG,CAAC,IAAU,EAAE,EAAE,CAAC,CAAC,IAAc,EAAE,IAAY,EAAE,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;IAE/G,OAAO,CACL,mBAAS,SAAS,EAAC,gBAAgB,eAAY,KAAK,CAAC,IAAI,kBAAgB,OAAO,gBAAc,IAAI,aAChG,kBAAQ,SAAS,EAAC,sBAAsB,aACtC,eAAM,SAAS,EAAC,qBAAqB,iBAAa,MAAM,GAAG,EAC3D,KAAC,IAAI,IAAC,IAAI,EAAE,EAAE,iBAAc,MAAM,GAAG,EACrC,eAAM,SAAS,EAAC,sBAAsB,EAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,YAC7E,IAAI,GACA,EACP,iBAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,wBAAwB,eAAW,MAAM,kBAAe,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAC,MAAM,kBAErK,EACT,iBAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,wBAAwB,eAAW,MAAM,kBAAe,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAC,MAAM,kBAEvJ,IACF,EACT,eAAK,SAAS,EAAC,sBAAsB,aACnC,KAAC,KAAK,IACJ,KAAK,EAAC,MAAM,EACZ,KAAK,EAAE,IAAI,IAAI,CAAC,EAChB,GAAG,EAAE,CAAC,EACN,GAAG,EAAE,GAAG,EACR,YAAY,EAAE,CAAC,EACf,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI,KAAK,IAAI,KACjC,CAAC,QAAQ,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,wBAAwB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EACxF,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,GAC/B,EACF,eAAK,SAAS,EAAC,sBAAsB,aAClC,CAAC,KAAK,IAAI,UAAU,CAAC,IAAI,CACxB,eAAK,SAAS,EAAC,qCAAqC,aACjD,KAAK,IAAI,CACR,4BACE,mCAAkB,EAClB,iBAAQ,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,EAAE,KAAM,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,YACpG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACjB,2BAAiB,CAAC,IAAL,CAAC,CAAc,CAC7B,CAAC,GACK,IACH,CACT,EACA,UAAU,IAAI,CACb,4BACE,iCAAgB,EAChB,iBACE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,EAChE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE,KAAM,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,YAE3G,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAChB,2BAAiB,CAAC,IAAL,CAAC,CAAc,CAC7B,CAAC,GACK,EACT,iBAAQ,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE,KAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,YACvI,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAE,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAChF,2BAAiB,CAAC,IAAL,CAAC,CAAc,CAC7B,CAAC,GACK,IACH,CACT,IACG,CACP,EACA,OAAO,EAAE,IAAI,IAAI,KAAC,QAAQ,IAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,GAAG,IAAI,QAAQ,GAAI,EACzG,CAAC,OAAO,IAAI,KAAK,EAAE,IAAI,IAAI,CAAC,KAAK,IAAI,KAAC,QAAQ,IAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,IAAI,SAAS,GAAI,EAC1H,OAAO,EAAE,KAAK,IAAI,YAAG,SAAS,EAAC,uBAAuB,YAAE,OAAO,CAAC,KAAK,CAAC,OAAO,GAAK,EACnF,eAAK,SAAS,EAAC,uBAAuB,aACnC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;wCACjB,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAE,CAAA;wCAChC,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAA;wCAC/B,MAAM,IAAI,GAAG,cAAc,CAAC,CAAC,CAAE,CAAA;wCAC/B,OAAO,CACL,eAAa,SAAS,EAAC,sBAAsB,aAC3C,KAAC,IAAI,IACH,KAAK,EAAE,IAAI,CAAC,KAAK,EACjB,KAAK,EAAE,KAAK,IAAI,IAAI,CAAC,OAAO,EAC5B,GAAG,EAAE,IAAI,CAAC,GAAG,EACb,GAAG,EAAE,IAAI,CAAC,GAAG,KACT,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EACnC,YAAY,EAAE,IAAI,CAAC,OAAO,EAC1B,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,aAAa,EACpC,QAAQ,EAAE,KAAK,KAAK,IAAI,KACpB,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,kBAAkB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EACjI,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAC1B,EACF,iBAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,wBAAwB,gBAAa,UAAU,IAAI,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,YAChJ,KAAC,CAAC,IAAC,IAAI,EAAE,EAAE,GAAI,GACR,KAfD,CAAC,CAgBL,CACP,CAAA;oCACH,CAAC,CAAC,EACD,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CACrB,iBAAO,SAAS,EAAC,qBAAqB,EAAC,KAAK,EAAC,eAAe,aAC1D,KAAC,IAAI,IAAC,IAAI,EAAE,EAAE,iBAAc,MAAM,GAAG,EACrC,gCACc,oBAAoB,IAAI,EAAE,EACtC,KAAK,EAAC,EAAE,EACR,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAE,CAAC,OAAO,CAAC,aAE/F,iBAAQ,KAAK,EAAC,EAAE,0BAAc,EAC7B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAClB,kBAAgB,KAAK,EAAE,CAAC,aACrB,cAAc,CAAC,CAAC,CAAE,CAAC,KAAK,QAAI,CAAC,UADnB,CAAC,CAEL,CACV,CAAC,IACK,IACH,CACT,IACG,IACF,IACF,IACE,CACX,CAAA;AACH,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,WAAW,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,UAAU,EAAoB;IACxH,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAA;IAChD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAkB,KAAK,CAAC,IAAI,IAAI,MAAM,CAAC,CAAA;IACvE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAa,KAAK,CAAC,IAAI,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAA;IACpF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,UAAU;YAAE,OAAM;QACvB,IAAI,CAAC;YACH,YAAY,CAAC,OAAO,CAAC,gBAAgB,UAAU,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAkB,CAAC,CAAC,CAAA;QACpG,CAAC;QAAC,MAAM,CAAC;YACP,wEAAwE;QAC1E,CAAC;IACH,CAAC,EAAE,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;IAC5B,MAAM,MAAM,GAAG,OAAO,CAAC,GAA8C,EAAE;QACrE,IAAI,CAAC;YACH,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAA;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,EAAE,KAAK,EAAE,GAAG,YAAY,kBAAkB,CAAC,CAAC,CAAC,iBAAiB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAA;QACpG,CAAC;IACH,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IACV,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAsB,GAAG,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,CAAA;IACxE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAsB,GAAG,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,CAAA;IACtE,MAAM,IAAI,GAAG,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;IAClD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAA;IAE3D,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,IAAI;YAAE,gBAAgB,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAA;IAClD,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAA;IAEf,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,CACL,cAAK,SAAS,EAAE,gBAAgB,SAAS,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,YACtD,YAAG,SAAS,EAAC,qBAAqB,EAAC,IAAI,EAAC,OAAO,YAC5C,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GACpC,GACA,CACP,CAAA;IACH,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,GAAwB,EAAE,CAAS,EAAE,EAAE;QACrD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;QACzB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QAChC,OAAO,IAAI,CAAA;IACb,CAAC,CAAA;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,CAAA;IAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAA;IAC/B,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAE1E,MAAM,WAAW,GAAG,CAChB,eAAK,SAAS,EAAC,sBAAsB,EAAC,IAAI,EAAC,OAAO,gBAAY,QAAQ,aACpE,gBAAM,SAAS,EAAC,qBAAqB,uBAEnC,sCAAsB,IACjB,EACP,kBAAQ,SAAS,EAAC,8BAA8B,gBAAY,OAAO,aAChE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,EAClE,kCAAkB,IACX,EACT,KAAC,IAAI,IACH,IAAI,EAAC,IAAI,EACT,KAAK,EAAC,OAAO,EACb,KAAK,EAAE,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAC9C,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,CAAC,EACN,YAAY,EAAE,GAAG,EACjB,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,EAC3C,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAC5C,EACD,MAAM,IAAI,CACT,KAAC,IAAI,IACH,IAAI,EAAC,IAAI,EACT,KAAK,EAAC,QAAQ,EACd,KAAK,EAAE,QAAQ,IAAI,CAAC,EACpB,GAAG,EAAE,CAAC,EACN,GAAG,EAAE,CAAC,EACN,YAAY,EAAE,CAAC,EACf,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,GAC/E,CACH,EACD,gBAAM,SAAS,EAAC,uBAAuB,aACpC,IAAI,CAAC,MAAM,CAAC,MAAM,YAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAC7D,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAC1E,EACP,cAAK,SAAS,EAAC,oBAAoB,EAAC,IAAI,EAAC,YAAY,gBAAY,QAAQ,YACrE,CAAC,MAAM,EAAE,MAAM,CAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACtC,iBAAgB,IAAI,EAAC,QAAQ,EAAC,IAAI,EAAC,OAAO,kBAAe,IAAI,KAAK,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,YAC3F,CAAC,IADS,CAAC,CAEL,CACV,CAAC,GACE,IACF,CACT,CAAA;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtC,GAAG,EAAE,SAAS,CAAC,CAAC,KAAK,EAAE;QACvB,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;QACnB,IAAI,EAAE,CAAC;QACP,IAAI,EAAE,CACJ,KAAC,MAAM,IACL,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,CAAC,EACR,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GACtG,CACH;KACF,CAAC,CAAC,CAAA;IAEH,OAAO,CACL,eAAK,SAAS,EAAE,gBAAgB,SAAS,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,eAAa,IAAI,aACtE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CACjB,KAAC,QAAQ,IAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,GAAG,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,GAAI,CAC1I,CAAC,CAAC,CAAC,CACF,8BACG,WAAW,EACX,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAClB,wBAAkB,CAAC,CAAC,IAAI,IAAd,CAAC,CAAC,GAAG,CAAgB,CAChC,CAAC,IACD,CACJ,EACA,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,YAAG,SAAS,EAAC,qBAAqB,kCAAsB,IACjF,CACP,CAAA;AACH,CAAC;AAED,eAAe,WAAW,CAAA"}
@@ -3,6 +3,8 @@ export type { StrudelPlayerProps } from "./StrudelPlayer.js";
3
3
  export { StrudelRack, STRUDEL_PARAMS, trackName } from "./StrudelRack.js";
4
4
  export type { StrudelRackProps } from "./StrudelRack.js";
5
5
  export { StepGrid } from "./StepGrid.js";
6
+ export { RackGrid } from "./RackGrid.js";
7
+ export type { GridItem, GridLayout, RackGridProps } from "./RackGrid.js";
6
8
  export type { StepGridProps } from "./StepGrid.js";
7
9
  export { Fader, Knob } from "./controls.js";
8
10
  export type { ControlProps } from "./controls.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/strudel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACtE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACxC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,aAAa,GACd,MAAM,UAAU,CAAA;AACjB,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC3E,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAA;AACxD,cAAc,OAAO,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/strudel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACtE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AACrE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACxC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,aAAa,GACd,MAAM,UAAU,CAAA;AACjB,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC3E,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAA;AACxD,cAAc,OAAO,CAAA"}
@@ -1,6 +1,7 @@
1
1
  export { StrudelPlayer } from "./StrudelPlayer.js";
2
2
  export { StrudelRack, STRUDEL_PARAMS, trackName } from "./StrudelRack.js";
3
3
  export { StepGrid } from "./StepGrid.js";
4
+ export { RackGrid } from "./RackGrid.js";
4
5
  export { Fader, Knob } from "./controls.js";
5
6
  export { DEFAULT_SAMPLES, getStrudelSnapshot, playStrudel, stopStrudel, strudelNow, subscribeStrudel, updateStrudel, } from "./engine.js";
6
7
  export { isStrudelFile, isStrudelLanguage } from "./url.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/strudel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE/C,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAEtE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAErC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAExC,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,aAAa,GACd,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAA;AACxD,cAAc,OAAO,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/strudel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE/C,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAEtE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAGrC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAExC,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,aAAa,GACd,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAA;AACxD,cAAc,OAAO,CAAA"}
package/dist/styles.css CHANGED
@@ -1104,6 +1104,116 @@
1104
1104
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.5), 0 3px 5px rgb(0 0 0 / 0.7), 0 0 0 1px rgb(0 0 0 / 0.6);
1105
1105
  }
1106
1106
 
1107
+ .strudel-rack__mode {
1108
+ display: inline-flex;
1109
+ padding: 2px;
1110
+ border-radius: 5px;
1111
+ background: #0a0b0d;
1112
+ box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.9), 0 1px 0 rgb(255 255 255 / 0.08);
1113
+ }
1114
+
1115
+ .strudel-rack__mode button {
1116
+ padding: 3px 9px;
1117
+ border: 0;
1118
+ border-radius: 3px;
1119
+ background: transparent;
1120
+ color: #8b9099;
1121
+ font: inherit;
1122
+ font-size: 9px;
1123
+ font-weight: 700;
1124
+ letter-spacing: 0.16em;
1125
+ text-transform: uppercase;
1126
+ cursor: pointer;
1127
+ }
1128
+
1129
+ .strudel-rack__mode button[aria-checked="true"] {
1130
+ background: linear-gradient(180deg, #4a4e56, #2b2e34);
1131
+ color: var(--strudel-accent);
1132
+ box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.18);
1133
+ text-shadow: 0 0 6px color-mix(in srgb, var(--strudel-accent) 60%, transparent);
1134
+ }
1135
+
1136
+ /* Grid mode: a Eurorack-style case — rails behind, modules dropped in a masonry grid. */
1137
+ .strudel-rack[data-mode="grid"] {
1138
+ padding-block: 14px;
1139
+ }
1140
+
1141
+ .strudel-grid {
1142
+ display: grid;
1143
+ grid-auto-flow: row dense;
1144
+ }
1145
+
1146
+ .strudel-grid__item {
1147
+ position: relative;
1148
+ min-width: 0;
1149
+ transition: transform 0s;
1150
+ }
1151
+
1152
+ .strudel-grid__item[data-dragging] {
1153
+ z-index: 5;
1154
+ filter: drop-shadow(0 18px 22px rgb(0 0 0 / 0.6));
1155
+ cursor: grabbing;
1156
+ }
1157
+
1158
+ .strudel-grid__content {
1159
+ display: flex;
1160
+ flex-direction: column;
1161
+ }
1162
+
1163
+ .strudel-grid__content > * {
1164
+ flex: 1;
1165
+ }
1166
+
1167
+ .strudel-grid__content > .strudel-rack__master {
1168
+ flex-wrap: wrap;
1169
+ }
1170
+
1171
+ /* The grip: an invisible handle over the module's title (left of its pads). */
1172
+ .strudel-grid__grip {
1173
+ position: absolute;
1174
+ top: 0;
1175
+ left: 0;
1176
+ width: calc(100% - 84px);
1177
+ height: 34px;
1178
+ padding: 0;
1179
+ border: 0;
1180
+ border-radius: 6px 0 0 0;
1181
+ background: transparent;
1182
+ cursor: grab;
1183
+ touch-action: none;
1184
+ }
1185
+
1186
+ .strudel-grid__item[data-grid-key="master"] .strudel-grid__grip {
1187
+ width: 140px;
1188
+ height: 100%;
1189
+ }
1190
+
1191
+ .strudel-grid__grip:focus-visible,
1192
+ .strudel-grid__corner:focus-visible {
1193
+ outline: 2px solid var(--strudel-accent);
1194
+ outline-offset: -2px;
1195
+ }
1196
+
1197
+ /* The corner: three engraved ribs. */
1198
+ .strudel-grid__corner {
1199
+ position: absolute;
1200
+ right: 0;
1201
+ bottom: 0;
1202
+ width: 18px;
1203
+ height: 18px;
1204
+ padding: 0;
1205
+ border: 0;
1206
+ border-radius: 0 0 6px 0;
1207
+ background: linear-gradient(135deg, transparent 0 45%, #7d828b 45% 52%, transparent 52% 62%, #7d828b 62% 69%, transparent 69% 79%, #7d828b 79% 86%, transparent 86%);
1208
+ cursor: nwse-resize;
1209
+ touch-action: none;
1210
+ opacity: 0.7;
1211
+ }
1212
+
1213
+ .strudel-grid__item:hover .strudel-grid__corner {
1214
+ opacity: 1;
1215
+ }
1216
+
1107
1217
  /* Steps: TR-style keys that light up. */
1108
1218
  .strudel-steps {
1109
1219
  display: flex;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brett_lamy/docstream",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "GitBook-aware readonly markdown and AI stream renderer.",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -0,0 +1,231 @@
1
+ /* A masonry grid of modules you can rearrange and resize. Columns follow the container's width; every module spans
2
+ some of them and as many 8px rows as its content (or the height you dragged it to) needs, and `dense` flow packs
3
+ the gaps. Drag a module's grip to move it (others reflow under the pointer); drag its corner to resize. Both
4
+ handles are keyboard-operable: arrows move or resize, Home/End move to the ends. */
5
+ import { useEffect, useLayoutEffect, useRef, useState, type KeyboardEvent, type PointerEvent, type ReactNode } from "react"
6
+
7
+ export interface GridItem {
8
+ key: string
9
+ label: string
10
+ node: ReactNode
11
+ /** Default width in twelfths of the grid (12 = full width). */
12
+ span?: number
13
+ }
14
+
15
+ export interface GridLayout {
16
+ order: string[]
17
+ /** Width in twelfths, and an optional minimum height in px, per item key. */
18
+ sizes: Record<string, { w: number; h?: number }>
19
+ }
20
+
21
+ export interface RackGridProps {
22
+ items: GridItem[]
23
+ layout: GridLayout
24
+ onLayoutChange: (layout: GridLayout) => void
25
+ }
26
+
27
+ const ROW = 8
28
+ const GAP = 10
29
+
30
+ /** Items in layout order: known keys first, new ones appended. */
31
+ function ordered(items: GridItem[], order: string[]): GridItem[] {
32
+ const byKey = new Map(items.map((i) => [i.key, i]))
33
+ const out = order.map((k) => byKey.get(k)).filter((i): i is GridItem => !!i)
34
+ for (const i of items) if (!order.includes(i.key)) out.push(i)
35
+ return out
36
+ }
37
+
38
+ export function RackGrid({ items, layout, onLayoutChange }: RackGridProps) {
39
+ const gridRef = useRef<HTMLDivElement>(null)
40
+ const [cols, setCols] = useState(12)
41
+ const [heights, setHeights] = useState<Record<string, number>>({})
42
+ const [dragging, setDragging] = useState<string | null>(null)
43
+ const drag = useRef<{ key: string; dx: number; dy: number; x: number; y: number } | null>(null)
44
+ const elements = useRef(new Map<string, HTMLDivElement>())
45
+ const list = ordered(items, layout.order)
46
+ const keys = list.map((i) => i.key)
47
+ const layoutRef = useRef(layout)
48
+ layoutRef.current = layout
49
+
50
+ // Columns: one per ~84px of width, at most 12 — spans are stored in twelfths and scaled.
51
+ useLayoutEffect(() => {
52
+ const grid = gridRef.current
53
+ if (!grid) return
54
+ const measure = () => setCols(Math.max(2, Math.min(12, Math.floor((grid.clientWidth + GAP) / 84))))
55
+ measure()
56
+ const ro = new ResizeObserver(measure)
57
+ ro.observe(grid)
58
+ return () => ro.disconnect()
59
+ }, [])
60
+
61
+ // Masonry: each module spans as many rows as its content is tall.
62
+ useEffect(() => {
63
+ const ro = new ResizeObserver((entries) => {
64
+ setHeights((prev) => {
65
+ let next = prev
66
+ for (const e of entries) {
67
+ const key = (e.target as HTMLElement).dataset.content!
68
+ const h = Math.ceil((e.target as HTMLElement).offsetHeight)
69
+ if (prev[key] !== h) next = { ...next, [key]: h }
70
+ }
71
+ return next
72
+ })
73
+ })
74
+ elements.current.forEach((el) => {
75
+ const content = el.querySelector<HTMLElement>("[data-content]")
76
+ if (content) ro.observe(content)
77
+ })
78
+ return () => ro.disconnect()
79
+ }, [keys.join("|")])
80
+
81
+ const span = (item: GridItem) => {
82
+ const w = layout.sizes[item.key]?.w ?? item.span ?? 6
83
+ return Math.max(1, Math.min(cols, Math.round((w / 12) * cols)))
84
+ }
85
+ const rows = (item: GridItem) => {
86
+ const h = Math.max(heights[item.key] ?? 120, layout.sizes[item.key]?.h ?? 0)
87
+ return Math.ceil((h + GAP) / (ROW + GAP))
88
+ }
89
+ const setSize = (key: string, size: { w?: number; h?: number }) => {
90
+ const cur = layoutRef.current
91
+ onLayoutChange({ order: keys, sizes: { ...cur.sizes, [key]: { ...cur.sizes[key], w: cur.sizes[key]?.w ?? 6, ...size } } })
92
+ }
93
+ const move = (key: string, to: number) => {
94
+ const from = keys.indexOf(key)
95
+ const next = keys.filter((k) => k !== key)
96
+ next.splice(Math.max(0, Math.min(next.length, to)), 0, key)
97
+ if (from !== next.indexOf(key)) onLayoutChange({ ...layoutRef.current, order: next })
98
+ }
99
+
100
+ // Moving: the module follows the pointer; hovering another module takes its place.
101
+ const place = (key: string, x: number, y: number) => {
102
+ const el = elements.current.get(key)
103
+ const grid = gridRef.current
104
+ const d = drag.current
105
+ if (!el || !grid || !d) return
106
+ const box = grid.getBoundingClientRect()
107
+ el.style.transform = `translate(${x - d.dx - box.left - el.offsetLeft}px, ${y - d.dy - box.top - el.offsetTop}px)`
108
+ }
109
+ const onGripDown = (key: string) => (e: PointerEvent<HTMLElement>) => {
110
+ if (e.button !== 0) return
111
+ const el = elements.current.get(key)!
112
+ const r = el.getBoundingClientRect()
113
+ e.currentTarget.setPointerCapture(e.pointerId)
114
+ drag.current = { key, dx: e.clientX - r.left, dy: e.clientY - r.top, x: e.clientX, y: e.clientY }
115
+ setDragging(key)
116
+ }
117
+ const onGripMove = (e: PointerEvent<HTMLElement>) => {
118
+ const d = drag.current
119
+ if (!d) return
120
+ d.x = e.clientX
121
+ d.y = e.clientY
122
+ place(d.key, e.clientX, e.clientY)
123
+ const dragged = elements.current.get(d.key)!
124
+ dragged.style.pointerEvents = "none"
125
+ const under = document.elementFromPoint(e.clientX, e.clientY)?.closest<HTMLElement>("[data-grid-key]")
126
+ dragged.style.pointerEvents = ""
127
+ const target = under?.dataset.gridKey
128
+ if (target && target !== d.key) move(d.key, keys.indexOf(target))
129
+ }
130
+ const onGripUp = () => {
131
+ const d = drag.current
132
+ if (!d) return
133
+ const el = elements.current.get(d.key)
134
+ if (el) el.style.transform = ""
135
+ drag.current = null
136
+ setDragging(null)
137
+ }
138
+ // After a reorder the module's slot moved: keep it under the pointer.
139
+ useLayoutEffect(() => {
140
+ const d = drag.current
141
+ if (d) place(d.key, d.x, d.y)
142
+ })
143
+
144
+ const onGripKey = (key: string) => (e: KeyboardEvent<HTMLElement>) => {
145
+ const i = keys.indexOf(key)
146
+ const to = { ArrowLeft: i - 1, ArrowUp: i - 1, ArrowRight: i + 1, ArrowDown: i + 1, Home: 0, End: keys.length - 1 }[e.key]
147
+ if (to === undefined) return
148
+ e.preventDefault()
149
+ move(key, to)
150
+ }
151
+
152
+ // Resizing: the corner sets the width in columns and a minimum height.
153
+ const resize = useRef<{ key: string; left: number; top: number } | null>(null)
154
+ const onCornerDown = (key: string) => (e: PointerEvent<HTMLElement>) => {
155
+ const r = elements.current.get(key)!.getBoundingClientRect()
156
+ e.currentTarget.setPointerCapture(e.pointerId)
157
+ resize.current = { key, left: r.left, top: r.top }
158
+ }
159
+ const onCornerMove = (e: PointerEvent<HTMLElement>) => {
160
+ const r = resize.current
161
+ const grid = gridRef.current
162
+ if (!r || !grid) return
163
+ const colWidth = (grid.clientWidth - GAP * (cols - 1)) / cols
164
+ const c = Math.max(1, Math.min(cols, Math.round((e.clientX - r.left + GAP) / (colWidth + GAP))))
165
+ setSize(r.key, { w: Math.round((c / cols) * 12 * 100) / 100, h: Math.max(60, Math.round(e.clientY - r.top)) })
166
+ }
167
+ const onCornerUp = () => {
168
+ resize.current = null
169
+ }
170
+ const onCornerKey = (item: GridItem) => (e: KeyboardEvent<HTMLElement>) => {
171
+ const w = layout.sizes[item.key]?.w ?? item.span ?? 6
172
+ const h = layout.sizes[item.key]?.h ?? heights[item.key] ?? 120
173
+ const step = 12 / cols
174
+ const next = {
175
+ ArrowRight: { w: Math.min(12, w + step) },
176
+ ArrowLeft: { w: Math.max(step, w - step) },
177
+ ArrowDown: { h: h + 24 },
178
+ ArrowUp: { h: Math.max(0, h - 24) },
179
+ }[e.key]
180
+ if (!next) return
181
+ e.preventDefault()
182
+ setSize(item.key, next)
183
+ }
184
+
185
+ return (
186
+ <div ref={gridRef} className="strudel-grid" style={{ gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`, gridAutoRows: ROW, rowGap: GAP, columnGap: GAP }}>
187
+ {list.map((item) => {
188
+ const h = layout.sizes[item.key]?.h
189
+ return (
190
+ <div
191
+ key={item.key}
192
+ ref={(el) => {
193
+ if (el) elements.current.set(item.key, el)
194
+ else elements.current.delete(item.key)
195
+ }}
196
+ className="strudel-grid__item"
197
+ data-grid-key={item.key}
198
+ data-dragging={dragging === item.key || undefined}
199
+ style={{ gridColumn: `span ${span(item)}`, gridRow: `span ${rows(item)}` }}
200
+ >
201
+ <div data-content={item.key} className="strudel-grid__content" style={h ? { minHeight: h } : undefined}>
202
+ {item.node}
203
+ </div>
204
+ <button
205
+ type="button"
206
+ className="strudel-grid__grip"
207
+ aria-label={`Move ${item.label}`}
208
+ title="Drag to move (arrow keys too)"
209
+ onPointerDown={onGripDown(item.key)}
210
+ onPointerMove={onGripMove}
211
+ onPointerUp={onGripUp}
212
+ onPointerCancel={onGripUp}
213
+ onKeyDown={onGripKey(item.key)}
214
+ />
215
+ <button
216
+ type="button"
217
+ className="strudel-grid__corner"
218
+ aria-label={`Resize ${item.label}`}
219
+ title="Drag to resize (arrow keys too)"
220
+ onPointerDown={onCornerDown(item.key)}
221
+ onPointerMove={onCornerMove}
222
+ onPointerUp={onCornerUp}
223
+ onPointerCancel={onCornerUp}
224
+ onKeyDown={onCornerKey(item)}
225
+ />
226
+ </div>
227
+ )
228
+ })}
229
+ </div>
230
+ )
231
+ }
@@ -9,6 +9,7 @@ import { findCall, parseStrudel, StrudelSyntaxError, type StrudelArg, type Strud
9
9
  import { formatNumber, isAudible, mixCode, removeMethod, setMethod, setMiniAtom, setMiniSource, setTempo, type StrudelMix } from "./ast/edit"
10
10
  import { Fader, Knob, defaultFormat } from "./controls"
11
11
  import { StepGrid } from "./StepGrid"
12
+ import { RackGrid, type GridLayout } from "./RackGrid"
12
13
 
13
14
  export interface StrudelRackProps {
14
15
  code: string
@@ -16,6 +17,24 @@ export interface StrudelRackProps {
16
17
  /** The code to play for the current mute/solo mix (the written code with silenced tracks). */
17
18
  onPlayableChange?: (code: string) => void
18
19
  className?: string
20
+ /** "rack": modules stacked full width. "grid": a masonry grid you drag and resize. Defaults to "rack". */
21
+ layout?: "rack" | "grid"
22
+ /** Remember the layout (mode, order and sizes) in localStorage under this key. */
23
+ persistKey?: string
24
+ }
25
+
26
+ interface Saved {
27
+ mode: "rack" | "grid"
28
+ grid: GridLayout
29
+ }
30
+
31
+ function load(key: string | undefined): Partial<Saved> {
32
+ if (!key) return {}
33
+ try {
34
+ return JSON.parse(localStorage.getItem(`strudel-rack:${key}`) ?? "{}") as Partial<Saved>
35
+ } catch {
36
+ return {}
37
+ }
19
38
  }
20
39
 
21
40
  interface Param {
@@ -230,7 +249,18 @@ function Device({
230
249
  }
231
250
 
232
251
  /** Equipment generated from Strudel code. Controlled: `code` in, edited code out through `onChange`. */
233
- export function StrudelRack({ code, onChange, onPlayableChange, className }: StrudelRackProps) {
252
+ export function StrudelRack({ code, onChange, onPlayableChange, className, layout = "rack", persistKey }: StrudelRackProps) {
253
+ const [saved] = useState(() => load(persistKey))
254
+ const [mode, setMode] = useState<"rack" | "grid">(saved.mode ?? layout)
255
+ const [grid, setGrid] = useState<GridLayout>(saved.grid ?? { order: [], sizes: {} })
256
+ useEffect(() => {
257
+ if (!persistKey) return
258
+ try {
259
+ localStorage.setItem(`strudel-rack:${persistKey}`, JSON.stringify({ mode, grid } satisfies Saved))
260
+ } catch {
261
+ // Storage unavailable (private mode): the layout just isn't remembered.
262
+ }
263
+ }, [persistKey, mode, grid])
234
264
  const parsed = useMemo((): { song: StrudelSong } | { error: string } => {
235
265
  try {
236
266
  return { song: parseStrudel(code) }
@@ -266,8 +296,7 @@ export function StrudelRack({ code, onChange, onPlayableChange, className }: Str
266
296
  const master = song.masterChain
267
297
  const postgain = master ? firstNumber(findCall(master, "postgain")) : null
268
298
 
269
- return (
270
- <div className={`strudel-rack ${className ?? ""}`.trim()}>
299
+ const masterStrip = (
271
300
  <div className="strudel-rack__master" role="group" aria-label="Master">
272
301
  <span className="strudel-rack__title">
273
302
  Master
@@ -303,18 +332,43 @@ export function StrudelRack({ code, onChange, onPlayableChange, className }: Str
303
332
  {song.tracks.length} track{song.tracks.length === 1 ? "" : "s"}
304
333
  {song.layout === "stack" ? " · stack" : song.layout === "labels" ? " · $:" : ""}
305
334
  </span>
335
+ <div className="strudel-rack__mode" role="radiogroup" aria-label="Layout">
336
+ {(["rack", "grid"] as const).map((m) => (
337
+ <button key={m} type="button" role="radio" aria-checked={mode === m} onClick={() => setMode(m)}>
338
+ {m}
339
+ </button>
340
+ ))}
341
+ </div>
306
342
  </div>
343
+ )
344
+ const devices = song.tracks.map((t) => ({
345
+ key: `track-${t.index}`,
346
+ label: trackName(t),
347
+ span: 6,
348
+ node: (
349
+ <Device
350
+ song={song}
351
+ track={t}
352
+ mix={mix}
353
+ onChange={onChange}
354
+ onMix={(kind) => (kind === "mute" ? setMuted(toggle(muted, t.index)) : setSolo(toggle(solo, t.index)))}
355
+ />
356
+ ),
357
+ }))
358
+
359
+ return (
360
+ <div className={`strudel-rack ${className ?? ""}`.trim()} data-mode={mode}>
361
+ {mode === "grid" ? (
362
+ <RackGrid items={[{ key: "master", label: "Master", span: 12, node: masterStrip }, ...devices]} layout={grid} onLayoutChange={setGrid} />
363
+ ) : (
364
+ <>
365
+ {masterStrip}
366
+ {devices.map((d) => (
367
+ <div key={d.key}>{d.node}</div>
368
+ ))}
369
+ </>
370
+ )}
307
371
  {song.tracks.length === 0 && <p className="strudel-rack__error">No pattern found.</p>}
308
- {song.tracks.map((t) => (
309
- <Device
310
- key={t.index}
311
- song={song}
312
- track={t}
313
- mix={mix}
314
- onChange={onChange}
315
- onMix={(kind) => (kind === "mute" ? setMuted(toggle(muted, t.index)) : setSolo(toggle(solo, t.index)))}
316
- />
317
- ))}
318
372
  </div>
319
373
  )
320
374
  }
@@ -3,6 +3,8 @@ export type { StrudelPlayerProps } from "./StrudelPlayer"
3
3
  export { StrudelRack, STRUDEL_PARAMS, trackName } from "./StrudelRack"
4
4
  export type { StrudelRackProps } from "./StrudelRack"
5
5
  export { StepGrid } from "./StepGrid"
6
+ export { RackGrid } from "./RackGrid"
7
+ export type { GridItem, GridLayout, RackGridProps } from "./RackGrid"
6
8
  export type { StepGridProps } from "./StepGrid"
7
9
  export { Fader, Knob } from "./controls"
8
10
  export type { ControlProps } from "./controls"
package/src/styles.css CHANGED
@@ -1104,6 +1104,116 @@
1104
1104
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.5), 0 3px 5px rgb(0 0 0 / 0.7), 0 0 0 1px rgb(0 0 0 / 0.6);
1105
1105
  }
1106
1106
 
1107
+ .strudel-rack__mode {
1108
+ display: inline-flex;
1109
+ padding: 2px;
1110
+ border-radius: 5px;
1111
+ background: #0a0b0d;
1112
+ box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.9), 0 1px 0 rgb(255 255 255 / 0.08);
1113
+ }
1114
+
1115
+ .strudel-rack__mode button {
1116
+ padding: 3px 9px;
1117
+ border: 0;
1118
+ border-radius: 3px;
1119
+ background: transparent;
1120
+ color: #8b9099;
1121
+ font: inherit;
1122
+ font-size: 9px;
1123
+ font-weight: 700;
1124
+ letter-spacing: 0.16em;
1125
+ text-transform: uppercase;
1126
+ cursor: pointer;
1127
+ }
1128
+
1129
+ .strudel-rack__mode button[aria-checked="true"] {
1130
+ background: linear-gradient(180deg, #4a4e56, #2b2e34);
1131
+ color: var(--strudel-accent);
1132
+ box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.18);
1133
+ text-shadow: 0 0 6px color-mix(in srgb, var(--strudel-accent) 60%, transparent);
1134
+ }
1135
+
1136
+ /* Grid mode: a Eurorack-style case — rails behind, modules dropped in a masonry grid. */
1137
+ .strudel-rack[data-mode="grid"] {
1138
+ padding-block: 14px;
1139
+ }
1140
+
1141
+ .strudel-grid {
1142
+ display: grid;
1143
+ grid-auto-flow: row dense;
1144
+ }
1145
+
1146
+ .strudel-grid__item {
1147
+ position: relative;
1148
+ min-width: 0;
1149
+ transition: transform 0s;
1150
+ }
1151
+
1152
+ .strudel-grid__item[data-dragging] {
1153
+ z-index: 5;
1154
+ filter: drop-shadow(0 18px 22px rgb(0 0 0 / 0.6));
1155
+ cursor: grabbing;
1156
+ }
1157
+
1158
+ .strudel-grid__content {
1159
+ display: flex;
1160
+ flex-direction: column;
1161
+ }
1162
+
1163
+ .strudel-grid__content > * {
1164
+ flex: 1;
1165
+ }
1166
+
1167
+ .strudel-grid__content > .strudel-rack__master {
1168
+ flex-wrap: wrap;
1169
+ }
1170
+
1171
+ /* The grip: an invisible handle over the module's title (left of its pads). */
1172
+ .strudel-grid__grip {
1173
+ position: absolute;
1174
+ top: 0;
1175
+ left: 0;
1176
+ width: calc(100% - 84px);
1177
+ height: 34px;
1178
+ padding: 0;
1179
+ border: 0;
1180
+ border-radius: 6px 0 0 0;
1181
+ background: transparent;
1182
+ cursor: grab;
1183
+ touch-action: none;
1184
+ }
1185
+
1186
+ .strudel-grid__item[data-grid-key="master"] .strudel-grid__grip {
1187
+ width: 140px;
1188
+ height: 100%;
1189
+ }
1190
+
1191
+ .strudel-grid__grip:focus-visible,
1192
+ .strudel-grid__corner:focus-visible {
1193
+ outline: 2px solid var(--strudel-accent);
1194
+ outline-offset: -2px;
1195
+ }
1196
+
1197
+ /* The corner: three engraved ribs. */
1198
+ .strudel-grid__corner {
1199
+ position: absolute;
1200
+ right: 0;
1201
+ bottom: 0;
1202
+ width: 18px;
1203
+ height: 18px;
1204
+ padding: 0;
1205
+ border: 0;
1206
+ border-radius: 0 0 6px 0;
1207
+ background: linear-gradient(135deg, transparent 0 45%, #7d828b 45% 52%, transparent 52% 62%, #7d828b 62% 69%, transparent 69% 79%, #7d828b 79% 86%, transparent 86%);
1208
+ cursor: nwse-resize;
1209
+ touch-action: none;
1210
+ opacity: 0.7;
1211
+ }
1212
+
1213
+ .strudel-grid__item:hover .strudel-grid__corner {
1214
+ opacity: 1;
1215
+ }
1216
+
1107
1217
  /* Steps: TR-style keys that light up. */
1108
1218
  .strudel-steps {
1109
1219
  display: flex;