lilact 0.2.3 → 0.4.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 (51) hide show
  1. package/README.md +1 -1
  2. package/dist/lilact.development.min.js +1 -1
  3. package/dist/lilact.development.min.js.map +1 -1
  4. package/dist/lilact.production.min.js +1 -1
  5. package/dist/lilact.production.min.js.map +1 -1
  6. package/docs/assets/navigation.js +1 -1
  7. package/docs/assets/search.js +1 -1
  8. package/docs/classes/accessories.ErrorBoundary.html +8 -8
  9. package/docs/classes/accessories.Suspense.html +7 -7
  10. package/docs/classes/components.Component.html +10 -10
  11. package/docs/classes/components.HTMLComponent.html +10 -10
  12. package/docs/classes/components.RootComponent.html +10 -10
  13. package/docs/functions/components.createComponent.html +1 -1
  14. package/docs/functions/components.createRoot.html +1 -1
  15. package/docs/functions/components.render.html +1 -1
  16. package/docs/functions/hooks.forwardRef.html +1 -1
  17. package/docs/functions/hooks.useImperativeHandle.html +1 -1
  18. package/docs/functions/misc.toBool.html +3 -0
  19. package/docs/functions/redux.combineReducers.html +12 -0
  20. package/docs/functions/redux.connect.html +1 -1
  21. package/docs/functions/timers.animationFramePromise.html +1 -1
  22. package/docs/functions/timers.clearInterval.html +1 -1
  23. package/docs/functions/timers.clearTimeout.html +1 -1
  24. package/docs/functions/timers.grabTimers.html +1 -1
  25. package/docs/functions/timers.pauseTimers.html +1 -1
  26. package/docs/functions/timers.releaseTimers.html +1 -1
  27. package/docs/functions/timers.resetTimers.html +1 -1
  28. package/docs/functions/timers.resumeTimers.html +1 -1
  29. package/docs/functions/timers.setInterval.html +1 -1
  30. package/docs/functions/timers.setTimeout.html +1 -1
  31. package/docs/functions/timers.timeoutPromise.html +1 -1
  32. package/docs/index.html +2 -2
  33. package/docs/modules/misc.html +1 -1
  34. package/docs/modules/redux.html +1 -1
  35. package/docs/static/demos/form-elements.jsx +110 -0
  36. package/docs/static/index.html +2 -1
  37. package/docs/static/lilact.development.min.js +1 -1
  38. package/docs/static/lilact.production.min.js +1 -1
  39. package/package.json +2 -2
  40. package/root/demos/form-elements.jsx +110 -0
  41. package/root/index.html +2 -1
  42. package/root/lilact.development.min.js +1 -1
  43. package/root/lilact.production.min.js +1 -1
  44. package/src/components.jsx +27 -10
  45. package/src/hooks.jsx +1 -2
  46. package/src/jsx.js +5 -1
  47. package/src/lilact.jsx +3 -7
  48. package/src/misc.jsx +42 -14
  49. package/src/redux.jsx +60 -55
  50. package/src/timers.jsx +7 -2
  51. package/webpack.config.js +1 -1
package/src/misc.jsx CHANGED
@@ -10,10 +10,10 @@
10
10
  modification, are permitted provided that the following conditions are met:
11
11
 
12
12
  * Redistributions of source code must retain the above copyright
13
- notice, this list of conditions and the following disclaimer.
13
+ notice, this list of conditions and the following disclaimer.
14
14
  * Redistributions in binary form must reproduce the above copyright
15
- notice, this list of conditions and the following disclaimer in the
16
- documentation and/or other materials provided with the distribution.
15
+ notice, this list of conditions and the following disclaimer in the
16
+ documentation and/or other materials provided with the distribution.
17
17
 
