@toife/vue 2.1.7 → 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 (252) 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/src/components/gesture-indicator/gesture-indicator.type.ts +4 -0
  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/src/type.ts +3 -0
  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/t-action.vue.d.ts +0 -29
  203. package/dist/components/t-alert.vue.d.ts +0 -35
  204. package/dist/components/t-app.vue.d.ts +0 -17
  205. package/dist/components/t-avatar.vue.d.ts +0 -24
  206. package/dist/components/t-back-button.vue.d.ts +0 -21
  207. package/dist/components/t-button.vue.d.ts +0 -36
  208. package/dist/components/t-cable.vue.d.ts +0 -24
  209. package/dist/components/t-card.vue.d.ts +0 -22
  210. package/dist/components/t-checkbox.vue.d.ts +0 -38
  211. package/dist/components/t-collapse.vue.d.ts +0 -32
  212. package/dist/components/t-content.vue.d.ts +0 -17
  213. package/dist/components/t-divider.vue.d.ts +0 -7
  214. package/dist/components/t-flex.vue.d.ts +0 -24
  215. package/dist/components/t-gesture-indicator.vue.d.ts +0 -7
  216. package/dist/components/t-grid.vue.d.ts +0 -24
  217. package/dist/components/t-icon-spinner.vue.d.ts +0 -23
  218. package/dist/components/t-image.vue.d.ts +0 -6
  219. package/dist/components/t-input.vue.d.ts +0 -47
  220. package/dist/components/t-keyboard-space.vue.d.ts +0 -2
  221. package/dist/components/t-loading.vue.d.ts +0 -29
  222. package/dist/components/t-present.vue.d.ts +0 -47
  223. package/dist/components/t-refresher.vue.d.ts +0 -43
  224. package/dist/components/t-rich-text.vue.d.ts +0 -2
  225. package/dist/components/t-ripple.vue.d.ts +0 -7
  226. package/dist/components/t-screen-router.vue.d.ts +0 -15
  227. package/dist/components/t-screen.vue.d.ts +0 -17
  228. package/dist/components/t-sheet.vue.d.ts +0 -251
  229. package/dist/components/t-skeleton.vue.d.ts +0 -13
  230. package/dist/components/t-switch.vue.d.ts +0 -12
  231. package/dist/components/t-tab.vue.d.ts +0 -23
  232. package/dist/components/t-tabs.vue.d.ts +0 -43
  233. package/dist/components/t-text.vue.d.ts +0 -24
  234. package/dist/components/t-textarea.vue.d.ts +0 -2
  235. package/dist/components/t-toast.vue.d.ts +0 -38
  236. package/dist/components/t-toggle-password.vue.d.ts +0 -31
  237. package/dist/components/t-toolbar.vue.d.ts +0 -26
  238. package/dist/controllers/action.d.ts +0 -4
  239. package/dist/controllers/alert.d.ts +0 -4
  240. package/dist/controllers/index.d.ts +0 -8
  241. package/dist/controllers/keyboard.d.ts +0 -3
  242. package/dist/controllers/loading.d.ts +0 -5
  243. package/dist/controllers/present.d.ts +0 -4
  244. package/dist/controllers/screen.d.ts +0 -20
  245. package/dist/controllers/toast.d.ts +0 -4
  246. package/dist/index.css +0 -1
  247. package/dist/index.d.ts +0 -5
  248. package/dist/index.es.js +0 -1501
  249. package/dist/index.umd.js +0 -1
  250. package/dist/utils/defaultEvent.d.ts +0 -2
  251. package/dist/utils/element.d.ts +0 -2
  252. package/dist/utils/index.d.ts +0 -1
