native-document 1.0.15 → 1.0.16-8.2

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 (649) hide show
  1. package/.npmrc.example +1 -0
  2. package/.vitepress/config.js +166 -0
  3. package/CHANGELOG.md +153 -0
  4. package/cdn.js +19 -0
  5. package/components.d.ts +2 -0
  6. package/components.js +30 -0
  7. package/devtools/ComponentRegistry.js +113 -0
  8. package/devtools/index.js +8 -0
  9. package/devtools/plugin/dev-tools-plugin.js +15 -0
  10. package/devtools/transformers/nd-vite-devtools.js +55 -0
  11. package/devtools/transformers/src/transformComponentForHrm.js +73 -0
  12. package/devtools/transformers/src/transformJsFile.js +9 -0
  13. package/devtools/transformers/src/utils.js +79 -0
  14. package/devtools/transformers/templates/hrm.hook.template.js +46 -0
  15. package/devtools/transformers/templates/hrm.orbservable.hook.template.js +76 -0
  16. package/devtools/widget/Widget.js +49 -0
  17. package/devtools/widget/widget.css +81 -0
  18. package/devtools/widget.js +23 -0
  19. package/dist/native-document.components.min.css +1 -0
  20. package/dist/native-document.components.min.js +23847 -0
  21. package/dist/native-document.dev.js +8421 -1492
  22. package/dist/native-document.dev.js.map +1 -0
  23. package/dist/native-document.devtools.min.js +1 -0
  24. package/dist/native-document.min.js +1 -1
  25. package/docs/advanced-components.md +419 -0
  26. package/docs/anchor.md +181 -257
  27. package/docs/cache.md +180 -0
  28. package/docs/cli.md +179 -0
  29. package/docs/components/accordion.md +172 -0
  30. package/docs/components/alert.md +99 -0
  31. package/docs/components/avatar.md +160 -0
  32. package/docs/components/badge.md +102 -0
  33. package/docs/components/breadcrumb.md +89 -0
  34. package/docs/components/button.md +183 -0
  35. package/docs/components/card.md +69 -0
  36. package/docs/components/context-menu.md +118 -0
  37. package/docs/components/data-table.md +345 -0
  38. package/docs/components/dropdown.md +214 -0
  39. package/docs/components/form/autocomplete-field.md +81 -0
  40. package/docs/components/form/checkbox-field.md +41 -0
  41. package/docs/components/form/checkbox-group-field.md +54 -0
  42. package/docs/components/form/color-field.md +64 -0
  43. package/docs/components/form/date-field.md +92 -0
  44. package/docs/components/form/field-collection.md +63 -0
  45. package/docs/components/form/file-field.md +203 -0
  46. package/docs/components/form/form-control.md +87 -0
  47. package/docs/components/form/image-field.md +90 -0
  48. package/docs/components/form/index.md +115 -0
  49. package/docs/components/form/number-field.md +65 -0
  50. package/docs/components/form/radio-field.md +51 -0
  51. package/docs/components/form/select-field.md +123 -0
  52. package/docs/components/form/slider.md +136 -0
  53. package/docs/components/form/string-field.md +134 -0
  54. package/docs/components/form/textarea-field.md +65 -0
  55. package/docs/components/form-fields.md +372 -0
  56. package/docs/components/getting-started.md +264 -0
  57. package/docs/components/index.md +337 -0
  58. package/docs/components/layout.md +279 -0
  59. package/docs/components/list.md +73 -0
  60. package/docs/components/menu.md +215 -0
  61. package/docs/components/modal.md +156 -0
  62. package/docs/components/pagination.md +95 -0
  63. package/docs/components/popover.md +131 -0
  64. package/docs/components/progress.md +111 -0
  65. package/docs/components/shortcut-manager.md +221 -0
  66. package/docs/components/simple-table.md +107 -0
  67. package/docs/components/skeleton.md +155 -0
  68. package/docs/components/spinner.md +100 -0
  69. package/docs/components/splitter.md +133 -0
  70. package/docs/components/stepper.md +163 -0
  71. package/docs/components/switch.md +113 -0
  72. package/docs/components/tabs.md +153 -0
  73. package/docs/components/toast.md +119 -0
  74. package/docs/components/tooltip.md +151 -0
  75. package/docs/components/traits.md +261 -0
  76. package/docs/conditional-rendering.md +177 -502
  77. package/docs/contributing.md +300 -25
  78. package/docs/core-concepts.md +207 -366
  79. package/docs/elements.md +266 -254
  80. package/docs/extending-native-document-element.md +259 -0
  81. package/docs/filters.md +247 -0
  82. package/docs/getting-started.md +195 -257
  83. package/docs/i18n.md +241 -0
  84. package/docs/index.md +76 -0
  85. package/docs/lifecycle-events.md +146 -67
  86. package/docs/list-rendering.md +240 -460
  87. package/docs/memory-management.md +135 -46
  88. package/docs/native-document-element.md +487 -0
  89. package/docs/native-fetch.md +213 -0
  90. package/docs/observable-resource.md +364 -0
  91. package/docs/observables.md +690 -357
  92. package/docs/routing.md +246 -646
  93. package/docs/state-management.md +213 -306
  94. package/docs/svg-elements.md +231 -0
  95. package/docs/theming.md +409 -0
  96. package/docs/tutorials/.gitkeep +0 -0
  97. package/docs/validation.md +98 -91
  98. package/docs/vitepress-conventions.md +219 -0
  99. package/elements.d.ts +7 -0
  100. package/elements.js +3 -4
  101. package/eslint.config.js +35 -0
  102. package/i18n.js +1 -0
  103. package/i18n.ts +2 -0
  104. package/index.d.ts +21 -0
  105. package/index.def.js +1086 -0
  106. package/index.js +19 -13
  107. package/package.json +59 -9
  108. package/readme.md +296 -93
  109. package/rollup.config.js +52 -3
  110. package/router.d.ts +7 -0
  111. package/router.js +0 -0
  112. package/src/components/$traits/has-draggable/HasDraggable.d.ts +4 -0
  113. package/src/components/$traits/has-draggable/HasDraggable.js +82 -0
  114. package/src/components/$traits/has-draggable/has-draggable.css +8 -0
  115. package/src/components/$traits/has-items/HasItems.d.ts +9 -0
  116. package/src/components/$traits/has-items/HasItems.js +64 -0
  117. package/src/components/$traits/has-position/HasFullPosition.d.ts +14 -0
  118. package/src/components/$traits/has-position/HasFullPosition.js +95 -0
  119. package/src/components/$traits/has-position/HasPosition.d.ts +7 -0
  120. package/src/components/$traits/has-position/HasPosition.js +45 -0
  121. package/src/components/$traits/has-resizable/HasResizable.d.ts +13 -0
  122. package/src/components/$traits/has-resizable/HasResizable.js +122 -0
  123. package/src/components/$traits/has-resizable/has-resizable.css +121 -0
  124. package/src/components/$traits/has-validation/HasValidation.d.ts +17 -0
  125. package/src/components/$traits/has-validation/HasValidation.js +133 -0
  126. package/src/components/BaseComponent.d.ts +32 -0
  127. package/src/components/BaseComponent.js +247 -0
  128. package/src/components/accordion/Accordion.js +268 -0
  129. package/src/components/accordion/AccordionItem.js +233 -0
  130. package/src/components/accordion/index.js +7 -0
  131. package/src/components/accordion/types/Accordion.d.ts +47 -0
  132. package/src/components/accordion/types/AccordionItem.d.ts +48 -0
  133. package/src/components/alert/Alert.js +350 -0
  134. package/src/components/alert/index.js +6 -0
  135. package/src/components/alert/types/Alert.d.ts +62 -0
  136. package/src/components/avatar/Avatar.js +430 -0
  137. package/src/components/avatar/AvatarGroup.js +97 -0
  138. package/src/components/avatar/index.js +7 -0
  139. package/src/components/avatar/types/Avatar.d.ts +74 -0
  140. package/src/components/avatar/types/AvatarGroup.d.ts +32 -0
  141. package/src/components/badge/Badge.js +245 -0
  142. package/src/components/badge/index.js +6 -0
  143. package/src/components/badge/types/Badge.d.ts +51 -0
  144. package/src/components/base-component.css +0 -0
  145. package/src/components/breadcrumb/BreadCrumb.js +138 -0
  146. package/src/components/breadcrumb/index.js +5 -0
  147. package/src/components/breadcrumb/types/BreadCrumb.d.ts +42 -0
  148. package/src/components/button/Button.js +320 -0
  149. package/src/components/button/index.js +5 -0
  150. package/src/components/button/types/Button.d.ts +62 -0
  151. package/src/components/card/Card.js +282 -0
  152. package/src/components/card/index.js +5 -0
  153. package/src/components/card/types/Card.d.ts +42 -0
  154. package/src/components/context-menu/ContextMenu.js +127 -0
  155. package/src/components/context-menu/ContextMenuGroup.js +29 -0
  156. package/src/components/context-menu/ContextMenuItem.js +28 -0
  157. package/src/components/context-menu/index.js +10 -0
  158. package/src/components/context-menu/types/ContextMenu.d.ts +30 -0
  159. package/src/components/context-menu/types/ContextMenuGroup.d.ts +18 -0
  160. package/src/components/context-menu/types/ContextMenuItem.d.ts +18 -0
  161. package/src/components/divider/Divider.js +256 -0
  162. package/src/components/divider/index.js +6 -0
  163. package/src/components/divider/types/Divider.d.ts +55 -0
  164. package/src/components/dropdown/Dropdown.js +531 -0
  165. package/src/components/dropdown/DropdownDivider.js +45 -0
  166. package/src/components/dropdown/DropdownGroup.js +83 -0
  167. package/src/components/dropdown/DropdownItem.js +150 -0
  168. package/src/components/dropdown/DropdownTrigger.js +93 -0
  169. package/src/components/dropdown/helpers.js +53 -0
  170. package/src/components/dropdown/index.js +13 -0
  171. package/src/components/dropdown/types/Dropdown.d.ts +88 -0
  172. package/src/components/dropdown/types/DropdownDivider.d.ts +20 -0
  173. package/src/components/dropdown/types/DropdownGroup.d.ts +25 -0
  174. package/src/components/dropdown/types/DropdownItem.d.ts +41 -0
  175. package/src/components/dropdown/types/DropdownTrigger.d.ts +32 -0
  176. package/src/components/form/FormControl.js +498 -0
  177. package/src/components/form/field/Field.js +419 -0
  178. package/src/components/form/field/FieldCollection.js +292 -0
  179. package/src/components/form/field/types/AutocompleteField.js +168 -0
  180. package/src/components/form/field/types/CheckboxField.js +77 -0
  181. package/src/components/form/field/types/CheckboxGroupField.js +171 -0
  182. package/src/components/form/field/types/ColorField.js +102 -0
  183. package/src/components/form/field/types/DateField.js +315 -0
  184. package/src/components/form/field/types/EmailField.js +104 -0
  185. package/src/components/form/field/types/FileField.js +276 -0
  186. package/src/components/form/field/types/HiddenField.js +44 -0
  187. package/src/components/form/field/types/ImageField.js +138 -0
  188. package/src/components/form/field/types/NumberField.js +177 -0
  189. package/src/components/form/field/types/PasswordField.js +200 -0
  190. package/src/components/form/field/types/RadioField.js +145 -0
  191. package/src/components/form/field/types/RangeField.js +117 -0
  192. package/src/components/form/field/types/SearchField.js +66 -0
  193. package/src/components/form/field/types/SelectField.js +247 -0
  194. package/src/components/form/field/types/StringField.js +148 -0
  195. package/src/components/form/field/types/TelField.js +98 -0
  196. package/src/components/form/field/types/TextAreaField.js +142 -0
  197. package/src/components/form/field/types/TimeField.js +215 -0
  198. package/src/components/form/field/types/UrlField.js +115 -0
  199. package/src/components/form/field/types/file-field-mode/FileAvatarMode.js +183 -0
  200. package/src/components/form/field/types/file-field-mode/FileDropzoneMode.js +117 -0
  201. package/src/components/form/field/types/file-field-mode/FileItemPreview.js +150 -0
  202. package/src/components/form/field/types/file-field-mode/FileNativeMode.js +43 -0
  203. package/src/components/form/field/types/file-field-mode/FileUploadButtonMode.js +120 -0
  204. package/src/components/form/field/types/file-field-mode/FileWallMode.js +106 -0
  205. package/src/components/form/index.js +61 -0
  206. package/src/components/form/merge +0 -0
  207. package/src/components/form/types/Field.d.ts +73 -0
  208. package/src/components/form/types/FieldCollection.d.ts +53 -0
  209. package/src/components/form/types/FormControl.d.ts +64 -0
  210. package/src/components/form/types/fields/AutocompleteField.d.ts +48 -0
  211. package/src/components/form/types/fields/CheckboxField.d.ts +33 -0
  212. package/src/components/form/types/fields/CheckboxGroupField.d.ts +49 -0
  213. package/src/components/form/types/fields/ColorField.d.ts +37 -0
  214. package/src/components/form/types/fields/DateField.d.ts +70 -0
  215. package/src/components/form/types/fields/EmailField.d.ts +35 -0
  216. package/src/components/form/types/fields/FileAvatarMode.d.ts +46 -0
  217. package/src/components/form/types/fields/FileDropzoneMode.d.ts +28 -0
  218. package/src/components/form/types/fields/FileField.d.ts +56 -0
  219. package/src/components/form/types/fields/FileItemPreview.d.ts +35 -0
  220. package/src/components/form/types/fields/FileNativeMode.d.ts +21 -0
  221. package/src/components/form/types/fields/FileUploadButtonMode.d.ts +34 -0
  222. package/src/components/form/types/fields/FileWallMode.d.ts +32 -0
  223. package/src/components/form/types/fields/HiddenField.d.ts +26 -0
  224. package/src/components/form/types/fields/ImageField.d.ts +45 -0
  225. package/src/components/form/types/fields/NumberField.d.ts +48 -0
  226. package/src/components/form/types/fields/PasswordField.d.ts +46 -0
  227. package/src/components/form/types/fields/RadioField.d.ts +48 -0
  228. package/src/components/form/types/fields/RangeField.d.ts +44 -0
  229. package/src/components/form/types/fields/SearchField.d.ts +34 -0
  230. package/src/components/form/types/fields/SelectField.d.ts +71 -0
  231. package/src/components/form/types/fields/StringField.d.ts +48 -0
  232. package/src/components/form/types/fields/TelField.d.ts +37 -0
  233. package/src/components/form/types/fields/TextAreaField.d.ts +44 -0
  234. package/src/components/form/types/fields/TimeField.d.ts +51 -0
  235. package/src/components/form/types/fields/UrlField.d.ts +35 -0
  236. package/src/components/form/utils.js +17 -0
  237. package/src/components/form/validation/Validation.js +565 -0
  238. package/src/components/index.d.ts +160 -0
  239. package/src/components/list/HasListItem.js +171 -0
  240. package/src/components/list/List.js +125 -0
  241. package/src/components/list/ListDivider.js +39 -0
  242. package/src/components/list/ListGroup.js +135 -0
  243. package/src/components/list/ListItem.js +212 -0
  244. package/src/components/list/index.js +12 -0
  245. package/src/components/list/types/List.d.ts +43 -0
  246. package/src/components/list/types/ListGroup.d.ts +37 -0
  247. package/src/components/list/types/ListItem.d.ts +53 -0
  248. package/src/components/menu/HasMenuItem.js +182 -0
  249. package/src/components/menu/Menu.js +227 -0
  250. package/src/components/menu/MenuDivider.js +37 -0
  251. package/src/components/menu/MenuGroup.js +126 -0
  252. package/src/components/menu/MenuItem.js +190 -0
  253. package/src/components/menu/MenuLink.js +51 -0
  254. package/src/components/menu/index.js +14 -0
  255. package/src/components/menu/types/Menu.d.ts +60 -0
  256. package/src/components/menu/types/MenuDivider.d.ts +19 -0
  257. package/src/components/menu/types/MenuGroup.d.ts +44 -0
  258. package/src/components/menu/types/MenuItem.d.ts +46 -0
  259. package/src/components/menu/types/MenuLink.d.ts +16 -0
  260. package/src/components/modal/Modal.js +524 -0
  261. package/src/components/modal/index.js +5 -0
  262. package/src/components/modal/types/Modal.d.ts +94 -0
  263. package/src/components/pagination/Pagination.js +411 -0
  264. package/src/components/pagination/index.js +5 -0
  265. package/src/components/pagination/types/Pagination.d.ts +68 -0
  266. package/src/components/popover/Popover.js +459 -0
  267. package/src/components/popover/PopoverFooter.js +61 -0
  268. package/src/components/popover/PopoverHeader.js +68 -0
  269. package/src/components/popover/index.js +10 -0
  270. package/src/components/popover/types/Popover.d.ts +83 -0
  271. package/src/components/popover/types/PopoverFooter.d.ts +24 -0
  272. package/src/components/popover/types/PopoverHeader.d.ts +26 -0
  273. package/src/components/progress/Progress.js +401 -0
  274. package/src/components/progress/index.js +6 -0
  275. package/src/components/progress/types/Progress.d.ts +77 -0
  276. package/src/components/skeleton/Skeleton.js +228 -0
  277. package/src/components/skeleton/index.js +6 -0
  278. package/src/components/skeleton/types/Skeleton.d.ts +55 -0
  279. package/src/components/slider/Slider.js +406 -0
  280. package/src/components/slider/index.js +5 -0
  281. package/src/components/slider/types/Slider.d.ts +82 -0
  282. package/src/components/spacer/Spacer.js +27 -0
  283. package/src/components/spacer/index.js +5 -0
  284. package/src/components/spacer/types/Spacer.d.ts +19 -0
  285. package/src/components/spinner/Spinner.js +350 -0
  286. package/src/components/spinner/index.js +5 -0
  287. package/src/components/spinner/types/Spinner.d.ts +71 -0
  288. package/src/components/splitter/Splitter.js +164 -0
  289. package/src/components/splitter/SplitterGutter.js +140 -0
  290. package/src/components/splitter/SplitterPanel.js +143 -0
  291. package/src/components/splitter/index.js +10 -0
  292. package/src/components/splitter/types/Splitter.d.ts +38 -0
  293. package/src/components/splitter/types/SplitterGutter.d.ts +38 -0
  294. package/src/components/splitter/types/SplitterPanel.d.ts +41 -0
  295. package/src/components/stacks/AbsoluteStack.js +53 -0
  296. package/src/components/stacks/FixedStack.js +53 -0
  297. package/src/components/stacks/HStack.js +54 -0
  298. package/src/components/stacks/PositionStack.js +254 -0
  299. package/src/components/stacks/RelativeStack.js +53 -0
  300. package/src/components/stacks/Stack.js +166 -0
  301. package/src/components/stacks/VStack.js +55 -0
  302. package/src/components/stacks/index.js +21 -0
  303. package/src/components/stacks/types/AbsoluteStack.d.ts +16 -0
  304. package/src/components/stacks/types/FixedStack.d.ts +16 -0
  305. package/src/components/stacks/types/HStack.d.ts +16 -0
  306. package/src/components/stacks/types/PositionStack.d.ts +54 -0
  307. package/src/components/stacks/types/RelativeStack.d.ts +17 -0
  308. package/src/components/stacks/types/Stack.d.ts +39 -0
  309. package/src/components/stacks/types/VStack.d.ts +16 -0
  310. package/src/components/stepper/Stepper.js +461 -0
  311. package/src/components/stepper/StepperStep.js +241 -0
  312. package/src/components/stepper/index.js +8 -0
  313. package/src/components/stepper/types/Stepper.d.ts +68 -0
  314. package/src/components/stepper/types/StepperStep.d.ts +54 -0
  315. package/src/components/switch/Switch.js +266 -0
  316. package/src/components/switch/index.js +6 -0
  317. package/src/components/switch/types/Switch.d.ts +55 -0
  318. package/src/components/table/Column.js +212 -0
  319. package/src/components/table/ColumnGroup.js +90 -0
  320. package/src/components/table/DataTable.js +720 -0
  321. package/src/components/table/SimpleTable.js +139 -0
  322. package/src/components/table/index.js +7 -0
  323. package/src/components/table/types/Column.d.ts +49 -0
  324. package/src/components/table/types/ColumnGroup.d.ts +28 -0
  325. package/src/components/table/types/DataTable.d.ts +97 -0
  326. package/src/components/table/types/SimpleTable.d.ts +40 -0
  327. package/src/components/tabs/Tabs.js +395 -0
  328. package/src/components/tabs/index.js +6 -0
  329. package/src/components/tabs/types/Tabs.d.ts +78 -0
  330. package/src/components/toast/Toast.js +262 -0
  331. package/src/components/toast/ToastError.js +0 -0
  332. package/src/components/toast/ToastInfo.js +0 -0
  333. package/src/components/toast/ToastSuccess.js +0 -0
  334. package/src/components/toast/ToastWarning.js +0 -0
  335. package/src/components/toast/index.js +5 -0
  336. package/src/components/toast/types/Toast.d.ts +57 -0
  337. package/src/components/toast/types/ToastError.d.ts +7 -0
  338. package/src/components/toast/types/ToastInfo.d.ts +7 -0
  339. package/src/components/toast/types/ToastSuccess.d.ts +7 -0
  340. package/src/components/toast/types/ToastWarning.d.ts +7 -0
  341. package/src/components/tooltip/Tooltip.js +359 -0
  342. package/src/components/tooltip/index.js +5 -0
  343. package/src/components/tooltip/prototypes.js +6 -0
  344. package/src/components/tooltip/types/Tooltip.d.ts +65 -0
  345. package/src/{data → core/data}/MemoryManager.js +2 -3
  346. package/src/core/data/Observable.js +227 -0
  347. package/src/core/data/ObservableArray.js +522 -0
  348. package/src/core/data/ObservableChecker.js +39 -0
  349. package/src/core/data/ObservableItem.js +611 -0
  350. package/src/core/data/ObservableObject.js +274 -0
  351. package/src/core/data/ObservableResource.js +315 -0
  352. package/src/core/data/ObservableWhen.js +54 -0
  353. package/src/core/data/Store.js +520 -0
  354. package/src/core/data/observable-helpers/observable.is-to.js +390 -0
  355. package/src/core/data/observable-helpers/observable.prototypes.js +145 -0
  356. package/src/core/elements/anchor/anchor-with-sentinel.js +66 -0
  357. package/src/core/elements/anchor/anchor.js +210 -0
  358. package/src/core/elements/anchor/one-child-anchor-overwriting.js +66 -0
  359. package/src/core/elements/content-formatter.js +169 -0
  360. package/src/core/elements/control/for-each-array.js +292 -0
  361. package/src/{elements → core/elements}/control/for-each.js +42 -23
  362. package/src/core/elements/control/show-if.js +94 -0
  363. package/src/core/elements/control/show-when.js +54 -0
  364. package/src/core/elements/control/switch.js +141 -0
  365. package/src/core/elements/description-list.js +19 -0
  366. package/src/core/elements/form.js +255 -0
  367. package/src/core/elements/fragment.js +8 -0
  368. package/src/core/elements/html5-semantics.js +55 -0
  369. package/src/core/elements/img.js +59 -0
  370. package/src/{elements → core/elements}/index.js +4 -4
  371. package/src/core/elements/interactive.js +25 -0
  372. package/src/core/elements/list.js +37 -0
  373. package/src/core/elements/medias.js +37 -0
  374. package/src/core/elements/meta-data.js +43 -0
  375. package/src/core/elements/svg.js +61 -0
  376. package/src/core/elements/table.js +73 -0
  377. package/src/{errors → core/errors}/ArgTypesError.js +1 -1
  378. package/src/{errors → core/errors}/NativeDocumentError.js +0 -0
  379. package/src/core/utils/HasEventEmitter.js +85 -0
  380. package/src/core/utils/args-types.js +140 -0
  381. package/src/core/utils/cache.js +5 -0
  382. package/src/core/utils/callback-handler.js +50 -0
  383. package/src/core/utils/debug-manager.js +40 -0
  384. package/src/core/utils/events.js +148 -0
  385. package/src/core/utils/filters/date.js +178 -0
  386. package/src/core/utils/filters/index.js +4 -0
  387. package/src/core/utils/filters/standard.js +263 -0
  388. package/src/core/utils/filters/strings.js +67 -0
  389. package/src/core/utils/filters/utils.js +77 -0
  390. package/src/core/utils/formatters.js +90 -0
  391. package/src/core/utils/helpers.js +144 -0
  392. package/src/core/utils/localstorage.js +57 -0
  393. package/src/core/utils/memoize.js +115 -0
  394. package/src/core/utils/plugins-manager.js +81 -0
  395. package/src/core/utils/property-accumulator.js +72 -0
  396. package/src/core/utils/prototypes.js +44 -0
  397. package/src/core/utils/shortcut-manager.js +242 -0
  398. package/src/{utils → core/utils}/validator.js +58 -22
  399. package/src/core/wrappers/AttributesWrapper.js +98 -0
  400. package/src/core/wrappers/DocumentObserver.js +182 -0
  401. package/src/core/wrappers/ElementCreator.js +120 -0
  402. package/src/core/wrappers/HtmlElementWrapper.js +98 -0
  403. package/src/core/wrappers/NDElement.js +613 -0
  404. package/src/core/wrappers/NdPrototype.js +233 -0
  405. package/src/core/wrappers/SingletonView.js +99 -0
  406. package/src/core/wrappers/SvgElementWrapper.js +15 -0
  407. package/src/core/wrappers/TemplateBinding.js +7 -0
  408. package/src/core/wrappers/constants.js +66 -0
  409. package/src/core/wrappers/prototypes/attributes-extensions.js +179 -0
  410. package/src/core/wrappers/prototypes/bind-class-extensions.js +0 -0
  411. package/src/core/wrappers/prototypes/nd-element-extensions.js +157 -0
  412. package/src/core/wrappers/prototypes/nd-element.transition.extensions.js +127 -0
  413. package/src/core/wrappers/template-cloner/NodeCloner.js +209 -0
  414. package/src/core/wrappers/template-cloner/TemplateCloner.js +192 -0
  415. package/src/core/wrappers/template-cloner/attributes-hydrator.js +142 -0
  416. package/src/core/wrappers/template-cloner/utils.js +173 -0
  417. package/src/fetch/NativeFetch.js +89 -0
  418. package/src/i18n/bin/scan.js +132 -0
  419. package/src/i18n/index.d.ts +2 -0
  420. package/src/i18n/service/I18nService.d.ts +27 -0
  421. package/src/i18n/service/I18nService.js +46 -0
  422. package/src/i18n/service/functions.d.ts +22 -0
  423. package/src/i18n/service/functions.js +29 -0
  424. package/src/router/Route.js +33 -8
  425. package/src/router/RouteGroupHelper.js +10 -2
  426. package/src/router/Router.js +63 -22
  427. package/src/router/RouterComponent.js +114 -6
  428. package/src/{errors → router/errors}/RouterError.js +0 -1
  429. package/src/router/link.js +9 -10
  430. package/src/router/modes/HashRouter.js +2 -2
  431. package/src/router/modes/HistoryRouter.js +2 -3
  432. package/src/router/modes/MemoryRouter.js +1 -1
  433. package/src/ui/components/accordion/AccordionItemRender.js +63 -0
  434. package/src/ui/components/accordion/AccordionRender.js +35 -0
  435. package/src/ui/components/accordion/accordion.css +121 -0
  436. package/src/ui/components/alert/AlertRender.js +81 -0
  437. package/src/ui/components/alert/alert.css +163 -0
  438. package/src/ui/components/avatar/avata-group/AvatarGroupRender.js +50 -0
  439. package/src/ui/components/avatar/avata-group/avatar-group.css +38 -0
  440. package/src/ui/components/avatar/avatar/AvatarRender.js +87 -0
  441. package/src/ui/components/avatar/avatar/avatar.css +189 -0
  442. package/src/ui/components/badge/BadgeRender.js +25 -0
  443. package/src/ui/components/badge/badge.css +168 -0
  444. package/src/ui/components/breadcrumb/BreadcrumbRender.js +44 -0
  445. package/src/ui/components/breadcrumb/breadcrumb.css +55 -0
  446. package/src/ui/components/button/ButtonRender.js +65 -0
  447. package/src/ui/components/button/button.css +296 -0
  448. package/src/ui/components/card/CardRender.js +133 -0
  449. package/src/ui/components/card/card.css +169 -0
  450. package/src/ui/components/contextmenu/ContextmenuRender.js +68 -0
  451. package/src/ui/components/contextmenu/contextmenu.css +36 -0
  452. package/src/ui/components/divider/DividerRender.js +70 -0
  453. package/src/ui/components/divider/divider.css +70 -0
  454. package/src/ui/components/dropdown/DropdownRender.js +92 -0
  455. package/src/ui/components/dropdown/divider/DropdownDividerRender.js +9 -0
  456. package/src/ui/components/dropdown/divider/dropdown-divider.css +0 -0
  457. package/src/ui/components/dropdown/dropdown.css +179 -0
  458. package/src/ui/components/dropdown/group/DropdownGroupRender.js +23 -0
  459. package/src/ui/components/dropdown/group/dropdown-group.css +0 -0
  460. package/src/ui/components/dropdown/item/DropdownItemRender.js +29 -0
  461. package/src/ui/components/dropdown/item/dropdown-item.css +0 -0
  462. package/src/ui/components/form/FieldCollectionRender.js +110 -0
  463. package/src/ui/components/form/FormControlRender.js +85 -0
  464. package/src/ui/components/form/field-collection.css +55 -0
  465. package/src/ui/components/form/fields/AutocompleteFieldRender.js +143 -0
  466. package/src/ui/components/form/fields/CheckboxFieldRender.js +59 -0
  467. package/src/ui/components/form/fields/CheckboxGroupFieldRender.js +92 -0
  468. package/src/ui/components/form/fields/ColorFieldRender.js +30 -0
  469. package/src/ui/components/form/fields/DateFieldRender.js +155 -0
  470. package/src/ui/components/form/fields/EmailFieldRender.js +5 -0
  471. package/src/ui/components/form/fields/FieldRender.js +118 -0
  472. package/src/ui/components/form/fields/FileFieldRender.js +41 -0
  473. package/src/ui/components/form/fields/HiddenFieldRender.js +13 -0
  474. package/src/ui/components/form/fields/ImageFieldRender.js +0 -0
  475. package/src/ui/components/form/fields/NumberFieldRender.js +52 -0
  476. package/src/ui/components/form/fields/PasswordFieldRender.js +65 -0
  477. package/src/ui/components/form/fields/RadioFieldRender.js +77 -0
  478. package/src/ui/components/form/fields/RangeFieldRender.js +122 -0
  479. package/src/ui/components/form/fields/SelectFieldRender.js +248 -0
  480. package/src/ui/components/form/fields/SliderFieldRender.js +359 -0
  481. package/src/ui/components/form/fields/StringFieldRender.js +6 -0
  482. package/src/ui/components/form/fields/TelFieldRender.js +6 -0
  483. package/src/ui/components/form/fields/TextAreaFieldRender.js +96 -0
  484. package/src/ui/components/form/fields/TimeFieldRender.js +142 -0
  485. package/src/ui/components/form/fields/UrlFieldRender.js +6 -0
  486. package/src/ui/components/form/fields/date-field.css +32 -0
  487. package/src/ui/components/form/fields/field.css +402 -0
  488. package/src/ui/components/form/fields/file-field.css +79 -0
  489. package/src/ui/components/form/fields/password-field.css +50 -0
  490. package/src/ui/components/form/fields/range-field.css +120 -0
  491. package/src/ui/components/form/fields/slider.css +195 -0
  492. package/src/ui/components/form/file-upload-mode/FileAvatarModeRender.js +143 -0
  493. package/src/ui/components/form/file-upload-mode/FileDropzoneModeRender.js +108 -0
  494. package/src/ui/components/form/file-upload-mode/FileNativeModeRender.js +22 -0
  495. package/src/ui/components/form/file-upload-mode/FileUploadButtonModeRender.js +89 -0
  496. package/src/ui/components/form/file-upload-mode/FileWallModeRender.js +90 -0
  497. package/src/ui/components/form/file-upload-mode/file-avatar-mode.css +139 -0
  498. package/src/ui/components/form/file-upload-mode/file-dropzone-mode.css +88 -0
  499. package/src/ui/components/form/file-upload-mode/file-upload-button-mode.css +44 -0
  500. package/src/ui/components/form/file-upload-mode/file-wall-mode.css +88 -0
  501. package/src/ui/components/form/form-control.css +40 -0
  502. package/src/ui/components/form/helpers.js +111 -0
  503. package/src/ui/components/form/index.js +27 -0
  504. package/src/ui/components/list/ListRender.js +18 -0
  505. package/src/ui/components/list/divider/ListDividerRender.js +10 -0
  506. package/src/ui/components/list/divider/list-divider.css +12 -0
  507. package/src/ui/components/list/group/ListGroupRender.js +61 -0
  508. package/src/ui/components/list/group/list-group.css +62 -0
  509. package/src/ui/components/list/item/ListItemRender.js +238 -0
  510. package/src/ui/components/list/item/list-item.css +191 -0
  511. package/src/ui/components/list/list.css +24 -0
  512. package/src/ui/components/menu/MenuDividerRender.js +12 -0
  513. package/src/ui/components/menu/MenuGroupRender.js +59 -0
  514. package/src/ui/components/menu/MenuItemRender.js +57 -0
  515. package/src/ui/components/menu/MenuLinkRender.js +55 -0
  516. package/src/ui/components/menu/MenuRender.js +22 -0
  517. package/src/ui/components/menu/helpers.js +121 -0
  518. package/src/ui/components/menu/menu.css +308 -0
  519. package/src/ui/components/modal/ModalRender.js +118 -0
  520. package/src/ui/components/modal/modal.css +156 -0
  521. package/src/ui/components/pagination/PaginationRender.js +112 -0
  522. package/src/ui/components/pagination/pagination.css +63 -0
  523. package/src/ui/components/popover/PopoverRender.js +233 -0
  524. package/src/ui/components/popover/popover.css +139 -0
  525. package/src/ui/components/progress/ProgressRender.js +168 -0
  526. package/src/ui/components/progress/progress.css +197 -0
  527. package/src/ui/components/skeleton/SkeletonRender.js +136 -0
  528. package/src/ui/components/skeleton/skeleton.css +154 -0
  529. package/src/ui/components/spacer/SpacerRender.js +10 -0
  530. package/src/ui/components/spinner/SpinnerRender.js +47 -0
  531. package/src/ui/components/spinner/spinner.css +152 -0
  532. package/src/ui/components/splitter/SplitterGutterRender.js +94 -0
  533. package/src/ui/components/splitter/SplitterPanelRender.js +38 -0
  534. package/src/ui/components/splitter/SplitterRender.js +75 -0
  535. package/src/ui/components/splitter/splitter.css +128 -0
  536. package/src/ui/components/stacks/PositionStackRender.js +39 -0
  537. package/src/ui/components/stacks/StackRender.js +41 -0
  538. package/src/ui/components/stacks/absolute-stack/AbsoluteStackRender.js +5 -0
  539. package/src/ui/components/stacks/fixed-stack/FixedStackRender.js +5 -0
  540. package/src/ui/components/stacks/h-stack/HStackRender.js +7 -0
  541. package/src/ui/components/stacks/h-stack/h-stack.css +4 -0
  542. package/src/ui/components/stacks/index.js +5 -0
  543. package/src/ui/components/stacks/position-stack.css +62 -0
  544. package/src/ui/components/stacks/relative-stack/RelativeStackRender.js +7 -0
  545. package/src/ui/components/stacks/relative-stack/relative-stack.css +3 -0
  546. package/src/ui/components/stacks/stack.css +78 -0
  547. package/src/ui/components/stacks/v-stack/VStackRender.js +6 -0
  548. package/src/ui/components/stacks/v-stack/v-stack.css +4 -0
  549. package/src/ui/components/stepper/StepperRender.js +71 -0
  550. package/src/ui/components/stepper/StepperStepRender.js +67 -0
  551. package/src/ui/components/stepper/stepper.css +359 -0
  552. package/src/ui/components/switch/SwitchRender.js +83 -0
  553. package/src/ui/components/switch/switch.css +143 -0
  554. package/src/ui/components/table/data-table/DataTableRender.js +50 -0
  555. package/src/ui/components/table/data-table/bulk-actions.js +34 -0
  556. package/src/ui/components/table/data-table/data-table.css +246 -0
  557. package/src/ui/components/table/data-table/pagination.js +56 -0
  558. package/src/ui/components/table/data-table/tables.js +368 -0
  559. package/src/ui/components/table/data-table/toolbar.js +67 -0
  560. package/src/ui/components/table/simple-table/SimpleTableRender.js +203 -0
  561. package/src/ui/components/table/simple-table/simple-table.css +50 -0
  562. package/src/ui/components/tabs/TabsRender.js +226 -0
  563. package/src/ui/components/tabs/tabs.css +253 -0
  564. package/src/ui/components/toast/ToastRender.js +99 -0
  565. package/src/ui/components/toast/toast.css +201 -0
  566. package/src/ui/components/tooltip/TooltipRender.js +8 -0
  567. package/src/ui/components/tooltip/tooltip.css +113 -0
  568. package/src/ui/index.js +47 -0
  569. package/src/ui/theme.js +0 -0
  570. package/src/ui/theme.scss +1 -0
  571. package/src/ui/tokens/animation.scss +36 -0
  572. package/src/ui/tokens/colors-dark.scss +58 -0
  573. package/src/ui/tokens/colors.scss +54 -0
  574. package/src/ui/tokens/components.scss +32 -0
  575. package/src/ui/tokens/fonts.scss +57 -0
  576. package/src/ui/tokens/glass.scss +10 -0
  577. package/src/ui/tokens/index.scss +38 -0
  578. package/src/ui/tokens/layouts.scss +228 -0
  579. package/src/ui/tokens/opacity.scss +21 -0
  580. package/src/ui/tokens/others.scss +11 -0
  581. package/src/ui/tokens/radius.scss +6 -0
  582. package/src/ui/tokens/reset.scss +51 -0
  583. package/src/ui/tokens/shadows.scss +29 -0
  584. package/src/ui/tokens/spacings.scss +13 -0
  585. package/src/ui/tokens/vars.scss +35 -0
  586. package/src/ui/tokens/viewports.scss +30 -0
  587. package/types/args-types.d.ts +58 -0
  588. package/types/control-flow.d.ts +62 -0
  589. package/types/elements.d.ts +231 -0
  590. package/types/filters/dates.d.ts +43 -0
  591. package/types/filters/index.d.ts +4 -0
  592. package/types/filters/standard.d.ts +70 -0
  593. package/types/filters/strings.d.ts +21 -0
  594. package/types/filters/types.d.ts +20 -0
  595. package/types/forms.d.ts +84 -0
  596. package/types/globals.d.ts +543 -0
  597. package/types/images.d.ts +23 -0
  598. package/types/localStorage.ts +102 -0
  599. package/types/memoize.d.ts +26 -0
  600. package/types/native-fetch.d.ts +72 -0
  601. package/types/nd-element.d.ts +407 -0
  602. package/types/observable-resource.d.ts +3 -0
  603. package/types/observable.d.ts +227 -0
  604. package/types/plugins-manager.d.ts +65 -0
  605. package/types/polyfill.d.ts +18 -0
  606. package/types/property-accumulator.d.ts +33 -0
  607. package/types/router.d.ts +85 -0
  608. package/types/service.d.ts +23 -0
  609. package/types/singleton.d.ts +19 -0
  610. package/types/store.d.ts +63 -0
  611. package/types/template-cloner.ts +43 -0
  612. package/types/validator.ts +66 -0
  613. package/ui.js +1 -0
  614. package/utils.d.ts +4 -0
  615. package/utils.js +12 -0
  616. package/src/data/Observable.js +0 -55
  617. package/src/data/ObservableChecker.js +0 -39
  618. package/src/data/ObservableItem.js +0 -195
  619. package/src/data/Store.js +0 -74
  620. package/src/data/observable-helpers/array.js +0 -74
  621. package/src/data/observable-helpers/batch.js +0 -22
  622. package/src/data/observable-helpers/computed.js +0 -28
  623. package/src/data/observable-helpers/object.js +0 -111
  624. package/src/elements/anchor.js +0 -129
  625. package/src/elements/content-formatter.js +0 -32
  626. package/src/elements/control/for-each-array.js +0 -280
  627. package/src/elements/control/show-if.js +0 -79
  628. package/src/elements/control/switch.js +0 -98
  629. package/src/elements/description-list.js +0 -5
  630. package/src/elements/form.js +0 -71
  631. package/src/elements/html5-semantics.js +0 -12
  632. package/src/elements/img.js +0 -45
  633. package/src/elements/interactive.js +0 -7
  634. package/src/elements/list.js +0 -10
  635. package/src/elements/medias.js +0 -8
  636. package/src/elements/meta-data.js +0 -9
  637. package/src/elements/table.js +0 -14
  638. package/src/utils/args-types.js +0 -100
  639. package/src/utils/debug-manager.js +0 -31
  640. package/src/utils/helpers.js +0 -60
  641. package/src/utils/plugins-manager.js +0 -12
  642. package/src/utils/prototypes.js +0 -45
  643. package/src/wrappers/AttributesWrapper.js +0 -144
  644. package/src/wrappers/DocumentObserver.js +0 -80
  645. package/src/wrappers/ElementCreator.js +0 -114
  646. package/src/wrappers/HtmlElementEventsWrapper.js +0 -64
  647. package/src/wrappers/HtmlElementWrapper.js +0 -50
  648. package/src/wrappers/NdPrototype.js +0 -109
  649. package/src/wrappers/constants.js +0 -2
