native-document 1.0.15 → 1.0.16-8.1

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 +181 -0
  400. package/src/core/wrappers/DocumentObserver.js +182 -0
  401. package/src/core/wrappers/ElementCreator.js +110 -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 +24 -0
  410. package/src/core/wrappers/prototypes/bind-class-extensions.js +0 -0
  411. package/src/core/wrappers/prototypes/nd-element-extensions.js +149 -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,629 +1,304 @@
1
- # Conditional Rendering
2
-
3
- Conditional rendering in NativeDocument allows you to dynamically show, hide, or switch between different pieces of content based on reactive state. Unlike traditional approaches that require manual DOM manipulation, NativeDocument's conditional rendering utilities automatically update the interface when observable values change.
1
+ ---
2
+ title: Conditional Rendering
3
+ description: Dynamically show, hide, or switch between content based on reactive state - ShowIf, Switch, Match, When, and more
4
+ ---
4
5
 
5
- ## Understanding Conditional Rendering
6
+ # Conditional Rendering
6
7
 
7
- All conditional rendering functions in NativeDocument work with Observables and automatically manage DOM updates. When the condition changes, content is efficiently added or removed from the DOM without affecting other elements.
8
+ NativeDocument's conditional rendering utilities automatically update the DOM when observable values change. All functions work with observables and manage DOM updates for you.
8
9
 
9
10
  ```javascript
10
- import { ShowIf, Button, Div, Observable } from 'native-document';
11
-
12
- const isVisible = Observable(false);
13
-
14
- // Content automatically appears/disappears based on isVisible
15
- const conditionalContent = ShowIf(isVisible, 'This content toggles!');
11
+ import { ShowIf, HideIf, ShowWhen, Switch, Match, When } from 'native-document/elements';
16
12
  ```
17
13
 
18
- ## ShowIf - Basic Conditional Display
14
+ ---
15
+
16
+ ## `ShowIf` - Basic Conditional Display
19
17
 
20
- The `ShowIf` function renders content only when the Observable condition is truthy. When false, the content is completely removed from the DOM.
18
+ Renders content only when the condition is truthy. When false, the content is removed from the DOM.
21
19
 
22
20
  ```javascript
23
- const user = Observable({ name: 'Alice', isLoggedIn: false });
21
+ const isVisible = Observable(false);
24
22
 
25
- const App = Div([
26
- Button('Login').nd.onClick(() =>
27
- user.set({ ...user.val(), isLoggedIn: true })
28
- ),
29
- Button('Logout').nd.onClick(() =>
30
- user.set({ ...user.val(), isLoggedIn: false })
31
- ),
32
-
33
- // Shows only when user is logged in
34
- ShowIf(user.check(u => u.isLoggedIn), 'Welcome back!')
35
- ]);
23
+ ShowIf(isVisible, Div('Hello!'))
24
+
25
+ // With a boolean (non-reactive)
26
+ ShowIf(true, Div('Always visible'))
36
27
  ```
37
28
 
38
- ### Dynamic Content Generation
29
+ ### Function children
39
30
 
40
- Use functions to create content that reflects current observable values:
31
+ Pass a function to create content that reflects current observable values:
41
32
 
42
33
  ```javascript
43
34
  const notifications = Observable.array([]);
44
35
 
45
- const notificationBadge = ShowIf(
46
- notifications.check(list => list.length > 0),
47
- () => Span({ class: 'badge' }, `${notifications.val().length} new`)
48
- );
49
-
50
- // When notifications change, the badge updates automatically
51
- notifications.push('New message');
36
+ ShowIf(notifications.isNotEmpty(),
37
+ () => Span({ class: 'badge' }, notifications.toLength())
38
+ )
52
39
  ```
53
40
 
54
- ### Using Observable Checkers
55
-
56
- Observable checkers create derived conditions for cleaner code:
41
+ ### Options
57
42
 
