native-document 1.0.165 → 1.0.168
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vitepress/config.js +166 -0
- package/CHANGELOG.md +153 -0
- package/components.d.ts +2 -0
- package/components.js +2 -1
- package/devtools/widget.js +1 -1
- package/dist/native-document.components.min.js +11589 -2983
- package/dist/native-document.dev.js +2280 -396
- package/dist/native-document.dev.js.map +1 -1
- package/dist/native-document.min.js +1 -1
- package/docs/advanced-components.md +213 -608
- package/docs/anchor.md +173 -312
- package/docs/cache.md +95 -803
- 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 +170 -588
- package/docs/contributing.md +300 -25
- package/docs/core-concepts.md +205 -374
- package/docs/elements.md +251 -367
- package/docs/extending-native-document-element.md +192 -207
- package/docs/filters.md +153 -1122
- package/docs/getting-started.md +193 -267
- package/docs/i18n.md +241 -0
- package/docs/index.md +76 -0
- package/docs/lifecycle-events.md +143 -75
- package/docs/list-rendering.md +227 -852
- package/docs/memory-management.md +134 -47
- package/docs/native-document-element.md +337 -186
- package/docs/native-fetch.md +99 -630
- package/docs/observable-resource.md +364 -0
- package/docs/observables.md +592 -526
- package/docs/routing.md +244 -653
- package/docs/state-management.md +134 -241
- package/docs/svg-elements.md +231 -0
- package/docs/theming.md +409 -0
- package/docs/validation.md +95 -97
- package/docs/vitepress-conventions.md +219 -0
- package/eslint.config.js +28 -33
- package/i18n.js +1 -1
- package/i18n.ts +2 -0
- package/index.js +3 -0
- package/package.json +36 -14
- package/readme.md +269 -89
- package/src/components/$traits/has-draggable/HasDraggable.d.ts +4 -0
- package/src/components/$traits/has-draggable/HasDraggable.js +13 -0
- package/src/components/$traits/has-items/HasItems.d.ts +9 -0
- package/src/components/$traits/has-items/HasItems.js +6 -6
- package/src/components/$traits/has-position/HasFullPosition.d.ts +14 -0
- package/src/components/$traits/has-position/HasFullPosition.js +44 -0
- package/src/components/$traits/has-position/HasPosition.d.ts +7 -0
- package/src/components/$traits/has-position/HasPosition.js +23 -1
- package/src/components/$traits/has-resizable/HasResizable.d.ts +13 -0
- package/src/components/$traits/has-resizable/HasResizable.js +9 -0
- package/src/components/$traits/has-validation/HasValidation.d.ts +17 -0
- package/src/components/$traits/has-validation/HasValidation.js +54 -7
- package/src/components/BaseComponent.d.ts +32 -0
- package/src/components/BaseComponent.js +65 -9
- package/src/components/accordion/Accordion.js +39 -14
- package/src/components/accordion/AccordionItem.js +45 -14
- package/src/components/accordion/index.js +2 -2
- 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 +70 -38
- package/src/components/alert/index.js +2 -2
- package/src/components/alert/types/Alert.d.ts +62 -0
- package/src/components/avatar/Avatar.js +49 -12
- package/src/components/avatar/AvatarGroup.js +50 -2
- package/src/components/avatar/index.js +2 -2
- 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 +125 -5
- package/src/components/badge/index.js +2 -2
- package/src/components/badge/types/Badge.d.ts +51 -0
- package/src/components/breadcrumb/BreadCrumb.js +61 -5
- package/src/components/breadcrumb/index.js +2 -2
- package/src/components/breadcrumb/types/BreadCrumb.d.ts +42 -0
- package/src/components/button/Button.js +164 -9
- package/src/components/button/index.js +1 -1
- package/src/components/button/types/Button.d.ts +62 -0
- package/src/components/card/Card.js +204 -32
- package/src/components/card/index.js +4 -4
- package/src/components/card/types/Card.d.ts +42 -0
- package/src/components/context-menu/ContextMenu.js +49 -5
- package/src/components/context-menu/ContextMenuGroup.js +15 -2
- package/src/components/context-menu/ContextMenuItem.js +14 -2
- package/src/components/context-menu/index.js +5 -5
- 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 +120 -4
- package/src/components/divider/index.js +3 -3
- package/src/components/divider/types/Divider.d.ts +55 -0
- package/src/components/dropdown/Dropdown.js +239 -16
- package/src/components/dropdown/DropdownDivider.js +22 -2
- package/src/components/dropdown/DropdownGroup.js +44 -5
- package/src/components/dropdown/DropdownItem.js +76 -3
- package/src/components/dropdown/DropdownTrigger.js +49 -20
- package/src/components/dropdown/helpers.js +1 -1
- package/src/components/dropdown/index.js +6 -6
- 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 +156 -13
- package/src/components/form/field/Field.js +172 -9
- package/src/components/form/field/FieldCollection.js +116 -12
- package/src/components/form/field/types/AutocompleteField.js +92 -2
- package/src/components/form/field/types/CheckboxField.js +43 -2
- package/src/components/form/field/types/CheckboxGroupField.js +83 -6
- package/src/components/form/field/types/ColorField.js +56 -3
- package/src/components/form/field/types/DateField.js +155 -4
- package/src/components/form/field/types/EmailField.js +54 -4
- package/src/components/form/field/types/FileField.js +140 -6
- package/src/components/form/field/types/HiddenField.js +27 -1
- package/src/components/form/field/types/ImageField.js +82 -3
- package/src/components/form/field/types/NumberField.js +97 -4
- package/src/components/form/field/types/PasswordField.js +103 -7
- package/src/components/form/field/types/RadioField.js +75 -4
- package/src/components/form/field/types/RangeField.js +67 -1
- package/src/components/form/field/types/SearchField.js +41 -2
- package/src/components/form/field/types/SelectField.js +133 -4
- package/src/components/form/field/types/StringField.js +91 -2
- package/src/components/form/field/types/TelField.js +55 -4
- package/src/components/form/field/types/TextAreaField.js +76 -2
- package/src/components/form/field/types/TimeField.js +120 -5
- package/src/components/form/field/types/UrlField.js +59 -4
- package/src/components/form/field/types/file-field-mode/FileAvatarMode.js +83 -4
- package/src/components/form/field/types/file-field-mode/FileDropzoneMode.js +61 -3
- package/src/components/form/field/types/file-field-mode/FileItemPreview.js +79 -3
- package/src/components/form/field/types/file-field-mode/FileNativeMode.js +24 -2
- package/src/components/form/field/types/file-field-mode/FileUploadButtonMode.js +64 -3
- package/src/components/form/field/types/file-field-mode/FileWallMode.js +56 -3
- package/src/components/form/index.js +28 -28
- 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/validation/Validation.js +54 -54
- package/src/components/index.d.ts +160 -0
- package/src/components/list/HasListItem.js +171 -0
- package/src/components/list/List.js +85 -67
- package/src/components/list/ListDivider.js +39 -0
- package/src/components/list/ListGroup.js +105 -38
- package/src/components/list/ListItem.js +158 -49
- package/src/components/list/index.js +8 -6
- 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 +55 -6
- package/src/components/menu/Menu.js +113 -22
- package/src/components/menu/MenuDivider.js +18 -2
- package/src/components/menu/MenuGroup.js +61 -6
- package/src/components/menu/MenuItem.js +95 -11
- package/src/components/menu/MenuLink.js +27 -2
- package/src/components/menu/index.js +6 -6
- 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 +258 -17
- package/src/components/modal/index.js +3 -3
- package/src/components/modal/types/Modal.d.ts +94 -0
- package/src/components/pagination/Pagination.js +155 -7
- package/src/components/pagination/index.js +3 -3
- package/src/components/pagination/types/Pagination.d.ts +68 -0
- package/src/components/popover/Popover.js +198 -11
- package/src/components/popover/PopoverFooter.js +33 -9
- package/src/components/popover/PopoverHeader.js +33 -8
- package/src/components/popover/index.js +4 -4
- 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 +182 -13
- package/src/components/progress/index.js +3 -3
- package/src/components/progress/types/Progress.d.ts +77 -0
- package/src/components/skeleton/Skeleton.js +117 -49
- package/src/components/skeleton/index.js +3 -3
- package/src/components/skeleton/types/Skeleton.d.ts +55 -0
- package/src/components/slider/Slider.js +207 -10
- package/src/components/slider/index.js +2 -2
- package/src/components/slider/types/Slider.d.ts +82 -0
- package/src/components/spacer/Spacer.js +12 -3
- package/src/components/spacer/index.js +2 -2
- package/src/components/spacer/types/Spacer.d.ts +19 -0
- package/src/components/spinner/Spinner.js +180 -9
- package/src/components/spinner/index.js +3 -3
- package/src/components/spinner/types/Spinner.d.ts +71 -0
- package/src/components/splitter/Splitter.js +76 -13
- package/src/components/splitter/SplitterGutter.js +67 -5
- package/src/components/splitter/SplitterPanel.js +69 -2
- package/src/components/splitter/index.js +5 -5
- 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 +23 -3
- package/src/components/stacks/FixedStack.js +23 -3
- package/src/components/stacks/HStack.js +24 -3
- package/src/components/stacks/PositionStack.js +111 -3
- package/src/components/stacks/RelativeStack.js +23 -3
- package/src/components/stacks/Stack.js +73 -2
- package/src/components/stacks/VStack.js +24 -4
- package/src/components/stacks/index.js +7 -7
- 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 +152 -12
- package/src/components/stepper/StepperStep.js +104 -3
- package/src/components/stepper/index.js +4 -4
- 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 +143 -6
- package/src/components/switch/index.js +1 -1
- package/src/components/switch/types/Switch.d.ts +55 -0
- package/src/components/table/Column.js +105 -6
- package/src/components/table/ColumnGroup.js +48 -3
- package/src/components/table/DataTable.js +256 -19
- package/src/components/table/SimpleTable.js +58 -4
- package/src/components/table/index.js +2 -2
- 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 +192 -5
- package/src/components/tabs/index.js +3 -3
- package/src/components/tabs/types/Tabs.d.ts +78 -0
- package/src/components/toast/Toast.js +133 -5
- package/src/components/toast/index.js +3 -3
- 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 +157 -13
- package/src/components/tooltip/index.js +2 -2
- package/src/components/tooltip/prototypes.js +1 -1
- package/src/components/tooltip/types/Tooltip.d.ts +65 -0
- package/src/core/data/MemoryManager.js +2 -2
- package/src/core/data/Observable.js +15 -18
- package/src/core/data/ObservableArray.js +118 -46
- package/src/core/data/ObservableChecker.js +2 -2
- package/src/core/data/ObservableItem.js +135 -21
- package/src/core/data/ObservableObject.js +126 -35
- package/src/core/data/ObservableResource.js +118 -3
- package/src/core/data/Store.js +142 -26
- package/src/core/data/observable-helpers/observable.is-to.js +196 -1
- package/src/core/data/observable-helpers/observable.prototypes.js +35 -8
- package/src/core/elements/anchor/anchor-with-sentinel.js +23 -2
- package/src/core/elements/anchor/anchor.js +16 -7
- package/src/core/elements/anchor/one-child-anchor-overwriting.js +2 -2
- package/src/core/elements/content-formatter.js +1 -1
- package/src/core/elements/control/for-each-array.js +9 -9
- package/src/core/elements/control/for-each.js +14 -14
- package/src/core/elements/control/show-if.js +11 -11
- package/src/core/elements/control/show-when.js +5 -5
- package/src/core/elements/control/switch.js +14 -14
- package/src/core/elements/description-list.js +1 -1
- package/src/core/elements/form.js +2 -2
- package/src/core/elements/fragment.js +1 -1
- package/src/core/elements/html5-semantics.js +1 -1
- package/src/core/elements/img.js +3 -3
- package/src/core/elements/interactive.js +1 -1
- package/src/core/elements/list.js +1 -1
- package/src/core/elements/medias.js +1 -1
- package/src/core/elements/meta-data.js +1 -1
- package/src/core/elements/svg.js +1 -1
- package/src/core/elements/table.js +1 -1
- package/src/core/errors/ArgTypesError.js +1 -1
- package/src/core/utils/HasEventEmitter.js +36 -2
- package/src/core/utils/args-types.js +9 -9
- package/src/core/utils/cache.js +1 -1
- package/src/core/utils/callback-handler.js +29 -0
- package/src/core/utils/debug-manager.js +6 -6
- package/src/core/utils/events.js +139 -139
- package/src/core/utils/filters/date.js +84 -3
- package/src/core/utils/filters/standard.js +136 -11
- package/src/core/utils/filters/strings.js +34 -2
- package/src/core/utils/filters/utils.js +40 -4
- package/src/core/utils/formatters.js +4 -4
- package/src/core/utils/helpers.js +39 -7
- package/src/core/utils/localstorage.js +11 -11
- package/src/core/utils/memoize.js +56 -3
- package/src/core/utils/plugins-manager.js +3 -3
- package/src/core/utils/property-accumulator.js +6 -6
- package/src/core/utils/prototypes.js +26 -1
- package/src/core/utils/shortcut-manager.js +2 -2
- package/src/core/utils/validator.js +8 -8
- package/src/core/wrappers/AttributesWrapper.js +32 -22
- package/src/core/wrappers/DocumentObserver.js +3 -3
- package/src/core/wrappers/ElementCreator.js +5 -5
- package/src/core/wrappers/HtmlElementWrapper.js +38 -12
- package/src/core/wrappers/NDElement.js +328 -22
- package/src/core/wrappers/NdPrototype.js +60 -16
- package/src/core/wrappers/SingletonView.js +50 -2
- package/src/core/wrappers/SvgElementWrapper.js +1 -1
- package/src/core/wrappers/constants.js +35 -2
- package/src/core/wrappers/prototypes/attributes-extensions.js +7 -7
- package/src/core/wrappers/prototypes/nd-element-extensions.js +72 -6
- package/src/core/wrappers/prototypes/nd-element.transition.extensions.js +42 -2
- package/src/core/wrappers/template-cloner/NodeCloner.js +53 -8
- package/src/core/wrappers/template-cloner/TemplateCloner.js +75 -6
- package/src/core/wrappers/template-cloner/attributes-hydrator.js +58 -2
- package/src/core/wrappers/template-cloner/utils.js +42 -6
- package/src/fetch/NativeFetch.js +3 -3
- package/src/i18n/bin/scan.js +6 -6
- package/src/i18n/index.d.ts +2 -0
- package/src/i18n/service/I18nService.d.ts +27 -0
- package/src/i18n/service/I18nService.js +5 -5
- package/src/i18n/service/functions.d.ts +22 -0
- package/src/i18n/service/functions.js +2 -2
- package/src/router/Route.js +3 -3
- package/src/router/RouteGroupHelper.js +2 -2
- package/src/router/Router.js +15 -15
- package/src/router/RouterComponent.js +33 -7
- package/src/router/link.js +4 -4
- package/src/router/modes/HashRouter.js +2 -2
- package/src/router/modes/HistoryRouter.js +2 -2
- package/src/router/modes/MemoryRouter.js +1 -1
- package/src/ui/components/accordion/AccordionItemRender.js +3 -3
- package/src/ui/components/accordion/AccordionRender.js +1 -1
- package/src/ui/components/alert/AlertRender.js +10 -10
- package/src/ui/components/avatar/avata-group/AvatarGroupRender.js +1 -1
- package/src/ui/components/avatar/avatar/AvatarRender.js +1 -1
- package/src/ui/components/breadcrumb/BreadcrumbRender.js +2 -2
- package/src/ui/components/button/ButtonRender.js +1 -1
- 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 +6 -6
- package/src/ui/components/dropdown/DropdownRender.js +8 -8
- package/src/ui/components/dropdown/group/DropdownGroupRender.js +2 -2
- package/src/ui/components/dropdown/item/DropdownItemRender.js +1 -1
- package/src/ui/components/form/FieldCollectionRender.js +2 -2
- package/src/ui/components/form/FormControlRender.js +5 -5
- package/src/ui/components/form/fields/AutocompleteFieldRender.js +3 -3
- package/src/ui/components/form/fields/CheckboxFieldRender.js +1 -1
- package/src/ui/components/form/fields/CheckboxGroupFieldRender.js +1 -1
- package/src/ui/components/form/fields/DateFieldRender.js +7 -7
- package/src/ui/components/form/fields/EmailFieldRender.js +1 -1
- package/src/ui/components/form/fields/FieldRender.js +4 -4
- package/src/ui/components/form/fields/FileFieldRender.js +1 -1
- package/src/ui/components/form/fields/PasswordFieldRender.js +2 -2
- package/src/ui/components/form/fields/RadioFieldRender.js +1 -1
- package/src/ui/components/form/fields/RangeFieldRender.js +1 -1
- package/src/ui/components/form/fields/SelectFieldRender.js +2 -2
- package/src/ui/components/form/fields/SliderFieldRender.js +6 -6
- package/src/ui/components/form/fields/StringFieldRender.js +1 -1
- package/src/ui/components/form/fields/TelFieldRender.js +1 -1
- package/src/ui/components/form/fields/TextAreaFieldRender.js +1 -1
- package/src/ui/components/form/fields/TimeFieldRender.js +3 -3
- package/src/ui/components/form/fields/UrlFieldRender.js +1 -1
- package/src/ui/components/form/file-upload-mode/FileAvatarModeRender.js +1 -1
- package/src/ui/components/form/file-upload-mode/FileDropzoneModeRender.js +2 -2
- package/src/ui/components/form/file-upload-mode/FileUploadButtonModeRender.js +2 -2
- package/src/ui/components/form/file-upload-mode/FileWallModeRender.js +1 -1
- package/src/ui/components/form/helpers.js +8 -8
- package/src/ui/components/form/index.js +27 -27
- 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 +1 -1
- package/src/ui/components/menu/MenuGroupRender.js +3 -3
- package/src/ui/components/menu/MenuItemRender.js +2 -2
- package/src/ui/components/menu/MenuLinkRender.js +3 -3
- package/src/ui/components/menu/helpers.js +4 -4
- package/src/ui/components/modal/ModalRender.js +4 -4
- package/src/ui/components/pagination/PaginationRender.js +9 -9
- package/src/ui/components/popover/PopoverRender.js +7 -7
- package/src/ui/components/progress/ProgressRender.js +12 -12
- package/src/ui/components/skeleton/SkeletonRender.js +56 -0
- package/src/ui/components/spacer/SpacerRender.js +10 -0
- package/src/ui/components/splitter/SplitterGutterRender.js +1 -1
- package/src/ui/components/splitter/SplitterPanelRender.js +2 -2
- package/src/ui/components/stacks/PositionStackRender.js +1 -1
- package/src/ui/components/stacks/StackRender.js +1 -1
- package/src/ui/components/stacks/absolute-stack/AbsoluteStackRender.js +1 -1
- package/src/ui/components/stacks/fixed-stack/FixedStackRender.js +1 -1
- package/src/ui/components/stacks/h-stack/HStackRender.js +1 -1
- package/src/ui/components/stacks/index.js +5 -5
- package/src/ui/components/stacks/relative-stack/RelativeStackRender.js +1 -1
- package/src/ui/components/stacks/v-stack/VStackRender.js +1 -1
- package/src/ui/components/stepper/StepperRender.js +2 -2
- package/src/ui/components/stepper/StepperStepRender.js +4 -4
- package/src/ui/components/switch/SwitchRender.js +4 -4
- package/src/ui/components/table/data-table/DataTableRender.js +5 -5
- package/src/ui/components/table/data-table/bulk-actions.js +7 -7
- package/src/ui/components/table/data-table/pagination.js +6 -6
- package/src/ui/components/table/data-table/tables.js +25 -25
- package/src/ui/components/table/data-table/toolbar.js +3 -3
- package/src/ui/components/table/simple-table/SimpleTableRender.js +8 -8
- package/src/ui/components/tabs/TabsRender.js +11 -11
- package/src/ui/components/toast/ToastRender.js +3 -3
- package/src/ui/components/tooltip/TooltipRender.js +1 -1
- package/src/ui/index.js +44 -36
- package/types/elements.d.ts +163 -1037
- package/types/forms.d.ts +16 -20
- package/types/globals.d.ts +543 -0
- package/types/images.d.ts +2 -2
- package/types/observable-resource.d.ts +3 -0
- package/types/property-accumulator.d.ts +4 -4
- package/types/store.d.ts +26 -2
- package/types/validator.ts +3 -3
- package/ui.js +1 -0
- package/src/components/form/field/DefaultRender.js +0 -77
- package/src/components/form/field/FieldFactory.js +0 -107
- package/src/components/skeleton/SkeletonList.js +0 -0
- package/src/components/skeleton/SkeletonParagraph.js +0 -0
- package/src/components/skeleton/SkeletonTable.js +0 -0
- /package/{src/components/skeleton/SkeletonCard.js → docs/tutorials/.gitkeep} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import ObservableItem from
|
|
2
|
-
import {debounce} from
|
|
1
|
+
import ObservableItem from './ObservableItem';
|
|
2
|
+
import {debounce} from '../utils/helpers';
|
|
3
3
|
|
|
4
4
|
const STATE = {
|
|
5
5
|
UNRESOLVED: 'unresolved',
|
|
@@ -9,6 +9,28 @@ const STATE = {
|
|
|
9
9
|
ERRORED: 'errored',
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Reactive async data fetcher with built-in state management.
|
|
14
|
+
* Tracks loading, ready, refreshing, and error states automatically.
|
|
15
|
+
* Use Observable.resource() rather than instantiating directly.
|
|
16
|
+
*
|
|
17
|
+
* @constructor
|
|
18
|
+
* @param {(...depValues: any[], signal?: AbortSignal) => Promise<*>} fn - Async function to fetch data. Receives dependency values as arguments. If its arity exceeds the number of dependencies, an AbortSignal is passed as the last argument.
|
|
19
|
+
* @param {ObservableItem[]} deps - Observable dependencies — resource re-fetches when any changes
|
|
20
|
+
* @param {{ auto?: boolean, lazy?: boolean, debounce?: number, into?: ObservableItem, apply?: Function }} config - Configuration
|
|
21
|
+
* @param {boolean} [config.auto=false] - If true, fetch runs automatically on creation (or when deps change)
|
|
22
|
+
* @param {boolean} [config.lazy=false] - If true with deps, does not fetch immediately — waits for first dep change
|
|
23
|
+
* @param {number} [config.debounce=0] - Debounce delay in ms for dependency-triggered re-fetches
|
|
24
|
+
* @param {ObservableItem} [config.into] - Observable to write results into instead of creating a new one
|
|
25
|
+
* @param {Function} [config.apply] - Custom function to apply the result to this.data
|
|
26
|
+
* @example
|
|
27
|
+
* const userId = Observable(1);
|
|
28
|
+
* const user = Observable.resource(
|
|
29
|
+
* async (id, signal) => fetch(`/api/users/${id}`, { signal }).then(r => r.json()),
|
|
30
|
+
* [userId],
|
|
31
|
+
* { auto: true }
|
|
32
|
+
* );
|
|
33
|
+
*/
|
|
12
34
|
export default function ObservableResource(fn, deps, config) {
|
|
13
35
|
this.$fn = (config.debounce > 0) ? debounce(fn, config.debounce) : fn;
|
|
14
36
|
this.$dependencies = deps;
|
|
@@ -22,7 +44,7 @@ export default function ObservableResource(fn, deps, config) {
|
|
|
22
44
|
|
|
23
45
|
this.loading = ObservableItem.computed(
|
|
24
46
|
(state) => state === STATE.PENDING || state === STATE.REFRESHING,
|
|
25
|
-
[this.state]
|
|
47
|
+
[this.state],
|
|
26
48
|
);
|
|
27
49
|
|
|
28
50
|
if (config.auto) {
|
|
@@ -104,6 +126,11 @@ ObservableResource.prototype.$runWithoutAbortController = function(isRefetch = f
|
|
|
104
126
|
});
|
|
105
127
|
};
|
|
106
128
|
|
|
129
|
+
ObservableResource.prototype.into = function($observable) {
|
|
130
|
+
this.data = $observable;
|
|
131
|
+
return this;
|
|
132
|
+
};
|
|
133
|
+
|
|
107
134
|
ObservableResource.prototype.$run = function(isRefetch = false) {
|
|
108
135
|
const needsSignal = this.$fn.length > this.$dependencies.length;
|
|
109
136
|
if(needsSignal) {
|
|
@@ -129,58 +156,138 @@ ObservableResource.prototype.$watchDependencies = function() {
|
|
|
129
156
|
}
|
|
130
157
|
};
|
|
131
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Sets a custom function to apply fetched results to this.data.
|
|
161
|
+
* Useful when the raw response needs transformation before storing.
|
|
162
|
+
*
|
|
163
|
+
* @param {(result: *, data: ObservableItem) => void} fn - Function receiving the result and the data observable
|
|
164
|
+
* @returns {this}
|
|
165
|
+
* @example
|
|
166
|
+
* resource.apply((result, data) => data.set(result.items));
|
|
167
|
+
*/
|
|
132
168
|
ObservableResource.prototype.apply = function(fn) {
|
|
133
169
|
this.$config.apply = fn;
|
|
134
170
|
return this;
|
|
135
171
|
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Redirects fetched results into an existing ObservableItem instead of the default internal one.
|
|
175
|
+
* Updates both this.data reference and config.into.
|
|
176
|
+
*
|
|
177
|
+
* @param {ObservableItem} $observable - Target observable to write results into
|
|
178
|
+
* @returns {this}
|
|
179
|
+
* @example
|
|
180
|
+
* const items = Observable([]);
|
|
181
|
+
* resource.into(items);
|
|
182
|
+
*/
|
|
136
183
|
ObservableResource.prototype.into = function($observable) {
|
|
137
184
|
this.$config.into = $observable;
|
|
138
185
|
this.data = $observable;
|
|
139
186
|
return this;
|
|
140
187
|
};
|
|
141
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Triggers a fresh fetch (state transitions to 'pending').
|
|
191
|
+
* Use when no prior data exists or when a full reload is needed.
|
|
192
|
+
*
|
|
193
|
+
* @returns {this}
|
|
194
|
+
*/
|
|
142
195
|
ObservableResource.prototype.fetch = function() {
|
|
143
196
|
this.$run(false);
|
|
144
197
|
return this;
|
|
145
198
|
};
|
|
146
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Triggers a re-fetch (state transitions to 'refreshing' if data already exists).
|
|
202
|
+
* Use when you want to reload while keeping the previous data visible.
|
|
203
|
+
*
|
|
204
|
+
* @returns {this}
|
|
205
|
+
*/
|
|
147
206
|
ObservableResource.prototype.refetch = function() {
|
|
148
207
|
this.$run(true);
|
|
149
208
|
return this;
|
|
150
209
|
};
|
|
151
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Manually sets the data value and marks the state as 'ready'.
|
|
213
|
+
* Useful for optimistic updates or seeding initial data without a network call.
|
|
214
|
+
*
|
|
215
|
+
* @param {*} value - New value to set on this.data
|
|
216
|
+
* @returns {this}
|
|
217
|
+
* @example
|
|
218
|
+
* resource.mutate([...resource.data.val(), newItem]);
|
|
219
|
+
*/
|
|
152
220
|
ObservableResource.prototype.mutate = function(value) {
|
|
153
221
|
this.data.set(value);
|
|
154
222
|
this.state.set(STATE.READY);
|
|
155
223
|
return this;
|
|
156
224
|
};
|
|
157
225
|
|
|
226
|
+
/**
|
|
227
|
+
* Cancels any pending request, unsubscribes from all dependencies, and clears subscriptions.
|
|
228
|
+
* Call this when the component using this resource is unmounted.
|
|
229
|
+
*
|
|
230
|
+
* @returns {void}
|
|
231
|
+
*/
|
|
158
232
|
ObservableResource.prototype.destroy = function() {
|
|
159
233
|
this.$abort();
|
|
160
234
|
this.$subscriptions.forEach(unsub => unsub());
|
|
161
235
|
this.$subscriptions = [];
|
|
162
236
|
};
|
|
163
237
|
|
|
238
|
+
/**
|
|
239
|
+
* Returns a derived observable that emits true when the state is 'ready'.
|
|
240
|
+
*
|
|
241
|
+
* @returns {ObservableChecker<boolean>}
|
|
242
|
+
*/
|
|
164
243
|
ObservableResource.prototype.isReady = function() {
|
|
165
244
|
return this.state.isEqualTo(STATE.READY);
|
|
166
245
|
};
|
|
167
246
|
|
|
247
|
+
/**
|
|
248
|
+
* Returns a derived observable that emits true when the state is 'pending' (initial load).
|
|
249
|
+
*
|
|
250
|
+
* @returns {ObservableChecker<boolean>}
|
|
251
|
+
*/
|
|
168
252
|
ObservableResource.prototype.isPending = function() {
|
|
169
253
|
return this.state.isEqualTo(STATE.PENDING);
|
|
170
254
|
};
|
|
171
255
|
|
|
256
|
+
/**
|
|
257
|
+
* Returns a derived observable that emits true when the state is 'refreshing' (reload with existing data).
|
|
258
|
+
*
|
|
259
|
+
* @returns {ObservableChecker<boolean>}
|
|
260
|
+
*/
|
|
172
261
|
ObservableResource.prototype.isRefreshing = function() {
|
|
173
262
|
return this.state.isEqualTo(STATE.REFRESHING);
|
|
174
263
|
};
|
|
175
264
|
|
|
265
|
+
/**
|
|
266
|
+
* Returns a derived observable that emits true when the state is 'errored'.
|
|
267
|
+
*
|
|
268
|
+
* @returns {ObservableChecker<boolean>}
|
|
269
|
+
*/
|
|
176
270
|
ObservableResource.prototype.isErrored = function() {
|
|
177
271
|
return this.state.isEqualTo(STATE.ERRORED);
|
|
178
272
|
};
|
|
179
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Returns a derived observable that emits true when no fetch has been triggered yet.
|
|
276
|
+
*
|
|
277
|
+
* @returns {ObservableChecker<boolean>}
|
|
278
|
+
*/
|
|
180
279
|
ObservableResource.prototype.isUnresolved = function() {
|
|
181
280
|
return this.state.isEqualTo(STATE.UNRESOLVED);
|
|
182
281
|
};
|
|
183
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Registers a callback that is called every time a fetch completes successfully.
|
|
285
|
+
*
|
|
286
|
+
* @param {(value: *) => void} callback - Called with the fetched data value
|
|
287
|
+
* @returns {this}
|
|
288
|
+
* @example
|
|
289
|
+
* resource.onSuccess((data) => console.log('Loaded:', data));
|
|
290
|
+
*/
|
|
184
291
|
ObservableResource.prototype.onSuccess = function(callback) {
|
|
185
292
|
this.data.subscribe((value) => {
|
|
186
293
|
if (this.state.val() === STATE.READY) {
|
|
@@ -190,6 +297,14 @@ ObservableResource.prototype.onSuccess = function(callback) {
|
|
|
190
297
|
return this;
|
|
191
298
|
};
|
|
192
299
|
|
|
300
|
+
/**
|
|
301
|
+
* Registers a callback called every time a fetch fails.
|
|
302
|
+
*
|
|
303
|
+
* @param {(error: Error) => void} callback - Called with the error object
|
|
304
|
+
* @returns {this}
|
|
305
|
+
* @example
|
|
306
|
+
* resource.onError((err) => console.error('Failed:', err.message));
|
|
307
|
+
*/
|
|
193
308
|
ObservableResource.prototype.onError = function(callback) {
|
|
194
309
|
this.error.subscribe((err) => {
|
|
195
310
|
if (err !== null) {
|
package/src/core/data/Store.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import { Observable } from
|
|
2
|
-
import NativeDocumentError from
|
|
3
|
-
import DebugManager from
|
|
4
|
-
import {$getFromStorage, $saveToStorage, LocalStorage} from
|
|
1
|
+
import { Observable } from './Observable';
|
|
2
|
+
import NativeDocumentError from '../errors/NativeDocumentError';
|
|
3
|
+
import DebugManager from '../utils/debug-manager';
|
|
4
|
+
import {$getFromStorage, $saveToStorage, LocalStorage} from '../utils/localstorage';
|
|
5
|
+
import Validator from '../utils/validator';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const WRITE_METHODS = [
|
|
9
|
+
'use', 'get', 'create', 'createResettable', 'createComposed',
|
|
10
|
+
'createPersistent', 'createPersistentResettable', 'delete', 'reset',
|
|
11
|
+
];
|
|
5
12
|
|
|
6
13
|
export const StoreFactory = function() {
|
|
7
14
|
|
|
@@ -16,7 +23,7 @@ export const StoreFactory = function() {
|
|
|
16
23
|
if (!item) {
|
|
17
24
|
DebugManager.error('Store', `Store.${method}('${name}') : store not found. Did you call Store.create('${name}') first?`);
|
|
18
25
|
throw new NativeDocumentError(
|
|
19
|
-
`Store.${method}('${name}') : store not found
|
|
26
|
+
`Store.${method}('${name}') : store not found.`,
|
|
20
27
|
);
|
|
21
28
|
}
|
|
22
29
|
return item;
|
|
@@ -29,7 +36,7 @@ export const StoreFactory = function() {
|
|
|
29
36
|
const readOnlyError = (method) => () => {
|
|
30
37
|
DebugManager.error('Store', `Store.${context}('${name}') is read-only. '${method}()' is not allowed.`);
|
|
31
38
|
throw new NativeDocumentError(
|
|
32
|
-
`Store.${context}('${name}') is read-only
|
|
39
|
+
`Store.${context}('${name}') is read-only.`,
|
|
33
40
|
);
|
|
34
41
|
};
|
|
35
42
|
observer.set = readOnlyError('set');
|
|
@@ -41,11 +48,11 @@ export const StoreFactory = function() {
|
|
|
41
48
|
if(Array.isArray(value)) {
|
|
42
49
|
return Observable.array(value, options);
|
|
43
50
|
}
|
|
44
|
-
if(
|
|
51
|
+
if(Validator.isJson(value)) {
|
|
45
52
|
return Observable.object(value, options);
|
|
46
53
|
}
|
|
47
54
|
return Observable(value, options);
|
|
48
|
-
}
|
|
55
|
+
};
|
|
49
56
|
|
|
50
57
|
const $api = {
|
|
51
58
|
/**
|
|
@@ -60,10 +67,10 @@ export const StoreFactory = function() {
|
|
|
60
67
|
if ($stores.has(name)) {
|
|
61
68
|
DebugManager.warn('Store', `Store.create('${name}') : a store with this name already exists. Use Store.get('${name}') to retrieve it.`);
|
|
62
69
|
throw new NativeDocumentError(
|
|
63
|
-
`Store.create('${name}') : a store with this name already exists
|
|
70
|
+
`Store.create('${name}') : a store with this name already exists.`,
|
|
64
71
|
);
|
|
65
72
|
}
|
|
66
|
-
const observer = $createObservable(value)
|
|
73
|
+
const observer = $createObservable(value);
|
|
67
74
|
$stores.set(name, { observer, subscribers: new Set(), resettable: false, composed: false });
|
|
68
75
|
return observer;
|
|
69
76
|
},
|
|
@@ -81,7 +88,7 @@ export const StoreFactory = function() {
|
|
|
81
88
|
if ($stores.has(name)) {
|
|
82
89
|
DebugManager.warn('Store', `Store.createResettable('${name}') : a store with this name already exists.`);
|
|
83
90
|
throw new NativeDocumentError(
|
|
84
|
-
`Store.createResettable('${name}') : a store with this name already exists
|
|
91
|
+
`Store.createResettable('${name}') : a store with this name already exists.`,
|
|
85
92
|
);
|
|
86
93
|
}
|
|
87
94
|
const observer = $createObservable(value, { reset: true });
|
|
@@ -117,17 +124,17 @@ export const StoreFactory = function() {
|
|
|
117
124
|
if ($stores.has(name)) {
|
|
118
125
|
DebugManager.warn('Store', `Store.createComposed('${name}') : a store with this name already exists.`);
|
|
119
126
|
throw new NativeDocumentError(
|
|
120
|
-
`Store.createComposed('${name}') : a store with this name already exists
|
|
127
|
+
`Store.createComposed('${name}') : a store with this name already exists.`,
|
|
121
128
|
);
|
|
122
129
|
}
|
|
123
130
|
if (typeof computation !== 'function') {
|
|
124
131
|
throw new NativeDocumentError(
|
|
125
|
-
`Store.createComposed('${name}') : computation must be a function
|
|
132
|
+
`Store.createComposed('${name}') : computation must be a function.`,
|
|
126
133
|
);
|
|
127
134
|
}
|
|
128
135
|
if (!Array.isArray(dependencies) || dependencies.length === 0) {
|
|
129
136
|
throw new NativeDocumentError(
|
|
130
|
-
`Store.createComposed('${name}') : dependencies must be a non-empty array of store names
|
|
137
|
+
`Store.createComposed('${name}') : dependencies must be a non-empty array of store names.`,
|
|
131
138
|
);
|
|
132
139
|
}
|
|
133
140
|
|
|
@@ -140,7 +147,7 @@ export const StoreFactory = function() {
|
|
|
140
147
|
if (!depItem) {
|
|
141
148
|
DebugManager.error('Store', `Store.createComposed('${name}') : dependency '${depName}' not found. Create it first.`);
|
|
142
149
|
throw new NativeDocumentError(
|
|
143
|
-
`Store.createComposed('${name}') : dependency store '${depName}' not found
|
|
150
|
+
`Store.createComposed('${name}') : dependency store '${depName}' not found.`,
|
|
144
151
|
);
|
|
145
152
|
}
|
|
146
153
|
return depItem.observer;
|
|
@@ -174,13 +181,13 @@ export const StoreFactory = function() {
|
|
|
174
181
|
if (item.composed) {
|
|
175
182
|
DebugManager.error('Store', `Store.reset('${name}') : composed stores cannot be reset. Their value is derived from dependencies.`);
|
|
176
183
|
throw new NativeDocumentError(
|
|
177
|
-
`Store.reset('${name}') : composed stores cannot be reset
|
|
184
|
+
`Store.reset('${name}') : composed stores cannot be reset.`,
|
|
178
185
|
);
|
|
179
186
|
}
|
|
180
187
|
if (!item.resettable) {
|
|
181
188
|
DebugManager.error('Store', `Store.reset('${name}') : this store is not resettable. Use Store.createResettable('${name}', value) instead of Store.create().`);
|
|
182
189
|
throw new NativeDocumentError(
|
|
183
|
-
`Store.reset('${name}') : this store is not resettable. Use Store.createResettable('${name}', value) instead of Store.create()
|
|
190
|
+
`Store.reset('${name}') : this store is not resettable. Use Store.createResettable('${name}', value) instead of Store.create().`,
|
|
184
191
|
);
|
|
185
192
|
}
|
|
186
193
|
item.observer.reset();
|
|
@@ -201,7 +208,7 @@ export const StoreFactory = function() {
|
|
|
201
208
|
if (item.composed) {
|
|
202
209
|
DebugManager.error('Store', `Store.use('${name}') : composed stores are read-only. Use Store.follow('${name}') instead.`);
|
|
203
210
|
throw new NativeDocumentError(
|
|
204
|
-
`Store.use('${name}') : composed stores are read-only. Use Store.follow('${name}') instead
|
|
211
|
+
`Store.use('${name}') : composed stores are read-only. Use Store.follow('${name}') instead.`,
|
|
205
212
|
);
|
|
206
213
|
}
|
|
207
214
|
|
|
@@ -239,7 +246,9 @@ export const StoreFactory = function() {
|
|
|
239
246
|
const { observer: originalObserver, subscribers } = $getStoreOrThrow('follow', name);
|
|
240
247
|
const observerFollower = $createObservable(originalObserver.val());
|
|
241
248
|
|
|
242
|
-
const
|
|
249
|
+
const originalSet = observerFollower.set.bind(observerFollower);
|
|
250
|
+
const onStoreChange = value => originalSet(value);
|
|
251
|
+
|
|
243
252
|
originalObserver.subscribe(onStoreChange);
|
|
244
253
|
|
|
245
254
|
$applyReadOnly(observerFollower, name, 'follow');
|
|
@@ -295,6 +304,7 @@ export const StoreFactory = function() {
|
|
|
295
304
|
item.subscribers.clear();
|
|
296
305
|
item.observer.cleanup();
|
|
297
306
|
$stores.delete(name);
|
|
307
|
+
$followersCache.delete(name);
|
|
298
308
|
},
|
|
299
309
|
/**
|
|
300
310
|
* Creates an isolated store group with its own state namespace.
|
|
@@ -349,18 +359,60 @@ export const StoreFactory = function() {
|
|
|
349
359
|
callback && callback(store);
|
|
350
360
|
return store;
|
|
351
361
|
},
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Creates a store that is automatically persisted to localStorage.
|
|
365
|
+
* On creation, the store is initialized with the value from localStorage
|
|
366
|
+
* if it exists, otherwise falls back to the provided default value.
|
|
367
|
+
* Every mutation is automatically saved to localStorage.
|
|
368
|
+
*
|
|
369
|
+
* @param {string} name - Store name
|
|
370
|
+
* @param {*} value - Default value if nothing is found in localStorage
|
|
371
|
+
* @param {string} [localstorage_key] - Custom localStorage key. Defaults to the store name.
|
|
372
|
+
* @returns {ObservableItem}
|
|
373
|
+
*
|
|
374
|
+
* @example
|
|
375
|
+
* const $theme = Store.createPersistent('theme', 'light');
|
|
376
|
+
*
|
|
377
|
+
* $theme.set('dark'); // saved to localStorage automatically
|
|
378
|
+
*
|
|
379
|
+
* // With a custom key
|
|
380
|
+
* const $lang = Store.createPersistent('language', 'en', 'nd:lang');
|
|
381
|
+
*/
|
|
352
382
|
createPersistent(name, value, localstorage_key) {
|
|
353
383
|
localstorage_key = localstorage_key || name;
|
|
354
384
|
const observer = this.create(name, $getFromStorage(localstorage_key, value));
|
|
355
|
-
const saver = $saveToStorage(value)
|
|
385
|
+
const saver = $saveToStorage(value);
|
|
356
386
|
|
|
357
387
|
observer.subscribe((val) => saver(localstorage_key, val));
|
|
358
388
|
return observer;
|
|
359
389
|
},
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Creates a resettable store that is automatically persisted to localStorage.
|
|
393
|
+
* On creation, the store is initialized with the value from localStorage
|
|
394
|
+
* if it exists, otherwise falls back to the provided default value.
|
|
395
|
+
* Every mutation is automatically saved to localStorage.
|
|
396
|
+
* Calling reset() restores the initial value AND removes the localStorage entry.
|
|
397
|
+
*
|
|
398
|
+
* @param {string} name - Store name
|
|
399
|
+
* @param {*} value - Default value if nothing is found in localStorage
|
|
400
|
+
* @param {string} [localstorage_key] - Custom localStorage key. Defaults to the store name.
|
|
401
|
+
* @returns {ObservableItem}
|
|
402
|
+
*
|
|
403
|
+
* @example
|
|
404
|
+
* const $filters = Store.createPersistentResettable('filters', { category: null, date: null });
|
|
405
|
+
*
|
|
406
|
+
* $filters.set({ category: 'news', date: '2024-01-01' }); // saved to localStorage
|
|
407
|
+
* $filters.reset(); // restored to { category: null, date: null } + localStorage entry removed
|
|
408
|
+
*
|
|
409
|
+
* // With a custom key
|
|
410
|
+
* const $prefs = Store.createPersistentResettable('preferences', { lang: 'en' }, 'nd:prefs');
|
|
411
|
+
*/
|
|
360
412
|
createPersistentResettable(name, value, localstorage_key) {
|
|
361
413
|
localstorage_key = localstorage_key || name;
|
|
362
414
|
const observer = this.createResettable(name, $getFromStorage(localstorage_key, value));
|
|
363
|
-
const saver = $saveToStorage(value)
|
|
415
|
+
const saver = $saveToStorage(value);
|
|
364
416
|
observer.subscribe((val) => saver(localstorage_key, val));
|
|
365
417
|
|
|
366
418
|
const originalReset = observer.reset.bind(observer);
|
|
@@ -370,7 +422,68 @@ export const StoreFactory = function() {
|
|
|
370
422
|
};
|
|
371
423
|
|
|
372
424
|
return observer;
|
|
373
|
-
}
|
|
425
|
+
},
|
|
426
|
+
/**
|
|
427
|
+
* Returns a read-only proxy of this store.
|
|
428
|
+
* All write operations (use, get, create, createResettable, createComposed,
|
|
429
|
+
* createPersistent, createPersistentResettable, delete, reset) will throw.
|
|
430
|
+
* Property access returns a read-only follower via follow().
|
|
431
|
+
*
|
|
432
|
+
* The recommended pattern is to keep the original store private
|
|
433
|
+
* and export only the protected version as the public contract.
|
|
434
|
+
*
|
|
435
|
+
* @returns {Proxy}
|
|
436
|
+
*
|
|
437
|
+
* @example
|
|
438
|
+
* // store/user.store.js
|
|
439
|
+
*
|
|
440
|
+
* const PrivateUserStore = Store.group('user', (group) => {
|
|
441
|
+
* group.create('profile', null);
|
|
442
|
+
* group.create('role', 'viewer');
|
|
443
|
+
* group.create('token', null);
|
|
444
|
+
* });
|
|
445
|
+
*
|
|
446
|
+
* // Only the read-only version is exported
|
|
447
|
+
* export const UserStore = PrivateUserStore.protected();
|
|
448
|
+
*
|
|
449
|
+
* // --- In any other module ---
|
|
450
|
+
*
|
|
451
|
+
* import { UserStore } from './store/user.store.js';
|
|
452
|
+
*
|
|
453
|
+
* UserStore.profile // ✅ follower read-only
|
|
454
|
+
* UserStore.follow('role') // ✅
|
|
455
|
+
* UserStore.has('token') // ✅
|
|
456
|
+
*
|
|
457
|
+
* UserStore.use('profile') // ❌ throws — read-only store
|
|
458
|
+
* UserStore.get('profile') // ❌ throws — read-only store
|
|
459
|
+
* UserStore.create('x', 1) // ❌ throws — read-only store
|
|
460
|
+
*/
|
|
461
|
+
protected() {
|
|
462
|
+
return new Proxy($api, {
|
|
463
|
+
get(target, prop) {
|
|
464
|
+
if (typeof prop === 'symbol' || prop.startsWith('$')) {
|
|
465
|
+
return target[prop];
|
|
466
|
+
}
|
|
467
|
+
if (WRITE_METHODS.includes(prop)) {
|
|
468
|
+
return () => {
|
|
469
|
+
throw new NativeDocumentError(
|
|
470
|
+
`Store.${prop}() is not allowed on a read-only store. Use the original store reference instead.`
|
|
471
|
+
);
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
if (target.has(prop)) {
|
|
475
|
+
return target.follow(prop);
|
|
476
|
+
}
|
|
477
|
+
return target[prop];
|
|
478
|
+
},
|
|
479
|
+
set() {
|
|
480
|
+
throw new NativeDocumentError('This store is read-only.');
|
|
481
|
+
},
|
|
482
|
+
deleteProperty() {
|
|
483
|
+
throw new NativeDocumentError('This store is read-only.');
|
|
484
|
+
},
|
|
485
|
+
});
|
|
486
|
+
},
|
|
374
487
|
};
|
|
375
488
|
|
|
376
489
|
|
|
@@ -391,14 +504,17 @@ export const StoreFactory = function() {
|
|
|
391
504
|
},
|
|
392
505
|
set(target, prop, value) {
|
|
393
506
|
DebugManager.error('Store', `Forbidden: You cannot overwrite the store key '${String(prop)}'. Use .use('${String(prop)}').set(value) instead.`);
|
|
394
|
-
throw new NativeDocumentError(
|
|
507
|
+
throw new NativeDocumentError('Store structure is immutable. Use .set() on the observable.');
|
|
395
508
|
},
|
|
396
509
|
deleteProperty(target, prop) {
|
|
397
|
-
throw new NativeDocumentError(
|
|
398
|
-
}
|
|
510
|
+
throw new NativeDocumentError('Store keys cannot be deleted.');
|
|
511
|
+
},
|
|
399
512
|
});
|
|
400
513
|
};
|
|
401
514
|
|
|
402
515
|
export const Store = StoreFactory();
|
|
403
516
|
|
|
404
|
-
Store.create(
|
|
517
|
+
Store.create(
|
|
518
|
+
'locale',
|
|
519
|
+
(typeof navigator !== 'undefined' ? navigator.language.split('-')[0] : 'en') || 'en'
|
|
520
|
+
);
|