@bquery/bquery 1.3.0 → 1.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 (71) hide show
  1. package/README.md +527 -501
  2. package/dist/{batch-4LAvfLE7.js → batch-x7b2eZST.js} +2 -2
  3. package/dist/{batch-4LAvfLE7.js.map → batch-x7b2eZST.js.map} +1 -1
  4. package/dist/component.es.mjs +1 -1
  5. package/dist/core/collection.d.ts +19 -3
  6. package/dist/core/collection.d.ts.map +1 -1
  7. package/dist/core/element.d.ts +23 -4
  8. package/dist/core/element.d.ts.map +1 -1
  9. package/dist/core/index.d.ts +1 -0
  10. package/dist/core/index.d.ts.map +1 -1
  11. package/dist/core/utils/function.d.ts +21 -4
  12. package/dist/core/utils/function.d.ts.map +1 -1
  13. package/dist/{core-COenAZjD.js → core-BhpuvPhy.js} +62 -37
  14. package/dist/core-BhpuvPhy.js.map +1 -0
  15. package/dist/core.es.mjs +174 -131
  16. package/dist/core.es.mjs.map +1 -1
  17. package/dist/full.es.mjs +7 -7
  18. package/dist/full.iife.js +2 -2
  19. package/dist/full.iife.js.map +1 -1
  20. package/dist/full.umd.js +2 -2
  21. package/dist/full.umd.js.map +1 -1
  22. package/dist/index.es.mjs +7 -7
  23. package/dist/motion.es.mjs.map +1 -1
  24. package/dist/{persisted-Dz_ryNuC.js → persisted-DHoi3uEs.js} +4 -4
  25. package/dist/{persisted-Dz_ryNuC.js.map → persisted-DHoi3uEs.js.map} +1 -1
  26. package/dist/platform/storage.d.ts.map +1 -1
  27. package/dist/platform.es.mjs +12 -7
  28. package/dist/platform.es.mjs.map +1 -1
  29. package/dist/reactive/core.d.ts +12 -0
  30. package/dist/reactive/core.d.ts.map +1 -1
  31. package/dist/reactive/effect.d.ts.map +1 -1
  32. package/dist/reactive/internals.d.ts +6 -0
  33. package/dist/reactive/internals.d.ts.map +1 -1
  34. package/dist/reactive.es.mjs +6 -6
  35. package/dist/router.es.mjs +1 -1
  36. package/dist/{sanitize-1FBEPAFH.js → sanitize-Cxvxa-DX.js} +50 -39
  37. package/dist/sanitize-Cxvxa-DX.js.map +1 -0
  38. package/dist/security/sanitize-core.d.ts.map +1 -1
  39. package/dist/security.es.mjs +2 -2
  40. package/dist/store.es.mjs +2 -2
  41. package/dist/type-guards-BdKlYYlS.js +32 -0
  42. package/dist/type-guards-BdKlYYlS.js.map +1 -0
  43. package/dist/untrack-DNnnqdlR.js +6 -0
  44. package/dist/{untrack-BuEQKH7_.js.map → untrack-DNnnqdlR.js.map} +1 -1
  45. package/dist/view/evaluate.d.ts.map +1 -1
  46. package/dist/view.es.mjs +157 -151
  47. package/dist/view.es.mjs.map +1 -1
  48. package/dist/{watch-CXyaBC_9.js → watch-DXXv3iAI.js} +3 -3
  49. package/dist/{watch-CXyaBC_9.js.map → watch-DXXv3iAI.js.map} +1 -1
  50. package/package.json +132 -132
  51. package/src/core/collection.ts +628 -588
  52. package/src/core/element.ts +774 -746
  53. package/src/core/index.ts +48 -47
  54. package/src/core/utils/function.ts +151 -110
  55. package/src/motion/animate.ts +113 -113
  56. package/src/motion/flip.ts +176 -176
  57. package/src/motion/scroll.ts +57 -57
  58. package/src/motion/spring.ts +150 -150
  59. package/src/motion/timeline.ts +246 -246
  60. package/src/motion/transition.ts +51 -51
  61. package/src/platform/storage.ts +215 -208
  62. package/src/reactive/core.ts +114 -93
  63. package/src/reactive/effect.ts +54 -43
  64. package/src/reactive/internals.ts +122 -105
  65. package/src/security/sanitize-core.ts +364 -343
  66. package/src/view/evaluate.ts +290 -274
  67. package/dist/core-COenAZjD.js.map +0 -1
  68. package/dist/sanitize-1FBEPAFH.js.map +0 -1
  69. package/dist/type-guards-DRma3-Kc.js +0 -16
  70. package/dist/type-guards-DRma3-Kc.js.map +0 -1
  71. package/dist/untrack-BuEQKH7_.js +0 -6
