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
package/docs/native-fetch.md
CHANGED
|
@@ -1,103 +1,66 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
---
|
|
2
|
+
title: NativeFetch
|
|
3
|
+
description: HTTP client built on the native Fetch API with request and response interceptors
|
|
4
|
+
---
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
# NativeFetch
|
|
6
7
|
|
|
7
|
-
NativeFetch
|
|
8
|
-
- **Interceptors** - Request and response transformation
|
|
9
|
-
- **Base URL** - Centralized endpoint configuration
|
|
10
|
-
- **Automatic JSON handling** - Parse and stringify automatically
|
|
11
|
-
- **Error handling** - Consistent error responses
|
|
12
|
-
- **Request cancellation** - AbortController integration
|
|
13
|
-
- **TypeScript-friendly** - Clean, predictable API
|
|
8
|
+
NativeFetch is an HTTP client built on top of the native Fetch API. It adds interceptors, a base URL, and automatic JSON handling.
|
|
14
9
|
|
|
15
|
-
## Import
|
|
16
10
|
```javascript
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
## Basic Usage
|
|
11
|
+
import { utils } from 'native-document';
|
|
12
|
+
const { NativeFetch } = utils;
|
|
21
13
|
|
|
22
|
-
|
|
23
|
-
```javascript
|
|
14
|
+
// Or
|
|
24
15
|
import { NativeFetch } from 'native-document/utils';
|
|
16
|
+
```
|
|
25
17
|
|
|
26
|
-
|
|
27
|
-
const api = new NativeFetch('https://api.example.com');
|
|
18
|
+
---
|
|
28
19
|
|
|
29
|
-
|
|
30
|
-
const users = await api.get('/users');
|
|
31
|
-
const user = await api.get('/users/123');
|
|
32
|
-
const newUser = await api.post('/users', { name: 'Alice', email: 'alice@example.com' });
|
|
33
|
-
```
|
|
20
|
+
## Creating an Instance
|
|
34
21
|
|
|
35
|
-
### HTTP Methods
|
|
36
22
|
```javascript
|
|
37
|
-
import { NativeFetch } from 'native-document/utils';
|
|
38
|
-
|
|
39
23
|
const api = new NativeFetch('https://api.example.com');
|
|
24
|
+
```
|
|
40
25
|
|
|
41
|
-
|
|
42
|
-
const data = await api.get('/endpoint');
|
|
43
|
-
const dataWithParams = await api.get('/endpoint', { page: 1, limit: 10 });
|
|
26
|
+
---
|
|
44
27
|
|
|
45
|
-
|
|
46
|
-
const created = await api.post('/endpoint', {
|
|
47
|
-
name: 'New Item',
|
|
48
|
-
description: 'Description'
|
|
49
|
-
});
|
|
28
|
+
## HTTP Methods
|
|
50
29
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
// PATCH request
|
|
57
|
-
const patched = await api.patch('/endpoint/123', {
|
|
58
|
-
status: 'active'
|
|
59
|
-
});
|
|
30
|
+
```javascript
|
|
31
|
+
// GET
|
|
32
|
+
const users = await api.get('/users');
|
|
33
|
+
const user = await api.get('/users/123');
|
|
60
34
|
|
|
61
|
-
//
|
|
62
|
-
const
|
|
63
|
-
|
|
35
|
+
// GET with query parameters
|
|
36
|
+
const page = await api.get('/users', { page: 1, limit: 20, sort: 'name' });
|
|
37
|
+
// -> GET /users?page=1&limit=20&sort=name
|
|
64
38
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
import { NativeFetch } from 'native-document/utils';
|
|
39
|
+
// POST
|
|
40
|
+
const newUser = await api.post('/users', { name: 'Alice', email: 'alice@example.com' });
|
|
68
41
|
|
|
69
|
-
|
|
42
|
+
// PUT
|
|
43
|
+
const updated = await api.put('/users/123', { name: 'Alice Updated' });
|
|
70
44
|
|
|
71
|
-
//
|
|
72
|
-
const
|
|
73
|
-
page: 1,
|
|
74
|
-
limit: 20,
|
|
75
|
-
sort: 'name',
|
|
76
|
-
filter: 'active'
|
|
77
|
-
});
|
|
78
|
-
// Request: GET /users?page=1&limit=20&sort=name&filter=active
|
|
45
|
+
// PATCH
|
|
46
|
+
const patched = await api.patch('/users/123', { status: 'active' });
|
|
79
47
|
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
tags: ['javascript', 'tutorial'],
|
|
83
|
-
categories: ['tech', 'programming']
|
|
84
|
-
});
|
|
85
|
-
// Request: GET /posts?tags=javascript,tutorial&categories=tech,programming
|
|
48
|
+
// DELETE
|
|
49
|
+
await api.delete('/users/123');
|
|
86
50
|
```
|
|
87
51
|
|
|
52
|
+
---
|
|
53
|
+
|
|
88
54
|
## Interceptors
|
|
89
55
|
|
|
90
|
-
|
|
56
|
+
### Request interceptors
|
|
91
57
|
|
|
92
|
-
|
|
93
|
-
```javascript
|
|
94
|
-
import { NativeFetch } from 'native-document/utils';
|
|
58
|
+
Run before the request is sent:
|
|
95
59
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const token = localStorage.getItem('auth_token');
|
|
60
|
+
```javascript
|
|
61
|
+
// Add authentication
|
|
62
|
+
api.interceptors.request(config => {
|
|
63
|
+
const token = localStorage.getItem('token');
|
|
101
64
|
if (token) {
|
|
102
65
|
config.headers['Authorization'] = `Bearer ${token}`;
|
|
103
66
|
}
|
|
@@ -105,640 +68,146 @@ api.interceptors.request((config) => {
|
|
|
105
68
|
});
|
|
106
69
|
|
|
107
70
|
// Add custom headers
|
|
108
|
-
api.interceptors.request(
|
|
71
|
+
api.interceptors.request(config => {
|
|
109
72
|
config.headers['X-App-Version'] = '1.0.0';
|
|
110
|
-
config.headers['X-Request-ID'] = generateRequestId();
|
|
111
|
-
return config;
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
// Log requests
|
|
115
|
-
api.interceptors.request((config) => {
|
|
116
|
-
console.log(`[${config.method}] ${config.url}`);
|
|
117
73
|
return config;
|
|
118
74
|
});
|
|
119
75
|
```
|
|
120
76
|
|
|
121
|
-
### Response
|
|
122
|
-
```javascript
|
|
123
|
-
import { NativeFetch } from 'native-document/utils';
|
|
77
|
+
### Response interceptors
|
|
124
78
|
|
|
125
|
-
|
|
79
|
+
Run after the response is received:
|
|
126
80
|
|
|
127
|
-
|
|
128
|
-
|
|
81
|
+
```javascript
|
|
82
|
+
// Handle 401
|
|
83
|
+
api.interceptors.response(response => {
|
|
129
84
|
if (response.status === 401) {
|
|
130
|
-
|
|
85
|
+
Store.get('auth').set({ user: null, token: null, isLoggedIn: false });
|
|
131
86
|
window.location.href = '/login';
|
|
132
|
-
throw new Error('Unauthorized');
|
|
133
87
|
}
|
|
134
88
|
return response;
|
|
135
89
|
});
|
|
136
90
|
|
|
137
|
-
//
|
|
138
|
-
api.interceptors.response(
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
return {
|
|
142
|
-
...response,
|
|
143
|
-
data: response.data.result
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
return response;
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
// Log responses
|
|
150
|
-
api.interceptors.response((response) => {
|
|
151
|
-
console.log(`[${response.status}] ${response.url}`);
|
|
152
|
-
return response;
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
// Handle errors globally
|
|
156
|
-
api.interceptors.response((response) => {
|
|
157
|
-
if (!response.ok) {
|
|
158
|
-
console.error(`Error: ${response.status} - ${response.statusText}`);
|
|
91
|
+
// Unwrap data envelope
|
|
92
|
+
api.interceptors.response(response => {
|
|
93
|
+
if (response.data?.result) {
|
|
94
|
+
return { ...response, data: response.data.result };
|
|
159
95
|
}
|
|
160
96
|
return response;
|
|
161
97
|
});
|
|
162
98
|
```
|
|
163
99
|
|
|
164
|
-
|
|
165
|
-
```javascript
|
|
166
|
-
import { NativeFetch } from 'native-document/utils';
|
|
167
|
-
|
|
168
|
-
const api = new NativeFetch('https://api.example.com');
|
|
169
|
-
|
|
170
|
-
// Interceptors are executed in order
|
|
171
|
-
api.interceptors.request((config) => {
|
|
172
|
-
console.log('Interceptor 1');
|
|
173
|
-
return config;
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
api.interceptors.request((config) => {
|
|
177
|
-
console.log('Interceptor 2');
|
|
178
|
-
return config;
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
// When making a request:
|
|
182
|
-
await api.get('/users');
|
|
183
|
-
// Logs: "Interceptor 1"
|
|
184
|
-
// Logs: "Interceptor 2"
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
## Advanced Features
|
|
188
|
-
|
|
189
|
-
### Custom Headers
|
|
190
|
-
```javascript
|
|
191
|
-
import { NativeFetch } from 'native-document/utils';
|
|
192
|
-
|
|
193
|
-
const api = new NativeFetch('https://api.example.com');
|
|
194
|
-
|
|
195
|
-
// Set default headers
|
|
196
|
-
api.interceptors.request((config) => {
|
|
197
|
-
config.headers['Content-Type'] = 'application/json';
|
|
198
|
-
config.headers['Accept'] = 'application/json';
|
|
199
|
-
return config;
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
// Per-request headers
|
|
203
|
-
const data = await api.get('/endpoint', {}, {
|
|
204
|
-
headers: {
|
|
205
|
-
'X-Custom-Header': 'value'
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Retry Logic
|
|
211
|
-
```javascript
|
|
212
|
-
import { NativeFetch } from 'native-document/utils';
|
|
100
|
+
Multiple interceptors run in the order they were registered.
|
|
213
101
|
|
|
214
|
-
|
|
102
|
+
---
|
|
215
103
|
|
|
216
|
-
|
|
217
|
-
api.interceptors.response(async (response) => {
|
|
218
|
-
if (response.status === 429) {
|
|
219
|
-
// Rate limited - wait and retry
|
|
220
|
-
const retryAfter = response.headers.get('Retry-After') || 1;
|
|
221
|
-
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
|
|
222
|
-
|
|
223
|
-
// Retry the request
|
|
224
|
-
return fetch(response.url, response.config);
|
|
225
|
-
}
|
|
226
|
-
return response;
|
|
227
|
-
});
|
|
228
|
-
```
|
|
104
|
+
## Practical Example - API Service Layer
|
|
229
105
|
|
|
230
|
-
|
|
106
|
+
Combine with `Cache` for a clean service pattern:
|
|
231
107
|
|
|
232
|
-
### Authentication Flow
|
|
233
108
|
```javascript
|
|
234
|
-
import { NativeFetch } from 'native-document/utils';
|
|
109
|
+
import { Cache, NativeFetch } from 'native-document/utils';
|
|
235
110
|
import { Store } from 'native-document';
|
|
236
111
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
// Create auth store
|
|
240
|
-
Store.create('auth', {
|
|
241
|
-
user: null,
|
|
242
|
-
token: null,
|
|
243
|
-
isAuthenticated: false
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
// Add token to requests
|
|
247
|
-
api.interceptors.request((config) => {
|
|
248
|
-
const auth = Store.get('auth').val();
|
|
249
|
-
if (auth.token) {
|
|
250
|
-
config.headers['Authorization'] = `Bearer ${auth.token}`;
|
|
251
|
-
}
|
|
252
|
-
return config;
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
// Handle unauthorized
|
|
256
|
-
api.interceptors.response((response) => {
|
|
257
|
-
if (response.status === 401) {
|
|
258
|
-
const auth = Store.get('auth');
|
|
259
|
-
auth.set({
|
|
260
|
-
user: null,
|
|
261
|
-
token: null,
|
|
262
|
-
isAuthenticated: false
|
|
263
|
-
});
|
|
264
|
-
window.location.href = '/login';
|
|
265
|
-
}
|
|
266
|
-
return response;
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
// Login function
|
|
270
|
-
async function login(email, password) {
|
|
271
|
-
const { data } = await api.post('/auth/login', { email, password });
|
|
272
|
-
|
|
273
|
-
const auth = Store.get('auth');
|
|
274
|
-
auth.set({
|
|
275
|
-
user: data.user,
|
|
276
|
-
token: data.token,
|
|
277
|
-
isAuthenticated: true
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
return data;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Logout function
|
|
284
|
-
async function logout() {
|
|
285
|
-
await api.post('/auth/logout');
|
|
286
|
-
|
|
287
|
-
const auth = Store.get('auth');
|
|
288
|
-
auth.set({
|
|
289
|
-
user: null,
|
|
290
|
-
token: null,
|
|
291
|
-
isAuthenticated: false
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
### API Service Layer
|
|
297
|
-
```javascript
|
|
298
|
-
import { NativeFetch } from 'native-document/utils';
|
|
299
|
-
import { Cache } from 'native-document/utils';
|
|
300
|
-
|
|
301
|
-
// Create API client singleton
|
|
112
|
+
// Singleton API client
|
|
302
113
|
const getAPI = Cache.singleton(() => {
|
|
303
114
|
const client = new NativeFetch('https://api.example.com');
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
config.headers['Content-Type'] = 'application/json';
|
|
308
|
-
const token = localStorage.getItem('token');
|
|
115
|
+
|
|
116
|
+
client.interceptors.request(config => {
|
|
117
|
+
const token = Store.get('auth').$value?.token;
|
|
309
118
|
if (token) {
|
|
310
119
|
config.headers['Authorization'] = `Bearer ${token}`;
|
|
311
120
|
}
|
|
312
121
|
return config;
|
|
313
122
|
});
|
|
314
|
-
|
|
123
|
+
|
|
124
|
+
client.interceptors.response(response => {
|
|
125
|
+
if (response.status === 401) {
|
|
126
|
+
Store.reset('auth');
|
|
127
|
+
Router.push({ name: 'login' });
|
|
128
|
+
}
|
|
129
|
+
return response;
|
|
130
|
+
});
|
|
131
|
+
|
|
315
132
|
return client;
|
|
316
133
|
});
|
|
317
134
|
|
|
318
|
-
//
|
|
319
|
-
|
|
135
|
+
// Resource endpoints via memoize
|
|
136
|
+
const API = Cache.memoize(resource => {
|
|
320
137
|
const client = getAPI();
|
|
321
|
-
|
|
322
138
|
return {
|
|
323
139
|
list: (params = {}) => client.get(`/${resource}`, params),
|
|
324
140
|
get: (id) => client.get(`/${resource}/${id}`),
|
|
325
141
|
create: (data) => client.post(`/${resource}`, data),
|
|
326
142
|
update: (id, data) => client.put(`/${resource}/${id}`, data),
|
|
327
|
-
patch: (id, data) => client.patch(`/${resource}/${id}`, data),
|
|
328
143
|
delete: (id) => client.delete(`/${resource}/${id}`)
|
|
329
144
|
};
|
|
330
145
|
});
|
|
331
146
|
|
|
332
147
|
// Usage
|
|
333
|
-
const users = await API.users.list({ page: 1
|
|
148
|
+
const users = await API.users.list({ page: 1 });
|
|
334
149
|
const user = await API.users.get('123');
|
|
335
150
|
const newUser = await API.users.create({ name: 'Alice' });
|
|
336
|
-
await API.users.update('123', { name: 'Alice Updated' });
|
|
337
151
|
await API.users.delete('123');
|
|
338
152
|
```
|
|
339
153
|
|
|
340
|
-
|
|
341
|
-
```javascript
|
|
342
|
-
import { NativeFetch } from 'native-document/utils';
|
|
343
|
-
import { Observable } from 'native-document';
|
|
154
|
+
---
|
|
344
155
|
|
|
345
|
-
|
|
156
|
+
## Loading State with Observables
|
|
346
157
|
|
|
158
|
+
```javascript
|
|
347
159
|
const isLoading = Observable(false);
|
|
348
|
-
const
|
|
160
|
+
const requestCount = Observable(0);
|
|
349
161
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
loadingCount.set(loadingCount.val() + 1);
|
|
162
|
+
api.interceptors.request(config => {
|
|
163
|
+
requestCount.set(requestCount.val() + 1);
|
|
353
164
|
isLoading.set(true);
|
|
354
165
|
return config;
|
|
355
166
|
});
|
|
356
167
|
|
|
357
|
-
api.interceptors.response(
|
|
358
|
-
const count =
|
|
359
|
-
|
|
168
|
+
api.interceptors.response(response => {
|
|
169
|
+
const count = requestCount.val() - 1;
|
|
170
|
+
requestCount.set(count);
|
|
360
171
|
if (count === 0) {
|
|
361
172
|
isLoading.set(false);
|
|
362
173
|
}
|
|
363
174
|
return response;
|
|
364
175
|
});
|
|
365
176
|
|
|
366
|
-
|
|
367
|
-
import { Div } from 'native-document/src/elements';
|
|
368
|
-
import { ShowIf } from 'native-document';
|
|
369
|
-
|
|
370
|
-
const LoadingIndicator = Div({ class: 'loading-indicator' }, [
|
|
371
|
-
ShowIf(isLoading, () =>
|
|
372
|
-
Div({ class: 'spinner' }, 'Loading...')
|
|
373
|
-
)
|
|
374
|
-
]);
|
|
177
|
+
ShowIf(isLoading.isTruthy(), Div({ class: 'spinner' }, 'Loading...'))
|
|
375
178
|
```
|
|
376
179
|
|
|
377
|
-
|
|
378
|
-
```javascript
|
|
379
|
-
import { NativeFetch } from 'native-document/utils';
|
|
380
|
-
import { Observable } from 'native-document';
|
|
381
|
-
|
|
382
|
-
const api = new NativeFetch('https://api.example.com');
|
|
383
|
-
const globalError = Observable(null);
|
|
384
|
-
|
|
385
|
-
// Global error handler
|
|
386
|
-
api.interceptors.response((response) => {
|
|
387
|
-
if (!response.ok) {
|
|
388
|
-
const error = {
|
|
389
|
-
status: response.status,
|
|
390
|
-
message: response.statusText,
|
|
391
|
-
url: response.url
|
|
392
|
-
};
|
|
393
|
-
|
|
394
|
-
globalError.set(error);
|
|
395
|
-
|
|
396
|
-
// Auto-clear after 5 seconds
|
|
397
|
-
setTimeout(() => globalError.set(null), 5000);
|
|
398
|
-
}
|
|
399
|
-
return response;
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
// Error display component
|
|
403
|
-
import { Div } from 'native-document/src/elements';
|
|
404
|
-
import { ShowIf } from 'native-document';
|
|
405
|
-
|
|
406
|
-
const ErrorNotification = Div([
|
|
407
|
-
ShowIf(globalError, () =>
|
|
408
|
-
Div({
|
|
409
|
-
class: 'error-notification',
|
|
410
|
-
style: {
|
|
411
|
-
position: 'fixed',
|
|
412
|
-
top: '20px',
|
|
413
|
-
right: '20px',
|
|
414
|
-
background: '#ff4444',
|
|
415
|
-
color: 'white',
|
|
416
|
-
padding: '16px',
|
|
417
|
-
borderRadius: '8px'
|
|
418
|
-
}
|
|
419
|
-
}, [
|
|
420
|
-
globalError.check(err => err ? err.message : '')
|
|
421
|
-
])
|
|
422
|
-
)
|
|
423
|
-
]);
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
### Request Logging
|
|
427
|
-
```javascript
|
|
428
|
-
import { NativeFetch } from 'native-document/utils';
|
|
429
|
-
|
|
430
|
-
const api = new NativeFetch('https://api.example.com');
|
|
431
|
-
|
|
432
|
-
// Log all requests
|
|
433
|
-
api.interceptors.request((config) => {
|
|
434
|
-
console.group(`🔵 ${config.method} ${config.url}`);
|
|
435
|
-
console.log('Headers:', config.headers);
|
|
436
|
-
console.log('Body:', config.body);
|
|
437
|
-
console.log('Timestamp:', new Date().toISOString());
|
|
438
|
-
console.groupEnd();
|
|
439
|
-
return config;
|
|
440
|
-
});
|
|
441
|
-
|
|
442
|
-
// Log all responses
|
|
443
|
-
api.interceptors.response((response) => {
|
|
444
|
-
const color = response.ok ? '🟢' : '🔴';
|
|
445
|
-
console.group(`${color} ${response.status} ${response.url}`);
|
|
446
|
-
console.log('Status:', response.statusText);
|
|
447
|
-
console.log('Data:', response.data);
|
|
448
|
-
console.log('Duration:', /* calculate duration */);
|
|
449
|
-
console.groupEnd();
|
|
450
|
-
return response;
|
|
451
|
-
});
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
### Analytics Tracking
|
|
455
|
-
```javascript
|
|
456
|
-
import { NativeFetch } from 'native-document/utils';
|
|
457
|
-
|
|
458
|
-
const api = new NativeFetch('https://api.example.com');
|
|
459
|
-
|
|
460
|
-
// Track API calls
|
|
461
|
-
api.interceptors.request((config) => {
|
|
462
|
-
config._startTime = Date.now();
|
|
463
|
-
return config;
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
api.interceptors.response((response) => {
|
|
467
|
-
const duration = Date.now() - response.config._startTime;
|
|
468
|
-
|
|
469
|
-
// Send to analytics
|
|
470
|
-
if (window.analytics) {
|
|
471
|
-
window.analytics.track('api_request', {
|
|
472
|
-
method: response.config.method,
|
|
473
|
-
endpoint: response.url,
|
|
474
|
-
status: response.status,
|
|
475
|
-
duration: duration,
|
|
476
|
-
success: response.ok
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
return response;
|
|
481
|
-
});
|
|
482
|
-
```
|
|
180
|
+
---
|
|
483
181
|
|
|
484
182
|
## Response Format
|
|
485
183
|
|
|
486
|
-
NativeFetch
|
|
487
|
-
```javascript
|
|
488
|
-
{
|
|
489
|
-
ok: boolean, // true if status 200-299
|
|
490
|
-
status: number, // HTTP status code
|
|
491
|
-
statusText: string, // Status message
|
|
492
|
-
headers: Headers, // Response headers
|
|
493
|
-
data: any, // Parsed JSON data
|
|
494
|
-
url: string, // Request URL
|
|
495
|
-
config: object // Original request config
|
|
496
|
-
}
|
|
497
|
-
```
|
|
184
|
+
NativeFetch returns a consistent response object:
|
|
498
185
|
|
|
499
|
-
### Handling Different Response Types
|
|
500
186
|
```javascript
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
//
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
// Text response
|
|
510
|
-
const response = await fetch('https://api.example.com/text');
|
|
511
|
-
const text = await response.text();
|
|
512
|
-
|
|
513
|
-
// Blob response (files, images)
|
|
514
|
-
const blobResponse = await fetch('https://api.example.com/image.png');
|
|
515
|
-
const blob = await blobResponse.blob();
|
|
516
|
-
const imageUrl = URL.createObjectURL(blob);
|
|
517
|
-
```
|
|
518
|
-
|
|
519
|
-
## Error Handling
|
|
520
|
-
|
|
521
|
-
### Try-Catch Pattern
|
|
522
|
-
```javascript
|
|
523
|
-
import { NativeFetch } from 'native-document/utils';
|
|
524
|
-
|
|
525
|
-
const api = new NativeFetch('https://api.example.com');
|
|
526
|
-
|
|
527
|
-
try {
|
|
528
|
-
const data = await api.get('/endpoint');
|
|
529
|
-
console.log('Success:', data);
|
|
530
|
-
} catch (error) {
|
|
531
|
-
if (error.response) {
|
|
532
|
-
// Server responded with error
|
|
533
|
-
console.error('Server error:', error.response.status);
|
|
534
|
-
console.error('Message:', error.response.data);
|
|
535
|
-
} else if (error.request) {
|
|
536
|
-
// Request made but no response
|
|
537
|
-
console.error('Network error:', error.message);
|
|
538
|
-
} else {
|
|
539
|
-
// Other errors
|
|
540
|
-
console.error('Error:', error.message);
|
|
541
|
-
}
|
|
187
|
+
{
|
|
188
|
+
ok: boolean, // true if status 200-299
|
|
189
|
+
status: number, // HTTP status code
|
|
190
|
+
statusText: string, // status message
|
|
191
|
+
headers: Headers, // response headers
|
|
192
|
+
data: any, // parsed JSON body
|
|
193
|
+
url: string // request URL
|
|
542
194
|
}
|
|
543
195
|
```
|
|
544
196
|
|
|
545
|
-
|
|
546
|
-
```javascript
|
|
547
|
-
import { NativeFetch } from 'native-document/utils';
|
|
548
|
-
import { Observable } from 'native-document';
|
|
549
|
-
|
|
550
|
-
const api = new NativeFetch('https://api.example.com');
|
|
551
|
-
|
|
552
|
-
async function fetchData() {
|
|
553
|
-
const data = Observable(null);
|
|
554
|
-
const error = Observable(null);
|
|
555
|
-
const loading = Observable(true);
|
|
556
|
-
|
|
557
|
-
try {
|
|
558
|
-
const response = await api.get('/data');
|
|
559
|
-
data.set(response.data);
|
|
560
|
-
} catch (err) {
|
|
561
|
-
error.set(err.message);
|
|
562
|
-
} finally {
|
|
563
|
-
loading.set(false);
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
return { data, error, loading };
|
|
567
|
-
}
|
|
568
|
-
```
|
|
197
|
+
---
|
|
569
198
|
|
|
570
199
|
## Best Practices
|
|
571
200
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
// ✅ Good: Single instance with interceptors
|
|
578
|
-
const getAPI = Cache.singleton(() => {
|
|
579
|
-
const client = new NativeFetch('https://api.example.com');
|
|
580
|
-
|
|
581
|
-
client.interceptors.request((config) => {
|
|
582
|
-
// Add auth header
|
|
583
|
-
return config;
|
|
584
|
-
});
|
|
585
|
-
|
|
586
|
-
return client;
|
|
587
|
-
});
|
|
588
|
-
|
|
589
|
-
// ❌ Bad: New instance every time
|
|
590
|
-
function makeRequest() {
|
|
591
|
-
const api = new NativeFetch('https://api.example.com');
|
|
592
|
-
return api.get('/data');
|
|
593
|
-
}
|
|
594
|
-
```
|
|
595
|
-
|
|
596
|
-
### 2. Use Resource-Based Endpoints
|
|
597
|
-
```javascript
|
|
598
|
-
import { Cache } from 'native-document/utils';
|
|
599
|
-
|
|
600
|
-
// ✅ Good: Organized by resource
|
|
601
|
-
const API = Cache.memoize((resource) => ({
|
|
602
|
-
list: () => api.get(`/${resource}`),
|
|
603
|
-
get: (id) => api.get(`/${resource}/${id}`),
|
|
604
|
-
create: (data) => api.post(`/${resource}`, data)
|
|
605
|
-
}));
|
|
606
|
-
|
|
607
|
-
// ❌ Bad: Scattered API calls
|
|
608
|
-
async function getUsers() {
|
|
609
|
-
return api.get('/users');
|
|
610
|
-
}
|
|
611
|
-
async function getUser(id) {
|
|
612
|
-
return api.get('/users/' + id);
|
|
613
|
-
}
|
|
614
|
-
```
|
|
615
|
-
|
|
616
|
-
### 3. Handle Errors Consistently
|
|
617
|
-
```javascript
|
|
618
|
-
import { NativeFetch } from 'native-document/utils';
|
|
619
|
-
|
|
620
|
-
const api = new NativeFetch('https://api.example.com');
|
|
621
|
-
|
|
622
|
-
// ✅ Good: Centralized error handling
|
|
623
|
-
api.interceptors.response((response) => {
|
|
624
|
-
if (!response.ok) {
|
|
625
|
-
handleError(response);
|
|
626
|
-
}
|
|
627
|
-
return response;
|
|
628
|
-
});
|
|
629
|
-
|
|
630
|
-
// ❌ Bad: Error handling in every request
|
|
631
|
-
try {
|
|
632
|
-
await api.get('/endpoint1');
|
|
633
|
-
} catch (error) {
|
|
634
|
-
showError(error);
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
try {
|
|
638
|
-
await api.get('/endpoint2');
|
|
639
|
-
} catch (error) {
|
|
640
|
-
showError(error);
|
|
641
|
-
}
|
|
642
|
-
```
|
|
643
|
-
|
|
644
|
-
### 4. Use Query Parameters Object
|
|
645
|
-
```javascript
|
|
646
|
-
import { NativeFetch } from 'native-document/utils';
|
|
647
|
-
|
|
648
|
-
const api = new NativeFetch('https://api.example.com');
|
|
649
|
-
|
|
650
|
-
// ✅ Good: Clean object syntax
|
|
651
|
-
const users = await api.get('/users', {
|
|
652
|
-
page: 1,
|
|
653
|
-
limit: 20,
|
|
654
|
-
sort: 'name'
|
|
655
|
-
});
|
|
656
|
-
|
|
657
|
-
// ❌ Bad: Manual query string
|
|
658
|
-
const users = await api.get('/users?page=1&limit=20&sort=name');
|
|
659
|
-
```
|
|
660
|
-
|
|
661
|
-
### 5. Type Your Responses
|
|
662
|
-
```javascript
|
|
663
|
-
import { NativeFetch } from 'native-document/utils';
|
|
664
|
-
|
|
665
|
-
const api = new NativeFetch('https://api.example.com');
|
|
666
|
-
|
|
667
|
-
// ✅ Good: Document expected response
|
|
668
|
-
/**
|
|
669
|
-
* @returns {Promise<{data: User[]}>}
|
|
670
|
-
*/
|
|
671
|
-
async function getUsers() {
|
|
672
|
-
return await api.get('/users');
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
// Use with confidence
|
|
676
|
-
const { data } = await getUsers();
|
|
677
|
-
data.forEach(user => console.log(user.name));
|
|
678
|
-
```
|
|
679
|
-
|
|
680
|
-
## Performance Tips
|
|
681
|
-
|
|
682
|
-
### 1. Reuse Client Instances
|
|
683
|
-
```javascript
|
|
684
|
-
import { Cache } from 'native-document/utils';
|
|
685
|
-
|
|
686
|
-
// ✅ Singleton - created once
|
|
687
|
-
const getAPI = Cache.singleton(() => new NativeFetch('https://api.example.com'));
|
|
688
|
-
```
|
|
689
|
-
|
|
690
|
-
### 2. Cancel Unnecessary Requests
|
|
691
|
-
```javascript
|
|
692
|
-
let controller = new AbortController();
|
|
693
|
-
|
|
694
|
-
async function search(query) {
|
|
695
|
-
// Cancel previous request
|
|
696
|
-
controller.abort();
|
|
697
|
-
controller = new AbortController();
|
|
698
|
-
|
|
699
|
-
return await api.get('/search', { q: query }, {
|
|
700
|
-
signal: controller.signal
|
|
701
|
-
});
|
|
702
|
-
}
|
|
703
|
-
```
|
|
704
|
-
|
|
705
|
-
### 3. Batch Related Requests
|
|
706
|
-
```javascript
|
|
707
|
-
// ✅ Good: Batch requests
|
|
708
|
-
const [users, posts, comments] = await Promise.all([
|
|
709
|
-
api.get('/users'),
|
|
710
|
-
api.get('/posts'),
|
|
711
|
-
api.get('/comments')
|
|
712
|
-
]);
|
|
713
|
-
|
|
714
|
-
// ❌ Bad: Sequential requests
|
|
715
|
-
const users = await api.get('/users');
|
|
716
|
-
const posts = await api.get('/posts');
|
|
717
|
-
const comments = await api.get('/comments');
|
|
718
|
-
```
|
|
719
|
-
|
|
720
|
-
## Next Steps
|
|
201
|
+
1. Create a single instance via `Cache.singleton()` - not a new instance per request
|
|
202
|
+
2. Use `Cache.memoize()` for resource-based endpoint collections
|
|
203
|
+
3. Handle authentication and errors in interceptors - not in each call
|
|
204
|
+
4. Use `Promise.all()` for parallel requests instead of sequential awaits
|
|
721
205
|
|
|
722
|
-
|
|
206
|
+
---
|
|
723
207
|
|
|
724
208
|
## Next Steps
|
|
725
209
|
|
|
726
|
-
- **[
|
|
727
|
-
- **[
|
|
728
|
-
- **[
|
|
729
|
-
- **[
|
|
730
|
-
- **[Conditional Rendering](conditional-rendering.md)** - Dynamic content
|
|
731
|
-
- **[List Rendering](list-rendering.md)** - (ForEach | ForEachArray) and dynamic lists
|
|
732
|
-
- **[Routing](routing.md)** - Navigation and URL management
|
|
733
|
-
- **[State Management](state-management.md)** - Global state patterns
|
|
734
|
-
- **[NDElement](native-document-element.md)** - Native Document Element
|
|
735
|
-
- **[Extending NDElement](extending-native-document-element.md)** - Custom Methods Guide
|
|
736
|
-
- **[Advanced Components](advanced-components.md)** - Template caching and singleton views
|
|
737
|
-
- **[Args Validation](validation.md)** - Function Argument Validation
|
|
738
|
-
- **[Memory Management](memory-management.md)** - Memory management
|
|
739
|
-
|
|
740
|
-
## Utilities
|
|
741
|
-
|
|
742
|
-
- **[Cache](docs/utils/cache.md)** - Lazy initialization and singleton patterns
|
|
743
|
-
- **[NativeFetch](docs/utils/native-fetch.md)** - HTTP client with interceptors
|
|
744
|
-
- **[Filters](docs/utils/filters.md)** - Data filtering helpers
|
|
210
|
+
- **[Cache](./cache.md)** - Lazy initialization and singleton patterns
|
|
211
|
+
- **[Filters](./filters.md)** - Data filtering helpers
|
|
212
|
+
- **[State Management](./state-management.md)** - Global state with Store
|
|
213
|
+
- **[Observable Resource](./observable-resource.md)** - Async data with built-in states
|