58
43
  ```javascript
59
- const temperature = Observable(25);
60
- const isCold = temperature.check(temp => temp < 15);
61
- const isHot = temperature.check(temp => temp > 30);
62
-
63
- const WeatherApp = Div([
64
- Div(['Current temperature: ', temperature, '°C']),
65
- ShowIf(isCold, Div({ class: 'cold' }, '🧥 It\'s cold! Wear a jacket.')),
66
- ShowIf(isHot, Div({ class: 'hot' }, '☀️ It\'s hot! Stay hydrated.')),
67
- Div([
68
- Button('-').nd.onClick(() => --temperature.$value),
69
- Button('+').nd.onClick(() => ++temperature.$value),
70
- ])
71
- ]);
44
+ ShowIf(condition, content, {
45
+ comment: 'my-component', // label visible in DOM comments (debug)
46
+ shouldKeepInCache: false // default true - set to false to recreate on each show
47
+ })
72
48
  ```
73
49
 
74
- ## HideIf and HideIfNot - Inverse Conditions
75
-
76
- These functions provide convenient inverses to `ShowIf`:
50
+ ### Practical example
77
51
 
78
52
  ```javascript
79
- const isLoading = Observable(true);
80
- const hasData = Observable(false);
81
-
82
- const DataDisplay = Div([
83
- // Hide content while loading
84
- HideIf(isLoading, Div('Data is ready to display')),
85
-
86
- // Show loading message only while loading
87
- // Equivalent to ShowIf()
88
- HideIfNot(isLoading, Div({ class: 'spinner' }, 'Loading...')),
53
+ const user = Observable({ name: 'Alice', isLoggedIn: false });
54
+
55
+ Div([
56
+ Button('Login').nd.onClick(() =>
57
+ user.set({ ...user.val(), isLoggedIn: true })
58
+ ),
59
+ ShowIf(user.is(u => u.isLoggedIn),
60
+ () => Div(['Welcome back, ', user.select(u => u.name), '!'])
61
+ )
89
62
  ]);
90
63
  ```
91
64
 
92
- **Understanding the differences:**
93
- ```javascript
94
- const condition = Observable(true);
95
-
96
- // These are equivalent:
97
- ShowIf(condition, content)
98
- HideIfNot(condition, content)
65
+ ---
99
66
 
100
- // These are equivalent:
101
- HideIf(condition, content)
102
- ShowIf(condition.check(val => !val), content)
103
- ```
104
-
105
- ## Switch - Binary Content Switching
67
+ ## `HideIf` / `HideIfNot` - Inverse Conditions
106
68
 
107
- `Switch` efficiently toggles between exactly two pieces of content based on a boolean condition:
69
+ Convenient inverses of `ShowIf`:
108
70
 
109
71
  ```javascript
110
- const isDarkMode = Observable(false);
72
+ const isLoading = Observable(true);
111
73
 
112
- const ThemeToggle = Div([
113
- Button('Toggle Theme').nd.onClick(() => isDarkMode.set(!isDarkMode.val())),
114
-
115
- Switch(isDarkMode,
116
- Div({ class: 'dark-indicator' }, '🌙 Dark Mode'), // when true
117
- Div({ class: 'light-indicator' }, '☀️ Light Mode') // when false
118
- )
119
- ]);
120
- ```
74
+ // Hide content while loading
75
+ HideIf(isLoading, Div('Data is ready'))
121
76
 
122
- ### Dynamic Switch Content
77
+ // Show content only while loading (equivalent to ShowIf)
78
+ HideIfNot(isLoading, Div('Loading...'))
79
+ ```
123
80
 
124
- Functions allow for reactive content that updates with current values:
81
+ Equivalences:
125
82
 
126
83
  ```javascript