@@ -1,607 +1,387 @@
1
- # List Rendering
2
-
3
- List rendering in NativeDocument provides powerful utilities for efficiently displaying dynamic collections of data. The framework offers two specialized functions: `ForEach` for generic iteration over objects and arrays, and `ForEachArray` for high-performance array-specific operations with advanced optimization features.
1
+ ---
2
+ title: List Rendering
3
+ description: Efficiently render dynamic collections with ForEach and ForEachArray - automatic DOM updates, keyed diffing, and reactive filtering
4
+ ---
4
5
 
5
- ## Understanding List Rendering
6
+ # List Rendering
6
7
 
7
- List rendering automatically manages DOM updates when your data changes. Instead of manually manipulating the DOM, you define how each item should be rendered, and NativeDocument handles creation, updates, reordering, and cleanup efficiently.
8
+ NativeDocument provides two functions for rendering dynamic collections: `ForEach` for generic iteration over arrays and objects, and `ForEachArray` for high-performance array-specific operations.
8
9
 
9
10
  ```javascript
10
- import { ForEach, Observable, Li, Ul } from 'native-document';
11
-
12
- const items = Observable.array(['Apple', 'Banana', 'Cherry']);
11
+ import { ForEach, ForEachArray } from 'native-document/elements';
12
+ ```
13
13
 