18
18
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
19
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -38,10 +38,10 @@ const typeOf = (input) => {
38
38
  // used for object comparison functions
39
39
  // https://monsterlessons-academy.com/posts/shallow-comparison-vs-deep-comparison-in-javascript
40
40
 
41
- const rawObject = Object.prototype.toString.call(input).toLowerCase();
42
- const typeOfRegex = /\[object (.*)]/g;
43
- const type = typeOfRegex.exec(rawObject)[1];
44
- return type;
41
+ const rawObject = Object.prototype.toString.call(input).toLowerCase();
42
+ const typeOfRegex = /\[object (.*)]/g;
43
+ const type = typeOfRegex.exec(rawObject)[1];
44
+ return type;
45
45
  };
46
46
 
47
47
 
@@ -347,7 +347,7 @@ export function isClass(func) {
347
347
  * @returns True if the value is an async function; otherwise false.
348
348
  */
349
349
  export function isAsync(fn) {
350
- return typeof fn === 'function' && fn.constructor && fn.constructor.name === 'AsyncFunction';
350
+ return typeof fn === 'function' && fn.constructor && fn.constructor.name === 'AsyncFunction';
351
351
  }
352
352
 
353
353
  /**
@@ -370,7 +370,25 @@ export function isError(x) {
370
370
  return x instanceof Error || Object.prototype.toString.call(x) === '[object Error]';
371
371
  }
372
372
 
373
+ /**
374
+ * Converts the input to a boolean value
375
+ *
376
+ * @param value - Value to inspect.
377
+ * @returns boolean value
378
+ */
379
+ export function toBool(x) {
380
+ if (typeof x === "boolean") return x;
381
+
382
+ if (typeof x === "number") return x !== 0;
383
+
384
+ if (typeof x === "string") {
385
+ x = x.trim().toLowerCase();
386
+ if (x === "true") return true;
387
+ if (x === "false") return false;
388
+ }
373
389
 
390
+ return Boolean(x);
391
+ }
374
392
 
375
393
 
376
394
  // Internals
@@ -395,13 +413,18 @@ export let update_cbs = new Set;
395
413
  /** @ignore */
396
414
  export let roots = new Set;
397
415
  /** @ignore */
398
- export let special_attributes = new Set(["classname", "classname", "ref", "action", "lilact_jsx_loc", "children", "key"]);
399
- /** @ignore */
400
416
  export let err = null; // this is only to ease debuggin,
401
417
  /** @ignore */
402
418
  export let layout_effects = new Set;
419
+
403
420
  /** @ignore */
404
- export let events_set = new Set([
421
+ export const special_attributes = new Set([
422
+ "classname", "classname", "ref", "action", "lilact_jsx_loc", "children", "key",
423
+ "defaultvalue", "defaultchecked"
424
+ ]);
425
+
426
+ /** @ignore */
427
+ export const events_set = new Set([
405
428
  "onafterprint","onbeforeprint","onbeforeunload","onerror","onhashchange","onload","onmessage",
406
429
  "onoffline","ononline","onpagehide","onpageshow","onpopstate","onresize","onstorage","onunload",
407
430
  "onblur","onchange","oncontextmenu","onfocus","oninput","oninvalid","onreset","onsearch","onselect",
@@ -418,14 +441,19 @@ export let events_set = new Set([
418
441
 
419
442
  "onpointerdown", "onpointerup", "onpointermove", "onpointercancel", "onpointerover", "onpointerout",
420
443
  "onpointerenter", "onpointerleave"
421
- ])
444
+ ]);
445
+
422
446
  /** @ignore */
423
- export let length_css_attributes_set = new Set([
447
+ export const length_css_attributes_set = new Set([
424
448
  "width","height","minWidth","minHeight","maxWidth","maxHeight","top","right","bottom","left","margin",
425
449
  "marginTop","marginRight","marginBottom","marginLeft","padding","paddingTop","paddingRight","paddingBottom",
426
450
  "paddingLeft","borderWidth","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth",
427
451
  "outlineWidth","fontSize","lineHeight","letterSpacing","wordSpacing","textIndent","borderRadius",
428
452
  "borderTopLeftRadius","borderTopRightRadius","borderBottomLeftRadius","borderBottomRightRadius",
429
453
  "columnGap","rowGap","gap"
430
- ])
454
+ ]);
431
455
 
456
+ /** @ignore */
457
+ export const boolean_html_attributes_set = new
458
+ Set(["disabled", "readOnly", "required", "checked", "multiple",
459
+ "hidden","open","loop","muted","controls","playsInline","allowFullScreen"]);
package/src/redux.jsx CHANGED
@@ -81,68 +81,35 @@ export function useDispatch()
81
81
  * @param [equalityFn=(a, b) => a === b] - Determines when the selected value should update.
82
82
  * @returns The selected slice of state.
83
83
  */
84
- export function useSelector(selector, equalityFn = (a, b) => a === b)
85
- {
86
- const store = Lilact.useStore();
87
- const latestSelectedRef = Lilact.useRef();
88
- const latestSelectorRef = Lilact.useRef();
89
- const [, forceRender] = Lilact.useState(0);
90
-
91
- if (!latestSelectorRef.current) {
92
- latestSelectorRef.current = selector;
93
- }
94
- latestSelectorRef.current = selector;
95
-
96
- let selected = selector(store.getState()); // todo: should exception be covered?
84
+ export function useSelector(selector, equalityFn = (a, b) => a === b) {
85
+ const store = Lilact.useStore();
86
+ const latestSelected = Lilact.useRef();
87
+ const selectorRef = Lilact.useRef(selector);
88
+ selectorRef.current = selector;
97
89
 
98
- if (latestSelectedRef.current === undefined) {
99
- latestSelectedRef.current = selected;
100
- }
101
-
102
- Lilact.useLayoutEffect(() => {
103
- // keep latestSelectedRef in sync after render (in case selector used props or similar)
104
- latestSelectedRef.current = selected;
105
- }, [selected]);
90
+ const [selected, setSelected] = Lilact.useState(() => selector(store.getState()));
106
91
 
107
- Lilact.useEffect(() => {
92
+ // Keep ref in sync for the subscription callback
93
+ latestSelected.current = selected;
108
94
 
109
- let didUnsubscribe = false;
95
+ Lilact.useEffect(() => {
96
+ function checkForUpdates() {
97
+ const nextSelected = selectorRef.current(store.getState());
98
+ if (!equalityFn(latestSelected.current, nextSelected)) {
99
+ latestSelected.current = nextSelected;
100
+ setSelected(nextSelected);
101
+ }
102
+ }
110
103
 
111
- function checkForUpdates() {
112
- if (didUnsubscribe) return;
113
- try {
114
- const newSelected = latestSelectorRef.current(store.getState());
115
- const oldSelected = latestSelectedRef.current;
116
- if (!equalityFn(oldSelected, newSelected)) {
117
- latestSelectedRef.current = newSelected;
104
+ const unsubscribe = store.subscribe(checkForUpdates);
118
105
 
119
- forceRender((n) => n + 1);
120
- }
121
- } catch (err) {
106
+ // In case state changed between render and effect
107
+ checkForUpdates();
122
108
 
123
- ʔ if(DEBUG) {
124
- // todo: which is better? cover the error or throw?
109
+ return unsubscribe;
110
+ }, [store, equalityFn]);
125
111
 
126
- // If selector throws during subscription notifications, re-render to surface error
127
- // (could instead log or ignore)
128
- // throw err;
129
- console.warn(err);
130
- ʔ }
131
- }
132
- }
133
-
134
- const unsubscribe = store.subscribe(checkForUpdates);
135
-
136
- // run check once in case state changed between render and effect
137
- checkForUpdates();
138
-
139
- return () => {
140
- didUnsubscribe = true;
141
- unsubscribe();
142
- };
143
- }, [store, equalityFn]);
144
-
145
- return latestSelectedRef.current;
112
+ return selected;
146
113
  }
147
114
 
148
115
 
@@ -196,3 +163,41 @@ export function connect(mapStateToProps, mapDispatchToProps)
196
163
  };
197
164
  }
198
165
 
166
+ /**
167
+ * Creates a root reducer by mapping keys to slice reducers.
168
+ *
169
+ * Each slice reducer is called with:
170
+ * - the previous slice state at `state[key]` (or `undefined` initially)
171
+ * - the dispatched action
172
+ *
173
+ * The returned reducer builds the next state object using all reducer keys.
174
+ * If none of the slice reducers produce a change (reference equality),
175
+ * the previous `state` object is returned to avoid unnecessary updates.
176
+ *
177
+ * @param {object} reducers - An object whose values are reducers.
178
+ * @returns {function} A root reducer function compatible with your createStore.
179
+ */
180
+ export function combineReducers(reducers) {
181
+ const reducerKeys = Object.keys(reducers);
182
+
183
+ for (const key of reducerKeys) {
184
+ if (typeof reducers[key] !== "function") {
185
+ throw new Error(`combineReducers: reducer for key "${key}" is not a function`);
186
+ }
187
+ }
188
+
189
+ return function rootReducer(state = {}, action) {
190
+ let hasChanged = false;
191
+ const nextState = {};
192
+
193
+ for (const key of reducerKeys) {
194
+ const reducer = reducers[key];
195
+ const prevSlice = state[key];
196
+ const nextSlice = reducer(prevSlice, action);
197
+ nextState[key] = nextSlice;
198
+ hasChanged = hasChanged || nextSlice !== prevSlice;
199
+ }
200
+
201
+ return hasChanged ? nextState : state;
202
+ };
203
+ }
package/src/timers.jsx CHANGED
@@ -38,11 +38,16 @@
38
38
  /**
39
39
  * Timer helpers for a promise-friendly timer framework.
40
40
  *
41
- * These functions keep the same call signatures as the standard JavaScript timer APIs where applicable (`setTimeout`/`setInterval`/`clearTimeout`/`clearInterval`), but add extra capabilities for promise-friendly control and lifecycle management. This module can “grab” timers and later pause/resume/reset/release them, plus provide promise wrappers like `timeoutPromise` and `animationFramePromise`.
41
+ * These functions keep the same call signatures as the standard JavaScript timer APIs where applicable
42
+ * (`setTimeout`/`setInterval`/`clearTimeout`/`clearInterval`),
43
+ * but add extra capabilities for promise-friendly control and lifecycle management.
44
+ *
45
+ * This module can “grab” timers and later pause/resume/reset/release them, plus provide promise wrappers
46
+ * like `timeoutPromise` and `animationFramePromise`.
42
47
  *
43
48
  * - `setTimeout` / `setInterval`: schedule callbacks (same interface as the built-ins).
44
49
  * - `clearTimeout` / `clearInterval`: cancel scheduled timers (same interface as the built-ins).
45
- * - `grabTimers` / `pauseTimers` / `resumeTimers` / `resetTimers` / `releaseTimers`: manage tracked timers (implementation-dependent behavior).
50
+ * - `grabTimers` / `pauseTimers` / `resumeTimers` / `resetTimers` / `releaseTimers`: manage tracked timers.
46
51
  * - `timeoutPromise` / `animationFramePromise`: promise-based convenience wrappers.
47
52
  */
48
53
 
package/webpack.config.js CHANGED
@@ -56,7 +56,7 @@ export default (env, argv) => {
56
56
  optimization: {
57
57
  concatenateModules: true, // scope hoisting
58
58
  moduleIds: 'deterministic', // smaller stable ids (or 'hashed')
59
- minimize: true, //mode === 'production',
59
+ minimize: true //mode === 'production',
60
60
  },
61
61
  experiments: {
62
62
  outputModule: true // enable module output