127
- const user = Observable({ name: 'Guest', isAuthenticated: false });
128
-
129
- const UserGreeting = Switch(
130
- user.check(u => u.isAuthenticated),
131
- () => Div({ class: 'welcome' }, `Welcome back, ${user.val().name}!`),
132
- () => Div({ class: 'login-prompt' }, 'Please sign in to continue')
133
- );
84
+ ShowIf(condition, content) // same as HideIfNot(condition, content)
85
+ HideIf(condition, content) // same as ShowIf(condition.isFalsy(), content)
134
86
  ```
135
87
 
136
- ## Match - Multiple Condition Handling
137
-
138
- `Match` provides switch-case like functionality for handling multiple states:
139
-
140
- ```javascript
141
- const requestStatus = Observable('idle');
88
+ ---
142
89
 
143
- const StatusDisplay = Match(requestStatus, {
144
- idle: Div({ class: 'status-idle' }, 'Ready to make request'),
145
- loading: Div({ class: 'status-loading' }, [
146
- Span({ class: 'spinner' }),
147
- ' Loading...'
148
- ]),
149
- success: Div({ class: 'status-success' }, '✅ Request completed'),
150
- error: Div({ class: 'status-error' }, '❌ Request failed'),
151
- timeout: Div({ class: 'status-timeout' }, '⏰ Request timed out')
152
- });
153
- ```
90
+ ## `ShowWhen` - Value Matching
154
91
 
155
- ### Dynamic Match Content
92
+ Shows content when an observable matches a specific value.
156
93
 
157
- Functions in Match provide access to current observable values:
94
+ **Two-argument form** - pass an `ObservableWhen` result from `.when()`:
158
95
 
159
96
  ```javascript
160
- const gameState = Observable({
161
- phase: 'menu',
162
- score: 0,
163
- level: 1
164
- });
97
+ const theme = Observable('light');
98
+ const isDark = theme.when('dark'); // ObservableWhen result
165
99
 
166
- const GameDisplay = Match(gameState.check(state => state.phase), {
167
- menu: () => Div({ class: 'game-menu' }, [
168
- H1('Welcome to the Game'),
169
- Button('Start Game').nd.onClick(() =>
170
- gameState.set({ ...gameState.val(), phase: 'playing' })
171
- )
172
- ]),
173
-
174
- playing: () => Div({ class: 'game-ui' }, [
175
- Div(['Score: ', gameState.check(s => s.score)]),
176
- Div(['Level: ', gameState.check(s => s.level)]),
177
- Button('Pause').nd.onClick(() =>
178
- gameState.set({ ...gameState.val(), phase: 'paused' })
179
- ),
180
- Button('Game Over').nd.onClick(() =>
181
- gameState.set({ ...gameState.val(), phase: 'gameOver' })
182
- )
183
- ]),
184
-
185
- paused: () => Div({ class: 'game-paused' }, [
186
- H2('Game Paused'),
187
- Button('Resume').nd.onClick(() =>
188
- gameState.set({ ...gameState.val(), phase: 'playing' })
189
- )
190
- ]),
191
-
192
- gameOver: () => Div({ class: 'game-over' }, [
193
- H2('Game Over'),
194
- Div(['Final Score: ', gameState.check(s => s.score)]),
195
- Button('Play Again').nd.onClick(() =>
196
- gameState.set({ phase: 'menu', score: 0, level: 1 })
197
- )
198
- ])
199
- });
100
+ ShowWhen(isDark, Div('Dark mode active'))
200
101
  ```
201
102
 
202
- ### Match with Default Cases
203
-
204
- Handle unexpected values with default cases:
103
+ **Three-argument form** - pass the observable, the target value, and the content:
205
104
 
206
105
  ```javascript
207
- const userRole = Observable('guest');
208
-
209
- const RoleBasedMenu = Match(userRole, {
210
- admin: AdminMenu(),
211
- moderator: ModeratorMenu(),
212
- user: UserMenu(),
213
- // Default case for unknown roles
214
- default: GuestMenu()
215
- });
106
+ ShowWhen(theme, 'dark', Div('Dark mode active'))
216
107
  ```
217
108
 
218
- ## When - Fluent Builder Pattern
219
-
220
- `When` provides a chainable interface for conditional rendering:
109
+ ### Practical example
221
110
 
222
111
  ```javascript
223
- const score = Observable(85);
112
+ const status = Observable('disconnected');
224
113
 
