microtags 0.0.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/LICENSE ADDED
@@ -0,0 +1,168 @@
1
+ # Big Time Public License
2
+
3
+ Version 2.0.2
4
+
5
+ <https://bigtimelicense.com/versions/2.0.2>
6
+
7
+ ## Purpose
8
+
9
+ These terms let you use and share this software for noncommercial purposes
10
+ and in small business for free, while also guaranteeing that paid licenses
11
+ for big businesses will be available on fair, reasonable, and
12
+ nondiscriminatory terms.
13
+
14
+ ## Acceptance
15
+
16
+ In order to get any license under these terms, you must agree to them as
17
+ both strict obligations and conditions to all your licenses.
18
+
19
+ ## Noncommercial Purposes
20
+
21
+ You may use the software for any noncommercial purpose.
22
+
23
+ ## Personal Uses
24
+
25
+ Personal use for research, experiment, and testing for the benefit of
26
+ public knowledge, personal study, private entertainment, hobby projects,
27
+ amateur pursuits, or religious observance, without any anticipated
28
+ commercial application, count as use for noncommercial purposes.
29
+
30
+ ## Noncommercial Organizations
31
+
32
+ Use by any charitable organization, educational institution, public
33
+ research organization, public safety or health organization, environmental
34
+ protection organization, or government institution counts as use for
35
+ noncommercial purposes, regardless of the source of funding or obligations
36
+ resulting from the funding.
37
+
38
+ ## Small Business
39
+
40
+ You may use the software for the benefit of your company if it meets all
41
+ these criteria:
42
+
43
+ 1. had fewer than 20 total individuals working as employees and
44
+ independent contractors at all times during the last tax year
45
+
46
+ 2. earned less than $1,000,000 total revenue in the last tax year
47
+
48
+ 3. received less than $1,000,000 total debt, equity, and other investment
49
+ in the last five tax years, counting investment in predecessor
50
+ companies that reorganized into, merged with, or spun out your company
51
+
52
+ All dollar figures are United States dollars as of 2019. Adjust for them
53
+ inflation according to the United States Bureau of Labor Statistics'
54
+ consumer price index for all urban consumers, United States city average,
55
+ for all items, not seasonally adjusted, with 1982–1984=100 reference base.
56
+
57
+ ## Big Business
58
+
59
+ You may use the software for the benefit of your company:
60
+
61
+ 1. for 128 days after your company stops qualifying under
62
+ [Small Business](#small-business)
63
+
64
+ 2. indefinitely, if the licensor or their legal successor does not offer
65
+ fair, reasonable, and nondiscriminatory terms for a commercial license for
66
+ the software within 32 days of [written request](#how-to-request) and
67
+ negotiate in good faith to conclude a deal
68
+
69
+ ## How to Request
70
+
71
+ If this software includes an address for the licensor or an agent of the
72
+ licensor in a standard place, such as in documentation, software package
73
+ metadata, or an "about" page or screen, try to request a fair commercial
74
+ license at that address. If this package includes both online and offline
75
+ addresses, try online before offline. If you can't deliver a request that
76
+ way, or this software doesn't include any addressees, spend one hour online
77
+ researching an address, recording all your searches and inquiries as you
78
+ go, and try any addresses that you find. If you can't find any addresses,
79
+ or if those addresses also fail, that counts as failure to offer a fair
80
+ commercial license by the licensor under [Big Business](#big-business).
81
+
82
+ ## Fair, Reasonable, and Nondiscriminatory Terms
83
+
84
+ Fair, reasonable, and nondiscriminatory terms may license the software
85
+ perpetually or for a term, and may or may not cover new versions of the
86
+ software. If the licensor advertises license terms and a pricing structure
87
+ for generally available commercial licenses, the licensor proposes license
88
+ terms and a price as advertised, and a customer not affiliated with the
89
+ licensor has bought a commercial license for the software on substantially
90
+ equivalent terms in the past year, the proposal is fair, reasonable, and
91
+ nondiscriminatory.
92
+
93
+ ## Copyright License
94
+
95
+ The licensor grants you a copyright license to do everything with the
96
+ software that would otherwise infringe the licensor's copyright in it for
97
+ any purpose allowed by these terms.
98
+
99
+ ## Notices
100
+
101
+ You must ensure that anyone who gets a copy of any part of the software
102
+ from you also gets a copy of these terms or the URL for them above, as well
103
+ as copies of any plain-text lines beginning with `Required Notice:` that
104
+ the licensor provided with the software. For example:
105
+
106
+ > Required Notice: Copyright Nick Thomas (https://nichoth.com)
107
+
108
+ ## Patent License
109
+
110
+ The licensor grants you a patent license for the software that covers
111
+ patent claims the licensor can license, or becomes able to license, that
112
+ you would infringe by using the software.
113
+
114
+ ## Fair Use
115
+
116
+ You may have "fair use" rights for the software under the law. These terms
117
+ do not limit them.
118
+
119
+ ## No Other Rights
120
+
121
+ These terms do not allow you to sublicense or transfer any of your licenses
122
+ to anyone else, or prevent the licensor from granting licenses to anyone
123
+ else. These terms do not imply any other licenses.
124
+
125
+ ## Patent Defense
126
+
127
+ If you make any written claim that the software infringes or contributes to
128
+ infringement of any patent, your patent license for the software granted
129
+ under these terms ends immediately. If your company makes such a claim,
130
+ your patent license ends immediately for work on behalf of your company.
131
+
132
+ ## Violations
133
+
134
+ The first time you are notified in writing that you have violated any of
135
+ these terms, or done anything with the software not covered by your
136
+ licenses, your licenses can nonetheless continue if you come into full
137
+ compliance with these terms, and take practical steps to correct past
138
+ violations, within 32 days of receiving notice. Otherwise, all your
139
+ licenses end immediately.
140
+
141
+ ## No Liability
142
+
143
+ ***As far as the law allows, the software comes as is, without any warranty
144
+ or condition, and the licensor will not be liable to you for any damages
145
+ arising out of these terms or the use or nature of the software, under any
146
+ kind of legal claim.***
147
+
148
+ ## Definitions
149
+
150
+ The **licensor** is the individual or entity offering these terms, and
151
+ the **software** is the software the licensor makes available under these
152
+ terms.
153
+
154
+ **You** refers to the individual or entity agreeing to these terms.
155
+
156
+ **Your company** is any legal entity, sole proprietorship, or other kind of
157
+ organization that you work for, plus all organizations that have control
158
+ over, are under the control of, or are under common control with that
159
+ organization. **Control** means ownership of substantially all the assets
160
+ of an entity, or the power to direct its management and policies by vote,
161
+ contract, or otherwise. Control can be direct or indirect.
162
+
163
+ **Your licenses** are all the licenses granted to you for the software
164
+ under these terms.
165
+
166
+ **Use** means anything you do with the software requiring one of your
167
+ licenses.
168
+
package/README.md ADDED
@@ -0,0 +1,246 @@
1
+ # microtags
2
+
3
+ ![tests](https://github.com/nichoth/microtags/actions/workflows/nodejs.yml/badge.svg)
4
+ [![types](https://img.shields.io/npm/types/microtags?style=flat-square)](README.md)
5
+ [![module](https://img.shields.io/badge/module-ESM%2FCJS-blue?style=flat-square)](README.md)
6
+ [![semantic versioning](https://img.shields.io/badge/semver-2.0.0-blue?logo=semver&style=flat-square)](https://semver.org/)
7
+ [![Common Changelog](https://nichoth.github.io/badge/common-changelog.svg)](./CHANGELOG.md)
8
+ [![license](https://img.shields.io/badge/license-Big_Time-blue?style=flat-square)](LICENSE)
9
+
10
+ Web component helper with reactive props, automatic cleanup,
11
+ and no Shadow DOM. Reactive via
12
+ [alien-signals](https://github.com/stackblitz/alien-signals).
13
+
14
+ Inspired by [nanotags](https://nanotags.psdcoder.dev/), with one change:
15
+ reactive props are **alien-signals** instead of nanostores atoms.
16
+ You call `count()` to read and `count(42)` to write — no `$` prefix,
17
+ no `.get()` / `.set()`.
18
+
19
+ <details><summary><h2>Contents</h2></summary>
20
+
21
+ - [Install](#install)
22
+ - [Quick start](#quick-start)
23
+ - [API](#api)
24
+ - [define](#define)
25
+ - [withProps](#withprops)
26
+ - [withRefs](#withrefs)
27
+ - [withContexts](#withcontexts)
28
+ - [setup and ctx](#setup-and-ctx)
29
+ - [Subpaths](#subpaths)
30
+ - [microtags/context](#microtagscontext)
31
+ - [microtags/render](#microtagsrender)
32
+ - [Divergence from nanotags](#divergence-from-nanotags)
33
+
34
+ </details>
35
+
36
+ ## Install
37
+
38
+ ```sh
39
+ npm i -S microtags
40
+ ```
41
+
42
+ ## Quick start
43
+
44
+ ```ts
45
+ import { define } from 'microtags'
46
+ import { signal } from 'alien-signals'
47
+
48
+ define('my-counter')
49
+ .withProps(p => ({
50
+ start: p.number(), // hydrated from the `start` attribute
51
+ }))
52
+ .withRefs(r => ({
53
+ display: r.one, // [data-ref="display"] inside the element
54
+ inc: r.one,
55
+ dec: r.one,
56
+ }))
57
+ .setup(ctx => {
58
+ // Create a local signal seeded from the hydrated prop.
59
+ const count = signal(ctx.props.start())
60
+
61
+ // Two-way bind the display's textContent to a derived value.
62
+ ctx.bind(ctx.refs.display as HTMLElement, 'textContent',
63
+ () => `Count: ${count()}`)
64
+
65
+ // Wire up click handlers — auto-removed on disconnect.
66
+ ctx.on(ctx.refs.inc as HTMLElement, 'click', () => count(count() + 1))
67
+ ctx.on(ctx.refs.dec as HTMLElement, 'click', () => count(count() - 1))
68
+ })
69
+ ```
70
+
71
+ ```html
72
+ <my-counter start="5">
73
+ <div data-ref="display"></div>
74
+ <button data-ref="dec">-</button>
75
+ <button data-ref="inc">+</button>
76
+ </my-counter>
77
+ ```
78
+
79
+ ## API
80
+
81
+ ### define
82
+
83
+ ```ts
84
+ import { define } from 'microtags'
85
+
86
+ define(tagName: string): ComponentBuilder
87
+ ```
88
+
89
+ Returns a fluent builder. Call `.setup()` to register the custom element.
90
+ All builder methods are chainable and fully type-inferred.
91
+
92
+ ### withProps
93
+
94
+ ```ts
95
+ .withProps(p => ({
96
+ count: p.number(), // attribute -> number (NaN when absent)
97
+ label: p.string(), // attribute -> string ('' when absent)
98
+ active: p.boolean(), // attribute -> boolean (true if present)
99
+ data: p.json<MyType>(), // attribute -> JSON.parse or undefined
100
+ schema: p.schema(zodSchema), // Standard Schema (Zod, Valibot, ArkType …)
101
+ value: p.prop(0), // property-only, not observed as an attribute
102
+ }))
103
+ ```
104
+
105
+ Inside `setup()`, every prop is a callable signal:
106
+
107
+ ```ts
108
+ ctx.props.count() // read
109
+ ctx.props.count(42) // write
110
+ ```
111
+
112
+ ### withRefs
113
+
114
+ ```ts
115
+ .withRefs(r => ({
116
+ button: r.one, // resolves [data-ref="button"] — throws if missing
117
+ items: r.all, // resolves all [data-ref="items"] — empty array if none
118
+ }))
119
+ ```
120
+
121
+ Refs are resolved from within the element during `connectedCallback`.
122
+
123
+ ```ts
124
+ ctx.refs.button // Element
125
+ ctx.refs.items // Element[]
126
+ ```
127
+
128
+ ### withContexts
129
+
130
+ ```ts
131
+ import { createContext } from 'microtags/context'
132
+
133
+ const ThemeToken = createContext<string>()
134
+
135
+ define('my-child')
136
+ .withContexts(() => ({
137
+ theme: ThemeToken,
138
+ }))
139
+ .setup(ctx => {
140
+ ctx.effect(() => {
141
+ console.log('theme is', ctx.contexts.theme)
142
+ })
143
+ })
144
+ ```
145
+
146
+ `setup()` is deferred until all required contexts resolve. See
147
+ [microtags/context](#microtagscontext) for the provider API.
148
+
149
+ ### setup and ctx
150
+
151
+ ```ts
152
+ .setup(ctx => {
153
+ // ctx.host — the HTMLElement itself
154
+ // ctx.props — callable signals for each declared prop
155
+ // ctx.refs — resolved DOM refs
156
+ // ctx.contexts — consumed context values (reactive)
157
+
158
+ // Run a tracked effect; auto-disposed on disconnect.
159
+ ctx.effect(() => {
160
+ document.title = ctx.props.label()
161
+ })
162
+
163
+ // Bind a DOM property to a signal expression; auto-cleaned.
164
+ ctx.bind(el, 'textContent', () => String(ctx.props.count()))
165
+
166
+ // Add an event listener; auto-removed on disconnect.
167
+ ctx.on(el, 'click', handler)
168
+
169
+ // Read a signal without creating a subscription.
170
+ const snap = ctx.peek(ctx.props.count)
171
+
172
+ // Register arbitrary teardown logic.
173
+ ctx.onCleanup(() => { /* ... */ })
174
+
175
+ // Consume a context imperatively (returns value or undefined).
176
+ const theme = ctx.consume(ThemeToken)
177
+ })
178
+ ```
179
+
180
+ #### peek and untracked
181
+
182
+ When you need a non-subscribing read outside of `ctx.peek`, both helpers are
183
+ exported from the main entry:
184
+
185
+ ```ts
186
+ import { peek, untracked } from 'microtags'
187
+
188
+ ctx.effect(() => {
189
+ const current = peek(ctx.props.count) // does NOT subscribe
190
+ untracked(() => {
191
+ // reads inside here do not subscribe either
192
+ })
193
+ })
194
+ ```
195
+
196
+ ## Subpaths
197
+
198
+ ### microtags/context
199
+
200
+ Cross-component context backed by alien-signals.
201
+
202
+ ```ts
203
+ import { createContext, provide, resolveContextSignal } from 'microtags/context'
204
+
205
+ const ThemeToken = createContext<string>()
206
+
207
+ // In a provider component's setup():
208
+ const cleanup = provide(ctx.host, ThemeToken, 'dark')
209
+ ctx.onCleanup(cleanup)
210
+
211
+ // In a consumer component via withContexts:
212
+ ctx.contexts.theme // 'dark' (reactive — re-runs effects when value changes)
213
+ ```
214
+
215
+ ### microtags/render
216
+
217
+ DOM diffing helpers for rendering lists and single items without a virtual DOM.
218
+
219
+ ```ts
220
+ import { render, renderList } from 'microtags/render'
221
+
222
+ // Render a single item into a container from a <template>.
223
+ render(container, template, {
224
+ data: item,
225
+ update: (el, item) => { el.querySelector('span')!.textContent = item.name },
226
+ })
227
+
228
+ // Render a keyed list with minimal DOM mutations.
229
+ renderList(container, template, {
230
+ data: items,
231
+ key: item => item.id,
232
+ update: (el, item) => { /* update el from item */ },
233
+ })
234
+ ```
235
+
236
+ ## Divergence from nanotags
237
+
238
+ | nanotags (nanostores) | microtags (alien-signals) |
239
+ |---|---|
240
+ | `$count = atom(0)` | `const count = signal(0)` |
241
+ | `$count.get()` | `count()` |
242
+ | `$count.set(1)` | `count(1)` |
243
+ | `ctx.props.$count` (store) | `ctx.props.count` (callable signal) |
244
+
245
+ Props declared with `withProps` are native alien-signals callable signals.
246
+ There is no `$` prefix convention — all prop names are plain identifiers.
@@ -0,0 +1,46 @@
1
+ import type { StandardSchemaV1 } from '@standard-schema/spec';
2
+ import type { PropDef, PropertyOnlyProp, SetupContext, Coercer, RefDef, SingleRefDef, MultipleRefDef, RefsMap, ContextToken, ContextsMap } from './types.js';
3
+ /** The DSL object passed to the withProps callback. */
4
+ export type PropDSL = {
5
+ number(): Coercer<number>;
6
+ string(): Coercer<string>;
7
+ boolean(): Coercer<boolean>;
8
+ json<T>(): Coercer<T | undefined>;
9
+ schema<T>(validator: StandardSchemaV1<unknown, T>): StandardSchemaV1<unknown, T>;
10
+ prop<T>(initial: T): PropertyOnlyProp<T>;
11
+ };
12
+ export declare const propDSL: PropDSL;
13
+ /**
14
+ * DSL object passed to the withRefs callback.
15
+ * Assign `r.one` for a single element or `r.all` for multiple.
16
+ */
17
+ export type RefsDSL = {
18
+ readonly one: SingleRefDef;
19
+ readonly all: MultipleRefDef;
20
+ };
21
+ export declare const refsDSL: RefsDSL;
22
+ /**
23
+ * DSL object passed to the withContexts callback.
24
+ * Currently a no-op placeholder; the user references imported
25
+ * context tokens directly in the returned record.
26
+ */
27
+ export type ContextDSL = Record<never, never>;
28
+ /**
29
+ * Fluent builder that accumulates props/refs/contexts config
30
+ * before registering a custom element via `.setup()`.
31
+ */
32
+ export declare class ComponentBuilder<Props extends Record<string, PropDef> = Record<never, never>, RefDefs extends Record<string, RefDef> = Record<never, never>, CtxDefs extends Record<string, ContextToken<unknown>> = Record<never, never>> {
33
+ readonly tagName: string;
34
+ private readonly _coercers;
35
+ private readonly _observed;
36
+ private readonly _refDefs;
37
+ private readonly _ctxDefs;
38
+ constructor(tagName: string, coercers?: Record<string, Coercer<unknown>>, observed?: string[], refDefs?: Record<string, RefDef>, ctxDefs?: Record<string, ContextToken<unknown>>);
39
+ withProps<P extends Record<string, PropDef>>(fn: (p: PropDSL) => P): ComponentBuilder<P, RefDefs, CtxDefs>;
40
+ withRefs<R extends Record<string, RefDef>>(fn: (r: RefsDSL) => R): ComponentBuilder<Props, R, CtxDefs>;
41
+ withContexts<C extends Record<string, ContextToken<unknown>>>(fn: (c: ContextDSL) => C): ComponentBuilder<Props, RefDefs, C>;
42
+ setup(fn: (ctx: SetupContext<Props, RefsMap<RefDefs>, ContextsMap<CtxDefs>>) => void): typeof HTMLElement;
43
+ }
44
+ /** Create a new component builder for the given tag name. */
45
+ export declare function define(tagName: string): ComponentBuilder;
46
+ //# sourceMappingURL=builders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builders.d.ts","sourceRoot":"","sources":["../src/builders.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var context_exports = {};
21
+ __export(context_exports, {
22
+ createContext: () => createContext,
23
+ onContextAvailable: () => onContextAvailable,
24
+ provide: () => provide,
25
+ resolveContextSignal: () => resolveContextSignal
26
+ });
27
+ module.exports = __toCommonJS(context_exports);
28
+ var import_reactivity = require("./reactivity.js");
29
+ const providerStorage = /* @__PURE__ */ new WeakMap();
30
+ const pendingCallbacks = /* @__PURE__ */ new Map();
31
+ function createContext() {
32
+ return { id: /* @__PURE__ */ Symbol("microtag-context") };
33
+ }
34
+ __name(createContext, "createContext");
35
+ function provide(element, token, value) {
36
+ let map = providerStorage.get(element);
37
+ if (!map) {
38
+ map = /* @__PURE__ */ new Map();
39
+ providerStorage.set(element, map);
40
+ }
41
+ const existing = map.get(token.id);
42
+ if (existing) {
43
+ existing(value);
44
+ } else {
45
+ const sig = (0, import_reactivity.signal)(value);
46
+ map.set(token.id, sig);
47
+ }
48
+ notifyPending(token.id);
49
+ return () => {
50
+ const m = providerStorage.get(element);
51
+ if (m) {
52
+ m.delete(token.id);
53
+ if (m.size === 0) providerStorage.delete(element);
54
+ }
55
+ };
56
+ }
57
+ __name(provide, "provide");
58
+ function resolveContextSignal(element, token) {
59
+ let current = element.parentElement;
60
+ while (current) {
61
+ const map = providerStorage.get(current);
62
+ if (map && map.has(token.id)) {
63
+ return map.get(token.id);
64
+ }
65
+ current = current.parentElement;
66
+ }
67
+ return void 0;
68
+ }
69
+ __name(resolveContextSignal, "resolveContextSignal");
70
+ function onContextAvailable(id, callback) {
71
+ let set = pendingCallbacks.get(id);
72
+ if (!set) {
73
+ set = /* @__PURE__ */ new Set();
74
+ pendingCallbacks.set(id, set);
75
+ }
76
+ set.add(callback);
77
+ return () => {
78
+ pendingCallbacks.get(id)?.delete(callback);
79
+ };
80
+ }
81
+ __name(onContextAvailable, "onContextAvailable");
82
+ function notifyPending(id) {
83
+ const set = pendingCallbacks.get(id);
84
+ if (set) {
85
+ for (const cb of set) cb();
86
+ }
87
+ }
88
+ __name(notifyPending, "notifyPending");
89
+ //# sourceMappingURL=context.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/context.ts"],
4
+ "sourcesContent": ["import { signal } from './reactivity.js'\nimport type { ContextToken, Signal } from './types.js'\n\n// Provider storage: element -> (contextId -> Signal)\nconst providerStorage = new WeakMap<Element, Map<symbol, Signal<unknown>>>()\n\n// Pending consumers waiting for a context by id\nconst pendingCallbacks = new Map<symbol, Set<() => void>>()\n\n/**\n * Create a new context token.\n * Each token uniquely identifies a type of shared context.\n */\nexport function createContext<T> (): ContextToken<T> {\n return { id: Symbol('microtag-context') }\n}\n\n/**\n * Provide a context value from an element to its descendants.\n * Returns a cleanup function that removes the provided value.\n */\nexport function provide<T> (\n element: Element,\n token: ContextToken<T>,\n value: T\n): () => void {\n let map = providerStorage.get(element)\n if (!map) {\n map = new Map()\n providerStorage.set(element, map)\n }\n\n const existing = map.get(token.id) as Signal<T> | undefined\n if (existing) {\n existing(value)\n } else {\n const sig = signal(value) as unknown as Signal<T>\n map.set(token.id, sig as Signal<unknown>)\n }\n\n notifyPending(token.id)\n\n return () => {\n const m = providerStorage.get(element)\n if (m) {\n m.delete(token.id)\n if (m.size === 0) providerStorage.delete(element)\n }\n }\n}\n\n/**\n * Walk up the DOM from element to find the nearest provider signal.\n * Returns the signal (not the value) so callers can subscribe to changes.\n */\nexport function resolveContextSignal<T> (\n element: Element,\n token: ContextToken<T>\n): Signal<T> | undefined {\n let current: Element | null = element.parentElement\n while (current) {\n const map = providerStorage.get(current)\n if (map && map.has(token.id)) {\n return map.get(token.id) as Signal<T>\n }\n current = current.parentElement\n }\n return undefined\n}\n\n/**\n * Register a callback to run when the given context becomes available.\n * Returns a cleanup function to unregister.\n */\nexport function onContextAvailable (\n id: symbol,\n callback: () => void\n): () => void {\n let set = pendingCallbacks.get(id)\n if (!set) {\n set = new Set()\n pendingCallbacks.set(id, set)\n }\n set.add(callback)\n return () => { pendingCallbacks.get(id)?.delete(callback) }\n}\n\nfunction notifyPending (id: symbol): void {\n const set = pendingCallbacks.get(id)\n if (set) {\n for (const cb of set) cb()\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAuB;AAIvB,MAAM,kBAAkB,oBAAI,QAA+C;AAG3E,MAAM,mBAAmB,oBAAI,IAA6B;AAMnD,SAAS,gBAAqC;AACjD,SAAO,EAAE,IAAI,uBAAO,kBAAkB,EAAE;AAC5C;AAFgB;AAQT,SAAS,QACZ,SACA,OACA,OACU;AACV,MAAI,MAAM,gBAAgB,IAAI,OAAO;AACrC,MAAI,CAAC,KAAK;AACN,UAAM,oBAAI,IAAI;AACd,oBAAgB,IAAI,SAAS,GAAG;AAAA,EACpC;AAEA,QAAM,WAAW,IAAI,IAAI,MAAM,EAAE;AACjC,MAAI,UAAU;AACV,aAAS,KAAK;AAAA,EAClB,OAAO;AACH,UAAM,UAAM,0BAAO,KAAK;AACxB,QAAI,IAAI,MAAM,IAAI,GAAsB;AAAA,EAC5C;AAEA,gBAAc,MAAM,EAAE;AAEtB,SAAO,MAAM;AACT,UAAM,IAAI,gBAAgB,IAAI,OAAO;AACrC,QAAI,GAAG;AACH,QAAE,OAAO,MAAM,EAAE;AACjB,UAAI,EAAE,SAAS,EAAG,iBAAgB,OAAO,OAAO;AAAA,IACpD;AAAA,EACJ;AACJ;AA5BgB;AAkCT,SAAS,qBACZ,SACA,OACqB;AACrB,MAAI,UAA0B,QAAQ;AACtC,SAAO,SAAS;AACZ,UAAM,MAAM,gBAAgB,IAAI,OAAO;AACvC,QAAI,OAAO,IAAI,IAAI,MAAM,EAAE,GAAG;AAC1B,aAAO,IAAI,IAAI,MAAM,EAAE;AAAA,IAC3B;AACA,cAAU,QAAQ;AAAA,EACtB;AACA,SAAO;AACX;AAbgB;AAmBT,SAAS,mBACZ,IACA,UACU;AACV,MAAI,MAAM,iBAAiB,IAAI,EAAE;AACjC,MAAI,CAAC,KAAK;AACN,UAAM,oBAAI,IAAI;AACd,qBAAiB,IAAI,IAAI,GAAG;AAAA,EAChC;AACA,MAAI,IAAI,QAAQ;AAChB,SAAO,MAAM;AAAE,qBAAiB,IAAI,EAAE,GAAG,OAAO,QAAQ;AAAA,EAAE;AAC9D;AAXgB;AAahB,SAAS,cAAe,IAAkB;AACtC,QAAM,MAAM,iBAAiB,IAAI,EAAE;AACnC,MAAI,KAAK;AACL,eAAW,MAAM,IAAK,IAAG;AAAA,EAC7B;AACJ;AALS;",
6
+ "names": []
7
+ }
@@ -0,0 +1,22 @@
1
+ import type { ContextToken, Signal } from './types.js';
2
+ /**
3
+ * Create a new context token.
4
+ * Each token uniquely identifies a type of shared context.
5
+ */
6
+ export declare function createContext<T>(): ContextToken<T>;
7
+ /**
8
+ * Provide a context value from an element to its descendants.
9
+ * Returns a cleanup function that removes the provided value.
10
+ */
11
+ export declare function provide<T>(element: Element, token: ContextToken<T>, value: T): () => void;
12
+ /**
13
+ * Walk up the DOM from element to find the nearest provider signal.
14
+ * Returns the signal (not the value) so callers can subscribe to changes.
15
+ */
16
+ export declare function resolveContextSignal<T>(element: Element, token: ContextToken<T>): Signal<T> | undefined;
17
+ /**
18
+ * Register a callback to run when the given context becomes available.
19
+ * Returns a cleanup function to unregister.
20
+ */
21
+ export declare function onContextAvailable(id: symbol, callback: () => void): () => void;
22
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAQtD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,KAAM,YAAY,CAAC,CAAC,CAAC,CAEnD;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACrB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,EACtB,KAAK,EAAE,CAAC,GACT,MAAM,IAAI,CAwBZ;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAClC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GACvB,MAAM,CAAC,CAAC,CAAC,GAAG,SAAS,CAUvB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAC9B,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,IAAI,GACrB,MAAM,IAAI,CAQZ"}
@@ -0,0 +1,70 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import { signal } from "./reactivity.js";
4
+ const providerStorage = /* @__PURE__ */ new WeakMap();
5
+ const pendingCallbacks = /* @__PURE__ */ new Map();
6
+ function createContext() {
7
+ return { id: /* @__PURE__ */ Symbol("microtag-context") };
8
+ }
9
+ __name(createContext, "createContext");
10
+ function provide(element, token, value) {
11
+ let map = providerStorage.get(element);
12
+ if (!map) {
13
+ map = /* @__PURE__ */ new Map();
14
+ providerStorage.set(element, map);
15
+ }
16
+ const existing = map.get(token.id);
17
+ if (existing) {
18
+ existing(value);
19
+ } else {
20
+ const sig = signal(value);
21
+ map.set(token.id, sig);
22
+ }
23
+ notifyPending(token.id);
24
+ return () => {
25
+ const m = providerStorage.get(element);
26
+ if (m) {
27
+ m.delete(token.id);
28
+ if (m.size === 0) providerStorage.delete(element);
29
+ }
30
+ };
31
+ }
32
+ __name(provide, "provide");
33
+ function resolveContextSignal(element, token) {
34
+ let current = element.parentElement;
35
+ while (current) {
36
+ const map = providerStorage.get(current);
37
+ if (map && map.has(token.id)) {
38
+ return map.get(token.id);
39
+ }
40
+ current = current.parentElement;
41
+ }
42
+ return void 0;
43
+ }
44
+ __name(resolveContextSignal, "resolveContextSignal");
45
+ function onContextAvailable(id, callback) {
46
+ let set = pendingCallbacks.get(id);
47
+ if (!set) {
48
+ set = /* @__PURE__ */ new Set();
49
+ pendingCallbacks.set(id, set);
50
+ }
51
+ set.add(callback);
52
+ return () => {
53
+ pendingCallbacks.get(id)?.delete(callback);
54
+ };
55
+ }
56
+ __name(onContextAvailable, "onContextAvailable");
57
+ function notifyPending(id) {
58
+ const set = pendingCallbacks.get(id);
59
+ if (set) {
60
+ for (const cb of set) cb();
61
+ }
62
+ }
63
+ __name(notifyPending, "notifyPending");
64
+ export {
65
+ createContext,
66
+ onContextAvailable,
67
+ provide,
68
+ resolveContextSignal
69
+ };
70
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/context.ts"],
4
+ "sourcesContent": ["import { signal } from './reactivity.js'\nimport type { ContextToken, Signal } from './types.js'\n\n// Provider storage: element -> (contextId -> Signal)\nconst providerStorage = new WeakMap<Element, Map<symbol, Signal<unknown>>>()\n\n// Pending consumers waiting for a context by id\nconst pendingCallbacks = new Map<symbol, Set<() => void>>()\n\n/**\n * Create a new context token.\n * Each token uniquely identifies a type of shared context.\n */\nexport function createContext<T> (): ContextToken<T> {\n return { id: Symbol('microtag-context') }\n}\n\n/**\n * Provide a context value from an element to its descendants.\n * Returns a cleanup function that removes the provided value.\n */\nexport function provide<T> (\n element: Element,\n token: ContextToken<T>,\n value: T\n): () => void {\n let map = providerStorage.get(element)\n if (!map) {\n map = new Map()\n providerStorage.set(element, map)\n }\n\n const existing = map.get(token.id) as Signal<T> | undefined\n if (existing) {\n existing(value)\n } else {\n const sig = signal(value) as unknown as Signal<T>\n map.set(token.id, sig as Signal<unknown>)\n }\n\n notifyPending(token.id)\n\n return () => {\n const m = providerStorage.get(element)\n if (m) {\n m.delete(token.id)\n if (m.size === 0) providerStorage.delete(element)\n }\n }\n}\n\n/**\n * Walk up the DOM from element to find the nearest provider signal.\n * Returns the signal (not the value) so callers can subscribe to changes.\n */\nexport function resolveContextSignal<T> (\n element: Element,\n token: ContextToken<T>\n): Signal<T> | undefined {\n let current: Element | null = element.parentElement\n while (current) {\n const map = providerStorage.get(current)\n if (map && map.has(token.id)) {\n return map.get(token.id) as Signal<T>\n }\n current = current.parentElement\n }\n return undefined\n}\n\n/**\n * Register a callback to run when the given context becomes available.\n * Returns a cleanup function to unregister.\n */\nexport function onContextAvailable (\n id: symbol,\n callback: () => void\n): () => void {\n let set = pendingCallbacks.get(id)\n if (!set) {\n set = new Set()\n pendingCallbacks.set(id, set)\n }\n set.add(callback)\n return () => { pendingCallbacks.get(id)?.delete(callback) }\n}\n\nfunction notifyPending (id: symbol): void {\n const set = pendingCallbacks.get(id)\n if (set) {\n for (const cb of set) cb()\n }\n}\n"],
5
+ "mappings": ";;AAAA,SAAS,cAAc;AAIvB,MAAM,kBAAkB,oBAAI,QAA+C;AAG3E,MAAM,mBAAmB,oBAAI,IAA6B;AAMnD,SAAS,gBAAqC;AACjD,SAAO,EAAE,IAAI,uBAAO,kBAAkB,EAAE;AAC5C;AAFgB;AAQT,SAAS,QACZ,SACA,OACA,OACU;AACV,MAAI,MAAM,gBAAgB,IAAI,OAAO;AACrC,MAAI,CAAC,KAAK;AACN,UAAM,oBAAI,IAAI;AACd,oBAAgB,IAAI,SAAS,GAAG;AAAA,EACpC;AAEA,QAAM,WAAW,IAAI,IAAI,MAAM,EAAE;AACjC,MAAI,UAAU;AACV,aAAS,KAAK;AAAA,EAClB,OAAO;AACH,UAAM,MAAM,OAAO,KAAK;AACxB,QAAI,IAAI,MAAM,IAAI,GAAsB;AAAA,EAC5C;AAEA,gBAAc,MAAM,EAAE;AAEtB,SAAO,MAAM;AACT,UAAM,IAAI,gBAAgB,IAAI,OAAO;AACrC,QAAI,GAAG;AACH,QAAE,OAAO,MAAM,EAAE;AACjB,UAAI,EAAE,SAAS,EAAG,iBAAgB,OAAO,OAAO;AAAA,IACpD;AAAA,EACJ;AACJ;AA5BgB;AAkCT,SAAS,qBACZ,SACA,OACqB;AACrB,MAAI,UAA0B,QAAQ;AACtC,SAAO,SAAS;AACZ,UAAM,MAAM,gBAAgB,IAAI,OAAO;AACvC,QAAI,OAAO,IAAI,IAAI,MAAM,EAAE,GAAG;AAC1B,aAAO,IAAI,IAAI,MAAM,EAAE;AAAA,IAC3B;AACA,cAAU,QAAQ;AAAA,EACtB;AACA,SAAO;AACX;AAbgB;AAmBT,SAAS,mBACZ,IACA,UACU;AACV,MAAI,MAAM,iBAAiB,IAAI,EAAE;AACjC,MAAI,CAAC,KAAK;AACN,UAAM,oBAAI,IAAI;AACd,qBAAiB,IAAI,IAAI,GAAG;AAAA,EAChC;AACA,MAAI,IAAI,QAAQ;AAChB,SAAO,MAAM;AAAE,qBAAiB,IAAI,EAAE,GAAG,OAAO,QAAQ;AAAA,EAAE;AAC9D;AAXgB;AAahB,SAAS,cAAe,IAAkB;AACtC,QAAM,MAAM,iBAAiB,IAAI,EAAE;AACnC,MAAI,KAAK;AACL,eAAW,MAAM,IAAK,IAAG;AAAA,EAC7B;AACJ;AALS;",
6
+ "names": []
7
+ }