@wcstack/state 1.3.11

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 (574) hide show
  1. package/README.ja.md +1078 -0
  2. package/README.md +1078 -0
  3. package/dist/address/AbsolutePathInfo.d.ts +4 -0
  4. package/dist/address/AbsolutePathInfo.d.ts.map +1 -0
  5. package/dist/address/AbsolutePathInfo.js +33 -0
  6. package/dist/address/AbsolutePathInfo.js.map +1 -0
  7. package/dist/address/AbsoluteStateAddress.d.ts +4 -0
  8. package/dist/address/AbsoluteStateAddress.d.ts.map +1 -0
  9. package/dist/address/AbsoluteStateAddress.js +56 -0
  10. package/dist/address/AbsoluteStateAddress.js.map +1 -0
  11. package/dist/address/PathInfo.d.ts +3 -0
  12. package/dist/address/PathInfo.d.ts.map +1 -0
  13. package/dist/address/PathInfo.js +104 -0
  14. package/dist/address/PathInfo.js.map +1 -0
  15. package/dist/address/ResolvedAddress.d.ts +31 -0
  16. package/dist/address/ResolvedAddress.d.ts.map +1 -0
  17. package/dist/address/ResolvedAddress.js +110 -0
  18. package/dist/address/ResolvedAddress.js.map +1 -0
  19. package/dist/address/StateAddress.d.ts +4 -0
  20. package/dist/address/StateAddress.d.ts.map +1 -0
  21. package/dist/address/StateAddress.js +56 -0
  22. package/dist/address/StateAddress.js.map +1 -0
  23. package/dist/address/calcWildcardLen.d.ts +3 -0
  24. package/dist/address/calcWildcardLen.d.ts.map +1 -0
  25. package/dist/address/calcWildcardLen.js +31 -0
  26. package/dist/address/calcWildcardLen.js.map +1 -0
  27. package/dist/address/types.d.ts +54 -0
  28. package/dist/address/types.d.ts.map +1 -0
  29. package/dist/address/types.js +2 -0
  30. package/dist/address/types.js.map +1 -0
  31. package/dist/apply/applyChange.d.ts +4 -0
  32. package/dist/apply/applyChange.d.ts.map +1 -0
  33. package/dist/apply/applyChange.js +105 -0
  34. package/dist/apply/applyChange.js.map +1 -0
  35. package/dist/apply/applyChangeFromBindings.d.ts +9 -0
  36. package/dist/apply/applyChangeFromBindings.d.ts.map +1 -0
  37. package/dist/apply/applyChangeFromBindings.js +74 -0
  38. package/dist/apply/applyChangeFromBindings.js.map +1 -0
  39. package/dist/apply/applyChangeToAttribute.d.ts +4 -0
  40. package/dist/apply/applyChangeToAttribute.d.ts.map +1 -0
  41. package/dist/apply/applyChangeToAttribute.js +8 -0
  42. package/dist/apply/applyChangeToAttribute.js.map +1 -0
  43. package/dist/apply/applyChangeToCheckbox.d.ts +4 -0
  44. package/dist/apply/applyChangeToCheckbox.d.ts.map +1 -0
  45. package/dist/apply/applyChangeToCheckbox.js +11 -0
  46. package/dist/apply/applyChangeToCheckbox.js.map +1 -0
  47. package/dist/apply/applyChangeToClass.d.ts +4 -0
  48. package/dist/apply/applyChangeToClass.d.ts.map +1 -0
  49. package/dist/apply/applyChangeToClass.js +10 -0
  50. package/dist/apply/applyChangeToClass.js.map +1 -0
  51. package/dist/apply/applyChangeToFor.d.ts +9 -0
  52. package/dist/apply/applyChangeToFor.d.ts.map +1 -0
  53. package/dist/apply/applyChangeToFor.js +186 -0
  54. package/dist/apply/applyChangeToFor.js.map +1 -0
  55. package/dist/apply/applyChangeToIf.d.ts +4 -0
  56. package/dist/apply/applyChangeToIf.d.ts.map +1 -0
  57. package/dist/apply/applyChangeToIf.js +42 -0
  58. package/dist/apply/applyChangeToIf.js.map +1 -0
  59. package/dist/apply/applyChangeToProperty.d.ts +4 -0
  60. package/dist/apply/applyChangeToProperty.d.ts.map +1 -0
  61. package/dist/apply/applyChangeToProperty.js +37 -0
  62. package/dist/apply/applyChangeToProperty.js.map +1 -0
  63. package/dist/apply/applyChangeToRadio.d.ts +4 -0
  64. package/dist/apply/applyChangeToRadio.d.ts.map +1 -0
  65. package/dist/apply/applyChangeToRadio.js +8 -0
  66. package/dist/apply/applyChangeToRadio.js.map +1 -0
  67. package/dist/apply/applyChangeToStyle.d.ts +4 -0
  68. package/dist/apply/applyChangeToStyle.d.ts.map +1 -0
  69. package/dist/apply/applyChangeToStyle.js +9 -0
  70. package/dist/apply/applyChangeToStyle.js.map +1 -0
  71. package/dist/apply/applyChangeToText.d.ts +4 -0
  72. package/dist/apply/applyChangeToText.d.ts.map +1 -0
  73. package/dist/apply/applyChangeToText.js +6 -0
  74. package/dist/apply/applyChangeToText.js.map +1 -0
  75. package/dist/apply/applyChangeToWebComponent.d.ts +4 -0
  76. package/dist/apply/applyChangeToWebComponent.d.ts.map +1 -0
  77. package/dist/apply/applyChangeToWebComponent.js +15 -0
  78. package/dist/apply/applyChangeToWebComponent.js.map +1 -0
  79. package/dist/apply/getFilteredValue.d.ts +3 -0
  80. package/dist/apply/getFilteredValue.d.ts.map +1 -0
  81. package/dist/apply/getFilteredValue.js +8 -0
  82. package/dist/apply/getFilteredValue.js.map +1 -0
  83. package/dist/apply/getValue.d.ts +4 -0
  84. package/dist/apply/getValue.d.ts.map +1 -0
  85. package/dist/apply/getValue.js +20 -0
  86. package/dist/apply/getValue.js.map +1 -0
  87. package/dist/apply/rootNodeByFragment.d.ts +3 -0
  88. package/dist/apply/rootNodeByFragment.d.ts.map +1 -0
  89. package/dist/apply/rootNodeByFragment.js +13 -0
  90. package/dist/apply/rootNodeByFragment.js.map +1 -0
  91. package/dist/apply/types.d.ts +15 -0
  92. package/dist/apply/types.d.ts.map +1 -0
  93. package/dist/apply/types.js +2 -0
  94. package/dist/apply/types.js.map +1 -0
  95. package/dist/applyChangeToNode.d.ts +2 -0
  96. package/dist/applyChangeToNode.d.ts.map +1 -0
  97. package/dist/applyChangeToNode.js +38 -0
  98. package/dist/applyChangeToNode.js.map +1 -0
  99. package/dist/auto.js +3 -0
  100. package/dist/auto.min.js +3 -0
  101. package/dist/bindTextParser/parseBindTextForEmbeddedNode.d.ts +3 -0
  102. package/dist/bindTextParser/parseBindTextForEmbeddedNode.d.ts.map +1 -0
  103. package/dist/bindTextParser/parseBindTextForEmbeddedNode.js +13 -0
  104. package/dist/bindTextParser/parseBindTextForEmbeddedNode.js.map +1 -0
  105. package/dist/bindTextParser/parseBindTextsForElement.d.ts +3 -0
  106. package/dist/bindTextParser/parseBindTextsForElement.d.ts.map +1 -0
  107. package/dist/bindTextParser/parseBindTextsForElement.js +80 -0
  108. package/dist/bindTextParser/parseBindTextsForElement.js.map +1 -0
  109. package/dist/bindTextParser/parseFilterArgs.d.ts +2 -0
  110. package/dist/bindTextParser/parseFilterArgs.d.ts.map +1 -0
  111. package/dist/bindTextParser/parseFilterArgs.js +31 -0
  112. package/dist/bindTextParser/parseFilterArgs.js.map +1 -0
  113. package/dist/bindTextParser/parseFilters.d.ts +4 -0
  114. package/dist/bindTextParser/parseFilters.d.ts.map +1 -0
  115. package/dist/bindTextParser/parseFilters.js +52 -0
  116. package/dist/bindTextParser/parseFilters.js.map +1 -0
  117. package/dist/bindTextParser/parsePropPart.d.ts +5 -0
  118. package/dist/bindTextParser/parsePropPart.d.ts.map +1 -0
  119. package/dist/bindTextParser/parsePropPart.js +44 -0
  120. package/dist/bindTextParser/parsePropPart.js.map +1 -0
  121. package/dist/bindTextParser/parseStatePart.d.ts +5 -0
  122. package/dist/bindTextParser/parseStatePart.d.ts.map +1 -0
  123. package/dist/bindTextParser/parseStatePart.js +39 -0
  124. package/dist/bindTextParser/parseStatePart.js.map +1 -0
  125. package/dist/bindTextParser/types.d.ts +3 -0
  126. package/dist/bindTextParser/types.d.ts.map +1 -0
  127. package/dist/bindTextParser/types.js +2 -0
  128. package/dist/bindTextParser/types.js.map +1 -0
  129. package/dist/bindTextParser/utils.d.ts +2 -0
  130. package/dist/bindTextParser/utils.d.ts.map +1 -0
  131. package/dist/bindTextParser/utils.js +2 -0
  132. package/dist/bindTextParser/utils.js.map +1 -0
  133. package/dist/binding/getAbsoluteStateAddressByBinding.d.ts +5 -0
  134. package/dist/binding/getAbsoluteStateAddressByBinding.d.ts.map +1 -0
  135. package/dist/binding/getAbsoluteStateAddressByBinding.js +41 -0
  136. package/dist/binding/getAbsoluteStateAddressByBinding.js.map +1 -0
  137. package/dist/binding/getBindingSetByAbsoluteStateAddress.d.ts +7 -0
  138. package/dist/binding/getBindingSetByAbsoluteStateAddress.d.ts.map +1 -0
  139. package/dist/binding/getBindingSetByAbsoluteStateAddress.js +22 -0
  140. package/dist/binding/getBindingSetByAbsoluteStateAddress.js.map +1 -0
  141. package/dist/binding/getStateAddressByBindingInfo.d.ts +5 -0
  142. package/dist/binding/getStateAddressByBindingInfo.d.ts.map +1 -0
  143. package/dist/binding/getStateAddressByBindingInfo.js +28 -0
  144. package/dist/binding/getStateAddressByBindingInfo.js.map +1 -0
  145. package/dist/binding/types.d.ts +23 -0
  146. package/dist/binding/types.d.ts.map +1 -0
  147. package/dist/binding/types.js +2 -0
  148. package/dist/binding/types.js.map +1 -0
  149. package/dist/bindings/bindLoopContextToContent.d.ts +5 -0
  150. package/dist/bindings/bindLoopContextToContent.d.ts.map +1 -0
  151. package/dist/bindings/bindLoopContextToContent.js +15 -0
  152. package/dist/bindings/bindLoopContextToContent.js.map +1 -0
  153. package/dist/bindings/bindingsByContent.d.ts +5 -0
  154. package/dist/bindings/bindingsByContent.d.ts.map +1 -0
  155. package/dist/bindings/bindingsByContent.js +8 -0
  156. package/dist/bindings/bindingsByContent.js.map +1 -0
  157. package/dist/bindings/collectNodesAndBindingInfos.d.ts +6 -0
  158. package/dist/bindings/collectNodesAndBindingInfos.d.ts.map +1 -0
  159. package/dist/bindings/collectNodesAndBindingInfos.js +46 -0
  160. package/dist/bindings/collectNodesAndBindingInfos.js.map +1 -0
  161. package/dist/bindings/getBindingInfos.d.ts +4 -0
  162. package/dist/bindings/getBindingInfos.d.ts.map +1 -0
  163. package/dist/bindings/getBindingInfos.js +22 -0
  164. package/dist/bindings/getBindingInfos.js.map +1 -0
  165. package/dist/bindings/getBindingsByNode.d.ts +5 -0
  166. package/dist/bindings/getBindingsByNode.d.ts.map +1 -0
  167. package/dist/bindings/getBindingsByNode.js +17 -0
  168. package/dist/bindings/getBindingsByNode.js.map +1 -0
  169. package/dist/bindings/getParseBindTextResults.d.ts +3 -0
  170. package/dist/bindings/getParseBindTextResults.d.ts.map +1 -0
  171. package/dist/bindings/getParseBindTextResults.js +36 -0
  172. package/dist/bindings/getParseBindTextResults.js.map +1 -0
  173. package/dist/bindings/getSubscriberNodes.d.ts +7 -0
  174. package/dist/bindings/getSubscriberNodes.d.ts.map +1 -0
  175. package/dist/bindings/getSubscriberNodes.js +32 -0
  176. package/dist/bindings/getSubscriberNodes.js.map +1 -0
  177. package/dist/bindings/indexBindingsByContent.d.ts +5 -0
  178. package/dist/bindings/indexBindingsByContent.d.ts.map +1 -0
  179. package/dist/bindings/indexBindingsByContent.js +8 -0
  180. package/dist/bindings/indexBindingsByContent.js.map +1 -0
  181. package/dist/bindings/initializeBindingPromiseByNode.d.ts +5 -0
  182. package/dist/bindings/initializeBindingPromiseByNode.d.ts.map +1 -0
  183. package/dist/bindings/initializeBindingPromiseByNode.js +28 -0
  184. package/dist/bindings/initializeBindingPromiseByNode.js.map +1 -0
  185. package/dist/bindings/initializeBindings.d.ts +6 -0
  186. package/dist/bindings/initializeBindings.d.ts.map +1 -0
  187. package/dist/bindings/initializeBindings.js +59 -0
  188. package/dist/bindings/initializeBindings.js.map +1 -0
  189. package/dist/bindings/nodesByContent.d.ts +4 -0
  190. package/dist/bindings/nodesByContent.d.ts.map +1 -0
  191. package/dist/bindings/nodesByContent.js +8 -0
  192. package/dist/bindings/nodesByContent.js.map +1 -0
  193. package/dist/bindings/parseCommentNode.d.ts +3 -0
  194. package/dist/bindings/parseCommentNode.d.ts.map +1 -0
  195. package/dist/bindings/parseCommentNode.js +47 -0
  196. package/dist/bindings/parseCommentNode.js.map +1 -0
  197. package/dist/bindings/replaceToReplaceNode.d.ts +3 -0
  198. package/dist/bindings/replaceToReplaceNode.d.ts.map +1 -0
  199. package/dist/bindings/replaceToReplaceNode.js +13 -0
  200. package/dist/bindings/replaceToReplaceNode.js.map +1 -0
  201. package/dist/bindings/types.d.ts +11 -0
  202. package/dist/bindings/types.d.ts.map +1 -0
  203. package/dist/bindings/types.js +2 -0
  204. package/dist/bindings/types.js.map +1 -0
  205. package/dist/bootstrapState.d.ts +3 -0
  206. package/dist/bootstrapState.d.ts.map +1 -0
  207. package/dist/bootstrapState.js +9 -0
  208. package/dist/bootstrapState.js.map +1 -0
  209. package/dist/buildBindings.d.ts +2 -0
  210. package/dist/buildBindings.d.ts.map +1 -0
  211. package/dist/buildBindings.js +30 -0
  212. package/dist/buildBindings.js.map +1 -0
  213. package/dist/cache/cacheEntryByAbsoluteStateAddress.d.ts +6 -0
  214. package/dist/cache/cacheEntryByAbsoluteStateAddress.d.ts.map +1 -0
  215. package/dist/cache/cacheEntryByAbsoluteStateAddress.js +19 -0
  216. package/dist/cache/cacheEntryByAbsoluteStateAddress.js.map +1 -0
  217. package/dist/cache/types.d.ts +5 -0
  218. package/dist/cache/types.d.ts.map +1 -0
  219. package/dist/cache/types.js +2 -0
  220. package/dist/cache/types.js.map +1 -0
  221. package/dist/components/State.d.ts +83 -0
  222. package/dist/components/State.d.ts.map +1 -0
  223. package/dist/components/State.js +340 -0
  224. package/dist/components/State.js.map +1 -0
  225. package/dist/components/types.d.ts +26 -0
  226. package/dist/components/types.d.ts.map +1 -0
  227. package/dist/components/types.js +2 -0
  228. package/dist/components/types.js.map +1 -0
  229. package/dist/config.d.ts +4 -0
  230. package/dist/config.d.ts.map +1 -0
  231. package/dist/config.js +49 -0
  232. package/dist/config.js.map +1 -0
  233. package/dist/createEmptyArray.d.ts +2 -0
  234. package/dist/createEmptyArray.d.ts.map +1 -0
  235. package/dist/createEmptyArray.js +4 -0
  236. package/dist/createEmptyArray.js.map +1 -0
  237. package/dist/createEmptySet.d.ts +2 -0
  238. package/dist/createEmptySet.d.ts.map +1 -0
  239. package/dist/createEmptySet.js +4 -0
  240. package/dist/createEmptySet.js.map +1 -0
  241. package/dist/define.d.ts +14 -0
  242. package/dist/define.d.ts.map +1 -0
  243. package/dist/define.js +25 -0
  244. package/dist/define.js.map +1 -0
  245. package/dist/dependency/types.d.ts +2 -0
  246. package/dist/dependency/types.d.ts.map +1 -0
  247. package/dist/dependency/types.js +2 -0
  248. package/dist/dependency/types.js.map +1 -0
  249. package/dist/dependency/walkDependency.d.ts +6 -0
  250. package/dist/dependency/walkDependency.d.ts.map +1 -0
  251. package/dist/dependency/walkDependency.js +194 -0
  252. package/dist/dependency/walkDependency.js.map +1 -0
  253. package/dist/event/checkboxHandler.d.ts +14 -0
  254. package/dist/event/checkboxHandler.d.ts.map +1 -0
  255. package/dist/event/checkboxHandler.js +120 -0
  256. package/dist/event/checkboxHandler.js.map +1 -0
  257. package/dist/event/handler.d.ts +8 -0
  258. package/dist/event/handler.d.ts.map +1 -0
  259. package/dist/event/handler.js +81 -0
  260. package/dist/event/handler.js.map +1 -0
  261. package/dist/event/isPossibleTwoWay.d.ts +2 -0
  262. package/dist/event/isPossibleTwoWay.d.ts.map +1 -0
  263. package/dist/event/isPossibleTwoWay.js +29 -0
  264. package/dist/event/isPossibleTwoWay.js.map +1 -0
  265. package/dist/event/radioHandler.d.ts +14 -0
  266. package/dist/event/radioHandler.d.ts.map +1 -0
  267. package/dist/event/radioHandler.js +101 -0
  268. package/dist/event/radioHandler.js.map +1 -0
  269. package/dist/event/twowayHandler.d.ts +14 -0
  270. package/dist/event/twowayHandler.d.ts.map +1 -0
  271. package/dist/event/twowayHandler.js +100 -0
  272. package/dist/event/twowayHandler.js.map +1 -0
  273. package/dist/exports.d.ts +3 -0
  274. package/dist/exports.d.ts.map +1 -0
  275. package/dist/exports.js +2 -0
  276. package/dist/exports.js.map +1 -0
  277. package/dist/filters/builtinFilters.d.ts +16 -0
  278. package/dist/filters/builtinFilters.d.ts.map +1 -0
  279. package/dist/filters/builtinFilters.js +716 -0
  280. package/dist/filters/builtinFilters.js.map +1 -0
  281. package/dist/filters/errorMessages.d.ts +43 -0
  282. package/dist/filters/errorMessages.d.ts.map +1 -0
  283. package/dist/filters/errorMessages.js +72 -0
  284. package/dist/filters/errorMessages.js.map +1 -0
  285. package/dist/filters/types.d.ts +23 -0
  286. package/dist/filters/types.d.ts.map +1 -0
  287. package/dist/filters/types.js +2 -0
  288. package/dist/filters/types.js.map +1 -0
  289. package/dist/getUUID.d.ts +2 -0
  290. package/dist/getUUID.d.ts.map +1 -0
  291. package/dist/getUUID.js +5 -0
  292. package/dist/getUUID.js.map +1 -0
  293. package/dist/hydrater/hydrate.d.ts +1 -0
  294. package/dist/hydrater/hydrate.d.ts.map +1 -0
  295. package/dist/hydrater/hydrate.js +2 -0
  296. package/dist/hydrater/hydrate.js.map +1 -0
  297. package/dist/index.d.ts +20 -0
  298. package/dist/index.esm.js +5677 -0
  299. package/dist/index.esm.js.map +1 -0
  300. package/dist/index.esm.min.js +2 -0
  301. package/dist/index.esm.min.js.map +1 -0
  302. package/dist/isCustomElement.d.ts +2 -0
  303. package/dist/isCustomElement.d.ts.map +1 -0
  304. package/dist/isCustomElement.js +26 -0
  305. package/dist/isCustomElement.js.map +1 -0
  306. package/dist/list/createListDiff.d.ts +13 -0
  307. package/dist/list/createListDiff.d.ts.map +1 -0
  308. package/dist/list/createListDiff.js +181 -0
  309. package/dist/list/createListDiff.js.map +1 -0
  310. package/dist/list/createListIndex.d.ts +10 -0
  311. package/dist/list/createListIndex.d.ts.map +1 -0
  312. package/dist/list/createListIndex.js +136 -0
  313. package/dist/list/createListIndex.js.map +1 -0
  314. package/dist/list/getIndexValueByLoopContext.d.ts +3 -0
  315. package/dist/list/getIndexValueByLoopContext.d.ts.map +1 -0
  316. package/dist/list/getIndexValueByLoopContext.js +18 -0
  317. package/dist/list/getIndexValueByLoopContext.js.map +1 -0
  318. package/dist/list/getListIndexByBindingInfo.d.ts +4 -0
  319. package/dist/list/getListIndexByBindingInfo.d.ts.map +1 -0
  320. package/dist/list/getListIndexByBindingInfo.js +32 -0
  321. package/dist/list/getListIndexByBindingInfo.js.map +1 -0
  322. package/dist/list/lastListValueByAbsoluteStateAddress.d.ts +6 -0
  323. package/dist/list/lastListValueByAbsoluteStateAddress.d.ts.map +1 -0
  324. package/dist/list/lastListValueByAbsoluteStateAddress.js +14 -0
  325. package/dist/list/lastListValueByAbsoluteStateAddress.js.map +1 -0
  326. package/dist/list/listIndexesByList.d.ts +4 -0
  327. package/dist/list/listIndexesByList.d.ts.map +1 -0
  328. package/dist/list/listIndexesByList.js +12 -0
  329. package/dist/list/listIndexesByList.js.map +1 -0
  330. package/dist/list/loopContext.d.ts +3 -0
  331. package/dist/list/loopContext.d.ts.map +1 -0
  332. package/dist/list/loopContext.js +54 -0
  333. package/dist/list/loopContext.js.map +1 -0
  334. package/dist/list/loopContextByNode.d.ts +4 -0
  335. package/dist/list/loopContextByNode.d.ts.map +1 -0
  336. package/dist/list/loopContextByNode.js +20 -0
  337. package/dist/list/loopContextByNode.js.map +1 -0
  338. package/dist/list/types.d.ts +38 -0
  339. package/dist/list/types.d.ts.map +1 -0
  340. package/dist/list/types.js +2 -0
  341. package/dist/list/types.js.map +1 -0
  342. package/dist/mustache/convertMustacheToComments.d.ts +2 -0
  343. package/dist/mustache/convertMustacheToComments.d.ts.map +1 -0
  344. package/dist/mustache/convertMustacheToComments.js +66 -0
  345. package/dist/mustache/convertMustacheToComments.js.map +1 -0
  346. package/dist/polyfills.d.ts +8 -0
  347. package/dist/polyfills.d.ts.map +1 -0
  348. package/dist/polyfills.js +22 -0
  349. package/dist/polyfills.js.map +1 -0
  350. package/dist/proxy/StateHandler.d.ts +32 -0
  351. package/dist/proxy/StateHandler.d.ts.map +1 -0
  352. package/dist/proxy/StateHandler.js +91 -0
  353. package/dist/proxy/StateHandler.js.map +1 -0
  354. package/dist/proxy/apis/connectedCallback.d.ts +18 -0
  355. package/dist/proxy/apis/connectedCallback.d.ts.map +1 -0
  356. package/dist/proxy/apis/connectedCallback.js +23 -0
  357. package/dist/proxy/apis/connectedCallback.js.map +1 -0
  358. package/dist/proxy/apis/disconnectedCallback.d.ts +17 -0
  359. package/dist/proxy/apis/disconnectedCallback.d.ts.map +1 -0
  360. package/dist/proxy/apis/disconnectedCallback.js +22 -0
  361. package/dist/proxy/apis/disconnectedCallback.js.map +1 -0
  362. package/dist/proxy/apis/getAll.d.ts +11 -0
  363. package/dist/proxy/apis/getAll.d.ts.map +1 -0
  364. package/dist/proxy/apis/getAll.js +87 -0
  365. package/dist/proxy/apis/getAll.js.map +1 -0
  366. package/dist/proxy/apis/postUpdate.d.ts +5 -0
  367. package/dist/proxy/apis/postUpdate.d.ts.map +1 -0
  368. package/dist/proxy/apis/postUpdate.js +30 -0
  369. package/dist/proxy/apis/postUpdate.js.map +1 -0
  370. package/dist/proxy/apis/resolve.d.ts +22 -0
  371. package/dist/proxy/apis/resolve.d.ts.map +1 -0
  372. package/dist/proxy/apis/resolve.js +65 -0
  373. package/dist/proxy/apis/resolve.js.map +1 -0
  374. package/dist/proxy/apis/trackDependency.d.ts +34 -0
  375. package/dist/proxy/apis/trackDependency.d.ts.map +1 -0
  376. package/dist/proxy/apis/trackDependency.js +32 -0
  377. package/dist/proxy/apis/trackDependency.js.map +1 -0
  378. package/dist/proxy/apis/updatedCallback.d.ts +28 -0
  379. package/dist/proxy/apis/updatedCallback.d.ts.map +1 -0
  380. package/dist/proxy/apis/updatedCallback.js +56 -0
  381. package/dist/proxy/apis/updatedCallback.js.map +1 -0
  382. package/dist/proxy/methods/checkDependency.d.ts +4 -0
  383. package/dist/proxy/methods/checkDependency.d.ts.map +1 -0
  384. package/dist/proxy/methods/checkDependency.js +16 -0
  385. package/dist/proxy/methods/checkDependency.js.map +1 -0
  386. package/dist/proxy/methods/getByAddress.d.ts +23 -0
  387. package/dist/proxy/methods/getByAddress.d.ts.map +1 -0
  388. package/dist/proxy/methods/getByAddress.js +81 -0
  389. package/dist/proxy/methods/getByAddress.js.map +1 -0
  390. package/dist/proxy/methods/getContextListIndex.d.ts +21 -0
  391. package/dist/proxy/methods/getContextListIndex.d.ts.map +1 -0
  392. package/dist/proxy/methods/getContextListIndex.js +32 -0
  393. package/dist/proxy/methods/getContextListIndex.js.map +1 -0
  394. package/dist/proxy/methods/getListIndex.d.ts +22 -0
  395. package/dist/proxy/methods/getListIndex.d.ts.map +1 -0
  396. package/dist/proxy/methods/getListIndex.js +55 -0
  397. package/dist/proxy/methods/getListIndex.js.map +1 -0
  398. package/dist/proxy/methods/setByAddress.d.ts +21 -0
  399. package/dist/proxy/methods/setByAddress.d.ts.map +1 -0
  400. package/dist/proxy/methods/setByAddress.js +135 -0
  401. package/dist/proxy/methods/setByAddress.js.map +1 -0
  402. package/dist/proxy/methods/setLoopContext.d.ts +22 -0
  403. package/dist/proxy/methods/setLoopContext.d.ts.map +1 -0
  404. package/dist/proxy/methods/setLoopContext.js +43 -0
  405. package/dist/proxy/methods/setLoopContext.js.map +1 -0
  406. package/dist/proxy/methods/swapInfo.d.ts +5 -0
  407. package/dist/proxy/methods/swapInfo.d.ts.map +1 -0
  408. package/dist/proxy/methods/swapInfo.js +13 -0
  409. package/dist/proxy/methods/swapInfo.js.map +1 -0
  410. package/dist/proxy/methods/types.d.ts +6 -0
  411. package/dist/proxy/methods/types.d.ts.map +1 -0
  412. package/dist/proxy/methods/types.js +2 -0
  413. package/dist/proxy/methods/types.js.map +1 -0
  414. package/dist/proxy/symbols.d.ts +8 -0
  415. package/dist/proxy/symbols.d.ts.map +1 -0
  416. package/dist/proxy/symbols.js +8 -0
  417. package/dist/proxy/symbols.js.map +1 -0
  418. package/dist/proxy/traps/get.d.ts +21 -0
  419. package/dist/proxy/traps/get.d.ts.map +1 -0
  420. package/dist/proxy/traps/get.js +120 -0
  421. package/dist/proxy/traps/get.js.map +1 -0
  422. package/dist/proxy/traps/set.d.ts +18 -0
  423. package/dist/proxy/traps/set.d.ts.map +1 -0
  424. package/dist/proxy/traps/set.js +31 -0
  425. package/dist/proxy/traps/set.js.map +1 -0
  426. package/dist/proxy/types.d.ts +27 -0
  427. package/dist/proxy/types.d.ts.map +1 -0
  428. package/dist/proxy/types.js +2 -0
  429. package/dist/proxy/types.js.map +1 -0
  430. package/dist/raiseError.d.ts +2 -0
  431. package/dist/raiseError.d.ts.map +1 -0
  432. package/dist/raiseError.js +4 -0
  433. package/dist/raiseError.js.map +1 -0
  434. package/dist/registerComponents.d.ts +2 -0
  435. package/dist/registerComponents.d.ts.map +1 -0
  436. package/dist/registerComponents.js +9 -0
  437. package/dist/registerComponents.js.map +1 -0
  438. package/dist/stateElementByName.d.ts +4 -0
  439. package/dist/stateElementByName.d.ts.map +1 -0
  440. package/dist/stateElementByName.js +53 -0
  441. package/dist/stateElementByName.js.map +1 -0
  442. package/dist/stateLoader/loadFromInnerScript.d.ts +3 -0
  443. package/dist/stateLoader/loadFromInnerScript.d.ts.map +1 -0
  444. package/dist/stateLoader/loadFromInnerScript.js +24 -0
  445. package/dist/stateLoader/loadFromInnerScript.js.map +1 -0
  446. package/dist/stateLoader/loadFromJsonFile.d.ts +3 -0
  447. package/dist/stateLoader/loadFromJsonFile.d.ts.map +1 -0
  448. package/dist/stateLoader/loadFromJsonFile.js +16 -0
  449. package/dist/stateLoader/loadFromJsonFile.js.map +1 -0
  450. package/dist/stateLoader/loadFromScriptFile.d.ts +3 -0
  451. package/dist/stateLoader/loadFromScriptFile.d.ts.map +1 -0
  452. package/dist/stateLoader/loadFromScriptFile.js +11 -0
  453. package/dist/stateLoader/loadFromScriptFile.js.map +1 -0
  454. package/dist/stateLoader/loadFromScriptJson.d.ts +3 -0
  455. package/dist/stateLoader/loadFromScriptJson.d.ts.map +1 -0
  456. package/dist/stateLoader/loadFromScriptJson.js +15 -0
  457. package/dist/stateLoader/loadFromScriptJson.js.map +1 -0
  458. package/dist/structural/activateContent.d.ts +6 -0
  459. package/dist/structural/activateContent.d.ts.map +1 -0
  460. package/dist/structural/activateContent.js +29 -0
  461. package/dist/structural/activateContent.js.map +1 -0
  462. package/dist/structural/collectStructuralFragments.d.ts +2 -0
  463. package/dist/structural/collectStructuralFragments.d.ts.map +1 -0
  464. package/dist/structural/collectStructuralFragments.js +160 -0
  465. package/dist/structural/collectStructuralFragments.js.map +1 -0
  466. package/dist/structural/contentsByNode.d.ts +5 -0
  467. package/dist/structural/contentsByNode.d.ts.map +1 -0
  468. package/dist/structural/contentsByNode.js +29 -0
  469. package/dist/structural/contentsByNode.js.map +1 -0
  470. package/dist/structural/createContent.d.ts +4 -0
  471. package/dist/structural/createContent.d.ts.map +1 -0
  472. package/dist/structural/createContent.js +92 -0
  473. package/dist/structural/createContent.js.map +1 -0
  474. package/dist/structural/createNotFilter.d.ts +3 -0
  475. package/dist/structural/createNotFilter.d.ts.map +1 -0
  476. package/dist/structural/createNotFilter.js +17 -0
  477. package/dist/structural/createNotFilter.js.map +1 -0
  478. package/dist/structural/define.d.ts +3 -0
  479. package/dist/structural/define.d.ts.map +1 -0
  480. package/dist/structural/define.js +7 -0
  481. package/dist/structural/define.js.map +1 -0
  482. package/dist/structural/expandShorthandPaths.d.ts +3 -0
  483. package/dist/structural/expandShorthandPaths.d.ts.map +1 -0
  484. package/dist/structural/expandShorthandPaths.js +96 -0
  485. package/dist/structural/expandShorthandPaths.js.map +1 -0
  486. package/dist/structural/fragmentInfoByUUID.d.ts +4 -0
  487. package/dist/structural/fragmentInfoByUUID.d.ts.map +1 -0
  488. package/dist/structural/fragmentInfoByUUID.js +30 -0
  489. package/dist/structural/fragmentInfoByUUID.js.map +1 -0
  490. package/dist/structural/getFragmentNodeInfos.d.ts +3 -0
  491. package/dist/structural/getFragmentNodeInfos.d.ts.map +1 -0
  492. package/dist/structural/getFragmentNodeInfos.js +16 -0
  493. package/dist/structural/getFragmentNodeInfos.js.map +1 -0
  494. package/dist/structural/getNodePath.d.ts +2 -0
  495. package/dist/structural/getNodePath.d.ts.map +1 -0
  496. package/dist/structural/getNodePath.js +12 -0
  497. package/dist/structural/getNodePath.js.map +1 -0
  498. package/dist/structural/optimizeFragment.d.ts +2 -0
  499. package/dist/structural/optimizeFragment.d.ts.map +1 -0
  500. package/dist/structural/optimizeFragment.js +13 -0
  501. package/dist/structural/optimizeFragment.js.map +1 -0
  502. package/dist/structural/resolveNodePath.d.ts +2 -0
  503. package/dist/structural/resolveNodePath.d.ts.map +1 -0
  504. package/dist/structural/resolveNodePath.js +13 -0
  505. package/dist/structural/resolveNodePath.js.map +1 -0
  506. package/dist/structural/types.d.ts +19 -0
  507. package/dist/structural/types.d.ts.map +1 -0
  508. package/dist/structural/types.js +2 -0
  509. package/dist/structural/types.js.map +1 -0
  510. package/dist/types.d.ts +35 -0
  511. package/dist/types.d.ts.map +1 -0
  512. package/dist/types.js +2 -0
  513. package/dist/types.js.map +1 -0
  514. package/dist/updater/types.d.ts +7 -0
  515. package/dist/updater/types.d.ts.map +1 -0
  516. package/dist/updater/types.js +2 -0
  517. package/dist/updater/types.js.map +1 -0
  518. package/dist/updater/updater.d.ts +14 -0
  519. package/dist/updater/updater.d.ts.map +1 -0
  520. package/dist/updater/updater.js +49 -0
  521. package/dist/updater/updater.js.map +1 -0
  522. package/dist/version/types.d.ts +5 -0
  523. package/dist/version/types.d.ts.map +1 -0
  524. package/dist/version/types.js +2 -0
  525. package/dist/version/types.js.map +1 -0
  526. package/dist/version/version.d.ts +3 -0
  527. package/dist/version/version.d.ts.map +1 -0
  528. package/dist/version/version.js +9 -0
  529. package/dist/version/version.js.map +1 -0
  530. package/dist/waitForStateInitialize.d.ts +2 -0
  531. package/dist/waitForStateInitialize.d.ts.map +1 -0
  532. package/dist/waitForStateInitialize.js +12 -0
  533. package/dist/waitForStateInitialize.js.map +1 -0
  534. package/dist/webComponent/MappingRule.d.ts +10 -0
  535. package/dist/webComponent/MappingRule.d.ts.map +1 -0
  536. package/dist/webComponent/MappingRule.js +120 -0
  537. package/dist/webComponent/MappingRule.js.map +1 -0
  538. package/dist/webComponent/bindWebComponent.d.ts +3 -0
  539. package/dist/webComponent/bindWebComponent.d.ts.map +1 -0
  540. package/dist/webComponent/bindWebComponent.js +49 -0
  541. package/dist/webComponent/bindWebComponent.js.map +1 -0
  542. package/dist/webComponent/completeWebComponent.d.ts +4 -0
  543. package/dist/webComponent/completeWebComponent.d.ts.map +1 -0
  544. package/dist/webComponent/completeWebComponent.js +17 -0
  545. package/dist/webComponent/completeWebComponent.js.map +1 -0
  546. package/dist/webComponent/innerState.d.ts +3 -0
  547. package/dist/webComponent/innerState.d.ts.map +1 -0
  548. package/dist/webComponent/innerState.js +120 -0
  549. package/dist/webComponent/innerState.js.map +1 -0
  550. package/dist/webComponent/lastValueByAbsoluteStateAddress.d.ts +4 -0
  551. package/dist/webComponent/lastValueByAbsoluteStateAddress.d.ts.map +1 -0
  552. package/dist/webComponent/lastValueByAbsoluteStateAddress.js +10 -0
  553. package/dist/webComponent/lastValueByAbsoluteStateAddress.js.map +1 -0
  554. package/dist/webComponent/meltFrozenObject.d.ts +2 -0
  555. package/dist/webComponent/meltFrozenObject.d.ts.map +1 -0
  556. package/dist/webComponent/meltFrozenObject.js +17 -0
  557. package/dist/webComponent/meltFrozenObject.js.map +1 -0
  558. package/dist/webComponent/outerState.d.ts +3 -0
  559. package/dist/webComponent/outerState.d.ts.map +1 -0
  560. package/dist/webComponent/outerState.js +41 -0
  561. package/dist/webComponent/outerState.js.map +1 -0
  562. package/dist/webComponent/plainOuterState.d.ts +3 -0
  563. package/dist/webComponent/plainOuterState.d.ts.map +1 -0
  564. package/dist/webComponent/plainOuterState.js +36 -0
  565. package/dist/webComponent/plainOuterState.js.map +1 -0
  566. package/dist/webComponent/stateElementByWebComponent.d.ts +4 -0
  567. package/dist/webComponent/stateElementByWebComponent.d.ts.map +1 -0
  568. package/dist/webComponent/stateElementByWebComponent.js +17 -0
  569. package/dist/webComponent/stateElementByWebComponent.js.map +1 -0
  570. package/dist/webComponent/types.d.ts +3 -0
  571. package/dist/webComponent/types.d.ts.map +1 -0
  572. package/dist/webComponent/types.js +2 -0
  573. package/dist/webComponent/types.js.map +1 -0
  574. package/package.json +70 -0
