simplify widget creation + fix bugs

This commit is contained in:
Felix Roos 2024-03-15 09:50:17 +01:00
parent 6dce9d5deb
commit 8742d50bad
10 changed files with 58 additions and 62 deletions

View File

@ -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 {
constructor(col, type) {
super();
@ -64,11 +70,7 @@ export class BlockWidget extends WidgetType {
}
toDOM() {
const id = getWidgetID(this.col); // matches id generated in transpiler
let el = document.getElementById(id);
if (!el) {
el = document.createElement(this.type);
el.id = id;
}
const el = widgetElements[id];
return el;
}
ignoreEvent(e) {

View File

@ -3,16 +3,9 @@ import { parse } from 'acorn';
import escodegen from 'escodegen';
import { walk } from 'estree-walker';
let widgetComponents = {};
// this function allows registering a pattern method name and component name
// e.g. register('claviature', 'strudel-claviature')
// .. 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;
let widgetMethods = [];
export function registerWidgetType(type) {
widgetMethods.push(type);
}
export function transpiler(input, options = {}) {
@ -63,7 +56,7 @@ export function transpiler(input, options = {}) {
emitWidgets &&
widgets.push({
to: node.end,
type: widgetComponents[node.callee.property.name],
type: node.callee.property.name,
});
return this.replace(widgetWithLocation(node));
}
@ -131,7 +124,7 @@ function isSliderFunction(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) {

View File

@ -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;
}

View File

@ -2,8 +2,7 @@ import { For } from 'solid-js';
import { customElement } from 'solid-element';
import { getClaviature } from 'claviature';
import { Dynamic } from 'solid-js/web';
import { Pattern } from '@strudel/core';
import { registerWidget } from '@strudel/transpiler';
import { registerWidget } from './registry.mjs';
let defaultOptions = {
range: ['A1', 'C6'],
@ -31,12 +30,11 @@ customElement('strudel-claviature', { options: JSON.stringify(defaultOptions) },
);
});
registerWidget('claviature', 'strudel-claviature');
Pattern.prototype.claviature = function (id, options = {}) {
return this.onFrame((haps) => {
registerWidget('claviature', (id, options = {}, pat) => {
const el = document.getElementById(id) || document.createElement('strudel-claviature');
setWidget(id, el);
return pat.onFrame(id, (haps) => {
const colorize = haps.map((h) => ({ keys: [h.value.note], color: h.context?.color || 'steelblue' }));
let el = document.getElementById(id);
el?.setAttribute(
'options',
JSON.stringify({
@ -46,4 +44,4 @@ Pattern.prototype.claviature = function (id, options = {}) {
}),
);
});
};
});

View File

@ -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;
};

View 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 });
});

View File

@ -1,3 +1,3 @@
export * from './Claviature.jsx';
export * from './Pianoroll.jsx';
export * from './Canvas.jsx';
export * from './canvas.mjs';
export * from './registry.mjs';

View File

@ -30,6 +30,7 @@
"@strudel/core": "workspace:*",
"@strudel/transpiler": "workspace:*",
"@strudel/draw": "workspace:*",
"@strudel/codemirror": "workspace:*",
"claviature": "^0.1.0",
"solid-element": "^1.8.0",
"solid-js": "^1.8.15",

View 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
View File

@ -490,6 +490,9 @@ importers:
packages/widgets:
dependencies:
'@strudel/codemirror':
specifier: workspace:*
version: link:../codemirror
'@strudel/core':
specifier: workspace:*
version: link:../core