@toife/vue 2.2.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (324) hide show
  1. package/README.md +171 -0
  2. package/package.json +41 -9
  3. package/src/components/action/action.composable.ts +32 -0
  4. package/src/components/action/action.html +25 -0
  5. package/src/components/action/action.scss +106 -0
  6. package/src/components/action/action.type.ts +35 -0
  7. package/src/components/action/action.vue +82 -0
  8. package/src/components/action/index.ts +9 -0
  9. package/src/components/app/app.constants.ts +1 -0
  10. package/src/components/app/app.html +24 -0
  11. package/src/components/app/app.scss +27 -0
  12. package/src/components/app/app.type.ts +21 -0
  13. package/src/components/app/app.vue +45 -0
  14. package/src/components/app/index.ts +3 -0
  15. package/src/components/avatar/avatar.html +3 -0
  16. package/src/components/avatar/avatar.scss +35 -0
  17. package/src/components/avatar/avatar.type.ts +6 -0
  18. package/src/components/avatar/avatar.vue +45 -0
  19. package/src/components/avatar/index.ts +2 -0
  20. package/src/components/button/button.html +6 -0
  21. package/src/components/button/button.scss +113 -0
  22. package/src/components/button/button.type.ts +14 -0
  23. package/src/components/button/button.vue +66 -0
  24. package/src/components/button/index.ts +2 -0
  25. package/src/components/cable/cable.constants.ts +1 -0
  26. package/src/components/cable/cable.html +3 -0
  27. package/src/components/cable/cable.scss +37 -0
  28. package/src/components/cable/cable.type.ts +11 -0
  29. package/src/components/cable/cable.vue +33 -0
  30. package/src/components/cable/index.ts +3 -0
  31. package/src/components/card/card/card.constants.ts +1 -0
  32. package/src/components/card/card/card.html +3 -0
  33. package/src/components/card/card/card.scss +34 -0
  34. package/src/components/card/card/card.type.ts +14 -0
  35. package/src/components/card/card/card.vue +62 -0
  36. package/src/components/card/card/index.ts +3 -0
  37. package/src/components/card/card-body/card-body.html +3 -0
  38. package/src/components/card/card-body/card-body.scss +23 -0
  39. package/src/components/card/card-body/card-body.vue +14 -0
  40. package/src/components/card/card-body/index.ts +1 -0
  41. package/src/components/card/card-footer/card-footer.html +3 -0
  42. package/src/components/card/card-footer/card-footer.scss +31 -0
  43. package/src/components/card/card-footer/card-footer.vue +28 -0
  44. package/src/components/card/card-footer/index.ts +1 -0
  45. package/src/components/card/card-header/card-header.html +3 -0
  46. package/src/components/card/card-header/card-header.scss +31 -0
  47. package/src/components/card/card-header/card-header.vue +28 -0
  48. package/src/components/card/card-header/index.ts +1 -0
  49. package/src/components/card/index.ts +4 -0
  50. package/src/components/checkbox/checkbox.html +13 -0
  51. package/src/components/checkbox/checkbox.scss +138 -0
  52. package/src/components/checkbox/checkbox.type.ts +17 -0
  53. package/src/components/checkbox/checkbox.vue +91 -0
  54. package/src/components/checkbox/index.ts +2 -0
  55. package/src/components/collapse/collapse.html +16 -0
  56. package/src/components/collapse/collapse.scss +59 -0
  57. package/src/components/collapse/collapse.type.ts +11 -0
  58. package/src/components/collapse/collapse.vue +131 -0
  59. package/src/components/collapse/index.ts +2 -0
  60. package/src/components/container/container.html +1 -0
  61. package/src/components/container/container.scss +10 -0
  62. package/src/components/container/container.vue +14 -0
  63. package/src/components/container/index.ts +1 -0
  64. package/src/components/decision-modal/decision-modal.composable.ts +32 -0
  65. package/src/components/decision-modal/decision-modal.html +29 -0
  66. package/src/components/decision-modal/decision-modal.scss +136 -0
  67. package/src/components/decision-modal/decision-modal.type.ts +35 -0
  68. package/src/components/decision-modal/decision-modal.vue +98 -0
  69. package/src/components/decision-modal/index.ts +9 -0
  70. package/src/components/divider/divider.html +1 -0
  71. package/src/components/divider/divider.scss +29 -0
  72. package/src/components/divider/divider.type.ts +6 -0
  73. package/src/components/divider/divider.vue +34 -0
  74. package/src/components/divider/index.ts +2 -0
  75. package/src/components/field/field.html +1 -0
  76. package/src/components/field/field.type.ts +43 -0
  77. package/src/components/field/field.vue +85 -0
  78. package/src/components/field/index.ts +2 -0
  79. package/src/components/field/outline/index.ts +1 -0
  80. package/src/components/field/outline/outline.html +32 -0
  81. package/src/components/field/outline/outline.scss +224 -0
  82. package/src/components/field/outline/outline.vue +243 -0
  83. package/src/components/form-group/form-group.html +3 -0
  84. package/src/components/form-group/form-group.scss +91 -0
  85. package/src/components/form-group/form-group.type.ts +5 -0
  86. package/src/components/form-group/form-group.vue +21 -0
  87. package/src/components/form-group/index.ts +2 -0
  88. package/src/components/gesture-indicator/gesture-indicator.html +1 -0
  89. package/src/components/gesture-indicator/gesture-indicator.scss +45 -0
  90. package/{dist/components/gesture-indicator/gesture-indicator.type.d.ts → src/components/gesture-indicator/gesture-indicator.type.ts} +2 -1
  91. package/src/components/gesture-indicator/gesture-indicator.vue +32 -0
  92. package/src/components/gesture-indicator/index.ts +1 -0
  93. package/src/components/image/image.html +1 -0
  94. package/src/components/image/image.scss +1 -0
  95. package/src/components/image/image.type.ts +5 -0
  96. package/src/components/image/image.vue +25 -0
  97. package/src/components/image/index.ts +2 -0
  98. package/src/components/index.ts +27 -0
  99. package/src/components/modal/index.ts +2 -0
  100. package/src/components/modal/modal.html +20 -0
  101. package/src/components/modal/modal.scss +78 -0
  102. package/src/components/modal/modal.type.ts +21 -0
  103. package/src/components/modal/modal.vue +186 -0
  104. package/src/components/page/index.ts +1 -0
  105. package/src/components/page/page.html +3 -0
  106. package/src/components/page/page.scss +17 -0
  107. package/src/components/page/page.vue +14 -0
  108. package/src/components/present/index.ts +3 -0
  109. package/src/components/present/present.composable.ts +21 -0
  110. package/src/components/present/present.html +9 -0
  111. package/src/components/present/present.scss +81 -0
  112. package/src/components/present/present.type.ts +26 -0
  113. package/src/components/present/present.vue +198 -0
  114. package/src/components/radio/index.ts +2 -0
  115. package/src/components/radio/radio/index.ts +2 -0
  116. package/src/components/radio/radio/radio.html +11 -0
  117. package/src/components/radio/radio/radio.scss +125 -0
  118. package/src/components/radio/radio/radio.type.ts +11 -0
  119. package/src/components/radio/radio/radio.vue +103 -0
  120. package/src/components/radio/radio-group/index.ts +7 -0
  121. package/src/components/radio/radio-group/radio-group.constants.ts +1 -0
  122. package/src/components/radio/radio-group/radio-group.html +3 -0
  123. package/src/components/radio/radio-group/radio-group.scss +16 -0
  124. package/src/components/radio/radio-group/radio-group.type.ts +28 -0
  125. package/src/components/radio/radio-group/radio-group.vue +62 -0
  126. package/src/components/refresher/index.ts +2 -0
  127. package/src/components/refresher/refresher.html +6 -0
  128. package/src/components/refresher/refresher.scss +36 -0
  129. package/src/components/refresher/refresher.type.ts +16 -0
  130. package/src/components/refresher/refresher.vue +137 -0
  131. package/src/components/route/index.ts +5 -0
  132. package/src/components/route/route-navigator/index.ts +2 -0
  133. package/src/components/route/route-navigator/route-navigator.html +19 -0
  134. package/src/components/route/route-navigator/route-navigator.scss +127 -0
  135. package/src/components/route/route-navigator/route-navigator.type.ts +12 -0
  136. package/src/components/route/route-navigator/route-navigator.vue +250 -0
  137. package/src/components/route/route-outlet/index.ts +1 -0
  138. package/src/components/route/route-outlet/route-outlet.html +1 -0
  139. package/src/components/route/route-outlet/route-outlet.vue +30 -0
  140. package/src/components/route/route-provider/index.ts +3 -0
  141. package/src/components/route/route-provider/route-provider.constant.ts +1 -0
  142. package/src/components/route/route-provider/route-provider.html +1 -0
  143. package/src/components/route/route-provider/route-provider.type.ts +10 -0
  144. package/src/components/route/route-provider/route-provider.vue +20 -0
  145. package/src/components/route/route-wrapper/index.ts +3 -0
  146. package/src/components/route/route-wrapper/route-wrapper.composable.ts +43 -0
  147. package/src/components/route/route-wrapper/route-wrapper.html +3 -0
  148. package/src/components/route/route-wrapper/route-wrapper.type.ts +3 -0
  149. package/src/components/route/route-wrapper/route-wrapper.vue +43 -0
  150. package/src/components/route/route.type.ts +7 -0
  151. package/src/components/route/route.util.ts +8 -0
  152. package/src/components/segmented-field/index.ts +7 -0
  153. package/src/components/segmented-field/segmented-field.html +17 -0
  154. package/src/components/segmented-field/segmented-field.scss +52 -0
  155. package/src/components/segmented-field/segmented-field.type.ts +29 -0
  156. package/src/components/segmented-field/segmented-field.vue +151 -0
  157. package/src/components/skeleton/index.ts +2 -0
  158. package/src/components/skeleton/skeleton.html +1 -0
  159. package/src/components/skeleton/skeleton.scss +45 -0
  160. package/src/components/skeleton/skeleton.type.ts +7 -0
  161. package/src/components/skeleton/skeleton.vue +38 -0
  162. package/src/components/switch/index.ts +2 -0
  163. package/src/components/switch/switch.html +15 -0
  164. package/src/components/switch/switch.scss +134 -0
  165. package/src/components/switch/switch.type.ts +13 -0
  166. package/src/components/switch/switch.vue +92 -0
  167. package/src/components/tabs/index.ts +2 -0
  168. package/src/components/tabs/tab/index.ts +2 -0
  169. package/src/components/tabs/tab/tab.html +5 -0
  170. package/src/components/tabs/tab/tab.type.ts +5 -0
  171. package/src/components/tabs/tab/tab.vue +38 -0
  172. package/src/components/tabs/tabs/index.ts +9 -0
  173. package/src/components/tabs/tabs/tabs.constants.ts +1 -0
  174. package/src/components/tabs/tabs/tabs.html +3 -0
  175. package/src/components/tabs/tabs/tabs.scss +272 -0
  176. package/src/components/tabs/tabs/tabs.type.ts +36 -0
  177. package/src/components/tabs/tabs/tabs.vue +159 -0
  178. package/src/components/toast/index.ts +4 -0
  179. package/src/components/toast/toast/index.ts +1 -0
  180. package/src/components/toast/toast/toast.html +9 -0
  181. package/src/components/toast/toast/toast.scss +61 -0
  182. package/src/components/toast/toast/toast.vue +34 -0
  183. package/src/components/toast/toast-content/index.ts +1 -0
  184. package/src/components/toast/toast-content/toast-content.html +1 -0
  185. package/src/components/toast/toast-content/toast-content.scss +41 -0
  186. package/src/components/toast/toast-content/toast-content.vue +59 -0
  187. package/src/components/toast/toast.composable.ts +22 -0
  188. package/src/components/toast/toast.type.ts +25 -0
  189. package/src/components/toolbar/index.ts +2 -0
  190. package/src/components/toolbar/toolbar.html +5 -0
  191. package/src/components/toolbar/toolbar.scss +79 -0
  192. package/src/components/toolbar/toolbar.type.ts +7 -0
  193. package/src/components/toolbar/toolbar.vue +47 -0
  194. package/src/env.d.ts +7 -0
  195. package/src/factory.ts +81 -0
  196. package/src/index.ts +4 -0
  197. package/{dist/type.d.ts → src/type.ts} +1 -1
  198. package/src/utils/element.ts +16 -0
  199. package/src/utils/events.ts +12 -0
  200. package/src/utils/index.ts +3 -0
  201. package/src/utils/style/index.ts +42 -0
  202. package/dist/components/action/action.type.d.ts +0 -17
  203. package/dist/components/action/action.vue.d.ts +0 -14
  204. package/dist/components/action/factory.d.ts +0 -3
  205. package/dist/components/action/index.d.ts +0 -2
  206. package/dist/components/alert/alert.type.d.ts +0 -16
  207. package/dist/components/alert/alert.vue.d.ts +0 -14
  208. package/dist/components/alert/factory.d.ts +0 -3
  209. package/dist/components/alert/index.d.ts +0 -2
  210. package/dist/components/app/app.type.d.ts +0 -1
  211. package/dist/components/app/app.vue.d.ts +0 -3
  212. package/dist/components/app/index.d.ts +0 -1
  213. package/dist/components/avatar/avatar.type.d.ts +0 -4
  214. package/dist/components/avatar/avatar.vue.d.ts +0 -6
  215. package/dist/components/avatar/index.d.ts +0 -1
  216. package/dist/components/back-button/back-button.type.d.ts +0 -4
  217. package/dist/components/back-button/back-button.vue.d.ts +0 -3
  218. package/dist/components/back-button/index.d.ts +0 -1
  219. package/dist/components/button/button.type.d.ts +0 -10
  220. package/dist/components/button/button.vue.d.ts +0 -12
  221. package/dist/components/button/index.d.ts +0 -1
  222. package/dist/components/cable/cable.type.d.ts +0 -4
  223. package/dist/components/cable/cable.vue.d.ts +0 -6
  224. package/dist/components/cable/index.d.ts +0 -1
  225. package/dist/components/card/card.type.d.ts +0 -3
  226. package/dist/components/card/card.vue.d.ts +0 -5
  227. package/dist/components/card/index.d.ts +0 -1
  228. package/dist/components/checkbox/checkbox.type.d.ts +0 -12
  229. package/dist/components/checkbox/checkbox.vue.d.ts +0 -14
  230. package/dist/components/checkbox/index.d.ts +0 -1
  231. package/dist/components/collapse/collapse.type.d.ts +0 -6
  232. package/dist/components/collapse/collapse.vue.d.ts +0 -7
  233. package/dist/components/collapse/index.d.ts +0 -1
  234. package/dist/components/content/content.type.d.ts +0 -1
  235. package/dist/components/content/content.vue.d.ts +0 -3
  236. package/dist/components/content/index.d.ts +0 -1
  237. package/dist/components/divider/divider.type.d.ts +0 -3
  238. package/dist/components/divider/divider.vue.d.ts +0 -5
  239. package/dist/components/divider/index.d.ts +0 -1
  240. package/dist/components/flex/flex.type.d.ts +0 -4
  241. package/dist/components/flex/flex.vue.d.ts +0 -6
  242. package/dist/components/flex/index.d.ts +0 -1
  243. package/dist/components/gesture-indicator/gesture-indicator.vue.d.ts +0 -5
  244. package/dist/components/gesture-indicator/index.d.ts +0 -1
  245. package/dist/components/grid/grid.type.d.ts +0 -4
  246. package/dist/components/grid/grid.vue.d.ts +0 -6
  247. package/dist/components/grid/index.d.ts +0 -1
  248. package/dist/components/icon-spinner/icon-spinner.type.d.ts +0 -4
  249. package/dist/components/icon-spinner/icon-spinner.vue.d.ts +0 -6
  250. package/dist/components/icon-spinner/index.d.ts +0 -1
  251. package/dist/components/image/image.type.d.ts +0 -4
  252. package/dist/components/image/image.vue.d.ts +0 -3
  253. package/dist/components/image/index.d.ts +0 -1
  254. package/dist/components/index.d.ts +0 -36
  255. package/dist/components/input/index.d.ts +0 -1
  256. package/dist/components/input/input.type.d.ts +0 -15
  257. package/dist/components/input/input.vue.d.ts +0 -16
  258. package/dist/components/keyboard-space/factory.d.ts +0 -3
  259. package/dist/components/keyboard-space/index.d.ts +0 -2
  260. package/dist/components/keyboard-space/keyboard-space.type.d.ts +0 -1
  261. package/dist/components/keyboard-space/keyboard-space.vue.d.ts +0 -3
  262. package/dist/components/loading/factory.d.ts +0 -4
  263. package/dist/components/loading/index.d.ts +0 -2
  264. package/dist/components/loading/loading.type.d.ts +0 -6
  265. package/dist/components/loading/loading.vue.d.ts +0 -12
  266. package/dist/components/present/factory.d.ts +0 -1
  267. package/dist/components/present/index.d.ts +0 -2
  268. package/dist/components/present/present.type.d.ts +0 -13
  269. package/dist/components/present/present.vue.d.ts +0 -17
  270. package/dist/components/refresher/index.d.ts +0 -1
  271. package/dist/components/refresher/refresher.type.d.ts +0 -11
  272. package/dist/components/refresher/refresher.vue.d.ts +0 -17
  273. package/dist/components/richtext/index.d.ts +0 -1
  274. package/dist/components/richtext/richtext.type.d.ts +0 -1
  275. package/dist/components/richtext/richtext.vue.d.ts +0 -3
  276. package/dist/components/ripple/index.d.ts +0 -1
  277. package/dist/components/ripple/ripple.type.d.ts +0 -3
  278. package/dist/components/ripple/ripple.vue.d.ts +0 -5
  279. package/dist/components/screen/index.d.ts +0 -1
  280. package/dist/components/screen/screen.type.d.ts +0 -1
  281. package/dist/components/screen/screen.vue.d.ts +0 -3
  282. package/dist/components/screen-router/factory.d.ts +0 -19
  283. package/dist/components/screen-router/index.d.ts +0 -2
  284. package/dist/components/screen-router/screen-router.type.d.ts +0 -8
  285. package/dist/components/screen-router/screen-router.vue.d.ts +0 -9
  286. package/dist/components/sheet/index.d.ts +0 -1
  287. package/dist/components/sheet/sheet.type.d.ts +0 -18
  288. package/dist/components/sheet/sheet.vue.d.ts +0 -18
  289. package/dist/components/skeleton/index.d.ts +0 -1
  290. package/dist/components/skeleton/skeleton.type.d.ts +0 -6
  291. package/dist/components/skeleton/skeleton.vue.d.ts +0 -8
  292. package/dist/components/switch/index.d.ts +0 -1
  293. package/dist/components/switch/switch.type.d.ts +0 -7
  294. package/dist/components/switch/switch.vue.d.ts +0 -9
  295. package/dist/components/tab/index.d.ts +0 -1
  296. package/dist/components/tab/tab.type.d.ts +0 -4
  297. package/dist/components/tab/tab.vue.d.ts +0 -5
  298. package/dist/components/tabs/index.d.ts +0 -1
  299. package/dist/components/tabs/tabs.type.d.ts +0 -13
  300. package/dist/components/tabs/tabs.vue.d.ts +0 -15
  301. package/dist/components/text/index.d.ts +0 -1
  302. package/dist/components/text/text.type.d.ts +0 -4
  303. package/dist/components/text/text.vue.d.ts +0 -6
  304. package/dist/components/textarea/index.d.ts +0 -1
  305. package/dist/components/textarea/textarea.type.d.ts +0 -1
  306. package/dist/components/textarea/textarea.vue.d.ts +0 -3
  307. package/dist/components/toast/factory.d.ts +0 -3
  308. package/dist/components/toast/index.d.ts +0 -2
  309. package/dist/components/toast/toast.type.d.ts +0 -11
  310. package/dist/components/toast/toast.vue.d.ts +0 -16
  311. package/dist/components/toggle-password/index.d.ts +0 -1
  312. package/dist/components/toggle-password/toggle-password.type.d.ts +0 -6
  313. package/dist/components/toggle-password/toggle-password.vue.d.ts +0 -9
  314. package/dist/components/toolbar/index.d.ts +0 -1
  315. package/dist/components/toolbar/toolbar.type.d.ts +0 -5
  316. package/dist/components/toolbar/toolbar.vue.d.ts +0 -7
  317. package/dist/factory.d.ts +0 -4
  318. package/dist/index.css +0 -1
  319. package/dist/index.d.ts +0 -4
  320. package/dist/index.es.js +0 -1836
  321. package/dist/index.umd.js +0 -1
  322. package/dist/utils/element.d.ts +0 -2
  323. package/dist/utils/events.d.ts +0 -1
  324. package/dist/utils/index.d.ts +0 -2
