native-document 1.0.164 → 1.0.166
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/components.d.ts +2 -0
- package/devtools/widget.js +1 -1
- package/dist/native-document.components.min.js +11074 -2735
- package/dist/native-document.dev.js +2269 -392
- package/dist/native-document.dev.js.map +1 -1
- package/dist/native-document.min.js +1 -1
- package/eslint.config.js +28 -33
- package/i18n.js +1 -1
- package/i18n.ts +2 -0
- package/index.js +4 -1
- package/package.json +3 -2
- 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 +128 -10
- package/src/components/card/index.js +3 -3
- 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/List.js +99 -15
- package/src/components/list/ListGroup.js +58 -8
- package/src/components/list/ListItem.js +79 -18
- package/src/components/list/index.js +5 -5
- 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 +42 -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 +11 -2
- 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 +113 -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 +33 -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/contextmenu/ContextmenuRender.js +5 -5
- 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/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/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 +36 -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/SkeletonCard.js +0 -0
- package/src/components/skeleton/SkeletonList.js +0 -0
- package/src/components/skeleton/SkeletonParagraph.js +0 -0
- package/src/components/skeleton/SkeletonTable.js +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) {
|
|
@@ -129,58 +151,138 @@ ObservableResource.prototype.$watchDependencies = function() {
|
|
|
129
151
|
}
|
|
130
152
|
};
|
|
131
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Sets a custom function to apply fetched results to this.data.
|
|
156
|
+
* Useful when the raw response needs transformation before storing.
|
|
157
|
+
*
|
|
158
|
+
* @param {(result: *, data: ObservableItem) => void} fn - Function receiving the result and the data observable
|
|
159
|
+
* @returns {this}
|
|
160
|
+
* @example
|
|
161
|
+
* resource.apply((result, data) => data.set(result.items));
|
|
162
|
+
*/
|
|
132
163
|
ObservableResource.prototype.apply = function(fn) {
|
|
133
164
|
this.$config.apply = fn;
|
|
134
165
|
return this;
|
|
135
166
|
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Redirects fetched results into an existing ObservableItem instead of the default internal one.
|
|
170
|
+
* Updates both this.data reference and config.into.
|
|
171
|
+
*
|
|
172
|
+
* @param {ObservableItem} $observable - Target observable to write results into
|
|
173
|
+
* @returns {this}
|
|
174
|
+
* @example
|
|
175
|
+
* const items = Observable([]);
|
|
176
|
+
* resource.into(items);
|
|
177
|
+
*/
|
|
136
178
|
ObservableResource.prototype.into = function($observable) {
|
|
137
179
|
this.$config.into = $observable;
|
|
138
180
|
this.data = $observable;
|
|
139
181
|
return this;
|
|
140
182
|
};
|
|
141
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Triggers a fresh fetch (state transitions to 'pending').
|
|
186
|
+
* Use when no prior data exists or when a full reload is needed.
|
|
187
|
+
*
|
|
188
|
+
* @returns {this}
|
|
189
|
+
*/
|
|
142
190
|
ObservableResource.prototype.fetch = function() {
|
|
143
191
|
this.$run(false);
|
|
144
192
|
return this;
|
|
145
193
|
};
|
|
146
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Triggers a re-fetch (state transitions to 'refreshing' if data already exists).
|
|
197
|
+
* Use when you want to reload while keeping the previous data visible.
|
|
198
|
+
*
|
|
199
|
+
* @returns {this}
|
|
200
|
+
*/
|
|
147
201
|
ObservableResource.prototype.refetch = function() {
|
|
148
202
|
this.$run(true);
|
|
149
203
|
return this;
|
|
150
204
|
};
|
|
151
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Manually sets the data value and marks the state as 'ready'.
|
|
208
|
+
* Useful for optimistic updates or seeding initial data without a network call.
|
|
209
|
+
*
|
|
210
|
+
* @param {*} value - New value to set on this.data
|
|
211
|
+
* @returns {this}
|
|
212
|
+
* @example
|
|
213
|
+
* resource.mutate([...resource.data.val(), newItem]);
|
|
214
|
+
*/
|
|
152
215
|
ObservableResource.prototype.mutate = function(value) {
|
|
153
216
|
this.data.set(value);
|
|
154
217
|
this.state.set(STATE.READY);
|
|
155
218
|
return this;
|
|
156
219
|
};
|
|
157
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Cancels any pending request, unsubscribes from all dependencies, and clears subscriptions.
|
|
223
|
+
* Call this when the component using this resource is unmounted.
|
|
224
|
+
*
|
|
225
|
+
* @returns {void}
|
|
226
|
+
*/
|
|
158
227
|
ObservableResource.prototype.destroy = function() {
|
|
159
228
|
this.$abort();
|
|
160
229
|
this.$subscriptions.forEach(unsub => unsub());
|
|
161
230
|
this.$subscriptions = [];
|
|
162
231
|
};
|
|
163
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Returns a derived observable that emits true when the state is 'ready'.
|
|
235
|
+
*
|
|
236
|
+
* @returns {ObservableChecker<boolean>}
|
|
237
|
+
*/
|
|
164
238
|
ObservableResource.prototype.isReady = function() {
|
|
165
239
|
return this.state.isEqualTo(STATE.READY);
|
|
166
240
|
};
|
|
167
241
|
|
|
242
|
+
/**
|
|
243
|
+
* Returns a derived observable that emits true when the state is 'pending' (initial load).
|
|
244
|
+
*
|
|
245
|
+
* @returns {ObservableChecker<boolean>}
|
|
246
|
+
*/
|
|
168
247
|
ObservableResource.prototype.isPending = function() {
|
|
169
248
|
return this.state.isEqualTo(STATE.PENDING);
|
|
170
249
|
};
|
|
171
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Returns a derived observable that emits true when the state is 'refreshing' (reload with existing data).
|
|
253
|
+
*
|
|
254
|
+
* @returns {ObservableChecker<boolean>}
|
|
255
|
+
*/
|
|
172
256
|
ObservableResource.prototype.isRefreshing = function() {
|
|
173
257
|
return this.state.isEqualTo(STATE.REFRESHING);
|
|
174
258
|
};
|
|
175
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Returns a derived observable that emits true when the state is 'errored'.
|
|
262
|
+
*
|
|
263
|
+
* @returns {ObservableChecker<boolean>}
|
|
264
|
+
*/
|
|
176
265
|
ObservableResource.prototype.isErrored = function() {
|
|
177
266
|
return this.state.isEqualTo(STATE.ERRORED);
|
|
178
267
|
};
|
|
179
268
|
|
|
269
|
+
/**
|
|
270
|
+
* Returns a derived observable that emits true when no fetch has been triggered yet.
|
|
271
|
+
*
|
|
272
|
+
* @returns {ObservableChecker<boolean>}
|
|
273
|
+
*/
|
|
180
274
|
ObservableResource.prototype.isUnresolved = function() {
|
|
181
275
|
return this.state.isEqualTo(STATE.UNRESOLVED);
|
|
182
276
|
};
|
|
183
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Registers a callback that is called every time a fetch completes successfully.
|
|
280
|
+
*
|
|
281
|
+
* @param {(value: *) => void} callback - Called with the fetched data value
|
|
282
|
+
* @returns {this}
|
|
283
|
+
* @example
|
|
284
|
+
* resource.onSuccess((data) => console.log('Loaded:', data));
|
|
285
|
+
*/
|
|
184
286
|
ObservableResource.prototype.onSuccess = function(callback) {
|
|
185
287
|
this.data.subscribe((value) => {
|
|
186
288
|
if (this.state.val() === STATE.READY) {
|
|
@@ -190,6 +292,14 @@ ObservableResource.prototype.onSuccess = function(callback) {
|
|
|
190
292
|
return this;
|
|
191
293
|
};
|
|
192
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Registers a callback called every time a fetch fails.
|
|
297
|
+
*
|
|
298
|
+
* @param {(error: Error) => void} callback - Called with the error object
|
|
299
|
+
* @returns {this}
|
|
300
|
+
* @example
|
|
301
|
+
* resource.onError((err) => console.error('Failed:', err.message));
|
|
302
|
+
*/
|
|
193
303
|
ObservableResource.prototype.onError = function(callback) {
|
|
194
304
|
this.error.subscribe((err) => {
|
|
195
305
|
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
|
+
);
|