native-document 1.0.165 → 1.0.168

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 (488) hide show
  1. package/.vitepress/config.js +166 -0
  2. package/CHANGELOG.md +153 -0
  3. package/components.d.ts +2 -0
  4. package/components.js +2 -1
  5. package/devtools/widget.js +1 -1
  6. package/dist/native-document.components.min.js +11589 -2983
  7. package/dist/native-document.dev.js +2280 -396
  8. package/dist/native-document.dev.js.map +1 -1
  9. package/dist/native-document.min.js +1 -1
  10. package/docs/advanced-components.md +213 -608
  11. package/docs/anchor.md +173 -312
  12. package/docs/cache.md +95 -803
  13. package/docs/cli.md +179 -0
  14. package/docs/components/accordion.md +172 -0
  15. package/docs/components/alert.md +99 -0
  16. package/docs/components/avatar.md +160 -0
  17. package/docs/components/badge.md +102 -0
  18. package/docs/components/breadcrumb.md +89 -0
  19. package/docs/components/button.md +183 -0
  20. package/docs/components/card.md +69 -0
  21. package/docs/components/context-menu.md +118 -0
  22. package/docs/components/data-table.md +345 -0
  23. package/docs/components/dropdown.md +214 -0
  24. package/docs/components/form/autocomplete-field.md +81 -0
  25. package/docs/components/form/checkbox-field.md +41 -0
  26. package/docs/components/form/checkbox-group-field.md +54 -0
  27. package/docs/components/form/color-field.md +64 -0
  28. package/docs/components/form/date-field.md +92 -0
  29. package/docs/components/form/field-collection.md +63 -0
  30. package/docs/components/form/file-field.md +203 -0
  31. package/docs/components/form/form-control.md +87 -0
  32. package/docs/components/form/image-field.md +90 -0
  33. package/docs/components/form/index.md +115 -0
  34. package/docs/components/form/number-field.md +65 -0
  35. package/docs/components/form/radio-field.md +51 -0
  36. package/docs/components/form/select-field.md +123 -0
  37. package/docs/components/form/slider.md +136 -0
  38. package/docs/components/form/string-field.md +134 -0
  39. package/docs/components/form/textarea-field.md +65 -0
  40. package/docs/components/form-fields.md +372 -0
  41. package/docs/components/getting-started.md +264 -0
  42. package/docs/components/index.md +337 -0
  43. package/docs/components/layout.md +279 -0
  44. package/docs/components/list.md +73 -0
  45. package/docs/components/menu.md +215 -0
  46. package/docs/components/modal.md +156 -0
  47. package/docs/components/pagination.md +95 -0
  48. package/docs/components/popover.md +131 -0
  49. package/docs/components/progress.md +111 -0
  50. package/docs/components/shortcut-manager.md +221 -0
  51. package/docs/components/simple-table.md +107 -0
  52. package/docs/components/skeleton.md +155 -0
  53. package/docs/components/spinner.md +100 -0
  54. package/docs/components/splitter.md +133 -0
  55. package/docs/components/stepper.md +163 -0
  56. package/docs/components/switch.md +113 -0
  57. package/docs/components/tabs.md +153 -0
  58. package/docs/components/toast.md +119 -0
  59. package/docs/components/tooltip.md +151 -0
  60. package/docs/components/traits.md +261 -0
  61. package/docs/conditional-rendering.md +170 -588
  62. package/docs/contributing.md +300 -25
  63. package/docs/core-concepts.md +205 -374
  64. package/docs/elements.md +251 -367
  65. package/docs/extending-native-document-element.md +192 -207
  66. package/docs/filters.md +153 -1122
  67. package/docs/getting-started.md +193 -267
  68. package/docs/i18n.md +241 -0
  69. package/docs/index.md +76 -0
  70. package/docs/lifecycle-events.md +143 -75
  71. package/docs/list-rendering.md +227 -852
  72. package/docs/memory-management.md +134 -47
  73. package/docs/native-document-element.md +337 -186
  74. package/docs/native-fetch.md +99 -630
  75. package/docs/observable-resource.md +364 -0
  76. package/docs/observables.md +592 -526
  77. package/docs/routing.md +244 -653
  78. package/docs/state-management.md +134 -241
  79. package/docs/svg-elements.md +231 -0
  80. package/docs/theming.md +409 -0
  81. package/docs/validation.md +95 -97
  82. package/docs/vitepress-conventions.md +219 -0
  83. package/eslint.config.js +28 -33
  84. package/i18n.js +1 -1
  85. package/i18n.ts +2 -0
  86. package/index.js +3 -0
  87. package/package.json +36 -14
  88. package/readme.md +269 -89
  89. package/src/components/$traits/has-draggable/HasDraggable.d.ts +4 -0
  90. package/src/components/$traits/has-draggable/HasDraggable.js +13 -0
  91. package/src/components/$traits/has-items/HasItems.d.ts +9 -0
  92. package/src/components/$traits/has-items/HasItems.js +6 -6
  93. package/src/components/$traits/has-position/HasFullPosition.d.ts +14 -0
  94. package/src/components/$traits/has-position/HasFullPosition.js +44 -0
  95. package/src/components/$traits/has-position/HasPosition.d.ts +7 -0
  96. package/src/components/$traits/has-position/HasPosition.js +23 -1
  97. package/src/components/$traits/has-resizable/HasResizable.d.ts +13 -0
  98. package/src/components/$traits/has-resizable/HasResizable.js +9 -0
  99. package/src/components/$traits/has-validation/HasValidation.d.ts +17 -0
  100. package/src/components/$traits/has-validation/HasValidation.js +54 -7
  101. package/src/components/BaseComponent.d.ts +32 -0
  102. package/src/components/BaseComponent.js +65 -9
  103. package/src/components/accordion/Accordion.js +39 -14
  104. package/src/components/accordion/AccordionItem.js +45 -14
  105. package/src/components/accordion/index.js +2 -2
  106. package/src/components/accordion/types/Accordion.d.ts +47 -0
  107. package/src/components/accordion/types/AccordionItem.d.ts +48 -0
  108. package/src/components/alert/Alert.js +70 -38
  109. package/src/components/alert/index.js +2 -2
  110. package/src/components/alert/types/Alert.d.ts +62 -0
  111. package/src/components/avatar/Avatar.js +49 -12
  112. package/src/components/avatar/AvatarGroup.js +50 -2
  113. package/src/components/avatar/index.js +2 -2
  114. package/src/components/avatar/types/Avatar.d.ts +74 -0
  115. package/src/components/avatar/types/AvatarGroup.d.ts +32 -0
  116. package/src/components/badge/Badge.js +125 -5
  117. package/src/components/badge/index.js +2 -2
  118. package/src/components/badge/types/Badge.d.ts +51 -0
  119. package/src/components/breadcrumb/BreadCrumb.js +61 -5
  120. package/src/components/breadcrumb/index.js +2 -2
  121. package/src/components/breadcrumb/types/BreadCrumb.d.ts +42 -0
  122. package/src/components/button/Button.js +164 -9
  123. package/src/components/button/index.js +1 -1
  124. package/src/components/button/types/Button.d.ts +62 -0
  125. package/src/components/card/Card.js +204 -32
  126. package/src/components/card/index.js +4 -4
  127. package/src/components/card/types/Card.d.ts +42 -0
  128. package/src/components/context-menu/ContextMenu.js +49 -5
  129. package/src/components/context-menu/ContextMenuGroup.js +15 -2
  130. package/src/components/context-menu/ContextMenuItem.js +14 -2
  131. package/src/components/context-menu/index.js +5 -5
  132. package/src/components/context-menu/types/ContextMenu.d.ts +30 -0
  133. package/src/components/context-menu/types/ContextMenuGroup.d.ts +18 -0
  134. package/src/components/context-menu/types/ContextMenuItem.d.ts +18 -0
  135. package/src/components/divider/Divider.js +120 -4
  136. package/src/components/divider/index.js +3 -3
  137. package/src/components/divider/types/Divider.d.ts +55 -0
  138. package/src/components/dropdown/Dropdown.js +239 -16
  139. package/src/components/dropdown/DropdownDivider.js +22 -2
  140. package/src/components/dropdown/DropdownGroup.js +44 -5
  141. package/src/components/dropdown/DropdownItem.js +76 -3
  142. package/src/components/dropdown/DropdownTrigger.js +49 -20
  143. package/src/components/dropdown/helpers.js +1 -1
  144. package/src/components/dropdown/index.js +6 -6
  145. package/src/components/dropdown/types/Dropdown.d.ts +88 -0
  146. package/src/components/dropdown/types/DropdownDivider.d.ts +20 -0
  147. package/src/components/dropdown/types/DropdownGroup.d.ts +25 -0
  148. package/src/components/dropdown/types/DropdownItem.d.ts +41 -0
  149. package/src/components/dropdown/types/DropdownTrigger.d.ts +32 -0
  150. package/src/components/form/FormControl.js +156 -13
  151. package/src/components/form/field/Field.js +172 -9
  152. package/src/components/form/field/FieldCollection.js +116 -12
  153. package/src/components/form/field/types/AutocompleteField.js +92 -2
  154. package/src/components/form/field/types/CheckboxField.js +43 -2
  155. package/src/components/form/field/types/CheckboxGroupField.js +83 -6
  156. package/src/components/form/field/types/ColorField.js +56 -3
  157. package/src/components/form/field/types/DateField.js +155 -4
  158. package/src/components/form/field/types/EmailField.js +54 -4
  159. package/src/components/form/field/types/FileField.js +140 -6
  160. package/src/components/form/field/types/HiddenField.js +27 -1
  161. package/src/components/form/field/types/ImageField.js +82 -3
  162. package/src/components/form/field/types/NumberField.js +97 -4
  163. package/src/components/form/field/types/PasswordField.js +103 -7
  164. package/src/components/form/field/types/RadioField.js +75 -4
  165. package/src/components/form/field/types/RangeField.js +67 -1
  166. package/src/components/form/field/types/SearchField.js +41 -2
  167. package/src/components/form/field/types/SelectField.js +133 -4
  168. package/src/components/form/field/types/StringField.js +91 -2
  169. package/src/components/form/field/types/TelField.js +55 -4
  170. package/src/components/form/field/types/TextAreaField.js +76 -2
  171. package/src/components/form/field/types/TimeField.js +120 -5
  172. package/src/components/form/field/types/UrlField.js +59 -4
  173. package/src/components/form/field/types/file-field-mode/FileAvatarMode.js +83 -4
  174. package/src/components/form/field/types/file-field-mode/FileDropzoneMode.js +61 -3
  175. package/src/components/form/field/types/file-field-mode/FileItemPreview.js +79 -3
  176. package/src/components/form/field/types/file-field-mode/FileNativeMode.js +24 -2
  177. package/src/components/form/field/types/file-field-mode/FileUploadButtonMode.js +64 -3
  178. package/src/components/form/field/types/file-field-mode/FileWallMode.js +56 -3
  179. package/src/components/form/index.js +28 -28
  180. package/src/components/form/types/Field.d.ts +73 -0
  181. package/src/components/form/types/FieldCollection.d.ts +53 -0
  182. package/src/components/form/types/FormControl.d.ts +64 -0
  183. package/src/components/form/types/fields/AutocompleteField.d.ts +48 -0
  184. package/src/components/form/types/fields/CheckboxField.d.ts +33 -0
  185. package/src/components/form/types/fields/CheckboxGroupField.d.ts +49 -0
  186. package/src/components/form/types/fields/ColorField.d.ts +37 -0
  187. package/src/components/form/types/fields/DateField.d.ts +70 -0
  188. package/src/components/form/types/fields/EmailField.d.ts +35 -0
  189. package/src/components/form/types/fields/FileAvatarMode.d.ts +46 -0
  190. package/src/components/form/types/fields/FileDropzoneMode.d.ts +28 -0
  191. package/src/components/form/types/fields/FileField.d.ts +56 -0
  192. package/src/components/form/types/fields/FileItemPreview.d.ts +35 -0
  193. package/src/components/form/types/fields/FileNativeMode.d.ts +21 -0
  194. package/src/components/form/types/fields/FileUploadButtonMode.d.ts +34 -0
  195. package/src/components/form/types/fields/FileWallMode.d.ts +32 -0
  196. package/src/components/form/types/fields/HiddenField.d.ts +26 -0
  197. package/src/components/form/types/fields/ImageField.d.ts +45 -0
  198. package/src/components/form/types/fields/NumberField.d.ts +48 -0
  199. package/src/components/form/types/fields/PasswordField.d.ts +46 -0
  200. package/src/components/form/types/fields/RadioField.d.ts +48 -0
  201. package/src/components/form/types/fields/RangeField.d.ts +44 -0
  202. package/src/components/form/types/fields/SearchField.d.ts +34 -0
  203. package/src/components/form/types/fields/SelectField.d.ts +71 -0
  204. package/src/components/form/types/fields/StringField.d.ts +48 -0
  205. package/src/components/form/types/fields/TelField.d.ts +37 -0
  206. package/src/components/form/types/fields/TextAreaField.d.ts +44 -0
  207. package/src/components/form/types/fields/TimeField.d.ts +51 -0
  208. package/src/components/form/types/fields/UrlField.d.ts +35 -0
  209. package/src/components/form/validation/Validation.js +54 -54
  210. package/src/components/index.d.ts +160 -0
  211. package/src/components/list/HasListItem.js +171 -0
  212. package/src/components/list/List.js +85 -67
  213. package/src/components/list/ListDivider.js +39 -0
  214. package/src/components/list/ListGroup.js +105 -38
  215. package/src/components/list/ListItem.js +158 -49
  216. package/src/components/list/index.js +8 -6
  217. package/src/components/list/types/List.d.ts +43 -0
  218. package/src/components/list/types/ListGroup.d.ts +37 -0
  219. package/src/components/list/types/ListItem.d.ts +53 -0
  220. package/src/components/menu/HasMenuItem.js +55 -6
  221. package/src/components/menu/Menu.js +113 -22
  222. package/src/components/menu/MenuDivider.js +18 -2
  223. package/src/components/menu/MenuGroup.js +61 -6
  224. package/src/components/menu/MenuItem.js +95 -11
  225. package/src/components/menu/MenuLink.js +27 -2
  226. package/src/components/menu/index.js +6 -6
  227. package/src/components/menu/types/Menu.d.ts +60 -0
  228. package/src/components/menu/types/MenuDivider.d.ts +19 -0
  229. package/src/components/menu/types/MenuGroup.d.ts +44 -0
  230. package/src/components/menu/types/MenuItem.d.ts +46 -0
  231. package/src/components/menu/types/MenuLink.d.ts +16 -0
  232. package/src/components/modal/Modal.js +258 -17
  233. package/src/components/modal/index.js +3 -3
  234. package/src/components/modal/types/Modal.d.ts +94 -0
  235. package/src/components/pagination/Pagination.js +155 -7
  236. package/src/components/pagination/index.js +3 -3
  237. package/src/components/pagination/types/Pagination.d.ts +68 -0
  238. package/src/components/popover/Popover.js +198 -11
  239. package/src/components/popover/PopoverFooter.js +33 -9
  240. package/src/components/popover/PopoverHeader.js +33 -8
  241. package/src/components/popover/index.js +4 -4
  242. package/src/components/popover/types/Popover.d.ts +83 -0
  243. package/src/components/popover/types/PopoverFooter.d.ts +24 -0
  244. package/src/components/popover/types/PopoverHeader.d.ts +26 -0
  245. package/src/components/progress/Progress.js +182 -13
  246. package/src/components/progress/index.js +3 -3
  247. package/src/components/progress/types/Progress.d.ts +77 -0
  248. package/src/components/skeleton/Skeleton.js +117 -49
  249. package/src/components/skeleton/index.js +3 -3
  250. package/src/components/skeleton/types/Skeleton.d.ts +55 -0
  251. package/src/components/slider/Slider.js +207 -10
  252. package/src/components/slider/index.js +2 -2
  253. package/src/components/slider/types/Slider.d.ts +82 -0
  254. package/src/components/spacer/Spacer.js +12 -3
  255. package/src/components/spacer/index.js +2 -2
  256. package/src/components/spacer/types/Spacer.d.ts +19 -0
  257. package/src/components/spinner/Spinner.js +180 -9
  258. package/src/components/spinner/index.js +3 -3
  259. package/src/components/spinner/types/Spinner.d.ts +71 -0
  260. package/src/components/splitter/Splitter.js +76 -13
  261. package/src/components/splitter/SplitterGutter.js +67 -5
  262. package/src/components/splitter/SplitterPanel.js +69 -2
  263. package/src/components/splitter/index.js +5 -5
  264. package/src/components/splitter/types/Splitter.d.ts +38 -0
  265. package/src/components/splitter/types/SplitterGutter.d.ts +38 -0
  266. package/src/components/splitter/types/SplitterPanel.d.ts +41 -0
  267. package/src/components/stacks/AbsoluteStack.js +23 -3
  268. package/src/components/stacks/FixedStack.js +23 -3
  269. package/src/components/stacks/HStack.js +24 -3
  270. package/src/components/stacks/PositionStack.js +111 -3
  271. package/src/components/stacks/RelativeStack.js +23 -3
  272. package/src/components/stacks/Stack.js +73 -2
  273. package/src/components/stacks/VStack.js +24 -4
  274. package/src/components/stacks/index.js +7 -7
  275. package/src/components/stacks/types/AbsoluteStack.d.ts +16 -0
  276. package/src/components/stacks/types/FixedStack.d.ts +16 -0
  277. package/src/components/stacks/types/HStack.d.ts +16 -0
  278. package/src/components/stacks/types/PositionStack.d.ts +54 -0
  279. package/src/components/stacks/types/RelativeStack.d.ts +17 -0
  280. package/src/components/stacks/types/Stack.d.ts +39 -0
  281. package/src/components/stacks/types/VStack.d.ts +16 -0
  282. package/src/components/stepper/Stepper.js +152 -12
  283. package/src/components/stepper/StepperStep.js +104 -3
  284. package/src/components/stepper/index.js +4 -4
  285. package/src/components/stepper/types/Stepper.d.ts +68 -0
  286. package/src/components/stepper/types/StepperStep.d.ts +54 -0
  287. package/src/components/switch/Switch.js +143 -6
  288. package/src/components/switch/index.js +1 -1
  289. package/src/components/switch/types/Switch.d.ts +55 -0
  290. package/src/components/table/Column.js +105 -6
  291. package/src/components/table/ColumnGroup.js +48 -3
  292. package/src/components/table/DataTable.js +256 -19
  293. package/src/components/table/SimpleTable.js +58 -4
  294. package/src/components/table/index.js +2 -2
  295. package/src/components/table/types/Column.d.ts +49 -0
  296. package/src/components/table/types/ColumnGroup.d.ts +28 -0
  297. package/src/components/table/types/DataTable.d.ts +97 -0
  298. package/src/components/table/types/SimpleTable.d.ts +40 -0
  299. package/src/components/tabs/Tabs.js +192 -5
  300. package/src/components/tabs/index.js +3 -3
  301. package/src/components/tabs/types/Tabs.d.ts +78 -0
  302. package/src/components/toast/Toast.js +133 -5
  303. package/src/components/toast/index.js +3 -3
  304. package/src/components/toast/types/Toast.d.ts +57 -0
  305. package/src/components/toast/types/ToastError.d.ts +7 -0
  306. package/src/components/toast/types/ToastInfo.d.ts +7 -0
  307. package/src/components/toast/types/ToastSuccess.d.ts +7 -0
  308. package/src/components/toast/types/ToastWarning.d.ts +7 -0
  309. package/src/components/tooltip/Tooltip.js +157 -13
  310. package/src/components/tooltip/index.js +2 -2
  311. package/src/components/tooltip/prototypes.js +1 -1
  312. package/src/components/tooltip/types/Tooltip.d.ts +65 -0
  313. package/src/core/data/MemoryManager.js +2 -2
  314. package/src/core/data/Observable.js +15 -18
  315. package/src/core/data/ObservableArray.js +118 -46
  316. package/src/core/data/ObservableChecker.js +2 -2
  317. package/src/core/data/ObservableItem.js +135 -21
  318. package/src/core/data/ObservableObject.js +126 -35
  319. package/src/core/data/ObservableResource.js +118 -3
  320. package/src/core/data/Store.js +142 -26
  321. package/src/core/data/observable-helpers/observable.is-to.js +196 -1
  322. package/src/core/data/observable-helpers/observable.prototypes.js +35 -8
  323. package/src/core/elements/anchor/anchor-with-sentinel.js +23 -2
  324. package/src/core/elements/anchor/anchor.js +16 -7
  325. package/src/core/elements/anchor/one-child-anchor-overwriting.js +2 -2
  326. package/src/core/elements/content-formatter.js +1 -1
  327. package/src/core/elements/control/for-each-array.js +9 -9
  328. package/src/core/elements/control/for-each.js +14 -14
  329. package/src/core/elements/control/show-if.js +11 -11
  330. package/src/core/elements/control/show-when.js +5 -5
  331. package/src/core/elements/control/switch.js +14 -14
  332. package/src/core/elements/description-list.js +1 -1
  333. package/src/core/elements/form.js +2 -2
  334. package/src/core/elements/fragment.js +1 -1
  335. package/src/core/elements/html5-semantics.js +1 -1
  336. package/src/core/elements/img.js +3 -3
  337. package/src/core/elements/interactive.js +1 -1
  338. package/src/core/elements/list.js +1 -1
  339. package/src/core/elements/medias.js +1 -1
  340. package/src/core/elements/meta-data.js +1 -1
  341. package/src/core/elements/svg.js +1 -1
  342. package/src/core/elements/table.js +1 -1
  343. package/src/core/errors/ArgTypesError.js +1 -1
  344. package/src/core/utils/HasEventEmitter.js +36 -2
  345. package/src/core/utils/args-types.js +9 -9
  346. package/src/core/utils/cache.js +1 -1
  347. package/src/core/utils/callback-handler.js +29 -0
  348. package/src/core/utils/debug-manager.js +6 -6
  349. package/src/core/utils/events.js +139 -139
  350. package/src/core/utils/filters/date.js +84 -3
  351. package/src/core/utils/filters/standard.js +136 -11
  352. package/src/core/utils/filters/strings.js +34 -2
  353. package/src/core/utils/filters/utils.js +40 -4
  354. package/src/core/utils/formatters.js +4 -4
  355. package/src/core/utils/helpers.js +39 -7
  356. package/src/core/utils/localstorage.js +11 -11
  357. package/src/core/utils/memoize.js +56 -3
  358. package/src/core/utils/plugins-manager.js +3 -3
  359. package/src/core/utils/property-accumulator.js +6 -6
  360. package/src/core/utils/prototypes.js +26 -1
  361. package/src/core/utils/shortcut-manager.js +2 -2
  362. package/src/core/utils/validator.js +8 -8
  363. package/src/core/wrappers/AttributesWrapper.js +32 -22
  364. package/src/core/wrappers/DocumentObserver.js +3 -3
  365. package/src/core/wrappers/ElementCreator.js +5 -5
  366. package/src/core/wrappers/HtmlElementWrapper.js +38 -12
  367. package/src/core/wrappers/NDElement.js +328 -22
  368. package/src/core/wrappers/NdPrototype.js +60 -16
  369. package/src/core/wrappers/SingletonView.js +50 -2
  370. package/src/core/wrappers/SvgElementWrapper.js +1 -1
  371. package/src/core/wrappers/constants.js +35 -2
  372. package/src/core/wrappers/prototypes/attributes-extensions.js +7 -7
  373. package/src/core/wrappers/prototypes/nd-element-extensions.js +72 -6
  374. package/src/core/wrappers/prototypes/nd-element.transition.extensions.js +42 -2
  375. package/src/core/wrappers/template-cloner/NodeCloner.js +53 -8
  376. package/src/core/wrappers/template-cloner/TemplateCloner.js +75 -6
  377. package/src/core/wrappers/template-cloner/attributes-hydrator.js +58 -2
  378. package/src/core/wrappers/template-cloner/utils.js +42 -6
  379. package/src/fetch/NativeFetch.js +3 -3
  380. package/src/i18n/bin/scan.js +6 -6
  381. package/src/i18n/index.d.ts +2 -0
  382. package/src/i18n/service/I18nService.d.ts +27 -0
  383. package/src/i18n/service/I18nService.js +5 -5
  384. package/src/i18n/service/functions.d.ts +22 -0
  385. package/src/i18n/service/functions.js +2 -2
  386. package/src/router/Route.js +3 -3
  387. package/src/router/RouteGroupHelper.js +2 -2
  388. package/src/router/Router.js +15 -15
  389. package/src/router/RouterComponent.js +33 -7
  390. package/src/router/link.js +4 -4
  391. package/src/router/modes/HashRouter.js +2 -2
  392. package/src/router/modes/HistoryRouter.js +2 -2
  393. package/src/router/modes/MemoryRouter.js +1 -1
  394. package/src/ui/components/accordion/AccordionItemRender.js +3 -3
  395. package/src/ui/components/accordion/AccordionRender.js +1 -1
  396. package/src/ui/components/alert/AlertRender.js +10 -10
  397. package/src/ui/components/avatar/avata-group/AvatarGroupRender.js +1 -1
  398. package/src/ui/components/avatar/avatar/AvatarRender.js +1 -1
  399. package/src/ui/components/breadcrumb/BreadcrumbRender.js +2 -2
  400. package/src/ui/components/button/ButtonRender.js +1 -1
  401. package/src/ui/components/card/CardRender.js +133 -0
  402. package/src/ui/components/card/card.css +169 -0
  403. package/src/ui/components/contextmenu/ContextmenuRender.js +6 -6
  404. package/src/ui/components/dropdown/DropdownRender.js +8 -8
  405. package/src/ui/components/dropdown/group/DropdownGroupRender.js +2 -2
  406. package/src/ui/components/dropdown/item/DropdownItemRender.js +1 -1
  407. package/src/ui/components/form/FieldCollectionRender.js +2 -2
  408. package/src/ui/components/form/FormControlRender.js +5 -5
  409. package/src/ui/components/form/fields/AutocompleteFieldRender.js +3 -3
  410. package/src/ui/components/form/fields/CheckboxFieldRender.js +1 -1
  411. package/src/ui/components/form/fields/CheckboxGroupFieldRender.js +1 -1
  412. package/src/ui/components/form/fields/DateFieldRender.js +7 -7
  413. package/src/ui/components/form/fields/EmailFieldRender.js +1 -1
  414. package/src/ui/components/form/fields/FieldRender.js +4 -4
  415. package/src/ui/components/form/fields/FileFieldRender.js +1 -1
  416. package/src/ui/components/form/fields/PasswordFieldRender.js +2 -2
  417. package/src/ui/components/form/fields/RadioFieldRender.js +1 -1
  418. package/src/ui/components/form/fields/RangeFieldRender.js +1 -1
  419. package/src/ui/components/form/fields/SelectFieldRender.js +2 -2
  420. package/src/ui/components/form/fields/SliderFieldRender.js +6 -6
  421. package/src/ui/components/form/fields/StringFieldRender.js +1 -1
  422. package/src/ui/components/form/fields/TelFieldRender.js +1 -1
  423. package/src/ui/components/form/fields/TextAreaFieldRender.js +1 -1
  424. package/src/ui/components/form/fields/TimeFieldRender.js +3 -3
  425. package/src/ui/components/form/fields/UrlFieldRender.js +1 -1
  426. package/src/ui/components/form/file-upload-mode/FileAvatarModeRender.js +1 -1
  427. package/src/ui/components/form/file-upload-mode/FileDropzoneModeRender.js +2 -2
  428. package/src/ui/components/form/file-upload-mode/FileUploadButtonModeRender.js +2 -2
  429. package/src/ui/components/form/file-upload-mode/FileWallModeRender.js +1 -1
  430. package/src/ui/components/form/helpers.js +8 -8
  431. package/src/ui/components/form/index.js +27 -27
  432. package/src/ui/components/list/ListRender.js +18 -0
  433. package/src/ui/components/list/divider/ListDividerRender.js +10 -0
  434. package/src/ui/components/list/divider/list-divider.css +12 -0
  435. package/src/ui/components/list/group/ListGroupRender.js +61 -0
  436. package/src/ui/components/list/group/list-group.css +62 -0
  437. package/src/ui/components/list/item/ListItemRender.js +238 -0
  438. package/src/ui/components/list/item/list-item.css +191 -0
  439. package/src/ui/components/list/list.css +24 -0
  440. package/src/ui/components/menu/MenuDividerRender.js +1 -1
  441. package/src/ui/components/menu/MenuGroupRender.js +3 -3
  442. package/src/ui/components/menu/MenuItemRender.js +2 -2
  443. package/src/ui/components/menu/MenuLinkRender.js +3 -3
  444. package/src/ui/components/menu/helpers.js +4 -4
  445. package/src/ui/components/modal/ModalRender.js +4 -4
  446. package/src/ui/components/pagination/PaginationRender.js +9 -9
  447. package/src/ui/components/popover/PopoverRender.js +7 -7
  448. package/src/ui/components/progress/ProgressRender.js +12 -12
  449. package/src/ui/components/skeleton/SkeletonRender.js +56 -0
  450. package/src/ui/components/spacer/SpacerRender.js +10 -0
  451. package/src/ui/components/splitter/SplitterGutterRender.js +1 -1
  452. package/src/ui/components/splitter/SplitterPanelRender.js +2 -2
  453. package/src/ui/components/stacks/PositionStackRender.js +1 -1
  454. package/src/ui/components/stacks/StackRender.js +1 -1
  455. package/src/ui/components/stacks/absolute-stack/AbsoluteStackRender.js +1 -1
  456. package/src/ui/components/stacks/fixed-stack/FixedStackRender.js +1 -1
  457. package/src/ui/components/stacks/h-stack/HStackRender.js +1 -1
  458. package/src/ui/components/stacks/index.js +5 -5
  459. package/src/ui/components/stacks/relative-stack/RelativeStackRender.js +1 -1
  460. package/src/ui/components/stacks/v-stack/VStackRender.js +1 -1
  461. package/src/ui/components/stepper/StepperRender.js +2 -2
  462. package/src/ui/components/stepper/StepperStepRender.js +4 -4
  463. package/src/ui/components/switch/SwitchRender.js +4 -4
  464. package/src/ui/components/table/data-table/DataTableRender.js +5 -5
  465. package/src/ui/components/table/data-table/bulk-actions.js +7 -7
  466. package/src/ui/components/table/data-table/pagination.js +6 -6
  467. package/src/ui/components/table/data-table/tables.js +25 -25
  468. package/src/ui/components/table/data-table/toolbar.js +3 -3
  469. package/src/ui/components/table/simple-table/SimpleTableRender.js +8 -8
  470. package/src/ui/components/tabs/TabsRender.js +11 -11
  471. package/src/ui/components/toast/ToastRender.js +3 -3
  472. package/src/ui/components/tooltip/TooltipRender.js +1 -1
  473. package/src/ui/index.js +44 -36
  474. package/types/elements.d.ts +163 -1037
  475. package/types/forms.d.ts +16 -20
  476. package/types/globals.d.ts +543 -0
  477. package/types/images.d.ts +2 -2
  478. package/types/observable-resource.d.ts +3 -0
  479. package/types/property-accumulator.d.ts +4 -4
  480. package/types/store.d.ts +26 -2
  481. package/types/validator.ts +3 -3
  482. package/ui.js +1 -0
  483. package/src/components/form/field/DefaultRender.js +0 -77
  484. package/src/components/form/field/FieldFactory.js +0 -107
  485. package/src/components/skeleton/SkeletonList.js +0 -0
  486. package/src/components/skeleton/SkeletonParagraph.js +0 -0
  487. package/src/components/skeleton/SkeletonTable.js +0 -0
  488. /package/{src/components/skeleton/SkeletonCard.js → docs/tutorials/.gitkeep} +0 -0