14
- // Automatically updates when items change
15
- const itemList = Ul([
16
- ForEach(items, item => Li(item))
17
- ]);
14
+ ---
18
15
 
19
- // Add items - DOM updates automatically
20
- items.push('Orange', 'Grape');
21
- ```
16
+ ## `ForEach` - Generic Collection Rendering
22
17
 
23
- ## ForEach - Generic Collection Rendering
18
+ `ForEach` works with both observable arrays and observable objects.
24
19
 
25
- `ForEach` is the versatile option that works with both arrays and objects. It's perfect when you need flexibility or are working with mixed data types.
20
+ ```javascript
21
+ ForEach(data, callback, key?, options?)
22
+ ```
26
23
 
27
- ### Basic Array Iteration
24
+ ### Array iteration
28
25
 
29
26
  ```javascript
30
27
  const fruits = Observable.array(['Apple', 'Banana', 'Cherry']);
31
28
 
32
- const FruitList = Ul([
33
- ForEach(fruits, fruit =>
34
- Li({ class: 'fruit-item' }, fruit)
35
- )
36
- ]);
29
+ Ul(
30
+ ForEach(fruits, fruit => Li(fruit))
31
+ )
37
32
 
38
- // All array operations trigger updates
39
- fruits.push('Orange'); // Adds new item
40
- fruits.splice(1, 1); // Removes 'Banana'
41
- fruits.sort(); // Reorders items
33
+ // All array operations trigger DOM updates
34
+ fruits.push('Orange');
35
+ fruits.splice(1, 1);
36
+ fruits.sort();
42
37
  ```
43
38
 
44
- ### Object Iteration
39
+ ### Object iteration
45
40
 
46
41
  ```javascript
