sprae 2.14.2 → 3.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/package.json CHANGED
@@ -1,13 +1,11 @@
1
1
  {
2
2
  "name": "sprae",
3
3
  "description": "DOM microhydration.",
4
- "version": "2.14.2",
4
+ "version": "3.0.0",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
7
7
  "type": "module",
8
8
  "dependencies": {
9
- "@preact/signals-core": "^1.2.3",
10
- "signal-struct": "^1.10.0",
11
9
  "swapdom": "^1.1.1"
12
10
  },
13
11
  "devDependencies": {
@@ -16,6 +14,7 @@
16
14
  "esbuild": "^0.15.14",
17
15
  "hyperf": "^1.5.0",
18
16
  "jsdom": "^21.1.0",
17
+ "signal-struct": "^1.10.0",
19
18
  "terser": "^5.15.1",
20
19
  "tst": "^7.1.1",
21
20
  "usignal": "^0.8.9",
@@ -24,7 +23,7 @@
24
23
  },
25
24
  "scripts": {
26
25
  "test": "node -r ./test/register.cjs test/test.js",
27
- "build": "esbuild --bundle ./src/index.js --outfile=sprae.js --format=esm",
26
+ "build": "esbuild --bundle ./src/index.js --outfile=sprae.js --format=esm && npm run min",
28
27
  "watch": "esbuild --bundle ./src/index.js --outfile=sprae.js --format=esm --sourcemap --watch",
29
28
  "min": "terser sprae.js -o sprae.min.js --module -c passes=3 -m"
30
29
  },
package/r&d.md CHANGED
@@ -320,7 +320,7 @@
320
320
  + it has better control over serialization
321
321
  + `:onchange:oninput="e=>xyz"` is very good
322
322
 
323
- ## [ ] Sandbox? -> too complex for now. Waiting for use-cases
323
+ ## [x] Sandbox? -> we need it anyways via Proxy, so yes
324
324
 
325
325
  1. Use subscript?
326
326
  + solves access to any internal signals on syntactic level
@@ -365,6 +365,7 @@
365
365
  + does minimal catch
366
366
  + allows scope control
367
367
  + allows dynamic subscription to requested fields ( no need for preact/signals neither for signal-struct )
368
+ + we anyways need sandbox even in case of subscript
368
369
 
369
370
  ## [x] :onclick="direct code" ? -> no: immediately invoked.
370
371
 
@@ -451,29 +452,28 @@
451
452
 
452
453
  ## [ ] Prop modifiers
453
454
 
454
- * [ ] Prop modifiers
455
- - overall seems code complication without much benefit
456
- * [ ] value.bind? value.watch?
457
- - let's wait for use-case: value can be too big to set it every time
458
- * [ ] prop.reflect, prop.observe
459
- - let's wait for use-case
460
- * [ ] prop.boolean, .number, .string, .array, .object
461
- - let's wait for use-case
462
- * [ ] prop.once, prop.fx ? prop.init?
463
- - doesn't seem required, let's wait for use case
464
- * [ ] prop.change - run only if value changes
465
- - seems like unnecessary manual optimization that must be done always automatically
466
- ? are there cases where force-update is necessary?
467
- * [ ] prop.throttle-xxx, prop.debounce-xxx
468
- - let's wait until that's really a problem
469
- * [ ] prop.class
470
- ? what's the use-case
471
- * [ ] prop.next="" - run update after other DOM updates happen
472
- * [ ] prop.fx="" - run effect without changing property
473
- * [ ] x.prop="xyz" - set element property, rather than attribute (following topic)
474
- * [ ] x.raf="abc" - run regularly?
475
- * [ ] x.watch-a-b-c - update by change of any of the deps
476
- * [ ] :x.always - update by _any_ dep change
455
+ - overall seems code complication without much benefit
456
+ * [ ] value.bind? value.watch?
457
+ - let's wait for use-case: value can be too big to set it every time
458
+ * [ ] prop.reflect, prop.observe
459
+ - let's wait for use-case
460
+ * [ ] prop.boolean, .number, .string, .array, .object
461
+ - let's wait for use-case
462
+ * [ ] prop.once, prop.fx ? prop.init?
463
+ - doesn't seem required, let's wait for use case
464
+ * [ ] prop.change - run only if value changes
465
+ - seems like unnecessary manual optimization that must be done always automatically
466
+ ? are there cases where force-update is necessary?
467
+ * [ ] prop.throttle-xxx, prop.debounce-xxx
468
+ - let's wait until that's really a problem
469
+ * [ ] prop.class
470
+ ? what's the use-case
471
+ * [ ] prop.next="" - run update after other DOM updates happen
472
+ * [ ] prop.fx="" - run effect without changing property
473
+ * [ ] x.prop="xyz" - set element property, rather than attribute (following topic)
474
+ * [ ] x.raf="abc" - run regularly?
475
+ * [ ] x.watch-a-b-c - update by change of any of the deps
476
+ * [ ] :x.always - update by _any_ dep change
477
477
 
478
478
  ## [x] Writing props on elements (like ones in :each) -> nah, just use `:x="this.x=abc"`
479
479
 
package/readme.md CHANGED
@@ -22,6 +22,7 @@ Sprae defines attributes starting with `:` as directives:
22
22
 
23
23
  * `sprae` initializes subtree with data and immediately evaporates `:` attrs.
24
24
  * `state` is object reflecting current values, changing any of its props rerenders subtree.
25
+ * To batch-update multiple properties `sprae` can be run repeatedly as: `sprae(container, newValues)`
25
26
 
26
27
  <!--
27
28
  <details>
@@ -251,96 +252,13 @@ Expose element to data scope with the `id`:
251
252
  </script>
252
253
  ```
253
254
 
255
+ ## Sandbox
254
256
 
255
- <!--
256
-
257
- ### Reactivity
258
-
259
- _sprae_ is built on top of [_@preact/signals_](https://ghub.io/@preact/signals). That gives:
260
-
261
- * Expressions don't require explicit access to `.value` (see [signal-struct](https://github.com/dy/signal-struct))
262
- * Expressions support any reactive values in data (see [sube](https://github.com/dy/sube))
263
- * Updates happen minimally only when used values update
264
- * Subscription is weak and get disposed when element is disposed.
265
-
266
- Directive expressions are natively reactive, ie. data may contain any async/reactive values, such as:
267
-
268
- * _Promise_ / _Thenable_
269
- * _Observable_ / _Subject_ / _Subscribable_
270
- * _AsyncIterable_
271
- * _observ-*_
272
- * etc., see [sube](https://github.com/dy/sube/blob/main/README.md) for the full list.
273
-
274
- This way, for example, _@preact/signals_ or _rxjs_ can be connected directly bypassing subscription or reading value.
275
- -->
276
-
277
- ## Hints
278
-
279
- **1.** To batch-update state (avoid multiple DOM changes), rerun sprae with new state:
280
-
281
- ```html
282
- <li :each="item, id in items" :key="id" :text="item"></li>
283
-
284
- <script type="module">
285
- sprae(el, {items: ['foo', 'bar', 'baz']})
286
- // <li>foo</li><li>bar</li><li>baz</li>
287
-
288
- sprae(el, {items: ['foo', 'qux']})
289
- // <li>foo</li><li>qux</li>
290
- </script>
291
- ```
292
-
293
- **2.** Data supports signal values, which can be an alternative way to control template state:
294
-
295
- ```html
296
- <div id="done" :text="loading ? 'loading' : result">...</div>
297
-
298
- <script type="module">
299
- import sprae from 'sprae';
300
- import { signal } from '@preact/signals';
257
+ Expressions are sandboxed, ie. have no access to global or window.
301
258
 
302
- // <div id="done">...</div>
259
+ Default sandbox provides: _Array_, _Object_, _Number_, _String_, _Boolean_, _Date_, _console_.
303
260
 
304
- const loading = signal(true), result = signal(false);
305
- sprae(done, { loading, result })
306
- setTimeout(() => (loading.value = true, result.value = 'done'), 1000)
307
-
308
- // <div id="done">loading</div>
309
-
310
- // ... 1s after
311
- // <div id="done">done</div>
312
- </script>
313
- ```
314
-
315
- **3.** Data recognizes reactive values as inputs as well: _Promise_ / _Thenable_, _Observable_ / _Subscribable_, _AsyncIterable_ (etc., see [sube](https://github.com/dy/sube/blob/main/README.md)). This way, for example, _rxjs_ can be connected to template directly.
316
-
317
- ```html
318
- <div :text="clicks">#</div> clicks
319
-
320
- <script type="module">
321
- import sprae from 'sprae';
322
- import { fromEvent, scan } from 'rxjs';
323
- sprae(document, {
324
- clicks: fromEvent(document, 'click').pipe(scan((count) => count + 1, 0))
325
- });
326
- </script>
327
- ```
328
-
329
- **4.** Getters turn into computed values automatically (setters remain as is):
330
-
331
- ```html
332
- <div id="x-plus-y">
333
- <span :text="x">x</span> + <span :text="y">y</span> = <span :text="z">z</span>
334
- </div>
335
-
336
- <script type="module">
337
- import sprae from 'sprae';
338
- let state = sprae(document, { x:1, y:1, get z() { return this.x + this.y } })
339
-
340
- state.x = 2, state.y = 2
341
- state.z // 4
342
- </script>
343
- ```
261
+ Sandbox can be extended via `Object.assign(sprae.sandbox, { BigInt, window, document })` etc.
344
262
 
345
263
  ## Examples
346
264