From caeb9fa0a379e3729e6a21bcea22a9f77396f203 Mon Sep 17 00:00:00 2001 From: Gimmy <975402925@qq.com> Date: Tue, 11 Feb 2025 11:43:32 +0800 Subject: [PATCH] chore: mobile project migrate --- examples/docs/package.json | 1 - examples/nuxt/playground/package.json | 1 - internals/cli/src/config/vite.ts | 1 - packages/mobile/LICENSE | 22 - packages/mobile/common/index.ts | 368 --- packages/mobile/common/src/adapter/index.ts | 495 --- .../mobile/common/src/adapter/teleport.ts | 209 -- packages/mobile/common/src/adapter/utils.ts | 120 - .../mobile/common/src/adapter/vue3/index.ts | 496 --- packages/mobile/common/src/breakpoint.ts | 51 - packages/mobile/common/src/csscls.ts | 88 - packages/mobile/common/src/usedefer.ts | 41 - .../mobile/components/action-sheet/index.ts | 19 - .../action-sheet/src/action-sheet.ts | 115 - .../components/action-sheet/src/mobile.vue | 68 - .../action-sheet/src/renderless/index.ts | 135 - .../action-sheet/src/renderless/vue.ts | 92 - packages/mobile/components/alert/index.ts | 19 - packages/mobile/components/alert/src/alert.ts | 126 - .../mobile/components/alert/src/mobile.vue | 50 - .../components/alert/src/renderless/index.ts | 117 - .../components/alert/src/renderless/vue.ts | 78 - packages/mobile/components/avatar/index.ts | 19 - .../mobile/components/avatar/src/mobile.vue | 96 - .../components/avatar/src/renderless/index.ts | 45 - .../components/avatar/src/renderless/vue.ts | 34 - packages/mobile/components/badge/index.ts | 19 - packages/mobile/components/badge/src/badge.ts | 78 - .../mobile/components/badge/src/mobile.vue | 51 - .../components/badge/src/renderless/index.ts | 46 - .../components/badge/src/renderless/vue.ts | 40 - packages/mobile/components/button/index.ts | 19 - .../mobile/components/button/src/button.ts | 89 - .../mobile/components/button/src/mobile.vue | 59 - .../components/button/src/renderless/index.ts | 33 - .../components/button/src/renderless/vue.ts | 52 - .../mobile/components/checkbox-group/index.ts | 19 - .../checkbox-group/src/checkbox-group.ts | 47 - .../components/checkbox-group/src/mobile.vue | 46 - .../checkbox-group/src/renderless/index.ts | 18 - .../checkbox-group/src/renderless/vue.ts | 46 - packages/mobile/components/checkbox/index.ts | 19 - .../components/checkbox/src/checkbox.ts | 168 - .../mobile/components/checkbox/src/mobile.vue | 80 - .../checkbox/src/renderless/index.ts | 242 -- .../components/checkbox/src/renderless/vue.ts | 160 - packages/mobile/components/container/index.ts | 19 - .../components/container/src/container.ts | 52 - .../components/container/src/mobile.vue | 38 - .../container/src/renderless/index.ts | 140 - .../container/src/renderless/vue.ts | 58 - .../mobile/components/date-picker/index.ts | 19 - .../components/date-picker/src/date-picker.ts | 267 -- .../components/date-picker/src/mobile.vue | 55 - .../date-picker/src/renderless/index.ts | 354 --- .../date-picker/src/renderless/vue.ts | 151 - .../mobile/components/dialog-box/index.ts | 18 - .../components/dialog-box/src/dialog-box.ts | 234 -- .../components/dialog-box/src/mobile.vue | 56 - .../dialog-box/src/renderless/index.ts | 365 --- .../dialog-box/src/renderless/vue.ts | 220 -- .../mobile/components/dropdown-item/index.ts | 19 - .../dropdown-item/src/dropdown-item.ts | 205 -- .../components/dropdown-item/src/mobile.vue | 134 - .../dropdown-item/src/renderless/index.ts | 195 -- .../dropdown-item/src/renderless/vue.ts | 142 - .../mobile/components/dropdown-menu/index.ts | 19 - .../dropdown-menu/src/dropdown-menu.ts | 138 - .../components/dropdown-menu/src/mobile.vue | 93 - .../dropdown-menu/src/renderless/index.ts | 211 -- .../dropdown-menu/src/renderless/vue.ts | 86 - packages/mobile/components/exception/index.ts | 19 - .../components/exception/src/exception.ts | 19 - .../components/exception/src/mobile.vue | 56 - .../exception/src/renderless/index.ts | 13 - .../exception/src/renderless/vue.ts | 28 - .../mobile/components/file-upload/index.ts | 19 - .../components/file-upload/src/file-upload.ts | 632 ---- .../components/file-upload/src/mobile.vue | 151 - .../file-upload/src/renderless/index.ts | 2748 ----------------- .../file-upload/src/renderless/vue.ts | 370 --- packages/mobile/components/form-item/index.ts | 19 - .../components/form-item/src/form-item.ts | 208 -- .../components/form-item/src/label-wrap.ts | 86 - .../components/form-item/src/mobile.vue | 229 -- .../form-item/src/renderless/index.ts | 539 ---- .../form-item/src/renderless/vue.ts | 192 -- packages/mobile/components/form/index.ts | 19 - packages/mobile/components/form/src/form.ts | 186 -- .../mobile/components/form/src/mobile.vue | 42 - .../components/form/src/renderless/index.ts | 279 -- .../components/form/src/renderless/vue.ts | 122 - .../mobile/components/image-viewer/index.ts | 19 - .../image-viewer/src/image-viewer.ts | 109 - .../components/image-viewer/src/mobile.vue | 147 - .../image-viewer/src/mobileTouch.ts | 119 - .../image-viewer/src/renderless/index.ts | 874 ------ .../image-viewer/src/renderless/vue.ts | 268 -- .../components/index-bar-anchor/index.ts | 19 - .../components/index-bar-anchor/src/index.vue | 34 - .../index-bar-anchor/src/renderless/vue.ts | 26 - packages/mobile/components/index-bar/index.ts | 19 - .../components/index-bar/src/mobile.vue | 54 - .../index-bar/src/renderless/index.ts | 86 - .../index-bar/src/renderless/vue.ts | 94 - packages/mobile/components/input/index.ts | 19 - packages/mobile/components/input/src/input.ts | 241 -- .../mobile/components/input/src/mobile.vue | 208 -- .../components/input/src/renderless/index.ts | 528 ---- .../src/renderless/tall-storage/index.ts | 179 -- .../tall-storage/vue-storage-box.ts | 27 - .../components/input/src/renderless/vue.ts | 396 --- packages/mobile/components/label/index.ts | 19 - packages/mobile/components/label/src/label.ts | 89 - .../mobile/components/label/src/mobile.vue | 32 - .../components/label/src/renderless/index.ts | 78 - .../components/label/src/renderless/vue.ts | 48 - packages/mobile/components/list/index.ts | 19 - .../mobile/components/list/src/mobile.vue | 70 - .../components/list/src/renderless/index.ts | 24 - .../components/list/src/renderless/vue.ts | 28 - packages/mobile/components/loading/index.ts | 31 - .../components/loading/src/directive.ts | 183 -- .../mobile/components/loading/src/loading.ts | 73 - .../mobile/components/loading/src/mobile.vue | 41 - .../loading/src/renderless/index.ts | 47 - .../components/loading/src/renderless/vue.ts | 53 - .../mobile/components/loading/src/service.ts | 136 - packages/mobile/components/mask/index.ts | 19 - .../mobile/components/mask/src/mobile.vue | 54 - .../components/mask/src/renderless/index.ts | 24 - .../components/mask/src/renderless/vue.ts | 29 - packages/mobile/components/message/index.ts | 14 - .../mobile/components/mini-picker/index.ts | 19 - .../components/mini-picker/src/mobile.vue | 111 - .../mini-picker/src/renderless/index.ts | 210 -- .../mini-picker/src/renderless/vue.ts | 141 - packages/mobile/components/modal/index.ts | 138 - .../mobile/components/modal/src/mobile.vue | 185 -- packages/mobile/components/modal/src/modal.ts | 265 -- .../components/modal/src/renderless/index.ts | 916 ------ .../components/modal/src/renderless/vue.ts | 139 - .../components/multi-select-item/index.ts | 18 - .../multi-select-item/src/mobile.vue | 71 - .../src/multi-select-item.ts | 24 - .../multi-select-item/src/renderless/index.ts | 37 - .../multi-select-item/src/renderless/vue.ts | 42 - .../mobile/components/multi-select/index.ts | 18 - .../components/multi-select/src/mobile.vue | 191 -- .../multi-select/src/multi-select.ts | 55 - .../multi-select/src/renderless/index.ts | 461 --- .../multi-select/src/renderless/vue.ts | 136 - packages/mobile/components/nav-bar/index.ts | 20 - .../mobile/components/nav-bar/src/mobile.vue | 91 - packages/mobile/components/numeric/index.ts | 19 - .../mobile/components/numeric/src/mobile.vue | 96 - .../mobile/components/numeric/src/numeric.ts | 283 -- .../numeric/src/renderless/index.ts | 534 ---- .../components/numeric/src/renderless/vue.ts | 203 -- .../mobile/components/picker-column/index.ts | 19 - .../components/picker-column/src/mobile.vue | 57 - .../picker-column/src/renderless/index.ts | 294 -- .../picker-column/src/renderless/vue.ts | 124 - packages/mobile/components/popover/index.ts | 19 - .../mobile/components/popover/src/mobile.vue | 67 - .../mobile/components/popover/src/popover.ts | 153 - .../popover/src/renderless/index.ts | 280 -- .../components/popover/src/renderless/vue.ts | 205 -- packages/mobile/components/popup/index.ts | 19 - .../mobile/components/popup/src/mobile.vue | 117 - .../components/popup/src/renderless/index.ts | 141 - .../components/popup/src/renderless/vue.ts | 84 - packages/mobile/components/progress/index.ts | 19 - .../mobile/components/progress/src/mobile.vue | 90 - .../components/progress/src/progress.ts | 190 -- .../progress/src/renderless/index.ts | 238 -- .../components/progress/src/renderless/vue.ts | 108 - .../mobile/components/pull-refresh/index.ts | 19 - .../components/pull-refresh/src/mobile.vue | 76 - .../pull-refresh/src/pull-refresh.ts | 56 - .../pull-refresh/src/renderless/index.ts | 158 - .../pull-refresh/src/renderless/vue.ts | 90 - .../mobile/components/radio-group/index.ts | 19 - .../components/radio-group/src/mobile.vue | 46 - .../components/radio-group/src/radio-group.ts | 71 - .../radio-group/src/renderless/index.ts | 65 - .../radio-group/src/renderless/vue.ts | 62 - packages/mobile/components/radio/index.ts | 19 - .../mobile/components/radio/src/mobile.vue | 61 - packages/mobile/components/radio/src/radio.ts | 97 - .../components/radio/src/renderless/index.ts | 105 - .../components/radio/src/renderless/vue.ts | 82 - packages/mobile/components/search/index.ts | 19 - .../mobile/components/search/src/mobile.vue | 86 - .../components/search/src/renderless/index.ts | 148 - .../components/search/src/renderless/vue.ts | 126 - .../mobile/components/search/src/search.ts | 138 - packages/mobile/components/slider/index.ts | 18 - .../mobile/components/slider/src/mobile.vue | 75 - .../components/slider/src/renderless/index.ts | 642 ---- .../components/slider/src/renderless/vue.ts | 231 -- .../mobile/components/slider/src/slider.ts | 232 -- packages/mobile/components/switch/index.ts | 19 - .../mobile/components/switch/src/mobile.vue | 32 - .../components/switch/src/renderless/index.ts | 60 - .../components/switch/src/renderless/vue.ts | 69 - .../mobile/components/switch/src/switch.ts | 108 - packages/mobile/components/tab-item/index.ts | 19 - .../mobile/components/tab-item/src/mobile.vue | 41 - .../tab-item/src/renderless/index.ts | 42 - .../components/tab-item/src/renderless/vue.ts | 55 - .../components/tab-item/src/tab-item.ts | 55 - .../mobile/components/tabbar-item/index.ts | 19 - .../components/tabbar-item/src/mobile.vue | 47 - .../tabbar-item/src/renderless/index.ts | 69 - .../tabbar-item/src/renderless/vue.ts | 51 - .../components/tabbar-item/src/tabbar-item.ts | 15 - packages/mobile/components/tabbar/index.ts | 19 - .../mobile/components/tabbar/src/mobile.vue | 38 - .../components/tabbar/src/renderless/index.ts | 79 - .../components/tabbar/src/renderless/vue.ts | 84 - .../mobile/components/tabbar/src/tabbar.ts | 28 - packages/mobile/components/table/index.ts | 19 - .../mobile/components/table/src/mobile.vue | 129 - .../components/table/src/renderless/index.ts | 118 - .../components/table/src/renderless/vue.ts | 55 - packages/mobile/components/table/src/table.ts | 19 - packages/mobile/components/tabs/index.ts | 19 - .../mobile/components/tabs/src/mobile.vue | 149 - .../components/tabs/src/renderless/index.ts | 230 -- .../components/tabs/src/renderless/vue.ts | 148 - .../mobile/components/tabs/src/tab-nav/mb.vue | 188 -- .../tabs/src/tab-nav/renderless/index.ts | 449 --- .../tabs/src/tab-nav/renderless/vue.ts | 127 - .../components/tabs/src/tab-nav/tab-nav.ts | 137 - packages/mobile/components/tabs/src/tabs.ts | 157 - packages/mobile/components/tag/index.ts | 19 - packages/mobile/components/tag/src/mobile.vue | 36 - .../components/tag/src/renderless/index.ts | 33 - .../components/tag/src/renderless/vue.ts | 39 - packages/mobile/components/tag/src/tag.ts | 74 - packages/mobile/components/time-line/index.ts | 19 - .../components/time-line/src/mobile.vue | 99 - .../time-line/src/renderless/index.ts | 135 - .../time-line/src/renderless/vue.ts | 86 - .../components/time-line/src/time-line.ts | 175 -- packages/mobile/components/toast/index.ts | 19 - .../mobile/components/toast/src/mobile.vue | 31 - .../components/toast/src/renderless/index.ts | 17 - .../components/toast/src/renderless/vue.ts | 31 - .../mobile/components/toast/src/service.ts | 46 - packages/mobile/components/toast/src/toast.ts | 59 - packages/mobile/components/tooltip/index.ts | 19 - .../mobile/components/tooltip/src/mobile.vue | 172 -- .../tooltip/src/renderless/index.ts | 247 -- .../components/tooltip/src/renderless/vue.ts | 136 - .../mobile/components/tooltip/src/tooltip.ts | 153 - .../mobile/components/upload-list/index.ts | 19 - .../components/upload-list/src/mobile.vue | 375 --- .../upload-list/src/renderless/index.ts | 321 -- .../upload-list/src/renderless/vue.ts | 147 - .../components/upload-list/src/upload-list.ts | 184 -- packages/mobile/components/upload/index.ts | 19 - .../mobile/components/upload/src/mobile.vue | 87 - .../components/upload/src/renderless/index.ts | 488 --- .../components/upload/src/renderless/vue.ts | 109 - .../mobile/components/upload/src/upload.ts | 194 -- packages/mobile/components/user-head/index.ts | 19 - .../components/user-head/src/mobile.vue | 55 - .../user-head/src/renderless/index.ts | 99 - .../user-head/src/renderless/vue.ts | 62 - .../components/user-head/src/user-head.ts | 140 - packages/mobile/components/wheel/index.ts | 18 - .../mobile/components/wheel/src/mobile.vue | 82 - .../components/wheel/src/renderless/index.ts | 222 -- .../components/wheel/src/renderless/vue.ts | 96 - packages/mobile/index.ts | 158 - packages/mobile/package.json | 55 - packages/mobile/shared.type.ts | 186 -- packages/mobile/tsconfig.json | 38 - packages/mobile/tsconfig.node.json | 10 - packages/mobile/utils/array.ts | 240 -- packages/mobile/utils/bigInt.ts | 419 --- packages/mobile/utils/browser.ts | 98 - packages/mobile/utils/calendar/calendar.ts | 158 - packages/mobile/utils/dataset/index.ts | 142 - packages/mobile/utils/date.ts | 537 ---- packages/mobile/utils/decimal.ts | 261 -- packages/mobile/utils/deps/ResizeObserver.ts | 607 ---- packages/mobile/utils/deps/after-leave.ts | 42 - packages/mobile/utils/deps/clickoutside.ts | 101 - packages/mobile/utils/deps/date-util.ts | 310 -- packages/mobile/utils/deps/date.ts | 342 -- packages/mobile/utils/deps/debounce.ts | 17 - packages/mobile/utils/deps/dom.ts | 295 -- packages/mobile/utils/deps/eSpaceCtrl.ts | 417 --- packages/mobile/utils/deps/fastdom/async.ts | 59 - packages/mobile/utils/deps/fastdom/index.ts | 16 - packages/mobile/utils/deps/fastdom/sandbox.ts | 75 - .../mobile/utils/deps/fastdom/singleton.ts | 109 - packages/mobile/utils/deps/fullscreen/apis.ts | 197 -- .../utils/deps/fullscreen/screenfull.ts | 170 - packages/mobile/utils/deps/infinite-scroll.ts | 223 -- packages/mobile/utils/deps/letter-only.ts | 38 - packages/mobile/utils/deps/memorize.ts | 162 - packages/mobile/utils/deps/number-only.ts | 40 - .../mobile/utils/deps/observe-visibility.ts | 130 - packages/mobile/utils/deps/popper.ts | 883 ------ packages/mobile/utils/deps/popup-manager.ts | 262 -- packages/mobile/utils/deps/repeat-click.ts | 45 - packages/mobile/utils/deps/resize-event.ts | 58 - .../mobile/utils/deps/scroll-into-view.ts | 43 - packages/mobile/utils/deps/scrollbar-width.ts | 50 - packages/mobile/utils/deps/throttle.ts | 79 - packages/mobile/utils/deps/touch-emulator.ts | 122 - packages/mobile/utils/deps/touch.ts | 51 - packages/mobile/utils/deps/tree-model/node.ts | 625 ---- .../utils/deps/tree-model/tree-store.ts | 396 --- packages/mobile/utils/deps/tree-model/util.ts | 33 - packages/mobile/utils/deps/upload-ajax.ts | 113 - .../mobile/utils/deps/useEventListener.ts | 59 - packages/mobile/utils/deps/useRect.ts | 25 - packages/mobile/utils/deps/useTouch.ts | 74 - packages/mobile/utils/deps/vue-emitter.ts | 47 - packages/mobile/utils/deps/vue-popper.ts | 228 -- packages/mobile/utils/deps/vue-popup.ts | 196 -- packages/mobile/utils/event.ts | 61 - packages/mobile/utils/global.ts | 7 - packages/mobile/utils/index.ts | 269 -- packages/mobile/utils/object.ts | 445 --- packages/mobile/utils/runtime.ts | 96 - packages/mobile/utils/string.ts | 832 ----- packages/mobile/utils/type.ts | 164 - packages/mobile/utils/validate/index.ts | 20 - packages/mobile/utils/validate/messages.ts | 73 - packages/mobile/utils/validate/rules/enum.ts | 23 - packages/mobile/utils/validate/rules/index.ts | 27 - .../mobile/utils/validate/rules/pattern.ts | 31 - packages/mobile/utils/validate/rules/range.ts | 68 - .../mobile/utils/validate/rules/required.ts | 20 - packages/mobile/utils/validate/rules/type.ts | 129 - .../mobile/utils/validate/rules/whitespace.ts | 19 - packages/mobile/utils/validate/schema.ts | 398 --- packages/mobile/utils/validate/util.ts | 291 -- .../utils/validate/validations/array.ts | 35 - .../mobile/utils/validate/validations/date.ts | 47 - .../mobile/utils/validate/validations/enum.ts | 36 - .../utils/validate/validations/float.ts | 35 - .../utils/validate/validations/index.ts | 55 - .../utils/validate/validations/integer.ts | 35 - .../utils/validate/validations/method.ts | 34 - .../utils/validate/validations/number.ts | 39 - .../utils/validate/validations/pattern.ts | 34 - .../utils/validate/validations/required.ts | 21 - .../utils/validate/validations/string.ts | 47 - .../mobile/utils/validate/validations/type.ts | 42 - packages/mobile/utils/xss.ts | 204 -- packages/mobile/vite.config.ts | 38 - packages/vue-locale/package.json | 3 +- 359 files changed, 1 insertion(+), 47458 deletions(-) delete mode 100644 packages/mobile/LICENSE delete mode 100644 packages/mobile/common/index.ts delete mode 100644 packages/mobile/common/src/adapter/index.ts delete mode 100644 packages/mobile/common/src/adapter/teleport.ts delete mode 100644 packages/mobile/common/src/adapter/utils.ts delete mode 100644 packages/mobile/common/src/adapter/vue3/index.ts delete mode 100644 packages/mobile/common/src/breakpoint.ts delete mode 100644 packages/mobile/common/src/csscls.ts delete mode 100644 packages/mobile/common/src/usedefer.ts delete mode 100644 packages/mobile/components/action-sheet/index.ts delete mode 100644 packages/mobile/components/action-sheet/src/action-sheet.ts delete mode 100644 packages/mobile/components/action-sheet/src/mobile.vue delete mode 100644 packages/mobile/components/action-sheet/src/renderless/index.ts delete mode 100644 packages/mobile/components/action-sheet/src/renderless/vue.ts delete mode 100644 packages/mobile/components/alert/index.ts delete mode 100644 packages/mobile/components/alert/src/alert.ts delete mode 100644 packages/mobile/components/alert/src/mobile.vue delete mode 100644 packages/mobile/components/alert/src/renderless/index.ts delete mode 100644 packages/mobile/components/alert/src/renderless/vue.ts delete mode 100644 packages/mobile/components/avatar/index.ts delete mode 100644 packages/mobile/components/avatar/src/mobile.vue delete mode 100644 packages/mobile/components/avatar/src/renderless/index.ts delete mode 100644 packages/mobile/components/avatar/src/renderless/vue.ts delete mode 100644 packages/mobile/components/badge/index.ts delete mode 100644 packages/mobile/components/badge/src/badge.ts delete mode 100644 packages/mobile/components/badge/src/mobile.vue delete mode 100644 packages/mobile/components/badge/src/renderless/index.ts delete mode 100644 packages/mobile/components/badge/src/renderless/vue.ts delete mode 100644 packages/mobile/components/button/index.ts delete mode 100644 packages/mobile/components/button/src/button.ts delete mode 100644 packages/mobile/components/button/src/mobile.vue delete mode 100644 packages/mobile/components/button/src/renderless/index.ts delete mode 100644 packages/mobile/components/button/src/renderless/vue.ts delete mode 100644 packages/mobile/components/checkbox-group/index.ts delete mode 100644 packages/mobile/components/checkbox-group/src/checkbox-group.ts delete mode 100644 packages/mobile/components/checkbox-group/src/mobile.vue delete mode 100644 packages/mobile/components/checkbox-group/src/renderless/index.ts delete mode 100644 packages/mobile/components/checkbox-group/src/renderless/vue.ts delete mode 100644 packages/mobile/components/checkbox/index.ts delete mode 100644 packages/mobile/components/checkbox/src/checkbox.ts delete mode 100644 packages/mobile/components/checkbox/src/mobile.vue delete mode 100644 packages/mobile/components/checkbox/src/renderless/index.ts delete mode 100644 packages/mobile/components/checkbox/src/renderless/vue.ts delete mode 100644 packages/mobile/components/container/index.ts delete mode 100644 packages/mobile/components/container/src/container.ts delete mode 100644 packages/mobile/components/container/src/mobile.vue delete mode 100644 packages/mobile/components/container/src/renderless/index.ts delete mode 100644 packages/mobile/components/container/src/renderless/vue.ts delete mode 100644 packages/mobile/components/date-picker/index.ts delete mode 100644 packages/mobile/components/date-picker/src/date-picker.ts delete mode 100644 packages/mobile/components/date-picker/src/mobile.vue delete mode 100644 packages/mobile/components/date-picker/src/renderless/index.ts delete mode 100644 packages/mobile/components/date-picker/src/renderless/vue.ts delete mode 100644 packages/mobile/components/dialog-box/index.ts delete mode 100644 packages/mobile/components/dialog-box/src/dialog-box.ts delete mode 100644 packages/mobile/components/dialog-box/src/mobile.vue delete mode 100644 packages/mobile/components/dialog-box/src/renderless/index.ts delete mode 100644 packages/mobile/components/dialog-box/src/renderless/vue.ts delete mode 100644 packages/mobile/components/dropdown-item/index.ts delete mode 100644 packages/mobile/components/dropdown-item/src/dropdown-item.ts delete mode 100644 packages/mobile/components/dropdown-item/src/mobile.vue delete mode 100644 packages/mobile/components/dropdown-item/src/renderless/index.ts delete mode 100644 packages/mobile/components/dropdown-item/src/renderless/vue.ts delete mode 100644 packages/mobile/components/dropdown-menu/index.ts delete mode 100644 packages/mobile/components/dropdown-menu/src/dropdown-menu.ts delete mode 100644 packages/mobile/components/dropdown-menu/src/mobile.vue delete mode 100644 packages/mobile/components/dropdown-menu/src/renderless/index.ts delete mode 100644 packages/mobile/components/dropdown-menu/src/renderless/vue.ts delete mode 100644 packages/mobile/components/exception/index.ts delete mode 100644 packages/mobile/components/exception/src/exception.ts delete mode 100644 packages/mobile/components/exception/src/mobile.vue delete mode 100644 packages/mobile/components/exception/src/renderless/index.ts delete mode 100644 packages/mobile/components/exception/src/renderless/vue.ts delete mode 100644 packages/mobile/components/file-upload/index.ts delete mode 100644 packages/mobile/components/file-upload/src/file-upload.ts delete mode 100644 packages/mobile/components/file-upload/src/mobile.vue delete mode 100644 packages/mobile/components/file-upload/src/renderless/index.ts delete mode 100644 packages/mobile/components/file-upload/src/renderless/vue.ts delete mode 100644 packages/mobile/components/form-item/index.ts delete mode 100644 packages/mobile/components/form-item/src/form-item.ts delete mode 100644 packages/mobile/components/form-item/src/label-wrap.ts delete mode 100644 packages/mobile/components/form-item/src/mobile.vue delete mode 100644 packages/mobile/components/form-item/src/renderless/index.ts delete mode 100644 packages/mobile/components/form-item/src/renderless/vue.ts delete mode 100644 packages/mobile/components/form/index.ts delete mode 100644 packages/mobile/components/form/src/form.ts delete mode 100644 packages/mobile/components/form/src/mobile.vue delete mode 100644 packages/mobile/components/form/src/renderless/index.ts delete mode 100644 packages/mobile/components/form/src/renderless/vue.ts delete mode 100644 packages/mobile/components/image-viewer/index.ts delete mode 100644 packages/mobile/components/image-viewer/src/image-viewer.ts delete mode 100644 packages/mobile/components/image-viewer/src/mobile.vue delete mode 100644 packages/mobile/components/image-viewer/src/mobileTouch.ts delete mode 100644 packages/mobile/components/image-viewer/src/renderless/index.ts delete mode 100644 packages/mobile/components/image-viewer/src/renderless/vue.ts delete mode 100644 packages/mobile/components/index-bar-anchor/index.ts delete mode 100644 packages/mobile/components/index-bar-anchor/src/index.vue delete mode 100644 packages/mobile/components/index-bar-anchor/src/renderless/vue.ts delete mode 100644 packages/mobile/components/index-bar/index.ts delete mode 100644 packages/mobile/components/index-bar/src/mobile.vue delete mode 100644 packages/mobile/components/index-bar/src/renderless/index.ts delete mode 100644 packages/mobile/components/index-bar/src/renderless/vue.ts delete mode 100644 packages/mobile/components/input/index.ts delete mode 100644 packages/mobile/components/input/src/input.ts delete mode 100644 packages/mobile/components/input/src/mobile.vue delete mode 100644 packages/mobile/components/input/src/renderless/index.ts delete mode 100644 packages/mobile/components/input/src/renderless/tall-storage/index.ts delete mode 100644 packages/mobile/components/input/src/renderless/tall-storage/vue-storage-box.ts delete mode 100644 packages/mobile/components/input/src/renderless/vue.ts delete mode 100644 packages/mobile/components/label/index.ts delete mode 100644 packages/mobile/components/label/src/label.ts delete mode 100644 packages/mobile/components/label/src/mobile.vue delete mode 100644 packages/mobile/components/label/src/renderless/index.ts delete mode 100644 packages/mobile/components/label/src/renderless/vue.ts delete mode 100644 packages/mobile/components/list/index.ts delete mode 100644 packages/mobile/components/list/src/mobile.vue delete mode 100644 packages/mobile/components/list/src/renderless/index.ts delete mode 100644 packages/mobile/components/list/src/renderless/vue.ts delete mode 100644 packages/mobile/components/loading/index.ts delete mode 100644 packages/mobile/components/loading/src/directive.ts delete mode 100644 packages/mobile/components/loading/src/loading.ts delete mode 100644 packages/mobile/components/loading/src/mobile.vue delete mode 100644 packages/mobile/components/loading/src/renderless/index.ts delete mode 100644 packages/mobile/components/loading/src/renderless/vue.ts delete mode 100644 packages/mobile/components/loading/src/service.ts delete mode 100644 packages/mobile/components/mask/index.ts delete mode 100644 packages/mobile/components/mask/src/mobile.vue delete mode 100644 packages/mobile/components/mask/src/renderless/index.ts delete mode 100644 packages/mobile/components/mask/src/renderless/vue.ts delete mode 100644 packages/mobile/components/message/index.ts delete mode 100644 packages/mobile/components/mini-picker/index.ts delete mode 100644 packages/mobile/components/mini-picker/src/mobile.vue delete mode 100644 packages/mobile/components/mini-picker/src/renderless/index.ts delete mode 100644 packages/mobile/components/mini-picker/src/renderless/vue.ts delete mode 100644 packages/mobile/components/modal/index.ts delete mode 100644 packages/mobile/components/modal/src/mobile.vue delete mode 100644 packages/mobile/components/modal/src/modal.ts delete mode 100644 packages/mobile/components/modal/src/renderless/index.ts delete mode 100644 packages/mobile/components/modal/src/renderless/vue.ts delete mode 100644 packages/mobile/components/multi-select-item/index.ts delete mode 100644 packages/mobile/components/multi-select-item/src/mobile.vue delete mode 100644 packages/mobile/components/multi-select-item/src/multi-select-item.ts delete mode 100644 packages/mobile/components/multi-select-item/src/renderless/index.ts delete mode 100644 packages/mobile/components/multi-select-item/src/renderless/vue.ts delete mode 100644 packages/mobile/components/multi-select/index.ts delete mode 100644 packages/mobile/components/multi-select/src/mobile.vue delete mode 100644 packages/mobile/components/multi-select/src/multi-select.ts delete mode 100644 packages/mobile/components/multi-select/src/renderless/index.ts delete mode 100644 packages/mobile/components/multi-select/src/renderless/vue.ts delete mode 100644 packages/mobile/components/nav-bar/index.ts delete mode 100644 packages/mobile/components/nav-bar/src/mobile.vue delete mode 100644 packages/mobile/components/numeric/index.ts delete mode 100644 packages/mobile/components/numeric/src/mobile.vue delete mode 100644 packages/mobile/components/numeric/src/numeric.ts delete mode 100644 packages/mobile/components/numeric/src/renderless/index.ts delete mode 100644 packages/mobile/components/numeric/src/renderless/vue.ts delete mode 100644 packages/mobile/components/picker-column/index.ts delete mode 100644 packages/mobile/components/picker-column/src/mobile.vue delete mode 100644 packages/mobile/components/picker-column/src/renderless/index.ts delete mode 100644 packages/mobile/components/picker-column/src/renderless/vue.ts delete mode 100644 packages/mobile/components/popover/index.ts delete mode 100644 packages/mobile/components/popover/src/mobile.vue delete mode 100644 packages/mobile/components/popover/src/popover.ts delete mode 100644 packages/mobile/components/popover/src/renderless/index.ts delete mode 100644 packages/mobile/components/popover/src/renderless/vue.ts delete mode 100644 packages/mobile/components/popup/index.ts delete mode 100644 packages/mobile/components/popup/src/mobile.vue delete mode 100644 packages/mobile/components/popup/src/renderless/index.ts delete mode 100644 packages/mobile/components/popup/src/renderless/vue.ts delete mode 100644 packages/mobile/components/progress/index.ts delete mode 100644 packages/mobile/components/progress/src/mobile.vue delete mode 100644 packages/mobile/components/progress/src/progress.ts delete mode 100644 packages/mobile/components/progress/src/renderless/index.ts delete mode 100644 packages/mobile/components/progress/src/renderless/vue.ts delete mode 100644 packages/mobile/components/pull-refresh/index.ts delete mode 100644 packages/mobile/components/pull-refresh/src/mobile.vue delete mode 100644 packages/mobile/components/pull-refresh/src/pull-refresh.ts delete mode 100644 packages/mobile/components/pull-refresh/src/renderless/index.ts delete mode 100644 packages/mobile/components/pull-refresh/src/renderless/vue.ts delete mode 100644 packages/mobile/components/radio-group/index.ts delete mode 100644 packages/mobile/components/radio-group/src/mobile.vue delete mode 100644 packages/mobile/components/radio-group/src/radio-group.ts delete mode 100644 packages/mobile/components/radio-group/src/renderless/index.ts delete mode 100644 packages/mobile/components/radio-group/src/renderless/vue.ts delete mode 100644 packages/mobile/components/radio/index.ts delete mode 100644 packages/mobile/components/radio/src/mobile.vue delete mode 100644 packages/mobile/components/radio/src/radio.ts delete mode 100644 packages/mobile/components/radio/src/renderless/index.ts delete mode 100644 packages/mobile/components/radio/src/renderless/vue.ts delete mode 100644 packages/mobile/components/search/index.ts delete mode 100644 packages/mobile/components/search/src/mobile.vue delete mode 100644 packages/mobile/components/search/src/renderless/index.ts delete mode 100644 packages/mobile/components/search/src/renderless/vue.ts delete mode 100644 packages/mobile/components/search/src/search.ts delete mode 100644 packages/mobile/components/slider/index.ts delete mode 100644 packages/mobile/components/slider/src/mobile.vue delete mode 100644 packages/mobile/components/slider/src/renderless/index.ts delete mode 100644 packages/mobile/components/slider/src/renderless/vue.ts delete mode 100644 packages/mobile/components/slider/src/slider.ts delete mode 100644 packages/mobile/components/switch/index.ts delete mode 100644 packages/mobile/components/switch/src/mobile.vue delete mode 100644 packages/mobile/components/switch/src/renderless/index.ts delete mode 100644 packages/mobile/components/switch/src/renderless/vue.ts delete mode 100644 packages/mobile/components/switch/src/switch.ts delete mode 100644 packages/mobile/components/tab-item/index.ts delete mode 100644 packages/mobile/components/tab-item/src/mobile.vue delete mode 100644 packages/mobile/components/tab-item/src/renderless/index.ts delete mode 100644 packages/mobile/components/tab-item/src/renderless/vue.ts delete mode 100644 packages/mobile/components/tab-item/src/tab-item.ts delete mode 100644 packages/mobile/components/tabbar-item/index.ts delete mode 100644 packages/mobile/components/tabbar-item/src/mobile.vue delete mode 100644 packages/mobile/components/tabbar-item/src/renderless/index.ts delete mode 100644 packages/mobile/components/tabbar-item/src/renderless/vue.ts delete mode 100644 packages/mobile/components/tabbar-item/src/tabbar-item.ts delete mode 100644 packages/mobile/components/tabbar/index.ts delete mode 100644 packages/mobile/components/tabbar/src/mobile.vue delete mode 100644 packages/mobile/components/tabbar/src/renderless/index.ts delete mode 100644 packages/mobile/components/tabbar/src/renderless/vue.ts delete mode 100644 packages/mobile/components/tabbar/src/tabbar.ts delete mode 100644 packages/mobile/components/table/index.ts delete mode 100644 packages/mobile/components/table/src/mobile.vue delete mode 100644 packages/mobile/components/table/src/renderless/index.ts delete mode 100644 packages/mobile/components/table/src/renderless/vue.ts delete mode 100644 packages/mobile/components/table/src/table.ts delete mode 100644 packages/mobile/components/tabs/index.ts delete mode 100644 packages/mobile/components/tabs/src/mobile.vue delete mode 100644 packages/mobile/components/tabs/src/renderless/index.ts delete mode 100644 packages/mobile/components/tabs/src/renderless/vue.ts delete mode 100644 packages/mobile/components/tabs/src/tab-nav/mb.vue delete mode 100644 packages/mobile/components/tabs/src/tab-nav/renderless/index.ts delete mode 100644 packages/mobile/components/tabs/src/tab-nav/renderless/vue.ts delete mode 100644 packages/mobile/components/tabs/src/tab-nav/tab-nav.ts delete mode 100644 packages/mobile/components/tabs/src/tabs.ts delete mode 100644 packages/mobile/components/tag/index.ts delete mode 100644 packages/mobile/components/tag/src/mobile.vue delete mode 100644 packages/mobile/components/tag/src/renderless/index.ts delete mode 100644 packages/mobile/components/tag/src/renderless/vue.ts delete mode 100644 packages/mobile/components/tag/src/tag.ts delete mode 100644 packages/mobile/components/time-line/index.ts delete mode 100644 packages/mobile/components/time-line/src/mobile.vue delete mode 100644 packages/mobile/components/time-line/src/renderless/index.ts delete mode 100644 packages/mobile/components/time-line/src/renderless/vue.ts delete mode 100644 packages/mobile/components/time-line/src/time-line.ts delete mode 100644 packages/mobile/components/toast/index.ts delete mode 100644 packages/mobile/components/toast/src/mobile.vue delete mode 100644 packages/mobile/components/toast/src/renderless/index.ts delete mode 100644 packages/mobile/components/toast/src/renderless/vue.ts delete mode 100644 packages/mobile/components/toast/src/service.ts delete mode 100644 packages/mobile/components/toast/src/toast.ts delete mode 100644 packages/mobile/components/tooltip/index.ts delete mode 100644 packages/mobile/components/tooltip/src/mobile.vue delete mode 100644 packages/mobile/components/tooltip/src/renderless/index.ts delete mode 100644 packages/mobile/components/tooltip/src/renderless/vue.ts delete mode 100644 packages/mobile/components/tooltip/src/tooltip.ts delete mode 100644 packages/mobile/components/upload-list/index.ts delete mode 100644 packages/mobile/components/upload-list/src/mobile.vue delete mode 100644 packages/mobile/components/upload-list/src/renderless/index.ts delete mode 100644 packages/mobile/components/upload-list/src/renderless/vue.ts delete mode 100644 packages/mobile/components/upload-list/src/upload-list.ts delete mode 100644 packages/mobile/components/upload/index.ts delete mode 100644 packages/mobile/components/upload/src/mobile.vue delete mode 100644 packages/mobile/components/upload/src/renderless/index.ts delete mode 100644 packages/mobile/components/upload/src/renderless/vue.ts delete mode 100644 packages/mobile/components/upload/src/upload.ts delete mode 100644 packages/mobile/components/user-head/index.ts delete mode 100644 packages/mobile/components/user-head/src/mobile.vue delete mode 100644 packages/mobile/components/user-head/src/renderless/index.ts delete mode 100644 packages/mobile/components/user-head/src/renderless/vue.ts delete mode 100644 packages/mobile/components/user-head/src/user-head.ts delete mode 100644 packages/mobile/components/wheel/index.ts delete mode 100644 packages/mobile/components/wheel/src/mobile.vue delete mode 100644 packages/mobile/components/wheel/src/renderless/index.ts delete mode 100644 packages/mobile/components/wheel/src/renderless/vue.ts delete mode 100644 packages/mobile/index.ts delete mode 100644 packages/mobile/package.json delete mode 100644 packages/mobile/shared.type.ts delete mode 100644 packages/mobile/tsconfig.json delete mode 100644 packages/mobile/tsconfig.node.json delete mode 100644 packages/mobile/utils/array.ts delete mode 100644 packages/mobile/utils/bigInt.ts delete mode 100644 packages/mobile/utils/browser.ts delete mode 100644 packages/mobile/utils/calendar/calendar.ts delete mode 100644 packages/mobile/utils/dataset/index.ts delete mode 100644 packages/mobile/utils/date.ts delete mode 100644 packages/mobile/utils/decimal.ts delete mode 100644 packages/mobile/utils/deps/ResizeObserver.ts delete mode 100644 packages/mobile/utils/deps/after-leave.ts delete mode 100644 packages/mobile/utils/deps/clickoutside.ts delete mode 100644 packages/mobile/utils/deps/date-util.ts delete mode 100644 packages/mobile/utils/deps/date.ts delete mode 100644 packages/mobile/utils/deps/debounce.ts delete mode 100644 packages/mobile/utils/deps/dom.ts delete mode 100644 packages/mobile/utils/deps/eSpaceCtrl.ts delete mode 100644 packages/mobile/utils/deps/fastdom/async.ts delete mode 100644 packages/mobile/utils/deps/fastdom/index.ts delete mode 100644 packages/mobile/utils/deps/fastdom/sandbox.ts delete mode 100644 packages/mobile/utils/deps/fastdom/singleton.ts delete mode 100644 packages/mobile/utils/deps/fullscreen/apis.ts delete mode 100644 packages/mobile/utils/deps/fullscreen/screenfull.ts delete mode 100644 packages/mobile/utils/deps/infinite-scroll.ts delete mode 100644 packages/mobile/utils/deps/letter-only.ts delete mode 100644 packages/mobile/utils/deps/memorize.ts delete mode 100644 packages/mobile/utils/deps/number-only.ts delete mode 100644 packages/mobile/utils/deps/observe-visibility.ts delete mode 100644 packages/mobile/utils/deps/popper.ts delete mode 100644 packages/mobile/utils/deps/popup-manager.ts delete mode 100644 packages/mobile/utils/deps/repeat-click.ts delete mode 100644 packages/mobile/utils/deps/resize-event.ts delete mode 100644 packages/mobile/utils/deps/scroll-into-view.ts delete mode 100644 packages/mobile/utils/deps/scrollbar-width.ts delete mode 100644 packages/mobile/utils/deps/throttle.ts delete mode 100644 packages/mobile/utils/deps/touch-emulator.ts delete mode 100644 packages/mobile/utils/deps/touch.ts delete mode 100644 packages/mobile/utils/deps/tree-model/node.ts delete mode 100644 packages/mobile/utils/deps/tree-model/tree-store.ts delete mode 100644 packages/mobile/utils/deps/tree-model/util.ts delete mode 100644 packages/mobile/utils/deps/upload-ajax.ts delete mode 100644 packages/mobile/utils/deps/useEventListener.ts delete mode 100644 packages/mobile/utils/deps/useRect.ts delete mode 100644 packages/mobile/utils/deps/useTouch.ts delete mode 100644 packages/mobile/utils/deps/vue-emitter.ts delete mode 100644 packages/mobile/utils/deps/vue-popper.ts delete mode 100644 packages/mobile/utils/deps/vue-popup.ts delete mode 100644 packages/mobile/utils/event.ts delete mode 100644 packages/mobile/utils/global.ts delete mode 100644 packages/mobile/utils/index.ts delete mode 100644 packages/mobile/utils/object.ts delete mode 100644 packages/mobile/utils/runtime.ts delete mode 100644 packages/mobile/utils/string.ts delete mode 100644 packages/mobile/utils/type.ts delete mode 100644 packages/mobile/utils/validate/index.ts delete mode 100644 packages/mobile/utils/validate/messages.ts delete mode 100644 packages/mobile/utils/validate/rules/enum.ts delete mode 100644 packages/mobile/utils/validate/rules/index.ts delete mode 100644 packages/mobile/utils/validate/rules/pattern.ts delete mode 100644 packages/mobile/utils/validate/rules/range.ts delete mode 100644 packages/mobile/utils/validate/rules/required.ts delete mode 100644 packages/mobile/utils/validate/rules/type.ts delete mode 100644 packages/mobile/utils/validate/rules/whitespace.ts delete mode 100644 packages/mobile/utils/validate/schema.ts delete mode 100644 packages/mobile/utils/validate/util.ts delete mode 100644 packages/mobile/utils/validate/validations/array.ts delete mode 100644 packages/mobile/utils/validate/validations/date.ts delete mode 100644 packages/mobile/utils/validate/validations/enum.ts delete mode 100644 packages/mobile/utils/validate/validations/float.ts delete mode 100644 packages/mobile/utils/validate/validations/index.ts delete mode 100644 packages/mobile/utils/validate/validations/integer.ts delete mode 100644 packages/mobile/utils/validate/validations/method.ts delete mode 100644 packages/mobile/utils/validate/validations/number.ts delete mode 100644 packages/mobile/utils/validate/validations/pattern.ts delete mode 100644 packages/mobile/utils/validate/validations/required.ts delete mode 100644 packages/mobile/utils/validate/validations/string.ts delete mode 100644 packages/mobile/utils/validate/validations/type.ts delete mode 100644 packages/mobile/utils/xss.ts delete mode 100644 packages/mobile/vite.config.ts diff --git a/examples/docs/package.json b/examples/docs/package.json index f9984e12bd..35b62e1ed6 100644 --- a/examples/docs/package.json +++ b/examples/docs/package.json @@ -15,7 +15,6 @@ "@opentiny/vue-design-aurora": "workspace:~", "@opentiny/vue-design-saas": "workspace:~", "@opentiny/vue-icon": "workspace:~", - "@opentiny/vue-theme-mobile": "workspace:~", "@opentiny/vue-theme-saas": "workspace:~", "sortablejs": "1.15.0" }, diff --git a/examples/nuxt/playground/package.json b/examples/nuxt/playground/package.json index 5b3ddf9444..841c42f239 100644 --- a/examples/nuxt/playground/package.json +++ b/examples/nuxt/playground/package.json @@ -25,7 +25,6 @@ "@opentiny/vue-locale": "workspace:~", "@opentiny/vue-renderless": "workspace:~", "@opentiny/vue-theme": "workspace:~", - "@opentiny/vue-theme-mobile": "workspace:~", "@opentiny/vue-vite-import": "~1.2.0", "@tiptap/vue-3": "^2.1.0", "@vitejs/plugin-vue-jsx": "^3.0.0", diff --git a/internals/cli/src/config/vite.ts b/internals/cli/src/config/vite.ts index 485be5e381..aa6d50f6f9 100644 --- a/internals/cli/src/config/vite.ts +++ b/internals/cli/src/config/vite.ts @@ -23,7 +23,6 @@ const getAlias = (vueVersion: string | number, theme = '', design) => { '@opentiny/vue-icon$': pathFromWorkspaceRoot(`packages/vue-icon${ns(design || theme)}/index.ts`), '@opentiny/vue-icon-multicolor$': pathFromWorkspaceRoot(`packages/vue-icon-multicolor${ns(theme)}/index.ts`), '@opentiny/vue-renderless': pathFromWorkspaceRoot('packages/renderless/src'), - '@opentiny/vue-theme-mobile': pathFromWorkspaceRoot('packages/theme-mobile/src'), '@opentiny/vue-theme': pathFromWorkspaceRoot(`packages/theme${ns(design || theme)}/src`), '@opentiny/vue-theme-saas': pathFromWorkspaceRoot('packages/theme-saas/src'), '@opentiny/vue-common': pathFromWorkspaceRoot('packages/vue-common/src/index-dev'), diff --git a/packages/mobile/LICENSE b/packages/mobile/LICENSE deleted file mode 100644 index 1803599544..0000000000 --- a/packages/mobile/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) 2022 - present TinyVue Authors. -Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/packages/mobile/common/index.ts b/packages/mobile/common/index.ts deleted file mode 100644 index b01048e3f0..0000000000 --- a/packages/mobile/common/index.ts +++ /dev/null @@ -1,368 +0,0 @@ -import hooks from './src/adapter' -import { - appContext, - appProperties, - bindFilter, - createComponentFn, - getElementCssClass, - getElementStatusClass -} from './src/adapter' -import { defineAsyncComponent, directive, emitter, h, markRaw, Teleport, KeepAlive } from './src/adapter' -import { - parseVnode, - isEmptyVnode, - renderComponent, - rootConfig, - tools, - useRouter, - getComponentName, - isVnode -} from './src/adapter' -import { t } from '@opentiny/vue-locale' -import { stringifyCssClass, stringifyCssClassObject, stringifyCssClassArray, deduplicateCssClass } from './src/csscls' -import { defineComponent, isVue2, isVue3 } from './src/adapter' -import { useBreakpoint } from './src/breakpoint' -import { useDefer } from './src/usedefer' - -export { stringifyCssClass, stringifyCssClassObject, stringifyCssClassArray, deduplicateCssClass } -export { useBreakpoint, useDefer } - -export { defineComponent, isVue2, isVue3, appProperties } - -export const $prefix = 'Tiny' - -export const $props = { - 'tiny_mode': String, - 'tiny_mode_root': Boolean, - 'tiny_template': [Function, Object], - 'tiny_renderless': Function, - 'tiny_theme': String, - 'tiny_chart_theme': Object -} - -export const props: Array< - | 'tiny_mode' - | 'tiny_mode_root' - | 'tiny_template' - | 'tiny_renderless' - | '_constants' - | 'tiny_theme' - | 'tiny_chart_theme' -> = ['tiny_mode', 'tiny_mode_root', 'tiny_template', 'tiny_renderless', '_constants', 'tiny_theme', 'tiny_chart_theme'] - -export const resolveMode = (props, context) => { - let isRightMode = (mode) => ~['pc', 'mobile', 'mobile-first'].indexOf(mode) - let config = rootConfig(context) - let tinyModeProp = typeof props.tiny_mode === 'string' ? props.tiny_mode : null - let tinyModeInject = hooks.inject('TinyMode', null) - let tinyModeGlobal - - // 解决modal、loading、notify 组件(函数式组件,脱离组件树)的内部组件模式判断错误问题。 - if (typeof config.tiny_mode === 'string') { - tinyModeGlobal = config.tiny_mode - } else if (config.tiny_mode) { - tinyModeGlobal = config.tiny_mode.value - } - - if (!isRightMode(tinyModeProp)) tinyModeProp = null - if (!isRightMode(tinyModeInject)) tinyModeInject = null - if (!isRightMode(tinyModeGlobal)) tinyModeGlobal = null - - let tinyMode = tinyModeProp || tinyModeInject || tinyModeGlobal || 'pc' - - if (props.tiny_mode_root) { - hooks.provide('TinyMode', tinyMode) - } - - let instance = hooks.getCurrentInstance() - - if (isVue2) { - instance = instance.proxy - } - - Object.defineProperty(instance, '_tiny_mode', { value: tinyMode }) - - return tinyMode -} - -export const resolveTheme = (props, context) => { - const isRightTheme = (theme) => ~['tiny', 'saas'].indexOf(theme) - const config = rootConfig(context) - let tinyThemeProp = typeof props.tiny_theme === 'string' ? props.tiny_theme : null - let tinyThemeInject = hooks.inject('TinyTheme', null) - let tinyThemeGlobal = config.tiny_theme && config.tiny_theme.value - - if (!isRightTheme(tinyThemeProp)) tinyThemeProp = null - if (!isRightTheme(tinyThemeInject)) tinyThemeInject = null - if (!isRightTheme(tinyThemeGlobal)) tinyThemeGlobal = null - - const tinyTheme = tinyThemeProp || tinyThemeInject || tinyThemeGlobal || 'tiny' - - return tinyTheme -} - -const resolveChartTheme = (props, context) => { - const config = rootConfig(context) - let tinyChartProp = typeof props.tiny_chart_theme === 'object' ? props.tiny_chart_theme : null - let tinyChartInject = hooks.inject('TinyChartTheme', null) - let tinyChartGlobal = config.tiny_chart_theme && config.tiny_chart_theme.value - - const tinyChartTheme = tinyChartProp || tinyChartInject || tinyChartGlobal || null - - return tinyChartTheme -} - -export const $setup = ({ props, context, template, extend = {} }) => { - const mode = resolveMode(props, context) - const view = hooks.computed(() => { - if (typeof props.tiny_template !== 'undefined') return props.tiny_template - - const component = template(mode, props) - - return typeof component === 'function' ? defineAsyncComponent(component) : component - }) - - return renderComponent({ view, props, context, extend }) -} - -// 提供给没有renderless层的组件使用(比如TinyVuePlus组件) -export const design = { - configKey: Symbol('designConfigKey'), - configInstance: null -} - -// 注入规范配置 -export const provideDesignConfig = (designConfig) => { - if (Object.keys(designConfig).length) { - hooks.provide(design.configKey, designConfig) - design.configInstance = designConfig - } -} - -const createComponent = createComponentFn(design) - -interface DesignConfig { - components?: any - name?: string - version?: string -} - -interface CustomDesignConfig { - designConfig: null | DesignConfig -} - -// 允许自定义主题规范,适用于MetaERP项目 -export const customDesignConfig: CustomDesignConfig = { - designConfig: null -} - -export const setup = ({ props, context, renderless, api, extendOptions = {}, classes = {} }) => { - const render = typeof props.tiny_renderless === 'function' ? props.tiny_renderless : renderless - - // 获取组件级配置和全局配置(inject需要带有默认值,否则控制台会报警告) - const globalDesignConfig: DesignConfig = customDesignConfig.designConfig || hooks.inject(design.configKey, {}) - const designConfig = globalDesignConfig?.components?.[getComponentName().replace($prefix, '')] - - const utils = { - $prefix, - t, - ...tools(context, resolveMode(props, context)), - designConfig, - globalDesignConfig, - useBreakpoint - } - - utils.vm.theme = resolveTheme(props, context) - utils.vm.chartTheme = resolveChartTheme(props, context) - const sdk = render(props, hooks, utils, extendOptions) - - // 加载全局配置,合并api - if (typeof designConfig?.renderless === 'function') { - Object.assign(sdk, designConfig.renderless(props, hooks, utils, sdk)) - } - - const attrs = { - t, - vm: utils.vm, - f: bindFilter, - a: filterAttrs, - d: utils.defineInstanceProperties, - dp: utils.defineParentInstanceProperties, - gcls: (key) => getElementCssClass(classes, key) - } - /** - * 修复 render 函数下 this.slots 不会动态更新的问题(vue3 环境没有问题) - * 解决方法:在 instance 下注入 slots、scopedSlots - * 注意:renderless 下尽量使用 vm.$refs、vm.$slots - */ - attrs.d({ - slots: { get: () => utils.vm.$slots, configurable: true }, - scopedSlots: { get: () => utils.vm.$scopedSlots, configurable: true } - }) - - attrs.dp({ - slots: { get: () => utils.parent.$slots, configurable: true }, - scopedSlots: { get: () => utils.parent.$scopedSlots, configurable: true } - }) - - initComponent() - - if (Array.isArray(api)) { - // 允许 design里定义的api扩展出来, - if (Array.isArray(designConfig?.api)) { - api = api.concat(designConfig.api) - } - api.forEach((name) => { - const value = sdk[name] - - if (typeof value !== 'undefined') { - attrs[name] = value - } - }) - } - - return attrs -} - -// 这里需要使用函数声明语句,可以提升变量,保证saas-common可以正常运行 -export function svg({ name = 'Icon', component }) { - return (propData?) => - markRaw( - defineComponent({ - name: $prefix + name, - setup: (props, context) => { - const { fill, width, height } = context.attrs || {} - const mergeProps = Object.assign({}, props, propData || null) - const mode = resolveMode(mergeProps, context) - const isMobileFirst = mode === 'mobile-first' - const tinyTag = { 'data-tag': isMobileFirst ? 'tiny-svg' : null } - const attrs = isVue3 ? tinyTag : { attrs: tinyTag } - let className = 'tiny-svg' - - const extend = Object.assign( - { - style: { fill, width, height }, - class: className, - isSvg: true - }, - attrs - ) - - // 解决本地运行会报大量警告的问题 - if (process.env.BUILD_TARGET) { - extend.nativeOn = context.listeners - } - - return renderComponent({ - component, - props: mergeProps, - context, - extend - }) - } - }) - ) -} -/** - * 将用户传入的 $attrs中的属性, 与 filters 中传入的属性做对比。 - * 如果include , 且属性在filters中, 则返回。 - * 如果 !include, 且属性不匹配filters, 则返回。 - * 在模板中,都是通过 v-bind="a($attrs,[])" 来使用该函数 。 - * @mark 由于现在组件都移除了 inheritAttrs。 加在外层的 v-bind="a()"" 都可以去掉了, 否则会出现双份效果。 - * - * @param attrs : Object - * @param filters : string[] - * @param include : boolean - * - * @example Button-pc中: v-bind="a($attrs, ['class', 'style', 'title', 'id'], true)" - * @exampleResult 把用户使用 等属性,会传递给该位置的dom。 - * - * @example Area-pc中: v-bind="a($attrs, ['^on[A-Z]'])" - * @exampleResult 把用户使用 等事件, 不会传递给内部的select上, 但是class,style等,会传递给select上。 - */ -export const filterAttrs = (attrs, filters, include) => { - const props = {} - - for (let name in attrs) { - const find = filters.some((r) => new RegExp(r).test(name)) - - if ((include && find) || (!include && !find)) { - props[name] = attrs[name] - } - } - return props -} - -// eslint-disable-next-line import/no-mutable-exports -export let setupComponent = {} - -export const initComponent = () => { - for (let name in setupComponent) { - const component = setupComponent[name] - - if (typeof component.install === 'function') { - component.install(appContext()) - } - - if (typeof component.init === 'function') { - component.init(appProperties()) - } - } - - setupComponent = {} -} - -export const $install = (component) => { - component.install = function (Vue) { - Vue.component(component.name, component) - } -} - -export type { - PropType, - ExtractPropTypes, - DefineComponent, - ComponentPublicInstance, - SetupContext, - ComputedRef -} from './adapter' - -export { - h, - hooks, - directive, - parseVnode, - isEmptyVnode, - useRouter, - emitter, - createComponent, - defineAsyncComponent, - getElementStatusClass, - Teleport, - KeepAlive, - isVnode -} - -export default { - h, - directive, - parseVnode, - isEmptyVnode, - useRouter, - emitter, - createComponent, - defineAsyncComponent, - filterAttrs, - initComponent, - setupComponent, - svg, - $prefix, - $props, - props, - $setup, - setup, - hooks, - getElementStatusClass, - $install, - isVnode -} diff --git a/packages/mobile/common/src/adapter/index.ts b/packages/mobile/common/src/adapter/index.ts deleted file mode 100644 index c438418538..0000000000 --- a/packages/mobile/common/src/adapter/index.ts +++ /dev/null @@ -1,495 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import * as hooks from 'vue' - -import { camelize, capitalize, hyphenate } from '@mobile-root/utils/string' -import { bindFilter, emitter, getElementCssClass, getElementStatusClass } from './utils' - -const Teleport = hooks.Teleport - -export { emitter, bindFilter, getElementCssClass, getElementStatusClass, Teleport } - -export const defineAsyncComponent = hooks.defineAsyncComponent - -export const markRaw = hooks.markRaw - -export const renderComponent = ({ - view = undefined as any, - component = undefined as any, - props, - context: { attrs, slots }, - extend = {} -}) => { - return () => hooks.h((view && view.value) || component, { ref: 'modeTemplate', ...props, ...attrs, ...extend }, slots) -} - -export const rootConfig = (context) => { - const instance = hooks.getCurrentInstance() - context && setInstanceEmitter(instance) - return instance?.appContext.config.globalProperties -} - -export const getComponentName = () => { - // 此处组件最多为两层组件,所以对多获取到父级组件即可 - const instance = hooks.getCurrentInstance() - let componentName = instance?.type?.name - if (!componentName) { - componentName = instance?.parent?.type?.name - } - - return componentName || '' -} - -export const appContext = () => - hooks.getCurrentInstance()?.appContext || { - component: () => { - // do nothing - } - } - -export const appProperties = () => { - const instance = hooks.getCurrentInstance() - return instance?.appContext.config.globalProperties || {} -} - -export const useRouter = (instance = hooks.getCurrentInstance()) => { - const router = instance?.appContext.config.globalProperties.$router - const route = router && router.currentRoute.value - - return { route, router } -} - -const setInstanceEmitter = (instance) => { - const $emitter = emitter() - - if (typeof instance.$emitter === 'undefined') Object.defineProperty(instance, '$emitter', { get: () => $emitter }) -} - -const emitEvent = (vm) => { - const broadcast = (vm, componentName, eventName, params) => { - const children = (vm.subTree && vm.subTree.children) || vm.children - - Array.isArray(children) && - children.forEach((child) => { - const name = child.type && child.type.componentName - const component = child.component - - if (name === componentName) { - component.emit(eventName, params) - component.$emitter && component.$emitter.emit(eventName, params) - } else { - broadcast(child, componentName, eventName, params) - } - }) - } - - return { - dispatch(componentName, eventName, params) { - let parent = vm.parent || vm.root - let name = parent.type && parent.type.componentName - - while (parent && (!name || name !== componentName)) { - parent = parent.parent - - if (parent) name = parent.type && parent.type.componentName - } - - if (parent) { - parent.emit(...[eventName].concat(params)) - // fix: VUE3下事件参数为数组,VUE2下事件参数不是数组,这里修改为和VUE2兼容 - parent.$emitter && parent.$emitter.emit(...[eventName].concat(params)) - } - }, - broadcast(componentName, eventName, params) { - broadcast(vm, componentName, eventName, params) - } - } -} - -const getRealParent = (vm) => { - if (vm && vm.parent) - return vm.parent.type.name === 'AsyncComponentWrapper' && vm.parent.parent ? vm.parent.parent : vm.parent -} - -const parent = (vm) => (handler) => { - let parent = getRealParent(vm) - let level = 0 - - const parentObject = (parent) => { - return { - level, - vm: createVm({}, parent), - el: parent.vnode.el, - options: parent.type - } - } - - if (typeof handler !== 'function') return parent ? parentObject(parent) : {} - - level++ - - while (parent) { - if (handler(parentObject(parent))) break - parent = getRealParent(parent) - level++ - } -} - -const children = (vm) => (handler) => { - if (typeof handler !== 'function') return generateChildren(vm.subTree) - - let layer = 1 - const broadcast = (subTree) => { - if (subTree) { - const children = subTree.children || subTree.dynamicChildren - const level = layer++ - - if (Array.isArray(children)) { - if ( - children.some((child) => { - return ( - child.component && - handler({ - level, - vm: createVm({}, child.component), - el: child.el, - options: child.type, - isLevel1: true - }) - ) - }) - ) - return - - children.forEach((child) => broadcast(child)) - } - } - } - - broadcast(vm.subTree) -} - -const regEventPrefix = /^on[A-Z]/ - -const generateListeners = (attrs) => { - const $attrs = {} - const $listeners = {} - - for (const name in attrs) { - const event = attrs[name] - - if (regEventPrefix.test(name) && typeof event === 'function') { - $listeners[hyphenate(name.substr(2))] = event - continue - } - - $attrs[name] = event - } - - return { $attrs, $listeners } -} - -const generateChildren = (subTree) => { - const children: any = [] - children.refs = {} - - if (subTree) { - const arr = subTree.dynamicChildren || subTree.children - - if (Array.isArray(arr)) { - arr.forEach((child) => { - if (child.component) { - const vm = createVm({}, child.component) - - children.push(vm) - child.props.ref && (children.refs[child.props.ref] = vm) - } - }) - } else if (subTree.component) { - children.push(createVm({}, subTree.component)) - } - } - - return children -} - -const defineProperties = (vm, instance, property, filter) => { - for (const name in instance[property]) { - if (typeof filter === 'function' && filter(name)) continue - - Object.defineProperty(vm, name, { - configurable: true, - enumerable: true, - get: () => instance[property][name], - set: (value) => (instance[property][name] = value) - }) - } - - return vm -} - -const filter = (name) => name.indexOf('_') === 0 - -const defineInstanceVm = (vm, instance) => { - defineProperties(vm, instance, 'setupState', null) - defineProperties(vm, instance, 'props', filter) - defineProperties(vm, instance, 'ctx', filter) - - return vm -} - -const createVm = (vm, instance, context = null) => { - const { $attrs, $listeners } = generateListeners(instance.attrs) - let $emitter = instance.$emitter - - if (!$emitter) { - setInstanceEmitter(instance) - $emitter = instance.$emitter - } - - const emit = (...args) => { - instance.emit(...args) - $emitter.emit.apply(vm, args) - } - - const $set = (target, propertyName, value) => (target[propertyName] = value) - - context || defineInstanceVm(vm, instance) - - Object.defineProperties(vm, { - $attrs: { get: () => $attrs }, - $children: { get: () => generateChildren(instance.subTree) }, - $constants: { get: () => instance.props._constants }, - $emit: { get: () => emit }, - $el: { get: () => instance.vnode.el }, - $listeners: { get: () => $listeners }, - $mode: { get: () => instance._tiny_mode }, - $nextTick: { get: () => hooks.nextTick }, - $off: { get: () => $emitter.off }, - $on: { get: () => $emitter.on }, - $once: { get: () => $emitter.once }, - $options: { get: () => ({ componentName: instance.type.componentName }) }, - $parent: { - get: () => instance.parent && createVm({}, getRealParent(instance)) - }, - $refs: { get: () => instance.refs }, - $renderless: { get: () => instance.props.tiny_renderless }, - $scopedSlots: { get: () => instance.slots }, - $set: { get: () => $set }, - $slots: { get: () => instance.slots }, - $template: { get: () => instance.props.tiny_template } - }) - - return vm -} - -const onBeforeMount = (instance, refs) => { - for (let name in instance.refs) { - if (Object.prototype.hasOwnProperty.call(instance.refs, name)) { - refs[name] = instance.refs[name] - } - } -} - -export const tools = (context, mode) => { - const instance = hooks.getCurrentInstance() as any - const root = instance?.appContext.config.globalProperties - const { route, router } = useRouter(instance) - const i18n = instance?.proxy?.$root?.$i18n - const { dispatch, broadcast } = emitEvent(instance) - const parentHandler = parent(instance) - const childrenHandler = children(instance) - const vm = createVm({}, instance, context) - const emit = context.emit - const refs = {} - const grandParent = typeof instance.props.tiny_template === 'undefined' && getRealParent(instance) - const parentVm = grandParent ? createVm({}, grandParent) : instance.parent ? createVm({}, instance.parent) : null - - const setParentAttribute = ({ name, value }) => { - const ctx = grandParent ? grandParent.ctx : instance?.parent?.ctx - ctx[name] = value - - // 当前的parentVm也保存一下。 - parentVm[name] = value - } - - const defineInstanceProperties = (props) => { - Object.defineProperties(vm, props) - Object.defineProperties(instance?.ctx, props) - } - - const defineParentInstanceProperties = (props) => { - parentVm && Object.defineProperties(parentVm, props) - } - - hooks.onBeforeMount(() => defineInstanceVm(vm, instance)) - hooks.onMounted(() => onBeforeMount(instance, refs)) - - return { - framework: 'vue3', - vm, - emit, - emitter, - route, - router, - dispatch, - broadcast, - parentHandler, - childrenHandler, - i18n, - refs, - slots: instance?.slots, - scopedSlots: instance?.slots, - attrs: context.attrs, - parent: parentVm, - nextTick: hooks.nextTick, - constants: instance?.props._constants, - mode, - isPCMode: mode === 'pc', - isMobileMode: mode === 'mobile', - service: root?.$service, - getService: () => root?.$getService(vm), - setParentAttribute, - defineInstanceProperties, - defineParentInstanceProperties - } -} - -const mapping = (content, before, after) => { - if (typeof content[before] !== 'undefined') { - const fn = content[before] - - content[after] = (el, binding, vnode) => { - vnode.context = binding.instance - fn(el, binding, vnode) - } - - delete content[before] - } -} - -export const directive = (directives) => { - for (const name in directives) { - const content = directives[name] - - mapping(content, 'bind', 'beforeMount') - mapping(content, 'update', 'updated') - mapping(content, 'unbind', 'unmounted') - } - - return directives -} - -export const parseVnode = (vnode) => vnode - -const { Text, Comment } = hooks - -export const isEmptyVnode = (vnode) => !vnode || !vnode.type || [Text, Comment].includes(vnode.type) - -const parseProps = (propsData) => { - const props = {} - - for (const name in propsData) { - if (name === 'class' || name === 'style') { - props[name] = propsData[name] - } else if (name === 'on' || name === 'nativeOn') { - const events = propsData[name] - - for (const eventName in events) props[`on${capitalize(camelize(eventName))}`] = events[eventName] - } else if (name === 'attrs' || name === 'props' || name === 'domProps') { - const attrs = propsData[name] - - for (const key in attrs) props[key] = attrs[key] - } else { - props[name] = propsData[name] - } - } - - return props -} - -const customResolveComponent = (component) => { - let type = component - let customElement = false - - if (typeof component === 'string' && typeof document !== 'undefined') { - const el = document.createElement(component) - const svgTagNames = ['SVG', 'CIRCLE', 'PATH'] - - if ((el instanceof HTMLUnknownElement && !svgTagNames.includes(el.nodeName)) || component.includes('-')) { - component = component.toLowerCase() - customElement = true - - if (component === 'transition') type = hooks.Transition - else if (component === 'transition-group') type = hooks.TransitionGroup - else type = hooks.resolveComponent(component) - } else { - type = component - } - } - - return { type, component, customElement } -} - -type CreateElement = (component: any, propsData?: any, childData?: any) => ReturnType - -export const h: CreateElement = (component, propsData, childData) => { - let props = {} - let children = childData - const ret = customResolveComponent(component) - const customElement = ret.customElement - const type = ret.type - - component = ret.component - - if (propsData && typeof propsData === 'object' && !Array.isArray(propsData)) { - props = parseProps(propsData) - propsData.scopedSlots && (children = propsData.scopedSlots) - } else if (typeof propsData === 'string' || Array.isArray(propsData)) { - childData = propsData - } - - if (typeof childData === 'string' || Array.isArray(childData)) - children = typeof component !== 'string' || customElement ? () => childData : childData - - return hooks.h(type, props, children) -} - -export const createComponentFn = (design) => { - return ({ component, propsData, el }) => { - const comp = Object.assign(component, { provide: { [design.configKey]: design.configInstance } }) - const vnode = hooks.createVNode(comp, propsData) - - hooks.render(vnode, el) - return createVm({}, vnode.component) - } -} -export const defineComponent = hooks.defineComponent - -export default hooks - -export const isVue2 = false - -export const isVue3 = true - -export const isVnode = hooks.isVNode - -export const KeepAlive = hooks.KeepAlive - -export type { - PropType, - ExtractPropTypes, - DefineComponent, - ComponentPublicInstance, - SetupContext, - ComputedRef -} from 'vue' diff --git a/packages/mobile/common/src/adapter/teleport.ts b/packages/mobile/common/src/adapter/teleport.ts deleted file mode 100644 index dada67247a..0000000000 --- a/packages/mobile/common/src/adapter/teleport.ts +++ /dev/null @@ -1,209 +0,0 @@ -let globalId = 0 - -const getHasComment = (state) => (comment) => { - const childNodes = state.parent ? Array.from(state.parent.childNodes) : [] - - for (let i = 0; i < childNodes.length; i++) { - if (childNodes[i].textContent === comment) { - return true - } - } -} - -const getGetFragment = - ({ hasComment, startComment, state, endComment }) => - (commentFlag) => { - const fragment = document.createDocumentFragment() - - if (commentFlag) { - !hasComment(startComment) && fragment.appendChild(document.createComment(startComment)) - state.nodes.forEach((node) => fragment.appendChild(node)) - !hasComment(endComment) && fragment.appendChild(document.createComment(endComment)) - } else { - const children = state.parent ? Array.from(state.parent.childNodes) : [] - - let start, end - - start = end = 0 - - for (let i = 0; i < children.length; i++) { - const node = children[i] - - if (node.nodeType !== 8) { - continue - } - - if (node.textContent === startComment) { - start = i - } - - if (node.textContent === endComment) { - end = i - break - } - } - - if (end > start) { - children.slice(start + 1, end).forEach((node) => fragment.appendChild(node)) - } - } - - return fragment - } - -const getDisable = - ({ instance, getFragment, state, startComment, endComment }) => - () => { - instance.$el.appendChild(getFragment()) - - const indices = [] - const children = state.parent ? Array.from(state.parent.childNodes) : [] - - children.forEach((child, i) => { - if (child.nodeType === 8) { - if (child.textContent === startComment || child.textContent === endComment) { - indices.push(i) - } - } - }) - - const minIndex = Math.min(...indices) - const maxIndex = Math.max(...indices) - - children - .slice(minIndex, maxIndex + 1) - .reverse() - .forEach((child) => state.parent && state.parent.removeChild(child)) - - state.parent = null - } - -const getMove = - ({ state, props, disable, getFragment }) => - () => { - state.waiting = false - state.parent = document.querySelector(props.to) - - if (!state.parent) { - disable() - state.waiting = true - - return - } - - if (props.where === 'before') { - state.parent.prepend(getFragment(true)) - } else { - state.parent.appendChild(getFragment(true)) - } - } - -const getTeardownObserver = (state) => () => { - if (state.observer) { - state.observer.disconnect() - state.observer = null - } -} - -const getOnMutations = - ({ state, disable, props, move }) => - (mutations) => { - let shouldMove = false - - for (let i = 0; i < mutations.length; i++) { - const mutation = mutations[i] - const filteredAddedNodes = Array.from(mutation.addedNodes).filter((node) => !state.nodes.includes(node)) - - if (Array.from(mutation.removedNodes).includes(state.parent)) { - disable() - state.waiting = !props.disabled - } else if (state.waiting && filteredAddedNodes.length > 0) { - shouldMove = true - } - } - - shouldMove && move() - } - -const getBootObserver = - ({ state, onMutations }) => - () => { - if (state.observer) return - - state.observer = new MutationObserver((mutations) => onMutations(mutations)) - - state.observer.observe(document.body, { - attributes: false, - characterData: false, - childList: true, - subtree: true - }) - } - -const getAfterUpdated = - ({ state, instance, props, bootObserver, maybeMove }) => - () => { - state.nodes = Array.from(instance.$el.childNodes) - - !props.disabled && bootObserver() - maybeMove() - } - -const getWatchDisabled = - ({ disable, teardownObserver, bootObserver, move }) => - (value) => { - if (value) { - disable() - teardownObserver() - - return - } - - bootObserver() - move() - } - -export default ({ reactive, watch, getCurrentInstance, onUpdated, onMounted, onBeforeUnmount, h, defineComponent }) => - defineComponent({ - name: 'Vue2Teleport', - props: { - to: { type: String, required: true }, - where: { type: String, default: 'after' }, - disabled: Boolean - }, - setup(props) { - const state = reactive({ nodes: [], waiting: false, observer: null, parent: null, id: ++globalId }) - const instance = getCurrentInstance()?.proxy - const startComment = `[${state.id}]vue2-teleporter-start` - const endComment = `[${state.id}]vue2-teleporter-end` - - const hasComment = getHasComment(state) - const getFragment = getGetFragment({ hasComment, startComment, state, endComment }) - const disable = getDisable({ instance, getFragment, state, startComment, endComment }) - const move = getMove({ state, props, disable, getFragment }) - const maybeMove = () => !props.disabled && move() - const teardownObserver = getTeardownObserver(state) - const onMutations = getOnMutations({ state, disable, props, move }) - const bootObserver = getBootObserver({ state, onMutations }) - const afterUpdated = getAfterUpdated({ state, instance, props, bootObserver, maybeMove }) - const watchDisabled = getWatchDisabled({ disable, teardownObserver, bootObserver, move }) - - watch(() => props.to, maybeMove) - watch(() => props.where, maybeMove) - watch(() => props.disabled, watchDisabled) - - onUpdated(afterUpdated) - onMounted(afterUpdated) - onBeforeUnmount(() => { - disable() - teardownObserver() - }) - - return () => - h( - 'div', - { class: 'vue2-teleporter', style: { 'visibility:hidden;display:none;': !props.disabled } }, - (typeof instance?.$slots.default === 'function' ? instance.$slots.default() : instance.$slots.default) || null - ) - } - }) diff --git a/packages/mobile/common/src/adapter/utils.ts b/packages/mobile/common/src/adapter/utils.ts deleted file mode 100644 index 8e87257313..0000000000 --- a/packages/mobile/common/src/adapter/utils.ts +++ /dev/null @@ -1,120 +0,0 @@ -export const emitter = () => { - let listeners = {} - - const on = (event, callback, once = false) => { - if (event && typeof event === 'string' && typeof callback === 'function') { - const callbacks = listeners[event] || [] - - listeners[event] = callbacks - callbacks.push(callback) - callback.once = once - } - } - - const emitter = { - emit(eventName) { - const callbacks = listeners[eventName] - - if (callbacks) { - // eslint-disable-next-line prefer-spread, prefer-rest-params - callbacks.forEach((callback) => callback.apply(null, [].slice.call(arguments, 1))) - - listeners[eventName] = callbacks.filter((callback) => !callback.once) - } - }, - on, - once(event, callback) { - on(event, callback, true) - }, - off(event, callback) { - if (event && typeof event === 'string') { - const callbacks = listeners[event] - - if (typeof callback === 'function') { - listeners[event] = callbacks.filter((cb) => cb !== callback) - } else { - delete listeners[event] - } - } else { - listeners = {} - } - } - } - - return emitter -} - -export const bindFilter = (props, attrs = {}) => { - const properties = {} - - for (let name in props) { - if (name.indexOf('_') !== 0) { - properties[name] = props[name] - } - } - - for (let name in attrs) { - properties[name] = attrs[name] - } - - return properties -} - -/** - * 根据类名生成对应的hover、active等类名 - * - * getElementStatusClass('border-color', 'hover') // 'border-color hover:border-color-hover' - * getElementStatusClass(['border-color'], ['hover', 'active']) // 'border-color hover:border-color-hover active:border-color-active' - * - * @method - * @param {String|Array} className - 类名 - * @param {String|Array} status - 状态 - * @returns {String} - 类名拼接的字符串 - */ -export const getElementStatusClass = (className, status) => { - if (!className || !status) return - - let classNames: string[] = [] - if (typeof className === 'string') { - classNames.push(className) - } else if (Array.isArray(className)) { - classNames = className - } - - let statusList: string[] = [] - if (typeof status === 'string') { - statusList.push(status) - } else if (Array.isArray(status)) { - statusList = status - } - - let res: string[] = [] - statusList.forEach((status) => classNames.forEach((name) => res.push(`${status}:${name}-${status}`))) - - return classNames.concat(res).join(' ') -} - -/** - * 根据key值获取对应的classes类名配置 - * - * getElementCssClass({ button: 'border-color' }, 'button') // 'border-color' - * getElementCssClass({ button: 'border-color' }, { 'button': true }) // 'border-color' - * getElementCssClass({ button: 'border-color', 'mini': 'p-1', 'small': 'p-2' }, ['button', 'small']) // 'border-color p-2' - * - * @method - * @param {Object} classes - 类名集合 - * @param {String|Object|Array} key - 状态或状态集合 - * @returns {String} - 类名配置值 - */ -export const getElementCssClass = (classes = {}, key) => { - if (typeof key === 'object') { - const keys = Array.isArray(key) ? key : Object.keys(key).filter((k) => key[k]) - let cls = '' - keys.forEach((k) => { - if (classes[k]) cls += `${classes[k]} ` - }) - return cls - } else { - return classes[key] || '' - } -} diff --git a/packages/mobile/common/src/adapter/vue3/index.ts b/packages/mobile/common/src/adapter/vue3/index.ts deleted file mode 100644 index b358c7ab38..0000000000 --- a/packages/mobile/common/src/adapter/vue3/index.ts +++ /dev/null @@ -1,496 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import * as hooks from 'vue' - -import { camelize, capitalize, hyphenate } from '@mobile-root/utils/string' -import { bindFilter, emitter, getElementCssClass, getElementStatusClass } from '../utils' - -const Teleport = hooks.Teleport - -export { emitter, bindFilter, getElementCssClass, getElementStatusClass, Teleport } - -export const defineAsyncComponent = hooks.defineAsyncComponent - -export const markRaw = hooks.markRaw - -export const renderComponent = ({ - view = undefined as any, - component = undefined as any, - props, - context: { attrs, slots }, - extend = {} -}) => { - return () => hooks.h((view && view.value) || component, { ref: 'modeTemplate', ...props, ...attrs, ...extend }, slots) -} - -export const rootConfig = (context) => { - const instance = hooks.getCurrentInstance() - context && setInstanceEmitter(instance) - return instance?.appContext.config.globalProperties -} - -export const getComponentName = () => { - // 此处组件最多为两层组件,所以对多获取到父级组件即可 - const instance = hooks.getCurrentInstance() - let componentName = instance?.type?.name - if (!componentName) { - componentName = instance?.parent?.type?.name - } - - return componentName || '' -} - -export const appContext = () => - hooks.getCurrentInstance()?.appContext || { - component: () => { - // do nothing - } - } - -export const appProperties = () => { - const instance = hooks.getCurrentInstance() - return instance?.appContext.config.globalProperties || {} -} - -export const useRouter = (instance = hooks.getCurrentInstance()) => { - const router = instance?.appContext.config.globalProperties.$router - const route = router && router.currentRoute.value - - return { route, router } -} - -const setInstanceEmitter = (instance) => { - const $emitter = emitter() - - if (typeof instance.$emitter === 'undefined') Object.defineProperty(instance, '$emitter', { get: () => $emitter }) -} - -const emitEvent = (vm) => { - const broadcast = (vm, componentName, eventName, params) => { - const children = (vm.subTree && vm.subTree.children) || vm.children - - Array.isArray(children) && - children.forEach((child) => { - const name = child.type && child.type.componentName - const component = child.component - - if (name === componentName) { - component.emit(eventName, params) - component.$emitter && component.$emitter.emit(eventName, params) - } else { - broadcast(child, componentName, eventName, params) - } - }) - } - - return { - dispatch(componentName, eventName, params) { - let parent = vm.parent || vm.root - let name = parent.type && parent.type.componentName - - while (parent && (!name || name !== componentName)) { - parent = parent.parent - - if (parent) name = parent.type && parent.type.componentName - } - - if (parent) { - parent.emit(...[eventName].concat(params)) - // fix: VUE3下事件参数为数组,VUE2下事件参数不是数组,这里修改为和VUE2兼容 - parent.$emitter && parent.$emitter.emit(...[eventName].concat(params)) - } - }, - broadcast(componentName, eventName, params) { - broadcast(vm, componentName, eventName, params) - } - } -} - -const getRealParent = (vm) => { - if (vm && vm.parent) - return vm.parent.type.name === 'AsyncComponentWrapper' && vm.parent.parent ? vm.parent.parent : vm.parent -} - -const parent = (vm) => (handler) => { - let parent = getRealParent(vm) - let level = 0 - - const parentObject = (parent) => { - return { - level, - vm: createVm({}, parent), - el: parent.vnode.el, - options: parent.type - } - } - - if (typeof handler !== 'function') return parent ? parentObject(parent) : {} - - level++ - - while (parent) { - if (handler(parentObject(parent))) break - parent = getRealParent(parent) - level++ - } -} - -const children = (vm) => (handler) => { - if (typeof handler !== 'function') return generateChildren(vm.subTree) - - let layer = 1 - const broadcast = (subTree) => { - if (subTree) { - const children = subTree.children || subTree.dynamicChildren - const level = layer++ - - if (Array.isArray(children)) { - if ( - children.some((child) => { - return ( - child.component && - handler({ - level, - vm: createVm({}, child.component), - el: child.el, - options: child.type, - isLevel1: true - }) - ) - }) - ) - return - - children.forEach((child) => broadcast(child)) - } - } - } - - broadcast(vm.subTree) -} - -const regEventPrefix = /^on[A-Z]/ - -const generateListeners = (attrs) => { - const $attrs = {} - const $listeners = {} - - for (const name in attrs) { - const event = attrs[name] - - if (regEventPrefix.test(name) && typeof event === 'function') { - $listeners[hyphenate(name.substr(2))] = event - continue - } - - $attrs[name] = event - } - - return { $attrs, $listeners } -} - -const generateChildren = (subTree) => { - const children: any = [] - children.refs = {} - - if (subTree) { - const arr = subTree.dynamicChildren || subTree.children - - if (Array.isArray(arr)) { - arr.forEach((child) => { - if (child.component) { - const vm = createVm({}, child.component) - - children.push(vm) - child.props.ref && (children.refs[child.props.ref] = vm) - } - }) - } else if (subTree.component) { - children.push(createVm({}, subTree.component)) - } - } - - return children -} - -const defineProperties = (vm, instance, property, filter) => { - for (const name in instance[property]) { - if (typeof filter === 'function' && filter(name)) continue - - Object.defineProperty(vm, name, { - configurable: true, - enumerable: true, - get: () => instance[property][name], - set: (value) => (instance[property][name] = value) - }) - } - - return vm -} - -const filter = (name) => name.indexOf('_') === 0 - -const defineInstanceVm = (vm, instance) => { - defineProperties(vm, instance, 'setupState', null) - defineProperties(vm, instance, 'props', filter) - defineProperties(vm, instance, 'ctx', filter) - - return vm -} - -const createVm = (vm, instance, context = null) => { - const { $attrs, $listeners } = generateListeners(instance.attrs) - let $emitter = instance.$emitter - - if (!$emitter) { - setInstanceEmitter(instance) - $emitter = instance.$emitter - } - - const emit = (...args) => { - instance.emit(...args) - $emitter.emit.apply(vm, args) - } - - const $set = (target, propertyName, value) => (target[propertyName] = value) - - context || defineInstanceVm(vm, instance) - - Object.defineProperties(vm, { - $attrs: { get: () => $attrs }, - $children: { get: () => generateChildren(instance.subTree) }, - $constants: { get: () => instance.props._constants }, - $emit: { get: () => emit }, - $el: { get: () => instance.vnode.el }, - $listeners: { get: () => $listeners }, - $mode: { get: () => instance._tiny_mode }, - $nextTick: { get: () => hooks.nextTick }, - $off: { get: () => $emitter.off }, - $on: { get: () => $emitter.on }, - $once: { get: () => $emitter.once }, - $options: { get: () => ({ componentName: instance.type.componentName }) }, - $parent: { - get: () => instance.parent && createVm({}, getRealParent(instance)) - }, - $refs: { get: () => instance.refs }, - $renderless: { get: () => instance.props.tiny_renderless }, - $scopedSlots: { get: () => instance.slots }, - $set: { get: () => $set }, - $slots: { get: () => instance.slots }, - $template: { get: () => instance.props.tiny_template } - }) - - return vm -} - -const onBeforeMount = (instance, refs) => { - for (let name in instance.refs) { - if (Object.prototype.hasOwnProperty.call(instance.refs, name)) { - refs[name] = instance.refs[name] - } - } -} - -export const tools = (context, mode) => { - const instance = hooks.getCurrentInstance() as any - const root = instance?.appContext.config.globalProperties - const { route, router } = useRouter(instance) - const i18n = instance?.proxy?.$root?.$i18n - const { dispatch, broadcast } = emitEvent(instance) - const parentHandler = parent(instance) - const childrenHandler = children(instance) - const vm = createVm({}, instance, context) - const emit = context.emit - const refs = {} - const grandParent = typeof instance.props.tiny_template === 'undefined' && getRealParent(instance) - const parentVm = grandParent ? createVm({}, grandParent) : instance.parent ? createVm({}, instance.parent) : null - - const setParentAttribute = ({ name, value }) => { - const ctx = grandParent ? grandParent.ctx : instance?.parent?.ctx - ctx[name] = value - - // 当前的parentVm也保存一下。 - parentVm[name] = value - } - - const defineInstanceProperties = (props) => { - Object.defineProperties(vm, props) - Object.defineProperties(instance?.ctx, props) - } - - const defineParentInstanceProperties = (props) => { - parentVm && Object.defineProperties(parentVm, props) - } - - hooks.onBeforeMount(() => defineInstanceVm(vm, instance)) - hooks.onMounted(() => onBeforeMount(instance, refs)) - - return { - framework: 'vue3', - vm, - emit, - emitter, - route, - router, - dispatch, - broadcast, - parentHandler, - childrenHandler, - i18n, - refs, - slots: instance?.slots, - scopedSlots: instance?.slots, - attrs: context.attrs, - parent: parentVm, - nextTick: hooks.nextTick, - constants: instance?.props._constants, - mode, - isPCMode: mode === 'pc', - isMobileMode: mode === 'mobile', - service: root?.$service, - getService: () => root?.$getService(vm), - setParentAttribute, - defineInstanceProperties, - defineParentInstanceProperties - } -} - -const mapping = (content, before, after) => { - if (typeof content[before] !== 'undefined') { - const fn = content[before] - - content[after] = (el, binding, vnode) => { - vnode.context = binding.instance - fn(el, binding, vnode) - } - - delete content[before] - } -} - -export const directive = (directives) => { - for (const name in directives) { - const content = directives[name] - - mapping(content, 'bind', 'beforeMount') - mapping(content, 'update', 'updated') - mapping(content, 'unbind', 'unmounted') - } - - return directives -} - -export const parseVnode = (vnode) => vnode - -const { Text, Comment } = hooks - -export const isEmptyVnode = (vnode) => !vnode || !vnode.type || [Text, Comment].includes(vnode.type) - -const parseProps = (propsData) => { - const props = {} - - for (const name in propsData) { - if (name === 'class' || name === 'style') { - props[name] = propsData[name] - } else if (name === 'on' || name === 'nativeOn') { - const events = propsData[name] - - for (const eventName in events) props[`on${capitalize(camelize(eventName))}`] = events[eventName] - } else if (name === 'attrs' || name === 'props' || name === 'domProps') { - const attrs = propsData[name] - - for (const key in attrs) props[key] = attrs[key] - } else { - props[name] = propsData[name] - } - } - - return props -} - -const customResolveComponent = (component) => { - let type = component - let customElement = false - - if (typeof component === 'string' && typeof document !== 'undefined') { - const el = document.createElement(component) - const svgTagNames = ['SVG', 'CIRCLE', 'PATH'] - - if ((el instanceof HTMLUnknownElement && !svgTagNames.includes(el.nodeName)) || component.includes('-')) { - component = component.toLowerCase() - customElement = true - - if (component === 'transition') type = hooks.Transition - else if (component === 'transition-group') type = hooks.TransitionGroup - else type = hooks.resolveComponent(component) - } else { - type = component - } - } - - return { type, component, customElement } -} - -type CreateElement = (component: any, propsData?: any, childData?: any) => ReturnType - -export const h: CreateElement = (component, propsData, childData) => { - let props = {} - let children = childData - const ret = customResolveComponent(component) - const customElement = ret.customElement - const type = ret.type - - component = ret.component - - if (propsData && typeof propsData === 'object' && !Array.isArray(propsData)) { - props = parseProps(propsData) - propsData.scopedSlots && (children = propsData.scopedSlots) - } else if (typeof propsData === 'string' || Array.isArray(propsData)) { - childData = propsData - } - - if (typeof childData === 'string' || Array.isArray(childData)) - children = typeof component !== 'string' || customElement ? () => childData : childData - - return hooks.h(type, props, children) -} - -export const createComponentFn = (design) => { - return ({ component, propsData, el }) => { - const comp = Object.assign(component, { provide: { [design.configKey]: design.configInstance } }) - const vnode = hooks.createVNode(comp, propsData) - - hooks.render(vnode, el) - return createVm({}, vnode.component) - } -} - -export const defineComponent = hooks.defineComponent - -export default hooks - -export const isVue2 = false - -export const isVue3 = true - -export const isVnode = hooks.isVNode - -export const KeepAlive = hooks.KeepAlive - -export type { - PropType, - ExtractPropTypes, - DefineComponent, - ComponentPublicInstance, - SetupContext, - ComputedRef -} from 'vue' diff --git a/packages/mobile/common/src/breakpoint.ts b/packages/mobile/common/src/breakpoint.ts deleted file mode 100644 index 7b9b498507..0000000000 --- a/packages/mobile/common/src/breakpoint.ts +++ /dev/null @@ -1,51 +0,0 @@ -import hooks from './adapter' -import { isServer } from '@mobile-root/utils/deps/dom' -import debounce from '@mobile-root/utils/deps/debounce' - -/** - * 组合使用 Tailwind 的响应性断点状态 - * - * @example - * const breakpoint = useBreakpoint() - * watch(breakpoint.current, (current) => { console.log(current) }) - */ -export const useBreakpoint = () => { - if (isServer) return - - const activeBreakpoint = hooks.ref('') - const prefixes = ['2xl', 'xl', 'lg', 'md', 'sm'] - const mediaQuerys = { - '2xl': window.matchMedia('(min-width:1536px)'), - 'xl': window.matchMedia('(min-width:1280px)'), - 'lg': window.matchMedia('(min-width:1024px)'), - 'md': window.matchMedia('(min-width:768px)'), - 'sm': window.matchMedia('(min-width:640px)') - } - - type MediaQuerysKey = keyof typeof mediaQuerys - - const setActiveBreakpoint = () => { - for (let i = 0; i < prefixes.length; i++) { - const key = prefixes[i] - - if (mediaQuerys[key as MediaQuerysKey].matches) { - activeBreakpoint.value = key - return - } - } - - activeBreakpoint.value = 'default' - } - - const mediaQueryListener: any = debounce(0, () => setActiveBreakpoint()) - - setActiveBreakpoint() - - prefixes.forEach((key) => mediaQuerys[key as MediaQuerysKey].addEventListener('change', mediaQueryListener)) - - hooks.onBeforeUnmount(() => { - prefixes.forEach((key) => mediaQuerys[key as MediaQuerysKey].removeEventListener('change', mediaQueryListener)) - }) - - return { current: activeBreakpoint } -} diff --git a/packages/mobile/common/src/csscls.ts b/packages/mobile/common/src/csscls.ts deleted file mode 100644 index 534a9f4580..0000000000 --- a/packages/mobile/common/src/csscls.ts +++ /dev/null @@ -1,88 +0,0 @@ -interface CssClassObject { - [k: string]: any -} -type CssClassArray = Array -export type CssClass = string | CssClassObject | CssClassArray - -/** - * 简单合并 tailwind 类对象为字符串值 - * - * @param cssClassObject tailwind 类对象 - * @returns string - */ -export const stringifyCssClassObject = (cssClassObject: CssClassObject): string => { - const allCssClass: Array = [] - - Object.keys(cssClassObject).forEach((cssClass) => cssClassObject[cssClass] && allCssClass.push(cssClass)) - - return allCssClass.join('\u{20}') -} - -/** - * 简单合并 tailwind 类数组为字符串值 - * - * @param cssClassArray tailwind 类数组 - * @returns string - */ -export const stringifyCssClassArray = (cssClassArray: CssClassArray): string => { - const allCssClass: Array = [] - - cssClassArray.forEach((cssClass) => { - if (typeof cssClass === 'string') { - allCssClass.push(cssClass) - } else if (typeof cssClass === 'object') { - allCssClass.push(stringifyCssClassObject(cssClass)) - } - }) - - return allCssClass.join('\u{20}') -} - -/** - * 简单合并 tailwind 类对象为字符串值,去重处理留给 tailwind-merge 处理 - * - * @param {*} cssClasses tailwind 类集合 - * @returns string - */ -export const stringifyCssClass = (cssClasses: Array | CssClass): string => { - if (!cssClasses) { - return '' - } - if (typeof cssClasses === 'string') { - return cssClasses - } - if (Array.isArray(cssClasses) && cssClasses.length > 0) { - const allCssClass: Array = [] - - cssClasses.forEach((cssClass) => { - if (cssClass) { - if (typeof cssClass === 'string') { - allCssClass.push(cssClass) - } else if (Array.isArray(cssClass)) { - allCssClass.push(stringifyCssClassArray(cssClass)) - } else if (typeof cssClass === 'object') { - allCssClass.push(stringifyCssClassObject(cssClass)) - } - } - }) - - return allCssClass.join('\u{20}') - } - if (typeof cssClasses === 'object') { - return stringifyCssClassObject(cssClasses) - } - return '' -} - -/** - * 对类名做一个简单去重处理 - * - * @param cssClasses 类集合 - * @returns string - */ -export const deduplicateCssClass = (cssClasses: Array | CssClass): string => { - const classNames = stringifyCssClass(cssClasses) - // 类名去重且去除多余空格 - const classArray = Array.from(new Set(classNames.split('\u{20}'))).filter((i) => i) - return stringifyCssClass(classArray) -} diff --git a/packages/mobile/common/src/usedefer.ts b/packages/mobile/common/src/usedefer.ts deleted file mode 100644 index c66ca71241..0000000000 --- a/packages/mobile/common/src/usedefer.ts +++ /dev/null @@ -1,41 +0,0 @@ -import hooks from './adapter' - -export function useDefer(maxCount = 100) { - const frameCount = hooks.ref(0) - let rafId: number - - function updateFrameCount() { - rafId = requestAnimationFrame(() => { - frameCount.value++ - - if (frameCount.value >= maxCount) { - return - } - - updateFrameCount() - }) - } - - function cancel() { - if (rafId) { - cancelAnimationFrame(rafId) - rafId = 0 - } - } - - updateFrameCount() - - hooks.onBeforeUnmount(() => cancel()) - - return { - defer(n: number) { - return frameCount.value >= n - }, - reset() { - cancel() - frameCount.value = 0 - updateFrameCount() - }, - cancel - } -} diff --git a/packages/mobile/components/action-sheet/index.ts b/packages/mobile/components/action-sheet/index.ts deleted file mode 100644 index d4d71b42a1..0000000000 --- a/packages/mobile/components/action-sheet/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import ActionSheet from './src/mobile.vue' - -/* istanbul ignore next */ -ActionSheet.install = function (Vue) { - Vue.component(ActionSheet.name, ActionSheet) -} - -export default ActionSheet diff --git a/packages/mobile/components/action-sheet/src/action-sheet.ts b/packages/mobile/components/action-sheet/src/action-sheet.ts deleted file mode 100644 index de6c3d25a1..0000000000 --- a/packages/mobile/components/action-sheet/src/action-sheet.ts +++ /dev/null @@ -1,115 +0,0 @@ -import type { CSSProperties, ExtractPropTypes } from 'vue' -import type { ISharedRenderlessParamUtils } from '@mobile-root/shared.type' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const actionSheetProps = { - menus: { - type: Array, - default: () => [] - }, - modelValue: [Number, String, Array], - beforeClose: Function, - visible: { - type: Boolean, - default: false - }, - ellipsis: { - type: Boolean, - default: false - }, - height: { - type: String, - default: '100%' - }, - valueField: { - type: String, - default: 'id' - }, - textField: { - type: String, - default: 'label' - }, - title: String, - showHeader: { - type: Boolean, - default: true - }, - showFooter: { - type: Boolean, - default: false - }, - showClose: { - type: Boolean, - default: () => true - }, - fullscreen: { - type: Boolean, - default: () => false - }, - customClass: [String, Object, Array], - contentClass: String, - type: { - type: String, - default: 'normal' - }, - mask: { - type: Boolean, - default: true - }, - maskClosable: { - type: Boolean, - default: true - }, - lockScroll: { - type: Boolean, - default: true - }, - flex: { - type: Boolean, - default: true - }, - contentPosition: { - type: Boolean, - default: false - }, - contentStyle: { - type: Object, - default: () => ({}) - } -} - -export interface IActionSheetState { - toggle: boolean - sheetMaskStyle: CSSProperties - sheetContentStyle: CSSProperties - scroll: null | object -} - -export type IActionSheetProps = ExtractPropTypes - -export type IActionSheetRenderlessParamUtils = ISharedRenderlessParamUtils - -export interface IActionSheetApi { - state: IActionSheetState - setSheetStyle: ({ state, props }: { state: IActionSheetState; props: IActionSheetProps }) => void - initScrollMenu: ({ - state, - nextTick, - refs, - BScroll - }: { - state: IActionSheetState - nextTick: IActionSheetRenderlessParamUtils['nextTick'] - refs: IActionSheetRenderlessParamUtils['refs'] - BScroll: object - }) => void - visibleHandle: ({ emit, state }: { emit: IActionSheetRenderlessParamUtils['emit']; state: IActionSheetState }) => void - watchVisible: (value: boolean) => void - menuHandle: (item: any) => void - confirm: () => void - selectOption: (option: any) => void - actionSelectOption: (option: any, index: any) => void - close: () => void - hide: () => void -} diff --git a/packages/mobile/components/action-sheet/src/mobile.vue b/packages/mobile/components/action-sheet/src/mobile.vue deleted file mode 100644 index 5517ce6367..0000000000 --- a/packages/mobile/components/action-sheet/src/mobile.vue +++ /dev/null @@ -1,68 +0,0 @@ - - - - - diff --git a/packages/mobile/components/action-sheet/src/renderless/index.ts b/packages/mobile/components/action-sheet/src/renderless/index.ts deleted file mode 100644 index 33a26a0a6d..0000000000 --- a/packages/mobile/components/action-sheet/src/renderless/index.ts +++ /dev/null @@ -1,135 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -export const setSheetStyle = - ({ state, props }) => - () => { - if (props.contentPosition) { - // 展示在视图中间 - state.sheetMaskStyle = { - 'position': 'absolute' - } - state.sheetContentStyle = { - 'position': 'absolute', - 'max-height': props.height - } - } else { - // 固定在页面底部 - state.sheetMaskStyle = { - 'position': 'fixed' - } - state.sheetContentStyle = { - 'position': 'fixed', - 'max-height': props.height - } - } - // 内容区支持自定义主题 - state.contentStyle = props.contentStyle ? props.contentStyle : '' - } - -export const initScrollMenu = - ({ state, nextTick, refs, BScroll }) => - () => { - nextTick(() => { - const { scrollMenu } = refs - - // mobile-first是不使用BS优化的,没有这个ref节点。 所以直接返回 - if (!scrollMenu) { - return - } - - if (!state.scroll) { - state.scroll = new BScroll(scrollMenu, { - probeType: 3, - tap: 'tap' - }) - } else { - state.scroll.refresh() - } - }) - } - -export const visibleHandle = - ({ emit, state }) => - () => { - state.scroll = null - emit('update:visible', false) - emit('close', false) - } - -export const watchVisible = - ({ emit, state }) => - (bool) => { - setTimeout(() => { - state.toggle = bool - }, 0) - emit('update:visible', bool) - } - -export const menuHandle = - ({ emit, state }) => - (item) => { - state.active = item.id - state.scroll = null - emit('update:visible', false) - emit('update:modelValue', item.id) - emit('click', item) - } - -export const close = - ({ api }) => - () => { - api.handleClose('close', false) - } - -export const hide = - ({ api }) => - () => { - api.handleClose('hide', false) - } - -export const selectOption = - ({ emit, props }) => - (option) => { - const { valueField } = props - - emit('update:visible', false) - emit('update:modelValue', option[valueField]) - emit('click', option) - } - -export const confirm = - ({ state, api }) => - () => { - api.handleClose('confirm', state) - } - -export const actionSelectOption = - ({ emit }) => - (option, index) => { - emit('update:visible', false) - emit('click', option, index) - } - -export const handleClose = - ({ vm, emit, props }) => - (type, show) => { - if (typeof props.beforeClose === 'function' && props.beforeClose(type) === false) return - - if (type === 'close') { - vm.$refs.drawer.close(true) - } else { - emit('update:visible', false) - } - - emit(type, show) - } diff --git a/packages/mobile/components/action-sheet/src/renderless/vue.ts b/packages/mobile/components/action-sheet/src/renderless/vue.ts deleted file mode 100644 index cb1f32d8dc..0000000000 --- a/packages/mobile/components/action-sheet/src/renderless/vue.ts +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { - IActionSheetApi, - IActionSheetState, - IActionSheetProps, - ISharedRenderlessParamHooks, - IActionSheetRenderlessParamUtils -} from '../action-sheet' - -import { - setSheetStyle, - initScrollMenu, - visibleHandle, - watchVisible, - menuHandle, - close, - selectOption, - confirm, - actionSelectOption, - hide, - handleClose -} from './index' - -export const api = [ - 'state', - 'setSheetStyle', - 'initScrollMenu', - 'visibleHandle', - 'watchVisible', - 'menuHandle', - 'close', - 'selectOption', - 'confirm', - 'actionSelectOption', - 'hide' -] - -export const renderless = ( - props: IActionSheetProps, - { reactive, watch }: ISharedRenderlessParamHooks, - { emit, nextTick, refs, vm }: IActionSheetRenderlessParamUtils, - { BScroll } -): IActionSheetApi => { - const state = reactive({ - toggle: false, - sheetMaskStyle: {}, - sheetContentStyle: {}, - scroll: null - }) - - const api: IActionSheetApi = {} as IActionSheetApi - Object.assign(api, { - state, - setSheetStyle: setSheetStyle({ state, props }), - initScrollMenu: initScrollMenu({ state, nextTick, refs, BScroll }), - visibleHandle: visibleHandle({ emit, state }), - watchVisible: watchVisible({ emit, state }), - menuHandle: menuHandle({ state, emit }), - confirm: confirm({ state, api }), - selectOption: selectOption({ emit, props }), - actionSelectOption: actionSelectOption({ emit }), - hide: hide({ api }), - close: close({ api }), - handleClose: handleClose({ vm, emit, props }) - }) - - watch( - () => props.visible, - (value) => { - if (value) { - api.setSheetStyle({ state, props }) - api.initScrollMenu({ state, nextTick, refs, BScroll }) - } - api.watchVisible(value) - } - ) - - watch(() => props.visible, api.watchVisible, { immediate: true }) - - return api -} diff --git a/packages/mobile/components/alert/index.ts b/packages/mobile/components/alert/index.ts deleted file mode 100644 index ec0c1c2ff3..0000000000 --- a/packages/mobile/components/alert/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Alert from './src/mobile.vue' - -/* istanbul ignore next */ -Alert.install = function (Vue) { - Vue.component(Alert.name, Alert) -} - -export default Alert diff --git a/packages/mobile/components/alert/src/alert.ts b/packages/mobile/components/alert/src/alert.ts deleted file mode 100644 index df1b56d2ac..0000000000 --- a/packages/mobile/components/alert/src/alert.ts +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { ExtractPropTypes, CSSProperties } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' - -export type { ISharedRenderlessParamHooks, ITinyVm } from '@mobile-root/shared.type' - -export const $constants = { - ICON_MAP: { - success: 'icon-success', - error: 'icon-error', - info: 'icon-help', - warning: 'icon-warning' - }, - TITLE_MAP: { - success: 'ui.alert.success', - error: 'ui.alert.error', - info: 'ui.alert.info', - warning: 'ui.alert.warning' - }, - CONTENT_MAXHEUGHT: 252 -} - -export const alertProps = { - _constants: { - type: Object, - default: () => $constants - }, - icon: [String, Object], - type: { - type: String, - default: 'info' - }, - size: { - type: String, - default: 'normal' - }, - description: { - type: String, - default: '' - }, - title: { - type: String - }, - center: Boolean, - showIcon: { - type: Boolean, - default: true - }, - closable: { - type: Boolean, - default: true - }, - closeText: { - type: String, - default: '' - }, - singleLine: { - type: Boolean, - default: false - }, - scrolling: { - type: Boolean, - default: false - }, - showFoldable: { - type: Boolean, - default: false - }, - customClass: [String, Object, Array], - offset: { - type: [Number, String], - default: 0 - }, - autoHide: { - type: Boolean, - default: false - }, - target: { - type: String, - default: '' - } -} - -export interface IAlertState { - show: boolean - getIcon: string - getTitle: string - contentVisible: boolean - contentDescribeHeight: number - contentDefaultHeight: number - contentMaxHeight: number - scrollStatus: boolean -} - -export type IAlertProps = ExtractPropTypes - -export type IAlertConstants = typeof $constants - -export type IAlertRenderlessParams = ISharedRenderlessFunctionParams & { - api: IAlertApi - state: IAlertState - props: IAlertProps -} - -export interface IAlertApi { - state: IAlertState - computedGetIcon: () => string - computedGetTitle: () => string - handleClose: () => void - handleHeaderClick: () => void - watchAutoHide: (value: boolean) => void - computedStyle: () => CSSProperties -} - -export type IAlertRenderlessParamUtils = ISharedRenderlessParamUtils diff --git a/packages/mobile/components/alert/src/mobile.vue b/packages/mobile/components/alert/src/mobile.vue deleted file mode 100644 index 4ed4a7867e..0000000000 --- a/packages/mobile/components/alert/src/mobile.vue +++ /dev/null @@ -1,50 +0,0 @@ - - - - diff --git a/packages/mobile/components/alert/src/renderless/index.ts b/packages/mobile/components/alert/src/renderless/index.ts deleted file mode 100644 index c4c0489195..0000000000 --- a/packages/mobile/components/alert/src/renderless/index.ts +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { CSSProperties } from 'vue' -import type { IAlertRenderlessParams, ITinyVm } from '../alert' - -export const ALERT_TIMEOUT = 2000 - -export const watchAutoHide = - ({ api, props }: Pick) => - (newVal: boolean) => { - if (props.autoHide && newVal) { - const timer = setTimeout(() => { - api.handleClose() - clearTimeout(timer) - }, ALERT_TIMEOUT) - } - } - -export const computedClass = - ({ props, mode }) => - (): string[] => { - const { type, size, center } = props - if (mode === 'mobile') { - const alertClass = ['tiny-mobile-alert', 'tiny-mobile-alert--' + type, 'tiny-mobile-alert--' + size] - if (center) { - alertClass.push('is-center') - } - - return alertClass - } - - return [] - } - -export const computedStyle = - ({ props, mode }) => - (): CSSProperties | null => { - if (mode === 'mobile') { - const style = { - top: isNaN(props.offset) ? props.offset : `${props.offset}px` - } - return style - } - - return null - } - -export const handleClose = - ({ emit, state }: Pick) => - () => { - state.show = false - emit('close') - } - -export const computedGetIcon = - ({ constants, props, designConfig }: Pick) => - () => { - const designIcon = designConfig?.icons?.[props.type] - - return props.icon || designIcon || constants.ICON_MAP[props.type] - } - -export const computedGetTitle = - ({ constants, t, props }: Pick) => - () => - props.title || t(constants.TITLE_MAP[props.type]) - -export const handleHeaderClick = - ({ state, props, vm }: Pick) => - () => { - if (props.showFoldable) { - state.contentVisible = !state.contentVisible - } - if (vm.$refs.ContentDescribe) { - state.contentDescribeHeight = vm.$refs.ContentDescribe.scrollHeight - - if (state.contentDescribeHeight > state.contentMaxHeight) { - state.scrollStatus = true - } - } - if (vm.$refs.ContentDefault) { - state.contentDefaultHeight = vm.$refs.ContentDefault.scrollHeight - - if (state.contentDefaultHeight > state.contentMaxHeight) { - state.scrollStatus = true - } - } - } - -const getEl = (node: ITinyVm): HTMLElement => { - return node.$el || node -} - -export const handlerTargetNode = - ({ props, parent, vm, nextTick }) => - () => { - const { target } = props - const { $parent } = parent - nextTick(() => { - const alertParentNode = $parent?.$refs[target] - if (!target || !alertParentNode) { - return - } - - const targetNode = Array.isArray(alertParentNode) ? alertParentNode[0] : alertParentNode - getEl(targetNode).insertBefore(vm.$el, getEl(targetNode).firstChild) - }) - } diff --git a/packages/mobile/components/alert/src/renderless/vue.ts b/packages/mobile/components/alert/src/renderless/vue.ts deleted file mode 100644 index 5ec566f0a5..0000000000 --- a/packages/mobile/components/alert/src/renderless/vue.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { - IAlertApi, - IAlertProps, - IAlertState, - ISharedRenderlessParamHooks, - IAlertRenderlessParamUtils -} from '../alert' -import { - computedGetIcon, - computedGetTitle, - computedStyle, - computedClass, - handleClose, - handleHeaderClick, - watchAutoHide, - handlerTargetNode -} from './index' - -export const api = ['handleClose', 'state', 'handleHeaderClick'] - -const initState = ({ api, computed, constants, reactive }): IAlertState => { - return reactive({ - show: true, - contentVisible: false, - contentDescribeHeight: 0, - contentDefaultHeight: 0, - contentMaxHeight: constants.CONTENT_MAXHEUGHT, - scrollStatus: false, - getIcon: computed(() => api.computedGetIcon()), - getTitle: computed(() => api.computedGetTitle()), - alertClass: computed(() => api.computedClass()), - alertStyle: computed(() => api.computedStyle()) - }) -} - -const initApi = ({ api, state, constants, props, designConfig, t, emit, vm, parent, nextTick, mode }): void => { - Object.assign(api, { - state, - computedGetIcon: computedGetIcon({ constants, props, designConfig }), - computedGetTitle: computedGetTitle({ constants, props, t }), - computedClass: computedClass({ props, mode }), - computedStyle: computedStyle({ props, mode }), - handleClose: handleClose({ emit, state }), - handleHeaderClick: handleHeaderClick({ state, props, vm }), - watchAutoHide: watchAutoHide({ api, props }), - handlerTargetNode: handlerTargetNode({ props, parent, vm, nextTick }) - }) -} - -const initWatcher = ({ watch, props, api }) => { - watch(() => props.autoHide, api.watchAutoHide, { immediate: true }) - watch(() => props.target, api.handlerTargetNode, { immediate: true }) -} - -export const renderless = ( - props: IAlertProps, - { computed, reactive, watch }: ISharedRenderlessParamHooks, - { t, emit, constants, vm, designConfig, parent, nextTick, mode }: IAlertRenderlessParamUtils -): IAlertApi => { - const api = {} as IAlertApi - const state: IAlertState = initState({ api, computed, constants, reactive }) - initApi({ api, state, constants, props, designConfig, t, emit, vm, parent, nextTick, mode }) - initWatcher({ watch, props, api }) - - return api -} diff --git a/packages/mobile/components/avatar/index.ts b/packages/mobile/components/avatar/index.ts deleted file mode 100644 index 9eb988f466..0000000000 --- a/packages/mobile/components/avatar/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Avatar from './src/mobile.vue' - -/* istanbul ignore next */ -Avatar.install = function (Vue) { - Vue.component(Avatar.name, Avatar) -} - -export default Avatar diff --git a/packages/mobile/components/avatar/src/mobile.vue b/packages/mobile/components/avatar/src/mobile.vue deleted file mode 100644 index 9b68ef9582..0000000000 --- a/packages/mobile/components/avatar/src/mobile.vue +++ /dev/null @@ -1,96 +0,0 @@ - - diff --git a/packages/mobile/components/avatar/src/renderless/index.ts b/packages/mobile/components/avatar/src/renderless/index.ts deleted file mode 100644 index 0ced2035e5..0000000000 --- a/packages/mobile/components/avatar/src/renderless/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -export const handleError = - ({ props, state }) => - () => { - const { error } = props - const errorFlag = error ? error() : undefined - - if (errorFlag !== false) { - if (state.isSrcImageExist) { - state.isSrcImageExist = false - } else { - state.isDefaultImageExist = false - } - } - } - -export const computedAvatarClass = (contants) => (props) => { - const { size, icon, shape } = props - let classList = [contants.COMPONENT_PREFIX] - - if (size && typeof size === 'string') { - classList.push(`${contants.COMPONENT_PREFIX}--${size}`) - } - - if (icon) { - classList.push(`${contants.COMPONENT_PREFIX}--${contants.icon}`) - } - - if (shape) { - classList.push(`${contants.COMPONENT_PREFIX}--${shape}`) - } - - return classList.join(' ') -} diff --git a/packages/mobile/components/avatar/src/renderless/vue.ts b/packages/mobile/components/avatar/src/renderless/vue.ts deleted file mode 100644 index ba62127fa5..0000000000 --- a/packages/mobile/components/avatar/src/renderless/vue.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { computedAvatarClass, handleError } from './index' - -export const api = ['state', 'handleError'] - -export const renderless = (props, { computed, reactive }, { constants }) => { - const api = { - computedAvatarClass: computedAvatarClass(constants) - } - - const state = reactive({ - isSrcImageExist: true, - isDefaultImageExist: true, - avatarClass: computed(() => api.computedAvatarClass(props)) - }) - - Object.assign(api, { - state, - handleError: handleError({ props, state }) - }) - - return api -} diff --git a/packages/mobile/components/badge/index.ts b/packages/mobile/components/badge/index.ts deleted file mode 100644 index 920e39ccf5..0000000000 --- a/packages/mobile/components/badge/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Badge from './src/mobile.vue' - -/* istanbul ignore next */ -Badge.install = function (Vue) { - Vue.component(Badge.name, Badge) -} - -export default Badge diff --git a/packages/mobile/components/badge/src/badge.ts b/packages/mobile/components/badge/src/badge.ts deleted file mode 100644 index c54693007b..0000000000 --- a/packages/mobile/components/badge/src/badge.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' -import type { computedValueRef, computedContent, computedTransform } from './renderless/index' - -export const badgeProps = { - showLeft: { - type: Boolean, - default: false - }, - isDot: { - type: Boolean, - default: false - }, - isFixed: { - type: Boolean, - default: true - }, - isMini: { - type: Boolean, - default: false - }, - max: Number, - value: [String, Number], - modelValue: [String, Number], - href: String, - target: String, - hidden: { - type: Boolean, - default: false - }, - type: { - type: String, - validator: (value: string) => - Boolean(~['primary', 'success', 'warning', 'info', 'danger', 'icon', 'label'].indexOf(value)) - }, - badgeClass: String, - offset: { - type: Array, - default: () => [0, 0] - }, - data: [String, Number] -} - -export type IBadgeContent = string | number | undefined -export interface IBadgeState { - isOverstep: boolean - valueRef: number | undefined - content: IBadgeContent - href: string -} - -export type IBadgeProps = ExtractPropTypes - -export type IBadgeRenderlessParams = ISharedRenderlessFunctionParams & { - state: IBadgeState - props: IBadgeProps -} - -export interface IBadgeApi { - state: IBadgeState - computedValueRef: ReturnType - computedContent: ReturnType - computedTransform: ReturnType -} - -export type IBadgeRenderlessParamUtils = ISharedRenderlessParamUtils diff --git a/packages/mobile/components/badge/src/mobile.vue b/packages/mobile/components/badge/src/mobile.vue deleted file mode 100644 index 7705fbf0e8..0000000000 --- a/packages/mobile/components/badge/src/mobile.vue +++ /dev/null @@ -1,51 +0,0 @@ - - - - diff --git a/packages/mobile/components/badge/src/renderless/index.ts b/packages/mobile/components/badge/src/renderless/index.ts deleted file mode 100644 index bcfd5d6126..0000000000 --- a/packages/mobile/components/badge/src/renderless/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { IBadgeRenderlessParams, IBadgeContent } from '../badge' -import type { StyleValue } from 'vue' - -export const computedContent = - ({ props, state }: Pick) => - (): IBadgeContent => - typeof state.valueRef === 'number' && typeof props.max === 'number' - ? props.max < state.valueRef - ? `${props.max}+` - : state.valueRef - : state.valueRef - -export const computedValueRef = - ({ props }: Pick) => - (): number | undefined => { - if (typeof props.value === 'number') { - return props.value - } - - return typeof props.modelValue === 'number' ? props.modelValue : undefined - } - -export const computedTransform = - ({ designConfig, props }: Pick) => - (): StyleValue => { - if (designConfig?.transform === 'unset') { - return null - } - return { - transform: `translate( - ${props.offset[0]}${typeof props.offset[0] === 'number' ? 'px' : ''}, - ${props.offset[1]}${typeof props.offset[1] === 'number' ? 'px' : ''} - )` - } - } diff --git a/packages/mobile/components/badge/src/renderless/vue.ts b/packages/mobile/components/badge/src/renderless/vue.ts deleted file mode 100644 index 55b2fc35d2..0000000000 --- a/packages/mobile/components/badge/src/renderless/vue.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { computedContent, computedValueRef, computedTransform } from './index' -import { xss } from '@mobile-root/utils/xss' -import type { IBadgeState, IBadgeProps, IBadgeApi, IBadgeRenderlessParams } from '../badge' - -export const api = ['state'] - -export const renderless = ( - props: IBadgeProps, - { computed, reactive }: IBadgeRenderlessParams, - { designConfig } -): IBadgeApi => { - const state: IBadgeState = reactive({ - isOverstep: false, - valueRef: computed(() => api.computedValueRef()), - content: computed(() => api.computedContent()), - href: computed(() => xss.filterUrl(props.href)), - transform: computed(() => api.computedTransform()) - }) - - const api: IBadgeApi = { - state, - computedValueRef: computedValueRef({ props }), - computedContent: computedContent({ props, state }), - computedTransform: computedTransform({ props, designConfig }) - } - - return api -} diff --git a/packages/mobile/components/button/index.ts b/packages/mobile/components/button/index.ts deleted file mode 100644 index c1d4ad8b74..0000000000 --- a/packages/mobile/components/button/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Button from './src/mobile.vue' - -/* istanbul ignore next */ -Button.install = function (Vue) { - Vue.component(Button.name, Button) -} - -export default Button diff --git a/packages/mobile/components/button/src/button.ts b/packages/mobile/components/button/src/button.ts deleted file mode 100644 index b1e0514cc6..0000000000 --- a/packages/mobile/components/button/src/button.ts +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ComputedRef, ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' -import type { clearTimer, handleClick } from './renderless' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const buttonProps = { - type: { - type: String, - default: 'default' - }, - tabindex: { type: String, default: '1' }, - icon: { - type: [Object, String], - default: '' - }, - text: { - type: String, - default: '' - }, - resetTime: { - type: [Number, String], - default: 1000 - }, - nativeType: { - type: String, - default: 'button' - }, - href: { - type: String, - default: '' - }, - size: { - type: String, - default: '', - validator(val: string) { - return ['large', 'medium', 'small', 'mini', ''].includes(val) - } - }, - round: Boolean, - plain: Boolean, - circle: Boolean, - loading: Boolean, - disabled: Boolean, - autofocus: Boolean, - customClass: { - type: String, - default: '' - }, - banner: { - type: Boolean, - default: false - }, - ghost: Boolean -} - -export interface IButtonState { - timer: number - disabled: boolean - plain: ComputedRef - formDisabled: ComputedRef - buttonDisabled: ComputedRef -} - -export type IButtonRenderlessParams = ISharedRenderlessFunctionParams & { - state: IButtonState - props: IButtonProps -} - -export type IButtonProps = ExtractPropTypes - -export interface IButtonApi { - state: IButtonState - clearTimer: ReturnType - handleClick: ReturnType -} - -export type IButtonRenderlessParamUtils = ISharedRenderlessParamUtils diff --git a/packages/mobile/components/button/src/mobile.vue b/packages/mobile/components/button/src/mobile.vue deleted file mode 100644 index 727f1e092a..0000000000 --- a/packages/mobile/components/button/src/mobile.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - - diff --git a/packages/mobile/components/button/src/renderless/index.ts b/packages/mobile/components/button/src/renderless/index.ts deleted file mode 100644 index be570b3bd6..0000000000 --- a/packages/mobile/components/button/src/renderless/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { IButtonRenderlessParams, IButtonState } from '../button' -import { xss } from '@mobile-root/utils' - -export const handleClick = - ({ emit, props, state }: Pick) => - (event: MouseEvent): void => { - const urlHref = xss.filterUrl(props.href) - let reset = Number(props.resetTime) - if (urlHref) { - location.href = urlHref - } else if (props.nativeType === 'button' && reset > 0) { - state.disabled = true - - state.timer = window.setTimeout(() => { - state.disabled = false - }, reset) - } - - emit('click', event) - } - -export const clearTimer = (state: IButtonState) => (): void => clearTimeout(state.timer) diff --git a/packages/mobile/components/button/src/renderless/vue.ts b/packages/mobile/components/button/src/renderless/vue.ts deleted file mode 100644 index 7cad47a856..0000000000 --- a/packages/mobile/components/button/src/renderless/vue.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ISharedRenderlessParamHooks, IButtonProps, IButtonApi, IButtonRenderlessParamUtils } from '../button' - -import { handleClick, clearTimer } from './index' - -export const api = ['state', 'handleClick'] - -export const renderless = ( - props: IButtonProps, - { computed, onBeforeUnmount, reactive, watch, inject }: ISharedRenderlessParamHooks, - { emit, parent }: IButtonRenderlessParamUtils -) => { - parent.tinyForm = parent.tinyForm || inject('form', null) - - const state = reactive({ - timer: 0, - disabled: props.disabled, - plain: computed(() => props.plain || (parent.buttonGroup || {}).plain), - formDisabled: computed(() => (parent.tinyForm || {}).disabled), - buttonDisabled: computed( - () => props.disabled || state.disabled || (parent.buttonGroup || {}).disabled || state.formDisabled - ) - }) - - watch( - () => props.disabled, - (value) => { - state.disabled = value - }, - { immediate: true } - ) - - const api: IButtonApi = { - state, - clearTimer: clearTimer(state), - handleClick: handleClick({ emit, props, state }) - } - - onBeforeUnmount(api.clearTimer) - - return api -} diff --git a/packages/mobile/components/checkbox-group/index.ts b/packages/mobile/components/checkbox-group/index.ts deleted file mode 100644 index a437a29dae..0000000000 --- a/packages/mobile/components/checkbox-group/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import CheckboxGroup from './src/mobile.vue' - -/* istanbul ignore next */ -CheckboxGroup.install = function (Vue) { - Vue.component(CheckboxGroup.name, CheckboxGroup) -} - -export default CheckboxGroup diff --git a/packages/mobile/components/checkbox-group/src/checkbox-group.ts b/packages/mobile/components/checkbox-group/src/checkbox-group.ts deleted file mode 100644 index 27b0adefad..0000000000 --- a/packages/mobile/components/checkbox-group/src/checkbox-group.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -export const $constants = { - FORM_ITEM: 'FormItem', - FORM_CHANGE: 'form.change' -} - -export const CheckboxGroupProps = { - _constants: { - type: Object, - default: () => $constants - }, - modelValue: {}, - disabled: Boolean, - min: Number, - max: Number, - size: String, - fill: String, - textColor: String, - vertical: Boolean, - options: { - type: Array, - default: () => [] - }, - type: { - type: String, - default: 'checkbox' - }, - displayOnly: { - type: Boolean, - default: false - }, - iconPosition: String as PropType, - shape: { - type: String, - default: '' - } -} diff --git a/packages/mobile/components/checkbox-group/src/mobile.vue b/packages/mobile/components/checkbox-group/src/mobile.vue deleted file mode 100644 index 87baaaf12a..0000000000 --- a/packages/mobile/components/checkbox-group/src/mobile.vue +++ /dev/null @@ -1,46 +0,0 @@ - - - - diff --git a/packages/mobile/components/checkbox-group/src/renderless/index.ts b/packages/mobile/components/checkbox-group/src/renderless/index.ts deleted file mode 100644 index 225afd3982..0000000000 --- a/packages/mobile/components/checkbox-group/src/renderless/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -export const computedFormItemSize = (props) => () => (props.formItem || {}).formItemSize - -export const computedCheckboxGroupSize = - ({ props, formItemSize }) => - () => - props.size || formItemSize.value diff --git a/packages/mobile/components/checkbox-group/src/renderless/vue.ts b/packages/mobile/components/checkbox-group/src/renderless/vue.ts deleted file mode 100644 index 54c9efb8b4..0000000000 --- a/packages/mobile/components/checkbox-group/src/renderless/vue.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { computedFormItemSize, computedCheckboxGroupSize } from './index' - -export const api = ['state'] - -export const renderless = (props, { computed, reactive, watch, provide }, { dispatch, constants }) => { - const api = { - computedFormItemSize: computedFormItemSize(props) - } - const formItemSize = computed(() => api.computedFormItemSize()) - - const state = reactive({ - checkboxGroupSize: computed(() => api.computedCheckboxGroupSize()) - }) - - Object.assign(api, { - state, - computedCheckboxGroupSize: computedCheckboxGroupSize({ props, formItemSize }) - }) - - watch( - () => props.modelValue, - (value) => dispatch(constants.FORM_ITEM, constants.FORM_CHANGE, [value]) - ) - - provide('size', props.size) - - provide('vertical', props.vertical) - - provide('iconPosition', props.iconPosition) - - provide('shape', props.shape) - - return api -} diff --git a/packages/mobile/components/checkbox/index.ts b/packages/mobile/components/checkbox/index.ts deleted file mode 100644 index 52283c4b5c..0000000000 --- a/packages/mobile/components/checkbox/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Checkbox from './src/mobile.vue' - -/* istanbul ignore next */ -Checkbox.install = function (Vue) { - Vue.component(Checkbox.name, Checkbox) -} - -export default Checkbox diff --git a/packages/mobile/components/checkbox/src/checkbox.ts b/packages/mobile/components/checkbox/src/checkbox.ts deleted file mode 100644 index 10e9d271cf..0000000000 --- a/packages/mobile/components/checkbox/src/checkbox.ts +++ /dev/null @@ -1,168 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import { $prefix } from '@mobile-root/common' -import type { PropType } from '@mobile-root/common' -import type { ExtractPropTypes, ComputedRef } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' - -import type { - addToStore, - removeFromStore, - computedStore, - computedFormItemSize, - computedIsChecked, - computedIsLimitDisabled, - computedIsDisabled, - computedIsDisplayOnly, - computedIsGroupDisplayOnly, - computedGetModelGet, - computedIsGroup, - computedCheckboxSize, - computedGetModelSet, - mounted, - handleChange, - computedDisplayLabel, - computedIsShowText, - computedShowText -} from './renderless' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export type IconPosition = 'center' | 'top' - -export const $constants = { - FORM_ITEM: 'FormItem', - FORM_CHANGE: 'form.change', - CHECKBOX: $prefix + 'Checkbox', - CHECKBOX_GROUP: 'CheckboxGroup' -} - -export const checkboxProps = { - _constants: { - type: Object, - default: () => $constants - }, - modelValue: { - type: [String, Number, Boolean] - }, - label: { - type: [String, Number, Boolean], - default: '' - }, - indeterminate: Boolean, - disabled: Boolean, - checked: Boolean, - name: String, - trueLabel: [String, Number], - falseLabel: [String, Number], - - /* - * 当indeterminate为真时,为controls提供相关连的checkbox的id,表明元素间的控制关系 - */ - id: String, - - /* - * 当indeterminate为真时,为controls提供相关连的checkbox的id,表明元素间的控制关系 - */ - controls: { type: String, default: '' }, - border: Boolean, - size: String, - text: String, - customClass: [String, Object, Array], - validateEvent: { - type: Boolean, - default: true - }, - events: { - type: Object, - default: () => ({}) - }, - displayOnly: { - type: Boolean, - default: false - }, - iconPosition: String as PropType, - shape: { - type: String, - default: '' - } -} - -export type ICheckboxSizeEnum = 'medium' | 'small' | 'mini' -export type ICheckboxModalValue = string | number | boolean - -export interface ICheckboxChangeEvent extends Event { - target: HTMLInputElement -} -export interface ICheckboxState { - size: ICheckboxSizeEnum - vertical: boolean - focus: boolean - selfModel: ICheckboxModalValue - showLabel: boolean - isLimitExceeded: boolean - checkboxGroup: ISharedRenderlessFunctionParams['parent'] - store: ICheckboxModalValue | ICheckboxModalValue[] - isGroup: boolean - isChecked: boolean - isDisabled: boolean - checkboxSize: boolean - isLimitDisabled: boolean - formDisabled: boolean - formDisplayOnly: boolean - isDisplayOnly: boolean - isGroupDisplayOnly: boolean - displayLabel: string - inputDisabled: boolean - model: ICheckboxModalValue | ICheckboxModalValue[] - showText: boolean - isShowText: boolean - tooltipVisible: boolean - displayedValue: string -} - -export type ICheckboxProps = ExtractPropTypes - -export type ICheckboxConstants = typeof $constants - -export type ICheckboxRenderlessParams = ISharedRenderlessFunctionParams & { - state: ICheckboxState - props: ICheckboxProps - formItemSize: ComputedRef - type: string - api: ICheckboxApi -} - -export interface ICheckboxApi { - state: ICheckboxState - dispatch: ISharedRenderlessParamUtils['dispatch'] - addToStore: ReturnType - removeFromStore: ReturnType - computedStore: ReturnType - computedFormItemSize: ReturnType - computedIsChecked: ReturnType - computedIsLimitDisabled: ReturnType - computedIsDisabled: ReturnType - computedIsDisplayOnly: ReturnType - computedIsGroupDisplayOnly: ReturnType - computedGetModelGet: ReturnType - computedIsGroup: ReturnType - computedCheckboxSize: ReturnType - computedGetModelSet: ReturnType - mounted: ReturnType - handleChange: ReturnType - computedDisplayLabel: ReturnType - computedIsShowText: ReturnType - computedShowText: ReturnType -} - -export type ICheckboxRenderlessParamUtils = ISharedRenderlessParamUtils diff --git a/packages/mobile/components/checkbox/src/mobile.vue b/packages/mobile/components/checkbox/src/mobile.vue deleted file mode 100644 index 73a9a4b7b9..0000000000 --- a/packages/mobile/components/checkbox/src/mobile.vue +++ /dev/null @@ -1,80 +0,0 @@ - - - - diff --git a/packages/mobile/components/checkbox/src/renderless/index.ts b/packages/mobile/components/checkbox/src/renderless/index.ts deleted file mode 100644 index 479a17ed6a..0000000000 --- a/packages/mobile/components/checkbox/src/renderless/index.ts +++ /dev/null @@ -1,242 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { ICheckboxRenderlessParams, ICheckboxState, ICheckboxChangeEvent, ICheckboxProps } from '../checkbox' -import { isNull } from '@mobile-root/utils/type' - -export const addToStore = - ({ state, props }: Pick) => - (): void => { - if (Array.isArray(state.model) && !state.model.includes(props.label)) { - state.model.push(props.label) - } else { - state.model = props.trueLabel || true - } - } - -export const removeFromStore = - ({ state, props }: Pick) => - (): void => { - if (Array.isArray(state.model)) { - const index = state.model.indexOf(props.label) - index !== -1 && state.model.splice(index, 1) - } else { - state.model = props.falseLabel !== undefined && props.falseLabel - } - } - -export const handleChange = - ({ - state, - props, - emit, - nextTick, - dispatch, - constants - }: Pick) => - (event: ICheckboxChangeEvent): void => { - if (state.isLimitExceeded) { - return - } - - let moduleValue - const { trueLabel, falseLabel } = props - - if (event.target.checked) { - moduleValue = trueLabel === undefined ? true : trueLabel - } else { - moduleValue = falseLabel === undefined ? false : falseLabel - } - - emit('change', moduleValue, event) - - nextTick(() => { - state.isGroup && dispatch(constants.CHECKBOX_GROUP, 'change', [state.checkboxGroup.modelValue]) - }) - } - -// prettier-ignore -export const computedGetModelGet = ({ state, props }: Pick) => (): ICheckboxState['model'] => { - const model = state.isGroup - ? state.store - : props.modelValue !== undefined - ? props.modelValue - : state.selfModel - - return isNull(model) ? state.isGroup ? [] : '' : model -} - -export const computedGetModelSet = - ({ - state, - dispatch, - emit, - constants - }: Pick) => - (value: ICheckboxState['model']): void => { - if (state.isGroup) { - state.isLimitExceeded = false - - state.checkboxGroup.min !== undefined && value.length < state.checkboxGroup.min && (state.isLimitExceeded = true) - - state.checkboxGroup.max !== undefined && value.length > state.checkboxGroup.max && (state.isLimitExceeded = true) - - state.isLimitExceeded === false && dispatch(constants.CHECKBOX_GROUP, 'update:modelValue', [value]) - } else { - emit('update:modelValue', value) - state.selfModel = value - } - } - -export const computedIsChecked = - ({ state, props }: Pick) => - (): boolean => { - if (typeof state.model === 'boolean') { - return state.model - } else if (Array.isArray(state.model)) { - return state.model.includes(props.label) - } else if (!isNull(state.model)) { - return state.model === props.trueLabel - } - return false - } - -export const computedIsGroup = - ({ state, vm, constants }: Pick) => - (): boolean => { - let parentObj = vm.$parent - while (parentObj) { - if (parentObj.$options.componentName !== constants.CHECKBOX_GROUP) { - parentObj = parentObj.$parent - } else { - state.checkboxGroup = parentObj - return true - } - } - - return false - } - -export const computedStore = - ({ state, props }: Pick) => - (): ICheckboxState['store'] => - state.checkboxGroup ? state.checkboxGroup.modelValue : props.modelValue - -export const computedIsLimitDisabled = (state) => () => { - const { max, min } = state.checkboxGroup - - return ( - (!!(max || min) && state.model.length >= max && !state.isChecked) || (state.model.length <= min && state.isChecked) - ) -} - -export const computedIsDisabled = - ({ state, props }: Pick) => - (): boolean => - (state.isGroup - ? state.checkboxGroup.disabled || - state.checkboxGroup.displayOnly || - props.disabled || - props.displayOnly || - state.isLimitDisabled - : props.disabled) || state.formDisabled - -export const computedFormItemSize = (props) => (): string => (props.formItem || {}).formItemSize - -export const computedCheckboxSize = - ({ state, props, formItemSize }: Pick) => - () => { - const tempCheckboxSize = props.size || formItemSize.value - - return state.isGroup ? state.checkboxGroup.state.checkboxGroupSize || tempCheckboxSize : tempCheckboxSize - } - -export const mounted = - ({ props, emit, api, parent }: Pick) => - (): void => { - props.checked && api.addToStore() - - props.indeterminate && parent.$el.setAttribute('aria-controls', props.controls) - - emit('complete', true) - } - -export const toggleEvent = ({ - parent, - props, - type -}: Pick): void => { - const inputEl = parent.$el - - for (let ev in props.events) { - inputEl[type + 'EventListener'](ev, props.events[ev]) - } -} - -export const computedIsDisplayOnly = - ({ state, props }: Pick) => - (): boolean => - props.displayOnly || state.formDisplayOnly - -export const computedIsGroupDisplayOnly = - ({ state }: Pick) => - (): boolean => - state.isGroup && (state.checkboxGroup.displayOnly || state.formDisplayOnly) - -export const computedDisplayLabel = - ({ state, props, t }: Pick) => - (): string => { - state.showLabel = true - if (props.trueLabel !== undefined && props.falseLabel !== undefined) { - return props.modelValue ? String(props.trueLabel) : String(props.falseLabel) - } else { - return props.modelValue ? t('yes') : t('no') - } - } - -export const computedIsShowText = - ({ props }: Pick) => - (): boolean => - !isNull(props.text) || !isNull(props.label) - -export const computedShowText = - ({ props }: Pick) => - (): ICheckboxProps['label'] | ICheckboxProps['text'] => { - if (props.text || !isNull(props.text)) { - return props.text - } else { - return props.label - } - } - -export const handleLabelMouseenter = - ({ state, vm }: Pick) => - (e) => { - const label = e.target - - if (label && label.scrollWidth > label.offsetWidth) { - const tooltip = vm.$refs.tooltip - - tooltip.state.referenceElm = label - tooltip.state.popperElm && (tooltip.state.popperElm.style.display = 'none') - tooltip.doDestroy() - - state.tooltipVisible = true - state.displayedValue = label.textContent - - setTimeout(tooltip.updatePopper, 20) - } - } - -export const handleMouseleave = (state) => () => { - state.tooltipVisible = false -} diff --git a/packages/mobile/components/checkbox/src/renderless/vue.ts b/packages/mobile/components/checkbox/src/renderless/vue.ts deleted file mode 100644 index 5c0f52eb0f..0000000000 --- a/packages/mobile/components/checkbox/src/renderless/vue.ts +++ /dev/null @@ -1,160 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { - ICheckboxApi, - ICheckboxProps, - ICheckboxState, - ISharedRenderlessParamHooks, - ICheckboxRenderlessParams, - ICheckboxRenderlessParamUtils -} from '../checkbox' -import { - addToStore, - removeFromStore, - handleChange, - computedGetModelGet, - computedGetModelSet, - computedIsChecked, - computedIsGroup, - computedStore, - computedIsLimitDisabled, - computedIsDisabled, - computedIsDisplayOnly, - computedIsGroupDisplayOnly, - computedFormItemSize, - computedCheckboxSize, - computedDisplayLabel, - mounted, - toggleEvent, - computedIsShowText, - computedShowText, - handleLabelMouseenter, - handleMouseleave -} from './index' - -export const api = ['state', 'handleChange', 'computedStore', 'handleLabelMouseenter', 'handleMouseleave'] - -const initState = ({ reactive, computed, parent, api, inject, props }) => { - const state: ICheckboxState = reactive({ - size: computed(() => props.size || inject('size', null) || (parent.tinyForm || {}).size), - vertical: inject('vertical', null), - iconPosition: props.iconPosition || inject('iconPosition', 'center'), - focus: false, - selfModel: false, - showLabel: false, - isLimitExceeded: false, - checkboxGroup: null, - store: computed(() => api.computedStore()), - isGroup: computed(() => api.computedIsGroup()), - isChecked: computed(() => api.computedIsChecked()), - isDisabled: computed(() => api.computedIsDisabled()), - checkboxSize: computed(() => api.computedCheckboxSize()), - isLimitDisabled: computed(() => api.computedIsLimitDisabled()), - formDisabled: computed(() => (parent.tinyForm || {}).disabled), - formDisplayOnly: computed(() => (parent.tinyForm || {}).displayOnly), - isDisplayOnly: computed(() => api.computedIsDisplayOnly()), - isGroupDisplayOnly: computed(() => api.computedIsGroupDisplayOnly()), - displayLabel: computed(() => api.computedDisplayLabel()), - inputDisabled: computed(() => state.isDisabled || state.isDisplayOnly || state.isGroupDisplayOnly), - model: computed({ - get: () => api.computedGetModelGet(), - set: (value) => api.computedGetModelSet(value) - }), - showText: computed(() => api.computedShowText()), - isShowText: computed(() => api.computedIsShowText()), - shape: inject('shape', null) || props.shape, - tooltipVisible: false, - displayedValue: '' - }) - - return state -} - -const initApi = ({ - api, - state, - dispatch, - props, - parent, - constants, - formItemSize, - emit, - nextTick, - t, - vm -}: Pick< - ICheckboxRenderlessParams & ICheckboxRenderlessParamUtils & ISharedRenderlessParamHooks, - 'api' | 'state' | 'dispatch' | 'props' | 'parent' | 'constants' | 'formItemSize' | 'emit' | 'nextTick' | 't' | 'vm' ->) => { - Object.assign(api, { - state, - addToStore: addToStore({ state, props }), - removeFromStore: removeFromStore({ state, props }), - computedStore: computedStore({ state, props }), - computedFormItemSize: computedFormItemSize(props), - computedIsChecked: computedIsChecked({ state, props }), - computedIsLimitDisabled: computedIsLimitDisabled(state), - computedIsDisabled: computedIsDisabled({ state, props }), - computedIsDisplayOnly: computedIsDisplayOnly({ state, props }), - computedIsGroupDisplayOnly: computedIsGroupDisplayOnly({ state }), - computedGetModelGet: computedGetModelGet({ state, props }), - computedIsGroup: computedIsGroup({ state, vm, constants }), - computedCheckboxSize: computedCheckboxSize({ state, props, formItemSize }), - computedGetModelSet: computedGetModelSet({ state, dispatch, emit, constants }), - mounted: mounted({ emit, props, api, parent }), - handleChange: handleChange({ state, props, emit, nextTick, dispatch, constants }), - computedDisplayLabel: computedDisplayLabel({ state, props, t }), - computedIsShowText: computedIsShowText({ props }), - computedShowText: computedShowText({ props }), - handleLabelMouseenter: handleLabelMouseenter({ state, vm }), - handleMouseleave: handleMouseleave(state) - } as Partial) -} - -export const renderless = ( - props: ICheckboxProps, - { computed, onMounted, onBeforeUnmount, reactive, watch, inject }: ISharedRenderlessParamHooks, - { vm, parent, emit, constants, nextTick, dispatch, t }: ICheckboxRenderlessParamUtils -): ICheckboxApi => { - const api = { dispatch } as ICheckboxApi - const formItemSize = computed(() => api.computedFormItemSize()) - const state: ICheckboxState = initState({ reactive, computed, parent, api, inject, props }) - - parent.tinyForm = parent.tinyForm || inject('form', null) - - initApi({ api, state, dispatch, props, parent, constants, formItemSize, emit, nextTick, t, vm }) - - watch( - () => props.modelValue, - (value) => props.validateEvent && api.dispatch(constants.FORM_ITEM, constants.FORM_CHANGE, value) - ) - - watch( - () => props.checked, - (value) => { - value ? api.addToStore() : api.removeFromStore() - } - ) - - onBeforeUnmount(() => { - toggleEvent({ parent, props, type: 'remove' }) - }) - - onMounted(() => { - dispatch('Tooltip', 'tooltip-update') - toggleEvent({ parent, props, type: 'add' }) - api.mounted() - }) - - return api -} diff --git a/packages/mobile/components/container/index.ts b/packages/mobile/components/container/index.ts deleted file mode 100644 index 7a32ea9c80..0000000000 --- a/packages/mobile/components/container/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Container from './src/mobile.vue' - -/* istanbul ignore next */ -Container.install = function (Vue) { - Vue.component(Container.name, Container) -} - -export default Container diff --git a/packages/mobile/components/container/src/container.ts b/packages/mobile/components/container/src/container.ts deleted file mode 100644 index 2e0682e184..0000000000 --- a/packages/mobile/components/container/src/container.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -export const $constants = { - DEFAULT: 'default', - SIMPLE: 'simple', - LEGEND: 'legend', - CLASSIC: 'classic', - FASHION: 'fashion' -} - -export const containerProps = { - _constants: { - type: Object, - default: () => $constants - }, - pattern: { - type: String, - default: 'default', - validator: (value: string) => !!$constants[value.toUpperCase()] - }, - headerHeight: { - type: [Number, String], - default: 60 - }, - asideWidth: { - type: [Number, String], - default: 200 - }, - footerHeight: { - type: [Number, String], - default: 60 - }, - - // mobile - leftWidth: { - type: [Number, String], - default: 60 - }, - rightWidth: { - type: [Number, String], - default: 44 - } -} diff --git a/packages/mobile/components/container/src/mobile.vue b/packages/mobile/components/container/src/mobile.vue deleted file mode 100644 index 3e3bd2dea2..0000000000 --- a/packages/mobile/components/container/src/mobile.vue +++ /dev/null @@ -1,38 +0,0 @@ - - - - diff --git a/packages/mobile/components/container/src/renderless/index.ts b/packages/mobile/components/container/src/renderless/index.ts deleted file mode 100644 index a0ca638ad3..0000000000 --- a/packages/mobile/components/container/src/renderless/index.ts +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { isNumber } from '@mobile-root/utils/type' - -export const computedShowHeader = - ({ constants, props }) => - () => - props.pattern !== constants.SIMPLE - -export const computedShowFooter = - ({ constants, props }) => - () => - props.pattern === constants.LEGEND || props.pattern === constants.CLASSIC - -export const computedShowAside = - ({ constants, props }) => - () => - props.pattern !== constants.CLASSIC - -const transferWidthOrHeight = (value) => (isNumber(value) ? value + 'px' : value) - -export const computedHeaderStyle = - ({ constants, props }) => - () => { - if (props.pattern === constants.FASHION) { - return { - height: transferWidthOrHeight(props.headerHeight), - left: transferWidthOrHeight(props.asideWidth) - } - } - - return { - height: transferWidthOrHeight(props.headerHeight) - } - } - -export const computedAsideStyle = - ({ constants, props }) => - () => { - if (props.pattern === constants.SIMPLE || props.pattern === constants.FASHION) { - return { - top: transferWidthOrHeight(0), - width: transferWidthOrHeight(props.asideWidth) - } - } - - return { - width: transferWidthOrHeight(props.asideWidth), - top: transferWidthOrHeight(props.headerHeight) - } - } - -export const computedMainStyle = - ({ constants, props }) => - () => { - if (props.pattern === constants.DEFAULT || props.pattern === constants.FASHION) { - return { - top: transferWidthOrHeight(props.headerHeight), - left: transferWidthOrHeight(props.asideWidth), - bottom: transferWidthOrHeight(0) - } - } - - if (props.pattern === constants.LEGEND) { - return { - top: transferWidthOrHeight(props.headerHeight), - left: transferWidthOrHeight(props.asideWidth), - bottom: transferWidthOrHeight(props.footerHeight) - } - } - - if (props.pattern === constants.SIMPLE) { - return { - top: transferWidthOrHeight(0), - left: transferWidthOrHeight(props.asideWidth), - bottom: transferWidthOrHeight(0) - } - } - - if (props.pattern === constants.CLASSIC) { - return { - top: transferWidthOrHeight(props.headerHeight), - left: transferWidthOrHeight(0), - bottom: transferWidthOrHeight(props.footerHeight) - } - } - } - -export const computedFooterStyle = - ({ constants, props }) => - () => { - if (props.pattern === constants.CLASSIC) { - return { - height: transferWidthOrHeight(props.footerHeight), - left: transferWidthOrHeight(0) - } - } else if (props.pattern === constants.LEGEND) { - return { - height: transferWidthOrHeight(props.footerHeight), - left: transferWidthOrHeight(props.asideWidth) - } - } - - return { - height: transferWidthOrHeight(props.footerHeight) - } - } - -// mobile -export const computedLeftStyle = - ({ constants, props }) => - () => { - return { - width: transferWidthOrHeight(props.leftWidth) - } - } - -export const computedShowRight = - ({ constants, props }) => - () => { - return props.pattern !== constants.DEFAULT - } - -export const computedRightStyle = - ({ constants, props }) => - () => { - return { - width: transferWidthOrHeight(props.rightWidth) - } - } diff --git a/packages/mobile/components/container/src/renderless/vue.ts b/packages/mobile/components/container/src/renderless/vue.ts deleted file mode 100644 index 203aceeb4f..0000000000 --- a/packages/mobile/components/container/src/renderless/vue.ts +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - computedShowHeader, - computedShowAside, - computedShowFooter, - computedHeaderStyle, - computedAsideStyle, - computedMainStyle, - computedFooterStyle, - computedLeftStyle, - computedShowRight, - computedRightStyle -} from './index' - -export const api = ['state'] - -export const renderless = (props, { computed, reactive }, { constants }) => { - const api = {} - const state = reactive({ - showAside: computed(() => api.computedShowAside()), - showHeader: computed(() => api.computedShowHeader()), - showFooter: computed(() => api.computedShowFooter()), - mainStyle: computed(() => api.computedMainStyle()), - asideStyle: computed(() => api.computedAsideStyle()), - headerStyle: computed(() => api.computedHeaderStyle()), - footerStyle: computed(() => api.computedFooterStyle()), - showRight: computed(() => api.computedShowRight()), - leftStyle: computed(() => api.computedLeftStyle()), - rightStyle: computed(() => api.computedRightStyle()) - }) - - Object.assign(api, { - state, - computedShowAside: computedShowAside({ constants, props }), - computedShowHeader: computedShowHeader({ constants, props }), - computedShowFooter: computedShowFooter({ constants, props }), - computedMainStyle: computedMainStyle({ constants, props }), - computedAsideStyle: computedAsideStyle({ constants, props }), - computedHeaderStyle: computedHeaderStyle({ constants, props }), - computedFooterStyle: computedFooterStyle({ constants, props }), - computedLeftStyle: computedLeftStyle({ constants, props }), - computedShowRight: computedShowRight({ constants, props }), - computedRightStyle: computedRightStyle({ constants, props }) - }) - - return api -} diff --git a/packages/mobile/components/date-picker/index.ts b/packages/mobile/components/date-picker/index.ts deleted file mode 100644 index d7276e239c..0000000000 --- a/packages/mobile/components/date-picker/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import DatePicker from './src/mobile.vue' - -/* istanbul ignore next */ -DatePicker.install = function (Vue) { - Vue.component(DatePicker.name, DatePicker) -} - -export default DatePicker diff --git a/packages/mobile/components/date-picker/src/date-picker.ts b/packages/mobile/components/date-picker/src/date-picker.ts deleted file mode 100644 index 9aa2f6c25a..0000000000 --- a/packages/mobile/components/date-picker/src/date-picker.ts +++ /dev/null @@ -1,267 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { PropType } from '@mobile-root/common' -import { iconClose } from '@opentiny/vue-icon' -import type { ComputedRef, ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -const currentYear = new Date().getFullYear() - -export const $constants = { - MonthDay: 32, - Minutes: 59, - Hours: 23, - TotalMonth: 12, - Max: 'max', - Min: 'min', - Hour: 'hour', - Minute: 'minute', - CapYear: 'Year', - CapMonth: 'Month', - CapDate: 'Date', - CapHour: 'Hour', - CapMinute: 'Minute', - YearMonth: 'year-month', - DateTime: 'datetime', - Date: 'date', - HookMounted: 'hook-mounted', - Hidden: 'hidden', - Year: 'year', - Day: 'day' -} - -const validator = (value) => { - const result = - value === null || - value === undefined || - typeof value === 'string' || - value instanceof String || - (Array.isArray(value) && - value.length === 2 && - value.every((item) => typeof item === 'string' || item instanceof String)) - - return result -} - -export const datePickerProps = { - tabindex: { - type: String, - default: '1' - }, - timeFormat: String, - suffixIcon: Object, - label: String, - shape: String, - tip: String, - changeOnConfirm: { - type: Boolean, - default: false - }, - popperAppendToBody: { - type: Boolean, - default: true - }, - isutc8: { - type: Boolean, - default: false - }, - dbTimezone: Number, - timezoneOffset: Number, - iso8601: Boolean, - autoFormat: { - type: Boolean, - default: false - }, - title: String, - blank: { - type: Boolean, - default: false - }, - - type: { - type: String as PropType< - | 'date' - | 'dates' - | 'daterange' - | 'week' - | 'month' - | 'monthrange' - | 'year' - | 'years' - | 'yearrange' - | 'datetime' - | 'datetimerange' - >, - default: 'date' - }, - _constants: { - type: Object, - default: () => $constants - }, - timeArrowControl: Boolean, - timeEditable: { - type: Boolean, - default: true - }, - size: String, - format: String, - valueFormat: String, - readonly: Boolean, - placeholder: String, - startPlaceholder: String, - endPlaceholder: String, - prefixIcon: Object, - clearIcon: { - type: Object, - default() { - return iconClose() - } - }, - name: { - default: '', - validator - }, - disabled: Boolean, - clearable: { - type: Boolean, - default: true - }, - id: { - default: '', - validator - }, - popperClass: String, - editable: { - type: Boolean, - default: true - }, - align: { - type: String, - default: 'left' - }, - modelValue: {}, - defaultValue: {}, - defaultTime: {}, - rangeSeparator: { - type: [Object, String], - default: '-' - }, - pickerOptions: {}, - unlinkPanels: Boolean, - validateEvent: { - type: Boolean, - default: true - }, - isRange: Boolean, - arrowControl: Boolean, - timezoneData: {}, - showTimezone: { - type: Boolean, - default: false - }, - defaultTimezone: {}, - visible: Boolean, - minDate: { - type: Date, - default: () => new Date(currentYear - 10, 0, 1), - validator: (val: Date) => Object.prototype.toString.call(val) === '[object Date]' && !isNaN(val.getTime()) - }, - maxDate: { - type: Date, - default: () => new Date(currentYear + 10, 11, 31), - validator: (val: Date) => Object.prototype.toString.call(val) === '[object Date]' && !isNaN(val.getTime()) - }, - formatter: { - type: Function, - default: (type, value) => value - }, - componentName: { type: String, default: 'DatePicker' }, - displayOnly: { - type: Boolean, - default: false - }, - step: { - type: Object, - default() { - return { hour: 1, minute: 1, second: 1 } - } - }, - showWeekNumber: { - type: Boolean, - default: false - }, - formatWeeks: Function, - changeCompat: { - type: Boolean, - default: false - } -} - -export type IDatePickerProps = ExtractPropTypes - -export type IDatePickerConstants = typeof $constants - -export type IDatePickerRenderlessParamUtils = ISharedRenderlessParamUtils - -export interface IDatePickerColumn { - type: string -} - -export interface IDatePickerOriginColumn extends IDatePickerColumn { - values: number[] -} - -export interface IDatePickerState { - visible: boolean - innerValue: Date - ranges: ComputedRef - originColumns: ComputedRef - columns: ComputedRef - displayValue: string - isReadonly: boolean - clearable: boolean -} - -export interface IDatePickerApi { - state: IDatePickerState - getOriginColumns: () => IDatePickerOriginColumn[] - onCancel: () => void - getColumns: () => IDatePickerColumn[] - clearDisplayValue: () => void - getDisplayValue: () => string - showPickerAndLockScroll: () => void - updateColumnValue: () => void - - formatValue: (value: number) => Date - getMonthEndDay: (year: number, month: number) => number - hookMounted: () => void - - getBoundary: ({ type, value }: { type: string; value: Date }) => { - [x: string]: number - } - updateInnerValue: () => void - getRanges: () => { - type: string - range: number[] - }[] - - onConfirm: () => void - onChange: () => void -} - -export type IDatePickerRenderlessParams = ISharedRenderlessFunctionParams & { - api: IDatePickerApi - state: IDatePickerState - props: IDatePickerProps -} diff --git a/packages/mobile/components/date-picker/src/mobile.vue b/packages/mobile/components/date-picker/src/mobile.vue deleted file mode 100644 index 3d1cb72502..0000000000 --- a/packages/mobile/components/date-picker/src/mobile.vue +++ /dev/null @@ -1,55 +0,0 @@ - - - - diff --git a/packages/mobile/components/date-picker/src/renderless/index.ts b/packages/mobile/components/date-picker/src/renderless/index.ts deleted file mode 100644 index bff14d47c0..0000000000 --- a/packages/mobile/components/date-picker/src/renderless/index.ts +++ /dev/null @@ -1,354 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { - IDatePickerColumn, - IDatePickerConstants, - IDatePickerOriginColumn, - IDatePickerProps, - IDatePickerRenderlessParams, - IDatePickerState -} from '../date-picker' - -export const getMonthEndDay = - (constants: IDatePickerConstants) => - (year: number, month: number): number => - constants.MonthDay - new Date(year, month - 1, constants.MonthDay).getDate() - -export const getTrueValue = (value: string): number => { - if (!value) { - return 0 - } - - while (isNaN(parseInt(value, 10))) { - if (value.length > 1) { - value = value.slice(1) - } else { - return 0 - } - } - - return parseInt(value, 10) -} - -export const getBoundary = - ({ api, constants, props }: Pick) => - ({ - type, - value: val - }: { - type: string - value: Date - }): { - [x: string]: number - } => { - const boundary = props[`${type}${constants.CapDate}`] - const year = boundary.getFullYear() - let month = 1 - let date = 1 - let hour = 0 - let minute = 0 - - if (type === constants.Max) { - month = constants.TotalMonth - date = api.getMonthEndDay(val.getFullYear(), val.getMonth() + 1) - hour = constants.Hours - minute = constants.Minutes - } - - if (val.getFullYear() === year) { - month = boundary.getMonth() + 1 - if (val.getMonth() + 1 === month) { - date = boundary.getDate() - if (val.getDate() === date) { - hour = boundary.getHours() - if (val.getHours() === hour) { - minute = boundary.getMinutes() - } - } - } - } - - return { - [`${type}${constants.CapYear}`]: year, - [`${type}${constants.CapMonth}`]: month, - [`${type}${constants.CapDate}`]: date, - [`${type}${constants.CapHour}`]: hour, - [`${type}${constants.CapMinute}`]: minute - } - } - -export const updateInnerValue = - ({ - api, - constants, - props, - refs, - state - }: Pick) => - () => { - const indexes = refs.picker && refs.picker.getIndexes() - - const getValue = (index) => { - const { values } = state.originColumns[index] - return getTrueValue(values[indexes[index]]) - } - - const year = getValue(0) - const month = getValue(1) - const maxDate = api.getMonthEndDay(year, month) - - let date - if (props.type === constants.YearMonth) { - date = 1 - } else { - date = getValue(2) - } - - date = date > maxDate ? maxDate : date - - let hour = 0 - let minute = 0 - - if (props.type === constants.DateTime) { - hour = getValue(3) - minute = getValue(4) - } - - const value = new Date(year, month - 1, date, hour, minute) - - state.innerValue = api.formatValue(value) - } - -export const formatValue = - (props: IDatePickerProps) => - (value: number): Date => { - if (!Object.prototype.toString.call(value) === '[object Date]' && !isNaN(value.getTime())) { - value = props.minDate - } - - value = Math.max(value, props.minDate.getTime()) - value = Math.min(value, props.maxDate.getTime()) - - return new Date(value) - } - -export const onChange = - ({ api, emit, refs, nextTick }: Pick) => - () => { - api.updateInnerValue() - - nextTick(() => { - nextTick(() => { - emit('change', refs.picker) - document.body.style.overflow = '' - }) - }) - } - -export const padZero = (num: number, targetLength = 2): string => { - let str = String(num) - - while (str.length < targetLength) { - str = '0' + str - } - - return str -} - -export const updateColumnValue = - ({ - constants, - nextTick, - props, - refs, - state - }: Pick) => - () => { - const value = state.innerValue - const { formatter } = props - - let values = [ - formatter('year', `${value.getFullYear()}`), - formatter('month', padZero(value.getMonth() + 1)), - formatter('day', padZero(value.getDate())) - ] - - if (props.type === constants.DateTime) { - values.push(formatter('hour', padZero(value.getHours())), formatter('minute', padZero(value.getMinutes()))) - } - - if (props.type === constants.YearMonth) { - values = values.slice(0, 2) - } - - nextTick(() => { - refs.picker.setValues(values) - }) - } - -export const getRanges = - ({ api, constants, props, state }) => - (): { - type: string - range: number[] - }[] => { - const { maxYear, maxDate, maxMonth, maxHour, maxMinute } = api.getBoundary({ - type: constants.Max, - value: state.innerValue - }) - - const { minYear, minDate, minMonth, minHour, minMinute } = api.getBoundary({ - type: constants.Min, - value: state.innerValue - }) - - const result: { - type: string - range: number[] - }[] = [ - { - type: constants.Year, - range: [minYear, maxYear] - }, - { - type: 'month', - range: [minMonth, maxMonth] - }, - { - type: constants.Day, - range: [minDate, maxDate] - }, - { - type: constants.Hour, - range: [minHour, maxHour] - }, - { - type: constants.Minute, - range: [minMinute, maxMinute] - } - ] - - if (props.type === constants.Date) { - result.splice(3, 2) - } - if (props.type === constants.YearMonth) { - result.splice(2, 3) - } - return result - } - -export function times(n: number, iteratee: (index: number) => string): number[] { - let index = -1 - const result = Array(n) - - while (++index < n) { - result[index] = iteratee(index) - } - - return result -} - -export const getOriginColumns = (state: IDatePickerState) => (): IDatePickerOriginColumn[] => - state.ranges.map(({ type, range: rangeArr }) => { - let values = times(rangeArr[1] - rangeArr[0] + 1, (index) => { - const value = padZero(rangeArr[0] + index) - return value - }) - - return { - type, - values - } - }) - -export const getColumns = - ({ props, state }: Pick) => - (): IDatePickerColumn[] => - state.originColumns.map((column) => ({ - values: column.values.map((value) => props.formatter(column.type, value)) - })) - -export const onConfirm = - ({ api, emit, state }: Pick) => - () => { - state.visible = false - emit('confirm', state.innerValue) - emit('update:modelValue', state.innerValue) - emit('update:visible', state.visible) - document.body.style.overflow = '' - state.displayValue = api.getDisplayValue() - state.clearable = false - } - -export const onCancel = - ({ emit, state }: Pick) => - () => { - state.visible = false - emit('cancel') - emit('update:visible', state.visible) - document.body.style.overflow = '' - } - -export const getDisplayValue = - ({ constants, DATE, props, state }: Pick) => - (): string => { - const format = function (value: Date, fmt: string): string { - const o = { - 'M+': value.getMonth() + 1, - 'd+': value.getDate(), - 'h+': value.getHours(), - 'm+': value.getMinutes(), - 's+': value.getSeconds(), - 'q+': Math.floor((value.getMonth() + 3) / 3), - 'S': value.getMilliseconds() - } - - if (/(y+)/.test(fmt)) { - fmt = fmt.replace(RegExp.$1, String(value.getFullYear()).substr(4 - RegExp.$1.length)) - } - for (let k in o) { - if (new RegExp('(' + k + ')').test(fmt)) { - fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(String(o[k]).length)) - } - } - return fmt - } - - return format(state.innerValue, props.type === constants.DateTime ? DATE.Datetime : DATE.Date) - } - -export const hookMounted = - ({ - constants, - parent, - refs, - nextTick - }: Pick) => - () => { - nextTick(() => { - parent.$emit(constants.HookMounted, refs.refrence.$el) - }) - } - -export const showPickerAndLockScroll = - ({ constants, state }: Pick) => - () => { - state.visible = true - document.body.style.overflow = constants.Hidden - state.isReadonly = true - } - -export const clearDisplayValue = (state: IDatePickerState) => () => { - state.displayValue = '' - state.clearable = true -} diff --git a/packages/mobile/components/date-picker/src/renderless/vue.ts b/packages/mobile/components/date-picker/src/renderless/vue.ts deleted file mode 100644 index b7089018a2..0000000000 --- a/packages/mobile/components/date-picker/src/renderless/vue.ts +++ /dev/null @@ -1,151 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - getBoundary, - clearDisplayValue, - showPickerAndLockScroll, - hookMounted, - getMonthEndDay, - getDisplayValue, - getRanges, - onConfirm, - onCancel, - getOriginColumns, - getColumns, - updateInnerValue, - formatValue, - onChange, - updateColumnValue -} from './index' -import { DATE } from '@mobile-root/utils' -import type { - IDatePickerApi, - IDatePickerProps, - IDatePickerRenderlessParamUtils, - IDatePickerState, - ISharedRenderlessParamHooks -} from '../date-picker' - -export const api = [ - 'state', - 'clearDisplayValue', - 'showPickerAndLockScroll', - 'hookMounted', - 'onConfirm', - 'onCancel', - 'onChange' -] - -const setWatchFn = ({ api, watch, props, state, emit }) => { - watch( - () => props.minDate, - () => api.updateInnerValue(), - { - lazy: true - } - ) - watch( - () => props.visible, - (value) => (state.visible = value), - { lazy: true } - ) - watch( - () => props.maxDate, - () => api.updateInnerValue(), - { - lazy: true - } - ) - watch( - () => props.modelValue, - (value) => { - if (value) { - const val = api.formatValue(new Date(value)) - if (val.valueOf() !== state.innerValue.valueOf()) { - state.innerValue = val - } - state.displayValue = api.getDisplayValue() - } - }, - { - immediate: true - } - ) - watch( - () => state.columns, - () => api.updateColumnValue(), - { - lazy: true - } - ) - watch( - () => state.innerValue, - (value) => emit('input', value), - { - lazy: true - } - ) -} - -export const renderless = ( - props: IDatePickerProps, - { computed, onMounted, reactive, watch }: ISharedRenderlessParamHooks, - { constants, emit, nextTick, refs, parent }: IDatePickerRenderlessParamUtils -): IDatePickerApi => { - const api: IDatePickerApi = { - formatValue: formatValue(props), - getMonthEndDay: getMonthEndDay(constants), - hookMounted: hookMounted({ constants, parent, refs, nextTick }) - } - - const state: IDatePickerState = reactive({ - visible: false, - innerValue: formatValue(props)(props.modelValue), - ranges: computed(() => api.getRanges()), - originColumns: computed(() => api.getOriginColumns()), - columns: computed(() => api.getColumns()), - displayValue: '', - isReadonly: false, - clearable: props.clearable - }) - - Object.assign(api, { - state, - getOriginColumns: getOriginColumns(state), - onCancel: onCancel({ emit, state }), - getColumns: getColumns({ props, state }), - clearDisplayValue: clearDisplayValue(state), - getDisplayValue: getDisplayValue({ constants, DATE, props, state }), - showPickerAndLockScroll: showPickerAndLockScroll({ constants, state }), - updateColumnValue: updateColumnValue({ constants, nextTick, props, refs, state }) - }) - - api.getBoundary = getBoundary({ api, constants, props }) - api.updateInnerValue = updateInnerValue({ api, constants, props, refs, state }) - api.getRanges = getRanges({ api, constants, props, state }) - - setWatchFn({ api, watch, props, state, emit }) - - onMounted(() => { - api.updateColumnValue() - - nextTick(() => { - api.updateInnerValue() - }) - }) - - return Object.assign(api, { - onConfirm: onConfirm({ api, emit, state }), - onChange: onChange({ api, emit, refs, nextTick }) - }) -} diff --git a/packages/mobile/components/dialog-box/index.ts b/packages/mobile/components/dialog-box/index.ts deleted file mode 100644 index 6a16aee916..0000000000 --- a/packages/mobile/components/dialog-box/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import DialogBox from './src/mobile.vue' - -DialogBox.install = function (Vue) { - Vue.component(DialogBox.name, DialogBox) -} - -export default DialogBox diff --git a/packages/mobile/components/dialog-box/src/dialog-box.ts b/packages/mobile/components/dialog-box/src/dialog-box.ts deleted file mode 100644 index 62dfe4f241..0000000000 --- a/packages/mobile/components/dialog-box/src/dialog-box.ts +++ /dev/null @@ -1,234 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { $prefix } from '@mobile-root/common' -import type { ExtractPropTypes } from 'vue' -import type { - handleCancel, - handleConfirm, - updatePopper, - handleWrapperClick, - useMouseEventDown, - useMouseEventUp, - hide, - handleClose, - watchVisible, - computedStyle, - computedBodyStyle, - mounted, - unMounted, - computedAnimationName, - afterEnter, - afterLeave, - hideScrollbar, - showScrollbar, - handleDrag -} from './renderless' - -import type { - ISharedRenderlessFunctionParams, - ISharedRenderlessParamHooks, - ISharedRenderlessParamUtils -} from '@mobile-root/shared.type' - -export type { ISharedRenderlessParamHooks } - -export const $constants = { - DIALOG_SLIDER_RIGHT: 'dialog-slideRight', - DIALOG_FADE: 'dialog-fade', - SELECT_DROPDOWN: $prefix + 'SelectDropdown', - DROPDOWN_MENU: $prefix + 'DropdownMenu', - DIALOG_BOX_CLASS: 'div.tiny-dialog-box', - PC_SCROLL_LOCK_CLASS: 'dialog-box__scroll-lock', - MOBILE_SCROLL_LOCK_CLASS: 'mobile-dialog-box__scroll-lock', - Mode: 'pc', - scrollLockClass(mode) { - return mode === this.Mode ? this.PC_SCROLL_LOCK_CLASS : this.MOBILE_SCROLL_LOCK_CLASS - } -} - -export const dialogBoxProps = { - _constants: { - type: Object, - default: () => $constants - }, - appendToBody: { - type: Boolean, - default: () => false - }, - beforeClose: Function, - center: { - type: Boolean, - default: () => false - }, - closeOnClickModal: { - type: Boolean, - default: () => true - }, - closeOnPressEscape: { - type: Boolean, - default: () => true - }, - destroyOnClose: { - type: Boolean, - default: () => false - }, - dialogClass: { - type: String, - default: () => '' - }, - draggable: { - type: Boolean, - default: () => false - }, - dragOutsideWindow: { - type: Boolean, - default: () => false - }, - fullscreen: { - type: Boolean, - default: () => false - }, - isFormReset: { - type: Boolean, - default: () => true - }, - lockScroll: { - type: Boolean, - default: () => true - }, - modal: { - type: Boolean, - default: () => true - }, - modalAppendToBody: { - type: Boolean, - default: () => true - }, - resize: { - type: Boolean, - default: () => false - }, - rightSlide: { - type: Boolean, - default: () => false - }, - showClose: { - type: Boolean, - default: () => true - }, - showHeader: { - type: Boolean, - default: () => true - }, - title: { - type: String, - default: () => '' - }, - top: String, - visible: { - type: Boolean, - default: () => false - }, - width: { - type: String, - default: () => '500px' - }, - maxHeight: { - type: String, - default: () => '' - } -} - -export type IDialogBoxProps = ExtractPropTypes - -export type IDialogBoxConstants = typeof $constants - -export interface IDialogBoxState { - emitter: ReturnType['emitter']> - key: number - x: number | string | null - y: number | string | null - top: number | string | null - left: number | string | null - max: number | string | null - move: boolean - closed: boolean - dragable: boolean - isFull: boolean - style: { [key: string]: string | number } - bodyStyle: { [key: string]: string | number } - animationName: string - opened?: boolean - rendered?: boolean - mouseUpWrapperFlag: boolean - mouseDownWrapperFlag: boolean -} - -export interface IDialogBoxApi { - state: IDialogBoxState - open: (options: any) => void - close: () => void - broadcast: ISharedRenderlessParamUtils['broadcast'] - handleCancel: ReturnType - handleConfirm: ReturnType - updatePopper: ReturnType - handleWrapperClick: ReturnType - useMouseEventDown: ReturnType - useMouseEventUp: ReturnType - hide: ReturnType - handleClose: ReturnType - watchVisible: ReturnType - computedStyle: ReturnType - computedBodyStyle: ReturnType - mounted: ReturnType - unMounted: ReturnType - computedAnimationName: ReturnType - afterEnter: ReturnType - afterLeave: ReturnType - hideScrollbar: ReturnType - showScrollbar: ReturnType - handleDrag: ReturnType -} - -export type IDialogBoxRenderlessParams = ISharedRenderlessFunctionParams & { - api: IDialogBoxApi - props: IDialogBoxProps - state: IDialogBoxState -} - -export type IDialogBoxRenderlessParamUtils = ISharedRenderlessParamUtils - -export type IDialogBoxMergeStateParam = Pick & { - usePopups: object -} - -export type IDialogBoxInitApiParam = Pick< - IDialogBoxRenderlessParams, - 'api' | 'state' | 'parent' | 'props' | 'emit' | 'constants' | 'nextTick' | 'vm' | 'broadcast' -> & { usePopups: object; lockScrollClass: string } - -export interface IDialogBoxInitWatchParam { - watch: ISharedRenderlessParamHooks['watch'] - state: IDialogBoxState - api: IDialogBoxApi - props: IDialogBoxProps -} - -export interface IDialogBoxStyle { - width?: string | number - height?: string | number - maxHeight?: string | number - top?: string | number - right?: string | number - left?: string | number -} diff --git a/packages/mobile/components/dialog-box/src/mobile.vue b/packages/mobile/components/dialog-box/src/mobile.vue deleted file mode 100644 index e489e08906..0000000000 --- a/packages/mobile/components/dialog-box/src/mobile.vue +++ /dev/null @@ -1,56 +0,0 @@ - - - - diff --git a/packages/mobile/components/dialog-box/src/renderless/index.ts b/packages/mobile/components/dialog-box/src/renderless/index.ts deleted file mode 100644 index f39df0547a..0000000000 --- a/packages/mobile/components/dialog-box/src/renderless/index.ts +++ /dev/null @@ -1,365 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { on, off, addClass, removeClass } from '@mobile-root/utils/deps/dom' -import { emitEvent } from '@mobile-root/utils/event' -import { getDomNode } from '@mobile-root/utils/deps/dom' -import type { IDialogBoxRenderlessParams, IDialogBoxStyle } from '../dialog-box' - -export const computedAnimationName = - ({ constants, props }: Pick) => - (): string => - props.rightSlide ? constants.DIALOG_SLIDER_RIGHT : constants.DIALOG_FADE - -export const computedAddUnit = (value: string): string => (isNaN(Number(value)) ? value : value + 'px') - -export const computedStyle = - ({ props, state, designConfig }: Pick) => - (): IDialogBoxStyle => { - let style = {} as IDialogBoxStyle - let { width, top, rightSlide, maxHeight } = props - - if (top === undefined) { - top = rightSlide ? '0' : designConfig?.state?.top ? '' : '15vh' - } - - width = computedAddUnit(width) - top = computedAddUnit(top) - maxHeight = computedAddUnit(maxHeight) - - if (!state.isFull) { - style.width = width - style.top = state.top || top - style.maxHeight = maxHeight - - if (rightSlide) { - style.right = 0 - style.height = 'calc(100vh - ' + style.top + ')' - } else { - style.left = state.left || 'calc((100vw - ' + width + ') / 2)' - } - } - - if (state.dragStyle) { - style = { ...style, ...state.dragStyle } - } - - return style - } - -export const computedBodyStyle = - ({ props }: Pick) => - (): { maxHeight?: string } => { - const style = { - maxHeight: '' - } - let { maxHeight } = props - - if (maxHeight) { - style.maxHeight = 'none' - } - return style - } - -export const watchVisible = - ({ - api, - constants, - emit, - nextTick, - parent, - props, - vm, - state - }: Pick< - IDialogBoxRenderlessParams, - 'api' | 'constants' | 'emit' | 'nextTick' | 'parent' | 'props' | 'vm' | 'state' - >) => - (val: boolean): void => { - const el = vm.$el - - if (props.lockScroll) { - val ? api.showScrollbar() : api.hideScrollbar() - } - - state.move = false - state.isFull = props.fullscreen - - emit('update:visible', val) - - if (val) { - state.closed = false - emit('open') - /* istanbul ignore next */ - on(el, 'scroll', api.updatePopper) - - nextTick(() => { - vm.$refs.dialog.scrollTop = 0 - }) - - if (props.appendToBody) { - document.body.appendChild(el) - } - } else { - /* istanbul ignore next */ - off(el, 'scroll', api.updatePopper) - - if (!state.closed) { - state.emitter.emit('boxclose', props.isFormReset) - emit('close') - } - - if (props.destroyOnClose) { - nextTick(() => state.key++) - } - - if (props.rightSlide) { - const dialogBoxDom = el.querySelector(constants.DIALOG_BOX_CLASS) || el - dialogBoxDom.style.left = '' - } - } - } - -export const mounted = - ({ api, parent, props }: Pick) => - (): void => { - if (props.lockScroll && props.visible) { - api.showScrollbar() - } - - if (props.visible) { - const el = vm.$el - - api.open() - - if (props.appendToBody) { - document.body.appendChild(el) - } - } - } - -export const unMounted = - ({ api, parent, props }: Pick) => - (): void => { - const el = parent.$el - - api.hideScrollbar() - - if (props.appendToBody && el && el.parentNode) { - el.parentNode.removeChild(el) - } - } - -export const useMouseEventDown = - ({ state }: Pick) => - (event: MouseEvent): void => { - state.mouseDownWrapperFlag = false - if (/tiny-dialog-box__wrapper/.test(event.target.className) && event.type === 'mousedown') { - state.mouseDownWrapperFlag = true - } - } - -export const useMouseEventUp = - ({ state }: Pick) => - (event: MouseEvent): void => { - state.mouseUpWrapperFlag = false - if (/tiny-dialog-box__wrapper/.test(event.target.className) && event.type === 'mouseup') { - state.mouseUpWrapperFlag = true - } - } - -export const handleWrapperClick = - ({ api, props, state }: Pick) => - (): void => { - if (!props.closeOnClickModal) { - return - } - // mouseDownFlag、mouseUpFlag判断是否点击wrapper状态 - if (state.mouseDownWrapperFlag && state.mouseUpWrapperFlag) { - api.handleClose('mask') - } - } - -export const handleClose = - ({ - api, - constants, - emit, - parent, - props - }: Pick) => - (type = 'close') => { - if (typeof props.beforeClose === 'function' && props.beforeClose(type) === false) { - return - } - - const el = parent.$el - - if (props.rightSlide) { - const dialogBoxDom = (el.querySelector(constants.DIALOG_BOX_CLASS) || el) as HTMLElement - dialogBoxDom.style.left = '' - } - - if (!emitEvent(emit, 'before-close', api.hide)) { - return - } - - api.hide() - } - -export const hide = - ({ api, emit, state, props }: Pick) => - (cancel?: boolean): void => { - if (cancel !== false) { - state.emitter.emit('boxclose', props.isFormReset) - - emit('update:visible', false) - emit('change', false) - emit('close') - - state.closed = true - api.hideScrollbar() - } - } - -export const handleConfirm = - ({ api, emit }: Pick) => - (): void => { - emit('confirm') - api.handleClose() - } - -export const handleCancel = - ({ api, emit }: Pick) => - (): void => { - emit('cancel') - api.handleClose() - } - -export const updatePopper = - ({ api, constants }: Pick) => - (): void => { - api.broadcast(constants.SELECT_DROPDOWN, 'updatePopper') - api.broadcast(constants.DROPDOWN_MENU, 'updatePopper') - } - -export const afterEnter = (emit: IDialogBoxRenderlessParams['emit']) => (): void => { - emit('opened') -} - -export const afterLeave = (emit: IDialogBoxRenderlessParams['emit']) => (): void => { - emit('closed') -} - -const findPopoverComponent = ({ - vm, - componentList -}: { - vm: IDialogBoxRenderlessParams['vm'] - componentList: IDialogBoxRenderlessParams['vm'][] -}): IDialogBoxRenderlessParams['vm'][] => { - const children = vm.$children - - if (!children || children.length === 0) { - return [] - } - - children.forEach((child) => { - const tag = child.$options.componentName - - if (tag === 'Select') { - componentList.push(child) - } - - findPopoverComponent({ vm: child, componentList }) - }) - - return componentList -} - -const closeAllPopover = (vm: IDialogBoxRenderlessParams['vm']) => { - findPopoverComponent({ vm, componentList: [] }).forEach((component) => { - component.state.visible = false - }) -} - -export const handleDrag = - ({ parent, props, state, emit }: Pick) => - (event: MouseEvent): void => { - if (!props.draggable) { - return - } - - let modalBoxElem = vm.$el.querySelector('.tiny-dialog-box') as HTMLDivElement - event.preventDefault() - - let demMousemove = document.onmousemove - let demMouseup = document.onmouseup - let disX = event.clientX - modalBoxElem.offsetLeft - let disY = event.clientY - modalBoxElem.offsetTop - let { visibleHeight, visibleWidth } = getDomNode() - - document.onmousemove = (event) => { - event.preventDefault() - - if (!state.move) { - emit('drag-start', event) - closeAllPopover(vm) - state.move = true - } - - let offsetWidth = modalBoxElem.offsetWidth - let offsetHeight = modalBoxElem.offsetHeight - let left: number - let top: number - if (!props.dragOutsideWindow) { - let maxX = Math.max(visibleWidth - offsetWidth, 0) - let maxY = Math.max(visibleHeight - offsetHeight, 0) - left = event.clientX - disX - top = event.clientY - disY - - left = left < 0 ? 0 : left > maxX ? maxX : left - top = top < 0 ? 0 : top > maxY ? maxY : top - } else { - let maxX = visibleWidth - 10 - let maxY = visibleHeight - 10 - left = event.clientX - disX - top = event.clientY - disY - - left = event.clientX < 0 ? -disX : left > maxX ? maxX : left - top = event.clientY < 0 ? -disY : top > maxY ? maxY : top - } - - state.dragStyle = { left: `${left}px`, top: `${top}px` } - - state.left = `${left}px` - state.top = `${top}px` - - state.emitter.emit('boxdrag') - emit('drag-move', event) - } - - document.onmouseup = () => { - document.onmousemove = demMousemove - document.onmouseup = demMouseup - state.move = false - props.draggable && emit('drag-end', event) - } - } - -export const showScrollbar = (lockScrollClass: string) => (): void => { - addClass(document.body, lockScrollClass) -} - -export const hideScrollbar = (lockScrollClass: string) => (): void => { - removeClass(document.body, lockScrollClass) -} diff --git a/packages/mobile/components/dialog-box/src/renderless/vue.ts b/packages/mobile/components/dialog-box/src/renderless/vue.ts deleted file mode 100644 index 1c8d7e499f..0000000000 --- a/packages/mobile/components/dialog-box/src/renderless/vue.ts +++ /dev/null @@ -1,220 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - afterEnter, - afterLeave, - computedAnimationName, - computedStyle, - handleConfirm, - handleCancel, - watchVisible, - hide, - handleClose, - handleWrapperClick, - useMouseEventDown, - useMouseEventUp, - mounted, - unMounted, - updatePopper, - handleDrag, - showScrollbar, - hideScrollbar, - computedBodyStyle -} from './index' -import usePopup from '@mobile-root/utils/deps/vue-popup' -import type { - IDialogBoxApi, - IDialogBoxProps, - IDialogBoxRenderlessParamUtils, - IDialogBoxRenderlessParams, - IDialogBoxState, - IDialogBoxMergeStateParam, - ISharedRenderlessParamHooks, - IDialogBoxInitApiParam, - IDialogBoxInitWatchParam -} from '../dialog-box' - -export const api = [ - 'afterEnter', - 'afterLeave', - 'handleClose', - 'handleWrapperClick', - 'useMouseEventDown', - 'useMouseEventUp', - 'handleCancel', - 'handleConfirm', - 'handleDrag', - 'state' -] - -const initState = ({ - reactive, - computed, - api, - emitter, - props, - useBreakpoint -}: Pick): IDialogBoxState => { - const { current } = useBreakpoint() - const state: IDialogBoxState = reactive({ - emitter: emitter(), - key: 0, - x: null, - y: null, - top: null, - left: null, - max: null, - move: false, - closed: false, - dragable: false, - isFull: props.fullscreen, - style: computed(() => api.computedStyle()), - bodyStyle: computed(() => api.computedBodyStyle()), - animationName: computed(() => api.computedAnimationName()), - current, - dragStyle: null - }) - - return state -} - -const mergeState = ({ reactive, state, toRefs, usePopups }: IDialogBoxMergeStateParam): IDialogBoxState => { - // 由于 usePopups返回的值已经是 toRefs过了,所以这里可以直接解构 - const { opened, rendered } = usePopups - - const merge = reactive({ - opened, - rendered, - ...toRefs(state) - }) - - return merge -} - -const initApi = ({ - emit, - api, - state, - parent, - props, - lockScrollClass, - constants, - usePopups, - nextTick, - broadcast, - designConfig, - vm -}: IDialogBoxInitApiParam): void => { - const { open, close } = usePopups - Object.assign(api, { - state, - open, - close, - broadcast, - handleCancel: handleCancel({ api, emit }), - handleConfirm: handleConfirm({ api, emit }), - updatePopper: updatePopper({ api, constants }), - handleWrapperClick: handleWrapperClick({ api, props, state }), - useMouseEventDown: useMouseEventDown({ state }), - useMouseEventUp: useMouseEventUp({ state }), - hide: hide({ api, emit, state, props }), - handleClose: handleClose({ api, constants, emit, parent, props }), - watchVisible: watchVisible({ - api, - constants, - emit, - nextTick, - parent, - props, - vm, - state - }), - computedStyle: computedStyle({ state, props, designConfig }), - computedBodyStyle: computedBodyStyle({ props }), - mounted: mounted({ api, parent, props }), - unMounted: unMounted({ api, parent, props }), - computedAnimationName: computedAnimationName({ constants, props }), - afterEnter: afterEnter(emit), - afterLeave: afterLeave(emit), - hideScrollbar: hideScrollbar(lockScrollClass), - showScrollbar: showScrollbar(lockScrollClass), - handleDrag: handleDrag({ parent, props, state, emit }) - }) -} - -const initWatch = ({ watch, state, api, props }: IDialogBoxInitWatchParam) => { - watch(() => props.visible, api.watchVisible) - - watch( - () => props.fullscreen, - (value: boolean) => { - state.isFull = value - } - ) -} - -export const renderless = ( - props: IDialogBoxProps, - { computed, onBeforeUnmount, onMounted, toRefs, reactive, watch }: ISharedRenderlessParamHooks, - { - vm, - emitter, - parent, - emit, - constants, - nextTick, - mode, - broadcast, - designConfig, - useBreakpoint - }: IDialogBoxRenderlessParamUtils -): IDialogBoxApi => { - const api = {} as IDialogBoxApi - const lockScrollClass = constants.scrollLockClass(mode) - let state = initState({ reactive, computed, api, emitter, props, useBreakpoint }) - const usePopups = usePopup({ - api, - nextTick, - onBeforeUnmount, - onMounted, - props, - reactive, - toRefs, - vm, - watch - }) - - initApi({ - api, - state, - parent, - props, - emit, - constants, - usePopups, - lockScrollClass, - nextTick, - vm, - broadcast, - designConfig - }) - - state = mergeState({ reactive, state, toRefs, usePopups }) - - initWatch({ watch, state, api, props }) - - onMounted(api.mounted) - onBeforeUnmount(api.unMounted) - - return api -} diff --git a/packages/mobile/components/dropdown-item/index.ts b/packages/mobile/components/dropdown-item/index.ts deleted file mode 100644 index 6c574614af..0000000000 --- a/packages/mobile/components/dropdown-item/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import DropdownItem from './src/mobile.vue' - -/* istanbul ignore next */ -DropdownItem.install = function (Vue) { - Vue.component(DropdownItem.name, DropdownItem) -} - -export default DropdownItem diff --git a/packages/mobile/components/dropdown-item/src/dropdown-item.ts b/packages/mobile/components/dropdown-item/src/dropdown-item.ts deleted file mode 100644 index 4037aff729..0000000000 --- a/packages/mobile/components/dropdown-item/src/dropdown-item.ts +++ /dev/null @@ -1,205 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ExtractPropTypes, ComponentPublicInstance, ComputedRef } from 'vue' -import type { - ISharedRenderlessFunctionParams, - ISharedRenderlessParamUtils, - ISharedRenderlessParamHooks -} from '@mobile-root/shared.type' -import type { IDropdownMenuVm } from '../../dropdown-menu/src/dropdown-menu' -import type { - open, - opened, - close, - getTitle, - onScroll, - reset, - closed, - clickWrapper, - clickOutside, - tagClick, - getOptionStyle, - toggle, - clickItem, - getItemStyle, - bindScroll, - confirm, - handleClick, - computedGetIcon, - getTip -} from './renderless' - -export type { ISharedRenderlessParamHooks, IDropdownMenuVm } - -export const $constants = { - ICON_MAP: { - leftWardArrow: 'icon-delta-left' - } -} - -export const dropdownItemProps = { - modelValue: [Number, String, Array], - _constants: { - type: Object, - default: () => $constants - }, - icon: [String, Object], - disabled: { - type: Boolean, - default: false - }, - divided: Boolean, - itemData: { - type: [String, Object], - default: '' - }, - title: String, - label: String, - level: String, - titleClass: String, - options: { - type: Array, - default: () => [] - }, - // mobile 属性,可选值 selection | filter | sort - type: { - type: String, - default: 'selection' - }, - // 是否选中,勾选状态功能 - selected: { - type: Boolean, - default: false - }, - // 暂没找到使用的地方 - selectedField: { - type: String, - default: 'selected' - }, - // 暂没找到使用的地方 - multiStage: { - type: Boolean, - default: false - }, - currentIndex: { - type: Number, - default: () => -1 - }, - // 以下为 tiny 新增 - appendToBody: { - type: Boolean, - default: true - }, - textField: { - type: String, - default: 'label' - }, - tip: { - type: [String, Function], - default: '' - }, - tipPosition: { - type: String, - default: 'right' - } -} - -export type IDropdownItemVm = ComponentPublicInstance & { - type: string - toggle: (value: boolean, options?: object) => void - state: IDropdownItemState -} & IDropdownItemProps - -export type IDropdownItemProps = ExtractPropTypes - -export type IDropdownItemConstants = typeof $constants - -export interface IDropdownItemState { - checkedStatus: boolean - sort: 'asc' | 'desc' - transition: boolean - getTitle: boolean - showWrapper: boolean - showPopup: boolean - duration: number | string - overlay: ComputedRef - offset: ComputedRef - direction: ComputedRef - displayTitle: ComputedRef - itemStyle: ComputedRef - activeColor: ComputedRef - closeOnClickOverlay: ComputedRef - dropdownMenuVm: IDropdownMenuVm - currentIndex: number - textField: string - popperClass: string - getIcon: ComputedRef -} - -export interface IDropdownItemApi { - state: IDropdownItemState - open: ReturnType - opened: ReturnType - close: ReturnType - getTitle: ReturnType - onScroll: ReturnType - reset: ReturnType - closed: ReturnType - clickWrapper: ReturnType - clickOutside: ReturnType - tagClick: ReturnType - getOptionStyle: ReturnType - toggle: ReturnType - clickItem: ReturnType - getItemStyle: ReturnType - bindScroll: ReturnType - confirm: ReturnType - handleClick: ReturnType - computedGetIcon: ReturnType - getTip: ReturnType -} - -export type IDropdownItemRenderlessParams = ISharedRenderlessFunctionParams & { - state: IDropdownItemState - props: IDropdownItemProps - api: IDropdownItemApi -} - -export type IDropdownItemRenderlessParamUtils = ISharedRenderlessParamUtils - -export interface IDropdownItemStyle { - zIndex: number - top: string - bottom: string -} - -export interface IDropdownItemTag { - value: string - text: string -} - -export interface IDropdownItemOptionStyle { - color: string - border?: string -} - -export interface IDropdownItemMfDataStore { - checkedStatus: boolean - multiStageMenu: boolean - multiStage: string - itemData: object - itemLabel: string - showContent: boolean - dropdownMenuVm: IDropdownMenuVm - currentIndex: string - level: number -} diff --git a/packages/mobile/components/dropdown-item/src/mobile.vue b/packages/mobile/components/dropdown-item/src/mobile.vue deleted file mode 100644 index 3e910fdf55..0000000000 --- a/packages/mobile/components/dropdown-item/src/mobile.vue +++ /dev/null @@ -1,134 +0,0 @@ - - - - - diff --git a/packages/mobile/components/dropdown-item/src/renderless/index.ts b/packages/mobile/components/dropdown-item/src/renderless/index.ts deleted file mode 100644 index ddc4b4e5d1..0000000000 --- a/packages/mobile/components/dropdown-item/src/renderless/index.ts +++ /dev/null @@ -1,195 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { - IDropdownItemRenderlessParams, - IDropdownItemStyle, - IDropdownItemTag, - IDropdownItemOptionStyle -} from '../dropdown-item' -import { on, off } from '@mobile-root/utils/deps/dom' - -export const getTitle = (props: IDropdownItemRenderlessParams['props']) => (): string => { - if (props.title) { - return props.title - } - - const match = props.options.filter((option) => option.value === props.modelValue) - - return match.length ? match[0].text : '' -} - -export const bindScroll = - ({ api, parent }: Pick) => - (value): void => { - const action = value ? on : off - action(parent.state.scroller, 'scroll', api.onScroll, true) - } - -export const toggle = - ({ parent, props, state }: Pick) => - (show: boolean): void => { - if (show === state.showPopup) { - return - } - - state.transition = !props.options.immediate - state.showPopup = show - - if (show) { - parent.updateOffset() - state.showWrapper = true - } - } - -export const onScroll = (parent: IDropdownItemRenderlessParams['parent']) => (): void => parent.updateOffset() - -export const clickWrapper = - (parent: IDropdownItemRenderlessParams['parent']) => - (event: MouseEvent): void => - parent.$el && event.stopPropagation() - -// mode为mobile时点击菜单项的方法 -export const clickItem = - ({ emit, props, state }: Pick) => - (value: string): void => { - state.showPopup = false - - if (value !== props.modelValue) { - emit('update:modelValue', value) - emit('change', value) - } - } - -export const getItemStyle = - ({ parent, state }: Pick) => - (): IDropdownItemStyle => ({ - zIndex: parent.zIndex, - top: parent.direction === 'down' ? state.offset + 'px' : '', - bottom: parent.direction !== 'down' ? state.offset + 'px' : '' - }) - -// mode为mobile时动态获取样式的方法 -export const getOptionStyle = - (state: IDropdownItemRenderlessParams['state']) => - (tag: IDropdownItemTag, tags: string | Array): IDropdownItemOptionStyle => { - if (tags.includes(tag.value)) { - return { - color: state.activeColor ? state.activeColor : '#f36f64', - border: `1px solid ${state.activeColor ? state.activeColor : '#f36f64'}` - } - } else { - return { - color: '#333' - } - } - } - -export const closed = - ({ emit, state }: Pick) => - (): void => { - state.showWrapper = false - emit('closed') - } - -export const open = (emit: IDropdownItemRenderlessParams['emit']) => (): void => emit('open') - -export const opened = (emit: IDropdownItemRenderlessParams['emit']) => (): void => emit('opened') - -export const close = (emit: IDropdownItemRenderlessParams['emit']) => (): void => emit('close') - -export const tagClick = - ({ emit, props }: Pick) => - (key: number, tag: IDropdownItemTag, event: MouseEvent): void => { - event.preventDefault() - event.stopPropagation() - - const filterValue = props.modelValue.slice() - const value = filterValue[key] - const index = value.indexOf(tag.value) - - if (index === -1) { - value.push(tag.value) - } else { - value.splice(index, 1) - } - - filterValue[key] = value - emit('update:modelValue', filterValue) - } - -export const confirm = - ({ emit, props, state }: Pick) => - (): void => { - state.showPopup = false - emit('confirm', props.modelValue) - } - -export const reset = - ({ emit, props }: Pick) => - (): void => { - const len = props.modelValue.length - const array = [] - - for (let i = 0; i < len; i++) { - array.push([]) - } - - emit('update:modelValue', array) - emit('reset', array) - } - -export const clickOutside = (parent: IDropdownItemRenderlessParams['parent']) => (): void => { - if (parent.closeOnClickOutside && parent.closeOnClickOverlay) { - parent.state.children.forEach((item) => { - item.toggle(false) - }) - } -} - -export const handleClick = - ({ - state, - props, - dispatch, - vm, - emit - }: Pick) => - (event: MouseEvent): void => { - // 此处需要手动阻止事件冒泡,如果使用@click.sotp在vue2.x下会导致在自循环组件(dropdown-item)事件绑定错乱 - event.stopPropagation() - state.currentIndex = `${props.currentIndex}` - - const data = { itemData: props.itemData, vm, disabled: props.disabled } - - if (!props.disabled) { - emit('item-click', data) - } - // 此处需要传递一个对象,如果是数组[param1,param2],会导致vue2和vue3的表现形式不一样,aui 目前还是数组形式 - dispatch('TinyDropdown', 'menu-item-click', data) - dispatch('TinyDropdown', 'is-disabled', [props.disabled]) - dispatch('TinyDropdown', 'selected-index', [state.currentIndex]) - } - -export const computedGetIcon = - ({ constants, designConfig }: Pick) => - (name = 'leftWardArrow'): object | string => { - return designConfig?.icons[name] || constants?.ICON_MAP[name] - } - -export const getTip = ({ props, vm }: Pick): string => { - if (props.tip && typeof props.tip === 'function') { - return props.tip({ itemData: props.itemData, vm }) - } - - return props.tip || '' -} diff --git a/packages/mobile/components/dropdown-item/src/renderless/vue.ts b/packages/mobile/components/dropdown-item/src/renderless/vue.ts deleted file mode 100644 index 0e1f216734..0000000000 --- a/packages/mobile/components/dropdown-item/src/renderless/vue.ts +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { - IDropdownItemState, - IDropdownItemApi, - IDropdownItemProps, - IDropdownItemRenderlessParamUtils, - ISharedRenderlessParamHooks, - IDropdownMenuVm -} from '../dropdown-item' -import { - tagClick, - confirm, - clickOutside, - getOptionStyle, - reset, - getTitle, - bindScroll, - toggle, - onScroll, - open, - opened, - close, - closed, - clickItem, - clickWrapper, - getItemStyle, - handleClick, - computedGetIcon, - getTip -} from './index' - -export const api = [ - 'state', - 'confirm', - 'clickOutside', - 'getOptionStyle', - 'reset', - 'tagClick', - 'clickItem', - 'clickWrapper', - 'toggle', - 'open', - 'opened', - 'close', - 'closed', - 'handleClick', - 'getTip' -] - -const initState = ({ reactive, computed, api, props, parent, dropdownMenuVm }) => { - const state: IDropdownItemState = reactive({ - checkedStatus: dropdownMenuVm?.checkedStatus, - sort: props.modelValue, - transition: true, - getTitle: false, - showWrapper: false, - showPopup: false, - duration: parent.duration, - overlay: computed(() => parent.overlay), - offset: computed(() => parent.state.offset), - direction: computed(() => parent.direction), - displayTitle: computed(() => api.getTitle()), - itemStyle: computed(() => api.getItemStyle()), - activeColor: computed(() => parent.activeColor), - closeOnClickOverlay: computed(() => parent.closeOnClickOverlay), - dropdownMenuVm, - currentIndex: props.currentIndex, - textField: dropdownMenuVm?.textField || props.textField, - popperClass: dropdownMenuVm?.popperClass || '', - getIcon: computed(() => api.computedGetIcon()), - children: [] - }) - - return state -} - -const initApi = ({ api, state, emit, props, parent, dispatch, vm, constants, designConfig }) => { - Object.assign(api, { - state, - open: open(emit), - opened: opened(emit), - close: close(emit), - getTitle: getTitle(props), - onScroll: onScroll(parent), - reset: reset({ emit, props }), - closed: closed({ emit, state }), - clickWrapper: clickWrapper(parent), - clickOutside: clickOutside(parent), - tagClick: tagClick({ emit, props }), - getOptionStyle: getOptionStyle(state), - toggle: toggle({ parent, props, state }), - clickItem: clickItem({ emit, props, state }), - getItemStyle: getItemStyle({ parent, state }), - bindScroll: bindScroll({ api, parent }), - confirm: confirm({ emit, props, state }), - handleClick: handleClick({ state, props, dispatch, vm, emit }), - computedGetIcon: computedGetIcon({ constants, designConfig }), - getTip: getTip({ props, vm }) - }) -} - -export const renderless = ( - props: IDropdownItemProps, - { computed, onMounted, reactive, watch, inject }: ISharedRenderlessParamHooks, - { parent, emit, vm, dispatch, constants, designConfig }: IDropdownItemRenderlessParamUtils -): IDropdownItemApi => { - const api = {} as IDropdownItemApi - const dropdownMenuVm = inject('dropdownMenuVm', null) as IDropdownMenuVm - const state: IDropdownItemState = initState({ reactive, computed, api, props, parent, dropdownMenuVm }) - - initApi({ api, state, emit, props, parent, dispatch, vm, constants, designConfig }) - - watch(() => state.showPopup, api.bindScroll) - - onMounted(() => { - const realParent = parent.$parent.$parent || {} - if (realParent.state && realParent.state.children) { - realParent.state.children.push(vm) - } else { - if (dropdownMenuVm) { - dropdownMenuVm.state.children = [...dropdownMenuVm.state.children, vm] - } - } - - if (props.disabled) { - state.checkedStatus = false - } - }) - - return api -} diff --git a/packages/mobile/components/dropdown-menu/index.ts b/packages/mobile/components/dropdown-menu/index.ts deleted file mode 100644 index dde87245bf..0000000000 --- a/packages/mobile/components/dropdown-menu/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import DropdownMenu from './src/mobile.vue' - -/* istanbul ignore next */ -DropdownMenu.install = function (Vue) { - Vue.component(DropdownMenu.name, DropdownMenu) -} - -export default DropdownMenu diff --git a/packages/mobile/components/dropdown-menu/src/dropdown-menu.ts b/packages/mobile/components/dropdown-menu/src/dropdown-menu.ts deleted file mode 100644 index bfea0bab2d..0000000000 --- a/packages/mobile/components/dropdown-menu/src/dropdown-menu.ts +++ /dev/null @@ -1,138 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { ExtractPropTypes, ComponentPublicInstance } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' -import type { IDropdownItemVm } from '../../dropdown-item/src/dropdown-item' - -export const dropdownMenuProps = { - multiStage: { - type: Boolean, - default: false - }, - checkedStatus: { - type: Boolean, - default: false - }, - visibleArrow: Boolean, - arrowOffset: { - type: Number, - default: 0 - }, - placement: String, // 默认主题 'bottom-end' - popperClass: String, - popperAppendToBody: { - type: Boolean, - default: true - }, - activeColor: String, - closeOnClickOutside: { - type: Boolean, - default: true - }, - closeOnClickOverlay: { - type: Boolean, - default: true - }, - direction: { - type: String, - default: 'down' - }, - duration: { - type: [Number, String], - default: 0.2 - }, - overlay: { - type: Boolean, - default: true - }, - zIndex: [Number, String], - maxHeight: { - type: [Number, String], - default: '400' - }, - // tiny新增 - options: { - type: Array, - default: () => [] - }, - textField: { - type: String, - default: 'label' - } -} - -export type { IDropdownItemVm } - -export type IDropdownMenuProps = ExtractPropTypes - -export interface IDropdownMenuState { - offset: number - scroller: null | HTMLElement - children: IDropdownItemVm[] - size: string - showPopper: boolean - label: string - showContent: boolean - selected: boolean - selectedIndex: number -} - -export interface IDropdownMenuApi { - state: IDropdownMenuState - toggleItem: (active: boolean, item) => void - clickOutside: () => void - updateOffset: () => void - mounted: () => void - handleMouseenter: ($event: MouseEvent) => void - handleMouseleave: ($event: MouseEvent) => void - handleMenuItemClick: ( - itemData: object, - instance: ComponentPublicInstance, - label: string, - showContent: boolean, - isDisabled: boolean - ) => void - doDestroy: () => void -} - -export type IDropdownMenuRenderlessParams = ISharedRenderlessFunctionParams & { - state: IDropdownMenuState - props: IDropdownMenuProps - api: IDropdownMenuApi -} - -export type IDropdownMenuRenderlessParamUtils = ISharedRenderlessParamUtils - -export interface IDropdownMenuPopperParams { - api: IDropdownMenuApi - props: IDropdownMenuProps - hooks: Pick< - IDropdownMenuRenderlessParams, - | 'reactive' - | 'provide' - | 'onMounted' - | 'inject' - | 'nextTick' - | 'onBeforeUnmount' - | 'onDeactivated' - | 'toRefs' - | 'watch' - > - instance: IDropdownMenuRenderlessParamUtils - state: IDropdownMenuState - dropdownVm: any -} - -export type IDropdownMenuVm = ComponentPublicInstance & { - state: IDropdownMenuState -} & IDropdownMenuProps diff --git a/packages/mobile/components/dropdown-menu/src/mobile.vue b/packages/mobile/components/dropdown-menu/src/mobile.vue deleted file mode 100644 index 2adca204a0..0000000000 --- a/packages/mobile/components/dropdown-menu/src/mobile.vue +++ /dev/null @@ -1,93 +0,0 @@ - - - - - diff --git a/packages/mobile/components/dropdown-menu/src/renderless/index.ts b/packages/mobile/components/dropdown-menu/src/renderless/index.ts deleted file mode 100644 index f35d0af239..0000000000 --- a/packages/mobile/components/dropdown-menu/src/renderless/index.ts +++ /dev/null @@ -1,211 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { IDropdownMenuRenderlessParams, IDropdownMenuPopperParams, IDropdownItemVm } from '../dropdown-menu' -import userPopper from '@mobile-root/utils/deps/vue-popper' - -export const toggleItem = - (state: IDropdownMenuRenderlessParams['state']) => - (active: number, item: IDropdownItemVm): void => { - if (item.disabled) { - return - } - - if (item.type === 'sort') { - if (!item.modelValue || item.modelValue === 'desc') { - item.state.sort = 'asc' - item.$emit('update:modelValue', 'asc') - item.$emit('click', 'asc') - } else { - item.state.sort = 'desc' - item.$emit('update:modelValue', 'desc') - item.$emit('click', 'desc') - } - } else { - const singleton = state.children.length === 1 && item.state.showPopup - - state.children.forEach((item, index) => { - if (index === active && !singleton) { - item.toggle(true) - } else if (item.state.showPopup) { - item.toggle(false, { immediate: true }) - } - }) - } - } - -export const updateOffset = - ({ props, state, vm }: Pick) => - (): void => { - if (!vm.$refs.menu) { - return - } - - const rect = vm.$refs.menu.getBoundingClientRect() - - if (props.direction === 'down') { - state.offset = rect.bottom - } else { - state.offset = window.innerHeight - rect.top - } - } - -export const clickOutside = - ({ props, state }: Pick) => - (): void => { - if (props.closeOnClickOutside && props.closeOnClickOverlay) { - state.children.forEach((item) => { - item.type !== 'filter' && item.toggle(false) - }) - } - } - -export const getScroller = (el: HTMLElement, root?: HTMLElement): HTMLElement | null => { - const overflowScrollReg = /scroll|auto/i - let node = el - let getComputedStyle = window.getComputedStyle - - while (node && node.tagName !== 'HTML' && node.nodeType === 1 && node !== root) { - const { overflowY } = getComputedStyle(node) - - if (overflowScrollReg.test(overflowY)) { - if (node.tagName !== 'BODY') { - return node - } - - const { overflowY: htmlOverflowY } = getComputedStyle(node.parentNode) - - if (overflowScrollReg.test(htmlOverflowY)) { - return node - } - } - - node = node.parentNode - } - - return root || null -} - -export const useVuePopper = ({ - api, - props, - hooks, - instance, - state, - dropdownVm, - designConfig -}: IDropdownMenuPopperParams): void => { - const { nextTick, onBeforeUnmount, onDeactivated, onMounted, reactive, toRefs, watch } = hooks - const { emit, slots, vm, parent } = instance - const designProps = { - placement: props.placement || designConfig?.props?.placement || 'bottom-end', - visibleArrow: props.visibleArrow || designConfig?.props?.visibleArrow || false - } - - const popper = userPopper({ - emit, - nextTick, - onBeforeUnmount, - onDeactivated, - props: { - popperOptions: { boundariesPadding: 0, gpuAcceleration: false }, - offset: 0, - boundariesPadding: 5, - ...props, - ...designProps - }, - reactive, - vm, - slots, - toRefs, - watch - }) - - onMounted(() => { - if (!dropdownVm) return - dropdownVm.popperElm = popper.popperElm.value = vm.$el - nextTick(() => (popper.referenceElm.value = dropdownVm.$el)) - - !props.multiStage && dropdownVm.initDomOperation() - - if (dropdownVm.inheritWidth) { - dropdownVm.popperElm.style.minWidth = dropdownVm.$el.clientWidth + 'px' - } - }) - - onBeforeUnmount(() => { - popper.destroyPopper('remove') - popper.popperElm = null - popper.referenceElm = null - }) - - api.doDestroy = popper.doDestroy - state.size = dropdownVm?.size || '' - state.showPopper = popper.showPopper.value - - parent.$on('updatePopper', () => { - if (state.showPopper) { - popper.updatePopper() - } - }) - - parent.$on('visible', (value) => { - state.showPopper = value - popper.showPopper.value = value - }) - - watch( - () => props.placement, - (value) => { - popper.currentPlacement.value = value - } - ) -} - -export const mounted = - ({ api, parent, state }: Pick) => - (): void => { - parent.$on('menu-selected-index', (selectedIndex) => { - state.selectedIndex = selectedIndex - }) - parent.$on('menu-item-click', api.handleMenuItemClick) - parent.$on('mouseenter-tips', (showContent, label) => { - state.label = label - state.showContent = showContent - }) - parent.$on('mouseleave-tips', (showContent, label) => { - state.label = label - state.showContent = showContent - }) - } - -export const handleMenuItemClick = - ({ state, dispatch }: Pick) => - ({ itemData, vm, label, showContent, disabled }): void => { - state.label = label - state.showContent = showContent - - const data = { itemData, vm, disabled } - dispatch('TinyDropdown', 'current-item-click', data) // 统一参数格式为对象 - } - -export const handleMouseenter = - (emit: IDropdownMenuRenderlessParams['emit']) => - ($event: MouseEvent): void => { - emit('mouseenter', $event) - } - -export const handleMouseleave = - (emit: IDropdownMenuRenderlessParams['emit']) => - ($event: MouseEvent): void => { - emit('mouseleave', $event) - } diff --git a/packages/mobile/components/dropdown-menu/src/renderless/vue.ts b/packages/mobile/components/dropdown-menu/src/renderless/vue.ts deleted file mode 100644 index bebd626b24..0000000000 --- a/packages/mobile/components/dropdown-menu/src/renderless/vue.ts +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { - IDropdownMenuState, - IDropdownMenuApi, - IDropdownMenuProps, - IDropdownMenuRenderlessParamUtils, - ISharedRenderlessParamHooks -} from '@/types' -import { - toggleItem, - updateOffset, - clickOutside, - getScroller, - mounted, - handleMenuItemClick, - handleMouseenter, - handleMouseleave -} from './index' - -export const api = [ - 'state', - 'toggleItem', - 'updateOffset', - 'clickOutside', - 'doDestroy', - 'handleMouseenter', - 'handleMouseleave' -] - -export const renderless = ( - props: IDropdownMenuProps, - hooks: ISharedRenderlessParamHooks, - instance: IDropdownMenuRenderlessParamUtils -): IDropdownMenuApi => { - const api = {} as IDropdownMenuApi - const { reactive, provide, onMounted, inject } = hooks - const { nextTick, mode, vm, parent, dispatch, emit, designConfig } = instance - - const state: IDropdownMenuState = reactive({ - offset: 0, - scroller: null, - children: [], - size: '', - showPopper: false, - label: '', - showContent: false, - selected: false, - selectedIndex: -1, - canvasHeight: inject('change-size', null) - }) - - provide('dropdownMenuVm', vm) - provide('multiStage', props.multiStage) - - if (mode === 'mobile') { - nextTick(() => { - state.scroller = getScroller(vm.$refs.menu as HTMLElement) - }) - } - - Object.assign(api, { - state, - toggleItem: toggleItem(state), - clickOutside: clickOutside({ props, state }), - updateOffset: updateOffset({ props, state, vm }), - mounted: mounted({ api, parent, state }), - handleMouseenter: handleMouseenter(emit), - handleMouseleave: handleMouseleave(emit), - handleMenuItemClick: handleMenuItemClick({ dispatch, state }) - }) - - onMounted(api.mounted) - - return api -} diff --git a/packages/mobile/components/exception/index.ts b/packages/mobile/components/exception/index.ts deleted file mode 100644 index 8d2d7ae7b5..0000000000 --- a/packages/mobile/components/exception/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Exception from './src/mobile.vue' - -/* istanbul ignore next */ -Exception.install = function (Vue) { - Vue.component(Exception.name, Exception) -} - -export default Exception diff --git a/packages/mobile/components/exception/src/exception.ts b/packages/mobile/components/exception/src/exception.ts deleted file mode 100644 index 3271e08e56..0000000000 --- a/packages/mobile/components/exception/src/exception.ts +++ /dev/null @@ -1,19 +0,0 @@ -export const exceptionProps = { - type: { - type: String, - default: 'nodata' - }, - buttonText: String, - message: String, - subMessage: String, - exceptionClass: String, - imageUrl: String, - pageEmpty: { - type: Boolean, - default: false - }, - componentPage: { - type: Boolean, - default: false - } -} diff --git a/packages/mobile/components/exception/src/mobile.vue b/packages/mobile/components/exception/src/mobile.vue deleted file mode 100644 index 076d87fbb3..0000000000 --- a/packages/mobile/components/exception/src/mobile.vue +++ /dev/null @@ -1,56 +0,0 @@ - - - - diff --git a/packages/mobile/components/exception/src/renderless/index.ts b/packages/mobile/components/exception/src/renderless/index.ts deleted file mode 100644 index 5db9404122..0000000000 --- a/packages/mobile/components/exception/src/renderless/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -export const emitClick = (emit) => () => emit('click') diff --git a/packages/mobile/components/exception/src/renderless/vue.ts b/packages/mobile/components/exception/src/renderless/vue.ts deleted file mode 100644 index 0cf95365d0..0000000000 --- a/packages/mobile/components/exception/src/renderless/vue.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { emitClick } from './index' - -export const api = ['state', 'create'] - -export const renderless = (props, { reactive }, { emit }) => { - const state = reactive({ - urlType: props.type - }) - - const api = { - state, - create: emitClick(emit) - } - - return api -} diff --git a/packages/mobile/components/file-upload/index.ts b/packages/mobile/components/file-upload/index.ts deleted file mode 100644 index b21806483c..0000000000 --- a/packages/mobile/components/file-upload/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import FileUpload from './src/mobile.vue' - -/* istanbul ignore next */ -FileUpload.install = function (Vue) { - Vue.component(FileUpload.name, FileUpload) -} - -export default FileUpload diff --git a/packages/mobile/components/file-upload/src/file-upload.ts b/packages/mobile/components/file-upload/src/file-upload.ts deleted file mode 100644 index ed1b415453..0000000000 --- a/packages/mobile/components/file-upload/src/file-upload.ts +++ /dev/null @@ -1,632 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils, ITinyVm } from '@mobile-root/shared.type' -import type { - sliceChunk, - getFormData, - abort, - handleClick, - getFile, - clearFiles, - watchFileList, - watchListType, - onBeforeDestroy, - computedUploadDisabled, - computedUploadingSize, - getFileUploadUrl, - getToken, - getDialogConfigObj, - computeDocChunkSize, - updateFile, - getPreviewUrlSync, - clearUploadingFiles, - calcUploadingFilesInfo, - properFileSize, - mounted, - previewFileSingle, - previewFileBatch, - previewImageSingle, - previewImageBatch, - abortDownload, - createDownloadCancelToken, - computedSourcetype, - getFileSourceType, - segmentUploadInit, - segmentUpload, - addFileToList, - downloadFile, - downloadFileSingleInner, - previewImage, - previewFile, - getNewTabPreviewUrl, - submit, - handleStart, - batchSegmentUpload, - largeDocumentUpload, - handleProgress, - handleSuccess, - handleError, - handleRemove, - updateUrl, - startUpload, - beforeUpload, - getDownloadFileInfo, - largeDocumentDownload, - sliceDownloadChunk, - batchSegmentDownload, - downloadFileInner, - setWriterFile, - afterDownload, - getFileHash, - modifyServiceUrlSingle, - getKiaScanTip, - downloadFileSingle, - downloadFileBatch, - downloadFileSingleHwh5, - validateDownloadStatus, - handleChange, - handleClickFileList, - handleTriggerClick, - noopFnCreator, - getCalcProgress, - getHandleSuccess, - handleReUpload, - handleReUploadTotal -} from './renderless' -import type { downloadFile as ordinaryDownload } from '../../upload-list/src/upload-list' -import type { IUploadFormData } from '../../upload/src/upload' -import { $props } from '@mobile-root/common' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const $constants = { - FILE_UPLOAD_INNER_TEMPLATE: 'file-upload-inner-template', - UPLOAD_INNER: 'upload-inner', - UPLOAD_INNER_TEMPLATE: 'upload-inner-template', - UPLOAD_LIST_INNER: 'upload-list-inner', - UPLOAD_LIST_INNER_TEMPLATE: 'upload-list-inner-template', - ONLY_SUPPORT: 'ui.fileUpload.onlySupport', - COMMA: 'ui.base.comma', - FILE_NOT_LESS_THAN: 'ui.fileUpload.fileNotLessThan', - FILE_NOT_MORE_THAN: 'ui.fileUpload.fileNotMoreThan', - NUMBER_LIMIT: 'ui.fileUpload.numberLimit', - FILE_STATUS: { - READY: 'ready', - SUCESS: 'success', - UPLOADING: 'uploading', - FAIL: 'fail', - DOWNLOADING: 'downloading' - }, - LIST_TYPE: { - TEXT: 'text', - PICTURE_CARD: 'picture-card', - PICTURE: 'picture', - THUMB: 'thumb', - PICTURE_SINGLE: 'picture-single', - DRAG_SINGLE: 'drag-single', - SAAS: 'saas' - }, - EDM: { - CHUNKINIT: 'chunkInit', - FILESIZE: 'fileSize', - CHUNKS: 'chunks', - FILENAME: 'fileName', - ISCHECKCODE: 'isCheckCode', - CHECKCODE: 'checkCode', - MULTIPART: 'multipartFile', - DOCID: 'docId', - CHUNK: 'chunk', - SINGLEUPLOAD: 'uploadFile', - LOWERNAME: 'filename', - FOLDERKEY: 'ui.fileUpload.folder', - FORMAT: 'docFormat=wm&', - WATER: 'usageScenes=water&wmType=wm&', - SOURCE: 'usageScenes=source&', - URLCONTS: '&type=doc&pageNum=1&docVersion=', - EDMTOKEN: 'EDM-Authorization', - TRACEID: 'x-trace-id', - TEXT: 'edm-text', - JSLIB: './jslib/', - I18NKEY: 'ui.fileUpload.token', - LARGEFILEKEY: 'ui.fileUpload.largefile', - EXCEED: 'ui.fileUpload.exceed', - SIZE: 'ui.fileUpload.fileSize', - SIZE_17G: 17 * 1024 * 1024, - SIZE_2G: 2 * 1024 * 1024, // 单位(KB) - SIZE_64M: 64 * 1024, - SIZE_32M: 32 * 1024, - SIZE_20M: 20 * 1024, - SIZE_16M: 16 * 1024, - SIZE_8M: 8 * 1024, - SIZE_4M: 4 * 1024, - SIZE_2M: 2 * 1024, - SIZE_0M: 0 * 1024, - FILEEMPTY: 'ui.fileUpload.empty', - KIASCANTIP: 'ui.fileUpload.kiaScanTip', - FILENAMEEXCEEDS: 'ui.fileUpload.fileNameExceeds', - THEFILENAME: 'ui.fileUpload.fileName', - CALCHASH: 'ui.fileUpload.calcHash', - KIASTATUS: 12079, - NumberExceed: 'ui.fileUpload.numberExceed', - notSupport: 'ui.fileUpload.notSupport', - NOT_SUPPORT_NO_SUFFIX: 'ui.fileUpload.notSupportNoSuffix', - STATUS_SPECIAL_CHARACTERS: 11005, - NOT_SUPPORT_SPECIAL_CHARACTERS: 'ui.fileUpload.notSupportSpecialCharacters', - DOC_PREVIEW: 'ui.fileUpload.docPreview' - }, - IMAGE_TYPE: 'image/*', - FILE_TYPE: { - EXCEL: 'xls/xlsx', - FILE: 'file', - PDF: 'pdf', - PICTURE: 'png/jpg/jpeg/gif/svg/webp/bmp/tif/pjp/apng/xbm/jxl/svgz/ico/tiff/jfif/pjpeg/avif', - PPT: 'ppt/pptx', - TEXT: 'txt', - WORD: 'doc/docx', - ZIP: 'zip/rar/arj/z/jar/lzh', - VIDEO: 'mp4/m4v/3gp/mpg/flv/f4v/swf/avi/wmv/rmvb/mov/mts/m2t/ogg/webm/mkv', - AUDIO: 'mp3/aac/ape/flac/wav/wma/amr/mid/pcm' - }, - SOURCE_TYPE: { - SOURCE_VIDEO: 'video', - SOURCE_AUDIO: 'audio', - SOURCE_PICTURE: 'picture' - }, - MODE: { - BUBBLE: 'bubble' - } -} - -export const fileUploadProps = { - ...$props, - _constants: { - type: Object, - default: () => $constants - }, - accept: String, - action: String, - autoUpload: { - type: Boolean, - default: () => true - }, - beforeRemove: Function, - beforeUpload: Function, - data: Object, - disabled: Boolean, - display: { - type: Boolean, - default: () => true - }, - drag: Boolean, - dragger: Boolean, - edm: { - type: Object, - default: () => ({}) - }, - fileIconList: { - type: Array, - default: () => [] - }, - fileList: { - type: Array, - default: () => [] - }, - fileSize: { - type: [Number, Array], - validator(value) { - return Array.isArray(value) ? value[0] < value[1] : typeof value === 'number' - } - }, - fileTitle: { - type: String, - default: () => '附件' - }, - headerShow: { - type: Boolean, - default: () => true - }, - headers: { - type: Object, - default: () => ({}) - }, - httpRequest: Function, - limit: Number, - listType: { - type: String, - default: () => 'text', - validator: (value: string) => !!$constants.LIST_TYPE[value.toUpperCase().replace('-', '_')] - }, - mergeService: { - type: Boolean, - default: () => false - }, - multiple: Boolean, - name: { - type: String, - default: () => 'file' - }, - openDownloadFile: { - type: Boolean, - default: () => false - }, - showFileList: { - type: Boolean, - default: () => true - }, - size: String, - successStatistics: { - type: Boolean, - default: () => true - }, - thumbOption: { - type: Object, - default: () => ({ - popperClass: '', - width: 270, - showDownload: false, - downloadFile: Function, - showDel: false, - icon: 'icon-attachment', - showTooltip: false - }) - }, - type: { - type: String, - default: () => 'select' - }, - uploadIcon: { - type: Boolean, - default: () => true - }, - withCredentials: { - type: Boolean, - default: () => true - }, - isFolderTitle: { - type: Boolean, - default: false - }, - listOption: { - type: Object, - default: () => ({ - showUpdate: true, - showDel: true - }) - }, - maxNameLength: { - type: Number, - default: 20 - }, - scale: { - type: [Number, String], - default: 1 - }, - showName: { - type: Boolean, - default: false - }, - sourceType: { - type: String, - default: 'picture', - validator(val) { - return val.split('/').every((type) => ['picture', 'video', 'audio'].includes(type)) - } - }, - showTitle: { - type: Boolean, - default: true - }, - title: { - type: String, - default: '' - }, - displayOnly: { - type: Boolean, - default: false - }, - customClass: [String, Object, Array], - hwh5: Object, - mode: { - type: String, - default: '', - validator(val) { - return ['', 'bubble'].includes(val) - } - }, - cacheToken: { - type: Boolean, - default: true - }, - lockScroll: { - type: Boolean, - default: true - }, - compact: { - type: Boolean, - default: false - }, - beforeAddFile: Function, - encryptConfig: { - type: Object, - default: () => ({ - enabled: false, - encrypt: false, - watermark: '' - }) - }, - isHidden: { - type: Boolean, - default: false - }, - pasteUpload: { - type: Boolean, - default: false - }, - reUploadable: Boolean, - reUploadTip: Function -} - -export interface IFileUploadState { - url: string - updateId: string - currentDownloadFiles: string - tempIndex: number - draging: boolean - uploadFiles: IFileUploadFile[] - dragOver: boolean - httpRequest: () => void - form: ITinyVm - listeners: object - docSize: number - chunkSize: number - chunkBatchLimit: number - downloadChunkLimit: number - batchQueue: object - batchQueueListen: object - batchCancelToken: object - replayAtoms: object - chunkUploadUrl: string - largeFileInfo: object - headers: object - accept: string | undefined - edmToken: object - isSuccess: boolean - singleMaxSize: number - formData: object - showPreview: boolean - iframeUrl: string - fileWater: boolean - tabUrl: string - cacheDocuments: object - isEdm: boolean - uploadDisabled: boolean - dialogConfigObj: object - uploadingFiles: IFileUploadFile[] - currentUploadingFileUids: number[] - uploadingSize: number - isEntireCheckCode: boolean - downloadBatchQueue: object - downloadBatchQueueListen: object - downloadChunkFile: object - downloadReplayAtoms: object - errorStatusCodes: number[] - hasFileInfoInterface: string - currentDownloadFile: string - isDragover: boolean - downloadCancelToken: object - downloadCancelData: object - isHwh5: boolean - selected: null | object - types: string - triggerClickType: string - visible: boolean - downloadParamsWhitelist: string[] -} - -export interface IFileUploadApi { - state: IFileUploadState - sliceChunk: ReturnType - getFormData: ReturnType - abort: ReturnType - handleClick: ReturnType - getFile: ReturnType - clearFiles: ReturnType - watchFileList: ReturnType - watchListType: ReturnType - onBeforeDestroy: ReturnType - computedUploadDisabled: ReturnType - computedUploadingSize: ReturnType - getFileUploadUrl: ReturnType - getToken: ReturnType - getDialogConfigObj: ReturnType - computeDocChunkSize: ReturnType - updateFile: ReturnType - getPreviewUrlSync: ReturnType - ordinaryDownload: ReturnType - clearUploadingFiles: ReturnType - calcUploadingFilesInfo: ReturnType - properFileSize: ReturnType - mounted: ReturnType - previewFileSingle: ReturnType - previewFileBatch: ReturnType - previewImageSingle: ReturnType - previewImageBatch: ReturnType - abortDownload: ReturnType - createDownloadCancelToken: ReturnType - computedSourcetype: ReturnType - getFileSourceType: ReturnType - segmentUploadInit: ReturnType - segmentUpload: ReturnType - addFileToList: ReturnType - downloadFile: ReturnType - downloadFileSingleInner: ReturnType - previewImage: ReturnType - previewFile: ReturnType - getNewTabPreviewUrl: ReturnType - submit: ReturnType - handleStart: ReturnType - batchSegmentUpload: ReturnType - largeDocumentUpload: ReturnType - handleProgress: ReturnType - handleSuccess: ReturnType - handleError: ReturnType - handleRemove: ReturnType - updateUrl: ReturnType - startUpload: ReturnType - beforeUpload: ReturnType - getDownloadFileInfo: ReturnType - largeDocumentDownload: ReturnType - sliceDownloadChunk: ReturnType - batchSegmentDownload: ReturnType - downloadFileInner: ReturnType - setWriterFile: ReturnType - afterDownload: ReturnType - getFileHash: ReturnType - modifyServiceUrlSingle: ReturnType - getKiaScanTip: ReturnType - downloadFileSingle: ReturnType - downloadFileBatch: ReturnType - downloadFileSingleHwh5: ReturnType - validateDownloadStatus: ReturnType - handleChange: ReturnType - handleClickFileList: ReturnType - handleTriggerClick: ReturnType - handleReUpload: ReturnType - handleReUploadTotal: ReturnType -} - -type IFileUploadNoopFnCreator = ReturnType - -export interface IFileUploadService { - get: IFileUploadNoopFnCreator - post: IFileUploadNoopFnCreator - request: IFileUploadNoopFnCreator - all: IFileUploadNoopFnCreator - spread: IFileUploadNoopFnCreator - cancelToken: IFileUploadNoopFnCreator - getSingleUploadUrl: IFileUploadNoopFnCreator - getFileUploadUrl: IFileUploadNoopFnCreator - getFileDownloadUrl: IFileUploadNoopFnCreator - getSingleDownloadUrl: IFileUploadNoopFnCreator - getPackageDownloadUrl: IFileUploadNoopFnCreator - getLargeFileInitUrl: IFileUploadNoopFnCreator - getChunkUploadUrl: IFileUploadNoopFnCreator - getPreviewUrl: IFileUploadNoopFnCreator - getDocumentInfoUrl: IFileUploadNoopFnCreator - getPreviewUrlBatch: IFileUploadNoopFnCreator - httpRequest: IFileUploadNoopFnCreator -} - -export type IFileUploadProps = ExtractPropTypes - -export type IFileUploadConstants = typeof $constants - -export type IFileUploadRenderlessParamUtils = ISharedRenderlessParamUtils - -export type IFileUploadRenderlessParams = ISharedRenderlessFunctionParams & { - state: IFileUploadState - props: IFileUploadProps - api: IFileUploadApi -} - -export type IFileUploadVm = ITinyVm & IFileUploadProps - -export interface IFileUploadModalVm { - Modal: ITinyVm -} - -export type IFileUploadFile = File & { [propName: string]: any } // 允许添加多余未知属性 - -export interface IFileUploadEdmDownload { - token: string - packageToken: string - loading: Function - fail: Function - paramsWhitelist: any[] -} - -export interface IFileUploadDownloadFileSingleInner { - file: IFileUploadFile - isBatch: boolean -} - -export interface IFileUploadLargeDocumentDownload extends IFileUploadDownloadFileSingleInner { - isLessThan17G?: boolean -} - -export interface IFileUploadDownloadFileInner extends IFileUploadLargeDocumentDownload { - batchIndex?: number - range?: { - index: number - } - isChunk?: boolean -} - -export interface IFileUploadDownloadFileSingle extends IFileUploadDownloadFileInner { - calcProgress: ReturnType - isFinished: boolean - handleSuccess: ReturnType - downloadOps: IFileUploadEdmDownload -} - -export interface IFileUploadBatchSegmentUpload { - docId: string - batchIndex: number - batches: Promise[][] - progress: { - file: IFileUploadFile - } -} - -export interface IFileUploadSegmentUploadInner { - batchIndex: number - file: IFileUploadFile - progress: { - file: IFileUploadFile - } -} - -export interface IFileUploadGetFormData { - formData: IUploadFormData - file: IFileUploadFile - type: string -} - -export interface IFileUploadSetWriterFile { - data: any - index: number - isLessThan17G: boolean - file: IFileUploadFile -} - -export interface IFileUploadAfterDownload extends IFileUploadDownloadFileSingle { - data: any -} - -export interface IFileUploadBatchSegmentDownload { - batchIndex: number - batches: IFileUploadSliceDownloadChunk[][] - docId: string - isBatch: boolean - isLessThan17G: boolean -} - -export interface IFileUploadSliceDownloadChunk { - startRange: number - endRange: number - index: number -} - -export interface IFileUploadStreamsaver { - createWriteStream: Function -} diff --git a/packages/mobile/components/file-upload/src/mobile.vue b/packages/mobile/components/file-upload/src/mobile.vue deleted file mode 100644 index 69bd424c96..0000000000 --- a/packages/mobile/components/file-upload/src/mobile.vue +++ /dev/null @@ -1,151 +0,0 @@ - - diff --git a/packages/mobile/components/file-upload/src/renderless/index.ts b/packages/mobile/components/file-upload/src/renderless/index.ts deleted file mode 100644 index 0e554c9c30..0000000000 --- a/packages/mobile/components/file-upload/src/renderless/index.ts +++ /dev/null @@ -1,2748 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { - IFileUploadRenderlessParams, - IFileUploadService, - IFileUploadFile, - IFileUploadModalVm, - IFileUploadEdmDownload, - IFileUploadDownloadFileSingle, - IFileUploadBatchSegmentUpload, - IFileUploadSegmentUploadInner, - IFileUploadGetFormData, - IUploadFormData, - IFileUploadSetWriterFile, - IFileUploadStreamsaver, - IFileUploadAfterDownload, - IFileUploadDownloadFileInner, - IFileUploadBatchSegmentDownload, - IFileUploadSliceDownloadChunk, - IFileUploadLargeDocumentDownload -} from '../file-upload' - -import { extend } from '@mobile-root/utils/object' -import { xss, log } from '@mobile-root/utils' -import uploadAjax from '@mobile-root/utils/deps/upload-ajax' -import { isObject } from '@mobile-root/utils/type' -import { isEmptyObject } from '@mobile-root/utils/type' - -let initTokenPromise = null - -export const noopFnCreator = (fn: Function, propName?: string): Function => { - const noFn = () => { - if (propName) { - return Promise.reject( - new Error(`[TINY Error][FileUpload] Prop ${propName} is mandatory when the framework service is not used`) - ) - } else { - return Promise.reject( - new Error('[TINY Error][FileUpload] Prop action is mandatory when the framework service is not used') - ) - } - } - - return fn || noFn -} - -export const initService = ({ - props, - service -}: Pick): IFileUploadService => { - const { network = {}, common = {} } = service || {} - const { request, get, post, all, spread, CancelToken = {} } = network - let requestFn - if (!isEmptyObject(props.hwh5)) { - const { HWH5 } = props.hwh5 - const { uploadToEDM } = HWH5() - requestFn = props.httpRequest || uploadToEDM - } else if (request) { - requestFn = props.httpRequest || request - } else { - requestFn = props.httpRequest || uploadAjax - } - - return { - get: noopFnCreator(get), - post: noopFnCreator(post), - request: noopFnCreator(request), - all: noopFnCreator(all), - spread: noopFnCreator(spread), - cancelToken: noopFnCreator(CancelToken.source), - getSingleUploadUrl: noopFnCreator(common.getSingleUploadUrl), - getFileUploadUrl: noopFnCreator(common.getFileUploadUrl), - getFileDownloadUrl: noopFnCreator(common.getFileDownloadUrl), - getSingleDownloadUrl: noopFnCreator(common.getSingleDownloadUrl), - getPackageDownloadUrl: noopFnCreator(common.getPackageDownloadUrl), - getAsyncPackageDownload: noopFnCreator(common.getAsyncPackageDownload), - getLargeFileInitUrl: noopFnCreator(common.getLargeFileInitUrl), - getChunkUploadUrl: noopFnCreator(common.getChunkUploadUrl), - getPreviewUrl: noopFnCreator(common.getPreviewUrl), - getDocumentInfoUrl: noopFnCreator(common.getDocumentInfoUrl), - getPreviewUrlBatch: noopFnCreator(common.getPreviewUrlBatch), - httpRequest: noopFnCreator(requestFn, 'httpRequest') - } -} - -export const computedUploadDisabled = - ({ props, state }: Pick) => - (): boolean => - props.disabled || (state.form || {}).disabled - -export const computedUploadingSize = - ({ state, constants }: Pick) => - (): number => - state.uploadingFiles.reduce( - (total, file) => (total + file.status !== constants.FILE_STATUS.FAIL ? file.size : 0), - 0 - ) - -export const watchListType = - ({ constants, state, api }: Pick) => - (type: string) => { - if ( - [ - constants.LIST_TYPE.PICTURE_CARD, - constants.LIST_TYPE.PICTURE, - constants.LIST_TYPE.PICTURE_SINGLE, - constants.LIST_TYPE.DRAG_SINGLE - ].includes(type) - ) { - state.uploadFiles = state.uploadFiles.map((file) => { - file.type = api.getFileSourceType({ file }) - if (!file.url && file.raw) { - try { - file.url = URL.createObjectURL(file.raw) - } catch (err) { - return null - } - } - - return file - }) - } - } - -export const watchFileList = - ({ constants, state, props, api }: Pick) => - (fileList: IFileUploadFile[]) => { - let uploadFiles = - fileList && - fileList.map((file) => { - file.uid = file.uid || Date.now() + state.tempIndex++ - file.status = file.status || constants.FILE_STATUS.SUCESS - file.type = api.getFileSourceType({ file }) - - return file - }) - if ([constants.LIST_TYPE.PICTURE_SINGLE, constants.LIST_TYPE.DRAG_SINGLE].includes(props.listType)) { - uploadFiles = uploadFiles.slice(0, 1) - } - - state.uploadFiles = uploadFiles - } - -const isNonFuncPropBeforeUpload = ({ - flag, - doUpload, - file -}: { - flag: boolean - doUpload: Function - file: IFileUploadFile -}) => !flag && doUpload(file) - -const onBeforeIsPromise = ({ - before, - rawFile, - file, - doUpload, - autoRemove, - api -}: Pick & { - before: Promise - rawFile: File - file: IFileUploadFile - doUpload: Function - autoRemove: boolean -}) => { - before.then( - (processedFile) => { - const fileType = Object.prototype.toString.call(processedFile) - - if (fileType === '[object File]' || fileType === '[object Blob]') { - if (fileType === '[object Blob]') { - processedFile = new File([processedFile], rawFile.name, { type: rawFile.type }) - } - - for (const p in rawFile) { - Object.prototype.hasOwnProperty.call(rawFile, p) && (processedFile[p] = rawFile[p]) - } - - file.raw = processedFile - } - - doUpload(file) - }, - () => { - if (autoRemove) { - if (!Array.isArray(rawFile)) { - api.handleRemove(null, rawFile) - } else { - rawFile.forEach((raw) => api.handleRemove(null, raw)) - } - } - } - ) -} - -const getFileType = ({ file }: { file: IFileUploadFile }): string => { - const { name, url } = file - let fileType = '' - if (name && /\.[^.]+$/.test(name)) { - fileType = name.split('.')[name.split('.').length - 1].toLowerCase() - } else if (url && /\.[.]+$/.test(url)) { - fileType = url.split('.')[url.split('.').length - 1].toLowerCase() - } - - return fileType -} - -const remove = ({ - api, - file, - autoRemove -}: Pick & { file: IFileUploadFile; autoRemove: boolean }) => { - if (autoRemove) { - const rawFile = file.raw - if (Array.isArray(rawFile)) { - rawFile.forEach((raw) => api.handleRemove(null, raw)) - } else { - api.handleRemove(null, rawFile) - } - } -} - -export const beforeUpload = - ({ - props, - api, - Modal, - constants, - t, - state - }: Pick & IFileUploadModalVm) => - (file: IFileUploadFile, autoRemove: boolean, doUpload: Function) => { - if (state.isEdm && file.name.length > 255) { - remove({ api, file, autoRemove }) - return Modal.message({ - message: `${t(constants.EDM.THEFILENAME)}"${file.name}"${t(constants.EDM.FILENAMEEXCEEDS)}`, - status: 'warning' - }) - } - - if (file) { - let isValid = true - const accept = state.isEdm ? state.accept : props.accept - const types = constants.FILE_TYPE[state.triggerClickType.toUpperCase()] - const fileType = getFileType({ file }) - - if (accept) { - const isExist = accept.split(',').some((type) => { - if (type.toLowerCase() === constants.IMAGE_TYPE) { - return constants.FILE_TYPE.PICTURE.split('/').includes(fileType) - } - return new RegExp(`(${type.trim()})$`, 'i').test(file.name) - }) - !isExist && (isValid = false) - } - - if (state.triggerClickType && types) { - const isExist = types.split('/').includes(fileType) - !isExist && (isValid = false) - } - - if (!isValid) { - remove({ api, file, autoRemove }) - return Modal.message({ - message: fileType - ? t(constants.EDM.notSupport, { format: fileType }) - : t(constants.EDM.NOT_SUPPORT_NO_SUFFIX), - status: 'warning' - }) - } - } - - let flag = typeof props.beforeUpload === 'function' - - isNonFuncPropBeforeUpload({ flag, doUpload, file }) - - if (flag) { - const { rawFile = file.raw, before = props.beforeUpload(rawFile) } = {} - - if (before && before.then) { - onBeforeIsPromise({ before, rawFile, file, doUpload, autoRemove, api }) - } else if (before !== false) { - doUpload(file) - } else { - if (autoRemove) { - if (Array.isArray(rawFile)) { - rawFile.forEach((raw) => api.handleRemove(null, raw)) - } else { - api.handleRemove(null, rawFile) - } - } - } - } - } - -export const startUpload = - ({ - state, - constants, - vm, - Modal, - api, - t - }: Pick & IFileUploadModalVm) => - (file: IFileUploadFile, isList: boolean) => { - if (state.isHwh5) { - vm.$refs[constants.UPLOAD_INNER].upload(file.raw) - return - } - if (file.size > state.docSize && file.size > state.chunkSize) { - file.isLargeFile = true - - isList && - state.uploadFiles.forEach((f) => { - if (f.cacheSign === file.cacheSign) { - f.percentage = 0 - } - }) - - api.largeDocumentUpload(file) - - Modal.message({ - message: `${file.name}${t(constants.EDM.LARGEFILEKEY)}`, - status: 'warning' - }) - } else { - vm.$refs[constants.UPLOAD_INNER].upload(file.raw) - } - } - -const calcFileForMobile = (rawFile: File, file: IFileUploadFile) => { - const fileName = rawFile.name.lastIndexOf('.') - const fileNameLen = rawFile.name.length - - file.fileType = rawFile.name.substring(fileName + 1, fileNameLen) - - const size = rawFile.size / 1024 - - if (size < 1024) { - file.size = Math.round(size * 10 ** 1) / 10 ** 1 + 'KB' - } else { - const fileSize = size / 1024 - file.size = Math.round(fileSize * 10 ** 1) / 10 ** 1 + 'MB' - } -} - -export const properFileSize = - ({ - props, - state, - api, - constants, - Modal, - t - }: Pick & IFileUploadModalVm) => - (file: IFileUploadFile): boolean => { - if ([undefined, null].includes(file.size)) return true - - let maxSize = 0 - - if (Array.isArray(props.fileSize) && props.fileSize[1]) { - maxSize = Math.min(state.singleMaxSize, props.fileSize[1] / 1024).toFixed(2) - } else { - maxSize = Math.min(state.singleMaxSize) - } - - if (state.isEdm || (!state.isEdm && Array.isArray(props.fileSize) && props.fileSize[1])) { - if (file.size > maxSize * 1024 * 1024) { - Modal.message({ - message: t(constants.EDM.EXCEED, { maxSize: api.formatFileSize(Number(maxSize), 'M') }), - status: 'warning' - }) - - return false - } - } - - if (file.size <= 0) { - Modal.message({ - message: `${file.name} ${t(constants.EDM.FILEEMPTY)}`, - status: 'warning' - }) - - return false - } - - const userMin = (props.fileSize && (props.fileSize[0] || props.fileSize)) || 0 - - if (file.size <= userMin * 1024) { - Modal.message({ - message: `${t(constants.EDM.SIZE, { minSize: api.formatFileSize(Number(userMin), ' KB'), sizeUnit: '' })}`, - status: 'warning' - }) - - return false - } - - return true - } - -export const addFileToList = - ({ - api, - constants, - emit, - props, - state, - mode - }: Pick) => - (rawFile: IFileUploadFile, updateId: string, reUpload: boolean) => { - !reUpload && (rawFile.uid = Date.now() + state.tempIndex++) - - let file = { status: constants.FILE_STATUS.READY, name: rawFile.name, size: rawFile.size } - - Object.assign(file, { percentage: 0, uid: rawFile.uid, raw: rawFile, response: {} }) - file.type = api.getFileSourceType({ file }) - - if (state.isEdm) { - let fileBase = { serverName: '', docRelativePath: '', docId: '', docVersion: '', cacheSign: rawFile.uid } - - file = Object.assign(file, fileBase) - - props.edm.upload.isFolder && (file.path = rawFile.webkitRelativePath.match(/.*\//g)[0]) - } - - state.cacheDocuments[file.uid] = file - - mode === 'mobile' && calcFileForMobile(rawFile, file) - - if ( - [ - constants.LIST_TYPE.PICTURE_CARD, - constants.LIST_TYPE.PICTURE, - constants.LIST_TYPE.PICTURE_SINGLE, - constants.LIST_TYPE.DRAG_SINGLE - ].includes(props.listType) - ) { - try { - if (state.isHwh5) { - file.url = rawFile.filePath - } else { - file.url = URL.createObjectURL(rawFile) - } - } catch (err) { - return - } - } - - if (state.isEdm && state.isSuccess) { - const proper = api.properFileSize(file) - if (!proper) { - return - } - - state.updateId = updateId || props.edm.updateId || '' - - if (reUpload) { - const index = state.uploadFiles.findIndex((item) => item.uid === file.uid) - state.uploadFiles.splice(index, 1) - } else if (state.updateId) { - const index = state.uploadFiles.findIndex((item) => item.docId === updateId) - state.uploadFiles.splice(index, 1, file) - emit('change', file, state.uploadFiles) - return - } - } - - if (!state.isEdm) { - const proper = api.properFileSize(file) - if (!proper) { - return - } - } - - state.uploadFiles.push(file) - state.currentUploadingFileUids.push(file.uid) - emit('change', file, state.uploadFiles) - } - -export const getFileHash = - ({ - emit, - Modal, - constants, - t, - CryptoJS, - state - }: Pick & - IFileUploadModalVm & { CryptoJS: object }) => - ({ file, chunkSize, showTips }: { file: IFileUploadFile; chunkSize: number; showTips: boolean }) => { - if (showTips) { - Modal.message({ - message: `${t(constants.EDM.CALCHASH)}`, - status: 'warning' - }) - } - - const chunks = Math.ceil(file.size / chunkSize) - let chunkIndex = 0 - let start = chunkIndex * chunkSize - let end = Math.min(file.size, start + chunkSize) - let chunk = file.raw.slice(start, end) - - const hasher = CryptoJS.algo.SHA256.create() - let calculated = 0 - - return new Promise((resolve) => { - const reader = new FileReader() - reader.readAsArrayBuffer(chunk) - reader.onload = (e) => { - if (file.status === constants.FILE_STATUS.FAIL) return - chunkIndex++ - - let wordArray = CryptoJS.lib.WordArray.create(e.target.result) - hasher.update(wordArray) - wordArray = null - - if (chunkIndex < chunks) { - start = chunkIndex * chunkSize - end = Math.min(file.size, start + chunkSize) - calculated += end - start - emit('hash-progress', Math.min(Math.floor((calculated / file.size) * 100), 100)) - chunk = file.raw.slice(start, end) - reader.readAsArrayBuffer(chunk) - } else { - const hash = hasher.finalize().toString() - file.hash = file.raw.hash = hash - resolve(hash) - emit('hash-progress', 100) - } - } - reader.onerror = (err) => { - file.status = constants.FILE_STATUS.FAIL - emit('error', err, file, state.uploadFiles) - } - }) - } - -const handleHwh5Files = (files: IFileUploadFile[], hwh5: object): IFileUploadFile[] | object[] => { - const fileMap = hwh5 && hwh5.fileMap - - return files.map((file) => { - if (file instanceof File) return file - let url - let f = {} - if (isObject(file)) { - url = file.url - f = file - } else { - url = file - } - const [name, index] = url.match(/[^/]*$/) - const [type] = url.match(/\.[^.]*$/) - const filePath = url.substring(0, index) - const updateFile = { ...f, type, name, filePath, webkitRelativePath: filePath } - - return typeof fileMap === 'function' ? fileMap(updateFile) : updateFile - }) -} - -export const handleStart = - ({ - api, - constants, - props, - state, - vm - }: Pick) => - (rawFiles: IFileUploadFile[], updateId: string, reUpload = false) => { - if (state.isHwh5) { - rawFiles = handleHwh5Files(rawFiles, props.hwh5) - } - state.currentUploadingFileUids = [] - rawFiles.forEach((rawFile) => api.addFileToList(rawFile, updateId, reUpload)) - - const { UPLOADING, READY } = constants.FILE_STATUS - state.uploadingFiles = state.uploadFiles.filter((file) => [UPLOADING, READY].includes(file.status)) - - if (state.isEdm && state.isSuccess) { - rawFiles.forEach((rawFile) => { - const file = api.getFile(rawFile) - - if (!file) return - - api.beforeUpload(file, true, (file) => { - typeof props.edm.upload.loading === 'function' && props.edm.upload.loading(file) - - new Promise((resolve) => { - if (state.isHwh5) return resolve() - - let isLargeFileHash = false - if (props.edm.isCheckCode !== true) return resolve() - if (file.size > state.docSize && file.size > state.chunkSize) { - if (!state.isEntireCheckCode) { - return resolve() - } else { - isLargeFileHash = true - } - } - - api - .getFileHash({ file, chunkSize: state.chunkSize, showTips: isLargeFileHash }) - .then((hash) => resolve(hash)) - }).then(() => { - if (props.autoUpload) { - const tokenParams = { token: props.edm.upload.token, file, type: 'upload' } - api.getToken(tokenParams).then((data) => { - if (data) { - file.status = constants.FILE_STATUS.UPLOADING - api.startUpload(file, true) - } - }) - } - }) - }) - }) - } - - if (!state.isEdm && props.autoUpload) { - if (props.multiple && props.mergeService) { - const handler = (file) => vm.$refs[constants.UPLOAD_INNER].upload(file.raw) - - rawFiles.length && api.beforeUpload({ raw: rawFiles }, true, handler) - } else { - rawFiles.forEach((rawFile) => { - const file = api.getFile(rawFile) - if (!file) return - const handler = (file) => vm.$refs[constants.UPLOAD_INNER].upload(file.raw) - - api.beforeUpload(file, true, handler) - }) - } - } - } - -export const calcUploadingFilesInfo = - ({ state, constants }: Pick) => - (): { percentage: number; uploadList: IFileUploadFile[]; uploadedCount: number } => { - let percentage - if (state.isHwh5) { - const totalPercentage = state.uploadingFiles.reduce((total, file) => { - const curPercentage = file.status !== constants.FILE_STATUS.FAIL ? file.percentage / 100 : 0 - return total + curPercentage - }, 0) - - percentage = Math.floor((totalPercentage / state.uploadingFiles.length) * 100) - } else { - const totalLoadedSize = state.uploadingFiles.reduce((loadedSize, file) => { - const loaded = file.status !== constants.FILE_STATUS.FAIL ? (file.size * file.percentage) / 100 : 0 - return loadedSize + loaded - }, 0) - - percentage = Math.floor((totalLoadedSize / state.uploadingSize) * 100) - } - - percentage = Math.min(percentage, 100) - const uploadedFiles = state.uploadingFiles.filter((file) => file.percentage === 100) - - return { - percentage, - uploadList: state.uploadingFiles, - uploadedCount: uploadedFiles.length - } - } - -export const handleProgress = - ({ api, constants, emit, state }: Pick) => - (event: any, rawFile: File) => { - if (Array.isArray(rawFile)) { - state.uploadFiles.forEach((file) => { - if (rawFile.some((raw) => file.uid === raw.uid)) { - file.status = constants.FILE_STATUS.UPLOADING - - if (event.lengthComputable) { - file.percentage = Math.floor((event.loaded * 100) / event.total) || 0 - } - - emit('progress', file, state.uploadFiles, api.calcUploadingFilesInfo()) - } - }) - } else { - const file = api.getFile(rawFile) - - if (file) { - file.status = constants.FILE_STATUS.UPLOADING - if (state.isHwh5) { - const { progress } = JSON.parse(event) - file.percentage = progress - if (file.percentage >= 100) { - file.isFinished = true - } - emit('progress', file, state.uploadFiles, api.calcUploadingFilesInfo()) - } else { - if (event.lengthComputable && !file.isLargeFile) { - file.percentage = Math.floor((event.loaded * 100) / event.total) || 0 - if (file.percentage >= 100) { - file.isFinished = true - } - emit('progress', file, state.uploadFiles, api.calcUploadingFilesInfo()) - } - } - } - } - } - -export const handleSuccess = - ({ - api, - constants, - emit, - state, - props, - Modal, - t - }: Pick) => - (res: any, rawFile: IFileUploadFile) => { - const currentUploadFiles = state.uploadFiles.filter((file) => state.currentUploadingFileUids.includes(file.uid)) - if (Array.isArray(rawFile)) { - state.uploadFiles.forEach((file) => { - if (rawFile.some((raw) => file.uid === raw.uid)) { - file.status = constants.FILE_STATUS.SUCESS - file.percentage = 100 - file.response = res - - emit('success', res, file, currentUploadFiles) - emit('change', file, state.uploadFiles) - - delete file.cancelToken - } - }) - } else { - const file = api.getFile(rawFile) - - const status = res?.data?.status - const { STATUS_SPECIAL_CHARACTERS, NOT_SUPPORT_SPECIAL_CHARACTERS } = constants.EDM - - delete file.cancelToken - - if (props.edm.upload && file && res.data && status !== 200) { - if (status === STATUS_SPECIAL_CHARACTERS) { - Modal.message({ - message: `${t(NOT_SUPPORT_SPECIAL_CHARACTERS)}`, - status: 'warning' - }) - } - file.status = constants.FILE_STATUS.FAIL - emit('error', res, file, state.uploadFiles) - return - } - - if (file) { - file.status = constants.FILE_STATUS.SUCESS - file.percentage = 100 - if (!file.isFinished) { - emit('progress', file, state.uploadFiles, api.calcUploadingFilesInfo()) - } - - file.isLargeFile && delete res.config - file.response = res - - if (state.isEdm) { - const result = state.isHwh5 ? res : res.data.result - - if (!result) return - - file.serverName = result.serverName - file.docRelativePath = result.docRelativePath - file.docId = result.docId - file.docVersion = result.version - file.docSize = result.docSize - file.isLargeFile && delete file.raw - - Object.assign(file, result) - } - - emit('success', res, file, currentUploadFiles) - emit('change', file, state.uploadFiles) - } - } - api.clearUploadingFiles() - } - -export const handleError = - ({ - api, - constants, - emit, - state, - props - }: Pick) => - (err: any, rawFile: IFileUploadFile) => { - const file = api.getFile(rawFile) - if (!file) return - - file.status = constants.FILE_STATUS.FAIL - file.percentage = 100 - - if (!state.isEdm && !props.reUploadable) { - state.uploadFiles.splice(state.uploadFiles.indexOf(file), 1) - } - - api.clearUploadingFiles() - emit('error', err, file, state.uploadFiles) - emit('change', file, state.uploadFiles) - } - -export const handleRemove = - ({ - api, - emit, - props, - state, - constants - }: Pick) => - (file: IFileUploadFile, raw: File) => { - if (raw) { - file = api.getFile(raw) - } - - let doRemove = () => { - // 删除动作不用改变文件状态为fail; 这样删除需要删两次。因为只有第二次时,indexOf才能在uploadFiles里面找到要删除的file。 - api.abort(file) - let fileList = state.uploadFiles - - fileList.splice(fileList.indexOf(file), 1) - emit('remove', { ...file, status: constants.FILE_STATUS.FAIL }, fileList) - } - - if (!props.beforeRemove) { - doRemove() - } else if (typeof props.beforeRemove === 'function') { - const before = props.beforeRemove(file, state.uploadFiles) - - if (before && before.then) { - before.then( - () => { - doRemove() - }, - () => undefined - ) - } else if (before !== false) { - doRemove() - } - } - } - -export const handleReUpload = - ({ vm, constants }: Pick) => - (file: IFileUploadFile) => { - const { READY } = constants.FILE_STATUS - file.status = READY - file.percentage = 0 - vm.$refs[constants.UPLOAD_INNER].upload(file.raw) - } - -export const handleReUploadTotal = (api: IFileUploadRenderlessParams['api']) => (files: IFileUploadFile[]) => { - files.forEach((file) => { - if (file.status === 'fail') { - api.handleReUpload(file) - } - }) -} - -export const clearUploadingFiles = - ({ constants, state }: Pick) => - () => { - const { SUCESS, FAIL } = constants.FILE_STATUS - const isUploadComplete = state.uploadingFiles.every((file) => [SUCESS, FAIL].includes(file.status)) - - if (isUploadComplete) { - state.uploadingFiles = [] - } - } - -export const getFile = - (state: IFileUploadRenderlessParams['state']) => - (rawFile: IFileUploadFile): IFileUploadFile => { - let fileList = state.uploadFiles - let target - - fileList.every((item) => { - target = rawFile.uid === item.uid ? item : null - return !target - }) - - return target - } - -export const abort = - ({ constants, vm, state }: Pick) => - (file: IFileUploadFile) => { - const { READY, UPLOADING, FAIL } = constants.FILE_STATUS - if (file) { - state.uploadingFiles.forEach((f) => { - const uid = file.uid || file - if (f.uid === uid && [READY, UPLOADING].includes(f.status)) { - f.status = FAIL - } - }) - } else { - state.uploadingFiles.forEach((f) => { - if ([READY, UPLOADING].includes(f.status)) { - f.status = FAIL - } - }) - } - - vm.$refs[constants.UPLOAD_INNER].abort(file) - } - -export const abortDownload = - ({ state }: Pick) => - (file: IFileUploadFile, batch = false) => { - const cancel = (docId) => { - if (!docId) return - const cancels = state.downloadCancelToken[docId] - cancels && cancels.forEach((cancel) => cancel()) - delete state.downloadCancelToken[docId] - - const clearDataFn = state.downloadCancelData[docId] - clearDataFn && clearDataFn(docId) - } - - if (Array.isArray(file)) { - if (batch) { - cancel( - file - .map((f) => f.docId || f) - .sort() - .join(',') - ) - } else { - file.forEach((f) => f && cancel(file.docId || file)) - } - } else if (file) { - cancel(file.docId || file) - } else { - Object.keys(state.downloadCancelToken).forEach((docId) => { - cancel(docId) - }) - } - } - -export const clearFiles = (state: IFileUploadRenderlessParams['state']) => () => { - state.uploadFiles = [] -} - -export const submit = - ({ - api, - constants, - vm, - state, - props - }: Pick) => - () => { - const files = state.uploadFiles.filter((file) => file.status === constants.FILE_STATUS.READY) - - if (state.isEdm && state.isSuccess) { - files.forEach((file) => { - api - .getToken({ - token: props.edm.upload.token, - file, - type: 'upload' - }) - .then((data) => { - if (data) { - api.beforeUpload(file, false, (file) => { - api.startUpload(file) - }) - } - }) - }) - } else { - if (props.multiple && props.mergeService) { - const rawFiles = files.map((file) => file.raw) - rawFiles.length && - api.beforeUpload({ raw: rawFiles }, false, (file) => { - vm.$refs[constants.UPLOAD_INNER].upload(file.raw) - }) - } else { - files.forEach((file) => { - api.beforeUpload(file, false, (file) => { - vm.$refs[constants.UPLOAD_INNER].upload(file.raw) - }) - }) - } - } - } - -export const handleClick = - ({ constants, vm }: Pick) => - () => - vm.$refs[constants.UPLOAD_INNER].handleClick() - -export const getFileUploadUrl = (service: IFileUploadRenderlessParams['service']) => (): Promise => - service.getFileUploadUrl() - -export const updateUrl = - ({ api, props, state }: Pick) => - () => { - if (props.action) { - state.url = props.action - } else { - api.getFileUploadUrl().then((url) => (state.url = url)) - } - } - -const getTranslateFile = - ({ - api, - isChunk, - isLessThan17G, - file, - state - }: Pick & { - isChunk: boolean - isLessThan17G: boolean - file: IFileUploadFile - }) => - (data: IFileUploadFile, type: string, index?: number) => { - if (isChunk) { - if (index === 0) { - state.downloadCancelData[file.docId] = api.setWriterFile({ data, index, isLessThan17G, file }) - } - } else { - const content = data.headers['content-disposition'] - const name = content ? content.match(/fileName.?=(.*)/)[1] || content.match(/fileName=(.*)/)[1] : '' - let type = 'application/zip' - - if (!name.includes('.')) { - type = data.headers['content-type'] - } else if (type !== 'zip') { - type = 'application / x - xls' - } - - const blob = new Blob([data.data], { type }) - aLinkDownload({ blob, name }) - } - } - -const aLinkDownload = ({ blob, name }: { blob: Blob; name: string }) => { - if (window && window.navigator.msSaveOrOpenBlob) { - window.navigator.msSaveOrOpenBlob(blob, decodeURIComponent(name)) - return - } - - const url = window.URL || window.webkitURL || window.moxURL - const downloadHref = xss.filterUrl(url.createObjectURL(blob)) - let downloadLink = document.createElement('a') - - downloadLink.href = downloadHref - downloadLink.download = decodeURIComponent(name) - downloadLink.click() - url.revokeObjectURL && url.revokeObjectURL(downloadHref) -} - -export const getHandleSuccess = - ({ - state, - downloadOps, - file, - translateFile, - isChunk, - isLessThan17G - }: Pick & { - downloadOps: IFileUploadEdmDownload - file: IFileUploadFile - translateFile: ReturnType - isChunk: boolean - isLessThan17G: boolean - }) => - (data: any, type: string, index?: number): boolean => { - if (isChunk) { - const res = isLessThan17G ? data.data : new Uint8Array(data.data) - let downloadChunkFile = state.downloadChunkFile[file.docId] - if (!downloadChunkFile) { - downloadChunkFile = {} - } - downloadChunkFile[index] = res - translateFile(data, type, index) - } else { - typeof downloadOps.loading === 'function' && downloadOps.loading(file) - translateFile(data, type) - } - - return true - } - -export const getCalcProgress = - () => - (evt: any): number => { - let total - if (evt.target && evt.target.getResponseHeader) { - total = Number(evt.target.getResponseHeader('Content-Size')) - } else { - total = Number(evt.total) - } - total = Math.max(total, evt.loaded) - - let progress = Math.ceil((evt.loaded / total) * 100) || 0 - progress = Math.max(progress, 0) - progress = Math.min(progress, 100) - - return progress - } - -export const modifyServiceUrlSingle = - ({ state, props, constants }: Pick) => - ({ file, serviceUrl, range }: { file: IFileUploadFile; serviceUrl: string; range: object }): string => { - if (typeof file === 'object') { - const downloadOps = props.edm.download || {} - const paramsWhitelist = Array.isArray(downloadOps.paramsWhitelist) ? downloadOps.paramsWhitelist : [] - const downloadParamsWhitelist = state.downloadParamsWhitelist.concat(paramsWhitelist) - - let tempFile = {} as IFileUploadFile - downloadParamsWhitelist.forEach((key) => (tempFile[key] = file[key])) - tempFile = Object.assign(tempFile, range) - - delete tempFile.docId - delete tempFile.docVersion - delete tempFile['x-download-sign'] - - for (let key in tempFile) { - const value = tempFile[key] - const dataType = typeof value - - if (!~['undefined', 'object', 'function'].indexOf(dataType)) { - serviceUrl += `&${key}=${value}` - } - } - - file.status = constants.FILE_STATUS.DOWNLOADING - file.percentage = 0 - } - - return serviceUrl - } - -export const getKiaScanTip = - ({ Modal, constants, t }: Pick & IFileUploadModalVm) => - ({ data }: { data: IFileUploadFile }): IFileUploadModalVm | undefined => { - if (data.status === constants.EDM.KIASTATUS) { - return Modal.message({ - message: `${t(constants.EDM.KIASCANTIP)}`, - status: 'warning' - }) - } - } - -export const validateDownloadStatus = - ({ state, Modal }: Pick & IFileUploadModalVm) => - ({ - downloadOps, - file, - isLessThan17G, - data - }: { - downloadOps: IFileUploadEdmDownload - file: IFileUploadFile - isLessThan17G: boolean - data: any - }) => { - const errorHandle = ({ state, file, errRes, Modal, downloadOps }) => { - if (state.currentDownloadFiles && state.currentDownloadFiles.docId === file.docId) return - - if (errRes && errRes.message) { - Modal.message({ - message: errRes.message, - status: 'warning' - }) - } - - state.currentDownloadFiles = file - - if (typeof downloadOps.fail === 'function') { - downloadOps.fail(errRes, file) - } - } - - if (data.data && data.data.type && data.data.type.includes('application/json')) { - const reader = new FileReader() - reader.onload = (e) => { - const errRes = JSON.parse(e.target.result) - errorHandle({ state, file, errRes, Modal, downloadOps }) - } - reader.readAsText(data.data) - return true - } - - if (!isLessThan17G && data.headers['content-type'].includes('application/json')) { - const errRes = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(data.data))) - errorHandle({ state, file, errRes, Modal, downloadOps }) - return true - } - } - -export const createDownloadCancelToken = - ({ state, service }: Pick) => - (file: IFileUploadFile): string => { - let docId - if (Array.isArray(file)) { - docId = file - .map((f) => f.docId || f) - .sort() - .join(',') - } else { - docId = file.docId || file - } - - if (!state.downloadCancelToken[docId]) { - state.downloadCancelToken[docId] = [] - } - - const { cancel, token } = service.cancelToken() - state.downloadCancelToken[docId].push(cancel) - - return token - } - -export const downloadFileSingle = - ({ - service, - constants, - props, - state, - api, - emit - }: Pick) => - (args: IFileUploadDownloadFileSingle) => { - let { - file, - batchIndex, - isChunk, - calcProgress, - handleSuccess, - range = {}, - isBatch, - isLessThan17G, - url: fileUrl - } = args - - let promise - - if (fileUrl) { - promise = Promise.resolve(fileUrl) - } else { - promise = service.getSingleDownloadUrl().then((url) => { - let serviceUrl = - url.replace(/{docId}/, file.docId || file) + - `${~url.indexOf('?') ? '&' : '?'}x-download-sign=true&docVersion=${file.docVersion || ''}${ - file.decryptKey ? '&decryptKey=' + file.decryptKey : '' - }` - - serviceUrl = api.modifyServiceUrlSingle({ file, serviceUrl, range }) - return serviceUrl - }) - } - - promise.then((url) => { - url = xss.filterUrl(url) - - let params = { - withCredentials: props.withCredentials, - headers: Object.assign(props.headers, state.headers), - responseType: isChunk && !isLessThan17G ? 'arraybuffer' : 'blob', - hideErr: true, - cancelToken: api.createDownloadCancelToken(file), - onDownloadProgress(evt) { - let progress = calcProgress(evt, isChunk) - if (progress !== 100) { - !isChunk && emit('download', progress, evt) - } - - if (typeof file === 'object') { - file.percentage = progress - } - } - } - - service - .get(url, params) - .then((data) => { - if (api.getKiaScanTip({ data })) return - if (api.validateDownloadStatus({ downloadOps: props.edm.download || {}, file, isLessThan17G, data })) return - - handleSuccess(data, '', range.index) - - const { checkcode, 'content-size': fileSize } = data.headers - !isChunk && emit('download', 100, '', { checkcode, fileSize }) - - if (typeof file === 'object') { - file.percentage = 100 - - setTimeout(() => (file.status = constants.FILE_STATUS.SUCESS), 1000) - } - - api.afterDownload({ batchIndex, data, file }) - }) - .catch((data) => { - if (data.response && state.errorStatusCodes.includes(data.response.status)) { - const downloadOps = props.edm.download || {} - const tokenParams = { token: downloadOps.token, file, type: 'download' } - api.getToken(tokenParams).then((data) => { - api.afterDownload({ batchIndex, data, file, range, isChunk, isBatch, isLessThan17G }) - }) - } - }) - }) - } - -export const downloadFileBatch = - ({ - api, - service, - props, - state, - emit - }: Pick) => - (args: IFileUploadDownloadFileSingle) => { - let { downloadOps, file, calcProgress, handleSuccess, range = {} } = args - let tokenParams = { token: downloadOps.packageToken, file, type: 'download' } - const { asyncPackages } = downloadOps || {} - api.getToken(tokenParams).then((data) => { - if (!data) { - return - } - - const params = { downloadTOs: [], attachdownloadTOs: [], isZip: 'true', transformType: 'sync', type: 'package' } - file.forEach((item) => { - if (item.wmType) { - params.attachdownloadTOs.push(item) - } else { - params.downloadTOs.push(item) - } - }) - - if (asyncPackages) { - api.downloadAsyncPackage(params) - return - } - - service.getPackageDownloadUrl().then((url) => { - url = xss.filterUrl(url + `${~url.indexOf('?') ? '&' : '?'}x-download-sign=true`) - - service - .post( - url, - { ...params, ...range }, - { - withCredentials: props.withCredentials, - headers: Object.assign(props.headers, state.headers), - responseType: 'blob', - cancelToken: api.createDownloadCancelToken(file), - onDownloadProgress(evt) { - let progress = calcProgress(evt) - if (progress !== 100) { - emit('download', progress, evt) - } - } - } - ) - .then((data) => { - if (api.getKiaScanTip({ data })) return - const { 'content-size': fileSize, checkcode } = data.headers - emit('download', 100, '', { fileSize, checkcode }) - handleSuccess(data, 'zip') - }) - }) - }) - } - -export const downloadAsyncPackage = - ({ state, props, service, api, constants }) => - (params) => { - return service.getAsyncPackageDownload().then((url) => { - service - .request({ - method: 'post', - url: xss.filterUrl(url), - withCredentials: props.withCredentials, - headers: Object.assign(props.headers, state.headers), - data: params - }) - .then((res) => { - if (res && res.data && res.data.status === 200) { - const files = (res.data.result || []).map(({ downloadLink, fileSize }) => { - return { url: downloadLink, fileSize } - }) - - const { SIZE_17G } = constants.EDM - const isBatch = false - const isChunk = false - const downloadOps = props.edm.download || {} - - files.forEach((file) => { - const isLessThan17G = !file.fileSize || file.fileSize < SIZE_17G * 1024 - const translateFile = getTranslateFile({ api, isChunk, isLessThan17G, file, state }) - const handleSuccess = getHandleSuccess({ - downloadOps, - file, - translateFile, - isChunk, - state, - isLessThan17G - }) - const calcProgress = getCalcProgress() - const args = { - url: file.url, - calcProgress, - handleSuccess, - downloadOps, - file, - isLessThan17G, - isFinished: false, - range: {}, - batchIndex: 0, - isBatch, - isChunk - } - - api.downloadFileSingle(args) - }) - } - }) - }) - } -export const downloadFileSingleHwh5 = - ({ state, props, emit, constants }: Pick) => - ({ file }: { file: IFileUploadFile }) => { - const { HWH5, appId } = props.hwh5 - const { downloadToEDM } = HWH5() - const options = { - edmAuth: { - edmToken: state.headers[constants.EDM.EDMTOKEN], - appId - }, - docId: file.docId || file, - docVersion: file.docVersion, - filePath: file.filePath, - progress: 1, - onProgress: (event) => { - const { progress } = JSON.parse(event) - if (progress * 1 !== 100) { - emit('download', progress) - } - } - } - - downloadToEDM(options).then((data) => { - emit('download', 100, '', { data }) - }) - } - -export const downloadFile = - ({ api, state }: Pick) => - (file: IFileUploadFile) => { - state.currentDownloadFiles = '' - - if (!state.isEdm) { - api.ordinaryDownload(file) - } else { - const isBatch = Array.isArray(file) - - if (state.isHwh5) { - let files = file - if (!isBatch) { - files = [file] - } - files.forEach((f) => api.downloadFileSingleInner({ file: f, isBatch: false })) - return - } - - if (isBatch) { - api.downloadFileInner({ file, isBatch }) - } else { - api.downloadFileSingleInner({ file, isBatch }) - } - } - } - -export const downloadFileSingleInner = - ({ props, state, api, constants }) => - ({ file, isBatch }) => { - const { SIZE_17G } = constants.EDM - const downloadOps = props.edm.download || {} - let tokenParams = { token: downloadOps.token, file, type: 'download' } - api.getToken(tokenParams).then((data) => { - if (!data) return - if (state.isHwh5) { - api.downloadFileSingleHwh5({ file }) - return - } - - const promise = state.hasFileInfoInterface ? api.getDownloadFileInfo({ docId: file.docId }) : Promise.resolve() - - promise.then((fileInfo) => { - const { fileSize } = fileInfo || {} - const isLargeFile = fileSize > state.docSize && fileSize > state.chunkSize - - if (fileSize && isLargeFile) { - api.largeDocumentDownload({ file: fileInfo, isBatch, isLessThan17G: fileSize < SIZE_17G * 1024 }) - } else { - api.downloadFileInner({ file, isBatch }) - } - }) - }) - } - -export const getDownloadFileInfo = - ({ api, state, props, service }: Pick) => - ({ docId }: { docId: string }) => { - return service.getDocumentInfoUrl().then((url) => { - return new Promise((resolve, reject) => { - service - .request({ - method: 'post', - url: xss.filterUrl(url), - withCredentials: props.withCredentials, - headers: Object.assign(props.headers, state.headers), - cancelToken: api.createDownloadCancelToken({ docId }), - data: { docInfoVO: { ids: [docId], docType: '', docVersion: '' } } - }) - .then((res) => { - const { data } = res || {} - - if (data && data.status === 200) { - const fileInfo = data.result.outDocQueryList && data.result.outDocQueryList[0].verInfo[0].docInfo[0] - - resolve(fileInfo) - } else { - reject(res) - } - }) - }) - }) - } - -export const largeDocumentDownload = - ({ api, state }: Pick) => - ({ file, isBatch, isLessThan17G }: IFileUploadLargeDocumentDownload) => { - const { fileSize, docId, docName } = file - const chunkSize = Math.ceil(fileSize / state.chunkSize) - state.downloadChunkFile[docId] = { chunkNum: chunkSize, fileSize, docName } - - file.chunkSize = chunkSize - const batches = api.sliceDownloadChunk(file) - api.batchSegmentDownload({ batchIndex: 0, batches, docId: file.docId, isBatch, isLessThan17G }) - } - -export const sliceDownloadChunk = - ({ state }: Pick) => - (file: IFileUploadFile): IFileUploadSliceDownloadChunk[][] => { - const chunkSize = file.chunkSize - const downloadChunkArray = [[]] as IFileUploadSliceDownloadChunk[][] - - state.downloadBatchQueue[file.docId + '-0'] = 0 - state.downloadBatchQueueListen[file.docId + '-0'] = 0 - - let startRange = 0 - let endRange = -1 - - for (let i = 0; i < chunkSize; i++) { - startRange = endRange + 1 - endRange = Math.min(file.fileSize, startRange + state.chunkSize) - - if (endRange < startRange) { - return downloadChunkArray - } - - const lastIndex = downloadChunkArray.length - 1 - - if (downloadChunkArray[lastIndex].length < state.downloadChunkLimit) { - downloadChunkArray[lastIndex].push({ startRange, endRange, index: i }) - } else { - state.downloadBatchQueue[file.docId + '-' + downloadChunkArray.length] = 0 - state.downloadBatchQueueListen[file.docId + '-' + downloadChunkArray.length] = 0 - downloadChunkArray.push([]) - downloadChunkArray[lastIndex + 1].push({ - startRange, - endRange, - index: i - }) - } - } - - return downloadChunkArray - } - -export const batchSegmentDownload = - ({ state, api }: Pick) => - ({ batchIndex, batches, docId, isBatch, isLessThan17G }: IFileUploadBatchSegmentDownload) => { - if (batchIndex < batches.length) { - const batch = batches[batchIndex] - const key = docId + '-' + batchIndex - - Object.defineProperty(state.downloadBatchQueue, key, { - get() { - return state.downloadBatchQueueListen[key] - }, - set(value) { - state.downloadBatchQueueListen[key] = value - - if (value >= batch.length) { - api.batchSegmentDownload({ - docId, - batchIndex: ++batchIndex, - batches, - isBatch, - isLessThan17G - }) - } - } - }) - - let index = 0 - while (batch.length - index > 0) { - api.downloadFileInner({ - batchIndex, - range: batch[index++], - file: { docId }, - isBatch, - isChunk: true, - isLessThan17G - }) - } - } - } - -export const downloadFileInner = - ({ api, props, state }: Pick) => - ({ batchIndex, file, range, isBatch, isChunk, isLessThan17G }: IFileUploadDownloadFileInner) => { - const downloadOps = props.edm.download || {} - const translateFile = getTranslateFile({ api, isChunk, isLessThan17G, file, state }) - const handleSuccess = getHandleSuccess({ downloadOps, file, translateFile, isChunk, state, isLessThan17G }) - const calcProgress = getCalcProgress() - - let { isFinished = false } = {} - - if (!isBatch) { - const args = { - calcProgress, - isFinished, - handleSuccess, - range, - batchIndex, - isBatch, - downloadOps, - file, - isChunk, - isLessThan17G - } - - api.downloadFileSingle(args) - - return - } - - const params = { downloadOps, file, calcProgress, handleSuccess, range } - isBatch && api.downloadFileBatch(params) - } - -export const afterDownload = - ({ api, state }: Pick) => - ({ batchIndex, range, data, file, isBatch, isChunk, isLessThan17G }: IFileUploadAfterDownload) => { - if (data.status === 200) { - const key = file.docId + '-' + batchIndex - const count = state.downloadBatchQueue[key] - state.downloadBatchQueue[key] = count + 1 - } else { - const countDownloadReplay = state.downloadReplayAtoms[file.docId + '-' + range.index] - - if (countDownloadReplay && countDownloadReplay >= 2) { - const msgArray = [ - 'The number of retry times exceeds the threshold! [docId:', - file.docId, - ', chunk:', - range.index, - ']' - ] - - log.logger.warn(msgArray.join('')) - delete state.downloadReplayAtoms[file.docId + '-' + range.index] - } else { - const msgArray = ['replay ', countDownloadReplay, '! [docId:', file.docId, ', chunk:', range.index, ']'] - - log.logger.warn(msgArray.join('')) - - state.downloadReplayAtoms[file.docId + '-' + range.index] = countDownloadReplay + 1 - - api.downloadFileInner({ batchIndex, range, file, isBatch, isChunk, isLessThan17G }) - } - } - } - -export const setWriterFile = - ({ - state, - emit, - Streamsaver - }: Pick & { Streamsaver: IFileUploadStreamsaver }) => - ({ data, index, isLessThan17G, file }: IFileUploadSetWriterFile): Function => { - let { fileStream, writer, fileData = [], downloaded = 0 } = {} - const { checkcode } = data.headers - const content = data.headers['content-disposition'] - - let { chunkNum, fileSize, docName } = state.downloadChunkFile[file.docId] - - if (content) { - docName = content.match(/fileName.?=(.*)/)[1] || content.match(/fileName=(.*)/)[1] || docName - } - - if (!isLessThan17G) { - fileStream = Streamsaver.createWriteStream(docName, { size: data.byteLength }) - writer = fileStream.getWriter() - } - - const writerStreamSaver = () => { - const downloadChunkFile = state.downloadChunkFile[file.docId] || {} - let chunk = downloadChunkFile[index] - - if (chunk) { - if (!isLessThan17G) { - writer.write(chunk).then(() => { - downloaded += chunk.byteLength - - downloadChunkFile[index] = null - delete downloadChunkFile[index] - if (index + 1 >= chunkNum) { - delete state.downloadChunkFile[file.docId] - - emit('download', 100, '', { fileSize, checkcode }) - writer.close() - } else { - const progress = Math.ceil((downloaded / fileSize) * 100) || 0 - progress !== 100 && emit('download', progress) - index++ - writerStreamSaver() - } - }) - } else { - fileData.push(chunk) - downloaded += chunk.size - state.downloadChunkFile[file.docId][index] = null - delete state.downloadChunkFile[file.docId][index] - if (index + 1 >= chunkNum) { - delete state.downloadChunkFile[file.docId] - aLinkDownload({ blob: new Blob(fileData), name: docName }) - emit('download', 100, '', { fileSize, checkcode }) - } else { - const progress = Math.ceil((downloaded / fileSize) * 100) || 0 - progress !== 100 && emit('download', progress) - index++ - writerStreamSaver() - } - } - } else { - setTimeout(() => writerStreamSaver(), 1000) - } - } - - writerStreamSaver() - - // 中止下载时需要清空数据 - return (docId) => { - const downloadChunkFile = state.downloadChunkFile[docId] - Object.keys(downloadChunkFile).forEach((k) => (downloadChunkFile[k] = null)) - delete state.downloadChunkFile[docId] - - if (isLessThan17G) { - fileData = [] - } else { - writer && writer.close() - } - } - } - -export const getFormData = - ({ constants, props, state }: Pick) => - ({ formData, file, type }: IFileUploadGetFormData): IUploadFormData => { - if (state.isEdm && props.edm.upload) { - const params = Object.assign({}, props.data || {}, props.edm.upload.params || {}) - - for (let key in params) { - formData.set(key, params[key] || '') - } - } - - if (props.edm.isCheckCode === true) { - formData.append(constants.EDM.ISCHECKCODE, 'Y') - file.hash && formData.append(constants.EDM.CHECKCODE, file.hash) - } else { - formData.append(constants.EDM.ISCHECKCODE, 'N') - } - - const updateId = state.updateId || props.edm.updateId - if (type === constants.EDM.CHUNKINIT) { - formData.append(constants.EDM.FILESIZE, file.size) - formData.append(constants.EDM.CHUNKS, file.chunkSize) - formData.append(constants.EDM.FILENAME, file.name) - - updateId && formData.append(constants.EDM.DOCID, updateId) - } else { - formData.append(constants.EDM.MULTIPART, file, file.filename) - formData.append(constants.EDM.CHUNK, file.chunk) - formData.append(constants.EDM.LOWERNAME, file.filename) - - const docId = updateId || file.docId - formData.append(constants.EDM.DOCID, docId) - } - - updateId && formData.append('updateFile', true) - - return formData - } - -export const largeDocumentUpload = - ({ - api, - Modal, - state, - t, - emit, - constants - }: Pick & IFileUploadModalVm) => - (file: IFileUploadFile) => { - const chunkSize = Math.ceil(file.size / state.chunkSize) - - file.chunkSize = chunkSize - file.cancelToken = [] - - api - .segmentUploadInit(file) - .then((data) => { - if (data) { - file.records = data.chunks - file.docId = data.docId - state.largeFileInfo[data.docId] = file - - const batches = api.sliceChunk(file) - - api.batchSegmentUpload({ - docId: data.docId, - batchIndex: 0, - batches, - progress: { size: file.size, trunks: [], file } - }) - } else { - Modal.message({ - message: t('ui.fileUpload.init'), - status: 'warning', - duration: '1000' - }) - - const file = api.getFile(file) - - state.uploadFiles.splice(state.uploadFiles.indexOf(file), 1) - } - }) - .catch((err) => { - file.status = constants.FILE_STATUS.FAIL - emit('error', err, file, state.uploadFiles) - }) - } - -export const segmentUploadInit = - ({ - api, - props, - service, - state, - constants - }: Pick) => - (file: IFileUploadFile) => { - const formData = new FormData() - - return new Promise((resolve, reject) => { - service.getLargeFileInitUrl().then((data) => { - service - .request({ - method: 'post', - url: xss.filterUrl(data), - data: api.getFormData({ formData, file, type: constants.EDM.CHUNKINIT }), - withCredentials: props.withCredentials, - headers: Object.assign(props.headers, state.headers) - }) - .then((data) => { - if (data.data.status === 200) { - resolve(data.data.result) - } else { - reject(data) - } - }) - }) - }) - } - -const afterUpload = ({ - data, - file, - batchIndex, - state, - api, - progress -}: Pick & IFileUploadSegmentUploadInner & { data: any }) => { - if (data.status === 200) { - const key = file.docId + '-' + batchIndex - const count = state.batchQueue[key] - - state.batchQueue[key] = count + 1 - } else { - const countReplay = state.replayAtoms[file.docId + '-' + file.chunk] - - if (countReplay && countReplay >= 2) { - const msgArray = [ - 'The number of retry times exceeds the threshold! [docId:', - file.docId, - ', chunk:', - file.chunk, - ']' - ] - log.logger.warn(msgArray.join('')) - - delete state.replayAtoms[file.docId + '-' + file.chunk] - } else { - const msgArray = ['replay ', countReplay, '! [docId:', file.docId, ', chunk:', file.chunk, ']'] - - log.logger.warn(msgArray.join('')) - - state.replayAtoms[file.docId + '-' + file.chunk] = countReplay + 1 - - api.segmentUpload(batchIndex, file, progress) - } - } -} - -const segmentUploadInner = ({ - api, - props, - service, - state, - emit, - constants, - batchIndex, - file, - progress -}: Pick & - IFileUploadSegmentUploadInner) => { - const formData = new FormData() - const postChunk = (url) => { - const source = service.cancelToken() - - if (progress.file.cancelToken) { - progress.file.cancelToken.push(source.cancel) - const { SUCESS, FAIL } = constants.FILE_STATUS - - service - .request({ - method: 'post', - url: xss.filterUrl(url), - data: api.getFormData({ formData, file, type: '' }), - withCredentials: props.withCredentials, - headers: Object.assign(props.headers, state.headers), - cancelToken: source.token, - hideErr: true, - onUploadProgress(event) { - progress.trunks[file.chunk] = event.loaded - - const count = progress.trunks.reduce((a, b) => a + b) - let percentage = Math.floor((count / progress.size) * 100) || 0 - file.percentage = Math.floor((event.loaded / event.total) * 100) - event.percentage = progress.file.percentage = percentage > 100 ? 100 : percentage - percentage >= 100 && (progress.file.isFinished = true) - - emit('progress', progress.file, state.uploadFiles, api.calcUploadingFilesInfo()) - } - }) - .then((data) => { - afterUpload({ data, file, batchIndex, state, api, progress }) - progress.file.percentage === 100 && (progress.file.status = SUCESS) - }) - .catch((data) => { - if (data.response && state.errorStatusCodes.includes(data.response.status)) { - const tokenParams = { token: props.edm.upload.token, file, type: 'upload' } - api.getToken(tokenParams).then((data) => afterUpload({ data, file, batchIndex, state, api, progress })) - } else { - progress.file.status !== FAIL && emit('error', data, progress.file, state.uploadFiles) - progress.file.status = FAIL - progress.file.docId = '' - } - }) - } - } - - if (!state.chunkUploadUrl) { - service.getChunkUploadUrl().then((data) => { - state.chunkUploadUrl = data - postChunk(data) - }) - } else { - postChunk(state.chunkUploadUrl) - } -} - -export const segmentUpload = - ({ - api, - props, - service, - state, - emit, - constants, - CryptoJS - }: Pick & { - CryptoJS: object - }) => - ( - batchIndex: number, - file: IFileUploadFile, - progress: { - file: IFileUploadFile - } - ) => { - if (typeof file.then === 'function') { - file - .then( - (file) => - new Promise((resolve) => { - if (props.edm.isCheckCode !== true) return resolve(file) - const reader = new FileReader() - - reader.readAsArrayBuffer(file) - reader.onload = (e) => { - if (props.edm.isCheckCode === true) { - let wordArray = CryptoJS.lib.WordArray.create(e.target.result) - const hash = CryptoJS.SHA256(wordArray).toString() - file.hash = hash - } - resolve(file) - } - }) - ) - .then((file) => { - segmentUploadInner({ - batchIndex, - api, - service, - state, - emit, - props, - file, - constants, - progress - }) - }) - } else { - segmentUploadInner({ - api, - props, - service, - state, - emit, - constants, - batchIndex, - file, - progress - }) - } - } - -export const batchSegmentUpload = - ({ - api, - constants, - props, - vm, - state - }: Pick) => - ({ docId, batchIndex, batches, progress }: IFileUploadBatchSegmentUpload) => { - if (batchIndex < batches.length && progress.file.cancelToken) { - const key = docId + '-' + batchIndex - const batch = batches[batchIndex] - - Object.defineProperty(state.batchQueue, key, { - get() { - return state.batchQueueListen[key] - }, - set(value) { - state.batchQueueListen[key] = value - - if (value >= batch.length) { - api.batchSegmentUpload({ - docId, - batchIndex: ++batchIndex, - batches, - progress - }) - } - } - }) - - let index = 0 - - while (batch.length - index > 0) { - api.segmentUpload(batchIndex, batch[index++], progress) - } - } else { - typeof props.edm.upload.closeloading === 'function' && props.edm.upload.closeloading() - - vm.$refs[constants.UPLOAD_INNER].upload(state.largeFileInfo[docId]) - } - } - -export const sliceChunk = - ({ state }: Pick) => - (file: IFileUploadFile) => { - const chunkSize = file.chunkSize - const chunkBatchArray = [[]] as Promise[][] - - state.batchQueue[file.docId + '-0'] = 0 - state.batchQueueListen[file.docId + '-0'] = 0 - - for (let i = 0; i < chunkSize; i++) { - if (file.records.includes(i.toString())) { - continue - } - - const start = i * state.chunkSize - const end = Math.min(file.size, start + state.chunkSize) - const atom = file.raw.slice(start, end) - - atom.chunk = i + 1 - atom.filename = file.name - atom.docId = file.docId - atom.chunkSize = chunkSize - atom.cacheSign = file.cacheSign - atom.records = file.records - atom.percentage = file.percentage - - const promise = Promise.resolve(atom) - - const lastIndex = chunkBatchArray.length - 1 - - if (chunkBatchArray[lastIndex].length < state.chunkBatchLimit) { - chunkBatchArray[lastIndex].push(promise) - } else { - state.batchQueue[file.docId + '-' + chunkBatchArray.length] = 0 - state.batchQueueListen[file.docId + '-' + chunkBatchArray.length] = 0 - chunkBatchArray.push([]) - chunkBatchArray[lastIndex + 1].push(promise) - } - } - - return chunkBatchArray - } - -export const getToken = - ({ - constants, - props, - state, - t, - Modal - }: Pick & IFileUploadModalVm) => - ({ - token, - file, - isOnlinePreview = false, - type = '', - isinit = false - }: { - token: Function - file: IFileUploadFile - isOnlinePreview: boolean - type: string - isinit: boolean - }) => { - if (props.edm.isExtranet && !isOnlinePreview) { - // EDM 外网场景除在线预览其他场景不需要调用 EDM Token - state.isSuccess = true - state.accept = props.accept - state.singleMaxSize = props.edm.singleFileMaxSize || 200 - - return Promise.resolve(true) - } - - if ((state.isEdm && !token) || typeof token !== 'function') { - Modal.message({ - message: t(constants.EDM.I18NKEY), - status: 'warning', - duration: '2000' - }) - - return new Promise((resolve) => { - resolve(false) - }) - } - - return new Promise((resolve, reject) => { - try { - let promise - - if (isinit && props.cacheToken) { - !initTokenPromise && (initTokenPromise = token(file)) - promise = initTokenPromise - } else { - promise = token(file) - } - - promise.then((data) => { - const result = data || {} - const whitelist = (result.config && result.config.fileWhiteList) || '' - - state.isSuccess = true - state.accept = - type === 'download' || type === 'preview' - ? props.accept - : `${whitelist}${props.accept ? `,${props.accept}` : ''}` - - state.headers[constants.EDM.EDMTOKEN] = result.edmToken || '' - state.headers[constants.EDM.TRACEID] = result.traceId || '' - - if (result.config) { - state.singleMaxSize = result.config.singleFileMaxSize - } - state.edmToken = result - resolve(true) - }) - } catch (error) { - reject(new Error(error)) - } - }) - } - -export const previewFile = - ({ api, props }: Pick) => - (file: IFileUploadFile, open = false) => { - return new Promise((resolve, reject) => { - try { - const tokenParams = { isOnlinePreview: true, file, type: 'preview', token: props.edm.preview.token } - - api - .getToken(tokenParams) - .then((data) => { - if (!data) { - const message = '[TINY Error][FileUpload] No edm token' - reject(new Error(message)) - return - } - - if (isObject(file) || (Array.isArray(file) && file.length === 1)) { - api.previewFileSingle({ file: Array.isArray(file) ? { ...file[0] } : file, resolve, open }) - } else if (Array.isArray(file) && file.length > 1) { - api.previewFileBatch({ file, resolve, open }) - } - }) - .catch((e) => reject(new Error(e))) - } catch (e) { - reject(new Error(e)) - } - }) - } - -export const getNewTabPreviewUrl = - ({ api }: Pick) => - (file: IFileUploadFile): Promise => - api.previewFile(file, true) - -export const previewFileSingle = - ({ - api, - state, - props, - constants, - service - }: Pick) => - ({ file, resolve, open }: { file: IFileUploadFile; resolve: (res: any) => void; open: boolean }) => { - const iframeUrl = api.getPreviewUrlSync(file) - - // 新标签页打开 - if (open) return resolve(iframeUrl) - - // iframe打开 - if (iframeUrl) { - state.showPreview = true - state.iframeUrl = iframeUrl - resolve(state.iframeUrl) - return - } - - const watermark = props.edm.preview.watermark || {} - const params = state.fileWater ? constants.EDM.FORMAT : '' - const downParams = state.fileWater ? constants.EDM.WATER : constants.EDM.SOURCE - const tools = props.edm.preview.plugin - - service.all([service.getPreviewUrl(), service.getSingleDownloadUrl()]).then( - service.spread((previewUrl, downloadurl) => { - const serviceUrl = props.edm.preview.serviceUrl - const infoUrl = - serviceUrl || previewUrl.replace(/{docId}/, file.docId) + `?${params}docVersion=${file.docVersion}` - - const pageUrl = - serviceUrl || - previewUrl.replace(/{docId}/, file.docId) + `?type=doc&pageNum=1&${params}docVersion=${file.docVersion}` - - const downloadUrl = - serviceUrl + - downloadurl.replace(/{docId}/, file.docId) + - `?docId=${file.docId}&docVersion=${file.docVersion}&${downParams}from=Experience&` - - tools.setIsEDM3(true) - tools.setDocumentInfoUrl(infoUrl) - tools.setDownloadUrl(downloadUrl, true) - tools.setPageUrl(pageUrl) - - tools.setWatermarkParameters({ - showWatermark: watermark.showWatermark || 1, - rotation: watermark.rotation || 30, - text: watermark.text || '' - }) - - tools.setPdfjsPaht(props.edm.preview.packageName || constants.EDM.JSLIB) - tools.setAuthToken(state.headers[constants.EDM.EDMTOKEN]) - - state.showPreview = true - state.iframeUrl = - props.edm.preview.previewUrl + `${constants.EDM.URLCONTS}${file.docVersion}&docId=${file.docId}` - resolve(state.iframeUrl) - }) - ) - } - -export const previewFileBatch = - ({ service, props, state, api }: Pick) => - ({ file, resolve, open }) => { - service.getPreviewUrlBatch().then((url) => { - const edm = props.edm || {} - const preview = edm.preview || {} - const online = preview.online || {} - const { jslibhtml, baseurl } = online - const { text } = preview.watermark || {} - - service - .request({ - method: 'post', - url: xss.filterUrl(url), - withCredentials: props.withCredentials, - headers: state.headers, - data: { - documents: file, - asposeClient: jslibhtml, - asposeService: baseurl, - watermark: text - } - }) - .then(({ data }) => { - const iframeUrl = api.getPreviewUrlSync({ generate: data.result.generate, size: file.length }, true) - // 新标签页打开 - if (open) return resolve(iframeUrl) - - // iframe打开 - if (iframeUrl) { - state.showPreview = true - state.iframeUrl = iframeUrl - resolve(state.iframeUrl) - } - }) - }) - } - -export const getPreviewUrlSync = - ({ constants, props, state }: Pick) => - (file: object, batch?: boolean) => { - const edm = props.edm || {} - const preview = edm.preview || {} - - const { watermark, online, bar = {}, lang } = preview - const { webPreview = false, http = false, jslibhtml, appid, baseurl } = online - - let html - if (webPreview) { - html = `${http ? 'http:' : 'https:'}${baseurl.replace(/\/$/, '')}/edm/projects/${appid}/web/preview` - } else { - html = jslibhtml.split('?').shift() - } - - const params = [] as string[] - let paramsData - const edmToken = state.headers[constants.EDM.EDMTOKEN] - - if (batch) { - // 批量预览 - html = html = `${baseurl.replace(/\/$/, '')}/edm/projects/${appid}/web/batchPreview` - const { generate, size } = file - paramsData = { generate, 'EDM-Authorization': edmToken, docIndex: 1, size } - } else { - // 单文件预览 - if (webPreview) { - const { styles } = bar - paramsData = Object.assign({}, watermark, { - 'EDM-Authorization': edmToken, - lang, - bar: window.btoa( - JSON.stringify({ - ...bar, - styles: JSON.stringify(styles) - }) - ), - docId: file.docId - }) - } else { - paramsData = Object.assign({}, online, watermark, { - authToken: edmToken, - jslibhtml: html, - docId: file.docId, - docVersion: file.docVersion || file.version || '', - type: 'doc', - pageNum: '1' - }) - } - } - - for (let key in paramsData) { - const val = paramsData[key] - if (!isObject(val)) { - if (key === 'text') { - params.push(`watermark=${encodeURIComponent(val)}`) - } - params.push(`${key}=${val}`) - } - } - - return html + '?' + params.join('&') - } - -export const previewImage = - ({ api, props, service }: Pick) => - (file: IFileUploadFile) => { - return new Promise((resolve, reject) => { - try { - api - .getToken({ - token: props.edm.preview.token, - file, - type: 'preview' - }) - .then((data) => { - if (!data) { - reject(new Error('[TINY Error][FileUpload] No edm token')) - return - } - - service.getPreviewUrl().then((url) => { - if (isObject(file) || (Array.isArray(file) && file.length === 1)) { - api - .previewImageSingle({ url, file: Array.isArray(file) ? { ...file[0] } : file }) - .then((link) => resolve(link)) - } else if (Array.isArray(file) && file.length > 1) { - api.previewImageBatch({ url, file }).then((links) => resolve(links)) - } - }) - }) - } catch (e) { - reject(new Error(e)) - } - }) - } - -export const previewImageSingle = - ({ service, state, props }: Pick) => - ({ file, url }: { file: IFileUploadFile; url: string }) => { - const edm = props.edm || {} - const preview = edm.preview || {} - let { text, textStyle } = preview.watermark || {} - textStyle = { tile: true, ...textStyle } - - const imgParam = Object.assign(file, { - type: 'image', - imageType: 'image', - watermark: text, - textStyle - }) - - return service - .post(xss.filterUrl(url.replace(/{docId}/, file.docId)), imgParam, { - withCredentials: props.withCredentials, - headers: Object.assign(props.headers, state.headers), - responseType: 'blob' - }) - .then((data) => { - const blob = new Blob([data.data]) - const URL = window.URL || window.webkitURL - return URL.createObjectURL(blob) - }) - } - -export const previewImageBatch = - ({ service, api }: Pick) => - ({ url, file }: { url: string; file: IFileUploadFile }) => { - const promises = [] as ReturnType[] - file.forEach((f) => { - promises.push(api.previewImageSingle({ url, file: f })) - }) - return service.all(promises) - } - -export const getDialogConfigObj = - ({ props, state, t, constants }: Pick) => - (): object => { - const dialogConfigDefault = { - class: 'single-download-modal single-download-modal1', - style: '', - props: { - lockScroll: true, - visible: state.showPreview, - dragable: true, - title: t(constants.EDM.DOC_PREVIEW), - width: '60%' - }, - on: { - 'update:visible': (value) => (state.showPreview = value) - } - } - let dialogConfig = {} - - if (props.edm && props.edm.preview && typeof props.edm.preview.dialogConfig === 'object') { - dialogConfig = props.edm.preview.dialogConfig || {} - } - - const dialogConfigCopy = extend(true, {}, dialogConfig) - const events = dialogConfigCopy.events || {} - // clazz、style只接受字符串值 - const clazz = dialogConfigCopy.class || '' - const style = dialogConfigCopy.style || '' - - delete dialogConfigCopy.events - delete dialogConfigCopy.class - delete dialogConfigCopy.style - - return extend(true, {}, dialogConfigDefault, { - class: `${dialogConfigDefault.class} ${clazz}`, - style: `${style}`, - props: { ...dialogConfigCopy }, - on: { ...events } - }) - } - -export const computeDocChunkSize = - ({ props, state, constants }: Pick) => - () => { - const isDefaultChunkSize = !(props.edm && props.edm.chunkSize) - const { SIZE_0M, SIZE_2M, SIZE_4M, SIZE_8M, SIZE_16M, SIZE_20M, SIZE_32M, SIZE_64M, SIZE_2G } = constants.EDM - - let { docSize = SIZE_20M, chunkSize = SIZE_8M } = props.edm || {} - docSize = docSize < 0 ? 0 : docSize - docSize = docSize > SIZE_2G ? SIZE_2G : docSize - - if (docSize) chunkSize = chunkSize < 0 ? 0 : chunkSize - if (!isDefaultChunkSize) { - const chunkSizes = [SIZE_64M, SIZE_32M, SIZE_16M, SIZE_8M, SIZE_4M, SIZE_2M, SIZE_0M] - chunkSizes.some((size) => { - if (chunkSize >= size) { - chunkSize = Math.max(size, SIZE_2M) - return true - } - return false - }) - } - - state.docSize = docSize * 1024 - state.chunkSize = chunkSize * 1024 - } - -export const computedSourcetype = - ({ props, constants }: Pick) => - (): string[] => { - const { sourceType, listType } = props - let types = sourceType.split('/') - if (listType !== constants.LIST_TYPE.PICTURE_CARD) { - types = types.slice(0, 1) - } - - return types - } - -export const getFileSourceType = - ({ state, props, constants }: Pick) => - ({ file }: { file: IFileUploadFile }) => { - const { PICTURE_SINGLE, PICTURE_CARD } = constants.LIST_TYPE - const { listType } = props - if (![PICTURE_SINGLE, PICTURE_CARD].includes(listType)) return - - let type = state.types[0] - if (file.type) { - type = file.type - } else if (listType === PICTURE_CARD) { - const { VIDEO, AUDIO, PICTURE } = constants.FILE_TYPE - const { SOURCE_VIDEO, SOURCE_AUDIO, SOURCE_PICTURE } = constants.SOURCE_TYPE - const matchs = { [VIDEO]: SOURCE_VIDEO, [AUDIO]: SOURCE_AUDIO, [PICTURE]: SOURCE_PICTURE } - - const fileType = getFileType({ file }) - const key = Object.keys(matchs).find((key) => key.split('/').includes(fileType)) - matchs[key] && (type = matchs[key]) - } - - return type - } - -export const updateFile = - ({ constants, vm }: Pick) => - (file: IFileUploadFile) => { - vm.$refs[constants.UPLOAD_INNER].handleUpdate(file) - } - -export const handleChange = - ({ vm, constants }: Pick) => - (file: IFileUploadFile) => { - if (typeof file === 'object' && file !== null && file !== undefined) { - let files = file - if (!Array.isArray(file)) { - files = [file] - } - vm.$refs[constants.UPLOAD_INNER].handleChange({ target: { files } }) - } - } - -export const handleTriggerClick = - ({ - vm, - state, - constants, - props, - emit - }: Pick) => - ($event: Event, type: string) => { - const { PICTURE_CARD, PICTURE_SINGLE } = constants.LIST_TYPE - const { isHwh5 } = state - const { listType } = props - - if (![PICTURE_CARD, PICTURE_SINGLE].includes(listType)) { - type = '' - } - - state.triggerClickType = type - - if (listType === PICTURE_CARD && isHwh5) { - vm.$refs[constants.UPLOAD_LIST_INNER].$refs[constants.UPLOAD_LIST_INNER_TEMPLATE].chooseFile(type) - return - } - - emit('trigger-click', $event, type) - } - -export const onBeforeDestroy = (state: IFileUploadRenderlessParams['state']) => () => { - if (!Array.isArray(state.uploadFiles)) return - - state.uploadFiles.forEach((file) => { - if (file.url && file.url.indexOf('blob:') === 0) { - URL.revokeObjectURL(file.url) - } - }) -} - -export const handleClickFileList = - ({ state, emit }: Pick) => - (file: IFileUploadFile) => { - state.selected = file - emit('click-file-list', file) - } - -export const mounted = - ({ vm, state }: Pick) => - () => { - vm.$on('drag-over', (isDragover) => (state.isDragover = isDragover)) - } - -export const encryptDialogConfirm = - ({ state }: Pick) => - () => { - const selectFileMethod = state.encryptDialogConfig.selectFileMethod - - state.encryptDialogConfig.show = false - typeof selectFileMethod === 'function' && selectFileMethod() - } - -export const closeRecordPanel = - ({ vm, constants, state, props }: Pick) => - () => { - const { PICTURE_CARD } = constants.LIST_TYPE - const { isHwh5 } = state - const { listType } = props - - if (listType === PICTURE_CARD && isHwh5) { - vm.$refs[constants.UPLOAD_LIST_INNER].$refs[constants.UPLOAD_LIST_INNER_TEMPLATE].state.showAudioPanel = false - } - } - -export const getTipMessage = - ({ t, api, constants }: Pick) => - ({ accept, fileSize, limit }: { accept: string; fileSize: string; limit: number }) => { - let acceptTip = '' - - if (accept) { - acceptTip = t(constants.ONLY_SUPPORT, { - type: accept - .split(',') - .map((item) => item.trim().replace(/^\./, '')) - .join(t(constants.COMMA)) - }) - } - - if (fileSize && acceptTip.length !== 0) { - acceptTip += `${t(constants.COMMA)} ` - } - - let fileSizeTip = '' - let kibibyte = 1024 - if (typeof fileSize === 'number') { - fileSizeTip = `${t(constants.FILE_NOT_LESS_THAN)}${api.formatFileSize(fileSize * kibibyte)}` - } else if (Array.isArray(fileSize)) { - fileSizeTip += !isNaN(fileSize[0]) - ? `${t(constants.FILE_NOT_LESS_THAN)}${api.formatFileSize(Number(fileSize[0]) * kibibyte)}${t(constants.COMMA)}` - : '' - fileSizeTip += !isNaN(fileSize[1]) - ? `${t(constants.FILE_NOT_MORE_THAN)}${api.formatFileSize(Number(fileSize[1]) * kibibyte)}` - : '' - } - - let limitTip = limit ? t(constants.NUMBER_LIMIT, { number: limit }) : '' - - if ((fileSize || acceptTip.length !== 0) && limit) { - limitTip = `${t(constants.COMMA)} ` + limitTip - } - - return acceptTip + fileSizeTip + limitTip - } diff --git a/packages/mobile/components/file-upload/src/renderless/vue.ts b/packages/mobile/components/file-upload/src/renderless/vue.ts deleted file mode 100644 index 6337cd1cfa..0000000000 --- a/packages/mobile/components/file-upload/src/renderless/vue.ts +++ /dev/null @@ -1,370 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { - IFileUploadState, - IFileUploadApi, - IFileUploadProps, - ISharedRenderlessParamHooks, - IFileUploadRenderlessParamUtils, - IFileUploadModalVm, - IFileUploadService, - IFileUploadStreamsaver -} from '../file-upload' -import { downloadFile as ordinaryDownload } from '../../../upload-list/src/renderless' -import { formatFileSize } from '@mobile-root/utils/string' - -import { - initService, - getNewTabPreviewUrl, - previewFile, - getToken, - downloadFile, - downloadFileSingleInner, - batchSegmentUpload, - segmentUpload, - sliceChunk, - segmentUploadInit, - largeDocumentUpload, - getFormData, - abort, - clearFiles, - computedUploadDisabled, - getFile, - handleStart, - handleProgress, - handleSuccess, - handleError, - handleRemove, - handleReUpload, - handleReUploadTotal, - onBeforeDestroy, - submit, - watchListType, - watchFileList, - handleClick, - getFileUploadUrl, - updateUrl, - previewImage, - startUpload, - getDialogConfigObj, - computeDocChunkSize, - updateFile, - getPreviewUrlSync, - beforeUpload, - computedUploadingSize, - clearUploadingFiles, - calcUploadingFilesInfo, - properFileSize, - addFileToList, - getDownloadFileInfo, - largeDocumentDownload, - sliceDownloadChunk, - batchSegmentDownload, - downloadFileInner, - setWriterFile, - afterDownload, - getFileHash, - modifyServiceUrlSingle, - getKiaScanTip, - downloadFileSingle, - downloadFileBatch, - downloadFileSingleHwh5, - downloadAsyncPackage, - validateDownloadStatus, - mounted, - handleChange, - previewFileSingle, - previewFileBatch, - previewImageSingle, - previewImageBatch, - abortDownload, - createDownloadCancelToken, - handleClickFileList, - computedSourcetype, - getFileSourceType, - encryptDialogConfirm, - handleTriggerClick, - closeRecordPanel, - getTipMessage -} from './index' -import { isEmptyObject } from '@mobile-root/utils/type' - -export const api = [ - 'state', - 'getNewTabPreviewUrl', - 'previewFile', - 'downloadFile', - 'abort', - 'clearFiles', - 'getFile', - 'handleStart', - 'handleProgress', - 'handleSuccess', - 'handleError', - 'handleRemove', - 'handleReUpload', - 'handleReUploadTotal', - 'submit', - 'handleClick', - 'getFileUploadUrl', - 'updateUrl', - 'previewImage', - 'updateFile', - 'handleChange', - 'abortDownload', - 'handleClickFileList', - 'handleTriggerClick', - 'closeRecordPanel', - 'encryptDialogConfirm', - 'formatFileSize', - 'getTipMessage' -] - -const initState = ({ - api, - reactive, - computed, - inject, - ref, - vm, - props, - httpRequest, - service, - useBreakpoint -}): IFileUploadState => { - const { current } = useBreakpoint() - const state = reactive({ - url: '', - updateId: '', - currentDownloadFiles: '', - tempIndex: 1, - draging: false, - uploadFiles: [], - dragOver: false, - httpRequest, - form: inject('form', ref({ default: '' })), - listeners: vm.$listeners, - docSize: 0, // unit(B) - chunkSize: 0, - chunkBatchLimit: 5, - downloadChunkLimit: 5, - batchQueue: {}, - batchQueueListen: {}, - batchCancelToken: {}, - replayAtoms: {}, - chunkUploadUrl: '', - largeFileInfo: {}, - headers: {}, - accept: '', - edmToken: {}, - isSuccess: false, - singleMaxSize: 200, - formData: {}, - showPreview: false, - iframeUrl: '', - fileWater: false, - tabUrl: '', - cacheDocuments: {}, - isEdm: computed(() => !isEmptyObject(props.edm)), - uploadDisabled: computed(() => api.computedUploadDisabled()), - dialogConfigObj: computed(() => api.getDialogConfigObj()), - uploadingFiles: [], - currentUploadingFileUids: [], - uploadingSize: computed(() => api.computedUploadingSize()), - isEntireCheckCode: computed(() => !('isEntireCheckCode' in props.edm && props.edm.isEntireCheckCode !== true)), - downloadBatchQueue: {}, - downloadBatchQueueListen: {}, - downloadChunkFile: {}, - downloadReplayAtoms: {}, - errorStatusCodes: [0, 401, 429], // 0:上传异常 401:没权限(token过期)429:超限 - hasFileInfoInterface: computed(() => service.setting.services.EDM && service.setting.services.EDM.DocumentInfoUrl), - currentDownloadFile: '', - isDragover: false, - downloadCancelToken: {}, // 取消下载token - downloadCancelData: {}, // 取消下载时需要清空的缓存数据 - isHwh5: computed(() => !isEmptyObject(props.hwh5)), - selected: null, - types: computed(() => api.computedSourcetype()), - triggerClickType: '', - visible: false, - downloadParamsWhitelist: ['docId', 'wmType', 'docVersion'], - encryptDialogConfig: { - show: false, - selectFileMethod: null - }, - current - }) - - return state -} - -const initApi = ({ api, state, props, constants, vm, $service, t, Modal }) => { - Object.assign(api, { - state, - sliceChunk: sliceChunk({ state }), - getFormData: getFormData({ constants, props, state }), - abort: abort({ constants, vm, state }), - handleClick: handleClick({ constants, vm }), - getFile: getFile(state), - clearFiles: clearFiles(state), - watchFileList: watchFileList({ constants, state, props, api }), - watchListType: watchListType({ constants, state, api }), - onBeforeDestroy: onBeforeDestroy(state), - computedUploadDisabled: computedUploadDisabled({ props, state }), - computedUploadingSize: computedUploadingSize({ state, constants }), - getFileUploadUrl: getFileUploadUrl($service), - getToken: getToken({ constants, props, state, t, Modal }), - getDialogConfigObj: getDialogConfigObj({ props, state, t, constants }), - computeDocChunkSize: computeDocChunkSize({ props, state, constants }), - updateFile: updateFile({ constants, vm }), - getPreviewUrlSync: getPreviewUrlSync({ constants, props, state }), - ordinaryDownload: ordinaryDownload($service), - clearUploadingFiles: clearUploadingFiles({ constants, state }), - calcUploadingFilesInfo: calcUploadingFilesInfo({ state, constants }), - properFileSize: properFileSize({ props, state, api, constants, Modal, t }), - mounted: mounted({ vm, state }), - previewFileSingle: previewFileSingle({ api, state, props, constants, service: $service }), - previewFileBatch: previewFileBatch({ service: $service, props, state, api }), - previewImageSingle: previewImageSingle({ state, props, service: $service }), - previewImageBatch: previewImageBatch({ service: $service, api }), - abortDownload: abortDownload({ state }), - createDownloadCancelToken: createDownloadCancelToken({ state, service: $service }), - computedSourcetype: computedSourcetype({ props, constants }), - getFileSourceType: getFileSourceType({ state, props, constants }), - encryptDialogConfirm: encryptDialogConfirm({ state }), - getTipMessage: getTipMessage({ t, api, constants }), - formatFileSize - }) -} - -const mergeApi = ({ api, props, $service, state, constants, emit, mode, Modal, t, vm, CryptoJS, Streamsaver }) => { - Object.assign(api, { - segmentUploadInit: segmentUploadInit({ api, props, service: $service, state, constants }), - segmentUpload: segmentUpload({ api, props, service: $service, state, emit, constants, CryptoJS }), - addFileToList: addFileToList({ api, constants, emit, props, state, mode }), - downloadFile: downloadFile({ api, state }), - downloadFileSingleInner: downloadFileSingleInner({ props, state, api, constants }), - previewImage: previewImage({ api, props, service: $service }), - previewFile: previewFile({ api, props }), - getNewTabPreviewUrl: getNewTabPreviewUrl({ api }), - submit: submit({ api, constants, vm, props, state }), - handleStart: handleStart({ api, constants, props, state, vm }), - batchSegmentUpload: batchSegmentUpload({ api, constants, props, vm, state }), - largeDocumentUpload: largeDocumentUpload({ api, Modal, state, emit, constants, t }), - handleProgress: handleProgress({ api, constants, emit, state }), - handleSuccess: handleSuccess({ api, constants, emit, Modal, props, state, t }), - handleError: handleError({ api, constants, emit, state, props }), - handleRemove: handleRemove({ api, emit, props, state, constants }), - handleReUpload: handleReUpload({ vm, constants }), - handleReUploadTotal: handleReUploadTotal(api), - updateUrl: updateUrl({ api, props, state }), - startUpload: startUpload({ api, state, constants, vm, Modal, t }), - beforeUpload: beforeUpload({ api, props, Modal, constants, t, state }), - getDownloadFileInfo: getDownloadFileInfo({ api, props, state, service: $service }), - largeDocumentDownload: largeDocumentDownload({ api, state }), - sliceDownloadChunk: sliceDownloadChunk({ state }), - batchSegmentDownload: batchSegmentDownload({ state, api }), - downloadFileInner: downloadFileInner({ api, props, state }), - setWriterFile: setWriterFile({ state, emit, Streamsaver }), - afterDownload: afterDownload({ api, state }), - getFileHash: getFileHash({ emit, Modal, constants, t, CryptoJS, state }), - modifyServiceUrlSingle: modifyServiceUrlSingle({ state, props, constants }), - getKiaScanTip: getKiaScanTip({ Modal, constants, t }), - downloadFileSingle: downloadFileSingle({ service: $service, constants, props, state, api, emit }), - downloadFileBatch: downloadFileBatch({ api, service: $service, props, state, emit }), - downloadFileSingleHwh5: downloadFileSingleHwh5({ state, props, emit, constants }), - downloadAsyncPackage: downloadAsyncPackage({ state, props, api, constants, service: $service }), - validateDownloadStatus: validateDownloadStatus({ state, Modal }), - handleChange: handleChange({ vm, constants }), - handleClickFileList: handleClickFileList({ state, emit }), - handleTriggerClick: handleTriggerClick({ vm, state, constants, props, emit }), - closeRecordPanel: closeRecordPanel({ vm, constants, state, props }) - }) -} - -const initWatch = ({ watch, state, api, props, $service }) => { - watch( - () => props.edm?.upload, - (value) => value && api.getToken({ token: value.token, isinit: true }), - { immediate: true, deep: true } - ) - - watch(() => props.listType, api.watchListType) - - watch( - () => props.fileList, - (value) => api.watchFileList(value), - { immediate: true, deep: true } - ) - - watch( - () => props.action, - () => { - if (!props.httpRequest && !state.isEdm) { - api.updateUrl() - } - }, - { immediate: true } - ) - - watch( - () => state.isSuccess, - (value) => value && $service.getSingleUploadUrl().then((url) => (state.url = url)), - { immediate: true } - ) - - watch(() => props.edm, api.computeDocChunkSize, { deep: true, immediate: true }) -} - -// eslint-disable-next-line import/no-mutable-exports -export let getApi = () => ({}) as { downloadFile: Function } - -export const renderless = ( - props: IFileUploadProps, - { computed, inject, onBeforeUnmount, provide, reactive, ref, watch, onMounted }: ISharedRenderlessParamHooks, - { t, vm, emit, service, mode, constants, useBreakpoint }: IFileUploadRenderlessParamUtils, - { Modal, CryptoJS, Streamsaver }: IFileUploadModalVm & { CryptoJS: object; Streamsaver: IFileUploadStreamsaver } -): IFileUploadApi => { - let api = {} as IFileUploadApi - const $service: IFileUploadService = initService({ props, service }) - const httpRequest: Function = $service.httpRequest - const state: IFileUploadState = initState({ - reactive, - computed, - api, - inject, - ref, - vm, - props, - httpRequest, - service, - useBreakpoint - }) - - initApi({ api, state, props, constants, vm, $service, t, Modal }) - mergeApi({ api, props, $service, state, constants, emit, mode, Modal, t, vm, CryptoJS, Streamsaver }) - getApi = () => api - - provide('uploader', vm) - - onMounted(api.mounted) - - // 注册生命周期函数必须要在(watch)异步函数/组件之前,否则会 Vue3 警告 - onBeforeUnmount(() => { - api.onBeforeDestroy() - api = {} as IFileUploadApi - }) - - initWatch({ watch, state, api, props, $service }) - - return api -} diff --git a/packages/mobile/components/form-item/index.ts b/packages/mobile/components/form-item/index.ts deleted file mode 100644 index db2d8dfa29..0000000000 --- a/packages/mobile/components/form-item/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import FormItem from './src/mobile.vue' - -/* istanbul ignore next */ -FormItem.install = function (Vue) { - Vue.component(FormItem.name, FormItem) -} - -export default FormItem diff --git a/packages/mobile/components/form-item/src/form-item.ts b/packages/mobile/components/form-item/src/form-item.ts deleted file mode 100644 index 71fada9c4c..0000000000 --- a/packages/mobile/components/form-item/src/form-item.ts +++ /dev/null @@ -1,208 +0,0 @@ -import type { ExtractPropTypes, StyleValue } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils, ITinyVm } from '@mobile-root/shared.type' - -import type { - watchError, - updateTip, - watchValidateStatus, - computedLabelStyle, - computedValueStyle, - computedContentStyle, - computedForm, - computedFieldValue, - computedGetValidateType, - computedValidateIcon, - computedIsErrorInline, - computedIsErrorBlock, - clearValidate, - getRules, - updateComputedLabelWidth, - removeValidateEvents, - unmounted, - mounted, - computedIsRequired, - resetField, - getFilteredRule, - onFieldBlur, - onFieldChange, - addValidateEvents, - validate, - getDisplayedValue, - clearDisplayedValue, - handleMouseenter, - handleMouseleave -} from './renderless' - -export type { IFormInstance } from '../../form/src/form' - -export const $constants = { - FORM_NAME: 'Form', - FORM_ITEM_NAME: 'FormItem' -} - -export const formItemProps = { - _constants: { - type: Object, - default: () => $constants - }, - appendToBody: { - type: Boolean, - default: undefined - }, - error: { - type: String, - default: '' - }, - for: String, - inlineMessage: { - type: Boolean, - default: undefined - }, - messageType: String, - label: String, - labelWidth: String, - manual: Boolean, - popperOptions: { - type: Object, - default: () => ({}) - }, - prop: String, - required: { - type: Boolean, - default: undefined - }, - rules: [Object, Array], - showMessage: { - type: Boolean, - default: true - }, - size: String, - tipContent: String, - validateDisabled: Boolean, - validateDebounce: Boolean, - validatePosition: String, - validateStatus: String, - validateType: String, - validateIcon: Object, - ellipsis: { - type: Boolean, - default: false - }, - vertical: { - type: Boolean, - default: false - }, - extra: String -} - -export interface IFormItemDisplayedValueParam { - type: string - val: string -} - -export type IFormItemValidateStatus = 'validating' | 'success' | 'error' - -export type IFormItemTrigger = 'blur' | 'change' | '' - -export interface IFormItemLabelStyle { - width: string -} - -export interface IFormItemRule { - required?: boolean - message?: string - trigger?: IFormItemTrigger | IFormItemTrigger[] - validator?: Function -} -export interface IFormItemState { - mode: string - validateState: string - validateMessage: string - validateDisabled: boolean - validator: object - isNested: boolean - computedLabelWidth: string - initialValue: any - canShowTip: boolean - validationRequired: boolean - validateType: string - tooltip: string - displayedValue: string - isBasicComp: boolean - showTooltip: boolean - typeName: string - formInstance: IFormInstance - labelFor: string - labelStyle: IFormItemLabelStyle - valueStyle: StyleValue - contentStyle: StyleValue - form: IFormInstance - fieldValue: any - isRequired: boolean - formInline: boolean | undefined - formSize: string | undefined - formItemSize: string | undefined - isDisplayOnly: boolean - labelPosition: string - hideRequiredAsterisk: boolean - labelSuffix: string - labelWidth: string - showMessage: boolean - sizeClass: string | undefined - getValidateType: string - validateIcon: object | null - isErrorInline: boolean - isErrorBlock: boolean - tooltipType: string -} - -export type IFormItemConstants = typeof $constants - -export type IFormItemProps = ExtractPropTypes - -export type IFormItemRenderlessParams = ISharedRenderlessFunctionParams & { - state: IFormItemState - props: IFormItemProps - api: IFormItemApi - instance: IFormItemInstance - validateFunc: Function -} - -export interface IFormItemApi { - state: IFormItemState - dispatch: ISharedRenderlessParamUtils['dispatch'] - broadcast: ISharedRenderlessParamUtils['broadcast'] - watchError: ReturnType - updateTip: ReturnType - watchValidateStatus: ReturnType - computedLabelStyle: ReturnType - computedValueStyle: ReturnType - computedContentStyle: ReturnType - computedForm: ReturnType - computedFieldValue: ReturnType - computedGetValidateType: ReturnType - computedValidateIcon: ReturnType - computedIsErrorInline: ReturnType - computedIsErrorBlock: ReturnType - clearValidate: ReturnType - getRules: ReturnType - updateComputedLabelWidth: ReturnType - removeValidateEvents: ReturnType - unmounted: ReturnType - mounted: ReturnType - computedIsRequired: ReturnType - resetField: ReturnType - getFilteredRule: ReturnType - onFieldBlur: ReturnType - onFieldChange: ReturnType - addValidateEvents: ReturnType - validate: ReturnType - getDisplayedValue: ReturnType - clearDisplayedValue: ReturnType - handleMouseenter: ReturnType - handleMouseleave: ReturnType -} - -export type IFormItemRenderlessParamUtils = ISharedRenderlessParamUtils - -export type IFormItemInstance = ITinyVm & IFormItemProps & IFormItemApi diff --git a/packages/mobile/components/form-item/src/label-wrap.ts b/packages/mobile/components/form-item/src/label-wrap.ts deleted file mode 100644 index 0a3c7e617a..0000000000 --- a/packages/mobile/components/form-item/src/label-wrap.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { setup, h, $props, defineComponent } from '@mobile-root/common' - -export default defineComponent({ - props: { - ...$props, - isAutoWidth: Boolean, - updateAll: Boolean, - isMobile: Boolean, - isMobileFirst: Boolean - }, - inject: ['form', 'formItem'], - render() { - const slotsDefault = this.slots.default && this.slots.default() - const classPrefix = this.isMobile ? 'tiny-mobile-' : 'tiny-' - - if (!slotsDefault) return null - - if (this.isAutoWidth) { - const autoLabelWidth = (this as any).form.autoLabelWidth - const style = {} as any - - if (autoLabelWidth && autoLabelWidth !== 'auto') { - const marginLeft = parseInt(autoLabelWidth, 10) - this.computedWidth - if (marginLeft) { - style.marginLeft = marginLeft + 'px' - } - } - - return h( - 'div', - { - class: this.isMobileFirst ? 'float-left' : `${classPrefix}form-item_label-wrap`, - style - }, - slotsDefault - ) - } else { - return slotsDefault[0] - } - }, - methods: { - getLabelWidth() { - const computedStylWidth = (elem) => window.getComputedStyle(elem).width - const ceilFloat = (f) => Math.ceil(parseFloat(f)) - - return !this.$el || !this.$el.firstElementChild ? 0 : ceilFloat(computedStylWidth(this.$el.firstElementChild)) - }, - updateLabelWidth(action = 'update') { - if (!this.$slots.default || !this.isAutoWidth || !this.$el.firstElementChild) { - return - } - - const setComputedWidth = () => (this.computedWidth = this.getLabelWidth()) - const deregisterFormLabelWidth = () => (this as any).form.deregisterLabelWidth(this.computedWidth) - - if (action === 'update') { - setComputedWidth() - } else if (action === 'remove') { - deregisterFormLabelWidth() - } - } - }, - watch: { - computedWidth(val, oldVal) { - if (this.updateAll) { - ;(this as any).form.registerLabelWidth(val, oldVal) - ;(this as any).formItem.updateComputedLabelWidth(val) - } - } - }, - setup(props, context): any { - const renderless = (props, { onMounted, onUpdated, onBeforeUnmount }, { vm }) => { - onMounted(() => vm.updateLabelWidth('update')) - onUpdated(() => vm.updateLabelWidth('update')) - onBeforeUnmount(() => vm.updateLabelWidth('remove')) - - return { - computedWidth: 0 - } - } - - const api = ['computedWidth'] - - return setup({ props, context, renderless, api }) - } -}) diff --git a/packages/mobile/components/form-item/src/mobile.vue b/packages/mobile/components/form-item/src/mobile.vue deleted file mode 100644 index 5619dbbf0b..0000000000 --- a/packages/mobile/components/form-item/src/mobile.vue +++ /dev/null @@ -1,229 +0,0 @@ - - diff --git a/packages/mobile/components/form-item/src/renderless/index.ts b/packages/mobile/components/form-item/src/renderless/index.ts deleted file mode 100644 index dc2f3f8972..0000000000 --- a/packages/mobile/components/form-item/src/renderless/index.ts +++ /dev/null @@ -1,539 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { POSITION, VALIDATE_STATE } from '@mobile-root/utils' -import { omitText } from '@mobile-root/utils/string' -import { merge } from '@mobile-root/utils/object' -import Validator from '@mobile-root/utils/validate' -import { isNull } from '@mobile-root/utils/type' -import debounce from '@mobile-root/utils/deps/debounce' -import type { - IFormItemRenderlessParams, - IFormItemDisplayedValueParam, - IFormItemRule, - IFormItemTrigger, - IFormItemValidateStatus, - IFormItemLabelStyle -} from '../form-item' -import type { StyleValue } from 'vue' - -export const watchError = - (state: IFormItemRenderlessParams['state']) => - (value: string): void => { - if (!isNull(value) && state.getValidateType === 'tip') { - state.canShowTip = true - } - - state.validateMessage = value - state.validateState = value ? VALIDATE_STATE.Error : '' - } - -export const watchValidateStatus = - (state: IFormItemRenderlessParams['state']) => - (value: IFormItemValidateStatus): void => { - state.validateState = value - } - -export const computedGetValidateType = - ({ props, state }: Pick) => - (): string => - props.validateType || (state.formInstance ? state.formInstance.validateType : '') - -export const computedValidateIcon = - ({ props, state }: Pick) => - (): object | null => - props.validateIcon ?? state?.formInstance?.state?.validateIcon ?? null - -export const computedIsErrorInline = - ({ props, state }: Pick) => - (): boolean => { - if (props.messageType) { - return props.messageType === 'inline' - } - if (typeof props.inlineMessage === 'boolean') { - return props.inlineMessage - } - return state?.formInstance?.state?.isErrorInline ?? false - } - -export const computedIsErrorBlock = - ({ props, state }: Pick) => - (): boolean => { - if (props.messageType) { - return props.messageType === 'block' - } - return state?.formInstance?.state?.isErrorBlock ?? false - } - -export const computedLabelStyle = - ({ props, state }: Pick) => - (): IFormItemLabelStyle => { - const result = { width: '' } - - if (state.formInstance?.labelPosition === POSITION.Top) { - return result - } - - const labelWidth = props.labelWidth || state.formInstance?.state?.labelWidth - - if (labelWidth) { - result.width = labelWidth - } - - return result - } - -export const computedValueStyle = - ({ props, state }: Pick) => - (): { width: string } => { - const result = { width: '' } - - if (state.formInstance?.labelPosition === POSITION.Top) { - result.width = '100%' - return result - } - - const labelWidth = props.labelWidth || state.formInstance?.state?.labelWidth - - if (labelWidth) { - if (labelWidth === 'auto') { - result.width = labelWidth - } else { - result.width = `calc(100% - ${labelWidth})` - } - } - - return result - } - -export const computedContentStyle = - ({ props, state }: Pick) => - (): StyleValue => { - const result: StyleValue = {} - const label = props.label - - if (state.formInstance.labelPosition === POSITION.Top || state.formInstance.inline) { - return result - } - - if (!label && !props.labelWidth && state.isNested) { - return result - } - - const labelWidth = props.labelWidth || state.formInstance.state.labelWidth - - if (labelWidth === 'auto') { - if (props.labelWidth === 'auto') { - result.marginLeft = state.computedLabelWidth - } else if (state.formInstance.state.labelWidth === 'auto') { - result.marginLeft = state.formInstance.state.autoLabelWidth - } - } else { - result.marginLeft = labelWidth - } - - return result - } - -export const computedIsRequired = - ({ api, state }: Pick) => - (): boolean => { - if (state.validationRequired) { - return true - } - - let rules = api.getRules() - let isRequired = false - - if (rules && rules.length) { - rules.every((rule) => { - if (rule.required) { - isRequired = true - return false - } - - return true - }) - } - - return isRequired - } -/** - * @description: 给定对象和路径,返回对象路径的值。 - * @param {object} obj - * @param {string} path - * @param {boolean} strict - * @return {*} - */ -export const getPropByPath = (obj: object, path: string, strict?: boolean) => { - let findObj = obj - - path = path.replace(/\[(\w+)\]/g, '.$1') - path = path.replace(/^\./, '') - - let index = 0 - let keys = path.split('.') - - for (let len = keys.length; index < len - 1; ++index) { - if (!findObj && !strict) { - break - } - - let key = keys[index] - - if (findObj && key in findObj) { - findObj = findObj[key] - } else { - if (strict) { - throw new Error('[Tiny Form] please transfer a valid prop path to form item!') - } - - break - } - } - - return { - o: findObj, - k: keys[index], - v: findObj ? findObj[keys[index]] : null - } -} - -export const computedFieldValue = - ({ props, state }: Pick) => - () => { - const model = state.formInstance?.model - - if (!model || !props.prop) { - return - } - - let path = props.prop - - if (path.includes(':')) { - path = path.replace(/:/, '.') - } - - return getPropByPath(model, path, true).v - } - -export const mounted = - ({ api, vm, props, state }: Pick) => - (): void => { - state.tooltip = vm.$refs.tooltip - - if (props.prop) { - api.dispatch('Form', 'form:addField', vm) - - let initialValue = state.fieldValue - - if (Array.isArray(initialValue)) { - initialValue = ([] as any).concat(initialValue) - } - - state.initialValue = initialValue - api.addValidateEvents() - } - } - -export const unmounted = - ({ api, vm, state }: Pick) => - (): void => { - state.canShowTip = false - api.dispatch('Form', 'form:removeField', vm) - } - -export const validate = - ({ api, props, state, t }: Pick) => - (trigger: IFormItemTrigger, callback: Function = () => undefined): void => { - state.validateDisabled = false - - const rules = api.getFilteredRule(trigger) - - if (((!rules || rules.length === 0) && props.required === undefined) || props.validateDisabled) { - callback() - return - } - - state.validateState = VALIDATE_STATE.Validating - - const descriptor = {} - if (rules && rules.length > 0) { - rules.forEach((rule) => { - delete rule.trigger - }) - } - - descriptor[props.prop || ''] = rules - - const validator = new Validator(descriptor, t) - const model = {} - - model[props.prop || ''] = state.fieldValue - - validator.validate(model, { firstFields: true }, (errors, invalidFields) => { - api.clearValidate() - - const handlerError = () => { - state.validateState = !errors ? VALIDATE_STATE.Success : VALIDATE_STATE.Error - - if (errors && props.error) { - errors[0].message = props.error - } - state.validateMessage = errors ? errors[0].message : '' - state.canShowTip = Boolean(errors) - - callback(state.validateMessage, invalidFields) - - state.formInstance && state.formInstance.$emit('validate', props.prop, !errors, state.validateMessage || null) - } - - handlerError() - }) - } - -export const clearValidate = (state: IFormItemRenderlessParams['state']) => (): void => { - state.validateState = '' - state.validateMessage = '' - state.validateDisabled = false -} - -export const resetField = - ({ api, nextTick, props, state }: Pick) => - (): void => { - if (state.getValidateType === 'tip') { - state.canShowTip = false - } - - state.validateState = '' - state.validateMessage = '' - - let model = state.formInstance.model || {} - let value = state.fieldValue - let path = props.prop || '' - - if (path && path.includes(':')) { - path = path.replace(/:/, '.') - } - - let prop = getPropByPath(model, path, true) - - state.validateDisabled = true - - if (Array.isArray(value)) { - prop.o[prop.k] = [].concat(state.initialValue) - } else { - prop.o[prop.k] = state.initialValue - } - // reset validateDisabled after onFieldChange triggered - nextTick(() => { - state.validateDisabled = false - }) - - setTimeout(() => state.validateState && (state.validateState = '')) - - api.broadcast('timeSelect', 'fieldReset', state.initialValue) - } - -/** - * @description 获取本表单项的校验规则 - * 来源有可能有3处:form中rules,form-item中的rules以及form-item配置了required属性 - */ -export const getRules = - ({ props, state }: Pick) => - (): IFormItemRule[] => { - let formRules = state.formInstance?.rules || {} - const selfRules = props.rules as IFormItemRule[] - const requiredRule = props.required !== undefined ? { required: Boolean(props.required) } : [] - const prop = getPropByPath(formRules, props.prop || '') - - formRules = formRules ? prop.o[props.prop || ''] || prop.v : [] - - return ([] as IFormItemRule[]).concat(selfRules || formRules || []).concat(requiredRule) - } - -/** - * @description 根据trigger来筛选符合条件和检验规则。此处的规则进行了一层浅拷贝处理。 - * 因为valide中使用会delete掉其中的trigger属性。 - * 不传或者传空字符串,则默认返回所有规则。 - * @param {trigger} target 触发检验规则 - * @returns {Array} 符合条件的检验规则 - */ -export const getFilteredRule = - (api: IFormItemRenderlessParams['api']) => - (trigger: IFormItemTrigger): IFormItemRule[] => { - const rules = api.getRules() - - return rules - .filter((rule) => { - if (!rule.trigger || trigger === '') { - return true - } - - if (Array.isArray(rule.trigger)) { - return rule.trigger.includes(trigger) - } - - return rule.trigger === trigger - }) - .map((rule) => merge({}, rule)) - } - -export const onFieldBlur = (api: IFormItemRenderlessParams['api']) => (): void => { - api.validate('blur') -} - -export const onFieldChange = - ({ api, state }: Pick) => - (): void => { - if (state.validateDisabled) { - state.validateDisabled = false - return - } - - api.validate('change') - } - -export const updateComputedLabelWidth = - (state: IFormItemRenderlessParams['state']) => - (width: number): void => { - state.computedLabelWidth = width ? `${width}px` : '' - } - -export const addValidateEvents = - ({ api, vm, props, state }: Pick) => - (): void => { - const rules = api.getRules() - - if (rules.length || props.required !== undefined) { - const manual = props.manual || (state.formInstance ? state.formInstance.manual : false) - - if (!manual) { - vm.$on('form.blur', api.onFieldBlur) - vm.$on('form.change', api.onFieldChange) - } - } - } - -export const removeValidateEvents = (vm: IFormItemRenderlessParams['vm']) => (): void => { - vm.$off() -} - -export const updateTip = - ({ vm, state }: Pick) => - (): void => { - if (state.getValidateType !== 'tip' && !state.canShowTip) { - return - } - - const tooltip = vm.$refs.tooltip - - if (!tooltip) { - return - } - - tooltip.updatePopper() - } - -export const getValueByPath = (object, prop) => { - prop = prop || '' - - const paths = prop.split('.') - let current = object - let result = null - - for (let i = 0, len = paths.length; i < len; i++) { - const path = paths[i] - - if (!current) { - break - } - - if (i === len - 1) { - result = current[path] - break - } - - current = current[path] - } - - return result -} - -export const wrapValidate = ({ - validateFunc, - props -}: Pick): Function => { - if (props.validateDebounce) { - return debounce(500, validateFunc) - } else { - return validateFunc - } -} - -/** - * 目前仅mobile-first模板使用到 - */ -export const handleMouseenter = - ({ state }: Pick) => - (e): void => { - if (!state.isDisplayOnly || !state.typeName || !state.formInstance) return - const dom = e.target - const text = dom.textContent - const font = window.getComputedStyle(dom).font - const rect = dom.getBoundingClientRect() - let res: { o?: boolean; t?: any } = {} - let overHeight = false - - if (['text', 'password', 'number'].includes(state.typeName)) { - res = omitText(text, font, rect.width) - } - - if (state.typeName === 'textarea' && dom && dom.scrollHeight > dom.offsetHeight) { - overHeight = true - } - - if (res.o || overHeight) { - state.formInstance.showTooltip(dom, state.displayedValue) - } - } - -export const handleLabelMouseenter = - ({ props, state, slots }) => - (e) => { - if (!state.formInstance?.overflowTitle || !state.formInstance || slots.label) return - const label = e.target - if (label && label.scrollWidth > label.offsetWidth) { - state.formInstance.showTooltip(label, props.label + state.formInstance.labelSuffix) - } - } - -export const handleMouseleave = (state: IFormItemRenderlessParams['state']) => (): void => { - state.formInstance && state.formInstance.hideTooltip() -} - -export const getDisplayedValue = - ({ state }: Pick) => - (param: IFormItemDisplayedValueParam): void => { - if (!state.formInstance.displayOnly) return - state.typeName = param.type - state.isBasicComp = true - state.displayedValue = param.val - } - -export const clearDisplayedValue = - ({ state }: Pick) => - (): void => { - state.typeName = '' - state.isBasicComp = false - state.displayedValue = '' - } diff --git a/packages/mobile/components/form-item/src/renderless/vue.ts b/packages/mobile/components/form-item/src/renderless/vue.ts deleted file mode 100644 index 612765378c..0000000000 --- a/packages/mobile/components/form-item/src/renderless/vue.ts +++ /dev/null @@ -1,192 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - validate, - clearValidate, - resetField, - getRules, - getFilteredRule, - onFieldBlur, - onFieldChange, - updateComputedLabelWidth, - addValidateEvents, - removeValidateEvents, - mounted, - unmounted, - watchError, - watchValidateStatus, - computedLabelStyle, - computedValueStyle, - computedContentStyle, - computedIsRequired, - computedFieldValue, - computedGetValidateType, - computedValidateIcon, - computedIsErrorInline, - computedIsErrorBlock, - updateTip, - wrapValidate, - getDisplayedValue, - clearDisplayedValue, - handleLabelMouseenter, - handleMouseenter, - handleMouseleave -} from './index' -import type { - IFormItemApi, - IFormItemProps, - IFormItemState, - IFormInstance, - IFormItemRenderlessParams, - IFormItemRenderlessParamUtils -} from '../form-item' - -export const api = [ - 'state', - 'validate', - 'clearValidate', - 'resetField', - 'getRules', - 'getFilteredRule', - 'onFieldBlur', - 'onFieldChange', - 'updateComputedLabelWidth', - 'addValidateEvents', - 'removeValidateEvents', - 'updateTip', - 'getDisplayedValue', - 'handleLabelMouseenter', - 'handleMouseenter', - 'handleMouseleave' -] - -const initState = ({ - reactive, - computed, - api, - mode, - inject, - props -}: Pick) => { - const state: IFormItemState = reactive({ - mode, - validateState: '', - validateMessage: '', - validateDisabled: false, - validator: {}, - isNested: false, - computedLabelWidth: '', - initialValue: null, - canShowTip: false, - // 兼容 2.0 validation 的 required - validationRequired: false, - validateType: 'text', - tooltip: '', - displayedValue: '', - isBasicComp: false, - showTooltip: false, - typeName: '', - formInstance: inject('form') as IFormInstance, - labelFor: computed(() => props.for || props.prop || ''), - labelStyle: computed(() => api.computedLabelStyle()), - valueStyle: computed(() => api.computedValueStyle()), - contentStyle: computed(() => api.computedContentStyle()), - fieldValue: computed(() => api.computedFieldValue()), - isRequired: computed(() => api.computedIsRequired()), - formInline: computed(() => state.formInstance.inline), - formSize: computed(() => state.formInstance.size), - formItemSize: computed(() => props.size || state.formSize), - isDisplayOnly: computed(() => state.formInstance.displayOnly), - labelPosition: computed(() => state.formInstance.labelPosition), - hideRequiredAsterisk: computed(() => state.formInstance?.state?.hideRequiredAsterisk), - labelSuffix: computed(() => state.formInstance.labelSuffix), - labelWidth: computed(() => state.formInstance.labelWidth), - showMessage: computed(() => state.formInstance.showMessage), - sizeClass: computed(() => state.formItemSize), - getValidateType: computed(() => api.computedGetValidateType()), - validateIcon: computed(() => api.computedValidateIcon()), - isErrorInline: computed(() => api.computedIsErrorInline()), - isErrorBlock: computed(() => api.computedIsErrorBlock()), - disabled: computed(() => state.formInstance.disabled), - tooltipType: computed(() => state.formInstance?.state?.tooltipType) - }) - - return state -} - -const initApi = ({ api, state, dispatch, broadcast, props, constants, vm, t, nextTick, slots }) => { - Object.assign(api, { - state, - dispatch, - broadcast, - watchError: watchError(state), - updateTip: updateTip({ vm, state }), - watchValidateStatus: watchValidateStatus(state), - computedLabelStyle: computedLabelStyle({ props, state }), - computedValueStyle: computedValueStyle({ props, state }), - computedContentStyle: computedContentStyle({ props, state }), - computedFieldValue: computedFieldValue({ props, state }), - computedGetValidateType: computedGetValidateType({ props, state }), - computedValidateIcon: computedValidateIcon({ props, state }), - computedIsErrorInline: computedIsErrorInline({ props, state }), - computedIsErrorBlock: computedIsErrorBlock({ props, state }), - clearValidate: clearValidate(state), - getRules: getRules({ props, state }), - updateComputedLabelWidth: updateComputedLabelWidth(state), - removeValidateEvents: removeValidateEvents(vm), - unmounted: unmounted({ api, vm, state }), - mounted: mounted({ api, vm, props, state }), - computedIsRequired: computedIsRequired({ api, state }), - resetField: resetField({ api, nextTick, props, state }), - getFilteredRule: getFilteredRule(api), - onFieldBlur: onFieldBlur(api), - onFieldChange: onFieldChange({ api, state }), - addValidateEvents: addValidateEvents({ api, vm, props, state }), - validate: wrapValidate({ validateFunc: validate({ api, props, state, t }), props }), - getDisplayedValue: getDisplayedValue({ state }), - clearDisplayedValue: clearDisplayedValue({ state }), - handleLabelMouseenter: handleLabelMouseenter({ props, state, slots }), - handleMouseenter: handleMouseenter({ state }), - handleMouseleave: handleMouseleave(state) - }) -} - -const initWatch = ({ watch, api, props, state }) => { - watch(() => props.error, api.watchError, { immediate: true }) - - watch(() => props.validateStatus, api.watchValidateStatus) - - watch(() => state.formInstance.displayOnly, api.clearDisplayedValue) -} - -export const renderless = ( - props: IFormItemProps, - { computed, inject, onMounted, onUnmounted, provide, reactive, watch }: IFormItemRenderlessParams, - { vm, constants, t, nextTick, broadcast, dispatch, mode, slots }: IFormItemRenderlessParamUtils -): IFormItemApi => { - const api = {} as IFormItemApi - const state = initState({ reactive, computed, api, mode, inject, props }) - - provide('formItem', vm) - - initApi({ api, state, dispatch, broadcast, props, constants, vm, t, nextTick, slots }) - initWatch({ watch, api, props, state }) - - onMounted(api.mounted) - vm.$on('displayed-value-changed', (param) => { - api.getDisplayedValue(param) - }) - onUnmounted(api.unmounted) - - return api -} diff --git a/packages/mobile/components/form/index.ts b/packages/mobile/components/form/index.ts deleted file mode 100644 index 004acc8d98..0000000000 --- a/packages/mobile/components/form/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Form from './src/mobile.vue' - -/* istanbul ignore next */ -Form.install = function (Vue) { - Vue.component(Form.name, Form) -} - -export default Form diff --git a/packages/mobile/components/form/src/form.ts b/packages/mobile/components/form/src/form.ts deleted file mode 100644 index d867064155..0000000000 --- a/packages/mobile/components/form/src/form.ts +++ /dev/null @@ -1,186 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { ExtractPropTypes, ComponentPublicInstance } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils, ITinyVm } from '@mobile-root/shared.type' -import type { IFormItemInstance, IFormItemRule } from '../../form-item/src/form-item' - -import type { - updateTip, - computedAutoLabelWidth, - computedHideRequiredAsterisk, - computedValidateIcon, - computedIsErrorInline, - computedIsErrorBlock, - created, - resetFields, - clearValidate, - validate, - validateField, - getLabelWidthIndex, - registerLabelWidth, - deregisterLabelWidth, - watchRules, - showTooltip, - hideTooltip -} from './renderless' - -export const formProps = { - model: Object, - rules: Object, - inlineMessage: { - type: Boolean, - default: undefined - }, - messageType: String, - statusIcon: Boolean, - showMessage: { - type: Boolean, - default: true - }, - validatePosition: { - type: String, - default: 'right' - }, - size: String, - disabled: Boolean, - validateOnRuleChange: { - type: Boolean, - default: true - }, - hideRequiredAsterisk: { - type: Boolean, - default: undefined - }, - labelPosition: { - type: String, - default: 'right', - validator: (value: string) => ['left', 'top', 'right'].includes(value) - }, - labelWidth: { - type: String, - // 默认值挪到design中 - default: '' - }, - labelAlign: { - type: Boolean, - default: false - }, - contentOffset: Number, - labelSuffix: { - type: String, - default: '' - }, - inline: { - type: Boolean, - default: false - }, - responsiveLayout: { - type: Boolean, - default: false - }, - validateType: { - type: String, - default: 'tip', - validator(value: string) { - return Boolean(~['tip', 'text'].indexOf(value)) - } - }, - validateIcon: Object, - manual: { - type: Boolean, - default: false - }, - appendToBody: { - type: Boolean, - default: undefined - }, - popperOptions: { - type: Object, - default: () => ({}) - }, - displayOnly: { - type: Boolean, - default: false - }, - showAutoWidth: { - type: Boolean, - default: false - }, - showEmptyValue: { - type: Boolean, - default: true - }, - validateTag: { - type: Boolean, - default: false - }, - overflowTitle: { - type: Boolean, - default: false - } -} - -export interface IFormRules { - [prop: string]: IFormItemRule -} -export interface IFormState { - showAutoWidth: boolean - fields: IFormItemInstance[] - timer: number - tooltipVisible: boolean - displayedValue: string - potentialLabelWidthArr: number[] - autoLabelWidth: string - isDisplayOnly: boolean - hasRequired: boolean - hideRequiredAsterisk: boolean - validateIcon: object | null - isErrorInline: boolean - isErrorBlock: boolean - labelWidth: string - tooltipType: string -} - -export type IFormProps = ExtractPropTypes - -export type IFormRenderlessParams = ISharedRenderlessFunctionParams & { - state: IFormState - props: IFormProps - api: IFormApi - dialog: ITinyVm | null -} - -export interface IFormApi { - state: IFormState - updateTip: ReturnType - computedAutoLabelWidth: ReturnType - computedHideRequiredAsterisk: ReturnType - computedValidateIcon: ReturnType - computedIsErrorInline: ReturnType - computedIsErrorBlock: ReturnType - created: ReturnType - resetFields: ReturnType - clearValidate: ReturnType - validate: ReturnType - validateField: ReturnType - getLabelWidthIndex: ReturnType - registerLabelWidth: ReturnType - deregisterLabelWidth: ReturnType - watchRules: ReturnType - showTooltip: ReturnType - hideTooltip: ReturnType -} - -export type IFormRenderlessParamUtils = ISharedRenderlessParamUtils - -export type IFormInstance = ComponentPublicInstance & IFormProps & IFormApi diff --git a/packages/mobile/components/form/src/mobile.vue b/packages/mobile/components/form/src/mobile.vue deleted file mode 100644 index 8fdc39dcf2..0000000000 --- a/packages/mobile/components/form/src/mobile.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - - diff --git a/packages/mobile/components/form/src/renderless/index.ts b/packages/mobile/components/form/src/renderless/index.ts deleted file mode 100644 index 72fbc63d57..0000000000 --- a/packages/mobile/components/form/src/renderless/index.ts +++ /dev/null @@ -1,279 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { merge } from '@mobile-root/utils/object' - -import type { IFormRenderlessParams } from '../form' - -export const watchRules = - ({ api, props, state }: Pick) => - (newRules = {}, oldRules = {}): void => { - const newValidFields = Object.keys(newRules) - const oldValidFields = Object.keys(oldRules) - const removeValidFields = oldValidFields.filter((item) => !newValidFields.includes(item)) - api.clearValidate(removeValidFields) - - state.fields.forEach((field) => { - field.removeValidateEvents() - field.addValidateEvents() - }) - - if (props.validateOnRuleChange) { - api.validate(() => undefined) - } - } - -export const computedAutoLabelWidth = - ({ state }: Pick) => - (): string => { - if (!state.potentialLabelWidthArr.length) { - return '0' - } - - const max = Math.max(...state.potentialLabelWidthArr) - - return max ? `${max}px` : '' - } - -export const computedHideRequiredAsterisk = - ({ props, designConfig }: Pick) => - (): boolean => { - return props.hideRequiredAsterisk ?? designConfig?.hideRequiredAsterisk ?? false - } - -export const computedValidateIcon = - ({ props, designConfig }: Pick) => - (): object | null => { - return props.validateIcon ?? designConfig?.icons?.validateIcon ?? null - } - -export const computedIsErrorInline = - ({ props, designConfig }: Pick) => - (): boolean => { - if (props.messageType) { - return props.messageType === 'inline' - } - if (typeof props.inlineMessage === 'boolean') { - return props.inlineMessage - } - return designConfig?.messageType === 'inline' || false - } - -export const computedIsErrorBlock = - ({ props, designConfig }: Pick) => - (): boolean => { - if (props.messageType) { - return props.messageType === 'block' - } - return designConfig?.messageType === 'block' || false - } - -export const created = - ({ vm, state }: Pick) => - (): void => { - vm.$on('form:addField', (field) => { - if (field) { - state.fields.push(field) - } - }) - /* istanbul ignore next */ - vm.$on('form:removeField', (field) => { - if (field.prop) { - state.fields.splice(state.fields.indexOf(field), 1) - } - }) - } - -export const resetFields = - ({ props, state }: Pick) => - (): void => { - if (!props.model) { - return - } - - state.fields.forEach((field) => { - field.resetField() - }) - } - -export const updateTip = - ({ props, state }: Pick) => - (): void => { - if (!props.model) { - return - } - - state.fields.forEach((field) => { - field.updateTip() - }) - } - -export const clearValidate = - (state: IFormRenderlessParams['state']) => - (props: string | string[] = []): void => { - let fields - // 如果没赋值,默认就是清除全部 - if (props.length) { - fields = - typeof props === 'string' - ? state.fields.filter((field) => props === field.prop) - : state.fields.filter((field) => field.prop && props.includes(field.prop)) - } else { - fields = state.fields - } - - fields.forEach((field) => { - field.clearValidate() - }) - } - -export const validate = - ({ props, state }: Pick) => - (callback?: (valid: boolean, invalidFields?: any) => void): Promise | void => { - if (!props.model) { - return - } - - let promise - - if (typeof callback !== 'function' && window.Promise) { - promise = new window.Promise((resolve, reject) => { - callback = (valid) => { - valid ? resolve(valid) : reject(valid) - } - }) - } - - let valid = true - let count = 0 - - // 如果需要验证的fields为空,调用验证时立刻返回callback - if (state.fields.length === 0 && callback) { - callback(true) - } - - let invalidFields = {} - - state.fields.forEach((field) => { - field.validate('', (message, field) => { - if (message) { - valid = false - } - - invalidFields = merge({}, invalidFields, field) - - if (typeof callback === 'function' && ++count === state.fields.length) { - callback(valid, invalidFields) - } - }) - }) - - if (promise) { - return promise - } - } - -export const validateField = - (state: IFormRenderlessParams['state']) => - (props, cb): void => { - props = [].concat(props) - - const fields = state.fields.filter((field) => props.includes(field.prop)) - - if (!fields.length) { - return - } - - fields.forEach((field) => { - field.validate('', cb) - }) - } - -export const getLabelWidthIndex = - (state: IFormRenderlessParams['state']) => - (width: number): number => { - const index = state.potentialLabelWidthArr.indexOf(width) - - if (index === -1) { - throw new Error('unpected width ', width as ErrorOptions) - } - - return index - } - -export const registerLabelWidth = - ({ api, state }: Pick) => - (val: number, oldVal: number): void => { - if (val && oldVal) { - const index = api.getLabelWidthIndex(oldVal) - state.potentialLabelWidthArr.splice(index, 1, val) - } else if (val) { - state.potentialLabelWidthArr.push(val) - } - } - -export const deregisterLabelWidth = - ({ api, state }: Pick) => - (val: number): void => { - const index = api.getLabelWidthIndex(val) - state.potentialLabelWidthArr.splice(index, 1) - } - -export const bindDialogEvent = ({ api, dialog, state }: Pick) => { - let unbindDialogEvent = () => { - // empty - } - - if (dialog) { - const boxCloseHandler = (isFormReset = true) => { - isFormReset ? api.resetFields() : api.clearValidate() - } - const boxDragHandler = () => { - if (!state.timer) { - state.timer = window.setTimeout(() => { - state.timer = 0 - api.updateTip() - }, 10) - } - } - - dialog.state.emitter.on('boxclose', boxCloseHandler) - dialog.state.emitter.on('boxdrag', boxDragHandler) - - unbindDialogEvent = () => { - dialog.state.emitter.off('boxclose', boxCloseHandler) - dialog.state.emitter.off('boxdrag', boxDragHandler) - } - } - - return unbindDialogEvent -} - -export const showTooltip = - ({ vm, state }: Pick) => - (dom: HTMLElement, val: string): void => { - const tooltip = vm.$refs.tooltip - tooltip.state.referenceElm = dom - tooltip.state.popperElm && (tooltip.state.popperElm.style.display = 'none') - tooltip.doDestroy() - - state.tooltipVisible = true - state.displayedValue = val - - setTimeout(tooltip.updatePopper, 20) - } - -export const hideTooltip = - ({ state }: Pick) => - (): void => { - state.tooltipVisible = false - } diff --git a/packages/mobile/components/form/src/renderless/vue.ts b/packages/mobile/components/form/src/renderless/vue.ts deleted file mode 100644 index 90fc575f61..0000000000 --- a/packages/mobile/components/form/src/renderless/vue.ts +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { IFormApi, IFormProps, IFormState, IFormRenderlessParams, IFormRenderlessParamUtils } from '../form' - -import { - watchRules, - computedAutoLabelWidth, - computedHideRequiredAsterisk, - computedValidateIcon, - computedIsErrorInline, - computedIsErrorBlock, - created, - resetFields, - clearValidate, - validate, - validateField, - getLabelWidthIndex, - registerLabelWidth, - deregisterLabelWidth, - updateTip, - bindDialogEvent, - showTooltip, - hideTooltip -} from './index' - -export const api = [ - 'state', - 'resetFields', - 'clearValidate', - 'validate', - 'validateField', - 'getLabelWidthIndex', - 'registerLabelWidth', - 'deregisterLabelWidth', - 'updateTip', - 'showTooltip', - 'hideTooltip' -] - -export const renderless = ( - props: IFormProps, - { computed, inject, provide, reactive, watch, onBeforeUnmount }: IFormRenderlessParams, - { vm, parent, designConfig }: IFormRenderlessParamUtils -): IFormApi => { - const api = {} as IFormApi - const dialog = inject('dialog', null) - - const state: IFormState = reactive({ - showAutoWidth: props.showAutoWidth, - fields: [], - timer: 0, - tooltipVisible: false, - displayedValue: '', - potentialLabelWidthArr: [], - autoLabelWidth: computed(() => api.computedAutoLabelWidth()), - hideRequiredAsterisk: computed(() => api.computedHideRequiredAsterisk()), - validateIcon: computed(() => api.computedValidateIcon()), - isErrorInline: computed(() => api.computedIsErrorInline()), - isErrorBlock: computed(() => api.computedIsErrorBlock()), - isDisplayOnly: computed(() => props.displayOnly), - hasRequired: computed(() => { - if (props.rules) { - return Object.values(props.rules).find((ruleOrRules) => { - if (Array.isArray(ruleOrRules)) { - return ruleOrRules.some((r) => r.required) - } else { - return ruleOrRules.required - } - }) - } else { - return false - } - }), - labelWidth: computed(() => props.labelWidth || designConfig?.state?.labelWidth || '80px'), - tooltipType: computed(() => designConfig?.state?.tooltipType || 'normal') - }) - - Object.assign(api, { - state, - updateTip: updateTip({ props, state }), - computedAutoLabelWidth: computedAutoLabelWidth({ state }), - computedHideRequiredAsterisk: computedHideRequiredAsterisk({ props, designConfig }), - computedValidateIcon: computedValidateIcon({ props, designConfig }), - computedIsErrorInline: computedIsErrorInline({ props, designConfig }), - computedIsErrorBlock: computedIsErrorBlock({ props, designConfig }), - created: created({ vm, state }), - resetFields: resetFields({ props, state }), - clearValidate: clearValidate(state), - validate: validate({ props, state }), - validateField: validateField(state), - getLabelWidthIndex: getLabelWidthIndex(state), - registerLabelWidth: registerLabelWidth({ api, state }), - deregisterLabelWidth: deregisterLabelWidth({ api, state }), - watchRules: watchRules({ api, props, state }), - showTooltip: showTooltip({ vm, state }), - hideTooltip: hideTooltip({ state }) - }) - - api.created() - - provide('form', vm) - - provide('showAutoWidth', state.showAutoWidth) - - const unbindDialogEvent = bindDialogEvent({ api, dialog, state }) - - onBeforeUnmount(unbindDialogEvent) - - watch(() => props.rules, api.watchRules) - - return api -} diff --git a/packages/mobile/components/image-viewer/index.ts b/packages/mobile/components/image-viewer/index.ts deleted file mode 100644 index b493ae79ae..0000000000 --- a/packages/mobile/components/image-viewer/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import ImageViewer from './src/mobile.vue' - -/* istanbul ignore next */ -ImageViewer.install = function (Vue) { - Vue.component(ImageViewer.name, ImageViewer) -} - -export default ImageViewer diff --git a/packages/mobile/components/image-viewer/src/image-viewer.ts b/packages/mobile/components/image-viewer/src/image-viewer.ts deleted file mode 100644 index cdb9cdfdc8..0000000000 --- a/packages/mobile/components/image-viewer/src/image-viewer.ts +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -const $constants = { - MODE: { - CONTAIN: { - name: 'contain', - icon: 'icon-fullscreen' - }, - ORIGINAL: { - name: 'original', - icon: 'icon-minscreen' - } - }, - DEFAULT_POPPER_ZINDEX: Number.POSITIVE_INFINITY, - THUMBNAILTOP: 8, - MENUTOP: 10 -} - -export const imageViewerProps = { - _constants: { - type: Object, - default: () => $constants - }, - urlList: { - type: Array, - default: () => [] - }, - zIndex: { - type: Number, - default: $constants.DEFAULT_POPPER_ZINDEX - }, - previewVisible: { - type: Boolean, - default: false - }, - closeShow: { - type: Boolean, - default: false - }, - arrowShow: { - type: Boolean, - default: false - }, - toolShow: { - type: Boolean, - default: false - }, - showIndex: { - type: Boolean, - default: false - }, - imageFullCurrent: { - type: Boolean, - default: false - }, - startPosition: { - type: Number, - default: 0 - }, - asyncClose: { - type: Boolean, - default: false - }, - deleteButton: { - type: Boolean, - default: false - }, - onSwitch: { - type: Function, - default: () => { - // do nothing - } - }, - onClose: { - type: Function, - default: () => { - // do nothing - } - }, - isThumbnail: { - type: Boolean, - default: false - }, - isMenuView: { - type: Boolean, - default: false - }, - modalView: { - type: Boolean, - default: false - }, - modalHeight: { - type: [String, Number], - default: 400 - }, - bgColor: { - type: String, - default: 'bg-color-icon-primary' - } -} diff --git a/packages/mobile/components/image-viewer/src/mobile.vue b/packages/mobile/components/image-viewer/src/mobile.vue deleted file mode 100644 index 0d22a3206f..0000000000 --- a/packages/mobile/components/image-viewer/src/mobile.vue +++ /dev/null @@ -1,147 +0,0 @@ - - - - diff --git a/packages/mobile/components/image-viewer/src/mobileTouch.ts b/packages/mobile/components/image-viewer/src/mobileTouch.ts deleted file mode 100644 index f2faaaa573..0000000000 --- a/packages/mobile/components/image-viewer/src/mobileTouch.ts +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import { directive } from '@mobile-root/common' -import { isObject } from '@mobile-root/utils/type' - -class TinyTouch { - constructor(element, tinyBinding, type) { - const that = this - that.element = element - that.tinyBinding = tinyBinding - that.touchType = type - that.tinyVueTouches = { x: 0, y: 0 } - that.tinyVueMoves = true - that.tinyVueLeave = true - that.tinyLongTouch = true - that.tinyVueCallBack = isObject(tinyBinding.value) ? tinyBinding.value.fn : tinyBinding.value - that.element.addEventListener('touchstart', (e) => { - that.start(e) - }) - that.element.addEventListener('touchend', (e) => { - that.end(e) - }) - that.element.addEventListener('touchmove', (e) => { - that.move(e) - }) - } - - start(e) { - if (e.touches >= 2) { - return - } - - this.tinyVueMoves = true - this.tinyVueLeave = true - this.tinyLongTouch = true - this.tinyVueTouches = { - x: e.changedTouches[0].pageX, - y: e.changedTouches[0].pageY - } - - this.time = setTimeout(() => { - if (this.tinyVueLeave && this.tinyVueMoves) { - this.touchType === 'longtap' && this.tinyVueCallBack(this.tinyBinding.value, e) - this.tinyLongTouch = false - } - }, 1000) - } - - end(e) { - if (e.touches >= 2) { - return - } - - let disX = e.changedTouches[0].pageX - this.tinyVueTouches.x - let disY = e.changedTouches[0].pageY - this.tinyVueTouches.y - - clearTimeout(this.time) - - if (Math.abs(disX) > 10 || Math.abs(disY) > 100) { - this.touchType === 'swipe' && this.tinyVueCallBack(this.tinyBinding.value, e) - - if (Math.abs(disX) > Math.abs(disY)) { - if (disX > 10) { - this.touchType === 'swiperight' && this.tinyVueCallBack(this.tinyBinding.value, e) - } - - if (disX < -10) { - this.touchType === 'swipeleft' && this.tinyVueCallBack(this.tinyBinding.value, e) - } - } else { - if (disY > 10) { - this.touchType === 'swipedown' && this.tinyVueCallBack(this.tinyBinding.value, e) - } - - if (disY < -10) { - this.touchType === 'swipeup' && this.tinyVueCallBack(this.tinyBinding.value, e) - } - } - } else { - if (this.tinyLongTouch && this.tinyVueMoves) { - this.touchType === 'tap' && this.tinyVueCallBack(this.tinyBinding.value, e) - this.tinyVueLeave = false - } - } - } - - move() { - this.tinyVueMoves = false - } -} - -const mapDirective = () => { - const deactives = {} - const names = ['tap', 'swipe', 'swipeleft', 'swiperight', 'swipedown', 'swipeup', 'longtap'] - - names.forEach((name) => { - deactives[name] = directive({ - vTouch: { - bind(el, tinyBinding) { - // eslint-disable-next-line no-new - new TinyTouch(el, tinyBinding, name) - } - } - }).vTouch - }) - - return deactives -} - -export default mapDirective() diff --git a/packages/mobile/components/image-viewer/src/renderless/index.ts b/packages/mobile/components/image-viewer/src/renderless/index.ts deleted file mode 100644 index 594e70c270..0000000000 --- a/packages/mobile/components/image-viewer/src/renderless/index.ts +++ /dev/null @@ -1,874 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { on, off } from '@mobile-root/utils/deps/dom' -import { KEY_CODE } from '@mobile-root/utils' -import PopupManager from '@mobile-root/utils/deps/popup-manager' -import { xss } from '@mobile-root/utils/xss' - -const isFirefox = () => !!window.navigator.userAgent.match(/firefox/i) - -const mousewheelEventName = isFirefox() ? 'DOMMouseScroll' : 'mousewheel' - -export const rafThrottle = (fn) => { - let locked = false - - return function (...args) { - if (locked) { - return - } - - locked = true - - window.requestAnimationFrame(() => { - fn.apply(this, args) - locked = false - }) - } -} - -export const hide = - ({ props, api, state }) => - () => { - api.deviceSupportUninstall() - props.onClose() - state.showImageViewer = false - } - -export const deviceSupportInstall = - ({ state, api, mode }) => - () => { - on(window, 'resize', api.initPage) - - state.urlList = state.urlList.map((subItem) => { - let subItemObj = {} - let lastSlashIndex = '' - - if (typeof subItem === 'string') { - subItem = api.filterImageUrl(subItem) - - if (state.isThumbnail || state.isMenuView) { - lastSlashIndex = subItem.lastIndexOf('/') - state.fileName = subItem.substring(lastSlashIndex + 1) - subItemObj.url = subItem - subItemObj.name = state.fileName - - return subItemObj - } else { - lastSlashIndex = subItem.lastIndexOf('/') - state.fileName = subItem.substring(lastSlashIndex + 1) - - return { url: subItem, name: state.fileName } - } - } else if (typeof subItem === 'object' && subItem !== null) { - subItem.url = api.filterImageUrl(subItem.url) - - if (!subItem.name) { - lastSlashIndex = subItem.url.lastIndexOf('/') - state.fileName = subItem.url.substring(lastSlashIndex + 1) - subItem.name = state.fileName - } - return subItem - } else { - return null - } - }) - - state._keyDownHandler = rafThrottle((event) => { - const keyCode = event.keyCode - - switch (keyCode) { - case KEY_CODE.Escape: - api.hide() - break - case KEY_CODE.Space: - api.toggleMode() - break - case KEY_CODE.ArrowLeft: - api.prev() - break - case KEY_CODE.ArrowUp: - api.handleActions('zoomIn') - break - case KEY_CODE.ArrowRight: - api.next() - break - case KEY_CODE.ArrowDown: - api.handleActions('zoomOut') - break - default: - break - } - }) - - state._mouseWheelHandler = rafThrottle((event) => { - const delta = event.wheelDelta ? event.wheelDelta : -event.detail - - if (delta > 0) { - api.handleActions('zoomIn', { - zoomRate: 0.015, - enableTransition: false - }) - } else { - api.handleActions('zoomOut', { - zoomRate: 0.015, - enableTransition: false - }) - } - }) - - on(document, 'keydown', state._keyDownHandler) - mode !== 'mobile-first' && on(document, mousewheelEventName, state._mouseWheelHandler) - } - -export const deviceSupportUninstall = - ({ state, mode }) => - () => { - off(document, 'keydown', state._keyDownHandler) - mode !== 'mobile-first' && off(document, mousewheelEventName, state._mouseWheelHandler) - - state._keyDownHandler = null - state._mouseWheelHandler = null - } - -export const handleImgLoad = (state) => () => (state.loading = false) - -export const handleImgError = - ({ state, t }) => - (event) => { - state.loading = false - event.target.alt = t('ui.imageViewer.loadErrorAlt') - } - -export const handleMouseDown = (state) => (event) => { - if (state.loading || event.button !== 0) { - return - } - - const { offsetX, offsetY } = state.transform - const startX = event.pageX - const startY = event.pageY - - state._dragHandler = rafThrottle((event) => { - state.transform.offsetX = offsetX + event.pageX - startX - state.transform.offsetY = offsetY + event.pageY - startY - }) - - on(document, 'mousemove', state._dragHandler) - - state._removeDrag = () => off(document, 'mousemove', state._dragHandler) - - if (state._clearMouse) { - state._clearMouse() - state._clearMouse = undefined - } - - on(document, 'mouseup', state._removeDrag) - on(document, 'mouseleave', state._removeDrag) - - state._clearMouse = () => { - off(document, 'mouseup', state._removeDrag) - off(document, 'mouseleave', state._removeDrag) - } - - event.preventDefault() -} - -export const reset = (state) => () => - (state.transform = { - scale: 1, - deg: 0, - offsetX: 0, - offsetY: 0, - enableTransition: false - }) - -export const toggleMode = - ({ state, constants, api }) => - () => { - if (state.loading) { - return - } - - const MODE = constants.MODE - const modeNames = Object.keys(MODE) - const modeValues = [] - - modeNames.forEach((key) => { - modeValues.push(MODE[key]) - }) - - let index = -1 - - modeValues.forEach((item, inx) => { - if (item.name === state.mode.name) { - index = inx - } - }) - - const nextIndex = (index + 1) % modeNames.length - - state.mode = MODE[modeNames[nextIndex]] - - api.reset() - } - -export const prev = - ({ state, api, vm }) => - () => { - if (state.isFirst && !state.infinite) { - return - } - - const len = state.urlList.length - let prevElement = '' - - state.index = (state.index - 1 + len) % len - - api.activeItems(state.index) - if (state.isThumbnail) { - prevElement = vm.$refs[`isThumbnail_${state.index}`][0] || vm.$refs[`isThumbnail_${state.index}`] - } else if (state.isMenuView) { - prevElement = vm.$refs[`isMenuView_${state.index}`][0] || vm.$refs[`isMenuView_${state.index}`] - } - - if (state.index === 1) { - state.isThumbnail && vm.$refs.isThumbnailContent && (vm.$refs.isThumbnailContent.scrollTop = 0) - state.isMenuView && vm.$refs.isMenuViewContent && (vm.$refs.isMenuViewContent.scrollTop = 0) - state.scrollTop = 0 - } else if (state.index === state.urlList.length - 1) { - api.getLastPrev(prevElement) - } else if (state.index === state.urlList.length - 2) { - // empty - // 判断逻辑需要return,提交代码eslint阻止提交,因此使用注释留空。 - } else if (state.index === state.urlList.length - 3) { - state.scrollTop = prevElement.offsetHeight - } else { - api.getDefaultPrev(prevElement) - } - } - -export const getLastPrev = - ({ state, vm }) => - (prevElement) => { - state.isThumbnail && vm.$refs.isThumbnailContent && (vm.$refs.isThumbnailContent.scrollTop = prevElement.offsetTop) - state.isMenuView && vm.$refs.isMenuViewContent && (vm.$refs.isMenuViewContent.scrollTop = prevElement.offsetTop) - state.scrollTop = prevElement.offsetTop - } - -export const getDefaultPrev = - ({ state, vm }) => - (prevElement) => { - if (state.scrollTop <= prevElement.offsetHeight) { - state.scrollTop = - prevElement.offsetTop - state.scrollTop - (state.isThumbnail ? state.thumbnailTop : state.menuTop) - } else { - state.scrollTop = - state.scrollTop - prevElement.offsetHeight - (state.isThumbnail ? state.thumbnailTop : state.menuTop) - } - state.isThumbnail && vm.$refs.isThumbnailContent && (vm.$refs.isThumbnailContent.scrollTop = state.scrollTop) - state.isMenuView && vm.$refs.isMenuViewContent.scrollTop && (vm.$refs.isMenuViewContent.scrollTop = state.scrollTop) - } - -export const next = - ({ state, api, vm }) => - () => { - if (state.isLast && !state.infinite) { - return - } - - const len = state.urlList.length - let element = '' - - state.index = (state.index + 1) % len - - api.activeItems(state.index) - if (state.isThumbnail) { - element = vm.$refs[`isThumbnail_${state.index}`][0] || vm.$refs[`isThumbnail_${state.index}`] - } else if (state.isMenuView) { - element = vm.$refs[`isMenuView_${state.index}`][0] || vm.$refs[`isMenuView_${state.index}`] - } - - state.centerIndex = api.getCenterPosition(element) - 1 - let slientIndex = -1 - - if (state.centerIndex > state.index) { - slientIndex = state.index - } - - if (state.index === 0) { - state.isThumbnail && vm.$refs.isThumbnailContent && (vm.$refs.isThumbnailContent.scrollTop = 0) - state.isMenuView && vm.$refs.isMenuViewContent && (vm.$refs.isMenuViewContent.scrollTop = 0) - state.scrollTop = 0 - } else if (state.index === slientIndex) { - // empty - // 判断逻辑需要return,提交代码eslint阻止提交,因此使用注释留空。 - } else { - if (state.isThumbnail) { - vm.$refs.isThumbnailContent && (vm.$refs.isThumbnailContent.scrollTop = state.scrollTop) - state.scrollTop = state.scrollTop + element.offsetHeight + state.thumbnailTop - } else if (state.isMenuView) { - vm.$refs.isMenuViewContent && (vm.$refs.isMenuViewContent.scrollTop = state.scrollTop) - state.scrollTop = state.scrollTop + element.offsetHeight + state.menuTop - } - } - } - -export const getCenterPosition = - ({ state, vm }) => - (element) => { - let contentHeight = 0 - let eleHeight = 0 - - if (state.isThumbnail && vm.$refs.isThumbnailContent) { - contentHeight = vm.$refs.isThumbnailContent.getBoundingClientRect().height - eleHeight = element.getBoundingClientRect().height + parseFloat(getComputedStyle(element).marginBottom) - 0 - - return Math.ceil(contentHeight / eleHeight) / 2 - } else if (vm.$refs.isMenuViewContent && vm.$refs.isMenuViewContent) { - contentHeight = vm.$refs.isMenuViewContent.getBoundingClientRect().height - eleHeight = element.getBoundingClientRect().height + parseFloat(getComputedStyle(element).marginTop) - 0 - - return Math.ceil(contentHeight / eleHeight) / 2 - } - } -export const handleActions = - (state, props, emit) => - (action, options = {}) => { - const { zoomRate, rotateDeg, enableTransition } = { - zoomRate: 0.2, - rotateDeg: 90, - enableTransition: true, - ...options - } - const { transform } = state - let lastSlashIndex = '' - let imageUrl = [] - - lastSlashIndex = state.currentImg.lastIndexOf('/') - let cutName = state.currentImg.substring(lastSlashIndex + 1) - - if (action === 'delImage') { - if (typeof state.urlList[0] === 'string') { - imageUrl = state.urlList - } else if (typeof state.urlList[0] === 'object' && state.urlList[0] !== null) { - cutName = state.urlList[state.index].name - - state.urlList.forEach((item) => { - imageUrl.push(item.url) - }) - } - - if (imageUrl.includes(state.currentImg)) { - if (state.index === state.urlList.length - 1) { - state.urlList.splice(state.index, 1) - state.index = state.urlList.length - 1 - } else { - state.urlList.splice(state.index, 1) - } - } - - state.imageName = cutName - - emit('delete', state.imageName) - } - - if (state.loading) { - return - } - - if (action === 'zoomOut') { - if (transform.scale > 0.2) { - transform.scale = parseFloat((transform.scale - zoomRate).toFixed(3)) - } - } else if (action === 'zoomIn') { - transform.scale = parseFloat((transform.scale + zoomRate).toFixed(3)) - } else if (action === 'clocelise') { - transform.deg += rotateDeg - } else if (action === 'anticlocelise') { - transform.deg -= rotateDeg - } - - transform.enableTransition = enableTransition - } - -export const computedIsSingle = (props) => () => props.urlList.length <= 1 - -export const computedIsFirst = (state) => () => state.index === 0 - -export const computedIsLast = - ({ state, props }) => - () => - state.index === props.urlList.length - 1 - -export const computedCurrentImg = - ({ state, api }) => - () => { - if (typeof state.urlList[0] === 'string') { - return api.filterImageUrl(state.urlList[state.index]) - } else if (typeof state.urlList[0] === 'object' && state.urlList[0] !== null) { - return api.filterImageUrl(state.urlList[state.index].url) - } - } - -export const computedImgStyle = - ({ state, constants }) => - () => { - const { offsetX, offsetY, scale, deg, enableTransition } = state.transform - const transition = enableTransition ? 'transform .3s' : '' - - const style = { - transform: `scale(${scale}) rotate(${deg}deg)`, - transition, - 'margin-top': `${offsetY}px`, - 'margin-left': `${offsetX}px` - } - - if (JSON.stringify(state.mode) === JSON.stringify(constants.MODE.CONTAIN)) { - style.maxWidth = style.maxHeight = '100%' - } - - return style - } - -export const watchVisible = (state) => (value) => (state.previewVisible = value) - -export const handleVisible = - ({ state, emit, props }) => - () => { - state.transform.scale = 1 - state.transform.deg = 0 - - setTimeout(() => { - if (props.startPosition > 0) { - state.index = (props.startPosition - 1 + state.urlList.length) % state.urlList.length - state.imageTransform = state.index * state.imageItemWidth - state.imageTransformSize = -state.index * state.imageItemWidth - } else { - state.index = 0 - state.imageTransform = state.index * state.imageItemWidth - state.imageTransformSize = -state.index * state.imageItemWidth - } - }, 300) - - emit('update:preview-visible', false) - emit('close', state.index, state.urlList[state.index]) - } - -export const getImageWidth = - ({ state, parent, props, vm, mode }) => - () => { - let imageW = 0 - const len = state.urlList.length - - if (mode === 'mobile-first') { - if (state.isThumbnail && state.isImagePreview) { - imageW = vm.$refs.thumbnailCanvasBox.offsetWidth - } else { - imageW = vm.$refs.canvasBox && vm.$refs.canvasBox.offsetWidth - } - - state.imageList = vm.$refs.viewerItem - } else if (mode === 'mobile') { - imageW = parent.$el.querySelector('.tiny-mobile-image-viewer__canvas').offsetWidth - - state.imageList = parent.$el.querySelectorAll('.tiny-mobile-image-viewer__item') - } else { - imageW = parent.$el.querySelector('.tiny-image-viewer__canvas').offsetWidth - - state.imageList = parent.$el.querySelectorAll('.tiny-image-viewer__img') - } - - state.imageItemWidth = imageW - state.imageAllWidth = state.urlList.length * imageW - - if (mode === 'mobile') { - if (props.startPosition > 0) { - state.index = props.startPosition - state.imageTransition = 0 - - const transformX = state.index * state.imageItemWidth - - state.imageTransform = transformX - state.imageTransformSize = -transformX - } - - if (state.index === 0 && props.deleteButton && state.delete) { - state.imageTransition = 0 - - const transformX = state.index * state.imageItemWidth - - state.imageTransform = transformX - state.imageTransformSize = -transformX - } - } - - setTimeout(() => { - state.imageTransition = 300 - }, 0) - - if (props.startPosition === 0) { - state.arrowStyle = 'N' - } - - if (props.startPosition === len - 1) { - state.arrowStyle = 'Y' - } - } - -export const swipeLeft = - ({ state, emit }) => - () => { - if (state.isLast && !state.infinite) { - return - } - - const len = state.urlList.length - - if (state.index >= state.urlList.length - 2) { - state.arrowStyle = 'Y' - } else { - state.arrowStyle = null - } - - if (state.imageTransform === state.imageAllWidth) { - state.imageTransformSize = state.imageTransform = 0 - state.imageList[0].style.transform = null - - return - } - - if ( - state.imageTransform === state.imageAllWidth - state.imageItemWidth && - state.index === state.urlList.length - 1 - ) { - return - } - - state.index = (state.index + 1) % len - - const transformX = state.index * state.imageItemWidth - - state.imageTransform = transformX - state.imageTransformSize = -transformX - - emit('change', state.index, state.urlList[state.index]) - } - -export const swipeRight = - ({ state, emit }) => - () => { - if (state.isFirst && !state.infinite) { - return - } - - const len = state.urlList.length - - if (state.index <= 1) { - state.arrowStyle = 'N' - } else { - state.arrowStyle = null - } - - if (state.imageTransform === 0 && state.index === 0) { - return - } - - state.index = (state.index - 1 + len) % len - - const transformX = state.index * state.imageItemWidth - - state.imageTransform = transformX - state.imageTransformSize = -transformX - - emit('change', state.index, state.urlList[state.index]) - } - -export const handleDelete = - ({ api, emit, state }) => - () => { - if (state.urlList.length <= 1) { - state.delete = false - return - } - - state.delete = true - - const currenIndex = state.index - const urlList = state.urlList - - urlList.splice(currenIndex, 1) - state.urlList = urlList - state.index = 0 - - api.getImageWidth() - - emit('newImageList', state.urlList, currenIndex) - } - -export const langClick = (state) => () => { - if (window.navigator.msSaveOrOpenBlob) { - let bstr = atob(state.currentImg.split(',')[1]) - let n = bstr.length - let u8arr = new Uint8Array(n) - while (n--) { - u8arr[n] = bstr.charCodeAt(n) - } - let blob = new Blob([u8arr]) - window.navigator.msSaveOrOpenBlob(blob, 'img' + '.' + 'png') - } else { - const a = document.createElement('a') - a.style = 'dispaly:none' - a.href = state.currentImg + '?response-content-type=application/octet-stream' - a.setAttribute('download', 'img') - a.setAttribute('target', 'downloadFile') - document.body.appendChild(a) - a.click() - document.body.removeChild(a) - } -} - -export const touchstart = - ({ state, mode, api }) => - (e) => { - state.firstX = e.targetTouches[0].clientX - - if (mode === 'mobile-first') { - state.time = setTimeout(() => { - if (!state.isImagePreview) { - api.langClick() - } else { - state.boxVisibility = true - } - }, 1000) - } - - const touches = e.touches - const events = touches[0] - const events2 = touches[1] - - preventDefault(e) - - state.pageX = events.pageX - state.pageY = events.pageY - state.moveable = true - - if (events2) { - state.pageX2 = events2.pageX - state.pageY2 = events2.pageY - } - - state.originScale = state.scale || 1 - } - -const preventDefault = (event, isStopPropagation) => { - if (typeof event.cancelable !== 'boolean' || event.cancelable) { - event.preventDefault() - } - - if (isStopPropagation) { - event.stopPropagation() - } -} - -export const touchmove = (state) => (event) => { - if (!state.moveable) { - return - } - - preventDefault(event) - - const touches = event.touches - const events = touches[0] - const events2 = touches[1] - - if (events2) { - if (!state.pageX2) { - state.pageX2 = events2.pageX - } - - if (!state.pageY2) { - state.pageY2 = events2.pageY - } - - const getDistance = (start, stop) => Math.hypot(stop.x - start.x, stop.y - start.y) - - const zoom = - getDistance( - { - x: events.pageX, - y: events.pageY - }, - { - x: events2.pageX, - y: events2.pageY - } - ) / - getDistance( - { - x: state.pageX, - y: state.pageY - }, - { - x: state.pageX2, - y: state.pageY2 - } - ) - - let newScale = state.originScale * zoom - - if (newScale > 3) { - newScale = 3 - } - - state.scale = newScale - state.transform.scale = newScale - } - - clearTimeout(state.time) -} - -export const touchend = (state) => (e) => { - let moveX = 0 - state.endX = e.changedTouches[0].clientX - moveX = state.endX - state.firstX - - if (!state.boxVisibility) { - if (moveX === 0) { - state.isImagePreview = false - state.hiddenThumbnail = false - } - } - - state.moveable = false - state.pageX2 = 0 - state.pageY2 = 0 - - clearTimeout(state.time) -} - -export const computeZIndex = - ({ constants, props }) => - () => - props.zIndex === constants.DEFAULT_POPPER_ZINDEX || props.zIndex < 1 ? PopupManager.nextZIndex() : props.zIndex - -export const activeItems = (state) => (i) => { - state.index = i - state.currentIndex = i -} - -export const imagePreview = (state) => (i) => { - state.index = i - - state.mobileCurrentIndex && (state.isImagePreview = true) -} - -export const initPage = - ({ state, nextTick, api }) => - () => { - state.isImagePreview = false - state.hiddenThumbnail = false - nextTick(() => { - api.getImageWidth() - }) - } - -export const beforeDestroy = - ({ api, state }) => - () => { - off(window, 'resize', api.initPage) - - if (state._clearMouse) { - state._clearMouse() - state._clearMouse = undefined - } - - if (state._dragHandler) { - state._dragHandler = undefined - } - - if (state._removeDrag) { - state._removeDrag = undefined - } - } - -export const itemClick = - ({ state, vm, nextTick }) => - (itemData) => { - if (state.isThumbnail) { - state.showFlag = 1 - } else if (state.isMenuView) { - state.showFlag = 2 - } - - switch (itemData) { - case '1': - state.isThumbnail = false - state.isMenuView = false - break - case '2': - state.isThumbnail = true - state.isMenuView = false - nextTick(() => { - state.currentIndex = 0 - state.index = 0 - vm.$refs.isThumbnailContent.scrollTop = 0 - }) - - break - case '3': - state.isThumbnail = false - state.isMenuView = true - nextTick(() => { - state.currentIndex = 0 - state.index = 0 - vm.$refs.isMenuViewContent.scrollTop = 0 - }) - - break - case '4': - if (state.showFlag === 1) { - state.isThumbnail = true - } else if (state.showFlag === 2) { - state.isMenuView = true - } - break - default: - break - } - } - -export const selectOption = - ({ state, api }) => - (item, index) => { - switch (index) { - case 0: - api.langClick() - break - case 1: - state.isThumbnail = true - state.isImagePreview = false - break - case 2: - api.handleActions('delImage') - api.getImageWidth() - break - default: - break - } - } - -export const filterImageUrl = () => (imageUrl) => { - const isBase64 = /^data:image\/(png|jpg|jpeg|gif);base64,([a-zA-Z0-9+/]+={0,2})/ - - return isBase64.test(imageUrl) ? imageUrl : xss.filterUrl(imageUrl) -} diff --git a/packages/mobile/components/image-viewer/src/renderless/vue.ts b/packages/mobile/components/image-viewer/src/renderless/vue.ts deleted file mode 100644 index 60c9e22067..0000000000 --- a/packages/mobile/components/image-viewer/src/renderless/vue.ts +++ /dev/null @@ -1,268 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - computedIsSingle, - watchVisible, - computedIsFirst, - computedIsLast, - computedCurrentImg, - computedImgStyle, - hide, - deviceSupportInstall, - deviceSupportUninstall, - handleImgLoad, - handleImgError, - handleMouseDown, - reset, - toggleMode, - prev, - next, - handleActions, - handleVisible, - getImageWidth, - swipeLeft, - swipeRight, - handleDelete, - touchstart, - touchmove, - touchend, - computeZIndex, - activeItems, - imagePreview, - initPage, - beforeDestroy, - itemClick, - selectOption, - langClick, - getLastPrev, - getDefaultPrev, - getCenterPosition, - filterImageUrl -} from './index' - -export const api = [ - 'state', - 'zIndex', - 'touchstart', - 'touchmove', - 'touchend', - 'urlList', - 'hide', - 'prev', - 'next', - 'handleActions', - 'toggleMode', - 'handleImgLoad', - 'handleImgError', - 'handleMouseDown', - 'handleVisible', - 'swipeLeft', - 'swipeRight', - 'handleDelete', - 'activeItems', - 'imagePreview', - 'itemClick', - 'selectOption', - 'langClick' -] - -const initState = ({ reactive, computed, api, mode, props, constants, inject }) => { - const state = reactive({ - originScale: '', - moveable: false, - pageX: '', - pageY: '', - pageY2: '', - pageX2: '', - mfPreviewVisible: inject('mfPreviewVisible', null), - scale: 1, - time: null, - index: mode === 'pc' || mode === 'mobile-first' ? 0 : props.startPosition, - imageName: '', - isShow: false, - infinite: true, - loading: false, - transform: { scale: 1, deg: 0, offsetX: 0, offsetY: 0, objfit: 'contain', enableTransition: false }, - urlList: props.urlList || inject('urlList', null), - mode: constants.MODE.CONTAIN, - previewVisible: props.previewVisible, - fullScreen: props.imageFullCurrent, - hammer: null, - imageItemWidth: 0, - imageAllWidth: 0, - imageTransform: 0, - imageTransformSize: 0, - imageTransition: 300, - imageList: null, - arrowStyle: null, - delete: false, - isLast: computed(() => api.computedIsLast()), - isFirst: computed(() => api.computedIsFirst()), - isSingle: computed(() => api.computedIsSingle()), - imgStyle: computed(() => api.computedImgStyle()), - currentImg: computed(() => api.computedCurrentImg()), - zIndex: computed(() => api.computeZIndex()), - currentIndex: 0, - mobileCurrentIndex: -1, - isImagePreview: false, - hiddenThumbnail: false, - firstX: 0, - endX: 0, - showImageViewer: true, - isThumbnail: props.isThumbnail, - isMenuView: props.isMenuView, - showFlag: 0, - boxVisibility: false, - fileName: '', - scrollTop: 0, - thumbnailTop: constants.THUMBNAILTOP, - menuTop: constants.MENUTOP, - centerIndex: -1 - }) - - return state -} - -const initApi = ({ api, state, props, parent, nextTick, emit, t, constants, vm, mode }) => { - Object.assign(api, { - state, - touchstart: touchstart({ state, mode, api }), - touchmove: touchmove(state), - touchend: touchend(state), - reset: reset(state), - prev: prev({ state, api, vm }), - next: next({ state, api, vm }), - getImageWidth: getImageWidth({ state, parent, props, nextTick, vm, mode }), - handleVisible: handleVisible({ state, emit, props }), - handleActions: handleActions(state, props, emit), - handleImgLoad: handleImgLoad(state), - handleMouseDown: handleMouseDown(state), - computedIsFirst: computedIsFirst(state), - computedIsSingle: computedIsSingle(props), - handleImgError: handleImgError({ state, t }), - computedIsLast: computedIsLast({ state, props }), - watchVisible: watchVisible(state), - deviceSupportUninstall: deviceSupportUninstall({ state, mode }), - computedCurrentImg: computedCurrentImg({ state, api }), - computedImgStyle: computedImgStyle({ state, constants }), - computeZIndex: computeZIndex({ constants, props }), - hide: hide({ props, api, state }), - deviceSupportInstall: deviceSupportInstall({ state, api, mode }), - toggleMode: toggleMode({ state, constants, api }), - swipeRight: swipeRight({ api, state, emit }), - swipeLeft: swipeLeft({ api, state, emit }), - handleDelete: handleDelete({ api, state, emit }), - activeItems: activeItems(state), - imagePreview: imagePreview(state), - initPage: initPage({ state, nextTick, api }), - beforeDestroy: beforeDestroy({ api, state }), - itemClick: itemClick({ state, vm, nextTick }), - selectOption: selectOption({ state, api }), - langClick: langClick(state), - getLastPrev: getLastPrev({ state, vm }), - getDefaultPrev: getDefaultPrev({ state, vm }), - getCenterPosition: getCenterPosition({ state, vm }), - filterImageUrl: filterImageUrl() - }) -} - -const initWatch = ({ watch, state, api, props, nextTick, vm }) => { - watch( - () => state.index, - (value) => { - api.reset() - props.onSwitch(value) - }, - { immediate: true } - ) - - watch( - () => props.previewVisible, - - (value) => { - api.watchVisible(value) - - if (props.previewVisible || state.mfPreviewVisible) { - nextTick(() => { - api.getImageWidth() - }) - } - }, - { immediate: true } - ) - - watch( - () => state.currentImg, - (value) => { - nextTick(() => { - const index = state.urlList.indexOf(value) - - let imageIns = vm.$refs[`img_${index}`] - if (Array.isArray(imageIns)) { - imageIns = imageIns[0] - } - - if (imageIns) { - state.loading = !imageIns.complete - } - }) - }, - { immediate: true } - ) - - watch( - () => state.isImagePreview, - () => - nextTick(() => { - api.getImageWidth() - }) - ) - - watch( - () => props.urlList, - () => { - state.urlList = props.urlList - }, - { deep: true } - ) -} - -export const renderless = ( - props, - { computed, onMounted, onBeforeUnmount, onUpdated, reactive, watch, inject, provide }, - { t, parent, nextTick, emit, constants, vm, mode } -) => { - const api = {} - const state = initState({ reactive, computed, api, mode, props, constants, inject }) - - initApi({ api, state, props, parent, nextTick, emit, t, constants, vm, mode }) - - initWatch({ watch, state, api, props, nextTick, vm }) - - onMounted(api.deviceSupportInstall) - - onUpdated(() => { - if (props.asyncClose) { - setTimeout(() => { - state.previewVisible = false - emit('update:preview-visible', false) - }, 3000) - } - }) - - onBeforeUnmount(api.beforeDestroy) - - provide('change-size', true) - - return api -} diff --git a/packages/mobile/components/index-bar-anchor/index.ts b/packages/mobile/components/index-bar-anchor/index.ts deleted file mode 100644 index 3238b3fac2..0000000000 --- a/packages/mobile/components/index-bar-anchor/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import IndexBarAnchor from './src/index.vue' - -/* istanbul ignore next */ -IndexBarAnchor.install = function (Vue) { - Vue.component(IndexBarAnchor.name, IndexBarAnchor) -} - -export default IndexBarAnchor diff --git a/packages/mobile/components/index-bar-anchor/src/index.vue b/packages/mobile/components/index-bar-anchor/src/index.vue deleted file mode 100644 index 203530ff67..0000000000 --- a/packages/mobile/components/index-bar-anchor/src/index.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - - diff --git a/packages/mobile/components/index-bar-anchor/src/renderless/vue.ts b/packages/mobile/components/index-bar-anchor/src/renderless/vue.ts deleted file mode 100644 index 535c7781e6..0000000000 --- a/packages/mobile/components/index-bar-anchor/src/renderless/vue.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -export const api = ['state'] - -export const renderless = (props, { computed, reactive, onMounted, onUpdated, watch }, { emit, parent, refs }) => { - const state = reactive({}) - - const api = { - state - } - - Object.assign(api, { - state - }) - - return api -} diff --git a/packages/mobile/components/index-bar/index.ts b/packages/mobile/components/index-bar/index.ts deleted file mode 100644 index db3d9aa9ad..0000000000 --- a/packages/mobile/components/index-bar/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import IndexBar from './src/mobile.vue' - -/* istanbul ignore next */ -IndexBar.install = function (Vue) { - Vue.component(IndexBar.name, IndexBar) -} - -export default IndexBar diff --git a/packages/mobile/components/index-bar/src/mobile.vue b/packages/mobile/components/index-bar/src/mobile.vue deleted file mode 100644 index b80a436c68..0000000000 --- a/packages/mobile/components/index-bar/src/mobile.vue +++ /dev/null @@ -1,54 +0,0 @@ - - - - diff --git a/packages/mobile/components/index-bar/src/renderless/index.ts b/packages/mobile/components/index-bar/src/renderless/index.ts deleted file mode 100644 index 966b7c2c87..0000000000 --- a/packages/mobile/components/index-bar/src/renderless/index.ts +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -export const switchIndex = (index, state, emit) => { - if (index === state.index) { - return - } - emit('select', index) - state.index = index - if (index < state.childrenAnchor.length) { - const item = state.childrenAnchor[index] - document.documentElement.scrollTop = item.offsetTop - } -} - -export const handleTouchDown = - ({ state }) => - () => { - state.isMouseDown = true - } - -export const handleTouchMove = - ({ emit, state }) => - (e) => { - if (state.isMouseDown && e.target.id) { - switchIndex(Number(e.target.id), state, emit) - } - } - -export const handleTouchUp = - ({ state }) => - () => { - state.isMouseDown = false - } - -export const handleIndexClick = - ({ emit, state }) => - (value) => { - switchIndex(value.index, state, emit) - } - -export const updateAnchorChildren = - ({ state, refs }) => - () => { - const node = refs.indexBarContent - if (node) { - state.childrenAnchor = [] - getAnchorChildren(node, state) - } - } - -export const getAnchorChildren = (node, state) => { - node.childNodes.forEach((ele) => { - if (ele.className === 'tiny-mobile-index-bar-anchor') { - state.childrenAnchor.push(ele) - } else { - getAnchorChildren(ele, state) - } - }) -} - -export const handleScroll = - ({ state }) => - () => { - findTopAnchor(state) - } - -export const findTopAnchor = (state) => { - const scrollTop = document.documentElement.scrollTop - for (let index = 0; index < state.childrenAnchor.length; index++) { - const item = state.childrenAnchor[index] - if (item.offsetTop + item.offsetHeight > scrollTop) { - state.index = index - break - } - } -} diff --git a/packages/mobile/components/index-bar/src/renderless/vue.ts b/packages/mobile/components/index-bar/src/renderless/vue.ts deleted file mode 100644 index 8d4d2fb2f9..0000000000 --- a/packages/mobile/components/index-bar/src/renderless/vue.ts +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - handleScroll, - updateAnchorChildren, - handleTouchDown, - handleTouchMove, - handleTouchUp, - handleIndexClick -} from './index' - -export const api = [ - 'state', - 'handleIndexClick', - 'handleScroll', - 'updateAnchorChildren', - 'handleTouchDown', - 'handleTouchMove', - 'handleTouchUp', - 'handleIndexClick' -] - -export const renderless = ( - props, - { computed, reactive, onMounted, onUnmounted, onUpdated, watch }, - { emit, parent, refs } -) => { - const state = reactive({ - index: 0, - childrenAnchor: [], - isFistUpdate: true - }) - - const api = { - state, - isMouseDown: false, - handleScroll: handleScroll({ state }), - updateAnchorChildren: updateAnchorChildren({ emit, parent, refs, state }), - handleTouchDown: handleTouchDown({ state }), - handleTouchMove: handleTouchMove({ emit, state }), - handleTouchUp: handleTouchUp({ state }), - handleIndexClick: handleIndexClick({ emit, parent, refs, state }) - } - - Object.assign(api, { - state - }) - - onMounted((e) => { - window.addEventListener('scroll', api.handleScroll) - }) - - onUnmounted(() => { - window.removeEventListener('scroll', api.handleScroll) - }) - - watch( - () => state.index, - (value, oldValue) => { - const isChange = value !== oldValue && value >= 0 && value < parent.indexList.length - if (isChange) { - emit('change', value) - } - }, - { immediate: false } - ) - - watch( - () => props.indexList, - () => { - api.updateAnchorChildren({ refs, state }) - }, - { immediate: false, deep: true } - ) - - onUpdated(() => { - if (state.isFistUpdate) { - state.isFistUpdate = false - api.updateAnchorChildren({ refs, state }) - } - }) - - return api -} diff --git a/packages/mobile/components/input/index.ts b/packages/mobile/components/input/index.ts deleted file mode 100644 index 067e5af628..0000000000 --- a/packages/mobile/components/input/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Input from './src/mobile.vue' - -/* istanbul ignore next */ -Input.install = function (Vue) { - Vue.component(Input.name, Input) -} - -export default Input diff --git a/packages/mobile/components/input/src/input.ts b/packages/mobile/components/input/src/input.ts deleted file mode 100644 index fdaf88fa9e..0000000000 --- a/packages/mobile/components/input/src/input.ts +++ /dev/null @@ -1,241 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { PropType } from '@mobile-root/common' -import type { ExtractPropTypes, ComputedRef } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' - -import type { - calculateNodeStyling, - calcTextareaHeight, - getInput, - handleInput, - calcIconOffset, - focus, - watchFormSelect, - setNativeInputValue, - resizeTextarea, - updateIconOffset, - hiddenPassword, - inputStyle -} from './renderless' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const $constants = { - INPUT_PC: 'tiny-input__', - INPUTGROUP_PC: 'tiny-input-group__', - INPUT_MOBILE: 'tiny-mobile-input__', - INPUTGROUP_MOBILE: 'tiny-mobile-input-group__', - Mode: 'pc', - inputMode(mode) { - return mode === this.Mode ? this.INPUT_PC : this.INPUT_MOBILE - }, - inputGroupMode(mode) { - return mode === this.Mode ? this.INPUTGROUP_PC : this.INPUTGROUP_MOBILE - }, - VALIDATE_ICON: { - Validating: 'tiny-icon-loading', - Success: 'tiny-icon-circle-check', - Error: 'tiny-icon-circle-close' - }, - COMPONENT_NAME: { - FormItem: 'FormItem' - }, - MASKSYMBOL: '******' -} - -export const inputProps = { - _constants: { - type: Object, - default: () => $constants - }, - name: String, - size: String, - form: String, - label: String, - height: Number, - resize: String, - tabindex: { type: String, default: '1' }, - disabled: Boolean, - readonly: Boolean, - hoverExpand: Boolean, - mask: Boolean, - suffixIcon: [Object, String], - prefixIcon: [Object, String], - modelValue: [String, Number] as PropType, - type: { - type: String, - default: 'text' - }, - memorySpace: { - type: Number, - default: 5 - }, - vertical: { - type: Boolean, - default: false - }, - selectMenu: { - type: Array<{ id: string; label: string }>, - default: () => [] - }, - ellipsis: { - type: Boolean, - default: false - }, - contentStyle: { - type: Object, - default: () => ({}) - }, - isSelect: { - type: Boolean, - default: false - }, - tips: String, - counter: { - type: Boolean, - default: false - }, - autosize: { - type: [Boolean, Object], - default: false - }, - clearable: { - type: Boolean, - default: false - }, - autocomplete: { - type: String, - default: 'off' - }, - showPassword: { - type: Boolean, - default: false - }, - showWordLimit: { - type: Boolean, - default: false - }, - title: { - type: String, - default: '' - }, - showTitle: { - type: Boolean, - default: false - }, - validateEvent: { - type: Boolean, - default: true - }, - // mobile特有属性 - textareaTitle: { - type: String, - default: '' - }, - displayOnly: { - type: Boolean, - default: false - }, - displayOnlyContent: { - type: String, - default: '' - }, - customClass: { - type: String, - default: '' - }, - frontClearIcon: { - type: Boolean, - default: false - }, - showEmptyValue: { - type: Boolean, - default: false - }, - textAlign: { - type: String, - default: 'left' - }, - width: { - type: [String, Number] as PropType - } -} - -export interface IInputState { - mode: string - focused: boolean - hovering: boolean - isComposing: boolean - passwordVisible: boolean - boxVisibility: boolean - textareaCalcStyle: object - checkedLabel: string - width: string - sheetvalue: string | number | undefined - inputSize: ComputedRef - showClear: ComputedRef - upperLimit: ComputedRef - textLength: ComputedRef - inputExceed: ComputedRef - formItemSize: ComputedRef - validateIcon: ComputedRef - showWordLimit: ComputedRef - inputDisabled: ComputedRef - validateState: ComputedRef - textareaStyle: ComputedRef - needStatusIcon: ComputedRef - showPwdVisible: ComputedRef - nativeInputValue: ComputedRef - isWordLimitVisible: ComputedRef - isDisplayOnly: ComputedRef - displayOnlyTooltip: string - hiddenPassword: ComputedRef -} - -export type IInputRenderlessParamUtils = ISharedRenderlessParamUtils - -export type IInputProps = ExtractPropTypes - -export type IInputConstants = typeof $constants - -export interface IInputApi extends Pick { - state: IInputState - setNativeInputValue: ReturnType - resizeTextarea: ReturnType - updateIconOffset: ReturnType - hiddenPassword: ReturnType - watchFormSelect: ReturnType - getInput: ReturnType - calcTextareaHeight: ReturnType - calculateNodeStyling: ReturnType - handleInput: ReturnType - calcIconOffset: ReturnType - focus: ReturnType - inputStyle: ReturnType -} - -export type IInputRenderlessParams = ISharedRenderlessFunctionParams & { - state: IInputState - props: IInputProps - api: IInputApi -} - -export interface IInputClassPrefixConstants { - Input: string - InputGroup: string -} - -export interface IInputEventNameConstants { - change: string - blur: string -} diff --git a/packages/mobile/components/input/src/mobile.vue b/packages/mobile/components/input/src/mobile.vue deleted file mode 100644 index 8fa183b675..0000000000 --- a/packages/mobile/components/input/src/mobile.vue +++ /dev/null @@ -1,208 +0,0 @@ - - - - diff --git a/packages/mobile/components/input/src/renderless/index.ts b/packages/mobile/components/input/src/renderless/index.ts deleted file mode 100644 index 565a223973..0000000000 --- a/packages/mobile/components/input/src/renderless/index.ts +++ /dev/null @@ -1,528 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { omitText } from '@mobile-root/utils/string' -import type { - IInputApi, - IInputClassPrefixConstants, - IInputRenderlessParamUtils, - IInputRenderlessParams, - IInputState -} from '../input' - -const HIDDEN_STYLE = ` -height:0 !important;visibility:hidden !important;overflow:hidden !important; -position:absolute !important;z-index:-1000 !important;top:0 !important;right:0 !important -` - -const CONTEXT_STYLE = [ - 'width', - 'line-height', - 'padding-top', - 'padding-bottom', - 'padding-left', - 'padding-right', - 'border-width', - 'box-sizing', - 'letter-spacing', - 'font-family', - 'font-weight', - 'font-size', - 'text-rendering', - 'text-transform', - 'text-indent' -] - -const STYLE = { - BoxSizing: 'box-sizing', - BorderBox: 'border-box', - ContentBox: 'content-box', - PaddingTop: 'padding-top', - PaddingBottom: 'padding-bottom', - BorderTopWidth: 'border-top-width', - BorderBottomWidth: 'border-bottom-width' -} - -const isServer = typeof window === 'undefined' -const isKorean = (text: string): boolean => /([(\uAC00-\uD7AF)|(\u3130-\u318F)])+/gi.test(text) - -export const showBox = (state: IInputState) => (): void => { - if (state.inputDisabled) { - return false - } - - state.boxVisibility = true -} - -export const inputStyle = - ({ props }) => - () => { - return { - textAlign: props.textAlign - } - } - -export const calculateNodeStyling = - () => - ( - targetElement: HTMLElement - ): { - contextStyle: string - paddingSize: number - borderSize: number - boxSizing: string - } => { - const style = window.getComputedStyle(targetElement) - const boxSizing = style.getPropertyValue(STYLE.BoxSizing) - - const paddingSize = - parseFloat(style.getPropertyValue(STYLE.PaddingBottom)) + parseFloat(style.getPropertyValue(STYLE.PaddingTop)) - - const borderSize = - parseFloat(style.getPropertyValue(STYLE.BorderBottomWidth)) + - parseFloat(style.getPropertyValue(STYLE.BorderTopWidth)) - - const contextStyle = CONTEXT_STYLE.map((name) => `${name}:${style.getPropertyValue(name)}`).join(';') - - return { contextStyle, paddingSize, borderSize, boxSizing } - } - -export const calcTextareaHeight = - ({ - api, - hiddenTextarea, - props, - state - }: Pick & { hiddenTextarea: HTMLTextAreaElement | null }) => - ( - targetElement: HTMLTextAreaElement, - minRows = 1, - maxRows = null - ): { - minHeight?: string - height?: string - } => { - if (!targetElement) { - return { - minHeight: '', - height: '' - } - } - - if (!hiddenTextarea) { - hiddenTextarea = document.createElement('textarea') - document.body.appendChild(hiddenTextarea) - } - - const { paddingSize, borderSize, boxSizing, contextStyle } = api.calculateNodeStyling(targetElement) - - hiddenTextarea.setAttribute('style', `${contextStyle};${HIDDEN_STYLE}`) - hiddenTextarea.value = targetElement.value || targetElement.placeholder || '' - - let height = hiddenTextarea.scrollHeight - const textareaStyle: { - minHeight?: string - height?: string - } = {} - - if (boxSizing === STYLE.ContentBox) { - height = height - paddingSize - } - - hiddenTextarea.value = '' - - const singleRowHeight = hiddenTextarea.scrollHeight - paddingSize - - if (minRows !== null) { - let minHeight = singleRowHeight * minRows - - if (boxSizing === STYLE.BorderBox) { - minHeight = minHeight + paddingSize + borderSize - } - - if (props.size) { - minHeight = props.size === 'mini' ? minHeight * 0.67 : props.size === 'small' ? minHeight : minHeight * 1.17 - } - - if (props.height) { - minHeight = props.height - } - - if (!state.isDisplayOnly) { - height = Math.max(minHeight, height) - textareaStyle.minHeight = `${minHeight}px` - } else { - textareaStyle.minHeight = `0px` - } - } - - if (maxRows !== null) { - let maxHeight = singleRowHeight * maxRows - - if (boxSizing === STYLE.BorderBox) { - maxHeight += borderSize + paddingSize - } - - height = Math.min(maxHeight, height) - } - - textareaStyle.height = `${height}px` - - hiddenTextarea.parentNode && hiddenTextarea.parentNode.removeChild(hiddenTextarea) - - hiddenTextarea = null - - return textareaStyle - } - -export const getInput = (vm: IInputRenderlessParamUtils['vm']) => (): HTMLTextAreaElement | HTMLInputElement => - vm.$refs.input || vm.$refs.textarea - -export const blur = (api: IInputApi) => (): void => api.getInput().blur() - -export const focus = (api: IInputApi) => (): void => api.getInput().focus() - -export const select = (api: IInputApi) => (): void => api.getInput().select() - -export const handleBlur = - ({ - api, - componentName, - eventName, - emit, - props, - state, - vm - }: Pick & { - componentName: string - eventName: string - }) => - (event: FocusEvent): void => { - state.focused = false - - emit('blur', event) - - api.isMemoryStorage.value = false - - if (props.validateEvent) { - api.dispatch(componentName, eventName, [props.modelValue]) - } - - if (props.hoverExpand) { - vm.$refs.textarea.scrollTop = 0 - } - } - -export const handleFocus = - ({ api, emit, state }: Pick) => - (event: FocusEvent): void => { - state.focused = true - - emit('focus', event) - - api.searchMemory((event.target as HTMLInputElement | HTMLTextAreaElement).value) - } - -export const handleInput = - ({ api, emit, nextTick, state }: Pick) => - (event: Event): void => { - if (state.isComposing) { - return - } - - if ((event.target as HTMLInputElement | HTMLTextAreaElement).value === state.nativeInputValue) { - return - } - - emit('update:modelValue', (event.target as HTMLInputElement | HTMLTextAreaElement).value) - - emit('input', event) - - api.searchMemory((event.target as HTMLInputElement | HTMLTextAreaElement).value) - - nextTick(api.setNativeInputValue) - } - -export const handleChange = - (emit: IInputRenderlessParams['emit']) => - (event: Event): void => - emit('change', (event.target as HTMLInputElement | HTMLTextAreaElement).value) - -export const resizeTextarea = - ({ api, parent, vm, state, props }: Pick) => - (): void => { - if (isServer) { - return - } - - const { autosize, type } = parent - - if (type !== 'textarea') { - return - } - - if (props.hoverExpand && !state.enteredTextarea) { - state.textareaCalcStyle = { - minHeight: state.textareaHeight, - height: state.textareaHeight - } - - return - } - - if (!autosize) { - state.textareaCalcStyle = { - minHeight: api.calcTextareaHeight(vm.$refs.textarea).minHeight - } - - return - } - - const minRows = autosize.minRows - const maxRows = autosize.maxRows - - state.textareaCalcStyle = api.calcTextareaHeight(vm.$refs.textarea, minRows, maxRows) - } - -export const setNativeInputValue = - ({ api, state }: Pick) => - (): void => { - const input = api.getInput() - - if (!input) { - return - } - - if (input.value === state.nativeInputValue) { - return - } - - input.value = state.nativeInputValue - } - -export const handleCompositionStart = (state: IInputState) => (): void => (state.isComposing = true) - -export const handleCompositionUpdate = - (state: IInputState) => - (event: CompositionEvent): void => { - const text = (event.target as HTMLInputElement | HTMLTextAreaElement).value - const lastCharacter = text[text.length - 1] || '' - - state.isComposing = !isKorean(lastCharacter) - } - -export const handleCompositionEnd = - ({ api, state }: Pick) => - (event: CompositionEvent): void => { - if (state.isComposing) { - state.isComposing = false - api.handleInput(event) - } - } - -export const calcIconOffset = - ({ CLASS_PREFIX, parent }: Pick & { CLASS_PREFIX: IInputClassPrefixConstants }) => - (place: 'prefix' | 'suffix'): void => { - const elList = [].slice.call( - parent.$el.querySelectorAll(`.${CLASS_PREFIX.Input}${place}`) || [] - ) as unknown as HTMLElement[] - - if (!elList.length) { - return - } - - let el: HTMLElement | null = null - - for (let i = 0, len = elList.length; i < len; i++) { - if (elList[i].parentNode === parent.$el) { - el = elList[i] - break - } - } - - if (!el) { - return - } - - const pendantMap = { suffix: 'append', prefix: 'prepend' } - const pendant = pendantMap[place] - - if (parent.$slots[pendant]) { - const dom = parent.$el.querySelector(`.${CLASS_PREFIX.InputGroup}${pendant}`) - let transform - - if (place === 'suffix') { - transform = `translateX(-${dom.offsetWidth}px)` - } else if (place === 'prefix') { - transform = `translate(${dom.offsetWidth}px, -50%)` - } - - el.style.transform = transform - } else { - el.removeAttribute('style') - } - } - -export const updateIconOffset = (api: IInputApi) => (): void => { - api.calcIconOffset('prefix') - api.calcIconOffset('suffix') -} - -export const clear = (emit: IInputRenderlessParams['emit']) => (): void => { - emit('update:modelValue', '') - emit('change', '') - emit('clear') -} - -export const handlePasswordVisible = - ({ api, nextTick, state }: Pick) => - (): void => { - state.passwordVisible = !state.passwordVisible - nextTick(api.focus) - } - -export const getSuffixVisible = - ({ vm, props, state }: Pick) => - (): boolean => - vm.$slots.suffix || - props.suffixIcon || - state.showClear || - props.showPassword || - state.isWordLimitVisible || - (state.validateState && state.needStatusIcon) || - (props.mask && state.inputDisabled) - -export const textLength = (value: number | string | undefined): number => { - if (typeof value === 'number') { - return String(value).length - } - - return (value || '').length -} - -export const watchFormSelect = - ({ emit, props, state }: Pick) => - (value: string | number | undefined): void => { - if (props.isSelect) { - emit('update:modelValue', value) - emit('change', value) - - const filterData = props.selectMenu.length && props.selectMenu.filter((item) => item.id === value).shift() - - state.checkedLabel = filterData ? filterData.label : '' - } - } - -export const hasSelection = (api: IInputApi) => (): boolean => { - const input = api.getInput() - return input && input.selectionStart !== input.selectionEnd -} - -export const handleEnterDisplayOnlyContent = - ({ state, props }: Pick) => - ($event: MouseEvent, type?: 'textarea'): void => { - const target = $event.target as HTMLElement - state.displayOnlyTooltip = '' - - if (!target) { - return - } - - const isOverText = - target.scrollWidth > target.offsetWidth || (type === 'textarea' && target.scrollHeight > target.offsetHeight) - - if (isOverText) { - state.displayOnlyTooltip = props.displayOnlyContent || state.nativeInputValue - } else { - let isOverTextWhenMask = false - - if (props.mask && state.maskValueVisible) { - const text = target.textContent - const font = window.getComputedStyle(target).font - const rect = target.getBoundingClientRect() - const iconWidth = 16 + 15 // 减去图标的宽度加上右边距 - isOverTextWhenMask = omitText(text, font, rect.width - iconWidth).o - } - - if (isOverTextWhenMask) { - state.displayOnlyTooltip = props.displayOnlyContent || state.nativeInputValue - } - } - } - -export const hiddenPassword = - ({ state, props }: Pick) => - (): string => { - let str = '' - const password = props.displayOnlyContent || state.nativeInputValue - - for (let i = 0; i < password.length; i++) { - str += '*' - } - return str - } - -export const getDisplayedMaskValue = - ({ state }: Pick) => - () => { - if (state.maskValueVisible) { - return state.nativeInputValue - } else { - return state.nativeInputValue && state.maskSymbol - } - } - -export const setInputDomValue = - ({ state, props, nextTick, vm }: Pick) => - (type) => { - nextTick(() => { - const input = vm.$refs.input - if (props.mask && state.nativeInputValue && input) { - input.value = state.maskValueVisible || !state.inputDisabled ? state.nativeInputValue : state.maskSymbol - } - - if (type === 'mask' && !props.mask && input) { - input.value = state.nativeInputValue - } - }) - } - -export const handleEnterTextarea = - ({ api, state, props, nextTick }) => - () => { - if (props.hoverExpand && !state.isDisplayOnly) { - state.enteredTextarea = true - nextTick(api.resizeTextarea) - } - } - -export const handleLeaveTextarea = - ({ api, state, props, nextTick, vm }) => - () => { - if (props.hoverExpand && !state.isDisplayOnly) { - state.enteredTextarea = false - nextTick(() => { - api.resizeTextarea() - vm.$refs.textarea.scrollTop = 0 - }) - } - } - -export const getDisplayOnlyText = - ({ parent, state, props }) => - () => { - const text = props.displayOnlyContent || state.nativeInputValue - const showEmptyValue = - typeof props.showEmptyValue === 'boolean' ? props.showEmptyValue : (parent.tinyForm || {}).showEmptyValue - - return showEmptyValue ? text : text || '-' - } diff --git a/packages/mobile/components/input/src/renderless/tall-storage/index.ts b/packages/mobile/components/input/src/renderless/tall-storage/index.ts deleted file mode 100644 index 11bbb3f448..0000000000 --- a/packages/mobile/components/input/src/renderless/tall-storage/index.ts +++ /dev/null @@ -1,179 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { KEY_CODE } from '@mobile-root/utils' - -export const mousedown = (event) => { - if (event && event.preventDefault) { - event.preventDefault() - } else { - window.event.returnValue = false - } - - return false -} - -export const selectItem = - ({ emit, state }) => - (value) => { - state.hoverValue = '' - emit('selected', value) - } - -export const keydown = - ({ emit, props, state }) => - () => { - const key = window.event.keyCode - const index = props.localstorageData.indexOf(state.hoverValue) - const endIndex = props.localstorageData.length - 1 - - if (key === KEY_CODE.ArrowUp && props.isMemoryStorage) { - if (index > 0 && index <= endIndex) { - state.hoverValue = props.localstorageData[index - 1] - } else { - state.hoverValue = props.localstorageData[endIndex] - } - - return false - } - - if (key === KEY_CODE.ArrowDown && props.isMemoryStorage) { - if (index >= 0 && index < endIndex) { - state.hoverValue = props.localstorageData[index + 1] - } else { - state.hoverValue = props.localstorageData[0] - } - - return false - } - - if (key === KEY_CODE.NumpadEnter) { - if (props.isMemoryStorage && state.hoverValue && state.hoverValue.length > 0) { - emit('selected', state.hoverValue) - } - } - } - -const sortDeduplication = (array, memorySpace = 5) => { - const length = array.length - let newArray = [] - let fillterObj = {} - - for (let i = 0, j = 1; j <= memorySpace; j++) { - if (i < 0 || i >= length) { - break - } - - if (fillterObj[array[i]]) { - j = j - 1 - } else { - fillterObj[array[i]] = true - newArray.push(array[i]) - } - - if (j === length) { - break - } - - i++ - } - - return newArray -} - -const isJSONobject = (string, type) => { - if (typeof string === 'string') { - try { - const obj = JSON.parse(string) - if (typeof obj === 'object' && obj && (type ? obj.constructor === type : true)) { - return true - } else { - return false - } - } catch (error) { - return false - } - } -} - -const setLocalStorageage = (name, value, memorySpace = 5) => { - if (typeof value === 'string') { - const oldValue = localStorage.getItem(name) - const isArray = isJSONobject(oldValue, Array) - let newValue = '' - - if (oldValue && isArray) { - let oldArray = JSON.parse(localStorage.getItem(name)) - - oldArray.unshift(value) - oldArray = sortDeduplication(oldArray, memorySpace) - newValue = JSON.stringify(oldArray) - } else if (oldValue === null || oldValue === value) { - newValue = value - } else { - newValue = JSON.stringify([value, oldValue]) - } - - localStorage.setItem(name, newValue) - } -} - -export const addMemory = (props) => (value) => { - if (props.name && value) { - setLocalStorageage(props.name, value, props.memorySpace) - } -} - -export const searchMemory = - ({ props, state }) => - (inputVal) => { - if (!props.name) { - return - } - const memoryBox = localStorage.getItem(props.name) - let storageData = [] - let isMemoryStorage = true - - if (isJSONobject(memoryBox)) { - const memoryArry = JSON.parse(memoryBox) - - if (!inputVal) { - storageData = JSON.parse(memoryBox) - } else { - for (let i = 0, len = memoryArry.length; i < len; i++) { - memoryArry[i].includes(inputVal) && storageData.push(memoryArry[i]) - } - } - - if (storageData.length === 0) { - isMemoryStorage = false - } - } else { - if (memoryBox === null) { - isMemoryStorage = false - } else { - storageData.push(memoryBox) - } - } - - state.storageData = storageData - state.isMemoryStorage = isMemoryStorage - } - -export const selectedMemory = - ({ api, state }) => - (value) => { - api.getInput().value = value - api.handleInput({ target: { value } }) - api.handleChange({ target: { value } }) - state.isMemoryStorage = false - } diff --git a/packages/mobile/components/input/src/renderless/tall-storage/vue-storage-box.ts b/packages/mobile/components/input/src/renderless/tall-storage/vue-storage-box.ts deleted file mode 100644 index 5e6fefdeb9..0000000000 --- a/packages/mobile/components/input/src/renderless/tall-storage/vue-storage-box.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { addMemory, searchMemory, selectedMemory } from './index' - -export default ({ api, props, reactive, toRefs }) => { - const state = reactive({ - storageData: [], - isMemoryStorage: false - }) - - return { - ...toRefs(state), - addMemory: addMemory(props), - searchMemory: searchMemory({ props, state }), - selectedMemory: selectedMemory({ api, state }) - } -} diff --git a/packages/mobile/components/input/src/renderless/vue.ts b/packages/mobile/components/input/src/renderless/vue.ts deleted file mode 100644 index 62624006ac..0000000000 --- a/packages/mobile/components/input/src/renderless/vue.ts +++ /dev/null @@ -1,396 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { - IInputApi, - IInputProps, - IInputState, - ISharedRenderlessParamHooks, - IInputRenderlessParamUtils, - IInputClassPrefixConstants, - IInputEventNameConstants, - IInputRenderlessParams -} from '../input' -import { - blur, - showBox, - watchFormSelect, - clear, - focus, - select, - getInput, - textLength, - handleBlur, - handleFocus, - handleInput, - handleChange, - calcIconOffset, - resizeTextarea, - getSuffixVisible, - updateIconOffset, - calcTextareaHeight, - setNativeInputValue, - calculateNodeStyling, - handleCompositionEnd, - handlePasswordVisible, - handleCompositionStart, - handleCompositionUpdate, - hasSelection, - handleEnterDisplayOnlyContent, - hiddenPassword, - setInputDomValue, - getDisplayedMaskValue, - inputStyle, - handleEnterTextarea, - handleLeaveTextarea, - getDisplayOnlyText -} from './index' -import useStorageBox from './tall-storage/vue-storage-box' - -export const api = [ - 'blur', - 'showBox', - 'clear', - 'focus', - 'state', - 'select', - 'getInput', - 'handleBlur', - 'handleInput', - 'handleFocus', - 'handleChange', - 'calcIconOffset', - 'resizeTextarea', - 'getSuffixVisible', - 'updateIconOffset', - 'calcTextareaHeight', - 'setNativeInputValue', - 'calculateNodeStyling', - 'handleCompositionEnd', - 'handlePasswordVisible', - 'handleCompositionStart', - 'handleCompositionUpdate', - 'addMemory', - 'searchMemory', - 'selectedMemory', - 'storageData', - 'isMemoryStorage', - 'hasSelection', - 'handleEnterDisplayOnlyContent', - 'hiddenPassword', - 'inputStyle', - 'handleEnterTextarea', - 'handleLeaveTextarea' -] - -const initState = ({ - reactive, - computed, - mode, - props, - parent, - constants, - api, - vm -}: Pick< - IInputRenderlessParams, - 'reactive' | 'computed' | 'mode' | 'props' | 'parent' | 'constants' | 'api' | 'vm' ->) => { - const state = reactive({ - mode, - maskSymbol: constants.MASKSYMBOL, - focused: false, - hovering: false, - isComposing: false, - passwordVisible: false, - maskValueVisible: false, - boxVisibility: false, - textareaCalcStyle: {}, - checkedLabel: '', - enteredTextarea: false, - sheetvalue: props.modelValue, - inputSize: computed(() => props.size || state.formItemSize), - inputSizeMf: computed(() => props.size || (parent.tinyForm || {}).size), - showClear: computed( - () => - props.clearable && - !state.inputDisabled && - !props.readonly && - state.nativeInputValue && - (state.focused || state.hovering) - ), - textareaHeight: vm.theme === 'saas' ? '28px' : '30px', - upperLimit: computed(() => parent.$attrs.maxlength), - textLength: computed(() => textLength(props.modelValue)), - inputExceed: computed(() => state.isWordLimitVisible && state.textLength > state.upperLimit), - formItemSize: computed(() => (parent.formItem || {}).formItemSize), - validateIcon: computed(() => constants.VALIDATE_ICON[state.validateState]), - showWordLimit: computed(() => props.showWordLimit && parent.$attrs.maxlength), - inputDisabled: computed( - () => - props.disabled || (parent.tinyForm || {}).disabled || state.isDisplayOnly || (parent.tinyForm || {}).displayOnly - ), - validateState: computed(() => (parent.formItem ? parent.formItem.validateState : '')), - inputStyle: computed(() => api.inputStyle()), - textareaStyle: computed(() => ({ - ...state.textareaCalcStyle, - resize: props.resize, - textAlign: props.textAlign - })), - needStatusIcon: computed(() => (parent.tinyForm ? parent.tinyForm.statusIcon : false)), - showPwdVisible: computed( - () => props.showPassword && !state.inputDisabled && !props.readonly && (!!state.nativeInputValue || state.focused) - ), - nativeInputValue: computed(() => - props.modelValue === null || props.modelValue === undefined ? '' : String(props.modelValue) - ), - - isWordLimitVisible: computed( - () => - ((props.showWordLimit && parent.$attrs.maxlength) || props.counter) && - (parent.type === 'text' || parent.type === 'textarea') && - !state.inputDisabled && - !props.readonly && - !props.showPassword - ), - isDisplayOnly: computed( - () => - (props.displayOnly || (parent.tinyForm || {}).displayOnly) && - ['text', 'textarea', 'password', 'number'].includes(props.type) - ), - displayOnlyTooltip: '', - hiddenPassword: computed(() => api.hiddenPassword()), - displayedMaskValue: computed(() => api.getDisplayedMaskValue()), - displayOnlyText: computed(() => api.getDisplayOnlyText()) - }) - - return state as IInputState -} - -const initApi = ({ - api, - state, - dispatch, - broadcast, - emit, - vm, - props, - CLASS_PREFIX, - parent, - nextTick -}: Pick< - IInputRenderlessParams, - 'api' | 'state' | 'dispatch' | 'broadcast' | 'emit' | 'refs' | 'props' | 'parent' | 'vm' | 'nextTick' -> & { - CLASS_PREFIX: IInputClassPrefixConstants -}) => { - Object.assign(api, { - state, - dispatch, - broadcast, - showBox: showBox(state), - clear: clear(emit), - getInput: getInput(vm), - handleChange: handleChange(emit), - watchFormSelect: watchFormSelect({ emit, props, state }), - calcIconOffset: calcIconOffset({ CLASS_PREFIX, parent }), - getSuffixVisible: getSuffixVisible({ vm, props, state }), - calculateNodeStyling: calculateNodeStyling(), - handleCompositionStart: handleCompositionStart(state), - handleCompositionUpdate: handleCompositionUpdate(state), - setInputDomValue: setInputDomValue({ state, props, nextTick, vm }), - getDisplayOnlyText: getDisplayOnlyText({ parent, props, state }), - handleEnterTextarea: handleEnterTextarea({ api, state, props, nextTick }), - handleLeaveTextarea: handleLeaveTextarea({ api, state, props, nextTick, vm }), - inputStyle: inputStyle({ props }) - }) -} - -const mergeApi = ({ - storages, - api, - componentName, - props, - emit, - eventName, - nextTick, - parent, - state, - vm -}: Pick & { - storages: ReturnType - componentName: string - eventName: IInputEventNameConstants -}) => { - const { storageData, isMemoryStorage, addMemory, searchMemory, selectedMemory } = storages - - return Object.assign(api, { - addMemory, - storageData, - searchMemory, - selectedMemory, - isMemoryStorage, - blur: blur(api), - focus: focus(api), - select: select(api), - handleBlur: handleBlur({ - api, - componentName, - emit, - eventName: eventName.blur, - props, - state, - vm - }), - handleFocus: handleFocus({ api, emit, state }), - handleInput: handleInput({ api, emit, nextTick, state }), - resizeTextarea: resizeTextarea({ api, parent, vm, state, props }), - updateIconOffset: updateIconOffset(api), - calcTextareaHeight: calcTextareaHeight({ - api, - hiddenTextarea: null, - props, - state - }), - setNativeInputValue: setNativeInputValue({ api, state }), - handleCompositionEnd: handleCompositionEnd({ api, state }), - handlePasswordVisible: handlePasswordVisible({ api, nextTick, state }), - hasSelection: hasSelection(api), - handleEnterDisplayOnlyContent: handleEnterDisplayOnlyContent({ state, props }), - hiddenPassword: hiddenPassword({ state, props }), - getDisplayedMaskValue: getDisplayedMaskValue({ state }) - }) -} - -const initWatch = ({ - watch, - state, - api, - props, - nextTick, - emit, - componentName, - eventName -}: Pick & { - componentName: string - eventName: IInputEventNameConstants -}) => { - watch( - () => props.modelValue, - (value) => { - if (state.mode === 'mobile') { - state.sheetvalue = value - emit('update:modelValue', value) - } - - nextTick(api.resizeTextarea) - - if (props.validateEvent) { - api.dispatch(componentName, eventName.change, [value]) - } - - api.setInputDomValue() - } - ) - - watch(() => state.maskValueVisible, api.setInputDomValue) - - watch(() => state.inputDisabled, api.setInputDomValue) - - watch( - () => props.mask, - () => { - api.setInputDomValue('mask') - } - ) - - watch( - () => props.size, - () => nextTick(api.resizeTextarea), - { immediate: true } - ) - - watch( - () => state.nativeInputValue, - () => { - api.setNativeInputValue() - } - ) - - watch( - () => props.type, - () => { - nextTick(() => { - api.setNativeInputValue() - api.resizeTextarea() - api.updateIconOffset() - }) - } - ) - - watch( - () => state.isDisplayOnly, - () => { - nextTick(() => { - api.setNativeInputValue() - api.resizeTextarea() - api.updateIconOffset() - }) - } - ) - - watch( - () => state.sheetvalue, - (value) => api.watchFormSelect(value), - { immediate: true } - ) -} - -export const renderless = ( - props: IInputProps, - { computed, onMounted, onUpdated, reactive, toRefs, watch, inject }: ISharedRenderlessParamHooks, - { vm, refs, parent, emit, constants, nextTick, broadcast, dispatch, mode }: IInputRenderlessParamUtils -): IInputApi => { - const api = {} as IInputApi - const componentName = constants.COMPONENT_NAME.FormItem - const eventName: IInputEventNameConstants = { change: 'form.change', blur: 'form.blur' } - const CLASS_PREFIX: IInputClassPrefixConstants = { - Input: constants.inputMode(mode), - InputGroup: constants.inputGroupMode(mode) - } - const state = initState({ reactive, computed, mode, props, parent, constants, api, vm }) - - initApi({ api, state, dispatch, broadcast, emit, refs, props, CLASS_PREFIX, parent, vm, nextTick }) - - const storages = useStorageBox({ api, props, reactive, toRefs }) - - parent.tinyForm = parent.tinyForm || inject('form', null) - - mergeApi({ api, storages, componentName, emit, eventName, props, state, nextTick, parent, vm }) - - initWatch({ watch, state, api, props, nextTick, emit, componentName, eventName }) - - onMounted(() => { - api.setNativeInputValue() - api.resizeTextarea() - api.updateIconOffset() - api.setInputDomValue() - - dispatch('Select', 'input-mounted', vm.$el) - dispatch('Tooltip', 'tooltip-update', vm.$el) - }) - - onUpdated(() => { - nextTick(api.updateIconOffset) - }) - - return api -} diff --git a/packages/mobile/components/label/index.ts b/packages/mobile/components/label/index.ts deleted file mode 100644 index e1274fb062..0000000000 --- a/packages/mobile/components/label/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Label from './src/mobile.vue' - -/* istanbul ignore next */ -Label.install = function (Vue) { - Vue.component(Label.name, Label) -} - -export default Label diff --git a/packages/mobile/components/label/src/label.ts b/packages/mobile/components/label/src/label.ts deleted file mode 100644 index 7807a65f39..0000000000 --- a/packages/mobile/components/label/src/label.ts +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ComputedRef, ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const labelProps = { - label: { - type: String, - default: '' - }, - color: { - type: String, - default: 'primary' - }, - size: { - type: String, - default: 'normal' - }, - type: { - type: String, - default: 'base' - }, - wholeline: { - type: Boolean, - default: false - }, - position: { - type: String, - default: 'left' - }, - ellipsis: { - type: Number, - default: 0 - }, - decimal: { - type: Number, - default: 2 - }, - limit: { - type: Number, - default: 0 - }, - isRequired: { - type: Boolean, - default: false - }, - bold: { - type: Boolean, - default: false - } -} - -export type ILabelProps = ExtractPropTypes - -export interface ILabelState { - label: ComputedRef - type: ComputedRef - color: ComputedRef - size: ComputedRef - labelStyle: ComputedRef - labelClass: ComputedRef - isRequired: ComputedRef -} - -export interface ILabelApi { - state: ILabelState - handleClick: (event: MouseEvent) => void - computeLabel: () => string - computeLabelStyle: () => object - computeLabelClass: () => [] -} -export type ILabelRenderlessParams = ISharedRenderlessFunctionParams & { - api: ILabelApi - state: ILabelState - props: ILabelProps -} - -export type ILabelRenderlessParamUtils = ISharedRenderlessParamUtils diff --git a/packages/mobile/components/label/src/mobile.vue b/packages/mobile/components/label/src/mobile.vue deleted file mode 100644 index 1d65dde0d0..0000000000 --- a/packages/mobile/components/label/src/mobile.vue +++ /dev/null @@ -1,32 +0,0 @@ - - - - diff --git a/packages/mobile/components/label/src/renderless/index.ts b/packages/mobile/components/label/src/renderless/index.ts deleted file mode 100644 index f4e73be041..0000000000 --- a/packages/mobile/components/label/src/renderless/index.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ILabelProps } from '../label' - -const prefix = 'tiny-mobile-label-' - -function numFormat(num, decimal) { - let str = '' - str = (Math.round(num * 100) / 100) - .toFixed(decimal) - .toString() - .replace(/(\d)(?=(\d{3})+\.)/g, function ($0, $1) { - return $1 + ',' - }) - return str -} - -function handleNumberLabel(label, decimal) { - let val = label - // 去除-和.以外的非数字字符 - const reg1 = /[^(\-|\+)?\d+(\.\d+)?$]/g - // 去掉前缀多余的0 - const reg2 = /0*([1-9]\d*|0\.\d+)/ - val = val.replace(reg1, '').replace(reg2, '$1') - let arr = val.split('.') - let numStr = '' - for (let i = 0; i < arr.length; i++) { - if (i === arr.length - 1 && arr.length > 1) { - numStr += '.' - } - numStr += arr[i] - } - - numStr = numFormat(numStr, decimal) - - numStr = numStr.replace(/\d+/, (s) => { - return s.replace(/(\d)(?=(\d{3})+$)/g, '$1,') - }) - - return numStr -} - -export const handleClick = - ({ emit, state }) => - () => { - emit('click', state.label) - } - -export const computeLabel = (props: ILabelProps) => () => { - let label = props.label - if (props.type === 'number') { - label = handleNumberLabel(props.label, props.decimal) - } - if (props.limit !== 0 && label.length > props.limit) { - return label.slice(0, props.limit) - } - return label -} - -export const computeLabelClass = (props: ILabelProps) => () => { - return [ - `${prefix}${props.size}`, - `${prefix}${props.color}`, - `${prefix}${props.position}`, - props.wholeline || props.ellipsis === 1 || props.ellipsis === 2 || props.ellipsis === 3 ? `${prefix}wholeline` : '', - props.ellipsis > 0 && props.ellipsis < 4 ? `${prefix}ellipsis${props.ellipsis}` : '', - props.bold ? `${prefix}bold` : '' - ] -} diff --git a/packages/mobile/components/label/src/renderless/vue.ts b/packages/mobile/components/label/src/renderless/vue.ts deleted file mode 100644 index 62a14fde32..0000000000 --- a/packages/mobile/components/label/src/renderless/vue.ts +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { - ILabelState, - ILabelProps, - ILabelRenderlessParamUtils, - ISharedRenderlessParamHooks, - ILabelApi -} from '../label' -import { handleClick, computeLabel, computeLabelClass } from './index' - -export const api = ['state', 'handleClick', 'computeLabel', 'computeLabelStyle', 'computeLabelClass'] - -export const renderless = ( - props: ILabelProps, - { computed, onBeforeUnmount, reactive, watch, inject }: ISharedRenderlessParamHooks, - { emit, parent }: ILabelRenderlessParamUtils -) => { - parent.tinyForm = parent.tinyForm || inject('form', null) - - const state: ILabelState = reactive({ - label: computed(() => api.computeLabel()), - type: props.type, - color: props.color, - size: props.size, - labelClass: computed(() => api.computeLabelClass()), - isRequired: props.isRequired - }) - - const api: ILabelApi = { - state, - handleClick: handleClick({ emit, state }), - computeLabel: computeLabel(props), - // computeLabelStyle: computeLabelStyle(props, state), - computeLabelClass: computeLabelClass(props) - } - - return api -} diff --git a/packages/mobile/components/list/index.ts b/packages/mobile/components/list/index.ts deleted file mode 100644 index ef6908812e..0000000000 --- a/packages/mobile/components/list/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import List from './src/mobile.vue' - -/* istanbul ignore next */ -List.install = function (Vue) { - Vue.component(List.name, List) -} - -export default List diff --git a/packages/mobile/components/list/src/mobile.vue b/packages/mobile/components/list/src/mobile.vue deleted file mode 100644 index d83b888fd1..0000000000 --- a/packages/mobile/components/list/src/mobile.vue +++ /dev/null @@ -1,70 +0,0 @@ - - - - diff --git a/packages/mobile/components/list/src/renderless/index.ts b/packages/mobile/components/list/src/renderless/index.ts deleted file mode 100644 index 4344b6a4cb..0000000000 --- a/packages/mobile/components/list/src/renderless/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -export const clickList = - ({ emit, props }) => - () => { - const list = { - id: props.id, - content: props.content, - subtext: props.subText, - contentdes: props.contentDes - } - - emit('click', list) - } diff --git a/packages/mobile/components/list/src/renderless/vue.ts b/packages/mobile/components/list/src/renderless/vue.ts deleted file mode 100644 index 7a152efae9..0000000000 --- a/packages/mobile/components/list/src/renderless/vue.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { clickList } from './index' - -export const api = ['state', 'clickList'] - -export const renderless = (props, { reactive }, { emit }) => { - const state = reactive({ - test: '1' - }) - - const api = { - state, - clickList: clickList({ emit, props }) - } - - return api -} diff --git a/packages/mobile/components/loading/index.ts b/packages/mobile/components/loading/index.ts deleted file mode 100644 index 08182901ef..0000000000 --- a/packages/mobile/components/loading/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import service from './src/service' -import directive from './src/directive' -import { setupComponent } from '@mobile-root/common' - -const Loadings: any = { - install(app) { - app.directive('loading', directive) - }, - service, - directive -} - -setupComponent.TINYLoading = { - init(root) { - let prefix = root.$apiPrefix || '$' - root[`${prefix}loading`] = service - } -} - -export default Loadings diff --git a/packages/mobile/components/loading/src/directive.ts b/packages/mobile/components/loading/src/directive.ts deleted file mode 100644 index 9578dead90..0000000000 --- a/packages/mobile/components/loading/src/directive.ts +++ /dev/null @@ -1,183 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import afterLeave from '@mobile-root/utils/deps/after-leave' -import PopupManager from '@mobile-root/utils/deps/popup-manager' -import { addClass, getStyle, removeClass } from '@mobile-root/utils/deps/dom' -import Loading from './mobile.vue' -import { hooks, directive, createComponent, appProperties } from '@mobile-root/common' -import { constants, defaults } from './service' - -const insertDom = (parent, el, binding) => { - if (!el.domVisible && getStyle(el, 'display') !== 'none' && getStyle(el, 'visibility') !== 'hidden') { - Object.keys(el.maskStyle).forEach((property) => { - el.mask.style[property] = el.maskStyle[property] - }) - - if (el.originalPosition !== 'absolute' && el.originalPosition !== 'fixed') { - addClass(parent, constants.PARENT_RELATIVE_CLS) - } - - if (binding.modifiers.fullscreen && binding.modifiers.lock) { - addClass(parent, constants.PARENT_HIDDEN_CLS) - } - - el.domVisible = true - - parent.appendChild(el.mask) - - hooks.nextTick(() => { - if (el.instance.hiding) { - el.instance.$emit('after-leave') - } else { - el.instance.state.visible = true - } - }) - - el.domInserted = true - } else if (el.domVisible && el.instance.hiding === true) { - el.instance.state.visible = true - el.instance.hiding = false - } -} - -const appendLoadingToBody = (el, binding) => { - const clientRect = el.getBoundingClientRect() - el.originalPosition = getStyle(document.body, 'position') - const direction = ['top', 'left'] - - direction.forEach((property) => { - const scroll = property === 'top' ? 'scrollTop' : 'scrollLeft' - el.maskStyle[property] = - clientRect[property] + - document.body[scroll] + - document.documentElement[scroll] - - parseInt(getStyle(document.body, `margin-${property}`), 10) + - 'px' - }) - const size = ['height', 'width'] - - size.forEach((property) => { - el.maskStyle[property] = clientRect[property] + 'px' - }) - - insertDom(document.body, el, binding) -} - -const toggleLoading = (el, binding, maskInstance) => { - if (binding.value) { - hooks.nextTick(() => { - if (binding.modifiers.fullscreen) { - el.originalPosition = getStyle(document.body, 'position') - el.originalOverflow = getStyle(document.body, 'overflow') - el.maskStyle.zIndex = PopupManager.nextZIndex() - - addClass(el.mask, constants.IS_FULLSCREEN_CLS) - insertDom(document.body, el, binding) - } else { - removeClass(el.mask, constants.IS_FULLSCREEN_CLS) - - if (binding.modifiers.body) { - appendLoadingToBody(el, binding) - } else { - el.originalPosition = getStyle(el, 'position') - - insertDom(el, el, binding) - } - } - }) - } else { - afterLeave( - maskInstance, - () => { - if (!maskInstance.hiding) { - return - } - - const target = binding.modifiers.fullscreen || binding.modifiers.body ? document.body : el - - el.domVisible = false - - removeClass(target, constants.PARENT_RELATIVE_CLS) - removeClass(target, constants.PARENT_HIDDEN_CLS) - - maskInstance.hiding = false - }, - 300, - true - ) - - maskInstance.state.visible = false - maskInstance.hiding = true - } -} - -const vLoading = { - bind(el, binding, vnode) { - const vm = vnode.context - const textExr = el.getAttribute(constants.TEXT_ATTR) - const spinnerExr = el.getAttribute(constants.TEXT_SPINNER) - const backgroundExr = el.getAttribute(constants.TEXT_BACKGROUND) - const customClassExr = el.getAttribute(constants.TEXT_CUSTOM_CLS) - - const mask = createComponent({ - component: Loading, - propsData: { - _constants: constants, - tiny_mode: vm.tiny_mode?.value || appProperties().tiny_mode?.value - }, - el: document.createElement('div') - }) - - const config = { - ...defaults, - text: (vm && vm[textExr]) || textExr, - spinner: (vm && vm[spinnerExr]) || spinnerExr, - background: (vm && vm[backgroundExr]) || backgroundExr, - customClass: (vm && vm[customClassExr]) || customClassExr, - fullscreen: !!binding.modifiers.fullscreen - } - - for (const key in config) { - if (Object.prototype.hasOwnProperty.call(config, key)) { - mask.state[key] = config[key] - } - } - - el.instance = mask - el.mask = mask.$el - el.maskStyle = {} - - binding.value && toggleLoading(el, binding, mask) - }, - update(el, binding) { - el.instance.setText(el.getAttribute(constants.TEXT_ATTR)) - - if (binding.oldValue !== binding.value) { - toggleLoading(el, binding, el.instance) - } - }, - unbind(el, binding) { - if (el.domInserted) { - el.mask && el.mask.parentNode && el.mask.parentNode.removeChild(el.mask) - toggleLoading(el, { value: false, modifiers: binding.modifiers }, el.instance) - } - - // 手动释放独立组件实例 - if (el.instance) { - typeof el.instance.$destroy === 'function' && el.instance.$destroy() - el.instance = null - el.mask = null - } - } -} - -export default directive({ vLoading }).vLoading diff --git a/packages/mobile/components/loading/src/loading.ts b/packages/mobile/components/loading/src/loading.ts deleted file mode 100644 index cf3d32e566..0000000000 --- a/packages/mobile/components/loading/src/loading.ts +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ExtractPropTypes, Component } from 'vue' -import { constants } from './service' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' -import type { setText, close, handleAfterLeave } from './renderless' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const loadingProps = { - type: { - type: String, - validator: (value: string) => Boolean(~['primary', 'simple'].indexOf(value)) - }, - loadtext: { - type: String, - default: () => constants.LOAD_ICON_TEXT - }, - _constants: { - type: Object, - default: () => constants - }, - loadingImg: { - type: String - }, - size: { - type: String, - default: 'small' - } -} - -export interface ILoadingState { - text: string | null - spinner: Component | null - visible: boolean - customClass: string - background: string | null - fullscreen: boolean - closed: boolean - size: string - body?: boolean - lock?: boolean - target?: HTMLElement | string - tiny_mode?: string - type?: string -} - -export type ILoadingProps = ExtractPropTypes - -export type ILoadingConstants = typeof constants - -export type ILoadingRenderlessParams = ISharedRenderlessFunctionParams & { - state: ILoadingState - props: ILoadingProps -} - -export interface ILoadingApi { - state: ILoadingState - setText: ReturnType - handleAfterLeave: ReturnType - close: ReturnType -} - -export type ILoadingRenderlessParamUtils = ISharedRenderlessParamUtils diff --git a/packages/mobile/components/loading/src/mobile.vue b/packages/mobile/components/loading/src/mobile.vue deleted file mode 100644 index e831c93bf3..0000000000 --- a/packages/mobile/components/loading/src/mobile.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - diff --git a/packages/mobile/components/loading/src/renderless/index.ts b/packages/mobile/components/loading/src/renderless/index.ts deleted file mode 100644 index a4611e2fbd..0000000000 --- a/packages/mobile/components/loading/src/renderless/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { ILoadingRenderlessParamUtils, ILoadingRenderlessParams, ILoadingState } from '../loading' -import afterLeave from '@mobile-root/utils/deps/after-leave' -import { removeClass } from '@mobile-root/utils/deps/dom' - -export const handleAfterLeave = (emit: ILoadingRenderlessParamUtils['emit']) => (): void => { - emit('after-leave') -} - -export const setText = - (state: ILoadingState) => - (text: string): void => { - state.text = text - } - -export const close = - ({ state, constants, vm }: Pick) => - (): void => { - afterLeave( - vm, - () => { - const target = state.fullscreen || state.body ? document.body : state.target - - if (vm.$el && vm.$el.parentNode) { - removeClass(target, constants.PARENT_RELATIVE_CLS) - removeClass(target, constants.PARENT_HIDDEN_CLS) - vm.$el.parentNode.removeChild(vm.$el) - } - - state.closed = true - }, - 300 - ) - - state.visible = false - } diff --git a/packages/mobile/components/loading/src/renderless/vue.ts b/packages/mobile/components/loading/src/renderless/vue.ts deleted file mode 100644 index dd05613dfc..0000000000 --- a/packages/mobile/components/loading/src/renderless/vue.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { handleAfterLeave, setText, close } from './index' -import type { - ILoadingApi, - ILoadingState, - ILoadingProps, - ILoadingRenderlessParamUtils, - ISharedRenderlessParamHooks -} from '../loading' - -export const api = ['state', 'handleAfterLeave', 'setText', 'close'] - -export const renderless = ( - props: ILoadingProps, - { reactive, computed }: ISharedRenderlessParamHooks, - { constants, vm, emit, designConfig }: ILoadingRenderlessParamUtils -): ILoadingApi => { - const state: ILoadingState = reactive({ - text: null, - spinner: null, - visible: false, - customClass: '', - background: null, - fullscreen: true, - closed: false, - size: '', - iconSize: '', - loadingImg: computed(() => { - return props.loadingImg || designConfig?.props?.loadingImg - }), - iconStyle: computed(() => (state.iconSize ? { width: state.iconSize + 'px', height: state.iconSize + 'px' } : {})) - }) - - const api: ILoadingApi = { - state, - setText: setText(state), - handleAfterLeave: handleAfterLeave(emit), - close: close({ state, constants, vm }) - } - - return api -} diff --git a/packages/mobile/components/loading/src/service.ts b/packages/mobile/components/loading/src/service.ts deleted file mode 100644 index 4a2c05cbe9..0000000000 --- a/packages/mobile/components/loading/src/service.ts +++ /dev/null @@ -1,136 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import PopupManager from '@mobile-root/utils/deps/popup-manager' -import { getStyle, addClass } from '@mobile-root/utils/deps/dom' -import { createComponent, hooks, appProperties } from '@mobile-root/common' -import Loading from './mobile.vue' - -export const defaults = { - text: null, - body: false, - lock: false, - customClass: '', - fullscreen: true, - iconSize: '' -} - -let fullscreenLoading = null - -export const constants = { - TEXT_ATTR: 'tiny-loading__text', - IS_FULLSCREEN_CLS: 'is-fullscreen', - TEXT_SPINNER: 'tiny-loading__spinner', - TEXT_BACKGROUND: 'tiny-loading__background', - TEXT_CUSTOM_CLS: 'tiny-loading__custom-class', - PARENT_HIDDEN_CLS: 'tiny-loading__parent-hidden', - PARENT_RELATIVE_CLS: 'tiny-loading__parent-relative', - LOAD_ICON_TEXT: 'ui.load.dot' -} -const addStyle = (options, parent, instance) => { - let maskStyle = {} - - if (options.fullscreen) { - instance.originalPosition = getStyle(document.body, 'position') - instance.originalOverflow = getStyle(document.body, 'overflow') - maskStyle.zIndex = PopupManager.nextZIndex() - } else if (options.body) { - const clientRect = options.target.getBoundingClientRect() - - instance.originalPosition = getStyle(document.body, 'position') - - const direction = ['top', 'left'] - - direction.forEach((property) => { - let scroll = property === 'top' ? 'scrollTop' : 'scrollLeft' - - maskStyle[property] = clientRect[property] + document.body[scroll] + document.documentElement[scroll] + 'px' - }) - - const size = ['height', 'width'] - - size.forEach((property) => { - maskStyle[property] = clientRect[property] + 'px' - }) - } else { - instance.originalPosition = getStyle(parent, 'position') - } - - Object.keys(maskStyle).forEach((property) => { - instance.$el.style[property] = maskStyle[property] - }) -} - -export default (configs = {}) => { - configs = { ...defaults, ...configs } - - if (typeof configs.target === 'string') { - configs.target = document.querySelector(configs.target) - } - - configs.target = configs.target || document.body - - if (configs.target !== document.body) { - configs.fullscreen = false - } else { - configs.body = true - } - - if (configs.fullscreen && fullscreenLoading && !fullscreenLoading.state.closed) { - return fullscreenLoading - } - - let parent = configs.body ? document.body : configs.target - - const loadingEl = parent.querySelector(':scope > [data-tag="tiny-loading"]') - - loadingEl && parent.removeChild(loadingEl) - - let instance = createComponent({ - component: Loading, - propsData: { - _constants: constants, - size: configs.size, - loadingImg: configs.loadingImg, - tiny_mode: configs.tiny_mode || appProperties().tiny_mode?.value - }, - el: document.createElement('div') - }) - - for (const key in configs) { - if (Object.prototype.hasOwnProperty.call(configs, key)) { - instance.state[key] = configs[key] - } - } - - addStyle(configs, parent, instance) - - if (instance.originalPosition !== 'absolute' && instance.originalPosition !== 'fixed') { - addClass(parent, constants.PARENT_RELATIVE_CLS) - } - - if (configs.fullscreen && configs.lock) { - addClass(parent, constants.PARENT_HIDDEN_CLS) - } - - parent.appendChild(instance.$el) - - hooks.nextTick(() => { - instance.state.visible = true - }) - - if (configs.fullscreen) { - fullscreenLoading = instance - } - - return instance -} diff --git a/packages/mobile/components/mask/index.ts b/packages/mobile/components/mask/index.ts deleted file mode 100644 index a3e3695d38..0000000000 --- a/packages/mobile/components/mask/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Mask from './src/mobile.vue' - -/* istanbul ignore next */ -Mask.install = function (Vue) { - Vue.component(Mask.name, Mask) -} - -export default Mask diff --git a/packages/mobile/components/mask/src/mobile.vue b/packages/mobile/components/mask/src/mobile.vue deleted file mode 100644 index 8add80d150..0000000000 --- a/packages/mobile/components/mask/src/mobile.vue +++ /dev/null @@ -1,54 +0,0 @@ - - - - diff --git a/packages/mobile/components/mask/src/renderless/index.ts b/packages/mobile/components/mask/src/renderless/index.ts deleted file mode 100644 index 0e83a9005d..0000000000 --- a/packages/mobile/components/mask/src/renderless/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -export const handleTouch = - ({ props, emit }) => - (event: TouchEvent) => { - if (props.cancelTouch) { - event.preventDefault() - event.stopPropagation() - } else { - emit('update:visible', false) - } - - emit('click', props.visible) - } diff --git a/packages/mobile/components/mask/src/renderless/vue.ts b/packages/mobile/components/mask/src/renderless/vue.ts deleted file mode 100644 index 111fb4756b..0000000000 --- a/packages/mobile/components/mask/src/renderless/vue.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { handleTouch } from './index' - -export const api = ['state', 'handleTouch'] - -export const renderless = (props, { reactive, computed }, { emit }) => { - const api = {} - const state = reactive({ - calcStyle: computed(() => ({ zIndex: props.zIndex })) - }) - - Object.assign(api, { - state, - handleTouch: handleTouch({ props, emit }) - }) - - return api -} diff --git a/packages/mobile/components/message/index.ts b/packages/mobile/components/message/index.ts deleted file mode 100644 index 8ae8520487..0000000000 --- a/packages/mobile/components/message/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import Modal from '../modal' -import { extend } from '@mobile-root/utils/object' -import { $prefix } from '@mobile-root/common' - -const Message = extend(true, { props: { componentName: { type: String, default: 'Message' } } }, Modal, { - name: $prefix + 'Message' -}) - -/* istanbul ignore next */ -Message.install = function (Vue) { - Vue.component(Message.name, Message) -} - -export default Message diff --git a/packages/mobile/components/mini-picker/index.ts b/packages/mobile/components/mini-picker/index.ts deleted file mode 100644 index 7e490d56b6..0000000000 --- a/packages/mobile/components/mini-picker/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import MiniPicker from './src/mobile.vue' - -/* istanbul ignore next */ -MiniPicker.install = function (Vue) { - Vue.component(MiniPicker.name, MiniPicker) -} - -export default MiniPicker diff --git a/packages/mobile/components/mini-picker/src/mobile.vue b/packages/mobile/components/mini-picker/src/mobile.vue deleted file mode 100644 index 2c9637fedf..0000000000 --- a/packages/mobile/components/mini-picker/src/mobile.vue +++ /dev/null @@ -1,111 +0,0 @@ - - - - diff --git a/packages/mobile/components/mini-picker/src/renderless/index.ts b/packages/mobile/components/mini-picker/src/renderless/index.ts deleted file mode 100644 index 95724cb7a0..0000000000 --- a/packages/mobile/components/mini-picker/src/renderless/index.ts +++ /dev/null @@ -1,210 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -export const visibleHandle = (emit) => () => emit('update:visible', false) - -export const watchVisible = - (emit) => - ({ state, value }) => { - setTimeout(() => { - value ? (state.toggle = true) : (state.toggle = false) - }, 0) - - emit('update:visible', value) - } - -export const getDataType = (state) => () => { - const { columns } = state - const firstColumn = columns[0] || {} - - if (firstColumn.children) { - return 'cascade' - } - - if (firstColumn.values) { - return 'object' - } - - return 'text' -} - -export const format = - ({ state, api }) => - () => { - const { columns, dataType } = state - - if (dataType === 'text') { - state.formattedColumns = [{ values: columns }] - } else if (dataType === 'cascade') { - api.formatCascade() - } else { - state.formattedColumns = columns - } - } - -export const formatCascade = - ({ state, props }) => - () => { - const formatted = [] - let cursor = { children: state.columns } - - while (cursor && cursor.children) { - const defaultIndex = cursor.defaultIndex || Number(state.defaultIndex) - - formatted.push({ - values: cursor.children.map((item) => item[props.valueKey]), - defaultIndex - }) - - cursor = cursor.children[defaultIndex] - } - - state.formattedColumns = formatted - } - -export const change = (api) => (index) => { - api.onChange(index) -} - -export const setColumnValue = (api) => (index, value) => { - const column = api.getColumn(index) - column && column.setValue(value) -} - -export const setValues = (api) => (values) => { - values.forEach((value, index) => { - api.setColumnValue(index, value) - }) -} - -export const getColumnValue = (api) => (index) => { - const column = api.getColumn(index) - return column && column.getValue() -} - -export const confirm = - ({ api, childrenPickerRefs }) => - () => { - const children = childrenPickerRefs.childrenPicker - - children && children.forEach((child) => child.onTransitionEnd()) - api.emitEvent('confirm') - api.visibleHandle() - } - -export const cancel = - ({ api, emit }) => - () => { - emit('cancel') - api.visibleHandle() - } - -export const emitEvent = - ({ api, state, emit }) => - (event) => { - if (state.dataType === 'text') { - emit(event, api.getColumnValue(0), api.getColumnIndex(0)) - } else { - emit(event, api.getValues(), api.getIndexes()) - } - } - -export const getColumn = (childrenPickerRefs) => (index) => { - const children = childrenPickerRefs.childrenPicker - return children[index] -} - -export const getColumnIndex = (api) => (columnIndex) => (api.getColumn(columnIndex) || {}).state.currentIndex - -export const getValues = (childrenPickerRefs) => () => - childrenPickerRefs.childrenPicker && childrenPickerRefs.childrenPicker.map((child) => child.getValue()) - -export const getIndexes = (childrenPickerRefs) => () => - childrenPickerRefs.childrenPicker && childrenPickerRefs.childrenPicker.map((child) => child.state.currentIndex) - -export const setIndexes = (api) => (indexes) => { - indexes.forEach((optionIndex, columnIndex) => { - api.setColumnIndex(columnIndex, optionIndex) - }) -} - -export const setColumnIndex = (api) => (columnIndex, optionIndex) => { - const column = api.getColumn(columnIndex) - column && column.setIndex(optionIndex) -} - -export const getColumnValues = (childrenPickerRefs) => (index) => - (childrenPickerRefs.childrenPicker[index] || {}).state.columnsItem.values - -export const setColumnValues = (childrenPickerRefs) => (index, options) => { - const children = childrenPickerRefs.childrenPicker - const column = children[index] - - if (column) { - column.setOptions(options) - } -} - -export const onCascadeChange = - ({ api, state, props }) => - (columnIndex) => { - const { columns } = state - let cursor = { children: columns } - const indexes = api.getIndexes() - - for (let i = 0; i <= columnIndex; i++) { - cursor = cursor.children[indexes[i]] - } - - while (columnIndex < state.formattedColumns.length) { - if (cursor.children && cursor.children.length !== 0) { - columnIndex++ - - api.setColumnValues( - columnIndex, - cursor.children.map((item) => item[props.valueKey]) - ) - - cursor = cursor.children[cursor.defaultIndex || 0] - } else { - columnIndex++ - api.setColumnValues(columnIndex, []) - } - } - } - -export const onChange = - ({ api, state, emit }) => - (columnIndex) => { - if (state.dataType === 'cascade') { - api.onCascadeChange(columnIndex) - } - - if (api.dataType === 'text') { - emit('change', api.getColumnValue(0), api.getColumnIndex(0)) - } else { - emit('change', api.getValues(), columnIndex) - } - } - -export const getChildrenComponent = ({ state, vm, constants }) => { - const childrenName = constants.CHILDREN_PICKER - const children = [] - - for (let index = 0; index < state.formattedColumns.length; index++) { - children.push( - Array.isArray(vm.$refs[childrenName + index]) ? vm.$refs[childrenName + index][0] : vm.$refs[childrenName + index] - ) - } - - return children -} diff --git a/packages/mobile/components/mini-picker/src/renderless/vue.ts b/packages/mobile/components/mini-picker/src/renderless/vue.ts deleted file mode 100644 index 18252fa43f..0000000000 --- a/packages/mobile/components/mini-picker/src/renderless/vue.ts +++ /dev/null @@ -1,141 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - visibleHandle, - watchVisible, - formatCascade, - format, - getDataType, - change, - setColumnValue, - setValues, - getColumnValue, - confirm, - cancel, - getColumnIndex, - getValues, - getIndexes, - setIndexes, - setColumnIndex, - getColumnValues, - setColumnValues, - onChange, - onCascadeChange, - emitEvent, - getColumn, - getChildrenComponent -} from './index' - -export const api = [ - 'state', - 'visibleHandle', - 'watchVisible', - 'change', - 'setValues', - 'getColumnValue', - 'confirm', - 'cancel', - 'getColumnIndex', - 'getValues', - 'getIndexes', - 'setIndexes', - 'setColumnIndex', - 'getColumnValues', - 'setColumnValues', - 'onChange', - 'onCascadeChange', - 'emitEvent', - 'getColumn', - 'setColumnValue' -] - -const initState = ({ reactive, computed, props, api }) => { - const state = reactive({ - columns: props.columns, - toggle: false, - itemHeight: Number(props.itemHeight), - defaultIndex: props.defaultIndex, - visibleItemCount: props.visibleItemCount, - clumnsWrapHeight: null, - formattedColumns: [], - dataType: computed(() => api.getDataType()) - }) - - return state -} - -const initApi = ({ api, props, state, emit, childrenPickerRefs }) => { - Object.assign(api, { - state, - getColumn: getColumn(childrenPickerRefs), - getValues: getValues(childrenPickerRefs), - getIndexes: getIndexes(childrenPickerRefs), - getDataType: getDataType(state), - visibleHandle: visibleHandle(emit), - formatCascade: formatCascade({ state, props }), - getColumnValues: getColumnValues(childrenPickerRefs), - setColumnValues: setColumnValues(childrenPickerRefs), - emitEvent: emitEvent({ api, state, emit }), - change: change(api), - onChange: onChange({ api, state, emit }), - cancel: cancel({ api, emit }), - confirm: confirm({ api, childrenPickerRefs }), - format: format({ state, api }), - setValues: setValues(api), - setIndexes: setIndexes(api), - watchVisible: watchVisible(emit), - setColumnIndex: setColumnIndex(api), - getColumnValue: getColumnValue(api), - getColumnIndex: getColumnIndex(api), - setColumnValue: setColumnValue(api), - onCascadeChange: onCascadeChange({ api, state, props }) - }) -} - -const initWatch = ({ watch, props, state, api }) => { - watch( - () => props.visible, - (value) => { - api.watchVisible({ state, value }) - } - ) - - watch( - () => props.columns, - (value) => { - state.columns = value - api.format() - } - ) -} - -export const renderless = (props, { computed, onMounted, reactive, watch }, { emit, nextTick, vm, constants }) => { - const api = {} - const childrenPickerRefs = { childrenPicker: null } - const state = initState({ reactive, computed, props, api }) - - initApi({ api, props, state, emit, childrenPickerRefs }) - - initWatch({ watch, props, state, api }) - - onMounted(() => { - nextTick(() => { - childrenPickerRefs.childrenPicker = getChildrenComponent({ state, vm, constants }) - }) - - api.format() - state.clumnsWrapHeight = state.itemHeight * state.visibleItemCount - }) - - return api -} diff --git a/packages/mobile/components/modal/index.ts b/packages/mobile/components/modal/index.ts deleted file mode 100644 index 57184deca0..0000000000 --- a/packages/mobile/components/modal/index.ts +++ /dev/null @@ -1,138 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { createComponent, setupComponent } from '@mobile-root/common' -import { MsgQueue } from './src/renderless' -import TINYModal from './src/mobile.vue' - -export function Modal(options) { - const modalPromise = new Promise((resolve) => { - if (options && options.id && MsgQueue.some((comp) => comp.id === options.id)) { - resolve('exist') - } else { - let events = options.events || {} - let $modal - - options.events = Object.assign({}, events, { - hide(params) { - events.hide && events.hide.call(this, params) - if ($modal.beforeUnmouted) { - $modal.beforeUnmouted() - } - resolve(params.type) - }, - confirm(params) { - events.confirm && events.confirm.call(this, params) - }, - show(params) { - events.show && events.show.call(this, params) - } - }) - - $modal = createComponent({ - el: document.createElement('div'), - propsData: Object.assign( - { - 'tiny_mode': TINYModal.tiny_mode, - 'tiny_theme': TINYModal.tiny_theme - }, - options - ), - component: TINYModal - }) - - const open = $modal.open - if (open) { - open() - } - setTimeout(() => (modalPromise.vm = $modal), 0) - } - }) - return modalPromise -} -const modal = Modal -const types = ['alert', 'confirm', 'message'] - -const defOpts = { - alert: { - showFooter: true, - type: 'alert' - }, - confirm: { - showFooter: true, - status: 'question', - type: 'confirm' - }, - message: { - mask: false, - lockView: false, - showHeader: false, - showClose: false, - type: 'message' - } -} - -types.forEach((type) => { - TINYModal[type] = Modal[type] = function (message, title, options) { - let opts - - if (typeof message === 'object' && message !== null) { - opts = message - } else if (title) { - opts = { title } - } - - if (message === undefined || message === null) { - message = '' - } - - return modal({ - message: message.toString(), - ...defOpts[type], - ...opts, - ...options, - componentType: type - }) - } -}) - -export const alert = (Modal as any).alert -export const message = (Modal as any).message -export const confirm = (Modal as any).confirm - -TINYModal.installed = false -setupComponent.TINYModal = { - install(Vue) { - if (TINYModal.installed) return - // vue3 或 vue2 - const isVue2 = !!Vue.component - const tinyMode = isVue2 ? Vue.prototype.tiny_mode : Vue.config.globalProperties.tiny_mode - const tinyTheme = isVue2 ? Vue.prototype.tiny_theme : Vue.config.globalProperties.tiny_theme - const specifyPc = typeof process === 'object' ? process.env?.TINY_MODE : null - TINYModal.tiny_mode = specifyPc || (tinyMode && tinyMode.value) - TINYModal.tiny_theme = tinyTheme && tinyTheme.value - TINYModal.installed = true - }, - init(root) { - let prefix = root.$TinyModalApiPrefix || root.$apiPrefix || '$' - - root[`${prefix}alert`] = (Modal as any).alert - root[`${prefix}message`] = (Modal as any).message - root[`${prefix}confirm`] = (Modal as any).confirm - } -} - -TINYModal.install = function (Vue) { - Vue.component(TINYModal.name, TINYModal) -} - -export default TINYModal diff --git a/packages/mobile/components/modal/src/mobile.vue b/packages/mobile/components/modal/src/mobile.vue deleted file mode 100644 index 0e43ac43c4..0000000000 --- a/packages/mobile/components/modal/src/mobile.vue +++ /dev/null @@ -1,185 +0,0 @@ - - diff --git a/packages/mobile/components/modal/src/modal.ts b/packages/mobile/components/modal/src/modal.ts deleted file mode 100644 index 3473b27027..0000000000 --- a/packages/mobile/components/modal/src/modal.ts +++ /dev/null @@ -1,265 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' -import type { mouseEnterEvent, mouseLeaveEvent } from './renderless' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const $constants = { - MODAL_STATUS: { - INFO: 'info', - SUCCESS: 'success', - WARNING: 'warning', - ERROR: 'error', - LOADING: 'loading' - }, - NODAL_TYPE: { - ALERT: 'alert', - CONFIRM: 'confirm', - MESSAGE: 'message' - }, - STATUS_MAPPING_CLASSS: { - INFO: 'tiny-modal-svg__info', - SUCCESS: 'tiny-modal-svg__success', - WARNING: 'tiny-modal-svg__warning', - ERROR: 'tiny-modal-svg__error', - LOADING: 'tiny-modal-svg__refresh roll' - }, - PC_SCROLL_LOCK_CLASS: 'tiny-dialog-box__scroll-lock', - MOBILE_FIRST_SCROLL_LOCK_CLASS: 'tiny-modal-lockscroll', - Mode: 'pc', - SCROLL_LOCK_CLASS(mode) { - return mode === this.Mode ? this.PC_SCROLL_LOCK_CLASS : this.MOBILE_FIRST_SCROLL_LOCK_CLASS - } -} - -export const modalProps = { - _constants: { - type: Object, - default: () => $constants - }, - animat: { type: Boolean, default: () => true }, - beforeClose: Function, - duration: { type: [Number, String], default: () => 3000 }, - escClosable: Boolean, - events: Object, - fullscreen: Boolean, - height: [Number, String], - id: String, - isFormReset: { - type: Boolean, - default: true - }, - lockScroll: Boolean, - lockView: { type: Boolean, default: () => true }, - marginSize: { type: [Number, String], default: 10 }, - mask: { type: Boolean, default: () => true }, - maskClosable: Boolean, - message: [String, Function, Object], - minHeight: { type: [Number, String], default: () => 200 }, - minWidth: { type: [Number, String], default: () => 340 }, - modelValue: Boolean, - resize: Boolean, - showFooter: Boolean, - showHeader: { type: Boolean, default: true }, - status: { - type: [String, Object], - default: '' - }, - title: String, - top: { type: [Number, String], default: 80 }, - type: { type: String, default: 'alert' }, - vSize: String, - width: [Number, String], - zIndex: [Number, String], - description: String, - options: Array, - showClose: { type: Boolean, default: true }, - confirmContent: String, - cancelContent: String, - position: { - type: String, - default: '', - validator(val: string) { - return ['', 'bottom-right'].includes(val) - } - }, - customClass: String, - confirmBtnProps: { type: Object, default: () => ({}) }, - cancelBtnProps: { type: Object, default: () => ({}) }, - footerDragable: Boolean, - tiny_theme: String, - slots: Object -} - -type zoomLocatType = null | { - top: number - left: number - width: number - height: number -} - -export interface IModalState { - emitter: ISharedRenderlessParamUtils['emitter'] - visible: boolean - contentVisible: boolean - cumsumZindex: number - modalTop: number - modalZindex: number | string - zoomLocat: zoomLocatType - isMsg: boolean - prevEvent: null | Event - options: any[] - theme: string | undefined -} - -export type IModalProps = ExtractPropTypes - -export type IModalConstants = typeof $constants - -export type IModalRenderlessParams = ISharedRenderlessFunctionParams & { - api: IModalApi - state: IModalState - props: IModalProps -} - -export interface IModalApi { - state: IModalState - broadcast: () => void - computedIsMsg: (props: IModalProps) => boolean - updateStyle: () => void - getBox: () => IModalRenderlessParams['vm'] - watchValue: (visible: boolean) => void - created: () => void - mounted: () => void - beforeUnmouted: () => void - selfClickEvent: (event: MouseEvent) => void - mouseEnterEvent: ReturnType - mouseLeaveEvent: ReturnType - updateZindex: () => void - handleEvent: (type: string, event: Event, options?: any[]) => void - closeEvent: (event: PointerEvent) => void - confirmEvent: (event: PointerEvent) => void - cancelEvent: (event: PointerEvent) => void - open: () => void - addMsgQueue: () => void - removeMsgQueue: () => void - close: (type: string) => void - handleGlobalKeydownEvent: (event: KeyboardEvent) => void - maximize: () => Promise - revert: () => Promise - toggleZoomEvent: (event: PointerEvent) => void - mousedownEvent: (event: MouseEvent) => void - dragEvent: (event: MouseEvent) => void - resetDragStyle: () => void -} - -export type IModalRenderlessParamUtils = ISharedRenderlessParamUtils - -export interface IModalEmitParam { - type: string - $modal: IModalRenderlessParamUtils['parent'] - options?: any[] -} - -export type IModalEmitZoomParam = { - params: IModalEmitParam - event: Event -} & Pick - -interface IModalSizeInfo { - width: number - height: number - top: number - offsetWidth: number - offsetHeight: number - visibleWidth: number - visibleHeight: number - minWidth: number | string - minHeight: number | string - x: number - y: number - temp: number - offsetLeft: number - offsetTop: number - marginSize: number | string - left: number - modalBoxElem: IModalRenderlessParams['vm'] -} - -export type IModalComputeLeftParam = Pick< - IModalSizeInfo, - 'width' | 'offsetWidth' | 'x' | 'minWidth' | 'temp' | 'offsetLeft' | 'marginSize' | 'left' -> - -export type IModalComputeTopParam = Pick< - IModalSizeInfo, - 'height' | 'offsetHeight' | 'y' | 'minHeight' | 'temp' | 'offsetTop' | 'marginSize' | 'top' -> - -export type IModalComputeRightParam = Pick< - IModalSizeInfo, - 'width' | 'offsetWidth' | 'x' | 'minWidth' | 'temp' | 'visibleWidth' | 'offsetLeft' | 'marginSize' -> -export type IModalComputeBottomParam = Pick< - IModalSizeInfo, - 'height' | 'offsetHeight' | 'y' | 'minHeight' | 'temp' | 'visibleHeight' | 'offsetTop' | 'marginSize' -> - -export type IModalUpdateWlParam = Pick< - IModalSizeInfo, - 'width' | 'offsetWidth' | 'x' | 'minWidth' | 'temp' | 'offsetLeft' | 'marginSize' | 'left' | 'modalBoxElem' -> - -export type IModalUpdateWrParam = Pick< - IModalSizeInfo, - 'width' | 'offsetWidth' | 'x' | 'minWidth' | 'temp' | 'visibleWidth' | 'offsetLeft' | 'marginSize' | 'modalBoxElem' -> - -export type IModalUpdateStParam = Pick< - IModalSizeInfo, - 'height' | 'offsetHeight' | 'y' | 'minHeight' | 'temp' | 'offsetTop' | 'marginSize' | 'top' | 'modalBoxElem' -> - -export type IModalUpdateSbParam = Pick< - IModalSizeInfo, - 'height' | 'offsetHeight' | 'y' | 'minHeight' | 'temp' | 'visibleHeight' | 'offsetTop' | 'marginSize' | 'modalBoxElem' -> - -export interface IModalRet { - width?: number - height?: number - top?: number - left?: number -} - -export interface IModalUpdateDeltaParam { - event: MouseEvent - delta: { - x: number - y: number - } - state: IModalRenderlessParams['state'] -} - -export type IModalDragDirection = 'wl' | 'wr' | 'st' | 'sb' | 'swst' | 'sest' | 'swlb' | 'selb' - -export interface IModalSetModalBoxStyleParam { - delta: { x: number; y: number } - params: { - type: IModalDragDirection - props: IModalProps - disX: number - disY: number - } & Pick -} diff --git a/packages/mobile/components/modal/src/renderless/index.ts b/packages/mobile/components/modal/src/renderless/index.ts deleted file mode 100644 index f79bc8807f..0000000000 --- a/packages/mobile/components/modal/src/renderless/index.ts +++ /dev/null @@ -1,916 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { KEY_CODE } from '@mobile-root/utils' -import { on, off, addClass, hasClass, removeClass } from '@mobile-root/utils/deps/dom' -import PopupManager from '@mobile-root/utils/deps/popup-manager' -import { getDomNode } from '@mobile-root/utils/deps/dom' -import { getViewportWindow } from '@mobile-root/utils/global' - -import type { - IModalProps, - IModalRenderlessParams, - IModalEmitZoomParam, - IModalApi, - IModalEmitParam, - IModalRenderlessParamUtils, - IModalComputeTopParam, - IModalComputeLeftParam, - IModalComputeRightParam, - IModalComputeBottomParam, - IModalRet, - IModalUpdateWlParam, - IModalUpdateWrParam, - IModalUpdateStParam, - IModalUpdateDeltaParam, - IModalSetModalBoxStyleParam, - IModalUpdateSbParam -} from '@/types' - -const DragClass = 'is__drag' - -let timer: number - -const emitZoom = ({ params, parent, emit, event }: IModalEmitZoomParam): void => { - let { $listeners, events = {} } = parent - if ($listeners.zoom) { - emit('zoom', params, event) - } else if (events.zoom) { - events.zoom.call(parent, params, event) - } -} - -export const MsgQueue: IModalRenderlessParams['vm'][] = [] - -export const computedIsMsg = - () => - (props: IModalProps): boolean => - props.type === 'message' - -export const computedBoxStyle = - ({ props, isMobileFirstMode }: Pick) => - (): { width?: string | number; height?: string | number } => { - if (isMobileFirstMode) { - return {} - } - - let width: string | number = '' - let height: string | number = '' - - if (props.width) { - width = isNaN(props.width as number) ? props.width : `${props.width}px` - } - - if (props.height) { - height = isNaN(props.height as number) ? props.height : `${props.height}px` - } - - return { width, height } - } - -export const watchValue = - (api: IModalApi) => - (visible: boolean): void => - visible ? api.open() : api.close('hide') - -export const watchVisible = - ({ api, props }) => - (visible) => { - if (props.lockScroll) { - visible ? api.showScrollbar() : api.hideScrollbar() - } - } - -export const created = - ({ api, props, state }: Pick) => - (): void => { - if (props.modelValue) { - api.open() - } - - state.modalZindex = props.zIndex || PopupManager.nextZIndex() - } - -export const mounted = - ({ - api, - parent, - props, - isMobileFirstMode, - state - }: Pick) => - () => { - if (!isMobileFirstMode) { - let modalBoxElem = api.getBox() - - Object.assign(modalBoxElem.style, { - width: props.width ? (isNaN(props.width) ? props.width : `${props.width}px`) : null, - - height: props.height ? (isNaN(props.height) ? props.height : `${props.height}px`) : null - }) - - if (props.lockScroll && state.visible) { - api.showScrollbar() - } - } else { - on(window, 'resize', api.resetDragStyle) - } - - if (props.escClosable) { - on(document, 'keydown', api.handleGlobalKeydownEvent) - } - - on(window, 'hashchange', api.handleHashChange) - - document.body.appendChild(parent.$el) - } - -export const beforeUnmouted = - ({ api, parent, isMobileFirstMode }: Pick) => - (): void => { - isMobileFirstMode && off(window, 'resize', api.resetDragStyle) - off(document, 'keydown', api.handleGlobalKeydownEvent) - off(window, 'hashchange', api.handleHashChange) - api.removeMsgQueue() - api.hideScrollbar() - - if (parent.$el.parentNode) { - parent.$el.parentNode.removeChild(parent.$el) - } - } - -export const selfClickEvent = - ({ api, parent, props }: Pick) => - (event: MouseEvent): void => { - if (props.maskClosable && event.target === parent.$el) { - api.close('mask') - } - } - -export const mouseEnterEvent = () => (): void => { - clearTimeout(timer) -} - -export const mouseLeaveEvent = - ({ api, props }: Pick) => - (): void => { - api.addMsgQueue() - - timer = window.setTimeout( - () => { - api.close('close') - }, - parseFloat(props.duration as string) - ) - } - -export const updateZindex = - ({ state, props }: Pick) => - (): void => { - state.modalZindex = props.zIndex || PopupManager.nextZIndex() - } - -export const handleEvent = - ({ - api, - emit, - parent, - props, - isMobileFirstMode - }: Pick) => - (type: string, event: Event, options?: any[]) => { - // close,confirm,cancel - if ( - ~['close', 'confirm', 'cancel'].indexOf(type) && - typeof props.beforeClose === 'function' && - props.beforeClose(type) === false - ) { - return - } - - const { events = {} } = parent - - const params: IModalEmitParam = { - type, - $modal: parent - } - - if (isMobileFirstMode && type === 'confirm') { - params.options = options - } - - emit(type, params, event) - events[type] && events[type].call(parent, params) - api.close(type) - } - -export const closeEvent = - (api: IModalApi) => - (event: PointerEvent): void => { - api.handleEvent('close', event) - } - -export const confirmEvent = - ({ api, state }: Pick) => - (event: PointerEvent): void => { - api.handleEvent('confirm', event, state.options) - } - -export const cancelEvent = - (api: IModalApi) => - (event: PointerEvent): void => { - api.handleEvent('cancel', event) - } - -export const open = - ({ - api, - emit, - nextTick, - parent, - props, - state, - isMobileFirstMode - }: Pick) => - (): void => { - let { $listeners, events = {} } = parent - - if (!state.visible) { - let params = { type: 'show', $modal: parent } - - state.visible = true - state.contentVisible = false - api.updateZindex() - - if (!events.show) { - emit('update:modelValue', true) - emit('show', params) - } - - setTimeout(() => { - state.contentVisible = true - - if (!$listeners.show && events.show) { - nextTick(() => { - events.show.call(parent, params) - }) - } - }, 10) - - if (state.isMsg) { - api.addMsgQueue() - - timer = window.setTimeout( - () => { - api.close(params.type) - }, - parseFloat(props.duration as string) - ) - } else { - nextTick(() => { - if (!isMobileFirstMode) { - let modalBoxElem = api.getBox() - - const viewportWindow = getViewportWindow() - - let clientVisibleWidth = - viewportWindow.document.documentElement.clientWidth || viewportWindow.document.body.clientWidth - - let clientVisibleHeight = - viewportWindow.document.documentElement.clientHeight || viewportWindow.document.body.clientHeight - - modalBoxElem.style.left = `${clientVisibleWidth / 2 - modalBoxElem.offsetWidth / 2}px` - - if ( - modalBoxElem.offsetHeight + modalBoxElem.offsetTop + (props.marginSize as number) > - clientVisibleHeight - ) { - modalBoxElem.style.top = `${props.marginSize}px` - } - } - - if (props.fullscreen) { - nextTick(api.maximize) - } - }) - } - } - } - -export const addMsgQueue = - ({ api, parent }: Pick) => - (): void => { - if (!~MsgQueue.indexOf(parent)) { - MsgQueue.push(parent) - } - - api.updateStyle() - } - -export const removeMsgQueue = - ({ api, parent }: Pick) => - (): void => { - const index = MsgQueue.indexOf(parent) - - if (~index) { - MsgQueue.splice(index, 1) - } - - api.updateStyle() - } - -export const updateStyle = - ({ nextTick, props }: Pick) => - () => { - nextTick(() => { - let offsetTop = 0 - let distance = props.top - - MsgQueue.forEach((comp: IModalRenderlessParams['vm']) => { - offsetTop += parseFloat(distance as string) - comp.state.modalTop = offsetTop - - const modalBox = comp.$refs.modalBox - - offsetTop += modalBox.clientHeight - distance = 15 - }) - }) - } - -export const close = - ({ emit, parent, props, state }: Pick) => - (type: string): void => { - // esc,hide,mask,show,... - if ( - !~['close', 'confirm', 'cancel'].indexOf(type) && - typeof props.beforeClose === 'function' && - props.beforeClose(type) === false - ) { - return - } - - let { events = {} } = parent - - state.emitter.emit('boxclose', props.isFormReset) - - if (state.visible) { - state.contentVisible = false - - setTimeout(() => { - state.visible = false - - let params = { type, $modal: parent } - - if (events.hide) { - events.hide.call(parent, params) - } else { - emit('update:modelValue', false) - emit('hide', params) - } - }, 200) - } - } - -export const handleGlobalKeydownEvent = - (api: IModalApi) => - (event: KeyboardEvent): void => { - if (event.keyCode === KEY_CODE.Escape) { - api.close('esc') - } - } - -export const handleHashChange = (api: IModalApi) => (): void => { - api.close('hide') -} - -export const getBox = - ({ vm }: Pick) => - (): IModalRenderlessParams['vm'] => - vm.$refs.modalBox - -export const maximize = - ({ - api, - nextTick, - props, - state, - isMobileFirstMode - }: Pick) => - (): Promise => { - return nextTick().then(() => { - if (!state.zoomLocat) { - let marginSize = props.marginSize - let modalBoxElement = api.getBox() - let { visibleHeight, visibleWidth } = getDomNode() - - state.zoomLocat = { - top: modalBoxElement.offsetTop, - left: modalBoxElement.offsetLeft, - width: modalBoxElement.clientWidth, - height: modalBoxElement.clientHeight - } - - if (!isMobileFirstMode) { - Object.assign(modalBoxElement.style, { - width: `${visibleWidth - marginSize * 2}px`, - height: `${visibleHeight - marginSize * 2}px`, - top: `${marginSize}px`, - left: `${marginSize}px` - }) - } - - state.emitter.emit('boxdrag') - } - }) - } - -export const revert = - ({ - api, - nextTick, - state, - isMobileFirstMode - }: Pick) => - (): Promise => { - return nextTick().then(() => { - let zoomLocat = state.zoomLocat - - if (zoomLocat) { - let modalBoxElement = api.getBox() - - state.zoomLocat = null - - if (!isMobileFirstMode) { - Object.assign(modalBoxElement.style, { - width: `${zoomLocat.width}px`, - height: `${zoomLocat.height}px`, - top: `${zoomLocat.top}px`, - left: `${zoomLocat.left}px` - }) - } - - state.emitter.emit('boxdrag') - } - }) - } - -export const toggleZoomEvent = - ({ - api, - emit, - parent, - state, - isMobileFirstMode - }: Pick) => - (event: PointerEvent): Promise => { - let params = { type: state.zoomLocat ? 'min' : 'max', $modal: parent } - const callback = state.zoomLocat ? api.revert : api.maximize - - isMobileFirstMode && api.resetDragStyle() - - return callback().then(() => { - emitZoom({ params, parent, emit, event }) - }) - } - -function getEventTargetNode( - event: MouseEvent, - container: IModalRenderlessParams['vm'], - queryCls: string -): { flag: boolean; container?: IModalRenderlessParams['vm']; targetElem?: IModalRenderlessParams['vm'] } { - let targetElem - let target = event.target as any - - while (target && target.nodeType && target !== document) { - if (queryCls && hasClass(target, queryCls)) { - targetElem = target - } else if (target === container) { - return { - flag: queryCls ? !!targetElem : true, - container, - targetElem - } - } - - target = target.parentNode - } - - return { flag: false } -} - -export const mousedownEvent = - ({ - api, - nextTick, - props, - state, - emit, - isMobileFirstMode - }: Pick) => - (event: MouseEvent): void => { - let modalBoxElement = api.getBox() - - if (!state.zoomLocat && event.button === 0 && !getEventTargetNode(event, modalBoxElement, 'trigger__btn').flag) { - event.preventDefault() - - let demMousemove = document.onmousemove - let demMouseup = document.onmouseup - let disX = event.clientX - modalBoxElement.offsetLeft - let disY = event.clientY - modalBoxElement.offsetTop - let { visibleHeight, visibleWidth } = getDomNode() - - document.onmousemove = (event) => { - event.preventDefault() - state.emitter.emit('boxdrag') - - let offsetWidth = modalBoxElement.offsetWidth - let offsetHeight = modalBoxElement.offsetHeight - let left = event.clientX - disX - let top = event.clientY - disY - let minX, maxX, minY, maxY - - if (isMobileFirstMode) { - minX = offsetWidth / 2 + props.marginSize - maxX = visibleWidth - offsetWidth / 2 - props.marginSize - minY = offsetHeight / 2 + props.marginSize - maxY = visibleHeight - offsetHeight / 2 - props.marginSize - } else { - minX = props.marginSize - maxX = visibleWidth - offsetWidth - props.marginSize - minY = props.marginSize - maxY = visibleHeight - offsetHeight - props.marginSize - } - - if (left < minX) { - left = minX - } - - if (left > maxX) { - left = maxX - } - - if (top < minY) { - top = minY - } - - if (top > maxY) { - top = maxY - } - - modalBoxElement.style.left = `${left}px` - modalBoxElement.style.top = `${top}px` - - addClass(modalBoxElement, DragClass) - - emit('custom-mousemove', event) - } - - document.onmouseup = (event) => { - document.onmousemove = demMousemove - document.onmouseup = demMouseup - - nextTick(() => { - removeClass(modalBoxElement, DragClass) - }) - - emit('custom-mouseup', event) - } - - emit('custom-mousedown', event) - } - } - -const computeLeft = ({ - width, - offsetWidth, - x, - minWidth, - temp, - offsetLeft, - marginSize, - left -}: IModalComputeLeftParam): { width: number; left: number } => { - width = offsetWidth - x - width = width < (minWidth as number) ? (minWidth as number) : width - temp = offsetLeft + offsetWidth - (marginSize as number) - width = width > temp ? temp : width - left = offsetLeft + offsetWidth - width - - return { width, left } -} - -const computeTop = ({ - height, - offsetHeight, - y, - minHeight, - temp, - offsetTop, - marginSize, - top -}: IModalComputeTopParam): { height: number; top: number } => { - height = offsetHeight - y - height = height < (minHeight as number) ? (minHeight as number) : height - temp = offsetTop + offsetHeight - (marginSize as number) - height = height > temp ? temp : height - top = offsetTop + offsetHeight - height - - return { height, top } -} - -const computeRight = ({ - width, - offsetWidth, - x, - minWidth, - temp, - visibleWidth, - offsetLeft, - marginSize -}: IModalComputeRightParam): { width: number } => { - width = offsetWidth + x - width = width < (minWidth as number) ? (minWidth as number) : width - temp = visibleWidth - offsetLeft - (marginSize as number) - width = width > temp ? temp : width - - return { width } -} - -const computeBottom = ({ - height, - offsetHeight, - y, - minHeight, - temp, - visibleHeight, - offsetTop, - marginSize -}: IModalComputeBottomParam): { height: number } => { - height = offsetHeight + y - height = height < (minHeight as number) ? (minHeight as number) : height - temp = visibleHeight - offsetTop - (marginSize as number) - height = height > temp ? temp : height - - return { height } -} - -const updateModalBox = ({ - ret: { width, left, height, top }, - modalBoxElem: modalBoxElement -}: { - ret: IModalRet - modalBoxElem: IModalRenderlessParams['vm'] -}): void => { - if (width) { - modalBoxElement.style.width = `${width}px` - } - - if (left) { - modalBoxElement.style.left = `${left}px` - } - - if (height) { - modalBoxElement.style.height = `${height}px` - } - - if (top) { - modalBoxElement.style.top = `${top}px` - } -} - -const updateWl = ({ - width, - offsetWidth, - x, - minWidth, - temp, - offsetLeft, - marginSize, - left, - modalBoxElem -}: IModalUpdateWlParam): void => { - updateModalBox({ - ret: computeLeft({ width, offsetWidth, x, minWidth, temp, offsetLeft, marginSize, left }), - modalBoxElem - }) -} - -const updateWr = ({ - width, - offsetWidth, - x, - minWidth, - temp, - visibleWidth, - offsetLeft, - marginSize, - modalBoxElem -}: IModalUpdateWrParam): void => { - updateModalBox({ - ret: computeRight({ width, offsetWidth, x, minWidth, temp, visibleWidth, offsetLeft, marginSize }), - modalBoxElem - }) -} - -const updateSt = ({ - height, - offsetHeight, - y, - minHeight, - temp, - offsetTop, - marginSize, - top, - modalBoxElem -}: IModalUpdateStParam): void => { - updateModalBox({ - ret: computeTop({ height, offsetHeight, y, minHeight, temp, offsetTop, marginSize, top }), - modalBoxElem - }) -} - -const updateSb = ({ - height, - offsetHeight, - y, - minHeight, - temp, - visibleHeight, - offsetTop, - marginSize, - modalBoxElem -}: IModalUpdateSbParam): void => { - updateModalBox({ - ret: computeBottom({ height, offsetHeight, y, minHeight, temp, visibleHeight, offsetTop, marginSize }), - modalBoxElem - }) -} - -const setModalBoxStyle = ({ params, delta: { x, y } }: IModalSetModalBoxStyleParam): void => { - const { visibleHeight, visibleWidth, modalBoxElem, type, props } = params - const { offsetWidth, offsetHeight, offsetLeft, offsetTop } = modalBoxElem - const { minWidth, minHeight, marginSize } = props - const [width, left, temp, height, top] = [0, 0, 0, 0, 0] - - switch (type) { - case 'wl': - updateWl({ offsetWidth, width, minWidth, x, offsetLeft, temp, marginSize, left, modalBoxElem }) - break - case 'wr': - updateWr({ width, offsetWidth, x, minWidth, temp, visibleWidth, offsetLeft, marginSize, modalBoxElem }) - break - case 'st': - updateSt({ height, offsetHeight, y, minHeight, temp, offsetTop, marginSize, top, modalBoxElem }) - break - case 'sb': - updateSb({ height, offsetHeight, y, minHeight, temp, visibleHeight, offsetTop, marginSize, modalBoxElem }) - break - case 'swst': - updateWl({ width, offsetWidth, x, minWidth, temp, offsetLeft, marginSize, left, modalBoxElem }) - updateSt({ height, offsetHeight, y, minHeight, temp, offsetTop, marginSize, top, modalBoxElem }) - break - case 'sest': - updateWr({ offsetWidth, width, x, temp, minWidth, marginSize, visibleWidth, offsetLeft, modalBoxElem }) - updateSt({ height, offsetHeight, y, minHeight, temp, offsetTop, marginSize, top, modalBoxElem }) - break - case 'swlb': - updateWl({ width, offsetWidth, minWidth, x, temp, marginSize, offsetLeft, modalBoxElem, left }) - updateSb({ height, offsetHeight, y, minHeight, temp, visibleHeight, offsetTop, marginSize, modalBoxElem }) - break - case 'selb': - updateWr({ width, offsetWidth, minWidth, x, visibleWidth, offsetLeft, marginSize, temp, modalBoxElem }) - updateSb({ height, offsetHeight, y, minHeight, temp, visibleHeight, offsetTop, marginSize, modalBoxElem }) - break - default: - break - } -} - -const updateDelta = ({ event, delta, state }: IModalUpdateDeltaParam): void => { - if (state.prevEvent) { - delta.x += event.screenX - (state.prevEvent as any).screenX - delta.y += event.screenY - (state.prevEvent as any).screenY - } - - state.prevEvent = event -} - -function _findFormComponent(vm: IModalRenderlessParams['vm'], formList: IModalRenderlessParams['vm'][]): void { - const children = vm.$children - - if (children && children.length === 0) { - return - } - - children.forEach((child) => { - const tag = child.$options.componentName - - if (/^Form$/.test(tag)) { - formList.push(child) - } - - _findFormComponent(child, formList) - }) -} - -function findFormComponent(vm: IModalRenderlessParams['vm']): IModalRenderlessParams['vm'][] { - const formList = [] - _findFormComponent(vm, formList) - return formList -} - -export const updateFormTip = (parent: IModalRenderlessParamUtils['parent']): void => { - const formList = findFormComponent(parent) - - if (formList.length > 0) { - formList.forEach((form: IModalRenderlessParamUtils['vm']) => { - form.updateTip() - }) - } -} - -export const dragEvent = - ({ api, emit, parent, props, state }: Pick) => - (event: MouseEvent) => { - event.preventDefault() - - const delta = { x: 0, y: 0 } - const { visibleHeight, visibleWidth } = getDomNode() - const modalBoxElem = api.getBox() - const demMousemove = document.onmousemove - const demMouseup = document.onmouseup - - const params = { - props, - offsetTop: modalBoxElem.offsetTop, - offsetLeft: modalBoxElem.offsetLeft, - visibleWidth, - modalBoxElem, - visibleHeight, - disX: event.clientX, - disY: event.clientY, - type: (event.target)?.dataset.type - } - - document.onmousemove = (event: MouseEvent) => { - updateFormTip(parent) - updateDelta({ event, delta, state }) - setModalBoxStyle({ params, delta }) - - delta.x = delta.y = 0 - - addClass(modalBoxElem, DragClass) - - emitZoom({ - params: { type: 'resize', $modal: parent }, - parent, - emit, - event - }) - } - - document.onmouseup = () => { - state.zoomLocat = null - document.onmousemove = demMousemove - document.onmouseup = demMouseup - - setTimeout(() => { - removeClass(modalBoxElem, DragClass) - state.prevEvent = null - }, 50) - } - } - -export const resetFormTip = (parent: IModalRenderlessParamUtils['parent'], isFormReset = true) => { - const formList = findFormComponent(parent) - - if (formList.length > 0) { - formList.forEach((form: IModalRenderlessParamUtils['vm']) => { - isFormReset ? form.resetFields() : form.clearValidate() - }) - } -} - -export const resetDragStyle = (api: IModalApi) => (): void => { - const modalBoxElement = api.getBox() - modalBoxElement.style.left = '' - modalBoxElement.style.top = '' -} - -export const showScrollbar = (lockScrollClass) => () => { - addClass(document.body, lockScrollClass) -} - -export const hideScrollbar = (lockScrollClass) => () => { - removeClass(document.body, lockScrollClass) -} diff --git a/packages/mobile/components/modal/src/renderless/vue.ts b/packages/mobile/components/modal/src/renderless/vue.ts deleted file mode 100644 index 95e7c7d469..0000000000 --- a/packages/mobile/components/modal/src/renderless/vue.ts +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - dragEvent, - handleEvent, - mousedownEvent, - toggleZoomEvent, - revert, - maximize, - getBox, - handleGlobalKeydownEvent, - close, - updateStyle, - addMsgQueue, - removeMsgQueue, - computedIsMsg, - watchValue, - created, - mounted, - beforeUnmouted, - selfClickEvent, - mouseEnterEvent, - mouseLeaveEvent, - updateZindex, - closeEvent, - confirmEvent, - cancelEvent, - open, - resetDragStyle, - computedBoxStyle, - handleHashChange, - showScrollbar, - hideScrollbar, - watchVisible -} from './index' -import type { IModalApi, IModalProps, IModalRenderlessParamUtils, ISharedRenderlessParamHooks } from '../modal' - -export const api = [ - 'state', - 'dragEvent', - 'mousedownEvent', - 'toggleZoomEvent', - 'revert', - 'maximize', - 'getBox', - 'close', - 'updateStyle', - 'selfClickEvent', - 'mouseEnterEvent', - 'mouseLeaveEvent', - 'updateZindex', - 'closeEvent', - 'confirmEvent', - 'cancelEvent', - 'open', - 'beforeUnmouted', - 'resetDragStyle' -] - -export const renderless = ( - props: IModalProps, - { computed, onMounted, onBeforeUnmount, reactive, watch }: ISharedRenderlessParamHooks, - { vm, emit, emitter, nextTick, broadcast, vm: parent, constants, mode }: IModalRenderlessParamUtils, - { isMobileFirstMode } -) => { - const api = {} as IModalApi - const lockScrollClass = constants.SCROLL_LOCK_CLASS(mode) - const state = reactive({ - emitter: emitter(), - visible: false, - contentVisible: false, - cumsumZindex: 0, - modalTop: 0, - modalZindex: 0, - zoomLocat: null, - isMsg: computed(() => api.computedIsMsg(props)), - prevEvent: null, - options: [], - theme: props.tiny_theme, - boxStyle: computed(() => api.computedBoxStyle()) - }) - - Object.assign(api, { - state, - broadcast, - computedIsMsg: computedIsMsg(), - updateStyle: updateStyle({ nextTick, props }), - getBox: getBox({ vm }), - watchValue: watchValue(api), - created: created({ api, props, state }), - mounted: mounted({ api, parent, props, isMobileFirstMode, state }), - beforeUnmouted: beforeUnmouted({ api, parent, isMobileFirstMode }), - selfClickEvent: selfClickEvent({ api, parent, props }), - mouseEnterEvent: mouseEnterEvent(), - mouseLeaveEvent: mouseLeaveEvent({ api, props }), - updateZindex: updateZindex({ state, props }), - handleEvent: handleEvent({ api, emit, parent, props, isMobileFirstMode }), - closeEvent: closeEvent(api), - confirmEvent: confirmEvent({ api, state }), - cancelEvent: cancelEvent(api), - open: open({ api, emit, nextTick, parent, props, state, isMobileFirstMode }), - addMsgQueue: addMsgQueue({ api, parent }), - removeMsgQueue: removeMsgQueue({ api, parent }), - close: close({ emit, parent, props, state }), - handleGlobalKeydownEvent: handleGlobalKeydownEvent(api), - handleHashChange: handleHashChange(api), - maximize: maximize({ api, nextTick, props, state, isMobileFirstMode }), - revert: revert({ api, nextTick, state, isMobileFirstMode }), - toggleZoomEvent: toggleZoomEvent({ api, emit, parent, state, isMobileFirstMode }), - mousedownEvent: mousedownEvent({ api, nextTick, props, state, emit, isMobileFirstMode }), - dragEvent: dragEvent({ api, emit, parent, props, state }), - resetDragStyle: resetDragStyle(api), - computedBoxStyle: computedBoxStyle({ props, isMobileFirstMode }), - watchVisible: watchVisible({ api, props }), - hideScrollbar: hideScrollbar(lockScrollClass), - showScrollbar: showScrollbar(lockScrollClass) - }) - - watch(() => props.modelValue, api.watchValue) - - watch(() => state.visible, api.watchVisible) - - api.created() - - onMounted(api.mounted) - onBeforeUnmount(api.beforeUnmouted) - - return api -} diff --git a/packages/mobile/components/multi-select-item/index.ts b/packages/mobile/components/multi-select-item/index.ts deleted file mode 100644 index 88658c0876..0000000000 --- a/packages/mobile/components/multi-select-item/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import MultiSelectItem from './src/mobile.vue' - -MultiSelectItem.install = function (Vue) { - Vue.component(MultiSelectItem.name, MultiSelectItem) -} - -export default MultiSelectItem diff --git a/packages/mobile/components/multi-select-item/src/mobile.vue b/packages/mobile/components/multi-select-item/src/mobile.vue deleted file mode 100644 index 2bc46b70ca..0000000000 --- a/packages/mobile/components/multi-select-item/src/mobile.vue +++ /dev/null @@ -1,71 +0,0 @@ - - - - diff --git a/packages/mobile/components/multi-select-item/src/multi-select-item.ts b/packages/mobile/components/multi-select-item/src/multi-select-item.ts deleted file mode 100644 index 79013793bf..0000000000 --- a/packages/mobile/components/multi-select-item/src/multi-select-item.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -export const multiSelectItemProps = { - option: { - type: Object, - default: () => ({ - label: '' - }) - }, - divided: { - type: Boolean, - default: false - } -} diff --git a/packages/mobile/components/multi-select-item/src/renderless/index.ts b/packages/mobile/components/multi-select-item/src/renderless/index.ts deleted file mode 100644 index 4d12a021a0..0000000000 --- a/packages/mobile/components/multi-select-item/src/renderless/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -export const handleClick = - ({ props, multiSelect }) => - (event) => { - if (props.option.disabled) { - return - } - - event.stopPropagation() - if (props.disabled !== true && multiSelect.disabled !== true) { - multiSelect.state.multiSelectEmitter.emit('multiSelectItemClick', props.option) - } - } - -export const toggleExpand = - ({ props, multiSelect }) => - (event) => { - if (props.option.disabled) { - return - } - - event.stopPropagation() - if (props.disabled !== true && multiSelect.disabled !== true) { - multiSelect.state.multiSelectEmitter.emit('toggleItemExpand', props.option) - } - } diff --git a/packages/mobile/components/multi-select-item/src/renderless/vue.ts b/packages/mobile/components/multi-select-item/src/renderless/vue.ts deleted file mode 100644 index 3c26a76120..0000000000 --- a/packages/mobile/components/multi-select-item/src/renderless/vue.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { handleClick, toggleExpand } from './index' - -export const api = [ - 'state', - 'created', - 'handleClick', - 'confirm', - 'reset', - 'wheelChange', - 'clickWheelItem', - 'loadDefault', - 'toggleExpand' -] - -const initApi = ({ api, props, state, multiSelect }) => { - Object.assign(api, { - state, - handleClick: handleClick({ props, multiSelect }), - toggleExpand: toggleExpand({ props, multiSelect }) - }) -} - -export const renderless = (props, { reactive, inject }, { emit, nextTick, refs, vm }) => { - const api = {} - const multiSelect = inject('multiSelect') - const state = reactive({}) - initApi({ api, multiSelect, props, state }) - - return api -} diff --git a/packages/mobile/components/multi-select/index.ts b/packages/mobile/components/multi-select/index.ts deleted file mode 100644 index 545f9d5ad1..0000000000 --- a/packages/mobile/components/multi-select/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import MultiSelect from './src/mobile.vue' - -MultiSelect.install = function (Vue) { - Vue.component(MultiSelect.name, MultiSelect) -} - -export default MultiSelect diff --git a/packages/mobile/components/multi-select/src/mobile.vue b/packages/mobile/components/multi-select/src/mobile.vue deleted file mode 100644 index f98d9adc53..0000000000 --- a/packages/mobile/components/multi-select/src/mobile.vue +++ /dev/null @@ -1,191 +0,0 @@ - - - - diff --git a/packages/mobile/components/multi-select/src/multi-select.ts b/packages/mobile/components/multi-select/src/multi-select.ts deleted file mode 100644 index 6cce77ceb9..0000000000 --- a/packages/mobile/components/multi-select/src/multi-select.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { PropType } from '@mobile-root/common' - -export const multiSelectProps = { - dataSource: { - type: Array, - default: () => [] - }, - modelValue: { - type: [String, Array], - default: '' - }, - searchValue: { - type: String, - default: '' - }, - defaultSelectedArray: { - type: Array, - default: () => [] - }, - filterable: { - type: Boolean, - default: false - }, - searchPlaceholder: { - type: String, - default: () => t('ui.search.placeholder') - }, - type: { - type: String as PropType<'list' | 'wheel'>, - default: 'list' - }, - disabled: { - type: Boolean, - default: false - }, - mask: { - type: Boolean, - default: false - }, - maskOptions: { - type: Object, - default: () => ({}) - } -} diff --git a/packages/mobile/components/multi-select/src/renderless/index.ts b/packages/mobile/components/multi-select/src/renderless/index.ts deleted file mode 100644 index cf9b6f193a..0000000000 --- a/packages/mobile/components/multi-select/src/renderless/index.ts +++ /dev/null @@ -1,461 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { cloneDeep } from '@mobile-root/utils/object' - -export const initValue = - ({ props, emit }) => - () => { - const { modelValue, dataSource = [], disabled } = props - - if (disabled) { - return - } - - let value = [] - dataSource?.forEach((data, index) => { - const isArrayVal = Array.isArray(modelValue[index]) - if (data.multiple) { - value.push(isArrayVal ? modelValue[index] : []) - } else { - value.push(isArrayVal ? '' : modelValue[index] || '') - } - }) - - emit('update:modelValue', value) - } - -export const updateValue = - ({ state, props, emit }) => - (value: string) => { - const activeIndex = state.headerIndex - const values = cloneDeep(props.modelValue) - if (!values) { - return - } - - if (Array.isArray(values[state.headerIndex])) { - const currentVal = values[activeIndex] - values[activeIndex] = currentVal.includes(value) ? currentVal.filter((i) => i !== value) : [...currentVal, value] - } else { - values[activeIndex] = value - } - - emit('update:modelValue', values) - } - -export const getOption = (options, target) => { - for (const option of options) { - if (option.value === target) { - return option - } - - if (option.children?.length) { - const result = getOption(option.children, target) - if (result) { - return result - } - } - } - - return null -} - -export const updateTitle = - ({ props, state }) => - () => { - const { modelValue = [], dataSource = [] } = props - const { headerInfo } = state - - modelValue.forEach((value, index) => { - if (!dataSource[index].multiple) { - headerInfo[index].title = getOption(dataSource[index].options, value)?.label || headerInfo[index].title - } - }) - } - -export const created = - ({ api, emit, props, state, refs, nextTick }) => - () => { - nextTick(() => { - state.dataSource = cloneDeep(props.dataSource) - state.defaultSelectedArray = cloneDeep(props.defaultSelectedArray) - state.labelLevelsInfo = getLabelLevelsInfo(refs) - state.labelsStyle = getLabelsStyle(state) - state.headerInfo = state.dataSource.map((item) => { - return { isSelected: false, title: item.title, isUP: false } - }) - api.initValue({ props, emit }) - - if (props.type === 'list') { - state.dataSource.forEach((item, index) => { - const { flattenData, dataMap } = getFlatOptions(item.options) - item.options = flattenData - state.optionMap[index] = dataMap - }) - } - }) - } - -export const computedCurrentOptions = - ({ state, props }) => - () => { - const { options = [], multiple } = state.dataSource[state.headerIndex] || {} - const selectedValue = props.modelValue[state.headerIndex] - - options.forEach((item) => { - item.show = state.isSearching - ? item.label.includes(state.searchValue) - : (item.show ?? parent?.expanded) || item.level === 0 - - item.active = multiple ? selectedValue.includes(item.value) : item.value === selectedValue - }) - - return options.filter((i) => i.show) - } - -const getFlatOptions = (options) => { - const flattenData = [] - const dataMap = {} - const getChild = (data, level = 0, parent?) => { - data.forEach((item, index) => { - const id = parent ? parent.id + index : String(index) - const parentId = parent?.id || '' - const expanded = (parent?.expanded && item.children?.length && item.expanded) || false - const currentData = { ...item, id, level, expanded, parentId } - flattenData.push(currentData) - - if (item.children?.length) { - getChild(item.children, level + 1, currentData) - } - dataMap[currentData.id] = item - }) - } - - getChild(options) - - flattenData.forEach((item) => { - if (item.children) { - item.hasChild = item.children.length > 0 - delete item.children - } - }) - - return { flattenData, dataMap } -} - -export const handleClick = - ({ api, props, state }) => - (value) => { - if (props.disabled || props.dataSource[value].disabled) { - return - } - - if (props.type === 'wheel') { - state.wheelData = props.dataSource[value]?.options - } - - if (state.headerIndex === -1) { - // 首次点击 - state.showOptions = true - state.headerIndex = value - state.headerInfo[value] = getNewHeaderInfo(state.headerInfo, value, true) - state.defaultSelectedIndexs = state.defaultSelectedArray[value] ?? api.loadDefault(value) - } else if (state.headerIndex !== value) { - // 切换 - state.showOptions = true - state.headerInfo[state.headerIndex] = getNewHeaderInfo(state.headerInfo, state.headerIndex, false) // 上一个 - state.headerIndex = value - state.headerInfo[value] = getNewHeaderInfo(state.headerInfo, value, true) - state.defaultSelectedIndexs = state.defaultSelectedArray[value] ?? api.loadDefault(value) // 下一个 - } else { - // 收起与展开 - state.showOptions = !state.showOptions - const { isUP } = state.headerInfo[value] - state.headerInfo[value] = getNewHeaderInfo(state.headerInfo, value, !isUP) - } - } - -export const handleOptionSelect = - ({ api, state, emit }) => - (option) => { - api.updateValue(option.value) - emit('item-click', state.optionMap[state.headerIndex][option.id], state.headerIndex) - - if (!state.dataSource[state.headerIndex].multiple) { - api.handleClose() - } - } - -export const handleSearchInput = - ({ state, emit }) => - () => { - const { searchValue } = state - emit('update:searchValue', searchValue) - } - -const toggleChildExpand = (state, parentId, index) => { - const { options } = state.dataSource[state.headerIndex] - for (let i = index + 1; i < options.length; i++) { - if (options[i].parentId === parentId) { - options[i].show = !options[i].show - } else { - break - } - } -} - -export const toggleItemExpand = - ({ state }) => - (option) => { - const index = state.dataSource[state.headerIndex].options.findIndex((i) => i.id === option.id) - - if (index !== -1) { - const target = state.dataSource[state.headerIndex].options[index] - target.expanded = !target.expanded - toggleChildExpand(state, target.id, index) - } - } - -export const confirm = - ({ state, emit }) => - () => { - const wheelLevelItems = getWheelLevelItems(state.wheelData, state.defaultSelectedIndexs) - const { selectedLabels, selectedItems } = getSelected(wheelLevelItems, state.defaultSelectedIndexs) - state.headerInfo[state.headerIndex] = { isSelected: true, title: selectedLabels, isUP: false } - state.defaultSelectedArray[state.headerIndex] = state.defaultSelectedIndexs - emit('confirm', selectedItems, state.headerIndex, state.defaultSelectedIndexs) - state.showOptions = false - } - -export const reset = - ({ api, props, state, emit }) => - () => { - state.headerInfo[state.headerIndex] = { - isSelected: false, - title: props.dataSource[state.headerIndex].title || '', - isUP: false - } - state.defaultSelectedIndexs = props.defaultSelectedArray[state.headerIndex] ?? api.loadDefault(state.headerIndex) - state.defaultSelectedArray[state.headerIndex] = state.defaultSelectedIndexs - emit('reset', [], state.headerIndex, state.defaultSelectedIndexs) - state.showOptions = false - } - -export const handleClose = (state) => () => { - state.showOptions = false - if (state.headerIndex !== -1) { - state.headerInfo[state.headerIndex].isUP = false - } -} - -export const wheelChange = (state) => (indexs) => { - state.defaultSelectedIndexs = indexs -} - -export const clickWheelItem = - ({ state, emit }) => - (indexs, text, item) => { - if (indexs.length === 0) { - // 反选 - state.defaultSelectedIndexs = [-1] - state.headerInfo[state.headerIndex] = { isSelected: false, title: '', isUP: false } - } else { - state.defaultSelectedIndexs = indexs - state.headerInfo[state.headerIndex] = { isSelected: true, title: text, isUP: false } - } - state.defaultSelectedArray[state.headerIndex] = state.defaultSelectedIndexs - emit('confirm', item, state.headerIndex, indexs) - state.showOptions = false - } - -export const getWheelLevelItems = (wheelData, newIndexs) => { - const level_1 = wheelData - const level_n = getNextLevel([], wheelData, newIndexs, 0) - let wheelLevelItems = [] - if (level_n.length === 0) { - // 单列 - wheelLevelItems = [level_1] - } else { - // 多列 - wheelLevelItems = [level_1, ...level_n] - } - return wheelLevelItems -} - -export const getNextLevel = (levelItems, children, nextIndexs, start) => { - let levelItem = children[nextIndexs[start]]?.children ?? [] - if (start !== nextIndexs.length - 1) { - levelItems.push(levelItem) - return getNextLevel(levelItems, levelItem, nextIndexs, ++start) - } else { - return levelItems - } -} - -export const getSelected = (wheelLevelItems, selectedIndexs) => { - const selectedItems = [] - wheelLevelItems.forEach((levelItem, i) => { - const index = selectedIndexs[i] - if (levelItem[index]) { - selectedItems.push(levelItem[index]) - } - }) - const selectedLabels = selectedItems.map((item) => item?.label).join(' ') - return { selectedLabels, selectedItems } -} - -export const loadDefault = - ({ props, state }) => - (value) => { - const current = props.defaultSelectedArray[value] ?? [] - let defaultSelectedIndexs = [] - if (state.dataSource[state.headerIndex]?.hasFooter) { - // 有确认,重置按钮。此情况不可点击,可滚动,且初始化默认选中每列第一个 - const defaultL = current.length - const dataSL = getMaxFloor(state.wheelData) - if (defaultL <= dataSL) { - defaultSelectedIndexs = current.concat(new Array(dataSL - defaultL).fill(0)) - } else { - defaultSelectedIndexs = current.slice(0, dataSL) - } - } else { - // 无确认,重置按钮。此情况默认为单列,可点击,且初始化默认不选中 - defaultSelectedIndexs = current.length > 0 ? current : [-1] - } - return defaultSelectedIndexs - } - -export const getMaxFloor = (treeData) => { - let maxFloor = 0 - const loop = (data, level) => { - data.forEach((item) => { - item.level = level - if (level > maxFloor) { - maxFloor = level - } - if (item?.children?.length > 0) { - loop(item.children, level + 1) - } - }) - } - loop(treeData, 1) - return maxFloor -} - -export const getNewHeaderInfo = (headerInfo, index, isUP) => { - return { isSelected: headerInfo[index]?.isSelected, title: headerInfo[index]?.title, isUP } -} - -export const getLabelLevelsInfo = (refs) => { - const { headerBox, label } = refs - if (!headerBox || !label) return [] - const totalWidth = getRect(getEl(headerBox)).width - const labelWidth = label.map((node) => getRect(getEl(node))).map((rect) => rect.width) - return labelWidth.map((labelWidth, idx) => { - const isOver25 = totalWidth * 0.25 < labelWidth - return { - idx, - labelWidth, - totalWidth, - isOver25 - } - }) -} - -export const getRect = (el) => { - return { - top: el.offsetTop, - left: el.offsetLeft, - width: el.offsetWidth, - height: el.offsetHeight - } -} - -export const getEl = (node) => { - return node.$el || node -} - -export const getLabelsStyle = (state) => { - const len = state.dataSource.length - if (len === 1) { - return [ - { - flex: 1, - justifyContent: 'space-between' - } - ] - } - - const over25Labels = state.labelLevelsInfo.filter((i) => i && !i.isOver25) - - // 不超过总宽度25%的头部下拉项 - let widthInfo = over25Labels - if (len >= 4) { - return getStyleConfig(state.labelLevelsInfo, { width: `${((1 / len) * 100).toFixed(2)}%` }) - } - if (!widthInfo.length || widthInfo.length === state.labelLevelsInfo.length) { - // 所有下拉项同时不超过或者超过25%宽度 - return getStyleConfig(state.labelLevelsInfo, { maxWidth: `${((1 / len) * 100).toFixed(2)}%` }) - } - let fillArr - if (widthInfo.length === 1) { - // 一个不超出25% - fillArr = getFillArray(state, widthInfo, '37.5%') - } else if (widthInfo.length === 2) { - // 两个不超出25% - fillArr = getFillArray(state, widthInfo, '50%') - } - widthInfo = widthInfo.concat(fillArr) - return widthInfo.reduce((styles, item) => { - styles[item.idx] = item.maxWidth ? { maxWidth: item.maxWidth } : { maxWidth: '25%' } - return styles - }, {}) -} - -export const getStyleConfig = (data, style) => { - return data.reduce((styleConfig, _, idx) => { - styleConfig[idx] = style - return styleConfig - }, {}) -} - -export const getFillArray = (state, widthInfo, maxWidth) => { - // 头部下拉项索引集合 - const labelIndexArr = state.labelLevelsInfo.map((_, idx) => idx) - - // 头部下拉项宽度超过25%索引集合 - const mapWidthInfoArr = widthInfo.map((i) => i.idx) - return labelIndexArr - .filter((i) => !mapWidthInfoArr.includes(i)) - .map((i) => { - return { - idx: i, - maxWidth - } - }) -} - -export const handleSearchBtnClick = - ({ props, state, nextTick, vm }) => - () => { - if (props.disabled) { - return - } - - state.isSearching = !state.isSearching - nextTick(() => { - if (state.isSearching) { - vm.$refs.searchInput.focus() - } - }) - } diff --git a/packages/mobile/components/multi-select/src/renderless/vue.ts b/packages/mobile/components/multi-select/src/renderless/vue.ts deleted file mode 100644 index 39e20100a8..0000000000 --- a/packages/mobile/components/multi-select/src/renderless/vue.ts +++ /dev/null @@ -1,136 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - created, - initValue, - handleClick, - confirm, - reset, - wheelChange, - clickWheelItem, - loadDefault, - handleSearchBtnClick, - handleOptionSelect, - handleClose, - toggleItemExpand, - computedCurrentOptions, - updateValue, - handleSearchInput, - updateTitle -} from './index' - -export const api = [ - 'state', - 'created', - 'handleClick', - 'confirm', - 'reset', - 'wheelChange', - 'clickWheelItem', - 'loadDefault', - 'handleSearchBtnClick', - 'handleClose', - 'handleSearchInput' -] - -const initState = ({ emitter, reactive, computed, api, props }) => { - const state = reactive({ - dataSource: [], - wheelData: [], - isSearching: false, - headerIndex: -1, - showOptions: false, - labelLevelsInfo: [], - labelsStyle: [], - wheelIndex: [], - wheelText: '', - headerInfo: [], - defaultSelectedIndexs: [], - defaultSelectedArray: [], - multiSelectEmitter: emitter(), - searchValue: '', - optionMap: [], - currentOptions: computed(() => api.computedCurrentOptions()), - showMask: computed(() => props.mask && state.showOptions) - }) - - return state -} - -const initApi = ({ api, props, state, emit, nextTick, refs, vm }) => { - Object.assign(api, { - state, - created: created({ api, emit, props, state, refs, nextTick }), - initValue: initValue({ props, emit }), - handleClick: handleClick({ api, props, state }), - confirm: confirm({ state, emit }), - reset: reset({ api, props, state, emit }), - wheelChange: wheelChange(state), - clickWheelItem: clickWheelItem({ state, emit }), - loadDefault: loadDefault({ props, state }), - handleSearchBtnClick: handleSearchBtnClick({ props, state, nextTick, vm }), - handleOptionSelect: handleOptionSelect({ api, state, emit }), - handleClose: handleClose(state), - toggleItemExpand: toggleItemExpand({ state }), - computedCurrentOptions: computedCurrentOptions({ state, props }), - updateValue: updateValue({ state, props, emit }), - updateTitle: updateTitle({ props, state }), - handleSearchInput: handleSearchInput({ state, emit }) - }) -} - -const initWatch = ({ api, watch, props, state, refs, nextTick }) => { - watch( - () => props.dataSource, - () => { - api.created({ props, state, refs, nextTick }) - } - ) - watch( - () => props.defaultSelectedArray, - () => { - api.created({ props, state, refs, nextTick }) - } - ) - watch( - () => props.modelValue, - () => { - api.updateTitle() - }, - { deep: true } - ) -} - -export const renderless = ( - props, - { onMounted, reactive, watch, provide, computed }, - { emit, nextTick, refs, vm, emitter } -) => { - const api = {} - const state = initState({ emitter, reactive, computed, api, props }) - - provide('multiSelect', vm) - - initApi({ api, props, state, emit, nextTick, refs, vm }) - - initWatch({ api, watch, props, state, refs, nextTick }) - - onMounted(() => { - api.created({ props, state, refs, nextTick }) - }) - - state.multiSelectEmitter.on('multiSelectItemClick', api.handleOptionSelect) - state.multiSelectEmitter.on('toggleItemExpand', api.toggleItemExpand) - - return api -} diff --git a/packages/mobile/components/nav-bar/index.ts b/packages/mobile/components/nav-bar/index.ts deleted file mode 100644 index 2a06431588..0000000000 --- a/packages/mobile/components/nav-bar/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import NavBar from './src/mobile.vue' -import '@opentiny/vue-theme-mobile/nav-bar/index.less' - -/* istanbul ignore next */ -NavBar.install = function (Vue) { - Vue.component(NavBar.name, NavBar) -} - -export default NavBar diff --git a/packages/mobile/components/nav-bar/src/mobile.vue b/packages/mobile/components/nav-bar/src/mobile.vue deleted file mode 100644 index 61cc694e6d..0000000000 --- a/packages/mobile/components/nav-bar/src/mobile.vue +++ /dev/null @@ -1,91 +0,0 @@ - - diff --git a/packages/mobile/components/numeric/index.ts b/packages/mobile/components/numeric/index.ts deleted file mode 100644 index 2aad67bd7f..0000000000 --- a/packages/mobile/components/numeric/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Numeric from './src/mobile.vue' - -/* istanbul ignore next */ -Numeric.install = function (Vue) { - Vue.component(Numeric.name, Numeric) -} - -export default Numeric diff --git a/packages/mobile/components/numeric/src/mobile.vue b/packages/mobile/components/numeric/src/mobile.vue deleted file mode 100644 index e9ee94eb1e..0000000000 --- a/packages/mobile/components/numeric/src/mobile.vue +++ /dev/null @@ -1,96 +0,0 @@ - - - - diff --git a/packages/mobile/components/numeric/src/numeric.ts b/packages/mobile/components/numeric/src/numeric.ts deleted file mode 100644 index 1b83913b28..0000000000 --- a/packages/mobile/components/numeric/src/numeric.ts +++ /dev/null @@ -1,283 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ExtractPropTypes } from 'vue' -import type { BigIntDecimal } from '@mobile-root/utils/bigInt' -import type { - focus, - select, - getPrecision, - toPrecision, - updated, - mounted, - unmounted, - getDecimal, - handleFocus, - decrease, - increase, - handleInput, - getNumPecision, - displayValue, - internalDecrease, - internalIncrease, - handleInputChange, - mouseEvent, - handleBlur, - watchValue, - setCurrentValue, - dispatchDisplayedValue, - getDisplayedValue, - initService, - getDisplayOnlyText, - filterValue, - handleClear, - handleChange -} from './renderless' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const $constants = { - MAX: 'aria-valuemax', - MIN: 'aria-valuemin', - VALUENOW: 'aria-valuenow', - DISABLED: 'aria-disabled', - KEY: 'role', - VALUE: 'spinbutton', - EVENT_NAME: { - blur: 'form.blur', - change: 'form.change' - }, - COMPONENT_NAME: 'FormItem', - FILTER_OPTION: [ - 'ui.numeric.equalTo', - 'ui.numeric.notEqualTo', - 'ui.numeric.moreThan', - 'ui.numeric.moreThanOrEqualTo', - 'ui.numeric.lessThan', - 'ui.numeric.lessThanOrEqualTo', - 'ui.numeric.empty', - 'ui.numeric.nonEmpty' - ] -} - -export const numericProps = { - _constants: { - type: Object, - default: () => $constants - }, - allowEmpty: { - type: Boolean, - default: false - }, - circulate: Boolean, - controls: { - type: Boolean, - default: true - }, - controlsPosition: { - type: String, - default: '' - }, - disabled: Boolean, - format: [Object, String], - hideUnit: { - type: Boolean, - default: false - }, - holdZero: { - type: Boolean, - default: true - }, - label: String, - max: { - type: [Number, String], - default: Infinity - }, - min: { - type: [Number, String], - default: -Infinity - }, - modelTruncation: { - type: Boolean, - default: true - }, - modelValue: [Number, String, undefined], - mouseWheel: Boolean, - name: String, - placeholder: String, - plugin: Function, - precision: { - type: Number, - validator(val) { - return val >= 0 && val === parseInt(val, 10) - } - }, - size: String, - step: { - type: [Number, String], - default: 1 - }, - stepStrictly: { - type: Boolean, - default: false - }, - strictInput: { - type: Boolean, - default: false - }, - stringMode: Boolean, - tabindex: { - type: String, - default: '1' - }, - theme: { - type: String, - default: '' - }, - unit: String, - unitCenter: { - type: Boolean, - default: false - }, - validateEvent: { - type: Boolean, - default: true - }, - displayOnly: { - type: Boolean, - default: false - }, - showLeft: { - type: Boolean, - default: false - }, - showEmptyValue: { - type: Boolean, - default: false - }, - title: { - type: String, - default: '' - }, - tip: String, - shape: String, - clearable: { - type: Boolean, - default: true - }, - filter: { - type: Boolean, - default: true - }, - blank: { - type: Boolean, - default: true - }, - changeCompat: { - type: Boolean, - default: false - } -} - -export type INumericProps = ExtractPropTypes - -export type INumericConstants = typeof $constants - -export interface INumericState { - radioVal: string - currentValue: number | string - userInput: number | string - lastInput: number | string - inputStatus: boolean - decimal: BigIntDecimal - strictInput: boolean - inputSize: INumericSize - formSize: string - formDisabled: boolean - inputDisabled: boolean - displayValue: number | string - numPrecision: number - minDisabled: boolean - maxDisabled: boolean - controlsAtRight: boolean - format: INumericUnitPrecision - isDisplayOnly: boolean -} - -export interface INumericApi { - focus: ReturnType - select: ReturnType - getPrecision: ReturnType - toPrecision: ReturnType - updated: ReturnType - mounted: ReturnType - unmounted: ReturnType - getDecimal: ReturnType - handleFocus: ReturnType - decrease: ReturnType - increase: ReturnType - handleInput: ReturnType - getNumPecision: ReturnType - displayValue: ReturnType - internalDecrease: ReturnType - internalIncrease: ReturnType - handleInputChange: ReturnType - mouseEvent: ReturnType - handleBlur: ReturnType - watchValue: ReturnType - setCurrentValue: ReturnType - dispatchDisplayedValue: ReturnType - getDisplayedValue: ReturnType - getDisplayOnlyText: ReturnType - filterValue: ReturnType - handleClear: ReturnType - handleChange: ReturnType -} - -export type INumericRenderlessParams = ISharedRenderlessFunctionParams & { - api: INumericApi - state: INumericState - props: INumericProps -} - -export type INumericRenderlessParamUtils = ISharedRenderlessParamUtils - -export type INumericSize = 'medium' | 'small' | 'mini' - -export interface INumericUnitPrecision { - decimalSeparator: string - groupSeparator: string - fraction?: string - rounding?: string - zeroize: boolean -} - -export interface INumericInitStateParams - extends Pick { - $service: ReturnType -} - -export interface INumericGetEmitValueParams { - newVal: number - emitValue: number | string | undefined - allowEmpty: boolean - defaultVal: number - bigNew: BigIntDecimal - oldVal: number - max: number - min: number - api: INumericApi - props: INumericProps - format: INumericState['format'] - plugin: INumericProps['plugin'] - stringMode: boolean -} diff --git a/packages/mobile/components/numeric/src/renderless/index.ts b/packages/mobile/components/numeric/src/renderless/index.ts deleted file mode 100644 index 9d3c00cd18..0000000000 --- a/packages/mobile/components/numeric/src/renderless/index.ts +++ /dev/null @@ -1,534 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { - INumericProps, - INumericState, - INumericRenderlessParamUtils, - INumericRenderlessParams, - INumericGetEmitValueParams, - INumericUnitPrecision -} from '../numeric' -import type { BigIntDecimal } from '@mobile-root/utils/bigInt' -import { formatNumber, roundFixed } from '@mobile-root/utils/decimal' -import { getMiniDecimal, lessEquals, equalsDecimal } from '@mobile-root/utils/bigInt' -import { isNumber, isNull } from '@mobile-root/utils/type' -import { MOUSEDELTA } from '@mobile-root/utils' -import { on, off } from '@mobile-root/utils/deps/dom' - -export const initService = ( - service: INumericRenderlessParamUtils['service'] -): { - getUnitPrecision: Function - getNumberFormat: Function -} => { - const { utils = {} } = service || {} - const noopFn = () => null - - return { - getUnitPrecision: utils.getUnitPrecision || noopFn, - getNumberFormat: utils.getNumberFormat || noopFn - } -} - -export const getDecimal = - (props: INumericProps) => - (value: number): BigIntDecimal => - getMiniDecimal(value, props.plugin) - -export const watchValue = - ({ api, props, state, nextTick }: Pick) => - (value: number): void => { - if (value === state.currentValue) { - return - } - api.setCurrentValue(value, props.changeCompat) - nextTick(() => { - api.dispatchDisplayedValue() - }) - } - -export const toPrecision = - (state: INumericState) => - ({ num, precision }: { num: number; precision: number }) => { - if (precision === undefined) { - precision = state.numPrecision - } - - return parseFloat(Math.round(num * 10 ** precision) / 10 ** precision) - } - -export const getPrecision = - () => - (value: number): number => { - if (value === undefined) { - return 0 - } - - const valueString = value.toString() - const dotPosition = valueString.indexOf('.') - let precision = 0 - - if (dotPosition !== -1) { - precision = valueString.length - dotPosition - 1 - } - - return precision - } - -export const internalIncrease = - ({ api, state }: Pick) => - ({ val, step }: { val: number; step: number }): string => { - const decimal = api.getDecimal(val) - - if (decimal.isNaN() && val !== undefined) { - return state.currentValue - } - - return decimal.add(step).toString() - } - -export const internalDecrease = - ({ api, state }: Pick) => - ({ val, step }: { val: number; step: number }): string | number => { - const decimal = api.getDecimal(val) - - if (decimal.isNaN() && val !== undefined) { - return state.currentValue - } - - return decimal.add(`-${step}`).toString() - } - -export const increase = - ({ api, props, state }: Pick) => - (): void => { - if (state.inputDisabled || state.maxDisabled) { - return - } - - // 处理高精度情况 - const userInput = props.stringMode ? state.userInput : Number(state.userInput) - - const value = (props.mouseWheel ? state.displayValue : userInput) || 0 - - if (value.toString().includes('e')) { - return - } - - let newVal = api.internalIncrease({ val: value, step: props.step }) - - if (!props.circulate || !isFinite(props.max) || !isFinite(props.min)) { - api.setCurrentValue(newVal) - return - } - - if (!lessEquals(newVal, props.max) || lessEquals(newVal, props.min)) { - newVal = props.min - } - - api.setCurrentValue(newVal) - } - -export const decrease = - ({ api, props, state }: Pick) => - (): void => { - if (state.inputDisabled || state.minDisabled) { - return - } - - // 处理高精度情况 - const userInput = props.stringMode ? state.userInput : Number(state.userInput) - - const value = (props.mouseWheel ? state.displayValue : userInput) || 0 - - if (value.toString().includes('e')) { - return - } - - let newVal = api.internalDecrease({ val: value, step: props.step }) - - if (!props.circulate || !isFinite(props.max) || !isFinite(props.min)) { - api.setCurrentValue(newVal) - return - } - - if (!lessEquals(props.min, newVal) || lessEquals(props.max, newVal)) { - newVal = props.max - } - - api.setCurrentValue(newVal) - } - -export const handleBlur = - ({ - constants, - dispatch, - emit, - props, - state, - api - }: Pick) => - (event: FocusEvent): void => { - state.inputStatus = false - api.setCurrentValue(event.target.value) - emit('blur', event) - - if (props.validateEvent) { - dispatch(constants.COMPONENT_NAME, constants.EVENT_NAME.blur, [state.displayValue]) - } - } - -export const handleFocus = - ({ emit, state, props, api, vm }: Pick) => - (event: FocusEvent): void => { - if (props.disabled) { - vm.$refs.input.blur() - } - - state.inputStatus = true - - const currentValue = api.getDecimal(state.currentValue) - - if (!currentValue.isNaN() && !isNull(state.currentValue)) { - const fractionLen = (currentValue.toString().split('.')[1] || '').length - - if (fractionLen < state.format.fraction && props.holdZero) { - state.currentValue = formatNumber(state.currentValue, { - fraction: state.format.fraction - }) - state.userInput = state.currentValue - state.lastInput = state.currentValue - } - } - - emit('focus', event) - } - -export const focus = (vm: INumericRenderlessParams['vm']) => (): void => { - vm.$refs.input.focus() -} - -const getEmitValue = ( - args: INumericGetEmitValueParams -): { newVal: number | string | undefined; emitValue: number | string | undefined } => { - let { newVal, emitValue, allowEmpty, defaultVal, bigNew, oldVal } = args - let { max, min, api, props, format, plugin, stringMode } = args - if (!newVal && newVal !== 0) { - emitValue = allowEmpty ? undefined : defaultVal - } else if (bigNew.isNaN()) { - emitValue = oldVal - } else { - if (isFinite(max) && lessEquals(max, newVal)) { - newVal = max - } - - if (isFinite(min) && lessEquals(newVal, min)) { - newVal = min - } - - emitValue = api.getDecimal(newVal).toString() - - if (props.modelTruncation) { - emitValue = roundFixed(emitValue, format.fraction, format.rounding, plugin) - } - - if (!props.holdZero) { - emitValue = api.getDecimal(emitValue).toString() - } - - if (!stringMode) { - emitValue = Number(emitValue) - } - } - - return { newVal, emitValue } -} - -export const setCurrentValue = - ({ - api, - constants, - dispatch, - emit, - props, - state - }: Pick) => - (newVal: number, emitChangeFlag: boolean = true): void => { - const { max, min, allowEmpty, validateEvent, stringMode, plugin } = props - const { format } = state - const oldVal = state.currentValue - const bigNew = api.getDecimal(newVal) - const defaultVal = isFinite(min) ? min : 0 - - let emitValue = bigNew.toString() - - if (equalsDecimal(state.currentValue, newVal)) { - state.userInput = state.currentValue - return - } - - let args = { newVal, emitValue, allowEmpty, defaultVal, bigNew, oldVal } - - Object.assign(args, { max, min, api, props, format, plugin, stringMode }) - - let ret = getEmitValue(args) - - newVal = ret.newVal - emitValue = ret.emitValue - - state.userInput = emitValue - state.lastInput = emitValue - - if (emitValue !== oldVal) { - emit('update:modelValue', emitValue) - if (emitChangeFlag) { - emit('change', emitValue, oldVal) - } - - state.currentValue = emitValue - state.userInput = emitValue - - if (validateEvent && oldVal === '') { - dispatch(constants.COMPONENT_NAME, constants.EVENT_NAME.blur, [state.currentValue]) - } - - if (validateEvent) { - dispatch(constants.COMPONENT_NAME, constants.EVENT_NAME.change, [state.currentValue]) - } - } - } - -export const handleInput = - ({ state, api, emit, props }: Pick) => - (event: InputEvent): void => { - const { fraction } = state.format - const emitError = () => { - if (state.pasting) { - emit('paste-error', event.target.value) - } - } - let value = event.target.value.replace(/^-+/, '-') - - if (value !== '-' && api.getDecimal(value).isNaN()) { - emitError() - - if (!(value === '' && props.allowEmpty)) { - value = !value.includes('e') ? state.lastInput : value - } - } else { - value = value - .split('.') - .map((a, i) => { - if (i && a.length > fraction) { - emitError() - } - - return i && state.strictInput && typeof fraction === 'number' ? a.substr(0, fraction) : a - }) - .join('.') - } - - event.target.value = isNull(value) ? '' : value - state.lastInput = value - state.userInput = value - } - -export const handleInputChange = - ({ api, state, props }: Pick) => - (event: Event): void => { - const value = event.target?.value === '-' ? 0 : event.target?.value - if (props.stepStrictly) { - const previousValue = Number((props.mouseWheel ? state.displayValue : props.modelValue) || 0) - if (Math.abs(previousValue - value) % Number(props.step) === 0) return api.setCurrentValue(value) - const step = Number(props.step) - const difference = value - previousValue - const sign = difference >= 0 ? 1 : -1 - return api.setCurrentValue(sign * Math.round(Math.abs(difference) / step) * step + previousValue) - } - api.setCurrentValue(value) - } - -export const select = (vm: INumericRenderlessParams['vm']) => () => vm.$refs.input.select() - -export const mounted = - ({ constants, parent, props, state }: Pick) => - (): void => { - if (props.shape === 'filter') { - state.controls = false - } - - if (isNumber(state.currentValue) && state.currentValue < (props.min as number)) { - state.currentValue = props.min as number - state.lastInput = props.min as number - state.userInput = props.min as number - } - if (isNumber(state.currentValue) && state.currentValue > (props.max as number)) { - state.currentValue = props.max as number - state.lastInput = props.max as number - state.userInput = props.max as number - } - - const innerInput = parent.$el.querySelector('input') - - innerInput.setAttribute(constants.KEY, constants.VALUE) - innerInput.setAttribute(constants.MAX, props.max) - innerInput.setAttribute(constants.MIN, props.min) - innerInput.setAttribute(constants.VALUENOW, state.currentValue) - innerInput.setAttribute(constants.DISABLED, state.inputDisabled) - - state.onPase = () => { - state.pasting = true - setTimeout(() => (state.pasting = false)) - } - - on(innerInput, 'paste', state.onPase) - } - -export const unmounted = - ({ parent, state }: Pick) => - (): void => { - const innerInput = parent.$el.querySelector('input') - - off(innerInput, 'paste', state.onPase) - } - -export const updated = - ({ constants, parent, state }: Pick) => - (): void => { - const innerInput = parent.$el.querySelector('input') - - innerInput && innerInput.setAttribute(constants.VALUENOW, state.currentValue) - } - -export const displayValue = - ({ props, state, api }: Pick) => - (): string | number => { - const { currentValue, inputStatus, userInput } = state - - if (props.shape === 'filter' && props.filter) { - api.filterValue() - } - - if (inputStatus) { - return userInput - } - - if (props.allowEmpty && currentValue === '') { - return '' - } - - return formatNumber(currentValue, state.format) - } - -export const getNumPecision = - ({ api, props }: Pick) => - (): number => { - const stepPrecision = api.getPrecision(props.step) - - if (props.precision !== undefined) { - return props.precision - } else { - return Math.max(api.getPrecision(props.modelValue), stepPrecision) - } - } - -export const mouseEvent = - ({ api, props, state }: Pick) => - (event: MouseEvent): void | boolean => { - if (props.mouseWheel && state.inputStatus) { - let delta = 0 - - if (event.wheelDelta) { - delta = event.wheelDelta / MOUSEDELTA - } - - delta > 0 ? api.increase() : api.decrease() - - return false - } - } - -export const getUnitPrecision = ({ - service, - props -}: Pick): INumericUnitPrecision => { - let fraction, rounding - const { format = {}, precision, unit } = props - const defaultFmt = { - groupSeparator: '', - decimalSeparator: '.', - zeroize: props.holdZero - } - - const { getUnitPrecision, getNumberFormat } = service - const serFra = getUnitPrecision(unit) || {} - const serFmt = getNumberFormat() || {} - - fraction = isNumber(precision) ? precision : isNumber(format.fraction) ? format.fraction : serFra.fraction - rounding = isNumber(format.rounding) ? format.rounding : serFra.rounding - - return { ...defaultFmt, fraction, rounding, ...serFmt, ...format } -} - -export const dispatchDisplayedValue = - ({ state, api, dispatch }: Pick) => - (): void => { - if (state.isDisplayOnly) { - dispatch('FormItem', 'displayed-value-changed', { type: 'numeric', val: api.getDisplayedValue() }) - } - } - -export const getDisplayedValue = - ({ state, props }: Pick) => - (): string => { - return state.displayValue || state.displayValue === 0 ? state.displayValue + ' ' + (props.unit || '') : '-' - } - -export const getDisplayOnlyText = - ({ parent, state, props }: Pick) => - (): string | number => { - const showEmptyValue = props.showEmptyValue || (parent.tinyForm || {}).showEmptyValue - - if (showEmptyValue) { - return state.displayValue - } else { - if (state.displayValue || state.displayValue === 0) { - return state.displayValue - } else { - return '-' - } - } - } - -export const filterValue = - ({ state }: Pick) => - (): number | string => { - return (state.radioVal || '') + state.lastInput - } - -export const handleClear = - ({ state, emit }: Pick) => - () => { - state.currentValue = '' - state.userInput = '' - state.lastInput = '' - state.radioVal = '' - - emit('clear') - } - -export const handleChange = - ({ state, emit }: Pick) => - () => { - emit('filter-change', state.radioVal) - } diff --git a/packages/mobile/components/numeric/src/renderless/vue.ts b/packages/mobile/components/numeric/src/renderless/vue.ts deleted file mode 100644 index 521e2e04ee..0000000000 --- a/packages/mobile/components/numeric/src/renderless/vue.ts +++ /dev/null @@ -1,203 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { - INumericApi, - INumericProps, - INumericState, - ISharedRenderlessParamHooks, - INumericRenderlessParamUtils, - INumericRenderlessParams, - INumericInitStateParams -} from '../numeric' -import { - watchValue, - toPrecision, - getPrecision, - internalIncrease, - internalDecrease, - focus, - decrease, - handleBlur, - handleFocus, - setCurrentValue, - handleInput, - handleInputChange, - select, - mounted, - updated, - increase, - displayValue, - getNumPecision, - mouseEvent, - getUnitPrecision, - getDecimal, - unmounted, - initService, - dispatchDisplayedValue, - getDisplayedValue, - getDisplayOnlyText, - filterValue, - handleClear, - handleChange -} from './index' - -export const api = [ - 'state', - 'decrease', - 'increase', - 'handleBlur', - 'handleFocus', - 'handleInput', - 'handleInputChange', - 'mouseEvent', - 'focus', - 'select', - 'handleClear', - 'handleChange' -] - -const initState = ({ - reactive, - computed, - props, - api, - $service, - constants, - parent -}: INumericInitStateParams): INumericState => { - const state = reactive({ - currentValue: props.modelValue, - userInput: props.modelValue, - lastInput: props.modelValue, - inputStatus: false, - decimal: null, - strictInput: computed(() => props.strictInput), - inputSize: computed(() => props.size || state.formSize), - formSize: computed(() => (parent.tinyForm || {}).size), - formDisabled: computed(() => (parent.tinyForm || {}).disabled), - inputDisabled: computed(() => props.disabled || state.formDisabled), - displayValue: computed(() => api.displayValue()), - numPrecision: computed(() => api.getNumPecision()), - - minDisabled: computed(() => (!props.circulate && state.currentValue <= props.min) || state.formDisabled), - - maxDisabled: computed(() => (!props.circulate && state.currentValue >= props.max) || state.formDisabled), - - controlsAtRight: computed(() => props.controls && props.controlsPosition === 'right'), - - format: computed(() => getUnitPrecision({ service: $service, props })), - - filterMenu: constants.FILTER_OPTION, - filterValue: computed(() => api.filterValue()), - - handleClear: computed(() => api.handleClear()), - handleChange: computed(() => api.handleClear()), - isDisplayOnly: computed(() => props.displayOnly || (parent.tinyForm || {}).displayOnly), - displayOnlyText: computed(() => api.getDisplayOnlyText()), - controls: props.controls - }) - return state -} - -const initApi = ({ - api, - props, - state, - parent, - vm, - emit, - dispatch, - constants, - nextTick -}: Pick< - INumericRenderlessParams, - 'api' | 'props' | 'state' | 'parent' | 'vm' | 'emit' | 'dispatch' | 'constants' | 'nextTick' ->): void => { - Object.assign(api, { - state, - focus: focus(vm), - select: select(vm), - getPrecision: getPrecision(), - toPrecision: toPrecision(state), - updated: updated({ constants, parent, state }), - mounted: mounted({ constants, parent, props, state }), - unmounted: unmounted({ parent, state }), - getDecimal: getDecimal(props), - handleFocus: handleFocus({ emit, state, props, api, vm }), - decrease: decrease({ api, props, state }), - increase: increase({ api, props, state }), - handleInput: handleInput({ state, api, emit, props }), - getNumPecision: getNumPecision({ api, props }), - displayValue: displayValue({ props, state, api }), - internalDecrease: internalDecrease({ api, state }), - internalIncrease: internalIncrease({ api, state }), - handleInputChange: handleInputChange({ api, state, props }), - mouseEvent: mouseEvent({ api, props, state }), - handleBlur: handleBlur({ constants, dispatch, emit, props, state, api }), - watchValue: watchValue({ api, props, state, nextTick }), - setCurrentValue: setCurrentValue({ api, constants, dispatch, emit, props, state }), - dispatchDisplayedValue: dispatchDisplayedValue({ api, state, dispatch }), - getDisplayedValue: getDisplayedValue({ state, props }), - getDisplayOnlyText: getDisplayOnlyText({ parent, props, state }), - filterValue: filterValue({ state }), - handleClear: handleClear({ state, emit }), - handleChange: handleChange({ state, emit }) - }) - - api.getDecimal(0) -} - -const initWatch = ({ - state, - watch, - props, - api -}: Pick): void => { - watch( - () => [props.max, props.min], - ([curMax, curMin]) => { - if (curMax < curMin) { - throw new Error('[Numeric]: The maximum value should not be less than to the minimum value') - } - }, - { immediate: true } - ) - - watch(() => props.modelValue, api.watchValue, { immediate: true }) - - watch(() => state.isDisplayOnly, api.dispatchDisplayedValue) -} - -export const renderless = ( - props: INumericProps, - { computed, onMounted, onUpdated, onUnmounted, reactive, watch, inject }: ISharedRenderlessParamHooks, - { parent, emit, vm, constants, dispatch, service, nextTick }: INumericRenderlessParamUtils -): INumericApi => { - const api = {} as INumericApi - const $service = initService(service) - const state = initState({ reactive, computed, props, api, constants, $service, parent }) - - parent.tinyForm = parent.tinyForm || inject('form', null) - - initApi({ api, props, state, parent, vm, emit, dispatch, constants, nextTick }) - initWatch({ state, watch, props, api }) - - onMounted(() => { - api.dispatchDisplayedValue() - api.mounted() - }) - onUpdated(api.updated) - onUnmounted(api.unmounted) - - return api -} diff --git a/packages/mobile/components/picker-column/index.ts b/packages/mobile/components/picker-column/index.ts deleted file mode 100644 index a90b067c49..0000000000 --- a/packages/mobile/components/picker-column/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import PickerColumn from './src/mobile.vue' - -/* istanbul ignore next */ -PickerColumn.install = function (Vue) { - Vue.component(PickerColumn.name, PickerColumn) -} - -export default PickerColumn diff --git a/packages/mobile/components/picker-column/src/mobile.vue b/packages/mobile/components/picker-column/src/mobile.vue deleted file mode 100644 index 27efb2eb8d..0000000000 --- a/packages/mobile/components/picker-column/src/mobile.vue +++ /dev/null @@ -1,57 +0,0 @@ - - - - diff --git a/packages/mobile/components/picker-column/src/renderless/index.ts b/packages/mobile/components/picker-column/src/renderless/index.ts deleted file mode 100644 index 3b160767bc..0000000000 --- a/packages/mobile/components/picker-column/src/renderless/index.ts +++ /dev/null @@ -1,294 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { on, off } from '@mobile-root/utils/deps/dom' - -export const computedWrapperStyle = (state) => () => { - const wrapperStyle = { - transform: `translate3d(0, ${state.offset + state.baseOffset}px, 0)`, - transitionDuration: `${state.duration}ms`, - transitionProperty: state.duration ? 'all' : 'none', - lineHeight: `${state.itemHeight}px` - } - - return wrapperStyle -} - -export const computedBaseOffset = - ({ state, props }) => - () => - (state.itemHeight * (props.visibleItemCount - 1)) / 2 - -export const onClickItem = - ({ api, state }) => - (index) => { - if (state.moving) { - return - } - - state.duration = state.defaultDuration - api.setIndex(index, true) - } - -export const setIndex = - ({ api, state, emit }) => - (index, emitChange) => { - index = api.adjustIndex(index) || 0 - - const offset = -index * state.itemHeight - - const trigger = () => { - if (index !== state.currentIndex) { - state.currentIndex = index - - if (emitChange) { - emit('change', index) - } - } - } - - if (state.moving && offset !== state.offset) { - state.transitionEndTrigger = trigger - } - - trigger() - state.offset = offset - } - -const range = (num, min, max) => Math.min(Math.max(num, min), max) - -const isOptionDisabled = (option) => option !== null && typeof option === 'object' && option.disabled - -export const adjustIndex = (state) => (index) => { - index = range(index, 0, state.count) - - for (let i = index; i < state.count; i++) { - if (!isOptionDisabled(state.columnsItem.values[i])) { - return i - } - } - - for (let i = index - 1; i >= 0; i--) { - if (!isOptionDisabled(state.columnsItem.values[i])) { - return i - } - } -} - -export const onTouchstart = - ({ vm, state }) => - (event) => { - state.direction = '' - state.deltaX = 0 - state.deltaY = 0 - state.offsetX = 0 - state.offsetY = 0 - state.startX = event.touches[0].clientX - state.startY = event.touches[0].clientY - - if (state.moving) { - const style = window.getComputedStyle(vm.$refs.track) - const transform = style.transform || style.webkitTransform - const translateY = Number(transform.slice(7, transform.length - 1).split(', ')[5]) - - state.offset = Math.min(0, translateY - state.baseOffset) - state.startOffset = state.offset - } else { - state.startOffset = state.offset - } - - state.duration = 0 - state.transitionEndTrigger = null - state.touchStartTime = Date.now() - state.momentumOffset = state.startOffset - } - -const getDirection = (x, y) => { - const MIN_DISTANCE = 10 - - if (x > y && x > MIN_DISTANCE) { - return 'horizontal' - } - - if (y > x && y > MIN_DISTANCE) { - return 'vertical' - } - - return '' -} - -export const onTouchmove = - ({ state }) => - (event) => { - const touch = event.touches[0] - - state.deltaX = touch.clientX - state.startX - state.deltaY = touch.clientY - state.startY - state.offsetX = Math.abs(state.deltaX) - state.offsetY = Math.abs(state.deltaY) - state.direction = state.direction || getDirection(state.offsetX, state.offsetY) - - if (state.direction === 'vertical') { - state.moving = true - } - - state.offset = range(state.startOffset + state.deltaY, -(state.count * state.itemHeight), state.itemHeight) - - const now = Date.now() - - if (now - state.touchStartTime > state.momentumLimitTime) { - state.touchStartTime = now - state.momentumOffset = state.offset - } - } - -export const onTouchend = - ({ api, state }) => - () => { - const distance = state.offset - state.momentumOffset - const duration = Date.now() - state.touchStartTime - const allowMomentum = duration < state.momentumLimitTime && Math.abs(distance) > state.momentumLimitDistance - - if (allowMomentum) { - api.momentum(distance, duration) - return - } - - const index = range(Math.round(-state.offset / state.itemHeight), 0, state.count - 1) - - state.duration = state.defaultDuration - api.setIndex(index, true) - - setTimeout(() => { - state.moving = false - }, 0) - } - -export const mountedHandler = - ({ api, vm, state }) => - () => { - const track = vm.$refs.track - - on(track, 'touchstart', api.onTouchstart) - on(track, 'touchmove', api.onTouchmove) - on(track, 'touchend', api.onTouchend) - - state.clumnsWrapHeight = state.itemHeight * state.visibleItemCount - - state.maskStyle = { - backgroundSize: `100% ${(state.clumnsWrapHeight - state.itemHeight) / 2}px` - } - } - -export const beforeUnmountHandler = - ({ api, vm }) => - () => { - const track = vm.$refs.track - - off(track, 'touchstart', api.onTouchstart) - off(track, 'touchmove', api.onTouchmove) - off(track, 'touchend', api.onTouchend) - } - -export const momentum = - ({ api, state, props }) => - (distance, duration) => { - const speed = Math.abs(distance / duration) - - distance = state.offset + (speed / 0.002) * (distance < 0 ? -1 : 1) - - const index = range(Math.round(-distance / state.itemHeight), 0, state.count - 1) - - state.duration = Number(props.swipeDuration) - api.setIndex(index, true) - } - -export const onTransitionEnd = (state) => () => { - state.moving = false - state.duration = 0 - - if (state.transitionEndTrigger) { - state.transitionEndTrigger() - state.transitionEndTrigger = null - } -} - -export const setValue = - ({ api, state }) => - (value) => { - const { columnsItem } = state - const values = columnsItem.values - - for (let i = 0; i < values.length; i++) { - if (api.getOptionText(values[i]) === value) { - return api.setIndex(i) - } - } - } - -export const getOptionText = - ({ state, props }) => - (option) => { - if (option !== null && typeof option === 'object' && props.valueKey in option) { - return option[state.valueKey] - } - - return option - } - -export const getValue = (state) => () => state.columnsItem.values[state.currentIndex] - -let deepAssign - -const assignKey = (to, from, key) => { - const { hasOwnProperty } = Object.prototype - const val = from[key] - - if (val === undefined || val === null) { - return - } - - if (!hasOwnProperty.call(to, key) || typeof val !== 'object') { - to[key] = val - } else { - to[key] = deepAssign(Object(to[key]), from[key]) - } -} - -deepAssign = (to, from) => { - Object.keys(from).forEach((key) => { - assignKey(to, from, key) - }) - - return to -} - -export const deepClone = (obj) => { - if (Array.isArray(obj)) { - return obj.map((item) => deepClone(item)) - } - - if (typeof obj === 'object' && obj !== null) { - return deepAssign({}, obj) - } - - return obj -} - -export const setOptions = - ({ api, state, props }) => - (options) => { - if (JSON.stringify(options) !== JSON.stringify(state.columnsItem.values)) { - state.columnsItem.values = deepClone(options) - api.setIndex(props.defaultIndex) - } - } diff --git a/packages/mobile/components/picker-column/src/renderless/vue.ts b/packages/mobile/components/picker-column/src/renderless/vue.ts deleted file mode 100644 index 47794dcb1a..0000000000 --- a/packages/mobile/components/picker-column/src/renderless/vue.ts +++ /dev/null @@ -1,124 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - computedWrapperStyle, - computedBaseOffset, - onClickItem, - setIndex, - adjustIndex, - mountedHandler, - momentum, - onTransitionEnd, - getOptionText, - setValue, - getValue, - setOptions, - deepClone, - beforeUnmountHandler, - onTouchstart, - onTouchmove, - onTouchend -} from './index' - -export const api = ['state', 'onClickItem', 'onTransitionEnd', 'setValue', 'getValue', 'setOptions', 'setIndex'] - -const initState = ({ reactive, computed, props, api }) => { - const state = reactive({ - columnsItem: props.columnsItem, - columnsItemArr: props.columnsItem.values, - currentIndex: props.defaultIndex, - itemHeight: props.itemHeight, - visibleItemCount: props.visibleItemCount, - offset: 0, - duration: 0, - startOffset: 0, - moving: false, - defaultDuration: 200, - momentumLimitTime: 300, - momentumLimitDistance: 15, - touchStartTime: null, - momentumOffset: 0, - direction: '', - deltaX: 0, - deltaY: 0, - offsetX: 0, - offsetY: 0, - count: props.columnsItem.values.length, - transitionEndTrigger: null, - clumnsWrapHeight: null, - maskStyle: null, - wrapperStyle: computed(() => api.computedWrapperStyle()), - baseOffset: computed(() => api.computedBaseOffset()) - }) - - return state -} - -const initApi = ({ api, props, state, vm, emit }) => { - Object.assign(api, { - state, - getValue: getValue(state), - adjustIndex: adjustIndex(state), - onTouchmove: onTouchmove({ state }), - onTouchstart: onTouchstart({ state }), - getOptionText: getOptionText({ state, props }), - onTransitionEnd: onTransitionEnd(state), - computedBaseOffset: computedBaseOffset({ state, props }), - computedWrapperStyle: computedWrapperStyle(state), - setValue: setValue({ api, state }), - onTouchend: onTouchend({ api, state }), - setOptions: setOptions({ api, state, props }), - momentum: momentum({ api, state, props }), - setIndex: setIndex({ api, state, emit }), - onClickItem: onClickItem({ api, state }), - mountedHandler: mountedHandler({ api, state, vm }), - beforeUnmountHandler: beforeUnmountHandler({ api, vm }) - }) -} - -const initWatch = ({ watch, props, state, api }) => { - watch(() => props.defaultIndex, api.setIndex, { immediate: true }) - - watch( - () => props.columnsItem, - (value) => { - state.columnsItem = value - }, - { immediate: true } - ) - - watch( - () => props.columnsItem.values, - (value) => { - state.count = value.length - }, - { immediate: true } - ) -} - -export const renderless = (props, { computed, onMounted, reactive, watch, onBeforeUnmount }, { emit, vm }) => { - const api = {} - const state = initState({ reactive, computed, props, api }) - - initApi({ api, props, state, vm, emit }) - - api.setIndex(state.currentIndex) - state.columnsItem = deepClone(props.columnsItem) - - initWatch({ watch, props, state, api }) - - onMounted(api.mountedHandler) - onBeforeUnmount(api.beforeUnmountHandler) - - return api -} diff --git a/packages/mobile/components/popover/index.ts b/packages/mobile/components/popover/index.ts deleted file mode 100644 index 86299bc51b..0000000000 --- a/packages/mobile/components/popover/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Popover from './src/mobile.vue' - -/* istanbul ignore next */ -Popover.install = function (Vue) { - Vue.component(Popover.name, Popover) -} - -export default Popover diff --git a/packages/mobile/components/popover/src/mobile.vue b/packages/mobile/components/popover/src/mobile.vue deleted file mode 100644 index 5e50194097..0000000000 --- a/packages/mobile/components/popover/src/mobile.vue +++ /dev/null @@ -1,67 +0,0 @@ - - - - diff --git a/packages/mobile/components/popover/src/popover.ts b/packages/mobile/components/popover/src/popover.ts deleted file mode 100644 index fc30a21673..0000000000 --- a/packages/mobile/components/popover/src/popover.ts +++ /dev/null @@ -1,153 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams } from '@mobile-root/shared.type' - -import type { - mounted, - computedTooltipId, - destroyed, - doToggle, - doShow, - doClose, - handleFocus, - handleClick, - handleBlur, - handleKeydown, - handleAfterEnter, - handleAfterLeave, - handleMouseEnter, - handleMouseLeave, - handleDocumentClick, - cleanup, - wrapMounted, - handleItemClick, - observeCallback -} from './renderless' - -export type { ISharedRenderlessParamHooks, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' - -export const popoverProps = { - appendToBody: { - type: Boolean, - default: true - }, - arrowOffset: { - type: Number, - default: 0 - }, - boundariesPadding: { - type: Number, - default: 5 - }, - closeDelay: { - type: Number, - default: 200 - }, - content: String, - disabled: Boolean, - modelValue: Boolean, - offset: { - default: 0 - }, - openDelay: { - type: Number, - default: 0 - }, - placement: { - type: String, - default: 'bottom' - }, - popper: {}, - popperClass: String, - popperOptions: { - type: Object, - default: () => ({ gpuAcceleration: false }) - }, - reference: {}, - tabindex: { - type: Number, - default: 0 - }, - title: String, - transition: { - type: String, - default: 'fade-in-linear' - }, - trigger: { - type: String, - default: 'click', - validator: (value: string) => Boolean(~['click', 'focus', 'hover', 'manual'].indexOf(value)) - }, - visibleArrow: { - default: true - }, - width: { - type: [String, Number] - }, - height: { - type: [String, Number] - }, - maxHeight: { - type: [String, Number] - }, - listData: [Object, Array], - genArrowByHtml: { - type: Boolean, - default: () => true - } -} - -export type IPopoverProps = ExtractPropTypes - -export interface IPopoverState { - popperElm: HTMLElement - referenceElm: HTMLElement - showPopper: boolean - timer: number - mounted: boolean - xPlacement: string - tooltipId: string - webCompEventTarget: HTMLElement | null -} - -export interface IPopoverApi { - state: IPopoverState - doDestroy: (forceDestroy?: boolean | undefined) => void - observer: MutationObserver - mounted: ReturnType - cleanup: ReturnType - destroyed: ReturnType - computedTooltipId: ReturnType - doShow: ReturnType - doClose: ReturnType - doToggle: ReturnType - handleClick: ReturnType - handleAfterEnter: ReturnType - handleBlur: ReturnType - handleFocus: ReturnType - handleKeydown: ReturnType - handleMouseLeave: ReturnType - handleAfterLeave: ReturnType - handleMouseEnter: ReturnType - handleDocumentClick: ReturnType - wrapMounted: ReturnType - handleItemClick: ReturnType - observeCallback: ReturnType -} - -export type IPopoverRenderlessParams = ISharedRenderlessFunctionParams & { - props: IPopoverProps - state: IPopoverState - api: IPopoverApi - updatePopper: () => void -} diff --git a/packages/mobile/components/popover/src/renderless/index.ts b/packages/mobile/components/popover/src/renderless/index.ts deleted file mode 100644 index 420544c9f7..0000000000 --- a/packages/mobile/components/popover/src/renderless/index.ts +++ /dev/null @@ -1,280 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { IPopoverRenderlessParams, IPopoverState } from '../popover' -import { on, off, addClass, removeClass } from '@mobile-root/utils/deps/dom' -import { guid } from '@mobile-root/utils/string' -import { KEY_CODE } from '@mobile-root/utils' - -const processTrigger = ({ - api, - state, - props, - nextTick -}: Pick) => { - const { referenceElm, popperElm } = state - - if (props.trigger === 'click') { - on(referenceElm, 'click', api.doToggle) - on(document, 'click', api.handleDocumentClick) - } else if (props.trigger === 'hover') { - on(referenceElm, 'mouseenter', api.handleMouseEnter) - on(popperElm, 'mouseenter', api.handleMouseEnter) - on(referenceElm, 'mouseleave', api.handleMouseLeave) - on(popperElm, 'mouseleave', api.handleMouseLeave) - } else if (props.trigger === 'focus') { - if (referenceElm.querySelector('input, textarea')) { - on(referenceElm, 'focusin', api.doShow) - on(referenceElm, 'focusout', api.doClose) - } else { - on(referenceElm, 'mousedown', api.doShow) - on(referenceElm, 'mouseup', api.doClose) - } - } else if (props.trigger === 'manual') { - // 手动模式,且用户初始modelValue=true,要触发show - if (props.modelValue) { - nextTick(api.doShow) - } - } -} - -/* istanbul ignore next */ -export const mounted = - ({ - api, - state, - constants, - props, - nextTick, - mode - }: Pick & { - constants: { IDPREFIX: string } - }) => - () => { - state.mounted = true - - const { referenceElm, popperElm, tooltipId } = state - - if (referenceElm) { - if (mode !== 'mobile-first') { - addClass(referenceElm, `${constants.IDPREFIX}__reference`) - } - - referenceElm.setAttribute('aria-describedby', tooltipId) - referenceElm.setAttribute('tabindex', props.tabindex.toString()) - popperElm.setAttribute('tabindex', 0) - - if (props.trigger !== 'click') { - on(referenceElm, 'focusin', () => { - api.handleFocus() - - // 仅vue2有 __vue__ - const instance = referenceElm.__vue__ - - if (instance && typeof instance.focus === 'function') { - instance.focus() - } - }) - - on(popperElm, 'focusin', api.handleFocus) - on(referenceElm, 'focusout', api.handleBlur) - on(popperElm, 'focusout', api.handleBlur) - } - - on(referenceElm, 'keydown', api.handleKeydown) - on(referenceElm, 'click', api.handleClick) - } - - processTrigger({ api, state, props, nextTick }) - } - -export const doToggle = (state: IPopoverState) => () => { - state.showPopper = !state.showPopper -} - -export const doShow = (state: IPopoverState) => () => { - state.showPopper = true -} - -export const doClose = (state: IPopoverState) => () => { - state.showPopper = false -} - -export const handleFocus = - ({ props, state }: Pick) => - () => { - addClass(state.referenceElm, 'focusing') - - if (props.trigger === 'click' || props.trigger === 'focus') { - state.showPopper = true - } - } - -/* istanbul ignore next */ -export const handleClick = (state: IPopoverState) => (event: MouseEvent) => { - const popperElm = state.popperElm - // 在webcomponents环境中,在事件传播到document之前对正确的target进行缓存 - if (event?.target && popperElm) { - state.webCompEventTarget = event.target as HTMLElement - } - removeClass(state.referenceElm, 'focusing') -} - -export const handleBlur = - ({ props, state }: Pick) => - () => { - removeClass(state.referenceElm, 'focusing') - - if (props.trigger === 'click' || props.trigger === 'focus') { - state.showPopper = false - } - } - -export const handleMouseEnter = - ({ props, state }: Pick) => - () => { - clearTimeout(state.timer) - - if (props.openDelay) { - state.timer = window.setTimeout(() => { - state.showPopper = true - }, props.openDelay) - } else { - state.showPopper = true - } - } - -export const handleKeydown = - ({ api, props }: Pick) => - (event: KeyboardEvent) => { - if (event.keyCode === KEY_CODE.Escape && props.trigger !== 'manual') { - api.doClose() - } - } - -export const handleMouseLeave = - ({ props, state }: Pick) => - () => { - clearTimeout(state.timer) - - if (props.closeDelay) { - state.timer = window.setTimeout(() => { - state.showPopper = false - }, props.closeDelay) - } else { - state.showPopper = false - } - } - -/* istanbul ignore next */ -export const handleDocumentClick = - ({ vm, state }: Pick) => - (event: MouseEvent) => { - const reference = state.referenceElm - const popperElm = state.popperElm - const $el = vm.$refs.root - let target = event.target as HTMLElement - - // 解决组件在webcomponents中触发document的click事件,但是e.target始终是webcomponents自定义标签,从而引起的判断失效的bug - if (target?.shadowRoot && popperElm) { - target = state.webCompEventTarget as HTMLElement - } - - if ( - !$el || - !reference || - $el.contains(target) || - reference.contains(target) || - !popperElm || - popperElm.contains(target) - ) { - return - } - - state.showPopper = false - } - -export const handleAfterEnter = (emit: IPopoverRenderlessParams['emit']) => () => { - emit('after-enter') -} - -export const handleAfterLeave = (emit: IPopoverRenderlessParams['emit']) => () => { - emit('after-leave') -} - -/** mobile.vue中,给listData项的点击事件 */ -export const handleItemClick = - ({ emit, state }: Pick) => - (item) => { - state.showPopper = false - emit('item-click', item) - } - -export const cleanup = - ({ props, state }: Pick) => - () => { - if (props.openDelay) { - clearTimeout(state.timer) - } - } - -/* istanbul ignore next */ -export const destroyed = - ({ state, api }: Pick) => - () => { - const { referenceElm, popperElm } = state - - // 原来 - off(referenceElm, 'click', api.doToggle) - off(referenceElm, 'mouseup', api.doClose) - off(referenceElm, 'mousedown', api.doShow) - off(referenceElm, 'focusin', api.doShow) - off(referenceElm, 'focusout', api.doClose) - off(referenceElm, 'mouseleave', api.handleMouseLeave) - off(referenceElm, 'mouseenter', api.handleMouseEnter) - off(document, 'click', api.handleDocumentClick) - - // 同步补充 - off(popperElm, 'focusin', api.handleFocus) // - off(popperElm, 'focusout', api.handleBlur) - off(popperElm, 'mouseenter', api.handleMouseEnter) - off(popperElm, 'mouseleave', api.handleMouseLeave) - off(referenceElm, 'click', api.handleClick) - off(referenceElm, 'focusout', api.handleBlur) - off(referenceElm, 'keydown', api.handleKeydown) - } - -export const computedTooltipId = (constants: { IDPREFIX: string }) => () => `${constants.IDPREFIX}-${guid('', 4)}` - -export const wrapMounted = - ({ api, props, vm, state }: Pick) => - () => { - const { reference, popper, wrapper } = vm.$refs - const referenceElm = (state.referenceElm = props.reference || reference) - - state.popperElm = state.popperElm || popper - - if (!referenceElm && wrapper.children) { - state.referenceElm = wrapper.children[0] || wrapper - } - - state.referenceElm && api.mounted() - } - -export const observeCallback = - ({ state, vm }: Pick) => - (mutationsList: any) => { - for (let mutation of mutationsList) { - if (mutation.type === 'attributes' && mutation.attributeName === 'x-placement') { - state.xPlacement = vm.$refs.popper.getAttribute('x-placement') || 'bottom' - } - } - } diff --git a/packages/mobile/components/popover/src/renderless/vue.ts b/packages/mobile/components/popover/src/renderless/vue.ts deleted file mode 100644 index 344a901e07..0000000000 --- a/packages/mobile/components/popover/src/renderless/vue.ts +++ /dev/null @@ -1,205 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - mounted, - computedTooltipId, - destroyed, - doToggle, - doShow, - doClose, - handleFocus, - handleClick, - handleBlur, - handleKeydown, - handleAfterEnter, - handleAfterLeave, - handleMouseEnter, - handleMouseLeave, - handleDocumentClick, - cleanup, - wrapMounted, - handleItemClick, - observeCallback -} from './index' -import userPopper from '@mobile-root/utils/deps/vue-popper' -import type { - IPopoverApi, - IPopoverProps, - IPopoverState, - IPopoverRenderlessParams, - ISharedRenderlessParamHooks, - ISharedRenderlessParamUtils -} from '../popover' - -export const api = [ - 'state', - 'handleAfterEnter', - 'handleAfterLeave', - 'doToggle', - 'doShow', - 'doClose', - 'doDestroy', - 'handleItemClick' -] - -const initState = ({ - reactive, - computed, - api, - popperElm, - showPopper, - referenceElm -}: Pick & IPopoverState) => { - const state = reactive({ - popperElm, - referenceElm, - /** popper 元素是否显示。 它是通过v-show 绑定到页面上,造成隐藏时,popperJs并没有destory,有一定的性能影响 */ - showPopper, - timer: 0, - mounted: false, - xPlacement: 'bottom', - tooltipId: computed(() => api.computedTooltipId()), - webCompEventTarget: null - }) - return state -} - -const initApi = ({ api, props, state, emit, doDestroy, constants, nextTick, vm, mode }) => { - Object.assign(api, { - state, - mounted: mounted({ api, state, constants, props, nextTick, mode }), - cleanup: cleanup({ state, props }), - destroyed: destroyed({ state, api }), - doDestroy, - computedTooltipId: computedTooltipId(constants), - doShow: doShow(state), - doClose: doClose(state), - doToggle: doToggle(state), - handleClick: handleClick(state), - handleAfterEnter: handleAfterEnter(emit), - handleBlur: handleBlur({ props, state }), - handleFocus: handleFocus({ props, state }), - handleKeydown: handleKeydown({ api, props }), - handleMouseLeave: handleMouseLeave({ props, state }), - handleAfterLeave: handleAfterLeave(emit), - handleMouseEnter: handleMouseEnter({ props, state }), - handleDocumentClick: handleDocumentClick({ vm, state }), - wrapMounted: wrapMounted({ api, props, vm, state }), - handleItemClick: handleItemClick({ emit, state }), - observeCallback: observeCallback({ vm, state }) - }) -} - -const initWatch = ({ - watch, - props, - state, - emit, - api, - nextTick, - updatePopper, - mode -}: Pick< - IPopoverRenderlessParams, - 'watch' | 'props' | 'state' | 'emit' | 'api' | 'nextTick' | 'updatePopper' | 'mode' ->) => { - watch( - () => state.showPopper, - (val) => { - if (props.disabled) { - return - } - if (val) { - nextTick(() => updatePopper()) - } - // 隐藏时,只冒一下事件,并没有调用doDestory(); - // 只是通过v-show=state.showPopper 来实现隐藏 - val ? emit('show') : emit('hide') - } - ) - - watch( - () => props.reference, - (val, oldVal) => { - if (val !== oldVal) { - api.destroyed() - - nextTick(() => { - api.wrapMounted() - }) - } - } - ) - - watch( - () => props.modelValue, - (val: boolean) => { - if (props.trigger === 'manual') { - state.showPopper = val - emit('update:modelValue', val) - } - } - ) -} - -export const renderless = ( - props: IPopoverProps, - { - reactive, - computed, - watch, - toRefs, - onBeforeUnmount, - onMounted, - onUnmounted, - onActivated, - onDeactivated - }: ISharedRenderlessParamHooks, - { $prefix, emit, vm, slots, nextTick, mode }: ISharedRenderlessParamUtils -) => { - const api = {} as IPopoverApi - const constants = { IDPREFIX: `${$prefix.toLowerCase()}-popover` } - const options = { emit, onBeforeUnmount, nextTick, reactive, props, watch, onDeactivated, vm, slots, toRefs } - const { showPopper, popperElm, referenceElm, doDestroy, updatePopper } = userPopper(options as any) - const state: IPopoverState = initState({ reactive, computed, api, popperElm, showPopper, referenceElm }) - - initApi({ api, constants, props, state, emit, doDestroy, nextTick, vm, mode }) - - onDeactivated(() => { - api.destroyed() - api.cleanup() - }) - - // 注册生命周期函数必须要在(watch)异步函数/组件之前,否则会 Vue3 警告 - onMounted(() => { - api.wrapMounted() - if (props.genArrowByHtml) { - const config = { attributes: true, childList: false, subtree: false } - api.observer = new MutationObserver(api.observeCallback) - api.observer.observe(vm.$refs.popper, config) - } - }) - - onActivated(api.mounted) - - onUnmounted(() => { - api.destroyed() - api.observer && api.observer.disconnect() - }) - - onBeforeUnmount(api.cleanup) - - initWatch({ watch, props, state, emit, api, nextTick, updatePopper, mode }) - - return api -} diff --git a/packages/mobile/components/popup/index.ts b/packages/mobile/components/popup/index.ts deleted file mode 100644 index e8ea4c5322..0000000000 --- a/packages/mobile/components/popup/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Popup from './src/mobile.vue' - -/* istanbul ignore next */ -Popup.install = function (Vue) { - Vue.component(Popup.name, Popup) -} - -export default Popup diff --git a/packages/mobile/components/popup/src/mobile.vue b/packages/mobile/components/popup/src/mobile.vue deleted file mode 100644 index 4fae6ad56b..0000000000 --- a/packages/mobile/components/popup/src/mobile.vue +++ /dev/null @@ -1,117 +0,0 @@ - - - - - diff --git a/packages/mobile/components/popup/src/renderless/index.ts b/packages/mobile/components/popup/src/renderless/index.ts deleted file mode 100644 index 9d6524f860..0000000000 --- a/packages/mobile/components/popup/src/renderless/index.ts +++ /dev/null @@ -1,141 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { on, off } from '@mobile-root/utils/deps/dom' -import { touchStart, touchMove } from '@mobile-root/utils/deps/touch' -import { getScroller } from '../../../dropdown-menu/src/renderless' -import { isNull } from '@mobile-root/utils/type' - -export const getStyle = (props) => () => { - const style = { ...props.popupStyle } - - if (!isNull(props.duration)) { - const key = props.position === 'center' ? 'animationDuration' : 'transitionDuration' - - style[key] = `${props.duration}s` - } - - return style -} - -export const watchValue = (api) => (value) => { - const type = value ? 'open' : 'close' - api[type]() -} - -export const open = - ({ api, constants, emit, props, state }) => - () => { - if (state.opened) { - return - } - - if (props.zIndex !== undefined) { - state.context.zIndex = props.zIndex - } - - api.renderOverlay() - - state.opened = true - - emit('open') - - if (props.lockScroll) { - on(document, 'touchstart', touchStart) - on(document, 'touchmove', api.onTouchMove) - - if (!state.context.lockCount) { - document.body.classList.add(constants.OVERFLOWHIDDEN) - } - - state.context.lockCount++ - } - } - -export const close = - ({ api, constants, emit, props, state }) => - () => { - if (!state.opened) { - return - } - - if (props.lockScroll) { - state.context.lockCount-- - - off(document, 'touchstart', touchStart) - off(document, 'touchmove', api.onTouchMove) - - if (!state.context.lockCount) { - document.body.classList.remove(constants.OVERFLOWHIDDEN) - } - } - - state.opened = false - - emit('update:modelValue', false) - emit('close') - } - -export const onTouchMove = - ({ vm, state }) => - (event) => { - touchMove(event) - - const direction = state.deltaY > 0 ? '10' : '01' - const el = getScroller()(event.target, vm.$refs.$el) - const { scrollHeight, offsetHeight, scrollTop } = el - let status = '11' - - if (scrollTop === 0) { - status = offsetHeight >= scrollHeight ? '00' : '01' - } else if (scrollTop + offsetHeight >= scrollHeight) { - status = '10' - } - - if (status !== '11' && state.direction === 'vertical' && !(parseInt(status, 2) & parseInt(direction, 2))) { - event.preventDefault() - } - } - -export const renderOverlay = - ({ api, nextTick, props, state }) => - () => { - if (!props.modelValue) { - return - } - - nextTick(() => { - api.updateZIndex(props.overlay ? 1 : 0) - - if (props.overlay) { - state.zIndex = state.context.zIndex++ - } - }) - } - -export const updateZIndex = - ({ vm, state }) => - (value = 0) => - (vm.$refs.popup.style.zIndex = ++state.context.zIndex + value) - -export const clickOverlay = - ({ api, props, emit }) => - () => { - if (props.closeOnClickOverlay) { - api.close() - emit('click-overlay') - } - } - -export const closed = (emit) => () => emit('closed') - -export const opened = (emit) => () => emit('opened') diff --git a/packages/mobile/components/popup/src/renderless/vue.ts b/packages/mobile/components/popup/src/renderless/vue.ts deleted file mode 100644 index 375a289479..0000000000 --- a/packages/mobile/components/popup/src/renderless/vue.ts +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - getStyle, - watchValue, - open, - opened, - closed, - onTouchMove, - close, - renderOverlay, - clickOverlay, - updateZIndex -} from './index' - -export const api = ['state', 'open', 'close', 'clickOverlay', 'onTouchMove', 'opened', 'closed'] - -const initState = ({ reactive, computed, props, api }) => { - const state = reactive({ - transitionName: computed(() => - props.transition || props.position === 'center' ? 'tiny-fade' : `tiny-popup-slide-${props.position}` - ), - style: computed(() => api.getStyle()), - inited: computed(() => state.inited || props.modelValue), - opened: false, - startX: 0, - startY: 0, - deltaX: 0, - deltaY: 0, - offsetX: 0, - offsetY: 0, - direction: '', - shouldRender: computed(() => state.inited || props.lazyRender), - context: { zIndex: 2000, lockCount: 0, stack: [] }, - zIndex: props.zIndex, - overlayStyle: computed(() => ({ - zIndex: state.zIndex, - ...props.overlayStyle - })) - }) - - return state -} - -const initApi = ({ api, props, state, vm, emit, nextTick, constants }) => { - Object.assign(api, { - state, - opened: opened(emit), - closed: closed(emit), - getStyle: getStyle(props), - watchValue: watchValue(api), - updateZIndex: updateZIndex({ vm, state }), - clickOverlay: clickOverlay({ api, emit, props }), - renderOverlay: renderOverlay({ api, nextTick, props, state }), - onTouchMove: onTouchMove({ vm, state }), - open: open({ api, constants, emit, props, state }), - close: close({ api, constants, emit, props, state }) - }) -} - -export const renderless = (props, { computed, onMounted, reactive, watch, nextTick }, { constants, vm, emit }) => { - const api = {} - const state = initState({ reactive, computed, props, api }) - - initApi({ api, props, state, vm, emit, nextTick, constants }) - - watch(() => props.modelValue, api.watchValue, { immediate: true }) - - onMounted(() => { - props.modelValue && api.open() - }) - - return api -} diff --git a/packages/mobile/components/progress/index.ts b/packages/mobile/components/progress/index.ts deleted file mode 100644 index 06a17d1a98..0000000000 --- a/packages/mobile/components/progress/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Progress from './src/mobile.vue' - -/* istanbul ignore next */ -Progress.install = function (Vue) { - Vue.component(Progress.name, Progress) -} - -export default Progress diff --git a/packages/mobile/components/progress/src/mobile.vue b/packages/mobile/components/progress/src/mobile.vue deleted file mode 100644 index f07e2c948d..0000000000 --- a/packages/mobile/components/progress/src/mobile.vue +++ /dev/null @@ -1,90 +0,0 @@ - - - - diff --git a/packages/mobile/components/progress/src/progress.ts b/packages/mobile/components/progress/src/progress.ts deleted file mode 100644 index 01e3fba612..0000000000 --- a/packages/mobile/components/progress/src/progress.ts +++ /dev/null @@ -1,190 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const $constants = { - PROGRESS_TYPE: { - LINE: 'line', - CIRCLE: 'circle', - DASHBOARD: 'dashboard' - }, - PROGRESS_SIZE: { - SMALL: 'small', - MEDIUM: 'medium', - LARGE: 'large' - }, - PROGRESS_SIZE_WIDTH: { - SMALL: 48, - MEDIUM: 96, - LARGE: 160 - }, - PROGRESS_STATUS: { - DEFAULT: 'default', - SUCCESS: 'success', - EXCEPTION: 'exception', - WARNING: 'warning' - }, - STATUS_TO_COLOR: { - success: '#00a874', - exception: '#eb171f', - warning: '#fdc000' - }, - STATUS_DEFAULT_COLOR: '#0067d1', - ICON_CIRCLE_WARNING: 'icon-warning', - ICON_CIRCLE_SUCCESS: 'icon-success', - ICON_CIRCLE_EXCEPTION: 'icon-error', - ICON_SUCCESS: 'icon-yes', - ICON_EXCEPTION: 'icon-close', - ICON_WARNING: 'icon-warning', - TEXT_XS: 12, - TEXT_SM: 14, - WIDTH_RATE_TWO: 2, - WIDTH_RATE_THREE: 3, - WIDTH_RATE_SIX: 6, - DEFAULT_STROKE_WIDTH: 6, - REL_STROKE_WIDTH: 4, - DEFAULT_WIDTH: 126, - STROKE_WIDTH_RATE: 0.4 -} - -export const progressProps = { - _constants: { - type: Object, - default: () => $constants - }, - color: { - type: [String, Array, Function], - default: '' - }, - info: String, - format: Function, - percentage: { - type: Number, - default: 0, - required: true, - validator: (val: number) => val >= 0 && val <= 100 - }, - showText: { - type: Boolean, - default: true - }, - status: { - type: String, - validator: (value: string) => !!$constants.PROGRESS_STATUS[value.toUpperCase()] - }, - strokeWidth: { - type: Number, - default: 0 - }, - textInside: { - type: Boolean, - default: false - }, - type: { - type: String, - default: $constants.PROGRESS_TYPE.LINE, - validator: (value: string) => !!$constants.PROGRESS_TYPE[value.toUpperCase()] - }, - size: { - type: String, - default: $constants.PROGRESS_SIZE.MEDIUM, - validator: (value) => !!$constants.PROGRESS_SIZE[value.toUpperCase()] - }, - width: { - type: Number, - default: 0 - } -} - -export type IProgressProps = ExtractPropTypes - -export interface IProgressState { - percentTextSize: number - rate: number - radius: number - stroke: string - content: string - barStyle: object - trackPath: string - perimeter: number - iconClass: string - iconStyle: object - circleStyle: object - trailPathStyle: object - circlePathStyle: object - progressTextSize: number - strokeDashoffset: string - strokeWidth: number - width: number - relativeStrokeWidth: number -} - -export interface IProgressColorItem { - color: string - progress: number -} - -export interface IProgressIconStyle { - width: T - height: T -} - -export interface IProgressPathStyle { - strokeDasharray: string - strokeDashoffset: string - transition?: string -} - -export interface IProgressBarStyle { - width: string - backgroundColor: string -} - -export interface IProgressApi { - state: IProgressState - customAppearHook: (el: HTMLElement) => void - computedContent: () => string - getColorArray: () => IProgressColorItem[] - computedRate: () => number - computedPerimeter: () => number - computedRadius: () => number - computedTrackPath: () => string - computedIconClass: () => string - computedIconStyle: () => IProgressIconStyle | object - computedCircleStyle: () => IProgressIconStyle | object - computedCirclePathStyle: () => IProgressPathStyle - computedStrokeDashoffset: () => string - computedTrailPathStyle: () => IProgressPathStyle - computedRelativeStrokeWidth: () => number - computedProgressTextSize: () => number - customAfterAppearHook: (el: HTMLElement) => void - customBeforeAppearHook: (el: HTMLElement) => void - getLevelColor: (p: number) => string - computedBarStyle: () => IProgressBarStyle - getCurrentColor: (p: number) => string - computedStroke: () => string -} - -export type IProgressConstants = typeof $constants - -export type IProgressRenderlessParamUtils = ISharedRenderlessParamUtils & { - constants: IProgressConstants -} - -export type IProgressRenderlessParams = ISharedRenderlessFunctionParams & { - state: IProgressState - props: IProgressProps - api: IProgressApi -} diff --git a/packages/mobile/components/progress/src/renderless/index.ts b/packages/mobile/components/progress/src/renderless/index.ts deleted file mode 100644 index 1b3905cc0b..0000000000 --- a/packages/mobile/components/progress/src/renderless/index.ts +++ /dev/null @@ -1,238 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { - IProgressRenderlessParams, - IProgressBarStyle, - IProgressPathStyle, - IProgressIconStyle, - IProgressColorItem -} from '../progress' - -export const computedBarStyle = - ({ api, props }: Pick) => - (): IProgressBarStyle => ({ - width: props.percentage + '%', - backgroundColor: api.getCurrentColor(props.percentage) - }) - -export const computedRelativeStrokeWidth = - ({ constants, state }: Pick) => - (): number => { - if (state.width === 0 || state.strokeWidth === 0) return constants.REL_STROKE_WIDTH - return Number(((state.strokeWidth / state.width) * 100).toFixed(1)) - } - -export const computedRadius = - ({ constants, props, state }: Pick) => - (): number => - props.type === constants.PROGRESS_TYPE.CIRCLE || props.type === constants.PROGRESS_TYPE.DASHBOARD - ? parseInt(String(50 - parseFloat(state.relativeStrokeWidth) / 2), 10) - : 0 - -export const computedTrackPath = - ({ constants, props, state }: Pick) => - (): string => { - const radiusValue = state.radius - const isDashboardType = props.type === constants.PROGRESS_TYPE.DASHBOARD - - return ` - M 50 50 - m 0 ${isDashboardType ? '' : '-'}${radiusValue} - a ${radiusValue} ${radiusValue} 0 1 1 0 ${isDashboardType ? '-' : ''}${radiusValue * 2} - a ${radiusValue} ${radiusValue} 0 1 1 0 ${isDashboardType ? '' : '-'}${radiusValue * 2} - ` - } - -export const computedPerimeter = - ({ state }: Pick) => - (): number => - 2 * Math.PI * state.radius - -export const computedRate = - ({ constants, props }: Pick) => - (): number => - props.type === constants.PROGRESS_TYPE.DASHBOARD ? 0.75 : 1 - -export const computedStrokeDashoffset = - ({ state }: Pick) => - (): string => - `${(-1 * state.perimeter * (1 - state.rate)) / 2}px` - -export const computedTrailPathStyle = - ({ state }: Pick) => - (): IProgressPathStyle => ({ - strokeDasharray: `${state.perimeter * state.rate}px, ${state.perimeter}px`, - strokeDashoffset: state.strokeDashoffset - }) - -export const computedCircleStyle = - ({ state }: Pick) => - () => - state.width ? { height: state.width + 'px', width: state.width + 'px' } : {} - -export const computedCirclePathStyle = - ({ props, state }: Pick) => - (): IProgressPathStyle => ({ - strokeDasharray: `${state.perimeter * state.rate * (props.percentage / 100)}px, ${state.perimeter}px`, - strokeDashoffset: state.strokeDashoffset, - transition: 'stroke-dasharray 0.6s ease 0s, stroke 0.6s ease' - }) - -export const computedStroke = - ({ api, constants, props }: Pick) => - (): string => - (props.color && api.getCurrentColor(props.percentage)) || - constants.STATUS_TO_COLOR[props.status] || - constants.STATUS_DEFAULT_COLOR - -export const computedIconClass = - ({ constants, props, mode }: Pick) => - (): string => { - if (props.status === constants.PROGRESS_STATUS.SUCCESS) { - const iconClasses = - props.type === constants.PROGRESS_TYPE.LINE - ? [constants.ICON_SUCCESS, constants.ICON_CIRCLE_SUCCESS] - : [constants.ICON_CIRCLE_SUCCESS, constants.ICON_SUCCESS] - return mode === 'mobile-first' ? iconClasses[1] : iconClasses[0] - } else if (props.status === constants.PROGRESS_STATUS.WARNING) { - return props.type === constants.PROGRESS_TYPE.LINE ? constants.ICON_WARNING : constants.ICON_CIRCLE_WARNING - } else if (props.status === constants.PROGRESS_STATUS.EXCEPTION) { - const iconClasses = - props.type === constants.PROGRESS_TYPE.LINE - ? [constants.ICON_EXCEPTION, constants.ICON_CIRCLE_EXCEPTION] - : [constants.ICON_CIRCLE_EXCEPTION, constants.ICON_EXCEPTION] - return mode === 'mobile-first' ? iconClasses[1] : iconClasses[0] - } else { - return '' - } - } - -export const computedIconStyle = - ({ constants, props, state }: Pick) => - (): IProgressIconStyle | {} => { - if (props.type === constants.PROGRESS_TYPE.LINE) { - return state.strokeWidth - ? { - width: constants.TEXT_XS + state.strokeWidth * constants.STROKE_WIDTH_RATE, - height: constants.TEXT_XS + state.strokeWidth * constants.STROKE_WIDTH_RATE - } - : {} - } else { - return state.width - ? { width: state.width / constants.WIDTH_RATE_TWO, height: state.width / constants.WIDTH_RATE_TWO } - : {} - } - } - -export const computedProgressTextSize = - ({ constants, props, state, mode }: Pick) => - (): number => { - if (mode === 'mobile-first') { - let fontSize = constants.TEXT_XS - const sizeWidthMap = { - small: constants.PROGRESS_SIZE_WIDTH.SMALL, - medium: constants.PROGRESS_SIZE_WIDTH.MEDIUM, - large: constants.PROGRESS_SIZE_WIDTH.LARGE - } - - if (props.type === constants.PROGRESS_TYPE.LINE) { - fontSize = state.strokeWidth - ? constants.TEXT_XS + state.strokeWidth * constants.STROKE_WIDTH_RATE - : props.size === constants.PROGRESS_SIZE.SMALL - ? constants.TEXT_XS - : constants.TEXT_SM - } else { - const width = state.width ? state.width : sizeWidthMap[props.size] - fontSize = width / constants.WIDTH_RATE_THREE - state.percentTextSize = width / constants.WIDTH_RATE_SIX - } - return fontSize - } else { - return props.type === constants.PROGRESS_TYPE.LINE - ? constants.TEXT_XS + state.strokeWidth * constants.STROKE_WIDTH_RATE - : state.width * 0.111111 + 2 - } - } - -export const computedContent = - ({ props }: Pick) => - (): string => - typeof props.format === 'function' ? props.format() || '' : `${props.percentage}%` - -export const getCurrentColor = - ({ api, props }: Pick) => - (percentage) => { - if (typeof props.color === 'function') { - return props.color(percentage) - } else if (typeof props.color === 'string') { - return props.color - } else { - return api.getLevelColor(percentage) - } - } - -export const getLevelColor = - ({ api }: Pick) => - (percentage: number): string => { - const colorArray = api.getColorArray().sort((a, b) => a.percentage - b.percentage) - - for (let i = 0; i < colorArray.length; i++) { - if (colorArray[i].percentage > percentage) { - return colorArray[i].color - } - } - - return colorArray[colorArray.length - 1].color - } - -export const getColorArray = - ({ props }: Pick) => - (): IProgressColorItem[] => { - const color = props.color - const span = 100 / color.length - - return color.map((seriesColor, index) => { - if (typeof seriesColor === 'string') { - return { - color: seriesColor, - progress: (index + 1) * span - } - } - - return seriesColor - }) - } - -export const customBeforeAppearHook = - ({ props, state }: Pick) => - (el: HTMLElement) => { - if (props.type === 'line') { - el.style.width = String(0) - } else if (props.type === 'circle') { - el.style.strokeDasharray = String(state.perimeter * state.content) - el.style.strokeDashoffset = state.perimeter - } - } - -export const customAppearHook = (el: HTMLElement) => { - el.style.transition = 'all 0.5s' -} - -export const customAfterAppearHook = - ({ state, props }: Pick) => - (el: HTMLElement) => { - if (props.type === 'line') { - el.style.width = state.barStyle.width - } else if (props.type === 'circle') { - el.style.strokeDashoffset = String(0) - } - } diff --git a/packages/mobile/components/progress/src/renderless/vue.ts b/packages/mobile/components/progress/src/renderless/vue.ts deleted file mode 100644 index f27710516a..0000000000 --- a/packages/mobile/components/progress/src/renderless/vue.ts +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { - IProgressProps, - IProgressState, - IProgressApi, - ISharedRenderlessParamHooks, - IProgressRenderlessParamUtils -} from '../progress' -import { - computedBarStyle, - computedRelativeStrokeWidth, - computedRadius, - computedTrackPath, - computedPerimeter, - computedRate, - computedStrokeDashoffset, - computedTrailPathStyle, - computedCircleStyle, - computedCirclePathStyle, - computedStroke, - computedIconClass, - computedIconStyle, - computedProgressTextSize, - computedContent, - getCurrentColor, - getLevelColor, - getColorArray, - customBeforeAppearHook, - customAppearHook, - customAfterAppearHook -} from './index' - -export const api = [ - 'state', - 'getCurrentColor', - 'getLevelColor', - 'getColorArray', - 'customBeforeAppearHook', - 'customAppearHook', - 'customAfterAppearHook' -] - -export const renderless = ( - props: IProgressProps, - { computed, reactive }: ISharedRenderlessParamHooks, - { constants, mode }: IProgressRenderlessParamUtils -): IProgressApi => { - const api = {} as IProgressApi - const state: IProgressState = reactive({ - percentTextSize: constants.TEXT_XS, - rate: computed(() => api.computedRate()), - radius: computed(() => api.computedRadius()), - stroke: computed(() => api.computedStroke()), - content: computed(() => api.computedContent()), - barStyle: computed(() => api.computedBarStyle()), - trackPath: computed(() => api.computedTrackPath()), - perimeter: computed(() => api.computedPerimeter()), - iconClass: computed(() => api.computedIconClass()), - iconStyle: computed(() => api.computedIconStyle()), - circleStyle: computed(() => api.computedCircleStyle()), - trailPathStyle: computed(() => api.computedTrailPathStyle()), - circlePathStyle: computed(() => api.computedCirclePathStyle()), - progressTextSize: computed(() => api.computedProgressTextSize()), - strokeDashoffset: computed(() => api.computedStrokeDashoffset()), - strokeWidth: computed(() => - mode === 'mobile-first' ? props.strokeWidth : props.strokeWidth || constants.DEFAULT_STROKE_WIDTH - ), - width: computed(() => (mode === 'mobile-first' ? props.width : props.width || constants.DEFAULT_WIDTH)), - relativeStrokeWidth: computed(() => api.computedRelativeStrokeWidth()) - }) - - Object.assign(api, { - state, - customAppearHook, - computedContent: computedContent({ props }), - getColorArray: getColorArray({ props }), - computedRate: computedRate({ constants, props }), - computedPerimeter: computedPerimeter({ state }), - computedRadius: computedRadius({ constants, props, state }), - computedTrackPath: computedTrackPath({ constants, props, state }), - computedIconClass: computedIconClass({ constants, props, mode }), - computedIconStyle: computedIconStyle({ constants, props, state }), - computedCircleStyle: computedCircleStyle({ state }), - computedCirclePathStyle: computedCirclePathStyle({ props, state }), - computedStrokeDashoffset: computedStrokeDashoffset({ state }), - computedTrailPathStyle: computedTrailPathStyle({ state }), - computedRelativeStrokeWidth: computedRelativeStrokeWidth({ state, constants }), - computedProgressTextSize: computedProgressTextSize({ state, constants, props, mode }), - customAfterAppearHook: customAfterAppearHook({ state, props }), - customBeforeAppearHook: customBeforeAppearHook({ props, state }), - getLevelColor: getLevelColor({ api }), - computedBarStyle: computedBarStyle({ api, props }), - getCurrentColor: getCurrentColor({ api, props }), - computedStroke: computedStroke({ api, constants, props }) - }) - - return api -} diff --git a/packages/mobile/components/pull-refresh/index.ts b/packages/mobile/components/pull-refresh/index.ts deleted file mode 100644 index ad2e7253a2..0000000000 --- a/packages/mobile/components/pull-refresh/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import PullRefresh from './src/mobile.vue' - -/* istanbul ignore next */ -PullRefresh.install = function (Vue) { - Vue.component(PullRefresh.name, PullRefresh) -} - -export default PullRefresh diff --git a/packages/mobile/components/pull-refresh/src/mobile.vue b/packages/mobile/components/pull-refresh/src/mobile.vue deleted file mode 100644 index ecf75d5fd4..0000000000 --- a/packages/mobile/components/pull-refresh/src/mobile.vue +++ /dev/null @@ -1,76 +0,0 @@ - - - - diff --git a/packages/mobile/components/pull-refresh/src/pull-refresh.ts b/packages/mobile/components/pull-refresh/src/pull-refresh.ts deleted file mode 100644 index 468d03e4fa..0000000000 --- a/packages/mobile/components/pull-refresh/src/pull-refresh.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { t } from '@opentiny/vue-locale' - -export const $constants = { - DEFAULT_HEAD_HEIGHT: 50, - STATUS: { - NORMAL: 'normal', - LOADING: 'loading', - LOOSING: 'loosing', - PULLING: 'pulling', - SUCCESS: 'success' - } -} - -export const pullRefreshProps = { - _constants: { type: Object, default: () => $constants }, - modelValue: Boolean, - loosingText: { type: String, default: t('ui.pullRefresh.loosing') }, - successText: { type: String, default: $constants.STATUS.SUCCESS }, - failedText: String, - successDuration: { - type: [Number, String], - default: 500 - }, - animationDuration: { - type: [Number, String], - default: 300 - }, - disabled: { - type: Boolean, - default: false - }, - pullUp: { - type: Object, - default: {} - }, - pullDown: { - type: Object, - default: {} - }, - hasMore: { - type: Boolean, - default: true - }, - pullUpLoadingText: { - type: String, - default: '' - }, - pullDownLoadingText: { - type: String, - default: '' - }, - disabledPullUp: { - type: Boolean, - default: false - } -} diff --git a/packages/mobile/components/pull-refresh/src/renderless/index.ts b/packages/mobile/components/pull-refresh/src/renderless/index.ts deleted file mode 100644 index 3d4e168dfa..0000000000 --- a/packages/mobile/components/pull-refresh/src/renderless/index.ts +++ /dev/null @@ -1,158 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { on, off } from '@mobile-root/utils/deps/dom' - -// 上拉触发事件超时时间 -const PULL_UP_TIME_OUT = 300 - -export const initPullRefresh = - ({ t, props, state }) => - () => { - const defaultOption = { - pullingUpText: t('ui.pullRefresh.pullingUp'), - pullingDownText: t('ui.pullRefresh.pullingDown'), - pullUpDisabled: false, - pullDownDisabled: false, - headHeight: 48 - } - - state.pullUp = { ...defaultOption, ...props.pullUp } - state.pullDown = { ...defaultOption, ...props.pullDown } - state.loosingText = props.loosingText ?? t('ui.pullRefresh.loosing') - state.successText = props.successText ?? t('ui.pullRefresh.success') - state.failedText = props.failedText ?? t('ui.pullRefresh.failed') - } - -export const onTouchstart = (state) => (event) => { - state.draggposition = event.touches[0].clientY -} - -export const onTouchmove = - ({ state, refs }) => - (event) => { - if (event.touches[0].clientY > state.draggposition) { - pullDownTouchMove(state, refs, event) - } - } - -export const pullDownTouchMove = (state, refs, event) => { - if (state.disabledPullDown || state.pullDownLoading) { - return - } - - if (refs.content.scrollTop <= 0 && window.scrollY <= 0 && event.cancelable) { - event.preventDefault() - - state.translate3d = (event.touches[0].clientY - state.draggposition) / 2 - state.pullDownReplaces = - Math.abs(state.translate3d) > state.pullDown.headHeight ? state.loosingText : state.pullDown.pullingDownText - } - state.animationDuration = 0 -} - -export const onTouchend = - ({ api, props, state, emit, refs }) => - (event) => { - state.animationDuration = props.animationDuration - if (event.changedTouches[0].clientY < state.draggposition) { - // 上拉 - pullUpTouchEnd(state, emit, refs) - } else { - // 下拉 - pullDownTouchEnd(api, state, emit) - } - } - -export const pullDownTouchEnd = (api, state, emit) => { - if (Math.abs(state.translate3d) < state.pullDown.headHeight) { - state.pullDownLoading = false - api.clearPullRefresh() - return - } - - state.translate3d = state.pullDown.headHeight - state.pullDownLoading = true - emit('update:modelValue', true) - emit('pullDown') -} - -export const pullUpTouchEnd = (state, emit, refs) => { - clearTimeout(state.timer) - - state.timer = setTimeout(() => { - const footNode = refs.foot - - if (!state.hasMore || !footNode) { - return - } - - const contentNode = refs.content - const bottomDis = footNode.offsetTop + footNode.clientHeight - contentNode.scrollTop - contentNode.clientHeight - if (bottomDis <= state.pullUpDistance) { - state.pullUpLoading = true - emit('update:modelValue', true) - emit('pullUp') - } - }, PULL_UP_TIME_OUT) -} - -export const onScroll = - ({ state, emit, refs }) => - () => { - pullUpTouchEnd(state, emit, refs) - } - -export const mountedHandler = - ({ api, refs }) => - () => { - const track = refs.track - - on(track, 'touchstart', api.onTouchstart) - on(track, 'touchmove', api.onTouchmove) - on(track, 'touchend', api.onTouchend) - on(track, 'scroll', api.onScroll) - } - -export const beforeUnmountHandler = - ({ api, refs }) => - () => { - const track = refs.track - - off(track, 'touchstart', api.onTouchstart) - off(track, 'touchmove', api.onTouchmove) - off(track, 'touchend', api.onTouchend) - off(track, 'scroll', api.onScroll) - } - -export const handlerModelValue = - ({ api, state }) => - (value, result) => { - state.pullUpLoading = false - state.pullDownLoading = false - - if (value === 'down') { - state.pullDownReplaces = state[`${result}Text`] - } else { - state.pullUpStateText = state[`${result}Text`] - } - setTimeout(() => { - api.clearPullRefresh() - }, state.successDuration) - } - -export const clearPullRefresh = (state) => () => { - state.translate3d = 0 - state.pullDownReplaces = '' - state.pullDownLoading = false - state.pullUpLoading = false -} diff --git a/packages/mobile/components/pull-refresh/src/renderless/vue.ts b/packages/mobile/components/pull-refresh/src/renderless/vue.ts deleted file mode 100644 index 7b0ce42d32..0000000000 --- a/packages/mobile/components/pull-refresh/src/renderless/vue.ts +++ /dev/null @@ -1,90 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - mountedHandler, - beforeUnmountHandler, - handlerModelValue, - onTouchstart, - onTouchmove, - onTouchend, - onScroll, - initPullRefresh, - clearPullRefresh -} from './index' - -export const api = ['state'] - -export const renderless = (props, { watch, onMounted, reactive, onBeforeUnmount }, { t, refs, emit, nextTick }) => { - const api = {} - const state = reactive({ - pullDownReplaces: '', - refreshStyle: {}, - translate3d: 0, - draggposition: 0, - pullUpLoading: false, - pullDownLoading: false, - loosingText: '', - successText: '', - failedText: '', - noMoreText: t('ui.pullRefresh.noMore'), - pullUpLoadingText: props.pullUpLoadingText, - pullDownLoadingText: props.pullDownLoadingText, - pullUp: null, - pullDown: null, - hasMore: true, - successDuration: props.successDuration, - animationDuration: props.animationDuration, - disabledPullDown: props.disabledPullDown, - disabledPullUp: props.disabledPullUp, - pullUpDistance: typeof props.pullUpDistance === 'string' ? Number(props.pullUpDistance) : props.pullUpDistance, - timer: null - }) - - Object.assign(api, { - state, - onTouchstart: onTouchstart(state), - onTouchmove: onTouchmove({ state, refs }), - onTouchend: onTouchend({ api, props, state, emit, refs }), - onScroll: onScroll({ state, emit, refs }), - mountedHandler: mountedHandler({ api, refs }), - beforeUnmountHandler: beforeUnmountHandler({ api, refs }), - handlerModelValue: handlerModelValue({ api, state }), - initPullRefresh: initPullRefresh({ t, props, state }), - clearPullRefresh: clearPullRefresh(state) - }) - - watch( - () => props.hasMore, - (value: boolean) => { - state.hasMore = value - }, - { immediate: true } - ) - - watch( - () => props.modelValue, - (value) => { - if (!value) { - api.clearPullRefresh() - } - } - ) - - onMounted(() => { - api.mountedHandler({ api, refs, state }) - api.initPullRefresh({ t, props, state }) - }) - onBeforeUnmount(api.beforeUnmountHandler) - - return api -} diff --git a/packages/mobile/components/radio-group/index.ts b/packages/mobile/components/radio-group/index.ts deleted file mode 100644 index 531e719ee5..0000000000 --- a/packages/mobile/components/radio-group/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import RadioGroup from './src/mobile.vue' - -/* istanbul ignore next */ -RadioGroup.install = function (Vue) { - Vue.component(RadioGroup.name, RadioGroup) -} - -export default RadioGroup diff --git a/packages/mobile/components/radio-group/src/mobile.vue b/packages/mobile/components/radio-group/src/mobile.vue deleted file mode 100644 index 75a1c8d2ee..0000000000 --- a/packages/mobile/components/radio-group/src/mobile.vue +++ /dev/null @@ -1,46 +0,0 @@ - - - - diff --git a/packages/mobile/components/radio-group/src/radio-group.ts b/packages/mobile/components/radio-group/src/radio-group.ts deleted file mode 100644 index b97e1be6b2..0000000000 --- a/packages/mobile/components/radio-group/src/radio-group.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { PropType } from 'vue' -import type { ExtractPropTypes } from 'vue' -import type { - ISharedRenderlessFunctionParams, - ISharedRenderlessParamUtils, - ISharedRenderlessParamHooks -} from '@mobile-root/shared.type' -import type { mounted, handleKeydown } from './renderless' - -export type { ISharedRenderlessParamHooks } - -export const radioGroupProps = { - modelValue: {}, - size: { - type: String as PropType<'mini' | 'small' | 'medium'>, - default: '' - }, - fill: String, - textColor: String, - disabled: Boolean, - vertical: Boolean, - options: { - type: Array, - default: () => [] - }, - type: { - type: String, - default: 'radio' - }, - showTips: { - type: Boolean, - default: false - }, - displayOnly: { - type: Boolean, - default: false - } -} - -export interface IRadioGroupState { - radioGroupSize: IRadioGroupProps['size'] - tag: string - activeStyle: string | undefined -} - -export type IRadioGroupProps = ExtractPropTypes - -export type IRadioGroupRenderlessParams = ISharedRenderlessFunctionParams & { - state: IRadioGroupState - props: IRadioGroupProps -} - -export interface IRadioGroupApi { - state: IRadioGroupState - dispatch: ISharedRenderlessParamUtils['dispatch'] - onMounted: ReturnType - handleKeydown: ReturnType -} - -export type IRadioGroupRenderlessParamUtils = ISharedRenderlessParamUtils diff --git a/packages/mobile/components/radio-group/src/renderless/index.ts b/packages/mobile/components/radio-group/src/renderless/index.ts deleted file mode 100644 index e3ac9fcd35..0000000000 --- a/packages/mobile/components/radio-group/src/renderless/index.ts +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { IRadioGroupRenderlessParams } from '../radio-group' -import { KEY_CODE } from '@mobile-root/utils' - -export const handleKeydown = - (parent: IRadioGroupRenderlessParams['parent']) => - (event: KeyboardEvent): void => { - const target = event.target - const className = target?.nodeName === 'INPUT' ? '[type=radio]' : '[role=radio]' - const radios = parent.$el.querySelectorAll(className) - const length = radios.length - const index = [].indexOf.call(radios, target) - const roleRadiosNodes: NodeListOf = parent.$el.querySelectorAll('[role=radio]') - - switch (event.keyCode) { - case KEY_CODE.ArrowDown: - case KEY_CODE.ArrowRight: - if (index === length - 1) { - event.stopPropagation() - event.preventDefault() - - roleRadiosNodes[0].click() - roleRadiosNodes[0].focus() - } else { - roleRadiosNodes[index + 1].click() - roleRadiosNodes[index + 1].focus() - } - break - case KEY_CODE.ArrowUp: - case KEY_CODE.ArrowLeft: - event.stopPropagation() - event.preventDefault() - - if (index === 0) { - roleRadiosNodes[length - 1].click() - roleRadiosNodes[length - 1].focus() - } else { - roleRadiosNodes[index - 1].click() - roleRadiosNodes[index - 1].focus() - } - break - default: - break - } - } - -export const mounted = (parent: IRadioGroupRenderlessParams['parent']) => (): void => { - const radios: NodeListOf = parent.$el.querySelectorAll('[type=radio]') - const firstLabel = parent.$el.querySelectorAll('[role=radio]')[0] as HTMLInputElement - - if (![].some.call(radios, (radio: HTMLInputElement) => radio.checked) && firstLabel) { - firstLabel.tabIndex = 0 - } -} diff --git a/packages/mobile/components/radio-group/src/renderless/vue.ts b/packages/mobile/components/radio-group/src/renderless/vue.ts deleted file mode 100644 index c75e98f23d..0000000000 --- a/packages/mobile/components/radio-group/src/renderless/vue.ts +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { - IRadioGroupApi, - IRadioGroupProps, - IRadioGroupState, - ISharedRenderlessParamHooks, - IRadioGroupRenderlessParamUtils -} from '../radio-group' -import { handleKeydown, mounted } from './index' - -export const api = ['state', 'handleKeydown'] - -export const renderless = ( - props: IRadioGroupProps, - { computed, onMounted, reactive, watch, provide }: ISharedRenderlessParamHooks, - { parent, dispatch }: IRadioGroupRenderlessParamUtils -): IRadioGroupApi => { - const state: IRadioGroupState = reactive({ - radioGroupSize: computed(() => props.size), - tag: 'div', - activeStyle: props.fill - }) - - parent.$on('handleChange', (value) => { - parent.$emit('change', value) - }) - - const api: IRadioGroupApi = { - state, - dispatch, - onMounted: mounted(parent), - handleKeydown: handleKeydown(parent) - } - - watch( - () => props.modelValue, - (value) => { - api.dispatch('FormItem', 'form.change', [value]) - } - ) - - onMounted(api.onMounted) - - provide('radioVertical', props.vertical) - - provide('showTips', props.showTips) - - provide('size', props.size) - - return api -} diff --git a/packages/mobile/components/radio/index.ts b/packages/mobile/components/radio/index.ts deleted file mode 100644 index d3c8780bc2..0000000000 --- a/packages/mobile/components/radio/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Radio from './src/mobile.vue' - -/* istanbul ignore next */ -Radio.install = function (Vue) { - Vue.component(Radio.name, Radio) -} - -export default Radio diff --git a/packages/mobile/components/radio/src/mobile.vue b/packages/mobile/components/radio/src/mobile.vue deleted file mode 100644 index e3e0d32ef8..0000000000 --- a/packages/mobile/components/radio/src/mobile.vue +++ /dev/null @@ -1,61 +0,0 @@ - - - - diff --git a/packages/mobile/components/radio/src/radio.ts b/packages/mobile/components/radio/src/radio.ts deleted file mode 100644 index 5228ed73f6..0000000000 --- a/packages/mobile/components/radio/src/radio.ts +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { PropType } from 'vue' -import type { ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' -import type { - handleChange, - isGroup, - radioSize, - isDisabled, - isDisplayOnly, - tabIndex, - getModel, - setModel -} from './renderless' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const $constants = { - RADIO_GROUP: 'RadioGroup' -} - -export const radioProps = { - _constants: { - type: Object, - default: () => $constants - }, - modelValue: {}, - label: {}, - disabled: Boolean, - name: String, - border: Boolean, - size: { - type: String as PropType<'mini' | 'small' | 'medium'>, - default: '' - }, - text: String, - events: { - type: Object, - default: () => ({}) - }, - tabindex: { - type: String, - default: '1' - }, - displayOnly: { - type: Boolean, - default: false - } -} - -export type IRadioProps = ExtractPropTypes - -export type IRadioConstants = typeof $constants -export interface IRadioState { - vertical: boolean - size: IRadioProps['size'] - focus: boolean - radioGroup: ISharedRenderlessParamUtils['parent'] | null - isGroup: boolean - radioSize: IRadioProps['size'] - isDisabled: boolean - isDisplayOnly: boolean - tabIndex: number - formDisabled: boolean - model: string -} - -export type IRadioRenderlessParams = ISharedRenderlessFunctionParams & { - state: IRadioState - props: IRadioProps - type: string - api: IRadioApi -} - -export interface IRadioApi { - state: IRadioState - handleChange: ReturnType - isGroup: ReturnType - radioSize: ReturnType - isDisabled: ReturnType - isDisplayOnly: ReturnType - tabIndex: ReturnType - getModel: ReturnType - setModel: ReturnType -} - -export type IRadioRenderlessParamUtils = ISharedRenderlessParamUtils diff --git a/packages/mobile/components/radio/src/renderless/index.ts b/packages/mobile/components/radio/src/renderless/index.ts deleted file mode 100644 index 1a9bc59df0..0000000000 --- a/packages/mobile/components/radio/src/renderless/index.ts +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { IRadioRenderlessParams, IRadioState } from '../radio' - -export const handleChange = - ({ - constants, - dispatch, - emit, - state, - nextTick - }: Pick) => - (): void => { - nextTick(() => { - emit('change', state.model) - - state.isGroup && dispatch(constants.RADIO_GROUP, 'handleChange', [state.model]) - }) - } - -export const isGroup = - ({ constants, parent: $parent, state }: Pick) => - (): boolean => { - let parent = $parent.$parent.$parent - - while (parent) { - if (parent.$options.componentName !== constants.RADIO_GROUP) { - parent = parent.$parent - } else { - state.radioGroup = parent as unknown as IRadioRenderlessParams['parent'] - - return true - } - } - - return false - } - -export const radioSize = - ({ props, state }: Pick) => - (): IRadioState['radioSize'] => { - if (state.isGroup && state.radioGroup?.state?.radioGroupSize) { - return state.radioGroup.state.radioGroupSize - } else { - return props.size - } - } - -export const isDisabled = - ({ props, state }: Pick) => - (): boolean => - props.disabled || state.radioGroup?.disabled || state.formDisabled - -export const isDisplayOnly = - ({ props }: Pick) => - (): boolean => - props.displayOnly - -export const tabIndex = - ({ props, state }: Pick) => - (): number => - state.isDisabled || (state.isGroup && state.model !== props.label) ? -1 : 0 - -export const getModel = - ({ props, state }: Pick) => - (): IRadioState['model'] => - state.isGroup && state.radioGroup ? state.radioGroup.modelValue : props.modelValue - -export const setModel = - ({ - constants, - dispatch, - emit, - props, - vm, - state - }: Pick) => - (val: IRadioState['model']): void => { - if (state.isGroup) { - dispatch(constants.RADIO_GROUP, 'update:modelValue', [val]) - } else { - emit('update:modelValue', val) - } - - vm.$refs.radio && (vm.$refs.radio.checked = state.model === props.label) - } - -export const toggleEvent = ({ props, vm, type }: Pick) => { - const radioEl = vm.$refs.radio - - if (radioEl) { - Object.keys(props.events).forEach((ev) => { - radioEl[type + 'EventListener'](ev, props.events[ev]) - }) - } -} diff --git a/packages/mobile/components/radio/src/renderless/vue.ts b/packages/mobile/components/radio/src/renderless/vue.ts deleted file mode 100644 index 44ccf9612c..0000000000 --- a/packages/mobile/components/radio/src/renderless/vue.ts +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { - IRadioApi, - IRadioProps, - IRadioState, - ISharedRenderlessParamHooks, - IRadioRenderlessParamUtils -} from '../radio' -import { - handleChange, - isGroup, - radioSize, - isDisabled, - isDisplayOnly, - tabIndex, - getModel, - setModel, - toggleEvent -} from './index' - -export const api = ['state', 'handleChange'] - -export const renderless = ( - props: IRadioProps, - { onMounted, onBeforeUnmount, computed, reactive, inject }: ISharedRenderlessParamHooks, - { vm, parent, emit, constants, nextTick, dispatch }: IRadioRenderlessParamUtils -): IRadioApi => { - parent.tinyForm = parent.tinyForm || inject('form', null) - - const api = {} as IRadioApi - - const state: IRadioState = reactive({ - vertical: inject('radioVertical', false), - size: computed(() => props.size || inject('size', null) || (parent.tinyForm || {}).size), - focus: false, - radioGroup: null, - isGroup: computed(() => api.isGroup()), - radioSize: computed(() => api.radioSize()), - isDisabled: computed(() => api.isDisabled()), - isDisplayOnly: computed(() => api.isDisplayOnly() || (parent.tinyForm || {}).displayOnly), - tabIndex: computed(() => api.tabIndex()), - formDisabled: computed(() => (parent.tinyForm || {}).disabled), - model: computed({ - get: () => api.getModel(), - set: (val) => api.setModel(val) - }) - }) - - Object.assign(api, { - state, - radioSize: radioSize({ props, state }), - getModel: getModel({ props, state }), - isGroup: isGroup({ constants, parent, state }), - tabIndex: tabIndex({ props, state }), - isDisabled: isDisabled({ props, state }), - isDisplayOnly: isDisplayOnly({ props }), - setModel: setModel({ constants, dispatch, emit, props, vm, state }), - handleChange: handleChange({ constants, dispatch, emit, state, nextTick }) - }) - - onMounted(() => { - dispatch('Tooltip', 'tooltip-update') - toggleEvent({ props, vm, type: 'add' }) - }) - - onBeforeUnmount(() => { - toggleEvent({ props, vm, type: 'remove' }) - }) - - return api -} diff --git a/packages/mobile/components/search/index.ts b/packages/mobile/components/search/index.ts deleted file mode 100644 index b4b3d217e1..0000000000 --- a/packages/mobile/components/search/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Search from './src/mobile.vue' - -/* istanbul ignore next */ -Search.install = function (Vue) { - Vue.component(Search.name, Search) -} - -export default Search diff --git a/packages/mobile/components/search/src/mobile.vue b/packages/mobile/components/search/src/mobile.vue deleted file mode 100644 index 238962f3dd..0000000000 --- a/packages/mobile/components/search/src/mobile.vue +++ /dev/null @@ -1,86 +0,0 @@ - - - - diff --git a/packages/mobile/components/search/src/renderless/index.ts b/packages/mobile/components/search/src/renderless/index.ts deleted file mode 100644 index e6436db966..0000000000 --- a/packages/mobile/components/search/src/renderless/index.ts +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ISearchRenderlessParams, ISearchValue } from '../search' -import { on, off } from '@mobile-root/utils/deps/dom' -import PopupManager from '@mobile-root/utils/deps/popup-manager' -import { isObject, typeOf } from '@mobile-root/utils/type' - -export const emitInput = - ({ emit }: Pick) => - (...args: [string, ISearchValue]) => { - emit('update:modelValue', ...args) - emit('input', ...args) - } - -// change跟tinyInput组件的change是同步的,所以此处不建议同步aui -export const handleChange = - ({ emit, state }: Pick) => - (event: Event) => { - const value = event.target.value - emit('change', state.searchValue, value) - } - -export const handleInput = - ({ api, props, state }: Pick) => - (event: Event) => { - const value = event.target ? event.target.value : event - - api.emitInput(value, state.searchValue) - } - -export const showSelector = - ({ vm, state }: Pick) => - () => { - vm.$refs.selector.style.zIndex = PopupManager.nextZIndex() - state.show = true - } - -export const changeKey = - ({ emit, state }: Pick) => - (key: ISearchValue) => { - state.searchValue = key - state.show = false - - emit('select', key) - } - -export const searchClick = - ({ emit, props, state }: Pick) => - (event: Event) => { - event.preventDefault() - if (props.mini && state.collapse) { - state.collapse = false - } else { - emit('search', state.searchValue, state.currentValue) - } - } - -export const searchEnterKey = - ({ api, props, vm, nextTick }: Pick) => - (event: Event) => { - if (props.isEnterSearch) { - api.searchClick(event) - nextTick(() => vm.$refs.input.blur()) - } - } - -export const clickOutside = - ({ parent, props, state }: Pick) => - (event: Event) => { - if (!parent.$el.contains(event.target)) { - state.show = false - props.mini && !state.currentValue && (state.collapse = true) - } - } - -export const setDefaultType = (searchTypes: ISearchValue[], typeValue: ISearchValue): ISearchValue => { - if (typeValue && searchTypes.includes(typeValue)) { - return typeValue - } - - let type = {} as ISearchValue - - for (let i = 0, len = searchTypes.length; i < len; i++) { - if ( - isObject(searchTypes[i]) && - typeOf(searchTypes[i].value) !== 'undefined' && - typeOf(searchTypes[i].text) !== 'undefined' - ) { - type = searchTypes[i] - break - } - } - - return type -} - -export const formatSearchTypes = (searchTypes: ISearchValue[]): ISearchValue[] => { - const types = [] as ISearchValue[] - - for (let i = 0, len = searchTypes.length; i < len; i++) { - if ( - isObject(searchTypes[i]) && - typeOf(searchTypes[i].value) !== 'undefined' && - typeOf(searchTypes[i].text) !== 'undefined' - ) { - types.push(searchTypes[i]) - } - } - - return types -} - -/* istanbul ignore next */ -export const mounted = - ({ api }: Pick) => - () => { - on(document.body, 'click', api.clickOutside) - } - -/* istanbul ignore next */ -export const beforeDestroy = - ({ api }: Pick) => - () => { - off(document.body, 'click', api.clickOutside) - } - -export const clear = - ({ api, emit, vm, state }: Pick) => - (event: Event) => { - event.preventDefault() - state.currentValue = '' - vm.$refs.input.focus() - state.focus = true - - // 应先更新modelValue的值,才能触发change事件。所以不同步aui - api.emitInput('', state.searchValue) - emit('change', [], '') - emit('clear') - } diff --git a/packages/mobile/components/search/src/renderless/vue.ts b/packages/mobile/components/search/src/renderless/vue.ts deleted file mode 100644 index 946361e4a3..0000000000 --- a/packages/mobile/components/search/src/renderless/vue.ts +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { - ISearchState, - ISearchProps, - ISearchApi, - ISharedRenderlessParamHooks, - ISearchRenderlessParamUtils -} from '../search' - -import { - clear, - handleChange, - handleInput, - showSelector, - changeKey, - searchClick, - clickOutside, - beforeDestroy, - mounted, - formatSearchTypes, - setDefaultType, - searchEnterKey, - emitInput -} from './index' - -export const api = [ - 'state', - 'handleChange', - 'handleInput', - 'showSelector', - 'changeKey', - 'searchClick', - 'searchEnterKey', - 'inputStyle', - 'formatSearchTypes', - 'setDefaultType', - 'clear' -] - -export const useFormatSearchTypes = ({ computed, props, reactive, toRefs, watch }) => { - const api = { - setDefaultType, - formatSearchTypes - } - - const state = reactive({ - searchValue: props.typeValue, - types: computed(() => api.formatSearchTypes(props.searchTypes)) - }) - - watch( - () => props.typeValue, - () => { - state.searchValue = api.setDefaultType(props.searchTypes, props.typeValue) - }, - { immediate: true } - ) - - return { - api, - state: toRefs(state) - } -} - -export const renderless = ( - props: ISearchProps, - { computed, onBeforeUnmount, onMounted, reactive, toRefs, watch }: ISharedRenderlessParamHooks, - { vm, parent, emit, nextTick }: ISearchRenderlessParamUtils -): ISearchApi => { - const formatSearchTypes = useFormatSearchTypes({ - computed, - props, - reactive, - toRefs, - watch - }) - - const state: ISearchState = reactive({ - show: false, - focus: false, - hovering: false, - collapse: props.mini, - currentValue: props.modelValue, - ...formatSearchTypes.state, - showClear: computed(() => props.clearable && (state.focus || state.hovering) && state.currentValue), - formItemSize: computed(() => (parent.formItem || {}).formItemSize), - searchSize: computed(() => props.size || state.formItemSize) - }) - - const api = { - state, - changeKey: changeKey({ state, emit }), - handleChange: handleChange({ emit, state }), - showSelector: showSelector({ vm, state }), - searchClick: searchClick({ emit, props, state }), - clickOutside: clickOutside({ parent, props, state }), - emitInput: emitInput({ emit }), - ...formatSearchTypes.api - } as ISearchApi - - Object.assign(api, { - clear: clear({ api, emit, vm, state }), - handleInput: handleInput({ api, props, state }), - searchEnterKey: searchEnterKey({ api, props, vm, nextTick }) - }) - - onMounted(mounted({ api })) - onBeforeUnmount(beforeDestroy({ api })) - - watch( - () => props.modelValue, - (value) => (state.currentValue = value) - ) - - return api -} diff --git a/packages/mobile/components/search/src/search.ts b/packages/mobile/components/search/src/search.ts deleted file mode 100644 index 7bfcdc5348..0000000000 --- a/packages/mobile/components/search/src/search.ts +++ /dev/null @@ -1,138 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import { t } from '@opentiny/vue-locale' -import type { ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const searchProps = { - mini: { - type: Boolean, - default: false - }, - big: { - type: Boolean, - default: false - }, - buttonText: { - type: String, - default: () => t('ui.search.placeholder') - }, - - /** - * 设置为透明模式,配置为true时,边框变为透明且收缩后半透明显示,一般用在带有背景的场景 - */ - transparent: { - type: Boolean, - default: false - }, - - /** - * 搜索的类型选项,格式为[{text:'文档',value:1},...],不配置时类型选择固定显示为All - */ - searchTypes: { - type: Array, - default: () => [] - }, - - /** - * 设置搜索输入框内的提示占位文本 - */ - placeholder: { - type: String, - default: '' - }, - modelValue: { - type: String, - default: '' - }, - clearable: { - type: Boolean, - default: false - }, - tabindex: { - type: String, - default: '1' - }, - - /** - * 配置搜索输入框enter键,enter按下触发搜索 - */ - isEnterSearch: { - type: Boolean, - default: true - }, - /** - * 配置主题色,primary:蓝 gray:灰 - */ - themeType: { - type: String, - default: 'primary', - validator: (value: string) => ['primary', 'gray'].includes(value) - }, - showButton: { - type: Boolean, - default: false - }, - changeBgColor: { - type: Boolean, - default: false - }, - size: { - type: String, - default: 'small' - }, - typeValue: Object, - suffixIcon: [Object, String] -} -export interface ISearchState { - show: boolean - focus: boolean - hovering: boolean - collapse: boolean - currentValue: string - searchValue: object - types: string[] - showClear: boolean - formItemSize: string - searchSize: string -} - -export type ISearchProps = ExtractPropTypes - -export type ISearchRenderlessParams = ISharedRenderlessFunctionParams & { - state: ISearchState - props: ISearchProps - api: ISearchApi -} - -export interface ISearchValue { - text: string - value: number -} -export interface ISearchApi { - state: ISearchState - changeKey: (key: ISearchValue) => void - handleChange: (event: Event) => void - showSelector: () => void - searchClick: (event: Event) => void - clickOutside: (event: Event) => void - emitInput: (...args: [string, ISearchValue]) => void - setDefaultType: (searchTypes: ISearchValue[]) => ISearchValue - formatSearchTypes: (searchTypes: ISearchValue[]) => ISearchValue[] - clear: (event: Event) => void - handleInput: (event: Event) => void - searchEnterKey: () => void -} - -export type ISearchRenderlessParamUtils = ISharedRenderlessParamUtils diff --git a/packages/mobile/components/slider/index.ts b/packages/mobile/components/slider/index.ts deleted file mode 100644 index fed60d8e07..0000000000 --- a/packages/mobile/components/slider/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Slider from './src/mobile.vue' - -Slider.install = function (Vue) { - Vue.component(Slider.name, Slider) -} - -export default Slider diff --git a/packages/mobile/components/slider/src/mobile.vue b/packages/mobile/components/slider/src/mobile.vue deleted file mode 100644 index 33f840cfb0..0000000000 --- a/packages/mobile/components/slider/src/mobile.vue +++ /dev/null @@ -1,75 +0,0 @@ - - - - diff --git a/packages/mobile/components/slider/src/renderless/index.ts b/packages/mobile/components/slider/src/renderless/index.ts deleted file mode 100644 index c2efb0e661..0000000000 --- a/packages/mobile/components/slider/src/renderless/index.ts +++ /dev/null @@ -1,642 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { KEY_CODE } from '@mobile-root/utils' -import { emitEvent } from '@mobile-root/utils/event' -import { on, off, hasClass } from '@mobile-root/utils/deps/dom' -import { toNumber } from '@mobile-root/utils/string' -import type { ISliderApi, ISliderRenderlessParams, ISliderState } from '../slider' - -export const bindEvent = (api: ISliderApi) => () => { - on(window, 'resize', api.bindResize) - api.bindResize() -} - -export const unBindEvent = (api: ISliderApi) => () => off(window, 'resize', api.bindResize) - -export const bindResize = - ({ vm, props, state }: Pick) => - () => { - const handleEl = vm.$refs.slider - state.sliderSize = handleEl['client' + (props.vertical ? 'Height' : 'Width')] - state.sliderOffset = handleEl.getBoundingClientRect() - } - -export const bindKeyDown = - ({ api, props, state }: Pick) => - (event) => { - if (state.disabled || state.activeIndex < 0) { - return - } - - event.preventDefault() - - let currentValue = 0 - - switch (event.keyCode) { - case KEY_CODE.Home: - currentValue = props.min - break - case KEY_CODE.End: - currentValue = props.max - break - case KEY_CODE.PageUp: - currentValue = state.activeValue + Math.ceil(state.rangeDiff / props.numPages) - break - case KEY_CODE.PageDown: - currentValue = state.activeValue - Math.ceil(state.rangeDiff / props.numPages) - break - case KEY_CODE.ArrowUp: - case KEY_CODE.ArrowRight: - currentValue = state.activeValue + props.step - break - case KEY_CODE.ArrowDown: - case KEY_CODE.ArrowLeft: - currentValue = state.activeValue - props.step - break - default: - currentValue = state.activeValue - break - } - - api.setActiveButtonValue(currentValue) - api.setButtonStyle() - api.setBarStyle() - } - -export const bindMouseDown = - ({ - api, - constants, - mode, - emit, - state, - props - }: Pick) => - (event) => { - if (event.button !== 0 && event.detail !== 0) { - state.activeIndex = -1 - return - } - - if (!emitEvent(emit, 'start', api.getActiveButtonValue())) { - state.activeIndex = -1 - return - } - - const handleEl = event.target - let isClickBar: boolean | undefined = false - let isClickBtn: boolean | undefined = false - let isClickLabel: boolean | undefined = false - - isClickBar = hasClass(handleEl, constants.sliderCls(mode)) || hasClass(handleEl, constants.rangeCls(mode)) - isClickBtn = - hasClass(handleEl, constants.buttonCls(mode)) || - hasClass(handleEl, constants.leftSvgCls(mode)) || - hasClass(handleEl, constants.rightSvgCls(mode)) - isClickLabel = hasClass(handleEl, constants.PC_LABEL_CLS) - - if (state.disabled || (!isClickBtn && !isClickBar && !isClickLabel)) { - state.activeIndex = -1 - return - } - - on(window, 'mouseup', api.bindMouseUp) - on(window, 'mousemove', api.bindMouseMove) - on(window, 'touchend', api.bindMouseUp) - on(window, 'touchmove', api.bindMouseMove) - - state.isDrag = isClickBtn - isClickBtn && (state.activeIndex = api.getActiveButtonIndex(event)) - - if (isClickBar || isClickLabel) { - const currentValue = api.calculateValue(event) - if (state.isDouble) { - if (Math.abs(currentValue - state.leftBtnValue) > Math.abs(state.rightBtnValue - currentValue)) { - api.changeActiveValue(state.rightBtnValue < state.leftBtnValue) - } else { - api.changeActiveValue(state.rightBtnValue > state.leftBtnValue) - } - } - api.setActiveButtonValue(currentValue) - api.setButtonStyle() - api.setBarStyle() - - emit('stop', api.getActiveButtonValue()) - - if (!props.changeCompat) { - emit('change', api.getActiveButtonValue()) - } - } - } - -export const bindMouseMove = - ({ api, nextTick, state }: Pick) => - (event) => { - if (state.disabled || !state.isDrag) { - return - } - - api.setActiveButtonValue(api.calculateValue(event)) - api.setButtonStyle() - api.setBarStyle() - - nextTick(() => { - api.setTipStyle() - }) - } - -export const bindMouseUp = - ({ api, emit, state, props }: Pick) => - () => { - if (state.disabled || !state.isDrag) { - return - } - - if (state.mouseOuterBtn) { - state.showTip = false - } - state.isDrag = false - - off(window, 'mouseup', api.bindMouseUp) - off(window, 'mousemove', api.bindMouseMove) - off(window, 'touchend', api.bindMouseUp) - off(window, 'touchmove', api.bindMouseMove) - - emit('stop', api.getActiveButtonValue()) - - if (!props.changeCompat) { - emit('change', api.getActiveButtonValue()) - } - } - -export const displayTip = - ({ api, nextTick, state }: Pick) => - (event) => { - state.mouseOuterBtn = false - if (!state.showTip) { - state.showTip = true - api.changeActiveValue(api.getActiveButtonIndex(event) === 0) - - nextTick(() => { - api.setTipStyle() - }) - } - } - -export const hideTip = (state: ISliderState) => () => { - state.mouseOuterBtn = true - !state.isDrag && (state.showTip = false) -} - -export const setTipStyle = - ({ - constants, - mode, - vm, - props, - state - }: Pick) => - () => { - if (!props.showTip) { - return - } - - const tipStyle = { top: 0, left: 0 } - const tipEl = vm.$refs.sliderTip - const moveSize = ((state.activeValue - props.min) / state.rangeDiff) * state.sliderSize - - if (props.vertical) { - tipStyle.top = - state.sliderSize - moveSize - constants.BUTTON_SIZE - constants.TIP_HEIGHT / 2 + constants.HALF_BAR_HEIGHT - tipStyle.left = -tipEl.getBoundingClientRect().width / 2 + constants.HALF_BAR_HEIGHT - } else { - tipStyle.top = -constants.TIP_HEIGHT - constants.BUTTON_SIZE / 2 + constants.HALF_BAR_HEIGHT - tipStyle.left = moveSize - tipEl.getBoundingClientRect().width / 2 - } - state.tipStyle = { - top: tipStyle.top + 'px', - left: tipStyle.left + 'px' - } - } - -const getActiveButtonIndexFlag = ({ - state, - event, - constants, - mode -}: Pick) => { - const cls = constants.buttonCls(mode) - const { previousElementSibling } = event.target as HTMLElement - - return ( - state.isDouble && - (hasClass(previousElementSibling, cls) || - (event.target as SVGAElement).className.baseVal === 'tiny-slider-right-svg') - ) -} - -export const getActiveButtonIndex = - ({ constants, mode, state }: Pick) => - (event) => { - const flag = getActiveButtonIndexFlag({ state, event, constants, mode }) - return flag ? 1 : 0 - } - -const calcCurrentValue = ({ - currentValue, - props, - state -}: Pick) => { - if (Array.isArray(currentValue)) { - currentValue = currentValue[state.activeIndex] - } - if (currentValue <= props.min) { - currentValue = props.min - } else if (currentValue >= props.max) { - currentValue = props.max - } else { - const step = props.step > 0 ? props.step : 1 - // step的精度 - let stepPrecision = 0 - if (step - parseInt(step) > 0) { - stepPrecision = step.toString().split('.')[1].length - } - const stepValue = (currentValue - props.min) % step - - if (stepValue) { - currentValue -= stepValue - currentValue += stepValue * 2 > step ? Number(step) : 0 - if (stepPrecision) { - // step为小数时,currentValue也保持相同的精度 - currentValue = Number(currentValue.toFixed(stepPrecision)) - } - } - - if (state.isDouble) { - if (state.activeIndex === 0 && currentValue >= state.rightBtnValue) { - currentValue = state.rightBtnValue - } else if (state.activeIndex === 1 && currentValue <= state.leftBtnValue) { - currentValue = state.leftBtnValue - } - } - } - - return currentValue -} - -export const setActiveButtonValue = - ({ api, emit, props, state }: Pick) => - (value: number | [number, number]) => { - if (Array.isArray(value)) { - // 在组件初始化和emit('update:modelValue')会发生modelValue为数组的情况 - ;[state.leftBtnValue, state.rightBtnValue] = value - } else { - let currentValue = calcCurrentValue({ currentValue: value, props, state }) - if (!state.isDouble) { - state.leftBtnValue = currentValue - } else { - if (state.activeIndex === 0) { - state.leftBtnValue = currentValue - } else { - state.rightBtnValue = currentValue - } - } - - state.activeValue = currentValue - } - - state.innerTrigger = true // 防止触发 watch - - emit('update:modelValue', api.getActiveButtonValue()) // 添加了一个emit触发input事件,实现双向绑定 - } - -export const setButtonStyle = - ({ props, state }: Pick) => - () => { - const percent = ((state.activeValue - props.min) / state.rangeDiff) * 100 - const style = (props.vertical ? 'bottom' : 'left') + ':' + percent + '%' - - if (!state.isDouble || state.activeIndex === 0) { - state.leftBtnPercent = percent - state.leftBtnStyle = style - } else { - state.rightBtnPercent = percent - state.rightBtnStyle = style - } - } - -export const setBarStyle = - ({ props, state }: Pick) => - () => { - const minSize = Math.abs(state.leftBtnPercent - state.rightBtnPercent) - const maxSize = Math.max(state.leftBtnPercent, state.rightBtnPercent) - - if (props.vertical) { - state.barStyle = { - bottom: maxSize - minSize + '%', - height: minSize + '%' - } - } else { - state.barStyle = { - left: maxSize - minSize + '%', - width: minSize + '%' - } - } - } - -export const initSlider = - ({ api, props, state }: Pick) => - (value) => { - if (state.isDrag) return - - state.isDouble = Array.isArray(value) - - const sliders = state.isDouble ? value : [value] - - sliders.length > 2 && (sliders.length = 2) - sliders.forEach((item, index) => { - if (index === 0) { - state.leftBtnValue = Math.max(Number(item), props.min) - } else { - state.rightBtnValue = Math.min(Number(item), props.max) - state.rightBtnShow = true - } - - api.changeActiveValue(index === 0) - - api.setButtonStyle() - }) - - api.setBarStyle() - } - -export const calculateValue = - ({ props, state, vm }: Pick) => - (event) => { - let currentValue = 0 - - if (state.sliderSize === 0) { - const handleEl = vm.$refs.slider - state.sliderSize = handleEl['client' + (props.vertical ? 'Height' : 'Width')] - state.sliderOffset = handleEl.getBoundingClientRect() - } - - const offset = state.sliderOffset as DOMRect - - if (event.type === 'touchmove' || event.type === 'touchstart' || event.type === 'touchend') { - if (props.vertical) { - currentValue = props.max - ((event.touches[0].pageY - offset.top) / state.sliderSize) * state.rangeDiff - } else { - currentValue = props.min + ((event.touches[0].pageX - offset.left) / state.sliderSize) * state.rangeDiff - } - } else { - if (props.vertical) { - currentValue = props.max - ((event.pageY - offset.top) / state.sliderSize) * state.rangeDiff - } else { - currentValue = props.min + ((event.pageX - offset.left) / state.sliderSize) * state.rangeDiff - } - } - return currentValue - } - -export const changeActiveValue = (state) => (isLeft) => { - state.activeIndex = isLeft ? 0 : 1 - state.activeValue = isLeft ? state.leftBtnValue : state.rightBtnValue -} - -export const formatTipValue = (props) => (value) => - props.formatTooltip instanceof Function ? props.formatTooltip(value) : value - -export const getActiveButtonValue = (state: ISliderRenderlessParams['state']) => (): number | number[] => - state.isDouble ? [state.leftBtnValue, state.rightBtnValue] : state.leftBtnValue - -export const autoSlider = (api) => (value) => { - api.setActiveButtonValue(value) - api.setButtonStyle() - api.setBarStyle() -} - -export const customBeforeAppearHook = (props) => (el) => { - if (props.vertical) { - el.style.bottom = 0 + '%' - el.style.height = 0 + '%' - } else { - el.style.left = 0 + '%' - el.style.width = 0 + '%' - } -} - -export const customAppearHook = () => (el) => { - el.style.transition = 'all 0.5s' -} - -export const customAfterAppearHook = - ({ state, props }) => - (el) => { - const minSize = Math.abs(state.leftBtnPercent - state.rightBtnPercent) - const maxSize = Math.max(state.leftBtnPercent, state.rightBtnPercent) - - if (props.vertical) { - el.style.bottom = maxSize - minSize + '%' - el.style.height = minSize + '%' - } else { - if (state.isDouble) { - el.style.left = maxSize - minSize + '%' - el.style.width = minSize + '%' - } else { - el.style.width = minSize + '%' - } - } - } - -export const watchActiveValue = - ({ api, emit, props, state }) => - (newValue, oldValue) => { - const nNewValue = toNumber(newValue) || 0 - const nOldValue = toNumber(oldValue) || 0 - - if (nNewValue !== nOldValue) { - api.autoSlider(nNewValue) - - if (nNewValue <= props.max && nNewValue >= props.min) { - const value = api.getActiveButtonValue() - - if (state.lastValue && state.lastValue.toString() !== value.toString()) { - emit('change', value) - } - - state.lastValue = value - } - } else { - state.activeValue = nNewValue || 0 - } - } - -export const watchModelValue = - ({ api, state }: Pick) => - (value) => { - // 防止多触点下,触发双向绑定导致渲染异常 - if (!state.innerTrigger) { - api.initSlider(value) - api.setActiveButtonValue(value) - } else { - state.innerTrigger = false - - if (!state.isDouble) { - api.initSlider(value) - api.setActiveButtonValue(value) - } - } - - // 正在输入时,不应该改变输入的内容 - if (!state.isSlotTyping) { - api.updateSlotValue() - } - } - -export const getPoints = - ({ props, state }: Pick) => - () => { - if (props.showSteps && props.step > 0) { - state.points = [] - const num = Math.floor(props.max / props.step) - for (let i = 1; i < num; i++) { - const point = { - position: (i / num) * 100 + '%', - value: (i / num) * props.max - } - state.points.push(point) - } - } - } - -export const getLabels = - ({ props, state }: Pick) => - () => { - if (props.showLabel) { - state.labels = [] - - const isFunction = props.formatLabel instanceof Function - const num = Math.floor(props.max / props.step) - for (let i = 0; i <= num; i++) { - const val = (i / num) * props.max - const label = { - position: (i / num) * 100 + '%', - label: isFunction ? props.formatLabel(val, i) : val, - value: val - } - state.labels.push(label) - } - } - } - -interface IMarkListItem { - value: number - label: string - percent: number - positionStyle: { [key: string]: string } -} - -export const getMarkList = - ({ props }: Pick) => - (): IMarkListItem[] => { - const markList: IMarkListItem[] = [] - - if (!props.marks) { - return markList - } - - for (const [key, label] of Object.entries(props.marks)) { - const markValue = Number(key) - - if (markValue >= props.min && markValue <= props.max) { - const percent = (markValue - props.min) / (props.max - props.min) - markList.push({ - value: markValue, - label, - percent, - positionStyle: { - [props.vertical ? 'bottom' : 'left']: percent * 100 + '%' - } - }) - } - } - - return markList - } - -export const inputValueChange = - ({ props, state, api, emit }: Pick) => - ($event, pos) => { - if (props.disabled || !state.isDouble) return - - if (!/^\d+$/.test($event.target.value)) { - if (pos === 'left') { - state.inputValue.splice(0, 1, state.leftBtnValue) - } else { - state.inputValue.splice(1, 1, state.rightBtnValue) - } - return - } - api.initSlider([Math.min(...state.inputValue), Math.max(...state.inputValue)]) - - if (!props.changeCompat) { - emit('change', api.getActiveButtonValue()) - } - } - -export const handleSlotInputFocus = (state: ISliderRenderlessParams['state']) => () => { - state.isSlotTyping = true -} - -export const handleSlotInputBlur = - ({ state, api }: Pick) => - () => { - state.isSlotTyping = false - api.updateSlotValue() - } - -export const updateSlotValue = - ({ state }: Pick) => - () => { - if (!state.isDouble) { - state.slotValue = state.activeValue - } else { - state.slotValue = - state.activeIndex === 0 ? [state.activeValue, state.rightBtnValue] : [state.leftBtnValue, state.activeValue] - } - } - -export const handleSlotInput = - ({ state, api }: Pick) => - (event: Event, isLeftInput = true): void => { - const inputValue = (event.target as HTMLInputElement).value - - api.changeActiveValue(state.isDouble ? isLeftInput : true) - state.activeValue = Number(inputValue) - api.updateSlotValue() - } - -export const inputOnChange = - ({ api, emit, props, state }: Pick) => - (event: Event) => { - if (!props.changeCompat) { - if (!/^\d+$/.test(event.target.value)) { - state.activeValue = state.leftBtnValue - return - } - const value = toNumber(state.activeValue) || 0 - api.autoSlider(value) - emit('change', api.getActiveButtonValue()) - } - } diff --git a/packages/mobile/components/slider/src/renderless/vue.ts b/packages/mobile/components/slider/src/renderless/vue.ts deleted file mode 100644 index 954922ab38..0000000000 --- a/packages/mobile/components/slider/src/renderless/vue.ts +++ /dev/null @@ -1,231 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - bindKeyDown, - bindMouseDown, - bindMouseMove, - bindMouseUp, - bindEvent, - unBindEvent, - bindResize, - setTipStyle, - getActiveButtonIndex, - setActiveButtonValue, - setBarStyle, - setButtonStyle, - initSlider, - calculateValue, - changeActiveValue, - formatTipValue, - getActiveButtonValue, - displayTip, - hideTip, - autoSlider, - customBeforeAppearHook, - customAppearHook, - customAfterAppearHook, - watchActiveValue, - watchModelValue, - getPoints, - getLabels, - inputValueChange, - inputOnChange, - handleSlotInputFocus, - handleSlotInputBlur, - handleSlotInput, - getMarkList, - updateSlotValue -} from './index' - -import type { - ISliderProps, - ISliderState, - ISharedRenderlessParamHooks, - ISliderApi, - ISliderRenderlessParamUtils -} from '../slider' - -export const api = [ - 'state', - 'bindKeyDown', - 'bindMouseDown', - 'bindMouseMove', - 'bindMouseUp', - 'bindEvent', - 'unBindEvent', - 'bindResize', - 'setTipStyle', - 'getActiveButtonIndex', - 'setActiveButtonValue', - 'setBarStyle', - 'setButtonStyle', - 'initSlider', - 'calculateValue', - 'changeActiveValue', - 'formatTipValue', - 'getActiveButtonValue', - 'displayTip', - 'hideTip', - 'autoSlider', - 'customBeforeAppearHook', - 'customAppearHook', - 'customAfterAppearHook', - 'inputValueChange', - 'inputOnChange', - 'handleSlotInputFocus', - 'handleSlotInputBlur', - 'handleSlotInput' -] - -const initState = ({ reactive, computed, props, api, parent, inject }) => { - const state: ISliderState = reactive({ - showAutoWidth: inject('showAutoWidth', null), - tipStyle: {}, - barStyle: {}, - moveStyle: [], - points: [], - labels: [], - markList: computed(() => api.getMarkList()), - inputValue: [0, 0], - isDrag: false, - sliderSize: 0, - showTip: false, - activeValue: 0, - activeIndex: 0, - isDouble: false, - leftBtnValue: 0, - sliderOffset: {}, - rightBtnValue: 0, - leftBtnStyle: {}, - leftBtnPercent: 0, - leftBtnShow: true, - rightBtnStyle: '', - rightBtnPercent: 0, - rightBtnShow: false, - innerTrigger: false, - changeCompat: computed(() => props.changeCompat), - rangeDiff: computed(() => props.max - props.min), - tipValue: computed(() => api.formatTipValue(state.activeValue)), - formDisabled: computed(() => (parent.tinyForm || {}).disabled), - disabled: computed(() => props.disabled || state.formDisabled), - slotValue: '', - isSlotTyping: false, - mouseOuterBtn: false - }) - - return state -} - -export const renderless = ( - props: ISliderProps, - { computed, onBeforeUnmount, onMounted, reactive, watch, inject }: ISharedRenderlessParamHooks, - { vm, parent, constants, nextTick, emit, mode }: ISliderRenderlessParamUtils -) => { - const api = {} as ISliderApi - const state: ISliderState = initState({ reactive, computed, props, api, parent, inject }) - parent.tinyForm = parent.tinyForm || inject('form', null) - - Object.assign(api, { - state, - hideTip: hideTip(state), - formatTipValue: formatTipValue(props), - setBarStyle: setBarStyle({ props, state }), - changeActiveValue: changeActiveValue(state), - bindResize: bindResize({ vm, props, state }), - setButtonStyle: setButtonStyle({ props, state }), - calculateValue: calculateValue({ vm, props, state }), - getActiveButtonValue: getActiveButtonValue(state), - getActiveButtonIndex: getActiveButtonIndex({ constants, mode, state }), - setTipStyle: setTipStyle({ vm, constants, mode, props, state }), - customAfterAppearHook: customAfterAppearHook({ state, props }), - customBeforeAppearHook: customBeforeAppearHook(props), - customAppearHook: customAppearHook(), - bindEvent: bindEvent(api), - autoSlider: autoSlider(api), - unBindEvent: unBindEvent(api), - displayTip: displayTip({ api, nextTick, state }), - bindKeyDown: bindKeyDown({ api, props, state }), - bindMouseUp: bindMouseUp({ api, emit, state, props }), - bindMouseMove: bindMouseMove({ api, nextTick, state }), - bindMouseDown: bindMouseDown({ api, constants, mode, emit, state, props }), - setActiveButtonValue: setActiveButtonValue({ api, emit, props, state }), - initSlider: initSlider({ api, props, state }), - watchModelValue: watchModelValue({ api, state }), - watchActiveValue: watchActiveValue({ api, emit, props, state }), - getPoints: getPoints({ props, state }), - getLabels: getLabels({ props, state }), - inputValueChange: inputValueChange({ props, api, state, emit }), - handleSlotInputFocus: handleSlotInputFocus(state), - handleSlotInputBlur: handleSlotInputBlur({ state, api }), - handleSlotInput: handleSlotInput({ state, api }), - getMarkList: getMarkList({ props }), - updateSlotValue: updateSlotValue({ state }), - inputOnChange: inputOnChange({ api, emit, props, state }) - }) - - watch( - () => props.modelValue, - (value) => { - if (props.max < props.min) { - throw new Error('Slider min should not be greater than max.') - } - api.watchModelValue(value) - }, - { immediate: true } - ) - - props.changeCompat && watch(() => state.activeValue, api.watchActiveValue, { immediate: true }) - - watch(() => state.activeValue, api.watchActiveValue, { immediate: true }) - - watch( - () => props.min, - (min) => { - const value = Math.max(props.modelValue, min) - api.initSlider(value) - api.setActiveButtonValue(value) - } - ) - watch( - () => props.max, - (max) => { - const value = Math.min(props.modelValue, max) - api.initSlider(Math.min(props.modelValue, max)) - api.setActiveButtonValue(value) - } - ) - - watch( - () => state.leftBtnValue, - (newVal) => { - state.inputValue[0] = newVal - }, - { immediate: true } - ) - watch( - () => state.rightBtnValue, - (newVal) => { - state.inputValue[1] = newVal - }, - { immediate: true } - ) - - onMounted(() => { - api.bindEvent() - api.getPoints() - api.getLabels() - }) - onBeforeUnmount(api.unBindEvent) - - return api -} diff --git a/packages/mobile/components/slider/src/slider.ts b/packages/mobile/components/slider/src/slider.ts deleted file mode 100644 index 181afed372..0000000000 --- a/packages/mobile/components/slider/src/slider.ts +++ /dev/null @@ -1,232 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { PropType } from 'vue' -import type { ExtractPropTypes, ComputedRef, CSSProperties } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' -import type { - getMarkList, - getActiveButtonValue, - handleSlotInputFocus, - handleSlotInputBlur, - handleSlotInput, - updateSlotValue -} from './renderless' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const $constants = { - TIP_HEIGHT: 22, - BUTTON_SIZE: 28, - HALF_BAR_HEIGHT: 2, - PC_TIP_CLS: 'tiny-slider__tips', - PC_SLIDER_CLS: 'tiny-slider', - PC_RANGE_CLS: 'tiny-slider__range', - PC_BUTTON_CLS: 'tiny-slider__handle', - PC_LABEL_CLS: 'tiny-slider__mark-label', - PC_LEFT_SVG_CLS: 'tiny-slider-left-svg', - PC_RIGHT_SVG_CLS: 'tiny-slider-right-svg', - MOBILE_TIP_CLS: 'tiny-mobile-slider__tips', - MOBILE_SLIDER_CLS: 'tiny-mobile-slider', - MOBILE_RANGE_CLS: 'tiny-mobile-slider__range', - MOBILE_BUTTON_CLS: 'tiny-mobile-slider__handle', - MOBILE_LEFT_SVG_CLS: 'tiny-mobile-slider-left-svg', - MOBILE_RIGHT_SVG_CLS: 'tiny-mobile-slider-right-svg', - Mode: 'pc', - tipCls(mode) { - return mode === this.Mode ? this.PC_TIP_CLS : this.MOBILE_TIP_CLS - }, - sliderCls(mode) { - return mode === this.Mode ? this.PC_SLIDER_CLS : this.MOBILE_SLIDER_CLS - }, - rangeCls(mode) { - return mode === this.Mode ? this.PC_RANGE_CLS : this.MOBILE_RANGE_CLS - }, - buttonCls(mode) { - return mode === this.Mode ? this.PC_BUTTON_CLS : this.MOBILE_BUTTON_CLS - }, - leftSvgCls(mode) { - return mode === this.Mode ? this.PC_LEFT_SVG_CLS : this.MOBILE_LEFT_SVG_CLS - }, - rightSvgCls(mode) { - return mode === this.Mode ? this.PC_RIGHT_SVG_CLS : this.MOBILE_RIGHT_SVG_CLS - }, - TIP_CLS(mode) { - return mode === this.Mode ? this.PC_TIP_CLS : this.MOBILE_TIP_CLS - }, - SLIDER_CLS(mode) { - return mode === this.Mode ? this.PC_SLIDER_CLS : this.MOBILE_SLIDER_CLS - }, - RANGE_CLS(mode) { - return mode === this.Mode ? this.PC_RANGE_CLS : this.MOBILE_RANGE_CLS - }, - BUTTON_CLS(mode) { - return mode === this.Mode ? this.PC_BUTTON_CLS : this.MOBILE_BUTTON_CLS - } -} - -export const sliderProps = { - _constants: { - type: Object, - default: () => $constants - }, - formatTooltip: Function, - disabled: { - type: Boolean, - default: false - }, - height: { - type: String, - default: '300px' - }, - max: { - type: Number, - default: 100 - }, - min: { - type: Number, - default: 0 - }, - modelValue: { - type: [Number, Array], - default: 0 - }, - numPages: { - type: Number, - default: 1 - }, - range: { - type: Boolean, - default: false - }, - showInput: { - type: Boolean, - default: false - }, - showTip: { - type: Boolean, - default: true - }, - step: { - type: Number, - default: 1 - }, - vertical: { - type: Boolean, - default: false - }, - unit: { - type: String, - default: '%' - }, - showSteps: { - type: Boolean, - default: false - }, - showLabel: { - type: Boolean, - default: false - }, - changeCompat: { - type: Boolean, - default: false - }, - // tiny 新增属性 - marks: { - type: Object as PropType> - } -} - -export type ISliderProps = ExtractPropTypes - -export type ISliderConstants = typeof $constants - -export interface ISliderState { - tipStyle: object - barStyle: CSSProperties - moveStyle: object - points: object[] - labels: object[] - isDrag: boolean - sliderSize: number - inputValue: [number, number] - showTip: boolean - activeValue: number - activeIndex: number - isDouble: boolean - leftBtnValue: number - sliderOffset: DOMRect | null - rightBtnValue: number - leftBtnStyle: string - leftBtnPercent: number - leftBtnShow: true - mouseOuterBtn: boolean - rightBtnStyle: string - rightBtnPercent: number - rightBtnShow: boolean - innerTrigger: boolean - rangeDiff: ComputedRef - tipValue: ComputedRef - formDisabled: ComputedRef - disabled: boolean - /** 使用这个值作为插槽中输入的值,而不是直接用activeValue,来实现在输入时不会被max min属性计算而改变 */ - slotValue: number | number[] | string - /** 是否正在输入 */ - isSlotTyping: boolean - markList: ReturnType -} - -export interface ISliderApi { - state: ISliderState - hideTip: () => boolean - formatTipValue: () => string - setBarStyle: () => object - changeActiveValue: (value: boolean) => void - bindResize: () => void - setButtonStyle: () => void - calculateValue: (event: Event) => number - getActiveButtonValue: ReturnType - getActiveButtonIndex: (event: Event) => number - setTipStyle: () => void - customAfterAppearHook: () => void - customBeforeAppearHook: () => void - bindEvent: () => void - autoSlider: () => void - unBindEvent: () => void - displayTip: () => void - bindKeyDown: () => void - bindMouseUp: () => void - bindMouseMove: () => void - bindMouseDown: () => void - setActiveButtonValue: (currentValue: number) => void - initSlider: (inputValue: number | number[]) => void - watchModelValue: () => void - watchActiveValue: () => void - getPoints: () => void - getLabels: () => void - inputValueChange: () => void - inputOnChange: () => void - handleSlotInputFocus: ReturnType - handleSlotInputBlur: ReturnType - handleSlotInput: ReturnType - getMarkList: ReturnType - updateSlotValue: ReturnType -} - -export type ISliderRenderlessParams = ISharedRenderlessFunctionParams & { - state: ISliderState - props: ISliderProps - api: ISliderApi - event: Event - currentValue: number -} - -export type ISliderRenderlessParamUtils = ISharedRenderlessParamUtils diff --git a/packages/mobile/components/switch/index.ts b/packages/mobile/components/switch/index.ts deleted file mode 100644 index 02beb7414b..0000000000 --- a/packages/mobile/components/switch/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Switch from './src/mobile.vue' - -/* istanbul ignore next */ -Switch.install = function (Vue) { - Vue.component(Switch.name, Switch) -} - -export default Switch diff --git a/packages/mobile/components/switch/src/mobile.vue b/packages/mobile/components/switch/src/mobile.vue deleted file mode 100644 index 162b1ee675..0000000000 --- a/packages/mobile/components/switch/src/mobile.vue +++ /dev/null @@ -1,32 +0,0 @@ - - - - diff --git a/packages/mobile/components/switch/src/renderless/index.ts b/packages/mobile/components/switch/src/renderless/index.ts deleted file mode 100644 index 9dcec79ce8..0000000000 --- a/packages/mobile/components/switch/src/renderless/index.ts +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { StyleValue } from 'vue' -import type { ISwitchRenderlessParams, ISwitchClass } from '../switch' - -export const toggle = - ({ emit, props, state }: Pick) => - (event: KeyboardEvent | MouseEvent): void => { - event.preventDefault() - - if (state.disabled || props.types === 'loading') { - return - } - - const change = () => { - state.currentValue = state.currentValue === props.trueValue ? props.falseValue : props.trueValue - - emit('update:modelValue', state.currentValue) - emit('change', state.currentValue) - } - - props.beforeChange ? props.beforeChange(change) : change() - } - -export const computedWarpClasses = - ({ prefixCls, props, state }: Pick) => - (): ISwitchClass => { - return [ - { - [prefixCls]: true, - [`${prefixCls}-checked`]: state.currentValue === props.trueValue, - [`${prefixCls}-disabled`]: state.disabled, - mini: props.mini, - disabled: state.disabled - } - ] - } - -export const computedInnerClasses = - ({ prefixCls }: Pick) => - (): string => - `${prefixCls}-inner` - -export const computedStyle = - ({ props, state }: Pick) => - (): StyleValue => { - return { - backgroundColor: props.trueValue === state.currentValue ? props.trueColor : props.falseColor - } - } diff --git a/packages/mobile/components/switch/src/renderless/vue.ts b/packages/mobile/components/switch/src/renderless/vue.ts deleted file mode 100644 index 268aa00ebd..0000000000 --- a/packages/mobile/components/switch/src/renderless/vue.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { toggle, computedWarpClasses, computedInnerClasses, computedStyle } from './index' -import type { - ISwitchApi, - ISwitchProps, - ISwitchState, - ISharedRenderlessParamHooks, - ISwitchRenderlessParamUtils -} from '../switch' - -export const api = ['toggle', 'state'] - -export const renderless = ( - props: ISwitchProps, - { computed, watch, reactive, inject }: ISharedRenderlessParamHooks, - { parent, constants, mode, emit, designConfig }: ISwitchRenderlessParamUtils -): ISwitchApi => { - const prefixCls = constants.prefixcls(mode) - - parent.tinyForm = parent.tinyForm || inject('form', null) - - const state: ISwitchState = reactive({ - currentValue: props.modelValue, - innerClasses: computed(() => api.computedInnerClasses()), - wrapClasses: computed(() => api.computedWarpClasses()), - style: computed(() => api.computedStyle()), - formDisabled: computed(() => (parent.tinyForm || {}).disabled), - disabled: computed(() => props.disabled || state.formDisabled || state.isDisplayOnly || props.loading), - isDisplayOnly: computed(() => props.displayOnly || (parent.tinyForm || {}).displayOnly), - showText: computed(() => { - // 用户没传showText属性时,aurora默认是展示文本 - if (props.showText === undefined) { - return designConfig?.showText || false - } else { - return props.showText - } - }) - }) - - const api: ISwitchApi = { - state, - computedInnerClasses: computedInnerClasses({ prefixCls }), - computedStyle: computedStyle({ props, state }), - computedWarpClasses: computedWarpClasses({ prefixCls, props, state }), - toggle: toggle({ emit, props, state }) - } - - watch( - () => props.modelValue, - (value) => { - state.currentValue = - typeof props.falseValue !== 'boolean' || typeof props.trueValue !== 'boolean' ? value : Boolean(value) - }, - { immediate: true } - ) - - return api -} diff --git a/packages/mobile/components/switch/src/switch.ts b/packages/mobile/components/switch/src/switch.ts deleted file mode 100644 index 6abc01eb8f..0000000000 --- a/packages/mobile/components/switch/src/switch.ts +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ExtractPropTypes, StyleValue } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' -import type { toggle, computedWarpClasses, computedInnerClasses, computedStyle } from './renderless' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const $constants = { - PC_PREFIXCLS: 'tiny-switch', - MOBILE_PREFIXCLS: 'tiny-mobile-switch', - Mode: 'pc', - prefixcls(mode) { - return mode === this.Mode ? this.PC_PREFIXCLS : this.MOBILE_PREFIXCLS - } -} - -export const switchProps = { - _constants: { - type: Object, - default: () => $constants - }, - disabled: { - type: Boolean, - default: false - }, - showText: { - type: Boolean || undefined, - default: undefined - }, - types: { - type: String - }, - falseColor: String, - falseValue: { - type: [String, Number, Boolean], - default: false - }, - mini: { - type: Boolean, - default: false - }, - modelValue: { - type: [String, Number, Boolean], - default: false - }, - size: [Number, String], - tabindex: { - type: String, - default: '1' - }, - trueColor: String, - trueValue: { - type: [String, Number, Boolean], - default: true - }, - beforeChange: Function, - displayOnly: { - type: Boolean, - default: false - }, - loading: { - type: Boolean, - default: false - } -} - -export interface ISwitchState { - currentValue: string | number | boolean - innerClasses: string - wrapClasses: ISwitchClass - style: StyleValue - formDisabled: boolean - disabled: boolean - isDisplayOnly: boolean - showText: boolean -} - -export type ISwitchClass = Array - -export type ISwitchProps = ExtractPropTypes - -export type ISwitchConstants = typeof $constants - -export type ISwitchRenderlessParams = ISharedRenderlessFunctionParams & { - state: ISwitchState - props: ISwitchProps - prefixCls: string -} - -export interface ISwitchApi { - state: ISwitchState - toggle: ReturnType - computedWarpClasses: ReturnType - computedInnerClasses: ReturnType - computedStyle: ReturnType -} - -export type ISwitchRenderlessParamUtils = ISharedRenderlessParamUtils diff --git a/packages/mobile/components/tab-item/index.ts b/packages/mobile/components/tab-item/index.ts deleted file mode 100644 index d29087e3e7..0000000000 --- a/packages/mobile/components/tab-item/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import TabItem from './src/mobile.vue' - -/* istanbul ignore next */ -TabItem.install = function (Vue) { - Vue.component(TabItem.name, TabItem) -} - -export default TabItem diff --git a/packages/mobile/components/tab-item/src/mobile.vue b/packages/mobile/components/tab-item/src/mobile.vue deleted file mode 100644 index 8d2252a5f0..0000000000 --- a/packages/mobile/components/tab-item/src/mobile.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - - diff --git a/packages/mobile/components/tab-item/src/renderless/index.ts b/packages/mobile/components/tab-item/src/renderless/index.ts deleted file mode 100644 index 68b40700ba..0000000000 --- a/packages/mobile/components/tab-item/src/renderless/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ITabItemRenderlessParams } from '@/types' - -export const computedIsClosable = - ({ rootTabs, props }: Pick) => - (): boolean => - props.withClose || rootTabs.withClose - -export const computedActive = - ({ nextTick, props, state }: Pick) => - (): boolean => { - const active = state.rootTabs.state.currentName === (props.name || state.index) - - if (active) { - state.loaded = true - - nextTick(() => { - state.animateShow = true - }) - } else { - state.animateShow = false - } - - return active - } - -export const computedPaneName = - ({ props, state }: Pick) => - (): string | null => - props.name || state.index - -export const watchTitle = (parent: ITabItemRenderlessParams['parent']) => () => parent.$emit('tab-nav-update') diff --git a/packages/mobile/components/tab-item/src/renderless/vue.ts b/packages/mobile/components/tab-item/src/renderless/vue.ts deleted file mode 100644 index 79106cd987..0000000000 --- a/packages/mobile/components/tab-item/src/renderless/vue.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { - ITabItemState, - ITabItemApi, - ITabItemProps, - ISharedRenderlessParamHooks, - ITabItemRenderlessParamUtils, - ITabsVm -} from '../tab-item' -import { computedIsClosable, computedActive, computedPaneName, watchTitle } from './index' - -export const api = ['state'] - -export const renderless = ( - props: ITabItemProps, - { computed, inject, reactive, watch }: ISharedRenderlessParamHooks, - { parent, nextTick }: ITabItemRenderlessParamUtils -): ITabItemApi => { - const rootTabs = inject('rootTabs') as ITabsVm - - const api = { - watchTitle: watchTitle(parent), - computedIsClosable: computedIsClosable({ rootTabs, props }) - } as ITabItemApi - - const state = reactive({ - index: null, - loaded: false, - animateShow: true, - rootTabs, - active: computed(() => api.computedActive()), - paneName: computed(() => api.computedPaneName()), - isClosable: computed(() => api.computedIsClosable()) - }) as ITabItemState - - Object.assign(api, { - state, - computedActive: computedActive({ nextTick, props, state }), - computedPaneName: computedPaneName({ props, state }) - }) - - watch(() => props.title, api.watchTitle) - - return api -} diff --git a/packages/mobile/components/tab-item/src/tab-item.ts b/packages/mobile/components/tab-item/src/tab-item.ts deleted file mode 100644 index 6e85a5a088..0000000000 --- a/packages/mobile/components/tab-item/src/tab-item.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' -import type { ITabsVm } from '../../tabs/src/tabs' -import type { computedIsClosable, computedActive, computedPaneName, watchTitle } from './renderless' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export { ITabsVm } - -export const $constants = {} - -export const tabItemProps = { - _constants: { - type: Object, - default: () => $constants - }, - title: String, - name: String, - withClose: Boolean, - disabled: Boolean, - lazy: Boolean, - selected: Boolean, - renderTitle: Function, - renderSetting: Function -} -export interface ITabItemState { - index: string | null - loaded: boolean - animateShow: boolean - rootTabs: ITabsVm - active: boolean - paneName: string | object | null - isClosable: boolean -} - -export interface ITabItemApi { - state: ITabItemState - watchTitle: ReturnType - computedIsClosable: ReturnType - computedActive: ReturnType - computedPaneName: ReturnType -} - -export type ITabItemProps = ExtractPropTypes - -export type ITabItemConstants = typeof $constants - -export type ITabItemRenderlessParamUtils = ISharedRenderlessParamUtils - -export type ITabItemRenderlessParams = ISharedRenderlessFunctionParams & { - state: ITabItemState - props: ITabItemProps - api: ITabItemApi - rootTabs: ITabsVm -} diff --git a/packages/mobile/components/tabbar-item/index.ts b/packages/mobile/components/tabbar-item/index.ts deleted file mode 100644 index d795659f19..0000000000 --- a/packages/mobile/components/tabbar-item/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import TabbarItem from './src/mobile.vue' - -/* istanbul ignore next */ -TabbarItem.install = function (Vue) { - Vue.component(TabbarItem.name, TabbarItem) -} - -export default TabbarItem diff --git a/packages/mobile/components/tabbar-item/src/mobile.vue b/packages/mobile/components/tabbar-item/src/mobile.vue deleted file mode 100644 index e08f68c858..0000000000 --- a/packages/mobile/components/tabbar-item/src/mobile.vue +++ /dev/null @@ -1,47 +0,0 @@ - - - - diff --git a/packages/mobile/components/tabbar-item/src/renderless/index.ts b/packages/mobile/components/tabbar-item/src/renderless/index.ts deleted file mode 100644 index 46481c29d9..0000000000 --- a/packages/mobile/components/tabbar-item/src/renderless/index.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { isObject, isNull } from '@mobile-root/utils/type' - -export const getRouteActive = - ({ props, route }) => - () => { - if (props.to && route) { - const config = isObject(props.to) ? props.to : { path: props.to } - const pathMatched = config.path === route.path - const nameMatched = !isNull(config.name) && config.name === route.name - - return pathMatched || nameMatched - } - } - -export const onClick = - ({ api, emit, parent, props, router, state, dispatch }) => - (event) => { - dispatch('Tabbar', 'activeItem', props.name || parent.index || state.index) - - emit('click', event) - - api.routeTab(router) - } - -export const bindChildren = - ({ parent, vm, dispatch }) => - () => { - if (!parent.$parent) { - return - } - - dispatch('Tabbar', 'updateItems', vm) - dispatch('Tabbar', 'showIndex') - } - -export const routeTab = (props, state) => (router) => { - const { to, replace } = props - const { url } = state - - if (to && router) { - const promise = router[replace ? 'replace' : 'push'](to) - - if (promise && promise.catch) { - promise.catch((err) => { - if (err && err.name !== 'NavigationDuplicated') { - throw err - } - }) - } - } else if (url) { - replace ? location.replace(url) : (location.href = url) - } -} - -export const getTabbarItemsWidth = (state) => (tabbarWidth, tabbarNumber) => { - state.itemWidth = tabbarWidth / tabbarNumber + 'px' -} diff --git a/packages/mobile/components/tabbar-item/src/renderless/vue.ts b/packages/mobile/components/tabbar-item/src/renderless/vue.ts deleted file mode 100644 index 3f7cd7121e..0000000000 --- a/packages/mobile/components/tabbar-item/src/renderless/vue.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { getRouteActive, onClick, bindChildren, routeTab, getTabbarItemsWidth } from './index' -import { xss } from '@mobile-root/utils' - -export const api = ['state', 'onClick', 'getTabbarItemsWidth'] - -export const renderless = ( - props, - { computed, onMounted, reactive, inject }, - { parent, emit, nextTick, route, router, dispatch, vm } -) => { - const api = {} - - const state = reactive({ - index: -1, - active: false, - info: computed(() => (props.dot ? '' : !props.dot && props.badge)), - url: computed(() => xss.filterUrl(props.url)), - routeActive: computed(() => api.getRouteActive()), - renderActive: computed(() => (vm.$parent.route ? state.routeActive : state.active)), - renderColor: computed(() => vm.$parent[state.active ? 'activeColor' : 'inactiveColor']), - showVm: true, - itemWidth: null, - childrenNumber: 0, - customIcon: inject('customIcon', null) || props.customIcon - }) - - Object.assign(api, { - state, - bindChildren: bindChildren({ parent, dispatch, vm }), - routeTab: routeTab(props, state), - getRouteActive: getRouteActive({ props, route }), - onClick: onClick({ api, emit, parent, props, router, state, dispatch }), - getTabbarItemsWidth: getTabbarItemsWidth(state) - }) - - onMounted(() => nextTick(api.bindChildren)) - - return api -} diff --git a/packages/mobile/components/tabbar-item/src/tabbar-item.ts b/packages/mobile/components/tabbar-item/src/tabbar-item.ts deleted file mode 100644 index e3c1e38eb4..0000000000 --- a/packages/mobile/components/tabbar-item/src/tabbar-item.ts +++ /dev/null @@ -1,15 +0,0 @@ -export const tabbarItemProps = { - url: String, - replace: Boolean, - to: [String, Object], - dot: Boolean, - icon: Object, - name: [Number, String], - text: String, - info: [Number, String], - badge: [Number, String], - customIcon: { - type: Boolean, - default: false - } -} diff --git a/packages/mobile/components/tabbar/index.ts b/packages/mobile/components/tabbar/index.ts deleted file mode 100644 index d1e13c4e3e..0000000000 --- a/packages/mobile/components/tabbar/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Tabbar from './src/mobile.vue' - -/* istanbul ignore next */ -Tabbar.install = function (Vue) { - Vue.component(Tabbar.name, Tabbar) -} - -export default Tabbar diff --git a/packages/mobile/components/tabbar/src/mobile.vue b/packages/mobile/components/tabbar/src/mobile.vue deleted file mode 100644 index 080adce7ae..0000000000 --- a/packages/mobile/components/tabbar/src/mobile.vue +++ /dev/null @@ -1,38 +0,0 @@ - - - - diff --git a/packages/mobile/components/tabbar/src/renderless/index.ts b/packages/mobile/components/tabbar/src/renderless/index.ts deleted file mode 100644 index b0e57a4104..0000000000 --- a/packages/mobile/components/tabbar/src/renderless/index.ts +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { off } from '@mobile-root/utils/deps/dom' - -export const setActiveItem = - ({ props, state }) => - () => { - state.children.forEach((item, index) => { - item.state ? (item.state.index = index) : (item.index = index) - - item.state && (item.state.active = (item.name || index) === props.modelValue) - }) - } - -export const onChange = - ({ emit, props }) => - (active) => { - if (active !== props.modelValue) { - emit('update:modelValue', active) - emit('change', active) - } - } - -export const getChildrens = - ({ childrenHandler, api }) => - () => { - const $children = [] - - childrenHandler(({ options, vm }) => { - options.componentName === 'TabbarItem' && $children.push(vm) - }) - api.setActiveItem() - - return $children - } - -export const getItems = (state) => (item) => { - if (state.showIndex >= state.showNumber) { - item.state.showVm = false - } - state.children.push(item) - - if (state.showNumber) { - item.getTabbarItemsWidth(state.tabbarWidth, state.showNumber) - } else if (state.children.length >= 5) { - item.getTabbarItemsWidth(state.tabbarWidth, 5) - } else { - item.getTabbarItemsWidth(state.tabbarWidth, state.children.length) - } -} - -export const initPage = - ({ vm, state }) => - () => { - state.tabbarWidth = vm.$refs.tabbar && vm.$refs.tabbar.offsetWidth - state.children.forEach((item) => { - if (state.showNumber) { - item.getTabbarItemsWidth(state.tabbarWidth, state.showNumber) - } else if (state.children.length >= 5) { - item.getTabbarItemsWidth(state.tabbarWidth, 5) - } else { - item.getTabbarItemsWidth(state.tabbarWidth, state.children.length) - } - }) - } - -export const beforeDestroy = (api) => () => { - off(window, 'resize', api.initPage) -} diff --git a/packages/mobile/components/tabbar/src/renderless/vue.ts b/packages/mobile/components/tabbar/src/renderless/vue.ts deleted file mode 100644 index 9f8d5e0f31..0000000000 --- a/packages/mobile/components/tabbar/src/renderless/vue.ts +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { setActiveItem, onChange, getChildrens, getItems, beforeDestroy, initPage } from './index' -import { on } from '@mobile-root/utils/deps/dom' - -export const api = ['state', 'onChange', 'getChildrens'] - -export const renderless = ( - props, - { computed, onMounted, reactive, watch, onBeforeUnmount, provide }, - { vm, emit, nextTick, childrenHandler } -) => { - const api = {} - const state = reactive({ - height: null, - children: [], - fit: computed(() => (props.safeAreaInsetBottom ? props.safeAreaInsetBottom : props.fixed)), - activeItem: false, - showIndex: 0, - showNumber: computed(() => (props.showNumber > 0 ? props.showNumber : -1)), - tabbarWidth: null, - itemList: computed(() => props.itemList || []) - }) - - Object.assign(api, { - state, - onChange: onChange({ emit, props }), - parent: computed(() => api.getParent()), - setActiveItem: setActiveItem({ props, state }), - getChildrens: getChildrens({ childrenHandler, api }), - getItems: getItems(state), - beforeDestroy: beforeDestroy(api), - initPage: initPage({ state, vm }) - }) - - onMounted(() => { - on(window, 'resize', api.initPage) - - state.tabbarWidth = vm.$refs.tabbar && vm.$refs.tabbar.offsetWidth - if (props.placeholder && props.fixed) { - nextTick(() => { - state.height = vm.$refs.tabbar.getBoundingClientRect().height - }) - } - - state.itemList.forEach((item) => { - if (item.customIcon) { - provide('customIcon', item.customIcon) - } - }) - }) - - vm.$on('updateItems', api.getItems) - vm.$on('activeItem', api.onChange) - vm.$on('showIndex', () => { - state.showIndex++ - }) - - watch( - () => props.modelValue, - () => { - setTimeout(() => { - api.setActiveItem() - }, 100) - }, - { immediate: true } - ) - - watch(() => state.children, api.setActiveItem, { immediate: true }) - - onBeforeUnmount(api.beforeDestroy) - - return api -} diff --git a/packages/mobile/components/tabbar/src/tabbar.ts b/packages/mobile/components/tabbar/src/tabbar.ts deleted file mode 100644 index 40d6496a95..0000000000 --- a/packages/mobile/components/tabbar/src/tabbar.ts +++ /dev/null @@ -1,28 +0,0 @@ -export const tabbarProps = { - activeColor: String, - border: { - type: Boolean, - default: true - }, - fixed: { - type: Boolean, - default: true - }, - inactiveColor: String, - modelValue: { - type: [Number, String], - default: 0 - }, - placeholder: Boolean, - route: Boolean, - safeAreaInsetBottom: Boolean, - zIndex: [Number, String], - showNumber: { - type: Number, - default: 5 - }, - itemList: { - type: Array, - default: () => [] - } -} diff --git a/packages/mobile/components/table/index.ts b/packages/mobile/components/table/index.ts deleted file mode 100644 index a42b3cd447..0000000000 --- a/packages/mobile/components/table/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Table from './src/mobile.vue' - -/* istanbul ignore next */ -Table.install = function (Vue) { - Vue.component(Table.name, Table) -} - -export default Table diff --git a/packages/mobile/components/table/src/mobile.vue b/packages/mobile/components/table/src/mobile.vue deleted file mode 100644 index 56fa367e5d..0000000000 --- a/packages/mobile/components/table/src/mobile.vue +++ /dev/null @@ -1,129 +0,0 @@ - - - - diff --git a/packages/mobile/components/table/src/renderless/index.ts b/packages/mobile/components/table/src/renderless/index.ts deleted file mode 100644 index f54cfb2106..0000000000 --- a/packages/mobile/components/table/src/renderless/index.ts +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -export const computedCheckableData = - ({ props }) => - () => - props.data.filter((item) => !item.disabled) - -export const computedSelectedKeys = - ({ props, state }) => - () => { - const keys = [] - - state.checkableData.forEach((item) => keys.push(item[props.keys])) - - return keys - } - -export const computedSelectCls = - ({ state }) => - () => { - if (state.selected.length > 0 && state.selected.length >= state.checkableData.length) { - return 'checked-sur' - } else if (state.selected.length > 0 && state.selected.length < state.checkableData.length) { - return 'halfselect' - } - - return 'check' - } - -export const watchDefaultChecked = - ({ props, state }) => - (value, oldvalue) => { - if (oldvalue && value.length === oldvalue.length && value.every((item) => oldvalue.includes(item))) { - return - } - - const checked = [] - - state.checkableData.forEach((item) => { - const index = value.indexOf(item[props.keys]) - - if (~index) { - checked.push(item) - } - }) - - state.selected = checked - state.checkedChangeByUser = false - } - -export const watchSelected = - ({ emit, props, state }) => - (value, oldvalue) => { - const keys = [] - - value.forEach((item) => keys.push(item[props.keys])) - - if (state.checkedChangeByUser) { - const movedKeys = value.concat(oldvalue).filter((item) => !value.includes(item) || !oldvalue.includes(item)) - - emit('checked-change', keys, false, movedKeys) - } else { - emit('checked-change', keys, false) - - state.checkedChangeByUser = true - } - } - -export const selectRow = - ({ emit, state }) => - (row) => { - state.selectedRow = row - emit('radio-change', row) - } - -export const togeSelected = - ({ state }) => - (row) => { - if (row.disabled) { - return - } - - const index = state.selected.indexOf(row) - - if (index !== -1) { - state.selected.splice(index, 1) - } else { - state.selected.push(row) - } - - state.selected = state.selected.slice() - } - -export const togeSelectAll = - ({ emit, props, state }) => - () => { - let data = [] - - if (state.selectCls === 'checked-sur') { - state.selected = [] - data = [] - } else { - data = state.checkableData.map((item) => item[props.keys]) - state.selected = state.checkableData - } - - emit('checked-change', data, true) - } diff --git a/packages/mobile/components/table/src/renderless/vue.ts b/packages/mobile/components/table/src/renderless/vue.ts deleted file mode 100644 index db74d2142b..0000000000 --- a/packages/mobile/components/table/src/renderless/vue.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - computedCheckableData, - computedSelectedKeys, - computedSelectCls, - watchDefaultChecked, - watchSelected, - selectRow, - togeSelected, - togeSelectAll -} from './index' - -export const api = ['state', 'selectRow', 'togeSelected', 'togeSelectAll'] - -export const renderless = (props, { computed, reactive, watch }, { t, emit }) => { - const api = {} - const state = reactive({ - selectedRow: null, - checkChangeByUser: false, - selected: [], - checkableData: computed(() => api.computedCheckableData()), - selectedKeys: computed(() => api.computedSelectedKeys()), - selectCls: computed(() => api.computedSelectCls()) - }) - - Object.assign(api, { - t, - state, - computedSelectCls: computedSelectCls({ state }), - computedSelectedKeys: computedSelectedKeys({ props, state }), - computedCheckableData: computedCheckableData({ props }), - selectRow: selectRow({ emit, state }), - togeSelected: togeSelected({ state }), - togeSelectAll: togeSelectAll({ emit, props, state }), - watchSelected: watchSelected({ emit, props, state }), - watchDefaultChecked: watchDefaultChecked({ props, state }) - }) - - watch(() => props.defaultChecked, api.watchDefaultChecked) - - watch(() => state.selected, api.watchSelected) - - return api -} diff --git a/packages/mobile/components/table/src/table.ts b/packages/mobile/components/table/src/table.ts deleted file mode 100644 index dfaa8f71f4..0000000000 --- a/packages/mobile/components/table/src/table.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -export const tableProps = { - columns: Array, - data: Array, - width: String, - defaultChecked: Array, - keys: String -} diff --git a/packages/mobile/components/tabs/index.ts b/packages/mobile/components/tabs/index.ts deleted file mode 100644 index 2eda13e29f..0000000000 --- a/packages/mobile/components/tabs/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Tabs from './src/mobile.vue' - -/* istanbul ignore next */ -Tabs.install = function (Vue) { - Vue.component(Tabs.name, Tabs) -} - -export default Tabs diff --git a/packages/mobile/components/tabs/src/mobile.vue b/packages/mobile/components/tabs/src/mobile.vue deleted file mode 100644 index bdf3328aa8..0000000000 --- a/packages/mobile/components/tabs/src/mobile.vue +++ /dev/null @@ -1,149 +0,0 @@ - - diff --git a/packages/mobile/components/tabs/src/renderless/index.ts b/packages/mobile/components/tabs/src/renderless/index.ts deleted file mode 100644 index f5d1467b1a..0000000000 --- a/packages/mobile/components/tabs/src/renderless/index.ts +++ /dev/null @@ -1,230 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ITabsRenderlessParams, ITabsPane, ITabsCustomEvent, ITabsPaneVm } from '../tabs' - -export const calcPaneInstances = - ({ - constants, - vm, - state, - childrenHandler - }: Pick) => - (isForceUpdate = false) => { - const tabItemVNodes = vm.$slots.default - - /* istanbul ignore if */ - if (tabItemVNodes) { - const currentPanes = [] as ITabsPaneVm[] - - childrenHandler(({ vm, isLevel1 }) => { - isLevel1 && vm.$options.componentName === constants.TAB_ITEM && currentPanes.push(vm) - }) - - const currentPaneStates = currentPanes.map((pane) => pane.state) - const paneStates = state.panes.map((pane) => pane.state) - - let newPanes = [] as ITabsPaneVm[] - for (let i = 0; i < paneStates.length; i++) { - const paneState = paneStates[i] - const index = currentPaneStates.indexOf(paneState) - - if (index > -1) { - newPanes.push(state.panes[i]) - currentPanes.splice(index, 1) - - currentPaneStates.splice(index, 1) - } - } - - newPanes = newPanes.concat(currentPanes) - - const panesChanged = !( - newPanes.length === state.panes.length && - newPanes.every((pane, index) => pane.state === state.panes[index].state) - ) - - if (isForceUpdate || panesChanged) { - state.panes = newPanes - } - } else if (state.panes.length !== 0) { - state.panes = [] - } - } - -/* istanbul ignore */ -export const calcMorePanes = - ({ vm, props, state, refs }: Pick) => - () => { - if (!props.showMoreTabs) { - return - } - - const el = vm.$el - const tabs = el.querySelectorAll('.tiny-tabs__item') - const tabNavRefs = refs.nav.$refs - - if (tabs && tabs.length) { - let tabsAllWidth = 0 - for (let i = 0; i < tabs.length; i++) { - const tabItem = tabs[i] as HTMLElement - // 遮住元素一半则隐藏 - tabsAllWidth = tabItem.offsetLeft + tabItem.offsetWidth / 2 - const tabsHeaderWidth = tabNavRefs.navScroll.offsetWidth - const currentName = Number(state.currentName || 0) - if (tabsAllWidth > tabsHeaderWidth && currentName >= 0) { - if (currentName >= i + 1) { - state.showPanesCount = currentName - 0 - } else { - state.showPanesCount = i - } - break - } - } - } - } - -export const calcExpandPanes = - ({ vm, props, state }: Pick) => - () => { - if (!props.showExpandTabs) { - return - } - const el = vm.$el - const tabsHeader = el.querySelector('.tiny-mobile-tabs__header') - - if (tabsHeader) { - state.expandPanesWidth = tabsHeader.clientWidth - } - } - -export const handleTabClick = - ({ api, emit, props, refs }: Pick) => - (pane: ITabsPane, tabName: string, event: Event) => { - if (pane.disabled) { - return - } - - api.setCurrentName(tabName) - - emit('click', pane, event) - - if (props.showExpandTabs) { - refs.nav && refs.nav.expandTabHide() - } - } - -export const handleTabRemove = - ({ emit, props }: Pick) => - (pane: ITabsPane, event: Event) => { - if (pane.disabled) { - return - } - - event.stopPropagation() - - const emitEvent = () => { - emit('edit', pane.name, 'remove') - emit('close', pane.name) - } - - if (typeof props.beforeClose === 'function') { - const beforeCloseResult = props.beforeClose(pane.name) - - if (beforeCloseResult && beforeCloseResult.then) { - beforeCloseResult.then((res) => res && emitEvent()) - } else { - beforeCloseResult && emitEvent() - } - } else { - emitEvent() - } - } - -export const handleTabAdd = (emit: ITabsRenderlessParams['emit']) => () => { - emit('edit', null, 'add') - emit('add') -} - -export const setCurrentName = - ({ api, props, refs, state }: Pick) => - (value: string) => { - api.changeDirection(state.currentName) - - if (state.currentName !== value && props.beforeLeave) { - const before = props.beforeLeave(value, state.currentName) - - if (before && before.then) { - before - .then(() => { - api.changeCurrentName(value) - refs.nav && refs.nav.removeFocus(value) - }) - .catch(() => null) - } else if (before !== false) { - api.changeCurrentName(value) - } - } else { - api.changeCurrentName(value) - } - } - -export const changeCurrentName = - ({ emit, state }: Pick) => - (value: string) => { - state.currentName = value - emit('update:modelValue', value) - } - -export const created = - ({ api, vm, state }: Pick) => - () => { - api.changeDirection(state.currentName) - - vm.$on('tab-nav-update', api.calcPaneInstances.bind(null, true)) - } - -export const changeDirection = - ({ props, state }: Pick) => - (currentName: string) => { - const panes = state.panes as ITabsPaneVm[] - panes.forEach((item, index) => { - if (item.state.paneName === currentName && state.currentIndex !== index) { - const isTopOrBottom = ~['top', 'bottom'].indexOf(props.position) - const isPrev = state.currentIndex < index - - state.direction = isTopOrBottom ? (isPrev ? 'right' : 'left') : isPrev ? 'bottom' : 'top' - state.currentIndex = index - } - }) - } - -export const handleTabDragStart = - ({ emit }: Pick) => - (event: ITabsCustomEvent) => { - emit('tab-drag-start', event) - } - -export const handleTabDragOver = - ({ emit }: Pick) => - (event: ITabsCustomEvent) => { - emit('tab-drag-over', event) - } - -export const handleTabDragEnd = - ({ state, emit }: Pick) => - (event: ITabsCustomEvent) => { - const { oldDraggableIndex, newDraggableIndex } = event - const panel = state.panes.splice(oldDraggableIndex, 1)[0] - state.panes.splice(newDraggableIndex, 0, panel) - - emit('tab-drag-end', event) - } diff --git a/packages/mobile/components/tabs/src/renderless/vue.ts b/packages/mobile/components/tabs/src/renderless/vue.ts deleted file mode 100644 index 0a15d34161..0000000000 --- a/packages/mobile/components/tabs/src/renderless/vue.ts +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { - ITabsState, - ITabsApi, - ITabsProps, - ISharedRenderlessParamHooks, - ITabsRenderlessParamUtils, - ITabsRenderlessParams -} from '../tabs' -import { - calcMorePanes, - calcExpandPanes, - calcPaneInstances, - handleTabClick, - handleTabAdd, - handleTabRemove, - setCurrentName, - changeCurrentName, - created, - changeDirection, - handleTabDragStart, - handleTabDragOver, - handleTabDragEnd -} from './index' - -export const api = [ - 'state', - 'handleTabAdd', - 'calcPaneInstances', - 'handleTabRemove', - 'handleTabClick', - 'handleTabDragStart', - 'handleTabDragOver', - 'handleTabDragEnd', - 'setCurrentName', - 'getNavRefs' -] - -const initState = ({ reactive, props }: Pick): ITabsState => - reactive({ - panes: [], - currentName: props.modelValue || props.activeName, - currentIndex: -1, - showPanesCount: -1, - startX: 0, - startY: 0, - deltaX: 0, - deltaY: 0, - offsetX: 0, - offsetY: 0, - direction: '', - expandPanesWidth: '', - activeIndex: 1, - separator: props.separator - }) as ITabsState - -const initWatcher = ({ - watch, - props, - api, - state, - nextTick, - refs -}: Pick) => { - watch(() => props.modelValue, api.setCurrentName) - - watch(() => props.activeName, api.setCurrentName) - - watch( - () => state.currentName, - () => { - nextTick(() => { - refs.nav.scrollToActiveTab() - }) - }, - { deep: true } - ) - - watch( - () => props.showMoreTabs, - (value) => { - if (!value) { - state.morePanes = [] - state.showPanesCount = -1 - } - }, - { immediate: true } - ) -} - -export const renderless = ( - props: ITabsProps, - { onMounted, onUpdated, provide, reactive, watch }: ISharedRenderlessParamHooks, - { refs, parent, vm, emit, constants, nextTick, childrenHandler }: ITabsRenderlessParamUtils -): ITabsApi => { - const api = {} as ITabsApi - const state: ITabsState = initState({ reactive, props }) - - Object.assign(api, { - state, - handleTabAdd: handleTabAdd(emit), - handleTabRemove: handleTabRemove({ emit, props }), - changeDirection: changeDirection({ props, state }), - changeCurrentName: changeCurrentName({ emit, state }), - calcMorePanes: calcMorePanes({ vm, props, state, refs }), - calcExpandPanes: calcExpandPanes({ vm, props, state }), - calcPaneInstances: calcPaneInstances({ constants, vm, state, childrenHandler }), - handleTabDragStart: handleTabDragStart({ emit }), - handleTabDragOver: handleTabDragOver({ emit }), - handleTabDragEnd: handleTabDragEnd({ state, emit }), - handleTabClick: handleTabClick({ api, emit, props, refs }), - setCurrentName: setCurrentName({ api, props, refs, state }), - created: created({ api, vm, state }) - }) - - api.created() - - provide('rootTabs', vm) - - provide('separator', state.separator) - - initWatcher({ watch, props, api, state, nextTick, refs }) - - onMounted(() => { - api.calcPaneInstances() - api.calcMorePanes() - api.calcExpandPanes() - }) - - onUpdated(() => { - api.calcPaneInstances() - api.calcMorePanes() - api.calcExpandPanes() - }) - - return api -} diff --git a/packages/mobile/components/tabs/src/tab-nav/mb.vue b/packages/mobile/components/tabs/src/tab-nav/mb.vue deleted file mode 100644 index 1a22dc01cf..0000000000 --- a/packages/mobile/components/tabs/src/tab-nav/mb.vue +++ /dev/null @@ -1,188 +0,0 @@ - - diff --git a/packages/mobile/components/tabs/src/tab-nav/renderless/index.ts b/packages/mobile/components/tabs/src/tab-nav/renderless/index.ts deleted file mode 100644 index 623ff5b86a..0000000000 --- a/packages/mobile/components/tabs/src/tab-nav/renderless/index.ts +++ /dev/null @@ -1,449 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ITabNavRenderlessParams } from '../tab-nav' -import { KEY_CODE, POSITION } from '@mobile-root/utils' -import { capitalize } from '@mobile-root/utils/string' -import { addResizeListener, removeResizeListener } from '@mobile-root/utils/deps/resize-event' -import { on, off } from '@mobile-root/utils/deps/dom' - -export const computedNavStyle = (state: ITabNavRenderlessParams['state']): { transform: string; width?: string } => { - const dir = ~[POSITION.Top, POSITION.Bottom].indexOf(state.rootTabs.position) ? 'X' : 'Y' - if (state.mode === 'mobile') { - const { offset, width } = state.lineStyle - return { - width: `${width}px`, - transform: `translate${dir}(${offset}px) translate${dir}(-50%)` - } - } -} - -export const scrollIntoView = - ({ parent, vm, state }: Pick) => - () => { - if (!state.scrollable) { - return - } - - const nav = vm.$refs.nav - const activeTab = parent.$el.querySelector('.is-active') as HTMLElement - - if (!activeTab) { - return - } - - const to = activeTab.offsetLeft - (nav.offsetWidth - activeTab.offsetWidth) / 2 - const from = nav.scrollLeft - - if (state.mode === 'mobile') { - nav.scrollLeft += to - from - const nameHtml = activeTab.querySelector('.tiny-mobile-tabs__name') as HTMLElement - state.lineStyle.width = nameHtml.offsetWidth - state.lineStyle.offset = activeTab.offsetLeft + activeTab.offsetWidth / 2 - } - } - -export const computedSizeName = (state: ITabNavRenderlessParams['state']): 'width' | 'height' => - ~[POSITION.Top, POSITION.Bottom].indexOf(state.rootTabs.position) ? 'width' : 'height' - -/* istanbul ignore next */ -export const updated = - ({ api, vm, state }: Pick) => - () => { - if (!vm.$refs.nav || state.dragging) { - return - } - - let navSize = vm.$refs.nav[`offset${capitalize(state.sizeName)}`] // taList 列表容器 - - if (state.mode === 'mobile') { - Array.prototype.forEach.call(vm.$refs.nav.children, (item) => { - if (item.classList && item.classList.contains('tiny-mobile-tabs__item')) { - navSize += item.offsetWidth - } - - if (item.classList && item.classList.contains('is-active')) { - const nameHtml = item.querySelector('.tiny-mobile-tabs__name') as HTMLElement - - state.isActive = true - state.lineStyle.width = nameHtml.offsetWidth - state.lineStyle.offset = item.offsetLeft + item.offsetWidth / 2 - } - }) - } - - const containerSize = vm.$refs.navScroll[`offset${capitalize(state.sizeName)}`] // 父容器宽度 - const currentOffset = state.navOffset - - if (containerSize < navSize) { - const currentOffset = state.navOffset - - if (!state.scrollable) { - state.scrollable = { - prev: currentOffset, - next: currentOffset + containerSize < navSize - } - } - - if (navSize - currentOffset < containerSize) { - state.navOffset = navSize - containerSize - } - } else { - state.scrollable = false - - if (currentOffset > 0) { - state.navOffset = 0 - } - } - - state.isActive && api.scrollIntoView() - - if (vm.$refs.tabBar) { - // active-bar动画滚动 - vm.$refs.tabBar.state.barStyle = vm.$refs.tabBar.computedBarStyle(vm.$refs.tabBar, state) - } else { - const line = vm.$refs.nav.querySelector('tiny-mobile-tabs__line') - line && line.style && (line.style.transform = api.computedNavStyle(state).transform) - } - } - -export const mounted = ({ api, parent }: Pick) => { - const el = parent.$refs.nav.$el - - /* istanbul ignore next */ - addResizeListener(el, api.updated) - on(document, 'visibilitychange', api.visibilityChangeHandler) - on(window, 'blur', api.windowBlurHandler) - on(window, 'focus', api.windowFocusHandler) - - api.scrollToActiveTab() - api.scrollIntoView() - api.sortableEvent() -} - -export const beforeUnmount = ({ api, parent }: Pick) => { - const el = parent.$refs.nav && parent.$refs.nav.$el - - /* istanbul ignore next */ - if (el && api.updated) { - removeResizeListener(el, api.updated) - } - - off(document, 'visibilitychange', api.visibilityChangeHandler) - off(window, 'blur', api.windowBlurHandler) - off(window, 'focus', api.windowFocusHandler) -} - -export const visibilityChangeHandler = (state: ITabNavRenderlessParams['state']) => () => { - const visibility = document.visibilityState - - /* istanbul ignore next */ - if (visibility === 'hidden') { - state.focusable = false - } else if (visibility === 'visible') { - setTimeout(() => { - state.focusable = true - }, 50) - } -} - -export const windowBlurHandler = (state: ITabNavRenderlessParams['state']) => () => { - state.focusable = false -} - -export const windowFocusHandler = (state: ITabNavRenderlessParams['state']) => () => { - setTimeout(() => { - state.focusable = true - }, 50) -} - -/* istanbul ignore next */ -export const scrollToActiveTab = - ({ parent, vm, state }: Pick) => - () => { - if (!state.scrollable) { - return - } - - const nav = vm.$refs.nav - const activeTab = parent.$el.querySelector('.is-active') - - if (!activeTab) { - return - } - - const navScroll = vm.$refs.navScroll - const activeTabBounding = activeTab.getBoundingClientRect() - const navScrollBounding = navScroll.getBoundingClientRect() - let maxOffset = nav.offsetWidth - navScrollBounding.width - - if (state.mode === 'mobile') { - if (activeTabBounding.left > navScrollBounding.width) { - maxOffset = activeTabBounding.left - navScrollBounding.width + activeTabBounding.width - } else { - maxOffset = activeTabBounding.width - } - } - - const currentOffset = state.navOffset - let newOffset = currentOffset - - if (activeTabBounding.left < navScrollBounding.left) { - newOffset = currentOffset - (navScrollBounding.left - activeTabBounding.left) - } - - if (activeTabBounding.right > navScrollBounding.right) { - newOffset = currentOffset + activeTabBounding.right - navScrollBounding.right - } - - newOffset = Math.max(newOffset, 0) - state.navOffset = Math.min(newOffset, maxOffset) - } - -export const scrollPrev = - ({ vm, state }: Pick) => - () => { - const containerSize = vm.$refs.navScroll[`offset${capitalize(state.sizeName)}`] - const currentOffset = state.navOffset - - if (!currentOffset) { - return - } - - const newOffset = currentOffset > containerSize ? currentOffset - containerSize : 0 - - state.navOffset = newOffset - } - -export const scrollNext = - ({ vm, state }: Pick) => - () => { - const navSize = vm.$refs.nav[`offset${capitalize(state.sizeName)}`] - const containerSize = vm.$refs.navScroll[`offset${capitalize(state.sizeName)}`] - const currentOffset = state.navOffset - - if (navSize - currentOffset <= containerSize) { - return - } - - const newOffset = - navSize - currentOffset > containerSize * 2 ? currentOffset + containerSize : navSize - containerSize - - state.navOffset = newOffset - } - -/* istanbul ignore next */ -export const changeTab = (api: ITabNavRenderlessParams['api']) => (event: KeyboardEvent) => { - const keyCode = event.keyCode - let nextIndex - let currentIndex, tabList - - if ( - ~[KEY_CODE.ArrowLeft, KEY_CODE.ArrowRight, KEY_CODE.ArrowUp, KEY_CODE.ArrowDown].indexOf(keyCode) && - event.currentTarget - ) { - const target = event.currentTarget as HTMLElement - tabList = target.querySelectorAll('[role=tab]') - currentIndex = Array.prototype.indexOf.call(tabList, event.target) - } else { - return - } - - if (keyCode === KEY_CODE.ArrowLeft || keyCode === KEY_CODE.ArrowUp) { - if (currentIndex === 0) { - nextIndex = tabList.length - 1 - } else { - nextIndex = currentIndex - 1 - } - } else { - if (currentIndex < tabList.length - 1) { - nextIndex = currentIndex + 1 - } else { - nextIndex = 0 - } - } - - tabList[nextIndex].focus() // 改变焦点元素 - tabList[nextIndex].click() // 选中下一个tab - api.setFocus() -} - -export const setFocus = (state: ITabNavRenderlessParams['state']) => () => { - if (state.focusable) { - state.isFocus = true - } -} - -export const removeFocus = (state: ITabNavRenderlessParams['state']) => () => { - state.isFocus = true -} - -// pc-展示更多的功能 -export const moreTabShow = (state: ITabNavRenderlessParams['state']) => () => { - if (state.showMoreItem) { - state.showMoreItem = false - } else { - state.showMoreItem = true - } -} - -// mobile-展示展开选项的功能 -export const expandTabShow = - ({ api, state }: Pick) => - () => { - state.showExpandItem = !state.showExpandItem - if (state.showExpandItem) { - api.computedHeaderStyle() - } - } - -export const expandTabHide = (state: ITabNavRenderlessParams['state']) => () => (state.showExpandItem = false) - -export const computedHeaderStyle = - ({ vm, state }: Pick) => - () => { - if (vm.$refs.nav) { - state.expandHeaderStyle[state.sizeName] = vm.$refs.nav[`offset${capitalize(state.sizeName)}`] + 'px' - } - - return state.expandHeaderStyle - } - -export const handleTabDragStart = - ({ state, vm, emit }: Pick) => - (event: DragEvent) => { - state.dragging = true - - if (![POSITION.Top, POSITION.Bottom].includes(state.rootTabs.position)) { - emit('tab-drag-start', event) - return - } - - const navContainer = vm.$refs.navScroll - const nav = vm.$refs.nav - - const containerWidth = navContainer.offsetWidth - const navWidth = nav.offsetWidth - - if (navWidth > containerWidth) { - const navHeight = nav.offsetHeight - - navContainer.style.height = navHeight + 'px' - nav.style.transition = 'none' - nav.style.transform = '' - nav.style.width = containerWidth + 'px' - nav.style.overflowX = 'scroll' - - nav.scrollTo(state.navOffset, 0) - } - - emit('tab-drag-start', event) - } - -export const handleTabDragEnd = - ({ vm, state, nextTick }: Pick) => - () => { - state.dragging = false - - if (![POSITION.Top, POSITION.Bottom].includes(state.rootTabs.position)) { - return - } - - const nav = vm.$refs.nav - - if (nav.style.width) { - const navOffset = nav.scrollLeft - const navContainer = vm.$refs.navScroll - - navContainer.style.height = '' - nav.style.width = '' - nav.style.overflowX = '' - state.navOffset = navOffset - - nextTick(() => { - nav.style.transition = '' - }) - } - } - -export const sortableEvent = - ({ - api, - props, - state, - vm, - emit, - markRaw - }: Pick) => - () => { - if (!props.dropConfig || typeof props.dropConfig.plugin !== 'function') { - return - } - - // eslint-disable-next-line new-cap - const navSortableObj = new props.dropConfig.plugin(vm.$refs.nav, { - sort: true, - draggable: '.tiny-tabs__item', - onUpdate(event) { - emit('tab-drag-end', event) - }, - onMove(event) { - emit('tab-drag-over', event) - }, - onStart(event) { - api.handleTabDragStart(event) - }, - onEnd() { - api.handleTabDragEnd() - } - }) - - state.navSortableObj = markRaw(navSortableObj) - } - -export const watchCurrentName = - ({ nextTick, vm, state }: Pick) => - () => { - nextTick(() => { - const tabBarVnode = vm.$refs.tabBar - - if (tabBarVnode) { - tabBarVnode.state.barStyle = tabBarVnode.computedBarStyle(tabBarVnode, state) - } - }) - } - -export const handleTitleMouseenter = - ({ state, vm }) => - (e, title) => { - const dom = e.target - - if (dom && dom.scrollWidth > dom.offsetWidth) { - const tooltip = vm.$refs.tooltip - tooltip.state.referenceElm = dom - tooltip.state.popperElm && (tooltip.state.popperElm.style.display = 'none') - tooltip.doDestroy() - - state.tooltipContent = title - state.tooltipVisible = true - - setTimeout(tooltip.updatePopper, 20) - } - } - -export const handleTitleMouseleave = - ({ state }) => - () => { - state.tooltipVisible = false - setTimeout(() => { - state.tooltipContent = '' - }, 20) - } diff --git a/packages/mobile/components/tabs/src/tab-nav/renderless/vue.ts b/packages/mobile/components/tabs/src/tab-nav/renderless/vue.ts deleted file mode 100644 index 1319ddf562..0000000000 --- a/packages/mobile/components/tabs/src/tab-nav/renderless/vue.ts +++ /dev/null @@ -1,127 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { - ITabNavState, - ITabNavApi, - ITabNavProps, - ISharedRenderlessParamHooks, - ITabNavRenderlessParamUtils -} from '../tab-nav' -import { - computedNavStyle, - computedSizeName, - updated, - visibilityChangeHandler, - windowBlurHandler, - windowFocusHandler, - scrollToActiveTab, - scrollIntoView, - mounted, - moreTabShow, - expandTabShow, - expandTabHide, - computedHeaderStyle, - beforeUnmount, - scrollPrev, - scrollNext, - changeTab, - setFocus, - removeFocus, - sortableEvent, - handleTabDragStart, - handleTabDragEnd, - watchCurrentName, - handleTitleMouseenter, - handleTitleMouseleave -} from './index' - -export const api = [ - 'state', - 'setFocus', - 'removeFocus', - 'scrollPrev', - 'scrollNext', - 'changeTab', - 'scrollToActiveTab', - 'scrollIntoView', - 'moreTabShow', - 'expandTabShow', - 'expandTabHide', - 'computedHeaderStyle', - 'swiperHandle', - 'updated', - 'handleTitleMouseenter', - 'handleTitleMouseleave' -] - -export const renderless = ( - props: ITabNavProps, - { computed, inject, onBeforeUnmount, onMounted, onUpdated, reactive, markRaw }: ISharedRenderlessParamHooks, - { parent, vm, nextTick, mode: tinyMode, emit }: ITabNavRenderlessParamUtils -): ITabNavApi => { - const api = { mounted, beforeUnmount, computedNavStyle, computedSizeName } as ITabNavApi - const state = reactive({ - dragging: false, - navOffset: 0, - lineStyle: { - width: 20, - offset: 0 - }, - scrollable: false, - isFocus: false, - focusable: false, - showMoreItem: false, - isActive: false, - tooltipVisible: false, - tooltipContent: '', - showMoreTabs: props.showMoreTabs, - showExpandItem: false, - showExpandTabs: props.showExpandTabs, - expandHeaderStyle: {}, - mode: props._mode || 'mobile', - rootTabs: inject('rootTabs'), - sizeName: computed(() => api.computedSizeName(state)), - navStyle: computed(() => api.computedNavStyle(state)), - navSortableObj: {}, - separator: inject('separator', null) - }) as ITabNavState - - Object.assign(api, { - state, - setFocus: setFocus(state), - removeFocus: removeFocus(state), - moreTabShow: moreTabShow(state), - expandTabShow: expandTabShow({ api, state }), - expandTabHide: expandTabHide(state), - scrollPrev: scrollPrev({ vm, state }), - scrollNext: scrollNext({ vm, state }), - windowBlurHandler: windowBlurHandler(state), - windowFocusHandler: windowFocusHandler(state), - visibilityChangeHandler: visibilityChangeHandler(state), - scrollToActiveTab: scrollToActiveTab({ parent, vm, state }), - scrollIntoView: scrollIntoView({ parent, vm, state }), - computedHeaderStyle: computedHeaderStyle({ vm, state }), - watchCurrentName: watchCurrentName({ nextTick, vm, state }), - handleTabDragStart: handleTabDragStart({ state, vm, emit }), - handleTabDragEnd: handleTabDragEnd({ state, vm, nextTick }), - sortableEvent: sortableEvent({ api, props, state, vm, emit, markRaw }), - handleTitleMouseenter: handleTitleMouseenter({ state, vm }), - handleTitleMouseleave: handleTitleMouseleave({ state }) - }) - - Object.assign(api, { updated: updated({ api, vm, state }), changeTab: changeTab(api) }) - onUpdated(() => api.updated()) - onMounted(() => api.mounted({ api, parent })) - onBeforeUnmount(() => api.beforeUnmount({ api, parent })) - - return api -} diff --git a/packages/mobile/components/tabs/src/tab-nav/tab-nav.ts b/packages/mobile/components/tabs/src/tab-nav/tab-nav.ts deleted file mode 100644 index b0fb3c85ca..0000000000 --- a/packages/mobile/components/tabs/src/tab-nav/tab-nav.ts +++ /dev/null @@ -1,137 +0,0 @@ -import type { ExtractPropTypes } from 'vue' -import type { ITabsVm, ITabsProps } from '../tabs' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '../../../../types/shared.type' -export type { ISharedRenderlessParamHooks } from '../../../../types/shared.type' -import type { - computedNavStyle, - scrollIntoView, - computedSizeName, - updated, - mounted, - beforeUnmount, - visibilityChangeHandler, - windowBlurHandler, - windowFocusHandler, - scrollToActiveTab, - scrollPrev, - scrollNext, - changeTab, - setFocus, - removeFocus, - moreTabShow, - expandTabShow, - expandTabHide, - computedHeaderStyle, - handleTabDragStart, - handleTabDragEnd, - sortableEvent, - watchCurrentName -} from './renderless' - -export const tabNavProps = { - panes: { - type: Array, - default: () => [] - }, - currentName: String, - activeColor: { - type: String, - default: '' - }, - onTabClick: { - type: Function, - default: () => {} - }, - onTabRemove: { - type: Function, - default: () => {} - }, - showExpandTabs: Boolean, - expandPanesWidth: { - type: String, - default: '' - }, - expandTabsTitle: { - type: String, - default: '请选择' - }, - expandTabsMode: { - type: String, - default: 'columns' - }, - stretch: { - type: Boolean, - default: false - } -} - -export type ITabNavProps = { _mode: string } & ExtractPropTypes & ITabsProps - -interface ITabNavStyle {} - -interface ITabLineStyle { - width: number - offset: number -} - -interface ITabNavScrollable { - prev: number - next: boolean -} - -export interface ITabNavState { - dragging: boolean - navOffset: number - lineStyle: ITabLineStyle - scrollable: boolean | ITabNavScrollable - isFocus: boolean - focusable: boolean - showMoreItem: boolean - isActive: boolean - showMoreTabs: boolean - showExpandItem: boolean - showExpandTabs: boolean - expandHeaderStyle: {} - mode: string - rootTabs: ITabsVm - sizeName: string - navStyle: ITabNavStyle - navSortableObj: object - separator: boolean | null -} - -export interface ITabNavApi { - state: ITabNavState - setFocus: ReturnType - removeFocus: ReturnType - moreTabShow: ReturnType - expandTabShow: ReturnType - expandTabHide: ReturnType - scrollPrev: ReturnType - scrollNext: ReturnType - windowBlurHandler: ReturnType - windowFocusHandler: ReturnType - visibilityChangeHandler: ReturnType - scrollToActiveTab: ReturnType - scrollIntoView: ReturnType - computedHeaderStyle: ReturnType - watchCurrentName: ReturnType - handleTabDragStart: ReturnType - handleTabDragEnd: ReturnType - sortableEvent: ReturnType - computedSizeName: typeof computedSizeName - computedNavStyle: typeof computedNavStyle - beforeUnmount: typeof beforeUnmount - mounted: typeof mounted - changeTab: ReturnType - updated: ReturnType -} - -export type ITabNavRenderlessParamUtils = ISharedRenderlessParamUtils - -export type ITabNavRenderlessParams = ISharedRenderlessFunctionParams & { - state: ITabNavState - props: ITabNavProps - api: ITabNavApi - rootTabs: ITabsVm -} diff --git a/packages/mobile/components/tabs/src/tabs.ts b/packages/mobile/components/tabs/src/tabs.ts deleted file mode 100644 index 7b4b307098..0000000000 --- a/packages/mobile/components/tabs/src/tabs.ts +++ /dev/null @@ -1,157 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ExtractPropTypes, ComponentPublicInstance } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils, ITinyVm } from '@mobile-root/shared.type' -import type { - calcPaneInstances, - calcMorePanes, - calcExpandPanes, - handleTabClick, - handleTabRemove, - handleTabAdd, - setCurrentName, - changeCurrentName, - created, - changeDirection, - handleTabDragStart, - handleTabDragOver, - handleTabDragEnd -} from './renderless' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const $constants = { - TAB_ITEM: 'TabItem' -} - -export const tabsProps = { - _constants: { - type: Object, - default: () => $constants - }, - tabStyle: String, - activeName: String, - withClose: Boolean, - withAdd: Boolean, - size: String, - activeColor: { - type: String, - default: '' - }, - modelValue: {}, - editable: Boolean, - position: { - type: String, - default: 'top' - }, - beforeLeave: Function, - stretch: Boolean, - showMoreTabs: Boolean, - swipeable: { - type: Boolean, - default: true - }, - popperClass: String, - popperAppendToBody: { - type: Boolean, - default: true - }, - dropConfig: { - type: Object, - default: () => null - }, - separator: Boolean, - // tiny 新增 - showExpandTabs: Boolean, - expandTabsTitle: String, - expandTabsMode: String, - tooltipConfig: [String, Object], - optimized: { - type: Boolean, - default: true - }, - beforeClose: Function, - overflowTitle: Boolean, - titleWidth: String -} - -export interface ITabsState { - panes: ITabsPaneVm[] | [] - currentName: string - currentIndex: number - showPanesCount: number - startX: number - startY: number - deltaX: number - deltaY: number - offsetX: number - offsetY: number - direction: string - expandPanesWidth: string | number - activeIndex: number - morePanes?: ITabsPaneVm[] - separator?: boolean -} - -/** - *tab根元素实例对象 - */ -export type ITabsVm = ComponentPublicInstance & { state: ITabsState } & ITabsProps - -export type ITabsPaneVm = ITinyVm<{ TAB_ITEM: string }> | ITabsPane | ITabsVm - -/** - * pane对象类型 - */ -export interface ITabsPane { - name: string - disabled: boolean - state: ITabsState -} - -/** - * 自定义拖拽事件 - */ -export interface ITabsCustomEvent { - originalEvent: DragEvent - oldDraggableIndex: number - newDraggableIndex: number -} - -export interface ITabsApi { - state: ITabsState - handleTabAdd: ReturnType - handleTabRemove: ReturnType - changeDirection: ReturnType - changeCurrentName: ReturnType - calcMorePanes: ReturnType - calcExpandPanes: ReturnType - calcPaneInstances: ReturnType - handleTabDragStart: ReturnType - handleTabDragOver: ReturnType - handleTabDragEnd: ReturnType - handleTabClick: ReturnType - setCurrentName: ReturnType - created: ReturnType -} - -export type ITabsProps = ExtractPropTypes - -export type ITabsConstants = typeof $constants - -export type ITabsRenderlessParamUtils = ISharedRenderlessParamUtils - -export type ITabsRenderlessParams = ISharedRenderlessFunctionParams & { - state: ITabsState - props: ITabsProps - api: ITabsApi -} diff --git a/packages/mobile/components/tag/index.ts b/packages/mobile/components/tag/index.ts deleted file mode 100644 index c217ed4368..0000000000 --- a/packages/mobile/components/tag/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Tag from './src/mobile.vue' - -/* istanbul ignore next */ -Tag.install = function (Vue) { - Vue.component(Tag.name, Tag) -} - -export default Tag diff --git a/packages/mobile/components/tag/src/mobile.vue b/packages/mobile/components/tag/src/mobile.vue deleted file mode 100644 index cec6ae84cf..0000000000 --- a/packages/mobile/components/tag/src/mobile.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - - - diff --git a/packages/mobile/components/tag/src/renderless/index.ts b/packages/mobile/components/tag/src/renderless/index.ts deleted file mode 100644 index 612abd3327..0000000000 --- a/packages/mobile/components/tag/src/renderless/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ITagRenderlessParams } from '../tag' - -export const handleClose = - ({ emit, props, state }: Pick) => - (event: Event) => { - if (props.disabled) return - event.stopPropagation() - state.show = false - const close = () => emit('close', event) - props.beforeDelete ? props.beforeDelete(close) : close() - } - -export const handleClick = - ({ emit, props, parent, state }: Pick) => - (event: Event) => { - // pc端没有selectable属性,不能以取反判断,会阻止pc的点击事件 - if (props.selectable || props.disabled) return - - parent.$parent && parent.$parent.tagSelectable && event.stopPropagation() - state.selected = !state.selected - emit('click', event) - } diff --git a/packages/mobile/components/tag/src/renderless/vue.ts b/packages/mobile/components/tag/src/renderless/vue.ts deleted file mode 100644 index 00ad8685ca..0000000000 --- a/packages/mobile/components/tag/src/renderless/vue.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ITagState, ITagProps, ITagApi, ISharedRenderlessParamHooks, ISharedRenderlessParamUtils } from '../tag' -import { handleClose, handleClick } from './index' - -export const api = ['state', 'handleClose', 'handleClick'] - -export const renderless = ( - props: ITagProps, - { reactive, computed }: ISharedRenderlessParamHooks, - { emit, parent }: ISharedRenderlessParamUtils -): ITagApi => { - const state: ITagState = reactive({ - type: computed(() => props.theme || props.type), - show: true, - selected: false, - mini: props.mini, - color: props.color, - text: props.text, - maxWidth: props.maxWidth - }) - - const api: ITagApi = { - state, - handleClose: handleClose({ emit, props, state }), - handleClick: handleClick({ emit, props, parent, state }) - } - - return api -} diff --git a/packages/mobile/components/tag/src/tag.ts b/packages/mobile/components/tag/src/tag.ts deleted file mode 100644 index 605ad11517..0000000000 --- a/packages/mobile/components/tag/src/tag.ts +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams } from '@mobile-root/shared.type' - -export type { ISharedRenderlessParamHooks, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' - -export const tagProps = { - hit: Boolean, - text: String, - type: String, - theme: String, - size: String, - color: String, - closable: Boolean, - operable: Boolean, - disabled: Boolean, - selectable: Boolean, - customClass: { - type: String, - default: '' - }, - effect: { - type: String, - default: 'light', - validator: (value: string) => Boolean(~['dark', 'light', 'plain'].indexOf(value)) - }, - beforeDelete: Function, - value: [Number, String], - - // mobile - mini: { - type: Boolean, - default: false - }, - maxWidth: { - type: [String, Number], - default: null - } -} - -export interface ITagState { - type: string | undefined - show: boolean - selected: boolean - text: string - color: string - mini: boolean - maxWidth: string | number -} - -export interface ITagApi { - state: ITagState - handleClose: (event: Event) => void - handleClick: (event: Event) => void -} - -export type ITagProps = ExtractPropTypes - -export type ITagRenderlessParams = ISharedRenderlessFunctionParams & { - state: ITagState - props: ITagProps - api: ITagApi -} diff --git a/packages/mobile/components/time-line/index.ts b/packages/mobile/components/time-line/index.ts deleted file mode 100644 index a8e9f271e2..0000000000 --- a/packages/mobile/components/time-line/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import TimeLine from './src/mobile.vue' - -/* istanbul ignore next */ -TimeLine.install = function (Vue) { - Vue.component(TimeLine.name, TimeLine) -} - -export default TimeLine diff --git a/packages/mobile/components/time-line/src/mobile.vue b/packages/mobile/components/time-line/src/mobile.vue deleted file mode 100644 index 00ca815997..0000000000 --- a/packages/mobile/components/time-line/src/mobile.vue +++ /dev/null @@ -1,99 +0,0 @@ - - - - diff --git a/packages/mobile/components/time-line/src/renderless/index.ts b/packages/mobile/components/time-line/src/renderless/index.ts deleted file mode 100644 index df3af3365c..0000000000 --- a/packages/mobile/components/time-line/src/renderless/index.ts +++ /dev/null @@ -1,135 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { format } from '@mobile-root/utils/date' -import type { - ITimelineProps, - ITimelineRenderlessParams, - ITimelineItem, - ITimelineStatusCls, - ITimelineCustomCls -} from '../time-line' - -export const getDate = (dateTime: string): { date: string; time: string } => ({ - date: format(dateTime, 'yyyy-MM-dd'), - time: format(dateTime, 'hh:mm') -}) - -export const getStatus = - ({ state, t }: Pick) => - (value: number): string => { - const status = state.current - value - - return status > 0 ? t('ui.steps.done') : status === 0 ? t('ui.steps.doing') : t('ui.steps.wait') - } - -export const computedSpace = - ({ props }: Pick) => - (): string | number => { - const { space } = props - if (/^\d+$/.test(space)) { - return `${space}px` - } - - return space - } - -export const handleClick = - ({ emit, state }: Pick) => - ({ index, node }: { index: number; node: ITimelineItem }): void => { - if (!node.disabled) { - emit('click', state.isReverse ? state.nodes.length - index - 1 : index, node) - } - } - -export const getStatusCls = - ({ constants, state }: Pick) => - (index: number, node?: ITimelineItem): ITimelineStatusCls => { - const { PROCESS_DONE_CLS, PROCESS_CUR_CLS, PROCESS_WAIT_CLS, PROCESS_DISABLED_CLS, PROCESS_ERROR_CLS } = constants - const cls = {} - const reverse = state.isReverse - - if (node?.disabled) { - cls[PROCESS_DISABLED_CLS] = true - } else if (node?.error) { - cls[PROCESS_ERROR_CLS] = true - } else { - cls[PROCESS_DONE_CLS] = reverse ? index > state.current : index < state.current - cls[PROCESS_CUR_CLS] = index === state.current - cls[PROCESS_WAIT_CLS] = reverse ? index < state.current : index > state.current - } - - return cls - } - -export const computedData = - ({ props, state }: Pick) => - (): ITimelineItem[] => { - if (props.data) { - return state.isReverse - ? props.data.map((item, i) => ({ ...props.data[props.data.length - 1 - i], index: i })) - : props.data.map((item, i) => ({ ...item, index: i })) - } - - return state.timelineItems - } - -export const computedCurrent = - ({ props, state }: Pick) => - (): number => - state.isReverse ? state.nodes.length - props.active - 1 : props.active - -export const computedIsReverse = (props: ITimelineProps) => (): boolean => props.reverse && props.vertical - -export const computedStackNodes = - ({ state, props }: Pick) => - (): ITimelineItem[] => { - if (state.nodes.length >= props.nodeMax && !props.foldDisabled) { - state.showData = true - return state.nodes.slice(0, props.limitedNodes) - } - return state.nodes - } - -export const changeStatus = - ({ state }: Pick) => - (): boolean => { - state.showAll = !state.showAll - return state.showAll - } - -export const computedWrapperClass = - ({ props }: Pick) => - (): ITimelineCustomCls => { - const { vertical, reverse, textPosition, showDivider } = props - const wrapperClass = [] as ITimelineCustomCls - - if (vertical) { - wrapperClass.push('tiny-steps-timeline', { reverse, 'tiny-timeline__shape-dot': props.shape === 'dot' }) - } else { - wrapperClass.push('tiny-steps-normal', textPosition === 'right' ? 'text-right' : 'text-bottom') - } - - if (showDivider && textPosition === 'right') { - wrapperClass.push('show-divider') - } - - return wrapperClass - } - -export const toggleFold = - ({ props }) => - (node: ITimelineItem): boolean => { - const isFold = !props.data[node.index].fold - props.data[node.index].fold = isFold - return isFold - } diff --git a/packages/mobile/components/time-line/src/renderless/vue.ts b/packages/mobile/components/time-line/src/renderless/vue.ts deleted file mode 100644 index acd036999e..0000000000 --- a/packages/mobile/components/time-line/src/renderless/vue.ts +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - handleClick, - getStatusCls, - getStatus, - computedData, - getDate, - computedCurrent, - computedIsReverse, - changeStatus, - computedStackNodes, - computedSpace, - computedWrapperClass, - toggleFold -} from './index' -import type { - ITimelineApi, - ITimelineProps, - ITimelineRenderlessParamUtils, - ITimelineState, - ISharedRenderlessParamHooks, - ITimelineItem -} from '../time-line' - -export const api = ['state', 'handleClick', 'getStatusCls', 'getStatus', 'getDate', 'changeStatus', 'toggleFold'] - -export const renderless = ( - props: ITimelineProps, - { computed, reactive, provide, watch }: ISharedRenderlessParamHooks, - { t, emit, constants }: ITimelineRenderlessParamUtils -): ITimelineApi => { - const api = {} as ITimelineApi - const state: ITimelineState = reactive({ - nodes: computed(() => api.computedData()), - timelineItems: [], - current: computed(() => api.computedCurrent()), - isReverse: computed(() => api.computedIsReverse()), - stackNodes: computed(() => (state.showAll ? state.nodes : api.computedStackNodes())), - computedSpace: computed(() => api.computedSpace()), - showData: false, - showAll: false, - computedWrapperClass: computed(() => api.computedWrapperClass()) - }) - - Object.assign(api, { - state, - getDate, - computedData: computedData({ props, state }), - computedCurrent: computedCurrent({ props, state }), - computedIsReverse: computedIsReverse(props), - computedSpace: computedSpace({ props }), - getStatus: getStatus({ state, t }), - handleClick: handleClick({ emit, state }), - getStatusCls: getStatusCls({ constants, state }), - computedStackNodes: computedStackNodes({ state, props }), - changeStatus: changeStatus({ state }), - computedWrapperClass: computedWrapperClass({ props }), - toggleFold: toggleFold({ props }) - }) - - provide('nodesInject', { timelineItems: state.timelineItems, nodes: state.nodes, props }) - - watch( - () => state.timelineItems, - (newVal: ITimelineItem[]) => { - newVal.forEach((item, i) => (item.index = i)) - }, - { - immediate: true, - deep: true - } - ) - - return api -} diff --git a/packages/mobile/components/time-line/src/time-line.ts b/packages/mobile/components/time-line/src/time-line.ts deleted file mode 100644 index 9449d2d9ae..0000000000 --- a/packages/mobile/components/time-line/src/time-line.ts +++ /dev/null @@ -1,175 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { PropType } from '@mobile-root/common' -import type { ExtractPropTypes } from 'vue' -import type { toggleFold } from './renderless' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const $constants = { - PROCESS_DONE_CLS: 'process-done', - PROCESS_CUR_CLS: 'process-current', - PROCESS_WAIT_CLS: 'process-wait', - PROCESS_DISABLED_CLS: 'process-disabled', - PROCESS_ERROR_CLS: 'process-error', - STACK_NODES_MAX: 7, - LIMITED_STACK_NODES: 3 -} - -export type ShapeType = 'circle' | 'dot' - -export const timelineProps = { - _constants: { - type: Object, - default: () => $constants - }, - vertical: { - type: Boolean, - default: false - }, - horizontal: { - type: Boolean, - default: true - }, - showNumber: { - type: Boolean, - default: true - }, - nameField: { - type: String, - default: 'name' - }, - timeField: { - type: String, - default: 'time' - }, - tipsField: { - type: String, - default: 'tips' - }, - autoColorField: { - type: String, - default: 'autoColor' - }, - showIconField: { - type: String, - default: 'showIcon' - }, - start: { - type: Number, - default: 1 - }, - data: Array, - space: { - type: [String, Number], - default: '' - }, - active: { - type: Number, - default: -1 - }, - reverse: { - type: Boolean, - default: false - }, - showStatus: { - type: Boolean, - default: false - }, - subField: { - type: Boolean, - default: false - }, - foldDisabled: { - type: Boolean, - default: false - }, - nodeMax: { - type: [Number, String], - default: $constants.STACK_NODES_MAX - }, - limitedNodes: { - type: [Number, String], - default: $constants.LIMITED_STACK_NODES - }, - onlyNumber: { - type: Boolean, - default: false - }, - lineWidth: { - type: [String, Number], - default: '' - }, - shape: { - type: String as PropType, - default: 'circle' - } -} - -export type ITimelineProps = ExtractPropTypes - -export type ITimelineConstants = typeof $constants - -export type ITimelineRenderlessParamUtils = ISharedRenderlessParamUtils - -export type TimelineItemType = 'primary' | 'success' | 'warning' | 'error' | 'info' -export interface ITimelineItem { - index: number - name: string - time: string - error: boolean - disabled: boolean - type: TimelineItemType - fold?: boolean -} - -export interface ITimelineState { - nodes: ITimelineItem[] - timelineItems: ITimelineItem[] - current: number - isReverse: boolean - stackNodes: ITimelineItem[] - computedSpace: string - showData: boolean - showAll: boolean - computedWrapperClass: ITimelineCustomCls - computedLineWidth: string -} - -export interface ITimelineApi { - state: ITimelineState - getDate: () => string - computedData: () => ITimelineItem[] - computedCurrent: () => number - computedIsReverse: () => boolean - computedSpace: () => string | number - getStatus: () => string - handleClick: () => void - getStatusCls: () => ITimelineStatusCls - computedStackNodes: () => ITimelineItem[] - changeStatus: () => boolean - computedWrapperClass: () => ITimelineCustomCls - toggleFold: ReturnType -} - -export type ITimelineRenderlessParams = ISharedRenderlessFunctionParams & { - api: ITimelineApi - state: ITimelineState - props: ITimelineProps -} - -export type ITimelineStatusCls = { - [key in keyof ITimelineConstants]?: boolean -} - -export type ITimelineCustomCls = (string | { [key: string]: boolean })[] diff --git a/packages/mobile/components/toast/index.ts b/packages/mobile/components/toast/index.ts deleted file mode 100644 index 2d08a32231..0000000000 --- a/packages/mobile/components/toast/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import service from './src/service.js' - -let Toast: any = { - install() {}, - service -} - -export default Toast diff --git a/packages/mobile/components/toast/src/mobile.vue b/packages/mobile/components/toast/src/mobile.vue deleted file mode 100644 index f061c3a120..0000000000 --- a/packages/mobile/components/toast/src/mobile.vue +++ /dev/null @@ -1,31 +0,0 @@ - - - diff --git a/packages/mobile/components/toast/src/renderless/index.ts b/packages/mobile/components/toast/src/renderless/index.ts deleted file mode 100644 index d5aafafe45..0000000000 --- a/packages/mobile/components/toast/src/renderless/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { IToastRenderlessParamUtils } from '../toast' - -export const timeout = (emit: IToastRenderlessParamUtils['emit']) => (): void => { - emit('timeout') -} diff --git a/packages/mobile/components/toast/src/renderless/vue.ts b/packages/mobile/components/toast/src/renderless/vue.ts deleted file mode 100644 index 34eaec4851..0000000000 --- a/packages/mobile/components/toast/src/renderless/vue.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { timeout } from './index' -import type { IToastApi, IToastState, IToastProps, ISharedRenderlessParamHooks } from '../toast' - -export const api = ['state', 'timeout'] - -export const renderless = (props: IToastProps, { reactive }: ISharedRenderlessParamHooks, { vm, emit }): IToastApi => { - const state: IToastState = reactive({ - text: props.text, - type: props.type, - time: props.time as number - }) - - const api: IToastApi = { - state, - timeout: timeout(emit) - } - - return api -} diff --git a/packages/mobile/components/toast/src/service.ts b/packages/mobile/components/toast/src/service.ts deleted file mode 100644 index 8a1686908e..0000000000 --- a/packages/mobile/components/toast/src/service.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { createComponent } from '@mobile-root/common' -import Toast from './mobile.vue' - -const defaults = { - type: 'text' -} - -export default (configs = {}) => { - configs = { ...defaults, ...configs } - let parent = document.body - let instance = createComponent({ - component: Toast, - propsData: {}, - el: document.createElement('div') - }) - - for (const key in configs) { - if (Object.prototype.hasOwnProperty.call(configs, key)) { - instance.state[key] = configs[key] - } - } - - parent.appendChild(instance.$el) - - setTimeout(() => { - if (instance.state.timeout) { - instance.state.timeout() - } - - parent.removeChild(instance.$el) - }, instance.state.time) - - return instance -} diff --git a/packages/mobile/components/toast/src/toast.ts b/packages/mobile/components/toast/src/toast.ts deleted file mode 100644 index e10e1ff5b8..0000000000 --- a/packages/mobile/components/toast/src/toast.ts +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' -import type { timeout } from './renderless' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const toastProps = { - type: { - type: String, - validator: (value: string) => ['text', 'correct', 'error'].includes(value) - }, - zIndex: { - type: Number, - default: 100 - }, - text: { - type: String, - default: 'text' - }, - time: { - type: [String, Number], - default: 2000 - }, - timeout: { - type: Function, - default: null - } -} - -export interface IToastState { - text: string | null - type?: string - time: number -} - -export type IToastProps = ExtractPropTypes - -export type IToastRenderlessParams = ISharedRenderlessFunctionParams & { - state: IToastState - props: IToastProps -} - -export interface IToastApi { - state: IToastState - timeout: ReturnType -} - -export type IToastRenderlessParamUtils = ISharedRenderlessParamUtils diff --git a/packages/mobile/components/tooltip/index.ts b/packages/mobile/components/tooltip/index.ts deleted file mode 100644 index d741919263..0000000000 --- a/packages/mobile/components/tooltip/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Tooltip from './src/mobile.vue' - -/* istanbul ignore next */ -Tooltip.install = function (Vue) { - Vue.component(Tooltip.name, Tooltip) -} - -export default Tooltip diff --git a/packages/mobile/components/tooltip/src/mobile.vue b/packages/mobile/components/tooltip/src/mobile.vue deleted file mode 100644 index ad048db4b9..0000000000 --- a/packages/mobile/components/tooltip/src/mobile.vue +++ /dev/null @@ -1,172 +0,0 @@ - - - - diff --git a/packages/mobile/components/tooltip/src/renderless/index.ts b/packages/mobile/components/tooltip/src/renderless/index.ts deleted file mode 100644 index 9f06d4cc63..0000000000 --- a/packages/mobile/components/tooltip/src/renderless/index.ts +++ /dev/null @@ -1,247 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { ITooltipApi, ITooltipRenderlessParams, ITooltipState } from '@/types' -import debounce from '@mobile-root/utils/deps/debounce' -import { on, off, addClass, removeClass } from '@mobile-root/utils/deps/dom' - -export const show = - ({ api, state, props }: Pick) => - (event?: MouseEvent) => { - const defaultDelay = 200 - const delay = event && event.type === 'mouseenter' ? defaultDelay : 0 - // 如果指定 visible='auto', 则只有超长时,才显示tip。 - if (props.visible === 'auto') { - const { clientWidth, scrollWidth } = state.referenceElm - if (scrollWidth <= clientWidth) { - return - } - } - api.setExpectedState(true) - api.handleShowPopper(delay) - } - -export const hide = (api: ITooltipApi) => () => { - api.setExpectedState(false) - api.debounceClose() -} - -export const handleFocus = - ({ api, state }: Pick) => - () => { - state.focusing = true - api.show() - } -export const handleBlur = - ({ api, state }: Pick) => - () => { - state.focusing = false - api.hide() - } - -export const removeFocusing = - ({ api, state }: Pick) => - () => { - state.focusing = false - api.show() - } - -export const handleShowPopper = - ({ props, state }: Pick) => - (delay: number) => { - if (!state.expectedState || props.manual) { - return - } - - clearTimeout(state.timeout) - - state.timeout = window.setTimeout(() => { - state.showPopper = true - }, props.openDelay || delay) - - if (props.hideAfter > 0) { - state.timeoutPending = window.setTimeout(() => { - state.showPopper = false - }, props.hideAfter) - } - } - -export const handleClosePopper = - ({ api, props, state }: Pick) => - () => { - if ((props.enterable && state.expectedState) || props.manual) { - return - } - - clearTimeout(state.timeout) - - if (state.timeoutPending) { - clearTimeout(state.timeoutPending) - } - - state.showPopper = false - - if (props.disabled) { - api.doDestroy() - } - } - -/* istanbul ignore next */ -export const handleDocumentClick = - ({ props, api, state, popperVmRef }: Pick) => - (event: MouseEvent) => { - if (props.manual) return - - const reference = state.referenceElm - const $el = popperVmRef.popper - - if ( - !$el || - !reference || - $el.contains(event.target as HTMLElement) || - reference.contains(event.target as HTMLElement) - ) { - return - } - - if (state.showPopper) { - api.setExpectedState(false) - api.debounceClose() - } - } - -export const setExpectedState = - ({ state }: Pick) => - (value: boolean) => { - if (state.expectedState === false) { - clearTimeout(state.timeoutPending) - } - - state.expectedState = value - } - -/* istanbul ignore next */ -export const destroyed = - ({ state, api, vm }: Pick) => - () => { - const reference = state.referenceElm - - state.showPopper = false - - if (reference && reference.nodeType === 1) { - off(document, 'click', api.handleDocumentClick) - off(reference, 'mouseenter', api.show) - off(reference, 'mouseleave', api.hide) - off(reference, 'focus', api.focusHandler) - off(reference, 'blur', api.handleBlur) - off(reference, 'click', api.removeFocusing) - } - - if (vm.popperVM) { - typeof vm.popperVM.$destroy === 'function' && vm.popperVM.$destroy() - vm.popperVM = null - } - } - -export const debounceClose = ({ api, props }: Pick) => - debounce(props.closeDelay, () => { - api.handleClosePopper() - }) - -/* istanbul ignore next */ -export const watchFocusing = (state: ITooltipState) => (value: boolean) => { - if (value) { - addClass(state.referenceElm, 'focusing') - } else { - removeClass(state.referenceElm, 'focusing') - } -} - -export const focusHandler = - ({ slots, api }: Pick) => - () => { - if (!slots.default || !slots.default().length) { - api.handleFocus() - return - } - - let instance = slots.default()[0] - - // vue2 vnode.elm ,vue3 vnode.el - instance = instance.elm || instance.el - - if (instance && instance.focus) { - instance.focus() - } else { - api.handleFocus() - } - } - -export const bindEvent = - ({ api, state, vm }: Pick) => - (reference: HTMLElement) => { - let referenceElm: HTMLElement = null as any - - if (vm.$el.nodeType === 8) { - referenceElm = reference - } else if (vm.$el.nodeType === 1) { - referenceElm = vm.$el - } - - if (!referenceElm || referenceElm.nodeType === 8 || state.referenceElm) { - return - } - - state.referenceElm = referenceElm - referenceElm.setAttribute('aria-describedby', state.tooltipId) - referenceElm.setAttribute('tabindex', state.tabindex.toString()) - - on(document, 'click', api.handleDocumentClick) - on(referenceElm, 'mouseenter', api.show) - on(referenceElm, 'mouseleave', api.hide) - on(referenceElm, 'focus', api.focusHandler) - on(referenceElm, 'blur', api.handleBlur) - on(referenceElm, 'click', api.removeFocusing) - } - -export const observeCallback = - ({ state, popperVmRef }: Pick) => - (mutationsList: any) => { - for (let mutation of mutationsList) { - if (mutation.type === 'attributes' && mutation.attributeName === 'x-placement') { - state.xPlacement = popperVmRef.popper.getAttribute('x-placement') || 'bottom' - } - } - } - -export const bindPopper = - ({ vm, nextTick, popperVmRef }: Pick) => - (el?: Element) => { - nextTick(() => vm.bindEvent(el)) - - // vm.popperVM 是一个get 方法,所以必须缓存下来,不能频繁访问 - let popperVM = vm.popperVM - if (!vm.$refs.popper) { - popperVmRef.popper = popperVM.$el - } else { - popperVmRef.popper = vm.$refs.popper - } - - // vm.$refs是只读的,不允许添加popper。 原来是refs.popper, 为什么要保存这个refs.popper - // vm.$refs.popper || (vm.$refs.popper = popperVM.$el) - - nextTick(() => { - if (vm.modelValue) { - vm.updatePopper() - } - }) - } diff --git a/packages/mobile/components/tooltip/src/renderless/vue.ts b/packages/mobile/components/tooltip/src/renderless/vue.ts deleted file mode 100644 index 1bc194113e..0000000000 --- a/packages/mobile/components/tooltip/src/renderless/vue.ts +++ /dev/null @@ -1,136 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - bindEvent, - show, - hide, - handleFocus, - handleBlur, - removeFocusing, - handleShowPopper, - handleClosePopper, - setExpectedState, - destroyed, - debounceClose, - watchFocusing, - bindPopper, - focusHandler, - observeCallback, - handleDocumentClick -} from './index' -import userPopper from '@mobile-root/utils/deps/vue-popper' -import { guid } from '@mobile-root/utils/string' -import type { ISharedRenderlessParamHooks, ISharedRenderlessParamUtils } from 'types/shared.type' -import type { ITooltipApi, ITooltipProps, ITooltipState } from 'types/tooltip.type' - -export const api = [ - 'state', - 'bindEvent', - 'hide', - 'show', - 'doDestroy', - 'handleFocus', - 'debounceClose', - 'handleShowPopper', - 'handleClosePopper', - 'setExpectedState', - 'updatePopper', - 'focusHandler' -] - -const initState = ({ reactive, showPopper, popperElm, referenceElm, props, inject }) => - reactive({ - showPopper, - popperElm, - referenceElm, - timeout: null, - focusing: false, - expectedState: undefined, - tooltipId: guid('tiny-tooltip-', 4), - tabindex: props.tabindex, - xPlacement: 'bottom', - showContent: inject('showContent', null), - tipsMaxWidth: inject('tips-max-width', null) - }) - -export const renderless = ( - props: ITooltipProps, - { - watch, - toRefs, - reactive, - onBeforeUnmount, - onDeactivated, - onMounted, - onUnmounted, - inject - }: ISharedRenderlessParamHooks, - { vm, emit, slots, nextTick, parent }: ISharedRenderlessParamUtils -) => { - const api = {} as ITooltipApi - - const popperVmRef = {} as { popper: HTMLElement } - const popperParam = { emit, props, nextTick, toRefs, reactive, parent: parent.$parent, vm, popperVmRef } - - Object.assign(popperParam, { slots, onBeforeUnmount, onDeactivated, watch }) - - const { showPopper, updatePopper, popperElm, referenceElm, doDestroy } = userPopper(popperParam as any) - const state: ITooltipState = initState({ reactive, showPopper, popperElm, referenceElm, props, inject }) - - Object.assign(api, { - state, - doDestroy, - updatePopper, - show: show({ api, state, props }), - hide: hide(api), - destroyed: destroyed({ state, api, vm }), - bindPopper: bindPopper({ vm, nextTick, popperVmRef }), - watchFocusing: watchFocusing(state), - removeFocusing: removeFocusing({ api, state }), - handleBlur: handleBlur({ api, state }), - handleFocus: handleFocus({ api, state }), - debounceClose: debounceClose({ api, props }), - setExpectedState: setExpectedState({ state }), - handleShowPopper: handleShowPopper({ props, state }), - handleClosePopper: handleClosePopper({ api, props, state }), - bindEvent: bindEvent({ api, state, vm }), - focusHandler: focusHandler({ slots, api }), - handleDocumentClick: handleDocumentClick({ props, api, state, popperVmRef }), - observeCallback: observeCallback({ state, popperVmRef }) - }) - - watch(() => state.focusing, api.watchFocusing) - - watch( - () => props.modelValue, - (val) => nextTick(() => props.manual && (state.showPopper = val)) - ) - - onMounted(() => { - api.bindPopper() - if (props.genArrowByHtml) { - const config = { attributes: true, childList: false, subtree: false } - api.observer = new MutationObserver(api.observeCallback) - api.observer.observe(popperVmRef.popper, config) - } - }) - - vm.$on('tooltip-update', api.bindPopper) - - onUnmounted(() => { - api.destroyed() - api.observer && api.observer.disconnect() - }) - - return api -} diff --git a/packages/mobile/components/tooltip/src/tooltip.ts b/packages/mobile/components/tooltip/src/tooltip.ts deleted file mode 100644 index 3e62265028..0000000000 --- a/packages/mobile/components/tooltip/src/tooltip.ts +++ /dev/null @@ -1,153 +0,0 @@ -import type { ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams, ITinyVm } from '@mobile-root/shared.type' - -import type { - bindEvent, - show, - hide, - handleFocus, - handleBlur, - removeFocusing, - handleShowPopper, - handleClosePopper, - setExpectedState, - destroyed, - debounceClose, - watchFocusing, - bindPopper, - focusHandler, - observeCallback, - handleDocumentClick -} from './renderless' - -export { ITinyVm } - -export const tooltipProps = { - visible: { - type: String, - default: () => 'always', - validator: (value: string) => ['always', 'auto'].includes(value) - }, - adjustArrow: { - type: Boolean, - default: () => false - }, - appendToBody: { - type: Boolean, - default: () => true - }, - arrowOffset: { - type: Number, - default: () => 0 - }, - content: { type: [String, Object] }, - disabled: { type: Boolean }, - enterable: { - type: Boolean, - default: () => true - }, - hideAfter: { - type: Number, - default: () => 0 - }, - manual: { type: Boolean }, - modelValue: { type: Boolean }, - offset: { - default: () => 0 - }, - effect: { - type: String, - default: () => '' - }, - openDelay: { - type: Number, - default: () => 0 - }, - closeDelay: { - type: Number, - default: () => 100 - }, - placement: { - type: String, - default: () => 'bottom' - }, - popper: {}, - popperClass: { type: String }, - popperOptions: { - default: () => ({}) - }, - pre: { type: Boolean }, - reference: {}, - renderContent: { type: Function }, - tabindex: { - type: Number, - default: () => 0 - }, - transition: { - type: String, - default: () => 'tiny-fade-in-linear' - }, - type: { - type: String, - validator: (value: string) => Boolean(~['normal', 'warning', 'error', 'info', 'success'].indexOf(value)) - }, - visibleArrow: { - type: Boolean, - default: () => true - }, - genArrowByHtml: { - type: Boolean, - default: () => true - }, - zIndex: { - type: String, - default: () => 'next' - } -} - -export type ITooltipProps = ExtractPropTypes - -export interface ITooltipState { - showPopper: boolean - popperElm: HTMLElement - referenceElm: HTMLElement - timeout: number - timeoutPending: number - focusing: boolean - expectedState: boolean - tooltipId: string - tabindex: number - xPlacement: string - showContent: boolean - tipsMaxWidth: string | number -} - -export interface ITooltipApi { - state: ITooltipState - observer: MutationObserver - doDestroy: (forceDestroy?: boolean | undefined) => void - updatePopper: (popperElm?: HTMLElement | undefined) => void - show: ReturnType - hide: ReturnType - destroyed: ReturnType - bindPopper: ReturnType - watchFocusing: ReturnType - removeFocusing: ReturnType - handleBlur: ReturnType - handleFocus: ReturnType - debounceClose: ReturnType - setExpectedState: ReturnType - handleShowPopper: ReturnType - handleClosePopper: ReturnType - bindEvent: ReturnType - focusHandler: ReturnType - handleDocumentClick: ReturnType - observeCallback: ReturnType -} - -export type ITooltipRenderlessParams = ISharedRenderlessFunctionParams & { - props: ITooltipProps - state: ITooltipState - api: ITooltipApi - popperVmRef: { popper: HTMLElement } -} diff --git a/packages/mobile/components/upload-list/index.ts b/packages/mobile/components/upload-list/index.ts deleted file mode 100644 index 725095449b..0000000000 --- a/packages/mobile/components/upload-list/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import UploadList from './src/mobile.vue' - -/* istanbul ignore next */ -UploadList.install = function (Vue) { - Vue.component(UploadList.name, UploadList) -} - -export default UploadList diff --git a/packages/mobile/components/upload-list/src/mobile.vue b/packages/mobile/components/upload-list/src/mobile.vue deleted file mode 100644 index a56cd4da3d..0000000000 --- a/packages/mobile/components/upload-list/src/mobile.vue +++ /dev/null @@ -1,375 +0,0 @@ - - - - - diff --git a/packages/mobile/components/upload-list/src/renderless/index.ts b/packages/mobile/components/upload-list/src/renderless/index.ts deleted file mode 100644 index 0a989c984f..0000000000 --- a/packages/mobile/components/upload-list/src/renderless/index.ts +++ /dev/null @@ -1,321 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { IUploadListRenderlessParams, IFileUploadFile, IUploadListVideoParam } from '../upload-list' - -import { xss } from '@mobile-root/utils/xss' -import { addResizeListener, removeResizeListener } from '@mobile-root/utils/deps/resize-event' - -export const parsePercentage = - () => - (val: string): number => - parseInt(val, 10) - -export const handleClick = - ({ props, api, parent }: Pick) => - (e: Event, file: IFileUploadFile): Function => { - e.preventDefault() - if (parent.state.isEdm) { - const { downloadFile } = api.getApi() - props.openDownloadFile && downloadFile && downloadFile(file) - } else { - props.openDownloadFile && api.downloadFile(file) - } - - return props.handlePreview && props.handlePreview(file) - } - -export const downloadFile = (service: IUploadListRenderlessParams['service']) => (file: IFileUploadFile) => { - const data = file && file.response && file.response.data - - let responseFile - if (Array.isArray(data)) { - responseFile = data[0] - } else if (data && typeof data === 'object') { - // eslint-disable-next-line no-unreachable-loop - for (let key in data) { - responseFile = data[key] - break - } - } - - if (responseFile) { - service.getFileDownloadUrl().then((url) => { - window.open(xss.filterUrl(url + '&id=' + responseFile.attachmentId + '&type=AttachmentDemo')).opener = null - }) - } else if (file.url) { - window.open(xss.filterUrl(file.url)).opener = null - } else { - throw new Error('[TINY Error][FileUpload]file.url must not be empty') - } -} - -export const picturefilePreview = (state: IUploadListRenderlessParams['state']) => (index: number) => { - state.startPostion = index - state.shows = true -} - -export const getDeleteData = (emit: IUploadListRenderlessParams['emit']) => (data: string[]) => { - emit('remove', data) -} - -export const showOperatePanel = - ({ state }: Pick) => - ({ file }: { file: IFileUploadFile }) => { - state.currentFile = file - state.showPanel = true - } - -export const reUpload = - ({ emit, props, parent }: Pick) => - (file: IFileUploadFile) => { - parent.state.isEdm - ? emit('start', [file && file.raw], '', true) - : props.handleReUpload && props.handleReUpload(file) - } - -const addPlayEventListener = ({ type, el }: IUploadListVideoParam, fn: Function) => el && el.addEventListener(type, fn) - -const removePlayEventListener = ({ type, el }: IUploadListVideoParam, fn: Function) => - el && el.removeEventListener(type, fn) - -export const play = - ({ vm, api, props }: Pick) => - ({ file, index, type }: { file: IFileUploadFile; index: number; type: string }) => { - if (props.isHwh5) { - return props.triggerPlay(file, type, 'play') - } - const videoOrAudioEle = vm.$refs[type + (file.uid || index)] && vm.$refs[type + (file.uid || index)][0] - if (file.isPlay) return api.pause({ file, index, type }) - if (videoOrAudioEle && videoOrAudioEle.play) { - file.playEvent = () => { - if (file) { - file.isPlay = false - removePlayEventListener({ type: 'ended', el: videoOrAudioEle }, file.playEvent) - } - } - file.el = videoOrAudioEle - removePlayEventListener({ type: 'ended', el: videoOrAudioEle }, file.playEvent) - addPlayEventListener({ type: 'ended', el: videoOrAudioEle }, file.playEvent) - vm.$set(file, 'isPlay', true) - videoOrAudioEle.play() - } - } - -export const pause = - ({ vm, props }: Pick) => - ({ file, index, type }: { file: IFileUploadFile; index: number; type: string }) => { - if (props.isHwh5) { - return props.triggerPlay(file, type, 'pause') - } - const videoOrAudioEle = vm.$refs[type + (file.uid || index)] && vm.$refs[type + (file.uid || index)][0] - if (videoOrAudioEle && videoOrAudioEle.pause) { - removePlayEventListener({ type: 'ended', el: videoOrAudioEle }, file.playEvent) - file.isPlay = false - videoOrAudioEle.pause() - } - } - -export const handleLoadedmetadata = - ({ vm }: Pick) => - ({ e, file }: { e: Event; file: IFileUploadFile }) => { - vm.$set(file, 'totalSecond', parseInt(e.target?.duration)) - vm.$set(file, 'currentSecond', parseInt(e.target?.currentTime)) - } - -export const handleTimeupdate = - () => - ({ e, file }: { e: Event; file: IFileUploadFile }) => { - file.currentSecond = parseInt(e.target?.currentTime) - } - -export const getFileType = - () => - ({ file }: { file: IFileUploadFile }): string => - file.name && file.name.split('.')[file.name.split('.').length - 1].toLowerCase() - -export const getFileIcon = - ({ constants }: Pick) => - ({ type }: { type: string }): { name: string; color: string } => { - const { EXCEL, FILE, PDF, PICTURE, PPT, TEXT, WORD, ZIP, VIDEO, AUDIO } = constants.FILE_TYPE - let iconTypes = { - [EXCEL]: { - name: 'icon-excel-type', - color: '#09AA71' - }, - [FILE]: { - name: 'icon-file-type', - color: '#09AA71' - }, - [PDF]: { - name: 'icon-pdf-type', - color: '#E02128' - }, - [PICTURE]: { - name: 'icon-picture-type', - color: '#5531EB' - }, - [PPT]: { - name: 'icon-ppt-type', - color: '#E02128' - }, - [TEXT]: { - name: 'icon-text-type', - color: '#2CB8C9' - }, - [WORD]: { - name: 'icon-word-type', - color: '#0067D1' - }, - [ZIP]: { - name: 'icon-zip-type', - color: '#2CB8C9' - }, - [VIDEO]: { - name: 'icon-video-type', - color: '#0067D1' - }, - [AUDIO]: { - name: 'icon-audio', - color: '#5531EB' - }, - default: { - name: 'icon-other-type', - color: '#9185F0' - } - } - - for (const typeName in iconTypes) { - if (Object.hasOwnProperty.call(iconTypes, typeName)) { - const typeValue = iconTypes[typeName] - delete iconTypes[typeName] - typeName.split('/').forEach((type) => (iconTypes[type] = typeValue)) - } - } - - return iconTypes[type] || iconTypes.default - } - -export const remove = - ({ emit }: Pick) => - ({ file }: { file: IFileUploadFile }) => - emit('remove', file) - -export const calcUploadListLiWidth = - ({ vm, nextTick, props, constants }: Pick) => - () => { - const { listType } = props - const { LIST_TYPE } = constants - nextTick(() => { - const uploadListEle = vm.$refs.uploadList - const uploadListLiEle = uploadListEle && uploadListEle.querySelectorAll('[data-tag="tiny-upload-list-item"]') - - if (!uploadListEle || !(uploadListLiEle && uploadListLiEle[0])) return - - if (listType === LIST_TYPE.TEXT || listType === LIST_TYPE.SAAS) { - const { minWidth } = window.getComputedStyle(uploadListLiEle && uploadListLiEle[0]) - const marginRight = 8 - - const num = Math.floor(uploadListEle.offsetWidth / (parseFloat(minWidth) + marginRight)) - - Array.from(uploadListLiEle).forEach((li, index) => { - if (!((index + 1) % num) || num === 1) { - li.style.marginRight = 0 - li.style.width = `${100 / num}%` - } else { - li.style.marginRight = `${marginRight}px` - li.style.width = `calc(${100 / num}% - ${marginRight}px)` - } - }) - } - }) - } - -export const calcVisible = - ({ props, constants, emit }: Pick) => - () => { - const { SUCESS } = constants.FILE_STATUS - const isAllSuccess = props.files.every(({ status }) => status === SUCESS || !status) - emit('update:visible', !isAllSuccess) - } - -export const getNotSuccessFiles = - ({ props, constants }: Pick) => - (): object[] => { - const { SUCESS } = constants.FILE_STATUS - let files = props.files - - if (props.mode === constants.MODE.BUBBLE && props.listType === constants.LIST_TYPE.TEXT) { - files = props.files.filter(({ status }) => status !== SUCESS) - } - - return files - } - -export const chooseFile = - ({ state, constants }: Pick) => - (type: string) => { - const { SOURCE_AUDIO } = constants.SOURCE_TYPE - if (type === SOURCE_AUDIO) { - state.showAudioPanel = true - } else { - state.showTriggerPanel = true - } - state.triggerClickType = type - } - -export const handleTriggerClick = - ({ state, props }: Pick) => - ($event: Event, type: string) => { - return new Promise((resolve) => { - let res = props.triggerClick($event, state.triggerClickType, type) - if (res && res.then) { - res - .then(() => { - state.showTriggerPanel = false - resolve() - }) - .catch(() => { - state.showTriggerPanel = false - state.showAudioPanel = false - }) - } else { - state.showTriggerPanel = false - resolve() - } - }) - } - -export const mounted = - ({ api, vm }: Pick) => - () => { - const el = vm.$refs.uploadList - if (el) { - addResizeListener(el, api.calcUploadListLiWidth) - vm._removeResizeListener = () => removeResizeListener(el, api.calcUploadListLiWidth) - } - } - -export const destroyed = - ({ props, vm }: Pick) => - () => { - if (vm._removeResizeListener) { - vm._removeResizeListener() - vm._removeResizeListener = null - } - - props.files.forEach((file) => { - removePlayEventListener({ type: 'ended', el: file.el }, file.playEvent) - delete file.playEvent - delete file.isPlay - delete file.el - }) - } diff --git a/packages/mobile/components/upload-list/src/renderless/vue.ts b/packages/mobile/components/upload-list/src/renderless/vue.ts deleted file mode 100644 index 8d63f7d1f9..0000000000 --- a/packages/mobile/components/upload-list/src/renderless/vue.ts +++ /dev/null @@ -1,147 +0,0 @@ -import type { - IUploadListState, - IUploadListApi, - IUploadListProps, - ISharedRenderlessParamHooks, - IUploadListRenderlessParamUtils, - IFileUploadModalVm, - IFileUploadConstants -} from '../upload-list' -import { - parsePercentage, - handleClick, - picturefilePreview, - getDeleteData, - downloadFile, - play, - pause, - handleLoadedmetadata, - handleTimeupdate, - destroyed, - showOperatePanel, - getFileType, - getFileIcon, - mounted, - calcUploadListLiWidth, - reUpload, - remove, - handleTriggerClick, - chooseFile, - calcVisible, - getNotSuccessFiles -} from './index' -import { getToken, initService } from '../../../file-upload/src/renderless' -import { formatFileSize } from '@mobile-root/utils/string' -import { getApi } from '../../../file-upload/src/renderless/vue' - -export const api = [ - 't', - 'state', - 'parsePercentage', - 'handleClick', - 'handlePreview', - 'picturefilePreview', - 'getDeleteData', - 'downloadFile', - 'play', - 'pause', - 'handleLoadedmetadata', - 'handleTimeupdate', - 'showOperatePanel', - 'getFileType', - 'getFileIcon', - 'reUpload', - 'remove', - 'handleTriggerClick', - 'chooseFile', - 'formatFileSize' -] - -export const renderless = ( - props: IUploadListProps, - { reactive, onMounted, onUnmounted, watch, inject, computed }: ISharedRenderlessParamHooks, - { t, parent, mode, emit, service, vm, nextTick, designConfig, useBreakpoint }: IUploadListRenderlessParamUtils, - { Modal }: IFileUploadModalVm -): IUploadListApi => { - const api = { getApi } as IUploadListApi - vm = inject('uploader') - const constants = vm.$constants as IFileUploadConstants - const $service = initService({ props, service }) - const { current } = useBreakpoint() - - const state = reactive({ - focusing: false, - shows: false, - currentBreakpoint: current, - progressType: designConfig?.state?.progressType || 'circle', - progressWidth: designConfig?.state?.progressWidth, - progressStrokeWidth: designConfig?.state?.progressStrokeWidth || 6, - tooltipDisabled: designConfig?.state?.tooltipDisabled !== false, - closeComponent: designConfig?.icons?.closeComponent || 'icon-close', - preViewComponent: designConfig?.icons?.preViewComponent, - failUploadFileCount: computed(() => - props.files.reduce((total, item) => (total += item.status === 'fail' ? 1 : 0), 0) - ), - startPostion: 0, - screenType: mode === 'mobile', - showPanel: false, - showTriggerPanel: false, - triggerClickType: '', - showAudioPanel: false, - files: computed(() => api.getNotSuccessFiles()), - currentFile: null - }) as IUploadListState - - parent.getToken = getToken({ constants, props: parent, state: parent.state, t, Modal }) - - Object.assign(api, { - state, - getDeleteData: getDeleteData(emit), - parsePercentage: parsePercentage(), - downloadFile: downloadFile($service), - picturefilePreview: picturefilePreview(state), - handleClick: handleClick({ props, api, parent }), - play: play({ vm, api, props }), - pause: pause({ vm, props }), - handleLoadedmetadata: handleLoadedmetadata({ vm }), - handleTimeupdate: handleTimeupdate(), - destroyed: destroyed({ props, vm }), - showOperatePanel: showOperatePanel({ state }), - getFileType: getFileType(), - getFileIcon: getFileIcon({ constants }), - mounted: mounted({ api, vm }), - calcUploadListLiWidth: calcUploadListLiWidth({ vm, nextTick, props, constants }), - reUpload: reUpload({ emit, props, parent }), - remove: remove({ emit }), - handleTriggerClick: handleTriggerClick({ state, props }), - chooseFile: chooseFile({ state, constants }), - calcVisible: calcVisible({ props, constants, emit }), - getNotSuccessFiles: getNotSuccessFiles({ props, constants }), - formatFileSize - }) - - props.listType === constants.LIST_TYPE.DRAG_SINGLE && - watch( - () => props.files && props.files[0], - (file) => { - if (file && file.status === constants.FILE_STATUS.FAIL) { - setTimeout(() => { - api.remove({ file }) - }, 2000) - } - }, - { immediate: true, deep: true } - ) - - watch(() => props.files, api.calcUploadListLiWidth) - - if (props.mode === constants.MODE.BUBBLE && props.listType === constants.LIST_TYPE.TEXT) { - constants && watch(() => props.files, api.calcVisible, { immediate: true, deep: true }) - } - - onMounted(api.mounted) - - onUnmounted(api.destroyed) - - return api -} diff --git a/packages/mobile/components/upload-list/src/upload-list.ts b/packages/mobile/components/upload-list/src/upload-list.ts deleted file mode 100644 index d9013d3536..0000000000 --- a/packages/mobile/components/upload-list/src/upload-list.ts +++ /dev/null @@ -1,184 +0,0 @@ -import type { ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' -import type { IFileUploadFile, IFileUploadConstants, IFileUploadModalVm } from '../../file-upload/src/file-upload' -import type { - getDeleteData, - parsePercentage, - downloadFile, - picturefilePreview, - handleClick, - play, - pause, - handleLoadedmetadata, - handleTimeupdate, - destroyed, - showOperatePanel, - getFileType, - getFileIcon, - mounted, - calcUploadListLiWidth, - reUpload, - remove, - handleTriggerClick, - chooseFile, - calcVisible, - getNotSuccessFiles -} from './renderless' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export type { IFileUploadConstants, IFileUploadModalVm, IFileUploadFile, downloadFile } - -export const uploadListProps = { - disabled: { - type: Boolean, - default: () => false - }, - display: { - type: Boolean, - default: () => true - }, - files: { - type: Array, - default: () => [] - }, - filesIcon: { - type: Array, - default: () => [] - }, - handlePreview: Function, - isEdm: { - type: Boolean, - default: () => false - }, - isFolder: { - type: Boolean, - default: () => false - }, - listType: String, - openDownloadFile: { - type: Boolean, - default: () => false - }, - srcList: { - type: Array, - default: () => [] - }, - isFolderTitle: { - type: Boolean, - default: false - }, - listOption: { - type: Object, - default: () => ({ - showUpdate: true, - showDel: true - }) - }, - maxNameLength: { - type: Number, - default: 20 - }, - scale: { - type: [Number, String], - default: 1 - }, - showName: { - type: Boolean, - default: false - }, - types: Array, - displayOnly: { - type: Boolean, - default: false - }, - handleDownloadFile: Function, - handleReUpload: Function, - isDragover: Boolean, - selected: Object, - triggerClick: { - type: Function, - default: () => {} - }, - isHwh5: { - type: Boolean, - default: false - }, - triggerPlay: { - type: Function, - default: () => {} - }, - mode: String, - lockScroll: { - type: Boolean, - default: true - }, - compact: { - type: Boolean, - default: false - }, - reUploadable: Boolean -} - -export interface IUploadListState { - focusing: boolean - shows: boolean - progressType: string - progressWidth: number - progressStrokeWidth: number - tooltipDisabled: boolean - closeComponent: string - preViewComponent: string - failUploadFileCount: number - startPostion: number - screenType: boolean - showPanel: boolean - showTriggerPanel: boolean - triggerClickType: string - showAudioPanel: boolean - files: object[] - currentFile: null | IFileUploadFile -} - -export interface IUploadListApi { - state: IUploadListState - getApi: () => void - getDeleteData: ReturnType - parsePercentage: ReturnType - downloadFile: ReturnType - picturefilePreview: ReturnType - handleClick: ReturnType - play: ReturnType - pause: ReturnType - handleLoadedmetadata: ReturnType - handleTimeupdate: ReturnType - destroyed: ReturnType - showOperatePanel: ReturnType - getFileType: ReturnType - getFileIcon: ReturnType - mounted: ReturnType - calcUploadListLiWidth: ReturnType - reUpload: ReturnType - remove: ReturnType - handleTriggerClick: ReturnType - chooseFile: ReturnType - calcVisible: ReturnType - getNotSuccessFiles: ReturnType -} - -export type IUploadListProps = ExtractPropTypes & { - files: { status: 'fail' | 'uploading' | 'success' | 'downloading' }[] -} - -export type IUploadListRenderlessParamUtils = ISharedRenderlessParamUtils - -export type IUploadListRenderlessParams = ISharedRenderlessFunctionParams & { - state: IUploadListState - props: IUploadListProps - api: IUploadListApi -} - -export interface IUploadListVideoParam { - type: 'ended' - el: HTMLVideoElement -} diff --git a/packages/mobile/components/upload/index.ts b/packages/mobile/components/upload/index.ts deleted file mode 100644 index 1a150313d8..0000000000 --- a/packages/mobile/components/upload/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Upload from './src/mobile.vue' - -/* istanbul ignore next */ -Upload.install = function (Vue) { - Vue.component(Upload.name, Upload) -} - -export default Upload diff --git a/packages/mobile/components/upload/src/mobile.vue b/packages/mobile/components/upload/src/mobile.vue deleted file mode 100644 index a83eace615..0000000000 --- a/packages/mobile/components/upload/src/mobile.vue +++ /dev/null @@ -1,87 +0,0 @@ - - - diff --git a/packages/mobile/components/upload/src/renderless/index.ts b/packages/mobile/components/upload/src/renderless/index.ts deleted file mode 100644 index fcce27035f..0000000000 --- a/packages/mobile/components/upload/src/renderless/index.ts +++ /dev/null @@ -1,488 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { - IUploadRenderlessParams, - IFileUploadModalVm, - IUploadRenderlessOtherParams, - IFileUploadFile, - IUploadFormData, - IUploadOptionsOfPost, - IUploadOptionsOfHwh5 -} from '../upload' - -import { KEY_CODE } from '@mobile-root/utils' - -export const isImage = (str: string): boolean => str.includes('image') - -export const handleChange = (api: IUploadRenderlessParams['api']) => (event: Event) => { - const files = (event.target).files - - if (!files) { - return - } - - api.uploadFiles(files) -} - -export const handlePaste = - ({ api, props }: Pick) => - (event: ClipboardEvent) => { - event.preventDefault() - - if (!props.pasteUpload) { - return - } - - const items = event.clipboardData?.items - - if (!items) { - return - } - - const files = [] as IFileUploadFile[] - for (let i = 0; i < items.length; i++) { - const file = items[i].getAsFile() - if (file) { - files.push(file) - } - } - - if (!files.length) { - return - } - - api.uploadFiles(files) - } - -export const getFormData = - ({ constants, state, props }: Pick) => - ({ formData, file, type }: { formData: IUploadFormData; file: IFileUploadFile; type: string }) => { - const uploaderInner = state.uploader.$refs[constants.FILE_UPLOAD_INNER_TEMPLATE] - if (uploaderInner.edm.upload) { - const params = uploaderInner.edm.upload.params - - for (let key in params) { - formData.set(key, params[key] || '') - } - } - - formData.append(constants.EDM.FILENAME, file.name) - - if (uploaderInner.edm.isCheckCode === true) { - formData.append(constants.EDM.ISCHECKCODE, 'Y') - formData.append(constants.EDM.CHECKCODE, file.hash) - } else { - formData.append(constants.EDM.ISCHECKCODE, 'N') - } - - if (props.isFolder) { - formData.append('filePath', file.path) - } - - const updateId = state.updateId || uploaderInner.edm.updateId - if (type === constants.EDM.SINGLEUPLOAD) { - formData.append(constants.EDM.MULTIPART, file, props.isFolder ? file.path + file.name : file.name) - updateId && formData.append(constants.EDM.DOCID, updateId) - } else { - const docId = updateId || file.docId - formData.append(constants.EDM.DOCID, docId) - formData.append(constants.EDM.FILESIZE, file.size) - } - - if (updateId) { - formData.append('updateFile', true) - state.updateId = '' - } - } - -export const uploadFiles = - ({ - state, - constants, - Modal, - props, - t - }: Pick & IFileUploadModalVm) => - (files: FileList | IFileUploadFile[]) => { - if (state.updateId === '') { - if (props.limit && props.fileList.length + files.length > props.limit) { - const fileUploadTem = state.uploader.$refs[constants.FILE_UPLOAD_INNER_TEMPLATE] - if (fileUploadTem && !fileUploadTem.state.listeners.exceed) { - Modal.message({ - message: t(constants.EDM.NumberExceed, { number: props.limit }), - status: 'warning' - }) - } - props.onExceed && props.onExceed(files, props.fileList) - return - } - } - - let postFiles = Array.prototype.slice.call(files) - - if (props.isFolder) { - postFiles = postFiles.filter((item) => { - const folderAry = item.webkitRelativePath.split('/') - item.path = folderAry.slice(0, folderAry.length - 1).join('/') + '/' - if (folderAry.length >= 7) { - Modal.message({ - message: `${item.name}${t(constants.EDM.FOLDERKEY)}`, - status: 'warning' - }) - } - - return folderAry.length < 7 - }) - } else if (!props.multiple) { - postFiles = postFiles.slice(0, 1) - } - - if (postFiles.length === 0) { - return - } - - if (props.onStart) { - props.onStart(postFiles, state.updateId) - } - } - -export const upload = - ({ api, props, refs }: Pick) => - (rawFile: File) => { - refs.input.value = null - - if (!props.beforeUpload) { - return api.post(rawFile) - } - - const previous = props.beforeUpload(rawFile) - - if (previous && previous.then) { - previous.then( - (fileProcessed) => { - const typeOfFile = Object.prototype.toString.call(fileProcessed) - - if (typeOfFile === '[object File]' || typeOfFile === '[object Blob]') { - if (typeOfFile === '[object Blob]') { - fileProcessed = new File([fileProcessed], rawFile.name, { - type: rawFile.type - }) - } - - for (const p in rawFile) { - if (Object.prototype.hasOwnProperty.call(rawFile, p)) { - fileProcessed[p] = rawFile[p] - } - } - - api.post(fileProcessed) - } else { - api.post(rawFile) - } - }, - () => { - props.onRemove(null, rawFile) - } - ) - } else if (previous !== false) { - api.post(rawFile) - } else { - props.onRemove(null, rawFile) - } - } - -export const abort = - ({ state, props, constants }: Pick) => - (file: IFileUploadFile) => { - const { reqs } = state - const cancel = function (uid) { - if (reqs[uid]?.abort) { - reqs[uid].abort('') - } else if (state.cancelToken[uid]) { - state.cancelToken[uid]('') - } - delete reqs[uid] - delete state.cancelToken[uid] - } - - if (file && file.isLargeFile && file.cancelToken) { - file.cancelToken && file.cancelToken.forEach((cancel) => cancel('')) - - delete file.cancelToken - } else if (file) { - let uid = file - - if (file.uid) { - uid = file.uid - } - - cancel(uid) - } else { - const { READY, UPLOADING, FAIL } = constants.FILE_STATUS - Object.keys(reqs).forEach((uid) => cancel(uid || '')) - - props.fileList.forEach((file: any) => { - file.cancelToken && file.cancelToken.forEach((cancel) => cancel('')) - if ([READY, UPLOADING].includes(file.status)) { - file.status = FAIL - } - }) - } - } - -const getOptionsOfPost = ({ - props, - state, - rawFile, - uploaderInner, - uid -}: Pick & IUploadRenderlessOtherParams): IUploadOptionsOfPost => { - return { - headers: Object.assign(props.headers || {}, state.headers || {}), - withCredentials: props.withCredentials, - file: rawFile, - data: props.data, - filename: props.name, - action: uploaderInner.action || props.action, - onSuccess: (res) => { - if (props.onSuccess) { - props.onSuccess(res, rawFile) - } - delete state.reqs[uid] - }, - onProgress: (event) => { - if (props.onProgress) { - props.onProgress(event, rawFile) - } - }, - onError: (error) => { - if (props.onError) { - props.onError(error, rawFile) - } - delete state.reqs[uid] - } - } -} - -const modifyOptionsOfPost = ({ - service, - props, - options, - rawFile, - state, - uid, - uploaderInner, - api, - constants -}: Pick & - IUploadRenderlessOtherParams & { options: IUploadOptionsOfPost }) => { - if (service && service.network && props.httpRequest === service.network.request) { - options.method = 'post' - options.url = options.action - options.onUploadProgress = (event) => { - if (props.onProgress) { - props.onProgress(event, rawFile) - } - } - delete options.action - delete options.onProgress - const formData = new FormData() as IUploadFormData - const source = service.network.CancelToken.source() - options.cancelToken = source.token - state.cancelToken[uid] = source.cancel - if (uploaderInner.edm.upload) { - !rawFile.isLargeFile && (options.method = 'put') - options.data = options.data || {} - } - if (options.data) { - Object.keys(options.data).forEach((key) => { - formData.append(key, options.data[key]) - }) - } - if (Array.isArray(rawFile)) { - rawFile.forEach((file) => formData.append(file.name, file.raw || file)) - } else { - if (state.isEdm) { - api.getFormData({ - formData, - file: rawFile, - type: !rawFile.isLargeFile ? constants.EDM.SINGLEUPLOAD : '' - }) - } else { - formData.append(options.filename, rawFile, rawFile.name) - } - } - options.data = formData - } -} - -const getOptionsOfHwh5 = ({ - state, - props, - rawFile, - uploaderInner, - uid -}: Pick & IUploadRenderlessOtherParams): IUploadOptionsOfHwh5 => { - const edm = uploaderInner.edm - const params = (edm && edm.upload && edm.upload.params) || {} - - return Object.assign( - { - edmAuth: { - edmToken: props.edmToken.edmToken, - appId: uploaderInner.hwh5.appId - }, - filePath: rawFile.filePath, - progress: 1 - }, - params, - { - onProgress: (data) => { - props.onProgress(data, rawFile) - }, - onSuccess: (res) => { - props.onSuccess(res, rawFile) - delete state.reqs[uid] - }, - onError: (error) => { - props.onError(error, rawFile) - delete state.reqs[uid] - } - } - ) -} - -export const post = - ({ - api, - constants, - props, - state, - service - }: Pick) => - (rawFile: IFileUploadFile) => { - const { uid } = rawFile - const uploaderInner = state.uploader.$refs[constants.FILE_UPLOAD_INNER_TEMPLATE] - - let options - if (uploaderInner.state.isHwh5) { - options = getOptionsOfHwh5({ state, props, rawFile, uploaderInner, uid }) - } else { - options = getOptionsOfPost({ props, state, rawFile, uploaderInner, uid }) - modifyOptionsOfPost({ service, props, options, rawFile, state, uid, uploaderInner, api, constants }) - } - - const excuteReq = (options) => { - if (props.httpRequest) { - const req = props.httpRequest(options) - - state.reqs[uid] = req - - if (req && req.then) { - req.then(options.onSuccess, options.onError) - } - } - } - - if (rawFile.isLargeFile) { - service.common.getChunkMergeUrl().then((url) => { - options.url = url - excuteReq(options) - }) - } else { - excuteReq(options) - } - } - -export const handleClick = - ({ props, refs, state }: Pick) => - ($event: Event, type: string) => { - if (props.disabled || props.displayOnly || state.isStopPropagation) { - return - } - - const { uploader, uploadInner } = state - const { encryptConfig = {} } = uploader - const fileUploadVm = uploadInner.$parent - const inputHandler = () => { - typeof props.handleTriggerClick === 'function' && props.handleTriggerClick($event, type) - - if (props.isHwh5) { - return - } - - refs.input.value = null - state.isStopPropagation = true - refs.input.click() - state.isStopPropagation = false - } - - if (typeof uploader.beforeAddFile === 'function') { - // beforeAddFile 添加文件前钩子函数 - $event.preventDefault() - // 支持返回 false、返回 promise 异步和执行回调方法 3 种方式阻止添加文件流程 - let isPromise - const promise = uploader.beforeAddFile(() => { - !isPromise && inputHandler() - }) - - isPromise = promise && typeof promise.then === 'function' - if (isPromise) { - promise.then(() => inputHandler()).catch(() => null) - } else if (promise) { - inputHandler() - } - } else if (encryptConfig && encryptConfig.enabled && fileUploadVm) { - fileUploadVm.state.encryptDialogConfig.show = true - fileUploadVm.state.encryptDialogConfig.selectFileMethod = () => { - inputHandler() - } - } else { - inputHandler() - } - } - -export const handleKeydown = (api: IUploadRenderlessParams['api']) => (event: KeyboardEvent) => { - if (event.target !== event.currentTarget) { - return - } - - if (event.keyCode === KEY_CODE.Enter || event.keyCode === KEY_CODE.Space) { - api.handleClick(event, '') - } -} - -export const handleUpdate = - ({ props, state }: Pick) => - (file: IFileUploadFile) => { - if (!props.disabled && state.updateInput) { - state.updateInput.value = '' - state.updateId = file.docId - state.updateInput.click() - } - } - -export const mounted = - ({ state, props, api }: Pick) => - () => { - let updateInput = document.createElement('input') - updateInput.type = 'file' - updateInput.name = props.name - updateInput.accept = props.accept || '' - updateInput.onchange = api.handleChange - - state.updateInput = Object.freeze(updateInput) - } - -export const onBeforeDestroy = (state: IUploadRenderlessParams['state']) => () => { - state.updateInput = null -} diff --git a/packages/mobile/components/upload/src/renderless/vue.ts b/packages/mobile/components/upload/src/renderless/vue.ts deleted file mode 100644 index 30d591c9e1..0000000000 --- a/packages/mobile/components/upload/src/renderless/vue.ts +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import type { - IUploadState, - IUploadApi, - IUploadProps, - ISharedRenderlessParamHooks, - IUploadRenderlessParamUtils, - IFileUploadModalVm, - IFileUploadVm -} from '../upload' - -import { - getFormData, - isImage, - handleChange, - uploadFiles, - handlePaste, - upload, - abort, - post, - handleClick, - handleKeydown, - handleUpdate, - mounted, - onBeforeDestroy -} from './index' - -export const api = [ - 'state', - 'isImage', - 'handleChange', - 'handlePaste', - 'uploadFiles', - 'upload', - 'abort', - 'post', - 'handleClick', - 'handleKeydown', - 'handleUpdate' -] - -export const renderless = ( - props: IUploadProps, - { computed, inject, reactive, onMounted, onBeforeUnmount }: ISharedRenderlessParamHooks, - { refs, service, t, useBreakpoint }: IUploadRenderlessParamUtils, - { Modal }: IFileUploadModalVm & { CryptoJS: object; Streamsaver: object } -): IUploadApi => { - const api = {} as IUploadApi - const uploader = inject('uploader') as IFileUploadVm - const constants = uploader.$constants - const { current } = useBreakpoint() - const state: IUploadState = reactive({ - currentBreakpoint: current, - mouseover: false, - reqs: {}, - uploader, - accecpt: '', - uploadInner: computed(() => state.uploader), - isEdm: computed(() => state.uploadInner.state.isEdm), - openEdmDownload: computed(() => state.uploadInner.edm.download), - - headers: computed(() => { - if (state.isEdm) { - return { - [constants.EDM.EDMTOKEN]: props.edmToken.edmToken || '', - [constants.EDM.TRACEID]: props.edmToken.traceId || '' - } - } - }), - - formData: {}, - cancelToken: {}, - updateId: '', - updateInput: null, - isStopPropagation: false - }) - - Object.assign(api, { - state, - isImage, - abort: abort({ state, props, constants }), - getFormData: getFormData({ state, constants, props }), - handleClick: handleClick({ props, refs, state }), - onBeforeDestroy: onBeforeDestroy(state), - handleUpdate: handleUpdate({ state, props }), - uploadFiles: uploadFiles({ constants, Modal, props, state, t }), - post: post({ api, constants, props, state, service }), - handleChange: handleChange(api), - handlePaste: handlePaste({ api, props }), - handleKeydown: handleKeydown(api), - upload: upload({ api, props, refs }), - mounted: mounted({ state, props, api }) - }) - - onMounted(api.mounted) - onBeforeUnmount(api.onBeforeDestroy) - - return api -} diff --git a/packages/mobile/components/upload/src/upload.ts b/packages/mobile/components/upload/src/upload.ts deleted file mode 100644 index 95eec38a61..0000000000 --- a/packages/mobile/components/upload/src/upload.ts +++ /dev/null @@ -1,194 +0,0 @@ -import uploadAjax from '@mobile-root/utils/deps/upload-ajax' -import type { ExtractPropTypes } from 'vue' -import type { - ISharedRenderlessFunctionParams, - ISharedRenderlessParamUtils, - ITinyVm, - ISharedRenderlessParamHooks -} from '@mobile-root/shared.type' -import type { - isImage, - abort, - getFormData, - handleClick, - onBeforeDestroy, - handleUpdate, - handlePaste, - uploadFiles, - post, - handleChange, - handleKeydown, - upload, - mounted -} from './renderless' -import type { - IFileUploadVm, - IFileUploadConstants, - IFileUploadFile, - IFileUploadModalVm -} from '../../file-upload/src/file-upload' - -export const uploadProps = { - accept: String, - action: { - type: String, - default: '' - }, - autoUpload: Boolean, - beforeUpload: Function, - pasteUpload: Boolean, - data: Object, - disabled: Boolean, - drag: Boolean, - edmToken: { - type: Object, - default: () => ({}) - }, - fileList: { - type: Array, - default: () => [] - }, - headers: Object, - httpRequest: { - type: Function, - default: uploadAjax - }, - isFolder: { - type: Boolean, - default: false - }, - limit: Number, - listType: String, - multiple: Boolean, - name: { - type: String, - default: 'file' - }, - onError: Function, - onExceed: Function, - onPreview: { - type: Function, - default: () => {} - }, - onProgress: Function, - onRemove: { - type: Function, - default: () => {} - }, - onStart: Function, - onSuccess: Function, - type: String, - withCredentials: Boolean, - isHidden: { - type: Boolean, - default: false - }, - scale: { - type: [Number, String], - default: 1 - }, - sourceType: { - type: String, - default: 'picture', - validator(val: string) { - return val.split('/').every((type) => ['picture', 'video', 'audio'].includes(type)) - } - }, - displayOnly: { - type: Boolean, - default: false - }, - customClass: [String, Object, Array], - handleTriggerClick: { - type: Function, - default: () => {} - }, - mode: String, - showTitle: Boolean, - isHwh5: { - type: Boolean, - default: false - } -} - -export type { IFileUploadVm, IFileUploadConstants, IFileUploadFile, ISharedRenderlessParamHooks, IFileUploadModalVm } - -export type IUploadStateHeader = { [propName: string]: string } | undefined - -export interface IUploadState { - mouseover: boolean - reqs: { - uid?: string - } - uploader: IFileUploadVm - accecpt: string - isEdm: boolean - openEdmDownload: boolean - headers: IUploadStateHeader - formData: object - cancelToken: object - updateId: string - updateInput: null | HTMLInputElement -} - -export interface IUploadApi { - state: IUploadState - isImage: typeof isImage - abort: ReturnType - getFormData: ReturnType - handleClick: ReturnType - onBeforeDestroy: ReturnType - handleUpdate: ReturnType - handlePaste: ReturnType - uploadFiles: ReturnType - post: ReturnType - handleChange: ReturnType - handleKeydown: ReturnType - upload: ReturnType - mounted: ReturnType -} - -export type IUploadProps = ExtractPropTypes - -export type IUploadRenderlessParamUtils = ISharedRenderlessParamUtils - -export type IUploadRenderlessParams = ISharedRenderlessFunctionParams & { - state: IUploadState - props: IUploadProps - api: IUploadApi -} - -export interface IUploadRenderlessOtherParams { - rawFile: IFileUploadFile - uploaderInner: ITinyVm - uid: string -} - -export interface IUploadFormData extends FormData { - append(name: string, value: boolean | string | number | Blob, fileName?: string): void -} - -export interface IUploadOptionsOfPost { - headers: object - withCredentials: boolean - file: File - data: IUploadFormData | undefined | Record - filename: string - action?: string // 涉及到删除,所以为可选;底下同理 - onSuccess: (res: object) => void - onProgress?: (event: Event) => void - onError: (error: object) => void - [x: string]: any // 允许动态添加属性 -} - -export interface IUploadOptionsOfHwh5 { - edmAuth: { - edmToken: string - appId: string - } - filePath: string - progress: number - onProgress: (data: object) => void - onSuccess: (res: object) => void - onError: (error: object) => void -} diff --git a/packages/mobile/components/user-head/index.ts b/packages/mobile/components/user-head/index.ts deleted file mode 100644 index 4adaaa58bd..0000000000 --- a/packages/mobile/components/user-head/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import UserHead from './src/mobile.vue' - -/* istanbul ignore next */ -UserHead.install = function (Vue) { - Vue.component(UserHead.name, UserHead) -} - -export default UserHead diff --git a/packages/mobile/components/user-head/src/mobile.vue b/packages/mobile/components/user-head/src/mobile.vue deleted file mode 100644 index 2a3685e31c..0000000000 --- a/packages/mobile/components/user-head/src/mobile.vue +++ /dev/null @@ -1,55 +0,0 @@ - - - - - diff --git a/packages/mobile/components/user-head/src/renderless/index.ts b/packages/mobile/components/user-head/src/renderless/index.ts deleted file mode 100644 index 597634f6ff..0000000000 --- a/packages/mobile/components/user-head/src/renderless/index.ts +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { IUserHeadRenderlessParams } from '../user-head' - -export const computedStyle = - ({ state, props }: Pick) => - () => { - return { - fill: state.color, - color: state.color, - backgroundColor: state.backgroundColor, - backgroundImage: /^(image)$/.test(props.type) && state.internalValue ? `url(${state.internalValue})` : 'none' - } - } - -export const computedMessage = - ({ props }: Pick) => - () => { - let result = '' - const total = Math.floor(Number(props.messageTotal) || NaN) - - if (props.messageType === 'details' && !isNaN(total) && total > 0) { - result = String(total) - - if (props.messageUpperLimit && total > props.messageUpperLimit) { - result = `${props.messageUpperLimit}+` - } - } - - return result - } - -export const computedFontSize = - ({ props, state, mode }: Pick) => - () => { - let fontSize = '' - - if (props.type === 'label' && state.label && !props.min) { - const length = state.label.length - const sizeMap = { - 1: '40px', - 2: '30px', - 3: '22px', - 4: '20px', - 5: '18px', - 6: '16px' - } - - const mfsizeMap = { - 1: `${state.size / 1.5}px`, - 2: `${state.size / 3}px`, - 3: `${state.size / 4.5}px`, - 4: `${state.size / 6}px`, - 5: `${state.size / 7.5}px`, - 6: `${state.size / 9}px` - } - - fontSize = sizeMap[length] - } - - return { fontSize } - } - -export const computedLabel = - ({ state, props }: Pick) => - () => - props.min ? state.internalValue.substr(0, 2) : state.internalValue.substr(0, 6) - -export const getInternalValue = - ({ props }: Pick) => - () => { - if (props.modelValue === null) { - let result = '' - - if (props.type === 'icon') { - result = 'icon-user' - } else if (props.type === 'label') { - result = 'U' - } - - return result || props.value - } else { - return props.modelValue - } - } - -export const handleClick = (emit) => (event) => emit('click', event) - -export const mouseEnter = (emit) => (event) => emit('mouseenter', event) diff --git a/packages/mobile/components/user-head/src/renderless/vue.ts b/packages/mobile/components/user-head/src/renderless/vue.ts deleted file mode 100644 index 3df80c83d5..0000000000 --- a/packages/mobile/components/user-head/src/renderless/vue.ts +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { - IUserHeadApi, - IUserHeadProps, - IUserHeadRenderlessParamUtils, - IUserHeadState, - ISharedRenderlessParamHooks -} from '../user-head' -import { - computedMessage, - computedStyle, - computedFontSize, - computedLabel, - getInternalValue, - handleClick, - mouseEnter -} from './index' - -export const api = ['state', 'handleClick', 'mouseEnter'] - -export const renderless = ( - props: IUserHeadProps, - { reactive, computed, inject }: ISharedRenderlessParamHooks, - { mode, emit }: IUserHeadRenderlessParamUtils -): IUserHeadApi => { - const groupSize = inject('groupSize', null) - - const state: IUserHeadState = reactive({ - internalValue: computed(() => api.getInternalValue()), - label: computed(() => api.computedLabel()), - style: computed(() => api.computedStyle()), - message: computed(() => api.computedMessage()), - fontSize: computed(() => api.computedFontSize()), - size: groupSize || props.size, - color: inject('color', null) || props.color, - backgroundColor: inject('backgroundColor', null) || props.backgroundColor - }) - - const api: IUserHeadApi = { - state, - computedLabel: computedLabel({ state, props }), - computedStyle: computedStyle({ state, props }), - computedMessage: computedMessage({ props }), - computedFontSize: computedFontSize({ props, state, mode }), - getInternalValue: getInternalValue({ props }), - handleClick: handleClick(emit), - mouseEnter: mouseEnter(emit) - } - - return api -} diff --git a/packages/mobile/components/user-head/src/user-head.ts b/packages/mobile/components/user-head/src/user-head.ts deleted file mode 100644 index 776091752d..0000000000 --- a/packages/mobile/components/user-head/src/user-head.ts +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type { ExtractPropTypes } from 'vue' -import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from '@mobile-root/shared.type' -import type { computedFontSize, computedLabel, computedMessage, computedStyle, getInternalValue } from './renderless' - -export type { ISharedRenderlessParamHooks } from '@mobile-root/shared.type' - -export const $constants = { - ITEM_NAME: '.user-head-item' -} - -export const userHeadProps = { - _constants: { - type: Object, - default: () => $constants - }, - /** - * @property {Boolean} [min=false] - 小尺寸模式 - */ - min: Boolean, - - /** - * @property {Boolean} [round=true] - 圆形模式 - */ - round: Boolean, - - /** - * @property {String} [color=#ffffff] - 文字颜色 - */ - color: { - type: String, - default: '#ffffff' - }, - - /** - * @property {String} [backgroundColor=#BBBBBB] - 背景色 - */ - backgroundColor: { - type: String, - default: '#B5BBC1' - }, - - /** - * @property {String} [type=label] - 头像类型,icon|image|label 可选 - */ - type: { - type: String, - default: 'label', - validator: (value: string) => Boolean(~['icon', 'image', 'label'].indexOf(value)) - }, - - /** - * @property {String} - 头像资源 - * type=icon 时为图标类名,type=label时为字体串,type=image时为资源路径 - */ - value: { - type: [Object, String], - default: null - }, - - /** - * @property {String} - 头像资源 - * type=icon 时为图标类名,type=label时为字体串,type=image时为资源路径 - */ - modelValue: { - type: [Object, String], - default: null - }, - - /** - * @property {Number} - 消息计数 - */ - messageTotal: [Number, String], - - /** - * @property {String} [messageType=details] - 消息类型 details|basic 可选 - */ - messageType: { - type: String, - default: 'details', - validator: (value: string) => Boolean(~['details', 'basic'].indexOf(value)) - }, - - /** - * @property {Number} [messageUpperLimit=0] - 消息显示上限 - */ - messageUpperLimit: { - type: Number, - default: 0 - }, - size: { - type: Number, - default: 40 - } -} - -export interface IUserHeadState { - internalValue: string | Record - label: string - style: ReturnType> - message: string - fontSize: { fontSize: string } - size: number - color: string - backgroundColor: string -} - -export type IUserHeadProps = ExtractPropTypes - -export type IUserHeadConstants = typeof $constants - -export type IUserHeadRenderlessParams = ISharedRenderlessFunctionParams & { - api: IUserHeadApi - state: IUserHeadState - props: IUserHeadProps -} - -export interface IUserHeadApi { - state: IUserHeadState - computedLabel: ReturnType - computedStyle: ReturnType - computedMessage: ReturnType - computedFontSize: ReturnType - getInternalValue: ReturnType - handleClick: (event: Event) => void - mouseEnter: (event: Event) => void -} - -export type IUserHeadRenderlessParamUtils = ISharedRenderlessParamUtils diff --git a/packages/mobile/components/wheel/index.ts b/packages/mobile/components/wheel/index.ts deleted file mode 100644 index 4fe7afd7a4..0000000000 --- a/packages/mobile/components/wheel/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Wheel from './src/mobile.vue' - -Wheel.install = function (Vue) { - Vue.component(Wheel.name, Wheel) -} - -export default Wheel diff --git a/packages/mobile/components/wheel/src/mobile.vue b/packages/mobile/components/wheel/src/mobile.vue deleted file mode 100644 index e9de9b0044..0000000000 --- a/packages/mobile/components/wheel/src/mobile.vue +++ /dev/null @@ -1,82 +0,0 @@ - - - - diff --git a/packages/mobile/components/wheel/src/renderless/index.ts b/packages/mobile/components/wheel/src/renderless/index.ts deleted file mode 100644 index 84a1544838..0000000000 --- a/packages/mobile/components/wheel/src/renderless/index.ts +++ /dev/null @@ -1,222 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { cloneDeep } from '@mobile-root/utils/object' - -export const created = (api) => () => { - api.loadPickerData() - api.loadWheels() -} - -/** - * @description 初始化组装数据 - */ - -export const loadPickerData = - ({ props, state }) => - () => { - state.dataSource = cloneDeep(props.dataSource) - state.defaultSelectedIndexs = cloneDeep(props.defaultSelectedIndexs) - - if (!state.dataSource.length) { - return - } - - const level_1 = state.dataSource - const level_n = getNextLevel([], state.dataSource, state.defaultSelectedIndexs, 0) - if (level_n.length === 0) { - // 单列 - state.pickerData = [level_1] - } else { - // 多列 - state.pickerData = [level_1, ...level_n] - } - } - -/** - * @description 获取第二列至最后一列的滚动数据 - * @param {*} levelItems 多列滚动数据集合,初始为空 - * @param {*} children 当前迭代的元素 - * @param {*} nextIndexs 当前迭代元素的下标 - * @param {*} start 起始迭代的下标 - * @returns 多列滚动数据集合 - */ - -export const getNextLevel = (levelItems, children, nextIndexs, start) => { - let levelItem = children[nextIndexs[start]]?.children ?? [] - if (start !== nextIndexs.length - 1) { - levelItems.push(levelItem) - return getNextLevel(levelItems, levelItem, nextIndexs, ++start) - } else { - return levelItems - } -} - -/** - * @description 滚动后重新组装数据 - * @param {*} newIndexs 当前迭代元素的下标集合 - * @param {*} oldIndexs 上次迭代元素的下标集合 - * @returns 组装后的数据 - */ - -export const wheelChanged = - ({ api, state }) => - (newIndexs, oldIndexs) => { - if (newIndexs.length > 1) { - // 多列 - newIndexs.forEach((ii, ri) => { - if (newIndexs[ri] !== oldIndexs[ri] && ri !== newIndexs.length - 1) { - const children = getChildren(state.dataSource, newIndexs, 0, ri) - state.pickerData.splice(ri + 1, 1, children) - } - }) - } - api.wheelsTo(newIndexs) - api.changeWheelItemStyle(state.pickerData, newIndexs) - } -/** - * @description 获取当前滚动元素的子元素 - * @param {*} levelItems 当前元素的集合 - * @param {*} newIndexs 当前迭代元素的下标集合 - * @param {*} start 起始迭代的下标,默认为0,后续每次增加1 - * @param {*} maxLoop 最大迭代深度(为滚动列的下标) - * @returns 当前滚动元素的子元素 - */ - -export const getChildren = (levelItems, newIndexs, start, maxLoop) => { - let levelItem = levelItems[newIndexs[start]]?.children ?? [] - if (start !== maxLoop) { - return getChildren(levelItem, newIndexs, ++start, maxLoop) - } else { - return levelItem - } -} - -export const wheelsTo = - ({ api, state, nextTick }) => - (indexs) => { - nextTick(() => { - state.wheels.forEach((wheel, i) => { - wheel.wheelTo(indexs[i], 0) - api.refreshWheel(wheel) - }) - }) - } - -export const refreshWheel = (nextTick) => (wheel) => { - nextTick(() => { - wheel.refresh() - }) -} - -export const loadWheels = - ({ api, props, state, nextTick, refs }) => - () => { - if (state.wheels.length === 0) { - nextTick(() => { - state.wheels = [] - const { wheelWrapper } = refs - if (props.hasFooter) { - for (let i = 0; i < state.pickerData.length; i++) { - api.createWheelHasFooter(wheelWrapper, i) - } - } else { - api.createWheelNoFooter(wheelWrapper) - } - }) - } - } - -export const createWheelHasFooter = - ({ api, state, emit, BScroll }) => - (wheelWrapper, i) => { - const wheels = state.wheels - if (!wheels[i]) { - wheels[i] = state.wheels[i] = new BScroll(wheelWrapper.children[i], { - wheel: { - selectedIndex: state.defaultSelectedIndexs[i], - wheelWrapperClass: 'wheel-scroll', - wheelItemClass: 'wheel-item' - }, - probeType: 3 - }) - state.prevSelectedIndexs = state.defaultSelectedIndexs - wheels[i].on('wheelIndexChanged', () => { - const currentSelectedIndex = wheels[i].getSelectedIndex() - - // 从滚动的当前列往后,默认都滚动到每列的首个元素 - let currentSelectedIndexs = [ - ...state.prevSelectedIndexs.slice(0, i), - currentSelectedIndex, - ...new Array(state.defaultSelectedIndexs.length - i - 1).fill(0) - ] - api.wheelChanged(currentSelectedIndexs, state.prevSelectedIndexs) - state.prevSelectedIndexs = currentSelectedIndexs - emit('change', currentSelectedIndexs) - }) - api.wheelsTo(state.defaultSelectedIndexs) - api.changeWheelItemStyle(state.pickerData, state.defaultSelectedIndexs) - } else { - wheels[i].refresh() - } - return wheels[i] - } - -export const createWheelNoFooter = - ({ api, state, BScroll }) => - (wheelWrapper) => { - const wheels = state.wheels - if (!wheels[0]) { - wheels[0] = state.wheels[0] = new BScroll(wheelWrapper.children[0], { - probeType: 3, - click: true - }) - api.changeWheelItemStyle(state.pickerData, state.defaultSelectedIndexs) - api.refreshWheel(wheels[0]) - } else { - wheels[0].refresh() - } - return wheels[0] - } - -export const changeWheelItemStyle = (state) => (pickerData, currentSelectedIndexs) => { - pickerData.forEach((item, index) => { - state.pickerData[index] = item.map((rItem, i) => { - rItem.selected = i === currentSelectedIndexs[index] - return rItem - }) - }) -} - -export const dealWheels = (state) => () => { - state.wheels.forEach((wheel) => { - wheel.destroy() - }) - state.wheels = [] - state.pickerData = [] - state.prevSelectedIndexs = [] - state.defaultSelectedIndexs = [] -} - -export const clickWheelItem = - ({ api, state, emit }) => - (index) => { - api.changeWheelItemStyle(state.pickerData, [index]) - const rItem = state.pickerData[0][index] - if (state.defaultSelectedIndexs[0] !== index) { - const selectedLabel = rItem?.label - emit('clickWheelItem', [index], selectedLabel, rItem) - } else { - // 反选 - emit('clickWheelItem', [], '', []) - } - } diff --git a/packages/mobile/components/wheel/src/renderless/vue.ts b/packages/mobile/components/wheel/src/renderless/vue.ts deleted file mode 100644 index 7f5e8113e7..0000000000 --- a/packages/mobile/components/wheel/src/renderless/vue.ts +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { - created, - loadPickerData, - wheelChanged, - changeWheelItemStyle, - loadWheels, - createWheelHasFooter, - createWheelNoFooter, - wheelsTo, - refreshWheel, - dealWheels, - clickWheelItem -} from './index' - -export const api = [ - 'state', - 'created', - 'loadPickerData', - 'wheelChanged', - 'changeWheelItemStyle', - 'loadWheels', - 'createWheelHasFooter', - 'createWheelNoFooter', - 'wheelsTo', - 'refreshWheel', - 'dealWheels', - 'clickWheelItem' -] - -const initState = (reactive) => { - const state = reactive({ - dataSource: [], - defaultSelectedIndexs: [], - pickerData: [], - wheels: [], - prevSelectedIndexs: [] - }) - - return state -} - -const initApi = ({ api, props, state, emit, nextTick, refs, BScroll }) => { - Object.assign(api, { - state, - created: created(api), - loadPickerData: loadPickerData({ props, state }), - wheelChanged: wheelChanged({ api, state }), - changeWheelItemStyle: changeWheelItemStyle(state), - loadWheels: loadWheels({ api, props, state, nextTick, refs }), - createWheelHasFooter: createWheelHasFooter({ api, state, emit, BScroll }), - createWheelNoFooter: createWheelNoFooter({ api, state, BScroll }), - wheelsTo: wheelsTo({ api, state, nextTick }), - refreshWheel: refreshWheel(nextTick), - dealWheels: dealWheels(state), - clickWheelItem: clickWheelItem({ api, state, emit }) - }) -} - -const initWatch = ({ watch, api, props, state, nextTick }) => { - watch( - () => props.defaultSelectedIndexs, - () => { - api.dealWheels(state) - nextTick(() => { - api.created(api) - }) - } - ) -} - -export const renderless = (props, { onMounted, reactive, watch }, { emit, nextTick, refs }, { BScroll }) => { - const api = {} - const state = initState(reactive) - - initApi({ api, props, state, emit, nextTick, refs, BScroll }) - - initWatch({ watch, api, props, state, nextTick }) - - onMounted(() => { - api.created(api) - }) - - return api -} diff --git a/packages/mobile/index.ts b/packages/mobile/index.ts deleted file mode 100644 index 42fb619837..0000000000 --- a/packages/mobile/index.ts +++ /dev/null @@ -1,158 +0,0 @@ -import ActionSheet from './components/action-sheet' -import Alert from './components/alert' -import Avatar from './components/avatar' -import Badge from './components/badge' -import Button from './components/button' -import Checkbox from './components/checkbox' -import CheckboxGroup from './components/checkbox-group' -import Container from './components/container' -import DatePicker from './components/date-picker' -import DialogBox from './components/dialog-box' -import DropdownItem from './components/dropdown-item' -import DropdownMenu from './components/dropdown-menu' -import Exception from './components/exception' -import FileUpload from './components/file-upload' -import Form from './components/form' -import FormItem from './components/form-item' -import ImageViewer from './components/image-viewer' -import IndexBar from './components/index-bar' -import IndexBarAnchor from './components/index-bar-anchor' -import Input from './components/input' -import Label from './components/label' -import List from './components/list' -import Loading from './components/loading' -import Mask from './components/mask' -import MiniPicker from './components/mini-picker' -import Modal from './components/modal' -import MultiSelect from './components/multi-select' -import MultiSelectItem from './components/multi-select-item' -import NavBar from './components/nav-bar' -import Numeric from './components/numeric' -import PickerColumn from './components/picker-column' -import Popover from './components/popover' -import Progress from './components/progress' -import PullRefresh from './components/pull-refresh' -import Radio from './components/radio' -import RadioGroup from './components/radio-group' -import Search from './components/search' -import Slider from './components/slider' -import Switch from './components/switch' -import Tabbar from './components/tabbar' -import TabbarItem from './components/tabbar-item' -import Table from './components/table' -import Tabs from './components/tabs' -import TabItem from './components/tab-item' -import Tag from './components/tag' -import TimeLine from './components/time-line' -import Toast from './components/toast' -import Tooltip from './components/tooltip' -import UploadList from './components/upload-list' -import UserHead from './components/user-head' -import Wheel from './components/wheel' - -export const version = '3.18.0' - -export { - ActionSheet, - ActionSheet as TinyActionSheet, - Alert, - Alert as TinyAlert, - Avatar, - Avatar as TinyAvatar, - Badge, - Badge as TinyBadge, - Button, - Button as TinyButton, - Checkbox, - Checkbox as TinyCheckbox, - CheckboxGroup, - CheckboxGroup as TinyCheckboxGroup, - Container, - Container as TinyContainer, - DatePicker, - DatePicker as TinyDatePicker, - DialogBox, - DialogBox as TinyDialogBox, - DropdownItem, - DropdownItem as TinyDropdownItem, - DropdownMenu, - DropdownMenu as TinyDropdownMenu, - Exception, - Exception as TinyException, - FileUpload, - FileUpload as TinyFileUpload, - Form, - Form as TinyForm, - FormItem, - FormItem as TinyFormItem, - ImageViewer, - ImageViewer as TinyImageViewer, - IndexBar, - IndexBar as TinyIndexBar, - IndexBarAnchor, - IndexBarAnchor as TinyIndexBarAnchor, - Input, - Input as TinyInput, - Label, - Label as TinyLabel, - List, - List as TinyList, - Loading, - Loading as TinyLoading, - Mask, - Mask as TinyMask, - MiniPicker, - MiniPicker as TinyMiniPicker, - Modal, - Modal as TinyModal, - MultiSelect, - MultiSelect as TinyMultiSelect, - MultiSelectItem, - MultiSelectItem as TinyMultiSelectItem, - NavBar, - NavBar as TinyNavBar, - Numeric, - Numeric as TinyNumeric, - PickerColumn, - PickerColumn as TinyPickerColumn, - Popover, - Popover as TinyPopover, - Progress, - Progress as TinyProgress, - PullRefresh, - PullRefresh as TinyPullRefresh, - Radio, - Radio as TinyRadio, - RadioGroup, - RadioGroup as TinyRadioGroup, - Search, - Search as TinySearch, - Slider, - Slider as TinySlider, - Switch, - Switch as TinySwitch, - Tabbar, - Tabbar as TinyTabbar, - TabbarItem, - TabbarItem as TinyTabbarItem, - Table, - Table as TinyTable, - Tabs, - Tabs as TinyTabs, - TabItem, - TabItem as TinyTabItem, - Tag, - Tag as TinyTag, - TimeLine, - TimeLine as TinyTimeLine, - Toast, - Toast as TinyToast, - Tooltip, - Tooltip as TinyTooltip, - UploadList, - UploadList as TinyUploadList, - UserHead, - UserHead as TinyUserHead, - Wheel, - Wheel as TinyWheel -} diff --git a/packages/mobile/package.json b/packages/mobile/package.json deleted file mode 100644 index e3499eed44..0000000000 --- a/packages/mobile/package.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "@opentiny/vue-mobile", - "type": "module", - "version": "1.0.0-alpha.6", - "description": "An enterprise-class UI component library, support both Vue.js 2 and Vue.js 3, as well as PC and mobile.", - "author": "OpenTiny Team", - "license": "MIT", - "homepage": "https://opentiny.design/tiny-vue", - "repository": { - "type": "git", - "url": "git@github.com:opentiny/tiny-vue.git" - }, - "bugs": { - "url": "https://github.com/opentiny/tiny-vue/issues" - }, - "keywords": [ - "vue3", - "frontend", - "component-library", - "components", - "vue-components", - "opentiny" - ], - "sideEffects": false, - "publishConfig": { - "main": "dist/index.js" - }, - "files": [ - "dist", - "LICENSE" - ], - "main": "index.ts", - "scripts": { - "build": "vite build", - "pub": "pnpm publish --no-git-checks --access=public" - }, - "dependencies": { - "@better-scroll/core": "^2.5.0", - "@better-scroll/wheel": "^2.5.0", - "xss": "1.0.14", - "@opentiny/vue-icon": "workspace:~", - "@opentiny/vue-locale": "workspace:~", - "@opentiny/vue-theme-mobile": "workspace:~" - }, - "devDependencies": { - "@vitejs/plugin-vue": "^5.2.1", - "@vitejs/plugin-vue-jsx": "^4.1.1", - "@rollup/plugin-replace": "^6.0.2", - "typescript": "catalog:", - "vite": "catalog:", - "vite-plugin-dts": "^4.3.0", - "vite-svg-loader": "^5.1.0", - "vue": "^3.5.0" - } -} diff --git a/packages/mobile/shared.type.ts b/packages/mobile/shared.type.ts deleted file mode 100644 index 757ef0f8fc..0000000000 --- a/packages/mobile/shared.type.ts +++ /dev/null @@ -1,186 +0,0 @@ -/** 该文件以Vue3版本的适配器为依据,编写了本声明,本文涉及以下术语: - * instance : 即一个Vue3组件实例, conext, attrs,emit等很多属性 - * vm,parentVm : 适配器封装的一个数据结构,具有大量$属性,以及组件上其它属性 - * emitter : 适配器中,自己封装的一个EventBus对象,和instance.emit没关系。 vm.$emit 会同时触发 instance.emit和instance.$emitter。 - * subTree : instance.subTree 是组件当前的vnode描述 - */ - -// 使用vue3的声明,来代表hooks中所有函数的声明 -import type * as hooks from 'vue' - -/** hooks 变量: renderless的第二个参数 */ -export type ISharedRenderlessParamHooks = typeof hooks - -/** utils变量: renderless的第三个参数 */ -export interface ISharedRenderlessParamUtils { - /** 当前使用的框架 */ - framework: 'vue3' | 'vue2' | 'vue2.7' - /** 组件前缀,默认为 Tiny */ - $prefix: string - - /** 所有规范的配置 */ - globalDesignConfig: { - components?: IComponentDesignConfig - name?: string - version?: string - } - /** 当前组件的规范配置 */ - designConfig: IComponentDesignConfig - - /** app的root上的i18n对象,renderless基本没有使用它 */ - i18n: any - /** 组件内国际化,常用函数 */ - t: (path: string, options?: any) => string - - /** 组件模式。 - * @mark 等同于 vm.$mode, 取值为:pc mobile mobile-first */ - mode: 'pc' | 'mobile' | 'mobile-first' - /** 是否为 mobile */ - isMobileMode: boolean - /** 是否为 pc */ - isPCMode: boolean - /** 是否为mobile-first */ - isMobileFirstMode: boolean - - /** vue组件实例的context.attrs */ - attrs: any - /** 返回组件props._constants */ - constants: CT - /** vue的内置nextTick, 其实可以从第二参 hooks中获取, 还可以通过当前vm.$nextTick来获取 */ - nextTick: typeof hooks.nextTick - /** parentVm */ - parent: ITinyVm - /** 当前vm */ - vm: ITinyVm - /** 第一次mount加载后的所有refs,不会更新! ⭐要避免使用 */ - refs: Record - /** 组件初化时的页面路由,不会更新! - * @mark ⭐要避免使用, 请使用vm.$refs */ - route: any - /** 当前的router实例。 从app的根上读取 */ - router: any - - /** 从app的根上读取: root?.$service, 用户必须引用服务适配器的包, 并传入app后,才有该变量 */ - service: any - /** 调用从app的根上$getService: root?.$getService(vm) */ - getService: any - - /** 返回 instance.slots。 vue2,vue3的这2个属性是同一个引用: scopedSlots===slots。 */ - slots: Record - /** 返回 instance.slots */ - scopedSlots: Record - - /** 向实例的 subTree.children 深度遍历发送广播消息。 如果component找到了触发component.emit(eventName, params) - * @param componentName 组件名 - */ - broadcast: (componentName: string, eventName: string, params?: any) => void - /** 向实例的 parent开始查找componentName, 找到匹配第一个组件, 触发component.emit(eventName, params) */ - dispatch: (componentName: string, eventName: string, params?: any) => void - /** 向实例的subTree 遍历。 - * 1、handler 是函数: handler入参{level,vm,el,options,isLevel1}. 给每个子节点遍历调用函数。 - * 2、handler 是非函数: 直接通过 instance.subTree 来生成一个同等树状的vm数据。 - * @mark ⭐全局有4个组件使用到`handler是函数`的用法 ,用于遍历子节点,将符合条件的信息收集到一个数组中。 - */ - childrenHandler: (handler?: (node: { level: number; vm: ITinyVm; el; options; isLevel1 }) => void) => void | any[] - /** 向实例的 parent 遍历。 - * 1、handler 是函数: handler入参{level,vm,el,options}. 遍历父节点。若handler处理某个节点时,返回true,则停止! - * 2、handler 是非函数: 直接返回{level,vm,el,options} 的数据体。 - * @mark ⭐全局未有使用该函数 - */ - parentHandler: (handler?: () => boolean) => void | any - - /** 给 instance.parent 的ctx 赋值,同时给parentVm 赋值。 适配器的内部方法⭐要避免使用 */ - setParentAttribute: ({ name, value }) => void - /** 给 vm 和 instance.ctx 同时添加属性。 - * @param props Object.defineProperties的第2参, 格式:{ property1: {value: 42,writable: true},property2: {...} } - */ - defineInstanceProperties: (props: PropertyDescriptorMap & ThisType) => void - /** 给parentVm 添加属性。 */ - defineParentInstanceProperties: (props: PropertyDescriptorMap & ThisType) => void - /** 返回 context.emit */ - emit: (event, ...args) => void - /** Tiny 适配器中,自行封装的一个 EventBus模型的工厂函数。⭐每次调用才返回一个新的模型对象。 - * @mark vm中,会给instance添加一个$emitter=emitter() ,就是该函数返回的模型。 vm中的$on, $off,$once 都是该模型的方法。 - * @mark ⭐所以不要直接使用该函数。 - */ - emitter: () => { - emit: (eventname: string) => void - on: (eventname: string, callback: Function, once?: boolean) => void - off: (eventname: string, callback: Function) => void - once: (eventname: string, callback: Function) => void - } - /** 合并 tailwind 类 */ - mergeClass: (...cssClasses) => string -} - -/** vue.ts的一个混合上下文,也是index.ts 文件中二层函数的入参混合体。 */ -export type ISharedRenderlessFunctionParams = { - api: object - props: object - state: object -} & ISharedRenderlessParamHooks & - ISharedRenderlessParamUtils - -/** 单个组件的规范的配置 */ -interface IComponentDesignConfig { - icons?: Record - renderless?: ( - props: any, - hooks: ISharedRenderlessParamHooks, - utils: ISharedRenderlessParamUtils, - sdk: any - ) => any - [otherKey: string]: any -} - -/** Tiny-Vue的Adapter 内部为组件创建的Vm */ -export interface ITinyVm { - /** 从instance.attrs上, 过滤出所有的非函数的attrs */ - $attrs: Record - /** 从instance.attrs上, 过滤出所有的函数的attrs, 并对大驼峰属性名转化为下划线名 */ - $listeners: Record - /** 返回instance.subTree的同等树状的vm数据 */ - $children: any[] - /** 返回 instance.props._constants */ - $constants: CT - /** 返回 instance.vnode.el */ - $el: HTMLElement - /** 返回 instance._tiny_mode */ - $mode: 'pc' | 'mobile' | 'mobile-first' - /** 即 hooks.nextTick */ - $nextTick: typeof hooks.nextTick - /** 自动触发 instance.emit 和 instance.$emitter 两处地方 */ - $emit: (...args) => void - /** instance.$emitter.off, 不传任何参数则是移除所有事件 */ - $off: (eventname?: string, callback?: Function) => void - /** instance.$emitter.on */ - $on: (eventname: string, callback: Function) => void - /** instance.$emitter.once */ - $once: (eventname: string, callback: Function) => void - /** 返回 instance.type.componentName。 - * @mark instance.type 可能是字符串,也可能是组件类,所以只有组件类的时候,才能返回组件的真实名字 */ - $options: { componentName: string | undefined } - /** 返回 instance.parent */ - $parent: hooks.ComponentPublicInstance - /** 返回 instance.refs, - * @mark ⭐ 尽量使用这个,每次都会是最新的refs */ - $refs: Record - /** 返回 instance.slots */ - $slots: Record - /** 返回 instance.slots */ - $scopedSlots: Record - - /** 给target赋值。 vue2是调用instance.$set - * @mark vue3是响应数据,直接转为 target[propertyName] = value。 - * @mark vue2 可能有数据修改不触发响应,就要调用$set去修改值。 - * @whenUse ⭐ Vue2组件中修改数据不触发响应时,要使用该$set. instance.$set - */ - $set: (target, propertyName, value) => void - /** 返回 props.tiny_renderless */ - $renderless: Function - /** 返回 props.tiny_template */ - $template: any - - /** 适配器或组件内,可能会赋值很多其它属性 */ - [otherProps: string]: any -} diff --git a/packages/mobile/tsconfig.json b/packages/mobile/tsconfig.json deleted file mode 100644 index 147f3e9455..0000000000 --- a/packages/mobile/tsconfig.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "skipLibCheck": true, - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "preserve", - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - /* alias */ - "paths": { - "@mobile-root/*": ["./*"] - } - }, - "include": [ - "components/**/*.ts", - "components/**/*.tsx", - "components/**/*.vue", - "index.ts", - "common/*.ts", - "utils/*.ts" - ], - "references": [ - { - "path": "./tsconfig.node.json" - } - ] -} diff --git a/packages/mobile/tsconfig.node.json b/packages/mobile/tsconfig.node.json deleted file mode 100644 index 42872c59f5..0000000000 --- a/packages/mobile/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/packages/mobile/utils/array.ts b/packages/mobile/utils/array.ts deleted file mode 100644 index 8d14eed251..0000000000 --- a/packages/mobile/utils/array.ts +++ /dev/null @@ -1,240 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { SORT } from './index' -import { isSame } from './type' -import { getObj } from './object' - -/** - * 返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。 TINY_NO_NEED 现在数组有 findIndex - * 修复数组原生的 indexOf 方法不能判断 NaN 的问题 - * - * let arr1 = [1, 2, 3, 4] - * let arr2 = [1, 2, NaN, 4] - * indexOf(arr1, 2) // 1 - * indexOf(arr2, NaN) // 2 - * - * @param {Array} arr 要查找的数组 - * @param {Object} data 需要查找的数据 - * @param {Function} [predicate] 断言函数,缺省为 isSame, 两个参数为数组的元素和查找的数据 - * @returns {Number} - */ -export const indexOf = (arr, data, predicate = isSame) => { - if (Array.isArray(arr) && typeof predicate === 'function') { - for (let i = 0, len = arr.length; i < len; i++) { - if (predicate(arr[i], data)) { - return i - } - } - } - - return -1 -} - -/** - * 在数组里查找对象,调用自定义的断言函数。 - * - * let arr = [1, 2, 3, 4] - * find(arr, function (value) { return value > 2 }) // 3 - * - * @param {Array} arr 要查找的数组 - * @param {Function} predicate 断言函数 - * @returns {Object} - */ -export const find = (arr, predicate) => { - const index = indexOf(arr, undefined, predicate) - return index !== -1 ? arr[index] : undefined -} - -/** - * 从数组中删除指定元素,并返回该数组。 - * - * let arr1 = [1, 2, 3, 4] - * let arr2 = [1, 2, NaN, 4] - * remove(arr1, 2, 2) // [1, 4] - * remove(arr2, NaN) // [1, 2, 4] - * - * @param {Array} arr 源数组 - * @param {Object} data 需要删除的数据 - * @param {Number} count 删除元素个数,默认为 1 - * @returns {Array} - */ -export const remove = (arr, data, count = 1) => { - if (Array.isArray(arr) && arr.length) { - const index = indexOf(arr, data) - if (index > -1) { - arr.splice(index, count) - } - } - - return arr -} - -/** - * 对象数组自定义排序,并返回该数组。 - * - * sort([ {a:100}, {a:1}, {a:NaN}, {a:10} ], 'a') // [ {a:1}, {a:10}, {a:100}, {a:NaN} ] - * sort([ {a:100}, {a:1}, {a:NaN}, {a:10} ], 'a','desc') // [ {a:100}, {a:10}, {a:1}, {a:NaN} ] - * - * @param {Array} arr 需要排序的对象数组 - * @param {string} field 要排序的对象字段 - * @param {String} sort 排序方向,取值为 "asc" 或 "desc" - * @returns {Array} 排好序的对象数组 - */ -export const sort = (arr, field, sort = SORT.Asc) => { - if (Array.isArray(arr) && arr.length > 1) { - arr.sort((x, y) => { - const compare = sort === SORT.Asc ? [1, -1] : [-1, 1] - const xField = getObj(x, field) - const yField = getObj(y, field) - - if (isNaN(xField)) { - return sort === SORT.Asc ? 1 : -1 - } else if (isNaN(yField)) { - return -1 - } - - return xField > yField ? compare[0] : compare[1] - }) - } - - return arr -} - -/** - * 向数组中添加不重复的数据,并返回该数组。 - * - * let arr = [ 1, 2, NaN, 4] - * push(arr, 1) // [ 1, 2, NaN, 4] - * push(arr, NaN) // [ 1, 2, NaN, 4] - * push(arr, 5) // [ 1, 2, NaN, 4, 5] - * - * @param {Array} arr 源数组 - * @param {Object} data 需要增加的数据 - * @returns {Array} - */ -export const push = (arr, data) => { - if (Array.isArray(arr) && !arr.some((value) => isSame(value, data))) { - arr.push(data) - } - - return arr -} - -/** - * 去除数组中的重复的值,并返回新数组。 - * - * let arr = [ 1, NaN, 2, NaN, 2, 3, 4] - * unique(arr) // [ 1, NaN, 2, 3, 4] - * - * @param {Array} arr - * @returns {Array} - */ -export const unique = (arr) => { - if (Array.isArray(arr)) { - const array = [] - - for (let i = 0, len = arr.length; i < len; i++) { - const value = arr[i] - if (indexOf(array, value) === -1) { - array.push(value) - } - } - - return array - } - - return arr -} - -const extend = (to, _from) => { - Object.keys(_from).forEach((key) => (to[key] = _from[key])) - - return to -} - -/** - * 数组转对象 - * - * let arr = [ { key1: value1 }, { key2: value2 } ] - * toObject(arr) // { key1: value1, key2: value2 } - * - * @param {Array} arr - * @returns {Object} - */ -export const toObject = (arr) => { - const res = {} - - for (let i = 0; i < arr.length; i++) { - if (arr[i]) { - extend(res, arr[i]) - } - } - - return res -} - -/** - * 将 id 与 pid 构成的扁平数据转换成 children 的树状数据 - * - * let data = [{ id: 100, pId: 0, label: '首页'}, { id: 101, pId: 100, label: '指南'}] - * transformPidToChildren(data) // [ 0: { id: 100, label: "首页", children: [ 0: { id: 101, label: "指南" } ] } ] - * - * @param {Array} data id 与 pid 构成的扁平数据的数组 - * @param {String} [pidName] pid 的属性名,缺省为 pId - * @param {String} [childrenName] children 的属性名,缺省为 children - * @param {String} [idName] id 的属性名,缺省为 id - * @returns {Array} - */ -export const transformPidToChildren = (data, pidName = 'pId', childrenName = 'children', idName = 'id') => { - const result = [] - - Array.isArray(data) && - data.forEach((item) => { - if (item[pidName] == '0') { - result.push(item) - } else { - const parent = find(data, (i) => i[idName] == item[pidName]) - - if (!parent) { - return - } - - if (!parent[childrenName]) { - parent[childrenName] = [] - } - - parent[childrenName].push(item) - } - - delete item[pidName] - }) - - return result -} - -/** - * 将pid标识的普通数组转换树结构数据 - * @param {*} data - * @param {*} key - * @param {*} parentKey - */ -export const transformTreeData = (data, key = 'id', parentKey = 'pId') => { - if (!Array.isArray(data)) { - data = [data] - } - - data = data.map((item) => ({ ...item })) - - const treeData = transformPidToChildren(data, parentKey, 'children', key) - return treeData -} diff --git a/packages/mobile/utils/bigInt.ts b/packages/mobile/utils/bigInt.ts deleted file mode 100644 index 5e4254141f..0000000000 --- a/packages/mobile/utils/bigInt.ts +++ /dev/null @@ -1,419 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { fillChar } from './string' -import { isBrowser } from './browser' - -const BigInt = isBrowser ? window.BigInt : global.BigInt - -export function supportBigInt() { - return typeof BigInt === 'function' -} - -export function trimNumber(numStr) { - let string = numStr.toString().trim() - let negative = string.startsWith('-') - - if (negative) { - string = string.slice(1) - } - - string = string // Remove decimal 0. `1.000` => `1.`, `1.100` => `1.1` - .replace(/(\.\d*[^0])0*$/, '$1') // Remove useless decimal. `1.` => `1` - .replace(/\.0*$/, '') // Remove integer 0. `0001` => `1`, 000.1' => `.1` - .replace(/^0+/, '') - - if (string.startsWith('.')) { - string = '0'.concat(string) - } - - let trimStr = string || '0' - let splitNumber = trimStr.split('.') - let integerStr = splitNumber[0] || '0' - let decimalStr = splitNumber[1] || '0' - - if (integerStr === '0' && decimalStr === '0') { - negative = false - } - - let negativeStr = negative ? '-' : '' - - return { - negative, - negativeStr, - trimStr, - integerStr, - decimalStr, - fullStr: ''.concat(negativeStr).concat(trimStr) - } -} - -export function isE(number) { - let str = String(number) - return !isNaN(Number(str)) && ~str.indexOf('e') -} - -export function validateNumber(num) { - if (typeof num === 'number') { - return !isNaN(num) - } // Empty - - if (!num) { - return false - } - - return ( - // Normal type: 11.28 - /^\s*-?\d+(\.\d+)?\s*$/.test(num) || // Pre-number: 1. - /^\s*-?\d+\.\s*$/.test(num) || // Post-number: .1 - /^\s*-?\.\d+\s*$/.test(num) - ) -} - -/** - * [Legacy] Convert 1e-9 to 0.000000001. - * This may lose some precision if user really want 1e-9. - */ - -export function getNumberPrecision(number) { - let numStr = String(number) - - if (isE(number)) { - let precision = Number(numStr.slice(numStr.indexOf('e-') + 2)) - let decimalMatch = numStr.match(/\.(\d+)/) - - if (decimalMatch === null || decimalMatch === void 0 ? void 0 : decimalMatch[1]) { - precision += decimalMatch[1].length - } - - return precision - } - - return ~numStr.indexOf('.') && validateNumber(numStr) ? numStr.length - numStr.indexOf('.') - 1 : 0 -} - -/** - * Convert number (includes scientific notation) to -xxx.yyy format - */ - -export function num2str(number) { - let numStr = String(number) - - if (isE(number)) { - if (number > Number.MAX_SAFE_INTEGER) { - return String(supportBigInt() ? BigInt(number).toString() : Number.MAX_SAFE_INTEGER) - } - - if (number < Number.MIN_SAFE_INTEGER) { - return String(supportBigInt() ? BigInt(number).toString() : Number.MIN_SAFE_INTEGER) - } - - numStr = number.toFixed(getNumberPrecision(numStr)) - } - - return trimNumber(numStr).fullStr -} - -function pluginDecimal(decimal) { - if (!decimal.add) { - Object.assign(decimal, { - add: decimal.plus, - lessEquals: decimal.isLessThan, - equals: decimal.isEqualTo - }) - } - - return decimal -} - -const DecimalCls = { - CLS: null -} - -let setDecimalClass - -export function getMiniDecimal(value, decimal) { - // We use BigInt here. Will fallback to Number if not support. - if (!DecimalCls.CLS) { - setDecimalClass(decimal) - } - - return pluginDecimal(new DecimalCls.CLS(value)) -} - -export class BigIntDecimal { - constructor(value) { - if ((!value && value !== 0) || !String(value).trim()) { - this.empty = true - return - } - - this.origin = String(value) - this.negative = void 0 - this.integer = void 0 - this.decimal = void 0 - this.decimalLen = void 0 - this.empty = void 0 - this.nan = void 0 - - if (value === '-') { - this.nan = true - - return - } - - let mergedValue = isE(value) ? Number(value) : value - - if (typeof mergedValue !== 'string') { - num2str(mergedValue) - } - const f = Function - const convertBigInt = (str) => { - // 将以多个零开头的整数前置零清空 '0000000000000003e+21' --> '3e+21' ,解决BigInt(0000000000000003e+21)报错问题 - const validStr = str.replace(/^0+/, '') || '0' - return f(`return BigInt('${validStr}')`)() - } - if (validateNumber(mergedValue)) { - const trimRet = trimNumber(mergedValue) - this.negative = trimRet.negative - const numbers = trimRet.trimStr.split('.') - this.integer = !numbers[0].includes('e') ? BigInt(numbers[0]) : numbers[0] - const decimalStr = numbers[1] || '0' - - // 如果小数点后有科学计数法,需要特殊处理,如果是正常数字则保留之前逻辑 - this.decimal = decimalStr.includes('e') ? convertBigInt(decimalStr) : BigInt(decimalStr) - this.decimalLen = decimalStr.length - } else { - this.nan = true - } - } - - getDecimalStr() { - return this.decimal.toString().padStart(this.decimalLen, '0') - } - - getIntegerStr() { - return this.integer.toString() - } - - getMark() { - return this.negative ? '-' : '' - } - - /** - * Align BigIntDecimal with same decimal length. e.g. 12.3 + 5 = 1230000 - * This is used for add function only. - */ - alignDecimal(decimalLength) { - const string = `${this.getMark()}${this.getIntegerStr()}${this.getDecimalStr().padEnd(decimalLength, '0')}` - - return BigInt(string) - } - - add(value) { - if (this.isInvalidate()) { - return new BigIntDecimal(value) - } - - const offsetObj = new BigIntDecimal(value) - if (offsetObj.isInvalidate()) { - return this - } - - const maxDecimalLength = Math.max(this.getDecimalStr().length, offsetObj.getDecimalStr().length) - const offsetAlignedDecimal = offsetObj.alignDecimal(maxDecimalLength) - const myAlignedDecimal = this.alignDecimal(maxDecimalLength) - - const valueStr = `${myAlignedDecimal + offsetAlignedDecimal}` - - const { negativeStr: str, trimStr } = trimNumber(valueStr) - const hydrateValueStr = `${str}${trimStr.padStart(maxDecimalLength + 1, '0')}` - - return getMiniDecimal(`${hydrateValueStr.slice(0, -maxDecimalLength)}.${hydrateValueStr.slice(-maxDecimalLength)}`) - } - - negate() { - const clone = new BigIntDecimal(this.toString()) - clone.negative = !clone.negative - - return clone - } - - isNaN() { - return this.nan - } - - isEmpty() { - return this.empty - } - - isInvalidate() { - return this.isEmpty() || this.isNaN() - } - - lessEquals(target) { - return this.add(target.negate().toString()).toNumber() <= 0 - } - - equals(target) { - return this.toString() === (target && target.toString()) - } - - toNumber() { - if (this.isNaN()) { - return NaN - } - - return Number(this.toString()) - } - - toString(safe = true) { - if (!safe) { - return this.origin - } - - if (this.isInvalidate()) { - return '' - } - - return trimNumber(`${this.getMark()}${this.getIntegerStr()}.${this.getDecimalStr()}`).fullStr - } -} - -export class NumberDecimal { - constructor(value = '') { - if ((!value && value !== 0) || !String(value).trim()) { - this.empty = true - return - } - this.origin = '' - this.number = void 0 - this.empty = void 0 - - this.origin = String(value) - this.number = Number(value) - } - - negate() { - return new NumberDecimal(-this.toNumber()) - } - - add(value) { - if (this.isInvalidate()) { - return new NumberDecimal(value) - } - - const target = Number(value) - - if (isNaN(target)) { - return this - } - - const number = this.number + target - - if (number < Number.MIN_SAFE_INTEGER) { - return new NumberDecimal(Number.MIN_SAFE_INTEGER) - } - - if (number > Number.MAX_SAFE_INTEGER) { - return new NumberDecimal(Number.MAX_SAFE_INTEGER) - } - - const maxPrecision = Math.max(getNumberPrecision(target), getNumberPrecision(this.number)) - return new NumberDecimal(number.toFixed(maxPrecision)) - } - - isNaN() { - return isNaN(this.number) - } - - isEmpty() { - return this.empty - } - - isInvalidate() { - return this.isEmpty() || this.isNaN() - } - - equals(target) { - return this.toNumber() === (target && target.toNumber()) - } - - lessEquals(target) { - return this.add(target.negate().toString()).toNumber() <= 0 - } - - toNumber() { - return this.number - } - - toString(safe = true) { - if (!safe) { - return this.origin - } - - if (this.isInvalidate()) { - return '' - } - - return num2str(this.number) - } -} - -setDecimalClass = function (decimaljs) { - DecimalCls.CLS = supportBigInt() ? BigIntDecimal : typeof decimaljs === 'function' ? decimaljs : NumberDecimal -} - -export { setDecimalClass } - -export function lessEquals(value1, value2) { - return getMiniDecimal(value1).lessEquals(getMiniDecimal(value2)) -} - -export function equalsDecimal(value1, value2) { - return getMiniDecimal(value1).equals(getMiniDecimal(value2)) -} - -export function toFixed(numStr, precision, rounding = 5) { - if (numStr === '') { - return '' - } - const separatorStr = '.' - const { negativeStr, integerStr, decimalStr } = trimNumber(numStr) - const precisionDecimalStr = `${separatorStr}${decimalStr}` - const numberWithoutDecimal = `${negativeStr}${integerStr}` - - if (precision >= 0) { - // We will get last + 1 number to check if need advanced number - const advancedNum = Number(decimalStr[precision]) - - if (advancedNum >= rounding && rounding !== 0) { - const advancedDecimal = getMiniDecimal(`${integerStr}${separatorStr}${decimalStr}`).add( - `0.${fillChar('', precision, true)}${10 - advancedNum}` - ) - - return toFixed(negativeStr + advancedDecimal.toString(), precision, 0) - } - - if (precision === 0) { - return numberWithoutDecimal - } - - return `${numberWithoutDecimal}${separatorStr}${fillChar(decimalStr, precision, true).slice(0, precision)}` - } - - if (precisionDecimalStr === '.0') { - return numberWithoutDecimal - } - - return `${numberWithoutDecimal}${precisionDecimalStr}` -} diff --git a/packages/mobile/utils/browser.ts b/packages/mobile/utils/browser.ts deleted file mode 100644 index 30ad81a76e..0000000000 --- a/packages/mobile/utils/browser.ts +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -const getIEVersion = () => { - let version = 8 - if (!!document.addEventListener && !!window.performance) { - version = 9 - if (!!window.atob && !!window.matchMedia) { - version = 10 - if (!window.attachEvent && !document.all) { - version = 11 - } - } - } - return version -} - -const isEdge = (browser) => { - if (browser.chrome && ~navigator.userAgent.indexOf('Edg')) { - browser.name = 'edge' - browser.edge = true - delete browser.chrome - } else if (!document.documentMode && !!window.StyleMedia) { - browser.name = 'edge' - browser.edge = true - } -} - -export const isBrowser = - typeof window !== 'undefined' && typeof document !== 'undefined' && window.document === document - -export default (() => { - const browser = { - name: undefined, - version: undefined, - isDoc: typeof document !== 'undefined', - isMobile: false, - isPC: true, - isNode: typeof window === 'undefined' - } - - if (isBrowser) { - const isMobile = /(Android|webOS|iPhone|iPad|iPod|SymbianOS|BlackBerry|Windows Phone)/.test(navigator.userAgent) - - browser.isMobile = isMobile - browser.isPC = !isMobile - - let matches - - if (!!window.chrome && (!!window.chrome.webstore || /^Google\b/.test(window.navigator.vendor))) { - browser.name = 'chrome' - browser.chrome = true - matches = navigator.userAgent.match(/chrome\/(\d+)/i) - browser.version = !!matches && !!matches[1] && parseInt(matches[1], 10) - matches = undefined - } else if (!!document.all || !!document.documentMode) { - browser.name = 'ie' - browser.version = getIEVersion() - browser.ie = true - } else if (typeof window.InstallTrigger !== 'undefined') { - browser.name = 'firefox' - browser.firefox = true - } else if (Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0) { - browser.name = 'safari' - browser.safari = true - } else if ((!!window.opr && !!window.opr.addons) || !!window.opera) { - browser.name = 'opera' - browser.opera = true - } - - isEdge(browser) - - if (!~['ie', 'chrome'].indexOf(browser.name)) { - const reg = browser.name + '/(\\d+)' - matches = navigator.userAgent.match(new RegExp(reg, 'i')) - browser.version = !!matches && !!matches[1] && parseInt(matches[1], 10) - matches = undefined - } - - if (browser.isDoc) { - const bodyEl = document.body || document.documentElement - ;['webkit', 'khtml', 'moz', 'ms', 'o'].forEach((core) => { - browser['-' + core] = !!bodyEl[core + 'MatchesSelector'] - }) - } - } - - return browser -})() diff --git a/packages/mobile/utils/calendar/calendar.ts b/packages/mobile/utils/calendar/calendar.ts deleted file mode 100644 index de66fe255b..0000000000 --- a/packages/mobile/utils/calendar/calendar.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { isLeapYear } from '../date' - -/** - * 获取指定年月的总天数 - * @method - * @param {Number} year - 年 - * @param {Number} month - 月 - * @returns {Number} - 总天数 - */ -export const getDays = (year, month) => { - return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1] -} - -/** - * 根据日期获取星期 - * @method - * @param {Number} year - 年 - * @param {Number} month - 月 - * @param {Number} month - 日 - * @returns {Number} - 星期 - */ -export const getWeek = (year, month, day) => new Date(`${year}/${month}/${day}`).getDay() - -/** - * 上月日期 - * @method - * @param {Number} year - 年 - * @param {Number} month - 月 - * @returns {Object} - 年月 - */ -export const lastMonth = (year, month) => { - // 年月转换成整型 - year = +year - month = +month - - if (month === 1) { - year-- - month = 12 - } else { - month-- - } - - return { year, month } -} - -/** - * 下月日期 - * @method - * @param {Number} year - 年 - * @param {Number} month - 月 - * @returns {Object} - 年月 - */ -export const nextMonth = (year, month) => { - // 年月转换成整型 - year = +year - month = +month - - if (month === 12) { - year++ - month = 1 - } else { - month++ - } - - return { year, month } -} - -/** - * 获取日历数据 - * @method - * @param {Number} year - 年 - * @param {Number} month - 月 - * @returns {Object} - 日历 - */ -export const getCalendar = (year, month) => { - if (year && month && month <= 12) { - const days = getDays(year, month) - const firstWeek = getWeek(year, month, 1) - const lastWeek = getWeek(year, month, days) - const last = lastMonth(year, month) - const next = nextMonth(year, month) - const lastDays = getDays(last.year, last.month) - - let remainDays = 0 - const totalDays = days + firstWeek + 7 - lastWeek - 1 - - // 补齐日期不足6行的(日期固定为6行) - if (totalDays / 7 < 6 && totalDays / 7 >= 5) { - remainDays = 6 * 7 - totalDays - } - - return { - last: { - year: last.year, - month: last.month, - start: lastDays - (firstWeek - 1), - end: lastDays - }, - current: { - year, - month, - start: 1, - end: days - }, - next: { - year: next.year, - month: next.month, - start: 1, - end: 7 - lastWeek - 1 + remainDays - } - } - } -} - -/** - * 将一维数组转换成 7*N 的二维数组 - * @method - * @param {Array} array - 一维数据 - * @returns {Array} - 7*N 日历数据 - */ -export const transformArray = (array) => { - const result = [] - let index = 0 - - if (array && array.length) { - const length = array.length / 7 - - for (let i = 0; i < length; i++) { - result[i] = [] - - for (let j = 0; j < 7; j++) { - result[i][j] = array[index++] - } - } - } - - return result -} - -/** - * 时间转换成年月日时分秒 - * @method - * @param {Number | String} time - 时间戳或标准的日期字符 - * @returns {Object} - 年月日时分秒 - */ -export const parseDate = (time) => { - /* istanbul ignore next */ - const date = new Date(time && typeof time === 'number' ? time : 0) - - return { - year: date.getFullYear(), - month: date.getMonth() + 1, - day: date.getDate(), - hours: date.getHours(), - minutes: date.getMinutes(), - seconds: date.getSeconds() - } -} diff --git a/packages/mobile/utils/dataset/index.ts b/packages/mobile/utils/dataset/index.ts deleted file mode 100644 index 921cea96df..0000000000 --- a/packages/mobile/utils/dataset/index.ts +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { format } from '../string' -import { isObject } from '../type' -import { transformTreeData } from '../array' - -/** - * 转换过滤参数 - * @param {*} filters - */ -const getFilterStr = (filters) => { - const filterArr = {} - - Object.keys(filters).forEach((property) => { - const { type, value } = filters[property] - - if (type === 'enum') { - filterArr[property] = { type: value.map(() => 0), value } - - if (value.length > 1) { - filters[property].relation = 'or' - } - } - - if (type === 'input') { - const { relation, text } = value - - filterArr[property] = { - type: [relation === 'startwith' ? 8 : relation === 'equals' ? 0 : 6], - value: text - } - } - }) - - return JSON.stringify(filterArr) -} - -/** - * 根据命名空间取对象的值 - * - * @param {*} obj - * @param {*} names - */ -const getNsObj = (obj, names) => { - const arr = Array.isArray(names) ? names : names.split('.') - const curkey = arr.shift() - const curObj = obj[curkey] - - if (isObject(curObj) && arr.length) { - return getNsObj(curObj, arr) - } - - return curObj -} - -const handlerArgs = (options, args) => { - if (args) { - const { page, sort, filters } = args - const { currentPage, pageSize } = page || {} - const filterStr = getFilterStr(filters || {}) - const orderBy = sort && sort.property ? sort.property + ' ' + sort.order : '' - - options.url = format(options.url, { - curPage: currentPage, - pageSize, - filterStr, - orderBy - }) - } -} - -const transForm = (response, tree) => { - const { result, pageVO } = response - const { key = 'id', parentKey } = tree || {} - let data = result || response - - if (parentKey) { - data = transformTreeData(data, key, parentKey) - } - - return pageVO ? { result: data, page: { total: pageVO.totalRows } } : data -} - -/** - * dataset简单数据处理 - * @param {*} dataset - * @param {*} service - */ -export const getDataset = ({ dataset, service, tree }, args) => - new Promise((resolve, reject) => { - const { source, value, api } = dataset || {} - const $service = service || (dataset && dataset.service) - if (Array.isArray(dataset)) { - return resolve(transForm(dataset, tree)) - } - if (Array.isArray(value)) { - return resolve(transForm(value, tree)) - } - if (!$service) { - return resolve([]) - } - if (isObject(source) && source.url) { - const { type = 'GET', data, beforeRequest, afterRequest, success, hideErr, url, method, ...options } = source - options.url = url - options.method = method || type.toLocaleLowerCase() - const mergeTarget = options.method === 'get' ? 'params' : 'data' - options[mergeTarget] = data || {} - const afterRequestFn = afterRequest || success - const config = { ...options } - handlerArgs(config, args) - beforeRequest && beforeRequest(config, args) - $service.network - .request(config) - .then((response) => { - afterRequestFn && afterRequestFn(response.data) - resolve(transForm(response.data, tree)) - }) - .catch((error) => { - hideErr || reject(error) - }) - } else if (api) { - const fetchFn = getNsObj($service, api.name) - fetchFn && - fetchFn({ ...api.data, ...args }) - .then((response) => { - resolve(transForm(response, tree)) - }) - .catch((error) => { - reject(error) - }) - } - }) diff --git a/packages/mobile/utils/date.ts b/packages/mobile/utils/date.ts deleted file mode 100644 index 5c4a8657b5..0000000000 --- a/packages/mobile/utils/date.ts +++ /dev/null @@ -1,537 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { isDate, isNumber, isNumeric } from './type' -import { fillChar } from './string' - -const daysInMonths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] -const yyyymmddReg = new RegExp( - '^(\\d{4})(/|-)(((0)?[1-9])|(1[0-2]))((/|-)(((0)?[1-9])|([1-2][0-9])|(3[0-1])))' + - '?( ((0)?[0-9]|1[0-9]|20|21|22|23):([0-5]?[0-9])((:([0-5]?[0-9]))?(.([0-9]{1,6}))?)?)?$' -) -const mmddyyyyReg = new RegExp( - '^(((0)?[1-9])|(1[0-2]))(/|-)(((0)?[1-9])|([1-2][0-9])|(3[0-1]))?(/|-)?(\\d{4})' + - '( ((0)?[0-9]|1[0-9]|20|21|22|23):([0-5]?[0-9])((:([0-5]?[0-9]))?(.([0-9]{1,6}))?)?)?$' -) -const iso8601Reg = new RegExp( - '^(\\d{4})-(((0)?[1-9])|(1[0-2]))-(((0)?[1-9])|([1-2][0-9])|(3[0-1]))T' + - '(((0)?[0-9]|1[0-9]|20|21|22|23):([0-5]?[0-9])((:([0-5]?[0-9]))?(.([0-9]{1,6}))?)?)?(Z|([+-])' + - '((0)?[0-9]|1[0-9]|20|21|22|23):?([0-5]?[0-9]))$' -) - -const dateFormatRegs = { - 'y{1,4}': /y{1,4}/, - 'M{1,2}': /M{1,2}/, - 'd{1,2}': /d{1,2}/, - 'h{1,2}': /h{1,2}/, - 'H{1,2}': /H{1,2}/, - 'm{1,2}': /m{1,2}/, - 's{1,2}': /s{1,2}/, - 'S{1,3}': /S{1,3}/, - 'Z{1,1}': /Z{1,1}/ -} - -const maxDateValues = { - YEAR: 9999, - MONTH: 11, - DATE: 31, - HOUR: 23, - MINUTE: 59, - SECOND: 59, - MILLISECOND: 999 -} - -const timezone1 = '-12:00,-11:00,-10:00,-09:30,-08:00,-07:00,-06:00,-05:00,-04:30,-04:00,-03:30,-02:00,-01:00' -const timezone2 = '-00:00,+00:00,+01:00,+02:00,+03:00,+03:30,+04:00,+04:30,+05:00,+05:30,+05:45,+06:00' -const timezone3 = '+06:30,+07:00,+08:00,+09:00,+10:00,+10:30,+11:00,+11:30,+12:00,+12:45,+13:00,+14:00' -const timezones = [].concat(timezone1.split(','), timezone2.split(','), timezone3.split(',')) - -const getTimezone = (date) => { - const timezoneoffset = 0 - date.getTimezoneOffset() / 60 - let timezone - - if (timezoneoffset === 0) { - timezone = 'Z' - } else if (timezoneoffset > 0) { - timezone = '+' + (timezoneoffset > 10 ? timezoneoffset : '0' + timezoneoffset) + '00' - } else { - timezone = (timezoneoffset < -10 ? timezoneoffset : '-0' + -timezoneoffset) + '00' - } - - return timezone -} - -/** - * 判断年份是否为闰年。 - * - * isLeapYear(2017) // false - * isLeapYear(2000) // true - * - * @param {Number} year 年份 - * @returns {Boolean} - */ -export const isLeapYear = (year) => year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0) - -const getMilliseconds = (milliseconds) => - milliseconds > maxDateValues.MILLISECOND ? Number(String(milliseconds).substring(0, 3)) : milliseconds - -const getDateFromData = ({ year, month, date, hours, minutes, seconds, milliseconds }) => { - let daysInMonth = daysInMonths[month] - - if (isLeapYear(year) && month === 1) { - daysInMonth += 1 - } - - if (date <= daysInMonth) { - return new Date(year, month, date, hours, minutes, seconds, getMilliseconds(milliseconds)) - } -} - -const yyyymmddDateParser = (m) => { - /* istanbul ignore else */ - if (m.length === 23) { - const year = Number(m[1]) - const month = m[3] - 1 - const date = Number(m[9] || 1) - const hours = m[15] || 0 - const minutes = m[17] || 0 - const seconds = m[20] || 0 - const milliseconds = m[22] || 0 - - return getDateFromData({ - date, - year, - hours, - month, - seconds, - minutes, - milliseconds - }) - } -} - -const mmddyyyyDateParser = (m) => { - /* istanbul ignore else */ - if (m.length === 22) { - const year = Number(m[12]) - const month = m[1] - 1 - const date = Number(m[6] || 1) - const hours = m[14] || 0 - const minutes = m[16] || 0 - const seconds = m[19] || 0 - const milliseconds = m[21] || 0 - - return getDateFromData({ - year, - month, - date, - hours, - minutes, - seconds, - milliseconds - }) - } -} - -const iso8601DateParser = (m) => { - if (m.length !== 25) { - return - } - const year = Number(m[1]) - const month = m[2] - 1 - const date = Number(m[6]) - const offset = new Date(year, month, date).getTimezoneOffset() - const hours = m[12] || 0 - const minutes = m[14] || 0 - const seconds = m[17] || 0 - const milliseconds = m[19] || 0 - let timeZone = m[20] - const sign = m[21] - const offsetHours = m[22] || 0 - const offsetMinutes = m[24] || 0 - let daysInMonth = daysInMonths[month] - let actHours - let actMinutes - if (isLeapYear(year) && month === 1) { - daysInMonth += 1 - } - if (date <= daysInMonth) { - if (timeZone === 'Z') { - actHours = hours - offset / 60 - actMinutes = minutes - } else { - if (!timeZone.includes(':')) { - timeZone = timeZone.substr(0, 3) + ':' + timeZone.substr(3) - } - if (!timezones.includes(timeZone)) { - return - } - - actHours = sign === '+' ? hours - offsetHours - offset / 60 : Number(hours) + Number(offsetHours) - offset / 60 - actMinutes = sign === '+' ? minutes - offsetMinutes : Number(minutes) + Number(offsetMinutes) - } - - return new Date(year, month, date, actHours, actMinutes, seconds, getMilliseconds(milliseconds)) - } -} - -const dateParsers = [ - [yyyymmddReg, yyyymmddDateParser], - [mmddyyyyReg, mmddyyyyDateParser], - [iso8601Reg, iso8601DateParser] -] - -const parseDate = (str) => { - for (let i = 0, len = dateParsers.length; i < len; i++) { - const m = dateParsers[i][0].exec(str) - - if (m && m.length > 0) { - return dateParsers[i][1](m) - } - } -} - -const matchDateArray = (arr, value, text) => { - if (text) { - switch (text) { - case 'yyyy': - case 'yy': - arr[0] = value - break - case 'M': - case 'MM': - arr[1] = value - 1 - break - case 'd': - case 'dd': - arr[2] = value - break - case 'h': - case 'hh': - arr[3] = value - break - case 'm': - case 'mm': - arr[4] = value - break - case 's': - case 'ss': - arr[5] = value - break - case 'S': - case 'SS': - case 'SSS': - arr[6] = value - break - default: - break - } - } -} - -const getDateArray = (str, dateFormat) => { - const arr = [0, -1, 0, 0, 0, 0] - - if (str.length !== dateFormat.length) { - return arr - } - - let valuePos = 0 - let textPos = 0 - - for (let i = 0, len = str.length; i < len; i++) { - const charValue = str.substr(i, 1) - const notNum = isNaN(Number(charValue)) || charValue.trim() === '' - - if ((notNum && charValue === dateFormat.substr(i, 1)) || i === len - 1) { - let value - let text - - if (notNum) { - value = str.substring(valuePos, i) - valuePos = i + 1 - const end = dateFormat.indexOf(charValue, textPos) - - text = dateFormat.substring(textPos, end === -1 ? dateFormat.length : end) - - textPos = end + 1 - } else { - value = str.substring(valuePos, len) - text = dateFormat.substring(textPos, len) - } - - if (value.length === text.length || value) { - matchDateArray(arr, value, text) - } - } - } - - return arr -} - -const invalideTime = (time, min, max) => isNaN(time) || time < min || time > max - -const invalideValue = ({ year, month, date, hours, minutes, seconds, milliseconds }) => - invalideTime(year, 0, maxDateValues.YEAR) || - invalideTime(month, 0, maxDateValues.MONTH) || - invalideTime(date, 0, maxDateValues.DATE) || - invalideTime(hours, 0, maxDateValues.HOUR) || - invalideTime(minutes, 0, maxDateValues.MINUTE) || - invalideTime(seconds, 0, maxDateValues.SECOND) || - invalideTime(milliseconds, 0, maxDateValues.MILLISECOND) - -const innerParse = (value, dateFormat) => { - if (typeof dateFormat === 'string') { - const arr = getDateArray(value, dateFormat) - const year = Number(arr[0]) - const month = Number(arr[1]) - const date = Number(arr[2] || 1) - const hours = Number(arr[3] || 0) - const minutes = Number(arr[4] || 0) - const seconds = Number(arr[5] || 0) - const milliseconds = Number(arr[6] || 0) - - if ( - invalideValue({ - year, - month, - date, - hours, - minutes, - seconds, - milliseconds - }) - ) { - return - } - - return getDateFromData({ - year, - date, - month, - minutes, - hours, - milliseconds, - seconds - }) - } else { - return parseDate(value) - } -} - -/** - * 将字符串或数字转换成 Date 类型。 - * - * toDate('2008/02/02') // new Date(2008, 1, 2) - * toDate(Date.UTC(2008, 1, 2)) // new Date(Date.UTC(2008, 1, 2)) - * toDate('2008/2/2', 'yyyy/M/d') // new Date(2008, 1, 2) - * toDate('2008/02') // new Date(2008, 1, 1) - * toDate('02/2008') // new Date(2008, 1, 1) - * toDate('2008-02-01T20:08+08:00') // new Date(Date.UTC(2008, 0, 31, 16)) - * toDate('2008-02-01T04:08-08:00') // new Date(Date.UTC(2008, 1, 1, 8)) - * - * @param {String|Number} value 日期类型字符串或数字 - * @param {String} [dateFormat] 转换格式 - * - * 当 value 为字符串类型时,如果不提供,则尽可能按常见格式去解析。 - * 常见格式为 yyyy[/-]MM[/-]dd hh:mm:ss.SSS, MM[/-]dd [/-]yyyy hh:mm:ss.SSS 及 ISO8601 时间格式。 - * - * 如果提供,则按具体格式严格匹配解析,并且年份必须为4位。 - * - yyyy 代表年份 - * - M 或 MM 代表1位或2位的月份 - * - d 或 dd 代表1位或2位的天数 - * - h 或 hh 代表24小时的1位或2位的小时 - * - m 或 mm 代表1位或2位的分钟, - * - s 或 ss 代表1位或2位的秒 - * - S 或 SS 或 SSS 代表1位或2位或3位的毫秒 - * - * @param {String} [minDate] 最小时间,默认为 0001-01-01 00:00:00.000 - * @returns {Date} - */ -export const toDate = (value, dateFormat, minDate) => { - let date - - if (isNumber(value)) { - date = new Date(value) - } else if (typeof value === 'string') { - date = innerParse(value, dateFormat) - } - - if (minDate) { - const min = (minDate && toDate(minDate)) || new Date(1, 1, 1, 0, 0, 0) - return date && date < min ? min : date - } - - return date -} - -/** - * 将 Date 实例转换成日期字符串。 - * 当 date 为日期字符串时,如果只有2个参数,则第2个参数为格式化后的格式化字符串 - * 如果有3个参数,则第2个参数为转换的格式化参数,第3个参数为格式化后的格式化参数 - * - * let date = new Date(2014, 4, 4, 1, 2, 3, 4) - * format(date) // "2014/05/04 01:02:03" - * format(date, 'yyyy/MM/dd hh:mm:ss.SSS') // "2014/05/04 01:02:03.004" - * format(date, 'yyyy/MM/dd hh:mm:ss.SSSZ') // "2014/05/04 01:02:03.004+0800" - * format(date, 'yyyy年MM月dd日 hh时mm分ss秒SSS毫秒') // "2014年05月04日 01时02分03秒004毫秒" - * format('2008/01/02', 'yyyy/MM/dd hh:mm:ss.SSS') // "2008/02/02 00:00:00.000" - * format('2014/01/02/03/04/05/06', 'yyyy/MM/dd/hh/mm/ss', 'yyyy年MM月dd日 hh时mm分ss秒') // "2014年01月02日 03时04分05秒006毫秒" - * - * @param {Date|String} date Date 实例或日期字符串 - * @param {String} [dateFormat='yyyy/MM/dd hh:mm:ss'] 转换格式 - * - * 常见格式为 yyyy[/-]MM[/-]dd hh:mm:ss.SSS, MM[/-]dd [/-]yyyy hh:mm:ss.SSS 及 ISO8601 时间格式。 - * - * 如果提供,则按具体格式严格匹配解析,并且年份必须为4位。 - * - yyyy 代表年份 - * - M 或 MM 代表1位或2位的月份 - * - d 或 dd 代表1位或2位的天数 - * - h 或 hh 代表24小时的1位或2位的小时 - * - m 或 mm 代表1位或2位的分钟, - * - s 或 ss 代表1位或2位的秒 - * - S 或 SS 或 SSS 代表1位或2位或3位的毫秒 - * - * @returns {String} - */ -export const format = function (date, dateFormat = 'yyyy/MM/dd hh:mm:ss') { - if (isDate(date)) { - if (typeof dateFormat === 'string') { - const o = { - 'y{1,4}': date.getFullYear(), - 'M{1,2}': date.getMonth() + 1, - 'd{1,2}': date.getDate(), - 'h{1,2}': date.getHours(), - 'H{1,2}': date.getHours(), - 'm{1,2}': date.getMinutes(), - 's{1,2}': date.getSeconds(), - 'S{1,3}': date.getMilliseconds(), - 'Z{1,1}': getTimezone(date) - } - - Object.keys(o).forEach((k) => { - const m = dateFormat.match(dateFormatRegs[k]) - - if (k && m && m.length) { - dateFormat = dateFormat.replace(m[0], k === 'Z{1,1}' ? o[k] : fillChar(o[k].toString(), m[0].length)) - } - }) - - return dateFormat - } - } else if (typeof date === 'string' && arguments.length >= 2) { - let afterFormat = dateFormat - - if (arguments.length === 2) { - dateFormat = undefined - } else { - afterFormat = arguments[2] - } - - const dateValue = toDate(date, dateFormat) - return dateValue ? format(dateValue, afterFormat) : '' - } -} - -/** - * 将当前操作的时间变更时区,主要用于转换一个其他时区的时间。 - * - * var date = new Date(2017, 0, 1) - * getDateWithNewTimezone(date, 0, -2) - * - * @param {Date} date Date 实例或日期字符串 - * @param {Number} otz 原时区 -12~13 - * @param {Number} ntz 目标时区 -12~13 默认为当前时区 - * @param {Boolean} TimezoneOffset 时区偏移量 - * @returns {Date} - */ -export const getDateWithNewTimezone = (date, otz, ntz, timezoneOffset = 0) => { - if (!isDate(date) || !isNumeric(otz) || !isNumeric(ntz) || !isNumeric(timezoneOffset)) { - return - } - - const otzOffset = -otz * 60 - const ntzOffset = -ntz * 60 - const dstOffeset = timezoneOffset * 60 - const utc = date.getTime() + otzOffset * 60000 - - return new Date(utc - (ntzOffset - dstOffeset) * 60000) -} - -/** - * 按时区将 Date 实例转换成字符串。 - * - * toDateStr(new Date(2017, 0, 1, 12, 30), 'yyyy/MM/dd hh:mm', 3) // "2017/01/01 15:30" - * toDateStr('2008/01/02', 'yyyy/MM/dd hh:mm', 3) // "2008/01/02 03:00" - * - * @param {Date|String} date Date 实例或日期字符串 - * @param {String} dateFormat 转换格式 - * @param {Number} [timezone] 时区 - * @returns {String} - */ -export const toDateStr = (date, dateFormat, timezone) => { - if (date && isNumeric(timezone)) { - timezone = parseFloat(parseFloat(timezone).toFixed(2)) - - date = getDateWithNewTimezone(isDate(date) ? date : new Date(toDate(date)), 0, timezone) - } - - return format(date, dateFormat) -} - -/** - * 获取日期所在周的第一天,默认周一为第一天(可扩展周日为第一天)。 - * - * getWeekOfFirstDay() // 返回当前日期所在周的周一同一时间 - * getWeekOfFirstDay(true) // 返回当前日期所在周的周日同一时间 - * getWeekOfFirstDay(new Date(2019, 8, 5)) // new Date(2019, 8, 2) - * getWeekOfFirstDay(new Date(2019, 8, 5)), true) // new Date(2019, 8, 1) - * - * @param {Date} [date=new Date()] date 日期实例,默认当天 - * @param {Boolean} [isSunFirst] 是否设置周日为第一天,非必填 - * @returns {Date} - */ -export const getWeekOfFirstDay = (date, isSunFirst) => { - typeof date === 'boolean' && (isSunFirst = date) - isDate(date) || (date = new Date()) - - const day = date.getDay() - let dayOfMonth = date.getDate() - - if (day === 0) { - !isSunFirst && (dayOfMonth -= 6) - } else { - dayOfMonth = dayOfMonth - day + (!isSunFirst && 1) - } - - return new Date(date.getFullYear(), date.getMonth(), dayOfMonth) -} - -const TZRE = /(-|\+)(\d{2}):?(\d{2})$/ - -export const getLocalTimezone = () => 0 - new Date().getTimezoneOffset() / 60 - -export const getStrTimezone = (value) => { - const localTimeZone = getLocalTimezone() - const match = typeof value === 'string' && value.match(TZRE) - - if (match) { - const minoffset = Number(match[2]) + Number(match[3]) / 60 - value = minoffset * `${match[1]}1` - } - - if (isNumber(value) && value >= -12 && value <= 12) { - return value - } - - return localTimeZone -} diff --git a/packages/mobile/utils/decimal.ts b/packages/mobile/utils/decimal.ts deleted file mode 100644 index 5c794ff502..0000000000 --- a/packages/mobile/utils/decimal.ts +++ /dev/null @@ -1,261 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { getMiniDecimal, toFixed as roundFixed } from './bigInt' - -export { roundFixed } - -const DECIMAL_SEPARATOR = '.' - -const asInteger = (number) => { - const tokens = number.split(DECIMAL_SEPARATOR) - const integer = tokens[0] - const fractional = tokens[1] - let value - let exp - - if (fractional) { - value = parseInt(number.split(DECIMAL_SEPARATOR).join(''), 10) - exp = fractional.length * -1 - } else { - const trailingZeros = integer.match(/0+$/) - if (trailingZeros) { - const length = trailingZeros[0].length - value = integer.substr(0, integer.length - length) - exp = length - } else { - value = integer - exp = 0 - } - } - - return { value, exp } -} - -const zero = (exp) => { - let result - - if (exp <= 0) { - result = '' - } else if (String.prototype.repeat) { - result = '0'.repeat(exp) - } else { - result = ((times) => { - const zeros = [] - - for (let i = 0; i < times; i++) { - zeros.push(0) - } - return zeros.join('') - })(exp) - } - - return result -} - -const negExp = (str, position) => { - position = Math.abs(position) - - const offset = position - str.length - let sep = DECIMAL_SEPARATOR - - if (offset >= 0) { - str = zero(offset) + str - sep = '0.' - } - - const length = str.length - const dif = length - position - const head = str.substr(0, dif) - const tail = str.substring(dif, length) - - return head + sep + tail -} - -const posExp = (str, exp) => String(str + zero(exp)) - -const format = (num, exp) => (exp >= 0 ? posExp : negExp)(String(num), exp) - -/** - * Decimal 类,解决 JS 的计算精度问题。 - * - * // 加法运算 1.1 + 2.2 = 3.3000000000000003 - * Decimal.add(1.1, 2.2).toNumber() // 3.3 - * new Decimal('1.1').add('2.2').toString() // "3.3" - * - * // 减法运算 0.3 - 0.1 = 0.19999999999999998 - * Decimal.sub(0.3, 0.1).toNumber() // 0.2 - * new Decimal('0.3').sub('0.1').toString() // "0.2" - * - * // 乘法运算 4.01 * 2.01 = 8.060099999999998 - * Decimal.mul(4.01, 2.01).toNumber() // 8.0601 - * new Decimal('4.01').mul('2.01').toString() // "8.0601" - * - * // 除法运算 0.3 / 0.1 = 2.9999999999999996 - * Decimal.div(0.3, 0.1).toNumber() // 3 - * new Decimal('0.3').div('0.1').toString() // "3" - * - * @param {Number|String|} num 数字或字符串代表的数字 - * @returns {Number} - */ -export function Decimal(num) { - if (!this || this.constructor !== Decimal) { - return new Decimal(num) - } - - if (num instanceof Decimal) { - return num - } - - this.internal = String(num) - this.asInt = asInteger(this.internal) - this.add = (target) => { - const operands = [this, new Decimal(target)] - operands.sort((x, y) => x.asInt.exp - y.asInt.exp) - const smallest = operands[0].asInt.exp - const biggest = operands[1].asInt.exp - const x = Number(format(operands[1].asInt.value, biggest - smallest)) - const y = Number(operands[0].asInt.value) - - return new Decimal(format(String(x + y), smallest)) - } - - this.sub = (target) => new Decimal(this.add(target * -1)) - this.mul = (target) => { - target = new Decimal(target) - const result = String(this.asInt.value * target.asInt.value) - const exp = this.asInt.exp + target.asInt.exp - - return new Decimal(format(result, exp)) - } - - this.div = (target) => { - target = new Decimal(target) - - const smallest = Math.min(this.asInt.exp, target.asInt.exp) - const absSmallest = 10 ** Math.abs(smallest) - const x = Decimal.mul(absSmallest, this) - const y = Decimal.mul(absSmallest, target) - - return new Decimal(x / y) - } - - this.toString = () => this.internal - this.toNumber = () => Number(this.internal) -} - -Decimal.add = (a, b) => new Decimal(a).add(b) -Decimal.mul = (a, b) => new Decimal(a).mul(b) -Decimal.sub = (a, b) => new Decimal(a).sub(b) -Decimal.div = (a, b) => new Decimal(a).div(b) - -/** - * 使用定点表示法表示给定数字的字符串,解决 JS 的计算精度问题。 - * - * toFixed(1.1 + 2.2, 2) // "3.30" - * toFixed(0.3 - 0.1, 2) // "0.20" - * toFixed(4.01 * 2.01, 4) // "8.0601" - * toFixed(0.3 / 0.1, 2) // "3.00" - * toFixed(0.0001, 2) // "0.00" - * toFixed(0.0001, 3) // "0.000" - * toFixed(0.0001, 4) // "0.0001" - * toFixed(0.0001, 5) // "0.00010" - * toFixed(-0.0001, 2) // "0.00" - * toFixed(-0.0001, 3) // "0.000" - * toFixed(-0.0001, 4) // "-0.0001" - * toFixed(-0.0001, 5) // "-0.00010" - * - * @param {Number} num 需精确计算的数字 - * @param {Number} [fraction=0] 浮点数的小数部分,默认0位 - * @returns {String} - */ -export const toFixed = (num, fraction = 0) => { - const sign = num < 0 ? '-' : '' - - num = Math.abs(num) - - const npmPow = num.toString().length < (2 ** 53).toString().length - 1 ? 10 ** fraction : 10 ** (fraction - 1) - const result = new Decimal(Math.round(new Decimal(num).mul(npmPow))).div(npmPow).toString() - - const numResult = Number(result) - - return numResult ? sign + numResult.toFixed(fraction) : numResult.toFixed(fraction) -} - -const formatInteger = (value, { secondaryGroupSize = 3, groupSize = 0, groupSeparator = ',' }) => { - const negative = /^-\d+/.test(value) - let result = negative ? value.slice(1) : value - const secSize = secondaryGroupSize || groupSize - - if (groupSize && result.length > groupSize) { - let left = result.slice(0, 0 - groupSize) - const right = result.slice(0 - groupSize) - - left = left.replace(new RegExp(`\\B(?=(\\d{${secSize}})+(?!\\d))`, 'g'), groupSeparator) - result = `${left}${groupSeparator}${right}` - } - - return `${negative ? '-' : ''}${result}` -} - -const reverseString = (str) => { - const arr = [] - - for (let i = 0; i < str.length; i++) { - arr.push(str[i]) - } - - return arr.reverse().join('') -} - -const formatDecimal = (num, { fractionGroupSize = 0, fractionGroupSeparator = '\xA0' }) => { - const RE = new RegExp(`\\B(?=(\\d{${fractionGroupSize}})+(?!\\d))`, 'g') - - return reverseString(reverseString(num).replace(RE, fractionGroupSeparator)) -} - -export const formatNumber = (value, format = {}) => { - const { fraction, rounding, prefix = '', decimalSeparator = '.', suffix = '' } = format - let reslut = getMiniDecimal(value) - - if (reslut.isNaN() || !reslut.toString()) { - return value - } - - reslut = roundFixed(reslut.toString(), fraction, rounding) - - format.zeroize === false && reslut.match(/\./) && (reslut = reslut.replace(/\.?0+$/g, '')) - - const number = reslut - .toString() - .split('.') - .slice(0, 2) - .map((str, index) => (index ? formatDecimal(str, format) : formatInteger(str, format))) - .join(decimalSeparator) - - return `${prefix}${number}${suffix}` -} - -export const recoverNumber = (number, format = {}) => { - const { prefix = '', suffix = '', decimalSeparator = '.' } = format - let result = number - - if (typeof number === 'string') { - result = number - .replace(new RegExp(`^${prefix}(.+)${suffix}$`), ($1, $2) => $2) - .split(decimalSeparator) - .map((s) => s.replace(/[^\d]/g, '')) - .join('.') - } - - return Number(result) -} diff --git a/packages/mobile/utils/deps/ResizeObserver.ts b/packages/mobile/utils/deps/ResizeObserver.ts deleted file mode 100644 index 717047044d..0000000000 --- a/packages/mobile/utils/deps/ResizeObserver.ts +++ /dev/null @@ -1,607 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { on, off } from './dom' -import { isBrowser } from '../browser' - -const MapShim = (function () { - if (typeof Map !== 'undefined') { - return Map - } - - const getIndex = (arr, key) => { - let result = -1 - - arr.some((entry, index) => { - if (entry[0] === key) { - result = index - return true - } - - return false - }) - - return result - } - - return (function () { - function obClass() { - this.__entries__ = [] - } - - Object.defineProperty(obClass.prototype, 'size', { - get() { - return this.__entries__.length - }, - enumerable: true, - configurable: true - }) - - obClass.prototype.get = function (key) { - const index = getIndex(this.__entries__, key) - const entry = this.__entries__[index] - - return entry && entry[1] - } - - obClass.prototype.set = function (key, value) { - const index = getIndex(this.__entries__, key) - - if (~index) { - this.__entries__[index][1] = value - } else { - this.__entries__.push([key, value]) - } - } - - obClass.prototype.delete = function (key) { - const entries = this.__entries__ - const index = getIndex(entries, key) - - if (~index) { - entries.splice(index, 1) - } - } - - obClass.prototype.clear = function () { - this.__entries__.splice(0) - } - - obClass.prototype.has = function (key) { - return !!~getIndex(this.__entries__, key) - } - - obClass.prototype.forEach = function (callback, ctx) { - if (ctx === void 0) { - ctx = null - } - - for (let _i = 0, _a = this.__entries__; _i < _a.length; _i++) { - const entry = _a[_i] - - callback.call(ctx, entry[1], entry[0]) - } - } - - return obClass - })() -})() - -const func = isBrowser ? window.Function : global.Function - -const global$1 = (function () { - const isMath = (val) => val.Math === Math - - if (typeof global !== 'undefined' && isMath(global)) { - return global - } - - if (typeof self !== 'undefined' && isMath(self)) { - return self - } - - if (typeof window !== 'undefined' && isMath(window)) { - return window - } - return func('return this')() -})() - -const requestAnimationFrame$1 = (function () { - if (typeof requestAnimationFrame === 'function') { - return requestAnimationFrame.bind(global$1) - } - - return function (callback) { - return setTimeout(() => callback(Date.now()), 1000 / 60) - } -})() - -let trailingTimeout = 2 - -function throttle(callback, delayTime) { - let leading = false - let trailing = false - let lastCallTime = 0 - let proxy - - const resolvePending = () => { - if (leading) { - leading = false - callback() - } - - trailing && proxy() - } - - const timeoutCallback = () => { - requestAnimationFrame$1(resolvePending) - } - - proxy = () => { - const timeStamps = Date.now() - - if (leading) { - if (timeStamps - lastCallTime < trailingTimeout) { - return - } - - trailing = true - } else { - leading = true - trailing = false - - setTimeout(timeoutCallback, delayTime) - } - - lastCallTime = timeStamps - } - - return proxy -} - -const REFRESH_DELAY = 20 -const transitionKeys = ['top', 'right', 'bottom', 'left', 'width', 'height', 'size', 'weight'] -const mutationObserverSupported = typeof MutationObserver !== 'undefined' -const ResizeObserverController = (function () { - function ResizeObserverController() { - this.observers_ = [] - this.connected_ = false - this.mutationEventsAdded_ = false - this.mutationsObserver_ = null - this.onTransitionEnd_ = this.onTransitionEnd_.bind(this) - this.refresh = throttle(this.refresh.bind(this), REFRESH_DELAY) - } - - ResizeObserverController.prototype.addObserver = function (observer) { - !~this.observers_.indexOf(observer) && this.observers_.push(observer) - !this.connected_ && this.connect_() - } - - ResizeObserverController.prototype.removeObserver = function (observer) { - const observers = this.observers_ - const index = observers.indexOf(observer) - - ~index && observers.splice(index, 1) - - if (!observers.length && this.connected_) { - this.disconnect_() - } - } - - ResizeObserverController.prototype.refresh = function () { - const changesDetected = this.updateObservers_() - - changesDetected && this.refresh() - } - - ResizeObserverController.prototype.updateObservers_ = function () { - const activeObservers = this.observers_.filter((observer) => { - observer.gatherActive() - return observer.hasActive() - }) - - activeObservers.forEach((observer) => observer.broadcastActive()) - - return activeObservers.length > 0 - } - - ResizeObserverController.prototype.connect_ = function () { - if (!isBrowser || this.connected_) { - return - } - - on(document, 'transitionend', this.onTransitionEnd_) - on(window, 'resize', this.refresh) - - if (mutationObserverSupported) { - this.mutationsObserver_ = new MutationObserver(this.refresh) - - const options = { - attributes: true, - childList: true, - characterData: true, - subtree: true - } - - this.mutationsObserver_.observe(document, options) - } else { - on(document, 'DOMSubtreeModified', this.refresh) - this.mutationEventsAdded_ = true - } - - this.connected_ = true - } - - ResizeObserverController.prototype.disconnect_ = function () { - if (!isBrowser || !this.connected_) { - return - } - - off(document, 'transitionend', this.onTransitionEnd_) - off(window, 'resize', this.refresh) - - this.mutationsObserver_ && this.mutationsObserver_.disconnect() - - if (this.mutationEventsAdded_) { - off(document, 'DOMSubtreeModified', this.refresh) - } - - this.mutationsObserver_ = null - this.mutationEventsAdded_ = false - this.connected_ = false - } - - ResizeObserverController.prototype.onTransitionEnd_ = function (_a) { - const _b = _a.propertyName - const propertyName = _b === void 0 ? '' : _b - const isReflowProperty = transitionKeys.some((key) => !!~propertyName.indexOf(key)) - - isReflowProperty && this.refresh() - } - - ResizeObserverController.getInstance = function () { - if (!this._instance) { - this._instance = new ResizeObserverController() - } - - return this._instance - } - - ResizeObserverController._instance = null - return ResizeObserverController -})() - -const defineConfigurable = function (target, props) { - for (let i = 0, a = Object.keys(props); i < a.length; i++) { - const key = a[i] - - Object.defineProperty(target, key, { - value: props[key], - configurable: true, - writable: false, - enumerable: false - }) - } - - return target -} - -const createRectInit = function (x, y, width, height) { - return { x, y, width, height } -} - -const getWindowOf = function (target) { - const ownerGlobal = target && target.ownerDocument && target.ownerDocument.defaultView - return ownerGlobal || global$1 -} - -const emptyRect = createRectInit(0, 0, 0, 0) -const toFloat = (value) => parseFloat(value) || 0 - -const getBordersSize = function (styles) { - let positions = [] - - for (let i = 1; i < arguments.length; i++) { - positions[i - 1] = arguments[i] - } - - return positions.reduce((size, position) => { - const value = styles[`border-${position}-width`] - - return size + toFloat(value) - }, 0) -} - -const getPaddings = function (styles) { - const positions = ['top', 'right', 'bottom', 'left'] - let paddings = {} - - for (let i = 0, pos = positions; i < pos.length; i++) { - const position = pos[i] - const value = styles[`padding-${position}`] - - paddings[position] = toFloat(value) - } - - return paddings -} - -const getSVGContentRect = function (target) { - const bbox = target.getBBox() - return createRectInit(0, 0, bbox.width, bbox.height) -} - -const isDocumentElement = function (target) { - return target === getWindowOf(target).document.documentElement -} - -const getHTMLElementContentRect = function (target) { - const clientWidth = target.clientWidth - const clientHeight = target.clientHeight - - if (!clientHeight && !clientWidth) { - return emptyRect - } - - const styles = getWindowOf(target).getComputedStyle(target) - const paddings = getPaddings(styles) - - const vertPad = paddings.top + paddings.bottom - const horizPad = paddings.left + paddings.right - - let width = toFloat(styles.width) - let height = toFloat(styles.height) - - if (styles.boxSizing === 'border-box') { - if (Math.round(height + vertPad) !== clientHeight) { - height -= getBordersSize(styles, 'top', 'bottom') + vertPad - } - - if (Math.round(width + horizPad) !== clientWidth) { - width -= getBordersSize(styles, 'left', 'right') + horizPad - } - } - - if (!isDocumentElement(target)) { - const horizScrollbar = Math.round(height + vertPad) - clientHeight - const vertScrollbar = Math.round(width + horizPad) - clientWidth - - if (Math.abs(horizScrollbar) !== 1) { - height -= horizScrollbar - } - - if (Math.abs(vertScrollbar) !== 1) { - width -= vertScrollbar - } - } - - return createRectInit(paddings.left, paddings.top, width, height) -} - -const isSVGGraphicsElement = (function () { - if (typeof SVGGraphicsElement !== 'undefined') { - return (target) => target instanceof getWindowOf(target).SVGGraphicsElement - } - - return (target) => target instanceof getWindowOf(target).SVGElement && typeof target.getBBox === 'function' -})() - -const getContentRect = function (target) { - if (!isBrowser) { - return emptyRect - } - - if (isSVGGraphicsElement(target)) { - return getSVGContentRect(target) - } - - return getHTMLElementContentRect(target) -} - -const createReadOnlyRect = function (_a) { - const x = _a.x - const y = _a.y - const width = _a.width - const height = _a.height - const Constr = typeof DOMRectReadOnly !== 'undefined' ? DOMRectReadOnly : Object - const rect = Object.create(Constr.prototype) - - defineConfigurable(rect, { - x, - y, - width, - height, - top: y, - right: x + width, - bottom: height + y, - left: x - }) - - return rect -} - -const ResizeObservation = (function () { - function ResizeObservation(target) { - this.broadcastWidth = 0 - this.broadcastHeight = 0 - this.contentRect_ = createRectInit(0, 0, 0, 0) - this.target = target - } - - ResizeObservation.prototype.broadcastRect = function () { - const rect = this.contentRect_ - this.broadcastWidth = rect.width - this.broadcastHeight = rect.height - - return rect - } - - ResizeObservation.prototype.isActive = function () { - const rect = getContentRect(this.target) - this.contentRect_ = rect - - return rect.width !== this.broadcastWidth || rect.height !== this.broadcastHeight - } - - return ResizeObservation -})() - -const ResizeObserverEntry = (function () { - function ResizeObserverEntry(target, rectInit) { - const contentRect = createReadOnlyRect(rectInit) - - defineConfigurable(this, { target, contentRect }) - } - - return ResizeObserverEntry -})() - -const ResizeObserverSPI = (function () { - function ResizeObserverSPI(callback, controller, callbackCtx) { - this.observations_ = new MapShim() - this.activeObservations_ = [] - - if (typeof callback !== 'function') { - throw new TypeError('[TINY-Resize] The callback provided as parameter 1 is not a function.') - } - - this.callback_ = callback - this.controller_ = controller - this.callbackCtx_ = callbackCtx - } - - ResizeObserverSPI.prototype.observe = function (target) { - if (!arguments.length) { - throw new TypeError('[TINY-Resize] 1 argument required, but only 0 present.') - } - - if (typeof Element === 'undefined' || !(Element instanceof Object)) { - return - } - - if (!(target instanceof getWindowOf(target).Element)) { - throw new TypeError('[TINY-Resize] parameter 1 is not of type "Element".') - } - - const obserVations = this.observations_ - - if (obserVations.has(target)) { - return - } - - obserVations.set(target, new ResizeObservation(target)) - - this.controller_.addObserver(this) - this.controller_.refresh() - } - - ResizeObserverSPI.prototype.unobserve = function (target) { - if (!arguments.length) { - throw new TypeError('[TINY-Resize]1 argument required, but only 0 present.') - } - - if (typeof Element === 'undefined' || !(Element instanceof Object)) { - return - } - - if (!(target instanceof getWindowOf(target).Element)) { - throw new TypeError('[TINY-Resize] parameter 1 is not of type "Element".') - } - - const obserVations = this.observations_ - - if (!obserVations.has(target)) { - return - } - - obserVations.delete(target) - - !obserVations.size && this.controller_.removeObserver(this) - } - - ResizeObserverSPI.prototype.gatherActive = function () { - const me = this - this.clearActive() - - this.observations_.forEach((observation) => { - observation.isActive() && me.activeObservations_.push(observation) - }) - } - - ResizeObserverSPI.prototype.disconnect = function () { - this.clearActive() - this.observations_.clear() - this.controller_.removeObserver(this) - } - - ResizeObserverSPI.prototype.broadcastActive = function () { - if (!this.hasActive()) { - return - } - - const ctx = this.callbackCtx_ - const entries = this.activeObservations_.map( - (observation) => new ResizeObserverEntry(observation.target, observation.broadcastRect()) - ) - - this.callback_.call(ctx, entries, ctx) - this.clearActive() - } - - ResizeObserverSPI.prototype.hasActive = function () { - return this.activeObservations_.length > 0 - } - - ResizeObserverSPI.prototype.clearActive = function () { - this.activeObservations_.splice(0) - } - - return ResizeObserverSPI -})() - -const observers = typeof WeakMap !== 'undefined' ? new WeakMap() : new MapShim() - -const ResizeObserver = (function () { - function ResizeObserver(callback) { - if (!(this instanceof ResizeObserver)) { - throw new TypeError('[TINY-Resize] Cannot call a class as a function.') - } - - if (!arguments.length) { - throw new TypeError('[TINY-Resize] 1 argument required, but only 0 present.') - } - - const controller = ResizeObserverController.getInstance() - const observer = new ResizeObserverSPI(callback, controller, this) - - observers.set(this, observer) - } - - return ResizeObserver -})() -;['observe', 'unobserve', 'disconnect'].forEach((method) => { - ResizeObserver.prototype[method] = function () { - let _a - - return (_a = observers.get(this))[method].apply(_a, arguments) - } -}) - -const index = (function () { - if (typeof global$1.ResizeObserver !== 'undefined') { - return global$1.ResizeObserver - } - - return ResizeObserver -})() - -export default index diff --git a/packages/mobile/utils/deps/after-leave.ts b/packages/mobile/utils/deps/after-leave.ts deleted file mode 100644 index 707ceff98a..0000000000 --- a/packages/mobile/utils/deps/after-leave.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -const AfterLave = 'after-leave' -const Speed = 300 - -export default (instance, callback, speed = Speed, once = false) => { - if (!instance || !callback) { - throw new Error('instance & callback is required') - } - - let called = false - - const eventCallback = function () { - if (called) { - return - } - - called = true - - if (typeof callback === 'function') { - callback.apply(null, arguments) - } - } - - if (once) { - instance.$once(AfterLave, eventCallback) - } else { - instance.$on(AfterLave, eventCallback) - } - - setTimeout(eventCallback, speed + 100) -} diff --git a/packages/mobile/utils/deps/clickoutside.ts b/packages/mobile/utils/deps/clickoutside.ts deleted file mode 100644 index b0cd772882..0000000000 --- a/packages/mobile/utils/deps/clickoutside.ts +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { on } from './dom' - -const isServer = typeof window === 'undefined' -const nodeList = [] -const nameSpace = '@@clickoutsideContext' -let startClick -let seed = 0 - -if (!isServer) { - on(document, 'mousedown', (event) => (startClick = event)) - - on(document, 'mouseup', (event) => { - nodeList.forEach((node) => node[nameSpace].documentHandler(event, startClick)) - startClick = void 0 - }) -} - -const createDocumentHandler = (el, binding, vnode) => - function (mouseup = {}, mousedown = {}) { - let popperElm = vnode.context.popperElm || (vnode.context.state && vnode.context.state.popperElm) - - if ( - !mouseup || - !mouseup.target || - !mousedown || - !mousedown.target || - el.contains(mouseup.target) || - el.contains(mousedown.target) || - el === mouseup.target || - (popperElm && (popperElm.contains(mouseup.target) || popperElm.contains(mousedown.target))) - ) { - return - } - - if (binding.expression && el[nameSpace].methodName && vnode.context[el[nameSpace].methodName]) { - vnode.context[el[nameSpace].methodName]() - } else { - el[nameSpace].bindingFn && el[nameSpace].bindingFn() - } - } - -/** - * v-clickoutside - * @desc 点击元素外面才会触发的事件 - * @example - * ```html - *
- * ``` - */ -export default { - bind: (el, binding, vnode) => { - nodeList.push(el) - const id = seed++ - - el[nameSpace] = { - id, - documentHandler: createDocumentHandler(el, binding, vnode), - methodName: binding.expression, - bindingFn: binding.value - } - }, - - update: (el, binding, vnode) => { - el[nameSpace].documentHandler = createDocumentHandler(el, binding, vnode) - el[nameSpace].methodName = binding.expression - el[nameSpace].bindingFn = binding.value - }, - - unbind: (el) => { - if (el.nodeType !== Node.ELEMENT_NODE) { - return - } - - let len = nodeList.length - - for (let i = 0; i < len; i++) { - if (nodeList[i][nameSpace].id === el[nameSpace].id) { - nodeList.splice(i, 1) - break - } - } - - if (nodeList.length === 0 && startClick) { - startClick = null - } - - delete el[nameSpace] - } -} diff --git a/packages/mobile/utils/deps/date-util.ts b/packages/mobile/utils/deps/date-util.ts deleted file mode 100644 index e4e92c0f81..0000000000 --- a/packages/mobile/utils/deps/date-util.ts +++ /dev/null @@ -1,310 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import fecha from './date' -import { isNull } from '../type' -import { isLeapYear } from '../date' -import { DATEPICKER } from '../index' - -const weeks = DATEPICKER.Weeks -const months = DATEPICKER.MonhtList -const defaultYMD = DATEPICKER.DateFormats.date -const defaultHMS = DATEPICKER.DateFormats.time - -const newArray = (start, end) => { - let res = [] - - for (let i = start; i <= end; i++) { - res.push(i) - } - - return res -} - -export const getI18nSettings = (t) => ({ - dayNamesShort: weeks.map((week) => t(`ui.datepicker.weeks.${week}`)), - dayNames: weeks.map((week) => t(`ui.datepicker.weeks.${week}`)), - monthNamesShort: months.map((month) => t(`ui.datepicker.months.${month}`)), - monthNames: months.map((month, index) => t(`ui.datepicker.month${index + 1}`)), - amPm: ['am', 'pm'] -}) - -export const isDate = function (date) { - if (isNull(date)) { - return false - } - if (isNaN(new Date(date).getTime())) { - return false - } - if (Array.isArray(date)) { - return false - } - - return true -} - -export const toDate = (date) => (isDate(date) ? new Date(date) : null) - -export const isDateObject = (val) => val instanceof Date - -export const formatDate = (date, format, t) => { - date = toDate(date) - if (!date) { - return '' - } - - return fecha.format(date, format || defaultYMD, getI18nSettings(t)) -} - -export const parseDate = (string, format, t) => fecha.parse(string, format || defaultYMD, getI18nSettings(t)) - -export const getDayCountOfMonth = (year, month) => { - if (~[3, 5, 8, 10].indexOf(month)) { - return 30 - } - - if (month === 1) { - return isLeapYear(year) ? 29 : 28 - } - - return 31 -} - -export const getDayCountOfYear = (year) => (isLeapYear(year) ? 366 : 365) - -export const getFirstDayOfMonth = (date) => { - const temp = new Date(date.getTime()) - temp.setDate(1) - return temp.getDay() -} - -export const prevDate = (date, amount = 1) => new Date(date.getFullYear(), date.getMonth(), date.getDate() - amount) - -export const nextDate = (date, amount = 1) => new Date(date.getFullYear(), date.getMonth(), date.getDate() + amount) - -export const getStartDateOfMonth = (year, month, offsetDay = 0) => { - const res = new Date(year, month, 1) - const day = res.getDay() - const _day = day === 0 ? 7 : day - - const offset = _day + offsetDay <= 0 ? 7 + _day : _day - return prevDate(res, offset) -} - -export const getWeekNumber = (src) => { - if (!isDate(src)) { - return null - } - - const date = new Date(src.getTime()) - - date.setHours(0, 0, 0, 0) - date.setDate(date.getDate() + 3 - ((date.getDay() + 6) % 7)) - - const week1 = new Date(date.getFullYear(), 0, 4) - - return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - 3 + ((week1.getDay() + 6) % 7)) / 7) -} - -export const getRangeHours = (ranges = []) => { - const hours = [] - let disHours = [] - - ranges.forEach((range) => { - const value = range.map((date) => date.getHours()) - disHours = disHours.concat(newArray(value[0], value[1])) - }) - - let isDisabled - - if (disHours.length) { - isDisabled = (i) => !~disHours.indexOf(i) - } else { - isDisabled = () => false - } - - for (let i = 0; i < 24; i++) { - hours[i] = isDisabled(i) - } - - return hours -} - -const setRangeData = (arr, start, end, value) => { - for (let i = start; i < end; i++) { - arr[i] = value - } -} - -// eslint-disable-next-line prefer-spread -export const range = (length) => Array.apply(null, { length }).map((_, n) => n) - -export const getMonthDays = (date) => { - const temp = new Date(date.getFullYear(), date.getMonth() + 1, 0) - const days = temp.getDate() - - return range(days).map((_, index) => index + 1) -} - -export const getPrevMonthLastDays = (date, amount) => { - if (amount <= 0) { - return [] - } - - const timeValue = new Date(date.getTime()) - timeValue.setDate(0) - const lastDay = timeValue.getDate() - - return range(amount).map((_, index) => lastDay - (amount - index - 1)) -} - -export const getRangeMinutes = (ranges, hour) => { - const sixty = 60 - const minutes = new Array(sixty) - - if (ranges.length > 0) { - ranges.forEach((range) => { - const [startDate, endDate] = range - const startHour = startDate.getHours() - const startMinute = startDate.getMinutes() - const endHour = endDate.getHours() - const endMinute = endDate.getMinutes() - const equealStartHour = startHour === hour - - if (equealStartHour && endHour !== hour) { - setRangeData(minutes, startMinute, sixty, true) - } else if (equealStartHour && endHour === hour) { - setRangeData(minutes, startMinute, endMinute + 1, true) - } else if (!equealStartHour && endHour === hour) { - setRangeData(minutes, 0, endMinute + 1, true) - } else if (startHour < hour && endHour > hour) { - setRangeData(minutes, 0, sixty, true) - } - }) - } else { - setRangeData(minutes, 0, sixty, true) - } - - return minutes -} - -export const modifyDate = (date, y, m, d) => { - date = toDate(date) - - return new Date(y, m, d, date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds()) -} - -export const modifyTime = (date, h, m, s) => { - date = toDate(date) - - return new Date(date.getFullYear(), date.getMonth(), date.getDate(), h, m, s, date.getMilliseconds()) -} - -export const modifyWithTimeString = (date, time, t) => { - if (isNull(date) || !time) { - return date - } - - time = parseDate(time, defaultHMS, t) - return modifyTime(date, time.getHours(), time.getMinutes(), time.getSeconds()) -} - -export const clearTime = (date) => new Date(date.getFullYear(), date.getMonth(), date.getDate()) - -export const clearMilliseconds = (date) => - new Date( - date.getFullYear(), - date.getMonth(), - date.getDate(), - date.getHours(), - date.getMinutes(), - date.getSeconds(), - 0 - ) - -export const limitTimeRange = (date, ranges, format = defaultHMS) => { - if (ranges.length === 0) { - return date - } - - const normalizeDate = (date) => fecha.parse(fecha.format(date, format), format) - - const ndate = normalizeDate(date) - const nranges = ranges.map((range) => range.map(normalizeDate)) - - if (nranges.some((nrange) => ndate >= nrange[0] && ndate <= nrange[1])) { - return date - } - - let minDate = nranges[0][0] - let maxDate = minDate - - nranges.forEach((nrange) => { - let minTempDate = (minDate = new Date(Math.min(nrange[0], minDate))) - maxDate = new Date(Math.max(nrange[1], minTempDate)) - }) - - const ret = ndate < minDate ? minDate : maxDate - return modifyDate(ret, date.getFullYear(), date.getMonth(), date.getDate()) -} - -export const timeWithinRange = (date, selectableRange, format) => { - const limitedDate = limitTimeRange(date, selectableRange, format) - return limitedDate.getTime() === date.getTime() -} - -export const changeYearMonthAndClampDate = (date, year, month) => { - const monthDate = Math.min(date.getDate(), getDayCountOfMonth(year, month)) - return modifyDate(date, year, month, monthDate) -} - -export const nextMonth = (date) => { - const year = date.getFullYear() - const month = date.getMonth() - const isLast = month === 11 - - return isLast ? changeYearMonthAndClampDate(date, year + 1, 0) : changeYearMonthAndClampDate(date, year, month + 1) -} - -export const prevMonth = (date) => { - const year = date.getFullYear() - const month = date.getMonth() - const isFirst = month === 0 - - return isFirst ? changeYearMonthAndClampDate(date, year - 1, 11) : changeYearMonthAndClampDate(date, year, month - 1) -} - -export const nextYear = (date, next = 1) => { - const year = date.getFullYear() - const month = date.getMonth() - - return changeYearMonthAndClampDate(date, year + next, month) -} - -export const prevYear = (date, prev = 1) => { - const year = date.getFullYear() - const month = date.getMonth() - - return changeYearMonthAndClampDate(date, year - prev, month) -} - -export const extractTimeFormat = (dateFormat) => - dateFormat.replace(/\W?D{1,2}|\W?Do|\W?d{1,4}|\W?M{1,4}|\W?y{2,4}/g, '').trim() - -export const extractDateFormat = (dateFormat) => - dateFormat - .replace(/\W?m{1,2}|\W?ZZ/g, '') - .replace(/\W?h{1,2}|\W?s{1,3}|\W?a/gi, '') - .trim() - -export const validateRangeInOneMonth = (startDate, endDate) => - startDate.getMonth() === endDate.getMonth() && startDate.getFullYear() === endDate.getFullYear() diff --git a/packages/mobile/utils/deps/date.ts b/packages/mobile/utils/deps/date.ts deleted file mode 100644 index 93d58c5971..0000000000 --- a/packages/mobile/utils/deps/date.ts +++ /dev/null @@ -1,342 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { DATEPICKER } from '../index' -import { isNull, isDate } from '../type' - -const fecha = {} -const digitsReg = ['\\d\\d?', '\\d{3}', '\\d{4}'] -const twoDigits = digitsReg[0] -const threeDigits = digitsReg[1] -const fourDigits = digitsReg[2] -const word = '[^\\s]+' -const literal = /\[([^]*?)\]/gm -const noop = () => undefined -const formats = { - shortDate: 'M/D/yy', - mediumDate: 'MMM d, yyyy', - longDate: 'MMMM d, yyyy', - fullDate: 'dddd, MMMM d, yyyy', - default: 'ddd MMM dd yyyy HH:mm:ss', - shortTime: 'HH:mm', - mediumTime: 'HH:mm:ss', - longTime: 'HH:mm:ss.SSS' -} - -const shorten = (arr, sLen) => { - let newArr = [] - - for (let i = 0, len = arr.length; i < len; i++) { - newArr.push(arr[i].substr(0, sLen)) - } - - return newArr -} - -const monthUpdate = (arrName) => (date, value, i18n) => { - const index = i18n[arrName].indexOf(value.charAt(0).toUpperCase() + value.substr(1).toLowerCase()) - - if (~index) { - date.month = index - } -} - -const pad = (val, len) => { - val = String(val) - len = len || 2 - - while (val.length < len) { - val = '0' + val - } - - return val -} - -const regexEscape = (str) => str.replace(/[|\\{()[^$+*?.-]/g, '\\$&') - -const fullTimeReg = /d{1,4}|M{1,4}|yy(?:yy)?|S{1,3}|Do|ZZ|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g -const dayNames = DATEPICKER.fullWeeks -const monthNames = DATEPICKER.fullMonths -const monthNamesShort = shorten(monthNames, 3) -const dayNamesShort = shorten(dayNames, 3) -const parts = ['th', 'st', 'nd', 'rd'] - -fecha.i18n = { - dayNames, - monthNames, - dayNamesShort, - monthNamesShort, - amPm: ['am', 'pm'], - doFn: (D) => D + parts[D % 10 > 3 ? 0 : ((D - (D % 10) !== 10) * D) % 10] -} - -const formatFlags = { - D: (dateObj) => dateObj.getDay(), - DD: (dateObj) => pad(dateObj.getDay()), - Do: (dateObj, i18n) => i18n.doFn(dateObj.getDate()), - d: (dateObj) => dateObj.getDate(), - dd: (dateObj) => pad(dateObj.getDate()), - ddd: (dateObj, i18n) => i18n.dayNamesShort[dateObj.getDay()], - dddd: (dateObj, i18n) => i18n.dayNames[dateObj.getDay()], - M: (dateObj) => dateObj.getMonth() + 1, - MM: (dateObj) => pad(dateObj.getMonth() + 1), - MMM: (dateObj, i18n) => i18n.monthNamesShort[dateObj.getMonth()], - MMMM: (dateObj, i18n) => i18n.monthNames[dateObj.getMonth()], - yy: (dateObj) => pad(String(dateObj.getFullYear()), 4).substr(2), - yyyy: (dateObj) => pad(dateObj.getFullYear(), 4), - h: (dateObj) => dateObj.getHours() % 12 || 12, - hh: (dateObj) => pad(dateObj.getHours() % 12 || 12), - H: (dateObj) => dateObj.getHours(), - HH: (dateObj) => pad(dateObj.getHours()), - m: (dateObj) => dateObj.getMinutes(), - mm: (dateObj) => pad(dateObj.getMinutes()), - s: (dateObj) => dateObj.getSeconds(), - ss: (dateObj) => pad(dateObj.getSeconds()), - S: (dateObj) => Math.round(dateObj.getMilliseconds() / 100), - SS: (dateObj) => pad(Math.round(dateObj.getMilliseconds() / 10), 2), - SSS: (dateObj) => pad(dateObj.getMilliseconds(), 3), - a: (dateObj, i18n) => (dateObj.getHours() < 12 ? i18n.amPm[0] : i18n.amPm[1]), - A: (dateObj, i18n) => (dateObj.getHours() < 12 ? i18n.amPm[0].toUpperCase() : i18n.amPm[1].toUpperCase()), - ZZ: (dateObj) => { - const offset = dateObj.getTimezoneOffset() - return (offset > 0 ? '-' : '+') + pad(Math.floor(Math.abs(offset) / 60) * 100 + (Math.abs(offset) % 60), 4) - } -} - -const parseFlags = { - d: [ - twoDigits, - (date, value) => { - date.day = value - } - ], - Do: [ - twoDigits + word, - (date, value) => { - date.day = parseInt(value, 10) - } - ], - M: [ - twoDigits, - (date, value) => { - date.month = value - 1 - } - ], - yy: [ - twoDigits, - (date, value) => { - const now = new Date() - const cent = Number(String(now.getFullYear()).substr(0, 2)) - date.year = String(value > 68 ? cent - 1 : cent) + value - } - ], - h: [ - twoDigits, - (date, value) => { - date.hour = value - } - ], - m: [ - twoDigits, - (date, value) => { - date.minute = value - } - ], - s: [ - twoDigits, - (date, value) => { - date.second = value - } - ], - yyyy: [ - fourDigits, - (date, value) => { - date.year = value - } - ], - S: [ - '\\d', - (date, value) => { - date.millisecond = value * 100 - } - ], - SS: [ - '\\d{2}', - (date, value) => { - date.millisecond = value * 10 - } - ], - SSS: [ - threeDigits, - (date, value) => { - date.millisecond = value - } - ], - D: [twoDigits, noop], - ddd: [word, noop], - MMM: [word, monthUpdate('monthNamesShort')], - MMMM: [word, monthUpdate('monthNames')], - a: [ - word, - (date, value, i18n) => { - const val = value.toLowerCase() - if (val === i18n.amPm[0]) { - date.isPm = false - } else if (val === i18n.amPm[1]) { - date.isPm = true - } - } - ], - ZZ: [ - '[^\\s]*?[\\+\\-]\\d\\d:?\\d\\d|[^\\s]*?Z', - (date, value) => { - let parts = String(value).match(/([+-]|\d\d)/gi) - let minutes - - if (parts) { - minutes = Number(parts[1] * 60) + parseInt(parts[2], 10) - date.timezoneOffset = parts[0] === '+' ? minutes : -minutes - } - } - ] -} - -const fmts = ['A', 'DD', 'dd', 'mm', 'hh', 'MM', 'ss', 'hh', 'H', 'HH'] - -fecha.masks = formats -parseFlags.dddd = parseFlags.ddd - -fmts.forEach((name) => { - if (name === 'MM') { - parseFlags[name] = parseFlags[name.substr(0, 1)] - } else { - parseFlags[name] = parseFlags[name.substr(0, 1).toLowerCase()] - } -}) - -fecha.format = (dateObj, mask, i18nSettings) => { - const i18n = i18nSettings || fecha.i18n - - if (typeof dateObj === 'number') { - dateObj = new Date(dateObj) - } - - if (!isDate(dateObj) || isNaN(dateObj.getTime())) { - throw new Error('Invalid Date in fecha.format') - } - - mask = fecha.masks[mask] || mask || fecha.masks.default - - let literals = [] - - mask = mask.replace(literal, ($0, $1) => { - literals.push($1) - return '@@@' - }) - - mask = mask.replace(fullTimeReg, ($0) => - $0 in formatFlags ? formatFlags[$0](dateObj, i18n) : $0.slice(1, $0.length - 1) - ) - - return mask.replace(/@@@/g, () => literals.shift()) -} - -const getNewFormat = (format, parseInfo) => { - let literals = [] - - let newFormat = regexEscape(format).replace(fullTimeReg, ($0) => { - if (parseFlags[$0]) { - const info = parseFlags[$0] - parseInfo.push(info[1]) - - return '(' + info[0] + ')' - } - - return $0 - }) - - newFormat = newFormat.replace(/@@@/g, () => literals.shift()) - - return newFormat -} - -const getDate = (dateInfo) => { - let date - const today = new Date() - - if (!isNull(dateInfo.timezoneOffset)) { - dateInfo.minute = Number(dateInfo.minute || 0) - Number(dateInfo.timezoneOffset) - - const { year, month, day, hour, minute, second, millisecond } = dateInfo - - date = new Date( - Date.UTC(year || today.getFullYear(), month || 0, day || 1, hour || 0, minute || 0, second || 0, millisecond || 0) - ) - } else { - const { year, month, day, hour, minute, second, millisecond } = dateInfo - - date = new Date( - year || today.getFullYear(), - month || 0, - day || 1, - hour || 0, - minute || 0, - second || 0, - millisecond || 0 - ) - } - return date -} - -fecha.parse = (dateStr, format, i18nSettings) => { - const i18n = i18nSettings || fecha.i18n - - if (typeof format !== 'string') { - throw new TypeError('Invalid format in fecha.parse') - } - - format = fecha.masks[format] || format - - if (dateStr.length > 1000) { - return null - } - - let dateInfo = {} - let parseInfo = [] - let literals = [] - - format = format.replace(literal, ($0, $1) => { - literals.push($1) - return '@@@' - }) - - const newFormat = getNewFormat(format, parseInfo) - const matches = dateStr.match(new RegExp(newFormat, 'i')) - - if (!matches) { - return null - } - - for (let i = 1, len = matches.length; i < len; i++) { - parseInfo[i - 1](dateInfo, matches[i], i18n) - } - - if (dateInfo.isPm === true && !isNull(dateInfo.hour) && Number(dateInfo.hour) !== 12) { - dateInfo.hour = Number(dateInfo.hour) + 12 - } else if (dateInfo.isPm === false && Number(dateInfo.hour) === 12) { - dateInfo.hour = 0 - } - - return getDate(dateInfo) -} - -export default fecha diff --git a/packages/mobile/utils/deps/debounce.ts b/packages/mobile/utils/deps/debounce.ts deleted file mode 100644 index 61fa79f007..0000000000 --- a/packages/mobile/utils/deps/debounce.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import throttle from './throttle' - -export default function (delay, atBegin, callback?: Function) { - return callback === undefined ? throttle(delay, atBegin, false) : throttle(delay, callback, atBegin !== false) -} diff --git a/packages/mobile/utils/deps/dom.ts b/packages/mobile/utils/deps/dom.ts deleted file mode 100644 index 4228e4d78e..0000000000 --- a/packages/mobile/utils/deps/dom.ts +++ /dev/null @@ -1,295 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { hasOwn, isNull } from '../type' -import globalConfig from '../global' - -export const isServer = typeof window === 'undefined' -const SPECIAL_CHARS_REGEXP = /([:\-_]+(.))/g -const MOZ_HACK_REGEXP = /^moz([A-Z])/ - -/** 处理style的名字。 - * 把 moz : - _ 等位置,转换为大写驼峰格式, 比如 :camelCase("moz:moz_abc:def-hjk_lmnOpqRst") = MozMozAbcDefHjkLmnOpqRst - */ -const camelCase = (name: string) => - name - .replace(SPECIAL_CHARS_REGEXP, (_, separator, letter, offset) => (offset ? letter.toUpperCase() : letter)) - .replace(MOZ_HACK_REGEXP, 'Moz$1') - -/** 绑定事件 */ -export const on = (el: EventTarget, event: any, handler: (this: HTMLElement, ev: any) => any, options = false) => { - if (el && event && handler) { - el.addEventListener(event, handler, options) - } -} -/** 移除事件 */ -export const off = (el: EventTarget, event: any, handler: (this: HTMLElement, ev: any) => any, options = false) => { - if (el && event) { - el.removeEventListener(event, handler, options) - } -} - -/** 执行一次就立即移除事件 */ -export const once = (el: HTMLElement, event: any, fn: (this: HTMLElement, ev: any) => any) => { - const listener = function () { - if (fn) { - // eslint-disable-next-line prefer-rest-params - fn.apply(this, arguments) - } - - off(el, event, listener) - } - - on(el, event, listener) -} - -/** 判断是否有class, 只能查询单个类名, 且不能有空格 */ -export const hasClass = (el: HTMLElement, clazz: string) => { - if (!el || !clazz) { - return false - } - - if (clazz.includes(' ')) { - throw new Error('className should not contain space.') - } - - if (el.classList) { - return el.classList.contains(clazz) - } -} - -/** 给el添加一组classes, clazz 允许为用空格分隔的多个类名 */ -export const addClass = (el: HTMLElement, clazz = '') => { - if (!el) { - return - } - - const classes = clazz.split(' ').filter((name) => name) - - classes.forEach((clsName) => el.classList.add(clsName)) -} - -/** 移除el上的classes, clazz 允许为用空格分隔的多个类名 */ -export const removeClass = (el: HTMLElement, clazz: string) => { - if (!el || !clazz) { - return - } - - const classes = clazz.split(' ').filter((name) => name) - - classes.forEach((clsName) => el.classList.remove(clsName)) -} - -/** 查询元素的style的值。 优先找el.style, 找不到则调用getComputedStyle(el) */ -export const getStyle = (el: HTMLElement, styleName: string) => { - if (isServer) { - return - } - if (!el || !styleName) { - return null - } - - styleName = camelCase(styleName) - - if (styleName === 'float') { - styleName = 'cssFloat' - } - - try { - if (el.style[styleName]) { - return el.style[styleName] - } - - const computed = window.getComputedStyle(el) - return computed ? computed[styleName] : null - } catch (e) { - return el.style[styleName] - } -} - -/** 给元素赋值style。 - * @param name 当它是对象时,遍历所有属性;当它是字符串时,需要传入第3个参数 value - */ -export const setStyle = (el: HTMLElement, name: string | object, value?: any) => { - if (!el || !name) { - return - } - - if (typeof name === 'object') { - for (const prop in name) { - if (hasOwn.call(name, prop)) { - setStyle(el, prop, name[prop]) - } - } - } else { - name = camelCase(name) - - el.style[name as string] = value - } -} - -/** 判断元素是否有滚动的style TINY_NO_USED - * @param vertical true时,只判断overflow-y属性; false时,只判断overflow-x属性; 不传入时,只判断overflow属性! - */ -export const isScroll = (el: HTMLElement, vertical?: boolean) => { - if (isServer) { - return - } - - /** 是否需要判断方向 - * 它的值为false: 当vertical = null / undefinded。 - * 它的值为 true: 当vertical =true /false - */ - const determinedDirection = !isNull(vertical) - let overflow - - if (determinedDirection) { - overflow = vertical ? getStyle(el, 'overflow-y') : getStyle(el, 'overflow-x') - } else { - overflow = getStyle(el, 'overflow') - } - - return overflow.match(/(scroll|auto)/) -} - -/** 查找离元素最近的父级滚动元素 - * @param vertical true时,只判断overflow-y属性; false时,只判断overflow-x属性; 不传入时,只判断overflow属性! - */ -export const getScrollContainer = (el: HTMLElement, vertical?: boolean) => { - if (isServer) { - return - } - - let parent = el - - while (parent) { - if (~[window, document, document.documentElement].indexOf(parent)) { - return window - } - - if (isScroll(parent, vertical)) { - return parent - } - - parent = parent.parentNode as any - } - - return parent -} - -/** 判断是否 el 完全在 container 中。 四个边有重合都不行,必须完全在里面。 */ -export const isInContainer = (el: HTMLElement, container: HTMLElement) => { - if (isServer || !el || !container) { - return false - } - - const elRect = el.getBoundingClientRect() - let containerRect - - if (~[window, document, document.documentElement].indexOf(container) || isNull(container)) { - containerRect = { - top: 0, - right: window.innerWidth, - bottom: window.innerHeight, - left: 0 - } - } else { - containerRect = container.getBoundingClientRect() - } - - return ( - elRect.top < containerRect.bottom && - elRect.bottom > containerRect.top && - elRect.right > containerRect.left && - elRect.left < containerRect.right - ) -} - -/** 查询页面的位置和尺寸 - * @returns scrollTop : document 或 body的滚动位置 - * @returns scrollLeft : document 或 body的滚动位置 - * @returns visibleHeight : 可视区高度 (不含滚动条) - * @returns visibleWidth : 可视区宽度(不含滚动条) - */ -export const getDomNode = () => { - const viewportWindow = globalConfig.viewportWindow || window - let documentElement = viewportWindow.document.documentElement - let bodyElem = viewportWindow.document.body - - return { - scrollTop: documentElement.scrollTop || bodyElem.scrollTop, - scrollLeft: documentElement.scrollLeft || bodyElem.scrollLeft, - visibleHeight: documentElement.clientHeight || bodyElem.clientHeight, - visibleWidth: documentElement.clientWidth || bodyElem.clientWidth - } -} - -export const getScrollTop = (el) => { - const top = 'scrollTop' in el ? el.scrollTop : el.pageYOffset - // iOS scroll bounce cause minus scrollTop - return Math.max(top, 0) -} - -export const stopPropagation = (event) => event.stopPropagation() - -export const preventDefault = (event, isStopPropagation) => { - /* istanbul ignore else */ - if (typeof event.cancelable !== 'boolean' || event.cancelable) { - event.preventDefault() - } - - if (isStopPropagation) { - stopPropagation(event) - } -} - -const overflowScrollReg = /scroll|auto|overlay/i -const defaultRoot = isServer ? undefined : window - -const isElement = (node) => node.tagName !== 'HTML' && node.tagName !== 'BODY' && node.nodeType === 1 - -export const getScrollParent = (el, root = defaultRoot) => { - let node = el - - while (node && node !== root && isElement(node)) { - const { overflowY } = window.getComputedStyle(node) - - if (overflowScrollReg.test(overflowY)) { - return node - } - - node = node.parentNode - } - - return root -} - -// 判断body的后代元素是否是隐藏的 -export const isDisplayNone = (elm) => { - if (isServer) return false - - if (elm) { - const computedStyle = getComputedStyle(elm) - - if (computedStyle.getPropertyValue('position') === 'fixed') { - if (computedStyle.getPropertyValue('display') === 'none') { - return true - } else if (elm.parentNode !== document.body) { - return isDisplayNone(elm.parentNode) - } - } else { - return elm.offsetParent === null - } - } - - return false -} diff --git a/packages/mobile/utils/deps/eSpaceCtrl.ts b/packages/mobile/utils/deps/eSpaceCtrl.ts deleted file mode 100644 index c62b74249d..0000000000 --- a/packages/mobile/utils/deps/eSpaceCtrl.ts +++ /dev/null @@ -1,417 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -let ws = null -const url = 'ws://localhost' -const ports = [27197, 27198, 27199] -let index = 0 -let connected -let pollingInterval = 1000 -let timeout = 30000 -let cid = 0 -let callbacks = {} -let pollingTimer -let userStatus = {} -const heartbeatInterval = 20 * 1000 -let heartbeatTimer = null -let connectTimer = null -let apiTimers = {} -let events = {} -let out = {} - -let error = () => undefined -let ready = () => undefined - -const clearCallback = function (cid) { - clearTimeout(apiTimers[cid]) - - delete callbacks[cid] - delete apiTimers[cid] -} - -const onopen = function () { - connectTimer = setTimeout(() => { - ws.close() - }, 5000) -} - -const send = function (argv, cb) { - let id = cid++ - id = String(id) - argv.cid = id - - if (!connected) { - cb && setTimeout(cb, 0, { ok: false, message: 'eSpace is not logged in.' }) - return - } - - if (typeof cb === 'function') { - callbacks[id] = cb - - apiTimers[id] = setTimeout(() => { - cb({ ok: false, message: 'time out' }) - clearCallback(id) - }, timeout) - } - - ws.send(JSON.stringify(argv)) -} - -const sendHeartbeat = function () { - heartbeatTimer = setTimeout(() => { - if (connected) { - send( - { - type: 'heartbeat' - }, - () => { - sendHeartbeat() - } - ) - } else { - clearTimeout(heartbeatTimer) - } - }, heartbeatInterval) -} - -const connectionSucceeded = function (data) { - connected = true - - sendHeartbeat() - clearTimeout(pollingTimer) - clearTimeout(connectTimer) - ready(data) -} - -const onmessage = function (evt) { - let data = evt.data - if (typeof data !== 'string') { - return - } - - data = data.replace(/^\d+/, '') - if (!data) { - return - } - - try { - data = JSON.parse(data) - } catch (e) { - return !e - } - - if (connected) { - let event = events[data.type] - - if (event) { - return event(data.data) - } - - let cid = data.cid - let cb = callbacks[cid] - - if (cb) { - if (data.ok) { - cb(null, data.data) - } else { - cb({ ok: data.ok }) - } - - clearCallback(cid) - } - } else { - if (data.type === 'eSpace-ctrl-connection-success') { - connectionSucceeded(data.data) - } else { - ws.close() - } - } -} - -const bindEvents = function () { - ws.onopen = onopen - ws.onclose = onclose - ws.onmessage = onmessage -} - -const connect = function (interval) { - pollingTimer = setTimeout(() => { - if (index >= ports.length) { - index = 0 - } - - ws = new WebSocket(url + ':' + ports[index++]) - - bindEvents() - }, interval || 0) -} - -const onclose = function () { - if (connected || typeof connected === 'undefined') { - connected = false - error() - } - - connect(pollingInterval) -} - -out.init = function (conf) { - if (conf) { - timeout = conf.timeout || 30000 - pollingInterval = conf.pollingInterval || 0 - } - - connect() -} - -out.ready = function (cb) { - ready = cb -} - -out.error = function (cb) { - error = cb -} - -const attrToArr = function (name, total, object) { - let result = [] - - for (let i = 0; i < total; i++) { - let attrName = name - if (i) { - attrName += i - } - - let attrVal = object[attrName] - if (attrVal) { - result.push(attrVal) - } - } - - return result -} - -/** - * 事件绑定 - * @param {String} event 事件名 - * @param {Function} hander 事件处理函数 - * - * example: - * out.on('user-status-change', function (data){ - * // do something - * }) - */ -out.on = function (event, hander) { - events[event] = hander -} - -/** - * 获取用户信息 - * @param {String|Array} accounts 单个帐号或者帐号数组 - * @param {Function} cb 回调函数 - */ -out.getUserInfo = function (account, cb) { - const fn = function (err, data) { - if (err) { - return cb(err) - } - - const formatInfo = function (user) { - return { - account: user.account, - name: user.name, - mobile: attrToArr('mobile', 6, user), - 'office_phone': attrToArr('office_phone', 6, user), - 'home_phone': user.home_phone, - 'ip_phone': user.ip_phone, - 'other_phone': user.other_phone - } - } - - if (data.account) { - cb(null, formatInfo(data)) - } else { - let result = {} - - for (let p in data) { - if (Object.prototype.hasOwnProperty.call(data, p)) { - let user = data[p] - result[p] = user ? formatInfo(user) : user - } - } - cb(null, result) - } - } - - send( - { - type: 'get-user-info', - param: account - }, - fn - ) -} - -/** - * 订阅用户状态 - * @param {String|Array} accounts 单个帐号或者帐号数组 - * @param {Function} cb 回调函数 - */ -out.subscribeUserStatus = function (accounts, cb) { - if (Array.isArray(accounts)) { - accounts.forEach((account) => { - userStatus[account] = true - }) - } - - send( - { - type: 'subscribe-user-status', - param: accounts - }, - cb - ) -} - -/** - * 拉起单人语音 - * @param {String} account 帐号 - * @param {String} num 可选,电话号码或voip - * @param {Function} cb 回调函数 - */ -out.eSpaceCall = function (account, num, cb) { - send( - { - type: 'espace-call', - param: { - account, - number: num - } - }, - cb - ) -} - -/** - * 拉起单人语音 - * @param {String} account 帐号 - * @param {Function} cb 回调函数 - */ -out.eSpaceCallByAccount = function (account, cb) { - send( - { - type: 'espace-call', - param: { - account - } - }, - cb - ) -} - -/** - * 拉起单人语音 - * @param {String} number 电话号码 - * @param {Function} cb 回调函数 - */ -out.eSpaceCallByNumber = function (number, cb) { - send( - { - type: 'espace-call', - param: { - number - } - }, - cb - ) -} - -/** - * 拉起单聊IM窗口 - * @param {String} account 帐号 - * @param {Function} cb 回调函数 - */ -out.showImDialog = function (account, cb) { - send( - { - type: 'show-espace-im-dialog', - param: account - }, - cb - ) -} - -/** - * 拉起群组IM窗口 - * @param {String} gid 群组id - * @param {Function} cb 回调函数 - */ -out.showGroupDialog = function (gid, cb) { - send( - { - type: 'show-espace-im-group-dialog', - param: gid - }, - cb - ) -} - -/** - * 添加到联系人列表 - * @param {String} account 帐号 - * @param {Function} cb 回调函数 - */ -out.addContactList = function (account, cb) { - send( - { - type: 'add-contact-list', - param: account - }, - cb - ) -} - -if (!window.WebSocket) { - const notFn = function () { - return undefined - } - - for (let api in out) { - if (Object.prototype.hasOwnProperty.call(out, api)) { - let fn = out[api] - - if (typeof fn === 'function') { - out[api] = notFn - } - } - } -} - -let initialized = false - -export function init() { - if (!initialized) { - localStorage.setItem('eSpaceCtrl_initialized', 0) - out.init({ timeout: 3000, pollingInterval: 1000 }) - out.ready(() => { - localStorage.setItem('eSpaceCtrl_initialized', 1) - }) - out.error(() => { - localStorage.setItem('eSpaceCtrl_initialized', 0) - }) - - initialized = true - } - - return out -} - -export default out diff --git a/packages/mobile/utils/deps/fastdom/async.ts b/packages/mobile/utils/deps/fastdom/async.ts deleted file mode 100644 index de8035facb..0000000000 --- a/packages/mobile/utils/deps/fastdom/async.ts +++ /dev/null @@ -1,59 +0,0 @@ -/** - * FastDom - * - * Eliminates layout thrashing - * by batching DOM read/write - * interactions. - * - * @author Wilson Page - * @author Kornel Lesinski - */ - -import fastdomSingleton from './singleton' - -const create = (promised, type, fn, ctx) => { - const tasks = promised._tasks - const fastdom = promised.fastdom - let task - - const promise = new Promise(function (resolve, reject) { - task = fastdom[type](function () { - tasks.delete(promise) - - try { - resolve(ctx ? fn.call(ctx) : fn()) - } catch (e) { - reject(e) - } - }, ctx) - }) - - tasks.set(promise, task) - - return promise -} - -const exports = { - initialize() { - this._tasks = new Map() - }, - - mutate(fn, ctx) { - return create(this, 'mutate', fn, ctx) - }, - - measure(fn, ctx) { - return create(this, 'measure', fn, ctx) - }, - - clear(promise) { - const tasks = this._tasks - const task = tasks.get(promise) - this.fastdom.clear(task) - tasks.delete(promise) - } -} - -const fastdomAsync = fastdomSingleton.extend(exports) - -export default fastdomAsync diff --git a/packages/mobile/utils/deps/fastdom/index.ts b/packages/mobile/utils/deps/fastdom/index.ts deleted file mode 100644 index c657751558..0000000000 --- a/packages/mobile/utils/deps/fastdom/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * FastDom - * - * Eliminates layout thrashing - * by batching DOM read/write - * interactions. - * - * @author Wilson Page - * @author Kornel Lesinski - */ - -import fastdom from './singleton' -import fastdomAsync from './async' -import fastdomSandbox from './sandbox' - -export { fastdom, fastdomAsync, fastdomSandbox } diff --git a/packages/mobile/utils/deps/fastdom/sandbox.ts b/packages/mobile/utils/deps/fastdom/sandbox.ts deleted file mode 100644 index 28ce7ddd91..0000000000 --- a/packages/mobile/utils/deps/fastdom/sandbox.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * FastDom - * - * Eliminates layout thrashing - * by batching DOM read/write - * interactions. - * - * @author Wilson Page - * @author Kornel Lesinski - */ - -import fastdomSingleton from './singleton' - -const clearAll = (fastdom, tasks) => { - let i = tasks.length - - while (i--) { - fastdom.clear(tasks[i]) - tasks.splice(i, 1) - } -} - -const remove = (array, item) => { - const index = array.indexOf(item) - return !!~index && !!array.splice(index, 1) -} - -class Sandbox { - constructor(fastdom) { - this.fastdom = fastdom - this.tasks = [] - } - - measure(fn, ctx) { - const tasks = this.tasks - const task = this.fastdom.measure(function () { - tasks.splice(tasks.indexOf(task)) - return fn.call(ctx) - }) - - tasks.push(task) - - return task - } - - mutate(fn, ctx) { - const tasks = this.tasks - const task = this.fastdom.mutate(function () { - tasks.splice(tasks.indexOf(task)) - return fn.call(ctx) - }) - - this.tasks.push(task) - - return task - } - - clear(task) { - if (!arguments.length) clearAll(this.fastdom, this.tasks) - - remove(this.tasks, task) - - return this.fastdom.clear(task) - } -} - -const exports = { - sandbox() { - return new Sandbox(this.fastdom) - } -} - -const fastdomSandbox = fastdomSingleton.extend(exports) - -export default fastdomSandbox diff --git a/packages/mobile/utils/deps/fastdom/singleton.ts b/packages/mobile/utils/deps/fastdom/singleton.ts deleted file mode 100644 index bf79f0a36a..0000000000 --- a/packages/mobile/utils/deps/fastdom/singleton.ts +++ /dev/null @@ -1,109 +0,0 @@ -/** - * FastDom - * - * Eliminates layout thrashing - * by batching DOM read/write - * interactions. - * - * @author Wilson Page - * @author Kornel Lesinski - */ - -const RAF = window.requestAnimationFrame - -const scheduleFlush = (fastdom) => { - if (!fastdom.scheduled) { - fastdom.scheduled = true - fastdom.raf(flush.bind(null, fastdom)) - } -} - -const flush = (fastdom) => { - const { reads, writes } = fastdom - let error - - try { - fastdom.runTasks(reads) - fastdom.runTasks(writes) - } catch (e) { - error = e - } - - fastdom.scheduled = false - - if (reads.length || writes.length) scheduleFlush(fastdom) - - if (error) { - if (fastdom.catch) { - fastdom.catch(error) - } else { - throw error - } - } -} - -const remove = (array, item) => { - const index = array.indexOf(item) - return !!~index && !!array.splice(index, 1) -} - -const mixin = (target, source) => { - for (let key in source) { - if (Object.hasOwnProperty.call(source, key)) target[key] = source[key] - } -} - -class FastDom { - constructor() { - this.reads = [] - this.writes = [] - this.raf = RAF.bind(window) - } - - runTasks(tasks) { - let task - while ((task = tasks.shift())) task() - } - - measure(fn, ctx) { - const task = !ctx ? fn : fn.bind(ctx) - - this.reads.push(task) - - scheduleFlush(this) - - return task - } - - mutate(fn, ctx) { - const task = !ctx ? fn : fn.bind(ctx) - - this.writes.push(task) - - scheduleFlush(this) - - return task - } - - clear(task) { - return remove(this.reads, task) || remove(this.writes, task) - } - - extend(props) { - if (!props || typeof props !== 'object') throw new Error('[TINY][FastDom] expected object') - - const child = Object.create(this) - - mixin(child, props) - - child.fastdom = this - - if (child.initialize) child.initialize() - - return child - } -} - -const fastdomSingleton = new FastDom() - -export default fastdomSingleton diff --git a/packages/mobile/utils/deps/fullscreen/apis.ts b/packages/mobile/utils/deps/fullscreen/apis.ts deleted file mode 100644 index 759c772115..0000000000 --- a/packages/mobile/utils/deps/fullscreen/apis.ts +++ /dev/null @@ -1,197 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { extend } from '../../object' -import { on, off } from '../dom' -import screenfull from './screenfull' - -const defaults = { - callback: () => undefined, - fullscreenClass: 'fullscreen', - pageOnly: false, - teleport: false -} - -let token -let parentNode - -const setStyle = (element, style) => { - element.style.position = style.position - element.style.left = style.left - element.style.top = style.top - element.style.width = style.width - element.style.height = style.height - element.style.zIndex = style.zIndex -} - -const resetElement = (api) => { - const targetEle = api.targetElement - - if (targetEle) { - // 移除全屏class - targetEle.classList.remove(api.opts.fullscreenClass) - - if (api.opts.teleport || api.opts.pageOnly) { - if (api.opts.teleport && parentNode) { - // 还原位置 - parentNode.insertBefore(targetEle, token) - parentNode.removeChild(token) - } - // 移除样式 - if (targetEle.__styleCache) { - setStyle(targetEle, targetEle.__styleCache) - } - } - } -} - -const setTargetStyle = (target, options) => { - const { position, left, top, width, height, zIndex } = target.style - // 添加全屏class - target.classList.add(options.fullscreenClass) - // teleport或者网页全屏时,为目标元素添加全屏样式 - if (options.teleport || options.pageOnly) { - const style = { - position: 'fixed', - left: '0', - top: '0', - width: '100%', - height: '100%' - } - - target.__styleCache = { position, left, top, width, height, zIndex } - options.zIndex && (style.zIndex = options.zIndex) - setStyle(target, style) - } -} - -const getOptions = (screenfull, options, target) => { - options = extend({}, defaults, options) - - // body不可teleport - if (target === document.body) { - options.teleport = false - } - // 不支持全屏api则自动启用网页全屏 - if (!screenfull.isEnabled) { - options.pageOnly = true - } - return options -} - -const api = { - targetElement: null, - opts: null, - isEnabled: screenfull.isEnabled, - isFullscreen: false, - toggle(target, options, force) { - if (force === undefined) { - // 如果已经是全屏状态,则退出 - return !this.isFullscreen ? this.request(target, options) : this.exit() - } - - return force ? this.request(target, options) : this.exit() - }, - request(targetEle, options) { - if (this.isFullscreen) { - return Promise.resolve() - } - // 默认全屏对象为body - if (!targetEle) { - targetEle = document.body - } - - this.opts = getOptions(screenfull, options, targetEle) - - setTargetStyle(targetEle, this.opts) - // teleport:将目标元素挪到body下,并在原地留一个标记用于还原 - if (this.opts.teleport) { - parentNode = targetEle.parentNode - - if (parentNode) { - token = document.createComment('fullscreen-token') - parentNode.insertBefore(token, targetEle) - document.body.appendChild(targetEle) - } - } - - if (this.opts.pageOnly) { - // 网页全屏模式 按键回调 - const keypressCallback = (e) => { - if (e.key === 'Escape') { - off(document, 'keyup', keypressCallback) - this.exit() - } - } - - this.isFullscreen = true - this.targetElement = targetEle - - off(document, 'keyup', keypressCallback) - on(document, 'keyup', keypressCallback) - - if (this.opts.callback) { - this.opts.callback(this.isFullscreen) - } - - return Promise.resolve() - } else { - // 全屏api模式 全屏api事件回调 - const fullScreenCallback = () => { - if (!screenfull.isFullscreen) { - // 退出全屏时解绑回调 - screenfull.off('change', fullScreenCallback) - resetElement(this) - } - - this.isFullscreen = screenfull.isFullscreen - - this.targetElement = !this.opts.teleport ? screenfull.targetElement : targetEle || null - - if (this.opts.callback) { - this.opts.callback(screenfull.isFullscreen) - } - } - - screenfull.on('change', fullScreenCallback) - - return screenfull.request(this.opts.teleport ? document.body : targetEle) - } - }, - exit() { - if (!this.isFullscreen) { - return Promise.resolve() - } - - if (this.opts.pageOnly) { - resetElement(this) - - this.isFullscreen = false - this.targetElement = null - - if (this.opts.callback) { - this.opts.callback(this.isFullscreen) - } - - return Promise.resolve() - } - - return screenfull.exit() - } -} - -// 向下兼容 -api.support = api.isEnabled -api.getState = () => api.isFullscreen -api.enter = api.request - -export default api diff --git a/packages/mobile/utils/deps/fullscreen/screenfull.ts b/packages/mobile/utils/deps/fullscreen/screenfull.ts deleted file mode 100644 index 96214b181e..0000000000 --- a/packages/mobile/utils/deps/fullscreen/screenfull.ts +++ /dev/null @@ -1,170 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { on, off } from '../dom' - -const fullscreenApi = [ - 'fullscreenElement', - 'fullscreenEnabled', - 'requestFullscreen', - 'exitFullscreen', - 'fullscreenchange', - 'fullscreenerror' -] - -const fullscreenApiMoz = [ - 'mozFullScreenElement', - 'mozFullScreenEnabled', - 'mozRequestFullScreen', - 'mozCancelFullScreen', - 'mozfullscreenchange', - 'mozfullscreenerror' -] - -const fullscreenApiWebkit = [ - 'webkitFullscreenElement', - 'webkitFullscreenEnabled', - 'webkitRequestFullscreen', - 'webkitExitFullscreen', - 'webkitfullscreenchange', - 'webkitfullscreenerror' -] - -const fullscreenApiMs = [ - 'msFullscreenElement', - 'msFullscreenEnabled', - 'msRequestFullscreen', - 'msExitFullscreen', - 'MSFullscreenChange', - 'MSFullscreenError' -] - -const fullscreenApiMap = [fullscreenApi, fullscreenApiWebkit, fullscreenApiMoz, fullscreenApiMs] - -const document = typeof window !== 'undefined' && typeof window.document !== 'undefined' ? window.document : {} - -let fullscreenEvents = null - -const getFullScreenEvents = () => { - for (let i = 0, len = fullscreenApiMap.length; i < len; i++) { - let eventName = fullscreenApiMap[i] - - if (eventName && eventName[1] in document) { - fullscreenEvents = {} - - for (i = 0; i < eventName.length; i++) { - fullscreenEvents[fullscreenApiMap[0][i]] = eventName[i] - } - - return - } - } -} - -getFullScreenEvents() - -const eventNameMap = { - change: fullscreenEvents && fullscreenEvents.fullscreenchange, - error: fullscreenEvents && fullscreenEvents.fullscreenerror -} - -const screenfull = { - request(element, options) { - return new Promise((resolve, reject) => { - const onFullscreenEntered = () => { - this.off('change', onFullscreenEntered) - resolve() - } - - this.on('change', onFullscreenEntered) - - element = element || document.documentElement - - if (element[fullscreenEvents && fullscreenEvents.requestFullscreen]) { - const promiseReturn = element[fullscreenEvents && fullscreenEvents.requestFullscreen](options) - - if (promiseReturn instanceof Promise) { - promiseReturn.then(onFullscreenEntered).catch(reject) - } - } - }) - }, - exit() { - return new Promise((resolve, reject) => { - if (!this.isFullscreen) { - resolve() - return - } - - const onFullscreenExit = () => { - this.off('change', onFullscreenExit) - resolve() - } - - this.on('change', onFullscreenExit) - - if (document[fullscreenEvents && fullscreenEvents.exitFullscreen]) { - const promiseReturn = document[fullscreenEvents && fullscreenEvents.exitFullscreen]() - - if (promiseReturn instanceof Promise) { - promiseReturn.then(onFullscreenExit).catch(reject) - } - } - }) - }, - toggle(element, options) { - return this.isFullscreen ? this.exit() : this.request(element, options) - }, - onchange(callback) { - this.on('change', callback) - }, - onerror(callback) { - this.on('error', callback) - }, - on(event, callback) { - const eventName = eventNameMap[event] - - if (eventName) { - on(document, eventName, callback) - } - }, - off(event, callback) { - const eventName = eventNameMap[event] - - if (eventName) { - off(document, eventName, callback) - } - }, - raw: fullscreenEvents -} - -Object.defineProperties(screenfull, { - isFullscreen: { - get() { - return !!document[fullscreenEvents && fullscreenEvents.fullscreenElement] - } - }, - element: { - enumerable: true, - get() { - return document[fullscreenEvents && fullscreenEvents.fullscreenElement] - } - }, - isEnabled: { - enumerable: true, - get() { - return !!document[fullscreenEvents && fullscreenEvents.fullscreenEnabled] - } - } -}) - -export default screenfull diff --git a/packages/mobile/utils/deps/infinite-scroll.ts b/packages/mobile/utils/deps/infinite-scroll.ts deleted file mode 100644 index bcb844586a..0000000000 --- a/packages/mobile/utils/deps/infinite-scroll.ts +++ /dev/null @@ -1,223 +0,0 @@ -import throttle from './throttle' - -const CONTEXT_KEY = '@@infinitescrollContext' -const OBSERVER_CHECK_INTERVAL = 50 -const ATTR_DEFAULT_DELAY = 200 -const ATTR_DEFAULT_DISTANCE = 0 - -const attrs = { - delay: { type: Number, default: ATTR_DEFAULT_DELAY }, - disabled: { type: Boolean, default: false }, - distance: { type: Number, default: ATTR_DEFAULT_DISTANCE }, - immediate: { type: Boolean, default: true } -} - -const isNull = (val) => val === null - -const parseAttrValue = (attrVal, type, defaultVal) => { - if (isNull(attrVal)) return defaultVal - - if (type === Boolean) { - return attrVal !== 'false' - } else if (type === Number) { - return Number(attrVal) - } -} - -const computeScrollOptions = (el, instance) => - Object.entries(attrs).reduce((accumulator, [name, option]) => { - const { type, default: defaultValue } = option - const attrKey = `infinite-scroll-${name}` - const $attrValue = instance.$el.getAttribute(attrKey) - const attrValue = el.getAttribute(attrKey) - let value - - if ((isNull(attrValue) && isNull($attrValue)) || !isNull(attrValue)) { - value = parseAttrValue(attrValue, type, defaultValue) - } - - if (isNull(attrValue) && !isNull($attrValue)) { - value = parseAttrValue($attrValue, type, defaultValue) - } - - accumulator[name] = Number.isNaN(value) ? defaultValue : value - - return accumulator - }, {}) - -const stopObserver = (el) => { - const { observer } = el[CONTEXT_KEY] - - if (observer) { - observer.disconnect() - delete el[CONTEXT_KEY].observer - } -} - -const accumOffsetTop = (el) => { - let totalOffset = 0 - let parent = el - - while (parent) { - totalOffset += parent.offsetTop - parent = parent.offsetParent - } - - return totalOffset -} - -const distanceOffsetTop = (el, containerEl) => Math.abs(accumOffsetTop(el) - accumOffsetTop(containerEl)) - -const scroller = (el, cb) => { - const { container, containerEl, instance, observer, lastScrollTop } = el[CONTEXT_KEY] - const { disabled, distance } = computeScrollOptions(el, instance) - const { clientHeight, scrollHeight, scrollTop } = containerEl - const deltaTop = scrollTop - lastScrollTop - - el[CONTEXT_KEY].lastScrollTop = scrollTop - - if (observer || disabled || deltaTop < 0) return - - let isTrigger = false - - if (container === el) { - isTrigger = scrollHeight - (clientHeight + scrollTop) <= distance - } else { - const { clientTop, scrollHeight: height } = el - const offsetTop = distanceOffsetTop(el, containerEl) - - isTrigger = scrollTop + clientHeight >= offsetTop + clientTop + height - distance - } - - if (isTrigger) { - cb.call(instance) - } -} - -function observerChecker(el, cb) { - const { containerEl, instance } = el[CONTEXT_KEY] - const { disabled } = computeScrollOptions(el, instance) - - if (disabled || containerEl.clientHeight === 0) return - - if (containerEl.scrollHeight <= containerEl.clientHeight) { - cb.call(instance) - } else { - stopObserver(el) - } -} - -const cached = (fn) => { - const cache = Object.create(null) - return (str) => cache[str] || (cache[str] = fn(str)) -} - -const camelizeRE = /-(\w)/g - -const camelize = cached((str) => str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''))) - -/** TINY_DUP dom.ts */ -const getElementStyle = (elem, styleKey) => { - if (!elem || !styleKey) return '' - - let key = camelize(styleKey) - - if (key === 'float') key = 'cssFloat' - - try { - const styleValue = elem.style[key] - - if (styleValue) return styleValue - - const computedStyle = document.defaultView ? document.defaultView.getComputedStyle(elem, '') : null - - return computedStyle ? computedStyle[key] : '' - } catch (e) { - return elem.style[key] - } -} -/** TINY_DUP dom.ts */ -const canScroll = (el, isVertical) => { - const overflowKey = { undefined: 'overflow', true: 'overflow-y', false: 'overflow-x' }[String(isVertical)] - const overflowVal = getElementStyle(el, overflowKey) - return ['scroll', 'auto', 'overlay'].some((s) => overflowVal.includes(s)) -} -/** TINY_DUP dom.ts */ -export const getScrollContainer = (el, isVertical) => { - let parentEl = el - - while (parentEl) { - if ([window, document, document.documentElement].includes(parentEl)) return window - - if (canScroll(parentEl, isVertical)) return parentEl - - parentEl = parentEl.parentNode - } - - return parentEl -} - -const bind = (el, binding, vnode) => { - const instance = binding.instance || vnode.context - const { value: cb } = binding - - if (typeof cb !== 'function') { - throw new TypeError('[TINY Error][InfiniteScroll] "v-infinite-scroll" binding value must be a function') - } - - instance.$nextTick(() => { - const { delay, immediate } = computeScrollOptions(el, instance) - const container = getScrollContainer(el, true) - const containerEl = container === window ? document.documentElement : container - const onScroll = throttle(delay, scroller.bind(null, el, cb)) - - if (!container) return - - el[CONTEXT_KEY] = { instance, container, containerEl, delay, cb, onScroll, lastScrollTop: containerEl.scrollTop } - - if (immediate) { - const observer = new MutationObserver(throttle(OBSERVER_CHECK_INTERVAL, observerChecker.bind(null, el, cb))) - - el[CONTEXT_KEY].observer = observer - - observer.observe(el, { childList: true, subtree: true }) - - observerChecker(el, cb) - } - - container.addEventListener('scroll', onScroll) - }) -} - -const update = (el, binding, vnode) => { - if (!el[CONTEXT_KEY]) { - const instance = binding.instance || vnode.context - - return instance.$nextTick() - } else { - const { containerEl, cb, observer } = el[CONTEXT_KEY] - - if (containerEl.clientHeight && observer) { - observerChecker(el, cb) - } - } -} - -const unbind = (el) => { - const { container, onScroll } = el[CONTEXT_KEY] - - if (container) container.removeEventListener('scroll', onScroll) - - stopObserver(el) -} - -const InfiniteScroll = { - bind, - update, - unbind, - beforeMount: bind, - updated: update, - unmounted: unbind -} - -export default InfiniteScroll diff --git a/packages/mobile/utils/deps/letter-only.ts b/packages/mobile/utils/deps/letter-only.ts deleted file mode 100644 index c838b572b5..0000000000 --- a/packages/mobile/utils/deps/letter-only.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { on, off } from './dom' - -/** - * v-letter-only - * @desc 只接受输入非数字字符 - * @example - * ```html - * - * ``` - */ -const checkValue = (event) => { - if (event.charCode >= 48 && event.charCode <= 57) { - event.preventDefault() - } - - return true -} - -export default { - bind(element) { - on(element, 'keypress', checkValue) - }, - unbind(element) { - off(element, 'keypress', checkValue) - } -} diff --git a/packages/mobile/utils/deps/memorize.ts b/packages/mobile/utils/deps/memorize.ts deleted file mode 100644 index b15e81729a..0000000000 --- a/packages/mobile/utils/deps/memorize.ts +++ /dev/null @@ -1,162 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -class Memorize { - constructor(value, options = {}) { - if (value && typeof value === 'object') { - options = value - } else { - value = [] - } - - if (typeof options.key !== 'string' || !options.key) { - throw new Error('Memorize Initialization error.') - } - - this._prefix = 'tiny_memorize_' - this._customField1 = 'frequency' - this._customField2 = 'time' - this._sortBy = (options.sortBy || 'frequency').toUpperCase() - this._sort = (options.sort || 'desc').toUpperCase() - this._dataKey = options.dataKey || 'value' - this._highlightClass = options.highlightClass || 'memorize-highlight' - this._highlightNum = options.highlightNum || Infinity - this._cacheNum = options.cacheNum || Infinity - this._serialize = options.serialize || JSON.stringify - this._deserialize = options.deserialize || JSON.parse - this.setKey(options.key) - this.assemble(value) - } - - setKey(storeKey) { - this._storeKey = this._prefix + (storeKey || Number(new Date())) - } - - getValue(isSort = true) { - const storeVlue = window.localStorage[this._storeKey] || '' - - if (storeVlue) { - try { - const list = this._deserialize(storeVlue) - return isSort ? this.sort(list) : list - } catch (e) { - return [] - } - } - - return [] - } - - setValue(value) { - try { - window.localStorage.setItem(this._storeKey, this._serialize(value)) - } catch (e) { - throw new Error('Memorize set localStorage error.') - } - } - - clear() { - window.localStorage.removeItem(this._storeKey) - } - - add(dataKey) { - const list = this.getValue(false) - const newData = { - key: dataKey - } - - newData[this._customField1] = 1 - newData[this._customField2] = Number(new Date()) - - if (list.length < this._cacheNum) { - list.push(newData) - this.setValue(list) - } - } - - updateByKey(dataKey) { - let isChanged = false - const list = this.getValue(false) - - list.some((item) => { - if (item.key === dataKey) { - item[this._customField1] = (item[this._customField1] || 0) + 1 - item[this._customField2] = Number(new Date()) - isChanged = true - - return true - } - - return false - }) - - isChanged ? this.setValue(list) : this.add(dataKey) - } - - sort(list) { - if (Array.isArray(list)) { - return list.sort((x, y) => { - const isDesc = this._sort === 'DESC' - const compare = isDesc ? [-1, 1] : [1, -1] - - const sortField = this._sortBy === 'FREQUENCY' ? this._customField1 : this._customField2 - - const xField = x[sortField] - const yField = y[sortField] - - if (isNaN(xField)) { - return isDesc ? -1 : 1 - } else if (isNaN(yField)) { - return -1 - } - - return xField > yField ? compare[0] : compare[1] - }) - } else { - return list - } - } - - assemble(list) { - const storeValue = this.getValue(true) - if (!(Array.isArray(list) && list.length) || !storeValue.length) { - return list - } - - let matchCount = 0 - const handler = (storeItem) => (listItem, index) => { - if (listItem[this._dataKey] === storeItem.key) { - matchCount++ - list.splice(index, 1) - - if (matchCount <= this._highlightNum) { - listItem._highlightClass = this._highlightClass - } - - list.unshift(listItem) - - return true - } - - return false - } - - for (let i = storeValue.length - 1; i > -1; i--) { - const storeItem = storeValue[i] - list.some(handler(storeItem)) - } - - return list - } -} - -export default Memorize diff --git a/packages/mobile/utils/deps/number-only.ts b/packages/mobile/utils/deps/number-only.ts deleted file mode 100644 index 9f02c53a2b..0000000000 --- a/packages/mobile/utils/deps/number-only.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { on, off } from './dom' - -/** - * v-number-only - * @desc 只接受输入数字 - * @example - * ```html - * - * ``` - */ -const checkValue = (event) => { - event.target.value = event.target.value.replace(/[^0-9]/g, '') - - if (event.charCode >= 48 && event.charCode <= 57) { - return true - } - - event.preventDefault() -} - -export default { - bind(element) { - on(element, 'keypress', checkValue) - }, - unbind(element) { - off(element, 'keypress', checkValue) - } -} diff --git a/packages/mobile/utils/deps/observe-visibility.ts b/packages/mobile/utils/deps/observe-visibility.ts deleted file mode 100644 index edbc3acced..0000000000 --- a/packages/mobile/utils/deps/observe-visibility.ts +++ /dev/null @@ -1,130 +0,0 @@ -import throttle from './throttle' -import { isEqual } from '../object' - -const CONTEXT_KEY = '@@observevisibilityContext' - -const processOptions = (value) => { - let options - - if (typeof value === 'function') { - options = { callback: value } - } else { - options = value - } - - return options -} - -const createObserver = ({ options, instance, state }) => { - if (state.observer) { - destroyObserver(state) - } - - if (state.frozen) return - - state.options = processOptions(options) - state.callback = (result, entry) => { - state.options.callback(result, entry) - - if (result && state.options.once) { - state.frozen = true - destroyObserver(state) - } - } - - if (state.callback && state.options.throttle) { - state.callback = throttle(state.options.throttleDelay || 20, state.callback) - } - - state.observer = new IntersectionObserver((entries) => { - let entry = entries[0] - - if (entries.length > 1) { - const intersectingEntry = entries.find((e) => e.isIntersecting) - - if (intersectingEntry) { - entry = intersectingEntry - } - } - - if (state.callback) { - state.callback(entry.isIntersecting, entry) - } - }, state.options.intersection) - - instance.$nextTick(() => { - if (state.observer) { - state.observer.observe(state.el) - } - }) -} - -const destroyObserver = (state) => { - if (state.observer) { - state.observer.disconnect() - state.observer = null - } - - if (state.callback) { - state.callback = null - } -} - -const createVisibilityState = ({ el, options, instance }) => { - const state = { el, observer: null, frozen: false } - - createObserver({ options, instance, state }) - - return state -} - -const bind = (el, { value, instance }, { context }) => { - if (!value) return - - if (typeof IntersectionObserver === 'undefined') { - throw new TypeError('[TINY Error][ObserveVisibility] IntersectionObserver API is not available in your browser') - } else { - instance = instance || context - - el[CONTEXT_KEY] = createVisibilityState({ el, options: value, instance }) - } -} - -const update = (el, { value, oldValue, instance }, { context }) => { - if (isEqual(value, oldValue)) return - - const state = el[CONTEXT_KEY] - - if (!value) { - unbind(el) - return - } - - instance = instance || context - - if (state) { - createObserver({ options: value, instance, state }) - } else { - bind(el, { value, instance }, { context }) - } -} - -const unbind = (el) => { - const state = el[CONTEXT_KEY] - - if (state) { - destroyObserver(state) - delete el[CONTEXT_KEY] - } -} - -const ObserveVisibility = { - bind, - update, - unbind, - beforeMount: bind, - updated: update, - unmounted: unbind -} - -export default ObserveVisibility diff --git a/packages/mobile/utils/deps/popper.ts b/packages/mobile/utils/deps/popper.ts deleted file mode 100644 index f2bdd41766..0000000000 --- a/packages/mobile/utils/deps/popper.ts +++ /dev/null @@ -1,883 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { on, off, isDisplayNone } from './dom' -import PopupManager from './popup-manager' -import globalConfig from '../global' -import { typeOf } from '../type' - -const positions = ['left', 'right', 'top', 'bottom'] -const modifiers = ['shift', 'offset', 'preventOverflow', 'keepTogether', 'arrow', 'flip', 'applyStyle'] - -const DEFAULTS = { - arrowOffset: 0, - arrowElement: '[x-arrow]', - boundariesElement: 'viewport', - boundariesPadding: 5, - flipBehavior: 'flip', // 全局没有修改过它,所以它一直是flip - forceAbsolute: false, - gpuAcceleration: true, - offset: 0, - placement: 'bottom', - preventOverflowOrder: positions, - modifiers, // 此处是string数组, 构造函数调用之后转为函数数组 - updateHiddenPopperOnScroll: false // 滚动过程中是否更新隐藏的弹出层位置 -} - -/** 用 styles 对象赋值el.style */ -const setStyle = (el: HTMLElement, styles: object) => { - const isNumeric = (n) => n !== '' && !isNaN(parseFloat(n)) && isFinite(n) - - Object.keys(styles).forEach((prop) => { - let unit = '' - - if (~['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) && isNumeric(styles[prop])) { - unit = 'px' - } - - el.style[prop] = styles[prop] + unit - }) -} - -/** 查找el的 offsetParent ,找不到则默认为 */ -const getOffsetParent = (el: HTMLElement) => { - let offsetParent = el.offsetParent as HTMLElement - - return offsetParent === window.document.body || !offsetParent ? window.document.documentElement : offsetParent -} - -/** 查找基本元素的计算属性值 */ -const getStyleComputedProperty = (el: HTMLElement, property: string) => { - if (!el || el.nodeType !== 1) { - return - } - - let css = window.getComputedStyle(el, null) - - return css[property] -} - -/** 向上查找,判断是不是某一层级有fixed */ -const isFixed = (el: HTMLElement) => { - if (el === window.document.body) { - return false - } - - if (getStyleComputedProperty(el, 'position') === 'fixed') { - return true - } - - return el.parentNode ? isFixed(el.parentNode as HTMLElement) : false -} - -/** 在页面上的相对视口位置。 也就是说滚动条会影响它的值 */ -const getBoundingClientRect = (el: HTMLElement) => { - let rect = el.getBoundingClientRect() - - return { - left: rect.left, - top: rect.top, - right: rect.right, - bottom: rect.bottom, - width: rect.right - rect.left, - height: rect.bottom - rect.top - } -} - -/** 判断el的overflow是不是可能滚动的 */ -const isScrollElement = (el: HTMLElement) => { - const scrollTypes = ['scroll', 'auto'] - - return ( - scrollTypes.includes(getStyleComputedProperty(el, 'overflow')) || - scrollTypes.includes(getStyleComputedProperty(el, 'overflow-x')) || - scrollTypes.includes(getStyleComputedProperty(el, 'overflow-y')) - ) -} - -/** 设置transform等样式后,fixed定位不再相对于视口,使用1X1PX透明元素获取fixed定位相对于视口的修正偏移量。 */ -const getAdjustOffset = (parent: HTMLElement) => { - const placeholder = document.createElement('div') - setStyle(placeholder, { - opacity: 0, - position: 'fixed', - width: 1, - height: 1, - top: 0, - left: 0, - 'z-index': '-99' - }) - parent.appendChild(placeholder) - const result = getBoundingClientRect(placeholder) - parent.removeChild(placeholder) - return result -} - -/** 查找滚动父元素,只找第一个就返回 */ -export const getScrollParent: (el: HTMLElement) => HTMLElement = (el) => { - let parent = el.parentNode - - if (!parent) { - return el - } - - if (parent === window.document) { - if (window.document.body.scrollTop || window.document.body.scrollLeft) { - return window.document.body as HTMLElement - } - return window.document.documentElement - } - - if (isScrollElement(parent as any)) { - return parent as HTMLElement - } - - return getScrollParent(parent as any) -} - -/** 计算 el 在父元素中的定位 */ -const getOffsetRectRelativeToCustomParent = ( - el: HTMLElement, - parent: HTMLElement, - fixed: boolean, - popper: HTMLElement -) => { - let { top, left, width, height } = getBoundingClientRect(el) - - // 如果是fixed定位,需计算要修正的偏移量。 - if (fixed) { - if (popper.parentElement) { - const { top: adjustTop, left: adjustLeft } = getAdjustOffset(popper.parentElement) - top -= adjustTop - left -= adjustLeft - } - return { - top, - left, - bottom: top + height, - right: left + width, - width, - height - } - } - - let parentRect = getBoundingClientRect(parent) - let rect = { - top: top - parentRect.top, - left: left - parentRect.left, - bottom: top - parentRect.top + height, - right: left - parentRect.left + width, - width, - height - } - - return rect -} - -const getScrollTopValue = (el: HTMLElement) => - el === document.body ? Math.max(document.documentElement.scrollTop, document.body.scrollTop) : el.scrollTop - -const getScrollLeftValue = (el: HTMLElement) => - el === document.body ? Math.max(document.documentElement.scrollLeft, document.body.scrollLeft) : el.scrollLeft - -const getMaxWH = (body, html) => { - const height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight) - const width = Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth) - return { width, height } -} - -/** 计算元素的margin盒子的大小 */ -const getOuterSizes = (el: HTMLElement) => { - let _display = el.style.display - let _visibility = el.style.visibility - - el.style.display = 'block' - el.style.visibility = 'hidden' - - let styles = window.getComputedStyle(el) - let x = parseFloat(styles.marginTop) + parseFloat(styles.marginBottom) - let y = parseFloat(styles.marginLeft) + parseFloat(styles.marginRight) - let result = { width: el.offsetWidth + y, height: el.offsetHeight + x } - - el.style.display = _display - el.style.visibility = _visibility - - return result -} - -/** 把字符串位置替换为反方向, 例如: left替换为right */ -const getOppositePlacement = (placement: string) => { - let hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' } - - return placement.replace(/left|right|bottom|top/g, (matched) => hash[matched]) -} - -/** 克隆popperOffsets,并补上 right,bottom的值 */ -const getPopperClientRect = (popperOffsets: PopperOffsets) => { - let offsets = { ...popperOffsets } - - offsets.right = offsets.left + offsets.width - offsets.bottom = offsets.top + offsets.height - - return offsets -} - -/** 收集所有的带scroll的父元素到一个数组中 */ -const getAllScrollParents: (el: HTMLElement, parents?: HTMLElement[]) => HTMLElement[] = ( - el: HTMLElement, - parents = [] as HTMLElement[] -) => { - const parent = el.parentNode as HTMLElement - - if (parent) { - isScrollElement(parent) && parents.push(parent) - // 如果祖先元素是fixed,则不再继续往上查找 - if (getStyleComputedProperty(parent, 'position') === 'fixed') { - return parents - } - return getAllScrollParents(parent, parents) as HTMLElement[] - } - - return parents -} - -/** 返回当前元素的offset值 */ -const getOffsetRect = (el: HTMLElement) => { - const elementRect = { - width: el.offsetWidth, - height: el.offsetHeight, - left: el.offsetLeft, - top: el.offsetTop, - right: 0, - bottom: 0 - } - - elementRect.right = elementRect.left + elementRect.width - elementRect.bottom = elementRect.top + elementRect.height - - return elementRect -} - -const stopFn = (ev: Event) => { - ev.stopPropagation() -} -interface PopperOptions { - arrowOffset: number - arrowElement: string - boundariesElement: string | HTMLElement - boundariesPadding: number - flipBehavior: string - forceAbsolute: boolean - gpuAcceleration: boolean - offset: number - placement: string - preventOverflowOrder: string[] - modifiers: string[] - modifierFns: Function[] // 区分2个modifiers变量 - removeOnDestroy?: boolean // destory时,是否移除popper dom - bubbling?: boolean // 是否给所有祖先的scroll都监听上 - adjustArrow?: boolean // 是否校正。 只有tooltip使用它个属性了 -} -interface PopperState { - position: 'absolute' | 'fixed' - updateCallback?: (data: UpdateData) => void - scrollTarget: HTMLElement | null - scrollTargets: HTMLElement[] | null - updateBoundFn: () => void - scrollUpdate: () => void -} - -interface ReferenceOffsets { - top: number - left: number - bottom: number - right: number - width: number - height: number -} -export interface PopperOffsets { - position: 'absolute' | 'fixed' - top: number - left: number - bottom: number - right: number - width: number - height: number -} -interface arrowOffsets { - top: number - left: number -} -/** update时的data变量 */ -export interface UpdateData { - instance: Popper - styles: {} - placement: string - _originalPlacement: string - - offsets: { - popper: PopperOffsets - reference: ReferenceOffsets - arrow?: arrowOffsets - } - arrowElement: HTMLElement - - boundaries: { - right: number - left: number - top: number - bottom: number - } - flipped?: boolean -} -/** Popper 类是用于处理 reference 和 popper 两个dom,让popper悬浮的功能 - * 调用后就popper就'absolute' | 'fixed' 定位,并立即计算一次popper后的位置,并绑定scroll 和 resize事件! - */ -class Popper { - _reference: HTMLElement - _popper: HTMLElement - state: PopperState - _options: PopperOptions - modifiers: Record = {} - /** 每次update, 计算popper的大小并缓存 */ - popperOuterSize = null as unknown as { width: number; height: number } - - constructor(reference: HTMLElement, popper: HTMLElement, options: PopperOptions) { - this._reference = reference - this._popper = popper - this.state = {} as PopperState - - this._options = { ...DEFAULTS, ...options } as any - - this._options.modifierFns = modifiers.map((modifier) => { - return this[modifier] - }) - this._popper.setAttribute('x-placement', this._options.placement) - - this.state.position = this._getPopperPositionByRefernce(this._reference) - - setStyle(this._popper, { position: this.state.position, top: 0 }) - - this.update() - this._setupEventListeners() - } - - destroy() { - this._popper.removeAttribute('x-placement') - - // 记录 _oldreference 就是为了保留之前的top,left, 但必要性并不大,因为此时强行把popper给display:none了。 - // 它的位置也并不重要了。 所以 _oldreference TINY_NO_NEED - // const popperStyle = (this._reference === this._oldreference && this._oldreference._popper) || {} - - this._popper.style.display = 'none' - // this._popper.style.position = '' - // this._popper.style.top = popperStyle.top || '' - // this._popper.style.left = popperStyle.left || '' - // this._popper.style.transform = '' - this._removeEventListeners() - - /** 只有示例中,用到这个属性了。 由于8个组件默认值没有用,所以默认popper是display:none的状态,留在了页面上 */ - this._options.removeOnDestroy && this._popper.remove() - - return this - } - - onUpdate(callback) { - this.state.updateCallback = callback - return this - } - - update() { - let data = { instance: this, styles: {} } as unknown as UpdateData - - this.stopEventBubble() // 每次更新都检查 - - this.popperOuterSize = null as unknown as { width: number; height: number } - data.placement = data._originalPlacement = this._options.placement - data.offsets = this._getRefPopOffsets(this._popper, this._reference, data.placement) - - data.boundaries = this._getBoundaries(data, this._options.boundariesPadding, this._options.boundariesElement) - - data = this.runModifiers(data, this._options.modifierFns) - - typeof this.state.updateCallback === 'function' && this.state.updateCallback(data) - } - - // 阻止popper的mousewheel等事件冒泡。 通过 onxxx 绑定,是为了避免重复绑定事件 - stopEventBubble() { - if (!this._popper) return - - if (!this._popper.onmousewheel) this._popper.onmousewheel = stopFn // onmousewheel 是非标准属性 - if (!this._popper.onwheel) this._popper.onwheel = stopFn - } - - /** 按顺序执行Modifiers, 如果传入终点modifier,则执行到指定位置 */ - runModifiers(data: UpdateData, modifiers: Function[], ends?: Function) { - let modifiersToRun = modifiers.slice() - const _options = this._options - - if (ends !== undefined) { - modifiersToRun = this._options.modifierFns.slice( - 0, - _options.modifierFns.findIndex((m) => m === ends) - ) - } - - modifiersToRun.forEach((modifier) => { - if (typeOf(modifier) === 'function') { - data = modifier.call(this, data) - } - }) - - return data - } - - // 此时才把offsets.popper 赋值给popper dom, offsets.array赋值给array dom - applyStyle(data: UpdateData) { - let styles: any = { position: data.offsets.popper.position } - let left = Math.round(data.offsets.popper.left) - let top = Math.round(data.offsets.popper.top) - - // 加速模式时,使用transform, 否则使用left,top - if (this._options.gpuAcceleration) { - styles.transform = `translate3d(${left}px, ${top}px, 0)` - Object.assign(styles, { top: 0, left: 0 }) - } else { - Object.assign(styles, { top, left }) - } - - Object.assign(styles, data.styles) - - setStyle(this._popper, styles) - - this._popper.setAttribute('x-placement', data.placement) - - if (data.offsets.arrow) { - setStyle(data.arrowElement, data.offsets.arrow) - } - - return data - } - - // 判断 placement是不是2段式的,是则处理一下偏移。 修改data.offsets.popper的值 - shift(data: UpdateData) { - let placement = data.placement - let basePlacement = placement.split('-')[0] - let shiftVariation = placement.split('-')[1] - - if (shiftVariation) { - let { top, left, height, width } = data.offsets.reference - let popper = getPopperClientRect(data.offsets.popper) - - let shiftOffsets = { - y: { - start: { top }, - end: { top: top + height - popper.height } - }, - x: { - start: { left }, - end: { left: left + width - popper.width } - } - } - - let axis = ~['bottom', 'top'].indexOf(basePlacement) ? 'x' : 'y' - - data.offsets.popper = Object.assign(popper, shiftOffsets[axis][shiftVariation]) - } - - return data - } - - // 校正popper的位置在boundaries 的内部 - preventOverflow(data: UpdateData) { - let order = this._options.preventOverflowOrder - let popper = getPopperClientRect(data.offsets.popper) - - let check = { - top: () => { - let { top } = popper - - if (top < data.boundaries.top) { - top = Math.max(top, data.boundaries.top) - } - - return { top } - }, - right: () => { - let { left } = popper - - if (popper.right > data.boundaries.right) { - left = Math.min(left, data.boundaries.right - popper.width) - } - - return { left } - }, - bottom: () => { - let { top } = popper - - if (popper.bottom > data.boundaries.bottom) { - top = Math.min(top, data.boundaries.bottom - popper.height) - } - - return { top } - }, - left: () => { - let { left } = popper - - if (popper.left < data.boundaries.left) { - left = Math.max(left, data.boundaries.left) - } - - return { left } - } - } - - order.forEach((direction) => { - data.offsets.popper = Object.assign(popper, check[direction]()) - }) - return data - } - - // 校正popper的位置在reference的边上。 如果2个分离了,重新调整popper的位置。 可能是担心 modifiers.offset 带来的副作用吧 - keepTogether(data: UpdateData) { - let popper = getPopperClientRect(data.offsets.popper) - let reference = data.offsets.reference - - if (popper.right < Math.floor(reference.left)) { - data.offsets.popper.left = Math.floor(reference.left) - popper.width - } - - if (popper.left > Math.floor(reference.right)) { - data.offsets.popper.left = Math.floor(reference.right) - } - - if (popper.bottom < Math.floor(reference.top)) { - data.offsets.popper.top = Math.floor(reference.top) - popper.height - } - - if (popper.top > Math.floor(reference.bottom)) { - data.offsets.popper.top = Math.floor(reference.bottom) - } - - return data - } - - // 根据flip的策略,计算当前应该显示的位置。 空间不够要计算出flip的位置。 可能是担心preventOverflow 时,造成pop, reference会重叠。 重叠了就要flip一下 - flip(data: UpdateData) { - // 只翻转一次,避免重复的flip - if (data.flipped && data.placement === data._originalPlacement) { - return data - } - - const placements = data.placement.split('-') - let placement = placements[0] - let placementOpposite = getOppositePlacement(placement) - let variation = placements[1] || '' - let flipOrderArr = [placement, placementOpposite] - - flipOrderArr.forEach((step, index) => { - if (placement !== step || flipOrderArr.length === index + 1) { - return - } - - placement = data.placement.split('-')[0] - placementOpposite = getOppositePlacement(placement) - - let popperOffsets = getPopperClientRect(data.offsets.popper) - // 变量起名不佳。 此处分2种情况: placement是right', 'bottom 或 left,top - let a = ~['right', 'bottom'].indexOf(placement) - let p = Math.floor(data.offsets.reference[placement]) - let po = Math.floor(popperOffsets[placementOpposite]) - - // 如果right, ref.right > pop.left - // bottom, ref.bottom > pop.top - // left, ref.left < pop.left - // top, ref.top < pop.bottom - // 则进行flip - if ((a && p > po) || (!a && p < po)) { - data.flipped = true - data.placement = flipOrderArr[index + 1] - - if (variation) { - data.placement += `-${variation}` - } - - data.offsets.popper = this._getRefPopOffsets(this._popper, this._reference, data.placement).popper - - data = this.runModifiers(data, this._options.modifierFns, this.flip) - } - }) - return data - } - - // 根据入参option上的offset, 给data.offset.popper进行校正 - offset(data: UpdateData) { - let offset = this._options.offset - let popper = data.offsets.popper - - if (~data.placement.indexOf('left')) { - popper.top -= offset - } else if (~data.placement.indexOf('right')) { - popper.top += offset - } else if (~data.placement.indexOf('top')) { - popper.left -= offset - } else if (~data.placement.indexOf('bottom')) { - popper.left += offset - } - - return data - } - - // 计算arrow的位置,保存在data.offsets.arrow ={top,left} - arrow(data: UpdateData) { - let arrow: string | HTMLElement = this._options.arrowElement // 小三角的dom - let arrowOffset = this._options.arrowOffset // 入参里的值,可能为 Infinity - - if (typeof arrow === 'string') { - arrow = this._popper.querySelector(arrow) as HTMLElement - } - - if (!arrow || !this._popper.contains(arrow)) { - return data - } - - let arrowStyle = {} as arrowOffsets - let placement = data.placement.split('-')[0] // 以下以 placement = right 为例 - let popper = getPopperClientRect(data.offsets.popper) // 整个popper的dom屏幕尺寸。(popper到底是right-start还是right-end,此时已经计算好了的。所以最后那里不需要校正) - let reference = data.offsets.reference // tiny-form-item__content 元素的屏幕尺寸。 不包含label - let isVertical = ~['left', 'right'].indexOf(placement) // true - let calcProp = isVertical ? 'height' : 'width' // calcProp:height - let opSide = isVertical ? 'bottom' : 'right' // opSide:bottom - let altSide = isVertical ? 'left' : 'top' // altSide:left left是无用的那个值 - let side = isVertical ? 'top' : 'left' // side:top - - let popperRect = this.popperOuterSize ? this.popperOuterSize : (this.popperOuterSize = getOuterSizes(this._popper)) // popper的大小 - let arrowRect = getOuterSizes(arrow) // arrow的大小 {height: 11,width: 5} - let arrowSize = arrowRect[calcProp] // 11 - - // 如果reference 比 popper 更靠上,则popper上移到 ref.bottom - arrowSize (上边缘对齐) - if (reference[opSide] - arrowSize < popper[side]) { - data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowSize) - } - // 如果reference 比 popper 更靠下,则popper下移到 ref.bottom + arrowSize(下边缘对齐) - if (reference[side] + arrowSize > popper[opSide]) { - data.offsets.popper[side] += reference[side] + arrowSize - popper[opSide] - } - // 如果arrowOffset有值,则center为ref的上边+arrowOffset。 此例arrowOffset为Infinity, center也为无穷大。 - let center = reference[side] + (arrowOffset || reference[calcProp] / 2 - arrowSize / 2) - let sideValue = center - popper[side] - - // 猜测是上下边距留下8px的距离。 确保箭头不太靠顶靠底。 - // 此时sideValue为“popper的顶- 箭头 - 8px” 的位置。 - sideValue = Math.max(Math.min(popper[calcProp] - arrowSize - 8, sideValue), 8) - arrowStyle[side] = sideValue - arrowStyle[altSide] = '' - - // adjustArrow此处还要校正一下,但不明白为什么只校正left, 不校正top的位置? - const params = this._options.placement.split('-') - if (this._options.adjustArrow && ~['top', 'bottom'].indexOf(params[0]) && side === 'left') { - if (params[1] === 'start') { - arrowStyle.left = 8 - } else if (!params[1]) { - arrowStyle.left = (popperRect.width - arrowRect.width) / 2 - } - } - - data.offsets.arrow = arrowStyle - data.arrowElement = arrow - - return data - } - - /** 判断 reference 的 offsetParent 元素是fix还是abs, 这个值会赋值给popper 的dom */ - _getPopperPositionByRefernce(reference: HTMLElement) { - if (this._options.forceAbsolute) { - return 'absolute' - } - - let isParentFixed = isFixed(reference) - return isParentFixed ? 'fixed' : 'absolute' - } - - /** 实时计算一下popper, reference的 位置信息, 用于 */ - _getRefPopOffsets(popper, reference, placement) { - placement = placement.split('-')[0] - let popperOffsets = { position: this.state.position } as PopperOffsets - - let isParentFixed = popperOffsets.position === 'fixed' - let referenceOffsets = getOffsetRectRelativeToCustomParent( - reference, - getOffsetParent(popper), - isParentFixed, - popper - ) - - // 利用 popperOuterSize 来减少一次outerSize的计算 - const { width, height } = this.popperOuterSize - ? this.popperOuterSize - : (this.popperOuterSize = getOuterSizes(popper)) - - if (~['right', 'left'].indexOf(placement)) { - popperOffsets.top = referenceOffsets.top + referenceOffsets.height / 2 - height / 2 - - if (placement === 'left') { - popperOffsets.left = referenceOffsets.left - width - } else { - popperOffsets.left = referenceOffsets.right - } - } else { - popperOffsets.left = referenceOffsets.left + referenceOffsets.width / 2 - width / 2 - - if (placement === 'top') { - popperOffsets.top = referenceOffsets.top - height - } else { - popperOffsets.top = referenceOffsets.bottom - } - } - - popperOffsets.width = width - popperOffsets.height = height - - return { - popper: popperOffsets, - reference: referenceOffsets - } - } - - _setupEventListeners() { - this.state.updateBoundFn = this.update.bind(this) - this.state.scrollUpdate = () => { - if (this._options.updateHiddenPopperOnScroll) { - this.state.updateBoundFn() - } else { - if (isDisplayNone(this._popper)) return - this.state.updateBoundFn() - } - } - - on(window, 'resize', this.state.updateBoundFn) - - if (this._options.boundariesElement !== 'window') { - let target: HTMLElement = getScrollParent(this._reference) - const customTargets = [] - - // 如果下拉框组件存在于多端表单中,需要同时监听上一层scroll元素的滚动 - if (target?.dataset?.tag?.includes('-form')) { - customTargets.push(target) - let realTarget = getScrollParent(target) - if (realTarget === window.document.body || realTarget === window.document.documentElement) { - realTarget = window as any - } - customTargets.push(realTarget) - } - - if (target === window.document.body || target === window.document.documentElement) { - target = window as any - } - - this.state.scrollTarget = target - - // 只有bubbling时,才启用所有祖先监听,根源在此。 getAll..Parents函数只有这一处调用 - if (this._options.bubbling || PopupManager.globalScroll) { - let targets = getAllScrollParents(this._reference) - - this.state.scrollTargets = targets || [] - targets.forEach((target) => { - on(target, 'scroll', this.state.scrollUpdate) - }) - } else { - if (customTargets.length) { - this.state.scrollTargets = customTargets - customTargets.forEach((target) => { - on(target, 'scroll', this.state.scrollUpdate) - }) - } else { - on(target, 'scroll', this.state.scrollUpdate) - } - } - } - } - - _removeEventListeners() { - off(window, 'resize', this.state.updateBoundFn) - - if (this._options.boundariesElement !== 'window' && this.state.scrollTarget) { - off(this.state.scrollTarget, 'scroll', this.state.scrollUpdate) - this.state.scrollTarget = null - - // 移除祖先监听 - if (this._options.bubbling || PopupManager.globalScroll) { - let targets = this.state.scrollTargets || [] - - targets.forEach((target) => { - off(target, 'scroll', this.state.scrollUpdate) - }) - this.state.scrollTargets = null - } - } - - this.state.updateBoundFn = null as any - this.state.scrollUpdate = null as any - } - - /** 实时计算一下Boundary的位置 */ - _getBoundaries(data: UpdateData, padding: number, boundariesElement: string | HTMLElement) { - let boundaries = { right: 0, left: 0, top: 0, bottom: 0 } - - if (boundariesElement === 'window' || boundariesElement === 'body') { - let body = window.document.body - let html = window.document.documentElement - let { width, height } = getMaxWH(body, html) - - boundaries = { top: 0, right: width, bottom: height, left: 0 } - } else if (boundariesElement === 'viewport') { - let offsetParent = getOffsetParent(this._popper) - let scrollParent = getScrollParent(this._popper) - let offsetParentRect = getOffsetRect(offsetParent) - let isFixed = data.offsets.popper.position === 'fixed' - const noScroll = isFixed || (!this._options.appendToBody && ['right', 'left'].includes(this._options.placement)) - let scrollTop = noScroll ? 0 : getScrollTopValue(scrollParent) - let scrollLeft = noScroll ? 0 : getScrollLeftValue(scrollParent) - - // PopupManager.viewportWindow是为了兼容之前已经采用此方法兼容微前端的用户,后续需要采用globalConfig.viewportWindow - const viewportWindow = globalConfig.viewportWindow || PopupManager.viewportWindow || window - boundaries = { - top: 0 - (offsetParentRect.top - scrollTop), - right: viewportWindow.document.documentElement.clientWidth - (offsetParentRect.left - scrollLeft), - bottom: viewportWindow.document.documentElement.clientHeight - (offsetParentRect.top - scrollTop), - left: 0 - (offsetParentRect.left - scrollLeft) - } - } else { - if (getOffsetParent(this._popper) === boundariesElement) { - const { clientWidth, clientHeight } = boundariesElement - - boundaries = { - right: clientWidth, - bottom: clientHeight, - top: 0, - left: 0 - } - } else { - boundaries = getOffsetRect(boundariesElement as HTMLElement) - } - } - - boundaries.right -= padding - boundaries.left += padding - boundaries.bottom = boundaries.bottom - padding - boundaries.top = boundaries.top + padding - - return boundaries - } -} - -export default Popper diff --git a/packages/mobile/utils/deps/popup-manager.ts b/packages/mobile/utils/deps/popup-manager.ts deleted file mode 100644 index 1295304e1c..0000000000 --- a/packages/mobile/utils/deps/popup-manager.ts +++ /dev/null @@ -1,262 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { KEY_CODE } from '../index' -import { addClass, removeClass, on } from './dom' - -const isServer = typeof window === 'undefined' - -const instances = {} as Record - -const classes = { - leave: 'v-modal-leave', - enter: 'v-modal-enter', - modal: 'v-modal' -} -export interface IModalStack { - id: string - zIndex: number - modalClass: string -} -const removeStack = (modalStack: IModalStack[], id: string) => { - for (let i = modalStack.length - 1; i >= 0; i--) { - if (modalStack[i].id === id) { - modalStack.splice(i, 1) - break - } - } -} - -/** 判断PopupManager.modalDom 是否有。 没有则创建一个div, 并绑上 touchmove, click */ -let getModal: () => HTMLElement - -const PopupManager = { - step: 2, - zIndex: 2000, - globalScroll: false, // 是否打开全局滚动监听 - modalFade: true, - modalStack: [] as IModalStack[], - modalDom: null as unknown as HTMLElement, // 当前model挂载的div. - hasModal: false, // 当前是否有Modal - popLockClass: 'popup-parent--hidden', - oldBodyBorder: '', - viewportWindow: null, - fixBodyBorder() { - const barWidth = window.innerWidth - document.documentElement.clientWidth - if (barWidth) { - this.oldBodyBorder = document.documentElement.style.borderRight - document.body.style.borderRight = `${barWidth}px solid transparent` - } - }, - resetBodyBorder() { - document.body.style.borderRight = this.oldBodyBorder - this.oldBodyBorder = '' - }, - /** 全局反注册 */ - deregister: (id: string) => { - if (id) { - instances[id] = null - delete instances[id] - } - }, - /** 返回全局实例 */ - getInstance: (id: string) => instances[id], - /** 全局注册 仅vue-popup.ts中使用,instance就是vm, 把vm注册到 vm._popupId 这个键值上 */ - register: (id: string, instance: any) => { - if (id && instance) { - instances[id] = instance - } - }, - nextZIndex: () => { - const zIndex = PopupManager.zIndex - PopupManager.zIndex += PopupManager.step - return zIndex - }, - /** 打开遮罩层, 仅vue-popup.ts中使用。 dom = vm.$el 或者 undefined (appendtoBody时) */ - openModal(id: string, zIndex: number, dom: HTMLElement | undefined, modalClass: string, modalFade: boolean) { - if (isServer) { - return - } - if (!id || zIndex === undefined) { - return - } - - this.modalFade = modalFade - - // 查找stack中,是否已经有id。 有了就直接退出函数 - for (let i = 0, len = this.modalStack.length; i < len; i++) { - const modal = this.modalStack[i] - - if (modal.id === id) { - return - } - } - - // 查询或创建一个modalDom----遮罩层, 为其赋值所有class ,style - const modalDom = getModal() - - addClass(modalDom, classes.modal) - - if (this.modalFade && !PopupManager.hasModal) { - addClass(modalDom, classes.enter) - } - - if (modalClass) { - const classArr = modalClass.trim().split(/\s+/) - classArr.forEach((cls) => addClass(modalDom, cls)) - } - - setTimeout(() => { - removeClass(modalDom, classes.enter) - }, 200) - - if (zIndex) { - modalDom.style.zIndex = zIndex.toString() - } - - modalDom.style.display = '' - modalDom.tabIndex = 0 - - // 查找父节点, - let parentNode - - if (dom && dom.parentNode && dom.parentNode.nodeType !== 11) { - // fragment = 11 - parentNode = dom.parentNode - } else { - parentNode = document.body - } - - parentNode.appendChild(modalDom) - - this.modalStack.push({ id, zIndex, modalClass }) - }, - /** 点击背景遮罩层时,调用栈顶的popup,调用它的close() */ - doOnModalClick: () => { - const modalStack = PopupManager.modalStack - const topPopup = modalStack[modalStack.length - 1] - if (!topPopup) { - return - } - - const instance = PopupManager.getInstance(topPopup.id) - if (instance && instance.closeOnClickModal) { - typeof instance.close === 'function' && instance.close() - } - }, - closeModal(id: string) { - const modalStack = this.modalStack - const modalDom = getModal() - - if (modalStack.length > 0) { - const topPopup = modalStack[modalStack.length - 1] - - if (topPopup.id === id) { - if (topPopup.modalClass) { - const classArr = topPopup.modalClass.trim().split(/\s+/) - classArr.forEach((cls) => removeClass(modalDom, cls)) - } - - modalStack.pop() - - const stackSize = modalStack.length - - if (stackSize > 0) { - modalDom.style.zIndex = modalStack[stackSize - 1].zIndex.toString() - } - } else { - removeStack(modalStack, id) - } - } - - if (modalStack.length === 0) { - this.modalFade && addClass(modalDom, classes.leave) - removeClass(document.body, this.popLockClass) - this.resetBodyBorder() - - setTimeout(() => { - if (modalStack.length === 0) { - if (modalDom.parentNode) { - modalDom.parentNode.removeChild(modalDom) - } - - modalDom.style.display = 'none' - PopupManager.modalDom = null as unknown as HTMLElement - } - - removeClass(modalDom, classes.leave) - }, 200) - } - } -} - -getModal = () => { - if (isServer) { - return null as unknown as HTMLElement - } - - let modalDom: HTMLElement = PopupManager.modalDom as any - - if (modalDom) { - PopupManager.hasModal = true - } else { - PopupManager.hasModal = false - modalDom = document.createElement('div') - PopupManager.modalDom = modalDom - - // 屏蔽touch, - modalDom.addEventListener( - 'touchmove', - (event) => { - event.preventDefault() - event.stopPropagation() - }, - { passive: true } - ) - - on(modalDom, 'click', () => { - PopupManager.doOnModalClick() - }) - } - - return modalDom -} - -if (!isServer) { - // 点esc时,关闭栈顶Popup。 也就是说组件内不用关心esc了, 这里统一接管了 - on(window, 'keydown', (event: KeyboardEvent) => { - if (event.keyCode === KEY_CODE.Escape) { - const modalStack = PopupManager.modalStack - - if (modalStack.length > 0) { - const topPopup = modalStack[modalStack.length - 1] - if (!topPopup) { - return - } - const topPopupVm = PopupManager.getInstance(topPopup.id) - - // 只有Dialog-box有 closeOnPressEscape , 所以它只是为 Dialog-box 服务 - if (topPopupVm && topPopupVm.closeOnPressEscape) { - if (topPopupVm.handleClose) { - topPopupVm.handleClose('esc') - } else if (topPopupVm.handleAction) { - topPopupVm.handleAction('cancel') - } else { - topPopupVm.close() - } - } - } - } - }) -} - -export default PopupManager diff --git a/packages/mobile/utils/deps/repeat-click.ts b/packages/mobile/utils/deps/repeat-click.ts deleted file mode 100644 index 76953bd37c..0000000000 --- a/packages/mobile/utils/deps/repeat-click.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { on, once } from './dom' - -export default (el, binding) => { - // fix issue#919 - const LONG_PRESS_INTERVAL = 200 - - let interval = null - let startTime - - const handler = () => { - typeof binding.value === 'function' && binding.value.apply() - } - - const clear = () => { - if (Date.now() - startTime < LONG_PRESS_INTERVAL) { - handler() - } - - clearInterval(interval) - interval = null - } - - on(el, 'mousedown', (e) => { - if (e.button !== 0) { - return - } - - startTime = Date.now() - once(document, 'mouseup', clear) - clearInterval(interval) - interval = setInterval(handler, LONG_PRESS_INTERVAL) - }) -} diff --git a/packages/mobile/utils/deps/resize-event.ts b/packages/mobile/utils/deps/resize-event.ts deleted file mode 100644 index 262189bae0..0000000000 --- a/packages/mobile/utils/deps/resize-event.ts +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import ResizeObserver from './ResizeObserver' - -const isServer = typeof window === 'undefined' -const cacheKey = '__resizeListeners__' - -/* istanbul ignore next */ -const resizeHandler = (entries) => { - entries.forEach((entry) => { - const listeners = entry.target[cacheKey] || [] - - if (listeners.length) { - listeners.forEach((fn) => { - fn() - }) - } - }) -} - -/* istanbul ignore next */ -export const addResizeListener = (el, fn) => { - if (isServer) { - return - } - - if (!el[cacheKey]) { - el[cacheKey] = [] - el.__ro__ = new ResizeObserver(resizeHandler) - el.__ro__.observe(el) - } - - el[cacheKey].push(fn) -} - -/* istanbul ignore next */ -export const removeResizeListener = (el, fn) => { - if (!el || !el[cacheKey]) { - return - } - - el[cacheKey].splice(el[cacheKey].indexOf(fn), 1) - - if (!el[cacheKey].length) { - el.__ro__.disconnect() - delete el.__ro__ - } -} diff --git a/packages/mobile/utils/deps/scroll-into-view.ts b/packages/mobile/utils/deps/scroll-into-view.ts deleted file mode 100644 index 3755c07d15..0000000000 --- a/packages/mobile/utils/deps/scroll-into-view.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -const isServer = typeof window === 'undefined' - -export default (container, selected) => { - if (isServer) { - return - } - - if (!selected) { - container.scrollTop = 0 - return - } - - const offsetParents = [] - let { offsetParent, offsetTop, offsetHeight } = selected - - while (offsetParent && container !== offsetParent && container.contains(offsetParent)) { - offsetParents.push(offsetParent) - offsetParent = offsetParent.offsetParent - } - - const top = offsetTop + offsetParents.reduce((prev, curr) => prev + curr.offsetTop, 0) - const bottom = top + offsetHeight - const viewRectTop = container.scrollTop - const viewRectBottom = viewRectTop + container.clientHeight - - if (top < viewRectTop) { - container.scrollTop = top - } else if (bottom > viewRectBottom) { - container.scrollTop = bottom - container.clientHeight - } -} diff --git a/packages/mobile/utils/deps/scrollbar-width.ts b/packages/mobile/utils/deps/scrollbar-width.ts deleted file mode 100644 index ddac2853b5..0000000000 --- a/packages/mobile/utils/deps/scrollbar-width.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -let scrollBarWidth: number -const isServer = typeof window === 'undefined' - -// 通过构造2层div,计算出来滚动条的宽度,并全局缓存值 -export default function () { - if (isServer) { - return 0 - } - if (scrollBarWidth !== undefined) { - return scrollBarWidth - } - - const container = document.createElement('div') - container.className = 'tiny-scrollbar' - container.style.visibility = 'hidden' - container.style.position = 'absolute' - container.style.top = '-9999px' - - const outer = document.createElement('div') - outer.className = 'tiny-scrollbar__wrap' - outer.style.width = '100px' - - container.appendChild(outer) - document.body.appendChild(container) - const widthNoScroll = outer.offsetWidth - outer.style.overflow = 'scroll' - - const inner = document.createElement('div') - inner.style.width = '100%' - - outer.appendChild(inner) - - const widthWithScroll = inner.offsetWidth - ;(outer.parentNode as HTMLElement).removeChild(outer) - scrollBarWidth = widthNoScroll - widthWithScroll - - return scrollBarWidth -} diff --git a/packages/mobile/utils/deps/throttle.ts b/packages/mobile/utils/deps/throttle.ts deleted file mode 100644 index 18f71be82f..0000000000 --- a/packages/mobile/utils/deps/throttle.ts +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -/** - * Throttle execution of a function. Especially useful for rate limiting - * execution of handlers on events like resize and scroll. - * - * @param {Number} delay A zero-or-greater delay in milliseconds. For event callbacks, - * values around 100 or 250 (or even higher) are most useful. - * @param {Boolean} [noTrailing] Optional, defaults to false. If noTrailing is true, - * callback will only execute every `delay` milliseconds while the - * throttled-function is being called. If noTrailing is false or unspecified, - * callback will be executed one final time - * after the last throttled-function call. - * (After the throttled-function has not been called for `delay` milliseconds, - * the internal counter is reset) - * @param {Function} callback A function to be executed after delay milliseconds. - * The `this` context and all arguments are passed through, as-is, - * to `callback` when the throttled-function is executed. - * @param {Boolean} [debounceMode] If `debounceMode` is true (at begin), - * schedule `clear` to execute after `delay` ms. - * If `debounceMode` is false (at end), - * schedule `callback` to execute after `delay` ms. - * - * @return {Function} A new, throttled, function. - */ - -export default function (delay, noTrailing, callback, debounceMode?: string): Function { - let timeoutID - let lastExec = 0 - - if (typeof noTrailing !== 'boolean') { - debounceMode = callback - callback = noTrailing - noTrailing = undefined - } - - function wrapper() { - const me = this - const elapsed = new Date().valueOf() - lastExec - const args = arguments - - function exec() { - lastExec = new Date().valueOf() - callback.apply(me, args) - } - - function clear() { - timeoutID = undefined - } - - if (debounceMode && !timeoutID) { - exec() - } - - if (timeoutID) { - clearTimeout(timeoutID) - } - - const isUndMode = debounceMode === undefined - - if (isUndMode && elapsed > delay) { - exec() - } else if (noTrailing !== true) { - timeoutID = setTimeout(debounceMode ? clear : exec, isUndMode ? delay - elapsed : delay) - } - } - - return wrapper -} diff --git a/packages/mobile/utils/deps/touch-emulator.ts b/packages/mobile/utils/deps/touch-emulator.ts deleted file mode 100644 index 0baa8b388e..0000000000 --- a/packages/mobile/utils/deps/touch-emulator.ts +++ /dev/null @@ -1,122 +0,0 @@ -let emulated = false -let initiated = false -let eventTarget = null -let mouseTarget = null - -const matches = Element.prototype.matches || Element.prototype.webkitMatchesSelector - -const closest = (el, s) => { - do { - if (matches.call(el, s)) return el - el = el.parentElement || el.parentNode - } while (el !== null && el.nodeType === 1) - - return null -} - -class Touch { - constructor(target, identifier, pos, deltaX, deltaY) { - this.target = target - this.identifier = identifier - - deltaX = deltaX || 0 - deltaY = deltaY || 0 - - this.pageX = pos.pageX + deltaX - this.pageY = pos.pageY + deltaY - this.screenX = pos.screenX + deltaX - this.screenY = pos.screenY + deltaY - this.clientX = pos.clientX + deltaX - this.clientY = pos.clientY + deltaY - this.offsetX = pos.offsetX + deltaX - this.offsetY = pos.offsetY + deltaY - } -} - -const TouchList = () => { - const touchList = [] - - touchList.item = (index) => touchList[index] || null - touchList.identifiedTouch = (id) => touchList[id + 1] || null - - return touchList -} - -const createTouchList = (mouseEv) => { - const touchList = TouchList() - touchList.push(new Touch(eventTarget, 1, mouseEv, 0, 0)) - return touchList -} - -const getActiveTouches = (mouseEv) => { - if (mouseEv.type === 'mouseup') { - return TouchList() - } - - return createTouchList(mouseEv) -} - -const triggerTouch = (eventName, mouseEv) => { - const touchEvent = document.createEvent('Event') - - touchEvent.initEvent(eventName, true, true) - - touchEvent.altKey = mouseEv.altKey - touchEvent.metaKey = mouseEv.metaKey - touchEvent.ctrlKey = mouseEv.ctrlKey - touchEvent.shiftKey = mouseEv.shiftKey - - touchEvent.changedTouches = createTouchList(mouseEv) - touchEvent.targetTouches = getActiveTouches(mouseEv) - touchEvent.touches = getActiveTouches(mouseEv) - // 模拟事件标记 - touchEvent.isTinySimulate = true - - eventTarget.dispatchEvent(touchEvent) -} - -const onMouse = (touchType) => (ev) => { - if (ev.type === 'mousedown') { - initiated = true - } - - if (ev.type === 'mouseup') { - initiated = false - } - - if (ev.type === 'mousemove' && !initiated) { - return - } - - if (ev.type === 'mousedown' || !mouseTarget) { - mouseTarget = ev.target - } - - eventTarget = closest(mouseTarget, '[data-tiny-touch-simulate-container]') - - if (eventTarget && eventTarget.dispatchEvent) { - triggerTouch(touchType, ev) - } - - if (ev.type === 'mouseup') { - eventTarget = null - mouseTarget = null - } -} - -const touchEmulator = () => { - window.addEventListener('mousedown', onMouse('touchstart'), true) - window.addEventListener('mousemove', onMouse('touchmove'), true) - window.addEventListener('mouseup', onMouse('touchend'), true) -} - -const emulate = () => { - const supportTouch = 'ontouchstart' in window - - if (!emulated && !supportTouch) { - emulated = true - touchEmulator() - } -} - -export default emulate diff --git a/packages/mobile/utils/deps/touch.ts b/packages/mobile/utils/deps/touch.ts deleted file mode 100644 index 50b05f62a6..0000000000 --- a/packages/mobile/utils/deps/touch.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -const MIN_DISTANCE = 10 - -export const getDirection = (x, y) => { - if (x > y && x > MIN_DISTANCE) { - return 'horizontal' - } - - if (y > x && y > MIN_DISTANCE) { - return 'vertical' - } - - return '' -} - -export const touchStart = (state) => (event) => { - resetTouchStatus(state) - - state.startX = event.touches[0].clientX - state.startY = event.touches[0].clientY -} - -export const touchMove = (state) => (event) => { - const touch = event.touches[0] - - state.deltaX = touch.clientX - state.startX - state.deltaY = touch.clientY - state.startY - state.offsetX = Math.abs(state.deltaX) - state.offsetY = Math.abs(state.deltaY) - - state.direction = state.direction || getDirection(state.offsetX, state.offsetY) -} - -export const resetTouchStatus = (state) => { - state.direction = '' - state.deltaX = 0 - state.deltaY = 0 - state.offsetX = 0 - state.offsetY = 0 -} diff --git a/packages/mobile/utils/deps/tree-model/node.ts b/packages/mobile/utils/deps/tree-model/node.ts deleted file mode 100644 index f0affba53c..0000000000 --- a/packages/mobile/utils/deps/tree-model/node.ts +++ /dev/null @@ -1,625 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { merge } from '../../object' -import { markNodeData, NODE_KEY } from './util' -import { indexOf } from '../../array' -import { hasOwn, typeOf } from '../../type' - -const defaultChildrenKey = 'children' -const defaultIsLeafKey = 'isLeaf' - -const getPropertyFromData = (node, prop) => { - const props = node.store.props - const dataData = node.data || {} - const config = props[prop] - - if (typeOf(config) === 'string') { - return dataData[config] - } else if (typeOf(config) === 'function') { - return config(dataData, node) - } else if (typeof config === 'undefined') { - const dataProp = dataData[prop] - return dataProp === undefined ? '' : dataProp - } -} - -export const getChildState = (node) => { - let all = true - let none = true - let allWithoutDisable = true - - for (let i = 0, len = node.length; i < len; i++) { - const { checked, disabled, indeterminate } = node[i] - - if (checked !== true || indeterminate) { - all = false - - if (!disabled) { - allWithoutDisable = false - } - } - - if (checked !== false || indeterminate) { - none = false - } - } - - const half = !all && !none - - return { all, none, allWithoutDisable, half } -} - -const reInitChecked = (node) => { - const childNodes = node.childNodes - - if (childNodes.length === 0) { - return - } - - const { all, none, half } = getChildState(childNodes) - - if (all) { - Object.assign(node, { checked: true, indeterminate: false }) - } else if (half) { - Object.assign(node, { checked: false, indeterminate: true }) - } else if (none) { - Object.assign(node, { checked: false, indeterminate: false }) - } - - const parent = node.parent - - if (!parent || parent.level === 0) { - return - } - - !node.store.checkStrictly && reInitChecked(parent) -} - -let nodeIdSeed = 0 - -export default class Node { - constructor(options) { - this.init(options) - - const store = this.store - - if (!store) { - throw new Error('[TINY-Tree][Node]store is required!') - } - - store.registerNode(this) - - const props = store.props - - if (props && typeof props.isLeaf !== 'undefined') { - const isLeaf = getPropertyFromData(this, defaultIsLeafKey) - - if (typeof isLeaf === 'boolean') { - this.isLeafByUser = isLeaf - } - } - - this.initExpandState() - - if (!Array.isArray(this.data)) { - markNodeData(this, this.data) - } - - if (!this.data) { - return - } - - this.expandByDefaultKeys() - - const { key, lazy, currentNodeKey } = store - - if (key && currentNodeKey !== undefined && this.key === currentNodeKey) { - store.currentNode = this - store.currentNode.isCurrent = true - } - - lazy && store._initDefaultCheckedNode(this) - - this.updateLeafState() - } - - initExpandState() { - const { store, data, level } = this - - if (store.lazy !== true && data) { - this.setData(data) - - if (store.defaultExpandAll) { - this.expanded = true - this.updateMethod(this, 'expanded') - } - } else if (level > 0 && store.lazy && store.defaultExpandAll) { - this.expand() - } - } - - init(options) { - this.id = nodeIdSeed++ - this.checked = false - this.indeterminate = false - this.expanded = false - this.visible = true - this.isCurrent = false - this.text = null - this.data = null - this.parent = null - this.updateMethod = () => {} - - Object.keys(options).forEach((key) => { - if (hasOwn.call(options, key)) { - this[key] = options[key] - } - }) - const isLeafKey = this.store?.props?.isLeaf || defaultIsLeafKey - this.isLeaf = !!(this.data && this.data[isLeafKey]) - this.loaded = this.isLeaf - this.loading = false - this.childNodes = [] - this.level = this.parent ? this.parent.level + 1 : 0 - } - - expandByDefaultKeys() { - const { defaultExpandedKeys, key, autoExpandParent } = this.store - - if (key && defaultExpandedKeys && ~defaultExpandedKeys.indexOf(this.key)) { - this.expand(null, autoExpandParent) - } - } - - setData(data) { - if (!Array.isArray(data)) { - markNodeData(this, data) - } - - this.data = data - this.childNodes = [] - let children - - if (this.level === 0 && Array.isArray(this.data)) { - children = this.data - } else { - children = getPropertyFromData(this, defaultChildrenKey) || [] - } - - for (let i = 0, len = children.length; i < len; i++) { - const data = children[i] - - this.insertChild({ data }) - } - } - - get key() { - const { store, data } = this - const nodeKey = store.key - - if (data) { - return data[nodeKey] - } - - return null - } - - get label() { - return getPropertyFromData(this, 'label') - } - - get disabled() { - return getPropertyFromData(this, 'disabled') - } - - get nextSibling() { - const parent = this.parent - - if (parent) { - const childNodes = parent.childNodes - const index = childNodes.indexOf(this) - - if (~index) { - return childNodes[index + 1] - } - } - - return null - } - - get previousSibling() { - const parent = this.parent - - if (parent) { - const childNodes = parent.childNodes - const index = childNodes.indexOf(this) - - if (~index) { - return index > 0 ? childNodes[index - 1] : null - } - } - - return null - } - - remove() { - const parent = this.parent - - parent && parent.removeChild(this) - } - - contains(target, deep = true) { - const walkTree = (parent) => { - const children = parent.childNodes || [] - let isContain = false - - for (let i = 0, len = children.length; i < len; i++) { - const child = children[i] - - if (child === target || (deep && walkTree(child))) { - isContain = true - break - } - } - - return isContain - } - - return walkTree(this) - } - - insertChild(child, index, batch) { - if (!child) { - throw new Error('[TINY-Tree] insertChild error: child is required.') - } - - const insertNode = ({ arr, index, item }) => { - if (typeof index === 'undefined' || index < 0) { - arr.push(item) - } else { - arr.splice(index, 0, item) - } - } - - if (!(child instanceof Node)) { - if (!batch) { - const children = this.getChildren(true) || [] - - if (!~children.indexOf(child.data)) { - insertNode({ arr: children, index, item: child.data }) - } - } - - merge(child, { parent: this, store: this.store }) - - child = new Node(child) - } - - child.level = this.level + 1 - - insertNode({ arr: this.childNodes, index, item: child }) - - this.updateLeafState() - } - - insertBefore(child, beforeNode) { - let index - - if (beforeNode) { - index = this.childNodes.indexOf(beforeNode) - } - - this.insertChild(child, index) - } - - insertAfter(child, afterNode) { - let index - - if (afterNode) { - index = this.childNodes.indexOf(afterNode) - if (~index) { - index += 1 - } - } - - this.insertChild(child, index) - } - - removeChild(child) { - const children = this.getChildren() || [] - let index = children.indexOf(child.data) - - if (~index) { - children.splice(index, 1) - } - - index = this.childNodes.indexOf(child) - - if (~index) { - this.store && this.store.deregisterNode(child) - child.parent = null - this.childNodes.splice(index, 1) - } - - this.updateLeafState() - } - - removeChildByData(data) { - let removeNode = null - - for (let i = 0, len = this.childNodes.length; i < len; i++) { - const child = this.childNodes[i] - - if (child.data === data) { - removeNode = child - break - } - } - - removeNode && this.removeChild(removeNode) - } - - expand(callback, expandParent) { - const expandNodes = () => { - if (expandParent) { - let parentNode = this.parent - - while (parentNode.level > 0) { - parentNode.expanded = true - parentNode.updateMethod(parentNode, 'expanded') - parentNode = parentNode.parent - } - } - - this.expanded = true - this.updateMethod(this, 'expanded') - callback && callback() - } - - if (this.shouldLoadData()) { - this.loadData((data) => { - if (Array.isArray(data)) { - if (this.checked) { - this.setChecked(true, true) - } else if (!this.store.checkStrictly) { - reInitChecked(this) - } - expandNodes() - } - }) - } else { - expandNodes() - } - } - - doCreateChildren(array, defaultProps = {}) { - array.forEach((data) => { - this.insertChild(merge({ data }, defaultProps), undefined, true) - }) - } - - collapse() { - this.expanded = false - this.updateMethod(this, 'expanded') - } - - shouldLoadData() { - return this.store.lazy === true && this.store.load && !this.loaded - } - - updateLeafState() { - const { store, loaded, isLeafByUser } = this - const lazy = store.lazy - - if (lazy === true && loaded !== true && typeof isLeafByUser !== 'undefined') { - this.isLeaf = isLeafByUser - return - } - - const childs = this.childNodes - - if (!lazy || (lazy === true && loaded === true)) { - this.isLeaf = !childs || childs.length === 0 - return - } - - this.isLeaf = false - } - - getChildren(forceInit = false) { - const { level, data } = this - - if (level === 0) { - return data - } - - if (!data) { - return null - } - - const props = this.store.props - let childrenKey = defaultChildrenKey - - if (props) { - childrenKey = props.children || defaultChildrenKey - } - - if (data[childrenKey] === undefined) { - data[childrenKey] = null - } - - if (forceInit && !data[childrenKey]) { - data[childrenKey] = [] - } - - return data[childrenKey] - } - - setChecked(value, isDeepChecked, recursion, passValue, checkEasily) { - this.checked = value === true - this.indeterminate = value === 'half' - - const { checkStrictly, checkDescendants } = this.store - - if (checkStrictly && !checkEasily) { - return - } - - let ret = this.setCheckedInner({ - checkDescendants, - value, - isDeepChecked, - passValue, - checkEasily - }) - let returnFlag = ret.returnFlag - passValue = ret.passValue - value = ret.value - - if (returnFlag || (checkStrictly && checkEasily)) { - return - } - - const parentNode = this.parent - if (!parentNode || parentNode.level === 0) { - return - } - - if (!recursion) { - reInitChecked(parentNode) - } - } - - setCheckedInner({ checkDescendants, value, isDeepChecked, passValue, checkEasily }) { - let returnFlag = false - - if (this.shouldLoadData() && !checkDescendants) { - return { value, passValue, returnFlag } - } - - const { all, allWithoutDisable } = getChildState(this.childNodes) - - if (!this.isLeaf && !all && allWithoutDisable && !checkEasily) { - this.checked = false - value = false - } - - const batchSetChecked = () => { - if (isDeepChecked) { - const childNodes = this.childNodes - - for (let i = 0, len = childNodes.length; i < len; i++) { - const childNode = childNodes[i] - - passValue = passValue || value !== false - - const isCheck = childNode.disabled ? childNode.checked : passValue - - childNode.setChecked(isCheck, isDeepChecked, true, passValue, checkEasily) - } - - const { half, all } = getChildState(childNodes) - - if (!all && !checkEasily) { - this.checked = all - this.indeterminate = half - } - } - } - - if (this.shouldLoadData()) { - const afterLoad = () => { - batchSetChecked() - reInitChecked(this) - } - - this.loadData(afterLoad, { checked: value !== false }) - - returnFlag = true - } else { - batchSetChecked() - } - - return { value, passValue, returnFlag } - } - - updateChildren() { - const children = this.getChildren() || [] - const oldChildren = this.childNodes.map((child) => child.data) - const newChildrenMap = {} - const newChildren = [] - - children.forEach((item, index) => { - const key = item[NODE_KEY] - const isNodeExists = !!key && indexOf(oldChildren, key, (item, data) => item[NODE_KEY] === data) >= 0 - - if (isNodeExists) { - newChildrenMap[key] = { index, data: item } - } else { - newChildren.push({ index, data: item }) - } - }) - - if (!this.store.lazy) { - oldChildren.forEach((item) => { - if (!newChildrenMap[item[NODE_KEY]]) { - this.removeChildByData(item) - } - }) - } - - newChildren.forEach(({ data, index }) => { - this.insertChild({ data }, index) - }) - - this.updateLeafState() - } - - loadData(callback, defaultProps = {}) { - const { lazy, load } = this.store - - if (lazy === true && load && !this.loaded && (!this.loading || Object.keys(defaultProps).length)) { - this.loading = true - - this.store.load(this, (children) => { - this.loading = false - this.loaded = true - this.childNodes = [] - - this.doCreateChildren(children, defaultProps) - this.updateLeafState() - - callback && callback.call(this, children) - typeof this.store.afterLoad === 'function' && this.store.afterLoad({ data: children }) - }) - } else { - callback && callback.call(this) - } - } - - getPathData(key) { - const nodes = [key ? this.data[key] : this.data] - let parentNode = this.parent - - while (parentNode && parentNode.parent) { - nodes.unshift(key ? parentNode.data[key] : parentNode.data) - parentNode = parentNode.parent - } - - return nodes - } - - getPathText(key, separator = ',') { - return (this.getPathData(key) || []).join(separator) - } -} diff --git a/packages/mobile/utils/deps/tree-model/tree-store.ts b/packages/mobile/utils/deps/tree-model/tree-store.ts deleted file mode 100644 index c032af055e..0000000000 --- a/packages/mobile/utils/deps/tree-model/tree-store.ts +++ /dev/null @@ -1,396 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { hasOwn, isNull } from '../../type' -import { getNodeKey } from './util' -import Node from './node' - -export default class TreeStore { - constructor(options) { - this.currentNode = null - this.currentNodeKey = null - - for (let option in options) { - if (hasOwn.call(options, option)) { - this[option] = options[option] - } - } - - this.nodesMap = {} - - this.root = new Node({ data: this.data, store: this }) - - if (this.lazy && this.load) { - this.load(this.root, (data) => { - this.root.doCreateChildren(data) - this._initDefaultCheckedNodes() - typeof this.afterLoad === 'function' && this.afterLoad({ data, init: true }) - }) - } else { - this._initDefaultCheckedNodes() - } - } - - filter(value) { - const { lazy, filterNodeMethod } = this - - const walkTree = (node) => { - const childNodes = node.root ? node.root.childNodes : node.childNodes - - childNodes.forEach((child) => { - child.visible = filterNodeMethod.call(child, value, child.data, child) - - walkTree(child) - }) - - if (!node.visible && childNodes.length) { - let allHidden = !childNodes.some(({ visible }) => visible) - - if (node.root) { - node.root.visible = allHidden === false - } else { - node.visible = allHidden === false - } - } - - if (!value) { - return - } - if (node.visible && !node.isLeaf && !lazy) { - node.expand() - } - } - - walkTree(this) - } - - setData(newVal) { - if (newVal !== this.root.data) { - this.root.setData(newVal) - this._initDefaultCheckedNodes() - } else { - this.root.updateChildren() - } - } - - getNode(data) { - if (data instanceof Node) { - return data - } - - const nodeKey = typeof data !== 'object' ? data : getNodeKey(this.key, data) - - return this.nodesMap[nodeKey] || null - } - - insertBefore(data, insertData) { - const refNode = this.getNode(insertData) - refNode.parent.insertBefore({ data }, refNode) - } - - insertAfter(data, insertData) { - const refNode = this.getNode(insertData) - refNode.parent.insertAfter({ data }, refNode) - } - - remove(data, isSaveChildNode, isNode) { - const treeNode = isNode ? data : this.getNode(data) - - if (treeNode && treeNode.parent) { - if (treeNode === this.currentNode) { - this.currentNode = null - } - - if (isSaveChildNode && treeNode.childNodes) { - treeNode.childNodes.forEach((child) => { - treeNode.parent.insertChild({ data: child.data }) - }) - } - - treeNode.parent.removeChild(treeNode) - } - } - - append(data, parentData, index) { - const parentNode = parentData ? this.getNode(parentData) : this.root - - parentNode && parentNode.insertChild({ data }, index) - } - - setDefaultCheckedKey(newValue) { - if (newValue !== this.defaultCheckedKeys) { - this.defaultCheckedKeys = newValue - this._initDefaultCheckedNodes() - } - } - - _initDefaultCheckedNodes() { - const defaultCheckedKeys = this.defaultCheckedKeys || [] - const nodesMap = this.nodesMap - - defaultCheckedKeys.forEach((checkedKey) => { - const node = nodesMap[checkedKey] - - node && node.setChecked(true, !this.checkStrictly) - }) - } - - _initDefaultCheckedNode(node) { - const defaultCheckedKeys = this.defaultCheckedKeys || [] - - ~defaultCheckedKeys.indexOf(node.key) && node.setChecked(true, !this.checkStrictly) - } - - getCheckedKeys(leafOnly = false) { - return this.getCheckedNodes(leafOnly).map((node) => (node || {})[this.key]) - } - - getHalfCheckedKeys() { - return this.getHalfCheckedNodes().map((node) => (node || {})[this.key]) - } - - deregisterNode(node) { - const key = this.key - if (!key || !node || !node.data) { - return - } - - node.childNodes.forEach((child) => { - this.deregisterNode(child) - }) - - delete this.nodesMap[node.key] - } - - registerNode(node) { - const key = this.key - if (!key || !node || !node.data) { - return - } - - const nodeKey = node.key - if (nodeKey !== undefined) { - this.nodesMap[nodeKey] = node - } - } - - getCheckedNodes(leafOnly = false, includeHalfChecked = false, isNode = false) { - const checkedNodes = [] - - const walkTree = (node) => { - const childNodes = node.root ? node.root.childNodes : node.childNodes - - childNodes.forEach((child) => { - const { checked, indeterminate, isLeaf, data } = child - - if ((checked || (includeHalfChecked && indeterminate)) && (!leafOnly || (leafOnly && isLeaf))) { - checkedNodes.push(isNode ? child : data) - } - - walkTree(child) - }) - } - - walkTree(this) - - return checkedNodes - } - - getHalfCheckedNodes() { - const nodes = [] - - const walkTree = (node) => { - const childNodes = node.root ? node.root.childNodes : node.childNodes - - childNodes.forEach((child) => { - const { indeterminate, data } = child - - indeterminate && nodes.push(data) - - walkTree(child) - }) - } - - walkTree(this) - - return nodes - } - - _getAllNodes() { - const allNodes = [] - const nodesMap = this.nodesMap - - Object.keys(nodesMap).forEach((nodeKey) => { - hasOwn.call(nodesMap, nodeKey) && allNodes.push(nodesMap[nodeKey]) - }) - - return allNodes - } - - updateChildren(key, data) { - const node = this.nodesMap[key] - if (!node) { - return - } - - const childNodes = node.childNodes - - for (let i = childNodes.length - 1; i >= 0; i--) { - this.remove(childNodes[i].data) - } - - for (let i = 0, len = data.length; i < len; i++) { - const child = data[i] - this.append(child, node.data) - } - } - - _setCheckedKeys(key, leafOnly = false, checkedKeys = {}) { - const nodes = this._getAllNodes().sort((prevNode, nextNode) => nextNode.level - prevNode.level) - const cache = Object.create(null) - const keys = Object.keys(checkedKeys) - - nodes.forEach((node) => { - node.setChecked(false, false) - }) - - for (let i = 0, len = nodes.length; i < len; i++) { - const node = nodes[i] - const nodeKey = node.data[key].toString() - let checked = ~keys.indexOf(nodeKey) - - if (!checked) { - if (node.checked && !cache[nodeKey]) { - node.setChecked(false, false) - } - } else { - let parentNode = node.parent - - while (parentNode && parentNode.level > 0) { - cache[parentNode.data[key]] = true - parentNode = parentNode.parent - } - - if (node.isLeaf || this.checkStrictly) { - node.setChecked(true, false) - } else if (leafOnly) { - node.setChecked(false, false) - - const walkTree = (node) => { - const childNodes = node.childNodes - - childNodes.forEach((child) => { - !child.isLeaf && child.setChecked(false, false) - - walkTree(child) - }) - } - - walkTree(node) - } else { - node.setChecked(true, true) - } - } - } - } - - setDefaultExpandedKeys(keys) { - keys = keys || [] - this.defaultExpandedKeys = keys - - keys.forEach((key) => { - const node = this.getNode(key) - node && node.expand(null, this.autoExpandParent) - }) - } - - setCheckedKeys(keys, leafOnly = false) { - this.defaultCheckedKeys = keys - const checkedKeys = {} - - keys.forEach((key) => { - checkedKeys[key] = true - }) - - this._setCheckedKeys(this.key, leafOnly, checkedKeys) - } - - setCheckedNodes(array, leafOnly = false) { - const key = this.key - const checkedKeys = {} - - array.forEach((item) => { - checkedKeys[(item || {})[key]] = true - }) - - this._setCheckedKeys(key, leafOnly, checkedKeys) - } - - setChecked(data, checked, deep) { - const node = this.getNode(data) - - node && node.setChecked(!!checked, deep) - } - - setCurrentNode(currentNode) { - const prevNode = this.currentNode - - if (prevNode) { - prevNode.isCurrent = false - } - - this.currentNode = currentNode - - if (currentNode) { - this.currentNode.isCurrent = true - } - } - - getCurrentNode() { - return this.currentNode - } - - setCurrentNodeKey(key) { - if (isNull(key)) { - this.currentNode && (this.currentNode.isCurrent = false) - this.currentNode = null - - return - } - - const node = this.getNode(key) - - node && this.setCurrentNode(node) - } - - setUserCurrentNode(node) { - const key = node[this.key] - const currNode = this.nodesMap[key] - - this.setCurrentNode(currNode) - } - - getData(data) { - return (this.getNode(data) || {}).data - } - - getAllData() { - const children = this.props.children - const walkTree = (nodes) => { - return nodes.map((node) => { - return { ...node.data, [children]: walkTree(node.childNodes) } - }) - } - - return walkTree(this.root.childNodes) - } -} diff --git a/packages/mobile/utils/deps/tree-model/util.ts b/packages/mobile/utils/deps/tree-model/util.ts deleted file mode 100644 index 8fca51aaa1..0000000000 --- a/packages/mobile/utils/deps/tree-model/util.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -export const NODE_KEY = '$treeNodeId' - -export const getNodeKey = function (key, data) { - if (!key) { - return data[NODE_KEY] - } - return data[key] -} - -export const markNodeData = function (node, data) { - if (!data || data[NODE_KEY]) { - return - } - - Object.defineProperty(data, NODE_KEY, { - value: node.id, - enumerable: false, - configurable: false, - writable: false - }) -} diff --git a/packages/mobile/utils/deps/upload-ajax.ts b/packages/mobile/utils/deps/upload-ajax.ts deleted file mode 100644 index 29182369cd..0000000000 --- a/packages/mobile/utils/deps/upload-ajax.ts +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { hasOwn } from '../type' -import { xss } from '../xss' - -const getBody = (xhr) => { - const text = xhr.responseText || xhr.response - - if (!text) { - return text - } - - try { - return JSON.parse(text) - } catch (e) { - return text - } -} - -const getError = (action, option, xhr) => { - let errorText - - if (xhr.response) { - errorText = xhr.response.error || xhr.response - } else if (xhr.responseText) { - errorText = xhr.responseText - } else { - errorText = `fail to post ${action} ${xhr.status}` - } - - const error = new Error(errorText) - - error.status = xhr.status - error.method = 'post' - error.url = action - - return error -} - -export default (option) => { - if (typeof XMLHttpRequest === 'undefined') { - return - } - - const xhr = new XMLHttpRequest() - const action = xss.filterUrl(option.action) - - if (xhr.upload) { - xhr.upload.onprogress = (event) => { - if (event.total > 0) { - event.percent = (event.loaded / event.total) * 100 - } - - option.onProgress(event) - } - } - - const formData = new FormData() - - if (option.data) { - Object.keys(option.data).forEach((key) => { - formData.append(key, option.data[key]) - }) - } - - if (Array.isArray(option.file)) { - option.file.forEach((file) => { - formData.append(option.filename, file, file.name) - }) - } else { - formData.append(option.filename, option.file, option.file.name) - } - - xhr.onerror = (event) => { - option.onError(event) - } - - xhr.onload = () => { - if (xhr.status < 200 || xhr.status >= 300) { - return option.onError(getError(action, option, xhr)) - } - - option.onSuccess(getBody(xhr)) - } - - xhr.open('post', action, true) - - if (option.withCredentials && 'withCredentials' in xhr) { - xhr.withCredentials = true - } - - const headers = option.headers || {} - - for (let header in headers) { - if (hasOwn.call(headers, header) && headers[header] !== null) { - xhr.setRequestHeader(header, headers[header]) - } - } - - xhr.send(formData) - - return xhr -} diff --git a/packages/mobile/utils/deps/useEventListener.ts b/packages/mobile/utils/deps/useEventListener.ts deleted file mode 100644 index fc66a99971..0000000000 --- a/packages/mobile/utils/deps/useEventListener.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { on, off, isServer } from './dom' - -const onMountedOrActivated = - ({ onMounted, onActivated, nextTick }) => - (hook) => { - let mounted - - onMounted(() => (hook(), nextTick(() => (mounted = true)))) - onActivated(() => mounted && hook()) - } - -export const useEventListener = - ({ unref, isRef, watch, nextTick, onMounted, onUnmounted, onActivated, onDeactivated }) => - (type, listener, options = {}) => { - if (isServer) return - - const { target = window, passive = false, capture = false } = options - - let cleaned = false - let attached - - const add = (target) => { - if (cleaned) return - - const element = unref(target) - - if (element && !attached) { - on(element, type, listener, { capture, passive }) - attached = true - } - } - - const remove = (target) => { - if (cleaned) return - - const element = unref(target) - - if (element && attached) { - off(element, type, listener, { capture, passive }) - attached = false - } - } - - onUnmounted(() => remove(target)) - onDeactivated(() => remove(target)) - onMountedOrActivated({ onMounted, onActivated, nextTick })(() => add(target)) - - let stopWatch - - if (isRef(target)) { - stopWatch = watch(target, (val, oldVal) => (remove(oldVal), add(val))) - } - - return () => { - stopWatch && stopWatch() - remove(target) - cleaned = true - } - } diff --git a/packages/mobile/utils/deps/useRect.ts b/packages/mobile/utils/deps/useRect.ts deleted file mode 100644 index eaec63154d..0000000000 --- a/packages/mobile/utils/deps/useRect.ts +++ /dev/null @@ -1,25 +0,0 @@ -const isWindow = (val) => val === window -const makeDOMRect = (width, height) => ({ - top: 0, - left: 0, - width, - right: width, - height, - bottom: height -}) - -export const useRect = (unref) => (elOrRef) => { - const el = unref(elOrRef) - - if (isWindow(el)) { - const width = el.innerWidth - const height = el.innerHeight - return makeDOMRect(width, height) - } - - if (el && el.getBoundingClientRect) { - return el.getBoundingClientRect() - } - - return makeDOMRect(0, 0) -} diff --git a/packages/mobile/utils/deps/useTouch.ts b/packages/mobile/utils/deps/useTouch.ts deleted file mode 100644 index a9e26f8f0b..0000000000 --- a/packages/mobile/utils/deps/useTouch.ts +++ /dev/null @@ -1,74 +0,0 @@ -const TAP_OFFSET = 5 - -const getDirection = (x, y) => { - if (x > y) return 'horizontal' - if (y > x) return 'vertical' - return '' -} - -const touchEvent = (event) => event.touches[0] - -export const useTouch = (ref) => () => { - const startX = ref(0) - const startY = ref(0) - const deltaX = ref(0) - const deltaY = ref(0) - const offsetX = ref(0) - const offsetY = ref(0) - const direction = ref('') - const isTap = ref(true) - - const isVertical = () => direction.value === 'vertical' - const isHorizontal = () => direction.value === 'horizontal' - - const reset = () => { - deltaX.value = 0 - deltaY.value = 0 - offsetX.value = 0 - offsetY.value = 0 - direction.value = '' - isTap.value = true - } - - const start = (event) => { - reset() - const touch = touchEvent(event) - startX.value = touch.clientX - startY.value = touch.clientY - } - - const move = (event) => { - const touch = touchEvent(event) - // safari back will set clientX to negative number - deltaX.value = (touch.clientX < 0 ? 0 : touch.clientX) - startX.value - deltaY.value = touch.clientY - startY.value - offsetX.value = Math.abs(deltaX.value) - offsetY.value = Math.abs(deltaY.value) - - // lock direction when distance is greater than a certain value - const LOCK_DIRECTION_DISTANCE = 10 - if (!direction.value || (offsetX.value < LOCK_DIRECTION_DISTANCE && offsetY.value < LOCK_DIRECTION_DISTANCE)) { - direction.value = getDirection(offsetX.value, offsetY.value) - } - - if (isTap.value && (offsetX.value > TAP_OFFSET || offsetY.value > TAP_OFFSET)) { - isTap.value = false - } - } - - return { - move, - start, - reset, - isVertical, - isHorizontal, - startX, - startY, - deltaX, - deltaY, - offsetX, - offsetY, - direction, - isTap - } -} diff --git a/packages/mobile/utils/deps/vue-emitter.ts b/packages/mobile/utils/deps/vue-emitter.ts deleted file mode 100644 index 2e1d9554e1..0000000000 --- a/packages/mobile/utils/deps/vue-emitter.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -export default (vm) => { - const broadcast = (vm, componentName, eventName, params) => { - vm.$children.forEach((child) => { - const name = child.$options.componentName - - if (name === componentName) { - child.$emit(eventName, params) - } else { - broadcast(child, componentName, eventName, params) - } - }) - } - - return { - dispatch(componentName, eventName, params) { - let parent = vm.$parent || vm.$root - let name = parent.$options.componentName - - while (parent && !parent.$attrs.novalid && (!name || name !== componentName)) { - parent = parent.$parent - - if (parent) { - name = parent.$options.componentName - } - } - - if (parent) { - parent.$emit.apply(parent, [eventName].concat(params)) - } - }, - broadcast(componentName, eventName, params) { - broadcast(vm, componentName, eventName, params) - } - } -} diff --git a/packages/mobile/utils/deps/vue-popper.ts b/packages/mobile/utils/deps/vue-popper.ts deleted file mode 100644 index 24d0d590bb..0000000000 --- a/packages/mobile/utils/deps/vue-popper.ts +++ /dev/null @@ -1,228 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import PopupManager from './popup-manager' -import PopperJS from './popper' -import { on, off, isDisplayNone } from './dom' -import type { ISharedRenderlessFunctionParams } from 'types/shared.type' -import type Popper from './popper' - -export interface IPopperState { - popperJS: Popper - appended: boolean - popperElm: HTMLElement - showPopper: boolean - referenceElm: HTMLElement - currentPlacement: string -} - -type IPopperInputParams = ISharedRenderlessFunctionParams & { - api: { open: Function; close: Function } - state: IPopperState - props: any -} - -/** 给 popper 的click添加stop, 阻止冒泡 */ -const stop = (e: Event) => e.stopPropagation() - -const isServer = typeof window === 'undefined' - -// 由于多个组件传入reference元素的方式不同,所以这里从多处查找。 -const getReference = ({ state, props, vm, slots }: Pick) => { - let reference = - state.referenceElm || props.reference || (vm.$refs.reference && vm.$refs.reference.$el) || vm.$refs.reference - - if (!reference && slots.reference && slots.reference()[0]) { - state.referenceElm = slots.reference()[0].elm || slots.reference()[0].el - reference = state.referenceElm - } - - return reference -} - -export default (options: IPopperInputParams) => { - const { - parent, - emit, - nextTick, - onBeforeUnmount, - onDeactivated, - props, - watch, - reactive, - vm, - slots, - toRefs, - popperVmRef - } = options - const state = reactive({ - popperJS: null as any, - appended: false, // arrow 是否添加 - popperElm: null as any, - showPopper: props.manual ? Boolean(props.modelValue) : false, - referenceElm: null as any, - currentPlacement: '' - }) - - /** 创建箭头函数 */ - const appendArrow = (el: HTMLElement) => { - if (state.appended) { - return - } - - state.appended = true - const div = document.createElement('div') - - div.setAttribute('x-arrow', '') - div.className = 'popper__arrow' - el.appendChild(div) - } - - // 如果触发源是隐藏的,其弹出层也设置为隐藏。组件可以通过 props.popperOptions.followReferenceHide = true/false来控制 - const followHide = (popperInstance: PopperJS) => { - const { followReferenceHide = true } = props?.popperOptions || {} - const { _popper: popper, _reference: reference } = popperInstance - - if (followReferenceHide && isDisplayNone(reference)) { - popper.style.display = 'none' - } - } - - const createPopper = (dom) => { - if (isServer) { - return - } - - state.currentPlacement = state.currentPlacement || props.placement - - if (!/^(top|bottom|left|right)(-start|-end)?$/g.test(state.currentPlacement)) { - return - } - - const options = props.popperOptions || { gpuAcceleration: false } - state.popperElm = state.popperElm || props.popper || vm.$refs.popper || popperVmRef.popper || dom - const popper = state.popperElm - let reference = getReference({ state, props, vm, slots }) - - if (!popper || !reference || reference.nodeType !== Node.ELEMENT_NODE) { - return - } - - if (props.visibleArrow) { - appendArrow(popper) - } - - // 使用的组件比较多,所以 appendToBody popperAppendToBody 这2个属性都要监听 - if (props.appendToBody || props.popperAppendToBody) { - document.body.appendChild(state.popperElm) - } else { - // 只有tooltip 传入parent了 - parent && parent.$el && parent.$el.appendChild(state.popperElm) - options.forceAbsolute = true - } - - options.placement = state.currentPlacement - options.offset = props.offset || 0 - options.arrowOffset = props.arrowOffset || 0 - options.adjustArrow = props.adjustArrow || false - options.appendToBody = props.appendToBody || props.popperAppendToBody - - // 创建一个popperJS, 内部会立即调用一次update() 并 applyStyle等操作 - state.popperJS = new PopperJS(reference, popper, options) - // 1、所有使用vue-popper的都有该事件;2、有的组件会多次触发 created - emit('created', state) - - if (typeof options.onUpdate === 'function') { - state.popperJS.onUpdate(options.onUpdate) - } - - state.popperJS._popper.style.zIndex = PopupManager.nextZIndex().toString() - followHide(state.popperJS) - on(state.popperElm, 'click', stop) - } - - /** 第一次 updatePopper 的时候,才真正执行创建 - * popperElmOrTrue===true的场景仅在select组件动态更新面版时,不更新zIndex - */ - const updatePopper = (popperElmOrTrue?: HTMLElement) => { - if (popperElmOrTrue && popperElmOrTrue !== true) { - state.popperElm = popperElmOrTrue - } - - const popperJS = state.popperJS - if (popperJS) { - popperJS.update() - - // 每次递增 z-index - if (popperJS._popper && popperElmOrTrue !== true) { - popperJS._popper.style.zIndex = PopupManager.nextZIndex().toString() - followHide(state.popperJS) - } - } else { - createPopper(popperElmOrTrue && popperElmOrTrue !== true ? popperElmOrTrue : undefined) - } - } - - /** 调用state.popperJS.destroy()。 默认不会移除popper dom - * doDestroy() 默认执行的条件是: state.popperJS 有值且 state.showPopper = false. - * 当state.showPopper 为true时, 需要 doDestroy(true)! - */ - const doDestroy = (forceDestroy?: boolean) => { - if (!state.popperJS || (state.showPopper && !forceDestroy)) { - return - } - state.popperJS.destroy() // 并未移除popper的dom - state.popperJS = null as any - } - - /** remove时,执行真的移除popper dom操作。 */ - const destroyPopper = (remove: 'remove' | boolean) => { - if (remove) { - if (state.popperElm) { - off(state.popperElm, 'click', stop) - state.popperElm.remove() - } - } - } - - // 注意: 一直以来,state.showPopper 为false时,并未调用doDestory. 像popover只是依赖这个值来 给reference元素 v-show一下 - watch( - () => state.showPopper, - (val) => { - if (props.disabled) { - return - } - if (val) { - nextTick(updatePopper) - } - props.trigger === 'manual' && emit('update:modelValue', val) - } - ) - - onBeforeUnmount(() => { - nextTick(() => { - doDestroy(true) - if (props.appendToBody || props.popperAppendToBody) { - destroyPopper('remove') - } - }) - }) - - onDeactivated(() => { - doDestroy(true) - if (props.appendToBody || props.popperAppendToBody) { - destroyPopper('remove') - } - }) - - return { updatePopper, destroyPopper, doDestroy, ...toRefs(state) } -} diff --git a/packages/mobile/utils/deps/vue-popup.ts b/packages/mobile/utils/deps/vue-popup.ts deleted file mode 100644 index 7e137bc874..0000000000 --- a/packages/mobile/utils/deps/vue-popup.ts +++ /dev/null @@ -1,196 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { merge } from '../object' -import PopupManager from './popup-manager' -import { addClass } from './dom' -import type { ISharedRenderlessFunctionParams } from 'types/shared.type' - -let idSeed = 1 -const isServer = typeof window === 'undefined' - -export interface IPopupState { - opened: boolean - rendered: boolean -} -type IPopupInputParams = ISharedRenderlessFunctionParams & { - api: { open: Function; close: Function } - state: IPopupState - props: any -} - -const setWatchFn = ({ - onMounted, - onBeforeUnmount, - watch, - vm, - api, - props, - state, - nextTick -}: Pick< - IPopupInputParams, - 'onMounted' | 'onBeforeUnmount' | 'watch' | 'vm' | 'api' | 'props' | 'state' | 'nextTick' ->) => { - onMounted(() => { - vm._popupId = `popup-${idSeed++}` - PopupManager.register(vm._popupId, vm) - }) - - onBeforeUnmount(() => { - PopupManager.deregister(vm._popupId) - PopupManager.closeModal(vm._popupId) - }) - - watch( - () => props.visible, - (val) => { - if (val) { - if (vm._opening) { - return - } - if (state.rendered) { - api.open() - } else { - state.rendered = true - nextTick(() => { - api.open() - }) - } - } else { - api.close() - } - } - ) -} - -const openFn = - ({ state, vm }: Pick) => - (options: any) => { - if (!state.rendered) { - state.rendered = true - } - - const props: any = merge({}, vm.$props || vm, options) - - if (vm._closeTimer) { - clearTimeout(vm._closeTimer) - vm._closeTimer = null - } - - clearTimeout(vm._openTimer) - - // 复用doOpen - const doOpen = () => { - if (isServer || state.opened) { - return - } - - vm._opening = true - - const dom = vm.$el - const modal = props.modal - const zIndex = props.zIndex - - if (zIndex) { - PopupManager.zIndex = zIndex - } - - if (modal) { - if (vm._closing) { - PopupManager.closeModal(vm._popupId) - vm._closing = false - } - - PopupManager.openModal( - vm._popupId, - PopupManager.nextZIndex(), - props.modalAppendToBody ? undefined : dom, - props.modalClass, - props.modalFade - ) - - if (props.lockScroll) { - // 必须先计算宽度,再添加popLockClass。 下面2行不能交换 - PopupManager.fixBodyBorder() - addClass(document.body, PopupManager.popLockClass) - } - } - - if (getComputedStyle(dom).position === 'static') { - dom.style.position = 'absolute' - } - - dom.style.zIndex = PopupManager.nextZIndex().toString() - state.opened = true - - vm._opening = false - } - const openDelay = Number(props.openDelay) - - if (openDelay > 0) { - vm._openTimer = setTimeout(() => { - vm._openTimer = null - doOpen() - }, openDelay) - } else { - doOpen() - } - } -const closeFn = - ({ state, vm }: Pick) => - () => { - if (vm._openTimer !== null) { - clearTimeout(vm._openTimer) - vm._openTimer = null - } - - clearTimeout(vm._closeTimer) - - // 复用 doClose - const doClose = () => { - vm._closing = true - - state.opened = false - PopupManager.closeModal(vm._popupId) - vm._closing = false - } - - const closeDelay = Number(vm.closeDelay) - - if (closeDelay > 0) { - vm._closeTimer = setTimeout(() => { - vm._closeTimer = null - doClose() - }, closeDelay) - } else { - doClose() - } - } - -/** vue-popup 只是dialog-box 自己使用的包, 封装了一些state和几个方法,处理mount,unmount 和watch。 它内部封装了 PopupManager 的调用! - * 计划:drawer/image 等组件均使用该函数 - */ -export default (options: IPopupInputParams) => { - const { api, nextTick, onBeforeUnmount, onMounted, props, reactive, toRefs, vm, watch } = options - const state = reactive({ - opened: false, - rendered: false - }) - - setWatchFn({ onMounted, onBeforeUnmount, watch, vm, api, props, state, nextTick }) - - const open = openFn({ state, vm }) - const close = closeFn({ state, vm }) - - return { open, close, PopupManager, ...toRefs(state) } -} diff --git a/packages/mobile/utils/event.ts b/packages/mobile/utils/event.ts deleted file mode 100644 index 45f3e6a82a..0000000000 --- a/packages/mobile/utils/event.ts +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -/** - * 触发事件,并返回是否在事件中执行了 preventDefault 方法,支持事件传递附加参数。 - * - * // 触发事件,返回 false 则退出 - * if (!emitEvent(emit, 'before', 1)) { - * return - * } - * - * // @before='before' 定义事件执行的函数 - * function before(event, value) { - * // value: 1 - * event.preventDefault() // 通知事件宿主停止执行 - * } - * - * @param {Function} emit 触发事件的函数 - * @param {String} name 事件的名称 - * @returns {Boolean} - */ -export const emitEvent = (emit, name, ...args) => { - let cancel = false - - if (typeof emit === 'function' && typeof name === 'string') { - const event = document.createEvent('HTMLEvents') - - event.initEvent(name, false, true) - event.preventDefault = () => { - cancel = true - } - - args.unshift(event) - args.unshift(name) - emit.apply(null, args) - } - - return !cancel -} - -/** - * webComponent中,有些事件的target会代理到webComponent根元素上,导致无法获取正确的target - * - * @param event 浏览器事件 - * @returns 正确的target - */ -export const getActualTarget = (e) => { - if (!e || !e.target) { - return null - } - return e.target.shadowRoot && e.composed ? e.composedPath()[0] || e.target : e.target -} diff --git a/packages/mobile/utils/global.ts b/packages/mobile/utils/global.ts deleted file mode 100644 index a73e754491..0000000000 --- a/packages/mobile/utils/global.ts +++ /dev/null @@ -1,7 +0,0 @@ -const globalConfig = { - viewportWindow: null // 获取真实视口的window,解决在微前端中某些bug -} - -export const getViewportWindow = () => globalConfig.viewportWindow || window - -export default globalConfig diff --git a/packages/mobile/utils/index.ts b/packages/mobile/utils/index.ts deleted file mode 100644 index 1b99b2c22c..0000000000 --- a/packages/mobile/utils/index.ts +++ /dev/null @@ -1,269 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { log as uLog, xss } from './xss.js' - -export const KEY_CODE = { - Backspace: 8, - Tab: 9, - Clear: 12, - Enter: 13, - Shift: 16, - Control: 17, - Alt: 18, - CapsLock: 20, - Escape: 27, - Space: 32, - PageUp: 33, - PageDown: 34, - End: 35, - Home: 36, - 'ArrowLeft': 37, - 'ArrowUp': 38, - 'ArrowRight': 39, - 'ArrowDown': 40, - Insert: 45, - Delete: 46, - Colon: 58, - Semicolon: 59, - LessThan: 60, - Equals: 61, - GreaterThan: 62, - QuestionMark: 63, - AtMark: 64, - KeyA: 65, - KeyB: 66, - KeyC: 67, - KeyD: 68, - 'KeyE': 69, - 'KeyF': 70, - 'KeyG': 71, - 'KeyH': 72, - KeyI: 73, - KeyJ: 74, - KeyK: 75, - KeyL: 76, - KeyM: 77, - KeyN: 78, - KeyO: 79, - KeyP: 80, - KeyQ: 81, - 'KeyR': 82, - 'KeyS': 83, - 'KeyT': 84, - 'KeyU': 85, - KeyV: 86, - KeyW: 87, - KeyX: 88, - KeyY: 89, - KeyZ: 90, - 'Digit0': 48, - 'Digit1': 49, - 'Digit2': 50, - 'Digit3': 51, - Digit4: 52, - Digit5: 53, - Digit6: 54, - Digit7: 55, - Digit8: 56, - Digit9: 57, - 'F1': 112, - 'F2': 113, - 'F3': 114, - 'F4': 115, - F5: 116, - F6: 117, - F7: 118, - F8: 119, - F9: 120, - F10: 121, - F11: 122, - F12: 123, - 'NumLock': 144, - 'Numpad0': 96, - 'Numpad1': 97, - 'Numpad2': 98, - Numpad3: 99, - Numpad4: 100, - Numpad5: 101, - Numpad6: 102, - Numpad7: 103, - Numpad8: 104, - Numpad9: 105, - 'NumpadMultiply': 106, - 'NumpadAdd': 107, - 'NumpadEnter': 13, - 'NumpadSubtract': 109, - NumpadDecimal: 110, - NumpadDivide: 111, - NumpadComma: 190 -} - -export const POSITION = { Left: 'left', Right: 'right', Top: 'top', Bottom: 'bottom' } - -export const SORT = { Asc: 'asc', Desc: 'desc' } - -export const REFRESH_INTERVAL = 100 - -export const IPTHRESHOLD = { Min: 0, Max: 255, NonNumeric: 25 } - -export const DATE = { - FullDatetime: 'yyyy-MM-dd hh:mm:ss.SSS', - LongDatetime: 'yyyy-MM-dd hh:mm:ss', - Datetime: 'yyyy-MM-dd hh:mm', - Date: 'yyyy-MM-dd', - FullTime: 'hh:mm:ss.SSS', - LongTime: 'hh:mm:ss', - Time: 'hh:mm', - YearMonth: 'yyyy-MM' -} - -const TriggerTypes = - 'date,datetime,time,time-select,week,month,year,years,yearrange,daterange,monthrange,timerange,datetimerange,dates,quarter' - -export const DATEPICKER = { - Day: 'day', - Date: 'date', - Dates: 'dates', - Year: 'year', - Years: 'years', - YearRange: 'yearrange', - PanelYearNum: 12, - Month: 'month', - Week: 'week', - Normal: 'normal', - Today: 'today', - PreMonth: 'pre-month', - NextMonth: 'next-month', - YearI18n: 'ui.datepicker.year', - List: [38, 40, 37, 39], - YearObj: { 38: -4, 40: 4, 37: -1, 39: 1 }, - WeekObj: { 38: -1, 40: 1, 37: -1, 39: 1 }, - DayObj: { 38: -7, 40: 7, 37: -1, 39: 1 }, - Aviailable: 'available', - Default: 'default', - Current: 'current', - InRange: 'in-range', - StartDate: 'start-date', - EndDate: 'end-date', - Selected: 'selected', - Disabled: 'disabled', - Range: 'range', - fullMonths: 'January,February,March,April,May,June,July,August,September,October,November,December'.split(','), - fullWeeks: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], - MonhtList: ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'], - Weeks: ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], - PlacementMap: { - left: 'bottom-start', - center: 'bottom', - right: 'bottom-end' - }, - QuarterMap: { - 0: 0, - 1: 3, - 2: 6, - 3: 9 - }, - MonthQuarterMap: { - 0: 1, - 3: 2, - 6: 3, - 9: 4 - }, - TriggerTypes: TriggerTypes.split(','), - DateFormats: { - year: 'yyyy', - years: 'yyyy', - yearrange: 'yyyy', - month: 'yyyy-MM', - time: 'HH:mm:ss', - week: 'yyyywWW', - date: 'yyyy-MM-dd', - timerange: 'HH:mm:ss', - monthrange: 'yyyy-MM', - daterange: 'yyyy-MM-dd', - datetime: 'yyyy-MM-dd HH:mm:ss', - datetimerange: 'yyyy-MM-dd HH:mm:ss' - }, - Time: 'time', - TimeRange: 'timerange', - Quarter: 'quarter', - IconTime: 'icon-time', - IconDate: 'icon-Calendar', - DateRange: 'daterange', - DateTimeRange: 'datetimerange', - MonthRange: 'monthrange', - TimeSelect: 'time-select', - TimesTamp: 'timestamp', - DateTime: 'datetime', - SelectbaleRange: 'selectableRange', - Start: '09:00', - End: '18:00', - Step: '00:30', - CompareOne: '-1:-1', - CompareHundred: '100:100', - selClass: '.selected', - queryClass: '.tiny-picker-panel__content', - disableClass: '.time-select-item:not(.disabled)', - defaultClass: '.default', - Qurtyli: '[data-tag="li"]', - MappingKeyCode: { 40: 1, 38: -1 }, - DatePicker: 'DatePicker', - TimePicker: 'TimePicker' -} - -export const BROWSER_NAME = { - IE: 'ie', - Edge: 'edge', - Chrome: 'chrome', - Firefox: 'firefox' -} - -export const MOUSEDELTA = 120 - -export const VALIDATE_STATE = { - Validating: 'validating', - Success: 'success', - Error: 'error' -} - -export const CASCADER = { - SvgStr: ' { - uLog.logger[type](data) -} - -export { xss } diff --git a/packages/mobile/utils/object.ts b/packages/mobile/utils/object.ts deleted file mode 100644 index 3bef45d5df..0000000000 --- a/packages/mobile/utils/object.ts +++ /dev/null @@ -1,445 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { hasOwn, typeOf, isObject, isPlainObject, isNull } from './type' - -/** - * 将对象的每个属性值进行循环处理。 - * - * let obj = { name: 'jacky', age: 28, job: 'coder', dept: 'it' } - * each(obj, function (field, value) { - * if (field === 'name') { - * // do something - * } - * }) - * - * @param {Object} obj 要处理的对象 - * @param {Function} handle 进行循环处理的函数,函数返回false, 则跳出循环 - */ -export const each = (obj: object, handle: (key: string, value?: any) => boolean) => { - if (typeof handle !== 'function') { - return - } - for (const name in obj) { - if (hasOwn.call(obj, name)) { - if (handle(name, obj[name]) === false) { - break - } - } - } -} - -/** 支持深度合并对象 - * 【首参为true】,则每一层是对象就合并, 但是简单值或数组时,就后面覆盖过来 - * 【首参为对象】,则仅第一层合并, 类似Object.assign - * 合并对象中,有非object类型的,统统忽略! - * @returns {Object} - */ - -// eslint-disable-next-line import/no-mutable-exports -let extend: (deep: boolean | object, ...values: object[]) => object - -/** - * 通过路径,获得对象指向位置的值。 - * - * getObj({ a: { b: 1 } }, 'a.b') // 1 - * getObj({ a: { b: 1 } }, 'data.a.b', true) // 1 - * getObj({ a: { b: undefined } }, 'a.b') // undefined - * - * @param {Object} data 查找数据源 - * @param {String} names 查找属性命名空间字符串 - * @param {Boolean} [isExceptRoot] 是否排除 names 的第一个节点,默认 false - * @returns {Object} - */ -export const getObj = (data: object, names: string, isExceptRoot?: boolean) => { - if (!data || !isPlainObject(data) || !names || typeof names !== 'string') { - return - } - - const nameArr = names.split('.') - - let obj = data - const len = nameArr.length - - if (len > 1) { - const startIndex = isExceptRoot ? 1 : 0 - - for (let i = startIndex; i < len; i++) { - obj = obj[nameArr[i]] - - if (isNull(obj)) { - return obj - } - } - - return obj - } else { - return obj[nameArr[0]] - } -} - -/** - * 通过路径,设置对象指向位置的值。 - * - * let obj = { limit: 5, data: { a: 1, b: 2 }, info: { a: 1, b: 2 } } - * setObj(obj, 'limit', 10) // obj.limit = 10 - * setObj(obj, 'data', { c: 3 }, true) // obj.data = { a: 1, b: 2, c: 3 } - * setObj(obj, 'info', { c: 3 }) // obj.info = { c: 3 } - * setObj(obj, 'info.c', { d: 4 }, true) // obj.info = { c: { d: 4 } } - * setObj(obj, 'info.c', { e: 5 }, true) // obj.info = { c: { d: 4, e: 5 } } - * - * @param {Object} data 设置数据源 - * @param {String} names 查找属性命名空间字符串 - * @param {Object} value 设置的值 - * @param {boolean} [isMerge] 是否覆盖还是合并,默认覆盖 - * @returns {Object} - */ -export const setObj = (data: object, names: string, value: any, isMerge) => { - if (!data || !isPlainObject(data) || !names || typeof names !== 'string') { - return data - } - - const nameArr = names.split('.') - - const obj = data - let len = nameArr.length - let item = nameArr[0] - - if (len > 1) { - len-- - - let tmpl = obj - let name, target - - for (let i = 0; i < len; i++) { - name = nameArr[i] - target = tmpl[name] - - if (target === null || !isPlainObject(target)) { - tmpl[name] = {} - target = tmpl[name] - } - - tmpl = target - } - - item = nameArr[len] - - isMerge - ? isPlainObject(tmpl[item]) - ? extend(true, tmpl[item], value) - : (tmpl[item] = value) - : (tmpl[item] = value) - } else { - isMerge - ? isPlainObject(obj[item]) - ? extend(true, obj[item], value) // - : (obj[item] = value) - : (obj[item] = value) - } - - return obj -} - -/** - * 根据指定的字段属性名,复制对应的数据。 - * - * let obj = { a: 1, b: '2', c: [3, 4, 5], d: { e: 'good' } } - * copyField(obj, ['a', 'b']) // { a: 1, b: '2' } - * copyField(obj, ['a', 'b'], false, true) // { c: [3, 4, 5], d: { e: 'good' } } - * - * @param {Object} data 源数据,合并数据源 - * @param {Array} [fields] 指定的值得命名空间字符串的数值。 不传入,默认为克隆一份数据出来 - * @param {Boolean} [isMerge] 是否覆盖还是合并,默认false覆盖 - * @param {Boolean} [isExclude] 是否排除指定的fields复制,默认false - * @returns {Array} - */ -export const copyField = (data: object, fields?: string[], isMerge?: boolean, isExclude?: boolean) => { - const setValue = (obj, result, name, key, isMerge?) => { - const include = key.indexOf(name) === 0 - const keySplit = key.split(name) - const hasNextDot = keySplit[1] && keySplit[1].indexOf('.') === 0 - - if (name === key || (include && hasNextDot)) { - if (name !== key) { - each(getObj(obj, name), (field) => { - setValue(obj, result, `${name}.${field}`, key) - return true - }) - } - } else { - if (fields && !fields.includes(name)) { - setObj(result, name, getObj(obj, name), isMerge) - } - } - } - const innerCopyFields = (obj, fields, isMerge, isExclude) => { - const result = {} - - if (isExclude) { - each(obj, (name) => fields.forEach((key) => setValue(obj, result, name, key, isMerge))) - } else { - fields.forEach((field) => setObj(result, field, getObj(obj, field), isMerge)) - } - - return result - } - - if (isPlainObject(data)) { - return Array.isArray(fields) - ? innerCopyFields(data, fields, isMerge, isExclude) - : extend(isMerge !== false, {}, data) - } - - return data -} - -/** - * 复制数组数据,数据如包含对象,则深度复制,并返回一个新数组,如果不是数组则直接返回原对象。 - * - * let arr1 = [ 1, 2, { name: 'jacky' } ] - * let arr2 = copyArray(arr1) - */ -export const copyArray = (arr: any[]) => { - return Array.isArray(arr) ? arr.map((item) => copyField(item)) : arr -} - -/** - * 对象复制,支持深度复制,修复 $.extend 数组复制的问题, 参数同 $.extend。 - * - * let obj1 = { a: 1, b: 2 } - * let obj2 = { c: 3, d: 4 } - * extend(obj1, obj2) // { a: 1, b: 2, c: 3, d: 4 } - * - * @param {Boolean} deep 如果是 true,合并成为递归(又叫做深拷贝)。仅支持 true | 空 - * @param {Object} target 对象扩展,这将接收新的属性。 - * @param {Object} object1 一个对象,它包含额外的属性合并到第一个参数。 - * @param {Object} objectN 包含额外的属性合并到第一个参数 - * @returns {Object} - */ - -const deepCopy = (target, name, deep, copy, src) => { - let copyIsArray - if (deep && copy && (isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { - if (copyIsArray) { - copyIsArray = false - target[name] = copyArray(copy) - } else { - const clone = src && isPlainObject(src) ? src : {} - target[name] = extend(deep, clone, copy) - } - } else if (copy !== undefined) { - try { - target[name] = copy - } catch (e) { - // do nothing - } - } -} - -extend = function (...args) { - const length = args.length - let target = args[0] || {} - let i = 1 - let deep = false - - if (typeOf(target) === 'boolean') { - deep = target as boolean - target = args[i] || {} - i++ - } - - if (!isObject(target) && typeOf(target) !== 'function') { - target = {} - } - - for (; i < length; i++) { - const options = args[i] - - if (options !== null && isObject(options)) { - const names = Object.keys(options) - - for (const name of names) { - const src = target[name] - const copy = options[name] - - if (target !== copy) { - deepCopy(target, name, deep, copy, src) - } - } - } - } - - return target -} as any - -/** - * 可深层比较两个对象或两个数组是否相等。注意以源对象为比较基础 - * - * isEachEqual({a: 1}, {a: 1, b: 2}) // true - * isEachEqual({a: 1, b: 2}, {a: 1}) // false (以源对象为比较基础,所以它是false) - * isEachEqual({a: 1, b: {c: 3, d: 4}}, {a: 1, b: {c: 3, d: 5}}) // false - * - * @param {Object} data1 数据源对象 - * @param {Object} data2 对比目标对象 - * @param {Boolean} [deep] 是否深度遍历,默认为true - * @returns {Boolean} - */ -// eslint-disable-next-line import/no-mutable-exports -let isEachEqual: (data1: any, data2: any, deep?: boolean) => boolean - -/** - * 可深层比较两个对象是否相等。 - * 与`isEachEqual` 区别是: - * 1、2个对象交换位置,判断2次 - * 2、它可以指定要比较的属性分支["a.b","a.c"] (整个系统使用fields这块功能) - * - * isEqual({ a: { b: 1 } }, { a: { b: 1, c: 2 } }, false, [ 'a.b' ]) // false - * isEqual({ a: { b: 1 } }, { a: { b: 1, c: 2 } }, true, [ 'a.b' ]) // true - * - * @param {Object} sourceData 源对象 - * @param {Object} targetData 目标对象 - * @param {Boolean} [deep] 是否深度比较,默认为true - * @param {Array} [fields] 指定需要比较的字段的数组 - * @returns {Boolean} - */ -export const isEqual: (sourceData: object, targetData: object, deep?: boolean, fields?: string[]) => boolean = ( - sourceData: object, - targetData: object, - deep?: boolean, - fields?: string[] -) => { - if (typeOf(sourceData) === typeOf(targetData)) { - deep = deep !== false - - if (Array.isArray(fields)) { - const _sourceData = copyField(sourceData, fields) - const _targetData = copyField(targetData, fields) - - return isEqual(_sourceData, _targetData, deep) as boolean - } - - // 此处交换了位置判断 - const source = isEachEqual(sourceData, targetData, deep) - const target = isEachEqual(targetData, sourceData, deep) - - return source && target - } - - return false -} - -isEachEqual = (data1: any, data2: any, deep?: boolean) => { - if (!isPlainObject(data1)) { - // 当是数组的情况 - if (!Array.isArray(data1)) { - return data1 === data2 - } - if (data1.length !== data2.length) { - return false - } - - for (let i = 0, length = data1.length; i < length; i++) { - const result = isEqual(data1[i], data2[i], deep) - - if (!result) { - return false - } - } - - return true - } - // 对象的情况 - let bEqual = true - const names = Object.keys(data1) - - for (const name of names) { - if (hasOwn.call(data2, name)) { - const _data1 = data1[name] - const _data2 = data2[name] - - if ((deep && isObject(_data1)) || Array.isArray(_data1)) { - bEqual = isEachEqual(_data1, _data2, deep) - } else { - bEqual = _data1 === _data2 - } - } else { - bEqual = false - } - - if (bEqual === false) { - break - } - } - - return bEqual -} - -export { isEachEqual, extend } - -/** - * 将json对象序列化为字符串。 - * - * let obj = { a: 1, b: 2 } - * toJsonStr(obj) // '{"a":1,"b":2}' - * obj.prop = obj - * toJsonStr(obj) // undefined 递归引用自己了,所以catch了 - * toJsonStr(null) // 'null' - * - * @param {Object} obj - * @returns {String} - */ -export const toJsonStr = (obj: any) => { - try { - return JSON.stringify(obj) - } catch (e) { - return undefined - } -} - -/** - * 将一个或多个源对象简单合并到目标对象中,合并时排除非 OwnProperty 及 undefined 属性。 - * 只处理第一层,功能基本等同于 Object.assign - * - * merge({ a: 1 }, { b: { c: 2 } }, { d: 3 }) // { a: 1, b: { c: 2 }, d: 3 } - * - * @param {Object} target 目标对象 - * @param {Object} [source] 源对象 - * @returns {Object} - */ -export const merge = function (target: object, ...rest: object[]) { - for (let i = 0, len = rest.length; i < len; i++) { - const source = rest[i] || {} - - for (const prop in source) { - if (hasOwn.call(source, prop)) { - const value = source[prop] - - if (value !== undefined) { - target[prop] = value - } - } - } - } - - return target -} - -export const cloneDeep = (data) => { - if (isObject(data)) { - return extend(true, data) - } else if (Array.isArray(data)) { - return copyArray(data) - } else { - return data - } -} diff --git a/packages/mobile/utils/runtime.ts b/packages/mobile/utils/runtime.ts deleted file mode 100644 index aa28e2c2b7..0000000000 --- a/packages/mobile/utils/runtime.ts +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -/* - * 以下是能对外抛出给用户使用的通用方法(运行时用) - * 涉及以下的依赖统一使用包名路径的形式引入 - * 导出对象命名规范:以文件名称的驼峰格式 - */ -import * as array from './array' -import browser from './browser' -import * as date from './date' -import * as decimal from './decimal' -import * as object from './object' -import * as string from './string' -import * as type from './type' -import * as dataset from './dataset' -import afterLeave from './deps/after-leave' -import clickoutside from './deps/clickoutside' -import debounce from './deps/debounce' -import * as dom from './deps/dom' -import popper from './deps/popper' -import popupManager from './deps/popup-manager' -import * as resizeEvent from './deps/resize-event' -import * as scrollbarWidth from './deps/scrollbar-width' -import throttle from './deps/throttle' -import vueEmitter from './deps/vue-emitter' -import vuePopper from './deps/vue-popper' - -/** TINY_NO_NEED 这个包只是dialog-box 自己使用的一个中间包,暴露给用户,用户也不会使用它呀 */ -import vuePopup from './deps/vue-popup' -import validate from './validate' -import memorize from './deps/memorize' -import * as common from '.' - -const Renderless = { - browser, - array, - date, - object, - decimal, - type, - string, - afterLeave, - dataset, - clickoutside, - dom, - debounce, - popper, - resizeEvent, - popupManager, - scrollbarWidth, - vueEmitter, - vuePopper, - throttle, - vuePopup, - memorize, - common, - validate -} - -export default Renderless - -export { - array, - browser, - date, - decimal, - object, - string, - type, - dataset, - afterLeave, - clickoutside, - debounce, - dom, - popper, - popupManager, - resizeEvent, - scrollbarWidth, - throttle, - vueEmitter, - vuePopper, - vuePopup, - validate, - memorize, - common -} diff --git a/packages/mobile/utils/string.ts b/packages/mobile/utils/string.ts deleted file mode 100644 index 20ba3663ee..0000000000 --- a/packages/mobile/utils/string.ts +++ /dev/null @@ -1,832 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { isPlainObject, isNumber, isNumeric, isNull } from './type' -import { getObj, toJsonStr } from './object' -import { toFixed, Decimal } from './decimal' - -/** - * 文本替换格式类型 - */ -export const formatTypes = { - text: 'text', - url: 'url', - html: 'html', - tmpl: 'tmpl' -} - -/** - * 字符对应的字符编码 - */ -export const escapeChars = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '[': '[', - ']': ']' -} - -/** - * 判断是否为null、undefined、空字符串 - * - * isNullOrEmpty('') // true - * - * @param {Object} value 需判断的对象 - * @return {Boolean} - */ -export const isNullOrEmpty = (value) => - value === null || value === undefined || (typeof value === 'string' && value.trim().length === 0) - -function cached(fn) { - let cache = Object.create(null) - - return function cachedFn(str) { - const hit = cache[str] - return hit || (cache[str] = fn(str)) - } -} - -const camelizeRE = /-(\w)/g -export const camelize = cached((str) => str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''))) - -/** - * 将字符串首写字母大写。 - * - * capitalize('hello') // "Hello" - * - * @param {String} string 要转换的字符串 - * @returns {String} - */ -export const capitalize = cached((str) => str.charAt(0).toUpperCase() + str.slice(1)) - -const hyphenateRE = /\B([A-Z])/g -export const hyphenate = cached((str) => str.replace(hyphenateRE, '-$1').toLowerCase()) - -/** - * 解析Json字符串成对象。 - * - * let str = '{ "value": "v1", "text": "t1" }' - * toJson(str) // { value: 'v1', text: 't1' } - * - * @param {String} string 要解析的Json字符串 - * @returns {Object} - */ -export const toJson = (string) => { - try { - return JSON.parse(string) - } catch (e) { - return undefined - } -} - -function getLengthInUtf16(string) { - const len = string.length - let count = 0 - - for (let i = 0; i < len; i++) { - let charCode = string.charCodeAt(i) - - /* istanbul ignore else */ - if (charCode <= 0xffff) { - count += 2 - } else { - count += 4 - } - } - - return count -} - -function getLengthInUtf8(string) { - const len = string.length - let count = 0 - - for (let i = 0; i < len; i++) { - let charCode = string.charCodeAt(i) - - /* istanbul ignore else */ - if (charCode <= 0x007f) { - count += 1 - } else if (charCode <= 0x07ff) { - count += 2 - } else if (charCode <= 0xffff) { - count += 3 - } else { - count += 4 - } - } - - return count -} - -function getLengthDefault(string) { - const len = string.length - let count = 0 - - for (let i = 0; i < len; i++) { - count++ - - if (string.charCodeAt(i) >> 8) { - count++ - } - } - - return count -} - -/** - * 计算字符串长度或所占的内存字节数。 - * 默认计算方式(中文算两个长度,数字字母算一个),也可指定为 'basic','UTF-16','UTF-8',或自定义的计算规则。 - * - * getLength('12ED') // => 4 - * getLength('深圳') // => 4 - * getLength('好a','basic') // '好a' => 2,'a' => 1 - * getLength('好a','UTF-8') // 好a' => 4,'a' => 1 - * getLength('好a','UTF-16') //'好a' => 4,'a' => 2 - * getLength(str, function (str) { - * return (str + 'xx').length - * }) - * - * UTF-8 是一种可变长度的 Unicode 编码格式,使用一至四个字节为每个字符编码 - * - * 000000 - 00007F(128个代码) 0zzzzzzz(00-7F) 一个字节 - * 000080 - 0007FF(1920个代码) 110yyyyy(C0-DF) 10zzzzzz(80-BF) 两个字节 - * 000800 - 00D7FF 注: Unicode在范围 D800-DFFF 中不存在任何字符 - * 00E000 - 00FFFF(61440个代码) 1110xxxx(E0-EF) 10yyyyyy 10zzzzzz 三个字节 - * 010000 - 10FFFF(1048576个代码) 11110www(F0-F7) 10xxxxxx 10yyyyyy 10zzzzzz 四个字节 - * - * - * 定义参考 http://zh.wikipedia.org/wiki/UTF-8 - * - * UTF-16 大部分使用两个字节编码,编码超出 65535 的使用四个字节 - * - * 000000 - 00FFFF 两个字节 - * 010000 - 10FFFF 四个字节 - * - * 定义参考 http://zh.wikipedia.org/wiki/UTF-16 - * - * @param {String} string - * @param {String|Function} regular 长度规则:'basic'、'UTF-16'、'UTF-8'或自定义的计算规则函数 - * @return {Number} - */ -export const getLength = (string, regular) => { - if (!string || typeof string !== 'string') { - return 0 - } - - let count = 0 - - if (typeof regular === 'string') { - regular = regular.toLowerCase() - - if (regular === 'utf-16' || regular === 'utf16') { - count = getLengthInUtf16(string) - } else if (regular === 'utf-8' || regular === 'utf8') { - count = getLengthInUtf8(string) - } else { - count = string.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '_').length - } - } else if (typeof regular === 'function') { - return regular(string) - } else { - count = getLengthDefault(string) - } - - return count -} - -/** - * 填充字符串,根据填充模式参数,在字符串前面或后面补充字附到指定的长度。 - * - * fillChar('1', 3) // "001" - * fillChar('1', 3, true) // "100" - * fillChar('1', 3, true, ' ') // "1 " - * - * @param {String} string 被填充的字符串 - * @param {Number} length 填充到某个长度 - * @param {Boolean} [append=false] 是否在后面填充,默认为在前面填充 - * @param {String} [chr="0"] 填充的字符,默认为0 - * @returns {String} - */ -export const fillChar = (string, length, append, chr = '0') => { - if (typeof string === 'string' && typeof chr === 'string' && isNumber(length)) { - let len = string.length - length - - if (len > 0) { - return append ? string.substr(0, length) : string.substr(len, length) - } else { - const appendStr = [] - len = Math.abs(len) / chr.length - - for (; len > 0; len--) { - appendStr.push(chr) - } - - const s = appendStr.join('') - - return append ? string + s : s + string - } - } -} - -export const random = () => { - let MAX_UINT32_PLUS_ONE = 4294967296 - return window.crypto.getRandomValues(new window.Uint32Array(1))[0] / MAX_UINT32_PLUS_ONE -} - -/** - * 生成一个guid。 - * - * guid('#') // #16722423 - * - * @param {String} [prefix] guid前缀,可选值,默认为空字符串 - * @param {Number} [length] 生成的guid的长度,可选值,默认为8 - * @returns {String} - */ -export const guid = (prefix = '', length = 8) => prefix + random().toString().substr(2, length) -/** - * 将HTML字符串进行编码。 - * - * escapeHtml('
&&
') // "<div>&&</div>" - * - * @param {String} string 要编码的字符串 - * @param {Boolean} [isReplaceSpace] 是否替换空格 - * @returns {String} - */ -export const escapeHtml = (string, isReplaceSpace) => { - if (!string || typeof string !== 'string') { - return string - } - - string = string.replace(/[&<>"']/g, (chr) => escapeChars[chr]) - return isReplaceSpace ? string.replace(/\s/g, ' ') : string -} - -/** - * 将URL字符串进行转义。 - * - * let str = '< >& []""' + "'" - * escape(str) // "< >& []""'" - * escape(str, 'uri', true) // "%3C%20%3E%26%20%5B%5D%22%22'" - * escape(str, true) // "< >& []""'" - * escape(str, 'html', true) // "< >& []""'" - * escape(str, 'prop', true) // "< >& []""'" - * - * @param {String} string 需要转换的字符串 - * @param {String} [escapeType] 转换类型,可选值:uri, html, prop - * @param {Boolean} [isReplaceSpace] 是否替换空格, 默认不替换 - * @returns {String} - */ -export const escape = (string, escapeType, isReplaceSpace) => { - if (!string || typeof string !== 'string') { - return string - } - - if (typeof escapeType === 'boolean') { - isReplaceSpace = !!escapeType - } - - if (escapeType === 'uri') { - return encodeURIComponent(string) - } else if (escapeType === 'html') { - return escapeHtml(string, isReplaceSpace) - } else if (escapeType === 'prop') { - string = escapeHtml(string, isReplaceSpace) - return string.replace(/[[\]]/g, (chr) => escapeChars[chr]) - } - - string = string.replace(/[<>"]/g, (chr) => escapeChars[chr]) - return isReplaceSpace ? string.replace(/\s/g, ' ') : string -} - -const getFormat = ({ sign, format, hasSign }) => { - switch (sign) { - case '#': - format = formatTypes.text - break - case '@': - format = formatTypes.url - break - case '$': - format = formatTypes.html - break - case '%': - format = formatTypes.tmpl - break - default: - hasSign = false - break - } - - return { format, hasSign } -} - -/** - * 使用具体的对象字段代替字符串中的字段占位符。 - * - * fieldFormat('url:{{url}}', { url: 'http://abc.com/a&b' }) // "url:http://abc.com/a&b" - * fieldFormat('url:{{#url}}', { url: 'http://abc.com/a&b' }) // "url:http://abc.com/a&b" - * fieldFormat('url:{{@url}}', { url: 'http://abc.com/a&b' }) // "url:http%3A%2F%2Fabc.com%2Fa%26b" - * fieldFormat('url:{{$url}}', { url: 'http://abc.com/a&b' }) // "url:http://abc.com/a&b" - * fieldFormat('url:{{%url}}', { url: 'http://abc.com/a&b' }) // "url:{{http://abc.com/a&b}}" - * - * @param {String} string 要替换的字符串模板 - * @param {Object} data 要替换模板的数据 - * @param {String} [type="html"] 替换的类型:"text"、"url"、"tmpl"、"html",默认"html" - * @returns {String} - */ -export const fieldFormat = (string, data, type = 'html') => { - if (typeof string === 'string') { - return string.replace(/(\/)?\{\{([\s\S]*?)}}/g, (match, slash = '', offset = '') => { - const sign = offset.substr(0, 1) - let hasSign = true - let format = formatTypes.html - let ret = getFormat({ sign, format, hasSign }) - - format = ret.format - hasSign = ret.hasSign - - if (hasSign) { - offset = (offset || '').substring(1) - } else if (type) { - format = type - } - - let value = getObj(data, offset) - - if (isNull(value)) { - value = '' - } - - if (format === formatTypes.tmpl) { - value = `{{${value}}}` - } else { - if (format === formatTypes.url) { - value = encodeURIComponent(value) - } else { - value = format === formatTypes.html ? escapeHtml(value) : value - } - } - - return format === formatTypes.url && value.length === 0 ? '' : slash + value - }) - } -} - -const getFormatText = () => (str, reg, args, format) => - str.replace(reg, (m, i, j, k) => { - if (!isNullOrEmpty(i) && !isNullOrEmpty(k)) { - return `{${j}}` - } - - const value = args[j] - const string = isPlainObject(value) ? toJsonStr(value) : value - - if (isNullOrEmpty(value)) { - return '' - } - - return typeof value === 'string' && typeof format === 'function' ? format(string) : string - }) - -const getResult = ({ type, res, formatText, string, reg, args }) => { - if (type === formatTypes.url) { - res = formatText(string, reg, args, encodeURIComponent) - } else if (type === formatTypes.html) { - res = formatText(string, reg, args, escapeHtml) - } else { - res = formatText(string, reg, args) - } - - return res -} - -const judgForFunc = (args, formatTypes, type) => { - const lastArg = args[args.length - 1] - - if (lastArg !== formatTypes.text && lastArg !== formatTypes.url && lastArg !== formatTypes.html) { - args = Array.prototype.slice.call(args, 1) - } else { - args = Array.prototype.slice.call(args, 1, args.length - 1) - type = lastArg - } - - return { args, type } -} - -const checkParam = ({ data, args, type, _arguments }) => { - if (Array.isArray(data)) { - args = data - } else { - const judgObj = judgForFunc(_arguments, formatTypes, type) - - args = judgObj.args - type = judgObj.type - } - - return { args, type } -} - -/** - * 使用具体的值替换字符串中的数字占位符。 - * - * format('{0}', 1) // "1" - * format('{0}', 1, 'text') // "1" - * format('{0}{1}', [1, 2, 'text']) // "12" - * format('age:{{age}}', { age: 20 }) // "age:20" - * format('\\{0\\}{1}', [0, 1]) // "{0}1" - * format('{0}', [{ age: 20 }]) // "{"age":20}" - * format('{0}', [ 'http://abc.com/a&b' ], 'url') // "http%3A%2F%2Fabc.com%2Fa%26b" - * format('{0}', [ '
&&
' ], 'html') // "<div>&&</div>" - * - * @param {String} string 要替换的字符串模板 - * @param {Object|Array|String} data 要替换模板的数据 - * @param {String} [type="text"] 替换的类型:"text"、"url"、"html",默认"text" - * @returns {String} - */ -export const format = function (string, data, type = 'text') { - if (typeof string !== 'string' || arguments.length < 2) { - return string - } - - let args, res - - if (isPlainObject(data)) { - return fieldFormat(string, data, type) - } - - // eslint-disable-next-line prefer-rest-params - const ret = checkParam({ data, args, type, _arguments: arguments }) - - args = ret.args - type = ret.type - - const reg = /(\\)?\{(\d+)(\\)?}/g - const formatText = getFormatText() - - res = getResult({ type, res, formatText, string, reg, args }) - - return res -} - -const getTruthyValue = ({ string, length, ellipsis }) => { - const flag = typeof string === 'string' && isNumber(length) && length < string.length - const truthyValue = flag && format(ellipsis, string.substr(0, length)) - - return { flag, truthyValue } -} - -/** - * 将字符串按指定长度截断。 - * - * truncate('abc', 5) // "abc" - * truncate('abc', 2) // "ab..." - * - * @param {String} string 要截断的字符串 - * @param {Number} length 要截断的长度 - * @param {String} [ellipsis="{0}..."] 截断类型,通常携带{0}占位符 - * @returns {String} - */ -export const truncate = (string, length, ellipsis = '{0}...') => { - const { flag, truthyValue } = getTruthyValue({ string, length, ellipsis }) - - return flag ? truthyValue : string -} - -/** - * 尝试按指定函数转换字符串,如果转换结果为 NaN,则返回 defaultValue。 - * - * tryToConvert(toInt, null, 0) // 0 - * - * @param {Function} convert 指定的转换的函数 - * @param {Number|String} defaultValue 若为 NaN 时,返回的缺省值 - * @param {Number|String} value 要转换的字符串或多个参数 - * @returns {Number|String} - */ -export const tryToConvert = (convert, defaultValue, ...args) => { - // eslint-disable-next-line prefer-spread - const result = convert.apply(null, args) - return isNaN(result) ? defaultValue : result -} - -/** - * 将字符串解析成十进制整数。 - * - * toInt(100) // 100 - * toInt('100.01') // 100 - * - * @param {Number|String} value 要解析的字符串 - * @returns {Number} - */ -export const toInt = (value) => - isNumber(value) ? Number(value.toFixed(0)) : typeof value === 'string' ? parseInt(value, 10) : NaN - -/** - * 尝试将字符串解析成十进制整数。如果 value 是个无效的整数,则返回 defaultValue。 - * - * tryToInt(100) // 100 - * tryToInt('100.01') // 100 - * tryToInt(null, 100) // 100 - * - * @param {Number|String} value 要解析的字符串 - * @param {Number|String} defaultValue 若为 NaN 时,返回的缺省值 - * @returns {Number|String} - */ -export const tryToInt = (value, defaultValue) => tryToConvert(toInt, defaultValue, value) - -/** - * 将字符串解析成数值。 - * - * toNumber(100) // 100 - * toNumber('100.01') // 100.01 - * - * @param {Number|String} value 要解析的字符串 - * @returns {Number} - */ -export const toNumber = (value) => (isNumber(value) ? value : typeof value === 'string' ? parseFloat(value) : NaN) - -/** - * 尝试将字符串解析成数值。如果 value 是个无效的数字,则返回 defaultValue。 - * - * tryToNumber(100) // 100 - * tryToNumber('100.01') // 100.01 - * tryToNumber(null, 100) // 100 - * - * @param {Number|String} value 要解析的字符串 - * @param {Number|String} defaultValue 若为 NaN 时,返回的缺省值 - * @returns {Number|String} - */ -export const tryToNumber = (value, defaultValue) => tryToConvert(toNumber, defaultValue, value) - -/** - * 将字符串解析成浮点数。 - * - * toDecimal(100) // "100.00" - * toDecimal("100.01", 2) // "100.01" - * toDecimal(0.8 - 0.6, 2, true) // "0.2" - * toDecimal(0.8 - 0.6, 2, false) // "0.20" - * - * @param {Number|String} value 要解析的数字或字符串 - * @param {Number} [fraction=2] 浮点数的小数部分,默认2位 - * @param {Boolean} [isTruncate=false] 是否截断,默认为四舍五入,不截断 - * @returns {String} - */ -export const toDecimal = (value, fraction = 2, isTruncate = false) => { - let result = NaN - - if (isNumber(value)) { - result = value - } - - if (typeof value === 'string') { - const val = parseFloat(value) - if (!isNaN(val)) { - result = val - } - } - - if (isNumber(result)) { - if (isTruncate) { - result = toFixed( - value - .toString() - .split('.') - .slice(0, 2) - .map((str, index) => (index ? str.slice(0, fraction) : str)) - .join('.'), - fraction - ) - } else { - result = toFixed(result, fraction) - } - } - - return result -} - -/** - * 尝试将字符串解析成浮点数。如果 value 是个无效的浮点数,则返回 defaultValue。 - * - * tryToDecimal(100) // "100.00" - * tryToDecimal("100.01", 2) // "100.01" - * tryToDecimal(0.8 - 0.6, 2, true) // "0.2" - * tryToDecimal(0.8 - 0.6, 2, false) // "0.20" - * tryToDecimal(null, 2, false, 100) // 100 - * - * @param {Number|String} value 要解析的数字或字符串 - * @param {Number} [fraction=2] 浮点数的小数部分,默认2位 - * @param {Boolean} [isTruncate=false] 是否截断,默认为四舍五入,不截断 - * @param {Number|String} [defaultValue] 若为 NaN 时,返回的缺省值 - * @returns {Number|String} - */ -export const tryToDecimal = (value, fraction, isTruncate, defaultValue) => - tryToConvert(toDecimal, defaultValue, value, fraction, isTruncate) - -/** - * 将数字或字符串转换成货币格式。 - * - * toCurrency(100) // "100.00" - * toCurrency(100, 2) // "100.00" - * toCurrency(1234.56) // "1,234.56" - * toCurrency(100, 2, '${0}') // "$100.00" - * - * @param {Number|String} value 要解析的数字或字符串 - * @param {Number} [fraction=2] 浮点数的小数部分,默认2位 - * @param {String} [placeholder] 货币符号,占位符格式,例如 "${0}" - * @param {Boolean} [isTruncate=false] 是否截断,默认为四舍五入,不截断 - * @returns {String} - */ -export const toCurrency = (value, fraction, placeholder, isTruncate) => { - if (isNumeric(value)) { - let val = toDecimal(Number(value), fraction, isTruncate) - val = String(val).replace(/(^|[^\w.])(\d{4,})/g, ($0, $1, $2) => $1 + $2.replace(/\d(?=(?:\d\d\d)+(?!\d))/g, '$&,')) - return placeholder ? format(placeholder, val) : val - } - - return NaN -} - -/** - * 尝试将数字转换成货币格式。如果 value 是个无效的金额,则返回 defaultValue。 - * - * tryToCurrency(100) // "100.00" - * tryToCurrency(100, 2) // "100.00" - * tryToCurrency(1234.56) // "1,234.56" - * tryToCurrency(100, 2, '${0}') // "$100.00" - * tryToCurrency(null, 3, '¥{0}', '金额错误') // "金额错误" - * - * @param {Number|String} value 要转换的数值 - * @param {Number} [fraction=2] 浮点数的小数部分,默认2位 - * @param {String} [placeholder] 货币符号,占位符格式,例如 "${0}" - * @param {Number|String} [defaultValue] 若为 NaN 时,返回的缺省值 - * @returns {Number|String} - */ -export const tryToCurrency = (value, fraction, placeholder, defaultValue) => - isNaN(toNumber(value)) ? defaultValue : toCurrency(value, fraction, placeholder) - -/** - * 转换成布尔值或0(表示false),1(表示true)。 - * - * toBoolValue(1) // 1 - * toBoolValue(true) // true - * toBoolValue('true') // true - * toBoolValue({}) // true - * toBoolValue('') // false - * - * @param {Number|String|Boolean} value 要转换的值 - * @returns {Boolean|number} - */ -export const toBoolValue = (value) => { - if (isNumber(value)) { - return value ? 1 : 0 - } else if (isNull(value) || value === 'false') { - return false - } else if (value === 'true') { - return true - } else if (typeof value === 'boolean') { - return value - } - - return !!value -} - -/** - * 将数值按百分比显示。 - * - * toRate(0.1) // "10.00%" - * toRate(10, 100, 2) // "10.00%" - * - * @param {Number} value 要转换的值 - * @param {Number} [total=1] 百分比基数,默认为1 - * @param {Number} [fraction=2] 数值的小数部分,默认为2 - * @returns {String} - */ -export const toRate = (value, total = 1, fraction = 2) => - isNumber(value) && isNumber(total) ? toDecimal(Decimal(value).mul(100).div(total).toNumber(), fraction) + '%' : value - -/** - * 文件大小值 单位互相转换。 - * - * toFileSize(1024) // "1.00KB" - * toFileSize(1024, 'B') // "1024.00B" - * toFileSize(1024, 'KB', 'B') // "1.00KB" - * toFileSize(1024, 'MB', 'KB') // "1.00MB" - * - * @param {Number} value 文件大小数值 - * @param {String} unit 转换后的单位 - * @param {String} [currUnit] 当前大小单位,默认为B,值可为B、KB、MB、GB、TB、PB、EB、ZB、YB - * @returns {String} - */ -export const toFileSize = (value, unit, currUnit) => { - if (isNumeric(value)) { - value = Number(value) - - if (value === 0) { - return `0${currUnit || unit || 'B'}` - } - - const fileSize = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] - - let index = fileSize.indexOf(currUnit) - if (index > -1) { - for (let i = 0; i < index; i++) { - value *= 1024 - } - } - - index = fileSize.indexOf(unit) - if (index < 0) { - index = fileSize.length - 1 - } - - let level = 0 - for (let i = 0; i < index && (value <= -1024 || value >= 1024); i++) { - value /= 1024.0 - level++ - } - - return toDecimal(value, 2) + fileSize[level] - } - - return value -} - -/** - * 文件大小值,单位自动转化,最多保留2位小数 - * - * formatFileSize(17252 * 1024) // "16.84M" - * formatFileSize(200 * 1024, 'M') // "200G" - * - * @param {Number} size 文件大小数值 - * @param {String} [baseUnit] 当前大小单位,默认为 B,值可为 B、K、M、G、T、P、E、Z、Y - * @returns {String} 转化后的文件大小和单位 - */ -export const formatFileSize = (size, baseUnit = '') => { - if ([undefined, null].includes(size)) { - return '' - } else if (!isNumber(size) || size <= 0) { - return size + baseUnit - } - - const unitArr = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] - let unitIndex = Math.max(unitArr.indexOf((baseUnit + '').toLocaleUpperCase()), 0) - - while (size >= 1024 && unitIndex < unitArr.length - 1) { - size = size / 1024.0 - unitIndex++ - } - - while (size < 1 && unitIndex > 0) { - size = size * 1024 - unitIndex-- - } - - return parseFloat(toDecimal(size, 2, true)) + ' ' + unitArr[unitIndex] -} - -/** - * 检查文本中是否包含韩文 - * @param {String} text - */ -export const isKorean = (text) => /([(\uAC00-\uD7AF)|(\u3130-\u318F)])+/gi.test(text) - -/** - * 对字符串进行省略截取 - * @param {*} text 待处理的字符串 - * @param {*} font 字符集,例如 '14px Arial' - * @param {*} w 字符串显示最大长度 - * @returns obj obj.t为处理后字符串,obj.o为是否已省略标志 - */ -export const omitText = (text: string, font: string, w: number) => { - const canvas = document.createElement('canvas') - const ctx = canvas.getContext('2d') - - ctx.font = font - - let metric = ctx.measureText(text) - let t: string - - if (metric.width < w) { - return { t: text, o: false } - } else { - for (let i = -1; ; i--) { - t = text.slice(0, i) + '...' - metric = ctx.measureText(t) - - if (metric.width < w) { - return { t, o: true } - } - } - } -} diff --git a/packages/mobile/utils/type.ts b/packages/mobile/utils/type.ts deleted file mode 100644 index 63197ddbd8..0000000000 --- a/packages/mobile/utils/type.ts +++ /dev/null @@ -1,164 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -export const toString = Object.prototype.toString -export const hasOwn = Object.prototype.hasOwnProperty - -const getProto = Object.getPrototypeOf -const fnToString = hasOwn.toString -const ObjectFunctionString = fnToString.call(Object) - -const class2type = { - '[object Error]': 'error', - '[object Object]': 'object', - '[object RegExp]': 'regExp', - '[object Date]': 'date', - '[object Array]': 'array', - '[object Function]': 'function', - '[object AsyncFunction]': 'asyncFunction', - '[object String]': 'string', - '[object Number]': 'number', - '[object Boolean]': 'boolean' -} - -/** 判断是否为 null / undefined */ -export const isNull = (x: any) => x === null || x === undefined - -/** - * 返回 JavaScript 对象的类型。 - * - * 如果对象是 undefined 或 null,则返回相应的'undefined'或'null'。 - * - * 其他一切都将返回它的类型'object'。 - * - * typeOf( undefined ) === 'undefined' - * typeOf() === 'undefined' - * typeOf( window.notDefined ) === 'undefined' - * typeOf( null ) === 'null' - * typeOf( true ) === 'boolean' - * typeOf( 3 ) === 'number' - * typeOf( "test" ) === 'string' - * typeOf( function (){} ) === 'function' - * typeOf( [] ) === 'array' - * typeOf( new Date() ) === 'date' - * typeOf( new Error() ) === 'error' - * typeOf( /test/ ) === 'regExp' - * - */ -export const typeOf: (obj: any) => string = (obj) => - isNull(obj) ? String(obj) : class2type[toString.call(obj)] || 'object' - -/** - * 判断对象是否为 object 类型。 - * - * isObject({}) // true - */ -export const isObject = (obj: any) => typeOf(obj) === 'object' - -/** - * 判断对象是否为 function 类型。 - * - * isObject(function (){) // true - - */ -export const isFunction = (fn: any) => ['asyncFunction', 'function'].includes(typeOf(fn)) - -/** - * 判断对象是否为简单对象。 - * - * 即不是 HTML 节点对象,也不是 window 对象,而是纯粹的对象(通过 '{}' 或者 'new Object' 创建的)。 - * - * let obj = {} - * isPlainObject(obj) //true - */ -export const isPlainObject = (obj: any) => { - if (!obj || toString.call(obj) !== '[object Object]') { - return false - } - - const proto = getProto(obj) - if (!proto) { - return true - } - - const Ctor = hasOwn.call(proto, 'constructor') && proto.constructor - return typeof Ctor === 'function' && fnToString.call(Ctor) === ObjectFunctionString -} - -/** - * 检查对象是否为空(不包含任何属性)。 - * - * let obj = {} - * isEmptyObject(obj) // true - */ -export const isEmptyObject = (obj: any) => { - const type = typeOf(obj) - - if (type === 'object' || type === 'array') { - for (const name in obj) { - if (hasOwn.call(obj, name)) { - return false - } - } - } - - return true -} - -/** - * 判断对象是否为数字类型。 - * - * isNumber(369) // true - */ -export const isNumber = (value: any) => typeof value === 'number' && isFinite(value) - -/** - * 判断对象是否代表一个数值。 - * - * isNumeric('-10') // true - * isNumeric(16) // true - * isNumeric(0xFF) // true - * isNumeric('0xFF') // true - * isNumeric('8e5') // true - * isNumeric(3.1415) // true - * isNumeric(+10) // true - * isNumeric('') // false - * isNumeric({}) // false - * isNumeric(NaN) // false - * isNumeric(null) // false - * isNumeric(true) // false - * isNumeric(Infinity) // false - * isNumeric(undefined) // false - */ -export const isNumeric = (value: any) => value - parseFloat(value) >= 0 - -/** - * 判断对象是否为日期类型。 - * - * let date = new Date() - * isDate(date) // true - */ -export const isDate = (value) => typeOf(value) === 'date' - -/** - * 判断两个值是否值相同且类型相同。 - * - * 注:在 JavaScript 里 NaN === NaN 为 false,因此不能简单的用 === 来判断。 - * - * isSame(1, 1) // true - * isSame(NaN, NaN) // true - */ -export const isSame = (x: any, y: any) => - x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y)) - -/** 判断是否是正则表达式 */ -export const isRegExp = (value: any) => typeOf(value) === 'regExp' diff --git a/packages/mobile/utils/validate/index.ts b/packages/mobile/utils/validate/index.ts deleted file mode 100644 index 2d821eede1..0000000000 --- a/packages/mobile/utils/validate/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import Schema from './schema' -import validators from './validations/index' -import getDefaultMessage from './messages' - -Schema.validators = validators -Schema.getDefaultMessage = getDefaultMessage - -export default Schema diff --git a/packages/mobile/utils/validate/messages.ts b/packages/mobile/utils/validate/messages.ts deleted file mode 100644 index 5d24a33225..0000000000 --- a/packages/mobile/utils/validate/messages.ts +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -const getTypesObj = (translate) => ({ - string: translate('validation.types.string'), - method: translate('validation.types.method'), - array: translate('validation.types.array'), - object: translate('validation.types.object'), - number: translate('validation.types.number'), - date: translate('validation.types.date'), - boolean: translate('validation.types.boolean'), - integer: translate('validation.types.integer'), - float: translate('validation.types.float'), - regexp: translate('validation.types.regexp'), - email: translate('validation.types.email'), - url: translate('validation.types.url'), - hex: translate('validation.types.hex'), - digits: translate('validation.types.digits'), - time: translate('validation.types.time'), - dateYM: translate('validation.types.dateYM'), - dateYMD: translate('validation.types.dateYMD'), - dateTime: translate('validation.types.dateTime'), - longDateTime: translate('validation.types.longDateTime'), - version: translate('validation.types.version'), - speczh: translate('validation.types.speczh'), - specialch: translate('validation.types.specialch'), - specialch2: translate('validation.types.hex'), - acceptImg: translate('validation.types.acceptImg'), - acceptFile: translate('validation.types.acceptFile'), - fileSize: translate('validation.types.fileSize') -}) -export default (translate = (value) => value) => ({ - default: translate('validation.default'), - required: translate('validation.required'), - enum: translate('validation.enum'), - whitespace: translate('validation.whitespace'), - date: { - format: translate('validation.date.format'), - parse: translate('validation.date.parse'), - invalid: translate('validation.date.invalid') - }, - types: getTypesObj(translate), - string: { - len: translate('validation.string.len'), - min: translate('validation.string.min'), - max: translate('validation.string.max'), - range: translate('validation.string.range') - }, - number: { - len: translate('validation.number.len'), - min: translate('validation.number.min'), - max: translate('validation.number.max'), - range: translate('validation.number.range') - }, - array: { - len: translate('validation.array.len'), - min: translate('validation.array.min'), - max: translate('validation.array.max'), - range: translate('validation.array.range') - }, - pattern: { - mismatch: translate('validation.pattern.mismatch') - } -}) diff --git a/packages/mobile/utils/validate/rules/enum.ts b/packages/mobile/utils/validate/rules/enum.ts deleted file mode 100644 index 3252a033be..0000000000 --- a/packages/mobile/utils/validate/rules/enum.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import * as util from '../util' - -const ENUM = 'enum' - -export default function (rule, checkValue, source, errors, options) { - rule[ENUM] = Array.isArray(rule[ENUM]) ? rule[ENUM] : [] - - if (!rule[ENUM].includes(checkValue)) { - errors.push(util.format(options.messages[ENUM], '', rule[ENUM].join(', '))) - } -} diff --git a/packages/mobile/utils/validate/rules/index.ts b/packages/mobile/utils/validate/rules/index.ts deleted file mode 100644 index 3da1a6ffdd..0000000000 --- a/packages/mobile/utils/validate/rules/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import type from './type' -import range from './range' -import enumRule from './enum' -import pattern from './pattern' -import required from './required' -import whitespace from './whitespace' - -export default { - type, - range, - pattern, - required, - whitespace, - enum: enumRule -} diff --git a/packages/mobile/utils/validate/rules/pattern.ts b/packages/mobile/utils/validate/rules/pattern.ts deleted file mode 100644 index 1f8d568261..0000000000 --- a/packages/mobile/utils/validate/rules/pattern.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import * as util from '../util' - -export default function (rule, checkValue, source, errors, options) { - if (rule.pattern) { - if (rule.pattern instanceof RegExp) { - rule.pattern.lastIndex = 0 - - if (!rule.pattern.test(checkValue)) { - errors.push(util.format(options.messages.pattern.mismatch, '', checkValue, rule.pattern)) - } - } else if (typeof rule.pattern === 'string') { - const _pattern = new RegExp(rule.pattern) - - if (!_pattern.test(checkValue)) { - errors.push(util.format(options.messages.pattern.mismatch, '', checkValue, rule.pattern)) - } - } - } -} diff --git a/packages/mobile/utils/validate/rules/range.ts b/packages/mobile/utils/validate/rules/range.ts deleted file mode 100644 index 12eafae2eb..0000000000 --- a/packages/mobile/utils/validate/rules/range.ts +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import * as util from '../util' -import { isNumber } from '../../type' -import { getLength } from '../../string' - -function getErro({ min, max, val, key, rule, errors, util, options }) { - if (min && !max && val < rule.min) { - errors.push(util.format(options.messages[key].min, '', rule.min)) - } else if (max && !min && val > rule.max) { - errors.push(util.format(options.messages[key].max, '', rule.max)) - } else if (min && max && (val < rule.min || val > rule.max)) { - errors.push(util.format(options.messages[key].range, '', rule.min, rule.max)) - } -} - -export default function (rule, checkValue, source, errors, options) { - const len = isNumber(rule.len) - const min = isNumber(rule.min) - const max = isNumber(rule.max) - let val = checkValue - let key: string | null = null - const num = isNumber(Number(checkValue)) - const str = typeof checkValue === 'string' - const arr = Array.isArray(checkValue) - - if (num) { - key = 'number' - } else if (str) { - key = 'string' - } else if (arr) { - key = 'array' - } - - if (!key) { - return false - } - - if (arr) { - val = checkValue.length - } - - if (str) { - val = getLength(checkValue, 'string') - } - - if (rule.type === 'number') { - val = checkValue - } - - if (len) { - if (val !== rule.len) { - errors.push(util.format(options.messages[key].len, '', rule.len)) - } - } else { - getErro({ min, max, val, key, rule, errors, util, options }) - } -} diff --git a/packages/mobile/utils/validate/rules/required.ts b/packages/mobile/utils/validate/rules/required.ts deleted file mode 100644 index 725888563c..0000000000 --- a/packages/mobile/utils/validate/rules/required.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import * as util from '../util' -import { hasOwn } from '../../type' - -export default function ({ rule, checkValue, source, errors, options, type }) { - if (rule.required && (!hasOwn.call(source, rule.field) || util.isEmptyValue(checkValue, type || rule.type))) { - errors.push(util.format(options.messages.required, '')) - } -} diff --git a/packages/mobile/utils/validate/rules/type.ts b/packages/mobile/utils/validate/rules/type.ts deleted file mode 100644 index b6942bedcb..0000000000 --- a/packages/mobile/utils/validate/rules/type.ts +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import * as util from '../util' -import required from './required' -import { format } from '../../date' -import { isNullOrEmpty } from '../../string' -import { isNumber, isObject, isDate, typeOf } from '../../type' - -const emailReg1 = '^(([^<>()\\[\\]\\\\.,;:\\s@"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@"]+)*)|(".+"))' -const emailReg = new RegExp( - emailReg1 + '@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,6}))$' -) - -const pattern = { - acceptImg: /\.(png|jpe?g|gif)$/, - acceptFile: /\.(doc?x|xls?x|ppt?x|txt)$/, - email: emailReg, - fileSize: /^\d+(\.\d+)?[KMGTPEZY]?B$/i, - hex: /^#?([a-f0-9]{6}|[a-f0-9]{3})$/i, - speczh: /^[0-9a-zA-Z_\u4E00-\u9FA5]+$/, - specialch: /^[0-9a-zA-Z_\-.]+$/, - specialch2: /^[0-9a-zA-Z_-]+$/, - url: /^(([a-zA-Z]{3,}):)?\/\/([\w-]+\.)+[\w]+(\/[a-zA-Z- ./?%&=]*)?/i, - version: /^\d+\.\d+(\.\d+)*$/ -} - -const types = { - integer: (value) => types.number(value) && /^[-]?[\d]+$/.test(value), - float: (value) => types.number(value) && !types.integer(value), - array: Array.isArray, - regexp(value) { - if (value instanceof RegExp) { - return true - } - try { - return !!new RegExp(value) - } catch (e) { - return false - } - }, - date: isDate, - number: (value) => isNumber(Number(value)), - object: (value) => isObject(value) && !types.array(value), - method: (value) => typeOf(value) === 'function', - - email: (value) => isNullOrEmpty(value) || (!!value.match(pattern.email) && value.length < 255), - - url: (value) => isNullOrEmpty(value) || !!value.match(pattern.url), - hex: (value) => isNullOrEmpty(value) || !!value.match(pattern.hex), - digits: (value) => isNullOrEmpty(value) || /^\d+$/.test(value), - - time: (value) => isNullOrEmpty(value) || /^((0)[0-9]|1[0-9]|20|21|22|23):([0-5][0-9])$/.test(value), - - dateYM: (value) => isNullOrEmpty(value) || format(value, 'yyyy-MM') === value, - - dateYMD: (value) => isNullOrEmpty(value) || format(value, 'yyyy-MM-dd') === value, - - dateTime: (value) => isNullOrEmpty(value) || format(value, 'yyyy-MM-dd hh:mm') === value, - - longDateTime: (value) => isNullOrEmpty(value) || format(value, 'yyyy-MM-dd hh:mm:ss') === value, - - version: (value) => isNullOrEmpty(value) || !!value.match(pattern.version), - speczh: (value) => isNullOrEmpty(value) || !!value.match(pattern.speczh), - - specialch: (value) => isNullOrEmpty(value) || !!value.match(pattern.specialch), - - specialch2: (value) => isNullOrEmpty(value) || !!value.match(pattern.specialch2), - - acceptImg: (value) => isNullOrEmpty(value) || !!value.match(pattern.acceptImg), - - acceptFile: (value) => isNullOrEmpty(value) || !!value.match(pattern.acceptFile), - - fileSize: (value) => isNullOrEmpty(value) || !!value.match(pattern.fileSize) -} - -export default function (rule, value, source, errors, options) { - if (rule.required && value === undefined) { - required(rule, value, source, errors, options) - return - } - - const custom = [ - 'array', - 'acceptImg', - 'acceptFile', - 'date', - 'digits', - 'dateTime', - 'dateYM', - 'dateYMD', - 'email', - 'float', - 'fileSize', - 'hex', - 'integer', - 'longDateTime', - 'method', - 'number', - 'object', - 'regexp', - 'speczh', - 'specialch', - 'specialch2', - 'time', - 'version', - 'url' - ] - - const ruleType = rule.type - - if (custom.includes(ruleType)) { - if (!types[ruleType](value)) { - errors.push(util.format(options.messages.types[ruleType], '', rule.type)) - } - // eslint-disable-next-line valid-typeof - } else if (ruleType && typeof value !== rule.type) { - errors.push(util.format(options.messages.types[ruleType], '', rule.type)) - } -} diff --git a/packages/mobile/utils/validate/rules/whitespace.ts b/packages/mobile/utils/validate/rules/whitespace.ts deleted file mode 100644 index fe4f7789ba..0000000000 --- a/packages/mobile/utils/validate/rules/whitespace.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import * as util from '../util' - -export default function (rule, checkValue, source, errors, options) { - if (/^\s+$/.test(checkValue) || checkValue === '') { - errors.push(util.format(options.messages.whitespace, '')) - } -} diff --git a/packages/mobile/utils/validate/schema.ts b/packages/mobile/utils/validate/schema.ts deleted file mode 100644 index cc4fd371a7..0000000000 --- a/packages/mobile/utils/validate/schema.ts +++ /dev/null @@ -1,398 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { format, complementError, asyncMap, warning, deepMerge, convertFieldsError } from './util' -import { hasOwn, isFunction } from '../type' - -function Schema(descriptor, translate) { - Schema.getSystemMessage = () => Schema.getDefaultMessage(translate) - Schema.messages = Schema.getSystemMessage(translate) - Schema.systemMessages = Schema.messages - - this.rules = null - this._messages = Schema.systemMessages - this.define(descriptor) -} - -/** - * @description 封装一下调用方传入的回调 - * @param validCallback - * @returns 新的回调 - */ -const getCompleteFn = (validCallback) => (results) => { - let idx - let errors = [] - let fields = {} - - function addValid(eror) { - if (Array.isArray(eror)) { - errors = errors.concat(...eror) - } else { - errors.push(eror) - } - } - - for (idx = 0; idx < results.length; idx++) { - addValid(results[idx]) - } - - if (errors.length) { - fields = convertFieldsError(errors) - } else { - errors = null - fields = null - } - - validCallback(errors, fields) -} - -/** - * @description 判断是否有嵌套的检验规则 - */ -const isDeep = (rule, data) => { - let deep = - (rule.type === 'object' || rule.type === 'array') && - (typeof rule.fields === 'object' || typeof rule.defaultField === 'object') - - deep = deep && (rule.required || (!rule.required && data.value)) - - return deep -} - -/** - * @description 为嵌套规则新构造一个校验实例 - */ -const getFieldsSchema = (rule, data) => { - let schema = {} - function addFullfield(key, item) { - return { - ...item, - fullField: `${rule.fullField}.${key}` - } - } - - if (rule.defaultField) { - for (const k in data.value) { - if (hasOwn.call(data.value, k)) { - schema[k] = rule.defaultField - } - } - } - - schema = { - ...schema, - ...data.rule.fields - } - - for (const f in schema) { - if (hasOwn.call(schema, f)) { - const fieldSchema = Array.isArray(schema[f]) ? schema[f] : [schema[f]] - - schema[f] = fieldSchema.map(addFullfield.bind(null, f)) - } - } - - return schema -} - -/** - * @description 工具方法,将入参变成数组 - */ -const arrayed = (failds) => { - if (!Array.isArray(failds)) { - failds = [failds] - } - - return failds -} - -/** - * @description 处理嵌套规则的错误message - */ -const getRequiredErrorFeilds = ({ rule, failds, options }) => { - if (rule.message) { - failds = [].concat(rule.message).map(complementError(rule)) - } else if (options.error) { - failds = [options.error(rule, format(options.messages.required, rule.field))] - } else { - failds = [] - } - - return failds -} - -/** - * @description 处理嵌套规则的option - */ -const setDataRuleOptions = ({ data, options }) => { - if (data.rule.options) { - let { messages, error } = options - - Object.assign(data.rule.options, { messages, error }) - } -} - -/** - * @description 处理嵌套规则的回调函数 - */ -const getValidateCallback = - ({ failds, doIt }) => - (errs) => { - const finalErrors = [] - - if (failds && failds.length) { - finalErrors.push(...failds) - } - - if (errs && errs.length) { - finalErrors.push(...errs) - } - - doIt(finalErrors.length ? finalErrors : null) - } - -/** - * @description 单条检验规则的回调函数 - */ -const asyncCallback = - (options, rule, errorFields, doIt, data) => - (e = []) => { - let failds = e - const deep = isDeep(rule, data) - - failds = arrayed(failds) - - if (!options.suppressWarning && failds.length) { - Schema.warning('async-validator:', failds) - } - - if (failds.length && rule.message) { - failds = [].concat(rule.message) - } - - failds = failds.map(complementError(rule)) - - if (options.first && failds.length) { - errorFields[rule.field] = 1 - return doIt(failds) - } - - if (deep) { - if (rule.required && !data.value) { - failds = getRequiredErrorFeilds({ rule, failds, options }) - - return doIt(failds) - } - const schema = new Schema(getFieldsSchema(rule, data)) - schema.messages(options.messages) - setDataRuleOptions({ data, options }) - schema.validate(data.value, data.rule.options || options, getValidateCallback({ failds, doIt })) - } else { - doIt(failds) - } - } - -Schema.prototype = { - messages(messages) { - if (messages) { - this._messages = deepMerge(Schema.getSystemMessage(), messages) - } - - return this._messages - }, - /** 格式化检验规则并添加到实例上。 - * rules格式化后的数据结构: { key: [ { type: 'xx', ...others } ] } - */ - define(rules) { - if (!rules) { - throw new Error('Cannot configure a schema with no rules') - } - - if (Array.isArray(rules) || typeof rules !== 'object') { - throw new TypeError('Rules must be an object') - } - - this.rules = {} - let rule - - Object.keys(rules).forEach((key) => { - if (hasOwn.call(rules, key)) { - rule = rules[key] - this.rules[key] = Array.isArray(rule) ? rule : [rule] - } - }) - }, - /** 将检验规则和源数据合并转化成新数据 - * rules: { key: [rule1, rule2] }, source: { key: sourceData, key2: sourceData2 } - * series { key: [{ rule: rule1, value: sourceData, source, field: key }, ...] } - */ - getSeries(options, source, source_) { - let arr - let value - const series = {} - const keys = options.keys || Object.keys(this.rules) - - keys.forEach((key) => { - arr = this.rules[key] - value = source[key] - - arr.forEach((r) => { - let rule = r - - if (typeof rule.transform === 'function') { - if (source === source_) { - source = { ...source } - } - - source[key] = rule.transform(value) - value = source[key] - } - - if (typeof rule === 'function') { - rule = { validator: rule } - } else { - rule = { ...rule } - } - - rule.validator = this.getValidationMethod(rule) - rule.field = key - rule.fullField = rule.fullField || key - rule.type = this.getType(rule) - - options.custom && Object.assign(rule, options.custom) - - if (!rule.validator) { - return - } - - series[key] = series[key] || [] - series[key].push({ rule, value, source, field: key }) - }) - }) - - return series - }, - mergeMessage(options) { - if (options.messages) { - let messages = this.messages() - - if (messages === Schema.systemMessages) { - messages = Schema.getSystemMessage() - } - - deepMerge(messages, options.messages) - - options.messages = messages - } else { - options.messages = this.messages() - } - }, - validate(source_, o = {}, oc = () => undefined) { - let source = source_ - let options = o - let validCallback = oc - if (typeof options === 'function') { - validCallback = options - options = {} - } - if (!this.rules || Object.keys(this.rules).length === 0) { - validCallback && validCallback() - return Promise.resolve() - } - const complete = getCompleteFn(validCallback) - this.mergeMessage(options) - const seriesData = this.getSeries(options, source, source_) - const errorFields = {} - return asyncMap( - seriesData, - options, - (data, doIt) => { - const rule = data.rule - const validHandler = asyncCallback(options, rule, errorFields, doIt, data) - let validResult - if (rule.asyncValidator) { - validResult = rule.asyncValidator(rule, data.value, validHandler, data.source, options) - } else if (rule.validator) { - validResult = rule.validator(rule, data.value, validHandler, data.source, options) - if (validResult === true) { - validHandler() - } else if (validResult === false) { - validHandler(rule.message || `${rule.field} fails`) - } else if (Array.isArray(validResult)) { - validHandler(validResult) - } else if (validResult instanceof Error) { - validHandler(validResult.message) - } - } - if (validResult && validResult.then) { - validResult.then( - () => validHandler(), - (e) => validHandler(e) - ) - } - }, - (results) => { - complete(results) - } - ) - }, - getValidationMethod(rule) { - if (isFunction(rule.validator)) { - return rule.validator - } - - const ruleKeys = Object.keys(rule) - const messageIndex = ruleKeys.indexOf('message') - - if (messageIndex > -1) { - ruleKeys.splice(messageIndex, 1) - } - - if (ruleKeys.length === 1 && ruleKeys[0] === 'required') { - return Schema.validators.required - } - - return Schema.validators[this.getType(rule)] || false - }, - getType(rule) { - if (rule.type === undefined && rule.pattern instanceof RegExp) { - rule.type = 'pattern' - } - - if (typeof rule.validator !== 'function' && rule.type && !hasOwn.call(Schema.validators, rule.type)) { - throw new Error(format('Unknown rule type %s', rule.type)) - } - - return rule.type || 'string' - } -} - -/** 注册的新类型的检验 */ -Schema.register = (type, validator) => { - if (typeof validator !== 'function') { - throw new TypeError('Cannot register a validator by type, validator is not a function') - } - - Schema.validators[type] = validator -} - -Schema.validators = {} - -Schema.warning = warning - -Schema.messages = {} - -Schema.systemMessages = {} - -Schema.getDefaultMessage = () => undefined - -export default Schema diff --git a/packages/mobile/utils/validate/util.ts b/packages/mobile/utils/validate/util.ts deleted file mode 100644 index 941110dd97..0000000000 --- a/packages/mobile/utils/validate/util.ts +++ /dev/null @@ -1,291 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import { hasOwn, isNull } from '../type' -import { log } from '../xss' - -const formatRegExp = /%[sdj%]/g - -export const warning = () => undefined - -/** - * @description 转换返回错误的数据结构 - */ -export function convertFieldsError(errors) { - if (!errors || !errors.length) { - return null - } - - const fields = {} - - errors.forEach((error) => { - const field = error.field - fields[field] = fields[field] || [] - fields[field].push(error) - }) - - return fields -} - -/** - * @description 生成校验错误的提示信息 - * @param i18nTemplate 带占位符的字符串 - * @param rest 替换占位符的字符串 - * 例:format('%s 必须等于 %s', 'A', 'B') 返回 A 必须等于 B - */ -export function format(i18nTemplate: Function | string, ...rest: string[]) { - if (typeof i18nTemplate === 'function') { - return i18nTemplate(...rest) - } - - if (typeof i18nTemplate === 'string') { - let i = 0 - const len = rest.length - let str = String(i18nTemplate).replace(formatRegExp, (matchChar) => { - if (matchChar === '%%') { - return '%' - } - - if (i >= len) { - return matchChar - } - - switch (matchChar) { - case '%j': - try { - return JSON.stringify(rest[i++]) - } catch (e) { - return '[Circular]' - } - case '%d': - return Number(rest[i++]) - case '%s': - return String(rest[i++]) - default: - return matchChar - } - }) - - return str - } - - return i18nTemplate -} - -/** - * @description 判断是否string类型 - */ -function isNativeStringType(type) { - return [ - 'string', - 'url', - 'hex', - 'email', - 'pattern', - 'digits', - 'time', - 'dateYMD', - 'longDateTime', - 'dateTime', - 'dateYM', - 'version', - 'speczh', - 'specialch', - 'specialch2', - 'acceptImg', - 'acceptFile', - 'fileSize' - ].includes(type) -} -/** - * @description 判断对应的类型是否是空值 - */ -export function isEmptyValue(data, dataType) { - if (isNull(data)) { - return true - } - - if (dataType === 'array' && Array.isArray(data) && !data.length) { - return true - } - - if (isNativeStringType(dataType) && typeof data === 'string' && !data) { - return true - } - - return false -} - -/** TINY_DUP type.ts TINY_NO_USED */ -export function isEmptyObject(data) { - return Object.keys(data).length === 0 -} - -/** - * @description 并行处理校验规则 - */ -function asyncParallelArray(arrData, func, callback) { - let count = 0 - const results = [] - const arrLength = arrData.length - - function checkCount(errors) { - results.push(...errors) - - count++ - - if (count === arrLength) { - callback(results) - } - } - - arrData.forEach((rule) => { - func(rule, checkCount) - }) -} - -/** - * @description 串行处理校验规则 - */ -function asyncSerialArray(arr, fn, cb) { - let idx = 0 - const arrLength = arr.length - - function checkNext(errorList) { - if (errorList && errorList.length) { - cb(errorList) - return - } - - const original = idx - idx = idx + 1 - - if (original < arrLength) { - fn(arr[original], checkNext) - } else { - cb([]) - } - } - - checkNext([]) -} - -/** - * @description 将一层数据平铺开 - */ -function flattenObjArr(objArr) { - const result = [] - - Object.keys(objArr).forEach((item) => { - result.push(...objArr[item]) - }) - - return result -} - -/** - * @description 转换返回错误的数据结构 - */ -export function asyncMap(objArray, option, func, callback) { - if (option.first) { - const pending = new Promise((resolve, reject) => { - const errorFn = reject - const next = (errors) => { - callback(errors) - return errors.length ? errorFn({ errors, fields: convertFieldsError(errors) }) : resolve() - } - const flattenArr = flattenObjArr(objArray) - asyncSerialArray(flattenArr, func, next) - }) - - // 校验器会报告中,errors fields 同时存在,属于正常,不打印; 代码真异常才打印。 - pending.catch((error) => (error.errors && error.fields) || log.logger.error(error)) - return pending - } - - let firstFields = option.firstFields || [] - - if (firstFields === true) { - firstFields = Object.keys(objArray) - } - - let total = 0 - const objArrayKeys = Object.keys(objArray) - const objArrLength = objArrayKeys.length - const results = [] - const pending = new Promise((resolve, reject) => { - const errorFn = reject - const next = (errors) => { - results.push(...errors) - total++ - if (total === objArrLength) { - callback(results) - return results.length ? errorFn({ errors: results, fields: convertFieldsError(results) }) : resolve() - } - } - - objArrayKeys.forEach((key) => { - const arr = objArray[key] - if (firstFields.includes(key)) { - asyncSerialArray(arr, func, next) - } else { - asyncParallelArray(arr, func, next) - } - }) - }) - - // 校验器会报告中,errors fields 同时存在,属于正常,不打印; 代码真异常才打印。 - pending.catch((error) => (error.errors && error.fields) || log.logger.error(error)) - - return pending -} - -/** - * @description 处理返回的错误 - */ -export function complementError(rule) { - return (onError) => { - if (onError && onError.message) { - onError.field = onError.field || rule.fullField - return onError - } - - return { - message: typeof onError === 'function' ? onError() : onError, - field: onError.field || rule.fullField - } - } -} - -/** - * @description 深度合并 - */ -export function deepMerge(target, sources) { - if (!sources) { - return target - } - for (const source in sources) { - if (hasOwn.call(sources, source)) { - const value = sources[source] - - if (typeof value === 'object' && typeof target[source] === 'object') { - target[source] = { - ...target[source], - ...value - } - } else { - target[source] = value - } - } - } - return target -} diff --git a/packages/mobile/utils/validate/validations/array.ts b/packages/mobile/utils/validate/validations/array.ts deleted file mode 100644 index 6f470b8a40..0000000000 --- a/packages/mobile/utils/validate/validations/array.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import rules from '../rules/index' -import { isEmptyValue } from '../util' -import { hasOwn } from '../../type' - -export default function (rule, checkValue, callback, source, options) { - const errors = [] - const validate = rule.required || (!rule.required && hasOwn.call(source, rule.field)) - - if (validate) { - if (isEmptyValue(checkValue, 'array') && !rule.required) { - return callback() - } - - rules.required({ rule, checkValue, source, errors, options, type: 'array' }) - - if (!isEmptyValue(checkValue, 'array')) { - rules.type(rule, checkValue, source, errors, options) - rules.range(rule, checkValue, source, errors, options) - } - } - - callback(errors) -} diff --git a/packages/mobile/utils/validate/validations/date.ts b/packages/mobile/utils/validate/validations/date.ts deleted file mode 100644 index a73661409f..0000000000 --- a/packages/mobile/utils/validate/validations/date.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import rules from '../rules/index' -import { isEmptyValue } from '../util' -import { hasOwn } from '../../type' - -export default function (rule, checkValue, callback, source, options) { - const errors = [] - const validate = rule.required || (!rule.required && hasOwn.call(source, rule.field)) - const isValidDateStr = (value) => value && typeof value === 'string' && new Date(value).toString() !== 'Invalid Date' - - if (validate) { - if (isEmptyValue(checkValue) && !rule.required) { - return callback() - } - - rules.required({ rule, checkValue, source, errors, options }) - - if (!isEmptyValue(checkValue)) { - let dateObject - - if (typeof checkValue === 'number' || isValidDateStr(checkValue)) { - dateObject = new Date(checkValue) - } else { - dateObject = checkValue - } - - rules.type(rule, dateObject, source, errors, options) - - if (dateObject && typeof dateObject.getTime === 'function') { - rules.range(rule, dateObject.getTime(), source, errors, options) - } - } - } - - callback(errors) -} diff --git a/packages/mobile/utils/validate/validations/enum.ts b/packages/mobile/utils/validate/validations/enum.ts deleted file mode 100644 index 155c023f11..0000000000 --- a/packages/mobile/utils/validate/validations/enum.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import rules from '../rules/index' -import { isEmptyValue } from '../util' -import { hasOwn } from '../../type' - -const ENUM = 'enum' - -export default function (rule, checkValue, callback, source, options) { - const errors = [] - const validate = rule.required || (!rule.required && hasOwn.call(source, rule.field)) - - if (validate) { - if (isEmptyValue(checkValue) && !rule.required) { - return callback() - } - - rules.required({ rule, checkValue, source, errors, options }) - - if (checkValue !== undefined) { - rules[ENUM](rule, checkValue, source, errors, options) - } - } - - callback(errors) -} diff --git a/packages/mobile/utils/validate/validations/float.ts b/packages/mobile/utils/validate/validations/float.ts deleted file mode 100644 index db58179a87..0000000000 --- a/packages/mobile/utils/validate/validations/float.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import rules from '../rules/index' -import { isEmptyValue } from '../util' -import { hasOwn } from '../../type' - -export default function (rule, checkValue, cb, source, options) { - const errors = [] - const validate = rule.required || (!rule.required && hasOwn.call(source, rule.field)) - - if (validate) { - if (isEmptyValue(checkValue) && !rule.required) { - return cb() - } - - rules.required({ rule, checkValue, source, errors, options }) - - if (checkValue !== undefined) { - rules.type(rule, checkValue, source, errors, options) - rules.range(rule, checkValue, source, errors, options) - } - } - - cb(errors) -} diff --git a/packages/mobile/utils/validate/validations/index.ts b/packages/mobile/utils/validate/validations/index.ts deleted file mode 100644 index aa7c924daa..0000000000 --- a/packages/mobile/utils/validate/validations/index.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import date from './date' -import type from './type' -import float from './float' -import array from './array' -import string from './string' -import method from './method' -import number from './number' -import integer from './integer' -import pattern from './pattern' -import required from './required' -import enumValidator from './enum' - -export default { - date, - float, - array, - string, - method, - number, - integer, - pattern, - required, - hex: type, - url: type, - time: type, - email: type, - digits: type, - dateYM: type, - speczh: type, - dateYMD: type, - version: type, - fileSize: type, - regexp: method, - object: method, - dateTime: type, - specialch: type, - boolean: method, - acceptImg: type, - specialch2: type, - acceptFile: type, - longDateTime: type, - enum: enumValidator -} diff --git a/packages/mobile/utils/validate/validations/integer.ts b/packages/mobile/utils/validate/validations/integer.ts deleted file mode 100644 index d890b4a7bc..0000000000 --- a/packages/mobile/utils/validate/validations/integer.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import rules from '../rules/index' -import { isEmptyValue } from '../util' -import { hasOwn } from '../../type' - -export default function (rule, checkValue, callback, source, options) { - const errors = [] - const validate = rule.required || (!rule.required && hasOwn.call(source, rule.field)) - - if (validate) { - if (isEmptyValue(checkValue) && !rule.required) { - return callback() - } - - rules.required({ rule, checkValue, source, errors, options }) - - if (checkValue !== undefined && checkValue !== '') { - rules.type(rule, checkValue, source, errors, options) - rules.range(rule, checkValue, source, errors, options) - } - } - - callback(errors) -} diff --git a/packages/mobile/utils/validate/validations/method.ts b/packages/mobile/utils/validate/validations/method.ts deleted file mode 100644 index 6ccfbc0c78..0000000000 --- a/packages/mobile/utils/validate/validations/method.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import rules from '../rules/index' -import { isEmptyValue } from '../util' -import { hasOwn } from '../../type' - -export default function (rule, checkValue, callback, source, options) { - const validate = rule.required || (!rule.required && hasOwn.call(source, rule.field)) - const errors = [] - - if (validate) { - if (!rule.required && isEmptyValue(checkValue)) { - return callback() - } - - rules.required({ rule, checkValue, source, errors, options }) - - if (checkValue !== undefined) { - rules.type(rule, checkValue, source, errors, options) - } - } - - callback(errors) -} diff --git a/packages/mobile/utils/validate/validations/number.ts b/packages/mobile/utils/validate/validations/number.ts deleted file mode 100644 index 8e457cfced..0000000000 --- a/packages/mobile/utils/validate/validations/number.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import rules from '../rules/index' -import { isEmptyValue } from '../util' -import { hasOwn } from '../../type' - -export default function (rule, checkValue, callback, source, options) { - const errors = [] - const validate = rule.required || (!rule.required && hasOwn.call(source, rule.field)) - - if (validate) { - if (checkValue === '') { - checkValue = undefined - } - - if (!rule.required && isEmptyValue(checkValue)) { - return callback() - } - - rules.required({ rule, checkValue, source, errors, options }) - - if (checkValue !== undefined) { - rules.type(rule, checkValue, source, errors, options) - rules.range(rule, checkValue, source, errors, options) - } - } - - callback(errors) -} diff --git a/packages/mobile/utils/validate/validations/pattern.ts b/packages/mobile/utils/validate/validations/pattern.ts deleted file mode 100644 index 1f914f458c..0000000000 --- a/packages/mobile/utils/validate/validations/pattern.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import rules from '../rules/index' -import { isEmptyValue } from '../util' -import { hasOwn } from '../../type' - -export default function (rule, checkValue, callback, source, options) { - const errors = [] - const validate = rule.required || (!rule.required && hasOwn.call(source, rule.field)) - - if (validate) { - if (isEmptyValue(checkValue, 'string') && !rule.required) { - return callback() - } - - rules.required({ rule, checkValue, source, errors, options }) - - if (!isEmptyValue(checkValue, 'string')) { - rules.pattern(rule, checkValue, source, errors, options) - } - } - - callback(errors) -} diff --git a/packages/mobile/utils/validate/validations/required.ts b/packages/mobile/utils/validate/validations/required.ts deleted file mode 100644 index 11fae17f3b..0000000000 --- a/packages/mobile/utils/validate/validations/required.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import rules from '../rules/index' - -export default function (rule, checkValue, callback, source, options) { - const errors = [] - const type = Array.isArray(checkValue) ? 'array' : typeof checkValue - - rules.required({ rule, checkValue, source, errors, options, type }) - callback(errors) -} diff --git a/packages/mobile/utils/validate/validations/string.ts b/packages/mobile/utils/validate/validations/string.ts deleted file mode 100644 index 23b73f39a1..0000000000 --- a/packages/mobile/utils/validate/validations/string.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import rules from '../rules/index' -import { isEmptyValue } from '../util' -import { hasOwn } from '../../type' - -export default function (rule, checkValue, callback, source, options) { - const errors = [] - const validate = rule.required || (!rule.required && hasOwn.call(source, rule.field)) - - if (validate) { - if (isEmptyValue(checkValue, 'string') && !rule.required) { - return callback() - } - - rules.required({ - rule, - checkValue, - source, - errors, - options, - type: 'string' - }) - - if (!isEmptyValue(checkValue, 'string')) { - rules.type(rule, checkValue, source, errors, options) - rules.range(rule, checkValue, source, errors, options) - rules.pattern(rule, checkValue, source, errors, options) - - if (rule.whitespace === true) { - rules.whitespace(rule, checkValue, source, errors, options) - } - } - } - - callback(errors) -} diff --git a/packages/mobile/utils/validate/validations/type.ts b/packages/mobile/utils/validate/validations/type.ts deleted file mode 100644 index ef5d3111de..0000000000 --- a/packages/mobile/utils/validate/validations/type.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import rules from '../rules/index' -import { isEmptyValue } from '../util' -import { hasOwn } from '../../type' - -export default function (rule, checkValue, callback, source, options) { - const ruleType = rule.type - const errors = [] - const validate = rule.required || (!rule.required && hasOwn.call(source, rule.field)) - - if (validate) { - if (isEmptyValue(checkValue, ruleType) && !rule.required) { - return callback() - } - - rules.required({ - rule, - checkValue, - source, - errors, - options, - type: ruleType - }) - - if (!isEmptyValue(checkValue, ruleType)) { - rules.type(rule, checkValue, source, errors, options) - } - } - - callback(errors) -} diff --git a/packages/mobile/utils/xss.ts b/packages/mobile/utils/xss.ts deleted file mode 100644 index 3ba14d943c..0000000000 --- a/packages/mobile/utils/xss.ts +++ /dev/null @@ -1,204 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ - -import * as xss$1 from 'xss' - -let getWindow = function () { - return typeof window === 'undefined' ? global : window -} - -let xssOptions = { - enableAttrs: true, - enableHtml: true, - enableUrl: true, - html: { - whiteList: { - a: ['class', 'style', 'contenteditable', 'data-id', 'data-title', 'data-size', 'data-last-modified'], - address: ['class', 'style'], - area: ['class', 'style'], - article: ['class', 'style'], - aside: ['class', 'style'], - audio: ['class', 'style'], - b: ['class', 'style'], - bdi: ['class', 'style'], - bdo: ['class', 'style'], - big: ['class', 'style'], - blockquote: ['class', 'style'], - br: ['class', 'style'], - caption: ['class', 'style'], - center: ['class', 'style'], - cite: ['class', 'style'], - code: ['class', 'style'], - col: ['class', 'style'], - colgroup: ['class', 'style'], - dd: ['class', 'style'], - del: ['class', 'style'], - details: ['class', 'style'], - div: [ - 'class', - 'style', - 'spellcheck', - 'data-gramm', - 'spellcheck', - 'data-mode', - 'data-position', - 'data-row', - 'data-cell', - 'data-rowspan', - 'data-colspan', - 'data-cell-bg', - 'data-parent-bg' - ], - dl: ['class', 'style'], - dt: ['class', 'style'], - em: ['class', 'style'], - figcaption: ['class', 'style'], - figure: ['class', 'style'], - font: ['class', 'style'], - footer: ['class', 'style'], - h1: ['class', 'style'], - h2: ['class', 'style'], - h3: ['class', 'style'], - h4: ['class', 'style'], - h5: ['class', 'style'], - h6: ['class', 'style'], - header: ['class', 'style'], - hr: ['class', 'style'], - i: ['class', 'style', 'data-image-id', 'data-image'], - img: ['class', 'style', 'devui-editorx-image', 'style', 'data-image-id'], - input: ['class', 'style', 'data-formula', 'data-link', 'data-video'], - ins: ['class', 'style'], - li: ['class', 'style'], - mark: ['class', 'style'], - nav: ['class', 'style'], - ol: ['class', 'style'], - p: ['class', 'style'], - pre: ['class', 'style'], - s: ['class', 'style'], - section: ['class', 'style'], - small: ['class', 'style'], - span: ['class', 'style', 'contenteditable', 'color', 'style'], - sub: ['class', 'style'], - summary: ['class', 'style'], - sup: ['class', 'style'], - strong: ['class', 'style'], - strike: ['class', 'style'], - svg: ['class', 'style', 't', 'viewBox', 'version', 'xmlns', 'p-id', 'xmlns:xlink'], - path: ['d', 'p-id'], - table: ['class', 'style'], - tbody: ['class', 'style'], - td: ['class', 'style', 'data-row', 'data-cell', 'data-cell-bg', 'data-parent-bg'], - tfoot: ['class', 'style'], - th: ['class', 'style'], - thead: ['class', 'style'], - tr: ['class', 'style', 'data-row'], - tt: ['class', 'style'], - u: ['class', 'style'], - ul: ['class', 'style'], - video: ['class', 'style'] - } - } -} -let defaultWhiteList = (xss$1.getDefaultWhiteList && xss$1.getDefaultWhiteList()) || {} -xssOptions.html.whiteList = Object.assign(defaultWhiteList, xssOptions.html.whiteList) -let xssFilterHtml = new xss$1.FilterXSS(xssOptions.html) -let getXssOption = function () { - return xssOptions -} -let setXssOption = function (option) { - let _a - let whiteList - if ( - (_a = option === null || option === void 0 ? void 0 : option.html) === null || _a === void 0 ? void 0 : _a.whiteList - ) { - whiteList = Object.assign(xssOptions.html.whiteList, option.html.whiteList) - } - xssOptions = Object.assign(xssOptions, option) - if (whiteList) { - xssOptions.html.whiteList = whiteList - } - xssFilterHtml = new xss$1.FilterXSS(xssOptions.html) -} -let filterHtml = function (content) { - if (!xssOptions.enableHtml || typeof content !== 'string') { - return content - } - return xssFilterHtml.process(content) -} -let setFilterHtml = function (filter) { - filterHtml = filter -} -let filterAttrs = function (content) { - if (!xssOptions.enableAttrs || typeof content !== 'string') { - return content - } - return content.replace(/<.*?>/gi, '').replace(/on[a-z]+=/gi, '') -} -let setFilterAttrs = function (filter) { - filterAttrs = filter -} -let filterUrl = function (content) { - if (!xssOptions.enableUrl || typeof content !== 'string') { - return content - } - let filteredUrl = content.replace(/&#(\w+)(^\w|;)?/g, (match, dec) => String.fromCharCode(dec)).trim() - if (!filteredUrl) { - return '' - } - if (['.', '/'].includes(filteredUrl[0])) { - return filteredUrl - } - let urlParse = filteredUrl.match(/^([^:]+):/gm) - if (!urlParse) { - return filteredUrl - } - if (/^([^\w]*)(javascript|data|vbscript)/im.test(urlParse[0])) { - return '' - } - return filteredUrl -} -let setFilterUrl = function (filter) { - filterUrl = filter -} -let index = { - getXssOption, - setXssOption, - filterHtml, - setFilterHtml, - filterAttrs, - setFilterAttrs, - filterUrl, - setFilterUrl -} - -let xss = Object.freeze({ - __proto__: null, - getXssOption, - setXssOption, - get filterHtml() { - return filterHtml - }, - setFilterHtml, - get filterAttrs() { - return filterAttrs - }, - setFilterAttrs, - get filterUrl() { - return filterUrl - }, - setFilterUrl, - 'default': index -}) -let log = { logger: getWindow().console } -let def = { xss, log } - -export { def as default, log, xss } diff --git a/packages/mobile/vite.config.ts b/packages/mobile/vite.config.ts deleted file mode 100644 index 58a1f6789b..0000000000 --- a/packages/mobile/vite.config.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import vueJsx from '@vitejs/plugin-vue-jsx' -import path from 'node:path' -import replace from '@rollup/plugin-replace' -import dts from 'vite-plugin-dts' - -export default defineConfig({ - plugins: [ - vue(), - vueJsx(), - dts(), - replace({ - '.less': '.css' - }) - ], - build: { - lib: { - entry: './index.ts' - }, - rollupOptions: { - external: [/@opentiny\/vue/, /@better-scroll/, 'vue', 'xss'], - input: ['index.ts'], - output: [ - { - format: 'es', - entryFileNames: '[name].js', - preserveModules: true - } - ] - } - }, - resolve: { - alias: { - '@mobile-root': path.resolve(__dirname, '') - } - } -}) diff --git a/packages/vue-locale/package.json b/packages/vue-locale/package.json index 9e3dfe5e8f..e409ecc1e8 100644 --- a/packages/vue-locale/package.json +++ b/packages/vue-locale/package.json @@ -14,7 +14,6 @@ "dependencies": { "@opentiny/utils": "workspace:~", "@opentiny/vue-renderless": "workspace:~", - "@opentiny/vue-theme": "workspace:~", - "@opentiny/vue-theme-mobile": "workspace:~" + "@opentiny/vue-theme": "workspace:~" } }