package/docs/cache.md CHANGED
@@ -1,888 +1,180 @@
1
- # Cache Utilities
1
+ ---
2
+ title: Cache
3
+ description: Lazy initialization, singleton patterns, and key-based memoization utilities
4
+ ---
2
5
 
3
- NativeDocument provides utility functions for optimizing function execution through lazy initialization, memoization, and singleton patterns. These utilities help improve performance by deferring execution and caching results.
6
+ # Cache
4
7
 
5
- ## Overview
8
+ NativeDocument provides three caching utilities for optimizing function execution: lazy initialization, eager singletons, and key-based memoization.
6
9
 
7
- The Cache utilities include:
8
- - **`Cache.once(fn)`** - Lazy execution (via `autoOnce`) - executes on first property access
9
- - **`Cache.singleton(fn)`** - Eager singleton (via `once`) - executes immediately on first call
10
- - **`Cache.memoize(fn)`** - Lazy memoization (via `autoMemoize`) - proxy-based caching
11
-
12
- ## Import
13
10
  ```javascript
14
- import { Cache } from 'native-document/utils';
11
+ import { utils } from 'native-document';
12
+ const { Cache } = utils;
15
13
 
16
- // Use Cache methods
17
- const lazyInit = Cache.once(() => { /* ... */ });
18
- const singleton = Cache.singleton(() => { /* ... */ });
19
- const memoized = Cache.memoize((key) => { /* ... */ });
14
+ // Or
15
+ import { Cache } from 'native-document/utils';
20
16
  ```