package/src/core/index.ts CHANGED
@@ -1,47 +1,48 @@
1
- export { BQueryCollection } from './collection';
2
- export { BQueryElement } from './element';
3
- export { $, $$ } from './selector';
4
- // Re-export the utils namespace for backward compatibility
5
- export { utils } from './utils';
6
- // Export individual utilities (except internal helpers)
7
- export {
8
- chunk,
9
- compact,
10
- ensureArray,
11
- flatten,
12
- unique,
13
- debounce,
14
- noop,
15
- once,
16
- throttle,
17
- isEmpty,
18
- parseJson,
19
- sleep,
20
- uid,
21
- clamp,
22
- inRange,
23
- randomInt,
24
- toNumber,
25
- clone,
26
- hasOwn,
27
- isPlainObject,
28
- merge,
29
- omit,
30
- pick,
31
- capitalize,
32
- escapeRegExp,
33
- slugify,
34
- toCamelCase,
35
- toKebabCase,
36
- truncate,
37
- isArray,
38
- isBoolean,
39
- isCollection,
40
- isDate,
41
- isElement,
42
- isFunction,
43
- isNumber,
44
- isObject,
45
- isPromise,
46
- isString,
47
- } from './utils';
1
+ export { BQueryCollection } from './collection';
2
+ export { BQueryElement } from './element';
3
+ export { $, $$ } from './selector';
4
+ // Re-export the utils namespace for backward compatibility
5
+ export { utils } from './utils';
6
+ // Export individual utilities (except internal helpers)
7
+ export {
8
+ chunk,
9
+ compact,
10
+ ensureArray,
11
+ flatten,
12
+ unique,
13
+ debounce,
14
+ noop,
15
+ once,
16
+ throttle,
17
+ isEmpty,
18
+ parseJson,
19
+ sleep,
20
+ uid,
21
+ clamp,
22
+ inRange,
23
+ randomInt,
24
+ toNumber,
25
+ clone,
26
+ hasOwn,
27
+ isPlainObject,
28
+ merge,
29
+ omit,
30
+ pick,
31
+ capitalize,
32
+ escapeRegExp,
33
+ slugify,
34
+ toCamelCase,
35
+ toKebabCase,
36
+ truncate,
37
+ isArray,
38
+ isBoolean,
39
+ isCollection,
40
+ isDate,
41
+ isElement,
42
+ isFunction,
43
+ isNumber,
44
+ isObject,
45
+ isPromise,
46
+ isString,
47
+ } from './utils';
48
+ export type { DebouncedFn, ThrottledFn } from './utils';
@@ -1,110 +1,151 @@
1
- /**
2
- * Function-focused utility helpers.
3
- *
4
- * @module bquery/core/utils/function
5
- */
6
-
7
- /**
8
- * Creates a debounced function that delays execution until after
9
- * the specified delay has elapsed since the last call.
10
- *
11
- * @template TArgs - The argument types of the function
12
- * @param fn - The function to debounce
13
- * @param delayMs - Delay in milliseconds
14
- * @returns A debounced version of the function
15
- *
16
- * @example
17
- * ```ts
18
- * const search = debounce((query: string) => {
19
- * console.log('Searching:', query);
20
- * }, 300);
21
- *
22
- * search('h');
23
- * search('he');
24
- * search('hello'); // Only this call executes after 300ms
25
- * ```
26
- */
27
- export function debounce<TArgs extends unknown[]>(
28
- fn: (...args: TArgs) => void,
29
- delayMs: number
30
- ): (...args: TArgs) => void {
31
- let timeoutId: ReturnType<typeof setTimeout> | undefined;
32
- return (...args: TArgs) => {
33
- if (timeoutId) {
34
- clearTimeout(timeoutId);
35
- }
36
- timeoutId = setTimeout(() => fn(...args), delayMs);
37
- };
38
- }
39
-
40
- /**
41
- * Creates a throttled function that runs at most once per interval.
42
- *
43
- * @template TArgs - The argument types of the function
44
- * @param fn - The function to throttle
45
- * @param intervalMs - Minimum interval between calls in milliseconds
46
- * @returns A throttled version of the function
47
- *
48
- * @example
49
- * ```ts
50
- * const handleScroll = throttle(() => {
51
- * console.log('Scroll position:', window.scrollY);
52
- * }, 100);
53
- *
54
- * window.addEventListener('scroll', handleScroll);
55
- * ```
56
- */
57
- export function throttle<TArgs extends unknown[]>(
58
- fn: (...args: TArgs) => void,
59
- intervalMs: number
60
- ): (...args: TArgs) => void {
61
- let lastRun = 0;
62
- return (...args: TArgs) => {
63
- const now = Date.now();
64
- if (now - lastRun >= intervalMs) {
65
- lastRun = now;
66
- fn(...args);
67
- }
68
- };
69
- }
70
-
71
- /**
72
- * Ensures a function only runs once. Subsequent calls return the first result.
73
- *
74
- * @template TArgs - The argument types of the function
75
- * @template TResult - The return type of the function
76
- * @param fn - The function to wrap
77
- * @returns A function that only runs once
78
- *
79
- * @example
80
- * ```ts
81
- * const init = once(() => ({ ready: true }));
82
- * init();
83
- * init(); // only runs once
84
- * ```
85
- */
86
- export function once<TArgs extends unknown[], TResult>(
87
- fn: (...args: TArgs) => TResult
88
- ): (...args: TArgs) => TResult {
89
- let hasRun = false;
90
- let result!: TResult;
91
- return (...args: TArgs) => {
92
- if (!hasRun) {
93
- result = fn(...args);
94
- hasRun = true;
95
- }
96
- return result;
97
- };
98
- }
99
-
100
- /**
101
- * A no-operation function.
102
- *
103
- * @example
104
- * ```ts
105
- * noop();
106
- * ```
107
- */
108
- export function noop(): void {
109
- // Intentionally empty
110
- }
1
+ /**
2
+ * Function-focused utility helpers.
3
+ *
4
+ * @module bquery/core/utils/function
5
+ */
6
+
7
+ /** A debounced function with a cancel method to clear the pending timeout. */
8
+ export interface DebouncedFn<TArgs extends unknown[]> {
9
+ (...args: TArgs): void;
10
+ /** Cancels the pending debounced invocation. */
11
+ cancel(): void;
12
+ }
13
+
14
+ /** A throttled function with a cancel method to reset the throttle timer. */
15
+ export interface ThrottledFn<TArgs extends unknown[]> {
16
+ (...args: TArgs): void;
17
+ /** Resets the throttle timer, allowing the next call to execute immediately. */
18
+ cancel(): void;
19
+ }
20
+
21
+ /**
22
+ * Creates a debounced function that delays execution until after
23
+ * the specified delay has elapsed since the last call.
24
+ *
25
+ * @template TArgs - The argument types of the function
26
+ * @param fn - The function to debounce
27
+ * @param delayMs - Delay in milliseconds
28
+ * @returns A debounced version of the function with a `cancel()` method
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * const search = debounce((query: string) => {
33
+ * console.log('Searching:', query);
34
+ * }, 300);
35
+ *
36
+ * search('h');
37
+ * search('he');
38
+ * search('hello'); // Only this call executes after 300ms
39
+ *
40
+ * search('cancel me');
41
+ * search.cancel(); // Cancels the pending invocation
42
+ * ```
43
+ */
44
+ export function debounce<TArgs extends unknown[]>(
45
+ fn: (...args: TArgs) => void,
46
+ delayMs: number
47
+ ): DebouncedFn<TArgs> {
48
+ let timeoutId: ReturnType<typeof setTimeout> | undefined;
49
+ const debounced: DebouncedFn<TArgs> = Object.assign(
50
+ (...args: TArgs) => {
51
+ if (timeoutId !== undefined) {
52
+ clearTimeout(timeoutId);
53
+ }
54
+ timeoutId = setTimeout(() => {
55
+ timeoutId = undefined;
56
+ fn(...args);
57
+ }, delayMs);
58
+ },
59
+ {
60
+ cancel: () => {
61
+ if (timeoutId !== undefined) {
62
+ clearTimeout(timeoutId);
63
+ timeoutId = undefined;
64
+ }
65
+ },
66
+ }
67
+ );
68
+ return debounced;
69
+ }
70
+
71
+ /**
72
+ * Creates a throttled function that runs at most once per interval.
73
+ *
74
+ * @template TArgs - The argument types of the function
75
+ * @param fn - The function to throttle
76
+ * @param intervalMs - Minimum interval between calls in milliseconds
77
+ * @returns A throttled version of the function with a `cancel()` method
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * const handleScroll = throttle(() => {
82
+ * console.log('Scroll position:', window.scrollY);
83
+ * }, 100);
84
+ *
85
+ * window.addEventListener('scroll', handleScroll);
86
+ *
87
+ * handleScroll.cancel(); // Resets throttle, next call executes immediately
88
+ * ```
89
+ */
90
+ export function throttle<TArgs extends unknown[]>(
91
+ fn: (...args: TArgs) => void,
92
+ intervalMs: number
93
+ ): ThrottledFn<TArgs> {
94
+ let lastRun = 0;
95
+ const throttled: ThrottledFn<TArgs> = Object.assign(
96
+ (...args: TArgs) => {
97
+ const now = Date.now();
98
+ if (now - lastRun >= intervalMs) {
99
+ lastRun = now;
100
+ fn(...args);
101
+ }
102
+ },
103
+ {
104
+ cancel: () => {
105
+ lastRun = 0;
106
+ },
107
+ }
108
+ );
109
+ return throttled;
110
+ }
111
+
112
+ /**
113
+ * Ensures a function only runs once. Subsequent calls return the first result.
114
+ *
115
+ * @template TArgs - The argument types of the function
116
+ * @template TResult - The return type of the function
117
+ * @param fn - The function to wrap
118
+ * @returns A function that only runs once
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * const init = once(() => ({ ready: true }));
123
+ * init();
124
+ * init(); // only runs once
125
+ * ```
126
+ */
127
+ export function once<TArgs extends unknown[], TResult>(
128
+ fn: (...args: TArgs) => TResult
129
+ ): (...args: TArgs) => TResult {
130
+ let hasRun = false;
131
+ let result!: TResult;
132
+ return (...args: TArgs) => {
133
+ if (!hasRun) {
134
+ result = fn(...args);
135
+ hasRun = true;
136
+ }
137
+ return result;
138
+ };
139
+ }
140
+
141
+ /**
142
+ * A no-operation function.
143
+ *
144
+ * @example
145
+ * ```ts
146
+ * noop();
147
+ * ```
148
+ */
149
+ export function noop(): void {
150
+ // Intentionally empty
151
+ }
@@ -1,113 +1,113 @@
1
- /**
2
- * Web Animations helpers.
3
- *
4
- * @module bquery/motion
5
- */
6
-
7
- import { prefersReducedMotion } from './reduced-motion';
8
- import type { AnimateOptions } from './types';
9
-
10
- /** @internal */
11
- const isStyleValue = (value: unknown): value is string | number =>
12
- typeof value === 'string' || typeof value === 'number';
13
-
14
- /**
15
- * Convert camelCase property names to kebab-case for CSS.
16
- * @internal
17
- */
18
- const toKebabCase = (str: string): string => {
19
- return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
20
- };
21
-
22
- /** @internal */
23
- export const applyFinalKeyframeStyles = (
24
- element: Element,
25
- keyframes: Keyframe[] | PropertyIndexedKeyframes
26
- ): void => {
27
- const htmlElement = element as HTMLElement;
28
- const style = htmlElement.style;
29
-
30
- if (Array.isArray(keyframes)) {
31
- const last = keyframes[keyframes.length - 1];
32
- if (!last) return;
33
- for (const [prop, value] of Object.entries(last)) {
34
- if (prop === 'offset' || prop === 'easing' || prop === 'composite') continue;
35
- if (isStyleValue(value)) {
36
- // Convert camelCase to kebab-case for CSS properties
37
- const cssProp = prop.startsWith('--') ? prop : toKebabCase(prop);
38
- style.setProperty(cssProp, String(value));
39
- }
40
- }
41
- return;
42
- }
43
-
44
- for (const [prop, value] of Object.entries(keyframes)) {
45
- if (prop === 'offset' || prop === 'easing' || prop === 'composite') continue;
46
- const finalValue = Array.isArray(value) ? value[value.length - 1] : value;
47
- if (isStyleValue(finalValue)) {
48
- // Convert camelCase to kebab-case for CSS properties
49
- const cssProp = prop.startsWith('--') ? prop : toKebabCase(prop);
50
- style.setProperty(cssProp, String(finalValue));
51
- }
52
- }
53
- };
54
-
55
- /**
56
- * Animate an element using the Web Animations API with reduced-motion fallback.
57
- *
58
- * @param element - Element to animate
59
- * @param config - Animation configuration
60
- * @returns Promise that resolves when animation completes
61
- *
62
- * @example
63
- * ```ts
64
- * await animate(element, {
65
- * keyframes: [{ opacity: 0 }, { opacity: 1 }],
66
- * options: { duration: 200, easing: 'ease-out' },
67
- * });
68
- * ```
69
- */
70
- export const animate = (element: Element, config: AnimateOptions): Promise<void> => {
71
- const { keyframes, options, commitStyles = true, respectReducedMotion = true, onFinish } = config;
72
-
73
- if (respectReducedMotion && prefersReducedMotion()) {
74
- if (commitStyles) {
75
- applyFinalKeyframeStyles(element, keyframes);
76
- }
77
- onFinish?.();
78
- return Promise.resolve();
79
- }
80
-
81
- const htmlElement = element as HTMLElement;
82
- if (typeof htmlElement.animate !== 'function') {
83
- if (commitStyles) {
84
- applyFinalKeyframeStyles(element, keyframes);
85
- }
86
- onFinish?.();
87
- return Promise.resolve();
88
- }
89
-
90
- return new Promise((resolve) => {
91
- const animation = htmlElement.animate(keyframes, options);
92
- let finalized = false;
93
- const finalize = () => {
94
- if (finalized) return;
95
- finalized = true;
96
- if (commitStyles) {
97
- if (typeof animation.commitStyles === 'function') {
98
- animation.commitStyles();
99
- } else {
100
- applyFinalKeyframeStyles(element, keyframes);
101
- }
102
- }
103
- animation.cancel();
104
- onFinish?.();
105
- resolve();
106
- };
107
-
108
- animation.onfinish = finalize;
109
- if (animation.finished) {
110
- animation.finished.then(finalize).catch(finalize);
111
- }
112
- });
113
- };
1
+ /**
2
+ * Web Animations helpers.
3
+ *
4
+ * @module bquery/motion
5
+ */
6
+
7
+ import { prefersReducedMotion } from './reduced-motion';
8
+ import type { AnimateOptions } from './types';
9
+
10
+ /** @internal */
11
+ const isStyleValue = (value: unknown): value is string | number =>
12
+ typeof value === 'string' || typeof value === 'number';
13
+
14
+ /**
15
+ * Convert camelCase property names to kebab-case for CSS.
16
+ * @internal
17
+ */
18
+ const toKebabCase = (str: string): string => {
19
+ return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
20
+ };
21
+
22
+ /** @internal */
23
+ export const applyFinalKeyframeStyles = (
24
+ element: Element,
25
+ keyframes: Keyframe[] | PropertyIndexedKeyframes
26
+ ): void => {
27
+ const htmlElement = element as HTMLElement;
28
+ const style = htmlElement.style;
29
+
30
+ if (Array.isArray(keyframes)) {
31
+ const last = keyframes[keyframes.length - 1];
32
+ if (!last) return;
33
+ for (const [prop, value] of Object.entries(last)) {
34
+ if (prop === 'offset' || prop === 'easing' || prop === 'composite') continue;
35
+ if (isStyleValue(value)) {
36
+ // Convert camelCase to kebab-case for CSS properties
37
+ const cssProp = prop.startsWith('--') ? prop : toKebabCase(prop);
38
+ style.setProperty(cssProp, String(value));
39
+ }
40
+ }
41
+ return;
42
+ }
43
+
44
+ for (const [prop, value] of Object.entries(keyframes)) {
45
+ if (prop === 'offset' || prop === 'easing' || prop === 'composite') continue;
46
+ const finalValue = Array.isArray(value) ? value[value.length - 1] : value;
47
+ if (isStyleValue(finalValue)) {
48
+ // Convert camelCase to kebab-case for CSS properties
49
+ const cssProp = prop.startsWith('--') ? prop : toKebabCase(prop);
50
+ style.setProperty(cssProp, String(finalValue));
51
+ }
52
+ }
53
+ };
54
+
55
+ /**
56
+ * Animate an element using the Web Animations API with reduced-motion fallback.
57
+ *
58
+ * @param element - Element to animate
59
+ * @param config - Animation configuration
60
+ * @returns Promise that resolves when animation completes
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * await animate(element, {
65
+ * keyframes: [{ opacity: 0 }, { opacity: 1 }],
66
+ * options: { duration: 200, easing: 'ease-out' },
67
+ * });
68
+ * ```
69
+ */
70
+ export const animate = (element: Element, config: AnimateOptions): Promise<void> => {
71
+ const { keyframes, options, commitStyles = true, respectReducedMotion = true, onFinish } = config;
72
+
73
+ if (respectReducedMotion && prefersReducedMotion()) {
74
+ if (commitStyles) {
75
+ applyFinalKeyframeStyles(element, keyframes);
76
+ }
77
+ onFinish?.();
78
+ return Promise.resolve();
79
+ }
80
+
81
+ const htmlElement = element as HTMLElement;
82
+ if (typeof htmlElement.animate !== 'function') {
83
+ if (commitStyles) {
84
+ applyFinalKeyframeStyles(element, keyframes);
85
+ }
86
+ onFinish?.();
87
+ return Promise.resolve();
88
+ }
89
+
90
+ return new Promise((resolve) => {
91
+ const animation = htmlElement.animate(keyframes, options);
92
+ let finalized = false;
93
+ const finalize = () => {
94
+ if (finalized) return;
95
+ finalized = true;
96
+ if (commitStyles) {
97
+ if (typeof animation.commitStyles === 'function') {
98
+ animation.commitStyles();
99
+ } else {
100
+ applyFinalKeyframeStyles(element, keyframes);
101
+ }
102
+ }
103
+ animation.cancel();
104
+ onFinish?.();
105
+ resolve();
106
+ };
107
+
108
+ animation.onfinish = finalize;
109
+ if (animation.finished) {
110
+ animation.finished.then(finalize).catch(finalize);
111
+ }
112
+ });
113
+ };