47
- const userRoles = Observable({
48
- admin: 'Administrator',
49
- editor: 'Content Editor',
42
+ const roles = Observable({
43
+ admin: 'Administrator',
44
+ editor: 'Content Editor',
50
45
  viewer: 'Read Only'
51
46
  });
52
47
 
53
- const RolesList = Ul([
54
- ForEach(userRoles, (roleName, roleKey) =>
55
- Li([
56
- Strong(roleKey), ': ', roleName
57
- ])
48
+ Ul(
49
+ ForEach(roles, (roleName, roleKey) =>
50
+ Li([Strong(roleKey), ': ', roleName])
58
51
  )
59
- ]);
60
-
61
- // Update object - DOM reflects changes
62
- userRoles.set({
63
- ...userRoles.val(),
64
- moderator: 'Community Moderator'
65
- });
52
+ )
66
53
  ```
67
54
 
68
- ### Using Index Parameter
55
+ ### Index parameter
56
+
57
+ The second callback argument is an **observable** tracking the item's current index:
69
58
 
70
59
  ```javascript
71
- const tasks = Observable.array([
72
- 'Review pull requests',
73
- 'Update documentation',
74
- 'Fix bug reports'
75
- ]);
60
+ const tasks = Observable.array(['Review PRs', 'Update docs', 'Fix bugs']);
76
61
 
77
- const TaskList = Ol([
78
- ForEach(tasks, (task, indexObservable) =>
79
- Li([
80
- Strong(indexObservable.get(val => val + 1)),
81
- ' ',
82
- task,
83
- Button('Remove').nd.onClick(() =>
84
- tasks.remove(indexObservable.val())
85
- )
86
- ])
87
- )
88
- ]);
62
+ Ol(ForEach(tasks, (task, index) =>
63
+ Li([
64
+ Strong(index.transform(i => i + 1)), '. ',
65
+ task,
66
+ Button('Remove').nd.onClick(() => tasks.remove(index.val()))
67
+ ])
68
+ ))
89
69
  ```
90
70
 
91
- ### Custom Key Functions
71
+ ### Key function
92
72
 
93
- Use custom key functions
73
+ Use a key to help NativeDocument identify items for efficient reordering. Pass a property name string or a function:
94
74
 
95
75
  ```javascript
96
76
  const users = Observable.array([
97
77
  { id: 1, name: 'Alice', role: 'admin' },
98
- { id: 2, name: 'Bob', role: 'user' },
99
- { id: 3, name: 'Carol', role: 'editor' }
78
+ { id: 2, name: 'Bob', role: 'user' }
100
79
  ]);
101
80
 
102
- // Use 'id' field as the key for efficient updates
103
- const UserList = Div([
104
- ForEach(users,
105
- user => Div({ class: 'user-card' }, [
106
- H3(user.name),
107
- Span({ class: 'role' }, user.role)
108
- ]),
109
- 'id' // Key function - uses user.id
110
- // Or (item) => item.id
111
- )
112
- ]);
81
+ // Property name shorthand
82
+ ForEach(users, user => Div(user.name), 'id')
113
83
 
114
- // When users reorder, DOM nodes are moved, not recreated
115
- users.set((items) => items.sort((a, b) => a.name.localeCompare(b.name)));
84
+ // Function
85
+ ForEach(users, user => Div(user.name), item => item.id)
116
86
  ```
117
87
 
118
- ## ForEachArray - High-Performance Array Rendering
88
+ ### Options
119
89
 
120
- `ForEachArray` is specifically optimized for **arrays of complex objects** and provides superior performance. **Use ForEachArray for object arrays** - it's designed for array-specific operations.
90
+ ```javascript
91
+ ForEach(data, callback, key, { shouldKeepItemsInCache: true })
92
+ ```
93
+
94
+ `shouldKeepItemsInCache` - when `true`, rendered items stay in cache even when removed. Useful when items toggle frequently:
121
95
 
122
- ### Why ForEachArray for Complex Arrays?
96
+ ```javascript
97
+ // Items are cached - re-adding won't re-render them
98
+ ForEach(items, renderItem, 'id', { shouldKeepItemsInCache: true })
99
+ ```
123
100
 
124
- `ForEachArray` includes optimizations that generic `ForEach` not provide:
101
+ ---
125
102
 
126
- - **Specialized diffing algorithm** optimized for array operations
127
- - **Batch DOM updates** for better performance
128
- - **Memory-efficient caching** with WeakMap references
129
- - **Array method detection** for targeted updates (push, splice, sort, etc.)
103
+ ## `ForEachArray` - High-Performance Array Rendering
130
104
 
131
- ### Basic Usage
105
+ `ForEachArray` is specifically optimized for arrays of objects. Use it when performance matters.
106
+
107
+ ```javascript
108
+ ForEachArray(data, callback, configs?)
109
+ ```
132
110
 
133
111
  ```javascript
134
112
  const messages = Observable.array([
135
- { id: 1, text: 'Hello world!', timestamp: Date.now() },
113
+ { id: 1, text: 'Hello!', timestamp: Date.now() },
136
114
  { id: 2, text: 'How are you?', timestamp: Date.now() + 1000 }
137
115
  ]);
138
116
 
139
- const ChatMessages = Div({ class: 'chat-container' }, [
140
- ForEachArray(messages, message =>
117
+ Div({ class: 'chat' },
118
+ ForEachArray(messages, message =>
141
119
  Div({ class: 'message' }, [
142
- Div({ class: 'message-text' }, message.text),
143
- Div({ class: 'timestamp' }, new Date(message.timestamp).toLocaleTimeString())
120
+ Div(message.text),
121
+ Div(new Date(message.timestamp).toLocaleTimeString())
144
122
  ])
145
123
  )
146
- ]);
147
-
148
- // Optimized array operations
149
- messages.push({ id: 3, text: 'New message!', timestamp: Date.now() });
124
+ )
150
125
  ```
151
126
 
152
- ### Advanced Array Operations
127
+ ### Index in `ForEachArray`
153
128
 
154
- `ForEachArray` efficiently handles all array mutations:
129
+ The index is a **computed observable** derived from the array - always reactive, no need to call `.val()` to use it in the DOM:
155
130
 
156
131
  ```javascript
157
- const playlist = Observable.array([
158
- { id: 1, title: 'Song One', artist: 'Artist A' },
159
- { id: 2, title: 'Song Two', artist: 'Artist B' },
160
- { id: 3, title: 'Song Three', artist: 'Artist C' }
161
- ]);
162
-
163
- const PlaylistView = Div({ class: 'playlist' }, [
164
- ForEachArray(playlist, (song, indexObservable) => {
165
-
166
- return Div({ class: 'song-item', style: 'display: flex; align-items: center; column-gap: 10px;' }, [
167
- Div({ class: 'song-info' }, [
168
- Strong(indexObservable.get((value) => value + 1)),
169
- ' - ',
170
- Strong(song.title),
171
- Span({ class: 'artist' }, ` by ${song.artist}`)
172
- ]),
173
- Div({ class: 'song-controls' }, [
174
- Button('↑').nd.onClick(() => {
175
- const index = indexObservable.$value;
176
- if(index > 0) {
177
- playlist.swap(index, index-1);
178
- }
179
- }),
180
- Button('↓').nd.onClick(() => {
181
- const index = indexObservable.$value;
182
- if(index < playlist.length()-1) {
183
- playlist.swap(index, index+1);
184
- }
185
- }),
186
- Button('Remove').nd.onClick(() =>{
187
- playlist.remove(indexObservable.$value);
188
- })
189
- ])
190
- ])
191
- }, 'id'),
192
- Br,
132
+ ForEachArray(playlist, (song, index) =>
193
133
  Div([
194
- Button('Push ').nd.onClick(() => {
195
- playlist.push({ id: 4, title: 'New Song', artist: 'New Artist' });
196
- }),
197
- Button('Unshift').nd.onClick(() => {
198
- playlist.unshift({ id: 0, title: 'First Song', artist: 'First' })
134
+ index.transform(i => i + 1), '. ',
135
+ song.title,
136
+ Button('Up').nd.onClick(() => {
137
+ const i = index.$value;
138
+ if (i > 0) {
139
+ playlist.swap(i, i - 1);
140
+ }
199
141
  }),
200
- Button('Reverse').nd.onClick(() => {
201
- playlist.reverse()
142
+ Button('Down').nd.onClick(() => {
143
+ const i = index.$value;
144
+ if (i < playlist.val().length - 1) {
145
+ playlist.swap(i, i + 1);
146
+ }
202
147
  }),
203
- Button('Sort').nd.onClick(() => {
204
- playlist.sort((a, b) => a.title.localeCompare(b.title))
205
- })
148
+ Button('Remove').nd.onClick(() => playlist.remove(index.$value))
206
149
  ])
207
- ]);
208
- ```
209
-
210
- ### Custom Key Functions with ForEachArray
211
-
212
- Key functions are crucial for optimal performance with complex objects:
213
-
214
- ```javascript
215
- const products = Observable.array([
216
- { sku: 'PHONE-001', name: 'Smartphone', price: 599 },
217
- { sku: 'LAPTOP-001', name: 'Laptop', price: 999 },
218
- { sku: 'TABLET-001', name: 'Tablet', price: 399 }
219
- ]);
220
-
221
- const ProductCatalog = Div({ class: 'catalog' }, [
222
- ForEachArray(products,
223
- product => Div({ class: 'product-card' }, [
224
- H3(product.name),
225
- Div({ class: 'price' }, `$${product.price}`),
226
- Div({ class: 'sku' }, `SKU: ${product.sku}`)
227
- ]),
228
- 'sku' // Use SKU as key for efficient tracking
229
- )
230
- ]);
231
-
150
+ )
232
151
  ```
233
152
 
234
- ### Performance Configuration
235
-
236
- `ForEachArray` supports performance tuning for large datasets:
153
+ ### Configs
237
154
 
238
155
  ```javascript
239
- const bigDataset = Observable.array([...Array(10000)].map((_, i) => ({
240
- id: i,
241
- value: `Item ${i}`,
242
- category: Math.floor(i / 100)
243
- })));
244
-
245
- const BigList = Div([
246
- ForEachArray(bigDataset,
247
- item => Div({ class: 'list-item' }, [
248
- Strong(`#${item.id}`), ' - ', item.value
249
- ]),
250
- 'id', // Key function
251
- {
252
- pushDelay: (items) => items.length > 100 ? 50 : 0 // Delay for large additions
253
- }
254
- )
255
- ]);
256
-
257
- // Large additions are automatically throttled
258
- bigDataset.push(...[...Array(500)].map((_, i) => ({
259
- id: 10000 + i,
260
- value: `New Item ${i}`,
261
- category: 999
262
- })));
156
+ ForEachArray(data, callback, {
157
+ shouldKeepItemsInCache: false, // same as ForEach
158
+ pushDelay: (items) => items.length > 100 ? 50 : 0 // throttle large batch inserts
159
+ })
263
160
  ```
264
161
 
265
- ## Choosing Between ForEach and ForEachArray
266
-
267
- ### Use ForEachArray When:
268
-
269
- ✅ **Working with arrays of complex objects**
270
- ✅ **Performance is critical** - Large lists, frequent updates
271
- ✅ **Using array methods** - push, pop, splice, sort, reverse, etc.
272
-
273
- ```javascript
274
- // Perfect for ForEachArray
275
- const comments = Observable.array([...]);
276
- const CommentList = ForEachArray(comments, comment => CommentComponent(comment));
277
-
278
- // Array operations work optimally
279
- comments.push(newComment);
280
-
281
- comments.splice(index, 1);
162
+ ---
282
163
 
283
- comments.sort((a, b) => b.timestamp - a.timestamp);
284
- ```
164
+ ## Choosing Between `ForEach` and `ForEachArray`
285
165
 
286
- ### Use ForEach When:
166
+ | | `ForEach` | `ForEachArray` |
167
+ |---|---|---|
168
+ | Arrays of objects | yes | yes (optimized) |
169
+ | Arrays of primitives | yes | yes |
170
+ | Object (non-array) iteration | yes | no |
171
+ | Index is observable | yes | yes (computed) |
172
+ | Key argument | third arg (string/fn) | inside configs |
173
+ | Best for | objects, primitives, small lists | large or frequently updated arrays |
287
174
 
288
- ✅ **Working with objects** - ForEach is required for object iteration
289
- ✅ **Mixed data types** - When data might be array or object
290
- ✅ **Arrays of primitive values** - string, number, boolean
291
- ✅ **Simple use cases** - Small lists with infrequent updates
175
+ ---
292
176
 
293
- ## Real-World Examples
177
+ ## Filtering with `.where()`
294
178
 
295
- ### Nested Lists with Mixed Rendering
179
+ `.where()` is available on `ObservableArray` only. It returns a new live `ObservableArray` that re-filters automatically. See [Observables](./observables.md) for the full `.where()` reference.
296
180
 
297
181
  ```javascript
298
- const categories = Observable.array([
299
- {
300
- id: 1,
301
- name: 'Electronics',
302
- items: Observable.array([
303
- { id: 101, name: 'Smartphone', price: 599 },
304
- { id: 102, name: 'Laptop', price: 999 }
305
- ])
306
- },
307
- {
308
- id: 2,
309
- name: 'Books',
310
- items: Observable.array([
311
- { id: 201, name: 'JavaScript Guide', price: 29.99 },
312
- { id: 202, name: 'Design Patterns', price: 39.99 }
313
- ])
314
- }
315
- ]);
182
+ import { equals, greaterThan, lessThan, between, includes, match,
183
+ startsWith, endsWith, inArray, notIn, custom,
184
+ and, or, not } from 'native-document/filters';
316
185
 
317
- const CategorizedProducts = Div({ class: 'product-categories' }, [
318
- // Categories use ForEachArray (it's an array)
319
- ForEachArray(categories, category =>
320
- Div({ class: 'category' }, [
321
- H3({ class: 'category-title' }, category.name),
322
-
323
- // Items within each category also use ForEachArray
324
- ForEachArray(category.items,
325
- item => Div({ class: 'product-item' }, [
326
- Span({ class: 'product-name' }, item.name),
327
- Span({ class: 'product-price' }, `$${item.price}`),
328
- Button('Add to Cart').nd.onClick(() => addToCart(item))
329
- ]),
330
- 'id'
331
- ),
332
-
333
- Button('Add Item').nd.onClick(() => {
334
- const newItem = {
335
- id: Date.now(),
336
- name: `New ${category.name} Item`,
337
- price: Math.floor(Math.random() * 100) + 10
338
- };
339
- category.items.push(newItem);
340
- })
341
- ]),
342
- 'id'
343
- )
186
+ const products = Observable.array([
187
+ { id: 1, name: 'Phone', price: 599, inStock: true, category: 'electronics' },
188
+ { id: 2, name: 'Laptop', price: 999, inStock: false, category: 'electronics' },
189
+ { id: 3, name: 'Book', price: 29, inStock: true, category: 'books' }
344
190
  ]);
345
191
  ```
346
192
 
347
- ## Performance Best Practices
348
-
349
- ### 1. Always Use Keys for Complex Objects
193
+ ### Comparison
350
194
 
351
195
  ```javascript
352
- // ✅ Good: Efficient updates and reordering
353
- ForEachArray(users, user => UserCard(user), 'id')
354
- ForEach(tags, tag => TagComponent(tag), 'index')
355
-
356
- // ❌ Poor: Inefficient, may cause unnecessary re-renders
357
- ForEachArray(users, user => UserCard(user))
196
+ products.where({ price: greaterThan(500) })
197
+ products.where({ price: lessThan(100) })
198
+ products.where({ price: between(200, 800) })
199
+ products.where({ inStock: equals(true) })
200
+ products.where({ name: notEquals('Phone') })
358
201
  ```
359
202
 
360
- ### 2. Choose the Right Function
203
+ ### String
361
204
 
362
205
  ```javascript
363
- // ✅ Perfect: ForEachArray for complex objects
364
- const users = Observable.array([{id: 1, name: 'Alice'}]);
365
- ForEachArray(users, renderUser, 'id')
366
-
367
- // Correct: ForEach for primitives
368
- const tags = Observable.array(['js', 'css']);
369
- ForEach(tags, renderTag)
370
-
371
- // ✅ Correct: ForEach for objects
372
- const config = Observable({theme: 'dark'});
373
- ForEach(config, renderSetting, (item, key) => key)
206
+ products.where({ name: includes('phone') }) // case-insensitive by default
207
+ products.where({ name: startsWith('P') })
208
+ products.where({ name: endsWith('book') })
209
+ products.where({ name: match(/^[A-Z]/) }) // regex
210
+ products.where({ name: match('lap', false) }) // plain string, no regex
374
211
  ```
375
212
 
376
- ### 3. Use Computed Values for Derived Lists
213
+ ### Array membership
377
214
 
378
215
  ```javascript
379
- // Efficient: Computed filtered list
380
- const searchTerm = Observable('');
381
- const filteredItems = Observable.computed(() =>
382
- allItems.val().filter(item =>
383
- item.name.toLowerCase().includes(searchTerm.val().toLowerCase())
384
- ),
385
- [allItems, searchTerm]
386
- );
387
-
388
- ForEachArray(filteredItems, renderItem, 'id')
389
-
390
- // ❌ Inefficient: Filtering in render
391
- ForEachArray(allItems, item => {
392
- if (item.name.includes(searchTerm.val())) {
393
- return renderItem(item);
394
- }
395
- return null;
396
- })
216
+ const allowed = Observable.array(['electronics', 'books']);
217
+
218
+ products.where({ category: inArray(allowed) }) // reactive
219
+ products.where({ category: notIn(['clothing']) })
397
220
  ```
398
221
 
399
- ## Memory Management
222
+ ### Reactive filters
400
223
 
401
- Both `ForEach` and `ForEachArray` automatically manage memory:
224
+ Pass an observable as the filter value - re-filters automatically when it changes:
402
225
 
403
226
  ```javascript
404
- // Cleanup is automatic when observables are garbage collected
405
- let myList = Observable.array([1, 2, 3]);
406
- let listComponent = ForEachArray(myList, item => Div(item));
227
+ const search = Observable('');
228
+ const minPrice = Observable(0);
229
+ const maxPrice = Observable(1000);
407
230
 
408
- // When references are lost, cleanup happens automatically
409
- myList = null;
410
- listComponent = null; // Memory will be freed
231
+ const filtered = products.where({
232
+ name: includes(search),
233
+ price: between(minPrice, maxPrice)
234
+ });
411
235
  ```
412
236
 
413
- For explicit cleanup:
237
+ ### Custom filter
414
238
 
415
239
  ```javascript
416
- const items = Observable.array([...]);
417
- const listComponent = ForEachArray(items, renderItem);
240
+ const minRating = Observable(4);
418
241
 
419
- // Manual cleanup when needed
420
- items.cleanup();
242
+ products.where({
243
+ _: custom((product, min) => {
244
+ return product.rating >= min && product.reviews > 10;
245
+ }, minRating) // observables passed as extra args
246
+ })
421
247
  ```
422
248
 
423
- ## Common Pitfalls and Solutions
424
-
425
- ### 1. Missing Keys with Complex Objects
249
+ ### Combining
426
250
 
427
251
  ```javascript
428
- // Problem: No key, inefficient updates
429
- ForEachArray(users, user => UserProfile(user))
430
-
431
- // ✅ Solution: Use unique key
432
- ForEachArray(users, user => UserProfile(user), 'id')
433
- ```
252
+ // and - field must pass ALL conditions
253
+ products.where({ price: and(greaterThan(100), lessThan(500)) })
434
254
 
435
- ### 2. Using ForEach for Complex Arrays
255
+ // or - field must pass AT LEAST ONE
256
+ products.where({ category: or(equals('electronics'), equals('books')) })
436
257
 
437
- ```javascript
438
- // ❌ Suboptimal: Generic ForEach for arrays
439
- ForEach(genericObject, renderItem)
258
+ // not - invert
259
+ products.where({ inStock: not(equals(true)) })
440
260
 
441
- // Optimal: Specialized ForEachArray for arrays
442
- ForEachArray(arrayData, renderItem)
261
+ // cross-field - use _ key with plain function
262
+ products.where({
263
+ _: item => item.inStock && item.price < 500
264
+ })
443
265
  ```
444
266
 
445
- ### 3. Modifying Arrays Directly
267
+ ### Date and time filters
446
268
 
447
269
  ```javascript
448
- // Wrong: Direct mutation doesn't trigger updates
449
- items.val().push(newItem);
270
+ import { dateEquals, dateBefore, dateAfter, dateBetween,
271
+ timeBefore, timeBetween } from 'native-document/filters';
450
272
 
451
- // Correct: Use Observable array methods
452
- items.push(newItem);
273
+ const events = Observable.array([
274
+ { name: 'Meeting', date: '2024-03-15' },
275
+ { name: 'Conference', date: '2024-06-20' }
276
+ ]);
453
277
 
454
- // ✅ Also correct: Set new array
455
- items.set([...items.val(), newItem]);
278
+ events.where({ date: dateAfter(new Date()) })
279
+ events.where({ date: dateBetween('2024-06-01', '2024-08-31') })
280
+ events.where({ date: timeBetween(
281
+ new Date('2024-01-01 09:00:00'),
282
+ new Date('2024-01-01 17:00:00')
283
+ )})
456
284
  ```
457
285
 
458
- ## Integration with Other Features
286
+ ---
459
287
 
460
- ### With Conditional Rendering
288
+ ## Common Patterns
461
289
 
462
- ```javascript
463
- const items = Observable.array([]);
464
- const showEmptyState = items.check(arr => arr.length === 0);
465
-
466
- const ItemList = Div([
467
- ShowIf(showEmptyState,
468
- Div({ class: 'empty-state' }, 'No items found')
469
- ),
470
- HideIf(showEmptyState,
471
- ForEachArray(items, item => ItemComponent(item), 'id')
472
- )
473
- ]);
474
- ```
475
-
476
- ### With Forms and Validation
290
+ ### Empty state
477
291
 
478
292
  ```javascript
479
- const formFields = Observable.array([
480
- { name: 'firstName', label: 'First Name', value: '', required: true },
481
- { name: 'lastName', label: 'Last Name', value: '', required: true },
482
- { name: 'email', label: 'Email', value: '', required: true }
483
- ]);
293
+ const items = Observable.array([]);
484
294
 
485
- const DynamicForm = Form([
486
- ForEachArray(formFields, field =>
487
- Div({ class: 'form-group' }, [
488
- Label(field.label + (field.required ? ' *' : '')),
489
- Input({
490
- name: field.name,
491
- value: field.value,
492
- required: field.required
493
- }),
494
- ShowIf(field.error,
495
- Div({ class: 'error' }, field.error)
496
- )
497
- ]),
498
- 'name'
499
- ),
500
- Button({ type: 'submit' }, 'Submit')
501
- ]);
295
+ Div([
296
+ ShowIf(items.isEmpty(), Div({ class: 'empty' }, 'No items yet')),
297
+ ForEachArray(items, item => ItemComponent(item))
298
+ ])
502
299
  ```
503
300
 
504
- ## Advanced Patterns
505
-
506
- ### Infinite Scrolling
301
+ ### Search + filter
507
302
 
508
303
  ```javascript
509
- const items = Observable.array([]);
510
- const isLoading = Observable(false);
511
- const hasMore = Observable(true);
512
-
513
- const loadMoreItems = async () => {
514
- if (isLoading.val()) return;
515
-
516
- isLoading.set(true);
517
- try {
518
- const newItems = await fetchItems(items.val().length);
519
- if (newItems.length === 0) {
520
- hasMore.set(false);
521
- } else {
522
- items.push(...newItems);
523
- }
524
- } finally {
525
- isLoading.set(false);
526
- }
527
- };
304
+ const search = Observable('');
305
+ const category = Observable('all');
528
306
 
529
- const InfiniteList = Div([
530
- ForEachArray(items, item => ItemComponent(item), 'id'),
531
- ShowIf(isLoading, LoadingSpinner()),
532
- ShowIf(hasMore.check(more => more && !isLoading.val()),
533
- Button('Load More').nd.onClick(loadMoreItems)
534
- )
535
- ]);
307
+ const filtered = products.where({
308
+ name: includes(search),
309
+ category: or(equals('all'), equals(category))
310
+ });
536
311
 
312
+ Div([
313
+ Input({ placeholder: 'Search...', value: search }),
314
+ ForEachArray(filtered, product => ProductCard(product))
315
+ ])
537
316
  ```
538
317
 
539
- ### Drag and Drop Reordering
318
+ ### Drag-and-drop reordering
540
319
 
541
320
  ```javascript
542
- const draggableItems = Observable.array([
543
- { id: 1, text: 'Item 1' },
544
- { id: 2, text: 'Item 2' },
545
- { id: 3, text: 'Item 3' }
546
- ]);
547
-
548
321
  let draggedIndex = null;
549
322
 
550
- const DraggableList = Div([
551
- ForEachArray(draggableItems, (item, indexObservable) =>
552
- Div({
553
- class: 'draggable-item',
554
- draggable: true
555
- }, item.text)
556
- .nd.onDragStart((e) => {
557
- draggedIndex = indexObservable.val();
558
- })
559
- .nd.onDragOver((e) => e.preventDefault())
560
- .nd.onDrop((e) => {
323
+ ForEachArray(items, (item, index) =>
324
+ Div({ class: 'item', draggable: true }, item.text)
325
+ .nd
326
+ .onDragStart(() => { draggedIndex = index.$value; })
327
+ .onDragOver(e => e.preventDefault())
328
+ .onDrop(e => {
561
329
  e.preventDefault();
562
- const dropIndex = indexObservable.val();
330
+ const dropIndex = index.$value;
563
331
  if (draggedIndex !== null && draggedIndex !== dropIndex) {
564
- const items = draggableItems.val();
565
- const draggedItem = items[draggedIndex];
566
-
567
- // Remove from old position
568
- items.splice(draggedIndex, 1);
569
- // Insert at new position
570
- items.splice(dropIndex, 0, draggedItem);
571
-
572
- draggableItems.set([...items]);
332
+ items.swap(draggedIndex, dropIndex);
573
333
  }
574
334
  draggedIndex = null;
575
- }),
576
- 'id'
577
- )
578
- ]);
335
+ })
336
+ )
579
337
  ```
580
338
 
581
- ## Debugging List Rendering
582
-
583
- ### Logging Updates
339
+ ### Infinite scroll
584
340
 
585
341
  ```javascript
586
- const items = Observable.array([]);
342
+ const items = Observable.array([]);
343
+ const isLoading = Observable(false);
344
+ const hasMore = Observable(true);
587
345
 
588
- // Log all array operations
589
- items.subscribe((newItems, oldItems, operations) => {
590
- console.log('Array operation:', operations);
591
- console.log('Old items:', oldItems);
592
- console.log('New items:', newItems);
593
- });
346
+ const loadMore = async () => {
347
+ if (isLoading.val()) return;
348
+ isLoading.set(true);
349
+ const next = await fetchItems(items.val().length);
350
+ next.length ? items.merge(next) : hasMore.set(false);
351
+ isLoading.set(false);
352
+ };
594
353
 
595
- const DebugList = ForEachArray(items, (item, index) => {
596
- console.log('Rendering item:', item, 'at index:', index?.val());
597
- return ItemComponent(item);
598
- }, 'id');
354
+ Div([
355
+ ForEachArray(items, item => ItemComponent(item)),
356
+ ShowIf(isLoading.isTruthy(), Div('Loading...')),
357
+ ShowIf(hasMore.isTruthy(),
358
+ Button('Load more').nd.onClick(loadMore)
359
+ )
360
+ ])
599
361
  ```
600
362
 
363
+ ---
364
+
365
+ ## Best Practices
366
+
367
+ 1. Use `ForEachArray` for arrays of objects - it's optimized for that case
368
+ 2. Use `ForEach` for objects (non-array) and arrays of primitives
369
+ 3. Always pass a key when items can be reordered - avoids unnecessary re-rendering
370
+ 4. Use `.where()` for filtering instead of filtering inside the callback
371
+ 5. Use `shouldKeepItemsInCache: true` when items toggle in and out frequently
372
+ 6. Never mutate `.val()` directly - use observable array methods (`push`, `splice`, `swap`, etc.)
373
+
374
+ ---
375
+
601
376
  ## Next Steps
602
377
 
603
- Now that you understand list rendering, explore these related topics:
378
+ - **[Conditional Rendering](./conditional-rendering.md)** - ShowIf, Match, Switch
379
+ - **[Observables](./observables.md)** - Observable arrays and `.where()` in depth
380
+ - **[Advanced Components](./advanced-components.md)** - `ForEachArray` with `useCache`
381
+ - **[Filters](./filters.md)** - Full filter reference
382
+
383
+ ## Utilities
604
384
 
605
- - **[Conditional Rendering](conditional-rendering.md)** - Show/hide content dynamically
606
- - **[State Management](state-management.md)** - Managing application state
607
- - **[Memory Management](memory-management.md)** - Understanding cleanup and memory
385
+ - **[Cache](./cache.md)** - Lazy initialization and singleton patterns
386
+ - **[NativeFetch](./native-fetch.md)** - HTTP client with interceptors
387
+ - **[Filters](./filters.md)** - Data filtering helpers