21
17
 
22
- ## Cache.once() - Lazy Initialization
18
+ ---
23
19
 
24
- Lazy execution using `autoOnce`. The function is **not executed immediately** - it only runs when you access a property on the returned object.
20
+ ## `Cache.once(fn)` - Lazy Initialization
25
21
 
26
- ### Basic Usage
27
- ```javascript
28
- import { Cache } from 'native-document/utils';
22
+ The function is **not executed immediately**. It runs only when you access a property on the returned Proxy object. The result is cached after the first access.
29
23
 
30
- const LazyConfig = Cache.once(() => {
24
+ ```javascript
25
+ const Config = Cache.once(() => {
31
26
  console.log('Loading config...');
32
27
  return {
33
- apiUrl: 'https://api.example.com',
34
- timeout: 5000,
28
+ apiUrl: 'https://api.example.com',
29
+ timeout: 5000,
35
30
  maxRetries: 3
36
31
  };
37
32
  });
38
33
 
39
34
  // Function not executed yet
40
- console.log('Config created');
41
-
42
- // First property access triggers execution
43
- console.log(LazyConfig.apiUrl);
44
- // Logs: "Loading config..."
45
- // Returns: "https://api.example.com"
46
-
47
- // Subsequent accesses use cached result
48
- console.log(LazyConfig.timeout); // No log, returns 5000
49
- console.log(LazyConfig.maxRetries); // No log, returns 3
35
+ Config.apiUrl; // "Loading config..." -> "https://api.example.com"
36
+ Config.timeout; // no log -> 5000 (cached)
50
37
  ```
51
38
 
52
- ### Lazy Module Loading
53
- ```javascript
54
- import { Cache } from 'native-document/utils';
55
-
56
- const Utils = Cache.once(() => {
57
- console.log('Initializing utils...');
58
- return {
59
- formatDate: (date) => new Date(date).toLocaleDateString(),
60
- capitalize: (str) => str.charAt(0).toUpperCase() + str.slice(1),
61
- truncate: (str, len) => str.length > len ? str.slice(0, len) + '...' : str,
62
- slugify: (str) => str.toLowerCase().replace(/\s+/g, '-')
63
- };
64
- });
65
-
66
- // Utils not initialized yet
67
- console.log('App started');
68
-
69
- // First use initializes the module
70
- const formatted = Utils.formatDate(new Date());
71
- // Logs: "Initializing utils..."
39
+ Use for optional features or heavy modules that may not always be needed:
72
40
 