225
- const GradeDisplay = When(score.check(s => s >= 90))
226
- .show(() => Div({ class: 'grade-a' }, `Excellent! Score: ${score.val()}`))
227
- .otherwise(() => Div({ class: 'grade-b' }, `Score: ${score.val()}`));
114
+ Div({ class: 'status-bar' }, [
115
+ ShowWhen(status, 'connecting', Span('Connecting...')),
116
+ ShowWhen(status, 'connected', Span('Connected')),
117
+ ShowWhen(status, 'disconnected', Span('Disconnected')),
118
+ ShowWhen(status, 'error', Span('Connection Error'))
119
+ ]);
228
120
  ```
229
121
 
230
- ### Complex Conditions with When
231
-
232
- ```javascript
233
- const user = Observable({
234
- age: 25,
235
- hasLicense: true,
236
- hasInsurance: false
237
- });
238
-
239
- const DrivingEligibility = When(user.check(u =>
240
- u.age >= 18 && u.hasLicense && u.hasInsurance
241
- ))
242
- .show(() => Div({ class: 'eligible' }, [
243
- '✅ You can drive legally',
244
- Div(`Age: ${user.val().age}, License: Yes, Insurance: Yes`)
245
- ]))
246
- .otherwise(() => {
247
- const u = user.val();
248
- const issues = [];
249
- if (u.age < 18) issues.push('Must be 18 or older');
250
- if (!u.hasLicense) issues.push('Need a valid license');
251
- if (!u.hasInsurance) issues.push('Need insurance coverage');
252
-
253
- return Div({ class: 'not-eligible' }, [
254
- '❌ Cannot drive legally',
255
- Div(['Issues: ', issues.join(', ')])
256
- ]);
257
- });
258
- ```
122
+ ---
259
123
 
260
- ## Practical Examples
124
+ ## `Switch` - Binary Content
261
125
 
262
- ### Form Validation with Progressive Disclosure
126
+ Toggles between exactly two pieces of content based on a boolean observable:
263
127
 
264
128
  ```javascript
265
- const formData = Observable.object({
266
- email: '',
267
- password: '',
268
- confirmPassword: ''
269
- });
270
-
271
- const isValidEmail = formData.email.check(e =>
272
- e.includes('@') && e.includes('.') && e.length > 5
273
- );
274
-
275
- const isValidPassword = formData.password.check(p => p.length >= 8);
276
-
277
- const passwordsMatch = Observable.computed(() => {
278
- const data = formData.$value;
279
- return data.password === data.confirmPassword && data.password.length > 0;
280
- }, [formData.password, formData.confirmPassword]);
281
-
282
- const canSubmit = Observable.computed(() =>
283
- isValidEmail.val() && isValidPassword.val() && passwordsMatch.val(),
284
- [isValidEmail, isValidPassword, passwordsMatch]
285
- );
129
+ const isDarkMode = Observable(false);
286
130
 
287
- const RegistrationForm = Div({ class: 'registration-form' }, [
288
- // Email field with validation
289
- Input({
290
- type: 'email',
291
- placeholder: 'Email',
292
- value: formData.email
293
- }),
294
- ShowIf(formData.email.check(e => e.length > 0 && !isValidEmail.val()),
295
- Div({ class: 'error' }, 'Please enter a valid email address')
296
- ),
297
-
298
- // Password field
299
- Input({
300
- type: 'password',
301
- placeholder: 'Password',
302
- value: formData.password
303
- }),
304
- ShowIf(formData.password.check(p => p.length > 0 && p.length < 8),
305
- Div({ class: 'error' }, 'Password must be at least 8 characters')
306
- ),
307
-
308
- // Confirm password (only show after password is valid)
309
- ShowIf(isValidPassword, [
310
- Input({
311
- type: 'password',
312
- placeholder: 'Confirm Password',
313
- value: formData.confirmPassword
314
- }),
315
- ShowIf(formData.confirmPassword.check(p => p.length > 0 && !passwordsMatch.val()),
316
- Div({ class: 'error' }, 'Passwords do not match')
317
- )
318
- ]),
319
-
320
- // Submit button
321
- Switch(canSubmit,
322
- Button('Create Account').nd.onClick(() => {
323
- console.log('Creating account...', formData.$value);
324
- }),
325
- Button({ disabled: true, class: 'disabled' }, 'Create Account')
326
- )
327
- ]);
131
+ Switch(isDarkMode,
132
+ Div('Dark mode'), // when true
133
+ Div('Light mode') // when false
134
+ )
328
135
  ```
329
136
 
330
- ### Progressive User Interface
137
+ With function children:
331
138
 
332
139
  ```javascript
