@hot-page/fun 0.0.1 → 0.0.2

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/README.md CHANGED
@@ -63,7 +63,7 @@ running all the time.
63
63
  well as the `html` templator. Shadow element renders in shadow DOM, and
64
64
  light element renders in normal DOM.
65
65
  3. Define your functional component by providing a function.
66
- 4. Use the `state` argument to create new reactive properties
66
+ 4. Use `state` to create reactive properties
67
67
  5. Return a template that will be re-rendered
68
68
 
69
69
  Create a new element in plain JavaScript:
@@ -140,6 +140,61 @@ The setup function receives a context object with:
140
140
  - observed attributes - Each declared attribute is passed as a signal (see Observed Attributes below)
141
141
 
142
142
 
143
+ ## State
144
+
145
+ `state(value)` creates a reactive container. Read its current value with `.get()`, update it with `.set()`:
146
+
147
+ ```javascript
148
+ const count = state(0)
149
+ count.get() // 0
150
+ count.set(1)
151
+ count.get() // 1
152
+ ```
153
+
154
+ Any signal reads inside the render function are tracked — when the signal changes, the element re-renders. State can hold any value: primitives, objects, arrays.
155
+
156
+
157
+ ## Computed Values
158
+
159
+ `computed(fn)` derives a read-only value from one or more signals. It's lazy and cached — the function only re-runs when a signal it depends on changes:
160
+
161
+ ```javascript
162
+ import { shadowElement, html, state, computed } from '@hot-page/fun'
163
+
164
+ shadowElement(function TemperatureConverter() {
165
+ const celsius = state(0)
166
+ const fahrenheit = computed(() => celsius.get() * 9 / 5 + 32)
167
+
168
+ return () => html`
169
+ <input
170
+ type="range" min="-30" max="50"
171
+ .value=${celsius.get()}
172
+ @input=${e => celsius.set(Number(e.target.value))}
173
+ >
174
+ <p>${celsius.get()}°C = ${fahrenheit.get()}°F</p>
175
+ `
176
+ })
177
+ ```
178
+
179
+ `computed` has `.get()` but no `.set()`. Computed values can depend on other computed values — the signal graph ensures nothing recomputes more than once per change:
180
+
181
+ ```javascript
182
+ const items = state(['apple', 'banana', 'cherry'])
183
+ const count = computed(() => items.get().length)
184
+ const isEmpty = computed(() => count.get() === 0)
185
+ ```
186
+
187
+ Like `state`, computed values can live at module level and be shared across components:
188
+
189
+ ```javascript
190
+ // store.js
191
+ export const cart = state([])
192
+ export const cartTotal = computed(() =>
193
+ cart.get().reduce((sum, item) => sum + item.price, 0)
194
+ )
195
+ ```
196
+
197
+
143
198
  ## Rendering in Shadow or Light DOM
144
199
 
145
200
  This package provides two define exports:
@@ -301,7 +356,7 @@ Use `styleProps` when you want to update visual state from an event handler with
301
356
 
302
357
  ## Lifecycle & Cleanup
303
358
 
304
- Use the `effect` function to register side effects that need cleanup:
359
+ Use the `effect` function to register side effects that automatically track signal dependencies:
305
360
 
306
361
  ```javascript
307
362
  shadowElement(function oneSecondCounter({ effect }) {
@@ -330,19 +385,148 @@ shadowElement(function oneSecondCounter({ effect }) {
330
385
  ```
331
386
 
332
387
  **When effects run:**