@@ -0,0 +1,137 @@
1
+ <style lang="scss" src="./refresher.scss" scoped></style>
2
+ <template src="./refresher.html"></template>
3
+ <script lang="ts" setup>
4
+ import { ref, onUnmounted, watch, computed } from "vue";
5
+ import { gesture } from "@toife/gesture";
6
+ import type { RefresherProps, RefresherEmit } from "./refresher.type";
7
+ import { property, withPrefix } from "../../utils";
8
+
9
+ /// Define
10
+ /// ------------------------------------------------------------
11
+ const emit = defineEmits<RefresherEmit>();
12
+ const props = withDefaults(defineProps<RefresherProps>(), {
13
+ threshold: 120,
14
+ variant: "max",
15
+ offset: undefined,
16
+ });
17
+
18
+ /// State
19
+ /// ------------------------------------------------------------
20
+ const moveOffset = ref(0);
21
+ const refreshing = ref(false);
22
+ const container = ref();
23
+ let cleanup: unknown;
24
+ let locked = false;
25
+
26
+ /// Computed
27
+ /// ------------------------------------------------------------
28
+ const calculateOffset = computed(() => {
29
+ return props.offset !== undefined ? props.offset : moveOffset.value / 2;
30
+ });
31
+
32
+ const refresherAttrs = computed(() => {
33
+ return {
34
+ style: {
35
+ [property("refresher-offset")]: `${calculateOffset.value}px`,
36
+ },
37
+ class: [
38
+ withPrefix("refresher"),
39
+ {
40
+ moving: calculateOffset.value > 0,
41
+ },
42
+ ],
43
+ };
44
+ });
45
+
46
+ const containerAttrs = computed(() => {
47
+ return {
48
+ class: [withPrefix("refresher-container")],
49
+ };
50
+ });
51
+
52
+ /// Methods
53
+ /// ------------------------------------------------------------
54
+ const close = () => {
55
+ refreshing.value = false;
56
+ moveOffset.value = 0;
57
+ locked = false;
58
+ };
59
+
60
+ const start = () => {
61
+ locked = true;
62
+ refreshing.value = true;
63
+ moveOffset.value = props.threshold;
64
+ emit("refresh", close);
65
+ };
66
+
67
+ const cancel = () => {
68
+ moveOffset.value = 0;
69
+ refreshing.value = false;
70
+ locked = false;
71
+ emit("cancel");
72
+ };
73
+
74
+ /// Lifecycle
75
+ /// ------------------------------------------------------------
76
+ watch(
77
+ () => container.value,
78
+ () => {
79
+ cleanup && (cleanup as { destroy: () => void }).destroy();
80
+ if (!container.value) return;
81
+ cleanup = gesture(
82
+ container.value,
83
+ {
84
+ options: {
85
+ minMove: 20,
86
+ },
87
+
88
+ beforeEvent() {
89
+ if (container.value.scrollTop > 0) return false;
90
+ return true;
91
+ },
92
+
93
+ down() {
94
+ if (refreshing.value || locked) return;
95
+ emit("start");
96
+ },
97
+
98
+ move({ deltaY, initialDirection }: unknown) {
99
+ if (refreshing.value || locked || initialDirection != "down") return;
100
+
101
+ const v = deltaY < 0 ? 0 : deltaY;
102
+ moveOffset.value = v;
103
+ emit("move", v);
104
+
105
+ if (props.variant == "max") {
106
+ if (deltaY >= props.threshold) {
107
+ start();
108
+ return;
109
+ }
110
+ }
111
+ },
112
+ up({ deltaY, initialDirection }: unknown) {
113
+ if (refreshing.value || locked || initialDirection != "down") return;
114
+
115
+ // max
116
+ if (props.variant == "up" && deltaY >= props.threshold) {
117
+ start();
118
+ } else {
119
+ cancel();
120
+ }
121
+ },
122
+ cancel() {
123
+ if (refreshing.value || locked) return;
124
+ cancel();
125
+ },
126
+ },
127
+ {
128
+ passive: false,
129
+ }
130
+ );
131
+ }
132
+ );
133
+
134
+ onUnmounted(() => {
135
+ cleanup && (cleanup as { destroy: () => void }).destroy();
136
+ });
137
+ </script>
@@ -0,0 +1,5 @@
1
+ export * from "./route-navigator";
2
+ export * from "./route-wrapper";
3
+ export * from "./route-provider";
4
+ export * from "./route-outlet";
5
+ export * from "./route.type";
@@ -0,0 +1,2 @@
1
+ export { default as RouteNavigator } from "./route-navigator.vue";
2
+ export * from "./route-navigator.type";
@@ -0,0 +1,19 @@
1
+ <div v-bind="navigatorAttrs" ref="navigatorRef">
2
+ <div
3
+ v-for="(item, index) in stack"
4
+ :key="item.name"
5
+ v-bind="componentAttrs"
6
+ :style="{zIndex: index * 2}"
7
+ :name="item.name"
8
+ :class="{
9
+ active: index === activeIndex,
10
+ prepare: index === activeIndex + 1,
11
+ back: index === activeIndex - 1,
12
+ }"
13
+ >
14
+ <RouteProvider :stack="item.stack">
15
+ <RouteOutlet :component="item.component" />
16
+ </RouteProvider>
17
+ </div>
18
+ <div v-bind="backdropAttrs"></div>
19
+ </div>
@@ -0,0 +1,127 @@
1
+ @use "@toife/sass-layer-generator" as sass;
2
+
3
+ // Classes
4
+ $navigator: sass.fn-naming-prefix("route-navigator");
5
+ $navigator-component: sass.fn-naming-prefix("route-navigator-component");
6
+ $navigator-backdrop: sass.fn-naming-prefix("route-navigator-backdrop");
7
+
8
+ // Property name
9
+ $background-color: sass.fn-naming-var("base", "background-color");
10
+ $transition-duration: sass.fn-naming-dvar(
11
+ ("route-navigator-transition-duration"),
12
+ sass.fn-naming-var("motion", "duration")
13
+ );
14
+ $transform-back: sass.fn-naming-var("route-navigator-transform", "back");
15
+ $transform-prepare: sass.fn-naming-var("route-navigator-transform", "prepare");
16
+ $transform-active: sass.fn-naming-var("route-navigator-transform", "active");
17
+ $backdrop-percent: sass.fn-naming-var("route-navigator-backdrop-percent");
18
+ $backdrop-opacity: sass.fn-naming-var("backdrop", "opacity");
19
+ $backdrop-background-color: sass.fn-naming-var("backdrop", "background-color");
20
+
21
+ // Properties
22
+ .#{$navigator} {
23
+ width: 100%;
24
+ height: 100%;
25
+ display: flex;
26
+ flex-wrap: nowrap;
27
+ overflow: hidden;
28
+ justify-content: flex-end;
29
+ position: relative;
30
+
31
+ &.right {
32
+ flex-direction: row;
33
+ }
34
+
35
+ &.left {
36
+ flex-direction: row-reverse;
37
+ }
38
+
39
+ &.up {
40
+ flex-direction: column;
41
+ }
42
+
43
+ &.down {
44
+ flex-direction: column-reverse;
45
+ }
46
+
47
+ .#{$navigator-backdrop} {
48
+ position: absolute;
49
+ width: 100%;
50
+ height: 100%;
51
+ top: 0;
52
+ left: 0;
53
+ background-color: rgb(#{$backdrop-background-color});
54
+ opacity: calc(#{$backdrop-opacity} * (#{$backdrop-percent} / 100));
55
+ transition: opacity #{$transition-duration} ease;
56
+ }
57
+
58
+ .#{$navigator-component} {
59
+ width: 100%;
60
+ height: 100%;
61
+ position: absolute;
62
+ max-width: 100%;
63
+ max-height: 100%;
64
+ top: 0;
65
+ left: 0;
66
+ flex: none;
67
+ background-color: rgb(#{$background-color});
68
+ transform: translate(0, 0);
69
+ transition:
70
+ transform #{$transition-duration} ease,
71
+ background-color #{$transition-duration} ease;
72
+
73
+ &.active {
74
+ &.right {
75
+ transform: translateX(#{$transform-active});
76
+ }
77
+
78
+ &.left {
79
+ transform: translateX(calc(-1 * #{$transform-active}));
80
+ }
81
+
82
+ &.up {
83
+ transform: translateY(calc(-1 * #{$transform-active}));
84
+ }
85
+
86
+ &.down {
87
+ transform: translateY(#{$transform-active});
88
+ }
89
+ }
90
+
91
+ &.prepare {
92
+ &.right {
93
+ transform: translateX(#{$transform-prepare});
94
+ }
95
+
96
+ &.left {
97
+ transform: translateX(calc(-1 * #{$transform-prepare}));
98
+ }
99
+
100
+ &.up {
101
+ transform: translateY(calc(-1 * #{$transform-prepare}));
102
+ }
103
+
104
+ &.down {
105
+ transform: translateY(#{$transform-prepare});
106
+ }
107
+ }
108
+
109
+ &.back {
110
+ &.right {
111
+ transform: translateX(calc(-1 * #{$transform-back}));
112
+ }
113
+
114
+ &.left {
115
+ transform: translateX(#{$transform-back});
116
+ }
117
+
118
+ &.up {
119
+ transform: translateY(#{$transform-back});
120
+ }
121
+
122
+ &.down {
123
+ transform: translateY(calc(-1 * #{$transform-back}));
124
+ }
125
+ }
126
+ }
127
+ }
@@ -0,0 +1,12 @@
1
+ export type RouteNavigatorVariant = "none" | "swipe";
2
+
3
+ export type RouteNavigatorProps = {
4
+ direction?: "left" | "right";
5
+ variant?: RouteNavigatorVariant;
6
+ keepalive?: boolean;
7
+ };
8
+
9
+ export type RouteNavigatorGesture = {
10
+ deltaX: number;
11
+ deltaY: number;
12
+ };
@@ -0,0 +1,250 @@
1
+ <style lang="scss" src="./route-navigator.scss" scoped></style>
2
+ <template src="./route-navigator.html"></template>
3
+ <script lang="ts" setup>
4
+ import { computed, inject, onMounted, onUnmounted, reactive, ref, watch } from "vue";
5
+ import { gesture } from "@toife/gesture";
6
+ import { withPrefix, property } from "../../../utils";
7
+ import type { RouteNavigatorProps } from "./route-navigator.type";
8
+ import {
9
+ ROUTE_PROVIDER_STATE_KEY,
10
+ RouteProvider,
11
+ type RouteProviderState,
12
+ } from "../route-provider";
13
+ import { RouteOutlet } from "../route-outlet";
14
+ import type { RouteNavigatorGesture } from "./route-navigator.type";
15
+ import type { RouteStack } from "../route.type";
16
+ import { useRouter } from "vue-router";
17
+ import { clone } from "../route.util";
18
+
19
+ /// Define
20
+ /// ------------------------------------------------------------
21
+ const props = withDefaults(defineProps<RouteNavigatorProps>(), {
22
+ direction: "right",
23
+ variant: "none",
24
+ keepalive: false,
25
+ });
26
+ const provider = inject<RouteProviderState>(ROUTE_PROVIDER_STATE_KEY);
27
+ const router = useRouter();
28
+ /// State
29
+ /// ------------------------------------------------------------
30
+ const navigatorRef = ref<HTMLElement>();
31
+ const ges = ref<unknown>(null);
32
+ const transform = reactive({
33
+ back: 30,
34
+ prepare: 100,
35
+ active: 0,
36
+ backdrop: 0,
37
+ duration: undefined as string | undefined,
38
+ });
39
+ const stack = ref<RouteStack[]>([]);
40
+ const activeIndex = ref(0);
41
+ const backdropIndex = ref(0);
42
+
43
+ /// Computed
44
+ /// ------------------------------------------------------------
45
+ const navigatorAttrs = computed(() => {
46
+ let duration =
47
+ transform.duration !== undefined ? transform.duration : transform.active > 0 ? "0s" : undefined;
48
+
49
+ if (props.variant === "none") {
50
+ duration = "0s";
51
+ }
52
+
53
+ return {
54
+ class: [withPrefix("route-navigator"), props.direction, props.variant],
55
+ style: {
56
+ [property("route-navigator-transform-back")]: transform.back + "%",
57
+ [property("route-navigator-transform-prepare")]: transform.prepare + "%",
58
+ [property("route-navigator-transform-active")]: transform.active + "%",
59
+ [property("route-navigator-transition-duration")]: duration,
60
+ [property("route-navigator-backdrop-percent")]: transform.backdrop,
61
+ },
62
+ };
63
+ });
64
+
65
+ const componentAttrs = computed(() => {
66
+ return {
67
+ class: [withPrefix("route-navigator-component"), props.direction],
68
+ };
69
+ });
70
+
71
+ const backdropAttrs = computed(() => {
72
+ return {
73
+ class: [withPrefix("route-navigator-backdrop"), withPrefix(["layer", "backdrop"])],
74
+ style: {
75
+ zIndex: backdropIndex.value * 2 - 1,
76
+ },
77
+ };
78
+ });
79
+
80
+ const prevPage = computed(() => {
81
+ if (activeIndex.value > 0) {
82
+ return stack.value.at(activeIndex.value - 1) ?? null;
83
+ }
84
+ return null;
85
+ });
86
+
87
+ /// Methods
88
+ /// ------------------------------------------------------------
89
+ const changeRoute = (value: RouteStack[]) => {
90
+ const data = clone(value);
91
+
92
+ // Case: first time
93
+ if (stack.value.length === 0) {
94
+ stack.value = data;
95
+ return;
96
+ }
97
+
98
+ // Case: update
99
+ if (stack.value.length === data.length) {
100
+ const ln = stack.value.length - 1;
101
+ stack.value[ln].stack = data[ln].stack;
102
+ }
103
+ // Case: back
104
+ else if (stack.value.length > data.length) {
105
+ const newIndex = activeIndex.value - 1;
106
+ resetTransform();
107
+ activeIndex.value = newIndex;
108
+ transform.backdrop = 0;
109
+ setTimeout(() => {
110
+ stack.value = stack.value.slice(0, -1);
111
+ backdropIndex.value = newIndex;
112
+ transform.backdrop = 100;
113
+ }, 250);
114
+ }
115
+ // Case: next
116
+ else {
117
+ stack.value.push(data[data.length - 1]);
118
+ transform.duration = "0s";
119
+ transform.backdrop = 0;
120
+
121
+ setTimeout(() => {
122
+ backdropIndex.value = backdropIndex.value + 1;
123
+ transform.duration = undefined;
124
+ }, 10);
125
+
126
+ setTimeout(() => {
127
+ transform.backdrop = 100;
128
+ activeIndex.value = stack.value.length - 1;
129
+ }, 100);
130
+ }
131
+ };
132
+
133
+ const goBack = () => {
134
+ router.back();
135
+ };
136
+
137
+ const resetTransform = () => {
138
+ transform.back = 40;
139
+ transform.prepare = 100;
140
+ transform.active = 0;
141
+ };
142
+
143
+ const move = (data: RouteNavigatorGesture) => {
144
+ const width = navigatorRef.value?.offsetWidth ?? 0;
145
+ let percent = 0;
146
+
147
+ if (props.direction == "left" || props.direction == "right") {
148
+ percent = (Math.abs(data.deltaX) / width) * 100;
149
+ } else {
150
+ percent = (Math.abs(data.deltaY) / width) * 100;
151
+ }
152
+
153
+ transform.back = Math.round(((100 - percent) * 40) / 100);
154
+ transform.active = Math.round(percent);
155
+ transform.backdrop = 100 - transform.active;
156
+ };
157
+
158
+ const up = (data: RouteNavigatorGesture) => {
159
+ const width = navigatorRef.value?.offsetWidth ?? 0;
160
+ let percent = 0;
161
+
162
+ if (props.direction == "left" || props.direction == "right") {
163
+ percent = (Math.abs(data.deltaX) / width) * 100;
164
+ } else {
165
+ percent = (Math.abs(data.deltaY) / width) * 100;
166
+ }
167
+
168
+ if (percent >= 60) {
169
+ goBack();
170
+ } else {
171
+ resetTransform();
172
+ }
173
+ };
174
+
175
+ /// Lifecycle
176
+ /// ------------------------------------------------------------
177
+ watch(
178
+ () => provider?.stack.value,
179
+ (value) => {
180
+ changeRoute(value as RouteStack[]);
181
+ }
182
+ );
183
+
184
+ onMounted(() => {
185
+ changeRoute(provider?.stack.value as RouteStack[]);
186
+
187
+ // Initialize gesture
188
+ ges.value =
189
+ navigatorRef.value &&
190
+ gesture(navigatorRef.value, {
191
+ beforeEvent(e: Event) {
192
+ const target = e.target as HTMLElement | null;
193
+ const isEditable = target?.closest("input, textarea, select, button, [contenteditable]");
194
+ if (isEditable) return false;
195
+ e.preventDefault();
196
+ e.stopPropagation();
197
+ return prevPage.value;
198
+ },
199
+
200
+ fast({ initialDirection, event }: { initialDirection: string; event: Event }) {
201
+ if (initialDirection !== props.direction) return;
202
+ event.stopPropagation();
203
+ event.preventDefault();
204
+ goBack();
205
+ },
206
+
207
+ move({
208
+ deltaX,
209
+ deltaY,
210
+ initialDirection,
211
+ event,
212
+ }: {
213
+ deltaX: number;
214
+ deltaY: number;
215
+ initialDirection: string;
216
+ event: Event;
217
+ }) {
218
+ if (initialDirection !== props.direction) return;
219
+ event.stopPropagation();
220
+ event.preventDefault();
221
+ move({ deltaX, deltaY });
222
+ },
223
+
224
+ up({
225
+ deltaX,
226
+ deltaY,
227
+ initialDirection,
228
+ event,
229
+ }: {
230
+ deltaX: number;
231
+ deltaY: number;
232
+ initialDirection: string;
233
+ event: Event;
234
+ }) {
235
+ if (initialDirection !== props.direction) return;
236
+ event.stopPropagation();
237
+ event.preventDefault();
238
+ up({ deltaX, deltaY });
239
+ },
240
+
241
+ cancel() {
242
+ resetTransform();
243
+ },
244
+ });
245
+ });
246
+
247
+ onUnmounted(() => {
248
+ if (ges.value) (ges.value as { destroy: () => void }).destroy();
249
+ });
250
+ </script>
@@ -0,0 +1 @@
1
+ export { default as RouteOutlet } from "./route-outlet.vue";
@@ -0,0 +1 @@
1
+ <component :is="renderComponent" v-if="renderComponent"></component>
@@ -0,0 +1,30 @@
1
+ <template src="./route-outlet.html"></template>
2
+ <script lang="ts" setup>
3
+ import { markRaw, onMounted, ref } from "vue";
4
+
5
+ /// Define
6
+ /// ------------------------------------------------------------
7
+ const props = defineProps<{
8
+ component: unknown;
9
+ }>();
10
+
11
+ /// State
12
+ /// ------------------------------------------------------------
13
+ const renderComponent = ref<unknown | null>(null);
14
+
15
+ /// Methods
16
+ /// ------------------------------------------------------------
17
+ const resolveComponent = async (raw: unknown): Promise<unknown> => {
18
+ if (typeof raw !== "function") return raw;
19
+ const mod = await (raw as () => Promise<{ default?: unknown }>)();
20
+ return mod?.default ?? mod;
21
+ };
22
+
23
+ /// Lifecycle
24
+ /// ------------------------------------------------------------
25
+ onMounted(async () => {
26
+ const c = props.component as { default?: unknown };
27
+ const component = await resolveComponent(c?.default);
28
+ renderComponent.value = component ? markRaw(component) : null;
29
+ });
30
+ </script>
@@ -0,0 +1,3 @@
1
+ export { default as RouteProvider } from "./route-provider.vue";
2
+ export * from "./route-provider.type";
3
+ export * from "./route-provider.constant";
@@ -0,0 +1 @@
1
+ export const ROUTE_PROVIDER_STATE_KEY = "route-provider-state";
@@ -0,0 +1,10 @@
1
+ import { ComputedRef } from "vue";
2
+ import { RouteStack } from "../route.type";
3
+
4
+ export type RouteProviderProps = {
5
+ stack: RouteStack[];
6
+ };
7
+
8
+ export type RouteProviderState = {
9
+ stack: ComputedRef<RouteStack[]>;
10
+ };
@@ -0,0 +1,20 @@
1
+ <template src="./route-provider.html"></template>
2
+ <script lang="ts" setup>
3
+ import { ROUTE_PROVIDER_STATE_KEY } from "./route-provider.constant";
4
+ import { type RouteProviderProps, type RouteProviderState } from "./route-provider.type";
5
+ import { provide, computed } from "vue";
6
+
7
+ /// Defined
8
+ /// ------------------------------------------------------------
9
+ const props = defineProps<RouteProviderProps>();
10
+
11
+ /// Computed
12
+ /// ------------------------------------------------------------
13
+ const stack = computed(() => props.stack);
14
+
15
+ /// Provide
16
+ /// ------------------------------------------------------------
17
+ provide<RouteProviderState>(ROUTE_PROVIDER_STATE_KEY, {
18
+ stack,
19
+ });
20
+ </script>
@@ -0,0 +1,3 @@
1
+ export { default as RouteWrapper } from "./route-wrapper.vue";
2
+ export * from "./route-wrapper.composable";
3
+ export * from "./route-wrapper.type";
@@ -0,0 +1,43 @@
1
+ import { shallowRef } from "vue";
2
+ import { type RouteComponent, type RouteLocationMatched } from "vue-router";
3
+ import { type RouteStack } from "../route.type";
4
+
5
+ const stack = shallowRef<RouteStack[]>([]);
6
+ const buildTree = (matched: RouteLocationMatched[], data: RouteStack[]) => {
7
+ if (matched.length === 0) return data;
8
+
9
+ // Case data is previous
10
+ if (data.length > 1 && data[data.length - 2]?.name === matched[0].name) {
11
+ data.pop();
12
+ }
13
+
14
+ // Case data is current
15
+ if (data.length > 0 && data[data.length - 1] && data[data.length - 1].name === matched[0].name) {
16
+ matched.shift();
17
+ data[data.length - 1].stack = buildTree(matched, data[data.length - 1].stack);
18
+ }
19
+ // Case data is add
20
+ else {
21
+ const name = String(matched[0].name);
22
+ const component = matched[0].components as RouteComponent;
23
+ matched.shift();
24
+ data.push({
25
+ name,
26
+ component,
27
+ stack: buildTree(matched, []),
28
+ });
29
+ }
30
+
31
+ return data;
32
+ };
33
+
34
+ export const useRouteWrapper = () => {
35
+ const updateRoutes = (matched: RouteLocationMatched[]) => {
36
+ stack.value = buildTree([...matched], [...stack.value]);
37
+ };
38
+
39
+ return {
40
+ stack,
41
+ updateRoutes,
42
+ };
43
+ };
@@ -0,0 +1,3 @@
1
+ <RouteProvider :stack="stack">
2
+ <slot />
3
+ </RouteProvider>
@@ -0,0 +1,3 @@
1
+ export type RouteWrapperProps = {
2
+ homeRouteName?: string;
3
+ };