333
- const appState = Observable.object({
334
- user: null,
335
- currentView: 'welcome',
336
- settings: { theme: 'light', notifications: true }
337
- });
140
+ const user = Observable({ name: 'Guest', isLoggedIn: false });
338
141
 
339
- const isLoggedIn = appState.user.check(user => user !== null);
340
- const isGuest = appState.user.check(user => user === null);
341
-
342
- const App = Div({ class: 'app' }, [
343
- // Header - changes based on auth state
344
- Header({ class: 'app-header' }, [
345
- H1('My App'),
346
- Switch(isLoggedIn,
347
- // Authenticated header
348
- () => Div({ class: 'user-menu' }, [
349
- Span(['Welcome, ', appState.user.val().name]),
350
- Button('Settings').nd.onClick(() =>
351
- appState.currentView.set('settings')
352
- ),
353
- Button('Logout').nd.onClick(() => {
354
- appState.user.set(null);
355
- appState.currentView.set('welcome');
356
- })
357
- ]),
358
- // Guest header
359
- Div({ class: 'auth-buttons' }, [
360
- Button('Sign In').nd.onClick(() =>
361
- appState.currentView.set('login')
362
- ),
363
- Button('Sign Up').nd.onClick(() =>
364
- appState.currentView.set('register')
365
- )
366
- ])
367
- )
368
- ]),
369
-
370
- // Main content area
371
- Match(appState.currentView, {
372
- welcome: WelcomeView(),
373
- login: LoginView(appState),
374
- register: RegisterView(appState),
375
- dashboard: When(isLoggedIn)
376
- .show(() => DashboardView(appState.user.val()))
377
- .otherwise(() => {
378
- appState.currentView.set('welcome');
379
- return Div('Redirecting...');
380
- }),
381
- settings: When(isLoggedIn)
382
- .show(() => SettingsView(appState))
383
- .otherwise(() => {
384
- appState.currentView.set('welcome');
385
- return Div('Please log in to access settings');
386
- })
387
- })
388
- ]);
142
+ Switch(user.is(u => u.isLoggedIn),
143
+ () => Div(['Welcome back, ', user.select(u => u.name)]),
144
+ () => Div('Please sign in')
145
+ )
389
146
  ```
390
147
 
391
- ## Performance Considerations
148
+ > `Switch` is built on top of `Match` using `.toBoolean()`.
392
149
 
393
- ### Efficient Content Updates
150
+ ---
394
151
 
395
- NativeDocument optimizes conditional rendering by only updating the DOM when conditions actually change:
152
+ ## `Match` - Multiple States
396
153
 
397
- ```javascript
398
- const isVisible = Observable(true);
154
+ Handles multiple states like a switch-case. Each key maps to a content value or function:
399
155
 
400
- // This content is created once and reused
401
- const expensiveContent = ShowIf(isVisible, () => {
402
- console.log('Creating expensive content'); // Only called when becoming visible
403
- return createComplexComponent();
404
- });
156
+ ```javascript
157
+ const status = Observable('idle');
405
158
 
406
- // Toggling rapidly won't recreate content unnecessarily
407
- isVisible.set(false);
408
- isVisible.set(true); // Content is recreated
409
- isVisible.set(true); // No recreation, already visible
159
+ Match(status, {
160
+ idle: Div('Ready'),
161
+ loading: Div('Loading...'),
162
+ success: Div('Done!'),
163
+ error: Div('Something went wrong'),
164
+ default: Div('Unknown state')
165
+ })
410
166
  ```
