nodality 1.0.221 → 1.1.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/API.md +227 -0
- package/bin/nodality.js +64 -0
- package/dist/animator.cjs.js +1 -1
- package/dist/animator.cjs.js.LICENSE.txt +1 -1
- package/dist/animator.esm.js +1 -1
- package/dist/animator.esm.js.LICENSE.txt +1 -1
- package/dist/audionew.cjs.js +1 -1
- package/dist/audionew.cjs.js.LICENSE.txt +1 -1
- package/dist/audionew.esm.js +1 -1
- package/dist/audionew.esm.js.LICENSE.txt +1 -1
- package/dist/base.cjs.js +1 -1
- package/dist/base.cjs.js.LICENSE.txt +1 -1
- package/dist/base.esm.js +1 -1
- package/dist/base.esm.js.LICENSE.txt +1 -1
- package/dist/beta-desktop-bar.cjs.js +1 -1
- package/dist/beta-desktop-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/beta-desktop-bar.esm.js +1 -1
- package/dist/beta-desktop-bar.esm.js.LICENSE.txt +1 -1
- package/dist/beta-mobile-bar.cjs.js +1 -1
- package/dist/beta-mobile-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/beta-mobile-bar.esm.js +1 -1
- package/dist/beta-mobile-bar.esm.js.LICENSE.txt +1 -1
- package/dist/bundle.umd.js +1 -1
- package/dist/bundle.umd.js.LICENSE.txt +131 -1
- package/dist/button.cjs.js +1 -1
- package/dist/button.cjs.js.LICENSE.txt +1 -1
- package/dist/button.esm.js +1 -1
- package/dist/button.esm.js.LICENSE.txt +1 -1
- package/dist/card-getter.cjs.js.LICENSE.txt +1 -1
- package/dist/card-getter.esm.js.LICENSE.txt +1 -1
- package/dist/center.cjs.js +1 -1
- package/dist/center.cjs.js.LICENSE.txt +1 -1
- package/dist/center.esm.js +1 -1
- package/dist/center.esm.js.LICENSE.txt +1 -1
- package/dist/checkbox.cjs.js +1 -1
- package/dist/checkbox.cjs.js.LICENSE.txt +1 -1
- package/dist/checkbox.esm.js +1 -1
- package/dist/checkbox.esm.js.LICENSE.txt +1 -1
- package/dist/code.cjs.js +1 -1
- package/dist/code.cjs.js.LICENSE.txt +1 -1
- package/dist/code.esm.js +1 -1
- package/dist/code.esm.js.LICENSE.txt +1 -1
- package/dist/container.cjs.js +1 -1
- package/dist/container.cjs.js.LICENSE.txt +1 -1
- package/dist/container.esm.js +1 -1
- package/dist/container.esm.js.LICENSE.txt +1 -1
- package/dist/data-list.cjs.js +1 -1
- package/dist/data-list.cjs.js.LICENSE.txt +1 -1
- package/dist/data-list.esm.js +1 -1
- package/dist/data-list.esm.js.LICENSE.txt +1 -1
- package/dist/designer.cjs.js +1 -1
- package/dist/designer.cjs.js.LICENSE.txt +97 -1
- package/dist/designer.esm.js +1 -1
- package/dist/designer.esm.js.LICENSE.txt +97 -1
- package/dist/element-mapper.cjs.js +1 -1
- package/dist/element-mapper.cjs.js.LICENSE.txt +17 -1
- package/dist/element-mapper.esm.js +1 -1
- package/dist/element-mapper.esm.js.LICENSE.txt +17 -1
- package/dist/finalresult.esm.js +1 -1
- package/dist/finalresult.esm.js.LICENSE.txt +158 -1
- package/dist/flex-card.cjs.js +1 -1
- package/dist/flex-card.cjs.js.LICENSE.txt +1 -1
- package/dist/flex-card.esm.js +1 -1
- package/dist/flex-card.esm.js.LICENSE.txt +1 -1
- package/dist/flex-grid.cjs.js +1 -1
- package/dist/flex-grid.cjs.js.LICENSE.txt +1 -1
- package/dist/flex-grid.esm.js +1 -1
- package/dist/flex-grid.esm.js.LICENSE.txt +1 -1
- package/dist/flex-row.cjs.js +1 -1
- package/dist/flex-row.cjs.js.LICENSE.txt +1 -1
- package/dist/flex-row.esm.js +1 -1
- package/dist/flex-row.esm.js.LICENSE.txt +1 -1
- package/dist/floating-input.cjs.js +1 -1
- package/dist/floating-input.cjs.js.LICENSE.txt +1 -1
- package/dist/floating-input.esm.js +1 -1
- package/dist/floating-input.esm.js.LICENSE.txt +1 -1
- package/dist/free.cjs.js +1 -1
- package/dist/free.cjs.js.LICENSE.txt +1 -1
- package/dist/free.esm.js +1 -1
- package/dist/free.esm.js.LICENSE.txt +1 -1
- package/dist/horizontal-scroller.cjs.js.LICENSE.txt +1 -1
- package/dist/horizontal-scroller.esm.js.LICENSE.txt +1 -1
- package/dist/image-picker.cjs.js +1 -1
- package/dist/image-picker.cjs.js.LICENSE.txt +1 -1
- package/dist/image-picker.esm.js +1 -1
- package/dist/image-picker.esm.js.LICENSE.txt +1 -1
- package/dist/image.cjs.js +1 -1
- package/dist/image.cjs.js.LICENSE.txt +1 -1
- package/dist/image.esm.js +1 -1
- package/dist/image.esm.js.LICENSE.txt +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.LICENSE.txt +158 -1
- package/dist/index.d.ts +962 -0
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.LICENSE.txt +158 -1
- package/dist/keyframe-animation.cjs.js.LICENSE.txt +1 -1
- package/dist/keyframe-animation.esm.js.LICENSE.txt +1 -1
- package/dist/link-getter.cjs.js +1 -1
- package/dist/link-getter.cjs.js.LICENSE.txt +1 -1
- package/dist/link-getter.esm.js +1 -1
- package/dist/link-getter.esm.js.LICENSE.txt +1 -1
- package/dist/link.cjs.js +1 -1
- package/dist/link.cjs.js.LICENSE.txt +1 -1
- package/dist/link.esm.js +1 -1
- package/dist/link.esm.js.LICENSE.txt +1 -1
- package/dist/meta-adder.cjs.js +1 -1
- package/dist/meta-adder.cjs.js.LICENSE.txt +1 -1
- package/dist/meta-adder.esm.js +1 -1
- package/dist/meta-adder.esm.js.LICENSE.txt +1 -1
- package/dist/modal-2025.cjs.js +1 -1
- package/dist/modal-2025.cjs.js.LICENSE.txt +1 -1
- package/dist/modal-2025.esm.js +1 -1
- package/dist/modal-2025.esm.js.LICENSE.txt +1 -1
- package/dist/multiswitcher.cjs.js +1 -1
- package/dist/multiswitcher.cjs.js.LICENSE.txt +1 -1
- package/dist/multiswitcher.esm.js +1 -1
- package/dist/multiswitcher.esm.js.LICENSE.txt +1 -1
- package/dist/new-nav-bar.cjs.js +1 -1
- package/dist/new-nav-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/new-nav-bar.esm.js +1 -1
- package/dist/new-nav-bar.esm.js.LICENSE.txt +1 -1
- package/dist/picker.cjs.js +1 -1
- package/dist/picker.cjs.js.LICENSE.txt +1 -1
- package/dist/picker.esm.js +1 -1
- package/dist/picker.esm.js.LICENSE.txt +1 -1
- package/dist/progress.cjs.js +1 -1
- package/dist/progress.cjs.js.LICENSE.txt +1 -1
- package/dist/progress.esm.js +1 -1
- package/dist/progress.esm.js.LICENSE.txt +1 -1
- package/dist/radio.cjs.js +1 -1
- package/dist/radio.cjs.js.LICENSE.txt +1 -1
- package/dist/radio.esm.js +1 -1
- package/dist/radio.esm.js.LICENSE.txt +1 -1
- package/dist/range.cjs.js +1 -1
- package/dist/range.cjs.js.LICENSE.txt +1 -1
- package/dist/range.esm.js +1 -1
- package/dist/range.esm.js.LICENSE.txt +1 -1
- package/dist/scroll-video.cjs.js.LICENSE.txt +1 -1
- package/dist/scroll-video.esm.js.LICENSE.txt +1 -1
- package/dist/side-bar.cjs.js +1 -1
- package/dist/side-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/side-bar.esm.js +1 -1
- package/dist/side-bar.esm.js.LICENSE.txt +1 -1
- package/dist/side-nav-bar.cjs.js +1 -1
- package/dist/side-nav-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/side-nav-bar.esm.js +1 -1
- package/dist/side-nav-bar.esm.js.LICENSE.txt +1 -1
- package/dist/simple-bar.cjs.js +1 -1
- package/dist/simple-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/simple-bar.esm.js +1 -1
- package/dist/simple-bar.esm.js.LICENSE.txt +1 -1
- package/dist/slider-2025.cjs.js +1 -1
- package/dist/slider-2025.cjs.js.LICENSE.txt +1 -1
- package/dist/slider-2025.esm.js +1 -1
- package/dist/slider-2025.esm.js.LICENSE.txt +1 -1
- package/dist/spacer.cjs.js +1 -1
- package/dist/spacer.cjs.js.LICENSE.txt +1 -1
- package/dist/spacer.esm.js +1 -1
- package/dist/spacer.esm.js.LICENSE.txt +1 -1
- package/dist/stack.cjs.js +1 -1
- package/dist/stack.cjs.js.LICENSE.txt +1 -1
- package/dist/stack.esm.js +1 -1
- package/dist/stack.esm.js.LICENSE.txt +1 -1
- package/dist/stacker.cjs.js.LICENSE.txt +1 -1
- package/dist/stacker.esm.js.LICENSE.txt +1 -1
- package/dist/table.cjs.js +1 -1
- package/dist/table.cjs.js.LICENSE.txt +1 -1
- package/dist/table.esm.js +1 -1
- package/dist/table.esm.js.LICENSE.txt +1 -1
- package/dist/text-field.cjs.js +1 -1
- package/dist/text-field.cjs.js.LICENSE.txt +1 -1
- package/dist/text-field.esm.js +1 -1
- package/dist/text-field.esm.js.LICENSE.txt +1 -1
- package/dist/text.cjs.js +1 -1
- package/dist/text.cjs.js.LICENSE.txt +1 -1
- package/dist/text.esm.js +1 -1
- package/dist/text.esm.js.LICENSE.txt +1 -1
- package/dist/theme.cjs.js.LICENSE.txt +1 -1
- package/dist/theme.esm.js.LICENSE.txt +1 -1
- package/dist/transform-anim.cjs.js.LICENSE.txt +1 -1
- package/dist/transform-anim.esm.js.LICENSE.txt +1 -1
- package/dist/ulist.cjs.js +1 -1
- package/dist/ulist.cjs.js.LICENSE.txt +1 -1
- package/dist/ulist.esm.js +1 -1
- package/dist/ulist.esm.js.LICENSE.txt +1 -1
- package/dist/video.cjs.js +1 -1
- package/dist/video.cjs.js.LICENSE.txt +1 -1
- package/dist/video.esm.js +1 -1
- package/dist/video.esm.js.LICENSE.txt +1 -1
- package/dist/wrap.cjs.js +1 -1
- package/dist/wrap.cjs.js.LICENSE.txt +1 -1
- package/dist/wrap.esm.js +1 -1
- package/dist/wrap.esm.js.LICENSE.txt +1 -1
- package/dist/zoom-card.cjs.js +1 -1
- package/dist/zoom-card.cjs.js.LICENSE.txt +1 -1
- package/dist/zoom-card.esm.js +1 -1
- package/dist/zoom-card.esm.js.LICENSE.txt +1 -1
- package/examples/custom-raster-op.js +174 -0
- package/layout/animator.js +30 -2
- package/layout/audio.js +1 -1
- package/layout/audionew.js +1 -1
- package/layout/base.js +1 -1
- package/layout/beta-desktop-bar.js +1 -1
- package/layout/beta-mobile-bar.js +3 -2
- package/layout/button.js +1 -1
- package/layout/center.js +1 -1
- package/layout/checkbox.js +2 -2
- package/layout/circle.js +3 -2
- package/layout/code.js +3 -2
- package/layout/container.js +3 -4
- package/layout/dropdown-2025.js +1 -1
- package/layout/flex-card.js +1 -1
- package/layout/flex-grid.js +1 -1
- package/layout/flex-row.js +3 -2
- package/layout/form-components/custom.js +1 -1
- package/layout/form-components/data-list.js +2 -2
- package/layout/form-components/floating-input.js +2 -2
- package/layout/form-components/form-all.js +2 -2
- package/layout/form-components/form.js +1 -1
- package/layout/form-components/image-picker.js +1 -1
- package/layout/form-components/picker.js +2 -2
- package/layout/form-components/radio.js +2 -2
- package/layout/form-components/radiogroup.js +2 -2
- package/layout/form-components/range.js +2 -2
- package/layout/free.js +3 -4
- package/layout/grid-switcher.js +1 -1
- package/layout/grid.js +1 -1
- package/layout/horizontal-scroller.js +1 -1
- package/layout/image.js +1 -1
- package/layout/index.js +1 -1
- package/layout/link.js +5 -5
- package/layout/list.js +3 -4
- package/layout/meta-adder.js +1 -1
- package/layout/modal-2025.js +1 -1
- package/layout/morph.js +1003 -0
- package/layout/multiswitcher.js +11 -3
- package/layout/nav-bar.js +2 -3
- package/layout/nav-factor/custom-div.js +2 -2
- package/layout/new-nav-bar.js +11 -4
- package/layout/polygon.js +3 -4
- package/layout/prerender-site.js +1 -1
- package/layout/prerender.js +1 -1
- package/layout/progress.js +1 -1
- package/layout/row.js +1 -1
- package/layout/scroll-video.js +1 -1
- package/layout/side-bar.js +1 -1
- package/layout/side-nav-bar.js +1 -1
- package/layout/simple-bar.js +1 -1
- package/layout/slider-2025.js +1 -1
- package/layout/spacer.js +1 -1
- package/layout/stack.js +1 -1
- package/layout/svg.js +3 -4
- package/layout/switcher.js +1 -1
- package/layout/table.js +1 -1
- package/layout/text-field.js +1 -1
- package/layout/text.js +5 -5
- package/layout/ulist.js +1 -1
- package/layout/video.js +1 -1
- package/layout/wrap.js +1 -1
- package/layout/zoom-card.js +1 -1
- package/lib/card-getter.js +1 -1
- package/lib/codegen.js +62 -0
- package/lib/data.js +37 -1
- package/lib/designer.js +18 -1
- package/lib/element-mapper.js +351 -247
- package/lib/keyframe-animation.js +1 -1
- package/lib/link-getter.js +1 -1
- package/lib/morph-node.js +424 -0
- package/lib/raster-inspect.js +409 -0
- package/lib/raster-ops.js +1980 -81
- package/lib/raster-presets.js +329 -0
- package/lib/scroll-video.js +1 -1
- package/lib/seo.js +28 -1
- package/lib/stacker.js +1 -1
- package/lib/suggest.js +66 -0
- package/lib/theme.js +1 -1
- package/lib/transform-anim.js +1 -1
- package/lib/transition.js +205 -0
- package/package.json +20 -7
package/lib/element-mapper.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* nodality v1.0
|
|
2
|
+
* nodality v1.1.0
|
|
3
3
|
* (c) 2026 Filip Vabrousek
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// CORE
|
|
8
8
|
import { Animator } from "../layout/animator.js";
|
|
9
9
|
import { RASTER_OP_NAMES } from "../lib/raster-ops.js";
|
|
10
|
+
import { didYouMean } from "../lib/suggest.js";
|
|
10
11
|
import { Base } from "../layout/base.js";
|
|
11
12
|
import { Text } from "../layout/text.js";
|
|
12
13
|
import { Image } from "../layout/image.js";
|
|
@@ -71,6 +72,17 @@ import { Polygon } from "../layout/polygon.js";
|
|
|
71
72
|
import { Circle } from "../layout/circle.js";
|
|
72
73
|
|
|
73
74
|
|
|
75
|
+
// The closed set of `type:` values mapType understands, in the order it
|
|
76
|
+
// tests them. Kept beside the dispatch so a new branch without a new entry
|
|
77
|
+
// is visible in review — the vocabulary and the router should not drift.
|
|
78
|
+
const ELEMENT_TYPES = [
|
|
79
|
+
"h1", "h2", "h3", "h4", "h5", "h6", "p",
|
|
80
|
+
"img", "a", "cards", "free", "nav", "sideNav", "row", "dropdown",
|
|
81
|
+
"radio", "input", "labelInput", "filePicker", "picker", "video",
|
|
82
|
+
"audio", "multiswitcher", "button", "form", "checkbox", "stack",
|
|
83
|
+
"simple", "copy", "wrap", "circle", "polygon", "code", "table", "ulist",
|
|
84
|
+
];
|
|
85
|
+
|
|
74
86
|
class ElementMapper { // 22:09:58 04/11/2024
|
|
75
87
|
static mapType(obj) {
|
|
76
88
|
// console.log("LOBJ");
|
|
@@ -146,6 +158,13 @@ class ElementMapper { // 22:09:58 04/11/2024
|
|
|
146
158
|
} else if (obj.el.type === "ulist"){
|
|
147
159
|
return this.mapUList(obj);
|
|
148
160
|
}
|
|
161
|
+
|
|
162
|
+
// Everything above returned. Falling through used to return
|
|
163
|
+
// `undefined`, which the caller then treated as an element —
|
|
164
|
+
// surfacing much later, and far from the cause, as
|
|
165
|
+
// "Cannot read properties of undefined (reading 'toCode')".
|
|
166
|
+
// A closed vocabulary should say so at the point of the typo.
|
|
167
|
+
throw new Error("[nodality] " + didYouMean(obj.el.type, ELEMENT_TYPES, "element type"));
|
|
149
168
|
}
|
|
150
169
|
|
|
151
170
|
static mapTable(obj){
|
|
@@ -265,6 +284,12 @@ new Text("row.").set({
|
|
|
265
284
|
const customOptions = obj.customOptions;
|
|
266
285
|
const ft = customOptions.filter(l => l.op === "copy")[0];
|
|
267
286
|
const count = ft?.count ?? 3;
|
|
287
|
+
// Any OTHER raster nodes aimed at this element. `copy` itself is
|
|
288
|
+
// consumed above to build the wheel, so it is excluded — leaving it in
|
|
289
|
+
// would attach a GPU copy pass on top of the DOM copies this mapper
|
|
290
|
+
// already emits, and the element would be duplicated twice.
|
|
291
|
+
const copyRaster = (this.filteroRaster(obj.el.id, customOptions) || [])
|
|
292
|
+
.filter((n) => n !== ft);
|
|
268
293
|
|
|
269
294
|
const minSize = 300; // size of whole wheel
|
|
270
295
|
const cardSize = 30; // width/height of text wrapper
|
|
@@ -326,7 +351,12 @@ animation: {
|
|
|
326
351
|
position: "absolute",
|
|
327
352
|
id: "#first",
|
|
328
353
|
scale: 0.3,
|
|
329
|
-
${ft?.animation ? animation : ""}
|
|
354
|
+
${ft?.animation ? animation : ""}${
|
|
355
|
+
// Wrapper routes its options through commonMethods(), so a raster
|
|
356
|
+
// chain serialised here reaches rasterize() when the emitted source
|
|
357
|
+
// runs. Plain data, so JSON.stringify round-trips it.
|
|
358
|
+
copyRaster.length ? `,\n raster: ${JSON.stringify(copyRaster)}` : ""
|
|
359
|
+
}
|
|
330
360
|
})
|
|
331
361
|
.add(
|
|
332
362
|
Array.from({ length: ${count} }).map((_, i) => {
|
|
@@ -385,101 +415,139 @@ animation: {
|
|
|
385
415
|
// referenced an undefined `radius`, so any call was a guaranteed
|
|
386
416
|
// ReferenceError. Kept in git history if the ring layout is wanted back.
|
|
387
417
|
|
|
388
|
-
|
|
389
|
-
|
|
418
|
+
// Took NO arguments at all, so `{type: "button", text: "Buy now"}`
|
|
419
|
+
// rendered a hardcoded "Submit" with a demo onTap that logged to the
|
|
420
|
+
// console and a keySet forcing a 3px green border on every button in
|
|
421
|
+
// every page. The label, the handler and the styling are the caller's.
|
|
422
|
+
static button(obj){
|
|
423
|
+
const el = obj.el;
|
|
424
|
+
return new Button(el.text ?? "Button")
|
|
390
425
|
.set({
|
|
391
426
|
fluidc: "S6",
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
arrpad: {sides: ["all"], value: ".3rem"},
|
|
395
|
-
radius: ".3rem",
|
|
396
|
-
onTap: () => { console.log("[nodality] demo button tapped"); },
|
|
397
|
-
keySet: {key: "border", value: "3px solid green"}
|
|
427
|
+
...this.elOpts(el),
|
|
428
|
+
raster: this.filteroRaster(el.id, obj.customOptions),
|
|
398
429
|
});
|
|
399
430
|
}
|
|
400
431
|
|
|
401
|
-
static multiswitcher(){
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
let r = new Switcher()
|
|
405
|
-
.set({breakpoints:[
|
|
406
|
-
{ at: "0px", view: new Text("First").set({}) },
|
|
432
|
+
static multiswitcher(obj){
|
|
407
433
|
|
|
408
|
-
{ at: "700px", view: new Text("Nice").set({}) },
|
|
409
|
-
|
|
410
|
-
{ at: "800px", view: new Text("Best").set({}) },
|
|
411
|
-
]}); // undefined must be passed to render method
|
|
412
|
-
|
|
413
|
-
// console.log("ROD");
|
|
414
|
-
// console.log(r.toCode().join(""));
|
|
415
|
-
|
|
416
|
-
// return new Text("MS").set({});
|
|
417
434
|
|
|
418
|
-
|
|
435
|
+
// Ignored obj: every switcher showed First/Nice/Best. Each
|
|
436
|
+
// breakpoint's `view` is an ELEMENT SPEC now, mapped like any
|
|
437
|
+
// other subtree, so a switcher can hold real content.
|
|
438
|
+
//
|
|
439
|
+
// { type: "multiswitcher", breakpoints: [
|
|
440
|
+
// { at: "0px", view: { type: "h2", text: "Small" } },
|
|
441
|
+
// { at: "700px", view: { type: "h1", text: "Large" } } ]}
|
|
442
|
+
//
|
|
443
|
+
// Switcher DOES extend Animator, so it has rasterize(); its set()
|
|
444
|
+
// just does not accept a `raster:` key, which is why the chain is
|
|
445
|
+
// attached directly rather than passed through.
|
|
446
|
+
const bps = Array.isArray(obj.el.breakpoints) ? obj.el.breakpoints : null;
|
|
447
|
+
if (!bps || !bps.length) {
|
|
448
|
+
throw new Error('[nodality] a "multiswitcher" element needs a non-empty ' +
|
|
449
|
+
"`breakpoints` array of { at, view }.");
|
|
450
|
+
}
|
|
451
|
+
return new Switcher().set({
|
|
452
|
+
id: obj.el.id,
|
|
453
|
+
area: obj.el.area,
|
|
454
|
+
breakpoints: bps.map((bp) => ({
|
|
455
|
+
at: bp.at,
|
|
456
|
+
// Already a component (someone built it by hand) or a spec.
|
|
457
|
+
view: bp.view && typeof bp.view.render === "function"
|
|
458
|
+
? bp.view
|
|
459
|
+
: this.mapType({ ...obj, el: bp.view }),
|
|
460
|
+
})),
|
|
461
|
+
});
|
|
419
462
|
}
|
|
420
463
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
464
|
+
// REMOVED: the old multiswitcher body — a hardcoded
|
|
465
|
+
// First/Nice/Best fixture that ignored obj entirely. Kept in git
|
|
466
|
+
// history; the version above takes its views from the element.
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
// Hardcoded to a w3schools Big Buck Bunny URL. A missing `url` now
|
|
470
|
+
// says so: silently playing someone else's sample reel is worse than
|
|
471
|
+
// an error, because it looks like it worked.
|
|
472
|
+
static video(obj){
|
|
473
|
+
const el = obj.el;
|
|
474
|
+
if (!el.url) throw new Error('[nodality] a "video" element needs a `url`.');
|
|
475
|
+
// Video defines its own set() and never calls commonMethods(), so
|
|
476
|
+
// `raster:` there would be a dead key.
|
|
477
|
+
return this.attachRaster(
|
|
478
|
+
new Video(el.url).set(this.elOpts(el)), el, obj.customOptions);
|
|
424
479
|
}
|
|
425
480
|
|
|
426
|
-
|
|
427
|
-
|
|
481
|
+
// This one did not merely ignore its input, it THREW: Audio defines
|
|
482
|
+
// no set() and Animator has none to inherit, so the old
|
|
483
|
+
// `.set({background})` was a TypeError on every `{type: "audio"}`.
|
|
484
|
+
// Options go to the constructor; styling belongs to the element.
|
|
485
|
+
static audio(obj){
|
|
486
|
+
const el = obj.el;
|
|
487
|
+
if (!el.url) throw new Error('[nodality] an "audio" element needs a `url`.');
|
|
488
|
+
return this.attachRaster(new Audio(el.url), el, obj.customOptions);
|
|
428
489
|
}
|
|
429
490
|
|
|
491
|
+
// Ignored obj: every radio group asked Male/Female/Other, and
|
|
492
|
+
// `multiple: true` on a RADIO group was wrong on its face — that is a
|
|
493
|
+
// checkbox. Defaults to single-select now, as radios are.
|
|
494
|
+
//
|
|
495
|
+
// RadioGroup is not an Animator (`class RadioGroup /*extends
|
|
496
|
+
// Animator*/`), so it has no rasterize() and cannot carry raster ops.
|
|
430
497
|
static radio(obj){
|
|
431
|
-
|
|
498
|
+
const el = obj.el;
|
|
432
499
|
return new RadioGroup()
|
|
433
500
|
.set({
|
|
434
|
-
items:
|
|
435
|
-
multiple:
|
|
501
|
+
items: Array.isArray(el.items) ? el.items : [],
|
|
502
|
+
multiple: el.multiple ?? false,
|
|
503
|
+
...this.elOpts(el),
|
|
436
504
|
});
|
|
437
505
|
}
|
|
438
506
|
|
|
507
|
+
// Ignored obj: every input on every page read "Enter swimming time".
|
|
508
|
+
// `inputType` rather than `type`, because `type` is already the
|
|
509
|
+
// ELEMENT type ("input") — see elOpts.
|
|
439
510
|
static input(obj){
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
type: "text",
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
511
|
+
const el = obj.el;
|
|
512
|
+
return new TextField().set({
|
|
513
|
+
type: el.inputType ?? "text",
|
|
514
|
+
...this.elOpts(el),
|
|
515
|
+
raster: this.filteroRaster(el.id, obj.customOptions),
|
|
516
|
+
});
|
|
446
517
|
}
|
|
447
518
|
|
|
519
|
+
// Ignored obj: every labelled input was titled "Your name".
|
|
448
520
|
static floatInput(obj){
|
|
449
|
-
|
|
450
|
-
|
|
521
|
+
const el = obj.el;
|
|
522
|
+
return this.attachRaster(new FloatingInput()
|
|
451
523
|
.set({
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
});
|
|
524
|
+
type: el.inputType ?? "input",
|
|
525
|
+
...this.elOpts(el),
|
|
526
|
+
}), el, obj.customOptions);
|
|
455
527
|
}
|
|
456
528
|
|
|
529
|
+
// Ignored obj, including a hardcoded `id: "A"` — two file pickers
|
|
530
|
+
// on one page produced duplicate DOM ids.
|
|
457
531
|
static filePicker(obj){
|
|
458
|
-
|
|
459
|
-
|
|
532
|
+
const el = obj.el;
|
|
533
|
+
return this.attachRaster(new FilePickera()
|
|
460
534
|
.set({
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
color: "white",
|
|
465
|
-
font: "Arial",
|
|
466
|
-
radius: "3rem",
|
|
467
|
-
accept: "application/pdf"
|
|
468
|
-
});
|
|
535
|
+
title: el.title ?? "Choose a file",
|
|
536
|
+
...this.elOpts(el),
|
|
537
|
+
}), el, obj.customOptions);
|
|
469
538
|
}
|
|
470
539
|
|
|
540
|
+
// Ignored obj: every picker offered Tesla and Audi.
|
|
471
541
|
static picker(obj){
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
return new Picker()
|
|
542
|
+
const el = obj.el;
|
|
543
|
+
return new Picker()
|
|
477
544
|
.set({
|
|
478
|
-
items: items,
|
|
479
|
-
font: "Arial",
|
|
545
|
+
items: Array.isArray(el.items) ? el.items : [],
|
|
480
546
|
arrayPadding: ({sides: ["all"], value: "0.5rem"}),
|
|
481
|
-
rounded: true
|
|
482
|
-
|
|
547
|
+
rounded: true,
|
|
548
|
+
...this.elOpts(el),
|
|
549
|
+
raster: this.filteroRaster(el.id, obj.customOptions),
|
|
550
|
+
});
|
|
483
551
|
}
|
|
484
552
|
|
|
485
553
|
|
|
@@ -506,8 +574,12 @@ animation: {
|
|
|
506
574
|
|
|
507
575
|
}));
|
|
508
576
|
|
|
509
|
-
|
|
510
|
-
.set(
|
|
577
|
+
// Bound rather than returned inline, so the raster chain can be
|
|
578
|
+
// attached below. Dropdown defines its own set() which handles
|
|
579
|
+
// only its own keys and never calls commonMethods(), so a
|
|
580
|
+
// `raster:` option here would be silently dropped.
|
|
581
|
+
const dd = new Dropdown()
|
|
582
|
+
.set({
|
|
511
583
|
behaviour: "click", // click otherwise
|
|
512
584
|
//width: "120px",
|
|
513
585
|
|
|
@@ -543,13 +615,18 @@ animation: {
|
|
|
543
615
|
|
|
544
616
|
new Wrapper().set({border: "1px solid green", background: "#1abc9c", radius: "0.7rem", socenter: true})
|
|
545
617
|
.add(items.slice(1)
|
|
546
|
-
|
|
618
|
+
|
|
547
619
|
/* new Text("Option 1o").set({font: "Arial", pad: [{a: 10}],}),
|
|
548
620
|
new Text("Option 2").set({font: "Arial", pad: [{a: 10}],}),
|
|
549
621
|
new Text("Option 3").set({font: "Arial", pad: [{a: 10}],}),
|
|
550
622
|
*/
|
|
551
623
|
)
|
|
552
|
-
])
|
|
624
|
+
]);
|
|
625
|
+
|
|
626
|
+
const ddRaster = this.filteroRaster(obj.el.id, obj.customOptions);
|
|
627
|
+
ddRaster && dd.rasterize(ddRaster);
|
|
628
|
+
|
|
629
|
+
return dd;
|
|
553
630
|
}
|
|
554
631
|
|
|
555
632
|
/* static row(obj){
|
|
@@ -755,7 +832,7 @@ if (obj.el.dropdown){
|
|
|
755
832
|
|
|
756
833
|
|
|
757
834
|
|
|
758
|
-
|
|
835
|
+
const navBar = new Switcher()
|
|
759
836
|
.set({
|
|
760
837
|
breakpoints: [ // 172800 almost
|
|
761
838
|
{
|
|
@@ -950,7 +1027,19 @@ new Wrapper().set({
|
|
|
950
1027
|
// { at: "700px", view: Object.assign(document.createElement("h1"), { textContent: "Medium View" }) },
|
|
951
1028
|
// { at: "800px", view: Object.assign(document.createElement("h1"), { textContent: "Large View" }) },
|
|
952
1029
|
],
|
|
953
|
-
})
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
// A raster chain aimed at this element reaches the component here.
|
|
1033
|
+
// Switcher DOES extend Animator (layout/multiswitcher.js) and so it
|
|
1034
|
+
// has rasterize() — the comment that said otherwise was wrong, and
|
|
1035
|
+
// the real gap was simply that protoNav never forwarded the chain.
|
|
1036
|
+
// Its own set() destructures {breakpoints, id, area}, so a `raster:`
|
|
1037
|
+
// key would be dropped; attachRaster calls rasterize() directly.
|
|
1038
|
+
//
|
|
1039
|
+
// Nothing changes for a nav with no raster nodes aimed at it:
|
|
1040
|
+
// filteroRaster returns undefined and attachRaster is a no-op, so
|
|
1041
|
+
// what {type:"nav"} produces today is untouched.
|
|
1042
|
+
return this.attachRaster(navBar, obj.el, customOptions);
|
|
954
1043
|
|
|
955
1044
|
// return new Text("A").set({})
|
|
956
1045
|
}
|
|
@@ -1208,6 +1297,19 @@ if (obj.el.dropdown){
|
|
|
1208
1297
|
// console.log("PPPP");
|
|
1209
1298
|
// console.log(obj.el.offcanvas);
|
|
1210
1299
|
// console.log(rt.toCode());
|
|
1300
|
+
|
|
1301
|
+
// Raster ops, like every other rasterable element.
|
|
1302
|
+
//
|
|
1303
|
+
// NOT `raster:` in the options above: SideNav configures itself
|
|
1304
|
+
// through `setup()`, which builds `this.res` directly and never
|
|
1305
|
+
// reaches Animator.commonMethods() — where `obj.raster &&
|
|
1306
|
+
// this.rasterize(...)` lives. A `raster` key there would be
|
|
1307
|
+
// accepted, ignored, and report nothing, which is the exact bug
|
|
1308
|
+
// this is fixing. SideNav extends Animator, so the inherited
|
|
1309
|
+
// attach point is called directly instead.
|
|
1310
|
+
const rtRaster = this.filteroRaster(obj.el.id, obj.customOptions);
|
|
1311
|
+
rtRaster && rt.rasterize(rtRaster);
|
|
1312
|
+
|
|
1211
1313
|
return rt;
|
|
1212
1314
|
|
|
1213
1315
|
// return new Text("A").set({})
|
|
@@ -1276,6 +1378,12 @@ if (obj.el.dropdown){
|
|
|
1276
1378
|
})
|
|
1277
1379
|
]);
|
|
1278
1380
|
|
|
1381
|
+
// Same wiring, same reason as sideNav: Free defines its own
|
|
1382
|
+
// set(), which handles only its own keys and never calls
|
|
1383
|
+
// commonMethods(), so a `raster:` option would be dead.
|
|
1384
|
+
const elaRaster = this.filteroRaster(obj.el.id, obj.customOptions);
|
|
1385
|
+
elaRaster && ela.rasterize(elaRaster);
|
|
1386
|
+
|
|
1279
1387
|
return ela;
|
|
1280
1388
|
// console.log("ETC");
|
|
1281
1389
|
// console.log(ela.toCode());
|
|
@@ -1362,11 +1470,12 @@ let elo = new Polygon({ id: "hex" })
|
|
|
1362
1470
|
transform: this.filtero("transform", el.id, obj.customOptions),
|
|
1363
1471
|
filtera: this.filtero("filter", el.id, obj.customOptions),
|
|
1364
1472
|
raster: this.filteroRaster(el.id, obj.customOptions),
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1473
|
+
// The caller's own breakpoints. This used to REPLACE them
|
|
1474
|
+
// with a two-breakpoint orange/green demo fixture whenever
|
|
1475
|
+
// `resprop` was merely present — so asking for responsive
|
|
1476
|
+
// styling got you someone else's debugging boxes, and the
|
|
1477
|
+
// option appeared to work while doing something unrelated.
|
|
1478
|
+
resprop: el.resprop ?? null,
|
|
1370
1479
|
});
|
|
1371
1480
|
}
|
|
1372
1481
|
|
|
@@ -1432,6 +1541,13 @@ let elo = new Polygon({ id: "hex" })
|
|
|
1432
1541
|
re["gradient"] = this.filtero("gradient", obj.el.id, obj.customOptions),
|
|
1433
1542
|
re["blast"] = this.filtero("blast", obj.el.id, obj.customOptions),
|
|
1434
1543
|
re["backgroundOp"] = this.filtero("background", obj.el.id, obj.customOptions),//customOptions.filter(l => l.op.name === "background")[0];
|
|
1544
|
+
// Raster ops. Every CSS-level op above was forwarded and
|
|
1545
|
+
// this was not, so a raster node targeting a link was
|
|
1546
|
+
// accepted, matched nothing, and silently did nothing —
|
|
1547
|
+
// the same class of dead option phase P3 removed from
|
|
1548
|
+
// mapWrap. Link takes `raster` through commonMethods like
|
|
1549
|
+
// every other component; only the wiring was missing.
|
|
1550
|
+
re["raster"] = this.filteroRaster(obj.el.id, obj.customOptions);
|
|
1435
1551
|
re["pad"] = [{ "a": 10 }];
|
|
1436
1552
|
|
|
1437
1553
|
if (bst.length > 0) {
|
|
@@ -1469,6 +1585,9 @@ const animation = this.filtero("animation", el.id, obj.customOptions);
|
|
|
1469
1585
|
const shadow = this.filtero("shadow", el.id, obj.customOptions);
|
|
1470
1586
|
const marginOp = this.filtero("margin", el.id, obj.customOptions);
|
|
1471
1587
|
const filtera = this.filtero("filter", el.id, obj.customOptions);
|
|
1588
|
+
// Raster nodes carry `op` as a plain string, so `filtero`'s `l.op.name`
|
|
1589
|
+
// matching never sees them — they need their own selector.
|
|
1590
|
+
const gridRaster = this.filteroRaster(el.id, obj.customOptions);
|
|
1472
1591
|
const blast = this.filtero("blast", el.id, obj.customOptions);
|
|
1473
1592
|
|
|
1474
1593
|
|
|
@@ -1556,6 +1675,14 @@ const blast = this.filtero("blast", el.id, obj.customOptions);
|
|
|
1556
1675
|
filtera !== undefined ? `,\n filtera: ${JSON.stringify(filtera)}` : ""
|
|
1557
1676
|
}${
|
|
1558
1677
|
blast !== undefined ? `,\n blast: ${JSON.stringify(blast)}` : ""
|
|
1678
|
+
}${
|
|
1679
|
+
// Raster ops, emitted like every other op above. This mapper
|
|
1680
|
+
// returns SOURCE rather than an instance, so the chain is
|
|
1681
|
+
// serialised into the generated `.set({...})` instead of being
|
|
1682
|
+
// attached to an object. FlexGrid routes its options through
|
|
1683
|
+
// commonMethods(), so the emitted code reaches rasterize().
|
|
1684
|
+
// Raster nodes are plain data, so JSON.stringify round-trips them.
|
|
1685
|
+
gridRaster !== undefined ? `,\n raster: ${JSON.stringify(gridRaster)}` : ""
|
|
1559
1686
|
}
|
|
1560
1687
|
})
|
|
1561
1688
|
.items(
|
|
@@ -1575,162 +1702,93 @@ const blast = this.filtero("blast", el.id, obj.customOptions);
|
|
|
1575
1702
|
// commented out for a long time and the body referenced undefined
|
|
1576
1703
|
// `rta`, `el` and `i`, so wiring it back up would have thrown.
|
|
1577
1704
|
|
|
1705
|
+
// Ignored obj: every checkbox was named "acceptTerms" and labelled
|
|
1706
|
+
// "Check it out!". `label` accepts a plain string — the component wants a
|
|
1707
|
+
// component, so a string is wrapped here rather than making every caller
|
|
1708
|
+
// construct a Text.
|
|
1578
1709
|
static checkbox(obj){
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
});
|
|
1588
|
-
|
|
1710
|
+
const el = obj.el;
|
|
1711
|
+
const label = typeof el.label === "string"
|
|
1712
|
+
? new Text(el.label).set({size: "S6"})
|
|
1713
|
+
: el.label;
|
|
1714
|
+
return this.attachRaster(new Checkbox().set({
|
|
1715
|
+
...this.elOpts(el, ["label"]),
|
|
1716
|
+
...(label !== undefined ? {label} : {}),
|
|
1717
|
+
}), el, obj.customOptions);
|
|
1589
1718
|
}
|
|
1590
1719
|
|
|
1720
|
+
// Ignored obj: every stack rendered the same photo and "Samuel Suresh".
|
|
1721
|
+
// Children come from the element now, mapped like any other subtree —
|
|
1722
|
+
// the same fix mapWrap got in phase P3.
|
|
1591
1723
|
static stack(obj){
|
|
1592
|
-
|
|
1593
|
-
.set(
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
new Text("Samuel Suresh")
|
|
1601
|
-
.set({
|
|
1602
|
-
color: "#00ae56",
|
|
1603
|
-
font: "SF Pro Display",
|
|
1604
|
-
fluidc: "S2",
|
|
1605
|
-
pad: {sides: ["top", "left"], value: 20}
|
|
1606
|
-
}),
|
|
1607
|
-
]);
|
|
1608
|
-
|
|
1724
|
+
const el = obj.el;
|
|
1725
|
+
const st = new Stack().set(this.elOpts(el));
|
|
1726
|
+
const kids = Array.isArray(el.children) ? el.children : null;
|
|
1727
|
+
if (kids) st.add(kids.map((child) => this.mapType({ ...obj, el: child })));
|
|
1728
|
+
return this.attachRaster(st, el, obj.customOptions);
|
|
1609
1729
|
}
|
|
1610
1730
|
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
}),
|
|
1632
|
-
|
|
1633
|
-
new RadioGroup()
|
|
1634
|
-
.set({
|
|
1635
|
-
name: "gender",
|
|
1636
|
-
items: ["Male", "Female", "Other"],
|
|
1637
|
-
multiple: false,
|
|
1638
|
-
tint: "#1abc9c",
|
|
1639
|
-
font: "Arial",
|
|
1640
|
-
exact: "3rem"
|
|
1641
|
-
}),
|
|
1642
|
-
|
|
1643
|
-
new Picker()
|
|
1644
|
-
.set({
|
|
1645
|
-
name: "car",
|
|
1646
|
-
items: [
|
|
1647
|
-
["none", "select a car---"], // Placeholder option
|
|
1648
|
-
["tesla", "Tesla"], // Tesla as a selectable option
|
|
1649
|
-
["audi", "Audi"] // Audi as a selectable option
|
|
1650
|
-
],
|
|
1651
|
-
font: "Arial",
|
|
1652
|
-
arrayPadding: ({sides: ["all"], value: "0.5rem"}),
|
|
1653
|
-
radius: "1rem",
|
|
1654
|
-
background: "#1abc9c"
|
|
1655
|
-
}),
|
|
1656
|
-
|
|
1657
|
-
new FilePickera()
|
|
1658
|
-
.set({
|
|
1659
|
-
id: "A",
|
|
1660
|
-
name: "image",
|
|
1661
|
-
title: "Add profile picture",
|
|
1662
|
-
background: "#3498DB",
|
|
1663
|
-
color: "white",
|
|
1664
|
-
font: "Arial",
|
|
1665
|
-
radius: "3rem",
|
|
1666
|
-
// accept: "application/pdf"
|
|
1667
|
-
}),
|
|
1668
|
-
|
|
1669
|
-
// datalist, range, filepicker, picker
|
|
1670
|
-
|
|
1671
|
-
// add radio and read it in PHP
|
|
1672
|
-
|
|
1673
|
-
new Button("Submit form").set({ // 174915 If I dont serve it, it downloads the php file
|
|
1674
|
-
type: "submit",
|
|
1675
|
-
background: "#3498db",
|
|
1676
|
-
color: "white",
|
|
1677
|
-
weight: "bold",
|
|
1678
|
-
radius: "1rem",
|
|
1679
|
-
pad: [{"a": "1rem"}], // add
|
|
1680
|
-
mar: [{"b": "1rem"}] // add
|
|
1681
|
-
})
|
|
1682
|
-
]);
|
|
1731
|
+
// Ignored obj: every form posted to "file.php" and contained the same
|
|
1732
|
+
// five demo fields (a name, an email, a gender radio, a car picker and a
|
|
1733
|
+
// profile-picture upload), whatever the caller asked for. Fields come
|
|
1734
|
+
// from `children` now, mapped like any other subtree.
|
|
1735
|
+
//
|
|
1736
|
+
// { type: "form", action: "/subscribe", method: "post", children: [
|
|
1737
|
+
// { type: "labelInput", title: "Your email", name: "email" },
|
|
1738
|
+
// { type: "button", text: "Subscribe" } ]}
|
|
1739
|
+
//
|
|
1740
|
+
// Form is not an Animator (`class Form {`), so it has no rasterize() and
|
|
1741
|
+
// cannot carry raster ops.
|
|
1742
|
+
static form(obj){
|
|
1743
|
+
const el = obj.el;
|
|
1744
|
+
const form = new Form().set({
|
|
1745
|
+
action: el.action ?? "",
|
|
1746
|
+
...(el.method !== undefined ? { method: el.method } : {}),
|
|
1747
|
+
});
|
|
1748
|
+
const kids = Array.isArray(el.children) ? el.children : null;
|
|
1749
|
+
if (kids) form.add(kids.map((child) => this.mapType({ ...obj, el: child })));
|
|
1750
|
+
return form;
|
|
1683
1751
|
}
|
|
1684
1752
|
|
|
1685
|
-
|
|
1686
|
-
//
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
])
|
|
1753
|
+
// REMOVED: the old form body — a hardcoded five-field demo. Kept in
|
|
1754
|
+
// git history; the version above builds from `children`.
|
|
1755
|
+
// Ignored obj: every "simple" element emitted the same AreaSwitcher —
|
|
1756
|
+
// three fixed breakpoints of a/b/c/d/e templates and five "Hello A…E"
|
|
1757
|
+
// texts. The regions and the children are the caller's now.
|
|
1758
|
+
//
|
|
1759
|
+
// { type: "simple", gap: "10px", height: "700px",
|
|
1760
|
+
// react: [{ at: "0", template: ["aa", "bb"] },
|
|
1761
|
+
// { at: "768", template: ["ab"] }],
|
|
1762
|
+
// children: [{ type: "h1", text: "A" }, { type: "p", text: "B" }] }
|
|
1763
|
+
//
|
|
1764
|
+
// Emits SOURCE rather than an instance, like mapGrid and mapCopy, so
|
|
1765
|
+
// children are mapped and then serialised through their own toCode().
|
|
1766
|
+
static simple(obj){
|
|
1767
|
+
const el = obj.el;
|
|
1768
|
+
const react = Array.isArray(el.react) ? el.react : [];
|
|
1769
|
+
if (!react.length) {
|
|
1770
|
+
throw new Error('[nodality] a "simple" element needs a non-empty `react` ' +
|
|
1771
|
+
"array of { at, template }.");
|
|
1772
|
+
}
|
|
1773
|
+
const kids = Array.isArray(el.children) ? el.children : [];
|
|
1774
|
+
const kidSrc = kids
|
|
1775
|
+
.map((child) => {
|
|
1776
|
+
const code = this.mapType({ ...obj, el: child }).toCode();
|
|
1777
|
+
return Array.isArray(code) ? code.join("") : String(code);
|
|
1778
|
+
})
|
|
1779
|
+
.join(",\n ");
|
|
1780
|
+
|
|
1781
|
+
return `new AreaSwitcher()
|
|
1782
|
+
.set(${JSON.stringify({
|
|
1783
|
+
gap: el.gap ?? "10px",
|
|
1784
|
+
height: el.height ?? "700px",
|
|
1785
|
+
...(el.id !== undefined ? { id: el.id } : {}),
|
|
1786
|
+
})})
|
|
1787
|
+
.react(${JSON.stringify(react, null, 2)})
|
|
1721
1788
|
.add([
|
|
1722
|
-
|
|
1723
|
-
new Text("Hello B").set({size: "S1"}),
|
|
1724
|
-
new Text("Hello C").set({size: "S1"}),
|
|
1725
|
-
new Text("Hello D").set({size: "S1"}),
|
|
1726
|
-
new Text("Hello E").set({size: "S1"})
|
|
1789
|
+
${kidSrc}
|
|
1727
1790
|
])`;
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
// return new Simple().set({}).react([]);
|
|
1731
|
-
}
|
|
1732
|
-
|
|
1733
|
-
|
|
1791
|
+
}
|
|
1734
1792
|
|
|
1735
1793
|
static mapWrap(obj) {
|
|
1736
1794
|
let el = obj.el;
|
|
@@ -1740,17 +1798,20 @@ return `new AreaSwitcher()
|
|
|
1740
1798
|
|
|
1741
1799
|
let kind = obj.el.kind ?? "";
|
|
1742
1800
|
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1801
|
+
// The caller's own options, then the node-derived ones. Everything
|
|
1802
|
+
// the element declares reaches the Wrapper — this used to forward a
|
|
1803
|
+
// fixed allowlist (id/class/color/size/font/keySet + the op slots)
|
|
1804
|
+
// and drop the rest, so a `wrap` element could not carry a width, a
|
|
1805
|
+
// background, or a grid.
|
|
1806
|
+
//
|
|
1807
|
+
// `size` is NOT defaulted here any more. It used to be
|
|
1808
|
+
// `getElType(el.type)`, which for type "wrap" produced the string
|
|
1809
|
+
// "Srap" — getElType slices the digit off h1…h6 and has nothing to
|
|
1810
|
+
// slice on a word. A caller-supplied `size` still passes through.
|
|
1811
|
+
const wrapper = new Wrapper(kind)
|
|
1746
1812
|
.set({
|
|
1747
|
-
|
|
1748
|
-
class: el.class,
|
|
1749
|
-
color: el.color,
|
|
1750
|
-
size: this.getElType(el.type), // update 23/07/2025
|
|
1813
|
+
...el,
|
|
1751
1814
|
font: el.font ?? "Arial",
|
|
1752
|
-
keySet: el.keySet,
|
|
1753
|
-
// keySet: {key: "border", value: "3px solid green"},
|
|
1754
1815
|
stroke: this.filtero("blast", el.id, obj.customOptions),
|
|
1755
1816
|
gradient: this.filtero("gradient", el.id, obj.customOptions),
|
|
1756
1817
|
animation: this.filtero("animation", el.id, obj.customOptions),
|
|
@@ -1758,12 +1819,18 @@ return `new AreaSwitcher()
|
|
|
1758
1819
|
transform: this.filtero("transform", el.id, obj.customOptions),
|
|
1759
1820
|
filtera: this.filtero("filter", el.id, obj.customOptions),
|
|
1760
1821
|
raster: this.filteroRaster(el.id, obj.customOptions),
|
|
1761
|
-
})
|
|
1762
|
-
new Text("Hello").set({}),
|
|
1763
|
-
new Text("Hello").set({}),
|
|
1764
|
-
new Text("Hello").set({}),
|
|
1822
|
+
});
|
|
1765
1823
|
|
|
1766
|
-
|
|
1824
|
+
// Children come from the element. There used to be three
|
|
1825
|
+
// `new Text("Hello")` here unconditionally, so every `wrap` in
|
|
1826
|
+
// every page rendered the same placeholder content and no page
|
|
1827
|
+
// could put anything of its own inside one.
|
|
1828
|
+
const kids = Array.isArray(el.children) ? el.children : null;
|
|
1829
|
+
if (kids) {
|
|
1830
|
+
wrapper.add(kids.map((child) =>
|
|
1831
|
+
this.mapType({ ...obj, el: child })));
|
|
1832
|
+
}
|
|
1833
|
+
return wrapper;
|
|
1767
1834
|
}
|
|
1768
1835
|
|
|
1769
1836
|
|
|
@@ -1778,15 +1845,13 @@ return `new AreaSwitcher()
|
|
|
1778
1845
|
|
|
1779
1846
|
|
|
1780
1847
|
|
|
1781
|
-
|
|
1848
|
+
// Same two fixes as mapWrap: the element's own options reach the
|
|
1849
|
+
// component, and `size` is not defaulted to the "Srap"-shaped
|
|
1850
|
+
// output of getElType on a non-heading type.
|
|
1851
|
+
const list = new UList(kind)
|
|
1782
1852
|
.set({
|
|
1783
|
-
|
|
1784
|
-
class: el.class,
|
|
1785
|
-
color: el.color,
|
|
1786
|
-
size: this.getElType(el.type), // update 23/07/2025
|
|
1853
|
+
...el,
|
|
1787
1854
|
font: el.font ?? "Arial",
|
|
1788
|
-
keySet: el.keySet,
|
|
1789
|
-
// keySet: {key: "border", value: "3px solid green"},
|
|
1790
1855
|
stroke: this.filtero("blast", el.id, obj.customOptions),
|
|
1791
1856
|
gradient: this.filtero("gradient", el.id, obj.customOptions),
|
|
1792
1857
|
animation: this.filtero("animation", el.id, obj.customOptions),
|
|
@@ -1794,11 +1859,17 @@ return `new AreaSwitcher()
|
|
|
1794
1859
|
transform: this.filtero("transform", el.id, obj.customOptions),
|
|
1795
1860
|
filtera: this.filtero("filter", el.id, obj.customOptions),
|
|
1796
1861
|
raster: this.filteroRaster(el.id, obj.customOptions),
|
|
1797
|
-
})
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1862
|
+
});
|
|
1863
|
+
|
|
1864
|
+
// `items` are the list's own; the hardcoded First/Second/Third
|
|
1865
|
+
// placeholders they replace made every ulist identical.
|
|
1866
|
+
const items = Array.isArray(el.items) ? el.items : null;
|
|
1867
|
+
if (items) {
|
|
1868
|
+
list.setItems(items.map((item) => (typeof item === "string"
|
|
1869
|
+
? new Text(item).set({})
|
|
1870
|
+
: this.mapType({ ...obj, el: item }))));
|
|
1871
|
+
}
|
|
1872
|
+
return list;
|
|
1802
1873
|
}
|
|
1803
1874
|
|
|
1804
1875
|
|
|
@@ -1847,6 +1918,39 @@ return `new AreaSwitcher()
|
|
|
1847
1918
|
// invisible to filtero's `l.op.name` matching and never collide with
|
|
1848
1919
|
// the CSS-level ops. Returns undefined when nothing applies so the
|
|
1849
1920
|
// property is dropped from the generated code.
|
|
1921
|
+
/**
|
|
1922
|
+
* The element's own options, minus the keys that belong to the mapper
|
|
1923
|
+
* rather than to the component.
|
|
1924
|
+
*
|
|
1925
|
+
* `type` is always dropped: it is the ELEMENT type ("input"), not an
|
|
1926
|
+
* `<input type>`, and spreading it into a field component would set
|
|
1927
|
+
* type="input" on the DOM node. Components that want an HTML type read
|
|
1928
|
+
* `inputType` instead.
|
|
1929
|
+
*/
|
|
1930
|
+
static elOpts(el, drop = []) {
|
|
1931
|
+
const skip = new Set(["type", "children", "items", "breakpoints",
|
|
1932
|
+
"inputType", "text", "url", ...drop]);
|
|
1933
|
+
const out = {};
|
|
1934
|
+
for (const k of Object.keys(el)) if (!skip.has(k)) out[k] = el[k];
|
|
1935
|
+
return out;
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
/**
|
|
1939
|
+
* Attach a raster chain to a component whose own `set()` bypasses
|
|
1940
|
+
* Animator.commonMethods() — where `obj.raster && this.rasterize(...)`
|
|
1941
|
+
* lives. Passing `raster:` to those would be a silently dropped key.
|
|
1942
|
+
*
|
|
1943
|
+
* Returns the instance so it can be used inline. Components that are
|
|
1944
|
+
* not Animators at all (Form, RadioGroup, Switcher) have no
|
|
1945
|
+
* `rasterize`; they are skipped rather than crashed, and the gap is
|
|
1946
|
+
* recorded in the element-mapper tests.
|
|
1947
|
+
*/
|
|
1948
|
+
static attachRaster(inst, el, customOptions) {
|
|
1949
|
+
const chain = this.filteroRaster(el.id, customOptions);
|
|
1950
|
+
if (chain && inst && typeof inst.rasterize === "function") inst.rasterize(chain);
|
|
1951
|
+
return inst;
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1850
1954
|
static filteroRaster(id, customOptions) {
|
|
1851
1955
|
const list = (customOptions || []).filter((l) =>
|
|
1852
1956
|
l && typeof l.op === "string" && RASTER_OP_NAMES.includes(l.op) &&
|