@toife/vue 3.1.3 → 3.1.5

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 (157) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/src/components/action/action.scss +1 -1
  4. package/src/components/action/action.vue +5 -5
  5. package/src/components/app/app.scss +2 -2
  6. package/src/components/app/app.type.ts +6 -0
  7. package/src/components/app/app.vue +8 -2
  8. package/src/components/avatar/avatar.scss +6 -4
  9. package/src/components/avatar/avatar.vue +6 -6
  10. package/src/components/button/button.scss +19 -16
  11. package/src/components/button/button.type.ts +3 -1
  12. package/src/components/button/button.vue +7 -7
  13. package/src/components/cable/cable.vue +2 -2
  14. package/src/components/card/card/card.scss +5 -3
  15. package/src/components/card/card/card.vue +5 -5
  16. package/src/components/card/card-body/card-body.scss +2 -2
  17. package/src/components/card/card-body/card-body.vue +2 -2
  18. package/src/components/card/card-footer/card-footer.scss +3 -3
  19. package/src/components/card/card-footer/card-footer.vue +2 -2
  20. package/src/components/card/card-header/card-header.scss +3 -3
  21. package/src/components/card/card-header/card-header.vue +2 -2
  22. package/src/components/checkbox/checkbox.html +1 -1
  23. package/src/components/checkbox/checkbox.scss +27 -27
  24. package/src/components/checkbox/checkbox.type.ts +4 -0
  25. package/src/components/checkbox/checkbox.vue +8 -6
  26. package/src/components/collapse/collapse.html +1 -1
  27. package/src/components/collapse/collapse.scss +2 -2
  28. package/src/components/collapse/collapse.vue +9 -9
  29. package/src/components/container/container.vue +2 -2
  30. package/src/components/decision-modal/decision-modal.scss +12 -10
  31. package/src/components/decision-modal/decision-modal.vue +8 -8
  32. package/src/components/divider/divider.scss +2 -2
  33. package/src/components/divider/divider.vue +4 -4
  34. package/src/components/dropdown/dropdown.scss +8 -5
  35. package/src/components/dropdown/dropdown.type.ts +4 -1
  36. package/src/components/dropdown/dropdown.vue +8 -6
  37. package/src/components/field/field.type.ts +4 -4
  38. package/src/components/field/outline/outline.scss +24 -21
  39. package/src/components/field/outline/outline.vue +26 -18
  40. package/src/components/form-group/form-group.vue +2 -2
  41. package/src/components/gesture-indicator/gesture-indicator.scss +4 -2
  42. package/src/components/gesture-indicator/gesture-indicator.vue +4 -4
  43. package/src/components/image/image.vue +12 -5
  44. package/src/components/index.ts +1 -0
  45. package/src/components/layout/flex/flex.scss +0 -2
  46. package/src/components/layout/flex/flex.vue +8 -8
  47. package/src/components/layout/flex-item/flex-item.html +1 -0
  48. package/src/components/layout/flex-item/flex-item.scss +48 -0
  49. package/src/components/layout/flex-item/flex-item.type.ts +11 -0
  50. package/src/components/layout/flex-item/flex-item.vue +27 -0
  51. package/src/components/layout/flex-item/index.ts +2 -0
  52. package/src/components/layout/grid/grid.scss +0 -2
  53. package/src/components/layout/grid/grid.vue +6 -6
  54. package/src/components/layout/grid-item/grid-item.html +1 -0
  55. package/src/components/layout/grid-item/grid-item.scss +49 -0
  56. package/src/components/layout/grid-item/grid-item.type.ts +14 -0
  57. package/src/components/layout/grid-item/grid-item.vue +27 -0
  58. package/src/components/layout/grid-item/index.ts +2 -0
  59. package/src/components/layout/index.ts +2 -1
  60. package/src/components/modal/modal.scss +4 -2
  61. package/src/components/modal/modal.vue +68 -5
  62. package/src/components/page/page.vue +2 -2
  63. package/src/components/present/present.scss +3 -3
  64. package/src/components/present/present.vue +14 -14
  65. package/src/components/radio/radio/radio.html +1 -1
  66. package/src/components/radio/radio/radio.scss +25 -18
  67. package/src/components/radio/radio/radio.type.ts +4 -0
  68. package/src/components/radio/radio/radio.vue +7 -5
  69. package/src/components/radio/radio-group/radio-group.vue +2 -2
  70. package/src/components/refresher/refresher.html +1 -4
  71. package/src/components/refresher/refresher.scss +8 -26
  72. package/src/components/refresher/refresher.vue +2 -16
  73. package/src/components/route/route-navigator/route-navigator.scss +2 -2
  74. package/src/components/route/route-navigator/route-navigator.vue +10 -13
  75. package/src/components/route/route-wrapper/route-wrapper.composable.ts +5 -15
  76. package/src/components/route/route-wrapper/route-wrapper.type.ts +0 -4
  77. package/src/components/route/route-wrapper/route-wrapper.vue +4 -12
  78. package/src/components/route/route.type.ts +0 -1
  79. package/src/components/segmented-field/segmented-field.html +1 -1
  80. package/src/components/segmented-field/segmented-field.scss +2 -2
  81. package/src/components/segmented-field/segmented-field.vue +8 -8
  82. package/src/components/select/select.html +2 -2
  83. package/src/components/select/select.scss +10 -10
  84. package/src/components/select/select.vue +10 -10
  85. package/src/components/skeleton/skeleton.scss +3 -1
  86. package/src/components/skeleton/skeleton.vue +7 -7
  87. package/src/components/slide-range/index.ts +2 -0
  88. package/src/components/slide-range/slide-range.html +19 -0
  89. package/src/components/slide-range/slide-range.scss +161 -0
  90. package/src/components/slide-range/slide-range.type.ts +16 -0
  91. package/src/components/slide-range/slide-range.vue +229 -0
  92. package/src/components/switch/switch.html +1 -1
  93. package/src/components/switch/switch.scss +29 -38
  94. package/src/components/switch/switch.type.ts +6 -0
  95. package/src/components/switch/switch.vue +24 -8
  96. package/src/components/tabs/tab/tab.html +1 -1
  97. package/src/components/tabs/tab/tab.scss +13 -0
  98. package/src/components/tabs/tab/tab.vue +4 -2
  99. package/src/components/tabs/tabs/index.ts +1 -0
  100. package/src/components/tabs/tabs/tabs.scss +194 -122
  101. package/src/components/tabs/tabs/tabs.type.ts +5 -2
  102. package/src/components/tabs/tabs/tabs.vue +47 -27
  103. package/src/components/toast/toast/toast.vue +2 -2
  104. package/src/components/toast/toast-content/toast-content.scss +6 -5
  105. package/src/components/toast/toast-content/toast-content.vue +5 -5
  106. package/src/components/toolbar/toolbar.scss +4 -4
  107. package/src/components/toolbar/toolbar.type.ts +1 -1
  108. package/src/components/toolbar/toolbar.vue +7 -7
  109. package/src/factory.ts +108 -50
  110. package/src/index.ts +1 -1
  111. package/src/type.ts +2 -1
  112. package/src/utils/style/index.ts +9 -9
  113. package/src/utils/style.md +9 -9
  114. package/src/components/action/action.md +0 -115
  115. package/src/components/app/app.md +0 -77
  116. package/src/components/avatar/avatar.md +0 -64
  117. package/src/components/button/button.md +0 -66
  118. package/src/components/cable/cable.md +0 -57
  119. package/src/components/card/card/card.md +0 -57
  120. package/src/components/card/card-body/card-body.md +0 -34
  121. package/src/components/card/card-footer/card-footer.md +0 -42
  122. package/src/components/card/card-header/card-header.md +0 -44
  123. package/src/components/checkbox/checkbox.md +0 -60
  124. package/src/components/collapse/collapse.md +0 -59
  125. package/src/components/container/container.md +0 -38
  126. package/src/components/decision-modal/decision-modal.md +0 -79
  127. package/src/components/divider/divider.md +0 -42
  128. package/src/components/field/field.md +0 -68
  129. package/src/components/field/outline/outline-field.md +0 -44
  130. package/src/components/form-group/form-group.md +0 -41
  131. package/src/components/gesture-indicator/gesture-indicator.md +0 -42
  132. package/src/components/image/image.md +0 -41
  133. package/src/components/layout/cell/cell.html +0 -1
  134. package/src/components/layout/cell/cell.md +0 -47
  135. package/src/components/layout/cell/cell.scss +0 -54
  136. package/src/components/layout/cell/cell.type.ts +0 -19
  137. package/src/components/layout/cell/cell.vue +0 -35
  138. package/src/components/layout/cell/index.ts +0 -2
  139. package/src/components/layout/grid/grid.md +0 -50
  140. package/src/components/modal/modal.md +0 -65
  141. package/src/components/page/page.md +0 -39
  142. package/src/components/present/present.md +0 -60
  143. package/src/components/radio/radio/radio.md +0 -53
  144. package/src/components/radio/radio-group/radio-group.md +0 -62
  145. package/src/components/refresher/refresher.md +0 -53
  146. package/src/components/route/route-navigator/route-navigator.md +0 -50
  147. package/src/components/route/route-outlet/route-outlet.md +0 -30
  148. package/src/components/route/route-provider/route-provider.md +0 -46
  149. package/src/components/route/route-wrapper/route-wrapper.md +0 -45
  150. package/src/components/segmented-field/segmented-field.md +0 -58
  151. package/src/components/skeleton/skeleton.md +0 -47
  152. package/src/components/switch/switch.md +0 -57
  153. package/src/components/tabs/tab/tab.md +0 -52
  154. package/src/components/tabs/tabs/tabs.md +0 -59
  155. package/src/components/toast/toast/toast.md +0 -56
  156. package/src/components/toast/toast-content/toast-content.md +0 -41
  157. package/src/components/toolbar/toolbar.md +0 -54
