@toife/vue 3.0.6 → 3.0.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toife/vue",
3
- "version": "3.0.6",
3
+ "version": "3.0.7",
4
4
  "description": "A Frontend framework for Vue",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -31,7 +31,6 @@
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@toife/gesture": "^1.1.4",
34
- "@toife/sass-layer-generator": "^1.0.9",
35
34
  "vue": "^3.5.0",
36
35
  "vue-router": "^4.0.0"
37
36
  },
@@ -48,7 +47,6 @@
48
47
  "devDependencies": {
49
48
  "@commitlint/cli": "^20.4.4",
50
49
  "@commitlint/config-conventional": "^20.4.4",
51
- "@toife/sass-layer-generator": "^1.0.9",
52
50
  "@types/node": "^25.0.3",
53
51
  "@vitejs/plugin-vue": "^6.0.1",
54
52
  "husky": "^9.1.7",
@@ -62,6 +60,7 @@
62
60
  },
63
61
  "packageManager": "yarn@4.12.0",
64
62
  "dependencies": {
65
- "@toife/gesture": "^1.1.4"
63
+ "@toife/gesture": "^1.1.4",
64
+ "@toife/sass-layer-generator": "^1.1.0"
66
65
  }
67
66
  }
@@ -46,7 +46,7 @@ const cardAttrs = computed(() => {
46
46
 
47
47
  const cardProviderState = computed(() => {
48
48
  return {
49
- role: props.role,
49
+ role: role.value,
50
50
  shape: shape.value,
51
51
  divider: divider.value,
52
52
  };
@@ -36,19 +36,17 @@ const shape = computed(() => {
36
36
  return props.shape || appState?.shape.value || "";
37
37
  });
38
38
 
39
- const role = computed(() => {
40
- return props.role || appState?.role.value || "";
41
- });
42
-
43
39
  const divider = computed(() => {
44
40
  return (props.divider !== undefined ? props.divider : appState?.divider.value) ?? false;
45
41
  });
46
42
 
47
43
  const decisionModalAttrs = computed(() => {
44
+ const role = props.role || appState?.role.value || "";
45
+
48
46
  return {
49
47
  class: [
50
48
  withPrefix(["layer", "decision-modal"]),
51
- withPrefix(["role", role.value]),
49
+ withPrefix(["role", role]),
52
50
  withPrefix(["shape", shape.value]),
53
51
  withPrefix("decision-modal"),
54
52
  {
@@ -0,0 +1,6 @@
1
+ <div ref="rootRef" v-bind="wrapperAttrs">
2
+ <slot name="trigger" :toggle="toggle" :isOpen="isOpen" />
3
+ <div v-show="isOpen" v-bind="panelAttrs">
4
+ <slot />
5
+ </div>
6
+ </div>
@@ -0,0 +1,74 @@
1
+ @use "@toife/sass-layer-generator" as sass;
2
+
3
+ $dropdown: sass.fn-naming-prefix("dropdown");
4
+ $dropdown-panel: sass.fn-naming-prefix("dropdown-panel");
5
+
6
+ $dropdown-border-color: sass.fn-naming-var("dropdown", "border-color");
7
+ $dropdown-background-color: sass.fn-naming-var("dropdown", "background-color");
8
+ $dropdown-color: sass.fn-naming-var("dropdown", "color");
9
+ $border-radius: sass.fn-naming-var("border-radius");
10
+ $border-width: sass.fn-naming-var("stroke", "width");
11
+ $spacing-x: sass.fn-naming-var("spacing", "x");
12
+ $spacing-y: sass.fn-naming-var("spacing", "y");
13
+ $size-font-size: sass.fn-naming-var("font-size");
14
+ $size-line-height: sass.fn-naming-var("line-height");
15
+ $transition-duration: sass.fn-naming-var("motion", "duration");
16
+
17
+ .#{$dropdown} {
18
+ position: relative;
19
+ display: block;
20
+ width: 100%;
21
+
22
+ &.disabled {
23
+ opacity: 0.5;
24
+ cursor: not-allowed;
25
+ }
26
+ }
27
+
28
+ .#{$dropdown-panel} {
29
+ position: absolute;
30
+ z-index: 20;
31
+ min-width: 100%;
32
+ box-sizing: border-box;
33
+ margin-top: calc(#{$spacing-y} * 0.25);
34
+ margin-bottom: calc(#{$spacing-y} * 0.25);
35
+ padding: calc(#{$spacing-y} * 0.5) 0;
36
+ border-radius: #{$border-radius};
37
+ border-width: #{$border-width};
38
+ border-style: solid;
39
+ border-color: rgb(#{$dropdown-border-color});
40
+ background-color: rgb(#{$dropdown-background-color});
41
+ color: rgb(#{$dropdown-color});
42
+ font-size: #{$size-font-size};
43
+ line-height: #{$size-line-height};
44
+ box-shadow: 0 #{$border-width} #{$spacing-y} rgb(#{$dropdown-border-color}, 0.12);
45
+ max-height: min(50vh, 16rem);
46
+ overflow-y: auto;
47
+ transition:
48
+ border-color #{$transition-duration} ease,
49
+ background-color #{$transition-duration} ease,
50
+ color #{$transition-duration} ease,
51
+ box-shadow #{$transition-duration} ease;
52
+
53
+ &.bottom-start {
54
+ top: 100%;
55
+ left: 0;
56
+ }
57
+
58
+ &.bottom-end {
59
+ top: 100%;
60
+ right: 0;
61
+ left: auto;
62
+ }
63
+
64
+ &.top-start {
65
+ bottom: 100%;
66
+ left: 0;
67
+ }
68
+
69
+ &.top-end {
70
+ bottom: 100%;
71
+ right: 0;
72
+ left: auto;
73
+ }
74
+ }
@@ -0,0 +1,19 @@
1
+ import type { AppDirection } from "../app";
2
+
3
+ export type DropdownPlacement = "bottom-start" | "bottom-end" | "top-start" | "top-end";
4
+
5
+ export type DropdownProps = {
6
+ modelValue?: boolean;
7
+ disabled?: boolean;
8
+ placement?: DropdownPlacement;
9
+ role?: string;
10
+ shadow?: boolean;
11
+ shape?: string;
12
+ direction?: AppDirection;
13
+ };
14
+
15
+ export type DropdownEmit = {
16
+ (e: "update:modelValue", open: boolean): void;
17
+ (e: "open"): void;
18
+ (e: "close"): void;
19
+ };
@@ -0,0 +1,109 @@
1
+ <style lang="scss" src="./dropdown.scss" scoped></style>
2
+ <template src="./dropdown.html"></template>
3
+ <script lang="ts" setup>
4
+ import { computed, inject, onMounted, onUnmounted, ref, watch } from "vue";
5
+ import type { DropdownEmit, DropdownProps } from "./dropdown.type";
6
+ import { withPrefix } from "../../utils";
7
+ import { type AppProviderState, APP_PROVIDER_STATE_KEY } from "../app";
8
+
9
+ // Component setup (props, emits, injects)
10
+ // ----------------------------------------------------------------------------
11
+ const props = withDefaults(defineProps<DropdownProps>(), {
12
+ modelValue: false,
13
+ disabled: false,
14
+ placement: "bottom-start",
15
+ role: undefined,
16
+ shadow: undefined,
17
+ shape: undefined,
18
+ direction: undefined,
19
+ });
20
+ const emit = defineEmits<DropdownEmit>();
21
+ const appState = inject<AppProviderState>(APP_PROVIDER_STATE_KEY);
22
+
23
+ // Reactive state
24
+ // ----------------------------------------------------------------------------
25
+ const rootRef = ref<HTMLElement | null>(null);
26
+ const isOpen = ref(false);
27
+
28
+ // Computed properties
29
+ // ----------------------------------------------------------------------------
30
+ const wrapperAttrs = computed(() => {
31
+ const role = props.role ?? appState?.role.value ?? "";
32
+ const shadow = props.shadow ?? appState?.shadow.value ?? false;
33
+ const shape = props.shape ?? appState?.shape.value ?? "";
34
+
35
+ return {
36
+ class: [
37
+ withPrefix(["layer", "dropdown"]),
38
+ withPrefix(["role", role]),
39
+ withPrefix(["shape", shape]),
40
+ withPrefix("dropdown"),
41
+ {
42
+ open: isOpen.value,
43
+ disabled: props.disabled,
44
+ shadow: shadow,
45
+ },
46
+ ],
47
+ };
48
+ });
49
+
50
+ const panelAttrs = computed(() => {
51
+ return {
52
+ class: [withPrefix("dropdown-panel"), props.placement],
53
+ };
54
+ });
55
+
56
+ // Methods
57
+ // ----------------------------------------------------------------------------
58
+ const toggle = () => {
59
+ if (props.disabled) return;
60
+ isOpen.value = !isOpen.value;
61
+ emit("update:modelValue", isOpen.value);
62
+ };
63
+
64
+ const close = () => {
65
+ if (!isOpen.value) return;
66
+ isOpen.value = false;
67
+ emit("update:modelValue", false);
68
+ };
69
+
70
+ const onDocPointerDown = (e: PointerEvent) => {
71
+ if (!isOpen.value) return;
72
+ const root = rootRef.value;
73
+ if (root && !root.contains(e.target as Node)) {
74
+ close();
75
+ }
76
+ };
77
+
78
+ const onDocKeydown = (e: KeyboardEvent) => {
79
+ if (e.key === "Escape" && isOpen.value) {
80
+ e.preventDefault();
81
+ close();
82
+ }
83
+ };
84
+
85
+ // Lifecycle
86
+ // ----------------------------------------------------------------------------
87
+ watch(
88
+ () => props.modelValue,
89
+ (open) => {
90
+ isOpen.value = open;
91
+ },
92
+ { immediate: true }
93
+ );
94
+
95
+ watch(isOpen, (next, prev) => {
96
+ if (next && !prev) emit("open");
97
+ if (!next && prev) emit("close");
98
+ });
99
+
100
+ onMounted(() => {
101
+ document.addEventListener("pointerdown", onDocPointerDown, true);
102
+ document.addEventListener("keydown", onDocKeydown, true);
103
+ });
104
+
105
+ onUnmounted(() => {
106
+ document.removeEventListener("pointerdown", onDocPointerDown, true);
107
+ document.removeEventListener("keydown", onDocKeydown, true);
108
+ });
109
+ </script>
@@ -0,0 +1,2 @@
1
+ export { default as Dropdown } from "./dropdown.vue";
2
+ export type { DropdownPlacement, DropdownProps, DropdownEmit } from "./dropdown.type";
@@ -1 +1,12 @@
1
- <OutlineField v-if="props.variant === 'outline'" v-bind="fieldAttrs" />
1
+ <OutlineField v-if="props.variant === 'outline'" v-bind="fieldAttrs">
2
+ <template #start-input>
3
+ <slot name="start-input"></slot>
4
+ </template>
5
+ <template #input>
6
+ <slot name="input"></slot>
7
+ </template>
8
+ <template #end-input>
9
+ <slot name="end-input"></slot>
10
+ </template>
11
+ <slot></slot>
12
+ </OutlineField>
@@ -1,30 +1,34 @@
1
1
  <div v-bind="fieldAttrs">
2
2
  <div v-bind="fieldContentAttrs">
3
- <div
4
- v-bind="fieldInputAttrs"
5
- @input="onInput"
6
- @compositionstart="onCompositionStart"
7
- @compositionend="onCompositionEnd"
8
- @focus="onFocus"
9
- @blur="onBlur"
10
- @beforeinput="onBeforeinput"
11
- ref="contentRef"
12
- v-text="content"
13
- v-if="type !== 'password'"
14
- ></div>
15
- <input
16
- v-bind="fieldInputAttrs"
17
- @input="onInput"
18
- @compositionstart="onCompositionStart"
19
- @compositionend="onCompositionEnd"
20
- @focus="onFocus"
21
- @blur="onBlur"
22
- @beforeinput="onBeforeinput"
23
- ref="contentRef"
24
- :value="content"
25
- type="password"
26
- v-else
27
- ></input>
3
+ <slot name="start-input"></slot>
4
+ <slot name="input">
5
+ <div
6
+ v-bind="fieldInputAttrs"
7
+ @input="onInput"
8
+ @compositionstart="onCompositionStart"
9
+ @compositionend="onCompositionEnd"
10
+ @focus="onFocus"
11
+ @blur="onBlur"
12
+ @beforeinput="onBeforeinput"
13
+ ref="contentRef"
14
+ v-text="content"
15
+ v-if="type !== 'password'"
16
+ ></div>
17
+ <input
18
+ v-bind="fieldInputAttrs"
19
+ @input="onInput"
20
+ @compositionstart="onCompositionStart"
21
+ @compositionend="onCompositionEnd"
22
+ @focus="onFocus"
23
+ @blur="onBlur"
24
+ @beforeinput="onBeforeinput"
25
+ ref="contentRef"
26
+ :value="content"
27
+ type="password"
28
+ v-else
29
+ />
30
+ </slot>
31
+ <slot name="end-input"></slot>
28
32
  </div>
29
33
  <div v-bind="fieldMessageAttrs" v-if="message">{{ message }}</div>
30
34
  <div v-bind="fieldHelpAttrs" v-if="help">{{ help }}</div>
@@ -6,8 +6,6 @@ $field-content: sass.fn-naming-prefix("field-content");
6
6
  $field-input: sass.fn-naming-prefix("field-input");
7
7
  $field-message: sass.fn-naming-prefix("field-message");
8
8
  $field-help: sass.fn-naming-prefix("field-help");
9
- $field-direction-left: sass.fn-naming-prefix("direction", "left");
10
- $field-direction-right: sass.fn-naming-prefix("direction", "right");
11
9
 
12
10
  // Property name - layer: field
13
11
  $field-border-color: sass.fn-naming-var("field", "border-color");
@@ -30,6 +28,9 @@ $size-line-height: sass.fn-naming-var("line-height");
30
28
 
31
29
  $transition-duration: sass.fn-naming-var("motion", "duration");
32
30
 
31
+ $direction-text-align: sass.fn-naming-var("text-align");
32
+ $direction-justify-content: sass.fn-naming-var("justify-content");
33
+
33
34
  .#{$field} {
34
35
  width: 100%;
35
36
  box-shadow: none !important;
@@ -50,6 +51,9 @@ $transition-duration: sass.fn-naming-var("motion", "duration");
50
51
  line-height: 0;
51
52
  height: fit-content;
52
53
  position: relative;
54
+ display: flex;
55
+ justify-content: center;
56
+ align-items: center;
53
57
  }
54
58
 
55
59
  // Input
@@ -69,6 +73,8 @@ $transition-duration: sass.fn-naming-var("motion", "duration");
69
73
  line-height: #{$size-line-height};
70
74
  box-sizing: border-box;
71
75
  width: 100%;
76
+ overflow: auto;
77
+ flex: 1;
72
78
  transition:
73
79
  box-shadow #{$transition-duration} ease,
74
80
  border-color #{$transition-duration} ease,
@@ -165,7 +171,6 @@ $transition-duration: sass.fn-naming-var("motion", "duration");
165
171
  display: block;
166
172
  white-space: pre-wrap;
167
173
  word-break: break-word;
168
- padding: inherit;
169
174
  line-height: inherit;
170
175
  font-size: inherit;
171
176
  display: flex;
@@ -202,25 +207,12 @@ $transition-duration: sass.fn-naming-var("motion", "duration");
202
207
  }
203
208
 
204
209
  // Direction
205
- &.#{$field-direction-left} {
206
- .#{$field-input} {
207
- justify-content: start;
208
- text-align: left;
209
- }
210
-
211
- .#{$field-input}::before {
212
- left: 0;
213
- }
210
+ .#{$field-input} {
211
+ justify-content: #{$direction-justify-content};
212
+ text-align: #{$direction-text-align};
214
213
  }
215
214
 
216
- &.#{$field-direction-right} {
217
- .#{$field-input} {
218
- justify-content: end;
219
- text-align: right;
220
- }
221
-
222
- .#{$field-input}::before {
223
- right: 0;
224
- }
215
+ .#{$field-input}::before {
216
+ #{$direction-text-align}: 0;
225
217
  }
226
218
  }
@@ -25,3 +25,5 @@ export * from "./route";
25
25
  export * from "./page";
26
26
  export * from "./collapse";
27
27
  export * from "./form-group";
28
+ export * from "./dropdown";
29
+ export * from "./select";
@@ -0,0 +1,2 @@
1
+ export { default as Select } from "./select.vue";
2
+ export type { SelectVariant, SelectSize, SelectProps } from "./select.type";
@@ -0,0 +1,26 @@
1
+ <div v-bind="selectAttrs">
2
+ <Dropdown v-bind="dropdownAttrs">
3
+ <template #trigger="{ toggle, isOpen }">
4
+ <Field
5
+ :role="role"
6
+ variant="outline"
7
+ @click="toggle"
8
+ v-bind="fieldAttrs"
9
+ :class="{focus: isOpen}"
10
+ >
11
+ <template #end-input>
12
+ <span v-bind="selectIconAttrs" :class="{open: isOpen}"></span>
13
+ </template>
14
+ </Field>
15
+ </template>
16
+ <button
17
+ v-for="item in menuItems"
18
+ :key="item"
19
+ type="button"
20
+ class="dropdown-demo-row"
21
+ @click="pickMenu(item)"
22
+ >
23
+ {{ item }}
24
+ </button>
25
+ </Dropdown>
26
+ </div>
@@ -0,0 +1,58 @@
1
+ @use "@toife/sass-layer-generator" as sass;
2
+
3
+ // Class name
4
+ $select: sass.fn-naming-prefix("select");
5
+ $select-icon: sass.fn-naming-prefix("select-icon");
6
+ $field: sass.fn-naming-prefix("field");
7
+ $field-input: sass.fn-naming-prefix("field-input");
8
+
9
+ // Property name
10
+ $app-color: sass.fn-naming-var("app", "color");
11
+ $spacing-x: sass.fn-naming-var("spacing", "x");
12
+ $size-coefficient-x: sass.fn-naming-var("coefficient-x");
13
+ $transition-duration: sass.fn-naming-var("motion", "duration");
14
+
15
+ .#{$select} {
16
+ &.disabled {
17
+ cursor: not-allowed;
18
+ }
19
+
20
+ &.readonly {
21
+ pointer-events: none;
22
+ }
23
+
24
+ .#{$select-icon} {
25
+ display: inline-flex;
26
+ align-items: center;
27
+ justify-content: center;
28
+ flex-shrink: 0;
29
+ margin-inline-end: calc(#{$spacing-x} * #{$size-coefficient-x} * 0.5);
30
+ color: inherit;
31
+ pointer-events: none;
32
+ width: 0.6rem;
33
+ height: 0.6rem;
34
+ border-radius: 0.1rem;
35
+ border-right: 2px solid rgb(var(--t-app-color));
36
+ border-bottom: 2px solid rgb(var(--t-app-color));
37
+ margin: calc(var(--t-spacing-y) * var(--t-coefficient-y))
38
+ calc(var(--t-spacing-x) * var(--t-coefficient-x));
39
+ transition: transform #{$transition-duration} ease;
40
+ transform-origin: center;
41
+
42
+ &.open {
43
+ transform: rotate(225deg);
44
+ }
45
+
46
+ &:not(.open) {
47
+ transform: rotate(45deg);
48
+ }
49
+ }
50
+
51
+ // :deep(.#{$field}.focus .#{$select-icon} svg) {
52
+ // transform: rotate(180deg);
53
+ // }
54
+
55
+ // :deep(.#{$field-input}) {
56
+ // cursor: pointer;
57
+ // }
58
+ }
@@ -0,0 +1,32 @@
1
+ import type { FieldSize, FieldVariant } from "../field";
2
+ import type { AppDirection } from "../app";
3
+
4
+ export type SelectVariant = FieldVariant;
5
+ export type SelectSize = FieldSize;
6
+
7
+ export type SelectProps = {
8
+ // Wrapper
9
+ modelValue?: string;
10
+ name?: string;
11
+ variant?: FieldVariant;
12
+ role?: string;
13
+ shape?: string;
14
+ size?: FieldSize;
15
+ shadow?: boolean;
16
+ direction?: AppDirection;
17
+
18
+ // Input
19
+ id?: string;
20
+ value?: string;
21
+ placeholder?: string;
22
+ disabled?: boolean;
23
+ readonly?: boolean;
24
+ autocomplete?: string;
25
+ tabindex?: number | string;
26
+ line?: number | string;
27
+ maxLine?: number | string;
28
+
29
+ // Support
30
+ message?: string;
31
+ help?: string;
32
+ };
@@ -0,0 +1,89 @@
1
+ <style lang="scss" src="./select.scss" scoped></style>
2
+ <template src="./select.html"></template>
3
+ <script lang="ts" setup>
4
+ import { computed, inject } from "vue";
5
+ import { type SelectProps } from "./select.type";
6
+ import { property, withPrefix } from "../../utils";
7
+ import { type AppProviderState, APP_PROVIDER_STATE_KEY } from "../app";
8
+ import { Field } from "../field";
9
+ import { Dropdown } from "../dropdown";
10
+
11
+ // Component setup (props, emits, injects)
12
+ // ----------------------------------------------------------------------------
13
+ const props = withDefaults(defineProps<SelectProps>(), {
14
+ modelValue: "",
15
+ type: "text",
16
+ size: "standard",
17
+ disabled: false,
18
+ readonly: false,
19
+ message: "",
20
+ help: "",
21
+ variant: "outline",
22
+ placeholder: "",
23
+ shadow: undefined,
24
+ direction: undefined,
25
+ });
26
+ const appState = inject<AppProviderState>(APP_PROVIDER_STATE_KEY);
27
+
28
+ // Computed properties
29
+ // ----------------------------------------------------------------------------
30
+ const role = computed(() => {
31
+ return props.role || appState?.role.value || "";
32
+ });
33
+
34
+ const direction = computed(() => {
35
+ return props.direction || appState?.direction?.value || "left";
36
+ });
37
+
38
+ const shadow = computed(() => {
39
+ return props.shadow || appState?.shadow.value || false;
40
+ });
41
+
42
+ const shape = computed(() => {
43
+ return props.shape || appState?.shape.value || "";
44
+ });
45
+
46
+ const selectAttrs = computed(() => {
47
+ return {
48
+ class: [
49
+ withPrefix(["layer", "select"]),
50
+ withPrefix("select"),
51
+ {
52
+ disabled: props.disabled,
53
+ readonly: props.readonly,
54
+ },
55
+ ],
56
+ };
57
+ });
58
+
59
+ const dropdownAttrs = computed(() => {
60
+ return {
61
+ role: role.value,
62
+ direction: direction.value,
63
+ shadow: shadow.value,
64
+ shape: shape.value,
65
+ disabled: props.disabled,
66
+ readonly: props.readonly,
67
+ };
68
+ });
69
+
70
+ const fieldAttrs = computed(() => {
71
+ return {
72
+ modelValue: props.modelValue,
73
+ size: props.size,
74
+ message: props.message,
75
+ help: props.help,
76
+ variant: props.variant,
77
+ placeholder: props.placeholder,
78
+ direction: direction.value,
79
+ role: role.value,
80
+ shape: shape.value,
81
+ readonly: true,
82
+ shadow: shadow.value,
83
+ };
84
+ });
85
+
86
+ const selectIconAttrs = computed(() => ({
87
+ class: [withPrefix("select-icon")],
88
+ }));
89
+ </script>
package/src/factory.ts CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  Container,
14
14
  DecisionModal,
15
15
  Divider,
16
+ Dropdown,
16
17
  Field,
17
18
  FormGroup,
18
19
  GestureIndicator,
@@ -28,6 +29,7 @@ import {
28
29
  RouteProvider,
29
30
  RouteOutlet,
30
31
  SegmentedField,
32
+ Select,
31
33
  Skeleton,
32
34
  Switch,
33
35
  Tab,
@@ -59,6 +61,7 @@ export const createToife = (options?: CreateToifeOptions) => {
59
61
  app.component(prefix + "container", Container);
60
62
  app.component(prefix + "decision-modal", DecisionModal);
61
63
  app.component(prefix + "divider", Divider);
64
+ app.component(prefix + "dropdown", Dropdown);
62
65
  app.component(prefix + "field", Field);
63
66
  app.component(prefix + "form-group", FormGroup);
64
67
  app.component(prefix + "gesture-indicator", GestureIndicator);
@@ -72,6 +75,7 @@ export const createToife = (options?: CreateToifeOptions) => {
72
75
  app.component(prefix + "route-provider", RouteProvider);
73
76
  app.component(prefix + "route-outlet", RouteOutlet);
74
77
  app.component(prefix + "segmented-field", SegmentedField);
78
+ app.component(prefix + "select", Select);
75
79
  app.component(prefix + "skeleton", Skeleton);
76
80
  app.component(prefix + "switch", Switch);
77
81
  app.component(prefix + "tab", Tab);