411
167
 
412
- ### Memory Management
413
-
414
- Functions in conditional rendering are called only when needed, preventing memory waste:
168
+ With function values for access to current observable state:
415
169
 
416
170
  ```javascript
417
- const currentTab = Observable('home');
418
-
419
- // Heavy components only created when their tab is active
420
- const TabContent = Match(currentTab, {
421
- home: () => {
422
- console.log('Creating home tab');
423
- return HomeTabComponent(); // Only created when needed
424
- },
425
- profile: () => {
426
- console.log('Creating profile tab');
427
- return ProfileTabComponent(); // Only created when needed
428
- },
429
- settings: () => {
430
- console.log('Creating settings tab');
431
- return SettingsTabComponent(); // Only created when needed
432
- }
433
- });
171
+ const phase = Observable('menu');
172
+
173
+ Match(phase, {
174
+ menu: () => Div([
175
+ H1('Welcome'),
176
+ Button('Start').nd.onClick(() => phase.set('playing'))
177
+ ]),
178
+ playing: () => Div([
179
+ Div(['Score: ', score]),
180
+ Button('Pause').nd.onClick(() => phase.set('paused'))
181
+ ]),
182
+ paused: () => Div([
183
+ H2('Paused'),
184
+ Button('Resume').nd.onClick(() => phase.set('playing'))
185
+ ])
186
+ })
434
187
  ```
435
188
 
436
- ### Avoiding Unnecessary Computations
189
+ ### Dynamic add / remove
437
190
 
438
- Use Observable.computed for expensive condition calculations:
191
+ `Match` exposes `.add()` and `.remove()` methods to update the available states at runtime:
439
192
 
440
193
  ```javascript
441
- const items = Observable.array([...largeDataset]);
442
- const searchTerm = Observable('');
443
-
444
- // Computed once, reused in multiple places
445
- const filteredItems = Observable.computed(() => {
446
- return items.val().filter(item =>
447
- item.name.toLowerCase().includes(searchTerm.val().toLowerCase())
448
- );
449
- }, [items, searchTerm]);
194
+ const view = Match(status, {
195
+ idle: Div('Ready'),
196
+ loading: Div('Loading...')
197
+ });
450
198
 
451
- const hasResults = filteredItems.check(results => results.length > 0);
199
+ // Add a new state
200
+ view.nd.add('success', Div('Done!'));
201
+ view.nd.add('success', Div('Done!'), true); // third arg: immediately switch to this state
452
202
 
453
- const SearchResults = Div([
454
- ShowIf(hasResults, () =>
455
- ForEach(filteredItems, item => ItemComponent(item))
456
- ),
457
- HideIf(hasResults, 'No results found')
458
- ]);
203
+ // Remove a state
204
+ view.nd.remove('idle');
459
205
  ```
460
206
 
461
- ## Best Practices
207
+ ### `shouldKeepInCache`
462
208
 
463
- ### 1. Choose the Right Tool
209
+ By default, `Match` caches each rendered state. Pass `false` to recreate content on every switch:
464
210
 
465
211
  ```javascript
466
- // Good: Use ShowIf for simple boolean conditions
467
- ShowIf(isVisible, content)
468
-
469
- // Good: Use Switch for binary choices
470
- Switch(isLoggedIn, welcomeMessage, loginPrompt)
471
-
472
- // Good: Use Match for multiple states
473
- Match(status, { loading: '...', success: '...', error: '...' })
474
-
475
- // Less ideal: Using Match for simple boolean
476
- Match(isVisible, { true: content, false: null })
212
+ Match(status, { loading: Div('...'), success: Div('Done') }, false)
477
213
  ```
478
214
 
479
- ### 2. Use Functions for Dynamic Content
215
+ ---
480
216
 
