@toife/vue 3.0.7 → 3.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/package.json +4 -7
- package/src/components/action/action.html +1 -1
- package/src/components/action/action.scss +1 -1
- package/src/components/app/app.scss +1 -1
- package/src/components/avatar/avatar.scss +1 -1
- package/src/components/button/button.scss +1 -1
- package/src/components/cable/cable.scss +1 -1
- package/src/components/card/card/card.scss +1 -1
- package/src/components/card/card-body/card-body.scss +1 -1
- package/src/components/card/card-footer/card-footer.scss +1 -1
- package/src/components/card/card-header/card-header.scss +1 -1
- package/src/components/checkbox/checkbox.scss +1 -1
- package/src/components/collapse/collapse.scss +1 -1
- package/src/components/container/container.scss +1 -1
- package/src/components/decision-modal/decision-modal.scss +6 -1
- package/src/components/divider/divider.md +6 -6
- package/src/components/divider/divider.scss +1 -1
- package/src/components/divider/divider.type.ts +2 -2
- package/src/components/divider/divider.vue +2 -2
- package/src/components/divider/index.ts +1 -1
- package/src/components/dropdown/dropdown.scss +4 -10
- package/src/components/field/outline/outline.html +13 -13
- package/src/components/field/outline/outline.scss +97 -36
- package/src/components/field/outline/outline.vue +59 -16
- package/src/components/form-group/form-group.md +4 -4
- package/src/components/form-group/form-group.scss +1 -1
- package/src/components/form-group/form-group.type.ts +2 -2
- package/src/components/form-group/form-group.vue +2 -2
- package/src/components/gesture-indicator/gesture-indicator.scss +1 -1
- package/src/components/index.ts +1 -0
- package/src/components/layout/cell/cell.html +1 -0
- package/src/components/layout/cell/cell.md +47 -0
- package/src/components/layout/cell/cell.scss +54 -0
- package/src/components/layout/cell/cell.type.ts +19 -0
- package/src/components/layout/cell/cell.vue +35 -0
- package/src/components/layout/cell/index.ts +2 -0
- package/src/components/layout/flex/flex.html +1 -0
- package/src/components/layout/flex/flex.scss +59 -0
- package/src/components/layout/flex/flex.type.ts +15 -0
- package/src/components/layout/flex/flex.vue +34 -0
- package/src/components/layout/flex/index.ts +2 -0
- package/src/components/layout/grid/grid.html +1 -0
- package/src/components/layout/grid/grid.md +50 -0
- package/src/components/layout/grid/grid.scss +53 -0
- package/src/components/layout/grid/grid.type.ts +12 -0
- package/src/components/layout/grid/grid.vue +32 -0
- package/src/components/layout/grid/index.ts +2 -0
- package/src/components/layout/index.ts +3 -0
- package/src/components/modal/modal.scss +1 -1
- package/src/components/page/page.scss +1 -1
- package/src/components/present/present.scss +1 -1
- package/src/components/radio/radio/radio.scss +1 -1
- package/src/components/radio/radio-group/index.ts +1 -1
- package/src/components/radio/radio-group/radio-group.md +10 -10
- package/src/components/radio/radio-group/radio-group.scss +1 -1
- package/src/components/radio/radio-group/radio-group.type.ts +2 -2
- package/src/components/radio/radio-group/radio-group.vue +2 -2
- package/src/components/refresher/refresher.scss +1 -1
- package/src/components/route/route-navigator/route-navigator.scss +5 -5
- package/src/components/route/route-navigator/route-navigator.vue +26 -20
- package/src/components/segmented-field/segmented-field.scss +1 -1
- package/src/components/select/index.ts +1 -1
- package/src/components/select/select.html +9 -6
- package/src/components/select/select.scss +82 -11
- package/src/components/select/select.type.ts +14 -1
- package/src/components/select/select.vue +38 -8
- package/src/components/skeleton/skeleton.scss +1 -1
- package/src/components/switch/switch.scss +1 -1
- package/src/components/tabs/tabs/tabs.scss +6 -6
- package/src/components/toast/toast/toast.scss +1 -1
- package/src/components/toast/toast-content/toast-content.scss +1 -1
- package/src/components/toolbar/toolbar.html +1 -3
- package/src/components/toolbar/toolbar.md +5 -8
- package/src/components/toolbar/toolbar.scss +25 -40
- package/src/components/toolbar/toolbar.type.ts +1 -1
- package/src/components/toolbar/toolbar.vue +4 -4
- package/src/factory.ts +6 -0
- package/src/utils/style/index.ts +1 -1
|
@@ -2,6 +2,6 @@ export { default as RadioGroup } from "./radio-group.vue";
|
|
|
2
2
|
export type {
|
|
3
3
|
RadioGroupProps,
|
|
4
4
|
RadioGroupProviderState,
|
|
5
|
-
|
|
5
|
+
RadioGroupDirection,
|
|
6
6
|
} from "./radio-group.type";
|
|
7
7
|
export { RADIO_GROUP_PROVIDER_STATE_KEY } from "./radio-group.constants";
|
|
@@ -16,7 +16,7 @@ Radio group with shared `v-model`; provides variant/readonly/disabled/shadow to
|
|
|
16
16
|
## Basic usage
|
|
17
17
|
|
|
18
18
|
```vue
|
|
19
|
-
<t-radio-group v-model="choice"
|
|
19
|
+
<t-radio-group v-model="choice" direction="vertical">
|
|
20
20
|
<t-radio value="a">A</t-radio>
|
|
21
21
|
<t-radio value="b">B</t-radio>
|
|
22
22
|
</t-radio-group>
|
|
@@ -24,15 +24,15 @@ Radio group with shared `v-model`; provides variant/readonly/disabled/shadow to
|
|
|
24
24
|
|
|
25
25
|
## Props
|
|
26
26
|
|
|
27
|
-
| Prop
|
|
28
|
-
|
|
|
29
|
-
| `modelValue`
|
|
30
|
-
| `role`
|
|
31
|
-
| `variant`
|
|
32
|
-
| `disabled`
|
|
33
|
-
| `readonly`
|
|
34
|
-
| `shadow`
|
|
35
|
-
| `
|
|
27
|
+
| Prop | Type | Default | Description |
|
|
28
|
+
| ------------ | ---------------------------- | ------------ | ------------------------------------- |
|
|
29
|
+
| `modelValue` | `string \| number` | — | Selected value (`v-model`). |
|
|
30
|
+
| `role` | `string` | — | Theme; default from app. |
|
|
31
|
+
| `variant` | `RadioVariant` | `"fill"` | Default for radios unless overridden. |
|
|
32
|
+
| `disabled` | `boolean` | `false` | Whole group. |
|
|
33
|
+
| `readonly` | `boolean` | `false` | |
|
|
34
|
+
| `shadow` | `boolean` | — | Default from app. |
|
|
35
|
+
| `direction` | `"horizontal" \| "vertical"` | `"vertical"` | Flex layout. |
|
|
36
36
|
|
|
37
37
|
**Type source:** `src/components/radio/radio-group/radio-group.type.ts`
|
|
38
38
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ComputedRef } from "vue";
|
|
2
2
|
import type { RadioVariant } from "../radio/radio.type";
|
|
3
3
|
|
|
4
|
-
export type
|
|
4
|
+
export type RadioGroupDirection = "horizontal" | "vertical";
|
|
5
5
|
|
|
6
6
|
export type RadioGroupProps = {
|
|
7
7
|
modelValue?: string | number;
|
|
@@ -10,7 +10,7 @@ export type RadioGroupProps = {
|
|
|
10
10
|
disabled?: boolean;
|
|
11
11
|
readonly?: boolean;
|
|
12
12
|
shadow?: boolean;
|
|
13
|
-
|
|
13
|
+
direction?: RadioGroupDirection;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
export type RadioGroupEmit = {
|
|
@@ -13,7 +13,7 @@ const props = withDefaults(defineProps<RadioGroupProps>(), {
|
|
|
13
13
|
disabled: false,
|
|
14
14
|
readonly: false,
|
|
15
15
|
variant: "fill",
|
|
16
|
-
|
|
16
|
+
direction: "vertical",
|
|
17
17
|
shadow: undefined,
|
|
18
18
|
});
|
|
19
19
|
const emit = defineEmits<RadioGroupEmit>();
|
|
@@ -37,7 +37,7 @@ const shadow = computed(() => {
|
|
|
37
37
|
|
|
38
38
|
const radioGroupAttrs = computed(() => {
|
|
39
39
|
return {
|
|
40
|
-
class: [withPrefix("radio-group"), props.
|
|
40
|
+
class: [withPrefix("radio-group"), props.direction],
|
|
41
41
|
};
|
|
42
42
|
});
|
|
43
43
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@use "@toife/sass-layer
|
|
1
|
+
@use "@toife/sass-layer" as sass;
|
|
2
2
|
|
|
3
3
|
// Classes
|
|
4
4
|
$navigator: sass.fn-naming-prefix("route-navigator");
|
|
@@ -108,19 +108,19 @@ $backdrop-background-color: sass.fn-naming-var("backdrop", "background-color");
|
|
|
108
108
|
|
|
109
109
|
&.back {
|
|
110
110
|
&.right {
|
|
111
|
-
transform: translateX(
|
|
111
|
+
transform: translateX(#{$transform-back});
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
&.left {
|
|
115
|
-
transform: translateX(#{$transform-back});
|
|
115
|
+
transform: translateX(calc(-1 * #{$transform-back}));
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
&.up {
|
|
119
|
-
transform: translateY(#{$transform-back});
|
|
119
|
+
transform: translateY(calc(-1 * #{$transform-back}));
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
&.down {
|
|
123
|
-
transform: translateY(
|
|
123
|
+
transform: translateY(#{$transform-back});
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
}
|
|
@@ -26,7 +26,7 @@ import { clone } from "../route.util";
|
|
|
26
26
|
// Active uses 0–100%; back uses (peek)*(100−percent)/100, so a peek of 40 makes the
|
|
27
27
|
// back layer move 2.5× slower than the active layer (parallax). Use 100 for 1:1 motion
|
|
28
28
|
// (no edge peek at rest: back starts at -100%).
|
|
29
|
-
const BACK_LAYER_PEEK_PCT = 40;
|
|
29
|
+
const BACK_LAYER_PEEK_PCT = -40;
|
|
30
30
|
|
|
31
31
|
const props = withDefaults(defineProps<RouteNavigatorProps>(), {
|
|
32
32
|
direction: "right",
|
|
@@ -134,17 +134,23 @@ const changeRoute = (value: RouteStack[]) => {
|
|
|
134
134
|
transform.backdrop = 0;
|
|
135
135
|
emit("transform", transform);
|
|
136
136
|
|
|
137
|
-
setTimeout(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
137
|
+
setTimeout(
|
|
138
|
+
() => {
|
|
139
|
+
backdropIndex.value = backdropIndex.value + 1;
|
|
140
|
+
transform.duration = undefined;
|
|
141
|
+
emit("transform", transform);
|
|
142
|
+
},
|
|
143
|
+
props.variant === "swipe" ? 10 : 0
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
setTimeout(
|
|
147
|
+
() => {
|
|
148
|
+
transform.backdrop = 100;
|
|
149
|
+
activeIndex.value = stack.value.length - 1;
|
|
150
|
+
emit("transform", transform);
|
|
151
|
+
},
|
|
152
|
+
props.variant === "swipe" ? 100 : 0
|
|
153
|
+
);
|
|
148
154
|
}
|
|
149
155
|
};
|
|
150
156
|
|
|
@@ -159,23 +165,24 @@ const resetTransform = () => {
|
|
|
159
165
|
transform.back = BACK_LAYER_PEEK_PCT;
|
|
160
166
|
transform.prepare = 100;
|
|
161
167
|
transform.active = 0;
|
|
162
|
-
|
|
168
|
+
transform.duration = undefined;
|
|
163
169
|
emit("transform", transform);
|
|
164
170
|
};
|
|
165
171
|
|
|
166
172
|
const move = (data: RouteNavigatorGesture) => {
|
|
167
173
|
const width = navigatorRef.value?.offsetWidth ?? 0;
|
|
168
|
-
let
|
|
174
|
+
let activePercent = 0;
|
|
169
175
|
|
|
170
176
|
if (props.direction == "left" || props.direction == "right") {
|
|
171
|
-
|
|
177
|
+
activePercent = (Math.abs(data.deltaX) / width) * 100;
|
|
172
178
|
} else {
|
|
173
|
-
|
|
179
|
+
activePercent = (Math.abs(data.deltaY) / width) * 100;
|
|
174
180
|
}
|
|
175
181
|
|
|
176
|
-
transform.back = ((100 -
|
|
177
|
-
transform.active =
|
|
182
|
+
transform.back = ((100 - activePercent) * BACK_LAYER_PEEK_PCT) / 100;
|
|
183
|
+
transform.active = activePercent;
|
|
178
184
|
transform.backdrop = 100 - transform.active;
|
|
185
|
+
transform.duration = "0s";
|
|
179
186
|
|
|
180
187
|
emit("transform", transform);
|
|
181
188
|
};
|
|
@@ -216,14 +223,13 @@ onMounted(() => {
|
|
|
216
223
|
beforeEvent(e: Event) {
|
|
217
224
|
const target = e.target as HTMLElement | null;
|
|
218
225
|
const isEditable = target?.closest("input, textarea, select, button, [contenteditable]");
|
|
219
|
-
if (isEditable || props.variant === "none") return false;
|
|
226
|
+
if (isEditable || props.variant === "none" || !prevPage.value) return false;
|
|
220
227
|
e.stopPropagation();
|
|
221
228
|
return prevPage.value;
|
|
222
229
|
},
|
|
223
230
|
|
|
224
231
|
fast({ initialDirection, event }: { initialDirection: string; event: Event }) {
|
|
225
232
|
if (initialDirection !== props.direction) return;
|
|
226
|
-
event.stopPropagation();
|
|
227
233
|
event.preventDefault();
|
|
228
234
|
goBack();
|
|
229
235
|
},
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { default as Select } from "./select.vue";
|
|
2
|
-
export
|
|
2
|
+
export * from "./select.type";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div v-bind="selectAttrs">
|
|
2
|
-
<Dropdown v-bind="dropdownAttrs">
|
|
2
|
+
<Dropdown v-bind="dropdownAttrs" v-model="visible">
|
|
3
3
|
<template #trigger="{ toggle, isOpen }">
|
|
4
4
|
<Field
|
|
5
5
|
:role="role"
|
|
@@ -14,13 +14,16 @@
|
|
|
14
14
|
</Field>
|
|
15
15
|
</template>
|
|
16
16
|
<button
|
|
17
|
-
v-for="
|
|
18
|
-
:key="
|
|
17
|
+
v-for="option in options"
|
|
18
|
+
:key="option.value"
|
|
19
19
|
type="button"
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
:disabled="option.disabled"
|
|
21
|
+
v-bind="selectOptionAttrs"
|
|
22
|
+
@click="pickOption(option)"
|
|
22
23
|
>
|
|
23
|
-
{{
|
|
24
|
+
{{ option.label }}
|
|
24
25
|
</button>
|
|
25
26
|
</Dropdown>
|
|
27
|
+
<div v-bind="selectMessageAttrs" v-if="message">{{ message }}</div>
|
|
28
|
+
<div v-bind="selectHelpAttrs" v-if="help">{{ help }}</div>
|
|
26
29
|
</div>
|
|
@@ -1,26 +1,36 @@
|
|
|
1
|
-
@use "@toife/sass-layer
|
|
1
|
+
@use "@toife/sass-layer" as sass;
|
|
2
2
|
|
|
3
3
|
// Class name
|
|
4
4
|
$select: sass.fn-naming-prefix("select");
|
|
5
5
|
$select-icon: sass.fn-naming-prefix("select-icon");
|
|
6
|
+
$select-option: sass.fn-naming-prefix("select-option");
|
|
7
|
+
$select-message: sass.fn-naming-prefix("select-message");
|
|
8
|
+
$select-help: sass.fn-naming-prefix("select-help");
|
|
6
9
|
$field: sass.fn-naming-prefix("field");
|
|
7
10
|
$field-input: sass.fn-naming-prefix("field-input");
|
|
8
11
|
|
|
9
12
|
// Property name
|
|
10
13
|
$app-color: sass.fn-naming-var("app", "color");
|
|
11
14
|
$spacing-x: sass.fn-naming-var("spacing", "x");
|
|
15
|
+
$spacing-y: sass.fn-naming-var("spacing", "y");
|
|
12
16
|
$size-coefficient-x: sass.fn-naming-var("coefficient-x");
|
|
17
|
+
$size-coefficient-y: sass.fn-naming-var("coefficient-y");
|
|
13
18
|
$transition-duration: sass.fn-naming-var("motion", "duration");
|
|
14
19
|
|
|
20
|
+
$select-background-color: sass.fn-naming-var("select", "background-color");
|
|
21
|
+
$select-background-color-hover: sass.fn-naming-var("select", "background-color", "hover");
|
|
22
|
+
$select-background-color-focus: sass.fn-naming-var("select", "background-color", "focus");
|
|
23
|
+
$select-background-color-active: sass.fn-naming-var("select", "background-color", "active");
|
|
24
|
+
$select-color: sass.fn-naming-var("select", "color");
|
|
25
|
+
$select-color-disabled: sass.fn-naming-var("select", "color", "disabled");
|
|
26
|
+
$select-border-color: sass.fn-naming-var("select", "border-color");
|
|
27
|
+
$select-message-color: sass.fn-naming-var("select", "message-color");
|
|
28
|
+
|
|
15
29
|
.#{$select} {
|
|
16
30
|
&.disabled {
|
|
17
31
|
cursor: not-allowed;
|
|
18
32
|
}
|
|
19
33
|
|
|
20
|
-
&.readonly {
|
|
21
|
-
pointer-events: none;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
34
|
.#{$select-icon} {
|
|
25
35
|
display: inline-flex;
|
|
26
36
|
align-items: center;
|
|
@@ -48,11 +58,72 @@ $transition-duration: sass.fn-naming-var("motion", "duration");
|
|
|
48
58
|
}
|
|
49
59
|
}
|
|
50
60
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
61
|
+
.#{$select-option} {
|
|
62
|
+
display: block;
|
|
63
|
+
width: 100%;
|
|
64
|
+
padding: calc(var(--t-spacing-y)) calc(var(--t-spacing-x) * var(--t-coefficient-x));
|
|
65
|
+
text-align: var(--t-text-align);
|
|
66
|
+
text-overflow: ellipsis;
|
|
67
|
+
white-space: nowrap;
|
|
68
|
+
overflow: hidden;
|
|
69
|
+
background: transparent;
|
|
70
|
+
cursor: pointer;
|
|
71
|
+
color: rgb(#{$select-color});
|
|
72
|
+
background-color: rgb(#{$select-background-color});
|
|
73
|
+
transition:
|
|
74
|
+
box-shadow #{$transition-duration} ease,
|
|
75
|
+
border-color #{$transition-duration} ease,
|
|
76
|
+
background-color #{$transition-duration} ease,
|
|
77
|
+
color #{$transition-duration} ease,
|
|
78
|
+
border-radius #{$transition-duration} ease;
|
|
79
|
+
|
|
80
|
+
&:not(:disabled):not(.disabled):not(.readonly) {
|
|
81
|
+
&:hover,
|
|
82
|
+
&.hover {
|
|
83
|
+
background: rgb(#{$select-background-color-hover});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&:focus,
|
|
87
|
+
&.focus {
|
|
88
|
+
background: rgb(#{$select-background-color-focus});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
&:active,
|
|
92
|
+
&.active {
|
|
93
|
+
background: rgb(#{$select-background-color-active});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
&:disabled,
|
|
98
|
+
&.disabled {
|
|
99
|
+
cursor: not-allowed;
|
|
100
|
+
color: rgb(#{$select-color-disabled});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Message
|
|
105
|
+
.#{$select-message} {
|
|
106
|
+
color: rgb(#{$select-message-color});
|
|
107
|
+
font-size: 0.9em;
|
|
108
|
+
line-height: 1.5;
|
|
109
|
+
transition:
|
|
110
|
+
box-shadow #{$transition-duration} ease,
|
|
111
|
+
border-color #{$transition-duration} ease,
|
|
112
|
+
background-color #{$transition-duration} ease,
|
|
113
|
+
color #{$transition-duration} ease,
|
|
114
|
+
border-radius #{$transition-duration} ease;
|
|
115
|
+
}
|
|
54
116
|
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
117
|
+
// Help
|
|
118
|
+
.#{$select-help} {
|
|
119
|
+
color: rgb(#{$app-color}, 0.75);
|
|
120
|
+
font-size: 0.8em;
|
|
121
|
+
line-height: 1.5;
|
|
122
|
+
transition:
|
|
123
|
+
box-shadow #{$transition-duration} ease,
|
|
124
|
+
border-color #{$transition-duration} ease,
|
|
125
|
+
background-color #{$transition-duration} ease,
|
|
126
|
+
color #{$transition-duration} ease,
|
|
127
|
+
border-radius #{$transition-duration} ease;
|
|
128
|
+
}
|
|
58
129
|
}
|
|
@@ -4,6 +4,12 @@ import type { AppDirection } from "../app";
|
|
|
4
4
|
export type SelectVariant = FieldVariant;
|
|
5
5
|
export type SelectSize = FieldSize;
|
|
6
6
|
|
|
7
|
+
export type SelectOption = {
|
|
8
|
+
label?: string;
|
|
9
|
+
value: string;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
7
13
|
export type SelectProps = {
|
|
8
14
|
// Wrapper
|
|
9
15
|
modelValue?: string;
|
|
@@ -20,7 +26,6 @@ export type SelectProps = {
|
|
|
20
26
|
value?: string;
|
|
21
27
|
placeholder?: string;
|
|
22
28
|
disabled?: boolean;
|
|
23
|
-
readonly?: boolean;
|
|
24
29
|
autocomplete?: string;
|
|
25
30
|
tabindex?: number | string;
|
|
26
31
|
line?: number | string;
|
|
@@ -29,4 +34,12 @@ export type SelectProps = {
|
|
|
29
34
|
// Support
|
|
30
35
|
message?: string;
|
|
31
36
|
help?: string;
|
|
37
|
+
|
|
38
|
+
// Data
|
|
39
|
+
options: Array<SelectOption>;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export type SelectEmit = {
|
|
43
|
+
(e: "update:modelValue", value: string): void;
|
|
44
|
+
(e: "select", option: SelectOption): void;
|
|
32
45
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<style lang="scss" src="./select.scss" scoped></style>
|
|
2
2
|
<template src="./select.html"></template>
|
|
3
3
|
<script lang="ts" setup>
|
|
4
|
-
import { computed, inject } from "vue";
|
|
5
|
-
import { type SelectProps } from "./select.type";
|
|
4
|
+
import { computed, inject, ref } from "vue";
|
|
5
|
+
import { type SelectOption, type SelectProps, type SelectEmit } from "./select.type";
|
|
6
6
|
import { property, withPrefix } from "../../utils";
|
|
7
7
|
import { type AppProviderState, APP_PROVIDER_STATE_KEY } from "../app";
|
|
8
8
|
import { Field } from "../field";
|
|
@@ -15,15 +15,17 @@ const props = withDefaults(defineProps<SelectProps>(), {
|
|
|
15
15
|
type: "text",
|
|
16
16
|
size: "standard",
|
|
17
17
|
disabled: false,
|
|
18
|
-
readonly: false,
|
|
19
18
|
message: "",
|
|
20
19
|
help: "",
|
|
21
20
|
variant: "outline",
|
|
22
21
|
placeholder: "",
|
|
23
22
|
shadow: undefined,
|
|
24
23
|
direction: undefined,
|
|
24
|
+
options: () => [] as Array<SelectOption>,
|
|
25
25
|
});
|
|
26
26
|
const appState = inject<AppProviderState>(APP_PROVIDER_STATE_KEY);
|
|
27
|
+
const emit = defineEmits<SelectEmit>();
|
|
28
|
+
const visible = ref(false);
|
|
27
29
|
|
|
28
30
|
// Computed properties
|
|
29
31
|
// ----------------------------------------------------------------------------
|
|
@@ -47,10 +49,12 @@ const selectAttrs = computed(() => {
|
|
|
47
49
|
return {
|
|
48
50
|
class: [
|
|
49
51
|
withPrefix(["layer", "select"]),
|
|
52
|
+
withPrefix(["role", role.value]),
|
|
50
53
|
withPrefix("select"),
|
|
54
|
+
withPrefix(["direction", direction.value]),
|
|
55
|
+
withPrefix(["size", props.size]),
|
|
51
56
|
{
|
|
52
57
|
disabled: props.disabled,
|
|
53
|
-
readonly: props.readonly,
|
|
54
58
|
},
|
|
55
59
|
],
|
|
56
60
|
};
|
|
@@ -63,22 +67,27 @@ const dropdownAttrs = computed(() => {
|
|
|
63
67
|
shadow: shadow.value,
|
|
64
68
|
shape: shape.value,
|
|
65
69
|
disabled: props.disabled,
|
|
66
|
-
readonly: props.readonly,
|
|
67
70
|
};
|
|
68
71
|
});
|
|
69
72
|
|
|
70
73
|
const fieldAttrs = computed(() => {
|
|
74
|
+
const propsValue = props.modelValue || props.value;
|
|
75
|
+
let val: string[] = [];
|
|
76
|
+
if (propsValue) val = typeof propsValue === "string" ? [propsValue] : (propsValue as string[]);
|
|
77
|
+
const values: string[] = props.options
|
|
78
|
+
.filter((option): option is SelectOption => (val || []).includes(option.value))
|
|
79
|
+
.map((option) => option.label ?? option.value);
|
|
80
|
+
|
|
71
81
|
return {
|
|
72
|
-
modelValue:
|
|
82
|
+
modelValue: values.join(","),
|
|
73
83
|
size: props.size,
|
|
74
|
-
message: props.message,
|
|
75
|
-
help: props.help,
|
|
76
84
|
variant: props.variant,
|
|
77
85
|
placeholder: props.placeholder,
|
|
78
86
|
direction: direction.value,
|
|
79
87
|
role: role.value,
|
|
80
88
|
shape: shape.value,
|
|
81
89
|
readonly: true,
|
|
90
|
+
disabled: props.disabled,
|
|
82
91
|
shadow: shadow.value,
|
|
83
92
|
};
|
|
84
93
|
});
|
|
@@ -86,4 +95,25 @@ const fieldAttrs = computed(() => {
|
|
|
86
95
|
const selectIconAttrs = computed(() => ({
|
|
87
96
|
class: [withPrefix("select-icon")],
|
|
88
97
|
}));
|
|
98
|
+
|
|
99
|
+
const selectOptionAttrs = computed(() => ({
|
|
100
|
+
class: [withPrefix("select-option")],
|
|
101
|
+
}));
|
|
102
|
+
|
|
103
|
+
const selectMessageAttrs = computed(() => ({
|
|
104
|
+
class: [withPrefix("select-message")],
|
|
105
|
+
}));
|
|
106
|
+
|
|
107
|
+
const selectHelpAttrs = computed(() => ({
|
|
108
|
+
class: [withPrefix("select-help")],
|
|
109
|
+
}));
|
|
110
|
+
|
|
111
|
+
// Methods
|
|
112
|
+
// ----------------------------------------------------------------------------
|
|
113
|
+
const pickOption = (option: SelectOption) => {
|
|
114
|
+
if (option.disabled || option.value === undefined) return;
|
|
115
|
+
emit("update:modelValue", option.value);
|
|
116
|
+
emit("select", option);
|
|
117
|
+
visible.value = false;
|
|
118
|
+
};
|
|
89
119
|
</script>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@use "@toife/sass-layer
|
|
1
|
+
@use "@toife/sass-layer" as sass;
|
|
2
2
|
|
|
3
3
|
// Class name
|
|
4
4
|
$tabs: sass.fn-naming-prefix("tabs");
|
|
@@ -30,7 +30,7 @@ $highlight-space-y: sass.fn-naming-var("highlight", "space-y");
|
|
|
30
30
|
position: relative;
|
|
31
31
|
margin: 0;
|
|
32
32
|
list-style: none;
|
|
33
|
-
border:
|
|
33
|
+
border: none;
|
|
34
34
|
transition:
|
|
35
35
|
box-shadow #{$transition-duration} ease,
|
|
36
36
|
border-color #{$transition-duration} ease,
|
|
@@ -113,25 +113,25 @@ $highlight-space-y: sass.fn-naming-var("highlight", "space-y");
|
|
|
113
113
|
&.top-start,
|
|
114
114
|
&.top-center,
|
|
115
115
|
&.top-end {
|
|
116
|
-
border-bottom
|
|
116
|
+
border-bottom: #{$border-width} solid rgb(#{$tabs-border-color});
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
&.bottom-start,
|
|
120
120
|
&.bottom-center,
|
|
121
121
|
&.bottom-end {
|
|
122
|
-
border-top
|
|
122
|
+
border-top: #{$border-width} solid rgb(#{$tabs-border-color});
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
&.left-start,
|
|
126
126
|
&.left-center,
|
|
127
127
|
&.left-end {
|
|
128
|
-
border-right
|
|
128
|
+
border-right: #{$border-width} solid rgb(#{$tabs-border-color});
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
&.right-start,
|
|
132
132
|
&.right-center,
|
|
133
133
|
&.right-end {
|
|
134
|
-
border-left
|
|
134
|
+
border-left: #{$border-width} solid rgb(#{$tabs-border-color});
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
|
|
@@ -25,12 +25,11 @@ Toolbar surface with height / safe-area; `placement` comes from props or from `t
|
|
|
25
25
|
|
|
26
26
|
## Props
|
|
27
27
|
|
|
28
|
-
| Prop | Type
|
|
29
|
-
| ----------- |
|
|
30
|
-
| `placement` | `string \| null`
|
|
31
|
-
| `safeArea` | `boolean`
|
|
32
|
-
| `
|
|
33
|
-
| `role` | `string` | — | Theme. |
|
|
28
|
+
| Prop | Type | Default | Description |
|
|
29
|
+
| ----------- | ---------------- | ------- | ------------------------------------------------- |
|
|
30
|
+
| `placement` | `string \| null` | `null` | Placement class; if null, uses `cable.placement`. |
|
|
31
|
+
| `safeArea` | `boolean` | `true` | Safe-area padding (notch, home indicator). |
|
|
32
|
+
| `role` | `string` | — | Theme. |
|
|
34
33
|
|
|
35
34
|
**Type source:** `src/components/toolbar/toolbar.type.ts`
|
|
36
35
|
|
|
@@ -50,8 +49,6 @@ Optional inject `CABLE_PROVIDER_STATE_KEY` and `APP_PROVIDER_STATE_KEY`.
|
|
|
50
49
|
|
|
51
50
|
## Style / class notes
|
|
52
51
|
|
|
53
|
-
Variable `--<prefix>-toolbar-size`; classes `with-safe-area`, placement.
|
|
54
|
-
|
|
55
52
|
## See also
|
|
56
53
|
|
|
57
54
|
- Source: `src/components/toolbar`
|