@toyz/loom 0.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.
Files changed (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +108 -0
  3. package/dist/app.d.ts +70 -0
  4. package/dist/app.d.ts.map +1 -0
  5. package/dist/app.js +152 -0
  6. package/dist/app.js.map +1 -0
  7. package/dist/bus.d.ts +27 -0
  8. package/dist/bus.d.ts.map +1 -0
  9. package/dist/bus.js +41 -0
  10. package/dist/bus.js.map +1 -0
  11. package/dist/css.d.ts +25 -0
  12. package/dist/css.d.ts.map +1 -0
  13. package/dist/css.js +48 -0
  14. package/dist/css.js.map +1 -0
  15. package/dist/decorators/component.d.ts +11 -0
  16. package/dist/decorators/component.d.ts.map +1 -0
  17. package/dist/decorators/component.js +38 -0
  18. package/dist/decorators/component.js.map +1 -0
  19. package/dist/decorators/di.d.ts +37 -0
  20. package/dist/decorators/di.d.ts.map +1 -0
  21. package/dist/decorators/di.js +65 -0
  22. package/dist/decorators/di.js.map +1 -0
  23. package/dist/decorators/dom.d.ts +15 -0
  24. package/dist/decorators/dom.d.ts.map +1 -0
  25. package/dist/decorators/dom.js +33 -0
  26. package/dist/decorators/dom.js.map +1 -0
  27. package/dist/decorators/events.d.ts +46 -0
  28. package/dist/decorators/events.d.ts.map +1 -0
  29. package/dist/decorators/events.js +69 -0
  30. package/dist/decorators/events.js.map +1 -0
  31. package/dist/decorators/index.d.ts +18 -0
  32. package/dist/decorators/index.d.ts.map +1 -0
  33. package/dist/decorators/index.js +27 -0
  34. package/dist/decorators/index.js.map +1 -0
  35. package/dist/decorators/lifecycle.d.ts +49 -0
  36. package/dist/decorators/lifecycle.d.ts.map +1 -0
  37. package/dist/decorators/lifecycle.js +105 -0
  38. package/dist/decorators/lifecycle.js.map +1 -0
  39. package/dist/decorators/state.d.ts +41 -0
  40. package/dist/decorators/state.d.ts.map +1 -0
  41. package/dist/decorators/state.js +125 -0
  42. package/dist/decorators/state.js.map +1 -0
  43. package/dist/decorators/symbols.d.ts +13 -0
  44. package/dist/decorators/symbols.d.ts.map +1 -0
  45. package/dist/decorators/symbols.js +15 -0
  46. package/dist/decorators/symbols.js.map +1 -0
  47. package/dist/decorators/timing.d.ts +35 -0
  48. package/dist/decorators/timing.d.ts.map +1 -0
  49. package/dist/decorators/timing.js +57 -0
  50. package/dist/decorators/timing.js.map +1 -0
  51. package/dist/decorators/transform.d.ts +45 -0
  52. package/dist/decorators/transform.d.ts.map +1 -0
  53. package/dist/decorators/transform.js +48 -0
  54. package/dist/decorators/transform.js.map +1 -0
  55. package/dist/element.d.ts +62 -0
  56. package/dist/element.d.ts.map +1 -0
  57. package/dist/element.js +150 -0
  58. package/dist/element.js.map +1 -0
  59. package/dist/event.d.ts +24 -0
  60. package/dist/event.d.ts.map +1 -0
  61. package/dist/event.js +35 -0
  62. package/dist/event.js.map +1 -0
  63. package/dist/icon.d.ts +35 -0
  64. package/dist/icon.d.ts.map +1 -0
  65. package/dist/icon.js +119 -0
  66. package/dist/icon.js.map +1 -0
  67. package/dist/index.d.ts +29 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +34 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/jsx-dev-runtime.d.ts +8 -0
  72. package/dist/jsx-dev-runtime.d.ts.map +1 -0
  73. package/dist/jsx-dev-runtime.js +8 -0
  74. package/dist/jsx-dev-runtime.js.map +1 -0
  75. package/dist/jsx-runtime.d.ts +13 -0
  76. package/dist/jsx-runtime.d.ts.map +1 -0
  77. package/dist/jsx-runtime.js +101 -0
  78. package/dist/jsx-runtime.js.map +1 -0
  79. package/dist/morph.d.ts +23 -0
  80. package/dist/morph.d.ts.map +1 -0
  81. package/dist/morph.js +212 -0
  82. package/dist/morph.js.map +1 -0
  83. package/dist/reactive.d.ts +75 -0
  84. package/dist/reactive.d.ts.map +1 -0
  85. package/dist/reactive.js +133 -0
  86. package/dist/reactive.js.map +1 -0
  87. package/dist/render-loop.d.ts +34 -0
  88. package/dist/render-loop.d.ts.map +1 -0
  89. package/dist/render-loop.js +70 -0
  90. package/dist/render-loop.js.map +1 -0
  91. package/dist/router/events.d.ts +12 -0
  92. package/dist/router/events.d.ts.map +1 -0
  93. package/dist/router/events.js +17 -0
  94. package/dist/router/events.js.map +1 -0
  95. package/dist/router/index.d.ts +14 -0
  96. package/dist/router/index.d.ts.map +1 -0
  97. package/dist/router/index.js +18 -0
  98. package/dist/router/index.js.map +1 -0
  99. package/dist/router/link.d.ts +18 -0
  100. package/dist/router/link.d.ts.map +1 -0
  101. package/dist/router/link.js +75 -0
  102. package/dist/router/link.js.map +1 -0
  103. package/dist/router/mode.d.ts +33 -0
  104. package/dist/router/mode.d.ts.map +1 -0
  105. package/dist/router/mode.js +48 -0
  106. package/dist/router/mode.js.map +1 -0
  107. package/dist/router/outlet.d.ts +40 -0
  108. package/dist/router/outlet.d.ts.map +1 -0
  109. package/dist/router/outlet.js +171 -0
  110. package/dist/router/outlet.js.map +1 -0
  111. package/dist/router/route.d.ts +76 -0
  112. package/dist/router/route.d.ts.map +1 -0
  113. package/dist/router/route.js +147 -0
  114. package/dist/router/route.js.map +1 -0
  115. package/dist/router/router.d.ts +50 -0
  116. package/dist/router/router.d.ts.map +1 -0
  117. package/dist/router/router.js +140 -0
  118. package/dist/router/router.js.map +1 -0
  119. package/dist/storage.d.ts +55 -0
  120. package/dist/storage.d.ts.map +1 -0
  121. package/dist/storage.js +90 -0
  122. package/dist/storage.js.map +1 -0
  123. package/dist/virtual.d.ts +69 -0
  124. package/dist/virtual.d.ts.map +1 -0
  125. package/dist/virtual.js +247 -0
  126. package/dist/virtual.js.map +1 -0
  127. package/package.json +58 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 toyz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,108 @@
1
+ <p align="center">
2
+ <img src="https://toyz.github.io/loom/loom-logo.svg" alt="Loom" width="80" />
3
+ </p>
4
+
5
+ <h1 align="center">Loom</h1>
6
+
7
+ <p align="center">
8
+ Decorator-driven web components that started as a meme and accidentally became useful.
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/@toyz/loom"><img src="https://img.shields.io/npm/v/@toyz/loom?color=c084fc&label=npm" alt="npm" /></a>
13
+ <a href="https://toyz.github.io/loom/"><img src="https://img.shields.io/badge/docs-live-86efac" alt="docs" /></a>
14
+ <a href="https://placing.space"><img src="https://img.shields.io/badge/used%20on-placing.space-67e8f9" alt="placing.space" /></a>
15
+ <a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-fbbf24" alt="MIT" /></a>
16
+ </p>
17
+
18
+ ---
19
+
20
+ ## What is this?
21
+
22
+ Loom was born out of pure spite for boilerplate. What began as an ironic "what if decorators did _everything_?" experiment turned into a genuinely useful framework for building web components.
23
+
24
+ It powers [placing.space](https://placing.space) in production — a real-time collaborative pixel canvas — so it's been battle-tested with WebSocket streams, thousands of DOM nodes, and zero framework overhead.
25
+
26
+ ## Features
27
+
28
+ - **`@component`** — register custom elements in one line
29
+ - **`@reactive` / `@prop`** — fine-grained reactivity that only re-renders what changed
30
+ - **`@computed` / `@watch`** — derived state and side effects
31
+ - **`@on` / `@emit`** — declarative event handling
32
+ - **JSX + DOM morphing** — write JSX, get surgical DOM patches (no virtual DOM)
33
+ - **`@inject` / `@service`** — dependency injection container
34
+ - **Hash & history router** — `@route`, `@guard`, `<loom-outlet>`
35
+ - **`css\`\``** — adopted stylesheets with zero FOUC
36
+ - **`<loom-virtual>`** — virtualized list for huge datasets
37
+ - **Zero dependencies** — just TypeScript and the platform
38
+
39
+ ## Install
40
+
41
+ ```bash
42
+ npm install @toyz/loom
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ```ts
48
+ import { LoomElement, component, reactive, css } from "@toyz/loom";
49
+
50
+ const styles = css`
51
+ button { padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer; }
52
+ span { font-weight: bold; margin-left: 0.5rem; }
53
+ `;
54
+
55
+ @component("click-counter")
56
+ class ClickCounter extends LoomElement {
57
+ @reactive count = 0;
58
+
59
+ update() {
60
+ this.shadow.adoptedStyleSheets = [styles];
61
+ return (
62
+ <button onClick={() => this.count++}>
63
+ Clicks: <span>{this.count}</span>
64
+ </button>
65
+ );
66
+ }
67
+ }
68
+ ```
69
+
70
+ ```html
71
+ <click-counter></click-counter>
72
+ <script type="module" src="./main.ts"></script>
73
+ ```
74
+
75
+ ## TSConfig
76
+
77
+ Loom ships its own JSX runtime. Point your config at it:
78
+
79
+ ```json
80
+ {
81
+ "compilerOptions": {
82
+ "jsx": "react-jsx",
83
+ "jsxImportSource": "@toyz/loom"
84
+ }
85
+ }
86
+ ```
87
+
88
+ For Vite:
89
+
90
+ ```ts
91
+ // vite.config.ts
92
+ export default defineConfig({
93
+ esbuild: {
94
+ jsx: "automatic",
95
+ jsxImportSource: "@toyz/loom",
96
+ },
97
+ });
98
+ ```
99
+
100
+ ## Docs
101
+
102
+ Full documentation with interactive examples:
103
+
104
+ **[toyz.github.io/loom](https://toyz.github.io/loom/)**
105
+
106
+ ## License
107
+
108
+ [MIT](./LICENSE) — do whatever you want with it.
package/dist/app.d.ts ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Loom — Application entry point
3
+ *
4
+ * Boots the render loop, instantiates @service singletons,
5
+ * runs @factory methods, and registers @component custom elements.
6
+ *
7
+ * ```ts
8
+ * import { app } from "loom";
9
+ *
10
+ * app
11
+ * .use(natsConnection)
12
+ * .use(chatClient)
13
+ * .start();
14
+ * ```
15
+ */
16
+ import { type Constructor, type Handler } from "./bus";
17
+ import type { LoomEvent } from "./event";
18
+ declare class LoomApp {
19
+ private providers;
20
+ private services;
21
+ private factories;
22
+ private components;
23
+ private _started;
24
+ /** Subscribe to a typed event. Returns unsubscribe function. */
25
+ on<T>(type: Constructor<T>, handler: Handler<T>): () => void;
26
+ /** Emit a typed event to all listeners. */
27
+ emit<T extends LoomEvent>(event: T): void;
28
+ /** Remove a specific event handler. */
29
+ off<T>(type: Constructor<T>, handler: Handler<T>): void;
30
+ /**
31
+ * Chainable provider registration.
32
+ *
33
+ * app.use(instance) — key auto-inferred from constructor
34
+ * app.use(MyClass) — class constructor, auto-instantiated
35
+ * app.use(() => createThing()) — factory fn, key from result constructor
36
+ * app.use(Key, instance) — explicit key
37
+ *
38
+ * T is always optional — no magic typing forced.
39
+ */
40
+ use<T = any>(thing: T): this;
41
+ use<T = any>(key: any, instance: T): this;
42
+ /** Queue a @service class for auto-instantiation on start() */
43
+ registerService(ctor: any): void;
44
+ /** Queue a @factory method for invocation on start() */
45
+ registerFactory(key: any, proto: any, method: string): void;
46
+ /** Queue a @component for customElements.define() on start() */
47
+ register(tag: string, ctor: CustomElementConstructor): void;
48
+ /** Retrieve a provider/service by key. Throws if missing. */
49
+ get<T = any>(key: any): T;
50
+ /** Retrieve a provider/service, or undefined if not registered. */
51
+ maybe<T = any>(key: any): T | undefined;
52
+ /** Resolve @inject parameter metadata for a constructor or method. */
53
+ private resolveParams;
54
+ /**
55
+ * Boot the app:
56
+ * 1. Auto-instantiate @service singletons (with constructor @inject)
57
+ * 2. Run @factory methods (with parameter @inject)
58
+ * 3. Start the render loop
59
+ * 4. Register all @component custom elements
60
+ */
61
+ start(): Promise<void>;
62
+ /** Tear down — stop render loop */
63
+ stop(): void;
64
+ /** Whether the app has been started */
65
+ get started(): boolean;
66
+ }
67
+ /** Module-level singleton — the Loom app instance */
68
+ export declare const app: LoomApp;
69
+ export type { LoomApp };
70
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,EAAO,KAAK,WAAW,EAAE,KAAK,OAAO,EAAE,MAAM,OAAO,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAQzC,cAAM,OAAO;IACX,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,UAAU,CAAyD;IAC3E,OAAO,CAAC,QAAQ,CAAS;IAIzB,gEAAgE;IAChE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAE5D,2CAA2C;IAC3C,IAAI,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAEzC,uCAAuC;IACvC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI;IAIvD;;;;;;;;;OASG;IACH,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAC5B,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI;IAuBzC,+DAA+D;IAC/D,eAAe,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI;IAIhC,wDAAwD;IACxD,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAI3D,gEAAgE;IAChE,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,wBAAwB,GAAG,IAAI;IAM3D,6DAA6D;IAC7D,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC;IAQzB,mEAAmE;IACnE,KAAK,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,GAAG,SAAS;IAIvC,sEAAsE;IACtE,OAAO,CAAC,aAAa;IAWrB;;;;;;OAMG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA+C5B,mCAAmC;IACnC,IAAI,IAAI,IAAI;IAKZ,uCAAuC;IACvC,IAAI,OAAO,IAAI,OAAO,CAErB;CACF;AAED,qDAAqD;AACrD,eAAO,MAAM,GAAG,SAAgB,CAAC;AACjC,YAAY,EAAE,OAAO,EAAE,CAAC"}
package/dist/app.js ADDED
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Loom — Application entry point
3
+ *
4
+ * Boots the render loop, instantiates @service singletons,
5
+ * runs @factory methods, and registers @component custom elements.
6
+ *
7
+ * ```ts
8
+ * import { app } from "loom";
9
+ *
10
+ * app
11
+ * .use(natsConnection)
12
+ * .use(chatClient)
13
+ * .start();
14
+ * ```
15
+ */
16
+ import { renderLoop } from "./render-loop";
17
+ import { INJECT_PARAMS, ON_HANDLERS } from "./decorators";
18
+ import { bus } from "./bus";
19
+ class LoomApp {
20
+ providers = new Map();
21
+ services = [];
22
+ factories = [];
23
+ components = [];
24
+ _started = false;
25
+ // ── Event bus (delegates to the module-level bus singleton) ──
26
+ /** Subscribe to a typed event. Returns unsubscribe function. */
27
+ on(type, handler) { return bus.on(type, handler); }
28
+ /** Emit a typed event to all listeners. */
29
+ emit(event) { bus.emit(event); }
30
+ /** Remove a specific event handler. */
31
+ off(type, handler) { bus.off(type, handler); }
32
+ use(keyOrThing, instance) {
33
+ if (instance !== undefined) {
34
+ // Explicit key: app.use(Key, value)
35
+ this.providers.set(keyOrThing, instance);
36
+ }
37
+ else if (typeof keyOrThing === "function") {
38
+ if (keyOrThing.prototype?.constructor === keyOrThing) {
39
+ // Class constructor → instantiate
40
+ this.providers.set(keyOrThing, new keyOrThing());
41
+ }
42
+ else {
43
+ // Factory function → call it
44
+ const result = keyOrThing();
45
+ this.providers.set(result.constructor, result);
46
+ }
47
+ }
48
+ else {
49
+ // Instance → key from constructor
50
+ this.providers.set(keyOrThing.constructor, keyOrThing);
51
+ }
52
+ return this;
53
+ }
54
+ // ── Registration (called by decorators) ──
55
+ /** Queue a @service class for auto-instantiation on start() */
56
+ registerService(ctor) {
57
+ this.services.push(ctor);
58
+ }
59
+ /** Queue a @factory method for invocation on start() */
60
+ registerFactory(key, proto, method) {
61
+ this.factories.push({ proto, method, key });
62
+ }
63
+ /** Queue a @component for customElements.define() on start() */
64
+ register(tag, ctor) {
65
+ this.components.push({ tag, ctor });
66
+ }
67
+ // ── Resolution ──
68
+ /** Retrieve a provider/service by key. Throws if missing. */
69
+ get(key) {
70
+ const v = this.providers.get(key);
71
+ if (v === undefined) {
72
+ throw new Error(`[loom] no provider for ${key?.name ?? key}`);
73
+ }
74
+ return v;
75
+ }
76
+ /** Retrieve a provider/service, or undefined if not registered. */
77
+ maybe(key) {
78
+ return this.providers.get(key);
79
+ }
80
+ /** Resolve @inject parameter metadata for a constructor or method. */
81
+ resolveParams(proto, method) {
82
+ const meta = proto?.[INJECT_PARAMS] ?? [];
83
+ const params = meta
84
+ .filter((m) => m.method === method)
85
+ .sort((a, b) => a.index - b.index);
86
+ return params.map((m) => this.get(m.key));
87
+ }
88
+ // ── Lifecycle ──
89
+ /**
90
+ * Boot the app:
91
+ * 1. Auto-instantiate @service singletons (with constructor @inject)
92
+ * 2. Run @factory methods (with parameter @inject)
93
+ * 3. Start the render loop
94
+ * 4. Register all @component custom elements
95
+ */
96
+ async start() {
97
+ if (this._started)
98
+ return;
99
+ // 1. Instantiate @service singletons and wire @on handlers
100
+ for (const Svc of this.services) {
101
+ if (!this.providers.has(Svc)) {
102
+ const args = this.resolveParams(Svc.prototype, "constructor");
103
+ this.providers.set(Svc, new Svc(...args));
104
+ }
105
+ // Wire @on event handlers (bus events + DOM events)
106
+ const instance = this.providers.get(Svc);
107
+ for (const handler of instance[ON_HANDLERS] ?? []) {
108
+ if (handler.domTarget) {
109
+ // DOM EventTarget: @on(window, "resize")
110
+ handler.domTarget.addEventListener(handler.event, (e) => instance[handler.key](e));
111
+ }
112
+ else {
113
+ // Bus event: @on(ColorSelect)
114
+ bus.on(handler.type, (e) => instance[handler.key](e));
115
+ }
116
+ }
117
+ }
118
+ // 2. Run @factory methods on instantiated services
119
+ for (const { proto, method, key } of this.factories) {
120
+ // Find the service instance that owns this factory method
121
+ const svc = this.providers.get(proto.constructor);
122
+ if (!svc)
123
+ continue;
124
+ const args = this.resolveParams(proto, method);
125
+ const result = await svc[method](...args);
126
+ if (result != null) {
127
+ this.providers.set(key ?? result.constructor, result);
128
+ }
129
+ }
130
+ // 3. Start render loop
131
+ renderLoop.start();
132
+ // 4. Register all queued custom elements
133
+ for (const { tag, ctor } of this.components) {
134
+ if (!customElements.get(tag)) {
135
+ customElements.define(tag, ctor);
136
+ }
137
+ }
138
+ this._started = true;
139
+ }
140
+ /** Tear down — stop render loop */
141
+ stop() {
142
+ renderLoop.stop();
143
+ this._started = false;
144
+ }
145
+ /** Whether the app has been started */
146
+ get started() {
147
+ return this._started;
148
+ }
149
+ }
150
+ /** Module-level singleton — the Loom app instance */
151
+ export const app = new LoomApp();
152
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
package/dist/bus.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Loom — EventBus (type-discriminated)
3
+ *
4
+ * Events are classes. The class constructor IS the channel key.
5
+ * No string registry, full type inference.
6
+ */
7
+ import type { LoomEvent } from "./event";
8
+ export type Constructor<T = any> = new (...args: any[]) => T;
9
+ export type Handler<T> = (data: T) => void;
10
+ export declare class EventBus {
11
+ private listeners;
12
+ /** Subscribe to a typed event. Returns unsubscribe function. */
13
+ on<T>(type: Constructor<T>, handler: Handler<T>): () => void;
14
+ /** Emit a typed event — dispatches to all handlers of that class */
15
+ emit<T extends LoomEvent>(event: T): void;
16
+ /** Remove a specific handler */
17
+ off<T>(type: Constructor<T>, handler: Handler<T>): void;
18
+ /** Remove all listeners for a given event type */
19
+ clear<T>(type: Constructor<T>): void;
20
+ /** Remove ALL listeners */
21
+ reset(): void;
22
+ }
23
+ /** Module-level default bus — used by LoomElement and available via import */
24
+ export declare let bus: EventBus;
25
+ /** Swap the global bus (for test isolation) */
26
+ export declare function useBus(b: EventBus): void;
27
+ //# sourceMappingURL=bus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../src/bus.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAC7D,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;AAE3C,qBAAa,QAAQ;IACnB,OAAO,CAAC,SAAS,CAA6C;IAE9D,gEAAgE;IAChE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAO5D,oEAAoE;IACpE,IAAI,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAKzC,gCAAgC;IAChC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI;IAIvD,kDAAkD;IAClD,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI;IAIpC,2BAA2B;IAC3B,KAAK,IAAI,IAAI;CAGd;AAED,8EAA8E;AAC9E,eAAO,IAAI,GAAG,UAAiB,CAAC;AAEhC,+CAA+C;AAC/C,wBAAgB,MAAM,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI,CAExC"}
package/dist/bus.js ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Loom — EventBus (type-discriminated)
3
+ *
4
+ * Events are classes. The class constructor IS the channel key.
5
+ * No string registry, full type inference.
6
+ */
7
+ export class EventBus {
8
+ listeners = new Map();
9
+ /** Subscribe to a typed event. Returns unsubscribe function. */
10
+ on(type, handler) {
11
+ if (!this.listeners.has(type))
12
+ this.listeners.set(type, new Set());
13
+ const set = this.listeners.get(type);
14
+ set.add(handler);
15
+ return () => set.delete(handler);
16
+ }
17
+ /** Emit a typed event — dispatches to all handlers of that class */
18
+ emit(event) {
19
+ const ctor = event.constructor;
20
+ this.listeners.get(ctor)?.forEach((h) => h(event));
21
+ }
22
+ /** Remove a specific handler */
23
+ off(type, handler) {
24
+ this.listeners.get(type)?.delete(handler);
25
+ }
26
+ /** Remove all listeners for a given event type */
27
+ clear(type) {
28
+ this.listeners.delete(type);
29
+ }
30
+ /** Remove ALL listeners */
31
+ reset() {
32
+ this.listeners.clear();
33
+ }
34
+ }
35
+ /** Module-level default bus — used by LoomElement and available via import */
36
+ export let bus = new EventBus();
37
+ /** Swap the global bus (for test isolation) */
38
+ export function useBus(b) {
39
+ bus = b;
40
+ }
41
+ //# sourceMappingURL=bus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bus.js","sourceRoot":"","sources":["../src/bus.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,MAAM,OAAO,QAAQ;IACX,SAAS,GAAG,IAAI,GAAG,EAAkC,CAAC;IAE9D,gEAAgE;IAChE,EAAE,CAAI,IAAoB,EAAE,OAAmB;QAC7C,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QACnE,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;QACtC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACjB,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAED,oEAAoE;IACpE,IAAI,CAAsB,KAAQ;QAChC,MAAM,IAAI,GAAI,KAAgB,CAAC,WAA0B,CAAC;QAC1D,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,gCAAgC;IAChC,GAAG,CAAI,IAAoB,EAAE,OAAmB;QAC9C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED,kDAAkD;IAClD,KAAK,CAAI,IAAoB;QAC3B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,2BAA2B;IAC3B,KAAK;QACH,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;CACF;AAED,8EAA8E;AAC9E,MAAM,CAAC,IAAI,GAAG,GAAG,IAAI,QAAQ,EAAE,CAAC;AAEhC,+CAA+C;AAC/C,MAAM,UAAU,MAAM,CAAC,CAAW;IAChC,GAAG,GAAG,CAAC,CAAC;AACV,CAAC"}
package/dist/css.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Loom — CSS tagged template + cache
3
+ *
4
+ * Standalone css`` tag for creating reusable, cached CSSStyleSheets.
5
+ * Same CSS string → same CSSStyleSheet instance (deduped across components).
6
+ */
7
+ /** Allowed types for css`` interpolation */
8
+ export type CSSValue = string | number;
9
+ /**
10
+ * Tagged template for creating cached CSSStyleSheets.
11
+ *
12
+ * ```ts
13
+ * const styles = css`
14
+ * :host { display: block; }
15
+ * button { padding: ${8}px; background: ${"#ff6b6b"}; }
16
+ * `;
17
+ * ```
18
+ */
19
+ export declare function css(strings: TemplateStringsArray, ...values: CSSValue[]): CSSStyleSheet;
20
+ /**
21
+ * Adopt a stylesheet into a shadow root from either a tagged template or string.
22
+ * Used internally by LoomElement.css().
23
+ */
24
+ export declare function adoptCSS(shadow: ShadowRoot, stringsOrText: string | TemplateStringsArray, ...values: CSSValue[]): void;
25
+ //# sourceMappingURL=css.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../src/css.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,4CAA4C;AAC5C,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AAKvC;;;;;;;;;GASG;AACH,wBAAgB,GAAG,CACjB,OAAO,EAAE,oBAAoB,EAC7B,GAAG,MAAM,EAAE,QAAQ,EAAE,GACpB,aAAa,CASf;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,UAAU,EAClB,aAAa,EAAE,MAAM,GAAG,oBAAoB,EAC5C,GAAG,MAAM,EAAE,QAAQ,EAAE,GACpB,IAAI,CAgBN"}
package/dist/css.js ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Loom — CSS tagged template + cache
3
+ *
4
+ * Standalone css`` tag for creating reusable, cached CSSStyleSheets.
5
+ * Same CSS string → same CSSStyleSheet instance (deduped across components).
6
+ */
7
+ /** Global cache — same CSS string → same CSSStyleSheet instance */
8
+ const cssCache = new Map();
9
+ /**
10
+ * Tagged template for creating cached CSSStyleSheets.
11
+ *
12
+ * ```ts
13
+ * const styles = css`
14
+ * :host { display: block; }
15
+ * button { padding: ${8}px; background: ${"#ff6b6b"}; }
16
+ * `;
17
+ * ```
18
+ */
19
+ export function css(strings, ...values) {
20
+ const text = String.raw(strings, ...values);
21
+ let sheet = cssCache.get(text);
22
+ if (!sheet) {
23
+ sheet = new CSSStyleSheet();
24
+ sheet.replaceSync(text);
25
+ cssCache.set(text, sheet);
26
+ }
27
+ return sheet;
28
+ }
29
+ /**
30
+ * Adopt a stylesheet into a shadow root from either a tagged template or string.
31
+ * Used internally by LoomElement.css().
32
+ */
33
+ export function adoptCSS(shadow, stringsOrText, ...values) {
34
+ const text = typeof stringsOrText === "string"
35
+ ? stringsOrText
36
+ : String.raw(stringsOrText, ...values);
37
+ const sheet = cssCache.get(text) ??
38
+ (() => {
39
+ const s = new CSSStyleSheet();
40
+ s.replaceSync(text);
41
+ cssCache.set(text, s);
42
+ return s;
43
+ })();
44
+ if (!shadow.adoptedStyleSheets.includes(sheet)) {
45
+ shadow.adoptedStyleSheets = [...shadow.adoptedStyleSheets, sheet];
46
+ }
47
+ }
48
+ //# sourceMappingURL=css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css.js","sourceRoot":"","sources":["../src/css.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,mEAAmE;AACnE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;AAElD;;;;;;;;;GASG;AACH,MAAM,UAAU,GAAG,CACjB,OAA6B,EAC7B,GAAG,MAAkB;IAErB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAC;IAC5C,IAAI,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,GAAG,IAAI,aAAa,EAAE,CAAC;QAC5B,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACxB,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CACtB,MAAkB,EAClB,aAA4C,EAC5C,GAAG,MAAkB;IAErB,MAAM,IAAI,GACR,OAAO,aAAa,KAAK,QAAQ;QAC/B,CAAC,CAAC,aAAa;QACf,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG,MAAM,CAAC,CAAC;IAC3C,MAAM,KAAK,GACT,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;QAClB,CAAC,GAAG,EAAE;YACJ,MAAM,CAAC,GAAG,IAAI,aAAa,EAAE,CAAC;YAC9B,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YACpB,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACtB,OAAO,CAAC,CAAC;QACX,CAAC,CAAC,EAAE,CAAC;IACP,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,MAAM,CAAC,kBAAkB,GAAG,CAAC,GAAG,MAAM,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;IACpE,CAAC;AACH,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Register a class as a custom element. Wires @prop observed attributes
3
+ * and attributeChangedCallback auto-parsing.
4
+ *
5
+ * ```ts
6
+ * @component("my-counter")
7
+ * class MyCounter extends LoomElement { ... }
8
+ * ```
9
+ */
10
+ export declare function component(tag: string): (ctor: any) => void;
11
+ //# sourceMappingURL=component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/decorators/component.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,IAC3B,MAAM,GAAG,UA8BlB"}
@@ -0,0 +1,38 @@
1
+ import { PROPS } from "./symbols";
2
+ import { app } from "../app";
3
+ /**
4
+ * Register a class as a custom element. Wires @prop observed attributes
5
+ * and attributeChangedCallback auto-parsing.
6
+ *
7
+ * ```ts
8
+ * @component("my-counter")
9
+ * class MyCounter extends LoomElement { ... }
10
+ * ```
11
+ */
12
+ export function component(tag) {
13
+ return (ctor) => {
14
+ const propMap = ctor[PROPS] ?? new Map();
15
+ // Wire observedAttributes from @prop fields
16
+ Object.defineProperty(ctor, "observedAttributes", {
17
+ get: () => [...propMap.keys()],
18
+ });
19
+ // Wire attributeChangedCallback to update @prop fields
20
+ const origCallback = ctor.prototype.attributeChangedCallback;
21
+ ctor.prototype.attributeChangedCallback = function (name, _old, val) {
22
+ const field = propMap.get(name);
23
+ if (field && val !== null) {
24
+ const current = this[field];
25
+ if (typeof current === "number")
26
+ this[field] = Number(val);
27
+ else if (typeof current === "boolean")
28
+ this[field] = val !== null && val !== "false";
29
+ else
30
+ this[field] = val;
31
+ }
32
+ origCallback?.call(this, name, _old, val);
33
+ };
34
+ app.register(tag, ctor);
35
+ ctor.__loom_tag = tag;
36
+ };
37
+ }
38
+ //# sourceMappingURL=component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component.js","sourceRoot":"","sources":["../../src/decorators/component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAE7B;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,OAAO,CAAC,IAAS,EAAE,EAAE;QACnB,MAAM,OAAO,GACV,IAAY,CAAC,KAAK,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;QAEpC,4CAA4C;QAC5C,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,oBAAoB,EAAE;YAChD,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;SAC/B,CAAC,CAAC;QAEH,uDAAuD;QACvD,MAAM,YAAY,GAAI,IAAI,CAAC,SAAiB,CAAC,wBAAwB,CAAC;QACrE,IAAI,CAAC,SAAiB,CAAC,wBAAwB,GAAG,UACjD,IAAY,EACZ,IAAmB,EACnB,GAAkB;YAElB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBAC1B,MAAM,OAAO,GAAI,IAAY,CAAC,KAAK,CAAC,CAAC;gBACrC,IAAI,OAAO,OAAO,KAAK,QAAQ;oBAAG,IAAY,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;qBAC/D,IAAI,OAAO,OAAO,KAAK,SAAS;oBAClC,IAAY,CAAC,KAAK,CAAC,GAAG,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,OAAO,CAAC;;oBACnD,IAAY,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC;YAClC,CAAC;YACD,YAAY,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QAC5C,CAAC,CAAC;QAEF,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAgC,CAAC,CAAC;QACnD,IAAY,CAAC,UAAU,GAAG,GAAG,CAAC;IACjC,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Auto-instantiated singleton. Registered on app.start().
3
+ * Constructor @inject params are resolved automatically.
4
+ *
5
+ * ```ts
6
+ * @service
7
+ * class BookmarkStore extends CollectionStore<Bookmark> { ... }
8
+ * ```
9
+ */
10
+ export declare function service(ctor: any): void;
11
+ /**
12
+ * Dual-mode dependency injection.
13
+ *
14
+ * Property: @inject(Foo) foo!: Foo;
15
+ * Constructor: constructor(@inject(Config) config: Config)
16
+ * Factory arg: createChat(@inject(NatsConn) nc: NatsConn)
17
+ *
18
+ * T is optional — use for explicit typing if desired.
19
+ */
20
+ export declare function inject<T = any>(key: any): (target: any, propOrMethod: string | undefined, index?: number) => void;
21
+ /**
22
+ * Method decorator on @service classes.
23
+ * Return value is registered as a provider on app.start().
24
+ * Supports @inject on parameters. Async methods are awaited.
25
+ *
26
+ * ```ts
27
+ * @service
28
+ * class Boot {
29
+ * @factory(ChatServiceNatsClient)
30
+ * createChat(@inject(NatsConnection) nc: NatsConnection) {
31
+ * return new ChatServiceNatsClient(nc);
32
+ * }
33
+ * }
34
+ * ```
35
+ */
36
+ export declare function factory(key?: any): (target: any, method: string) => void;
37
+ //# sourceMappingURL=di.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"di.d.ts","sourceRoot":"","sources":["../../src/decorators/di.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,CAEvC;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,IAC9B,QAAQ,GAAG,EAAE,cAAc,MAAM,GAAG,SAAS,EAAE,QAAQ,MAAM,UAiBtE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CAAC,GAAG,CAAC,EAAE,GAAG,IACvB,QAAQ,GAAG,EAAE,QAAQ,MAAM,UAGpC"}