@kaspernj/api-maker 1.0.2011 → 1.0.2013
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/{.eslintrc.cjs → .eslintrc.js} +10 -1
- package/README.md +35 -0
- package/android/build.gradle +43 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/expo/modules/api_maker/ApiMakerModule.kt +50 -0
- package/android/src/main/java/expo/modules/api_maker/ApiMakerView.kt +30 -0
- package/build/api.js +120 -0
- package/build/attribute-not-loaded-error.js +2 -0
- package/build/base-component.js +5 -0
- package/build/base-error.js +33 -0
- package/build/base-model/attribute.js +25 -0
- package/build/base-model/column.js +11 -0
- package/build/base-model/reflection.js +14 -0
- package/build/base-model/scope.js +11 -0
- package/build/base-model.js +828 -0
- package/build/bootstrap/attribute-row.js +135 -0
- package/build/bootstrap/attribute-rows.js +31 -0
- package/build/bootstrap/card.js +138 -0
- package/build/bootstrap/checkbox.js +97 -0
- package/build/bootstrap/checkboxes.js +183 -0
- package/build/bootstrap/index.js +2 -0
- package/build/bootstrap/input.js +129 -0
- package/build/bootstrap/invalid-feedback.js +27 -0
- package/build/bootstrap/paginate.js +150 -0
- package/build/bootstrap/radio-buttons.js +72 -0
- package/build/bootstrap/select.js +88 -0
- package/build/bootstrap/sort-link.js +131 -0
- package/build/cable-connection-pool.js +128 -0
- package/build/cable-subscription-pool.js +207 -0
- package/build/cable-subscription.js +21 -0
- package/build/cache-key-generator.js +81 -0
- package/build/can-can.js +134 -0
- package/build/channels-consumer.js +9 -0
- package/build/collection-loader.js +48 -0
- package/build/collection.js +280 -0
- package/build/command-submit-data.js +81 -0
- package/build/commands-pool.js +195 -0
- package/build/compose.js +9 -0
- package/build/config.js +62 -0
- package/build/custom-error.js +5 -0
- package/build/data-set-to-attributes.js +10 -0
- package/build/deserializer.js +56 -0
- package/build/destroy-error.js +5 -0
- package/build/devise.js +112 -0
- package/build/draggable-sort/controller.js +136 -0
- package/build/draggable-sort/index.js +114 -0
- package/build/draggable-sort/item.js +188 -0
- package/build/error-logger.js +101 -0
- package/build/error-messages.js +13 -0
- package/build/event-connection.js +32 -0
- package/build/event-emitter-listener.js +15 -0
- package/build/event-model-class.js +24 -0
- package/build/events.js +5 -0
- package/build/flash-message.js +79 -0
- package/build/form.js +83 -0
- package/build/history-expo.js +20 -0
- package/build/history-react-native.js +20 -0
- package/build/history.js +3 -0
- package/build/index.js +3 -0
- package/build/inputs/attachment.js +133 -0
- package/build/inputs/auto-submit.js +36 -0
- package/build/inputs/checkbox.js +138 -0
- package/build/inputs/checkboxes.js +112 -0
- package/build/inputs/id-for-component.js +15 -0
- package/build/inputs/input-wrapper.js +19 -0
- package/build/inputs/input.js +243 -0
- package/build/inputs/money.js +179 -0
- package/build/inputs/name-for-component.js +13 -0
- package/build/inputs/select.js +93 -0
- package/build/instance-of-class-name.js +23 -0
- package/build/is-expo.js +22 -0
- package/build/key-value-store.js +53 -0
- package/build/link.js +73 -0
- package/build/logger.js +30 -0
- package/build/modal.js +38 -0
- package/build/model-class-require.js +13 -0
- package/build/model-events.js +30 -0
- package/build/model-name.js +28 -0
- package/build/model-prop-type.js +101 -0
- package/build/model-recipes-loader.js +32 -0
- package/build/model-recipes-model-loader.js +357 -0
- package/build/models-response-reader.js +40 -0
- package/build/models.js +8 -0
- package/build/money-formatter.js +78 -0
- package/build/not-loaded-error.js +2 -0
- package/build/params.js +61 -0
- package/build/preloaded.js +38 -0
- package/build/resize-observer.js +11 -0
- package/build/result.js +13 -0
- package/build/router/route.js +270 -0
- package/build/router/switch.js +72 -0
- package/build/router.js +59 -0
- package/build/routes-native.js +202 -0
- package/build/routes.js +50 -0
- package/build/run-last.js +35 -0
- package/build/serializer.js +63 -0
- package/build/services.js +20 -0
- package/build/session-status-updater.js +134 -0
- package/build/source-maps-loader.js +184 -0
- package/build/super-admin/config-reader.js +85 -0
- package/build/super-admin/edit-page/edit-attribute-checkbox.js +85 -0
- package/build/super-admin/edit-page/edit-attribute-content.js +55 -0
- package/build/super-admin/edit-page/edit-attribute-input.js +79 -0
- package/build/super-admin/edit-page/edit-attribute.js +77 -0
- package/build/super-admin/edit-page.js +123 -0
- package/build/super-admin/has-edit-config.js +12 -0
- package/build/super-admin/index-page.js +25 -0
- package/build/super-admin/index.js +181 -0
- package/build/super-admin/layout/header/index.js +161 -0
- package/build/super-admin/layout/index.js +164 -0
- package/build/super-admin/layout/menu/index.js +206 -0
- package/build/super-admin/layout/menu/menu-content.js +46 -0
- package/build/super-admin/layout/menu/menu-item.js +84 -0
- package/build/super-admin/layout/no-access.js +27 -0
- package/build/super-admin/model-class-table.js +61 -0
- package/build/super-admin/models.js +8 -0
- package/build/super-admin/show-nav.js +51 -0
- package/build/super-admin/show-page/belongs-to-attribute-row.js +29 -0
- package/build/super-admin/show-page/index.js +141 -0
- package/build/super-admin/show-reflection-actions.js +47 -0
- package/build/super-admin/show-reflection-link.js +48 -0
- package/build/super-admin/show-reflection-page.js +48 -0
- package/build/table/column-content.js +117 -0
- package/build/table/column-identifier.js +18 -0
- package/build/table/column-visible.js +7 -0
- package/build/table/components/column.js +21 -0
- package/build/table/components/flat-list.js +21 -0
- package/build/table/components/header.js +26 -0
- package/build/table/components/row.js +26 -0
- package/build/table/filters/attribute-element.js +44 -0
- package/build/table/filters/filter-form.js +402 -0
- package/build/table/filters/filter.js +90 -0
- package/build/table/filters/index.js +184 -0
- package/build/table/filters/load-search-modal.js +175 -0
- package/build/table/filters/reflection-element.js +37 -0
- package/build/table/filters/save-search-modal.js +88 -0
- package/build/table/filters/scope-element.js +42 -0
- package/build/table/header-column-content.js +68 -0
- package/build/table/header-column.js +144 -0
- package/build/table/header-select.js +105 -0
- package/build/table/model-callback-args.js +10 -0
- package/build/table/model-column.js +97 -0
- package/build/table/model-row.js +193 -0
- package/build/table/select-calculator.js +63 -0
- package/build/table/settings/column-row.js +97 -0
- package/build/table/settings/download-action.js +79 -0
- package/build/table/settings/index.js +92 -0
- package/build/table/table-settings.js +219 -0
- package/build/table/table.js +972 -0
- package/build/table/use-sorting.js +34 -0
- package/build/table/widths.js +75 -0
- package/build/table/worker-plugins-check-all-checkbox.js +125 -0
- package/build/table/worker-plugins-checkbox.js +115 -0
- package/build/translated-attributes.js +10 -0
- package/build/translated-collections.js +12 -0
- package/build/updated-attribute.js +76 -0
- package/build/url-encode.js +15 -0
- package/build/use-breakpoint.js +71 -0
- package/build/use-can-can.js +55 -0
- package/build/use-collection.js +225 -0
- package/build/use-created-event.js +52 -0
- package/build/use-current-user.js +76 -0
- package/build/use-destroyed-event.js +60 -0
- package/build/use-event-emitter.js +13 -0
- package/build/use-event-listener.js +16 -0
- package/build/use-input.js +137 -0
- package/build/use-model-event.js +60 -0
- package/build/use-model.js +169 -0
- package/build/use-resize-observer.js +23 -0
- package/build/use-router.js +104 -0
- package/build/use-screen-layout.js +39 -0
- package/build/use-styles.js +41 -0
- package/build/use-updated-event.js +60 -0
- package/build/use-validation-errors.js +30 -0
- package/build/utils/card.js +51 -0
- package/build/utils/checkbox.js +78 -0
- package/build/utils/checkboxes.js +163 -0
- package/build/utils/default-style.js +18 -0
- package/build/utils/icon.js +23 -0
- package/build/utils/invalid-feedback.js +19 -0
- package/build/utils/modal.js +62 -0
- package/build/utils/text.js +44 -0
- package/build/validation-error.js +28 -0
- package/build/validation-errors.js +98 -0
- package/build/with-api-maker.js +29 -0
- package/build/with-collection.js +14 -0
- package/build/with-current-user.js +10 -0
- package/build/with-model.js +15 -0
- package/build/with-router.js +22 -0
- package/expo-module.config.json +17 -0
- package/ios/ApiMaker.podspec +29 -0
- package/ios/ApiMakerModule.swift +48 -0
- package/ios/ApiMakerView.swift +38 -0
- package/package.json +49 -46
- package/src/{api.mjs → api.js} +38 -37
- package/src/base-component.jsx +5 -0
- package/src/{base-error.mjs → base-error.js} +4 -6
- package/src/base-model/attribute.js +33 -0
- package/src/base-model/column.js +13 -0
- package/src/base-model/reflection.js +15 -0
- package/src/base-model/scope.js +12 -0
- package/src/{base-model.mjs → base-model.js} +302 -144
- package/src/bootstrap/attribute-row.jsx +135 -0
- package/src/bootstrap/attribute-rows.jsx +27 -0
- package/src/bootstrap/card.jsx +149 -0
- package/src/bootstrap/checkbox.jsx +86 -0
- package/src/bootstrap/checkboxes.jsx +185 -0
- package/src/bootstrap/index.js +0 -0
- package/src/bootstrap/input.jsx +173 -0
- package/src/bootstrap/invalid-feedback.jsx +31 -0
- package/src/bootstrap/paginate.jsx +187 -0
- package/src/bootstrap/radio-buttons.jsx +87 -0
- package/src/bootstrap/select.jsx +110 -0
- package/src/bootstrap/sort-link.jsx +106 -0
- package/src/{cable-connection-pool.mjs → cable-connection-pool.js} +16 -36
- package/src/{cable-subscription-pool.mjs → cable-subscription-pool.js} +26 -21
- package/src/{cable-subscription.mjs → cable-subscription.js} +6 -4
- package/src/cache-key-generator.js +100 -0
- package/src/{can-can.mjs → can-can.js} +13 -12
- package/src/channels-consumer.js +10 -0
- package/src/collection-loader.jsx +58 -224
- package/src/{collection.mjs → collection.js} +98 -44
- package/src/{command-submit-data.mjs → command-submit-data.js} +2 -7
- package/src/{commands-pool.mjs → commands-pool.js} +57 -41
- package/src/compose.js +11 -0
- package/src/{config.mjs → config.js} +6 -2
- package/src/{custom-error.mjs → custom-error.js} +1 -1
- package/src/data-set-to-attributes.js +13 -0
- package/src/{deserializer.mjs → deserializer.js} +3 -3
- package/src/destroy-error.js +7 -0
- package/src/devise.js +129 -0
- package/src/draggable-sort/controller.js +137 -0
- package/src/draggable-sort/index.jsx +108 -0
- package/src/draggable-sort/item.jsx +174 -0
- package/src/{error-logger.mjs → error-logger.js} +12 -7
- package/src/{error-messages.mjs → error-messages.js} +1 -0
- package/src/event-connection.jsx +1 -1
- package/src/event-emitter-listener.jsx +8 -27
- package/src/event-model-class.jsx +2 -4
- package/src/events.js +7 -0
- package/src/flash-message.js +70 -0
- package/src/form.jsx +91 -0
- package/src/history-expo.js +23 -0
- package/src/history-react-native.js +25 -0
- package/src/history.js +3 -0
- package/src/index.js +3 -0
- package/src/inputs/attachment.jsx +108 -0
- package/src/inputs/auto-submit.js +37 -0
- package/src/inputs/checkbox.jsx +125 -0
- package/src/inputs/checkboxes.jsx +116 -0
- package/src/inputs/id-for-component.js +15 -0
- package/src/inputs/input-wrapper.jsx +16 -0
- package/src/inputs/input.jsx +260 -0
- package/src/inputs/money.jsx +187 -0
- package/src/inputs/name-for-component.js +15 -0
- package/src/inputs/select.jsx +104 -0
- package/src/is-expo.js +18 -0
- package/src/{key-value-store.mjs → key-value-store.js} +1 -1
- package/src/link.jsx +54 -9
- package/src/logger.js +38 -0
- package/src/modal.jsx +37 -0
- package/src/model-class-require.js +17 -0
- package/src/{model-events.mjs → model-events.js} +1 -1
- package/src/{model-name.mjs → model-name.js} +8 -8
- package/src/{model-recipes-loader.mjs → model-recipes-loader.js} +1 -1
- package/src/{model-recipes-model-loader.mjs → model-recipes-model-loader.js} +5 -5
- package/src/{models-response-reader.mjs → models-response-reader.js} +3 -4
- package/src/models.js +7 -0
- package/src/{models.mjs.erb → models.js.erb} +6 -3
- package/src/{money-formatter.mjs → money-formatter.js} +5 -4
- package/src/{params.mjs → params.js} +17 -7
- package/src/{preloaded.mjs → preloaded.js} +2 -2
- package/src/resize-observer.jsx +10 -0
- package/src/result.js +13 -0
- package/src/router/route.jsx +246 -0
- package/src/router/switch.jsx +76 -0
- package/src/router.jsx +23 -21
- package/src/{routes-native.mjs → routes-native.js} +12 -6
- package/src/{routes.mjs → routes.js} +1 -1
- package/src/run-last.js +39 -0
- package/src/{serializer.mjs → serializer.js} +2 -2
- package/src/{services.mjs → services.js} +1 -1
- package/src/session-status-updater.js +172 -0
- package/src/{source-maps-loader.mjs → source-maps-loader.js} +54 -28
- package/src/super-admin/config-reader.jsx +93 -0
- package/src/super-admin/edit-page/edit-attribute-checkbox.jsx +81 -0
- package/src/super-admin/edit-page/edit-attribute-content.jsx +57 -0
- package/src/super-admin/edit-page/edit-attribute-input.jsx +71 -0
- package/src/super-admin/edit-page/edit-attribute.jsx +81 -0
- package/src/super-admin/edit-page.jsx +117 -0
- package/src/super-admin/has-edit-config.js +15 -0
- package/src/super-admin/index-page.jsx +23 -0
- package/src/super-admin/index.jsx +197 -0
- package/src/super-admin/layout/header/index.jsx +144 -0
- package/src/super-admin/layout/header/style.scss +45 -0
- package/src/super-admin/layout/index.jsx +154 -0
- package/src/super-admin/layout/menu/index.jsx +171 -0
- package/src/super-admin/layout/menu/menu-content.jsx +43 -0
- package/src/super-admin/layout/menu/menu-item.jsx +70 -0
- package/src/super-admin/layout/menu/style.scss +11 -0
- package/src/super-admin/layout/no-access.jsx +26 -0
- package/src/super-admin/model-class-table.jsx +66 -0
- package/src/super-admin/models.js +11 -0
- package/src/super-admin/show-nav.jsx +44 -0
- package/src/super-admin/show-page/belongs-to-attribute-row.jsx +30 -0
- package/src/super-admin/show-page/index.jsx +141 -0
- package/src/super-admin/show-reflection-actions.jsx +49 -0
- package/src/super-admin/show-reflection-link.jsx +40 -0
- package/src/super-admin/show-reflection-page.jsx +47 -0
- package/src/super-admin/stylesheets/variables.scss +11 -0
- package/src/table/column-content.jsx +122 -0
- package/src/table/column-identifier.js +23 -0
- package/src/table/column-visible.js +7 -0
- package/src/table/components/column.jsx +19 -0
- package/src/table/components/flat-list.jsx +19 -0
- package/src/table/components/header.jsx +21 -0
- package/src/table/components/row.jsx +23 -0
- package/src/table/filters/attribute-element.jsx +47 -0
- package/src/table/filters/filter-form.jsx +407 -0
- package/src/table/filters/filter.jsx +70 -0
- package/src/table/filters/index.jsx +170 -0
- package/src/table/filters/load-search-modal.jsx +146 -0
- package/src/table/filters/reflection-element.jsx +38 -0
- package/src/table/filters/save-search-modal.jsx +74 -0
- package/src/table/filters/scope-element.jsx +44 -0
- package/src/table/header-column-content.jsx +55 -0
- package/src/table/header-column.jsx +129 -0
- package/src/table/header-select.jsx +73 -0
- package/src/table/model-callback-args.js +10 -0
- package/src/table/model-column.jsx +82 -0
- package/src/table/model-row.jsx +136 -0
- package/src/table/select-calculator.js +65 -0
- package/src/table/settings/column-row.jsx +93 -0
- package/src/table/settings/download-action.jsx +68 -0
- package/src/table/settings/index.jsx +65 -0
- package/src/table/table-settings.js +263 -0
- package/src/table/table.jsx +950 -0
- package/src/table/use-sorting.js +35 -0
- package/src/table/variables.scss +11 -0
- package/src/table/widths.jsx +87 -0
- package/src/table/worker-plugins-check-all-checkbox.jsx +112 -0
- package/src/table/worker-plugins-checkbox.jsx +104 -0
- package/src/translated-attributes.js +11 -0
- package/src/{translated-collections.mjs → translated-collections.js} +3 -2
- package/src/updated-attribute.jsx +1 -1
- package/src/url-encode.js +18 -0
- package/src/use-breakpoint.js +87 -0
- package/src/use-can-can.js +55 -0
- package/src/use-collection.js +280 -0
- package/src/use-created-event.js +55 -0
- package/src/use-current-user.js +88 -0
- package/src/use-destroyed-event.js +60 -0
- package/src/use-event-emitter.js +15 -0
- package/src/use-event-listener.js +19 -0
- package/src/use-input.js +157 -0
- package/src/use-model-event.js +60 -0
- package/src/use-model.js +189 -0
- package/src/use-resize-observer.js +24 -0
- package/src/use-router.jsx +128 -0
- package/src/use-screen-layout.js +49 -0
- package/src/use-styles.js +50 -0
- package/src/use-updated-event.js +60 -0
- package/src/use-validation-errors.js +33 -0
- package/src/utils/card.jsx +49 -0
- package/src/utils/checkbox.jsx +80 -0
- package/src/utils/checkboxes.jsx +158 -0
- package/src/utils/default-style.jsx +25 -0
- package/src/utils/icon.jsx +21 -0
- package/src/utils/invalid-feedback.jsx +20 -0
- package/src/utils/modal.jsx +60 -0
- package/src/utils/text.jsx +38 -0
- package/src/{validation-error.mjs → validation-error.js} +9 -5
- package/src/{validation-errors.mjs → validation-errors.js} +15 -27
- package/src/with-api-maker.jsx +31 -0
- package/src/with-collection.jsx +17 -0
- package/src/with-current-user.jsx +7 -25
- package/src/with-model.jsx +16 -0
- package/src/with-router.jsx +7 -129
- package/__tests__/base-model.test.js +0 -71
- package/__tests__/cable-connection-pool.test.js +0 -227
- package/__tests__/cable-subscription-pool.test.js +0 -26
- package/__tests__/can-can.test.js +0 -34
- package/__tests__/collection.test.js +0 -51
- package/__tests__/custom-error.test.js +0 -13
- package/__tests__/model-name.test.js +0 -34
- package/__tests__/model-prop-type.test.js +0 -113
- package/__tests__/params.test.js +0 -40
- package/__tests__/routes-native.test.js +0 -103
- package/__tests__/routes.test.js +0 -46
- package/__tests__/serializer.test.js +0 -30
- package/__tests__/support/task.js +0 -27
- package/__tests__/support/user.js +0 -32
- package/index.js +0 -1
- package/jest.config.js +0 -4
- package/src/can-can-loader.jsx +0 -54
- package/src/channels-consumer.mjs +0 -3
- package/src/destroy-error.mjs +0 -7
- package/src/devise.mjs +0 -122
- package/src/event-created.jsx +0 -65
- package/src/event-destroyed.jsx +0 -29
- package/src/event-listener.jsx +0 -38
- package/src/event-updated.jsx +0 -74
- package/src/logger.mjs +0 -25
- package/src/model-class-require.mjs +0 -10
- package/src/model-load-wrapper.jsx +0 -116
- package/src/result.mjs +0 -29
- package/src/session-status-updater.mjs +0 -116
- package/webpack.config.js +0 -15
- /package/src/{attribute-not-loaded-error.mjs → attribute-not-loaded-error.js} +0 -0
- /package/src/{instance-of-class-name.mjs → instance-of-class-name.js} +0 -0
- /package/src/{model-prop-type.mjs → model-prop-type.js} +0 -0
- /package/src/{not-loaded-error.mjs → not-loaded-error.js} +0 -0
- /package/src/{translated-collections-data.mjs.erb → translated-collections-data.js.erb} +0 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {useCallback, useLayoutEffect, useMemo} from "react"
|
|
2
|
+
import debounceFunction from "debounce"
|
|
3
|
+
import ModelEvents from "./model-events"
|
|
4
|
+
import useShape from "set-state-compare/src/use-shape"
|
|
5
|
+
|
|
6
|
+
const apiMakerUseModelEvent = (model, event, onCallback, props) => {
|
|
7
|
+
const {active = true, debounce, onConnected, ...restProps} = props || {}
|
|
8
|
+
|
|
9
|
+
if (Object.keys(restProps).length > 0) {
|
|
10
|
+
throw new Error(`Unknown props given to apiMakerUseModelEvent: ${Object.keys(restProps).join(", ")}`)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const s = useShape({active, debounce, model, onCallback})
|
|
14
|
+
|
|
15
|
+
const debounceCallback = useMemo(() => {
|
|
16
|
+
if (typeof debounce == "number") {
|
|
17
|
+
return debounceFunction(s.p.onCallback, debounce)
|
|
18
|
+
} else {
|
|
19
|
+
return debounceFunction(s.p.onCallback)
|
|
20
|
+
}
|
|
21
|
+
}, [debounce])
|
|
22
|
+
|
|
23
|
+
s.updateMeta({debounceCallback})
|
|
24
|
+
|
|
25
|
+
const onCallbackCallback = useCallback((...args) => {
|
|
26
|
+
if (!s.p.active) {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (s.p.debounce) {
|
|
31
|
+
s.m.debounceCallback(...args)
|
|
32
|
+
} else {
|
|
33
|
+
s.p.onCallback(...args)
|
|
34
|
+
}
|
|
35
|
+
}, [])
|
|
36
|
+
|
|
37
|
+
useLayoutEffect(() => {
|
|
38
|
+
let connectEvent, onConnectedListener
|
|
39
|
+
|
|
40
|
+
if (model) {
|
|
41
|
+
connectEvent = ModelEvents.connect(model, event, onCallbackCallback)
|
|
42
|
+
|
|
43
|
+
if (onConnected) {
|
|
44
|
+
onConnectedListener = connectEvent.events.addListener("connected", onConnected)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return () => {
|
|
49
|
+
if (onConnectedListener) {
|
|
50
|
+
connectEvent.events.removeListener("connected", onConnected)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (connectEvent) {
|
|
54
|
+
connectEvent.unsubscribe()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}, [model?.id()])
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default apiMakerUseModelEvent
|
package/src/use-model.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import {useCallback, useLayoutEffect, useMemo} from "react"
|
|
2
|
+
import Devise from "./devise"
|
|
3
|
+
import * as inflection from "inflection"
|
|
4
|
+
import ModelEvents from "./model-events"
|
|
5
|
+
import useQueryParams from "on-location-changed/build/use-query-params"
|
|
6
|
+
import useShape from "set-state-compare/src/use-shape"
|
|
7
|
+
|
|
8
|
+
const useModel = (modelClassArg, argsArg = {}) => {
|
|
9
|
+
const queryParams = useQueryParams()
|
|
10
|
+
let args, modelClass
|
|
11
|
+
|
|
12
|
+
if (typeof argsArg == "function") {
|
|
13
|
+
args = argsArg({modelClass})
|
|
14
|
+
} else {
|
|
15
|
+
args = argsArg
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const s = useShape(args)
|
|
19
|
+
|
|
20
|
+
s.useStates({
|
|
21
|
+
model: undefined,
|
|
22
|
+
notFound: undefined
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
if ("active" in s.props && !s.props.active) {
|
|
26
|
+
s.meta.active = false
|
|
27
|
+
} else {
|
|
28
|
+
s.meta.active = true
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (typeof modelClassArg == "object") {
|
|
32
|
+
modelClass = modelClassArg.callback({queryParams})
|
|
33
|
+
} else {
|
|
34
|
+
modelClass = modelClassArg
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const paramsVariableName = `${modelClass.modelName().paramKey()}_id`
|
|
38
|
+
let modelId
|
|
39
|
+
|
|
40
|
+
if (args.loadByQueryParam) {
|
|
41
|
+
modelId = args.loadByQueryParam({queryParams})
|
|
42
|
+
} else if (!args.query) {
|
|
43
|
+
if (!args.match) throw new Error("Both 'loadByQueryParam' and 'match' wasn't given")
|
|
44
|
+
|
|
45
|
+
modelId = args.match.params[paramsVariableName] || args.match.params.id
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const modelVariableName = inflection.camelize(modelClass.modelClassData().name, true)
|
|
49
|
+
const cacheArgs = [modelId]
|
|
50
|
+
|
|
51
|
+
const loadExistingModel = useCallback(async () => {
|
|
52
|
+
let query
|
|
53
|
+
|
|
54
|
+
if (s.m.modelId) {
|
|
55
|
+
query = modelClass.ransack({id_eq: s.m.modelId})
|
|
56
|
+
} else if (s.m.args.query) {
|
|
57
|
+
query = s.m.args.query.clone()
|
|
58
|
+
} else {
|
|
59
|
+
throw new Error(`No model ID was given: ${s.m.modelId} by '${paramsVariableName}' in query params: ${Object.keys(s.props.match.params).join(", ")}`)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (s.props.abilities) query.abilities(s.p.abilities)
|
|
63
|
+
if (s.props.preload) query.preload(s.p.preload)
|
|
64
|
+
if (s.props.select) query.select(s.p.select)
|
|
65
|
+
|
|
66
|
+
const model = await query.first()
|
|
67
|
+
|
|
68
|
+
s.set({model, notFound: !model})
|
|
69
|
+
}, [])
|
|
70
|
+
|
|
71
|
+
const loadNewModel = useCallback(async () => {
|
|
72
|
+
const ModelClass = modelClass
|
|
73
|
+
const paramKey = ModelClass.modelName().paramKey()
|
|
74
|
+
const modelDataFromParams = s.m.queryParams[paramKey] || {}
|
|
75
|
+
|
|
76
|
+
let defaults = {}
|
|
77
|
+
|
|
78
|
+
if (s.props.newIfNoId?.defaults) {
|
|
79
|
+
defaults = await s.props.newIfNoId.defaults()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const modelData = Object.assign(defaults, s.props.newAttributes, modelDataFromParams)
|
|
83
|
+
const model = new ModelClass({
|
|
84
|
+
isNewRecord: true,
|
|
85
|
+
data: {a: modelData}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
s.set({model})
|
|
89
|
+
}, [])
|
|
90
|
+
|
|
91
|
+
const loadModel = useCallback(async () => {
|
|
92
|
+
if (!s.m.active) {
|
|
93
|
+
// Not active - don't do anything
|
|
94
|
+
} else if (s.props.newIfNoId && !s.m.modelId) {
|
|
95
|
+
return await loadNewModel()
|
|
96
|
+
} else if (!s.props.optional || s.m.modelId | s.m.args.query) {
|
|
97
|
+
return await loadExistingModel()
|
|
98
|
+
}
|
|
99
|
+
}, [])
|
|
100
|
+
|
|
101
|
+
const onDestroyed = useCallback(({model}) => {
|
|
102
|
+
const forwardArgs = {model}
|
|
103
|
+
|
|
104
|
+
forwardArgs[s.m.modelVariableName] = model
|
|
105
|
+
|
|
106
|
+
s.p.onDestroyed(forwardArgs)
|
|
107
|
+
}, [])
|
|
108
|
+
|
|
109
|
+
const onSignedIn = useCallback(() => {
|
|
110
|
+
loadModel()
|
|
111
|
+
}, [])
|
|
112
|
+
|
|
113
|
+
const onSignedOut = useCallback(() => {
|
|
114
|
+
loadModel()
|
|
115
|
+
}, [])
|
|
116
|
+
|
|
117
|
+
if (args.cacheArgs) {
|
|
118
|
+
cacheArgs.push(...args.cacheArgs)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
s.updateMeta({args, modelId, modelVariableName, queryParams})
|
|
122
|
+
|
|
123
|
+
useMemo(
|
|
124
|
+
() => { loadModel() },
|
|
125
|
+
cacheArgs
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
useLayoutEffect(() => {
|
|
129
|
+
let reloadModelCallback
|
|
130
|
+
|
|
131
|
+
if (args.events) {
|
|
132
|
+
reloadModelCallback = args.events.addListener("reloadModel", loadModel)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return () => {
|
|
136
|
+
if (reloadModelCallback) {
|
|
137
|
+
args.events.removeListener("reloadModel", loadModel)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}, [args.events])
|
|
141
|
+
|
|
142
|
+
useLayoutEffect(() => {
|
|
143
|
+
let connectUpdated
|
|
144
|
+
|
|
145
|
+
if (s.s.model && args.eventUpdated) {
|
|
146
|
+
connectUpdated = ModelEvents.connectUpdated(s.s.model, loadModel)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return () => {
|
|
150
|
+
connectUpdated?.unsubscribe()
|
|
151
|
+
}
|
|
152
|
+
}, [args.eventUpdated, s.s.model?.id()])
|
|
153
|
+
|
|
154
|
+
useLayoutEffect(() => {
|
|
155
|
+
Devise.events().addListener("onDeviseSignIn", onSignedIn)
|
|
156
|
+
Devise.events().addListener("onDeviseSignOut", onSignedOut)
|
|
157
|
+
|
|
158
|
+
return () => {
|
|
159
|
+
Devise.events().removeListener("onDeviseSignIn", onSignedIn)
|
|
160
|
+
Devise.events().removeListener("onDeviseSignOut", onSignedOut)
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
useLayoutEffect(() => {
|
|
165
|
+
let connectDestroyed
|
|
166
|
+
|
|
167
|
+
if (s.s.model && args.onDestroyed) {
|
|
168
|
+
connectDestroyed = ModelEvents.connectDestroyed(s.s.model, onDestroyed)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return () => {
|
|
172
|
+
connectDestroyed?.unsubscribe()
|
|
173
|
+
}
|
|
174
|
+
}, [args.onDestroyed, s.s.model?.id()])
|
|
175
|
+
|
|
176
|
+
const result = {
|
|
177
|
+
model: s.s.model,
|
|
178
|
+
modelId,
|
|
179
|
+
notFound: s.s.notFound
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
result[modelVariableName] = s.s.model
|
|
183
|
+
result[`${modelVariableName}Id`] = modelId
|
|
184
|
+
result[`${modelVariableName}NotFound`] = s.s.notFound
|
|
185
|
+
|
|
186
|
+
return result
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export default useModel
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {useCallback, useLayoutEffect, useMemo} from "react"
|
|
2
|
+
import useShape from "set-state-compare/src/use-shape"
|
|
3
|
+
|
|
4
|
+
const useResizeObserver = (element, callback) => {
|
|
5
|
+
const s = useShape({callback})
|
|
6
|
+
const onResize = useCallback((...args) => {
|
|
7
|
+
s.p.callback(...args)
|
|
8
|
+
}, [])
|
|
9
|
+
const observer = useMemo(() => new ResizeObserver(onResize), [])
|
|
10
|
+
|
|
11
|
+
useLayoutEffect(() => {
|
|
12
|
+
if (element) {
|
|
13
|
+
observer.observe(element)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return () => {
|
|
17
|
+
if (element) {
|
|
18
|
+
observer.disconnect()
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}, [element])
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default useResizeObserver
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import config from "./config"
|
|
2
|
+
import escapeStringRegexp from "escape-string-regexp"
|
|
3
|
+
import * as inflection from "inflection"
|
|
4
|
+
import PropTypes from "prop-types"
|
|
5
|
+
import propTypesExact from "prop-types-exact"
|
|
6
|
+
import {useCallback, useMemo} from "react"
|
|
7
|
+
import useShape from "set-state-compare/src/use-shape"
|
|
8
|
+
|
|
9
|
+
const useRouterPropTypes = propTypesExact({
|
|
10
|
+
locales: PropTypes.array.isRequired,
|
|
11
|
+
path: PropTypes.string,
|
|
12
|
+
routeDefinitions: PropTypes.object.isRequired,
|
|
13
|
+
routes: PropTypes.object.isRequired
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const useRouter = (props) => {
|
|
17
|
+
PropTypes.checkPropTypes(useRouterPropTypes, props, "prop", "useRouter")
|
|
18
|
+
|
|
19
|
+
const s = useShape(props)
|
|
20
|
+
|
|
21
|
+
const findRouteParams = useCallback((routeDefinition) => {
|
|
22
|
+
const result = []
|
|
23
|
+
const parts = routeDefinition.path.split("/")
|
|
24
|
+
|
|
25
|
+
for (const part of parts) {
|
|
26
|
+
if (part.match(/^:([a-z_]+)$/))
|
|
27
|
+
result.push(part)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return result
|
|
31
|
+
}, [])
|
|
32
|
+
|
|
33
|
+
const getPath = useCallback(() => {
|
|
34
|
+
let path = s.p.path || window.location.pathname
|
|
35
|
+
|
|
36
|
+
path = path.replace(/[/]+$/, "")
|
|
37
|
+
|
|
38
|
+
return path
|
|
39
|
+
}, [])
|
|
40
|
+
|
|
41
|
+
const getRouteDefinitions = useCallback(() => s.p.routeDefinitions || config.getRouteDefinitions(), [])
|
|
42
|
+
const getRoutes = useCallback(() => s.p.routes || config.getRoutes(), [])
|
|
43
|
+
|
|
44
|
+
const parseRouteDefinitions = useCallback(() => {
|
|
45
|
+
const routeDefinitions = getRouteDefinitions()
|
|
46
|
+
const routes = getRoutes()
|
|
47
|
+
const regex = /:([A-z\d_]+)/
|
|
48
|
+
const parsedRouteDefinitions = []
|
|
49
|
+
|
|
50
|
+
for (const locale of s.p.locales) {
|
|
51
|
+
for (const routeDefinition of routeDefinitions.routes) {
|
|
52
|
+
const routePathName = `${inflection.camelize(routeDefinition.name, true)}Path`
|
|
53
|
+
const params = findRouteParams(routeDefinition)
|
|
54
|
+
|
|
55
|
+
params.push({locale})
|
|
56
|
+
|
|
57
|
+
if (!(routePathName in routes))
|
|
58
|
+
throw new Error(`${routePathName} not found in routes: ${Object.keys(routes, ", ")}`)
|
|
59
|
+
|
|
60
|
+
const routePath = routes[routePathName](...params).replace(/[/]+$/, "")
|
|
61
|
+
const groups = []
|
|
62
|
+
let pathRegexString = "^"
|
|
63
|
+
|
|
64
|
+
pathRegexString += escapeStringRegexp(routePath)
|
|
65
|
+
|
|
66
|
+
while (true) {
|
|
67
|
+
const match = pathRegexString.match(regex)
|
|
68
|
+
|
|
69
|
+
if (!match) break
|
|
70
|
+
|
|
71
|
+
const variableName = match[1]
|
|
72
|
+
|
|
73
|
+
groups.push(variableName)
|
|
74
|
+
|
|
75
|
+
pathRegexString = pathRegexString.replace(match[0], "([^/]+)")
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
pathRegexString += "$"
|
|
79
|
+
|
|
80
|
+
const pathRegex = new RegExp(pathRegexString)
|
|
81
|
+
|
|
82
|
+
parsedRouteDefinitions.push({groups, pathRegex, routeDefinition})
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return parsedRouteDefinitions
|
|
87
|
+
}, [])
|
|
88
|
+
|
|
89
|
+
const parsedRouteDefinitions = useMemo(() => parseRouteDefinitions(), [])
|
|
90
|
+
|
|
91
|
+
s.updateMeta({parsedRouteDefinitions})
|
|
92
|
+
|
|
93
|
+
const findMatchingRoute = useCallback(() => {
|
|
94
|
+
const path = getPath()
|
|
95
|
+
|
|
96
|
+
for (const parsedRouteDefinition of s.m.parsedRouteDefinitions) {
|
|
97
|
+
const match = path.match(parsedRouteDefinition.pathRegex)
|
|
98
|
+
let matched, params
|
|
99
|
+
|
|
100
|
+
if (match) {
|
|
101
|
+
matched = true
|
|
102
|
+
params = {}
|
|
103
|
+
|
|
104
|
+
for (const groupKey in parsedRouteDefinition.groups) {
|
|
105
|
+
const groupName = parsedRouteDefinition.groups[groupKey]
|
|
106
|
+
|
|
107
|
+
params[groupName] = match[Number(groupKey) + 1]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (path == "" && parsedRouteDefinition.routeDefinition.path == "/") matched = true
|
|
112
|
+
if (matched) {
|
|
113
|
+
return {params, parsedRouteDefinition}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}, [])
|
|
117
|
+
|
|
118
|
+
const matchingRoute = findMatchingRoute()
|
|
119
|
+
const params = matchingRoute?.params || {}
|
|
120
|
+
const match = {
|
|
121
|
+
matchingRoute,
|
|
122
|
+
params
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return {match}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export default useRouter
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {Platform, useWindowDimensions} from "react-native"
|
|
2
|
+
|
|
3
|
+
const getWindowLayout = (width) => {
|
|
4
|
+
if (width <= 575) {
|
|
5
|
+
return "xs"
|
|
6
|
+
} else if (width <= 767) {
|
|
7
|
+
return "sm"
|
|
8
|
+
} else if (width <= 991) {
|
|
9
|
+
return "md"
|
|
10
|
+
} else if (width <= 1199) {
|
|
11
|
+
return "lg"
|
|
12
|
+
} else if (width <= 1399) {
|
|
13
|
+
return "xl"
|
|
14
|
+
} else if (width >= 1400) {
|
|
15
|
+
return "xxl"
|
|
16
|
+
} else {
|
|
17
|
+
console.error(`Couldn't determine window layout from width: ${width}`)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const useScreenLayout = () => {
|
|
22
|
+
if (Platform.OS == "web") {
|
|
23
|
+
const shared = useMemo(() => ({}))
|
|
24
|
+
|
|
25
|
+
shared.width = window.innerWidth
|
|
26
|
+
|
|
27
|
+
const [screenLayout, setScreenLayout] = useState(() => getWindowLayout(shared.width))
|
|
28
|
+
|
|
29
|
+
const onResize = useCallback(() => {
|
|
30
|
+
const newWindowLayout = getWindowLayout(window.innerWidth)
|
|
31
|
+
|
|
32
|
+
if (shared.screenlayout != newWindowLayout) {
|
|
33
|
+
setScreenLayout(newWindowLayout)
|
|
34
|
+
}
|
|
35
|
+
}, [])
|
|
36
|
+
|
|
37
|
+
useEventListener(window, "resize", onResize)
|
|
38
|
+
|
|
39
|
+
shared.screenLayout = screenLayout
|
|
40
|
+
|
|
41
|
+
return shared.screenLayout
|
|
42
|
+
} else {
|
|
43
|
+
const windowDimensions = useWindowDimensions()
|
|
44
|
+
|
|
45
|
+
return getWindowLayout(windowDimensions.width)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export default useScreenLayout
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import config from "./config"
|
|
2
|
+
import {digg} from "diggerize"
|
|
3
|
+
import * as inflection from "inflection"
|
|
4
|
+
import useBreakpoint from "./use-breakpoint"
|
|
5
|
+
import {useMemo} from "react"
|
|
6
|
+
|
|
7
|
+
const useStyles = (styles, args, dependencies = []) => {
|
|
8
|
+
const breakpoint = useBreakpoint()
|
|
9
|
+
const breakpointName = digg(breakpoint, "name")
|
|
10
|
+
const actualDependencies = [...dependencies, breakpointName]
|
|
11
|
+
|
|
12
|
+
const listOfStyles = useMemo(() => {
|
|
13
|
+
const listOfStyles = []
|
|
14
|
+
const breakpointsReverse = [...config.getBreakPoints()].reverse()
|
|
15
|
+
|
|
16
|
+
for (const arg of args) {
|
|
17
|
+
if (typeof arg == "string") {
|
|
18
|
+
if (!(arg in styles)) {
|
|
19
|
+
throw new Error(`No such styling '${arg}' in given styles: ${Object.keys(styles).join(", ")}`)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
listOfStyles.push(styles[arg])
|
|
23
|
+
|
|
24
|
+
for (const breakpointData of breakpointsReverse) {
|
|
25
|
+
const breakpointName = breakpointData[0]
|
|
26
|
+
const breakpointStyleNameUp = `${arg}${inflection.camelize(breakpointName)}Up`
|
|
27
|
+
const breakpointStyleNameDown = `${arg}${inflection.camelize(breakpointName)}Down`
|
|
28
|
+
const breakpointIsUp = digg(breakpoint, `${breakpointName}Up`)
|
|
29
|
+
const breakpointIsDown = digg(breakpoint, `${breakpointName}Down`)
|
|
30
|
+
|
|
31
|
+
if (breakpointStyleNameUp in styles && breakpointIsUp) {
|
|
32
|
+
listOfStyles.push(styles[breakpointStyleNameUp])
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (breakpointStyleNameDown in styles && breakpointIsDown) {
|
|
36
|
+
listOfStyles.push(styles[breakpointStyleNameDown])
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
throw new Error(`Unhandled type: ${typeof arg}`)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return listOfStyles
|
|
45
|
+
}, actualDependencies)
|
|
46
|
+
|
|
47
|
+
return listOfStyles
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default useStyles
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {useCallback, useLayoutEffect, useMemo} from "react"
|
|
2
|
+
import debounceFunction from "debounce"
|
|
3
|
+
import ModelEvents from "./model-events"
|
|
4
|
+
import useShape from "set-state-compare/src/use-shape"
|
|
5
|
+
|
|
6
|
+
const apiMakerUseUpdatedEvent = (model, onUpdated, props = {}) => {
|
|
7
|
+
const {active = true, debounce, onConnected, ...restProps} = props
|
|
8
|
+
|
|
9
|
+
if (Object.keys(restProps).length > 0) {
|
|
10
|
+
throw new Error(`Unknown props given to useUpdatedEvent: ${Object.keys(restProps).join(", ")}`)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const s = useShape({active, debounce, model, onUpdated})
|
|
14
|
+
|
|
15
|
+
const debounceCallback = useMemo(() => {
|
|
16
|
+
if (typeof debounce == "number") {
|
|
17
|
+
return debounceFunction(s.p.onUpdated, debounce)
|
|
18
|
+
} else {
|
|
19
|
+
return debounceFunction(s.p.onUpdated)
|
|
20
|
+
}
|
|
21
|
+
}, [debounce])
|
|
22
|
+
|
|
23
|
+
s.updateMeta({debounceCallback})
|
|
24
|
+
|
|
25
|
+
const onUpdatedCallback = useCallback((...args) => {
|
|
26
|
+
if (!s.p.active) {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (s.p.debounce) {
|
|
31
|
+
s.m.debounceCallback(...args)
|
|
32
|
+
} else {
|
|
33
|
+
s.p.onUpdated(...args)
|
|
34
|
+
}
|
|
35
|
+
}, [])
|
|
36
|
+
|
|
37
|
+
useLayoutEffect(() => {
|
|
38
|
+
let connectUpdated, onConnectedListener
|
|
39
|
+
|
|
40
|
+
if (model) {
|
|
41
|
+
connectUpdated = ModelEvents.connectUpdated(model, onUpdatedCallback)
|
|
42
|
+
|
|
43
|
+
if (onConnected) {
|
|
44
|
+
onConnectedListener = connectUpdated.events.addListener("connected", onConnected)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return () => {
|
|
49
|
+
if (onConnectedListener) {
|
|
50
|
+
connectUpdated.events.removeListener("connected", onConnected)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (connectUpdated) {
|
|
54
|
+
connectUpdated.unsubscribe()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}, [model?.id()])
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default apiMakerUseUpdatedEvent
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import events from "./events"
|
|
2
|
+
import {useCallback} from "react"
|
|
3
|
+
import useEventEmitter from "./use-event-emitter"
|
|
4
|
+
import useShape from "set-state-compare/src/use-shape"
|
|
5
|
+
|
|
6
|
+
const useValidationErrors = (callback) => {
|
|
7
|
+
const s = useShape({callback})
|
|
8
|
+
|
|
9
|
+
s.useStates({validationErrors: []})
|
|
10
|
+
|
|
11
|
+
const onValidationErrors = useCallback((validationErrors) => {
|
|
12
|
+
const matchedValidationErrors = []
|
|
13
|
+
|
|
14
|
+
for (const validationError of validationErrors.getValidationErrors()) {
|
|
15
|
+
if (s.p.callback(validationError)) {
|
|
16
|
+
validationError.setHandled()
|
|
17
|
+
matchedValidationErrors.push(validationError)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
s.set({
|
|
22
|
+
validationErrors: matchedValidationErrors
|
|
23
|
+
})
|
|
24
|
+
}, [])
|
|
25
|
+
|
|
26
|
+
useEventEmitter(events, "onValidationErrors", onValidationErrors)
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
validationErrors: s.s.validationErrors
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default useValidationErrors
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import BaseComponent from "../base-component"
|
|
2
|
+
import memo from "set-state-compare/src/memo"
|
|
3
|
+
import PropTypes from "prop-types"
|
|
4
|
+
import propTypesExact from "prop-types-exact"
|
|
5
|
+
import {shapeComponent} from "set-state-compare/src/shape-component"
|
|
6
|
+
import Text from "./text"
|
|
7
|
+
|
|
8
|
+
export default memo(shapeComponent(class ApiMakerUtilsCard extends BaseComponent {
|
|
9
|
+
static propTypes = propTypesExact({
|
|
10
|
+
children: PropTypes.node,
|
|
11
|
+
controls: PropTypes.node,
|
|
12
|
+
dataSet: PropTypes.object,
|
|
13
|
+
header: PropTypes.string,
|
|
14
|
+
style: PropTypes.object
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
render() {
|
|
18
|
+
const {children, controls, dataSet, header, style} = this.props
|
|
19
|
+
const {component, ...restDataSet} = dataSet || {}
|
|
20
|
+
const actualDataSet = Object.assign(
|
|
21
|
+
{component: classNames("api-maker/utils/card", component)},
|
|
22
|
+
restDataSet
|
|
23
|
+
)
|
|
24
|
+
const actualStyle = Object.assign(
|
|
25
|
+
{
|
|
26
|
+
backgroundColor: "#fff",
|
|
27
|
+
borderRadius: 15,
|
|
28
|
+
padding: 30
|
|
29
|
+
},
|
|
30
|
+
style
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<View dataSet={actualDataSet} style={actualStyle}>
|
|
35
|
+
{controls &&
|
|
36
|
+
<View style={{position: "absolute", top: 15, right: 15}}>
|
|
37
|
+
{controls}
|
|
38
|
+
</View>
|
|
39
|
+
}
|
|
40
|
+
{header &&
|
|
41
|
+
<Text style={{fontSize: 24}}>
|
|
42
|
+
{header}
|
|
43
|
+
</Text>
|
|
44
|
+
}
|
|
45
|
+
{children}
|
|
46
|
+
</View>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
}))
|