333
- - Setup functions run when the element connects to the DOM
334
- - Cleanup functions run when the element disconnects from the DOM
335
- - If an element is moved in the DOM, cleanup runs, then setup runs again
388
+ - Effects run when the element connects to the DOM
389
+ - Effects **automatically re-run** whenever any signal read inside them changes
390
+ - Cleanup functions run before re-running the effect, and when the element disconnects
391
+ - If an element is moved in the DOM, cleanup runs, then effects run again
392
+
393
+ **Reactive effects:**
394
+
395
+ Effects automatically track any signals you read inside them and re-run when those signals change:
396
+
397
+ ```javascript
398
+ shadowElement(['size'], function Button({ size, effect }) {
399
+ const validSizes = ['sm', 'md', 'lg']
400
+
401
+ effect(() => {
402
+ const value = size.get() // Automatically tracked!
403
+ if (!validSizes.includes(value)) {
404
+ console.error(`Invalid size: "${value}". Expected: ${validSizes.join(', ')}`)
405
+ }
406
+ })
407
+
408
+ return () => html`<button class="${size.get()}">Click me</button>`
409
+ })
410
+ ```
411
+
412
+ When the `size` attribute changes, the effect re-runs and validates the new value.
413
+
414
+ **Syncing to external APIs:**
415
+
416
+ ```javascript
417
+ shadowElement(['theme'], function ThemeStorage({ theme, effect }) {
418
+ // N.B. a real app would use try/catch and validation
419
+ theme.set(localStorage.theme || 'light')
420
+
421
+ effect(() => localStorage.theme = theme.get())
422
+ })
423
+ ```
424
+
425
+ ```html
426
+ <theme-storage theme="dark">
427
+ ...rest of your app uses [theme=light/dark] selectors...
428
+ </theme-storage>
429
+
430
+ <script>
431
+ // Update from anywhere in your app and the effect runs, saving the value to local storage
432
+ document.querySelector('theme-storage').theme = 'dark'
433
+ </script>
434
+ ```
435
+
436
+ **Dynamic subscriptions with cleanup:**
437
+
438
+ ```javascript
439
+ shadowElement(['userId'], function UserProfile({ userId, effect }) {
440
+ const user = state(null)
441
+
442
+ effect(() => {
443
+ const id = userId.get()
444
+ if (!id) return
445
+
446
+ // Subscribe when userId changes
447
+ const unsubscribe = subscribeToUser(id, data => user.set(data))
448
+
449
+ // `unsubscribe` runs before re-subscribing to a new user
450
+ return unsubscribe
451
+ })
452
+
453
+ return () => html`<div>${user.get()?.name || 'Loading...'}</div>`
454
+ })
455
+ ```
456
+
457
+ When `userId` changes, the previous subscription cleanup runs, then the effect re-runs and subscribes to the new user.
458
+
459
+ **Roll-your-own reactivity:**
460
+
461
+ You can skip lit-html entirely and manipulate the DOM directly in an effect:
462
+
463
+ ```javascript
464
+ shadowElement(function ManualCounter({ effect }) {
465
+ const count = state(1)
466
+
467
+ effect(() => {
468
+ // Update DOM manually when count changes
469
+ const span = this.shadowRoot.querySelector('#value')
470
+ span.textContent = count.get()
471
+ })
472
+
473
+ this.addEventListener('click', (event) => {
474
+ if (event.target.closest('#increment')) {
475
+ count.set(count.get() + 1)
476
+ } else if (event.target.closest('#decrement')) {
477
+ count.set(count.get() - 1)
478
+ }
479
+ })
480
+
481
+ return `
482
+ <button id="decrement">-</button>
483
+ <span id="value"></span>
484
+ <button id="increment">+</button>
485
+ `
486
+ })
487
+ ```
488
+
489
+ The first effect tracks `count` and updates the DOM when it changes. The second effect doesn't track any signals, so it runs once to set up event listeners.
490
+
491
+ **Non-reactive effects:**
492
+
493
+ If your effect doesn't read any signals, it behaves like a simple mount/unmount handler:
494
+
495
+ ```javascript
496
+ effect(() => {
497
+ console.log('Mounted!')
498
+ return () => console.log('Unmounted!')
499
+ })
500
+ ```
501
+
502
+ This runs once on mount and cleanup runs on unmount — no re-runs since it doesn't track any signals.
503
+
504
+ **Avoiding unintended tracking:**
505
+
506
+ If you need to read a signal's value without tracking it (rare), use `queueMicrotask`:
507
+
508
+ ```javascript
509
+ effect(() => {
510
+ const reactiveValue = count.get() // Tracked
511
+
512
+ queueMicrotask(() => {
513
+ const snapshot = otherSignal.get() // Not tracked
514
+ doSomething(snapshot)
515
+ })
516
+ })
517
+ ```
336
518
 
337
519
  **When you need effects:**
520
+ - Validation with side effects (logging errors, showing warnings)
521
+ - Syncing to external storage (localStorage, IndexedDB)
338
522
  - Global event listeners (window, document)
339
- - Timers (setInterval, setTimeout)
523
+ - Timers that depend on component state
340
524
  - Observers (IntersectionObserver, MutationObserver)
341
- - External subscriptions (WebSocket, EventSource)
525
+ - External subscriptions (WebSocket, EventSource, Firebase)
342
526
 
343
527
  **When you DON'T need effects:**
344
528
  - Event listeners in your template (lit-html handles cleanup automatically)
