native-document 1.0.14 → 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.
- package/.npmrc.example +1 -0
- package/.vitepress/config.js +166 -0
- package/CHANGELOG.md +153 -0
- package/cdn.js +19 -0
- package/components.d.ts +2 -0
- package/components.js +30 -0
- package/devtools/ComponentRegistry.js +113 -0
- package/devtools/index.js +8 -0
- package/devtools/plugin/dev-tools-plugin.js +15 -0
- package/devtools/transformers/nd-vite-devtools.js +55 -0
- package/devtools/transformers/src/transformComponentForHrm.js +73 -0
- package/devtools/transformers/src/transformJsFile.js +9 -0
- package/devtools/transformers/src/utils.js +79 -0
- package/devtools/transformers/templates/hrm.hook.template.js +46 -0
- package/devtools/transformers/templates/hrm.orbservable.hook.template.js +76 -0
- package/devtools/widget/Widget.js +49 -0
- package/devtools/widget/widget.css +81 -0
- package/devtools/widget.js +23 -0
- package/dist/native-document.components.min.css +1 -0
- package/dist/native-document.components.min.js +23847 -0
- package/dist/native-document.dev.js +8665 -1313
- package/dist/native-document.dev.js.map +1 -0
- package/dist/native-document.devtools.min.js +1 -0
- package/dist/native-document.min.js +1 -1
- package/docs/advanced-components.md +419 -0
- package/docs/anchor.md +218 -131
- package/docs/cache.md +180 -0
- package/docs/cli.md +179 -0
- package/docs/components/accordion.md +172 -0
- package/docs/components/alert.md +99 -0
- package/docs/components/avatar.md +160 -0
- package/docs/components/badge.md +102 -0
- package/docs/components/breadcrumb.md +89 -0
- package/docs/components/button.md +183 -0
- package/docs/components/card.md +69 -0
- package/docs/components/context-menu.md +118 -0
- package/docs/components/data-table.md +345 -0
- package/docs/components/dropdown.md +214 -0
- package/docs/components/form/autocomplete-field.md +81 -0
- package/docs/components/form/checkbox-field.md +41 -0
- package/docs/components/form/checkbox-group-field.md +54 -0
- package/docs/components/form/color-field.md +64 -0
- package/docs/components/form/date-field.md +92 -0
- package/docs/components/form/field-collection.md +63 -0
- package/docs/components/form/file-field.md +203 -0
- package/docs/components/form/form-control.md +87 -0
- package/docs/components/form/image-field.md +90 -0
- package/docs/components/form/index.md +115 -0
- package/docs/components/form/number-field.md +65 -0
- package/docs/components/form/radio-field.md +51 -0
- package/docs/components/form/select-field.md +123 -0
- package/docs/components/form/slider.md +136 -0
- package/docs/components/form/string-field.md +134 -0
- package/docs/components/form/textarea-field.md +65 -0
- package/docs/components/form-fields.md +372 -0
- package/docs/components/getting-started.md +264 -0
- package/docs/components/index.md +337 -0
- package/docs/components/layout.md +279 -0
- package/docs/components/list.md +73 -0
- package/docs/components/menu.md +215 -0
- package/docs/components/modal.md +156 -0
- package/docs/components/pagination.md +95 -0
- package/docs/components/popover.md +131 -0
- package/docs/components/progress.md +111 -0
- package/docs/components/shortcut-manager.md +221 -0
- package/docs/components/simple-table.md +107 -0
- package/docs/components/skeleton.md +155 -0
- package/docs/components/spinner.md +100 -0
- package/docs/components/splitter.md +133 -0
- package/docs/components/stepper.md +163 -0
- package/docs/components/switch.md +113 -0
- package/docs/components/tabs.md +153 -0
- package/docs/components/toast.md +119 -0
- package/docs/components/tooltip.md +151 -0
- package/docs/components/traits.md +261 -0
- package/docs/conditional-rendering.md +177 -501
- package/docs/contributing.md +300 -25
- package/docs/core-concepts.md +209 -367
- package/docs/elements.md +268 -255
- package/docs/extending-native-document-element.md +259 -0
- package/docs/filters.md +247 -0
- package/docs/getting-started.md +199 -260
- package/docs/i18n.md +241 -0
- package/docs/index.md +76 -0
- package/docs/lifecycle-events.md +146 -67
- package/docs/list-rendering.md +387 -0
- package/docs/memory-management.md +135 -46
- package/docs/native-document-element.md +487 -0
- package/docs/native-fetch.md +213 -0
- package/docs/observable-resource.md +364 -0
- package/docs/observables.md +690 -356
- package/docs/routing.md +246 -646
- package/docs/state-management.md +213 -306
- package/docs/svg-elements.md +231 -0
- package/docs/theming.md +409 -0
- package/docs/tutorials/.gitkeep +0 -0
- package/docs/validation.md +98 -93
- package/docs/vitepress-conventions.md +219 -0
- package/elements.d.ts +7 -0
- package/elements.js +3 -4
- package/eslint.config.js +35 -0
- package/i18n.js +1 -0
- package/i18n.ts +2 -0
- package/index.d.ts +21 -0
- package/index.def.js +1086 -0
- package/index.js +19 -8
- package/package.json +59 -9
- package/readme.md +294 -90
- package/rollup.config.js +52 -3
- package/router.d.ts +7 -0
- package/router.js +0 -0
- package/src/components/$traits/has-draggable/HasDraggable.d.ts +4 -0
- package/src/components/$traits/has-draggable/HasDraggable.js +82 -0
- package/src/components/$traits/has-draggable/has-draggable.css +8 -0
- package/src/components/$traits/has-items/HasItems.d.ts +9 -0
- package/src/components/$traits/has-items/HasItems.js +64 -0
- package/src/components/$traits/has-position/HasFullPosition.d.ts +14 -0
- package/src/components/$traits/has-position/HasFullPosition.js +95 -0
- package/src/components/$traits/has-position/HasPosition.d.ts +7 -0
- package/src/components/$traits/has-position/HasPosition.js +45 -0
- package/src/components/$traits/has-resizable/HasResizable.d.ts +13 -0
- package/src/components/$traits/has-resizable/HasResizable.js +122 -0
- package/src/components/$traits/has-resizable/has-resizable.css +121 -0
- package/src/components/$traits/has-validation/HasValidation.d.ts +17 -0
- package/src/components/$traits/has-validation/HasValidation.js +133 -0
- package/src/components/BaseComponent.d.ts +32 -0
- package/src/components/BaseComponent.js +247 -0
- package/src/components/accordion/Accordion.js +268 -0
- package/src/components/accordion/AccordionItem.js +233 -0
- package/src/components/accordion/index.js +7 -0
- package/src/components/accordion/types/Accordion.d.ts +47 -0
- package/src/components/accordion/types/AccordionItem.d.ts +48 -0
- package/src/components/alert/Alert.js +350 -0
- package/src/components/alert/index.js +6 -0
- package/src/components/alert/types/Alert.d.ts +62 -0
- package/src/components/avatar/Avatar.js +430 -0
- package/src/components/avatar/AvatarGroup.js +97 -0
- package/src/components/avatar/index.js +7 -0
- package/src/components/avatar/types/Avatar.d.ts +74 -0
- package/src/components/avatar/types/AvatarGroup.d.ts +32 -0
- package/src/components/badge/Badge.js +245 -0
- package/src/components/badge/index.js +6 -0
- package/src/components/badge/types/Badge.d.ts +51 -0
- package/src/components/base-component.css +0 -0
- package/src/components/breadcrumb/BreadCrumb.js +138 -0
- package/src/components/breadcrumb/index.js +5 -0
- package/src/components/breadcrumb/types/BreadCrumb.d.ts +42 -0
- package/src/components/button/Button.js +320 -0
- package/src/components/button/index.js +5 -0
- package/src/components/button/types/Button.d.ts +62 -0
- package/src/components/card/Card.js +282 -0
- package/src/components/card/index.js +5 -0
- package/src/components/card/types/Card.d.ts +42 -0
- package/src/components/context-menu/ContextMenu.js +127 -0
- package/src/components/context-menu/ContextMenuGroup.js +29 -0
- package/src/components/context-menu/ContextMenuItem.js +28 -0
- package/src/components/context-menu/index.js +10 -0
- package/src/components/context-menu/types/ContextMenu.d.ts +30 -0
- package/src/components/context-menu/types/ContextMenuGroup.d.ts +18 -0
- package/src/components/context-menu/types/ContextMenuItem.d.ts +18 -0
- package/src/components/divider/Divider.js +256 -0
- package/src/components/divider/index.js +6 -0
- package/src/components/divider/types/Divider.d.ts +55 -0
- package/src/components/dropdown/Dropdown.js +531 -0
- package/src/components/dropdown/DropdownDivider.js +45 -0
- package/src/components/dropdown/DropdownGroup.js +83 -0
- package/src/components/dropdown/DropdownItem.js +150 -0
- package/src/components/dropdown/DropdownTrigger.js +93 -0
- package/src/components/dropdown/helpers.js +53 -0
- package/src/components/dropdown/index.js +13 -0
- package/src/components/dropdown/types/Dropdown.d.ts +88 -0
- package/src/components/dropdown/types/DropdownDivider.d.ts +20 -0
- package/src/components/dropdown/types/DropdownGroup.d.ts +25 -0
- package/src/components/dropdown/types/DropdownItem.d.ts +41 -0
- package/src/components/dropdown/types/DropdownTrigger.d.ts +32 -0
- package/src/components/form/FormControl.js +498 -0
- package/src/components/form/field/Field.js +419 -0
- package/src/components/form/field/FieldCollection.js +292 -0
- package/src/components/form/field/types/AutocompleteField.js +168 -0
- package/src/components/form/field/types/CheckboxField.js +77 -0
- package/src/components/form/field/types/CheckboxGroupField.js +171 -0
- package/src/components/form/field/types/ColorField.js +102 -0
- package/src/components/form/field/types/DateField.js +315 -0
- package/src/components/form/field/types/EmailField.js +104 -0
- package/src/components/form/field/types/FileField.js +276 -0
- package/src/components/form/field/types/HiddenField.js +44 -0
- package/src/components/form/field/types/ImageField.js +138 -0
- package/src/components/form/field/types/NumberField.js +177 -0
- package/src/components/form/field/types/PasswordField.js +200 -0
- package/src/components/form/field/types/RadioField.js +145 -0
- package/src/components/form/field/types/RangeField.js +117 -0
- package/src/components/form/field/types/SearchField.js +66 -0
- package/src/components/form/field/types/SelectField.js +247 -0
- package/src/components/form/field/types/StringField.js +148 -0
- package/src/components/form/field/types/TelField.js +98 -0
- package/src/components/form/field/types/TextAreaField.js +142 -0
- package/src/components/form/field/types/TimeField.js +215 -0
- package/src/components/form/field/types/UrlField.js +115 -0
- package/src/components/form/field/types/file-field-mode/FileAvatarMode.js +183 -0
- package/src/components/form/field/types/file-field-mode/FileDropzoneMode.js +117 -0
- package/src/components/form/field/types/file-field-mode/FileItemPreview.js +150 -0
- package/src/components/form/field/types/file-field-mode/FileNativeMode.js +43 -0
- package/src/components/form/field/types/file-field-mode/FileUploadButtonMode.js +120 -0
- package/src/components/form/field/types/file-field-mode/FileWallMode.js +106 -0
- package/src/components/form/index.js +61 -0
- package/src/components/form/merge +0 -0
- package/src/components/form/types/Field.d.ts +73 -0
- package/src/components/form/types/FieldCollection.d.ts +53 -0
- package/src/components/form/types/FormControl.d.ts +64 -0
- package/src/components/form/types/fields/AutocompleteField.d.ts +48 -0
- package/src/components/form/types/fields/CheckboxField.d.ts +33 -0
- package/src/components/form/types/fields/CheckboxGroupField.d.ts +49 -0
- package/src/components/form/types/fields/ColorField.d.ts +37 -0
- package/src/components/form/types/fields/DateField.d.ts +70 -0
- package/src/components/form/types/fields/EmailField.d.ts +35 -0
- package/src/components/form/types/fields/FileAvatarMode.d.ts +46 -0
- package/src/components/form/types/fields/FileDropzoneMode.d.ts +28 -0
- package/src/components/form/types/fields/FileField.d.ts +56 -0
- package/src/components/form/types/fields/FileItemPreview.d.ts +35 -0
- package/src/components/form/types/fields/FileNativeMode.d.ts +21 -0
- package/src/components/form/types/fields/FileUploadButtonMode.d.ts +34 -0
- package/src/components/form/types/fields/FileWallMode.d.ts +32 -0
- package/src/components/form/types/fields/HiddenField.d.ts +26 -0
- package/src/components/form/types/fields/ImageField.d.ts +45 -0
- package/src/components/form/types/fields/NumberField.d.ts +48 -0
- package/src/components/form/types/fields/PasswordField.d.ts +46 -0
- package/src/components/form/types/fields/RadioField.d.ts +48 -0
- package/src/components/form/types/fields/RangeField.d.ts +44 -0
- package/src/components/form/types/fields/SearchField.d.ts +34 -0
- package/src/components/form/types/fields/SelectField.d.ts +71 -0
- package/src/components/form/types/fields/StringField.d.ts +48 -0
- package/src/components/form/types/fields/TelField.d.ts +37 -0
- package/src/components/form/types/fields/TextAreaField.d.ts +44 -0
- package/src/components/form/types/fields/TimeField.d.ts +51 -0
- package/src/components/form/types/fields/UrlField.d.ts +35 -0
- package/src/components/form/utils.js +17 -0
- package/src/components/form/validation/Validation.js +565 -0
- package/src/components/index.d.ts +160 -0
- package/src/components/list/HasListItem.js +171 -0
- package/src/components/list/List.js +125 -0
- package/src/components/list/ListDivider.js +39 -0
- package/src/components/list/ListGroup.js +135 -0
- package/src/components/list/ListItem.js +212 -0
- package/src/components/list/index.js +12 -0
- package/src/components/list/types/List.d.ts +43 -0
- package/src/components/list/types/ListGroup.d.ts +37 -0
- package/src/components/list/types/ListItem.d.ts +53 -0
- package/src/components/menu/HasMenuItem.js +182 -0
- package/src/components/menu/Menu.js +227 -0
- package/src/components/menu/MenuDivider.js +37 -0
- package/src/components/menu/MenuGroup.js +126 -0
- package/src/components/menu/MenuItem.js +190 -0
- package/src/components/menu/MenuLink.js +51 -0
- package/src/components/menu/index.js +14 -0
- package/src/components/menu/types/Menu.d.ts +60 -0
- package/src/components/menu/types/MenuDivider.d.ts +19 -0
- package/src/components/menu/types/MenuGroup.d.ts +44 -0
- package/src/components/menu/types/MenuItem.d.ts +46 -0
- package/src/components/menu/types/MenuLink.d.ts +16 -0
- package/src/components/modal/Modal.js +524 -0
- package/src/components/modal/index.js +5 -0
- package/src/components/modal/types/Modal.d.ts +94 -0
- package/src/components/pagination/Pagination.js +411 -0
- package/src/components/pagination/index.js +5 -0
- package/src/components/pagination/types/Pagination.d.ts +68 -0
- package/src/components/popover/Popover.js +459 -0
- package/src/components/popover/PopoverFooter.js +61 -0
- package/src/components/popover/PopoverHeader.js +68 -0
- package/src/components/popover/index.js +10 -0
- package/src/components/popover/types/Popover.d.ts +83 -0
- package/src/components/popover/types/PopoverFooter.d.ts +24 -0
- package/src/components/popover/types/PopoverHeader.d.ts +26 -0
- package/src/components/progress/Progress.js +401 -0
- package/src/components/progress/index.js +6 -0
- package/src/components/progress/types/Progress.d.ts +77 -0
- package/src/components/skeleton/Skeleton.js +228 -0
- package/src/components/skeleton/index.js +6 -0
- package/src/components/skeleton/types/Skeleton.d.ts +55 -0
- package/src/components/slider/Slider.js +406 -0
- package/src/components/slider/index.js +5 -0
- package/src/components/slider/types/Slider.d.ts +82 -0
- package/src/components/spacer/Spacer.js +27 -0
- package/src/components/spacer/index.js +5 -0
- package/src/components/spacer/types/Spacer.d.ts +19 -0
- package/src/components/spinner/Spinner.js +350 -0
- package/src/components/spinner/index.js +5 -0
- package/src/components/spinner/types/Spinner.d.ts +71 -0
- package/src/components/splitter/Splitter.js +164 -0
- package/src/components/splitter/SplitterGutter.js +140 -0
- package/src/components/splitter/SplitterPanel.js +143 -0
- package/src/components/splitter/index.js +10 -0
- package/src/components/splitter/types/Splitter.d.ts +38 -0
- package/src/components/splitter/types/SplitterGutter.d.ts +38 -0
- package/src/components/splitter/types/SplitterPanel.d.ts +41 -0
- package/src/components/stacks/AbsoluteStack.js +53 -0
- package/src/components/stacks/FixedStack.js +53 -0
- package/src/components/stacks/HStack.js +54 -0
- package/src/components/stacks/PositionStack.js +254 -0
- package/src/components/stacks/RelativeStack.js +53 -0
- package/src/components/stacks/Stack.js +166 -0
- package/src/components/stacks/VStack.js +55 -0
- package/src/components/stacks/index.js +21 -0
- package/src/components/stacks/types/AbsoluteStack.d.ts +16 -0
- package/src/components/stacks/types/FixedStack.d.ts +16 -0
- package/src/components/stacks/types/HStack.d.ts +16 -0
- package/src/components/stacks/types/PositionStack.d.ts +54 -0
- package/src/components/stacks/types/RelativeStack.d.ts +17 -0
- package/src/components/stacks/types/Stack.d.ts +39 -0
- package/src/components/stacks/types/VStack.d.ts +16 -0
- package/src/components/stepper/Stepper.js +461 -0
- package/src/components/stepper/StepperStep.js +241 -0
- package/src/components/stepper/index.js +8 -0
- package/src/components/stepper/types/Stepper.d.ts +68 -0
- package/src/components/stepper/types/StepperStep.d.ts +54 -0
- package/src/components/switch/Switch.js +266 -0
- package/src/components/switch/index.js +6 -0
- package/src/components/switch/types/Switch.d.ts +55 -0
- package/src/components/table/Column.js +212 -0
- package/src/components/table/ColumnGroup.js +90 -0
- package/src/components/table/DataTable.js +720 -0
- package/src/components/table/SimpleTable.js +139 -0
- package/src/components/table/index.js +7 -0
- package/src/components/table/types/Column.d.ts +49 -0
- package/src/components/table/types/ColumnGroup.d.ts +28 -0
- package/src/components/table/types/DataTable.d.ts +97 -0
- package/src/components/table/types/SimpleTable.d.ts +40 -0
- package/src/components/tabs/Tabs.js +395 -0
- package/src/components/tabs/index.js +6 -0
- package/src/components/tabs/types/Tabs.d.ts +78 -0
- package/src/components/toast/Toast.js +262 -0
- package/src/components/toast/ToastError.js +0 -0
- package/src/components/toast/ToastInfo.js +0 -0
- package/src/components/toast/ToastSuccess.js +0 -0
- package/src/components/toast/ToastWarning.js +0 -0
- package/src/components/toast/index.js +5 -0
- package/src/components/toast/types/Toast.d.ts +57 -0
- package/src/components/toast/types/ToastError.d.ts +7 -0
- package/src/components/toast/types/ToastInfo.d.ts +7 -0
- package/src/components/toast/types/ToastSuccess.d.ts +7 -0
- package/src/components/toast/types/ToastWarning.d.ts +7 -0
- package/src/components/tooltip/Tooltip.js +359 -0
- package/src/components/tooltip/index.js +5 -0
- package/src/components/tooltip/prototypes.js +6 -0
- package/src/components/tooltip/types/Tooltip.d.ts +65 -0
- package/src/{data → core/data}/MemoryManager.js +9 -22
- package/src/core/data/Observable.js +227 -0
- package/src/core/data/ObservableArray.js +522 -0
- package/src/core/data/ObservableChecker.js +39 -0
- package/src/core/data/ObservableItem.js +611 -0
- package/src/core/data/ObservableObject.js +274 -0
- package/src/core/data/ObservableResource.js +315 -0
- package/src/core/data/ObservableWhen.js +54 -0
- package/src/core/data/Store.js +520 -0
- package/src/core/data/observable-helpers/observable.is-to.js +390 -0
- package/src/core/data/observable-helpers/observable.prototypes.js +145 -0
- package/src/core/elements/anchor/anchor-with-sentinel.js +66 -0
- package/src/core/elements/anchor/anchor.js +210 -0
- package/src/core/elements/anchor/one-child-anchor-overwriting.js +66 -0
- package/src/core/elements/content-formatter.js +169 -0
- package/src/core/elements/control/for-each-array.js +292 -0
- package/src/core/elements/control/for-each.js +170 -0
- package/src/core/elements/control/show-if.js +94 -0
- package/src/core/elements/control/show-when.js +54 -0
- package/src/core/elements/control/switch.js +141 -0
- package/src/core/elements/description-list.js +19 -0
- package/src/core/elements/form.js +255 -0
- package/src/core/elements/fragment.js +8 -0
- package/src/core/elements/html5-semantics.js +55 -0
- package/src/core/elements/img.js +59 -0
- package/src/{elements → core/elements}/index.js +5 -4
- package/src/core/elements/interactive.js +25 -0
- package/src/core/elements/list.js +37 -0
- package/src/core/elements/medias.js +37 -0
- package/src/core/elements/meta-data.js +43 -0
- package/src/core/elements/svg.js +61 -0
- package/src/core/elements/table.js +73 -0
- package/src/{errors → core/errors}/ArgTypesError.js +1 -1
- package/src/{errors → core/errors}/NativeDocumentError.js +0 -0
- package/src/core/utils/HasEventEmitter.js +85 -0
- package/src/core/utils/args-types.js +140 -0
- package/src/core/utils/cache.js +5 -0
- package/src/core/utils/callback-handler.js +50 -0
- package/src/core/utils/debug-manager.js +40 -0
- package/src/core/utils/events.js +148 -0
- package/src/core/utils/filters/date.js +178 -0
- package/src/core/utils/filters/index.js +4 -0
- package/src/core/utils/filters/standard.js +263 -0
- package/src/core/utils/filters/strings.js +67 -0
- package/src/core/utils/filters/utils.js +77 -0
- package/src/core/utils/formatters.js +90 -0
- package/src/core/utils/helpers.js +144 -0
- package/src/core/utils/localstorage.js +57 -0
- package/src/core/utils/memoize.js +115 -0
- package/src/core/utils/plugins-manager.js +81 -0
- package/src/core/utils/property-accumulator.js +72 -0
- package/src/core/utils/prototypes.js +44 -0
- package/src/core/utils/shortcut-manager.js +242 -0
- package/src/{utils → core/utils}/validator.js +58 -22
- package/src/core/wrappers/AttributesWrapper.js +181 -0
- package/src/core/wrappers/DocumentObserver.js +182 -0
- package/src/core/wrappers/ElementCreator.js +110 -0
- package/src/core/wrappers/HtmlElementWrapper.js +98 -0
- package/src/core/wrappers/NDElement.js +613 -0
- package/src/core/wrappers/NdPrototype.js +233 -0
- package/src/core/wrappers/SingletonView.js +99 -0
- package/src/core/wrappers/SvgElementWrapper.js +15 -0
- package/src/core/wrappers/TemplateBinding.js +7 -0
- package/src/core/wrappers/constants.js +66 -0
- package/src/core/wrappers/prototypes/attributes-extensions.js +24 -0
- package/src/core/wrappers/prototypes/bind-class-extensions.js +0 -0
- package/src/core/wrappers/prototypes/nd-element-extensions.js +149 -0
- package/src/core/wrappers/prototypes/nd-element.transition.extensions.js +127 -0
- package/src/core/wrappers/template-cloner/NodeCloner.js +209 -0
- package/src/core/wrappers/template-cloner/TemplateCloner.js +192 -0
- package/src/core/wrappers/template-cloner/attributes-hydrator.js +142 -0
- package/src/core/wrappers/template-cloner/utils.js +173 -0
- package/src/fetch/NativeFetch.js +89 -0
- package/src/i18n/bin/scan.js +132 -0
- package/src/i18n/index.d.ts +2 -0
- package/src/i18n/service/I18nService.d.ts +27 -0
- package/src/i18n/service/I18nService.js +46 -0
- package/src/i18n/service/functions.d.ts +22 -0
- package/src/i18n/service/functions.js +29 -0
- package/src/router/Route.js +33 -8
- package/src/router/RouteGroupHelper.js +10 -2
- package/src/router/Router.js +63 -22
- package/src/router/RouterComponent.js +114 -6
- package/src/{errors → router/errors}/RouterError.js +0 -1
- package/src/router/link.js +9 -10
- package/src/router/modes/HashRouter.js +2 -2
- package/src/router/modes/HistoryRouter.js +2 -3
- package/src/router/modes/MemoryRouter.js +1 -1
- package/src/ui/components/accordion/AccordionItemRender.js +63 -0
- package/src/ui/components/accordion/AccordionRender.js +35 -0
- package/src/ui/components/accordion/accordion.css +121 -0
- package/src/ui/components/alert/AlertRender.js +81 -0
- package/src/ui/components/alert/alert.css +163 -0
- package/src/ui/components/avatar/avata-group/AvatarGroupRender.js +50 -0
- package/src/ui/components/avatar/avata-group/avatar-group.css +38 -0
- package/src/ui/components/avatar/avatar/AvatarRender.js +87 -0
- package/src/ui/components/avatar/avatar/avatar.css +189 -0
- package/src/ui/components/badge/BadgeRender.js +25 -0
- package/src/ui/components/badge/badge.css +168 -0
- package/src/ui/components/breadcrumb/BreadcrumbRender.js +44 -0
- package/src/ui/components/breadcrumb/breadcrumb.css +55 -0
- package/src/ui/components/button/ButtonRender.js +65 -0
- package/src/ui/components/button/button.css +296 -0
- package/src/ui/components/card/CardRender.js +133 -0
- package/src/ui/components/card/card.css +169 -0
- package/src/ui/components/contextmenu/ContextmenuRender.js +68 -0
- package/src/ui/components/contextmenu/contextmenu.css +36 -0
- package/src/ui/components/divider/DividerRender.js +70 -0
- package/src/ui/components/divider/divider.css +70 -0
- package/src/ui/components/dropdown/DropdownRender.js +92 -0
- package/src/ui/components/dropdown/divider/DropdownDividerRender.js +9 -0
- package/src/ui/components/dropdown/divider/dropdown-divider.css +0 -0
- package/src/ui/components/dropdown/dropdown.css +179 -0
- package/src/ui/components/dropdown/group/DropdownGroupRender.js +23 -0
- package/src/ui/components/dropdown/group/dropdown-group.css +0 -0
- package/src/ui/components/dropdown/item/DropdownItemRender.js +29 -0
- package/src/ui/components/dropdown/item/dropdown-item.css +0 -0
- package/src/ui/components/form/FieldCollectionRender.js +110 -0
- package/src/ui/components/form/FormControlRender.js +85 -0
- package/src/ui/components/form/field-collection.css +55 -0
- package/src/ui/components/form/fields/AutocompleteFieldRender.js +143 -0
- package/src/ui/components/form/fields/CheckboxFieldRender.js +59 -0
- package/src/ui/components/form/fields/CheckboxGroupFieldRender.js +92 -0
- package/src/ui/components/form/fields/ColorFieldRender.js +30 -0
- package/src/ui/components/form/fields/DateFieldRender.js +155 -0
- package/src/ui/components/form/fields/EmailFieldRender.js +5 -0
- package/src/ui/components/form/fields/FieldRender.js +118 -0
- package/src/ui/components/form/fields/FileFieldRender.js +41 -0
- package/src/ui/components/form/fields/HiddenFieldRender.js +13 -0
- package/src/ui/components/form/fields/ImageFieldRender.js +0 -0
- package/src/ui/components/form/fields/NumberFieldRender.js +52 -0
- package/src/ui/components/form/fields/PasswordFieldRender.js +65 -0
- package/src/ui/components/form/fields/RadioFieldRender.js +77 -0
- package/src/ui/components/form/fields/RangeFieldRender.js +122 -0
- package/src/ui/components/form/fields/SelectFieldRender.js +248 -0
- package/src/ui/components/form/fields/SliderFieldRender.js +359 -0
- package/src/ui/components/form/fields/StringFieldRender.js +6 -0
- package/src/ui/components/form/fields/TelFieldRender.js +6 -0
- package/src/ui/components/form/fields/TextAreaFieldRender.js +96 -0
- package/src/ui/components/form/fields/TimeFieldRender.js +142 -0
- package/src/ui/components/form/fields/UrlFieldRender.js +6 -0
- package/src/ui/components/form/fields/date-field.css +32 -0
- package/src/ui/components/form/fields/field.css +402 -0
- package/src/ui/components/form/fields/file-field.css +79 -0
- package/src/ui/components/form/fields/password-field.css +50 -0
- package/src/ui/components/form/fields/range-field.css +120 -0
- package/src/ui/components/form/fields/slider.css +195 -0
- package/src/ui/components/form/file-upload-mode/FileAvatarModeRender.js +143 -0
- package/src/ui/components/form/file-upload-mode/FileDropzoneModeRender.js +108 -0
- package/src/ui/components/form/file-upload-mode/FileNativeModeRender.js +22 -0
- package/src/ui/components/form/file-upload-mode/FileUploadButtonModeRender.js +89 -0
- package/src/ui/components/form/file-upload-mode/FileWallModeRender.js +90 -0
- package/src/ui/components/form/file-upload-mode/file-avatar-mode.css +139 -0
- package/src/ui/components/form/file-upload-mode/file-dropzone-mode.css +88 -0
- package/src/ui/components/form/file-upload-mode/file-upload-button-mode.css +44 -0
- package/src/ui/components/form/file-upload-mode/file-wall-mode.css +88 -0
- package/src/ui/components/form/form-control.css +40 -0
- package/src/ui/components/form/helpers.js +111 -0
- package/src/ui/components/form/index.js +27 -0
- package/src/ui/components/list/ListRender.js +18 -0
- package/src/ui/components/list/divider/ListDividerRender.js +10 -0
- package/src/ui/components/list/divider/list-divider.css +12 -0
- package/src/ui/components/list/group/ListGroupRender.js +61 -0
- package/src/ui/components/list/group/list-group.css +62 -0
- package/src/ui/components/list/item/ListItemRender.js +238 -0
- package/src/ui/components/list/item/list-item.css +191 -0
- package/src/ui/components/list/list.css +24 -0
- package/src/ui/components/menu/MenuDividerRender.js +12 -0
- package/src/ui/components/menu/MenuGroupRender.js +59 -0
- package/src/ui/components/menu/MenuItemRender.js +57 -0
- package/src/ui/components/menu/MenuLinkRender.js +55 -0
- package/src/ui/components/menu/MenuRender.js +22 -0
- package/src/ui/components/menu/helpers.js +121 -0
- package/src/ui/components/menu/menu.css +308 -0
- package/src/ui/components/modal/ModalRender.js +118 -0
- package/src/ui/components/modal/modal.css +156 -0
- package/src/ui/components/pagination/PaginationRender.js +112 -0
- package/src/ui/components/pagination/pagination.css +63 -0
- package/src/ui/components/popover/PopoverRender.js +233 -0
- package/src/ui/components/popover/popover.css +139 -0
- package/src/ui/components/progress/ProgressRender.js +168 -0
- package/src/ui/components/progress/progress.css +197 -0
- package/src/ui/components/skeleton/SkeletonRender.js +136 -0
- package/src/ui/components/skeleton/skeleton.css +154 -0
- package/src/ui/components/spacer/SpacerRender.js +10 -0
- package/src/ui/components/spinner/SpinnerRender.js +47 -0
- package/src/ui/components/spinner/spinner.css +152 -0
- package/src/ui/components/splitter/SplitterGutterRender.js +94 -0
- package/src/ui/components/splitter/SplitterPanelRender.js +38 -0
- package/src/ui/components/splitter/SplitterRender.js +75 -0
- package/src/ui/components/splitter/splitter.css +128 -0
- package/src/ui/components/stacks/PositionStackRender.js +39 -0
- package/src/ui/components/stacks/StackRender.js +41 -0
- package/src/ui/components/stacks/absolute-stack/AbsoluteStackRender.js +5 -0
- package/src/ui/components/stacks/fixed-stack/FixedStackRender.js +5 -0
- package/src/ui/components/stacks/h-stack/HStackRender.js +7 -0
- package/src/ui/components/stacks/h-stack/h-stack.css +4 -0
- package/src/ui/components/stacks/index.js +5 -0
- package/src/ui/components/stacks/position-stack.css +62 -0
- package/src/ui/components/stacks/relative-stack/RelativeStackRender.js +7 -0
- package/src/ui/components/stacks/relative-stack/relative-stack.css +3 -0
- package/src/ui/components/stacks/stack.css +78 -0
- package/src/ui/components/stacks/v-stack/VStackRender.js +6 -0
- package/src/ui/components/stacks/v-stack/v-stack.css +4 -0
- package/src/ui/components/stepper/StepperRender.js +71 -0
- package/src/ui/components/stepper/StepperStepRender.js +67 -0
- package/src/ui/components/stepper/stepper.css +359 -0
- package/src/ui/components/switch/SwitchRender.js +83 -0
- package/src/ui/components/switch/switch.css +143 -0
- package/src/ui/components/table/data-table/DataTableRender.js +50 -0
- package/src/ui/components/table/data-table/bulk-actions.js +34 -0
- package/src/ui/components/table/data-table/data-table.css +246 -0
- package/src/ui/components/table/data-table/pagination.js +56 -0
- package/src/ui/components/table/data-table/tables.js +368 -0
- package/src/ui/components/table/data-table/toolbar.js +67 -0
- package/src/ui/components/table/simple-table/SimpleTableRender.js +203 -0
- package/src/ui/components/table/simple-table/simple-table.css +50 -0
- package/src/ui/components/tabs/TabsRender.js +226 -0
- package/src/ui/components/tabs/tabs.css +253 -0
- package/src/ui/components/toast/ToastRender.js +99 -0
- package/src/ui/components/toast/toast.css +201 -0
- package/src/ui/components/tooltip/TooltipRender.js +8 -0
- package/src/ui/components/tooltip/tooltip.css +113 -0
- package/src/ui/index.js +47 -0
- package/src/ui/theme.js +0 -0
- package/src/ui/theme.scss +1 -0
- package/src/ui/tokens/animation.scss +36 -0
- package/src/ui/tokens/colors-dark.scss +58 -0
- package/src/ui/tokens/colors.scss +54 -0
- package/src/ui/tokens/components.scss +32 -0
- package/src/ui/tokens/fonts.scss +57 -0
- package/src/ui/tokens/glass.scss +10 -0
- package/src/ui/tokens/index.scss +38 -0
- package/src/ui/tokens/layouts.scss +228 -0
- package/src/ui/tokens/opacity.scss +21 -0
- package/src/ui/tokens/others.scss +11 -0
- package/src/ui/tokens/radius.scss +6 -0
- package/src/ui/tokens/reset.scss +51 -0
- package/src/ui/tokens/shadows.scss +29 -0
- package/src/ui/tokens/spacings.scss +13 -0
- package/src/ui/tokens/vars.scss +35 -0
- package/src/ui/tokens/viewports.scss +30 -0
- package/types/args-types.d.ts +58 -0
- package/types/control-flow.d.ts +62 -0
- package/types/elements.d.ts +231 -0
- package/types/filters/dates.d.ts +43 -0
- package/types/filters/index.d.ts +4 -0
- package/types/filters/standard.d.ts +70 -0
- package/types/filters/strings.d.ts +21 -0
- package/types/filters/types.d.ts +20 -0
- package/types/forms.d.ts +84 -0
- package/types/globals.d.ts +543 -0
- package/types/images.d.ts +23 -0
- package/types/localStorage.ts +102 -0
- package/types/memoize.d.ts +26 -0
- package/types/native-fetch.d.ts +72 -0
- package/types/nd-element.d.ts +407 -0
- package/types/observable-resource.d.ts +3 -0
- package/types/observable.d.ts +227 -0
- package/types/plugins-manager.d.ts +65 -0
- package/types/polyfill.d.ts +18 -0
- package/types/property-accumulator.d.ts +33 -0
- package/types/router.d.ts +85 -0
- package/types/service.d.ts +23 -0
- package/types/singleton.d.ts +19 -0
- package/types/store.d.ts +63 -0
- package/types/template-cloner.ts +43 -0
- package/types/validator.ts +66 -0
- package/ui.js +1 -0
- package/utils.d.ts +4 -0
- package/utils.js +12 -0
- package/src/data/Observable.js +0 -233
- package/src/data/ObservableChecker.js +0 -38
- package/src/data/ObservableItem.js +0 -116
- package/src/data/Store.js +0 -74
- package/src/elements/anchor.js +0 -84
- package/src/elements/content-formatter.js +0 -32
- package/src/elements/control/for-each.js +0 -174
- package/src/elements/control/show-if.js +0 -79
- package/src/elements/control/switch.js +0 -98
- package/src/elements/description-list.js +0 -5
- package/src/elements/form.js +0 -71
- package/src/elements/html5-semantics.js +0 -12
- package/src/elements/img.js +0 -45
- package/src/elements/interactive.js +0 -7
- package/src/elements/list.js +0 -6
- package/src/elements/medias.js +0 -8
- package/src/elements/meta-data.js +0 -9
- package/src/elements/table.js +0 -14
- package/src/utils/args-types.js +0 -100
- package/src/utils/debug-manager.js +0 -31
- package/src/utils/helpers.js +0 -37
- package/src/utils/plugins-manager.js +0 -12
- package/src/utils/prototypes.js +0 -45
- package/src/wrappers/AttributesWrapper.js +0 -157
- package/src/wrappers/DocumentObserver.js +0 -51
- package/src/wrappers/HtmlElementEventsWrapper.js +0 -77
- package/src/wrappers/HtmlElementWrapper.js +0 -206
- package/src/wrappers/constants.js +0 -2
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: List Rendering
|
|
3
|
+
description: Efficiently render dynamic collections with ForEach and ForEachArray - automatic DOM updates, keyed diffing, and reactive filtering
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# List Rendering
|
|
7
|
+
|
|
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.
|
|
9
|
+
|
|
10
|
+
```javascript
|
|
11
|
+
import { ForEach, ForEachArray } from 'native-document/elements';
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## `ForEach` - Generic Collection Rendering
|
|
17
|
+
|
|
18
|
+
`ForEach` works with both observable arrays and observable objects.
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
ForEach(data, callback, key?, options?)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Array iteration
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
const fruits = Observable.array(['Apple', 'Banana', 'Cherry']);
|
|
28
|
+
|
|
29
|
+
Ul(
|
|
30
|
+
ForEach(fruits, fruit => Li(fruit))
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
// All array operations trigger DOM updates
|
|
34
|
+
fruits.push('Orange');
|
|
35
|
+
fruits.splice(1, 1);
|
|
36
|
+
fruits.sort();
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Object iteration
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
const roles = Observable({
|
|
43
|
+
admin: 'Administrator',
|
|
44
|
+
editor: 'Content Editor',
|
|
45
|
+
viewer: 'Read Only'
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
Ul(
|
|
49
|
+
ForEach(roles, (roleName, roleKey) =>
|
|
50
|
+
Li([Strong(roleKey), ': ', roleName])
|
|
51
|
+
)
|
|
52
|
+
)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Index parameter
|
|
56
|
+
|
|
57
|
+
The second callback argument is an **observable** tracking the item's current index:
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
const tasks = Observable.array(['Review PRs', 'Update docs', 'Fix bugs']);
|
|
61
|
+
|
|
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
|
+
))
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Key function
|
|
72
|
+
|
|
73
|
+
Use a key to help NativeDocument identify items for efficient reordering. Pass a property name string or a function:
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
const users = Observable.array([
|
|
77
|
+
{ id: 1, name: 'Alice', role: 'admin' },
|
|
78
|
+
{ id: 2, name: 'Bob', role: 'user' }
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
// Property name shorthand
|
|
82
|
+
ForEach(users, user => Div(user.name), 'id')
|
|
83
|
+
|
|
84
|
+
// Function
|
|
85
|
+
ForEach(users, user => Div(user.name), item => item.id)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Options
|
|
89
|
+
|
|
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:
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
// Items are cached - re-adding won't re-render them
|
|
98
|
+
ForEach(items, renderItem, 'id', { shouldKeepItemsInCache: true })
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## `ForEachArray` - High-Performance Array Rendering
|
|
104
|
+
|
|
105
|
+
`ForEachArray` is specifically optimized for arrays of objects. Use it when performance matters.
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
ForEachArray(data, callback, configs?)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
const messages = Observable.array([
|
|
113
|
+
{ id: 1, text: 'Hello!', timestamp: Date.now() },
|
|
114
|
+
{ id: 2, text: 'How are you?', timestamp: Date.now() + 1000 }
|
|
115
|
+
]);
|
|
116
|
+
|
|
117
|
+
Div({ class: 'chat' },
|
|
118
|
+
ForEachArray(messages, message =>
|
|
119
|
+
Div({ class: 'message' }, [
|
|
120
|
+
Div(message.text),
|
|
121
|
+
Div(new Date(message.timestamp).toLocaleTimeString())
|
|
122
|
+
])
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Index in `ForEachArray`
|
|
128
|
+
|
|
129
|
+
The index is a **computed observable** derived from the array - always reactive, no need to call `.val()` to use it in the DOM:
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
ForEachArray(playlist, (song, index) =>
|
|
133
|
+
Div([
|
|
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
|
+
}
|
|
141
|
+
}),
|
|
142
|
+
Button('Down').nd.onClick(() => {
|
|
143
|
+
const i = index.$value;
|
|
144
|
+
if (i < playlist.val().length - 1) {
|
|
145
|
+
playlist.swap(i, i + 1);
|
|
146
|
+
}
|
|
147
|
+
}),
|
|
148
|
+
Button('Remove').nd.onClick(() => playlist.remove(index.$value))
|
|
149
|
+
])
|
|
150
|
+
)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Configs
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
ForEachArray(data, callback, {
|
|
157
|
+
shouldKeepItemsInCache: false, // same as ForEach
|
|
158
|
+
pushDelay: (items) => items.length > 100 ? 50 : 0 // throttle large batch inserts
|
|
159
|
+
})
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Choosing Between `ForEach` and `ForEachArray`
|
|
165
|
+
|
|
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 |
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Filtering with `.where()`
|
|
178
|
+
|
|
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.
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
import { equals, greaterThan, lessThan, between, includes, match,
|
|
183
|
+
startsWith, endsWith, inArray, notIn, custom,
|
|
184
|
+
and, or, not } from 'native-document/filters';
|
|
185
|
+
|
|
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' }
|
|
190
|
+
]);
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Comparison
|
|
194
|
+
|
|
195
|
+
```javascript
|
|
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') })
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### String
|
|
204
|
+
|
|
205
|
+
```javascript
|
|
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
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Array membership
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
const allowed = Observable.array(['electronics', 'books']);
|
|
217
|
+
|
|
218
|
+
products.where({ category: inArray(allowed) }) // reactive
|
|
219
|
+
products.where({ category: notIn(['clothing']) })
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Reactive filters
|
|
223
|
+
|
|
224
|
+
Pass an observable as the filter value - re-filters automatically when it changes:
|
|
225
|
+
|
|
226
|
+
```javascript
|
|
227
|
+
const search = Observable('');
|
|
228
|
+
const minPrice = Observable(0);
|
|
229
|
+
const maxPrice = Observable(1000);
|
|
230
|
+
|
|
231
|
+
const filtered = products.where({
|
|
232
|
+
name: includes(search),
|
|
233
|
+
price: between(minPrice, maxPrice)
|
|
234
|
+
});
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Custom filter
|
|
238
|
+
|
|
239
|
+
```javascript
|
|
240
|
+
const minRating = Observable(4);
|
|
241
|
+
|
|
242
|
+
products.where({
|
|
243
|
+
_: custom((product, min) => {
|
|
244
|
+
return product.rating >= min && product.reviews > 10;
|
|
245
|
+
}, minRating) // observables passed as extra args
|
|
246
|
+
})
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Combining
|
|
250
|
+
|
|
251
|
+
```javascript
|
|
252
|
+
// and - field must pass ALL conditions
|
|
253
|
+
products.where({ price: and(greaterThan(100), lessThan(500)) })
|
|
254
|
+
|
|
255
|
+
// or - field must pass AT LEAST ONE
|
|
256
|
+
products.where({ category: or(equals('electronics'), equals('books')) })
|
|
257
|
+
|
|
258
|
+
// not - invert
|
|
259
|
+
products.where({ inStock: not(equals(true)) })
|
|
260
|
+
|
|
261
|
+
// cross-field - use _ key with plain function
|
|
262
|
+
products.where({
|
|
263
|
+
_: item => item.inStock && item.price < 500
|
|
264
|
+
})
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Date and time filters
|
|
268
|
+
|
|
269
|
+
```javascript
|
|
270
|
+
import { dateEquals, dateBefore, dateAfter, dateBetween,
|
|
271
|
+
timeBefore, timeBetween } from 'native-document/filters';
|
|
272
|
+
|
|
273
|
+
const events = Observable.array([
|
|
274
|
+
{ name: 'Meeting', date: '2024-03-15' },
|
|
275
|
+
{ name: 'Conference', date: '2024-06-20' }
|
|
276
|
+
]);
|
|
277
|
+
|
|
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
|
+
)})
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Common Patterns
|
|
289
|
+
|
|
290
|
+
### Empty state
|
|
291
|
+
|
|
292
|
+
```javascript
|
|
293
|
+
const items = Observable.array([]);
|
|
294
|
+
|
|
295
|
+
Div([
|
|
296
|
+
ShowIf(items.isEmpty(), Div({ class: 'empty' }, 'No items yet')),
|
|
297
|
+
ForEachArray(items, item => ItemComponent(item))
|
|
298
|
+
])
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Search + filter
|
|
302
|
+
|
|
303
|
+
```javascript
|
|
304
|
+
const search = Observable('');
|
|
305
|
+
const category = Observable('all');
|
|
306
|
+
|
|
307
|
+
const filtered = products.where({
|
|
308
|
+
name: includes(search),
|
|
309
|
+
category: or(equals('all'), equals(category))
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
Div([
|
|
313
|
+
Input({ placeholder: 'Search...', value: search }),
|
|
314
|
+
ForEachArray(filtered, product => ProductCard(product))
|
|
315
|
+
])
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Drag-and-drop reordering
|
|
319
|
+
|
|
320
|
+
```javascript
|
|
321
|
+
let draggedIndex = null;
|
|
322
|
+
|
|
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 => {
|
|
329
|
+
e.preventDefault();
|
|
330
|
+
const dropIndex = index.$value;
|
|
331
|
+
if (draggedIndex !== null && draggedIndex !== dropIndex) {
|
|
332
|
+
items.swap(draggedIndex, dropIndex);
|
|
333
|
+
}
|
|
334
|
+
draggedIndex = null;
|
|
335
|
+
})
|
|
336
|
+
)
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Infinite scroll
|
|
340
|
+
|
|
341
|
+
```javascript
|
|
342
|
+
const items = Observable.array([]);
|
|
343
|
+
const isLoading = Observable(false);
|
|
344
|
+
const hasMore = Observable(true);
|
|
345
|
+
|
|
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
|
+
};
|
|
353
|
+
|
|
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
|
+
])
|
|
361
|
+
```
|
|
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
|
+
|
|
376
|
+
## Next Steps
|
|
377
|
+
|
|
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
|
|
384
|
+
|
|
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
|
|
@@ -1,90 +1,179 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Memory Management
|
|
3
|
+
description: NativeDocument's automatic memory management system using WeakRef and FinalizationRegistry - how it works and how to control it
|
|
4
|
+
---
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
# Memory Management
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
NativeDocument includes an automatic memory management system that prevents memory leaks using modern browser APIs - `WeakRef` and `FinalizationRegistry`. In most cases you don't need to think about this at all.
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
---
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
const data = Observable("test");
|
|
12
|
+
## How It Works
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
// NativeDocument automatically cleans up its internal listeners
|
|
14
|
-
// No manual cleanup required!
|
|
14
|
+
Every observable is registered in the `MemoryManager` using a `WeakRef`. When an observable goes out of scope and is garbage collected, the `FinalizationRegistry` notifies the system and the entry is cleaned up automatically.
|
|
15
15
|
|
|
16
|
+
```javascript
|
|
16
17
|
function createComponent() {
|
|
17
18
|
const localObservable = Observable(42);
|
|
18
|
-
return Div(localObservable);
|
|
19
|
+
return Div(localObservable);
|
|
20
|
+
// When the component is removed and localObservable goes out of scope,
|
|
21
|
+
// MemoryManager cleans up its entry automatically via FinalizationRegistry
|
|
19
22
|
}
|
|
20
23
|
```
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
Each observable gets an internal numeric ID on creation, accessible via `Observable.getById()`. Note that `.toString()` now returns the current value as a string, not the internal ID:
|
|
23
26
|
|
|
24
27
|
```javascript
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
console.log(count.toString()); // "{{#ObItem::(1)}}" - Shows internal ID
|
|
28
|
-
|
|
29
|
-
// When count becomes unreachable, cleanup happens automatically
|
|
30
|
-
// via FinalizationRegistry
|
|
28
|
+
const count = Observable(42);
|
|
29
|
+
console.log(count.toString()); // "42" - current value as string
|
|
31
30
|
```
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
---
|
|
34
33
|
|
|
35
|
-
|
|
34
|
+
## Manual Cleanup
|
|
35
|
+
|
|
36
|
+
### `observable.cleanup()`
|
|
37
|
+
|
|
38
|
+
Removes all listeners from an observable immediately and prevents new subscriptions:
|
|
36
39
|
|
|
37
40
|
```javascript
|
|
38
|
-
const obs = Observable(
|
|
41
|
+
const obs = Observable('data');
|
|
39
42
|
const unsubscribe = obs.subscribe(console.log);
|
|
40
43
|
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
obs.cleanup(); // removes all listeners
|
|
45
|
+
// obs is now unusable
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### `observable.onCleanup(callback)`
|
|
49
|
+
|
|
50
|
+
Register a callback that runs when the observable is cleaned up:
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
const obs = Observable('data');
|
|
54
|
+
|
|
55
|
+
obs.onCleanup(() => {
|
|
56
|
+
console.log('Observable cleaned up');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
obs.cleanup(); // triggers the callback
|
|
44
60
|
```
|
|
45
61
|
|
|
46
|
-
###
|
|
62
|
+
### `Observable.cleanup(observable)`
|
|
63
|
+
|
|
64
|
+
Static alias for `observable.cleanup()`:
|
|
47
65
|
|
|
48
66
|
```javascript
|
|
49
|
-
|
|
50
|
-
|
|
67
|
+
Observable.cleanup(myObservable);
|
|
68
|
+
```
|
|
51
69
|
|
|
52
|
-
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Auto-Cleanup
|
|
73
|
+
|
|
74
|
+
### `Observable.autoCleanup(enable, options?)`
|
|
75
|
+
|
|
76
|
+
Enables automatic periodic cleanup of orphaned observables (those that have been garbage collected but whose `WeakRef` entries remain in the registry):
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
53
79
|
Observable.autoCleanup(true, {
|
|
54
|
-
interval:
|
|
55
|
-
threshold: 100
|
|
80
|
+
interval: 60000, // run cleanup every 60 seconds (default)
|
|
81
|
+
threshold: 100 // only run when more than 100 entries exist (default)
|
|
56
82
|
});
|
|
57
83
|
```
|
|
58
84
|
|
|
59
|
-
|
|
85
|
+
Use this in long-running applications to prevent the registry from growing unbounded.
|
|
86
|
+
|
|
87
|
+
---
|
|
60
88
|
|
|
61
|
-
|
|
89
|
+
## MemoryManager API
|
|
90
|
+
|
|
91
|
+
`MemoryManager` is the internal registry that tracks all observables via `WeakRef`. It is not exported but its behavior is exposed through `Observable` static methods.
|
|
92
|
+
|
|
93
|
+
| Method | Description |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `MemoryManager.register(observable)` | Registers an observable, returns its internal ID |
|
|
96
|
+
| `MemoryManager.unregister(id)` | Removes an observable from the registry |
|
|
97
|
+
| `MemoryManager.getObservableById(id)` | Retrieves an observable by ID (via `Observable.getById()`) |
|
|
98
|
+
| `MemoryManager.cleanup()` | Calls `.cleanup()` on all registered observables and clears the registry |
|
|
99
|
+
| `MemoryManager.cleanObservables(threshold)` | Removes entries for GC'd observables when registry size exceeds threshold |
|
|
100
|
+
|
|
101
|
+
Access `getObservableById` via the public API:
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
// getById is useful for debugging - the ID is the internal MemoryManager key
|
|
105
|
+
// Access it via Observable.debug tools or the MemoryManager directly
|
|
106
|
+
Observable.getById(1); // returns the first observable registered
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Manual Subscriptions
|
|
112
|
+
|
|
113
|
+
The most common source of memory leaks is forgetting to clean up manual subscriptions. `.subscribe()` does not return an unsubscribe function - use `.cleanup()` to remove all listeners, or `.off()` to remove a specific watcher registered via `.on()`:
|
|
62
114
|
|
|
63
115
|
```javascript
|
|
64
|
-
|
|
65
|
-
|
|
116
|
+
const count = Observable(0);
|
|
117
|
+
|
|
118
|
+
// Remove all listeners at once
|
|
119
|
+
count.subscribe(value => console.log('Count:', value));
|
|
120
|
+
count.cleanup();
|
|
66
121
|
|
|
67
|
-
//
|
|
68
|
-
const
|
|
69
|
-
|
|
122
|
+
// Remove a specific .on() watcher
|
|
123
|
+
const handler = isActive => console.log('Loading:', isActive);
|
|
124
|
+
count.on('loading', handler);
|
|
125
|
+
count.off('loading', handler);
|
|
70
126
|
```
|
|
71
127
|
|
|
72
|
-
|
|
128
|
+
In element lifecycle hooks, only clean up **external resources**. Do not clean up observables unless the element is permanently destroyed:
|
|
73
129
|
|
|
74
130
|
```javascript
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
131
|
+
Div('Content')
|
|
132
|
+
.nd
|
|
133
|
+
.mounted(el => {
|
|
134
|
+
el.intervalId = setInterval(() => doWork(), 1000);
|
|
135
|
+
})
|
|
136
|
+
.unmounted(el => {
|
|
137
|
+
clearInterval(el.intervalId); // external resource - clean up
|
|
138
|
+
// do NOT call observable.cleanup() here unless permanently destroying
|
|
139
|
+
});
|
|
79
140
|
```
|
|
80
141
|
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Debug Mode
|
|
145
|
+
|
|
146
|
+
Enable debug mode during development to log memory-related events:
|
|
147
|
+
|
|
148
|
+
```javascript
|
|
149
|
+
Observable.debug.enable();
|
|
150
|
+
|
|
151
|
+
// MemoryManager will log when orphaned observables are cleaned:
|
|
152
|
+
// "🧹 Cleaned 3 orphaned observables"
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
81
157
|
## Best Practices
|
|
82
158
|
|
|
83
|
-
1.
|
|
84
|
-
2.
|
|
85
|
-
3.
|
|
86
|
-
4.
|
|
159
|
+
1. Trust the automatic system - `WeakRef` + `FinalizationRegistry` handles most cases
|
|
160
|
+
2. Always store and call the unsubscribe function for manual subscriptions
|
|
161
|
+
3. Use `Observable.autoCleanup(true)` in long-running SPAs
|
|
162
|
+
4. Only call `.cleanup()` manually when you need immediate release of resources
|
|
163
|
+
5. In `unmounted()` hooks, only clean up external resources (timers, websockets) - not observables
|
|
164
|
+
6. Use `Observable.resource()` for async data - it handles its own cleanup via `AbortController`
|
|
165
|
+
|
|
166
|
+
---
|
|
87
167
|
|
|
88
168
|
## Next Steps
|
|
89
169
|
|
|
90
|
-
- **[
|
|
170
|
+
- **[Observables](./observables.md)** - `cleanup()`, `onCleanup()`, `autoCleanup()`
|
|
171
|
+
- **[Lifecycle Events](./lifecycle-events.md)** - When to clean up in `unmounted()`
|
|
172
|
+
- **[Observable Resource](./observable-resource.md)** - Async data with built-in cleanup
|
|
173
|
+
- **[Anchor](./anchor.md)** - Anchor cleanup
|
|
174
|
+
|
|
175
|
+
## Utilities
|
|
176
|
+
|
|
177
|
+
- **[Cache](./cache.md)** - Lazy initialization and singleton patterns
|
|
178
|
+
- **[NativeFetch](./native-fetch.md)** - HTTP client with interceptors
|
|
179
|
+
- **[Filters](./filters.md)** - Data filtering helpers
|