@tschk/moonshine-solid 0.3.7 → 0.4.1

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.
Files changed (2) hide show
  1. package/package.json +4 -4
  2. package/src/index.ts +144 -171
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tschk/moonshine-solid",
3
- "version": "0.3.7",
3
+ "version": "0.4.1",
4
4
  "description": "Solid adapter — moonshine IR bridge + solid-js library re-exports",
5
5
  "license": "ISC",
6
6
  "type": "module",
@@ -14,9 +14,9 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@tschk/crepuscularity-wasm": "^0.1.3",
17
- "@tschk/moonshine": "^0.3.6",
18
- "@tschk/moonshine-framework": "^0.3.6",
19
- "@tschk/crepus-moonshine": "^0.3.6"
17
+ "@tschk/moonshine": "^0.4.1",
18
+ "@tschk/moonshine-framework": "^0.4.1",
19
+ "@tschk/crepus-moonshine": "^0.4.1"
20
20
  },
21
21
  "devDependencies": {
22
22
  "typescript": "7.0.2"
package/src/index.ts CHANGED
@@ -90,184 +90,157 @@ function renderChildren(children: ViewNode[]): JSX.Element[] {
90
90
  return children.map((child) => renderCrepusNodeSolid(child));
91
91
  }
92
92
 
93
- export function renderCrepusNodeSolid(node: ViewNode): JSX.Element {
94
- const cls = classOf(node);
95
-
96
- switch (node.kind) {
97
- case "text":
98
- return el("span", { class: cls }, node.content);
99
-
100
- case "link":
101
- return el(
102
- "a",
103
- { class: cls, href: node.href, target: node.target, rel: node.rel },
104
- ...renderChildren(node.children),
105
- );
106
-
107
- case "stack":
108
- case "scroll":
109
- return el("div", { class: cls }, ...renderChildren(node.children));
110
-
111
- case "dropzone":
112
- return el(
113
- "div",
114
- { class: cls, "aria-label": node.label },
115
- ...renderChildren(node.children),
116
- );
117
-
118
- case "list":
119
- return el(
120
- node.ordered ? "ol" : "ul",
121
- { class: cls },
122
- ...renderChildren(node.children),
123
- );
124
-
125
- case "listItem":
126
- return el("li", { class: cls }, ...renderChildren(node.children));
127
-
128
- case "button":
129
- return el("button", { class: cls, type: "button" }, node.label);
130
-
131
- case "badge":
132
- return el("span", { class: cls, "data-tone": node.tone }, node.label);
133
-
134
- case "divider":
135
- return el("hr", { class: cls });
136
-
137
- case "spacer":
138
- return el("div", { class: cls, "aria-hidden": true });
139
-
140
- case "image":
141
- return el("img", { class: cls, src: node.src, alt: node.alt ?? "" });
142
-
143
- case "webView":
144
- return el("iframe", { class: cls, src: node.src });
145
-
146
- case "toggle":
147
- return el(
148
- "button",
149
- {
150
- class: cls,
151
- type: "button",
152
- role: "switch",
153
- "aria-checked": node.checked,
154
- },
155
- node.label,
156
- );
157
-
158
- case "checkbox":
159
- return el(
160
- "label",
161
- { class: cls },
162
- el("input", {
163
- type: "checkbox",
164
- checked: node.checked,
165
- name: node.bind,
166
- }),
167
- node.label,
168
- );
169
-
170
- case "slider":
171
- return el("input", {
93
+ const RENDERERS: Record<
94
+ string,
95
+ (node: any, cls: string | undefined) => JSX.Element
96
+ > = {
97
+ text: (node, cls) => el("span", { class: cls }, node.content),
98
+ link: (node, cls) =>
99
+ el(
100
+ "a",
101
+ { class: cls, href: node.href, target: node.target, rel: node.rel },
102
+ ...renderChildren(node.children),
103
+ ),
104
+ stack: (node, cls) =>
105
+ el("div", { class: cls }, ...renderChildren(node.children)),
106
+ scroll: (node, cls) =>
107
+ el("div", { class: cls }, ...renderChildren(node.children)),
108
+ dropzone: (node, cls) =>
109
+ el(
110
+ "div",
111
+ { class: cls, "aria-label": node.label },
112
+ ...renderChildren(node.children),
113
+ ),
114
+ list: (node, cls) =>
115
+ el(
116
+ node.ordered ? "ol" : "ul",
117
+ { class: cls },
118
+ ...renderChildren(node.children),
119
+ ),
120
+ listItem: (node, cls) =>
121
+ el("li", { class: cls }, ...renderChildren(node.children)),
122
+ button: (node, cls) =>
123
+ el("button", { class: cls, type: "button" }, node.label),
124
+ badge: (node, cls) =>
125
+ el("span", { class: cls, "data-tone": node.tone }, node.label),
126
+ divider: (node, cls) => el("hr", { class: cls }),
127
+ spacer: (node, cls) => el("div", { class: cls, "aria-hidden": true }),
128
+ image: (node, cls) =>
129
+ el("img", { class: cls, src: node.src, alt: node.alt ?? "" }),
130
+ webView: (node, cls) => el("iframe", { class: cls, src: node.src }),
131
+ toggle: (node, cls) =>
132
+ el(
133
+ "button",
134
+ {
172
135
  class: cls,
173
- type: "range",
174
- value: node.value,
175
- min: node.min,
176
- max: node.max,
177
- step: node.step,
178
- name: node.bind,
179
- });
180
-
181
- case "progress":
182
- return el("progress", { class: cls, value: node.value, max: node.max });
183
-
184
- case "meter":
185
- return el("meter", {
136
+ type: "button",
137
+ role: "switch",
138
+ "aria-checked": node.checked,
139
+ },
140
+ node.label,
141
+ ),
142
+ checkbox: (node, cls) =>
143
+ el(
144
+ "label",
145
+ { class: cls },
146
+ el("input", { type: "checkbox", checked: node.checked, name: node.bind }),
147
+ node.label,
148
+ ),
149
+ slider: (node, cls) =>
150
+ el("input", {
151
+ class: cls,
152
+ type: "range",
153
+ value: node.value,
154
+ min: node.min,
155
+ max: node.max,
156
+ step: node.step,
157
+ name: node.bind,
158
+ }),
159
+ progress: (node, cls) =>
160
+ el("progress", { class: cls, value: node.value, max: node.max }),
161
+ meter: (node, cls) =>
162
+ el("meter", {
163
+ class: cls,
164
+ value: node.value,
165
+ min: node.min,
166
+ max: node.max,
167
+ }),
168
+ input: (node, cls) =>
169
+ el(node.multiline ? "textarea" : "input", {
170
+ class: cls,
171
+ type: node.multiline ? undefined : node.secure ? "password" : "text",
172
+ placeholder: node.placeholder,
173
+ name: node.bind,
174
+ }),
175
+ picker: (node, cls) =>
176
+ el(
177
+ "select",
178
+ { class: cls, name: node.bind },
179
+ ...node.options.map((option: any) =>
180
+ el("option", { value: option.value }, option.label),
181
+ ),
182
+ ),
183
+ filePicker: (node, cls) =>
184
+ el(
185
+ "label",
186
+ { class: cls },
187
+ el("input", {
188
+ type: "file",
189
+ accept: node.accept?.join(","),
190
+ multiple: node.multiple,
191
+ }),
192
+ node.label,
193
+ ),
194
+ slotRotate: (node, cls) =>
195
+ el(
196
+ "span",
197
+ {
186
198
  class: cls,
187
- value: node.value,
188
- min: node.min,
189
- max: node.max,
190
- });
191
-
192
- case "input":
193
- return el(node.multiline ? "textarea" : "input", {
194
- class: cls,
195
- type: node.multiline ? undefined : node.secure ? "password" : "text",
196
- placeholder: node.placeholder,
197
- name: node.bind,
198
- });
199
-
200
- case "picker":
201
- return el(
202
- "select",
203
- { class: cls, name: node.bind },
204
- ...node.options.map((option) =>
205
- el("option", { value: option.value }, option.label),
206
- ),
207
- );
208
-
209
- case "filePicker":
210
- return el(
211
- "label",
212
- { class: cls },
213
- el("input", {
214
- type: "file",
215
- accept: node.accept?.join(","),
216
- multiple: node.multiple,
217
- }),
218
- node.label,
219
- );
220
-
221
- case "slotRotate":
222
- return el(
223
- "span",
224
- {
225
- class: cls,
226
- "data-crepus-slot-rotate": node.phrases.join("|"),
227
- "data-interval-ms": node.intervalMs,
228
- },
229
- node.phrases[0] ?? "",
230
- );
231
-
232
- case "tabs":
233
- return el(
199
+ "data-crepus-slot-rotate": node.phrases.join("|"),
200
+ "data-interval-ms": node.intervalMs,
201
+ },
202
+ node.phrases[0] ?? "",
203
+ ),
204
+ tabs: (node, cls) =>
205
+ el(
206
+ "div",
207
+ { class: cls },
208
+ el(
234
209
  "div",
235
- { class: cls },
236
- el(
237
- "div",
238
- { role: "tablist" },
239
- ...node.tabs.map((tab: TabItem) =>
240
- el("button", { type: "button", role: "tab" }, tab.label),
241
- ),
242
- ),
210
+ { role: "tablist" },
243
211
  ...node.tabs.map((tab: TabItem) =>
244
- el("div", { role: "tabpanel" }, ...renderChildren(tab.children)),
212
+ el("button", { type: "button", role: "tab" }, tab.label),
245
213
  ),
246
- );
247
-
248
- // Control flow the parser could not resolve statically. The chosen branch is
249
- // rendered and the source expression kept as a data attribute.
250
- case "if":
251
- return el(
252
- "div",
253
- { class: cls, "data-crepus-if": node.condition },
254
- ...renderChildren(node.thenChildren),
255
- );
256
-
257
- case "forEach":
258
- return el(
259
- "div",
260
- {
261
- class: cls,
262
- "data-crepus-for-each": node.bind,
263
- "data-crepus-item": node.itemName,
264
- },
265
- ...renderChildren(node.itemBody),
266
- );
214
+ ),
215
+ ...node.tabs.map((tab: TabItem) =>
216
+ el("div", { role: "tabpanel" }, ...renderChildren(tab.children)),
217
+ ),
218
+ ),
219
+ if: (node, cls) =>
220
+ el(
221
+ "div",
222
+ { class: cls, "data-crepus-if": node.condition },
223
+ ...renderChildren(node.thenChildren),
224
+ ),
225
+ forEach: (node, cls) =>
226
+ el(
227
+ "div",
228
+ {
229
+ class: cls,
230
+ "data-crepus-for-each": node.bind,
231
+ "data-crepus-item": node.itemName,
232
+ },
233
+ ...renderChildren(node.itemBody),
234
+ ),
235
+ };
267
236
 
268
- default:
269
- return null as unknown as JSX.Element;
237
+ export function renderCrepusNodeSolid(node: ViewNode): JSX.Element {
238
+ const cls = classOf(node);
239
+ const renderer = RENDERERS[node.kind];
240
+ if (renderer) {
241
+ return renderer(node, cls);
270
242
  }
243
+ return null as unknown as JSX.Element;
271
244
  }
272
245
 
273
246
  /**