481
- ```javascript
482
- // Good: Function creates fresh content with current values
483
- ShowIf(user.check(u => u.isAdmin),
484
- () => Div(`Admin: ${user.val().name}`)
485
- )
486
-
487
- // Problematic: Static content won't update
488
- ShowIf(user.check(u => u.isAdmin),
489
- Div(`Admin: ${user.val().name}`) // Name won't update if user changes
490
- )
491
- ```
217
+ ## `When` - Fluent Builder
492
218
 
493
- ### 3. Combine Conditions Logically
219
+ A chainable interface for conditional rendering:
494
220
 
495
221
  ```javascript
496
- // Good: Use computed observables for complex conditions
497
- const canEdit = Observable.computed(() => {
498
- const u = user.val();
499
- const p = post.val();
500
- return u.isLoggedIn && (u.role === 'admin' || u.id === p.authorId);
501
- }, [user, post]);
502
-
503
- ShowIf(canEdit, editButton)
222
+ const score = Observable(85);
504
223
 
505
- // Less maintainable: Inline complex logic
506
- ShowIf(user.check(u => u.isLoggedIn && u.role === 'admin'), editButton)
224
+ When(score.isGreaterThanOrEqualTo(90))
225
+ .show(() => Div('Excellent!'))
226
+ .otherwise(() => Div('Keep going'))
507
227
  ```
508
228
 
509
- ### 4. Handle Edge Cases Gracefully
229
+ Convert to a DOM element explicitly with `.toNdElement()`:
510
230
 
511
231
  ```javascript
512
- // Good: Defensive programming
513
- ShowIf(data.check(d => d && d.items && d.items.length > 0),
514
- () => ForEach(data.val().items, renderItem)
515
- )
232
+ const greeting = When(isLoggedIn)
233
+ .show(() => Div('Welcome back!'))
234
+ .otherwise(() => Div('Please sign in'));
516
235
 
517
- // Risky: Might throw errors on null/undefined
518
- ShowIf(data.check(d => d.items.length > 0), content)
236
+ // .otherwise() already returns the element
237
+ // .toNdElement() is available if you build the chain without calling .otherwise()
238
+ const el = greeting.toNdElement();
519
239
  ```
520
240
 
521
- ### 5. Use Meaningful Variable Names
241
+ ---
522
242
 
523
- ```javascript
524
- // Good: Clear intent
525
- const isUserAuthenticated = user.check(u => u.token !== null);
526
- const hasUnreadMessages = messages.check(m => m.some(msg => !msg.read));
243
+ ## Choosing the Right Tool
527
244
 
528
- ShowIf(hasUnreadMessages, notificationBadge)
245
+ | Situation | Use |
246
+ |---|---|
247
+ | Simple show / hide | `ShowIf` |
248
+ | Inverse show / hide | `HideIf` / `HideIfNot` |
249
+ | Show when value matches | `ShowWhen` |
250
+ | Two options (true / false) | `Switch` |
251
+ | Multiple named states | `Match` |
252
+ | Fluent chaining style | `When` |
529
253
 
530
- // Less clear: Generic names
531
- const check1 = user.check(u => u.token !== null);
532
- const check2 = messages.check(m => m.some(msg => !msg.read));
533
- ```
254
+ ---
534
255
 
535
- ## Common Patterns
256
+ ## Best Practices
536
257
 
537
- ### Loading States with Error Handling
258
+ **Use functions for dynamic content** - static values are evaluated once at creation time:
538
259
 
539
260
  ```javascript
540
- const requestState = Observable.object({
541
- status: 'idle', // idle, loading, success, error
542
- data: null,
543
- error: null
544
- });
261
+ // Good - content reflects current value when shown
262
+ ShowIf(isAdmin, () => Div(user.select(u => u.name)))
545
263
 
546
- const DataView = Match(requestState.status, {
547
- idle: Button('Load Data').nd.onClick(loadData),
548
- loading: Div({ class: 'loading' }, 'Loading...'),
549
- success: () => DataDisplay(requestState.data.val()),
550
- error: () => Div({ class: 'error' }, [
551
- 'Error: ', requestState.error,
552
- Button('Retry').nd.onClick(loadData)
553
- ])
554
- });
264
+ // Risky - name captured at creation, won't update
265
+ ShowIf(isAdmin, Div(user.val().name))
555
266
  ```