73
- // Already initialized - no log
74
- const capitalized = Utils.capitalize('hello');
75
- const slug = Utils.slugify('Hello World');
76
- ```
77
-
78
- ### Lazy API Client
79
41
  ```javascript
80
- import { Cache } from 'native-document/utils';
81
- import { NativeFetch } from 'native-document/utils';
82
-
83
42
  const API = Cache.once(() => {
84
- console.log('Setting up API client...');
85
43
  const client = new NativeFetch('https://api.example.com');
86
-
87
- client.interceptors.request((config) => {
44
+ client.interceptors.request(config => {
88
45
  config.headers['Authorization'] = `Bearer ${getToken()}`;
89
46
  return config;
90
47
  });
91
-
92
48
  return {
93
49
  users: {
94
- get: (id) => client.get(`/users/${id}`),
95
- list: () => client.get('/users')
96
- },
97
- posts: {
98
- get: (id) => client.get(`/posts/${id}`),
99
- create: (data) => client.post('/posts', data)
50
+ list: () => client.get('/users'),
51
+ get: (id) => client.get(`/users/${id}`)
100
52
  }
101
53
  };
102
54
  });
103
55
 
104
- // Client not created yet
105
- console.log('Starting app...');
106
-
107
- // Client created on first API call
56
+ // Client created only on first use
108
57
  const users = await API.users.list();
109
- // Logs: "Setting up API client..."
110
-
111
- // Client already created
112
- const user = await API.users.get('123');
113
58
  ```
114
59
 
115
- ## Cache.singleton() - Eager Singleton
60
+ ---
116
61
 
117
- Eager execution using `once`. The function executes **on the first call** and caches the result for subsequent calls.
62
+ ## `Cache.singleton(fn)` - Eager Singleton
118
63
 
119
- ### Basic Usage
120
- ```javascript
121
- import { Cache } from 'native-document/utils';
64
+ The function executes on the **first call** and caches the result. All subsequent calls return the same instance.
122
65
 
66
+ ```javascript
123
67
  const getLogger = Cache.singleton(() => {
124
- console.log('Creating logger instance...');
68
+ console.log('Creating logger...');
125
69
  return {
126
- log: (msg) => console.log(`[LOG] ${msg}`),
127
- error: (msg) => console.error(`[ERROR] ${msg}`),
128
- warn: (msg) => console.warn(`[WARN] ${msg}`),
129
- info: (msg) => console.info(`[INFO] ${msg}`)
70
+ log: msg => console.log(`[LOG] ${msg}`),
71
+ error: msg => console.error(`[ERROR] ${msg}`)
130
72
  };
131
73
  });
132
74
 
133
- // First call creates the logger
134
- const logger = getLogger();
135
- // Logs: "Creating logger instance..."
136
-
137
- logger.log('Application started');
138
-
139
- // Subsequent calls return cached instance
140
- const logger2 = getLogger();
141
- // No log - returns cached instance
142
-
143
- console.log(logger === logger2); // true - same reference
75
+ const logger = getLogger(); // "Creating logger..."
76
+ const logger2 = getLogger(); // no log
77
+ console.log(logger === logger2); // true
144
78
  ```
145
79
 
146
- ### Application Configuration
147
- ```javascript
148
- import { Cache } from 'native-document/utils';
149
-
150
- const getConfig = Cache.singleton(() => {
151
- console.log('Loading configuration...');
152
- return {
153
- apiUrl: import.meta.env.VITE_API_URL || 'https://api.example.com',
154
- debug: import.meta.env.DEV,
155
- version: '1.0.0',
156
- features: {
157
- analytics: true,
158
- darkMode: true
159
- }
160
- };
161
- });
162
-
163
- // First call loads config
164
- const config = getConfig();
165
- // Logs: "Loading configuration..."
166
-
167
- console.log(config.apiUrl);
80
+ Use for core services that must exist exactly once:
168
81
 
169
- // Returns same config instance
170
- const config2 = getConfig();
171
- console.log(config === config2); // true
172
- ```
173
-
174
- ### Event Bus Singleton
175
82
  ```javascript
176
- import { Cache } from 'native-document/utils';
83
+ const getConfig = Cache.singleton(() => ({
84
+ apiUrl: import.meta.env.VITE_API_URL,
85
+ debug: import.meta.env.DEV,
86
+ version: '1.0.0'
87
+ }));
177
88
 
178
- const getEventBus = Cache.singleton(() => {
179
- console.log('Creating event bus...');
180
- const listeners = new Map();
181
-
182
- return {
183
- on: (event, callback) => {
184
- if (!listeners.has(event)) {
185
- listeners.set(event, []);
186
- }
187
- listeners.get(event).push(callback);
188
- },
189
- off: (event, callback) => {
190
- const eventListeners = listeners.get(event);
191
- if (eventListeners) {
192
- const index = eventListeners.indexOf(callback);
193
- if (index > -1) {
194
- eventListeners.splice(index, 1);
195
- }
196
- }
197
- },
198
- emit: (event, data) => {
199
- const eventListeners = listeners.get(event);
200
- if (eventListeners) {
201
- eventListeners.forEach(callback => callback(data));
202
- }
89
+ const getAPI = Cache.singleton(() => {
90
+ const config = getConfig();
91
+ const client = new NativeFetch(config.apiUrl);
92
+ client.interceptors.request(req => {
93
+ const token = localStorage.getItem('token');
94
+ if (token) {
95
+ req.headers['Authorization'] = `Bearer ${token}`;
203
96
  }
204
- };
97
+ return req;
98
+ });
99
+ return client;
205
100
  });
206
-
207
- // Create event bus
208
- const bus = getEventBus();
209
- // Logs: "Creating event bus..."
210
-
211
- bus.on('user:login', (user) => console.log('User logged in:', user));
212
- bus.emit('user:login', { id: 1, name: 'John' });
213
-
214
- // Same event bus everywhere
215
- const bus2 = getEventBus();
216
- console.log(bus === bus2); // true
217
101
  ```
218
102
 
219
- ## Cache.memoize() - Lazy Memoization with Key-Based Instances
103
+ ---
220
104
 
221
- Lazy memoization using `autoMemoize`. Each property access creates and caches a **separate instance** of the function result, using the property name as the key parameter.
105
+ ## `Cache.memoize(fn)` - Key-Based Memoization
222
106
 
223
- ### How It Works
224
- ```javascript
225
- import { Cache } from 'native-document/utils';
107
+ Each property access creates and caches a **separate instance** using the property name as the key argument.
226
108
 
227
- const API = Cache.memoize((key) => {
228
- console.log(`Creating API for: ${key}`);
229
- return {
230
- async list() {
231
- return await fetch('/' + key);
232
- },
233
- async get(id) {
234
- return await fetch('/' + key + '/' + id);
235
- }
236
- };
237
- });
238
-
239
- // First access to 'users' - executes function with key='users'
240
- await API.users.list();
241
- // Logs: "Creating API for: users"
242
- // Fetch: '/users'
243
-
244
- // Second access to 'users' - returns cached instance
245
- await API.users.get('123');
246
- // No log - cached instance
247
- // Fetch: '/users/123'
248
-
249
- // First access to 'posts' - executes function with key='posts'
250
- await API.posts.list();
251
- // Logs: "Creating API for: posts"
252
- // Fetch: '/posts'
253
-
254
- // Cached instance for 'posts'
255
- await API.posts.get('456');
256
- // No log - cached instance
257
- // Fetch: '/posts/456'
258
- ```
259
-
260
- ### Key Concepts
261
-
262
- 1. **Property name becomes the key**: `API.users` -> `key = 'users'`
263
- 2. **Function executed per unique key**: First access creates instance
264
- 3. **Results cached by key**: Subsequent accesses return same instance
265
- 4. **Each key has its own instance**: `API.users` ≠ `API.posts`
266
-
267
- ### Basic Resource Providers
268
109
  ```javascript
269
- import { Cache } from 'native-document/utils';
270
-
271
- const Resources = Cache.memoize((resource) => {
272
- console.log(`Loading ${resource}...`);
273
-
274
- return {
275
- data: `${resource} data`,
276
- load: () => console.log(`Reloading ${resource}`),
277
- save: (content) => console.log(`Saving to ${resource}:`, content)
278
- };
279
- });
280
-
281
- // First access - creates 'icons' instance
282
- Resources.icons.load();
283
- // Logs: "Loading icons..."
284
- // Logs: "Reloading icons"
285
-
286
- // Cached instance
287
- Resources.icons.save('new-icon.svg');
288
- // Logs: "Saving to icons: new-icon.svg"
289
-
290
- // Different key - creates 'fonts' instance
291
- Resources.fonts.load();
292
- // Logs: "Loading fonts..."
293
- // Logs: "Reloading fonts"
294
- ```
295
-
296
- ### API Endpoint Collections
297
- ```javascript
298
- import { Cache } from 'native-document/utils';
299
- import { NativeFetch } from 'native-document/utils';
300
-
301
- const api = new NativeFetch('https://api.example.com');
302
-
303
110
  const Endpoints = Cache.memoize((resource) => {
304
- console.log(`Creating endpoint for: ${resource}`);
305
-
111
+ console.log(`Creating endpoint: ${resource}`);
112
+ const api = getAPI();
306
113
  return {
307
- list: () => api.get(`/${resource}`),
308
- get: (id) => api.get(`/${resource}/${id}`),
309
- create: (data) => api.post(`/${resource}`, data),
310
- update: (id, data) => api.put(`/${resource}/${id}`, data),
311
- delete: (id) => api.delete(`/${resource}/${id}`)
114
+ list: (params = {}) => api.get(`/${resource}`, params),
115
+ get: (id) => api.get(`/${resource}/${id}`),
116
+ create: (data) => api.post(`/${resource}`, data),
117
+ update: (id, data) => api.put(`/${resource}/${id}`, data),
118
+ delete: (id) => api.delete(`/${resource}/${id}`)
312
119
  };
313
120
  });
314
121
 
315
- // Create 'users' endpoint instance
316
- const users = await Endpoints.users.list();
317
- // Logs: "Creating endpoint for: users"
318
- // GET: /users
319
-
320
- const user = await Endpoints.users.get('123');
321
- // GET: /users/123 (cached instance)
322
-
323
- // Create 'posts' endpoint instance
324
- const posts = await Endpoints.posts.list();
325
- // Logs: "Creating endpoint for: posts"
326
- // GET: /posts
327
-
328
- await Endpoints.posts.create({ title: 'New Post' });
329
- // POST: /posts (cached instance)
122
+ await Endpoints.users.list(); // "Creating endpoint: users"
123
+ await Endpoints.users.get('1'); // no log - cached
124
+ await Endpoints.posts.list(); // "Creating endpoint: posts"
330
125
  ```
331
126
 
332
- ### Store Providers
333
- ```javascript
334
- import { Cache } from 'native-document/utils';
335
- import { Store } from 'native-document';
127
+ Use for resources that share the same structure but need separate instances per key:
336
128
 
337
- const Stores = Cache.memoize((storeName) => {
338
- console.log(`Creating store: ${storeName}`);
339
-
340
- // Create store if it doesn't exist
341
- if (!Store.get(storeName)) {
342
- Store.create(storeName, {
343
- items: [],
344
- loading: false,
345
- error: null
346
- });
347
- }
348
-
349
- return {
350
- get: () => Store.use(storeName),
351
- setLoading: (value) => {
352
- /*...*/
353
- },
354
- addItem: (items) => {
355
- /*...*/
356
- },
357
- setItems: (items) => {
358
- /*...*/
359
- },
360
- setError: (error) => {
361
- /*...*/
362
- }
363
- };
364
- });
365
-
366
- // Create 'products' store
367
- const productsStore = Stores.products.get();
368
- // Logs: "Creating store: products"
369
-
370
- Stores.products.setLoading(true);
371
- Stores.products.addItem({ id: 1, name: 'Product 1' });
372
-
373
- // Create 'users' store
374
- const usersStore = Stores.users.get();
375
- // Logs: "Creating store: users"
376
-
377
- Stores.users.setItems([{ id: 1, name: 'Alice' }]);
378
- ```
379
-
380
- ### LocalStorage Namespaces
381
129
  ```javascript
382
- import { Cache } from 'native-document/utils';
383
-
384
- const Storage = Cache.memoize((namespace) => {
385
- console.log(`Creating storage for namespace: ${namespace}`);
130
+ // Namespaced localStorage
131
+ const Storage = Cache.memoize((namespace) => ({
132
+ get: (key) => JSON.parse(localStorage.getItem(`${namespace}:${key}`)),
386
133
 
387
- const prefix = `${namespace}:`;
134
+ set: (key, val) => localStorage.setItem(`${namespace}:${key}`, JSON.stringify(val)),
388
135
 
389
- return {
390
- get: (key) => {
391
- try {
392
- const item = localStorage.getItem(prefix + key);
393
- return item ? JSON.parse(item) : null;
394
- } catch {
395
- return null;
396
- }
397
- },
398
- set: (key, value) => {
399
- try {
400
- localStorage.setItem(prefix + key, JSON.stringify(value));
401
- return true;
402
- } catch {
403
- return false;
404
- }
405
- },
406
- remove: (key) => {
407
- localStorage.removeItem(prefix + key);
408
- },
409
- clear: () => {
410
- // Clear all keys with this namespace
411
- Object.keys(localStorage)
412
- .filter(key => key.startsWith(prefix))
413
- .forEach(key => localStorage.removeItem(key));
414
- }
415
- };
416
- });
136
+ remove: (key) => localStorage.removeItem(`${namespace}:${key}`)
137
+ }));
417
138
 
418
- // User preferences namespace
419
139
  Storage.user.set('theme', 'dark');
420
- // Logs: "Creating storage for namespace: user"
421
- // localStorage: "user:theme" = "dark"
422
-
423
- Storage.user.set('language', 'en');
424
- // localStorage: "user:language" = "en"
425
-
426
- const theme = Storage.user.get('theme');
427
- // Returns: "dark"
428
-
429
- // App settings namespace (different instance)
430
140
  Storage.app.set('version', '1.0.0');
431
- // Logs: "Creating storage for namespace: app"
432
- // localStorage: "app:version" = "1.0.0"
433
- ```
434
-
435
- ### Event Handlers by Type
436
- ```javascript
437
- import { Cache } from 'native-document/utils';
438
-
439
- const EventHandlers = Cache.memoize((eventType) => {
440
- console.log(`Creating handler for: ${eventType}`);
441
- const listeners = [];
442
-
443
- return {
444
- add: (callback) => {
445
- listeners.push(callback);
446
- },
447
- remove: (callback) => {
448
- const index = listeners.indexOf(callback);
449
- if (index > -1) {
450
- listeners.splice(index, 1);
451
- }
452
- },
453
- emit: (data) => {
454
- listeners.forEach(callback => callback(data));
455
- },
456
- count: () => listeners.length
457
- };
458
- });
459
-
460
- // Create 'click' event handler
461
- EventHandlers.click.add((data) => console.log('Clicked:', data));
462
- // Logs: "Creating handler for: click"
463
-
464
- EventHandlers.click.emit({ x: 100, y: 200 });
465
- // Logs: "Clicked: { x: 100, y: 200 }"
466
-
467
- // Create 'scroll' event handler (different instance)
468
- EventHandlers.scroll.add((data) => console.log('Scrolled:', data));
469
- // Logs: "Creating handler for: scroll"
470
-
471
- EventHandlers.scroll.emit({ top: 500 });
472
- // Logs: "Scrolled: { top: 500 }"
473
-
474
- console.log(EventHandlers.click.count()); // 1
475
- console.log(EventHandlers.scroll.count()); // 1
476
- ```
477
-
478
- ### Validation Rules by Type
479
- ```javascript
480
- import { Cache } from 'native-document/utils';
481
141
 
482
- const Validators = Cache.memoize((fieldType) => {
483
- console.log(`Creating validators for: ${fieldType}`);
484
-
485
- const rules = {
486
- email: {
487
- required: (value) => !!value || 'Email is required',
488
- format: (value) => /\S+@\S+\.\S+/.test(value) || 'Invalid email format'
489
- },
490
- password: {
491
- required: (value) => !!value || 'Password is required',
492
- minLength: (value) => value.length >= 8 || 'Password must be at least 8 characters',
493
- hasNumber: (value) => /\d/.test(value) || 'Password must contain a number'
494
- },
495
- phone: {
496
- required: (value) => !!value || 'Phone is required',
497
- format: (value) => /^\d{10}$/.test(value) || 'Phone must be 10 digits'
498
- }
499
- };
500
-
501
- return {
502
- validate: (value) => {
503
- const fieldRules = rules[fieldType];
504
- if (!fieldRules) return [];
505
-
506
- const errors = [];
507
- for (const [ruleName, rule] of Object.entries(fieldRules)) {
508
- const result = rule(value);
509
- if (result !== true) {
510
- errors.push(result);
511
- }
512
- }
513
- return errors;
514
- },
515
- isValid: (value) => {
516
- return Validators[fieldType].validate(value).length === 0;
517
- }
518
- };
519
- });
520
-
521
- // Validate email
522
- const emailErrors = Validators.email.validate('invalid-email');
523
- // Logs: "Creating validators for: email"
524
- // Returns: ['Invalid email format']
525
-
526
- const isEmailValid = Validators.email.isValid('test@example.com');
527
- // Returns: true (cached instance)
528
-
529
- // Validate password
530
- const passwordErrors = Validators.password.validate('weak');
531
- // Logs: "Creating validators for: password"
532
- // Returns: ['Password must be at least 8 characters', 'Password must contain a number']
533
- ```
534
-
535
- ### Chart Instances by Type
536
- ```javascript
537
- import { Cache } from 'native-document/utils';
538
-
539
- const Charts = Cache.memoize((chartType) => {
540
- console.log(`Creating ${chartType} chart instance...`);
541
-
542
- return {
543
- render: (container, data, options = {}) => {
544
- console.log(`Rendering ${chartType} chart`);
545
-
546
- // Simplified chart rendering
547
- const canvas = document.createElement('canvas');
548
- container.appendChild(canvas);
549
-
550
- // Chart-specific rendering logic
551
- switch (chartType) {
552
- case 'bar':
553
- renderBarChart(canvas, data, options);
554
- break;
555
- case 'line':
556
- renderLineChart(canvas, data, options);
557
- break;
558
- case 'pie':
559
- renderPieChart(canvas, data, options);
560
- break;
561
- }
562
-
563
- return canvas;
564
- },
565
- update: (canvas, data) => {
566
- console.log(`Updating ${chartType} chart`);
567
- // Update logic
568
- }
569
- };
570
- });
571
-
572
- // Create bar chart instance
573
- const barContainer = document.querySelector('#bar-chart');
574
- Charts.bar.render(barContainer, [10, 20, 30]);
575
- // Logs: "Creating bar chart instance..."
576
- // Logs: "Rendering bar chart"
577
-
578
- // Create line chart instance (different from bar)
579
- const lineContainer = document.querySelector('#line-chart');
580
- Charts.line.render(lineContainer, [5, 15, 25]);
581
- // Logs: "Creating line chart instance..."
582
- // Logs: "Rendering line chart"
583
-
584
- // Reuse bar chart instance
585
- Charts.bar.update(barCanvas, [15, 25, 35]);
586
- // Logs: "Updating bar chart"
587
- ```
588
-
589
- ### Form Field Managers
590
- ```javascript
591
- import { Cache } from 'native-document/utils';
592
- import { Observable } from 'native-document';
593
-
594
- const FormFields = Cache.memoize((fieldName) => {
595
- console.log(`Creating field manager for: ${fieldName}`);
596
-
597
- const value = Observable('');
598
- const errors = Observable([]);
599
- const touched = Observable(false);
600
-
601
- return {
602
- value,
603
- errors,
604
- touched,
605
- setValue: (newValue) => {
606
- value.set(newValue);
607
- touched.set(true);
608
- },
609
- setErrors: (newErrors) => {
610
- errors.set(newErrors);
611
- },
612
- reset: () => {
613
- value.set('');
614
- errors.set([]);
615
- touched.set(false);
616
- },
617
- isValid: () => errors.val().length === 0
618
- };
619
- });
620
-
621
- // Create email field
622
- FormFields.email.setValue('test@example.com');
623
- // Logs: "Creating field manager for: email"
624
-
625
- FormFields.email.setErrors([]);
626
- console.log(FormFields.email.isValid()); // true
627
-
628
- // Create password field (different instance)
629
- FormFields.password.setValue('weak');
630
- // Logs: "Creating field manager for: password"
631
-
632
- FormFields.password.setErrors(['Too short']);
633
- console.log(FormFields.password.isValid()); // false
634
- ```
635
-
636
- ## Comparison: once vs singleton vs memoize
637
-
638
- | Feature | `Cache.once()` | `Cache.singleton()` | `Cache.memoize()` |
639
- |---------|------------------|------------------------|---------------------|
640
- | **Execution** | Lazy (on property access) | Eager (on first call) | Lazy (per key on property access) |
641
- | **Implementation** | `autoOnce` | `once` | `autoMemoize` |
642
- | **Access Pattern** | `obj.property` | `fn()` | `obj[key].method()` |
643
- | **Instances Created** | 1 (single instance) | 1 (single instance) | N (one per key) |
644
- | **Cache Strategy** | Properties from result | Entire result | Result per property key |
645
- | **Use Case** | Lazy modules | Eager singletons | Multiple instances by key |
646
-
647
- ### Visual Comparison
648
- ```javascript
649
- import { Cache } from 'native-document/utils';
650
-
651
- // Cache.once() - Single lazy instance
652
- const LazyUtils = Cache.once(() => {
653
- console.log('Init utils');
654
- return {
655
- format: () => 'formatted',
656
- parse: () => 'parsed'
657
- };
658
- });
659
-
660
- LazyUtils.format(); // Logs: "Init utils"
661
- LazyUtils.parse(); // No log - same instance
662
-
663
- // Cache.singleton() - Single eager instance
664
- const getConfig = Cache.singleton(() => {
665
- console.log('Init config');
666
- return { api: 'url', debug: true };
667
- });
668
-
669
- const config = getConfig(); // Logs: "Init config"
670
- const config2 = getConfig(); // No log - same instance
671
-
672
- // Cache.memoize() - Multiple instances by key
673
- const API = Cache.memoize((resource) => {
674
- console.log(`Init ${resource}`);
675
- return {
676
- list: () => `List ${resource}`,
677
- get: (id) => `Get ${resource}/${id}`
678
- };
679
- });
680
-
681
- API.users.list(); // Logs: "Init users"
682
- API.users.get(1); // No log - cached 'users' instance
683
- API.posts.list(); // Logs: "Init posts" - new key, new instance
684
- API.posts.get(2); // No log - cached 'posts' instance
685
- ```
686
-
687
- ## When to Use Cache.memoize()
688
-
689
- ### ✅ Good Use Cases
690
- ```javascript
691
- import { Cache } from 'native-document/utils';
692
-
693
- // Multiple API endpoints with same structure
694
- const API = Cache.memoize((resource) => ({
695
- list: () => fetch(`/${resource}`),
696
- get: (id) => fetch(`/${resource}/${id}`)
697
- }));
698
-
699
- // Multiple storage namespaces
700
- const Storage = Cache.memoize((namespace) => ({
701
- get: (key) => localStorage.getItem(`${namespace}:${key}`),
702
- set: (key, val) => localStorage.setItem(`${namespace}:${key}`, val)
142
+ // Form fields with observables
143
+ const Fields = Cache.memoize(name => ({
144
+ value: Observable(''),
145
+ error: Observable(null),
146
+ reset: () => { Fields[name].value.set(''); Fields[name].error.set(null); }
703
147
  }));
704
148
 
705
- // Multiple event types with same handler structure
706
- const Events = Cache.memoize((type) => {
707
- const listeners = [];
708
- return {
709
- on: (cb) => listeners.push(cb),
710
- emit: (data) => listeners.forEach(cb => cb(data))
711
- };
712
- });
713
-
714
- // Multiple form fields with same structure
715
- const Fields = Cache.memoize((name) => ({
716
- value: Observable(''),
717
- error: Observable(null),
718
- validate: () => { /* ... */ }
719
- }));
149
+ Fields.email.value.set('alice@example.com');
150
+ Fields.password.value.set('secret');
720
151
  ```
721
152
 
722
- ### ❌ Bad Use Cases
723
- ```javascript
724
- import { Cache } from 'native-document/utils';
153
+ ---
725
154
 
726
- // ❌ Don't use for single instance
727
- const Config = Cache.memoize(() => loadConfig());
728
- // Use Cache.singleton() instead
155
+ ## Comparison
729
156
 
730
- // Don't use when keys are unpredictable
731
- const RandomData = Cache.memoize((timestamp) => generateData());
732
- // Each call has unique timestamp - cache never hits
157
+ | | `Cache.once()` | `Cache.singleton()` | `Cache.memoize()` |
158
+ |---|---|---|---|
159
+ | **Execution** | Lazy - on property access | Eager - on first call | Lazy - per key on property access |
160
+ | **Access** | `obj.property` | `fn()` | `obj.key.method()` |
161
+ | **Instances** | 1 | 1 | 1 per key |
162
+ | **Best for** | Optional modules | Core services | Resources by type |
733
163
 
734
- // ❌ Don't use for simple property access
735
- const Constants = Cache.memoize(() => ({
736
- PI: 3.14159,
737
- E: 2.71828
738
- }));
739
- // Use Cache.once() instead
740
- ```
164
+ ---
741
165
 
742
166
  ## Best Practices
743
167
 
744
- ### 1. Use Descriptive Keys
745
- ```javascript
746
- import { Cache } from 'native-document/utils';
747
-
748
- // Good: Clear, predictable keys
749
- const Endpoints = Cache.memoize((resource) => createAPI(resource));
750
- Endpoints.users.list();
751
- Endpoints.posts.list();
752
-
753
- // ❌ Bad: Dynamic, unpredictable keys
754
- const DynamicAPI = Cache.memoize((timestamp) => createAPI(timestamp));
755
- DynamicAPI[Date.now()].list(); // New instance every time
756
- ```
757
-
758
- ### 2. Document Key-Based Behavior
759
- ```javascript
760
- import { Cache } from 'native-document/utils';
761
-
762
- /**
763
- * API endpoints by resource type
764
- * @memoized Each resource type gets its own instance
765
- * @param {string} resource - Resource name (e.g., 'users', 'posts')
766
- */
767
- const API = Cache.memoize((resource) => ({
768
- list: () => fetch(`/${resource}`),
769
- get: (id) => fetch(`/${resource}/${id}`)
770
- }));
771
- ```
772
-
773
- ### 3. Keep Keys Simple
774
- ```javascript
775
- import { Cache } from 'native-document/utils';
776
-
777
- // ✅ Good: Simple string keys
778
- const Stores = Cache.memoize((name) => Store.create(name, {}));
779
- Stores.user;
780
- Stores.settings;
781
-
782
- // ❌ Bad: Complex keys (won't work as expected)
783
- const BadCache = Cache.memoize((config) => createThing(config));
784
- BadCache[{ type: 'user' }]; // Object as key - problematic
785
- ```
786
-
787
- ### 4. Combine with Other Patterns
788
- ```javascript
789
- import { Cache } from 'native-document/utils';
790
-
791
- // Eager config + Memoized resources
792
- const getConfig = Cache.singleton(() => loadConfig());
793
-
794
- const Resources = Cache.memoize((type) => {
795
- const config = getConfig(); // Config already loaded
796
- return createResource(type, config);
797
- });
798
- ```
799
-
800
- ## Performance Considerations
801
-
802
- ### Memory Usage
803
- ```javascript
804
- import { Cache } from 'native-document/utils';
805
-
806
- // ⚠️ Each key creates a new cached instance
807
- const API = Cache.memoize((resource) => createAPI(resource));
808
-
809
- API.users; // Instance 1
810
- API.posts; // Instance 2
811
- API.comments; // Instance 3
812
- // All instances stay in memory
813
-
814
- // Consider: Do you need separate instances per key?
815
- ```
816
-
817
- ### Cache Growth
818
- ```javascript
819
- import { Cache } from 'native-document/utils';
820
-
821
- // ⚠️ Warning: Unbounded cache growth
822
- const DynamicCache = Cache.memoize((id) => createInstance(id));
823
-
824
- // If IDs keep changing, cache grows indefinitely
825
- for (let i = 0; i < 1000; i++) {
826
- DynamicCache[`user-${i}`]; // 1000 cached instances
827
- }
828
-
829
- // ✅ Better: Limited, predictable keys
830
- const ResourceCache = Cache.memoize((type) => createResource(type));
831
- ResourceCache.users; // Only a few known types
832
- ResourceCache.posts;
833
- ResourceCache.comments;
834
- ```
835
-
836
- ## Summary
837
-
838
- ### Quick Reference
839
-
840
- | Pattern | Syntax | When to Use |
841
- |---------|--------|-------------|
842
- | **Lazy Module** | `Cache.once(() => {...})` | Optional features, heavy resources |
843
- | **Eager Singleton** | `Cache.singleton(() => {...})` | Core services, configuration |
844
- | **Multi-Instance** | `Cache.memoize((key) => {...})` | Resources by type, namespaced data |
845
-
846
- ### Key Differences
847
- ```javascript
848
- import { Cache } from 'native-document/utils';
849
-
850
- // Cache.once() - Single lazy instance via autoOnce
851
- const Lazy = Cache.once(() => ({ value: 1 }));
852
- Lazy.value; // Creates instance on property access
853
-
854
- // Cache.singleton() - Single eager instance via once
855
- const Eager = Cache.singleton(() => ({ value: 1 }));
856
- Eager(); // Creates instance on function call
857
-
858
- // Cache.memoize() - Multiple instances by key via autoMemoize
859
- const Multi = Cache.memoize((key) => ({ value: key }));
860
- Multi.a; // Creates instance for key 'a'
861
- Multi.b; // Creates instance for key 'b'
862
- ```
863
-
864
- ## Next Steps
168
+ 1. Use `Cache.singleton()` for core services (API client, config, logger)
169
+ 2. Use `Cache.once()` for optional or heavy modules that may not be needed
170
+ 3. Use `Cache.memoize()` for resources that share structure but need separate instances
171
+ 4. Keep memoize keys simple and predictable - avoid dynamic or timestamp-based keys
172
+ 5. Be aware that `Cache.memoize()` instances stay in memory - use only for a finite set of keys
865
173
 
866
- Explore related utilities and concepts:
174
+ ---
867
175
 
868
176
  ## Next Steps
869
177
 
870
- - **[Getting Started](getting-started.md)** - Installation and first steps
871
- - **[Core Concepts](core-concepts.md)** - Understanding the fundamentals
872
- - **[Observables](observables.md)** - Reactive state management
873
- - **[Elements](elements.md)** - Creating and composing UI
874
- - **[Conditional Rendering](conditional-rendering.md)** - Dynamic content
875
- - **[List Rendering](list-rendering.md)** - (ForEach | ForEachArray) and dynamic lists
876
- - **[Routing](routing.md)** - Navigation and URL management
877
- - **[State Management](state-management.md)** - Global state patterns
878
- - **[NDElement](native-document-element.md)** - Native Document Element
879
- - **[Extending NDElement](extending-native-document-element.md)** - Custom Methods Guide
880
- - **[Advanced Components](advanced-components.md)** - Template caching and singleton views
881
- - **[Args Validation](validation.md)** - Function Argument Validation
882
- - **[Memory Management](memory-management.md)** - Memory management
883
-
884
- ## Utilities
885
-
886
- - **[Cache](docs/utils/cache.md)** - Lazy initialization and singleton patterns
887
- - **[NativeFetch](docs/utils/native-fetch.md)** - HTTP client with interceptors
888
- - **[Filters](docs/utils/filters.md)** - Data filtering helpers
178
+ - **[NativeFetch](./native-fetch.md)** - HTTP client with interceptors
179
+ - **[State Management](./state-management.md)** - Global state with Store
180
+ - **[Observables](./observables.md)** - Reactive state management