@@ -1,7 +1,7 @@
1
1
  <style lang="scss" src="./form-group.scss" scoped></style>
2
2
  <template src="./form-group.html"></template>
3
3
  <script lang="ts" setup>
4
- import { withPrefix } from "../../utils";
4
+ import { cssPrefix } from "../../utils";
5
5
  import { computed } from "vue";
6
6
  import { type FormGroupProps } from "./form-group.type";
7
7
 
@@ -15,7 +15,7 @@ const props = withDefaults(defineProps<FormGroupProps>(), {
15
15
  // ----------------------------------------------------------------------------
16
16
  const formGroupAttrs = computed(() => {
17
17
  return {
18
- class: [withPrefix("form-group"), props.direction],
18
+ class: [cssPrefix("form-group"), props.direction],
19
19
  };
20
20
  });
21
21
  </script>
@@ -5,10 +5,12 @@ $gesture-indicator: sass.fn-naming-prefix("gesture-indicator");
5
5
 
6
6
  // Property name - layer: gesture-indicator
7
7
  $gesture-indicator-border-color: sass.fn-naming-var("gesture-indicator", "border-color");
8
+ $radius-ratio: sass.fn-naming-var("radius-ratio");
9
+ $radius-size: sass.fn-naming-var("radius-size");
8
10
  $transition-duration: sass.fn-naming-var("motion", "duration");
9
11
 
10
12
  .#{$gesture-indicator} {
11
- background-color: rgb(#{$gesture-indicator-border-color});
13
+ background-color: rgba(#{$gesture-indicator-border-color});
12
14
  transition:
13
15
  box-shadow #{$transition-duration} ease,
14
16
  border-color #{$transition-duration} ease,
@@ -16,7 +18,7 @@ $transition-duration: sass.fn-naming-var("motion", "duration");
16
18
  color #{$transition-duration} ease,
17
19
  border-radius #{$transition-duration} ease;
18
20
  position: absolute;
19
- border-radius: 3px;
21
+ border-radius: calc(min(40px, #{$radius-size}) * #{$radius-ratio});
20
22
  z-index: 99;
21
23
 
22
24
  &.bottom {
@@ -1,7 +1,7 @@
1
1
  <style lang="scss" src="./gesture-indicator.scss" scoped></style>
2
2
  <template src="./gesture-indicator.html"></template>
3
3
  <script lang="ts" setup>
4
- import { withPrefix } from "../../utils";
4
+ import { cssPrefix } from "../../utils";
5
5
  import { type GestureIndicatorProps } from "./gesture-indicator.type";
6
6
  import { computed, inject } from "vue";
7
7
  import { type AppProviderState, APP_PROVIDER_STATE_KEY } from "../app";
@@ -21,9 +21,9 @@ const gestureIndicatorAttrs = computed(() => {
21
21
 
22
22
  return {
23
23
  class: [
24
- withPrefix(["layer", "gesture-indicator"]),
25
- withPrefix(["role", role]),
26
- withPrefix("gesture-indicator"),
24
+ cssPrefix(["layer", "gesture-indicator"]),
25
+ cssPrefix(["role", role]),
26
+ cssPrefix("gesture-indicator"),
27
27
  props.placement,
28
28
  ],
29
29
  };
@@ -1,22 +1,29 @@
1
1
  <template src="./image.html"></template>
2
2
  <script setup lang="ts">
3
- import { ref } from "vue";
3
+ import { ref, watch } from "vue";
4
4
  import { type ImageProps } from "./image.type";
5
5
 
6
6
  // Component setup (props, emits, injects)
7
7
  // ----------------------------------------------------------------------------
8
- const { defaultSrc, src } = defineProps<ImageProps>();
8
+ const props = defineProps<ImageProps>();
9
9
 
10
10
  // Reactive state
11
11
  // ----------------------------------------------------------------------------
12
12
  // Initialize from src to avoid an empty src flash before mount
13
- const dataSrc = ref<string>(src ?? "");
13
+ const dataSrc = ref<string>(props.src ?? "");
14
14
 
15
15
  // Methods
16
16
  // ----------------------------------------------------------------------------
17
17
  const handleError = () => {
18
- if (defaultSrc) {
19
- dataSrc.value = defaultSrc;
18
+ if (props.defaultSrc) {
19
+ dataSrc.value = props.defaultSrc;
20
20
  }
21
21
  };
22
+
23
+ watch(
24
+ () => props.src,
25
+ (newVal) => {
26
+ dataSrc.value = newVal ?? "";
27
+ }
28
+ );
22
29
  </script>
@@ -28,3 +28,4 @@ export * from "./collapse";
28
28
  export * from "./form-group";
29
29
  export * from "./dropdown";
30
30
  export * from "./select";
31
+ export * from "./slide-range";
@@ -16,8 +16,6 @@ $flex-align-content: sass.fn-naming-var("flex", "align-content");
16
16
  .#{$flex} {
17
17
  display: flex;
18
18
  box-sizing: border-box;
19
- width: 100%;
20
- min-height: 0;
21
19
  gap: #{$flex-gap};
22
20
  flex-direction: #{$flex-direction};
23
21
  flex-wrap: #{$flex-wrap};
@@ -2,7 +2,7 @@
2
2
  <template src="./flex.html"></template>
3
3
  <script lang="ts" setup>
4
4
  import { computed } from "vue";
5
- import { withPrefix, property } from "../../../utils";
5
+ import { cssPrefix, cssProperty } from "../../../utils";
6
6
  import type { FlexProps } from "./flex.type";
7
7
 
8
8
  // Component setup (props, emits, injects)
@@ -16,18 +16,18 @@ const props = withDefaults(defineProps<FlexProps>(), {
16
16
  const flexAttrs = computed(() => {
17
17
  const style = props.options.map((option) => {
18
18
  return {
19
- [property(["flex", "gap", option?.breakpoint || ""])]:
19
+ [cssProperty(["flex", "gap", option?.breakpoint || ""])]:
20
20
  typeof option.gap === "number" ? `${option.gap}px` : option.gap,
21
- [property(["flex", "direction", option?.breakpoint || ""])]: option.direction,
22
- [property(["flex", "wrap", option?.breakpoint || ""])]: option.wrap,
23
- [property(["flex", "justify", option?.breakpoint || ""])]: option.justify,
24
- [property(["flex", "align", option?.breakpoint || ""])]: option.align,
25
- [property(["flex", "align-content", option?.breakpoint || ""])]: option.alignContent,
21
+ [cssProperty(["flex", "direction", option?.breakpoint || ""])]: option.direction,
22
+ [cssProperty(["flex", "wrap", option?.breakpoint || ""])]: option.wrap,
23
+ [cssProperty(["flex", "justify", option?.breakpoint || ""])]: option.justify,
24
+ [cssProperty(["flex", "align", option?.breakpoint || ""])]: option.align,
25
+ [cssProperty(["flex", "align-content", option?.breakpoint || ""])]: option.alignContent,
26
26
  };
27
27
  });
28
28
 
29
29
  return {
30
- class: [withPrefix("flex")],
30
+ class: [cssPrefix("flex")],
31
31
  style,
32
32
  };
33
33
  });
@@ -0,0 +1 @@
1
+ <div v-bind="flexItemAttrs"><slot /></div>
@@ -0,0 +1,48 @@
1
+ @use "@toife/sass-layer" as sass;
2
+ @use "sass:map";
3
+ @use "sass:list";
4
+
5
+ $flex-item: sass.fn-naming-prefix("flex-item");
6
+ $flex-item-grow: sass.fn-naming-var("flex-item", "grow");
7
+ $flex-item-shrink: sass.fn-naming-var("flex-item", "shrink");
8
+ $flex-item-basis: sass.fn-naming-var("flex-item", "basis");
9
+ $flex-item-order: sass.fn-naming-var("flex-item", "order");
10
+
11
+ .#{$flex-item} {
12
+ box-sizing: border-box;
13
+ min-width: 0;
14
+ flex-grow: #{$flex-item-grow};
15
+ flex-shrink: #{$flex-item-shrink};
16
+ flex-basis: #{$flex-item-basis};
17
+ order: #{$flex-item-order};
18
+
19
+ $bp-names: map.keys(sass.$breakpoints);
20
+ $bp-count: list.length($bp-names);
21
+
22
+ @for $i from 1 through $bp-count {
23
+ $bp-name: list.nth($bp-names, $i);
24
+ $bp-min: map.get(sass.$breakpoints, $bp-name);
25
+
26
+ @media (min-width: $bp-min) {
27
+ flex-grow: #{sass.fn-naming-cascade-dvar(
28
+ ("flex-item", "grow"),
29
+ $bp-names,
30
+ $i,
31
+ $flex-item-grow
32
+ )};
33
+ flex-shrink: #{sass.fn-naming-cascade-dvar(
34
+ ("flex-item", "shrink"),
35
+ $bp-names,
36
+ $i,
37
+ $flex-item-shrink
38
+ )};
39
+ flex-basis: #{sass.fn-naming-cascade-dvar(
40
+ ("flex-item", "basis"),
41
+ $bp-names,
42
+ $i,
43
+ $flex-item-basis
44
+ )};
45
+ order: #{sass.fn-naming-cascade-dvar(("flex-item", "order"), $bp-names, $i, $flex-item-order)};
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,11 @@
1
+ export type FlexItemOption = {
2
+ breakpoint?: string;
3
+ grow?: number;
4
+ shrink?: number;
5
+ basis?: string;
6
+ order?: number;
7
+ };
8
+
9
+ export type FlexItemProps = {
10
+ options?: FlexItemOption[];
11
+ };
@@ -0,0 +1,27 @@
1
+ <style lang="scss" src="./flex-item.scss" scoped></style>
2
+ <template src="./flex-item.html"></template>
3
+ <script lang="ts" setup>
4
+ import { computed } from "vue";
5
+ import { cssPrefix, cssProperty } from "../../../utils";
6
+ import type { FlexItemProps } from "./flex-item.type";
7
+
8
+ const props = withDefaults(defineProps<FlexItemProps>(), {
9
+ options: () => [],
10
+ });
11
+
12
+ const flexItemAttrs = computed(() => {
13
+ const style = props.options.map((option) => {
14
+ return {
15
+ [cssProperty(["flex-item", "grow", option?.breakpoint || ""])]: option.grow,
16
+ [cssProperty(["flex-item", "shrink", option?.breakpoint || ""])]: option.shrink,
17
+ [cssProperty(["flex-item", "basis", option?.breakpoint || ""])]: option.basis,
18
+ [cssProperty(["flex-item", "order", option?.breakpoint || ""])]: option.order,
19
+ };
20
+ });
21
+
22
+ return {
23
+ class: [cssPrefix("flex-item")],
24
+ style,
25
+ };
26
+ });
27
+ </script>
@@ -0,0 +1,2 @@
1
+ export { default as FlexItem } from "./flex-item.vue";
2
+ export * from "./flex-item.type";
@@ -14,8 +14,6 @@ $grid-auto-flow: sass.fn-naming-var("grid", "auto-flow");
14
14
  .#{$grid} {
15
15
  display: grid;
16
16
  box-sizing: border-box;
17
- width: 100%;
18
- min-height: 0;
19
17
  gap: #{$grid-gap};
20
18
  grid-template-columns: #{$grid-columns};
21
19
  grid-template-rows: #{$grid-rows};
@@ -2,7 +2,7 @@
2
2
  <template src="./grid.html"></template>
3
3
  <script lang="ts" setup>
4
4
  import { computed } from "vue";
5
- import { withPrefix, property } from "../../../utils";
5
+ import { cssPrefix, cssProperty } from "../../../utils";
6
6
  import type { GridProps } from "./grid.type";
7
7
 
8
8
  // Component setup (props, emits, injects)
@@ -16,16 +16,16 @@ const props = withDefaults(defineProps<GridProps>(), {
16
16
  const gridAttrs = computed(() => {
17
17
  const style = props.options.map((option) => {
18
18
  return {
19
- [property(["grid", "gap", option?.breakpoint || ""])]:
19
+ [cssProperty(["grid", "gap", option?.breakpoint || ""])]:
20
20
  typeof option.gap === "number" ? `${option.gap}px` : option.gap,
21
- [property(["grid", "columns", option?.breakpoint || ""])]: option.columns,
22
- [property(["grid", "rows", option?.breakpoint || ""])]: option.rows,
23
- [property(["grid", "auto-flow", option?.breakpoint || ""])]: option.autoFlow,
21
+ [cssProperty(["grid", "columns", option?.breakpoint || ""])]: option.columns,
22
+ [cssProperty(["grid", "rows", option?.breakpoint || ""])]: option.rows,
23
+ [cssProperty(["grid", "auto-flow", option?.breakpoint || ""])]: option.autoFlow,
24
24
  };
25
25
  });
26
26
 
27
27
  return {
28
- class: [withPrefix("grid")],
28
+ class: [cssPrefix("grid")],
29
29
  style,
30
30
  };
31
31
  });
@@ -0,0 +1 @@
1
+ <div v-bind="gridItemAttrs"><slot /></div>
@@ -0,0 +1,49 @@
1
+ @use "@toife/sass-layer" as sass;
2
+ @use "sass:map";
3
+ @use "sass:list";
4
+
5
+ $grid-item: sass.fn-naming-prefix("grid-item");
6
+ $grid-item-row: sass.fn-naming-var("grid-item", "row");
7
+ $grid-item-column: sass.fn-naming-var("grid-item", "column");
8
+ $grid-item-justify: sass.fn-naming-var("grid-item", "justify");
9
+ $grid-item-align: sass.fn-naming-var("grid-item", "align");
10
+
11
+ .#{$grid-item} {
12
+ display: grid;
13
+ box-sizing: border-box;
14
+ min-width: 0;
15
+ grid-column: #{$grid-item-column};
16
+ grid-row: #{$grid-item-row};
17
+ justify-self: #{$grid-item-justify};
18
+ align-self: #{$grid-item-align};
19
+
20
+ $bp-names: map.keys(sass.$breakpoints);
21
+ $bp-count: list.length($bp-names);
22
+
23
+ @for $i from 1 through $bp-count {
24
+ $bp-name: list.nth($bp-names, $i);
25
+ $bp-min: map.get(sass.$breakpoints, $bp-name);
26
+
27
+ @media (min-width: $bp-min) {
28
+ grid-column: #{sass.fn-naming-cascade-dvar(
29
+ ("grid-item", "column"),
30
+ $bp-names,
31
+ $i,
32
+ $grid-item-column
33
+ )};
34
+ grid-row: #{sass.fn-naming-cascade-dvar(("grid-item", "row"), $bp-names, $i, $grid-item-row)};
35
+ justify-self: #{sass.fn-naming-cascade-dvar(
36
+ ("grid-item", "justify"),
37
+ $bp-names,
38
+ $i,
39
+ $grid-item-justify
40
+ )};
41
+ align-self: #{sass.fn-naming-cascade-dvar(
42
+ ("grid-item", "align"),
43
+ $bp-names,
44
+ $i,
45
+ $grid-item-align
46
+ )};
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,14 @@
1
+ export type GridItemJustify = "start" | "end" | "center" | "stretch";
2
+ export type GridItemAlign = "start" | "end" | "center" | "stretch";
3
+
4
+ export type GridItemOption = {
5
+ breakpoint?: string;
6
+ row?: number;
7
+ column?: number;
8
+ justify?: GridItemJustify;
9
+ align?: GridItemAlign;
10
+ };
11
+
12
+ export type GridItemProps = {
13
+ options?: GridItemOption[];
14
+ };
@@ -0,0 +1,27 @@
1
+ <style lang="scss" src="./grid-item.scss" scoped></style>
2
+ <template src="./grid-item.html"></template>
3
+ <script lang="ts" setup>
4
+ import { computed } from "vue";
5
+ import { cssPrefix, cssProperty } from "../../../utils";
6
+ import type { GridItemProps } from "./grid-item.type";
7
+
8
+ const props = withDefaults(defineProps<GridItemProps>(), {
9
+ options: () => [],
10
+ });
11
+
12
+ const gridItemAttrs = computed(() => {
13
+ const style = props.options.map((option) => {
14
+ return {
15
+ [cssProperty(["grid-item", "row", option?.breakpoint || ""])]: option.row,
16
+ [cssProperty(["grid-item", "column", option?.breakpoint || ""])]: option.column,
17
+ [cssProperty(["grid-item", "justify", option?.breakpoint || ""])]: option.justify,
18
+ [cssProperty(["grid-item", "align", option?.breakpoint || ""])]: option.align,
19
+ };
20
+ });
21
+
22
+ return {
23
+ class: [cssPrefix("grid-item")],
24
+ style,
25
+ };
26
+ });
27
+ </script>
@@ -0,0 +1,2 @@
1
+ export { default as GridItem } from "./grid-item.vue";
2
+ export * from "./grid-item.type";
@@ -1,3 +1,4 @@
1
1
  export * from "./grid";
2
2
  export * from "./flex";
3
- export * from "./cell";
3
+ export * from "./grid-item";
4
+ export * from "./flex-item";
@@ -9,15 +9,17 @@ $viewport-width: sass.fn-naming-var("viewport", "width");
9
9
  $viewport-max-width: sass.fn-naming-var("viewport", "max-width");
10
10
  $viewport-height: sass.fn-naming-var("viewport", "height");
11
11
  $viewport-max-height: sass.fn-naming-var("viewport", "max-height");
12
- $border-radius: sass.fn-naming-var("border-radius");
12
+ $radius-ratio: sass.fn-naming-var("radius-ratio");
13
+ $radius-size: sass.fn-naming-var("radius-size");
13
14
  $safe-area-top: sass.fn-naming-var("safe-area", "top");
14
15
  $safe-area-bottom: sass.fn-naming-var("safe-area", "bottom");
15
16
  $safe-area-left: sass.fn-naming-var("safe-area", "left");
16
17
  $safe-area-right: sass.fn-naming-var("safe-area", "right");
17
18
  $transition-duration: sass.fn-naming-var("motion", "duration");
19
+ $border-radius: calc(min(#{$viewport-width}, #{$radius-size}) * #{$radius-ratio});
18
20
 
19
21
  .#{$modal} {
20
- background: rgb(#{$modal-background-color});
22
+ background: rgba(#{$modal-background-color});
21
23
  transition:
22
24
  box-shadow #{$transition-duration} ease,
23
25
  border-color #{$transition-duration} ease,
@@ -6,7 +6,7 @@ import { gesture as toifeGesture } from "@toife/gesture";
6
6
  import { Present } from "../present";
7
7
  import { GestureIndicator } from "../gesture-indicator";
8
8
  import { type ModalProps, type ModalEmit } from "./modal.type";
9
- import { withPrefix } from "../../utils";
9
+ import { cssPrefix } from "../../utils";
10
10
  import { type AppProviderState, APP_PROVIDER_STATE_KEY } from "../app";
11
11
 
12
12
  // Component setup (props, emits, injects)
@@ -47,10 +47,10 @@ const modalAttrs = computed(() => {
47
47
 
48
48
  return {
49
49
  class: [
50
- withPrefix(["layer", "modal"]),
51
- withPrefix(["role", role]),
52
- withPrefix(["shape", shape]),
53
- withPrefix("modal"),
50
+ cssPrefix(["layer", "modal"]),
51
+ cssPrefix(["role", role]),
52
+ cssPrefix(["shape", shape]),
53
+ cssPrefix("modal"),
54
54
  {
55
55
  fullscreen: props.fullscreen,
56
56
  [props.placement]: true,
@@ -67,6 +67,65 @@ const close = (e: string) => {
67
67
  emit("close", e);
68
68
  };
69
69
 
70
+ const SCROLLABLE_OVERFLOW_VALUES = ["auto", "scroll", "overlay"];
71
+
72
+ /**
73
+ * Check if the element is scrollable
74
+ * @param el - The element
75
+ * @param axis - The axis of the scroll
76
+ * @returns True if the element is scrollable, false otherwise
77
+ */
78
+ const isScrollable = (el: HTMLElement, axis: "x" | "y") => {
79
+ const style = getComputedStyle(el);
80
+ if (axis == "y") {
81
+ return (
82
+ el.scrollHeight > el.clientHeight && SCROLLABLE_OVERFLOW_VALUES.includes(style.overflowY)
83
+ );
84
+ }
85
+
86
+ return el.scrollWidth > el.clientWidth && SCROLLABLE_OVERFLOW_VALUES.includes(style.overflowX);
87
+ };
88
+
89
+ /**
90
+ * Check if the element has remaining scroll
91
+ * @param el - The element
92
+ * @param direction - The direction of the scroll
93
+ * @returns True if the element has remaining scroll, false otherwise
94
+ */
95
+ const hasRemainingScroll = (el: HTMLElement, direction: "up" | "down" | "left" | "right") => {
96
+ if (direction == "down") return el.scrollTop > 0;
97
+ if (direction == "up") return el.scrollTop < el.scrollHeight - el.clientHeight;
98
+ if (direction == "right") return el.scrollLeft > 0;
99
+
100
+ return el.scrollLeft < el.scrollWidth - el.clientWidth;
101
+ };
102
+
103
+ /**
104
+ * Check if the gesture can start
105
+ * @param e - The event
106
+ * @returns True if the gesture can start, false otherwise
107
+ */
108
+ const canStartGesture = (e: unknown) => {
109
+ if (!modal.value || !gestureDir.value) return true;
110
+
111
+ const target = (e as { target?: EventTarget }).target;
112
+ if (!(target instanceof Element)) return true;
113
+
114
+ const axis = gestureDir.value == "left" || gestureDir.value == "right" ? "x" : "y";
115
+ let current: Element | null = target;
116
+
117
+ while (current && current !== modal.value) {
118
+ if (current instanceof HTMLElement && isScrollable(current, axis)) {
119
+ if (hasRemainingScroll(current, gestureDir.value)) {
120
+ return false;
121
+ }
122
+ }
123
+ current = current.parentElement;
124
+ }
125
+
126
+ return true;
127
+ };
128
+
70
129
  // Cooldown so rapid gesture events do not fight the sheet animation
71
130
  const busy = () => {
72
131
  isBusy.value = true;
@@ -94,6 +153,10 @@ watch(
94
153
  return false;
95
154
  }
96
155
 
156
+ if (!canStartGesture(e)) {
157
+ return false;
158
+ }
159
+
97
160
  return true;
98
161
  },
99
162
 
@@ -1,10 +1,10 @@
1
1
  <template src="./page.html"></template>
2
2
  <style lang="scss" src="./page.scss" scoped></style>
3
3
  <script lang="ts" setup>
4
- import { withPrefix } from "../../utils";
4
+ import { cssPrefix } from "../../utils";
5
5
 
6
6
  // Top-level page surface inside the app shell
7
7
  const pageAttrs = {
8
- class: [withPrefix("page")],
8
+ class: [cssPrefix("page")],
9
9
  } as const;
10
10
  </script>
@@ -18,7 +18,7 @@ $present-translate-minus: sass.fn-naming-dvar(("translate"), "-100%");
18
18
  $present-opacity: sass.fn-naming-dvar(("present", "opacity"), 1);
19
19
 
20
20
  .#{$backdrop} {
21
- position: absolute;
21
+ position: fixed;
22
22
  width: 100%;
23
23
  height: 100%;
24
24
  top: 0;
@@ -30,7 +30,7 @@ $present-opacity: sass.fn-naming-dvar(("present", "opacity"), 1);
30
30
  color #{$transition-duration} ease,
31
31
  border-radius #{$transition-duration} ease,
32
32
  opacity #{$transition-duration} ease;
33
- background-color: rgb(#{$backdrop-background-color});
33
+ background-color: rgba(#{$backdrop-background-color});
34
34
  opacity: #{$backdrop-opacity};
35
35
  }
36
36
 
@@ -38,7 +38,7 @@ $present-opacity: sass.fn-naming-dvar(("present", "opacity"), 1);
38
38
  display: flex;
39
39
  justify-content: center;
40
40
  align-items: center;
41
- position: absolute;
41
+ position: fixed;
42
42
  width: fit-content;
43
43
  height: fit-content;
44
44
  transition: transform #{$transition-duration} ease;
@@ -3,7 +3,7 @@
3
3
  <script lang="ts" setup>
4
4
  import type { PresentEmit, PresentProps, RenderOptions } from "./present.type";
5
5
  import { computed, onMounted, reactive, ref, watch } from "vue";
6
- import { withPrefix, property } from "../../utils";
6
+ import { cssPrefix, cssProperty } from "../../utils";
7
7
  import { usePresent } from "./present.composable";
8
8
 
9
9
  // Component setup (props, emits, injects)
@@ -28,7 +28,7 @@ const zIndex = ref(0);
28
28
  const isShow = ref(false);
29
29
  const styles = reactive({
30
30
  backdropTransitionDuration: "0.2s",
31
- backdropOpacity: 0.4,
31
+ backdropOpacity: undefined,
32
32
  presentTransitionDuration: "0.2s",
33
33
  presentTranslate: "0px",
34
34
  presentOpacity: 1,
@@ -38,11 +38,11 @@ const styles = reactive({
38
38
  // ----------------------------------------------------------------------------
39
39
  const backdropAttrs = computed(() => {
40
40
  return {
41
- class: [withPrefix(["layer", "backdrop"]), withPrefix("present-backdrop")],
41
+ class: [cssPrefix(["layer", "backdrop"]), cssPrefix("present-backdrop")],
42
42
  style: {
43
43
  zIndex: zIndex.value - 1,
44
- [property("transition-duration")]: styles.backdropTransitionDuration,
45
- [property(["backdrop", "opacity"])]:
44
+ [cssProperty("transition-duration")]: styles.backdropTransitionDuration,
45
+ [cssProperty(["backdrop", "opacity"])]:
46
46
  props.backdrop === "transparent" ? 0 : styles.backdropOpacity,
47
47
  },
48
48
  };
@@ -51,13 +51,13 @@ const backdropAttrs = computed(() => {
51
51
  // Present attributes
52
52
  const presentAttrs = computed(() => {
53
53
  return {
54
- class: [withPrefix("present"), props.class, props.placement],
54
+ class: [cssPrefix("present"), props.class, props.placement],
55
55
  style: [
56
56
  {
57
57
  zIndex: zIndex.value,
58
- [property("transition-duration")]: styles.presentTransitionDuration,
59
- [property("translate")]: styles.presentTranslate,
60
- [property(["present", "opacity"])]: styles.presentOpacity,
58
+ [cssProperty("transition-duration")]: styles.presentTransitionDuration,
59
+ [cssProperty("translate")]: styles.presentTranslate,
60
+ [cssProperty(["present", "opacity"])]: styles.presentOpacity,
61
61
  },
62
62
  props.style,
63
63
  ],
@@ -87,9 +87,9 @@ const render = (data: RenderOptions) => {
87
87
  if (data.presentTransitionDuration !== undefined) {
88
88
  styles.presentTransitionDuration = data.presentTransitionDuration;
89
89
  }
90
- if (data.backdropOpacity !== undefined) {
91
- styles.backdropOpacity = data.backdropOpacity;
92
- }
90
+
91
+ styles.backdropOpacity = data.backdropOpacity;
92
+
93
93
  if (data.presentTranslate !== undefined) {
94
94
  styles.presentTranslate = data.presentTranslate;
95
95
  }
@@ -115,7 +115,7 @@ const open = () => {
115
115
 
116
116
  render({
117
117
  backdropTransitionDuration: time.value,
118
- backdropOpacity: 0.4,
118
+ backdropOpacity: undefined,
119
119
  presentTranslate: String(presentTranslate),
120
120
  presentTransitionDuration: time.value,
121
121
  presentOpacity: 1,
@@ -128,7 +128,7 @@ const open = () => {
128
128
  }, props.duration);
129
129
  } else {
130
130
  render({
131
- backdropOpacity: 0.4,
131
+ backdropOpacity: undefined,
132
132
  backdropTransitionDuration: time.value,
133
133
  presentTranslate: "0px",
134
134
  presentTransitionDuration: time.value,
@@ -1,6 +1,6 @@
1
1
  <div
2
2
  v-bind="radioAttrs"
3
- @click="onRadio"
3
+ @pointerup="onRadio"
4
4
  :tabindex="disabled ? -1 : 0"
5
5
  @focus="onFocus"
6
6
  @blur="onBlur"