@bquery/bquery 1.2.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 (309) hide show
  1. package/README.md +127 -27
  2. package/dist/batch-x7b2eZST.js +13 -0
  3. package/dist/batch-x7b2eZST.js.map +1 -0
  4. package/dist/component/component.d.ts +69 -0
  5. package/dist/component/component.d.ts.map +1 -0
  6. package/dist/component/html.d.ts +35 -0
  7. package/dist/component/html.d.ts.map +1 -0
  8. package/dist/component/index.d.ts +3 -126
  9. package/dist/component/index.d.ts.map +1 -1
  10. package/dist/component/props.d.ts +18 -0
  11. package/dist/component/props.d.ts.map +1 -0
  12. package/dist/component/types.d.ts +77 -0
  13. package/dist/component/types.d.ts.map +1 -0
  14. package/dist/component.es.mjs +90 -59
  15. package/dist/component.es.mjs.map +1 -1
  16. package/dist/core/collection.d.ts +55 -3
  17. package/dist/core/collection.d.ts.map +1 -1
  18. package/dist/core/dom.d.ts +6 -0
  19. package/dist/core/dom.d.ts.map +1 -0
  20. package/dist/core/element.d.ts +31 -4
  21. package/dist/core/element.d.ts.map +1 -1
  22. package/dist/core/index.d.ts +2 -0
  23. package/dist/core/index.d.ts.map +1 -1
  24. package/dist/core/utils/array.d.ts +74 -0
  25. package/dist/core/utils/array.d.ts.map +1 -0
  26. package/dist/core/utils/function.d.ts +87 -0
  27. package/dist/core/utils/function.d.ts.map +1 -0
  28. package/dist/core/utils/index.d.ts +70 -0
  29. package/dist/core/utils/index.d.ts.map +1 -0
  30. package/dist/core/utils/misc.d.ts +63 -0
  31. package/dist/core/utils/misc.d.ts.map +1 -0
  32. package/dist/core/utils/number.d.ts +65 -0
  33. package/dist/core/utils/number.d.ts.map +1 -0
  34. package/dist/core/utils/object.d.ts +133 -0
  35. package/dist/core/utils/object.d.ts.map +1 -0
  36. package/dist/core/utils/string.d.ts +80 -0
  37. package/dist/core/utils/string.d.ts.map +1 -0
  38. package/dist/core/utils/type-guards.d.ts +79 -0
  39. package/dist/core/utils/type-guards.d.ts.map +1 -0
  40. package/dist/core-BhpuvPhy.js +170 -0
  41. package/dist/core-BhpuvPhy.js.map +1 -0
  42. package/dist/core.es.mjs +495 -489
  43. package/dist/core.es.mjs.map +1 -1
  44. package/dist/full.d.ts +2 -2
  45. package/dist/full.d.ts.map +1 -1
  46. package/dist/full.es.mjs +87 -64
  47. package/dist/full.es.mjs.map +1 -1
  48. package/dist/full.iife.js +2 -2
  49. package/dist/full.iife.js.map +1 -1
  50. package/dist/full.umd.js +2 -2
  51. package/dist/full.umd.js.map +1 -1
  52. package/dist/index.es.mjs +138 -68
  53. package/dist/index.es.mjs.map +1 -1
  54. package/dist/motion/animate.d.ts +25 -0
  55. package/dist/motion/animate.d.ts.map +1 -0
  56. package/dist/motion/easing.d.ts +30 -0
  57. package/dist/motion/easing.d.ts.map +1 -0
  58. package/dist/motion/flip.d.ts +55 -0
  59. package/dist/motion/flip.d.ts.map +1 -0
  60. package/dist/motion/index.d.ts +11 -138
  61. package/dist/motion/index.d.ts.map +1 -1
  62. package/dist/motion/keyframes.d.ts +21 -0
  63. package/dist/motion/keyframes.d.ts.map +1 -0
  64. package/dist/motion/reduced-motion.d.ts +12 -0
  65. package/dist/motion/reduced-motion.d.ts.map +1 -0
  66. package/dist/motion/scroll.d.ts +15 -0
  67. package/dist/motion/scroll.d.ts.map +1 -0
  68. package/dist/motion/spring.d.ts +42 -0
  69. package/dist/motion/spring.d.ts.map +1 -0
  70. package/dist/motion/stagger.d.ts +22 -0
  71. package/dist/motion/stagger.d.ts.map +1 -0
  72. package/dist/motion/timeline.d.ts +21 -0
  73. package/dist/motion/timeline.d.ts.map +1 -0
  74. package/dist/motion/transition.d.ts +22 -0
  75. package/dist/motion/transition.d.ts.map +1 -0
  76. package/dist/motion/types.d.ts +182 -0
  77. package/dist/motion/types.d.ts.map +1 -0
  78. package/dist/motion.es.mjs +320 -61
  79. package/dist/motion.es.mjs.map +1 -1
  80. package/dist/persisted-DHoi3uEs.js +278 -0
  81. package/dist/persisted-DHoi3uEs.js.map +1 -0
  82. package/dist/platform/storage.d.ts.map +1 -1
  83. package/dist/platform.es.mjs +12 -7
  84. package/dist/platform.es.mjs.map +1 -1
  85. package/dist/reactive/batch.d.ts +13 -0
  86. package/dist/reactive/batch.d.ts.map +1 -0
  87. package/dist/reactive/computed.d.ts +50 -0
  88. package/dist/reactive/computed.d.ts.map +1 -0
  89. package/dist/reactive/core.d.ts +72 -0
  90. package/dist/reactive/core.d.ts.map +1 -0
  91. package/dist/reactive/effect.d.ts +15 -0
  92. package/dist/reactive/effect.d.ts.map +1 -0
  93. package/dist/reactive/index.d.ts +2 -2
  94. package/dist/reactive/index.d.ts.map +1 -1
  95. package/dist/reactive/internals.d.ts +42 -0
  96. package/dist/reactive/internals.d.ts.map +1 -0
  97. package/dist/reactive/linked.d.ts +36 -0
  98. package/dist/reactive/linked.d.ts.map +1 -0
  99. package/dist/reactive/persisted.d.ts +14 -0
  100. package/dist/reactive/persisted.d.ts.map +1 -0
  101. package/dist/reactive/readonly.d.ts +26 -0
  102. package/dist/reactive/readonly.d.ts.map +1 -0
  103. package/dist/reactive/signal.d.ts +13 -312
  104. package/dist/reactive/signal.d.ts.map +1 -1
  105. package/dist/reactive/type-guards.d.ts +20 -0
  106. package/dist/reactive/type-guards.d.ts.map +1 -0
  107. package/dist/reactive/untrack.d.ts +29 -0
  108. package/dist/reactive/untrack.d.ts.map +1 -0
  109. package/dist/reactive/watch.d.ts +42 -0
  110. package/dist/reactive/watch.d.ts.map +1 -0
  111. package/dist/reactive.es.mjs +30 -163
  112. package/dist/reactive.es.mjs.map +1 -1
  113. package/dist/router/index.d.ts +6 -252
  114. package/dist/router/index.d.ts.map +1 -1
  115. package/dist/router/links.d.ts +44 -0
  116. package/dist/router/links.d.ts.map +1 -0
  117. package/dist/router/match.d.ts +20 -0
  118. package/dist/router/match.d.ts.map +1 -0
  119. package/dist/router/navigation.d.ts +45 -0
  120. package/dist/router/navigation.d.ts.map +1 -0
  121. package/dist/router/query.d.ts +16 -0
  122. package/dist/router/query.d.ts.map +1 -0
  123. package/dist/router/router.d.ts +34 -0
  124. package/dist/router/router.d.ts.map +1 -0
  125. package/dist/router/state.d.ts +27 -0
  126. package/dist/router/state.d.ts.map +1 -0
  127. package/dist/router/types.d.ts +88 -0
  128. package/dist/router/types.d.ts.map +1 -0
  129. package/dist/router/utils.d.ts +65 -0
  130. package/dist/router/utils.d.ts.map +1 -0
  131. package/dist/router.es.mjs +168 -132
  132. package/dist/router.es.mjs.map +1 -1
  133. package/dist/sanitize-Cxvxa-DX.js +283 -0
  134. package/dist/sanitize-Cxvxa-DX.js.map +1 -0
  135. package/dist/security/constants.d.ts +42 -0
  136. package/dist/security/constants.d.ts.map +1 -0
  137. package/dist/security/csp.d.ts +24 -0
  138. package/dist/security/csp.d.ts.map +1 -0
  139. package/dist/security/index.d.ts +4 -2
  140. package/dist/security/index.d.ts.map +1 -1
  141. package/dist/security/sanitize-core.d.ts +13 -0
  142. package/dist/security/sanitize-core.d.ts.map +1 -0
  143. package/dist/security/sanitize.d.ts +5 -57
  144. package/dist/security/sanitize.d.ts.map +1 -1
  145. package/dist/security/trusted-types.d.ts +25 -0
  146. package/dist/security/trusted-types.d.ts.map +1 -0
  147. package/dist/security/types.d.ts +36 -0
  148. package/dist/security/types.d.ts.map +1 -0
  149. package/dist/security.es.mjs +50 -277
  150. package/dist/security.es.mjs.map +1 -1
  151. package/dist/store/create-store.d.ts +15 -0
  152. package/dist/store/create-store.d.ts.map +1 -0
  153. package/dist/store/define-store.d.ts +28 -0
  154. package/dist/store/define-store.d.ts.map +1 -0
  155. package/dist/store/devtools.d.ts +22 -0
  156. package/dist/store/devtools.d.ts.map +1 -0
  157. package/dist/store/index.d.ts +10 -286
  158. package/dist/store/index.d.ts.map +1 -1
  159. package/dist/store/mapping.d.ts +28 -0
  160. package/dist/store/mapping.d.ts.map +1 -0
  161. package/dist/store/persisted.d.ts +13 -0
  162. package/dist/store/persisted.d.ts.map +1 -0
  163. package/dist/store/plugins.d.ts +13 -0
  164. package/dist/store/plugins.d.ts.map +1 -0
  165. package/dist/store/registry.d.ts +28 -0
  166. package/dist/store/registry.d.ts.map +1 -0
  167. package/dist/store/types.d.ts +71 -0
  168. package/dist/store/types.d.ts.map +1 -0
  169. package/dist/store/utils.d.ts +28 -0
  170. package/dist/store/utils.d.ts.map +1 -0
  171. package/dist/store/watch.d.ts +23 -0
  172. package/dist/store/watch.d.ts.map +1 -0
  173. package/dist/store.es.mjs +22 -224
  174. package/dist/store.es.mjs.map +1 -1
  175. package/dist/type-guards-BdKlYYlS.js +32 -0
  176. package/dist/type-guards-BdKlYYlS.js.map +1 -0
  177. package/dist/untrack-DNnnqdlR.js +6 -0
  178. package/dist/untrack-DNnnqdlR.js.map +1 -0
  179. package/dist/view/directives/bind.d.ts +7 -0
  180. package/dist/view/directives/bind.d.ts.map +1 -0
  181. package/dist/view/directives/class.d.ts +8 -0
  182. package/dist/view/directives/class.d.ts.map +1 -0
  183. package/dist/view/directives/for.d.ts +23 -0
  184. package/dist/view/directives/for.d.ts.map +1 -0
  185. package/dist/view/directives/html.d.ts +7 -0
  186. package/dist/view/directives/html.d.ts.map +1 -0
  187. package/dist/view/directives/if.d.ts +7 -0
  188. package/dist/view/directives/if.d.ts.map +1 -0
  189. package/dist/view/directives/index.d.ts +12 -0
  190. package/dist/view/directives/index.d.ts.map +1 -0
  191. package/dist/view/directives/model.d.ts +7 -0
  192. package/dist/view/directives/model.d.ts.map +1 -0
  193. package/dist/view/directives/on.d.ts +7 -0
  194. package/dist/view/directives/on.d.ts.map +1 -0
  195. package/dist/view/directives/ref.d.ts +7 -0
  196. package/dist/view/directives/ref.d.ts.map +1 -0
  197. package/dist/view/directives/show.d.ts +7 -0
  198. package/dist/view/directives/show.d.ts.map +1 -0
  199. package/dist/view/directives/style.d.ts +7 -0
  200. package/dist/view/directives/style.d.ts.map +1 -0
  201. package/dist/view/directives/text.d.ts +7 -0
  202. package/dist/view/directives/text.d.ts.map +1 -0
  203. package/dist/view/evaluate.d.ts +43 -0
  204. package/dist/view/evaluate.d.ts.map +1 -0
  205. package/dist/view/index.d.ts +3 -93
  206. package/dist/view/index.d.ts.map +1 -1
  207. package/dist/view/mount.d.ts +69 -0
  208. package/dist/view/mount.d.ts.map +1 -0
  209. package/dist/view/process.d.ts +26 -0
  210. package/dist/view/process.d.ts.map +1 -0
  211. package/dist/view/types.d.ts +36 -0
  212. package/dist/view/types.d.ts.map +1 -0
  213. package/dist/view.es.mjs +358 -251
  214. package/dist/view.es.mjs.map +1 -1
  215. package/dist/watch-DXXv3iAI.js +58 -0
  216. package/dist/watch-DXXv3iAI.js.map +1 -0
  217. package/package.json +14 -14
  218. package/src/component/component.ts +289 -0
  219. package/src/component/html.ts +53 -0
  220. package/src/component/index.ts +40 -414
  221. package/src/component/props.ts +116 -0
  222. package/src/component/types.ts +85 -0
  223. package/src/core/collection.ts +181 -7
  224. package/src/core/dom.ts +38 -0
  225. package/src/core/element.ts +59 -25
  226. package/src/core/index.ts +48 -4
  227. package/src/core/utils/array.ts +102 -0
  228. package/src/core/utils/function.ts +151 -0
  229. package/src/core/utils/index.ts +83 -0
  230. package/src/core/utils/misc.ts +82 -0
  231. package/src/core/utils/number.ts +78 -0
  232. package/src/core/utils/object.ts +206 -0
  233. package/src/core/utils/string.ts +112 -0
  234. package/src/core/utils/type-guards.ts +112 -0
  235. package/src/full.ts +187 -150
  236. package/src/index.ts +36 -36
  237. package/src/motion/animate.ts +113 -0
  238. package/src/motion/easing.ts +40 -0
  239. package/src/motion/flip.ts +176 -0
  240. package/src/motion/index.ts +41 -358
  241. package/src/motion/keyframes.ts +46 -0
  242. package/src/motion/reduced-motion.ts +17 -0
  243. package/src/motion/scroll.ts +57 -0
  244. package/src/motion/spring.ts +150 -0
  245. package/src/motion/stagger.ts +43 -0
  246. package/src/motion/timeline.ts +246 -0
  247. package/src/motion/transition.ts +51 -0
  248. package/src/motion/types.ts +198 -0
  249. package/src/platform/storage.ts +215 -208
  250. package/src/reactive/batch.ts +22 -0
  251. package/src/reactive/computed.ts +92 -0
  252. package/src/reactive/core.ts +114 -0
  253. package/src/reactive/effect.ts +54 -0
  254. package/src/reactive/index.ts +23 -22
  255. package/src/reactive/internals.ts +122 -0
  256. package/src/reactive/linked.ts +56 -0
  257. package/src/reactive/persisted.ts +74 -0
  258. package/src/reactive/readonly.ts +35 -0
  259. package/src/reactive/signal.ts +20 -520
  260. package/src/reactive/type-guards.ts +22 -0
  261. package/src/reactive/untrack.ts +31 -0
  262. package/src/reactive/watch.ts +73 -0
  263. package/src/router/index.ts +41 -718
  264. package/src/router/links.ts +130 -0
  265. package/src/router/match.ts +106 -0
  266. package/src/router/navigation.ts +71 -0
  267. package/src/router/query.ts +35 -0
  268. package/src/router/router.ts +211 -0
  269. package/src/router/state.ts +46 -0
  270. package/src/router/types.ts +93 -0
  271. package/src/router/utils.ts +116 -0
  272. package/src/security/constants.ts +209 -0
  273. package/src/security/csp.ts +77 -0
  274. package/src/security/index.ts +4 -12
  275. package/src/security/sanitize-core.ts +364 -0
  276. package/src/security/sanitize.ts +66 -625
  277. package/src/security/trusted-types.ts +69 -0
  278. package/src/security/types.ts +40 -0
  279. package/src/store/create-store.ts +329 -0
  280. package/src/store/define-store.ts +48 -0
  281. package/src/store/devtools.ts +45 -0
  282. package/src/store/index.ts +22 -848
  283. package/src/store/mapping.ts +73 -0
  284. package/src/store/persisted.ts +61 -0
  285. package/src/store/plugins.ts +32 -0
  286. package/src/store/registry.ts +51 -0
  287. package/src/store/types.ts +94 -0
  288. package/src/store/utils.ts +141 -0
  289. package/src/store/watch.ts +52 -0
  290. package/src/view/directives/bind.ts +23 -0
  291. package/src/view/directives/class.ts +70 -0
  292. package/src/view/directives/for.ts +275 -0
  293. package/src/view/directives/html.ts +19 -0
  294. package/src/view/directives/if.ts +30 -0
  295. package/src/view/directives/index.ts +11 -0
  296. package/src/view/directives/model.ts +56 -0
  297. package/src/view/directives/on.ts +41 -0
  298. package/src/view/directives/ref.ts +41 -0
  299. package/src/view/directives/show.ts +26 -0
  300. package/src/view/directives/style.ts +47 -0
  301. package/src/view/directives/text.ts +15 -0
  302. package/src/view/evaluate.ts +290 -0
  303. package/src/view/index.ts +112 -1041
  304. package/src/view/mount.ts +200 -0
  305. package/src/view/process.ts +92 -0
  306. package/src/view/types.ts +44 -0
  307. package/dist/core/utils.d.ts +0 -313
  308. package/dist/core/utils.d.ts.map +0 -1
  309. package/src/core/utils.ts +0 -444
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Mapping helpers for store state and actions.
3
+ */
4
+
5
+ /**
6
+ * Maps store state properties to a reactive object for use in components.
7
+ *
8
+ * @param store - The store instance
9
+ * @param keys - State keys to map
10
+ * @returns Object with mapped properties
11
+ */
12
+ export const mapState = <S extends Record<string, unknown>, K extends keyof S>(
13
+ store: S,
14
+ keys: K[]
15
+ ): Pick<S, K> => {
16
+ const mapped = {} as Pick<S, K>;
17
+
18
+ for (const key of keys) {
19
+ Object.defineProperty(mapped, key, {
20
+ get: () => store[key],
21
+ enumerable: true,
22
+ });
23
+ }
24
+
25
+ return mapped;
26
+ };
27
+
28
+ /**
29
+ * Maps store getters to a reactive object for use in components.
30
+ *
31
+ * @param store - The store instance
32
+ * @param keys - Getter keys to map
33
+ * @returns Object with mapped getters
34
+ */
35
+ export const mapGetters = <G extends Record<string, unknown>, K extends keyof G>(
36
+ store: G,
37
+ keys: K[]
38
+ ): Pick<G, K> => {
39
+ const mapped = {} as Pick<G, K>;
40
+
41
+ for (const key of keys) {
42
+ Object.defineProperty(mapped, key, {
43
+ get: () => store[key],
44
+ enumerable: true,
45
+ });
46
+ }
47
+
48
+ return mapped;
49
+ };
50
+
51
+ /**
52
+ * Maps store actions to an object for easier destructuring.
53
+ *
54
+ * @param store - The store instance
55
+ * @param keys - Action keys to map
56
+ * @returns Object with mapped actions
57
+ */
58
+ export const mapActions = <
59
+ A extends Record<string, (...args: unknown[]) => unknown>,
60
+ K extends keyof A,
61
+ >(
62
+ store: A,
63
+ keys: K[]
64
+ ): Pick<A, K> => {
65
+ const mapped = {} as Pick<A, K>;
66
+
67
+ for (const key of keys) {
68
+ (mapped as Record<string, unknown>)[key as string] = (...args: unknown[]) =>
69
+ (store[key] as (...args: unknown[]) => unknown)(...args);
70
+ }
71
+
72
+ return mapped;
73
+ };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Store persistence helpers.
3
+ */
4
+
5
+ import { createStore } from './create-store';
6
+ import type { Store, StoreDefinition } from './types';
7
+
8
+ /**
9
+ * Creates a store with automatic persistence to localStorage.
10
+ *
11
+ * @param definition - Store definition
12
+ * @param storageKey - Optional custom storage key
13
+ * @returns The reactive store instance
14
+ */
15
+ export const createPersistedStore = <
16
+ S extends Record<string, unknown>,
17
+ G extends Record<string, unknown> = Record<string, never>,
18
+ A extends Record<string, (...args: unknown[]) => unknown> = Record<string, never>,
19
+ >(
20
+ definition: StoreDefinition<S, G, A>,
21
+ storageKey?: string
22
+ ): Store<S, G, A> => {
23
+ const key = storageKey ?? `bquery-store-${definition.id}`;
24
+
25
+ const originalStateFactory = definition.state;
26
+
27
+ const wrappedDefinition: StoreDefinition<S, G, A> = {
28
+ ...definition,
29
+ state: () => {
30
+ const defaultState = originalStateFactory();
31
+
32
+ if (typeof window !== 'undefined') {
33
+ try {
34
+ const saved = localStorage.getItem(key);
35
+ if (saved) {
36
+ return { ...defaultState, ...JSON.parse(saved) } as S;
37
+ }
38
+ } catch {
39
+ // Ignore parse errors
40
+ }
41
+ }
42
+
43
+ return defaultState;
44
+ },
45
+ };
46
+
47
+ const store = createStore(wrappedDefinition);
48
+
49
+ // Subscribe to save changes
50
+ store.$subscribe((state) => {
51
+ if (typeof window !== 'undefined') {
52
+ try {
53
+ localStorage.setItem(key, JSON.stringify(state));
54
+ } catch {
55
+ // Ignore quota errors
56
+ }
57
+ }
58
+ });
59
+
60
+ return store;
61
+ };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Store plugins API.
3
+ */
4
+
5
+ import type { Store, StoreDefinition, StorePlugin } from './types';
6
+
7
+ /** @internal Registered plugins */
8
+ const plugins: StorePlugin[] = [];
9
+
10
+ /**
11
+ * Registers a plugin that extends all stores.
12
+ *
13
+ * @param plugin - The plugin function
14
+ */
15
+ export const registerPlugin = (plugin: StorePlugin): void => {
16
+ plugins.push(plugin);
17
+ };
18
+
19
+ /** @internal */
20
+ export const applyPlugins = (
21
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
+ store: Store<any, any, any>,
23
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
24
+ options: StoreDefinition<any, any, any>
25
+ ): void => {
26
+ for (const plugin of plugins) {
27
+ const extension = plugin({ store, options });
28
+ if (extension) {
29
+ Object.assign(store, extension);
30
+ }
31
+ }
32
+ };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Store registry utilities.
3
+ */
4
+
5
+ import { unregisterDevtoolsStore } from './devtools';
6
+ import type { Store } from './types';
7
+
8
+ /** @internal Registry of all stores for devtools */
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
+ const storeRegistry = new Map<string, Store<any, any, any>>();
11
+
12
+ /** @internal */
13
+ export const hasStore = (id: string): boolean => storeRegistry.has(id);
14
+
15
+ /** @internal */
16
+ export const registerStore = (
17
+ id: string,
18
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
+ store: Store<any, any, any>
20
+ ): void => {
21
+ storeRegistry.set(id, store);
22
+ };
23
+
24
+ /**
25
+ * Retrieves an existing store by its ID.
26
+ *
27
+ * @param id - The store identifier
28
+ * @returns The store instance or undefined if not found
29
+ */
30
+ export const getStore = <T = unknown>(id: string): T | undefined => {
31
+ return storeRegistry.get(id) as T | undefined;
32
+ };
33
+
34
+ /**
35
+ * Lists all registered store IDs.
36
+ *
37
+ * @returns Array of store IDs
38
+ */
39
+ export const listStores = (): string[] => {
40
+ return Array.from(storeRegistry.keys());
41
+ };
42
+
43
+ /**
44
+ * Removes a store from the registry.
45
+ *
46
+ * @param id - The store identifier
47
+ */
48
+ export const destroyStore = (id: string): void => {
49
+ storeRegistry.delete(id);
50
+ unregisterDevtoolsStore(id);
51
+ };
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Store types for bQuery's state module.
3
+ * @module bquery/store
4
+ */
5
+
6
+ /**
7
+ * Store state factory function.
8
+ */
9
+ export type StateFactory<S> = () => S;
10
+
11
+ /**
12
+ * Getter definition - derives computed values from state.
13
+ */
14
+ export type Getters<S, G> = {
15
+ [K in keyof G]: (state: S, getters: G) => G[K];
16
+ };
17
+
18
+ /**
19
+ * Action definition - methods that can modify state.
20
+ * The `this` context includes state, getters, and other actions.
21
+ */
22
+ export type Actions<S, G, A> = {
23
+ [K in keyof A]: A[K] extends (...args: infer P) => infer R
24
+ ? (this: S & G & A, ...args: P) => R
25
+ : never;
26
+ };
27
+
28
+ /**
29
+ * Store definition for createStore.
30
+ */
31
+ export type StoreDefinition<
32
+ S extends Record<string, unknown> = Record<string, unknown>,
33
+ G extends Record<string, unknown> = Record<string, unknown>,
34
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
+ A extends Record<string, (...args: any[]) => any> = Record<string, never>,
36
+ > = {
37
+ /** Unique store identifier for devtools */
38
+ id: string;
39
+ /** State factory function */
40
+ state: StateFactory<S>;
41
+ /** Computed getters */
42
+ getters?: Getters<S, G>;
43
+ /** Action methods */
44
+ actions?: Actions<S, G, A>;
45
+ };
46
+
47
+ /**
48
+ * Store subscriber callback.
49
+ */
50
+ export type StoreSubscriber<S> = (state: S) => void;
51
+
52
+ /**
53
+ * Patch payload for store updates.
54
+ */
55
+ export type StorePatch<S> = Partial<S> | ((state: S) => void);
56
+
57
+ /**
58
+ * The returned store instance with state, getters, and actions merged.
59
+ */
60
+ export type Store<
61
+ S extends Record<string, unknown>,
62
+ G extends Record<string, unknown>,
63
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
64
+ A extends Record<string, (...args: any[]) => any>,
65
+ > = S &
66
+ G &
67
+ A & {
68
+ /** Store identifier */
69
+ $id: string;
70
+ /** Reset state to initial values */
71
+ $reset: () => void;
72
+ /** Subscribe to state changes */
73
+ $subscribe: (callback: StoreSubscriber<S>) => () => void;
74
+ /** Patch multiple state properties at once (shallow) */
75
+ $patch: (partial: StorePatch<S>) => void;
76
+ /**
77
+ * Patch with deep reactivity support.
78
+ * Unlike $patch, this method deep-clones nested objects before mutation,
79
+ * ensuring that all changes trigger reactive updates.
80
+ */
81
+ $patchDeep: (partial: StorePatch<S>) => void;
82
+ /** Get raw state object (non-reactive snapshot) */
83
+ $state: S;
84
+ };
85
+
86
+ /**
87
+ * Plugin that can extend store functionality.
88
+ */
89
+ export type StorePlugin<S = unknown> = (context: {
90
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
91
+ store: Store<any, any, any>;
92
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
93
+ options: StoreDefinition<any, any, any>;
94
+ }) => Partial<S> | void;
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Internal utilities for the store module.
3
+ * @internal
4
+ */
5
+
6
+ /**
7
+ * Check if a value is a plain object (not array, null, Date, etc.).
8
+ * @internal
9
+ */
10
+ export const isPlainObject = (value: unknown): value is Record<string, unknown> => {
11
+ return (
12
+ value !== null && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype
13
+ );
14
+ };
15
+
16
+ /**
17
+ * Deep clones an object. Used for deep reactivity support.
18
+ * @internal
19
+ */
20
+ export const deepClone = <T>(obj: T): T => {
21
+ if (obj === null || typeof obj !== 'object') {
22
+ return obj;
23
+ }
24
+
25
+ if (Array.isArray(obj)) {
26
+ return obj.map(deepClone) as T;
27
+ }
28
+
29
+ if (obj instanceof Date) {
30
+ return new Date(obj.getTime()) as T;
31
+ }
32
+
33
+ if (obj instanceof Map) {
34
+ return new Map(Array.from(obj.entries()).map(([k, v]) => [k, deepClone(v)])) as T;
35
+ }
36
+
37
+ if (obj instanceof Set) {
38
+ return new Set(Array.from(obj).map(deepClone)) as T;
39
+ }
40
+
41
+ const cloned = {} as T;
42
+ for (const key of Object.keys(obj)) {
43
+ (cloned as Record<string, unknown>)[key] = deepClone((obj as Record<string, unknown>)[key]);
44
+ }
45
+ return cloned;
46
+ };
47
+
48
+ /**
49
+ * Compares two values for deep equality.
50
+ * @internal
51
+ */
52
+ export const deepEqual = (a: unknown, b: unknown): boolean => {
53
+ if (a === b) return true;
54
+ if (a === null || b === null) return false;
55
+ if (typeof a !== 'object' || typeof b !== 'object') return false;
56
+
57
+ if (a instanceof Date && b instanceof Date) {
58
+ return a.getTime() === b.getTime();
59
+ }
60
+
61
+ if (a instanceof Map && b instanceof Map) {
62
+ if (a.size !== b.size) return false;
63
+ for (const [key, value] of a.entries()) {
64
+ if (!b.has(key) || !deepEqual(value, b.get(key))) return false;
65
+ }
66
+ return true;
67
+ }
68
+
69
+ if (a instanceof Set && b instanceof Set) {
70
+ if (a.size !== b.size) return false;
71
+ for (const value of a.values()) {
72
+ let found = false;
73
+ for (const candidate of b.values()) {
74
+ if (deepEqual(value, candidate)) {
75
+ found = true;
76
+ break;
77
+ }
78
+ }
79
+ if (!found) return false;
80
+ }
81
+ return true;
82
+ }
83
+
84
+ if (Array.isArray(a) && Array.isArray(b)) {
85
+ if (a.length !== b.length) return false;
86
+ return a.every((item, i) => deepEqual(item, b[i]));
87
+ }
88
+
89
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
90
+
91
+ const keysA = Object.keys(a as object);
92
+ const keysB = Object.keys(b as object);
93
+
94
+ if (keysA.length !== keysB.length) return false;
95
+
96
+ return keysA.every((key) =>
97
+ deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])
98
+ );
99
+ };
100
+
101
+ /**
102
+ * Detects if nested objects were mutated but the reference stayed the same.
103
+ * Returns the keys where nested mutations were detected.
104
+ * @internal
105
+ */
106
+ export const detectNestedMutations = <S extends Record<string, unknown>>(
107
+ before: S,
108
+ after: S,
109
+ signalValues: Map<keyof S, unknown>
110
+ ): Array<keyof S> => {
111
+ const mutatedKeys: Array<keyof S> = [];
112
+
113
+ for (const key of Object.keys(after) as Array<keyof S>) {
114
+ const beforeValue = before[key];
115
+ const afterValue = after[key];
116
+ const signalValue = signalValues.get(key);
117
+
118
+ // Check if it's the same reference but content changed
119
+ if (
120
+ signalValue === afterValue &&
121
+ isPlainObject(beforeValue) &&
122
+ isPlainObject(afterValue) &&
123
+ !deepEqual(beforeValue, afterValue)
124
+ ) {
125
+ mutatedKeys.push(key);
126
+ }
127
+ }
128
+
129
+ return mutatedKeys;
130
+ };
131
+
132
+ /** @internal Flag to enable/disable development warnings */
133
+ export const isDev = (() => {
134
+ try {
135
+ const globalProcess = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process;
136
+ // Default to dev mode unless explicitly set to production
137
+ return !(typeof globalProcess !== 'undefined' && globalProcess.env?.NODE_ENV === 'production');
138
+ } catch {
139
+ return true;
140
+ }
141
+ })();
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Store watch helpers.
3
+ */
4
+
5
+ import type { Store } from './types';
6
+ import { deepEqual } from './utils';
7
+
8
+ export type WatchStoreOptions<T> = {
9
+ /** Call the callback immediately with the current value. */
10
+ immediate?: boolean;
11
+ /** Use deep comparison when determining changes. */
12
+ deep?: boolean;
13
+ /** Custom equality check for selected values. */
14
+ equals?: (a: T, b: T) => boolean;
15
+ };
16
+
17
+ /**
18
+ * Watch a selected slice of store state.
19
+ *
20
+ * @param store - The store instance
21
+ * @param selector - Function to select the watched value
22
+ * @param callback - Called when the selected value changes
23
+ * @param options - Watch options
24
+ * @returns Unsubscribe function
25
+ */
26
+ export const watchStore = <
27
+ S extends Record<string, unknown>,
28
+ G extends Record<string, unknown>,
29
+ A extends Record<string, (...args: unknown[]) => unknown>,
30
+ T,
31
+ >(
32
+ store: Store<S, G, A>,
33
+ selector: (state: S) => T,
34
+ callback: (value: T, previous: T | undefined) => void,
35
+ options: WatchStoreOptions<T> = {}
36
+ ): (() => void) => {
37
+ const equals = options.equals ?? (options.deep ? deepEqual : Object.is);
38
+ let previous = selector(store.$state);
39
+
40
+ if (options.immediate) {
41
+ callback(previous, undefined);
42
+ }
43
+
44
+ return store.$subscribe((state) => {
45
+ const current = selector(state);
46
+ if (!equals(current, previous)) {
47
+ const prev = previous;
48
+ previous = current;
49
+ callback(current, prev);
50
+ }
51
+ });
52
+ };
@@ -0,0 +1,23 @@
1
+ import { effect } from '../../reactive/index';
2
+ import { evaluate } from '../evaluate';
3
+ import type { DirectiveHandler } from '../types';
4
+
5
+ /**
6
+ * Handles bq-bind:attr directive - attribute binding.
7
+ * @internal
8
+ */
9
+ export const handleBind = (attrName: string): DirectiveHandler => {
10
+ return (el, expression, context, cleanups) => {
11
+ const cleanup = effect(() => {
12
+ const value = evaluate(expression, context);
13
+ if (value == null || value === false) {
14
+ el.removeAttribute(attrName);
15
+ } else if (value === true) {
16
+ el.setAttribute(attrName, '');
17
+ } else {
18
+ el.setAttribute(attrName, String(value));
19
+ }
20
+ });
21
+ cleanups.push(cleanup);
22
+ };
23
+ };
@@ -0,0 +1,70 @@
1
+ import { effect } from '../../reactive/index';
2
+ import { evaluate, parseObjectExpression } from '../evaluate';
3
+ import type { DirectiveHandler } from '../types';
4
+
5
+ /**
6
+ * Handles bq-class directive - dynamic class binding.
7
+ * Tracks previously added classes to ensure proper cleanup when expressions change.
8
+ * @internal
9
+ */
10
+ export const handleClass: DirectiveHandler = (el, expression, context, cleanups) => {
11
+ // Track classes added by this directive to clean them up on re-evaluation
12
+ let previousClasses: Set<string> = new Set();
13
+
14
+ const cleanup = effect(() => {
15
+ const newClasses: Set<string> = new Set();
16
+
17
+ if (expression.trimStart().startsWith('{')) {
18
+ // Object syntax: { active: isActive, disabled: !enabled }
19
+ const classMap = parseObjectExpression(expression);
20
+ for (const [className, conditionExpr] of Object.entries(classMap)) {
21
+ const condition = evaluate<boolean>(conditionExpr, context);
22
+ el.classList.toggle(className, Boolean(condition));
23
+ // Track class regardless of condition - toggle handles add/remove
24
+ newClasses.add(className);
25
+ }
26
+ } else if (/^\s*\[/.test(expression)) {
27
+ // Array literal syntax: [class1, class2]
28
+ const classes = evaluate<string[]>(expression, context);
29
+ if (Array.isArray(classes)) {
30
+ for (const cls of classes) {
31
+ if (cls) {
32
+ el.classList.add(cls);
33
+ newClasses.add(cls);
34
+ }
35
+ }
36
+ }
37
+ } else {
38
+ // Single expression returning string or array
39
+ const result = evaluate<string | string[]>(expression, context);
40
+ if (typeof result === 'string') {
41
+ result.split(/\s+/).forEach((cls) => {
42
+ if (cls) {
43
+ el.classList.add(cls);
44
+ newClasses.add(cls);
45
+ }
46
+ });
47
+ } else if (Array.isArray(result)) {
48
+ result.forEach((cls) => {
49
+ if (cls) {
50
+ el.classList.add(cls);
51
+ newClasses.add(cls);
52
+ }
53
+ });
54
+ }
55
+ }
56
+
57
+ // Remove classes that were previously added but are no longer in the new set
58
+ // This keeps directive-managed classes in sync across all syntax forms and provides
59
+ // defensive cleanup behavior for edge cases (e.g. external classList changes)
60
+ for (const cls of previousClasses) {
61
+ if (!newClasses.has(cls)) {
62
+ el.classList.remove(cls);
63
+ }
64
+ }
65
+
66
+ previousClasses = newClasses;
67
+ });
68
+
69
+ cleanups.push(cleanup);
70
+ };