556
267
 
557
- ### Feature Flags and Progressive Enhancement
268
+ **Use `Observable.computed()` for complex conditions:**
558
269
 
559
270
  ```javascript
560
- const features = Observable.object({
561
- darkMode: true,
562
- newDashboard: false,
563
- betaFeatures: false
564
- });
271
+ const canEdit = Observable.computed((u, p) =>
272
+ u.isLoggedIn && (u.role === 'admin' || u.id === p.authorId),
273
+ [user, post]
274
+ );
565
275
 
566
- const App = Div([
567
- // Theme switching
568
- Switch(features.darkMode,
569
- Div({ class: 'app dark-theme' }, content),
570
- Div({ class: 'app light-theme' }, content)
571
- ),
572
-
573
- // Beta features for power users
574
- ShowIf(features.betaFeatures, BetaPanel()),
575
-
576
- // A/B testing new dashboard
577
- Switch(features.newDashboard,
578
- NewDashboard(),
579
- LegacyDashboard()
580
- )
581
- ]);
276
+ ShowIf(canEdit, editButton)
582
277
  ```
583
278
 
584
- ## Debugging Conditional Rendering
585
-
586
- ### Using Console Logs in Conditions
279
+ **Use shorthand checkers instead of manual conditions:**
587
280
 
588
281
  ```javascript
589
- const debugCondition = condition.check(value => {
590
- console.log('Condition evaluated:', value);
591
- return value > 10;
592
- });
282
+ // Good
283
+ ShowIf(list.isEmpty(), Div('No items'))
284
+ ShowIf(name.isTruthy(), Div(['Hello, ', name]))
593
285
 
594
- ShowIf(debugCondition, content);
286
+ // Avoid
287
+ ShowIf(list.check(l => l.length === 0), Div('No items'))
595
288
  ```
596
289
 
597
- ### Tracking State Changes
598
-
599
- ```javascript
600
- const status = Observable('idle');
601
-
602
- // Log all status changes
603
- status.subscribe(newStatus => {
604
- console.log('Status changed to:', newStatus);
605
- });
606
-
607
- // Debug what content is being rendered
608
- const StatusContent = Match(status, {
609
- idle: () => {
610
- console.log('Rendering idle state');
611
- return IdleComponent();
612
- },
613
- loading: () => {
614
- console.log('Rendering loading state');
615
- return LoadingComponent();
616
- }
617
- });
618
- ```
290
+ ---
619
291
 
620
292
  ## Next Steps
621
293
 
622
- Now that you understand conditional rendering, explore these related topics:
294
+ - **[List Rendering](./list-rendering.md)** - ForEach and dynamic lists
295
+ - **[Observables](./observables.md)** - Reactive state management
296
+ - **[Elements](./elements.md)** - Creating and composing UI
297
+ - **[State Management](./state-management.md)** - Global state patterns
298
+ - **[Anchor](./anchor.md)** - How conditional rendering works under the hood
299
+
300
+ ## Utilities
623
301
 
624
- - **[List Rendering](list-rendering.md)** - (ForEach | ForEachArray) and dynamic lists
625
- - **[Routing](routing.md)** - Navigation and URL management
626
- - **[State Management](state-management.md)** - Global state patterns
627
- - **[Lifecycle Events](lifecycle-events.md)** - Lifecycle events
628
- - **[Memory Management](memory-management.md)** - Memory management
629
- - **[Anchor](anchor.md)** - Anchor
302
+ - **[Cache](./cache.md)** - Lazy initialization and singleton patterns
303
+ - **[NativeFetch](./native-fetch.md)** - HTTP client with interceptors
304
+ - **[Filters](./filters.md)** - Data filtering helpers