345
- - Signal watchers (they're tied to the element lifecycle)
529
+ - Pure computations (use `computed` or derive inline in the render function)
346
530
 
347
531
 
348
532
  ## Observed Attributes
@@ -685,12 +869,13 @@ For more complex scenarios with multiple files, create a dedicated store module:
685
869
 
686
870
  ```javascript
687
871
  // store.js
688
- import { state } from '@hot-page/fun'
872
+ import { state, computed } from '@hot-page/fun'
689
873
 
690
874
  export const store = {
691
875
  user: state(null),
692
876
  theme: state('light'),
693
877
  notifications: state([]),
878
+ notificationCount: computed(() => store.notifications.get().length),
694
879
 
695
880
  login(userData) {
696
881
  this.user.set(userData)
@@ -727,6 +912,145 @@ shadowElement(function UserBadge() {
727
912
  All components reading from `store` will automatically re-render when the shared state changes.
728
913
 
729
914
 
915
+ ## What the Setup Function Can Return
916
+
917
+ The setup function can return different things depending on how much reactivity you need:
918
+
919
+ | Return value | Behavior |
920
+ |---|---|
921
+ | **Function** | Reactive. Called on every signal change to re-render the element. |
922
+ | **Template** (`html\`...\``) | Rendered once. No reactivity — signals read inside won't trigger updates. |
923
+ | **String** | Rendered once as HTML markup via `innerHTML`. If the render function returns a string, each update also goes through `innerHTML`. |
924
+ | **Nothing** (`undefined`) | Nothing is rendered. Useful when the setup function only registers effects or sets properties. |
925
+ | **Anything else** | Logs a `console.error` at construction time. |
926
+
927
+ The typical pattern is to return a render function so the element reacts to signal changes:
928
+
929
+ ```javascript
930
+ shadowElement(function MyEl() {
931
+ const count = state(0)
932
+
933
+ // ✅ function — reactive
934
+ return () => html`<p>${count.get()}</p>`
935
+ })
936
+ ```
937
+
938
+ The render function doesn't have to return a template. If it returns nothing, it's still called whenever signals change — you just manage the output yourself. This is useful when you want reactivity without handing DOM control to lit-html.
939
+
940
+ For example, an element that takes a `theme` attribute and sets its colors directly — no template needed, just style updates:
941
+
942
+ ```javascript
943
+ shadowElement(['theme'], function ThemedBox({ theme }) {
944
+ return () => {
945
+ const isDark = theme.get() === 'dark'
946
+ this.style.background = isDark ? '#1a1a2e' : '#f5f0e8'
947
+ this.style.color = isDark ? '#ffffff' : '#000000'
948
+ // no return — render function just sets styles
949
+ }
950
+ })
951
+ ```
952
+
953
+ ```html
954
+ <themed-box theme="dark">Dark mode content</themed-box>
955
+ <themed-box theme="light">Light mode content</themed-box>
956
+ ```
957
+
958
+ Change the `theme` attribute and the colors update reactively.
959
+
960
+ Or an element that manages its own DOM with `innerHTML`:
961
+
962
+ ```javascript
963
+ shadowElement(['items'], function RawRenderer({ items }) {
964
+ return () => {
965
+ this.shadowRoot.innerHTML = (items.get() ?? '')
966
+ .split(' ')
967
+ .map(item => `<li>${item.trim()}</li>`)
968
+ .join('')
969
+ // no return — we've already written to the DOM directly
970
+ }
971
+ })
972
+ ```
973
+
974
+ ```html
975
+ <raw-renderer items="one two three"></raw-renderer>
976
+ ```
977
+
978
+ Both are fully reactive: the function reruns whenever any signal read inside it changes.
979
+
980
+ You can also conditionally return nothing — it's a no-op:
981
+
982
+ ```javascript
983
+ shadowElement(['mode'], function ConditionalRender({ mode }) {
984
+ return () => {
985
+ if (mode.get() === 'custom') {
986
+ // manage DOM yourself
987
+ this.shadowRoot.innerHTML = '<p>Custom render</p>'
988
+ return // no-op, we already rendered
989
+ }
990
+ // otherwise return a template
991
+ return html`<p>Standard render</p>`
992
+ }
993
+ })
994
+ ```
995
+
996
+ If you want to render something that will never change, you can return a template directly:
997
+
998
+ ```javascript
999
+ shadowElement(function StaticGreeting() {
1000
+ // ✅ template — rendered once, no reactivity
1001
+ return html`<p>Hello, world!</p>`
1002
+ })
1003
+ ```
1004
+
1005
+ Returning nothing is fine when your setup only needs side effects:
1006
+
1007
+ ```javascript
1008
+ shadowElement(function SideEffectOnly({ effect }) {
1009
+ effect(() => {
1010
+ console.log('connected')
1011
+ return () => console.log('disconnected')
1012
+ })
1013
+
1014
+ // ✅ no return — nothing rendered
1015
+ })
1016
+ ```
1017
+
1018
+ Returning a plain string is a shortcut for fully static markup you control:
1019
+
1020
+ ```javascript
1021
+ shadowElement(function Disclaimer() {
1022
+ return '<p>All prices include VAT.</p>'
1023
+ })
1024
+ ```
1025
+
1026
+ A render function can also return a string, in which case each reactive update sets `innerHTML` with the new value:
1027
+
1028
+ ```javascript
1029
+ shadowElement(function Greeting() {
1030
+ const name = state('world')
1031
+
1032
+ return () => `<p>Hello, ${name.get()}!</p>`
1033
+ })
1034
+ ```
1035
+
1036
+ The same rule applies: this is direct `innerHTML` assignment, so only use it with content you control.
1037
+
1038
+ **Do not put user input in a string return.** The string goes straight into `innerHTML` with no escaping, so any HTML it contains is executed. If the content comes from a user, a database, or anywhere outside your source code, use `html\`...\`` instead — lit-html escapes expression values by default:
1039
+
1040
+ ```javascript
1041
+ // ❌ XSS: userBio could contain <script>...</script>
1042
+ return `<p>${userBio}</p>`
1043
+
1044
+ // ✅ Safe: lit-html escapes the value
1045
+ return () => html`<p>${userBio}</p>`
1046
+ ```
1047
+
1048
+ This library is for developers who know what they're putting in their markup and when to reach for `html\`...\``. It doesn't try to protect you from yourself.
1049
+
1050
+
1051
+ Any other return type (number, object, array, etc.) logs a `console.error` immediately so you catch the mistake early.
1052
+
1053
+
730
1054
  ## Gotchas
