@oh-just-another/templates 0.57.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/CHANGELOG.md +15 -0
- package/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/built-in.d.ts +16 -0
- package/dist/built-in.d.ts.map +1 -0
- package/dist/built-in.js +204 -0
- package/dist/built-in.js.map +1 -0
- package/dist/constants.d.ts +11 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +11 -0
- package/dist/constants.js.map +1 -0
- package/dist/icons.d.ts +21 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +24 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/library.d.ts +29 -0
- package/dist/library.d.ts.map +1 -0
- package/dist/library.js +60 -0
- package/dist/library.js.map +1 -0
- package/dist/registry.d.ts +27 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +48 -0
- package/dist/registry.js.map +1 -0
- package/dist/rich/binding.d.ts +10 -0
- package/dist/rich/binding.d.ts.map +1 -0
- package/dist/rich/binding.js +42 -0
- package/dist/rich/binding.js.map +1 -0
- package/dist/rich/bounds.d.ts +16 -0
- package/dist/rich/bounds.d.ts.map +1 -0
- package/dist/rich/bounds.js +13 -0
- package/dist/rich/bounds.js.map +1 -0
- package/dist/rich/define.d.ts +44 -0
- package/dist/rich/define.d.ts.map +1 -0
- package/dist/rich/define.js +3 -0
- package/dist/rich/define.js.map +1 -0
- package/dist/rich/drop-zones.d.ts +25 -0
- package/dist/rich/drop-zones.d.ts.map +1 -0
- package/dist/rich/drop-zones.js +63 -0
- package/dist/rich/drop-zones.js.map +1 -0
- package/dist/rich/extends.d.ts +35 -0
- package/dist/rich/extends.d.ts.map +1 -0
- package/dist/rich/extends.js +46 -0
- package/dist/rich/extends.js.map +1 -0
- package/dist/rich/hit-test.d.ts +14 -0
- package/dist/rich/hit-test.d.ts.map +1 -0
- package/dist/rich/hit-test.js +53 -0
- package/dist/rich/hit-test.js.map +1 -0
- package/dist/rich/index.d.ts +22 -0
- package/dist/rich/index.d.ts.map +1 -0
- package/dist/rich/index.js +15 -0
- package/dist/rich/index.js.map +1 -0
- package/dist/rich/interactive.d.ts +44 -0
- package/dist/rich/interactive.d.ts.map +1 -0
- package/dist/rich/interactive.js +80 -0
- package/dist/rich/interactive.js.map +1 -0
- package/dist/rich/layout.d.ts +44 -0
- package/dist/rich/layout.d.ts.map +1 -0
- package/dist/rich/layout.js +418 -0
- package/dist/rich/layout.js.map +1 -0
- package/dist/rich/node.d.ts +96 -0
- package/dist/rich/node.d.ts.map +1 -0
- package/dist/rich/node.js +7 -0
- package/dist/rich/node.js.map +1 -0
- package/dist/rich/ports.d.ts +19 -0
- package/dist/rich/ports.d.ts.map +1 -0
- package/dist/rich/ports.js +52 -0
- package/dist/rich/ports.js.map +1 -0
- package/dist/rich/registry.d.ts +19 -0
- package/dist/rich/registry.d.ts.map +1 -0
- package/dist/rich/registry.js +35 -0
- package/dist/rich/registry.js.map +1 -0
- package/dist/rich/render.d.ts +19 -0
- package/dist/rich/render.d.ts.map +1 -0
- package/dist/rich/render.js +306 -0
- package/dist/rich/render.js.map +1 -0
- package/dist/rich/style.d.ts +126 -0
- package/dist/rich/style.d.ts.map +1 -0
- package/dist/rich/style.js +35 -0
- package/dist/rich/style.js.map +1 -0
- package/dist/rich/svg.d.ts +90 -0
- package/dist/rich/svg.d.ts.map +1 -0
- package/dist/rich/svg.js +415 -0
- package/dist/rich/svg.js.map +1 -0
- package/dist/spec.d.ts +2789 -0
- package/dist/spec.d.ts.map +1 -0
- package/dist/spec.js +239 -0
- package/dist/spec.js.map +1 -0
- package/dist/types.d.ts +57 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAGpC,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACnG,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAGtB,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AAGxC,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { TemplateRegistry, defaultRegistry } from "./registry.js";
|
|
2
|
+
export { BUILTIN_TEMPLATES, installBuiltinTemplates, matchesTemplateSearch, } from "./built-in.js";
|
|
3
|
+
export * as icons from "./icons.js";
|
|
4
|
+
export { TemplateSpecZ, TemplateLibrarySpecZ, ShapeBlueprintZ, templateFromSpec } from "./spec.js";
|
|
5
|
+
export { parseTemplateLibrary, templatesFromLibrary, loadTemplateLibrary, TemplateLibraryError, } from "./library.js";
|
|
6
|
+
// Rich-template surface: node-tree + flex layout + bindings.
|
|
7
|
+
export * as rich from "./rich/index.js";
|
|
8
|
+
// Tunable visual constants.
|
|
9
|
+
export { ICON_VIEWBOX_SIZE, ICON_STROKE_WIDTH } from "./constants.js";
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAIpC,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACnG,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAEtB,6DAA6D;AAC7D,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AAExC,4BAA4B;AAC5B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type TemplateLibrarySpec } from "./spec.js";
|
|
2
|
+
import { type TemplateRegistry } from "./registry.js";
|
|
3
|
+
import type { Template } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Errors thrown by library import. Carries the underlying zod error in
|
|
6
|
+
* `reason` for callers that want field-level inspection.
|
|
7
|
+
*/
|
|
8
|
+
export declare class TemplateLibraryError extends Error {
|
|
9
|
+
readonly reason: unknown;
|
|
10
|
+
constructor(message: string, reason: unknown);
|
|
11
|
+
}
|
|
12
|
+
/** Validate `input` and return the typed library spec. */
|
|
13
|
+
export declare const parseTemplateLibrary: (input: unknown) => TemplateLibrarySpec;
|
|
14
|
+
/**
|
|
15
|
+
* Convert a validated library spec into runtime `Template[]`. Pure — no side
|
|
16
|
+
* effects on any registry.
|
|
17
|
+
*/
|
|
18
|
+
export declare const templatesFromLibrary: (lib: TemplateLibrarySpec) => readonly Template[];
|
|
19
|
+
/**
|
|
20
|
+
* Parse, materialise, and register in one call.
|
|
21
|
+
*
|
|
22
|
+
* @param input parsed JSON object or a JSON string
|
|
23
|
+
* @param registry which registry to load into (defaults to `defaultRegistry`)
|
|
24
|
+
* @param options `replace: true` overwrites duplicates; otherwise dupe ids throw
|
|
25
|
+
*/
|
|
26
|
+
export declare const loadTemplateLibrary: (input: unknown, registry?: TemplateRegistry, options?: {
|
|
27
|
+
replace?: boolean;
|
|
28
|
+
}) => readonly Template[];
|
|
29
|
+
//# sourceMappingURL=library.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"library.d.ts","sourceRoot":"","sources":["../src/library.ts"],"names":[],"mappings":"AACA,OAAO,EAA0C,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC7F,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;gBACb,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO;CAK7C;AAED,0DAA0D;AAC1D,eAAO,MAAM,oBAAoB,GAAI,OAAO,OAAO,KAAG,mBASrD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,mBAAmB,KAAG,SAAS,QAAQ,EAC5C,CAAC;AAEtC;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAC9B,OAAO,OAAO,EACd,WAAU,gBAAkC,EAC5C,UAAS;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,KAClC,SAAS,QAAQ,EASnB,CAAC"}
|
package/dist/library.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { templateFromSpec, TemplateLibrarySpecZ } from "./spec.js";
|
|
3
|
+
import { defaultRegistry } from "./registry.js";
|
|
4
|
+
/**
|
|
5
|
+
* Errors thrown by library import. Carries the underlying zod error in
|
|
6
|
+
* `reason` for callers that want field-level inspection.
|
|
7
|
+
*/
|
|
8
|
+
export class TemplateLibraryError extends Error {
|
|
9
|
+
reason;
|
|
10
|
+
constructor(message, reason) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "TemplateLibraryError";
|
|
13
|
+
this.reason = reason;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** Validate `input` and return the typed library spec. */
|
|
17
|
+
export const parseTemplateLibrary = (input) => {
|
|
18
|
+
try {
|
|
19
|
+
return TemplateLibrarySpecZ.parse(input);
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
if (err instanceof z.ZodError) {
|
|
23
|
+
throw new TemplateLibraryError(`Invalid template library: ${err.message}`, err);
|
|
24
|
+
}
|
|
25
|
+
throw err;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Convert a validated library spec into runtime `Template[]`. Pure — no side
|
|
30
|
+
* effects on any registry.
|
|
31
|
+
*/
|
|
32
|
+
export const templatesFromLibrary = (lib) => lib.templates.map(templateFromSpec);
|
|
33
|
+
/**
|
|
34
|
+
* Parse, materialise, and register in one call.
|
|
35
|
+
*
|
|
36
|
+
* @param input parsed JSON object or a JSON string
|
|
37
|
+
* @param registry which registry to load into (defaults to `defaultRegistry`)
|
|
38
|
+
* @param options `replace: true` overwrites duplicates; otherwise dupe ids throw
|
|
39
|
+
*/
|
|
40
|
+
export const loadTemplateLibrary = (input, registry = defaultRegistry, options = {}) => {
|
|
41
|
+
const raw = typeof input === "string" ? safeParseJson(input) : input;
|
|
42
|
+
const lib = parseTemplateLibrary(raw);
|
|
43
|
+
const templates = templatesFromLibrary(lib);
|
|
44
|
+
for (const t of templates) {
|
|
45
|
+
if (options.replace)
|
|
46
|
+
registry.replace(t);
|
|
47
|
+
else
|
|
48
|
+
registry.register(t);
|
|
49
|
+
}
|
|
50
|
+
return templates;
|
|
51
|
+
};
|
|
52
|
+
const safeParseJson = (s) => {
|
|
53
|
+
try {
|
|
54
|
+
return JSON.parse(s);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
throw new TemplateLibraryError("Library file is not valid JSON", err);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=library.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"library.js","sourceRoot":"","sources":["../src/library.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAA4B,MAAM,WAAW,CAAC;AAC7F,OAAO,EAAE,eAAe,EAAyB,MAAM,eAAe,CAAC;AAGvE;;;GAGG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IACpC,MAAM,CAAU;IACzB,YAAY,OAAe,EAAE,MAAe;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,0DAA0D;AAC1D,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAAc,EAAuB,EAAE;IAC1E,IAAI,CAAC;QACH,OAAO,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC9B,MAAM,IAAI,oBAAoB,CAAC,6BAA6B,GAAG,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;QAClF,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAwB,EAAuB,EAAE,CACpF,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;AAEtC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,KAAc,EACd,WAA6B,eAAe,EAC5C,UAAiC,EAAE,EACd,EAAE;IACvB,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACrE,MAAM,GAAG,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAC5C,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,IAAI,OAAO,CAAC,OAAO;YAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;;YACpC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,CAAS,EAAW,EAAE;IAC3C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,oBAAoB,CAAC,gCAAgC,EAAE,GAAG,CAAC,CAAC;IACxE,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Category, Template } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* In-process registry of templates. Plugins register at module load; the demo
|
|
4
|
+
* iterates by category to fill the palette.
|
|
5
|
+
*
|
|
6
|
+
* There is no precedence or namespace — registering an existing id throws so
|
|
7
|
+
* collisions are caught early.
|
|
8
|
+
*/
|
|
9
|
+
export declare class TemplateRegistry {
|
|
10
|
+
private readonly items;
|
|
11
|
+
register(template: Template): void;
|
|
12
|
+
/** Overwrite a registration. Use in tests / hot-reload paths. */
|
|
13
|
+
replace(template: Template): void;
|
|
14
|
+
get(id: string): Template | undefined;
|
|
15
|
+
has(id: string): boolean;
|
|
16
|
+
/** All templates in registration order. */
|
|
17
|
+
list(): readonly Template[];
|
|
18
|
+
/** Templates belonging to a given category, in registration order. */
|
|
19
|
+
byCategory(category: Category): readonly Template[];
|
|
20
|
+
/** Distinct categories present in the registry. */
|
|
21
|
+
categories(): readonly Category[];
|
|
22
|
+
/** Drop everything. */
|
|
23
|
+
clear(): void;
|
|
24
|
+
}
|
|
25
|
+
/** Default singleton used by `installBuiltinTemplates()` and most hosts. */
|
|
26
|
+
export declare const defaultRegistry: TemplateRegistry;
|
|
27
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAErD;;;;;;GAMG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+B;IAErD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAOlC,iEAAiE;IACjE,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAIjC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIrC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIxB,2CAA2C;IAC3C,IAAI,IAAI,SAAS,QAAQ,EAAE;IAI3B,sEAAsE;IACtE,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,QAAQ,EAAE;IAInD,mDAAmD;IACnD,UAAU,IAAI,SAAS,QAAQ,EAAE;IAMjC,uBAAuB;IACvB,KAAK,IAAI,IAAI;CAGd;AAED,4EAA4E;AAC5E,eAAO,MAAM,eAAe,kBAAyB,CAAC"}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-process registry of templates. Plugins register at module load; the demo
|
|
3
|
+
* iterates by category to fill the palette.
|
|
4
|
+
*
|
|
5
|
+
* There is no precedence or namespace — registering an existing id throws so
|
|
6
|
+
* collisions are caught early.
|
|
7
|
+
*/
|
|
8
|
+
export class TemplateRegistry {
|
|
9
|
+
items = new Map();
|
|
10
|
+
register(template) {
|
|
11
|
+
if (this.items.has(template.id)) {
|
|
12
|
+
throw new Error(`Template already registered: ${template.id}`);
|
|
13
|
+
}
|
|
14
|
+
this.items.set(template.id, template);
|
|
15
|
+
}
|
|
16
|
+
/** Overwrite a registration. Use in tests / hot-reload paths. */
|
|
17
|
+
replace(template) {
|
|
18
|
+
this.items.set(template.id, template);
|
|
19
|
+
}
|
|
20
|
+
get(id) {
|
|
21
|
+
return this.items.get(id);
|
|
22
|
+
}
|
|
23
|
+
has(id) {
|
|
24
|
+
return this.items.has(id);
|
|
25
|
+
}
|
|
26
|
+
/** All templates in registration order. */
|
|
27
|
+
list() {
|
|
28
|
+
return [...this.items.values()];
|
|
29
|
+
}
|
|
30
|
+
/** Templates belonging to a given category, in registration order. */
|
|
31
|
+
byCategory(category) {
|
|
32
|
+
return this.list().filter((t) => t.category === category);
|
|
33
|
+
}
|
|
34
|
+
/** Distinct categories present in the registry. */
|
|
35
|
+
categories() {
|
|
36
|
+
const out = new Set();
|
|
37
|
+
for (const t of this.items.values())
|
|
38
|
+
out.add(t.category);
|
|
39
|
+
return [...out];
|
|
40
|
+
}
|
|
41
|
+
/** Drop everything. */
|
|
42
|
+
clear() {
|
|
43
|
+
this.items.clear();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Default singleton used by `installBuiltinTemplates()` and most hosts. */
|
|
47
|
+
export const defaultRegistry = new TemplateRegistry();
|
|
48
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,OAAO,gBAAgB;IACV,KAAK,GAAG,IAAI,GAAG,EAAoB,CAAC;IAErD,QAAQ,CAAC,QAAkB;QACzB,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,gCAAgC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;QACjE,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IACxC,CAAC;IAED,iEAAiE;IACjE,OAAO,CAAC,QAAkB;QACxB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IACxC,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED,2CAA2C;IAC3C,IAAI;QACF,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,sEAAsE;IACtE,UAAU,CAAC,QAAkB;QAC3B,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;IAC5D,CAAC;IAED,mDAAmD;IACnD,UAAU;QACR,MAAM,GAAG,GAAG,IAAI,GAAG,EAAY,CAAC;QAChC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;IAClB,CAAC;IAED,uBAAuB;IACvB,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF;AAED,4EAA4E;AAC5E,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,gBAAgB,EAAE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TemplateNode } from "./node.js";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve every `{ bind: "key" }` reference in a tree against `data`. Returns
|
|
4
|
+
* a new tree with literal values in place of bindings. Unknown keys resolve
|
|
5
|
+
* to `undefined`, which the renderer treats as empty.
|
|
6
|
+
*
|
|
7
|
+
* Pure — does not mutate the input tree.
|
|
8
|
+
*/
|
|
9
|
+
export declare const resolveBindings: (node: TemplateNode, data: Readonly<Record<string, unknown>>) => TemplateNode;
|
|
10
|
+
//# sourceMappingURL=binding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../src/rich/binding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,YAAY,EAAE,MAAM,WAAW,CAAC;AAEvD;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC1B,MAAM,YAAY,EAClB,MAAM,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KACtC,YAsBF,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve every `{ bind: "key" }` reference in a tree against `data`. Returns
|
|
3
|
+
* a new tree with literal values in place of bindings. Unknown keys resolve
|
|
4
|
+
* to `undefined`, which the renderer treats as empty.
|
|
5
|
+
*
|
|
6
|
+
* Pure — does not mutate the input tree.
|
|
7
|
+
*/
|
|
8
|
+
export const resolveBindings = (node, data) => {
|
|
9
|
+
switch (node.type) {
|
|
10
|
+
case "container":
|
|
11
|
+
if (!node.children)
|
|
12
|
+
return node;
|
|
13
|
+
return {
|
|
14
|
+
...node,
|
|
15
|
+
children: node.children.map((c) => resolveBindings(c, data)),
|
|
16
|
+
};
|
|
17
|
+
case "text":
|
|
18
|
+
return { ...node, text: resolve(node.text, data, "") };
|
|
19
|
+
case "icon":
|
|
20
|
+
return { ...node, svg: resolve(node.svg, data, "") };
|
|
21
|
+
case "image":
|
|
22
|
+
return { ...node, src: resolve(node.src, data, "") };
|
|
23
|
+
case "button":
|
|
24
|
+
return node.label === undefined ? node : { ...node, label: resolve(node.label, data, "") };
|
|
25
|
+
case "drop-zone":
|
|
26
|
+
return node.label === undefined ? node : { ...node, label: resolve(node.label, data, "") };
|
|
27
|
+
case "port":
|
|
28
|
+
// Ports carry no bindings — they're pure positional markers.
|
|
29
|
+
return node;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const resolve = (value, data, fallback) => {
|
|
33
|
+
if (typeof value === "object" && value !== null && "bind" in value) {
|
|
34
|
+
const key = value.bind;
|
|
35
|
+
const raw = data[key];
|
|
36
|
+
if (raw === undefined || raw === null)
|
|
37
|
+
return fallback;
|
|
38
|
+
return raw;
|
|
39
|
+
}
|
|
40
|
+
return value;
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=binding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binding.js","sourceRoot":"","sources":["../../src/rich/binding.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,IAAkB,EAClB,IAAuC,EACzB,EAAE;IAChB,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,WAAW;YACd,IAAI,CAAC,IAAI,CAAC,QAAQ;gBAAE,OAAO,IAAI,CAAC;YAChC,OAAO;gBACL,GAAG,IAAI;gBACP,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;aAC7D,CAAC;QACJ,KAAK,MAAM;YACT,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;QACzD,KAAK,MAAM;YACT,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;QACvD,KAAK,OAAO;YACV,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;QACvD,KAAK,QAAQ;YACX,OAAO,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;QAC7F,KAAK,WAAW;YACd,OAAO,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;QAC7F,KAAK,MAAM;YACT,6DAA6D;YAC7D,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,OAAO,GAAG,CAAI,KAAiB,EAAE,IAAuC,EAAE,QAAW,EAAK,EAAE;IAChG,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;QACnE,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI;YAAE,OAAO,QAAQ,CAAC;QACvD,OAAO,GAAQ,CAAC;IAClB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Bounds } from "@oh-just-another/types";
|
|
2
|
+
import { type MeasureText } from "./layout.js";
|
|
3
|
+
import type { TemplateNode } from "./node.js";
|
|
4
|
+
/**
|
|
5
|
+
* Local AABB of a rich-template instance — the bounds of the root after
|
|
6
|
+
* layout. Use this from a `ElementBounder` registered on `"template"` to feed
|
|
7
|
+
* the scene's spatial index.
|
|
8
|
+
*/
|
|
9
|
+
export declare const getTemplateLocalBounds: (root: TemplateNode, data?: Readonly<Record<string, unknown>>, options?: {
|
|
10
|
+
measureText?: MeasureText;
|
|
11
|
+
available?: {
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
};
|
|
15
|
+
}) => Bounds;
|
|
16
|
+
//# sourceMappingURL=bounds.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bounds.d.ts","sourceRoot":"","sources":["../../src/rich/bounds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG9C;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GACjC,MAAM,YAAY,EAClB,OAAM,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAM,EAC5C,UAAS;IAAE,WAAW,CAAC,EAAE,WAAW,CAAC;IAAC,SAAS,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAO,KACzF,MAIF,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { layoutTree } from "./layout.js";
|
|
2
|
+
import { resolveBindings } from "./binding.js";
|
|
3
|
+
/**
|
|
4
|
+
* Local AABB of a rich-template instance — the bounds of the root after
|
|
5
|
+
* layout. Use this from a `ElementBounder` registered on `"template"` to feed
|
|
6
|
+
* the scene's spatial index.
|
|
7
|
+
*/
|
|
8
|
+
export const getTemplateLocalBounds = (root, data = {}, options = {}) => {
|
|
9
|
+
const resolved = resolveBindings(root, data);
|
|
10
|
+
const layouted = layoutTree(resolved, options);
|
|
11
|
+
return layouted.bounds;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=bounds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bounds.js","sourceRoot":"","sources":["../../src/rich/bounds.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAoB,MAAM,aAAa,CAAC;AAE3D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,IAAkB,EAClB,OAA0C,EAAE,EAC5C,UAAwF,EAAE,EAClF,EAAE;IACV,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC/C,OAAO,QAAQ,CAAC,MAAM,CAAC;AACzB,CAAC,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { TemplateNode } from "./node.js";
|
|
2
|
+
/**
|
|
3
|
+
* Description of a rich template's data shape. Each entry maps a `{ bind: }`
|
|
4
|
+
* key in the tree to its expected runtime type. The kernel does not enforce
|
|
5
|
+
* the schema beyond surfacing it in the registry — host UIs use it to render
|
|
6
|
+
* forms / inspectors.
|
|
7
|
+
*/
|
|
8
|
+
export type RichTemplateSchema = Readonly<Record<string, "string" | "number" | "boolean">>;
|
|
9
|
+
/**
|
|
10
|
+
* A rich template definition: tree + binding schema + version. Versioning is
|
|
11
|
+
* the template's own — kernel migrations apply to the scene document, not to
|
|
12
|
+
* individual templates.
|
|
13
|
+
*/
|
|
14
|
+
export interface RichTemplate {
|
|
15
|
+
readonly id: string;
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly category: string;
|
|
18
|
+
/** SVG markup for the palette thumbnail. */
|
|
19
|
+
readonly icon: string;
|
|
20
|
+
/** Root of the layout tree. */
|
|
21
|
+
readonly root: TemplateNode;
|
|
22
|
+
readonly schema?: RichTemplateSchema;
|
|
23
|
+
readonly version?: number;
|
|
24
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
25
|
+
/**
|
|
26
|
+
* Default values for the `data` argument the host will pass to the editor
|
|
27
|
+
* when an instance is created. Optional; the host can substitute its own.
|
|
28
|
+
*/
|
|
29
|
+
readonly defaults?: Readonly<Record<string, unknown>>;
|
|
30
|
+
/**
|
|
31
|
+
* Interactive-resize constraints. Copied onto the spawned `TemplateElement`'s
|
|
32
|
+
* `minWidth` / `minHeight` / `maxWidth` / `maxHeight` / `noFlip` fields so
|
|
33
|
+
* the editor enforces them. Omitted = no constraint on that axis.
|
|
34
|
+
*/
|
|
35
|
+
readonly minWidth?: number;
|
|
36
|
+
readonly minHeight?: number;
|
|
37
|
+
readonly maxWidth?: number;
|
|
38
|
+
readonly maxHeight?: number;
|
|
39
|
+
/** Disable mirroring when overshooting the opposite edge. Defaults to `false`. */
|
|
40
|
+
readonly noFlip?: boolean;
|
|
41
|
+
}
|
|
42
|
+
/** Type-safe constructor for `RichTemplate`. Identity function. */
|
|
43
|
+
export declare const defineRichTemplate: (template: RichTemplate) => RichTemplate;
|
|
44
|
+
//# sourceMappingURL=define.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/rich/define.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC;AAE3F;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,4CAA4C;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+BAA+B;IAC/B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtD;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAEtD;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,mEAAmE;AACnE,eAAO,MAAM,kBAAkB,GAAI,UAAU,YAAY,KAAG,YAAwB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define.js","sourceRoot":"","sources":["../../src/rich/define.ts"],"names":[],"mappings":"AA6CA,mEAAmE;AACnE,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,QAAsB,EAAgB,EAAE,CAAC,QAAQ,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Bounds } from "@oh-just-another/types";
|
|
2
|
+
import type { LayoutedNode } from "./layout.js";
|
|
3
|
+
/**
|
|
4
|
+
* Walk a layouted template tree and find the first `drop-zone` node.
|
|
5
|
+
* Returns its bounds in **local** coordinates — relative to the
|
|
6
|
+
* template root's top-left (so it can be stored as
|
|
7
|
+
* `shape.metadata.container.dropZone` without further translation).
|
|
8
|
+
*
|
|
9
|
+
* Templates with multiple drop-zone nodes are unusual; this helper
|
|
10
|
+
* returns the **largest** one (by area) so that the container
|
|
11
|
+
* protocol picks the meaningful body region instead of a tiny
|
|
12
|
+
* decoration. Returns `null` when the tree has no drop-zone.
|
|
13
|
+
*/
|
|
14
|
+
export declare const extractDropZone: (root: LayoutedNode) => Bounds | null;
|
|
15
|
+
/**
|
|
16
|
+
* Walk a layouted template tree and return **every** `drop-zone` node's bounds
|
|
17
|
+
* in **local** coordinates (relative to the root top-left), in tree order.
|
|
18
|
+
*
|
|
19
|
+
* Unlike `extractDropZone` (which collapses to the single largest zone for the
|
|
20
|
+
* container-attach protocol), this keeps all zones — e.g. each lane of a
|
|
21
|
+
* multi-lane swim-lane. Used by the debug hit-zone overlay to highlight every
|
|
22
|
+
* drop region; returns `[]` when the tree has no drop-zone.
|
|
23
|
+
*/
|
|
24
|
+
export declare const extractAllDropZones: (root: LayoutedNode) => Bounds[];
|
|
25
|
+
//# sourceMappingURL=drop-zones.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drop-zones.d.ts","sourceRoot":"","sources":["../../src/rich/drop-zones.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,YAAY,KAAG,MAAM,GAAG,IAuB7D,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,YAAY,KAAG,MAAM,EAgB9D,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Walk a layouted template tree and find the first `drop-zone` node.
|
|
3
|
+
* Returns its bounds in **local** coordinates — relative to the
|
|
4
|
+
* template root's top-left (so it can be stored as
|
|
5
|
+
* `shape.metadata.container.dropZone` without further translation).
|
|
6
|
+
*
|
|
7
|
+
* Templates with multiple drop-zone nodes are unusual; this helper
|
|
8
|
+
* returns the **largest** one (by area) so that the container
|
|
9
|
+
* protocol picks the meaningful body region instead of a tiny
|
|
10
|
+
* decoration. Returns `null` when the tree has no drop-zone.
|
|
11
|
+
*/
|
|
12
|
+
export const extractDropZone = (root) => {
|
|
13
|
+
const rootBounds = root.bounds;
|
|
14
|
+
let best = null;
|
|
15
|
+
let bestArea = 0;
|
|
16
|
+
const visit = (l) => {
|
|
17
|
+
if (l.node.type === "drop-zone") {
|
|
18
|
+
const local = {
|
|
19
|
+
x: l.bounds.x - rootBounds.x,
|
|
20
|
+
y: l.bounds.y - rootBounds.y,
|
|
21
|
+
width: l.bounds.width,
|
|
22
|
+
height: l.bounds.height,
|
|
23
|
+
};
|
|
24
|
+
const area = local.width * local.height;
|
|
25
|
+
if (area > bestArea) {
|
|
26
|
+
best = local;
|
|
27
|
+
bestArea = area;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
for (const child of l.children)
|
|
31
|
+
visit(child);
|
|
32
|
+
};
|
|
33
|
+
visit(root);
|
|
34
|
+
return best;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Walk a layouted template tree and return **every** `drop-zone` node's bounds
|
|
38
|
+
* in **local** coordinates (relative to the root top-left), in tree order.
|
|
39
|
+
*
|
|
40
|
+
* Unlike `extractDropZone` (which collapses to the single largest zone for the
|
|
41
|
+
* container-attach protocol), this keeps all zones — e.g. each lane of a
|
|
42
|
+
* multi-lane swim-lane. Used by the debug hit-zone overlay to highlight every
|
|
43
|
+
* drop region; returns `[]` when the tree has no drop-zone.
|
|
44
|
+
*/
|
|
45
|
+
export const extractAllDropZones = (root) => {
|
|
46
|
+
const rootBounds = root.bounds;
|
|
47
|
+
const zones = [];
|
|
48
|
+
const visit = (l) => {
|
|
49
|
+
if (l.node.type === "drop-zone") {
|
|
50
|
+
zones.push({
|
|
51
|
+
x: l.bounds.x - rootBounds.x,
|
|
52
|
+
y: l.bounds.y - rootBounds.y,
|
|
53
|
+
width: l.bounds.width,
|
|
54
|
+
height: l.bounds.height,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
for (const child of l.children)
|
|
58
|
+
visit(child);
|
|
59
|
+
};
|
|
60
|
+
visit(root);
|
|
61
|
+
return zones;
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=drop-zones.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drop-zones.js","sourceRoot":"","sources":["../../src/rich/drop-zones.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAAkB,EAAiB,EAAE;IACnE,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;IAC/B,IAAI,IAAI,GAAkB,IAAI,CAAC;IAC/B,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,MAAM,KAAK,GAAG,CAAC,CAAe,EAAQ,EAAE;QACtC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAChC,MAAM,KAAK,GAAW;gBACpB,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC;gBAC5B,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC;gBAC5B,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK;gBACrB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM;aACxB,CAAC;YACF,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;YACxC,IAAI,IAAI,GAAG,QAAQ,EAAE,CAAC;gBACpB,IAAI,GAAG,KAAK,CAAC;gBACb,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;QACH,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,QAAQ;YAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAkB,EAAY,EAAE;IAClE,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;IAC/B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,CAAC,CAAe,EAAQ,EAAE;QACtC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CAAC;gBACT,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC;gBAC5B,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC;gBAC5B,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK;gBACrB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM;aACxB,CAAC,CAAC;QACL,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,QAAQ;YAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,OAAO,KAAK,CAAC;AACf,CAAC,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { RichTemplate } from "./define.js";
|
|
2
|
+
/**
|
|
3
|
+
* Recipe for building a rich template by extending another. The base
|
|
4
|
+
* template is looked up by id in a registry-like map; `overrides` is
|
|
5
|
+
* deep-merged on top.
|
|
6
|
+
*
|
|
7
|
+
* extendRichTemplate({
|
|
8
|
+
* id: "myorg.bigger-card",
|
|
9
|
+
* extends: "myorg.card",
|
|
10
|
+
* overrides: { width: 360, defaults: { title: "Big" } },
|
|
11
|
+
* }, registry)
|
|
12
|
+
*/
|
|
13
|
+
export interface RichTemplateExtension {
|
|
14
|
+
readonly id: string;
|
|
15
|
+
readonly extends: string;
|
|
16
|
+
readonly name?: string;
|
|
17
|
+
readonly category?: string;
|
|
18
|
+
readonly icon?: string;
|
|
19
|
+
readonly overrides?: DeepPartial<RichTemplate>;
|
|
20
|
+
}
|
|
21
|
+
type DeepPartial<T> = {
|
|
22
|
+
[K in keyof T]?: T[K] extends Readonly<Record<string, unknown>> ? DeepPartial<T[K]> : T[K] extends readonly (infer U)[] ? readonly U[] : T[K];
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Resolve a `RichTemplateExtension` (and any chain of base templates it
|
|
26
|
+
* references) into a fully-merged `RichTemplate`. Each layer's
|
|
27
|
+
* `overrides` are deep-merged on top of the previous (base first, leaf
|
|
28
|
+
* last) so child layers naturally win.
|
|
29
|
+
*
|
|
30
|
+
* `lookup` is the registry accessor — usually `(id) => registry.get(id)`.
|
|
31
|
+
* Throws if the chain references a missing base id.
|
|
32
|
+
*/
|
|
33
|
+
export declare const resolveRichTemplateChain: (ext: RichTemplateExtension, lookup: (id: string) => RichTemplate | RichTemplateExtension | undefined) => RichTemplate;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=extends.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extends.d.ts","sourceRoot":"","sources":["../../src/rich/extends.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;CAChD;AAED,KAAK,WAAW,CAAC,CAAC,IAAI;KACnB,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC3D,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACjB,CAAC,CAAC,CAAC,CAAC,SAAS,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GAC/B,SAAS,CAAC,EAAE,GACZ,CAAC,CAAC,CAAC,CAAC;CACX,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,GACnC,KAAK,qBAAqB,EAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,KAAK,YAAY,GAAG,qBAAqB,GAAG,SAAS,KACvE,YAyBF,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a `RichTemplateExtension` (and any chain of base templates it
|
|
3
|
+
* references) into a fully-merged `RichTemplate`. Each layer's
|
|
4
|
+
* `overrides` are deep-merged on top of the previous (base first, leaf
|
|
5
|
+
* last) so child layers naturally win.
|
|
6
|
+
*
|
|
7
|
+
* `lookup` is the registry accessor — usually `(id) => registry.get(id)`.
|
|
8
|
+
* Throws if the chain references a missing base id.
|
|
9
|
+
*/
|
|
10
|
+
export const resolveRichTemplateChain = (ext, lookup) => {
|
|
11
|
+
const chain = [ext];
|
|
12
|
+
let current = lookup(ext.extends);
|
|
13
|
+
while (current && "extends" in current) {
|
|
14
|
+
chain.unshift(current);
|
|
15
|
+
current = lookup(current.extends);
|
|
16
|
+
}
|
|
17
|
+
if (!current) {
|
|
18
|
+
const first = chain[0];
|
|
19
|
+
throw new Error(`Rich template "${ext.id}" extends "${first ? first.extends : ext.extends}", which is not registered.`);
|
|
20
|
+
}
|
|
21
|
+
// `current` is the concrete base `RichTemplate` now.
|
|
22
|
+
let result = current;
|
|
23
|
+
for (const layer of chain) {
|
|
24
|
+
result = mergeRichTemplate(result, {
|
|
25
|
+
id: layer.id,
|
|
26
|
+
...(layer.name !== undefined ? { name: layer.name } : {}),
|
|
27
|
+
...(layer.category !== undefined ? { category: layer.category } : {}),
|
|
28
|
+
...(layer.icon !== undefined ? { icon: layer.icon } : {}),
|
|
29
|
+
...(layer.overrides ?? {}),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
const mergeRichTemplate = (base, patch) => {
|
|
35
|
+
return {
|
|
36
|
+
...base,
|
|
37
|
+
...patch,
|
|
38
|
+
// Defaults merge object-shallow — overriding individual keys is the
|
|
39
|
+
// common case; full replacement is rare and authors can pass the
|
|
40
|
+
// whole object.
|
|
41
|
+
...(patch.defaults !== undefined ? { defaults: { ...base.defaults, ...patch.defaults } } : {}),
|
|
42
|
+
// Same for metadata.
|
|
43
|
+
...(patch.metadata !== undefined ? { metadata: { ...base.metadata, ...patch.metadata } } : {}),
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=extends.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extends.js","sourceRoot":"","sources":["../../src/rich/extends.ts"],"names":[],"mappings":"AA8BA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CACtC,GAA0B,EAC1B,MAAwE,EAC1D,EAAE;IAChB,MAAM,KAAK,GAA4B,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,OAAO,GAAqD,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACpF,OAAO,OAAO,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;QACvC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvB,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IACD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,kBAAkB,GAAG,CAAC,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,6BAA6B,CACvG,CAAC;IACJ,CAAC;IACD,qDAAqD;IACrD,IAAI,MAAM,GAAiB,OAAO,CAAC;IACnC,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,GAAG,iBAAiB,CAAC,MAAM,EAAE;YACjC,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzD,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrE,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzD,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CACxB,IAAkB,EAClB,KAAiD,EACnC,EAAE;IAChB,OAAO;QACL,GAAG,IAAI;QACP,GAAG,KAAK;QACR,oEAAoE;QACpE,iEAAiE;QACjE,gBAAgB;QAChB,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9F,qBAAqB;QACrB,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/F,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Vec2 } from "@oh-just-another/types";
|
|
2
|
+
import type { LayoutedNode } from "./layout.js";
|
|
3
|
+
/**
|
|
4
|
+
* Walk the layouted tree top-down (parent before children) and return the
|
|
5
|
+
* deepest node that contains `point`. Returns `null` if `point` lies outside
|
|
6
|
+
* the root bounds. Coordinates are in the template's local space.
|
|
7
|
+
*/
|
|
8
|
+
export declare const nodeAtPoint: (root: LayoutedNode, point: Vec2) => LayoutedNode | null;
|
|
9
|
+
/**
|
|
10
|
+
* Like `nodeAtPoint` but only returns interactive nodes (`button` or
|
|
11
|
+
* `drop-zone`). Returns the innermost interactive ancestor under `point`.
|
|
12
|
+
*/
|
|
13
|
+
export declare const interactiveNodeAtPoint: (root: LayoutedNode, point: Vec2) => LayoutedNode | null;
|
|
14
|
+
//# sourceMappingURL=hit-test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hit-test.d.ts","sourceRoot":"","sources":["../../src/rich/hit-test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAOhD;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,YAAY,EAAE,OAAO,IAAI,KAAG,YAAY,GAAG,IAO5E,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,sBAAsB,GAAI,MAAM,YAAY,EAAE,OAAO,IAAI,KAAG,YAAY,GAAG,IAIvF,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { isInteractive } from "./node.js";
|
|
2
|
+
const containsPoint = (b, p) => p.x >= b.x && p.x <= b.x + b.width && p.y >= b.y && p.y <= b.y + b.height;
|
|
3
|
+
/**
|
|
4
|
+
* Walk the layouted tree top-down (parent before children) and return the
|
|
5
|
+
* deepest node that contains `point`. Returns `null` if `point` lies outside
|
|
6
|
+
* the root bounds. Coordinates are in the template's local space.
|
|
7
|
+
*/
|
|
8
|
+
export const nodeAtPoint = (root, point) => {
|
|
9
|
+
if (!containsPoint(root.bounds, point))
|
|
10
|
+
return null;
|
|
11
|
+
for (const child of root.children) {
|
|
12
|
+
const hit = nodeAtPoint(child, point);
|
|
13
|
+
if (hit)
|
|
14
|
+
return hit;
|
|
15
|
+
}
|
|
16
|
+
return root;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Like `nodeAtPoint` but only returns interactive nodes (`button` or
|
|
20
|
+
* `drop-zone`). Returns the innermost interactive ancestor under `point`.
|
|
21
|
+
*/
|
|
22
|
+
export const interactiveNodeAtPoint = (root, point) => {
|
|
23
|
+
const hit = nodeAtPoint(root, point);
|
|
24
|
+
if (!hit)
|
|
25
|
+
return null;
|
|
26
|
+
return findInteractiveAncestor(root, hit);
|
|
27
|
+
};
|
|
28
|
+
const findInteractiveAncestor = (root, target) => {
|
|
29
|
+
if (target === root) {
|
|
30
|
+
return isInteractive(root.node) ? root : null;
|
|
31
|
+
}
|
|
32
|
+
// Walk parent chain top-down. Build the chain by DFS from root.
|
|
33
|
+
const chain = findChain(root, target);
|
|
34
|
+
if (!chain)
|
|
35
|
+
return null;
|
|
36
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
37
|
+
const node = chain[i];
|
|
38
|
+
if (node && isInteractive(node.node))
|
|
39
|
+
return node;
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
};
|
|
43
|
+
const findChain = (root, target) => {
|
|
44
|
+
if (root === target)
|
|
45
|
+
return [root];
|
|
46
|
+
for (const child of root.children) {
|
|
47
|
+
const inner = findChain(child, target);
|
|
48
|
+
if (inner)
|
|
49
|
+
return [root, ...inner];
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=hit-test.js.map
|