@@ -0,0 +1,198 @@
1
+ <style lang="scss" src="./present.scss" scoped></style>
2
+ <template src="./present.html"></template>
3
+ <script lang="ts" setup>
4
+ import type { PresentEmit, PresentProps, RenderOptions } from "./present.type";
5
+ import { computed, onMounted, reactive, ref, watch } from "vue";
6
+ import { withPrefix, property } from "../../utils";
7
+ import { usePresent } from "./present.composable";
8
+
9
+ /// Define
10
+ /// ------------------------------------------------------------
11
+ const presentIndex = usePresent();
12
+ const emit = defineEmits(["close"]) as unknown as PresentEmit;
13
+ defineOptions({ inheritAttrs: false });
14
+
15
+ const props = withDefaults(defineProps<PresentProps>(), {
16
+ keepalive: false,
17
+ visible: false,
18
+ backdrop: "display",
19
+ duration: 200,
20
+ placement: "bottom",
21
+ bounce: false,
22
+ });
23
+
24
+ /// State
25
+ /// ------------------------------------------------------------
26
+ const isBounced = ref(false);
27
+ const zIndex = ref(0);
28
+ const isShow = ref(false);
29
+ const styles = reactive({
30
+ backdropTransitionDuration: "0.2s",
31
+ backdropOpacity: 0.4,
32
+ presentTransitionDuration: "0.2s",
33
+ presentTranslate: "0px",
34
+ presentOpacity: 1,
35
+ });
36
+
37
+ /// Computed
38
+ /// ------------------------------------------------------------
39
+ const backdropAttrs = computed(() => {
40
+ return {
41
+ class: [withPrefix(["layer", "backdrop"]), withPrefix("present-backdrop")],
42
+ style: {
43
+ zIndex: zIndex.value - 1,
44
+ [property("transition-duration")]: styles.backdropTransitionDuration,
45
+ [property(["backdrop", "opacity"])]:
46
+ props.backdrop === "transparent" ? 0 : styles.backdropOpacity,
47
+ },
48
+ };
49
+ });
50
+
51
+ // Present attributes
52
+ const presentAttrs = computed(() => {
53
+ return {
54
+ class: [withPrefix(["layer", "base"]), withPrefix("present"), props.class, props.placement],
55
+ style: [
56
+ {
57
+ zIndex: zIndex.value,
58
+ [property("transition-duration")]: styles.presentTransitionDuration,
59
+ [property("translate")]: styles.presentTranslate,
60
+ [property(["present", "opacity"])]: styles.presentOpacity,
61
+ },
62
+ props.style,
63
+ ],
64
+ };
65
+ });
66
+
67
+ const isRender = computed(() => {
68
+ return isShow.value || props.keepalive;
69
+ });
70
+
71
+ const time = computed(() => {
72
+ return props.duration / 1000 + "s";
73
+ });
74
+
75
+ // Methods
76
+ /// ------------------------------------------------------------
77
+ const createIndex = () => {
78
+ if (zIndex.value === 0 || !props.keepalive) {
79
+ zIndex.value = presentIndex.newIndex();
80
+ }
81
+ };
82
+
83
+ const render = (data: RenderOptions) => {
84
+ if (data.backdropTransitionDuration !== undefined) {
85
+ styles.backdropTransitionDuration = data.backdropTransitionDuration;
86
+ }
87
+ if (data.presentTransitionDuration !== undefined) {
88
+ styles.presentTransitionDuration = data.presentTransitionDuration;
89
+ }
90
+ if (data.backdropOpacity !== undefined) {
91
+ styles.backdropOpacity = data.backdropOpacity;
92
+ }
93
+ if (data.presentTranslate !== undefined) {
94
+ styles.presentTranslate = data.presentTranslate;
95
+ }
96
+ if (data.presentOpacity !== undefined) {
97
+ styles.presentOpacity = data.presentOpacity;
98
+ }
99
+ };
100
+
101
+ // On click backdrop
102
+ const onClickBackdrop = (e: unknown) => {
103
+ (e as Event).preventDefault();
104
+ emit("close", "backdrop");
105
+ };
106
+
107
+ const open = () => {
108
+ if (props.bounce && !isBounced.value) {
109
+ isBounced.value = true;
110
+ let presentTranslate = props.bounce;
111
+
112
+ if (props.placement == "bottom" || props.placement == "right") {
113
+ presentTranslate = `calc(${props.bounce} * -1)`;
114
+ }
115
+
116
+ render({
117
+ backdropTransitionDuration: time.value,
118
+ backdropOpacity: 0.4,
119
+ presentTranslate: String(presentTranslate),
120
+ presentTransitionDuration: time.value,
121
+ presentOpacity: 1,
122
+ });
123
+
124
+ setTimeout(() => {
125
+ render({
126
+ presentTranslate: "0px",
127
+ });
128
+ }, props.duration);
129
+ } else {
130
+ render({
131
+ backdropOpacity: 0.4,
132
+ backdropTransitionDuration: time.value,
133
+ presentTranslate: "0px",
134
+ presentTransitionDuration: time.value,
135
+ presentOpacity: 1,
136
+ });
137
+ }
138
+ };
139
+
140
+ const close = () => {
141
+ isBounced.value = false;
142
+ let presentTranslate = "0px";
143
+ let presentOpacity = 1;
144
+
145
+ if (props.placement == "bottom" || props.placement == "right") {
146
+ presentTranslate = "100%";
147
+ } else if (props.placement == "top" || props.placement == "left") {
148
+ presentTranslate = "-100%";
149
+ } else if (props.placement == "center") {
150
+ presentTranslate = "0px";
151
+ presentOpacity = 0;
152
+ }
153
+
154
+ render({
155
+ backdropOpacity: 0,
156
+ backdropTransitionDuration: time.value,
157
+ presentTranslate,
158
+ presentTransitionDuration: time.value,
159
+ presentOpacity,
160
+ });
161
+ };
162
+
163
+ // Lifecycle
164
+ /// ------------------------------------------------------------
165
+ onMounted(() => {
166
+ if (props.visible) open();
167
+ else close();
168
+ });
169
+
170
+ // Trigger visible
171
+ watch(
172
+ () => props.visible,
173
+ () => {
174
+ if (props.visible) {
175
+ createIndex();
176
+ isShow.value = true;
177
+
178
+ setTimeout(() => {
179
+ open();
180
+ }, 50);
181
+ } else {
182
+ close();
183
+
184
+ setTimeout(() => {
185
+ isShow.value = false;
186
+ }, props.duration);
187
+ }
188
+ }
189
+ );
190
+
191
+ // Export, Expose
192
+ /// ------------------------------------------------------------
193
+ defineExpose({
194
+ render,
195
+ open,
196
+ close,
197
+ });
198
+ </script>
@@ -0,0 +1,2 @@
1
+ export * from "./radio";
2
+ export * from "./radio-group";
@@ -0,0 +1,2 @@
1
+ export { default as Radio } from "./radio.vue";
2
+ export type { RadioProps } from "./radio.type";
@@ -0,0 +1,11 @@
1
+ <div
2
+ v-bind="radioAttrs"
3
+ @click="onRadio"
4
+ :tabindex="disabled ? -1 : 0"
5
+ @focus="onFocus"
6
+ @blur="onBlur"
7
+ @keydown="onKeydown"
8
+ >
9
+ <div v-bind="radioIconAttrs"></div>
10
+ <slot></slot>
11
+ </div>
@@ -0,0 +1,125 @@
1
+ @use "@toife/sass-layer-generator" as sass;
2
+
3
+ // Classes
4
+ $radio: sass.fn-naming-prefix("radio");
5
+ $radio-icon: sass.fn-naming-prefix("radio-icon");
6
+
7
+ // Properties - layer: item
8
+ $background-color: sass.fn-naming-var("item", "background-color");
9
+ $background-color-hover: sass.fn-naming-var("item", "background-color", "subtle");
10
+ $background-color-inactive: sass.fn-naming-var("item", "background-color", "soft");
11
+ $background-color-contrast: sass.fn-naming-var("item", "background-color", "contrast");
12
+ $background-color-disabled: sass.fn-naming-var("item", "background-color", "subtle");
13
+
14
+ $border-color: sass.fn-naming-var("item", "border-color");
15
+ $border-color-inactive: sass.fn-naming-var("item", "border-color", "subtle");
16
+
17
+ $transition-duration: sass.fn-naming-var("motion", "duration");
18
+ $border-radius: sass.fn-naming-var("border-radius");
19
+
20
+ .#{$radio} {
21
+ display: inline-flex;
22
+ align-items: center;
23
+ gap: 0.5rem;
24
+ position: relative;
25
+ cursor: pointer;
26
+ user-select: none;
27
+ box-shadow: none !important;
28
+
29
+ .#{$radio-icon} {
30
+ flex-shrink: 0;
31
+ width: 1.25rem;
32
+ height: 1.25rem;
33
+ display: flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+ border: 1px solid rgb(#{$border-color-inactive});
37
+ background-color: transparent;
38
+ transition:
39
+ box-shadow #{$transition-duration} ease,
40
+ border-color #{$transition-duration} ease,
41
+ background-color #{$transition-duration} ease,
42
+ color #{$transition-duration} ease,
43
+ border-radius #{$transition-duration} ease,
44
+ transform #{$transition-duration} ease;
45
+ border-radius: 50%;
46
+ box-sizing: border-box;
47
+
48
+ &::after {
49
+ content: "";
50
+ width: 0.5rem;
51
+ height: 0.5rem;
52
+ border-radius: 50%;
53
+ background-color: rgb(#{$background-color-contrast});
54
+ transform: scale(0);
55
+ transition:
56
+ transform #{$transition-duration} ease,
57
+ background-color #{$transition-duration} ease,
58
+ color #{$transition-duration} ease,
59
+ border-color #{$transition-duration} ease;
60
+ }
61
+ }
62
+
63
+ &:not(.on) {
64
+ .#{$radio-icon} {
65
+ background-color: transparent;
66
+ border-color: rgb(#{$border-color-inactive});
67
+ }
68
+
69
+ &:not(.disabled):not(.readonly):hover {
70
+ .#{$radio-icon} {
71
+ border-color: rgb(#{$border-color});
72
+ background-color: rgba(#{$background-color-hover}, 0.2);
73
+ }
74
+ }
75
+ }
76
+
77
+ &.on {
78
+ &.fill {
79
+ .#{$radio-icon} {
80
+ background-color: rgb(#{$background-color});
81
+ border-color: rgb(#{$background-color});
82
+
83
+ &::after {
84
+ transform: scale(1);
85
+ }
86
+ }
87
+ }
88
+
89
+ &.outline {
90
+ .#{$radio-icon} {
91
+ background-color: transparent;
92
+ border-color: rgb(#{$background-color});
93
+
94
+ &::after {
95
+ transform: scale(1.5);
96
+ background-color: rgb(#{$background-color});
97
+ }
98
+ }
99
+ }
100
+ }
101
+
102
+ &.disabled {
103
+ cursor: not-allowed;
104
+ opacity: 0.3;
105
+
106
+ &.on {
107
+ .#{$radio-icon} {
108
+ background-color: rgb(#{$background-color-disabled});
109
+ border-color: rgb(#{$background-color-disabled});
110
+ }
111
+ }
112
+ }
113
+
114
+ &.readonly {
115
+ cursor: default;
116
+ }
117
+
118
+ &.focus {
119
+ &.shadow {
120
+ .#{$radio-icon} {
121
+ box-shadow: 0 0 0 0.25rem rgb(#{$border-color}, 0.25);
122
+ }
123
+ }
124
+ }
125
+ }
@@ -0,0 +1,11 @@
1
+ export type RadioVariant = "fill" | "outline";
2
+
3
+ // Define
4
+ export type RadioProps = {
5
+ value: string | number;
6
+ role?: string;
7
+ variant?: RadioVariant;
8
+ disabled?: boolean;
9
+ readonly?: boolean;
10
+ shadow?: boolean;
11
+ };
@@ -0,0 +1,103 @@
1
+ <style lang="scss" src="./radio.scss" scoped></style>
2
+ <template src="./radio.html"></template>
3
+ <script lang="ts" setup>
4
+ import { computed, inject, ref } from "vue";
5
+ import type { RadioProps } from "./radio.type";
6
+ import { withPrefix } from "../../../utils";
7
+ import { type AppProviderState, APP_PROVIDER_STATE_KEY } from "../../app";
8
+ import { type RadioGroupProviderState, RADIO_GROUP_PROVIDER_STATE_KEY } from "../radio-group";
9
+
10
+ /// Define
11
+ /// ------------------------------------------------------------
12
+ const props = withDefaults(defineProps<RadioProps>(), {
13
+ disabled: false,
14
+ shadow: undefined,
15
+ });
16
+ const appState = inject<AppProviderState>(APP_PROVIDER_STATE_KEY);
17
+ const radioGroupState = inject<RadioGroupProviderState | null>(
18
+ RADIO_GROUP_PROVIDER_STATE_KEY,
19
+ null
20
+ );
21
+
22
+ /// State
23
+ /// ------------------------------------------------------------
24
+ const isFocused = ref(false);
25
+
26
+ /// Computed
27
+ /// ------------------------------------------------------------
28
+ const role = computed(() => {
29
+ return props.role || radioGroupState?.role.value || appState?.role.value || "";
30
+ });
31
+
32
+ const variant = computed(() => {
33
+ return props.variant || radioGroupState?.variant.value || "";
34
+ });
35
+
36
+ const disabled = computed(() => {
37
+ return props.disabled || (radioGroupState?.disabled.value ?? false);
38
+ });
39
+
40
+ const readonly = computed(() => {
41
+ return props.readonly || (radioGroupState?.readonly.value ?? false);
42
+ });
43
+
44
+ const isChecked = computed(() => {
45
+ return radioGroupState?.modelValue.value === props.value;
46
+ });
47
+
48
+ const shadow = computed(() => {
49
+ return (props?.shadow !== undefined ? props.shadow : radioGroupState?.shadow.value) ?? false;
50
+ });
51
+
52
+ const radioAttrs = computed(() => {
53
+ return {
54
+ class: [
55
+ withPrefix(["layer", "item"]),
56
+ withPrefix([
57
+ "role",
58
+ (isChecked.value && !disabled.value
59
+ ? role.value || radioGroupState?.role.value
60
+ : appState?.role.value) ?? "",
61
+ ]),
62
+ withPrefix("radio"),
63
+ variant.value,
64
+ {
65
+ on: isChecked.value,
66
+ disabled: disabled.value,
67
+ readonly: readonly.value,
68
+ shadow: shadow.value,
69
+ focus: isFocused.value,
70
+ },
71
+ ],
72
+ };
73
+ });
74
+
75
+ const radioIconAttrs = computed(() => {
76
+ return {
77
+ class: [withPrefix("radio-icon")],
78
+ };
79
+ });
80
+
81
+ /// Methods
82
+ /// ------------------------------------------------------------
83
+ const onRadio = () => {
84
+ if (disabled.value || readonly.value || !radioGroupState) return;
85
+ radioGroupState.setValue(props.value);
86
+ };
87
+
88
+ const onFocus = () => {
89
+ if (disabled.value || readonly.value) return;
90
+ isFocused.value = true;
91
+ };
92
+
93
+ const onBlur = () => {
94
+ if (disabled.value || readonly.value) return;
95
+ isFocused.value = false;
96
+ };
97
+
98
+ const onKeydown = (e: KeyboardEvent) => {
99
+ if (e.key !== " " && e.key !== "Enter") return;
100
+ e.preventDefault();
101
+ onRadio();
102
+ };
103
+ </script>
@@ -0,0 +1,7 @@
1
+ export { default as RadioGroup } from "./radio-group.vue";
2
+ export type {
3
+ RadioGroupProps,
4
+ RadioGroupProviderState,
5
+ RadioGroupOrientation,
6
+ } from "./radio-group.type";
7
+ export { RADIO_GROUP_PROVIDER_STATE_KEY } from "./radio-group.constants";
@@ -0,0 +1 @@
1
+ export const RADIO_GROUP_PROVIDER_STATE_KEY = "radio-group-state";
@@ -0,0 +1,3 @@
1
+ <div v-bind="radioGroupAttrs">
2
+ <slot />
3
+ </div>
@@ -0,0 +1,16 @@
1
+ @use "@toife/sass-layer-generator" as sass;
2
+
3
+ $radio-group: sass.fn-naming-prefix("radio-group");
4
+
5
+ .#{$radio-group} {
6
+ display: flex;
7
+ gap: 0.5rem;
8
+
9
+ &.horizontal {
10
+ flex-direction: row;
11
+ }
12
+
13
+ &.vertical {
14
+ flex-direction: column;
15
+ }
16
+ }
@@ -0,0 +1,28 @@
1
+ import type { ComputedRef } from "vue";
2
+ import type { RadioVariant } from "../radio/radio.type";
3
+
4
+ export type RadioGroupOrientation = "horizontal" | "vertical";
5
+
6
+ export type RadioGroupProps = {
7
+ modelValue?: string | number;
8
+ role?: string;
9
+ variant?: RadioVariant;
10
+ disabled?: boolean;
11
+ readonly?: boolean;
12
+ shadow?: boolean;
13
+ orientation?: RadioGroupOrientation;
14
+ };
15
+
16
+ export type RadioGroupEmit = {
17
+ (e: "update:modelValue", value: string | number): void;
18
+ };
19
+
20
+ export type RadioGroupProviderState = {
21
+ modelValue: ComputedRef<string | number | undefined>;
22
+ role: ComputedRef<string>;
23
+ variant: ComputedRef<RadioVariant>;
24
+ disabled: ComputedRef<boolean>;
25
+ readonly: ComputedRef<boolean>;
26
+ setValue: (val: string | number) => void;
27
+ shadow: ComputedRef<boolean>;
28
+ };
@@ -0,0 +1,62 @@
1
+ <style lang="scss" src="./radio-group.scss" scoped></style>
2
+ <template src="./radio-group.html"></template>
3
+ <script lang="ts" setup>
4
+ import { computed, inject, provide } from "vue";
5
+ import type { RadioGroupProps, RadioGroupEmit, RadioGroupProviderState } from "./radio-group.type";
6
+ import { withPrefix } from "../../../utils";
7
+ import { type AppProviderState, APP_PROVIDER_STATE_KEY } from "../../app";
8
+ import { RADIO_GROUP_PROVIDER_STATE_KEY } from "./radio-group.constants";
9
+
10
+ /// Define
11
+ /// ------------------------------------------------------------
12
+ const props = withDefaults(defineProps<RadioGroupProps>(), {
13
+ disabled: false,
14
+ readonly: false,
15
+ variant: "fill",
16
+ orientation: "vertical",
17
+ shadow: undefined,
18
+ });
19
+ const emit = defineEmits<RadioGroupEmit>();
20
+ const appState = inject<AppProviderState>(APP_PROVIDER_STATE_KEY);
21
+
22
+ /// Computed
23
+ /// ------------------------------------------------------------
24
+ const modelValue = computed(() => props.modelValue);
25
+
26
+ const role = computed(() => {
27
+ return props.role || appState?.role.value || "";
28
+ });
29
+
30
+ const variant = computed(() => {
31
+ return props.variant;
32
+ });
33
+
34
+ const shadow = computed(() => {
35
+ return (props?.shadow !== undefined ? props.shadow : appState?.shadow.value) ?? false;
36
+ });
37
+
38
+ const radioGroupAttrs = computed(() => {
39
+ return {
40
+ class: [
41
+ withPrefix(["layer", "item"]),
42
+ withPrefix(["role", role.value]),
43
+ withPrefix("radio-group"),
44
+ props.orientation,
45
+ ],
46
+ };
47
+ });
48
+
49
+ /// Provide
50
+ /// ------------------------------------------------------------
51
+ provide<RadioGroupProviderState>(RADIO_GROUP_PROVIDER_STATE_KEY, {
52
+ modelValue,
53
+ role,
54
+ variant,
55
+ disabled: computed(() => props.disabled),
56
+ readonly: computed(() => props.readonly),
57
+ shadow,
58
+ setValue: (val: string | number) => {
59
+ emit("update:modelValue", val);
60
+ },
61
+ });
62
+ </script>
@@ -0,0 +1,2 @@
1
+ export { default as Refresher } from "./refresher.vue";
2
+ export * from "./refresher.type";
@@ -0,0 +1,6 @@
1
+ <div v-bind="refresherAttrs" v-show="calculateOffset > 0">
2
+ <slot name="icon" :offset="calculateOffset" :refreshing="refreshing"></slot>
3
+ </div>
4
+ <div v-bind="containerAttrs" ref="container">
5
+ <slot></slot>
6
+ </div>
@@ -0,0 +1,36 @@
1
+ @use "@toife/sass-layer-generator" as sass;
2
+
3
+ // Class
4
+ $refresher: sass.fn-naming-prefix("refresher");
5
+ $container: sass.fn-naming-prefix("refresher-container");
6
+
7
+ // Variables
8
+ $safe-area-top: sass.fn-naming-var("safe-area", "top");
9
+ $transition-duration: sass.fn-naming-var("motion", "duration");
10
+ $offset: sass.fn-naming-var("refresher-offset");
11
+
12
+ .#{$container} {
13
+ width: 100%;
14
+ height: 100%;
15
+ position: relative;
16
+ overflow: auto;
17
+ }
18
+
19
+ // Refresher
20
+ .#{$refresher} {
21
+ display: flex;
22
+ justify-content: center;
23
+ align-items: center;
24
+ overflow: hidden;
25
+ transition: height #{$transition-duration} ease;
26
+ position: absolute;
27
+ top: 0;
28
+ left: 50%;
29
+ transform: translateX(-50%);
30
+ line-height: 0;
31
+ z-index: 1;
32
+
33
+ &.moving {
34
+ top: calc(#{$safe-area-top} + #{$offset});
35
+ }
36
+ }
@@ -0,0 +1,16 @@
1
+ // Props
2
+ export type RefresherVariant = "max" | "up";
3
+
4
+ // Define
5
+ export type RefresherProps = {
6
+ threshold?: number;
7
+ variant?: RefresherVariant;
8
+ offset?: number;
9
+ };
10
+
11
+ export type RefresherEmit = {
12
+ (e: "refresh", close: () => void): void;
13
+ (e: "move", offset: number): void;
14
+ (e: "cancel"): void;
15
+ (e: "start"): void;
16
+ };