731
1055
 
732
1056
  ### Call `signal.get()` inside the render function
@@ -807,6 +1131,43 @@ document.body.appendChild(el)
807
1131
  // now it runs
808
1132
  ```
809
1133
 
1134
+ ### Effects track signal reads automatically
1135
+
1136
+ Effects re-run whenever any signal read inside them changes. This is usually what you want, but watch out for:
1137
+
1138
+ **Infinite loops** — writing to a signal you're reading in the same effect can cause rapid re-runs:
1139
+
1140
+ ```javascript
1141
+ // ⚠️ Will re-run rapidly until stopped
1142
+ effect(() => {
1143
+ count.set(count.get() + 1) // Reads then writes
1144
+ })
1145
+
1146
+ // ✅ OK — conditional limits execution
1147
+ effect(() => {
1148
+ const val = count.get()
1149
+ if (val < 10) {
1150
+ count.set(val + 1)
1151
+ }
1152
+ })
1153
+ ```
1154
+
1155
+ Always add guards when writing to tracked signals within an effect.
1156
+
1157
+ **Unintended tracking** — reading a signal always tracks it, even in conditionals:
1158
+
1159
+ ```javascript
1160
+ effect(() => {
1161
+ if (enabled.get()) {
1162
+ console.log(value.get())
1163
+ }
1164
+ })
1165
+ // Tracks both `enabled` and `value` once enabled is true
1166
+ // Effect re-runs when either changes
1167
+ ```
1168
+
1169
+ Use `queueMicrotask` if you need to read a signal without tracking it (see Lifecycle & Cleanup section).
1170
+
810
1171
  ### Setting multiple signals triggers one render
811
1172
 
812
1173
  Updating several signals in a row is coalesced into a single render on the next microtask. This is a feature, but it means you can't observe intermediate state between sets:
@@ -863,6 +1224,11 @@ return () => svg`<circle ... />` // ✅ use svg only at SVG root
863
1224
  The distinction matters because lit-html uses the tag to parse the template in the correct namespace context. Using `html` for SVG roots will result in elements created in the HTML namespace, which browsers won't render correctly.
864
1225
 
865
1226
 
1227
+ ## Roadmap
1228
+
1229
+ - **Typed attributes** — Declare typed attributes so the framework converts them automatically, rather than having to parse strings manually in each component. Types: integer, float, boolean, token list, JSON, function. Yes, function for more _fun_.
1230
+
1231
+
866
1232
  ## A Hot Page Project
867
1233
 
868
1234
  This open-source project is built by the engineeers at [Hot Page](https://hot.page),
package/dist/index.d.ts CHANGED
@@ -31,6 +31,7 @@ declare function shadowElement(styles: string, fn: FunctionalComponent): void;
31
31
  declare function shadowElement<Attrs extends string>(observedAttributes: Attrs[], fn: FunctionalComponent<Attrs>): void;
32
32
  declare function shadowElement<Attrs extends string>(observedAttributes: Attrs[], styles: string, fn: FunctionalComponent<Attrs>): void;
33
33
  declare const state: <T>(value: T) => Signal.State<T>;
34
- export { state, lightElement, shadowElement };
34
+ declare const computed: <T>(fn: () => T) => Signal.Computed<T>;
35
+ export { state, computed, lightElement, shadowElement };
35
36
  export declare function define<Attrs extends string = never>(options: DefineOptions<Attrs>): void;
36
37
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}