simplify widget creation + fix bugs
This commit is contained in:
parent
6dce9d5deb
commit
8742d50bad
10 changed files with 58 additions and 62 deletions
|
|
@ -53,6 +53,12 @@ const widgetField = StateField.define(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const widgetElements = {};
|
||||||
|
export function setWidget(id, el) {
|
||||||
|
widgetElements[id] = el;
|
||||||
|
el.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
export class BlockWidget extends WidgetType {
|
export class BlockWidget extends WidgetType {
|
||||||
constructor(col, type) {
|
constructor(col, type) {
|
||||||
super();
|
super();
|
||||||
|
|
@ -64,11 +70,7 @@ export class BlockWidget extends WidgetType {
|
||||||
}
|
}
|
||||||
toDOM() {
|
toDOM() {
|
||||||
const id = getWidgetID(this.col); // matches id generated in transpiler
|
const id = getWidgetID(this.col); // matches id generated in transpiler
|
||||||
let el = document.getElementById(id);
|
const el = widgetElements[id];
|
||||||
if (!el) {
|
|
||||||
el = document.createElement(this.type);
|
|
||||||
el.id = id;
|
|
||||||
}
|
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
ignoreEvent(e) {
|
ignoreEvent(e) {
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,9 @@ import { parse } from 'acorn';
|
||||||
import escodegen from 'escodegen';
|
import escodegen from 'escodegen';
|
||||||
import { walk } from 'estree-walker';
|
import { walk } from 'estree-walker';
|
||||||
|
|
||||||
let widgetComponents = {};
|
let widgetMethods = [];
|
||||||
// this function allows registering a pattern method name and component name
|
export function registerWidgetType(type) {
|
||||||
// e.g. register('claviature', 'strudel-claviature')
|
widgetMethods.push(type);
|
||||||
// .. will map the Pattern method 'claviature' to the web component 'strudel-claviature'
|
|
||||||
// the transpiler will turn .claviature(...args) into .claviature(id, ...args)
|
|
||||||
// the widgetPlugin of @strudel/codemirror will automatically create an instance of 'strudel-claviature'
|
|
||||||
// .. so you only have to implement the actual .claviature method (or what you've called it..)
|
|
||||||
|
|
||||||
export function registerWidget(name, tagName) {
|
|
||||||
widgetComponents[name] = tagName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function transpiler(input, options = {}) {
|
export function transpiler(input, options = {}) {
|
||||||
|
|
@ -63,7 +56,7 @@ export function transpiler(input, options = {}) {
|
||||||
emitWidgets &&
|
emitWidgets &&
|
||||||
widgets.push({
|
widgets.push({
|
||||||
to: node.end,
|
to: node.end,
|
||||||
type: widgetComponents[node.callee.property.name],
|
type: node.callee.property.name,
|
||||||
});
|
});
|
||||||
return this.replace(widgetWithLocation(node));
|
return this.replace(widgetWithLocation(node));
|
||||||
}
|
}
|
||||||
|
|
@ -131,7 +124,7 @@ function isSliderFunction(node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isWidgetMethod(node) {
|
function isWidgetMethod(node) {
|
||||||
return node.type === 'CallExpression' && Object.keys(widgetComponents).includes(node.callee.property?.name);
|
return node.type === 'CallExpression' && widgetMethods.includes(node.callee.property?.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sliderWithLocation(node) {
|
function sliderWithLocation(node) {
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
import { customElement } from 'solid-element';
|
|
||||||
|
|
||||||
customElement('strudel-canvas', {}, () => {
|
|
||||||
return <canvas width={300} height={200} />;
|
|
||||||
});
|
|
||||||
|
|
||||||
export function getWidgetDrawContext(id, options) {
|
|
||||||
let el = document.getElementById(id);
|
|
||||||
if (!el) {
|
|
||||||
console.warn(`widget with id ${id} not found in the DOM`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { width = 300, height = 100, pixelRatio = window.devicePixelRatio } = options || {};
|
|
||||||
const canvas = el?.shadowRoot.firstChild;
|
|
||||||
canvas.width = width * pixelRatio;
|
|
||||||
canvas.height = height * pixelRatio;
|
|
||||||
canvas.style.width = width + 'px';
|
|
||||||
canvas.style.height = height + 'px';
|
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
|
|
@ -2,8 +2,7 @@ import { For } from 'solid-js';
|
||||||
import { customElement } from 'solid-element';
|
import { customElement } from 'solid-element';
|
||||||
import { getClaviature } from 'claviature';
|
import { getClaviature } from 'claviature';
|
||||||
import { Dynamic } from 'solid-js/web';
|
import { Dynamic } from 'solid-js/web';
|
||||||
import { Pattern } from '@strudel/core';
|
import { registerWidget } from './registry.mjs';
|
||||||
import { registerWidget } from '@strudel/transpiler';
|
|
||||||
|
|
||||||
let defaultOptions = {
|
let defaultOptions = {
|
||||||
range: ['A1', 'C6'],
|
range: ['A1', 'C6'],
|
||||||
|
|
@ -31,12 +30,11 @@ customElement('strudel-claviature', { options: JSON.stringify(defaultOptions) },
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
registerWidget('claviature', 'strudel-claviature');
|
registerWidget('claviature', (id, options = {}, pat) => {
|
||||||
|
const el = document.getElementById(id) || document.createElement('strudel-claviature');
|
||||||
Pattern.prototype.claviature = function (id, options = {}) {
|
setWidget(id, el);
|
||||||
return this.onFrame((haps) => {
|
return pat.onFrame(id, (haps) => {
|
||||||
const colorize = haps.map((h) => ({ keys: [h.value.note], color: h.context?.color || 'steelblue' }));
|
const colorize = haps.map((h) => ({ keys: [h.value.note], color: h.context?.color || 'steelblue' }));
|
||||||
let el = document.getElementById(id);
|
|
||||||
el?.setAttribute(
|
el?.setAttribute(
|
||||||
'options',
|
'options',
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|
@ -46,4 +44,4 @@ Pattern.prototype.claviature = function (id, options = {}) {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import { Pattern } from '@strudel/core';
|
|
||||||
import { registerWidget } from '@strudel/transpiler';
|
|
||||||
import { getWidgetDrawContext } from './Canvas.jsx';
|
|
||||||
|
|
||||||
registerWidget('roll', 'strudel-canvas');
|
|
||||||
|
|
||||||
Pattern.prototype.roll = function (id, options = { fold: 1 }) {
|
|
||||||
// TODO: remove setTimeout...
|
|
||||||
setTimeout(() => {
|
|
||||||
const ctx = getWidgetDrawContext(id, options);
|
|
||||||
this.pianoroll({ ...options, ctx });
|
|
||||||
});
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
23
packages/widgets/canvas.mjs
Normal file
23
packages/widgets/canvas.mjs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { registerWidget } from './registry.mjs';
|
||||||
|
import { setWidget } from '@strudel/codemirror';
|
||||||
|
|
||||||
|
function createCanvasWidget(id, options) {
|
||||||
|
const { width = 300, height = 100, pixelRatio = window.devicePixelRatio } = options || {};
|
||||||
|
let canvas = document.getElementById(id) || document.createElement('canvas');
|
||||||
|
canvas.width = width * pixelRatio;
|
||||||
|
canvas.height = height * pixelRatio;
|
||||||
|
canvas.style.width = width + 'px';
|
||||||
|
canvas.style.height = height + 'px';
|
||||||
|
setWidget(id, canvas);
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerWidget('roll', (id, options = { fold: 1 }, pat) => {
|
||||||
|
const ctx = createCanvasWidget(id, options).getContext('2d');
|
||||||
|
return pat.pianoroll({ ...options, ctx, id });
|
||||||
|
});
|
||||||
|
|
||||||
|
registerWidget('twist', (id, options = {}, pat) => {
|
||||||
|
const ctx = createCanvasWidget(id, options).getContext('2d');
|
||||||
|
return pat.spiral({ ...options, ctx, size: 50, id });
|
||||||
|
});
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
export * from './Claviature.jsx';
|
export * from './Claviature.jsx';
|
||||||
export * from './Pianoroll.jsx';
|
export * from './canvas.mjs';
|
||||||
export * from './Canvas.jsx';
|
export * from './registry.mjs';
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
"@strudel/core": "workspace:*",
|
"@strudel/core": "workspace:*",
|
||||||
"@strudel/transpiler": "workspace:*",
|
"@strudel/transpiler": "workspace:*",
|
||||||
"@strudel/draw": "workspace:*",
|
"@strudel/draw": "workspace:*",
|
||||||
|
"@strudel/codemirror": "workspace:*",
|
||||||
"claviature": "^0.1.0",
|
"claviature": "^0.1.0",
|
||||||
"solid-element": "^1.8.0",
|
"solid-element": "^1.8.0",
|
||||||
"solid-js": "^1.8.15",
|
"solid-js": "^1.8.15",
|
||||||
|
|
|
||||||
11
packages/widgets/registry.mjs
Normal file
11
packages/widgets/registry.mjs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { registerWidgetType } from '@strudel/transpiler';
|
||||||
|
import { Pattern } from '@strudel/core';
|
||||||
|
|
||||||
|
export function registerWidget(type, fn) {
|
||||||
|
registerWidgetType(type);
|
||||||
|
if (fn) {
|
||||||
|
Pattern.prototype[type] = function (id, options = { fold: 1 }) {
|
||||||
|
return fn(id, options, this);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
|
|
@ -490,6 +490,9 @@ importers:
|
||||||
|
|
||||||
packages/widgets:
|
packages/widgets:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@strudel/codemirror':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../codemirror
|
||||||
'@strudel/core':
|
'@strudel/core':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../core
|
version: link:../core
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue