@energie360/ui-library 0.1.4 → 0.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 (48) hide show
  1. package/components/card/card.scss +2 -25
  2. package/components/card-footer/card-footer.scss +5 -0
  3. package/components/card-footer/u-card-footer.vue +52 -0
  4. package/components/card-group/card-group.scss +29 -0
  5. package/components/card-group/u-card-group.vue +66 -0
  6. package/components/card-header/card-header.scss +1 -5
  7. package/components/card-section/card-section.scss +13 -0
  8. package/components/card-section/u-card-section.vue +7 -0
  9. package/components/tabs/tabs.scss +88 -0
  10. package/components/tabs/u-tabs.vue +140 -0
  11. package/dist/layout/split.css +6 -0
  12. package/dist/layout/split.css.map +1 -1
  13. package/elements/button/_button-base.scss +1 -1
  14. package/elements/form-field/form-field-base.scss +1 -1
  15. package/elements/icon-button/_icon-button-base.scss +1 -4
  16. package/elements/radio/index.js +1 -0
  17. package/elements/radio/radio.scss +7 -0
  18. package/elements/radio/u-radio.vue +33 -0
  19. package/elements/radio-group/index.js +1 -0
  20. package/elements/radio-group/radio-group-composables.ts +38 -0
  21. package/elements/radio-group/radio-group.scss +3 -0
  22. package/elements/radio-group/u-radio-group.vue +15 -0
  23. package/elements/select-chip/u-select-chip.vue +15 -21
  24. package/elements/select-chips/u-select-chips.vue +5 -8
  25. package/i18n/i18n.ts +5 -0
  26. package/layout/split/split.scss +5 -0
  27. package/modules/feedback/feedback-animations.scss +32 -0
  28. package/modules/feedback/feedback-form.scss +12 -0
  29. package/modules/feedback/feedback-vote-buttons.scss +73 -0
  30. package/modules/feedback/feedback.scss +31 -0
  31. package/modules/feedback/types/feedback.type.ts +33 -0
  32. package/modules/feedback/u-feedback-close.vue +32 -0
  33. package/modules/feedback/u-feedback-finish-view.vue +31 -0
  34. package/modules/feedback/u-feedback-form.vue +16 -0
  35. package/modules/feedback/u-feedback-vote-buttons.vue +59 -0
  36. package/modules/feedback/u-feedback.vue +58 -0
  37. package/modules/footer/footer.scss +13 -16
  38. package/modules/footer/u-footer.vue +4 -10
  39. package/package.json +3 -2
  40. package/utils/dom/dom.js +167 -0
  41. package/utils/functions/breakpoint.js +11 -0
  42. package/utils/functions/debounce.js +25 -0
  43. package/base-style.js +0 -1
  44. package/components/icon-teaser/icon-teaser.scss +0 -58
  45. package/components/icon-teaser/u-icon-teaser.vue +0 -35
  46. package/components/icon-teaser-group/icon-teaser-group.scss +0 -10
  47. package/components/icon-teaser-group/u-icon-teaser-group.vue +0 -19
  48. package/utility/utility-text.js +0 -1
@@ -26,33 +26,10 @@
26
26
  }
27
27
 
28
28
  // LAYOUT
29
- .card-header,
30
- .card-section,
31
- .card-footer {
32
- padding: var(--e-space-6);
33
-
34
- @include a.bp(m) {
35
- padding: var(--e-space-5);
36
- }
37
-
38
- @include a.bp(s) {
39
- padding: var(--e-space-4);
40
- }
41
- }
42
-
43
- .card-footer {
44
- display: flex;
45
- flex-direction: column;
46
- gap: var(--e-space-4);
47
- }
48
-
49
- .card-section:last-child:has(.card-hint),
50
- .card-footer {
29
+ .card-section:last-child:has(.card-hint, .card-footer) {
51
30
  margin-top: auto; // Make this element stick to bottom of the card.
52
31
  }
53
32
 
54
- .card-header + *,
55
- .card-section + .card-section,
56
- * + .card-footer {
33
+ .card-section + .card-section {
57
34
  border-top: 1px solid var(--e-c-mono-200);
58
35
  }
@@ -0,0 +1,5 @@
1
+ .card-footer {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--e-space-4);
5
+ }
@@ -0,0 +1,52 @@
1
+ <script setup lang="ts">
2
+ import { inject, watch, onMounted } from 'vue'
3
+ import UButton from '../../elements/button/u-button.vue'
4
+ import USelectChip from '../../elements/select-chip/u-select-chip.vue'
5
+
6
+ interface Link {
7
+ label: string
8
+ href?: string
9
+ target?: string
10
+ }
11
+
12
+ interface Radio {
13
+ label: string
14
+ name?: string
15
+ value?: string
16
+ }
17
+
18
+ interface Props {
19
+ cta: Radio | Link
20
+ }
21
+
22
+ const { cta } = defineProps<Props>()
23
+
24
+ const { toggleActiveCard } = inject('card')
25
+ const { currentValue } = inject('card-group', {})
26
+
27
+ const onChange = () => {
28
+ toggleActiveCard(true)
29
+ }
30
+
31
+ if (currentValue) {
32
+ watch(currentValue, (newV) => {
33
+ toggleActiveCard(newV === cta.value)
34
+ })
35
+
36
+ onMounted(() => {
37
+ if (currentValue?.value) {
38
+ toggleActiveCard(currentValue.value === cta.value)
39
+ }
40
+ })
41
+ }
42
+ </script>
43
+
44
+ <template>
45
+ <div class="card-footer">
46
+ <UButton v-if="cta.href" variant="outlined" v-bind="cta" />
47
+
48
+ <USelectChip v-else provide-key="card-group" v-bind="cta" @change="onChange" />
49
+ </div>
50
+ </template>
51
+
52
+ <style lang="scss" src="./card-footer.scss"></style>
@@ -0,0 +1,29 @@
1
+ @use '../../base/abstracts/' as a;
2
+
3
+ .card-group {
4
+ display: grid;
5
+ gap: var(--e-space-5);
6
+
7
+ // >= 3 card items
8
+ grid-template-columns: repeat(3, 1fr);
9
+ grid-template-rows: 1fr;
10
+
11
+ // 1 card item
12
+ &:has(> :last-child:nth-child(1)) {
13
+ grid-template-columns: repeat(1, 1fr);
14
+ grid-template-rows: 1fr;
15
+ }
16
+
17
+ // 2 card items
18
+ &:has(> :last-child:nth-child(2)) {
19
+ grid-template-columns: repeat(2, 1fr);
20
+ grid-template-rows: 1fr;
21
+ }
22
+
23
+ @include a.bp(lg) {
24
+ &:has(> :last-child:nth-child(n)) {
25
+ grid-template-columns: repeat(1, 1fr);
26
+ grid-template-rows: 1fr;
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,66 @@
1
+ <script setup lang="ts">
2
+ import { onMounted, onUnmounted, useTemplateRef } from 'vue'
3
+ import { debounceRaf } from '../../utils/functions/debounce'
4
+ import { isLarge } from '../../utils/functions/breakpoint'
5
+ import { useRadioGroup } from '../../elements/radio-group/radio-group-composables'
6
+
7
+ const model = defineModel<string>()
8
+
9
+ const group = useTemplateRef('group')
10
+
11
+ const onResize = debounceRaf(() => {
12
+ const headers = Array.from(group.value.querySelectorAll('.card-header'))
13
+
14
+ if (headers.length < 2) {
15
+ // We don't need this logic for just one card.
16
+ return
17
+ }
18
+
19
+ // Reset heights
20
+ headers.forEach((header) => {
21
+ header.style.height = ''
22
+ })
23
+
24
+ if (isLarge().matches) {
25
+ // Cards are stacked now. No need to set height.
26
+ return
27
+ }
28
+
29
+ // Get max height
30
+ const maxHeight = headers.reduce((acc, val) => {
31
+ return Math.max(acc, val.offsetHeight)
32
+ }, 0)
33
+
34
+ // Adjust heights
35
+ headers.forEach((header) => {
36
+ header.style.height = `${maxHeight}px`
37
+ })
38
+ })
39
+
40
+ onMounted(() => {
41
+ // Wait for webfonts to be ready (and rendered) to avoid calculating with 'wrong' font.
42
+ document.fonts.ready.then(() => {
43
+ window.addEventListener('resize', onResize)
44
+
45
+ // Initial state
46
+ onResize()
47
+ })
48
+ })
49
+
50
+ onUnmounted(() => {
51
+ window.removeEventListener('resize', onResize)
52
+ })
53
+
54
+ useRadioGroup({
55
+ model,
56
+ provideKey: 'card-group',
57
+ })
58
+ </script>
59
+
60
+ <template>
61
+ <div ref="group" class="card-group">
62
+ <slot></slot>
63
+ </div>
64
+ </template>
65
+
66
+ <style lang="scss" src="./card-group.scss"></style>
@@ -3,12 +3,8 @@
3
3
  $image-col-width: 112px;
4
4
  $image-col-width-small: 100px;
5
5
 
6
- :host {
7
- display: block;
8
- container: card / inline-size;
9
- }
10
-
11
6
  .card-header {
7
+ container: card / inline-size;
12
8
  position: relative;
13
9
  display: flex;
14
10
  column-gap: var(--e-space-2);
@@ -0,0 +1,13 @@
1
+ @use '../../base/abstracts/' as a;
2
+
3
+ .card-section {
4
+ padding: var(--e-space-6);
5
+
6
+ @include a.bp(m) {
7
+ padding: var(--e-space-5);
8
+ }
9
+
10
+ @include a.bp(s) {
11
+ padding: var(--e-space-4);
12
+ }
13
+ }
@@ -0,0 +1,7 @@
1
+ <template>
2
+ <div class="card-section">
3
+ <slot></slot>
4
+ </div>
5
+ </template>
6
+
7
+ <style lang="scss" src="./card-section.scss"></style>
@@ -0,0 +1,88 @@
1
+ @use '../../base/abstracts/' as a;
2
+
3
+ .tabs {
4
+ $scroll-space: 18px;
5
+
6
+ position: relative;
7
+
8
+ &::before {
9
+ content: '';
10
+ position: absolute;
11
+ bottom: 0;
12
+ left: 0;
13
+ width: 100%;
14
+ height: 1px;
15
+ background-color: var(--e-c-mono-100);
16
+ }
17
+
18
+ .tabs__wrapper {
19
+ position: relative;
20
+ width: 100%;
21
+ height: calc(100% + #{$scroll-space});
22
+
23
+ &::after {
24
+ content: '';
25
+ pointer-events: none;
26
+ position: absolute;
27
+ top: 0;
28
+ right: 0;
29
+ width: 30px;
30
+ height: calc(100% - #{$scroll-space} - 1px);
31
+ background: linear-gradient(270deg, #fff 0%, rgb(255 255 255 / 0%) 100%);
32
+ }
33
+ }
34
+
35
+ .tabs__row {
36
+ display: flex;
37
+ }
38
+
39
+ .tabs__col {
40
+ flex: 0 0 100%;
41
+ max-width: 100%;
42
+ }
43
+
44
+ .tabs__list {
45
+ position: relative;
46
+ display: flex;
47
+ align-items: flex-start;
48
+ height: 100%;
49
+ flex-wrap: nowrap;
50
+ overflow: auto;
51
+
52
+ a,
53
+ button {
54
+ @include a.type(200, strong);
55
+
56
+ display: block;
57
+ padding: var(--e-space-4);
58
+ text-decoration: none;
59
+ color: var(--e-c-mono-700);
60
+ transition: color a.$trs-default;
61
+ white-space: nowrap;
62
+ outline-offset: -4px;
63
+ cursor: pointer;
64
+
65
+ &.active,
66
+ &:focus,
67
+ &:hover {
68
+ color: var(--e-c-primary-01-700);
69
+ }
70
+
71
+ @include a.bp(lg) {
72
+ @include a.type(100, strong);
73
+
74
+ padding: var(--e-space-2) var(--e-space-3);
75
+ }
76
+ }
77
+ }
78
+
79
+ .tabs__active-bar {
80
+ position: absolute;
81
+ bottom: #{$scroll-space};
82
+ height: 2px;
83
+ background-color: var(--e-c-primary-01-200);
84
+ transition:
85
+ left a.$trs-default,
86
+ width a.$trs-default;
87
+ }
88
+ }
@@ -0,0 +1,140 @@
1
+ <script setup lang="ts">
2
+ import { useTemplateRef, ref, watch } from 'vue'
3
+ import { getOffsetParentPosition } from '../../utils/dom/dom'
4
+ import { debounce } from '../../utils/functions/debounce'
5
+
6
+ interface Tab {
7
+ label: string
8
+ value: string
9
+ }
10
+
11
+ interface Props {
12
+ activation?: 'manual' | 'automatic'
13
+ items: Tab[]
14
+ }
15
+
16
+ const { activation = 'manual' } = defineProps<Props>()
17
+ const emit = defineEmits<{ (e: 'tabFocus', id: string): void }>()
18
+
19
+ const model = defineModel<string>()
20
+ const activeBarStyles = ref({})
21
+
22
+ const tabs = useTemplateRef('tabs')
23
+ const list = useTemplateRef('list')
24
+
25
+ const ARROW_LEFT = 'ArrowLeft'
26
+ const ARROW_RIGHT = 'ArrowRight'
27
+ const ARROW_DOWN = 'ArrowDown'
28
+ const ARROW_UP = 'ArrowUp'
29
+
30
+ const onTabClick = (e) => {
31
+ e.preventDefault()
32
+
33
+ // Mark active tab
34
+ model.value = e.target.value
35
+
36
+ positionActiveBar()
37
+ }
38
+
39
+ const onTabKeyDown = (e) => {
40
+ let focusTabIndex: number
41
+ const currentIndex = tabs.value.findIndex((tab) => tab === e.target)
42
+
43
+ if (e.code === ARROW_RIGHT || e.code === ARROW_UP) {
44
+ e.stopPropagation()
45
+ e.preventDefault()
46
+
47
+ focusTabIndex = currentIndex + 1
48
+
49
+ if (focusTabIndex > tabs.value.length - 1) {
50
+ focusTabIndex = 0
51
+ }
52
+
53
+ tabs.value[focusTabIndex].focus()
54
+ emit('tabFocus', tabs.value[focusTabIndex].value)
55
+
56
+ if (activation === 'automatic') {
57
+ tabs.value[focusTabIndex].click()
58
+ }
59
+
60
+ return
61
+ }
62
+
63
+ if (e.code === ARROW_LEFT || e.code === ARROW_DOWN) {
64
+ e.stopPropagation()
65
+ e.preventDefault()
66
+
67
+ focusTabIndex = currentIndex - 1
68
+
69
+ if (focusTabIndex < 0) {
70
+ focusTabIndex = tabs.value.length - 1
71
+ }
72
+
73
+ tabs.value[focusTabIndex].focus()
74
+ emit('tabFocus', tabs.value[focusTabIndex].value)
75
+
76
+ if (activation === 'automatic') {
77
+ tabs.value[focusTabIndex].click()
78
+ }
79
+ }
80
+ }
81
+
82
+ const onResize = debounce(() => {
83
+ positionActiveBar()
84
+ }, 80)
85
+
86
+ const isActiveTab = (currentTabId: string) => currentTabId === model.value
87
+
88
+ const positionActiveBar = () => {
89
+ const activeTabEl = tabs.value.find((item) => item.value === model.value)
90
+ const activeTabRelPos = getOffsetParentPosition(activeTabEl)
91
+
92
+ activeBarStyles.value = {
93
+ width: `${activeTabEl.offsetWidth}px`,
94
+ left: `${activeTabRelPos.left + list.value.scrollLeft}px`,
95
+ }
96
+ }
97
+
98
+ watch(model, () => {
99
+ onResize()
100
+ })
101
+
102
+ window.addEventListener('resize', onResize)
103
+
104
+ // Initial state
105
+ onResize()
106
+ </script>
107
+
108
+ <template>
109
+ <div class="tabs">
110
+ <div class="tabs__row">
111
+ <div class="tabs__col">
112
+ <div class="tabs__wrapper">
113
+ <div ref="list" class="tabs__list" role="tablist">
114
+ <button
115
+ v-for="(item, idx) in items"
116
+ :key="idx"
117
+ ref="tabs"
118
+ :class="{ active: isActiveTab(item.value) }"
119
+ :value="item.value"
120
+ type="button"
121
+ role="tab"
122
+ :tabindex="isActiveTab(item.value) ? 0 : -1"
123
+ :aria-selected="isActiveTab(item.value)"
124
+ @click="onTabClick"
125
+ @keydown="onTabKeyDown"
126
+ >
127
+ {{ item.label }}
128
+ </button>
129
+
130
+ <div class="tabs__active-bar" :style="activeBarStyles"></div>
131
+ </div>
132
+ </div>
133
+ </div>
134
+ </div>
135
+ </div>
136
+ </template>
137
+
138
+ <style lang="scss">
139
+ @use './tabs.scss';
140
+ </style>
@@ -27,7 +27,10 @@
27
27
 
28
28
  .split {
29
29
  position: relative;
30
+ display: flex;
31
+ flex-direction: column;
30
32
  padding-left: 50%;
33
+ min-height: 100vh;
31
34
  }
32
35
  @media (max-width: 1020px) {
33
36
  .split {
@@ -110,6 +113,9 @@
110
113
  }
111
114
  }
112
115
 
116
+ .split__footer {
117
+ margin-top: auto;
118
+ }
113
119
  @media (max-width: 1020px) {
114
120
  .split__footer {
115
121
  grid-area: footer;
@@ -1 +1 @@
1
- {"version":3,"sourceRoot":"","sources":["../../base/abstracts/_functions.scss","../../layout/container/container.scss","../../base/abstracts/_mixins.scss","../../layout/split/split.scss"],"names":[],"mappings":"AAKA;ACsBA;EAtBE;EACA;EACA;EACA;EACA;;ACYA;EDMF;IAfI;IACA;;;ACQF;EDMF;IAVI;IACA;;;ACGF;EDMF;IALI;IACA;;;;AEjBJ;EACE;EACA;;ADaA;ECfF;IAKI;IACA;IACA;IACA;IACA;IACA,qBACE;;;ADIJ;ECfF;IAgBI;IACA;;;;AAIJ;EACE;EACA;;ADRA;ECMF;IAKI;IACA;;;ADZF;ECMF;IAUI;IACA;IACA;;;;AAIJ;EACE;;ADvBA;ECsBF;IAII;IACA;;;AD3BF;ECsBF;IASI;;;;AAIJ;EACE;EACA;EACA;EACA;;ADvCA;ECmCF;IAOI;IAIA;IACA;;;AD/CF;ECmCF;IAgBI;IACA;IACA;IACA;IACA;IACA;;;ADxDF;ECmCF;IAyBI;IACA;IACA;;;;AD9DF;ECkEF;IAEI;;;ADpEF;ECkEF;IAMI","file":"split.css"}
1
+ {"version":3,"sourceRoot":"","sources":["../../base/abstracts/_functions.scss","../../layout/container/container.scss","../../base/abstracts/_mixins.scss","../../layout/split/split.scss"],"names":[],"mappings":"AAKA;ACsBA;EAtBE;EACA;EACA;EACA;EACA;;ACYA;EDMF;IAfI;IACA;;;ACQF;EDMF;IAVI;IACA;;;ACGF;EDMF;IALI;IACA;;;;AEjBJ;EACE;EACA;EACA;EACA;EACA;;ADUA;ECfF;IAQI;IACA;IACA;IACA;IACA;IACA,qBACE;;;ADCJ;ECfF;IAmBI;IACA;;;;AAIJ;EACE;EACA;;ADXA;ECSF;IAKI;IACA;;;ADfF;ECSF;IAUI;IACA;IACA;;;;AAIJ;EACE;;AD1BA;ECyBF;IAII;IACA;;;AD9BF;ECyBF;IASI;;;;AAIJ;EACE;EACA;EACA;EACA;;AD1CA;ECsCF;IAOI;IAIA;IACA;;;ADlDF;ECsCF;IAgBI;IACA;IACA;IACA;IACA;IACA;;;AD3DF;ECsCF;IAyBI;IACA;IACA;;;;AAIJ;EACE;;ADtEA;ECqEF;IAII;;;ADzEF;ECqEF;IAQI","file":"split.css"}
@@ -35,7 +35,7 @@
35
35
 
36
36
  &.disabled,
37
37
  &:disabled {
38
- pointer-events: none;
38
+ cursor: not-allowed;
39
39
  }
40
40
 
41
41
  &.loading {
@@ -50,7 +50,7 @@
50
50
  }
51
51
 
52
52
  .control-border {
53
- z-index: -1;
53
+ z-index: 0;
54
54
  pointer-events: none;
55
55
  position: absolute;
56
56
  top: 0;
@@ -17,9 +17,6 @@ $icon-button-size: 48px;
17
17
  height: a.rem($icon-button-size);
18
18
  border-radius: 100%;
19
19
  color: transparent;
20
-
21
- // Pointer should only be used for actual 'links'.
22
- // And buttons shouldn't have a pointer cursor. But it seems people still want this.
23
20
  cursor: pointer;
24
21
 
25
22
  .icon,
@@ -54,6 +51,6 @@ $icon-button-size: 48px;
54
51
  }
55
52
 
56
53
  &:disabled {
57
- cursor: default;
54
+ cursor: not-allowed;
58
55
  }
59
56
  }
@@ -0,0 +1 @@
1
+ export { default as URadio } from './u-radio.vue'
@@ -0,0 +1,7 @@
1
+ .radio {
2
+ display: block;
3
+ }
4
+
5
+ .radio__control {
6
+ appearance: radio;
7
+ }
@@ -0,0 +1,33 @@
1
+ <script setup lang="ts">
2
+ import { useRadio } from '../radio-group/radio-group-composables'
3
+
4
+ interface Props {
5
+ label: string
6
+ name?: string
7
+ value: string | number
8
+ disabled?: boolean
9
+ }
10
+
11
+ defineProps<Props>()
12
+
13
+ const model = defineModel<string>()
14
+
15
+ const { onChange } = useRadio({ model })
16
+ </script>
17
+
18
+ <template>
19
+ <div class="radio">
20
+ <label>{{ label }}</label>
21
+ <input
22
+ v-model="model"
23
+ class="radio__control"
24
+ type="radio"
25
+ :name
26
+ :value
27
+ :disabled
28
+ @change="onChange"
29
+ />
30
+ </div>
31
+ </template>
32
+
33
+ <style lang="scss" src="./radio.scss"></style>
@@ -0,0 +1 @@
1
+ export { default as URadioGroup } from './u-radio-group.vue'
@@ -0,0 +1,38 @@
1
+ import { provide, ref, watch, inject, onMounted } from 'vue'
2
+
3
+ export const useRadioGroup = ({ model, provideKey = 'radio-group' }) => {
4
+ const currentValue = ref(model)
5
+
6
+ const updateValue = (value) => {
7
+ model.value = value
8
+ }
9
+
10
+ provide(provideKey, {
11
+ updateValue,
12
+ currentValue,
13
+ })
14
+ }
15
+
16
+ export const useRadio = ({ model, provideKey = 'radio-group' }) => {
17
+ const { updateValue, currentValue } = inject(provideKey, {})
18
+
19
+ const onChange = (e) => {
20
+ if (updateValue) {
21
+ updateValue(e.target.value)
22
+ }
23
+ }
24
+
25
+ if (currentValue) {
26
+ watch(currentValue, (newV) => {
27
+ model.value = newV
28
+ })
29
+
30
+ onMounted(() => {
31
+ if (currentValue) {
32
+ model.value = currentValue.value
33
+ }
34
+ })
35
+ }
36
+
37
+ return { onChange }
38
+ }
@@ -0,0 +1,3 @@
1
+ .radio-group {
2
+ display: block;
3
+ }
@@ -0,0 +1,15 @@
1
+ <script setup lang="ts">
2
+ import { useRadioGroup } from './radio-group-composables'
3
+
4
+ const model = defineModel<string>()
5
+
6
+ useRadioGroup({ model })
7
+ </script>
8
+
9
+ <template>
10
+ <div class="radio-group">
11
+ <slot></slot>
12
+ </div>
13
+ </template>
14
+
15
+ <style lang="scss" src="./radio-group.scss"></style>
@@ -1,41 +1,35 @@
1
1
  <script setup lang="ts">
2
2
  import UIcon from '../icon/u-icon.vue'
3
- import { computed, inject, useId, watch } from 'vue'
3
+ import { useRadio } from '../radio-group/radio-group-composables'
4
+ import { computed } from 'vue'
4
5
 
5
6
  interface Props {
6
7
  name: string
7
8
  label?: string
8
9
  disabled?: boolean
9
10
  value?: string
11
+ provideKey?: string
10
12
  }
11
- const { name, disabled = false, value = '' } = defineProps<Props>()
12
- const cId = useId()
13
+ const {
14
+ name,
15
+ disabled = false,
16
+ value = '',
17
+ provideKey = 'select-chip-group',
18
+ } = defineProps<Props>()
13
19
 
14
- const model = defineModel<boolean>({ default: false })
20
+ const model = defineModel<string>()
15
21
 
16
- const { activeSelectChip, updateActiveSelectChip } = inject('select-chip-group', {})
22
+ const { onChange } = useRadio({ model, provideKey })
17
23
 
18
- const onChange = () => {
19
- if (updateActiveSelectChip) {
20
- updateActiveSelectChip(cId)
21
- }
22
- }
23
-
24
- if (activeSelectChip) {
25
- watch(activeSelectChip, (newV) => {
26
- if (newV !== cId) {
27
- model.value = false
28
- }
29
- })
30
- }
31
-
32
- const classes = computed(() => (disabled ? 'disabled' : model.value ? 'filled' : 'outlined'))
24
+ const classes = computed(() =>
25
+ disabled ? 'disabled' : model.value === value ? 'filled' : 'outlined',
26
+ )
33
27
  </script>
34
28
 
35
29
  <template>
36
30
  <div class="select-chip">
37
31
  <label :class="classes" class="select-chip__button button">
38
- <UIcon v-if="model" name="mini-check"></UIcon>
32
+ <UIcon v-if="model === value" name="mini-check"></UIcon>
39
33
  {{ label }}
40
34
 
41
35
  <slot>