package/README.md ADDED
@@ -0,0 +1,1078 @@
1
+ # @wcstack/state
2
+
3
+ Declarative reactive state management for Web Components.
4
+ `<wcs-state>` custom element and `data-wcs` attribute binding — zero runtime dependencies.
5
+
6
+ ## Features
7
+
8
+ - **Declarative data binding** — `data-wcs` attribute for property / text / event / structural binding
9
+ - **Reactive Proxy** — ES Proxy-based automatic DOM updates with dependency tracking
10
+ - **Structural directives** — `for`, `if` / `elseif` / `else` via `<template>` elements
11
+ - **Built-in filters** — 40 filters for formatting, comparison, arithmetic, date, and more
12
+ - **Two-way binding** — automatic for `<input>`, `<select>`, `<textarea>`
13
+ - **Web Component binding** — bidirectional state binding with Shadow DOM components
14
+ - **Path getters** — dot-path key getters (`get "users.*.fullName"()`) for virtual properties at any depth in a data tree, all defined flat in one place with automatic dependency tracking and caching
15
+ - **Mustache syntax** — `{{ path|filter }}` in text nodes
16
+ - **Multiple state sources** — JSON, JS module, inline script, API, attribute
17
+ - **SVG support** — full binding support inside `<svg>` elements
18
+ - **Lifecycle hooks** — `$connectedCallback` / `$disconnectedCallback` / `$updatedCallback`, plus `$stateReadyCallback` for Web Components
19
+ - **Zero dependencies** — no runtime dependencies
20
+
21
+ ## Installation
22
+
23
+ ### CDN (recommended)
24
+
25
+ ```html
26
+ <!-- Auto-initialization — this is all you need -->
27
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@wcstack/state/dist/auto.js"></script>
28
+ ```
29
+
30
+ ### CDN (manual initialization)
31
+
32
+ ```html
33
+ <script type="module">
34
+ import { bootstrapState } from 'https://cdn.jsdelivr.net/npm/@wcstack/state/dist/index.esm.js';
35
+ bootstrapState();
36
+ </script>
37
+ ```
38
+
39
+ ## Basic Usage
40
+
41
+ ```html
42
+ <wcs-state>
43
+ <script type="module">
44
+ export default {
45
+ count: 0,
46
+ user: { id: 1, name: "Alice" },
47
+ users: [
48
+ { id: 1, name: "Alice" },
49
+ { id: 2, name: "Bob" },
50
+ { id: 3, name: "Charlie" }
51
+ ],
52
+ countUp() { this.count += 1; },
53
+ clearCount() { this.count = 0; },
54
+ get "users.*.displayName"() {
55
+ return this["users.*.name"] + " (ID: " + this["users.*.id"] + ")";
56
+ }
57
+ };
58
+ </script>
59
+ </wcs-state>
60
+
61
+ <!-- Text binding -->
62
+ <div data-wcs="textContent: count"></div>
63
+ {{ count }}
64
+
65
+ <!-- Two-way input binding -->
66
+ <input type="text" data-wcs="value: user.name">
67
+
68
+ <!-- Event binding -->
69
+ <button data-wcs="onclick: countUp">Increment</button>
70
+
71
+ <!-- Conditional class -->
72
+ <div data-wcs="textContent: count; class.over: count|gt(10)"></div>
73
+
74
+ <!-- Loop -->
75
+ <template data-wcs="for: users">
76
+ <div>
77
+ <span data-wcs="textContent: .id"></span>:
78
+ <span data-wcs="textContent: .displayName"></span>
79
+ </div>
80
+ </template>
81
+
82
+ <!-- Conditional rendering -->
83
+ <template data-wcs="if: count|gt(0)">
84
+ <p>The count is positive.</p>
85
+ </template>
86
+ <template data-wcs="elseif: count|lt(0)">
87
+ <p>The count is negative.</p>
88
+ </template>
89
+ <template data-wcs="else:">
90
+ <p>The count is zero.</p>
91
+ </template>
92
+ ```
93
+
94
+ ## State Initialization
95
+
96
+ `<wcs-state>` supports multiple ways to load initial state:
97
+
98
+ ```html
99
+ <!-- 1. Reference a <script type="application/json"> by id -->
100
+ <script type="application/json" id="state">
101
+ { "count": 0 }
102
+ </script>
103
+ <wcs-state state="state"></wcs-state>
104
+
105
+ <!-- 2. Inline JSON attribute -->
106
+ <wcs-state json='{ "count": 0 }'></wcs-state>
107
+
108
+ <!-- 3. External JSON file -->
109
+ <wcs-state src="./data.json"></wcs-state>
110
+
111
+ <!-- 4. External JS module (export default { ... }) -->
112
+ <wcs-state src="./state.js"></wcs-state>
113
+
114
+ <!-- 5. Inline script module -->
115
+ <wcs-state>
116
+ <script type="module">
117
+ export default { count: 0 };
118
+ </script>
119
+ </wcs-state>
120
+
121
+ <!-- 6. Programmatic API -->
122
+ <script>
123
+ const el = document.createElement('wcs-state');
124
+ el.setInitialState({ count: 0 });
125
+ document.body.appendChild(el);
126
+ </script>
127
+ ```
128
+
129
+ Resolution order: `state` → `src` (.json / .js) → `json` → inner `<script>` → wait for `setInitialState()`.
130
+
131
+ ### Named State
132
+
133
+ Multiple state elements can coexist with the `name` attribute. Bindings reference them with `@name`:
134
+
135
+ ```html
136
+ <wcs-state name="cart">...</wcs-state>
137
+ <wcs-state name="user">...</wcs-state>
138
+
139
+ <div data-wcs="textContent: total@cart"></div>
140
+ <div data-wcs="textContent: name@user"></div>
141
+ ```
142
+
143
+ Default name is `"default"` (no `@` needed).
144
+
145
+ ## Updating State
146
+
147
+ State changes are detected through **property assignment** (the Proxy `set` trap). To trigger reactive DOM updates, a value must be **assigned** to a state property.
148
+
149
+ ### Primitive and Object Properties
150
+
151
+ Direct property assignment is detected at any depth:
152
+
153
+ ```javascript
154
+ this.count = 10; // ✅ detected
155
+ this.user.name = "Bob"; // ✅ detected (nested assignment)
156
+ ```
157
+
158
+ ### Arrays
159
+
160
+ Array mutating methods (`push`, `splice`, `sort`, `reverse`, …) modify the array in place **without triggering a property assignment**, so the reactive system does not detect the change. Instead, use **non-destructive** methods that return a new array and assign the result:
161
+
162
+ ```javascript
163
+ // ✅ Non-destructive + assignment — change detected
164
+ this.items = this.items.concat({ id: 4, text: "New" });
165
+ this.items = this.items.toSpliced(index, 1);
166
+ this.items = this.items.filter(item => !item.done);
167
+ this.items = this.items.toSorted((a, b) => a.id - b.id);
168
+ this.items = this.items.toReversed();
169
+ this.items = this.items.with(index, newValue);
170
+
171
+ // ❌ Mutating — no assignment, change NOT detected
172
+ this.items.push({ id: 4, text: "New" });
173
+ this.items.splice(index, 1);
174
+ this.items.sort((a, b) => a.id - b.id);
175
+ ```
176
+
177
+ ## Binding Syntax
178
+
179
+ ### `data-wcs` Attribute
180
+
181
+ ```
182
+ property[#modifier]: path[@state][|filter[|filter(args)...]]
183
+ ```
184
+
185
+ Multiple bindings separated by `;`:
186
+
187
+ ```html
188
+ <div data-wcs="textContent: count; class.over: count|gt(10)"></div>
189
+ ```
190
+
191
+ | Part | Description | Example |
192
+ |---|---|---|
193
+ | `property` | DOM property to bind | `value`, `textContent`, `checked` |
194
+ | `#modifier` | Binding modifier | `#ro`, `#prevent`, `#stop`, `#onchange` |
195
+ | `path` | State property path | `count`, `user.name`, `users.*.name` |
196
+ | `@state` | Named state reference | `@cart`, `@user` |
197
+ | `\|filter` | Transform filter chain | `\|gt(0)`, `\|round\|locale` |
198
+
199
+ ### Property Types
200
+
201
+ | Property | Description |
202
+ |---|---|
203
+ | `value` | Element value (two-way for inputs) |
204
+ | `checked` | Checkbox / radio checked state (two-way) |
205
+ | `textContent` | Text content |
206
+ | `text` | Alias for textContent |
207
+ | `html` | innerHTML |
208
+ | `class.NAME` | Toggle a CSS class |
209
+ | `style.PROP` | Set a CSS style property |
210
+ | `attr.NAME` | Set an attribute (supports SVG namespace) |
211
+ | `radio` | Radio button group binding (two-way) |
212
+ | `checkbox` | Checkbox group binding to array (two-way) |
213
+ | `onclick`, `on*` | Event handler binding |
214
+
215
+ ### Modifiers
216
+
217
+ | Modifier | Description |
218
+ |---|---|
219
+ | `#ro` | Read-only — disables two-way binding |
220
+ | `#prevent` | Calls `event.preventDefault()` on event handlers |
221
+ | `#stop` | Calls `event.stopPropagation()` on event handlers |
222
+ | `#onchange` | Uses `change` event instead of `input` for two-way binding |
223
+
224
+ ### Two-Way Binding
225
+
226
+ Automatically enabled for:
227
+
228
+ | Element | Property | Event |
229
+ |---|---|---|
230
+ | `<input type="checkbox/radio">` | `checked` | `input` |
231
+ | `<input>` (other types) | `value`, `valueAsNumber`, `valueAsDate` | `input` |
232
+ | `<select>` | `value` | `change` |
233
+ | `<textarea>` | `value` | `input` |
234
+
235
+ `<input type="button">` is excluded. Use `#ro` to disable, `#onchange` to change the event.
236
+
237
+ ### Radio Binding
238
+
239
+ Bind a radio button group to a single state value with `radio`:
240
+
241
+ ```html
242
+ <input type="radio" value="red" data-wcs="radio: selectedColor">
243
+ <input type="radio" value="blue" data-wcs="radio: selectedColor">
244
+ ```
245
+
246
+ The radio button whose `value` matches the state value is automatically checked. When the user selects a different radio button, the state is updated. Use `#ro` for read-only.
247
+
248
+ Inside a `for` loop:
249
+
250
+ ```html
251
+ <template data-wcs="for: branches">
252
+ <label>
253
+ <input type="radio" data-wcs="value: .; radio: currentBranch">
254
+ {{ . }}
255
+ </label>
256
+ </template>
257
+ ```
258
+
259
+ ### Checkbox Binding
260
+
261
+ Bind a checkbox group to a state array with `checkbox`:
262
+
263
+ ```html
264
+ <input type="checkbox" value="apple" data-wcs="checkbox: selectedFruits">
265
+ <input type="checkbox" value="banana" data-wcs="checkbox: selectedFruits">
266
+ <input type="checkbox" value="orange" data-wcs="checkbox: selectedFruits">
267
+ ```
268
+
269
+ A checkbox is checked when its `value` is included in the state array. Toggling a checkbox adds or removes the value from the array. Use `|int` to convert string values to numbers, and `#ro` for read-only.
270
+
271
+ ### Mustache Syntax
272
+
273
+ When `enableMustache` is `true` (default), `{{ expression }}` in text nodes is supported:
274
+
275
+ ```html
276
+ <p>Hello, {{ user.name }}!</p>
277
+ <p>Count: {{ count|locale }}</p>
278
+ ```
279
+
280
+ Internally converted to comment-based bindings (`<!--@@:expression-->`).
281
+
282
+ ## Structural Directives
283
+
284
+ Structural directives use `<template>` elements:
285
+
286
+ ### Loop (`for`)
287
+
288
+ ```html
289
+ <template data-wcs="for: users">
290
+ <div>
291
+ <!-- Full path -->
292
+ <span data-wcs="textContent: users.*.name"></span>
293
+ <!-- Shorthand (relative to loop context) -->
294
+ <span data-wcs="textContent: .name"></span>
295
+ </div>
296
+ </template>
297
+ ```
298
+
299
+ #### Dot Shorthand
300
+
301
+ Inside a `for` loop, paths starting with `.` are expanded relative to the loop's array path:
302
+
303
+ | Shorthand | Expanded to | Description |
304
+ |---|---|---|
305
+ | `.name` | `users.*.name` | Property of the current element |
306
+ | `.` | `users.*` | The current element itself |
307
+ | `.name\|uc` | `users.*.name\|uc` | Filters are preserved |
308
+ | `.name@state` | `users.*.name@state` | State name is preserved |
309
+
310
+ For primitive arrays, `.` refers to the element value directly:
311
+
312
+ ```html
313
+ <template data-wcs="for: branches">
314
+ <label>
315
+ <input type="radio" data-wcs="value: .; radio: currentBranch">
316
+ {{ . }}
317
+ </label>
318
+ </template>
319
+ ```
320
+
321
+ Nested loops are supported with multi-level wildcards. The `.` shorthand in nested `for` directives also expands relative to the parent loop path:
322
+
323
+ ```html
324
+ <template data-wcs="for: regions">
325
+ <!-- .states → regions.*.states -->
326
+ <template data-wcs="for: .states">
327
+ <!-- .name → regions.*.states.*.name -->
328
+ <span data-wcs="textContent: .name"></span>
329
+ </template>
330
+ </template>
331
+ ```
332
+
333
+ ### Conditional (`if` / `elseif` / `else`)
334
+
335
+ ```html
336
+ <template data-wcs="if: count|gt(0)">
337
+ <p>Positive</p>
338
+ </template>
339
+ <template data-wcs="elseif: count|lt(0)">
340
+ <p>Negative</p>
341
+ </template>
342
+ <template data-wcs="else:">
343
+ <p>Zero</p>
344
+ </template>
345
+ ```
346
+
347
+ Conditions can be chained. `elseif` automatically inverts the previous condition.
348
+
349
+ ## Path Getters (Computed Properties)
350
+
351
+ **Path getters** are the core feature of `@wcstack/state`. Define computed properties using JavaScript getters with **dot-path string keys** containing wildcards (`*`). They act as **virtual properties that can be attached at any depth in a data tree — all defined flat in one place**. No matter how deeply data is nested, path getters keep definitions at the same level with automatic dependency tracking per loop element.
352
+
353
+ ### Basic Path Getter
354
+
355
+ ```html
356
+ <wcs-state>
357
+ <script type="module">
358
+ export default {
359
+ users: [
360
+ { id: 1, firstName: "Alice", lastName: "Smith" },
361
+ { id: 2, firstName: "Bob", lastName: "Jones" }
362
+ ],
363
+ // Path getter — runs per-element inside a loop
364
+ get "users.*.fullName"() {
365
+ return this["users.*.firstName"] + " " + this["users.*.lastName"];
366
+ },
367
+ get "users.*.displayName"() {
368
+ return this["users.*.fullName"] + " (ID: " + this["users.*.id"] + ")";
369
+ }
370
+ };
371
+ </script>
372
+ </wcs-state>
373
+
374
+ <template data-wcs="for: users">
375
+ <div data-wcs="textContent: .displayName"></div>
376
+ </template>
377
+ <!-- Output:
378
+ Alice Smith (ID: 1)
379
+ Bob Jones (ID: 2)
380
+ -->
381
+ ```
382
+
383
+ Inside a path getter, `this["users.*.firstName"]` automatically resolves to the current loop element — no manual indexing needed.
384
+
385
+ ### Top-Level Computed Properties
386
+
387
+ Getters without wildcards work as standard computed properties:
388
+
389
+ ```javascript
390
+ export default {
391
+ price: 100,
392
+ tax: 0.1,
393
+ get total() {
394
+ return this.price * (1 + this.tax);
395
+ }
396
+ };
397
+ ```
398
+
399
+ ### Getter Chaining
400
+
401
+ Path getters can reference other path getters, forming a dependency chain. The cache is automatically invalidated when any upstream value changes:
402
+
403
+ ```html
404
+ <wcs-state>
405
+ <script type="module">
406
+ export default {
407
+ taxRate: 0.1,
408
+ cart: {
409
+ items: [
410
+ { productId: "P001", quantity: 2, unitPrice: 500 },
411
+ { productId: "P002", quantity: 1, unitPrice: 1200 }
412
+ ]
413
+ },
414
+ // Per-item subtotal
415
+ get "cart.items.*.subtotal"() {
416
+ return this["cart.items.*.unitPrice"] * this["cart.items.*.quantity"];
417
+ },
418
+ // Aggregate: sum of all subtotals
419
+ get "cart.totalPrice"() {
420
+ return this.$getAll("cart.items.*.subtotal", []).reduce((sum, v) => sum + v, 0);
421
+ },
422
+ // Chained: tax derived from totalPrice
423
+ get "cart.tax"() {
424
+ return this["cart.totalPrice"] * this.taxRate;
425
+ },
426
+ // Chained: grand total
427
+ get "cart.grandTotal"() {
428
+ return this["cart.totalPrice"] + this["cart.tax"];
429
+ }
430
+ };
431
+ </script>
432
+ </wcs-state>
433
+
434
+ <template data-wcs="for: cart.items">
435
+ <div>
436
+ <span data-wcs="textContent: .productId"></span>:
437
+ <span data-wcs="textContent: .subtotal|locale"></span>
438
+ </div>
439
+ </template>
440
+ <p>Total: <span data-wcs="textContent: cart.totalPrice|locale"></span></p>
441
+ <p>Tax: <span data-wcs="textContent: cart.tax|locale"></span></p>
442
+ <p>Grand Total: <span data-wcs="textContent: cart.grandTotal|locale"></span></p>
443
+ ```
444
+
445
+ Dependency chain: `cart.grandTotal` → `cart.tax` → `cart.totalPrice` → `cart.items.*.subtotal` → `cart.items.*.unitPrice` / `cart.items.*.quantity`. Changing any item's `unitPrice` or `quantity` automatically recomputes the entire chain.
446
+
447
+ ### Nested Wildcard Getters
448
+
449
+ Multiple wildcards are supported for nested array structures:
450
+
451
+ ```html
452
+ <wcs-state>
453
+ <script type="module">
454
+ export default {
455
+ categories: [
456
+ {
457
+ name: "Fruits",
458
+ items: [
459
+ { name: "Apple", price: 150 },
460
+ { name: "Banana", price: 100 }
461
+ ]
462
+ },
463
+ {
464
+ name: "Vegetables",
465
+ items: [
466
+ { name: "Carrot", price: 80 }
467
+ ]
468
+ }
469
+ ],
470
+ get "categories.*.items.*.label"() {
471
+ return this["categories.*.name"] + " / " + this["categories.*.items.*.name"];
472
+ }
473
+ };
474
+ </script>
475
+ </wcs-state>
476
+
477
+ <template data-wcs="for: categories">
478
+ <h3 data-wcs="textContent: .name"></h3>
479
+ <template data-wcs="for: .items">
480
+ <div data-wcs="textContent: .label"></div>
481
+ </template>
482
+ </template>
483
+ <!-- Output:
484
+ Fruits
485
+ Fruits / Apple
486
+ Fruits / Banana
487
+ Vegetables
488
+ Vegetables / Carrot
489
+ -->
490
+ ```
491
+
492
+ ### Flat Virtual Properties Across Any Depth
493
+
494
+ A key advantage of path getters is that **no matter how deeply data is nested, all virtual properties are defined flat in one place**. This eliminates the need to split components just to hold computed properties at each nesting level.
495
+
496
+ ```javascript
497
+ export default {
498
+ regions: [
499
+ { name: "Kanto", prefectures: [
500
+ { name: "Tokyo", cities: [
501
+ { name: "Shibuya", population: 230000, area: 15.11 },
502
+ { name: "Shinjuku", population: 346000, area: 18.22 }
503
+ ]},
504
+ { name: "Kanagawa", cities: [
505
+ { name: "Yokohama", population: 3750000, area: 437.56 }
506
+ ]}
507
+ ]}
508
+ ],
509
+
510
+ // --- All flat, regardless of nesting depth ---
511
+
512
+ // City level — virtual properties
513
+ get "regions.*.prefectures.*.cities.*.density"() {
514
+ return this["regions.*.prefectures.*.cities.*.population"]
515
+ / this["regions.*.prefectures.*.cities.*.area"];
516
+ },
517
+ get "regions.*.prefectures.*.cities.*.label"() {
518
+ return this["regions.*.prefectures.*.name"] + " "
519
+ + this["regions.*.prefectures.*.cities.*.name"];
520
+ },
521
+
522
+ // Prefecture level — aggregate from cities
523
+ get "regions.*.prefectures.*.totalPopulation"() {
524
+ return this.$getAll("regions.*.prefectures.*.cities.*.population", [])
525
+ .reduce((a, b) => a + b, 0);
526
+ },
527
+
528
+ // Region level — aggregate from prefectures
529
+ get "regions.*.totalPopulation"() {
530
+ return this.$getAll("regions.*.prefectures.*.totalPopulation", [])
531
+ .reduce((a, b) => a + b, 0);
532
+ },
533
+
534
+ // Top level — aggregate from regions
535
+ get totalPopulation() {
536
+ return this.$getAll("regions.*.totalPopulation", [])
537
+ .reduce((a, b) => a + b, 0);
538
+ }
539
+ };
540
+ ```
541
+
542
+ Three levels of nesting, five virtual properties — all defined side by side in a single flat object. Each level can reference values from any depth, and aggregation flows naturally from bottom to top via `$getAll`. In component-based frameworks (React, Vue), achieving the same requires creating a separate component for each nesting level, with props drilling or state management to pass computed values up the tree.
543
+
544
+ ### Accessing Sub-Properties of Getter Results
545
+
546
+ When a path getter returns an object, you can access its sub-properties via dot-path:
547
+
548
+ ```javascript
549
+ export default {
550
+ products: [
551
+ { id: "P001", name: "Widget", price: 500, stock: 10 },
552
+ { id: "P002", name: "Gadget", price: 1200, stock: 3 }
553
+ ],
554
+ cart: {
555
+ items: [
556
+ { productId: "P001", quantity: 2 },
557
+ { productId: "P002", quantity: 1 }
558
+ ]
559
+ },
560
+ get productByProductId() {
561
+ return new Map(this.products.map(p => [p.id, p]));
562
+ },
563
+ // Returns the full product object
564
+ get "cart.items.*.product"() {
565
+ return this.productByProductId.get(this["cart.items.*.productId"]);
566
+ },
567
+ // Access sub-property of the returned object
568
+ get "cart.items.*.total"() {
569
+ return this["cart.items.*.product.price"] * this["cart.items.*.quantity"];
570
+ }
571
+ };
572
+ ```
573
+
574
+ `this["cart.items.*.product.price"]` transparently chains through the object returned by the `cart.items.*.product` getter.
575
+
576
+ ### Path Setters
577
+
578
+ Custom setter logic can be defined with `set "path"()`:
579
+
580
+ ```javascript
581
+ export default {
582
+ users: [
583
+ { firstName: "Alice", lastName: "Smith" },
584
+ { firstName: "Bob", lastName: "Jones" }
585
+ ],
586
+ get "users.*.fullName"() {
587
+ return this["users.*.firstName"] + " " + this["users.*.lastName"];
588
+ },
589
+ set "users.*.fullName"(value) {
590
+ const [first, ...rest] = value.split(" ");
591
+ this["users.*.firstName"] = first;
592
+ this["users.*.lastName"] = rest.join(" ");
593
+ }
594
+ };
595
+ ```
596
+
597
+ ```html
598
+ <template data-wcs="for: users">
599
+ <input type="text" data-wcs="value: .fullName">
600
+ </template>
601
+ ```
602
+
603
+ Two-way binding works with path setters — editing the input calls the setter, which splits and writes back to `firstName` / `lastName`.
604
+
605
+ ### Supported Path Getter Patterns
606
+
607
+ | Pattern | Description | Example |
608
+ |---|---|---|
609
+ | `get prop()` | Top-level computed | `get total()` |
610
+ | `get "a.b"()` | Nested computed (no wildcard) | `get "cart.totalPrice"()` |
611
+ | `get "a.*.b"()` | Single wildcard | `get "users.*.fullName"()` |
612
+ | `get "a.*.b.*.c"()` | Multiple wildcards | `get "categories.*.items.*.label"()` |
613
+ | `set "a.*.b"(v)` | Wildcard setter | `set "users.*.fullName"(v)` |
614
+
615
+ ### How It Works
616
+
617
+ 1. **Context resolution** — When a `for:` loop renders, each iteration pushes a `ListIndex` onto the address stack. Inside a path getter, `this["users.*.name"]` resolves the `*` using this stack, so it always points to the current element.
618
+
619
+ 2. **Automatic dependency tracking** — When a getter accesses `this["users.*.name"]`, the system registers a dynamic dependency from `users.*.name` to the getter's path. When `users.*.name` changes, the getter's cache is dirtied.
620
+
621
+ 3. **Caching** — Getter results are cached per concrete address (path + loop index). `users.*.fullName` at index 0 has a separate cache entry from index 1. The cache is invalidated only when dependencies change.
622
+
623
+ 4. **Direct index access** — You can also access specific elements by numeric index: `this["users.0.name"]` resolves as `users[0].name` without needing loop context.
624
+
625
+ ### Loop Index Variables (`$1`, `$2`, ...)
626
+
627
+ Inside getters and event handlers, `this.$1`, `this.$2`, etc. provide the current loop iteration index (0-based value, 1-based naming):
628
+
629
+ ```javascript
630
+ export default {
631
+ users: ["Alice", "Bob", "Charlie"],
632
+ get "users.*.rowLabel"() {
633
+ return "#" + (this.$1 + 1) + ": " + this["users.*"];
634
+ }
635
+ };
636
+ ```
637
+
638
+ ```html
639
+ <template data-wcs="for: users">
640
+ <div data-wcs="textContent: .rowLabel"></div>
641
+ </template>
642
+ <!-- Output:
643
+ #1: Alice
644
+ #2: Bob
645
+ #3: Charlie
646
+ -->
647
+ ```
648
+
649
+ For nested loops, `$1` is the outer index and `$2` is the inner index.
650
+
651
+ You can also display the loop index directly in templates:
652
+
653
+ ```html
654
+ <template data-wcs="for: items">
655
+ <td>{{ $1|inc(1) }}</td> <!-- 1-based row number -->
656
+ </template>
657
+ ```
658
+
659
+ ### Proxy APIs
660
+
661
+ Inside state objects (getters / methods), the following APIs are available via `this`:
662
+
663
+ | API | Description |
664
+ |---|---|
665
+ | `this.$getAll(path, indexes?)` | Get all values matching a wildcard path |
666
+ | `this.$resolve(path, indexes, value?)` | Resolve a wildcard path with specific indexes |
667
+ | `this.$postUpdate(path)` | Manually trigger update notification for a path |
668
+ | `this.$trackDependency(path)` | Manually register a dependency for cache invalidation |
669
+ | `this.$stateElement` | Access to the `IStateElement` instance |
670
+ | `this.$1`, `this.$2`, ... | Current loop index (1-based naming, 0-based value) |
671
+
672
+ #### `$getAll` — Aggregate Across Array Elements
673
+
674
+ `$getAll` collects all values that match a wildcard path, returning them as an array. Essential for aggregation patterns:
675
+
676
+ ```javascript
677
+ export default {
678
+ scores: [85, 92, 78, 95, 88],
679
+ get average() {
680
+ const all = this.$getAll("scores.*", []);
681
+ return all.reduce((sum, v) => sum + v, 0) / all.length;
682
+ },
683
+ get max() {
684
+ return Math.max(...this.$getAll("scores.*", []));
685
+ }
686
+ };
687
+ ```
688
+
689
+ #### `$resolve` — Access by Explicit Index
690
+
691
+ `$resolve` reads or writes a value at a specific wildcard index:
692
+
693
+ ```javascript
694
+ export default {
695
+ items: ["A", "B", "C"],
696
+ swapFirstTwo() {
697
+ const a = this.$resolve("items.*", [0]);
698
+ const b = this.$resolve("items.*", [1]);
699
+ this.$resolve("items.*", [0], b);
700
+ this.$resolve("items.*", [1], a);
701
+ }
702
+ };
703
+ ```
704
+
705
+ ## Event Handling
706
+
707
+ Bind event handlers with `on*` properties:
708
+
709
+ ```html
710
+ <button data-wcs="onclick: handleClick">Click me</button>
711
+ <form data-wcs="onsubmit#prevent: handleSubmit">...</form>
712
+ ```
713
+
714
+ Handler methods receive the event and loop indexes:
715
+
716
+ ```javascript
717
+ export default {
718
+ items: ["A", "B", "C"],
719
+ handleClick(event) {
720
+ console.log("clicked");
721
+ },
722
+ removeItem(event, index) {
723
+ // index is the loop context ($1)
724
+ this.items = this.items.toSpliced(index, 1);
725
+ }
726
+ };
727
+ ```
728
+
729
+ ```html
730
+ <template data-wcs="for: items">
731
+ <button data-wcs="onclick: removeItem">Delete</button>
732
+ </template>
733
+ ```
734
+
735
+ ## Filters
736
+
737
+ 40 built-in filters are available for both input (DOM → state) and output (state → DOM) directions.
738
+
739
+ ### Comparison
740
+
741
+ | Filter | Description | Example |
742
+ |---|---|---|
743
+ | `eq(value)` | Equal | `count\|eq(0)` → `true/false` |
744
+ | `ne(value)` | Not equal | `count\|ne(0)` |
745
+ | `not` | Boolean NOT | `isActive\|not` |
746
+ | `lt(n)` | Less than | `count\|lt(10)` |
747
+ | `le(n)` | Less than or equal | `count\|le(10)` |
748
+ | `gt(n)` | Greater than | `count\|gt(0)` |
749
+ | `ge(n)` | Greater than or equal | `count\|ge(0)` |
750
+
751
+ ### Arithmetic
752
+
753
+ | Filter | Description | Example |
754
+ |---|---|---|
755
+ | `inc(n)` | Add | `count\|inc(1)` |
756
+ | `dec(n)` | Subtract | `count\|dec(1)` |
757
+ | `mul(n)` | Multiply | `price\|mul(1.1)` |
758
+ | `div(n)` | Divide | `total\|div(100)` |
759
+ | `mod(n)` | Modulo | `index\|mod(2)` |
760
+
761
+ ### Number Formatting
762
+
763
+ | Filter | Description | Example |
764
+ |---|---|---|
765
+ | `fix(n)` | Fixed decimal places | `price\|fix(2)` → `"100.00"` |
766
+ | `round(n?)` | Round | `value\|round(2)` |
767
+ | `floor(n?)` | Floor | `value\|floor` |
768
+ | `ceil(n?)` | Ceiling | `value\|ceil` |
769
+ | `locale(loc?)` | Locale number format | `count\|locale` / `count\|locale(ja-JP)` |
770
+ | `percent(n?)` | Percentage format | `ratio\|percent(1)` |
771
+
772
+ ### String
773
+
774
+ | Filter | Description | Example |
775
+ |---|---|---|
776
+ | `uc` | Upper case | `name\|uc` |
777
+ | `lc` | Lower case | `name\|lc` |
778
+ | `cap` | Capitalize | `name\|cap` |
779
+ | `trim` | Trim whitespace | `text\|trim` |
780
+ | `slice(n)` | Slice string | `text\|slice(5)` |
781
+ | `substr(start, length)` | Substring | `text\|substr(0,10)` |
782
+ | `pad(n, char?)` | Pad start | `id\|pad(5,0)` → `"00001"` |
783
+ | `rep(n)` | Repeat | `text\|rep(3)` |
784
+ | `rev` | Reverse | `text\|rev` |
785
+
786
+ ### Type Conversion
787
+
788
+ | Filter | Description | Example |
789
+ |---|---|---|
790
+ | `int` | Parse integer | `input\|int` |
791
+ | `float` | Parse float | `input\|float` |
792
+ | `boolean` | To boolean | `value\|boolean` |
793
+ | `number` | To number | `value\|number` |
794
+ | `string` | To string | `value\|string` |
795
+ | `null` | To null | `value\|null` |
796
+
797
+ ### Date / Time
798
+
799
+ | Filter | Description | Example |
800
+ |---|---|---|
801
+ | `date(loc?)` | Date format | `timestamp\|date` / `timestamp\|date(ja-JP)` |
802
+ | `time(loc?)` | Time format | `timestamp\|time` |
803
+ | `datetime(loc?)` | Date + Time | `timestamp\|datetime(en-US)` |
804
+ | `ymd(sep?)` | YYYY-MM-DD | `timestamp\|ymd` / `timestamp\|ymd(/)` |
805
+
806
+ ### Boolean / Default
807
+
808
+ | Filter | Description | Example |
809
+ |---|---|---|
810
+ | `truthy` | Truthy check | `value\|truthy` |
811
+ | `falsy` | Falsy check | `value\|falsy` |
812
+ | `defaults(v)` | Fallback value | `name\|defaults(Anonymous)` |
813
+
814
+ ### Filter Chaining
815
+
816
+ Filters can be chained with `|`:
817
+
818
+ ```html
819
+ <div data-wcs="textContent: price|mul(1.1)|round(2)|locale(ja-JP)"></div>
820
+ ```
821
+
822
+ ## Web Component Binding
823
+
824
+ `@wcstack/state` supports bidirectional state binding with custom elements using Shadow DOM or Light DOM.
825
+
826
+ ### Component Definition (Shadow DOM)
827
+
828
+ ```javascript
829
+ class MyComponent extends HTMLElement {
830
+ state = { message: "" };
831
+
832
+ constructor() {
833
+ super();
834
+ this.attachShadow({ mode: "open" });
835
+ this.shadowRoot.innerHTML = `
836
+ <wcs-state bind-component="state"></wcs-state>
837
+ <div>{{ message }}</div>
838
+ <input type="text" data-wcs="value: message" />
839
+ `;
840
+ }
841
+ }
842
+ customElements.define("my-component", MyComponent);
843
+ ```
844
+
845
+ ### Component Definition (Light DOM)
846
+
847
+ Light DOM components do not use Shadow DOM. The state namespace is shared with the parent scope (just like CSS), so a `name` attribute is required.
848
+
849
+ ```javascript
850
+ class MyLightComponent extends HTMLElement {
851
+ state = { message: "" };
852
+
853
+ connectedCallback() {
854
+ this.innerHTML = `
855
+ <wcs-state bind-component="state" name="my-light"></wcs-state>
856
+ <div data-wcs="text: message@my-light"></div>
857
+ <input type="text" data-wcs="value: message@my-light" />
858
+ `;
859
+ }
860
+ }
861
+ customElements.define("my-light-component", MyLightComponent);
862
+ ```
863
+
864
+ - `name` attribute is **required** for Light DOM components (namespace is shared with the parent scope)
865
+ - Bindings must explicitly reference the state name with `@my-light`
866
+ - `<wcs-state>` must be a direct child of the component element
867
+
868
+ ### Host Usage
869
+
870
+ ```html
871
+ <wcs-state>
872
+ <script type="module">
873
+ export default {
874
+ user: { name: "Alice" }
875
+ };
876
+ </script>
877
+ </wcs-state>
878
+
879
+ <!-- Bind component's state.message to outer user.name -->
880
+ <my-component data-wcs="state.message: user.name"></my-component>
881
+ ```
882
+
883
+ - `bind-component="state"` maps the component's `state` property to `<wcs-state>`
884
+ - `data-wcs="state.message: user.name"` on the host element binds outer state paths to inner component state properties
885
+ - Changes propagate bidirectionally between the component and the outer state
886
+
887
+ ### Standalone Web Component Injection (`__e2e__/single-component`)
888
+
889
+ Even when a component is independent from outer host state, you can inject reactive state with `bind-component`.
890
+
891
+ ```javascript
892
+ class MyComponent extends HTMLElement {
893
+ state = Object.freeze({
894
+ message: "Hello, World!"
895
+ });
896
+
897
+ constructor() {
898
+ super();
899
+ this.attachShadow({ mode: "open" });
900
+ }
901
+
902
+ connectedCallback() {
903
+ this.shadowRoot.innerHTML = `
904
+ <wcs-state bind-component="state"></wcs-state>
905
+ <div>{{ message }}</div>
906
+ `;
907
+ }
908
+
909
+ async $stateReadyCallback(stateProp) {
910
+ console.log("state ready:", stateProp); // "state"
911
+ }
912
+ }
913
+ customElements.define("my-component", MyComponent);
914
+ ```
915
+
916
+ - Initial component `state` can be defined with `Object.freeze(...)` (it is replaced with a writable reactive state after injection)
917
+ - `bind-component="state"` exposes `this.state` as a state proxy powered by `@wcstack/state`
918
+ - Assignments like `this.state.message = "..."` immediately update `{{ message }}` inside Shadow DOM
919
+ - `async $stateReadyCallback(stateProp)` is called right after component state becomes ready for use (`stateProp` is the property name from `bind-component`)
920
+
921
+ ### Constraints
922
+
923
+ - `<wcs-state>` with `bind-component` must be a **direct child** of the component element (top-level)
924
+ - The parent element must be a **custom element** (tag name containing a hyphen)
925
+ - Light DOM components **require** a `name` attribute to avoid namespace conflicts with the parent scope
926
+ - Light DOM bindings must reference the state name explicitly (e.g., `@my-light`)
927
+
928
+ ### Loop with Components
929
+
930
+ ```html
931
+ <template data-wcs="for: users">
932
+ <my-component data-wcs="state.message: .name"></my-component>
933
+ </template>
934
+ ```
935
+
936
+ ## SVG Support
937
+
938
+ All bindings work inside `<svg>` elements. Use `attr.*` for SVG attributes:
939
+
940
+ ```html
941
+ <svg width="200" height="100">
942
+ <template data-wcs="for: points">
943
+ <circle data-wcs="attr.cx: .x; attr.cy: .y; attr.fill: .color" r="5" />
944
+ </template>
945
+ </svg>
946
+ ```
947
+
948
+ ## Lifecycle Hooks
949
+
950
+ State objects can define `$connectedCallback`, `$disconnectedCallback`, and `$updatedCallback` for initialization, cleanup, and update lifecycle handling.
951
+
952
+ ```html
953
+ <wcs-state>
954
+ <script type="module">
955
+ export default {
956
+ timer: null,
957
+ count: 0,
958
+
959
+ // Called when <wcs-state> is connected to the DOM (supports async)
960
+ async $connectedCallback() {
961
+ const res = await fetch("/api/initial-count");
962
+ this.count = await res.json();
963
+ this.timer = setInterval(() => { this.count++; }, 1000);
964
+ },
965
+
966
+ // Called when <wcs-state> is disconnected from the DOM (sync only)
967
+ $disconnectedCallback() {
968
+ clearInterval(this.timer);
969
+ }
970
+ };
971
+ </script>
972
+ </wcs-state>
973
+ ```
974
+
975
+ | Hook | Timing | Async |
976
+ |---|---|---|
977
+ | `$connectedCallback` | After state initialization on first connect; on every reconnect thereafter | Yes (`async` supported) |
978
+ | `$disconnectedCallback` | When the element is removed from the DOM | No (sync only) |
979
+ | `$updatedCallback(paths, indexesListByPath)` | After state updates are applied | Return value is ignored (not awaited) |
980
+
981
+ - `this` inside hooks is the state proxy with full read/write access
982
+ - `$connectedCallback` is called **every time** the element is connected (including re-insertion after removal), making it suitable for setup that should be re-established
983
+ - `$disconnectedCallback` is called synchronously — use it for cleanup such as clearing timers, removing event listeners, or releasing resources
984
+ - `$updatedCallback(paths, indexesListByPath)` receives the updated path list. For wildcard updates, `indexesListByPath` contains the updated index sets
985
+ - In Web Components, define `async $stateReadyCallback(stateProp)` to receive a hook when the bound state becomes available via `bind-component`
986
+
987
+ ## Configuration
988
+
989
+ Pass a partial configuration object to `bootstrapState()`:
990
+
991
+ ```javascript
992
+ import { bootstrapState } from '@wcstack/state';
993
+
994
+ bootstrapState({
995
+ locale: 'ja-JP',
996
+ debug: true,
997
+ enableMustache: false,
998
+ tagNames: { state: 'my-state' },
999
+ });
1000
+ ```
1001
+
1002
+ All options with defaults:
1003
+
1004
+ | Option | Default | Description |
1005
+ |---|---|---|
1006
+ | `bindAttributeName` | `'data-wcs'` | Binding attribute name |
1007
+ | `tagNames.state` | `'wcs-state'` | State element tag name |
1008
+ | `locale` | `'en'` | Default locale for filters |
1009
+ | `debug` | `false` | Debug mode |
1010
+ | `enableMustache` | `true` | Enable `{{ }}` syntax |
1011
+
1012
+ ## API Reference
1013
+
1014
+ ### `bootstrapState()`
1015
+
1016
+ Initialize the state system. Registers `<wcs-state>` custom element and sets up DOM content loaded handler.
1017
+
1018
+ ```javascript
1019
+ import { bootstrapState } from '@wcstack/state';
1020
+ bootstrapState();
1021
+ ```
1022
+
1023
+ ### `<wcs-state>` Element
1024
+
1025
+ | Attribute | Description |
1026
+ |---|---|
1027
+ | `name` | State name (default: `"default"`) |
1028
+ | `state` | ID of a `<script type="application/json">` element |
1029
+ | `src` | URL to `.json` or `.js` file |
1030
+ | `json` | Inline JSON string |
1031
+ | `bind-component` | Property name for web component binding |
1032
+
1033
+ ### IStateElement
1034
+
1035
+ | Property / Method | Description |
1036
+ |---|---|
1037
+ | `name` | State name |
1038
+ | `initializePromise` | Resolves when state is fully initialized |
1039
+ | `listPaths` | Set of paths used in `for` loops |
1040
+ | `getterPaths` | Set of paths defined as getters |
1041
+ | `setterPaths` | Set of paths defined as setters |
1042
+ | `createState(mutability, callback)` | Create a state proxy (`"readonly"` or `"writable"`) |
1043
+ | `createStateAsync(mutability, callback)` | Async version of `createState` |
1044
+ | `setInitialState(state)` | Set state programmatically (before initialization) |
1045
+ | `bindProperty(prop, descriptor)` | Define a property on the raw state object |
1046
+ | `nextVersion()` | Increment and return version number |
1047
+
1048
+ ## Architecture
1049
+
1050
+ ```
1051
+ bootstrapState()
1052
+ ├── registerComponents() // Register <wcs-state> custom element
1053
+ └── registerHandler() // DOMContentLoaded handler
1054
+ ├── waitForStateInitialize() // Wait for all <wcs-state> to load
1055
+ ├── convertMustacheToComments() // {{ }} → comment nodes
1056
+ ├── collectStructuralFragments() // Collect for/if templates
1057
+ └── initializeBindings() // Walk DOM, parse data-wcs, set up bindings
1058
+ ```
1059
+
1060
+ ### Reactivity Flow
1061
+
1062
+ 1. State changes via Proxy `set` trap → `setByAddress()`
1063
+ 2. Address resolved → updater enqueues absolute address
1064
+ 3. Dependency walker invalidates (dirties) downstream caches
1065
+ 4. Updater applies changes to bound DOM nodes via `applyChangeFromBindings()`
1066
+
1067
+ ### State Address System
1068
+
1069
+ Paths like `users.*.name` are decomposed into:
1070
+
1071
+ - **PathInfo** — static path metadata (segments, wildcard count, parent path)
1072
+ - **ListIndex** — runtime loop index chain
1073
+ - **StateAddress** — combination of PathInfo + ListIndex
1074
+ - **AbsoluteStateAddress** — state name + StateAddress (for cross-state references)
1075
+
1076
+ ## License
1077
+
1078
+ MIT