wcstack 1.22.6

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 (3) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +304 -0
  3. package/package.json +32 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wcstack
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,304 @@
1
+ # wcstack
2
+
3
+ **wcstack** is a set of 41 zero-dependency Web Components packages: reactive data binding, declarative SPA routing, and 30+ Web APIs exposed as HTML tags. No build step, no bundler, no framework runtime. One CDN `<script>` tag per package.
4
+
5
+ Project site: **https://wcstack.github.io** · Source: **https://github.com/wcstack/wcstack**
6
+
7
+ ---
8
+
9
+ ## Read this first if you are an AI coding agent
10
+
11
+ This file is a complete, self-contained guide to writing a correct wcstack app. Read it top to bottom, then **verify what you wrote**:
12
+
13
+ ```bash
14
+ npx @wcstack/lint index.html # exit code 0 = clean. Iterate until it exits 0.
15
+ ```
16
+
17
+ Do not guess at syntax that is not documented here. wcstack has little presence in training data, so invented syntax will look plausible and be wrong. Two rules cover most failures:
18
+
19
+ - **Filters transform values. They never attach to event handlers.**
20
+ - **State must be reassigned, not mutated in place.**
21
+
22
+ Both are spelled out under [What does not work](#what-does-not-work).
23
+
24
+ ---
25
+
26
+ ## Do not install this package
27
+
28
+ This package contains documentation only. wcstack is buildless — load what you need from a CDN:
29
+
30
+ ```html
31
+ <script type="module" src="https://esm.run/@wcstack/state/auto"></script>
32
+ <script type="module" src="https://esm.run/@wcstack/router/auto"></script>
33
+ <script type="module" src="https://esm.run/@wcstack/fetch/auto"></script>
34
+ ```
35
+
36
+ Each `/auto` script registers its custom elements and does nothing else. No initialization call, no bootstrap. Tags activate when the browser parses them.
37
+
38
+ If you do want npm packages, install the individual ones (`@wcstack/state`, `@wcstack/router`, …) rather than this one.
39
+
40
+ ---
41
+
42
+ ## A complete working app
43
+
44
+ This is a full todo app. Save it as `index.html` and open it in a browser — nothing else is required.
45
+
46
+ ```html
47
+ <!DOCTYPE html>
48
+ <html lang="en">
49
+ <head>
50
+ <meta charset="UTF-8">
51
+ <title>Todo</title>
52
+ <script type="module" src="https://esm.run/@wcstack/state/auto"></script>
53
+ <style>
54
+ .done { text-decoration: line-through; color: #999; }
55
+ </style>
56
+ </head>
57
+ <body>
58
+
59
+ <wcs-state>
60
+ <script type="module">
61
+ export default {
62
+ // ---- data ----
63
+ todos: [
64
+ { id: 1, text: "Read the guide", done: false }
65
+ ],
66
+ nextId: 2,
67
+ draft: "",
68
+ filter: "all",
69
+
70
+ // ---- computed: plain getters, recalculated automatically ----
71
+ get visible() {
72
+ if (this.filter === "active") return this.todos.filter(t => !t.done);
73
+ if (this.filter === "done") return this.todos.filter(t => t.done);
74
+ return this.todos;
75
+ },
76
+ get remaining() {
77
+ return this.todos.filter(t => !t.done).length;
78
+ },
79
+ get isEmpty() {
80
+ return this.todos.length === 0;
81
+ },
82
+
83
+ // ---- methods: always REASSIGN, never mutate ----
84
+ add() {
85
+ const text = this.draft.trim();
86
+ if (!text) return;
87
+ this.todos = [...this.todos, { id: this.nextId, text, done: false }];
88
+ this.nextId = this.nextId + 1;
89
+ this.draft = "";
90
+ },
91
+ toggle() {
92
+ // Inside a `for:` loop, the current row is readable by wildcard path.
93
+ const id = this["visible.*.id"];
94
+ this.todos = this.todos.map(t => t.id === id ? { ...t, done: !t.done } : t);
95
+ },
96
+ remove() {
97
+ const id = this["visible.*.id"];
98
+ this.todos = this.todos.filter(t => t.id !== id);
99
+ },
100
+ showAll() { this.filter = "all"; },
101
+ showActive() { this.filter = "active"; },
102
+ showDone() { this.filter = "done"; }
103
+ };
104
+ </script>
105
+ </wcs-state>
106
+
107
+ <form data-wcs="onsubmit#prevent: add">
108
+ <input data-wcs="value: draft" placeholder="What needs doing?">
109
+ <button type="submit">Add</button>
110
+ </form>
111
+
112
+ <ul>
113
+ <template data-wcs="for: visible">
114
+ <li>
115
+ <input type="checkbox" data-wcs="checked#ro: .done; onchange: toggle">
116
+ <span data-wcs="textContent: .text; class.done: .done"></span>
117
+ <button type="button" data-wcs="onclick: remove">x</button>
118
+ </li>
119
+ </template>
120
+ </ul>
121
+
122
+ <template data-wcs="if: isEmpty">
123
+ <p>Nothing yet.</p>
124
+ </template>
125
+
126
+ <p><span data-wcs="textContent: remaining"></span> remaining</p>
127
+
128
+ <button type="button" data-wcs="onclick: showAll">All</button>
129
+ <button type="button" data-wcs="onclick: showActive">Active</button>
130
+ <button type="button" data-wcs="onclick: showDone">Done</button>
131
+
132
+ </body>
133
+ </html>
134
+ ```
135
+
136
+ Note `checked#ro:` on the checkbox. Without `#ro`, the two-way binding writes `.done` back on `input`, and the `onchange` handler flips it again — a double toggle that nets to nothing. When a handler is the single writer, mark the reflection read-only.
137
+
138
+ ---
139
+
140
+ ## Binding syntax
141
+
142
+ State and UI are connected by **path strings only**. There are no hooks, selectors, or per-element binding objects.
143
+
144
+ ```
145
+ property[#modifier]: path[@state][|filter[|filter(args)]...]
146
+ ```
147
+
148
+ Multiple bindings are separated by `;`:
149
+
150
+ ```html
151
+ <div data-wcs="textContent: count; class.over: count|gt(10)"></div>
152
+ ```
153
+
154
+ ### Properties
155
+
156
+ | Property | Meaning |
157
+ |---|---|
158
+ | `value` | Element value (two-way on inputs) |
159
+ | `checked` | Checkbox / radio state (two-way) |
160
+ | `textContent` / `text` | Text content |
161
+ | `html` | innerHTML |
162
+ | `class.NAME` | Toggle one CSS class |
163
+ | `style.PROP` | Set one style property |
164
+ | `attr.NAME` | Set an attribute (SVG-aware) |
165
+ | `radio` | Radio group (two-way) |
166
+ | `checkbox` | Checkbox group bound to an array (two-way) |
167
+ | `onclick`, `on*` | Event handler |
168
+
169
+ ### Modifiers
170
+
171
+ | Modifier | Meaning |
172
+ |---|---|
173
+ | `#ro` | Read-only — disables the two-way write-back |
174
+ | `#prevent` | `event.preventDefault()` on handlers |
175
+ | `#stop` | `event.stopPropagation()` on handlers |
176
+ | `#onchange` | Use `change` instead of `input` for two-way binding |
177
+ | `#init=element` | The element owns the initial value (use with `<wcs-storage>` and monitors) |
178
+
179
+ Combine after one `#`, comma separated: `value#ro,init=none: path`.
180
+
181
+ ### Paths
182
+
183
+ | Form | Meaning |
184
+ |---|---|
185
+ | `count`, `user.name` | Plain property path |
186
+ | `items.*.price` | Wildcard — the current row inside a `for:` loop |
187
+ | `.price` | Shorthand for the current row's property inside a loop |
188
+ | `path@cart` | Read from a *named* state element (`<wcs-state name="cart">`) |
189
+
190
+ ### Structural directives
191
+
192
+ Always on a `<template>` element:
193
+
194
+ ```html
195
+ <template data-wcs="for: items"> ... </template>
196
+ <template data-wcs="if: isReady"> ... </template>
197
+ <template data-wcs="elseif: isLoading"> ... </template>
198
+ <template data-wcs="else:"> ... </template>
199
+ ```
200
+
201
+ ### Computed values
202
+
203
+ Plain getters. Wildcard getters compute per row, and `$getAll` aggregates across rows:
204
+
205
+ ```javascript
206
+ get "cart.items.*.subtotal"() {
207
+ return this["cart.items.*.price"] * this["cart.items.*.quantity"];
208
+ },
209
+ get "cart.total"() {
210
+ return this.$getAll("cart.items.*.subtotal", []).reduce((a, b) => a + b, 0);
211
+ }
212
+ ```
213
+
214
+ ### Event handlers
215
+
216
+ Handlers receive the event, then the loop indexes:
217
+
218
+ ```javascript
219
+ removeItem(event, index) {
220
+ // `index` is the loop position — correct only when the template iterates
221
+ // the same array you are mutating. If you loop over a FILTERED getter,
222
+ // identify the row by id via the wildcard path instead (see the app above).
223
+ this.items = this.items.toSpliced(index, 1);
224
+ }
225
+ ```
226
+
227
+ ---
228
+
229
+ ## What does not work
230
+
231
+ These are the mistakes that actually occur. Each has a working replacement.
232
+
233
+ ```html
234
+ <!-- Filters transform VALUES. An event handler never takes a filter. -->
235
+ BAD: <input data-wcs="onkeydown: add|enter">
236
+ GOOD: <input data-wcs="onkeydown: add"> <!-- check event.key inside add() -->
237
+
238
+ <!-- Structural directives require a <template>. -->
239
+ BAD: <div data-wcs="for: items"> ... </div>
240
+ GOOD: <template data-wcs="for: items"> ... </template>
241
+
242
+ <!-- `{{ }}` outside a template causes FOUC. -->
243
+ BAD: <p>{{ count }}</p>
244
+ GOOD: <p><span data-wcs="textContent: count"></span></p>
245
+ ```
246
+
247
+ ```javascript
248
+ // State must be REASSIGNED. In-place mutation is not tracked.
249
+ BAD: this.items.push(x);
250
+ BAD: this.items[0] = x;
251
+ BAD: this.user.name = "new";
252
+ GOOD: this.items = [...this.items, x];
253
+ GOOD: this["items.0"] = x;
254
+ GOOD: this["user.name"] = "new";
255
+
256
+ // Immutable array methods are the idiom.
257
+ this.items = this.items.toSpliced(index, 1);
258
+ this.items = this.items.map(t => t.id === id ? { ...t, done: true } : t);
259
+ ```
260
+
261
+ ---
262
+
263
+ ## Verify before you finish
264
+
265
+ ```bash
266
+ # Check any HTML against the data-wcs contract. No install, no config.
267
+ npx @wcstack/lint index.html
268
+
269
+ # Errors only, for a generate-validate-fix loop:
270
+ npx @wcstack/lint --errors-only index.html
271
+ ```
272
+
273
+ Exit code `0` means clean, `1` means at least one error-severity finding, `2` means a usage or read failure. Diagnostics carry stable `wcs/*` codes and `source:line:col` ranges.
274
+
275
+ ---
276
+
277
+ ## The rest of the stack
278
+
279
+ `<wcs-state>` is one package. Every other capability is a tag that speaks the same binding protocol, so they compose without glue code.
280
+
281
+ | Package | Tag | Role |
282
+ |---|---|---|
283
+ | `@wcstack/state` | `<wcs-state>` | Reactive state + `data-wcs` binding |
284
+ | `@wcstack/router` | `<wcs-router>` | Declarative SPA routing (Navigation API) |
285
+ | `@wcstack/autoloader` | — | Import-Map-driven auto-registration of components |
286
+ | `@wcstack/signals` | — | Signals core (`signal` / `computed` / `effect`), JS-first alternative |
287
+ | `@wcstack/fetch` | `<wcs-fetch>` | HTTP with automatic re-fetch on dependency change |
288
+ | `@wcstack/storage` | `<wcs-storage>` | localStorage / sessionStorage |
289
+ | `@wcstack/websocket` | `<wcs-ws>` | WebSocket |
290
+ | `@wcstack/sse` | `<wcs-sse>` | Server-Sent Events |
291
+ | `@wcstack/lint` | — | Static-contract validator CLI |
292
+ | `@wcstack/devtools` | — | In-page inspector overlay |
293
+
294
+ Plus 25+ more wrapping camera, speech, geolocation, notifications, clipboard, sensors, observers, and other Web APIs. Full catalog: https://wcstack.github.io
295
+
296
+ ### Deeper references
297
+
298
+ - **Agent skill** (complete binding syntax, router skeletons, tag catalog): https://github.com/wcstack/wcstack-skill
299
+ - **Repository guide for agents**: https://github.com/wcstack/wcstack/blob/main/AGENTS.md
300
+ - **Per-package docs**: `npm view @wcstack/state readme`, `npm view @wcstack/router readme`, …
301
+
302
+ ## License
303
+
304
+ MIT
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "wcstack",
3
+ "version": "1.22.6",
4
+ "description": "Entry point for wcstack - 41 zero-dependency Web Components packages. Reactive data binding, declarative routing and 30+ Web APIs as HTML tags. Buildless: one CDN script tag per package. Run `npm view wcstack readme` for the full authoring guide.",
5
+ "keywords": [
6
+ "web-components",
7
+ "custom-elements",
8
+ "reactive",
9
+ "data-binding",
10
+ "state-management",
11
+ "router",
12
+ "spa",
13
+ "buildless",
14
+ "zero-dependencies",
15
+ "declarative",
16
+ "wcstack"
17
+ ],
18
+ "author": "mogera551",
19
+ "homepage": "https://wcstack.github.io",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/wcstack/wcstack.git",
23
+ "directory": "packages/wcstack"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/wcstack/wcstack/issues"
27
+ },
28
+ "license": "MIT",
29
+ "files": [
30
+ "README.md"
31
+ ]
32
+ }