webcake-ui-kit 1.0.0 → 1.0.2

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 (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +358 -8
  3. package/package.json +68 -5
  4. package/src/components/accordion/Accordion.vue +70 -0
  5. package/src/components/accordion/accordion.css +5 -0
  6. package/src/components/accordion-item/AccordionItem.vue +98 -0
  7. package/src/components/accordion-item/accordion-item.css +143 -0
  8. package/src/components/alert-dialog/AlertDialog.vue +82 -0
  9. package/src/components/alert-dialog/alert-dialog.css +33 -0
  10. package/src/components/badge/Badge.vue +2 -2
  11. package/src/components/badge/badge.css +1 -4
  12. package/src/components/breadcrumb/Breadcrumb.vue +85 -0
  13. package/src/components/breadcrumb/breadcrumb.css +90 -0
  14. package/src/components/button/Button.vue +77 -10
  15. package/src/components/button/button.css +258 -24
  16. package/src/components/button-group/ButtonGroup.vue +25 -0
  17. package/src/components/button-group/button-group.css +30 -0
  18. package/src/components/checkbox/Checkbox.vue +55 -0
  19. package/src/components/checkbox/checkbox.css +86 -0
  20. package/src/components/checkbox-group/CheckboxGroup.vue +50 -0
  21. package/src/components/checkbox-group/checkbox-group.css +35 -0
  22. package/src/components/dialog/Dialog.vue +355 -0
  23. package/src/components/dialog/dialog.css +255 -0
  24. package/src/components/divider/Divider.vue +35 -0
  25. package/src/components/divider/divider.css +38 -0
  26. package/src/components/input/Input.vue +99 -0
  27. package/src/components/input/input.css +123 -0
  28. package/src/components/pagination/Pagination.vue +211 -0
  29. package/src/components/pagination/pagination.css +13 -0
  30. package/src/components/radio/Radio.vue +74 -0
  31. package/src/components/radio/radio.css +89 -0
  32. package/src/components/radio-group/RadioGroup.vue +70 -0
  33. package/src/components/radio-group/radio_group.css +11 -0
  34. package/src/components/rich-checkbox-group/RichCheckboxGroup.vue +59 -0
  35. package/src/components/rich-checkbox-group/rich-checkbox-group.css +54 -0
  36. package/src/components/rich-switch-group/RichSwitchGroup.vue +49 -0
  37. package/src/components/rich-switch-group/rich_switch_group.css +45 -0
  38. package/src/components/select/Select.vue +262 -0
  39. package/src/components/select/select.css +207 -0
  40. package/src/components/select-option/SelectOption.vue +82 -0
  41. package/src/components/select-option/select_option.css +60 -0
  42. package/src/components/sidebar-group-label/SidebarGroupLabel.vue +68 -0
  43. package/src/components/sidebar-group-label/sidebar_group_label.css +61 -0
  44. package/src/components/sidebar-item/SidebarItem.vue +110 -0
  45. package/src/components/sidebar-item/sidebar_item.css +142 -0
  46. package/src/components/slider/Slider.vue +255 -0
  47. package/src/components/slider/slider.css +89 -0
  48. package/src/components/spinner/Spinner.vue +47 -0
  49. package/src/components/spinner/spinner.css +48 -0
  50. package/src/components/switch/Switch.vue +32 -0
  51. package/src/components/switch/switch.css +46 -0
  52. package/src/components/switch-group/SwitchGroup.vue +32 -0
  53. package/src/components/switch-group/switch_group.css +28 -0
  54. package/src/components/tabs/Tabs.vue +57 -0
  55. package/src/components/tabs/tabs.css +118 -0
  56. package/src/components/tag/Tag.vue +47 -0
  57. package/src/components/tag/tag.css +115 -0
  58. package/src/components/toggle/Toggle.vue +112 -0
  59. package/src/components/toggle/toggle.css +174 -0
  60. package/src/components/toggle-group/ToggleGroup.vue +57 -0
  61. package/src/components/toggle-group/toggle-group.css +68 -0
  62. package/src/icons/LoaderIcon.vue +22 -0
  63. package/src/index.js +29 -2
  64. package/src/styles/.omc/state/agent-replay-645326b7-372b-463d-ab45-0adaafe31a51.jsonl +2 -0
  65. package/src/styles/.omc/state/subagent-tracking.json +7 -0
  66. package/src/styles/alpha_colors.css +35 -37
  67. package/src/styles/border_radius.css +21 -23
  68. package/src/styles/brand_colors.css +37 -39
  69. package/src/styles/chart_colors.css +27 -29
  70. package/src/styles/color_general.css +206 -201
  71. package/src/styles/raw_colors.css +267 -269
  72. package/src/styles/shadow.css +10 -12
  73. package/src/styles/spacing.css +31 -33
  74. package/src/styles/typography.css +76 -78
@@ -0,0 +1,255 @@
1
+ <template>
2
+ <div
3
+ class="ui-slider"
4
+ :class="{
5
+ 'ui-slider--vertical': orientation === 'vertical',
6
+ 'ui-slider--disabled': disabled,
7
+ 'ui-slider--range': range
8
+ }"
9
+ >
10
+ <div class="ui-slider__track" ref="track" @click="onTrackClick">
11
+ <div class="ui-slider__fill" :style="fillStyle" />
12
+ <div
13
+ v-if="!range"
14
+ class="ui-slider__thumb"
15
+ role="slider"
16
+ tabindex="0"
17
+ :aria-valuemin="min"
18
+ :aria-valuemax="max"
19
+ :aria-valuenow="localValue"
20
+ :aria-orientation="orientation"
21
+ :style="thumbStyle(localValue)"
22
+ @mousedown.prevent="startDrag('single', $event)"
23
+ @touchstart.prevent="startDragTouch('single', $event)"
24
+ @keydown="onKeydown('single', $event)"
25
+ @click.stop
26
+ />
27
+ <template v-if="range">
28
+ <div
29
+ class="ui-slider__thumb"
30
+ role="slider"
31
+ tabindex="0"
32
+ :aria-valuemin="min"
33
+ :aria-valuemax="localRangeMax"
34
+ :aria-valuenow="localRangeMin"
35
+ :aria-orientation="orientation"
36
+ :style="thumbStyle(localRangeMin)"
37
+ @mousedown.prevent="startDrag('min', $event)"
38
+ @touchstart.prevent="startDragTouch('min', $event)"
39
+ @keydown="onKeydown('min', $event)"
40
+ @click.stop
41
+ />
42
+ <div
43
+ class="ui-slider__thumb"
44
+ role="slider"
45
+ tabindex="0"
46
+ :aria-valuemin="localRangeMin"
47
+ :aria-valuemax="max"
48
+ :aria-valuenow="localRangeMax"
49
+ :aria-orientation="orientation"
50
+ :style="thumbStyle(localRangeMax)"
51
+ @mousedown.prevent="startDrag('max', $event)"
52
+ @touchstart.prevent="startDragTouch('max', $event)"
53
+ @keydown="onKeydown('max', $event)"
54
+ @click.stop
55
+ />
56
+ </template>
57
+ </div>
58
+ </div>
59
+ </template>
60
+
61
+ <script>
62
+ export default {
63
+ name: 'Slider',
64
+ props: {
65
+ value: { type: Number, default: 50 },
66
+ rangeValue: {
67
+ type: Array,
68
+ default: function () {
69
+ return [25, 75]
70
+ }
71
+ },
72
+ min: { type: Number, default: 0 },
73
+ max: { type: Number, default: 100 },
74
+ step: { type: Number, default: 1 },
75
+ range: { type: Boolean, default: false },
76
+ orientation: {
77
+ type: String,
78
+ default: 'horizontal',
79
+ validator: function (v) {
80
+ return ['horizontal', 'vertical'].indexOf(v) !== -1
81
+ }
82
+ },
83
+ disabled: { type: Boolean, default: false }
84
+ },
85
+ emits: ['change', 'input'],
86
+ data: function () {
87
+ return {
88
+ localValue: this.value,
89
+ localRangeMin: Array.isArray(this.rangeValue) ? this.rangeValue[0] : 25,
90
+ localRangeMax: Array.isArray(this.rangeValue) ? this.rangeValue[1] : 75,
91
+ dragging: null,
92
+ boundMouseMove: null,
93
+ boundMouseUp: null,
94
+ boundTouchMove: null,
95
+ boundTouchEnd: null
96
+ }
97
+ },
98
+ watch: {
99
+ value: function (v) {
100
+ this.localValue = v
101
+ },
102
+ rangeValue: function (v) {
103
+ if (Array.isArray(v)) {
104
+ this.localRangeMin = v[0]
105
+ this.localRangeMax = v[1]
106
+ }
107
+ }
108
+ },
109
+ computed: {
110
+ fillStyle: function () {
111
+ var minPct = (this.localRangeMin - this.min) / (this.max - this.min)
112
+ var maxPct = (this.localRangeMax - this.min) / (this.max - this.min)
113
+ var valPct = (this.localValue - this.min) / (this.max - this.min)
114
+ if (this.orientation === 'vertical') {
115
+ if (this.range) {
116
+ return { bottom: minPct * 100 + '%', height: (maxPct - minPct) * 100 + '%' }
117
+ }
118
+ return { bottom: '0%', height: valPct * 100 + '%' }
119
+ }
120
+ if (this.range) {
121
+ return { left: minPct * 100 + '%', width: (maxPct - minPct) * 100 + '%' }
122
+ }
123
+ return { left: '0%', width: valPct * 100 + '%' }
124
+ }
125
+ },
126
+ created: function () {
127
+ this.boundMouseMove = this.onMouseMove.bind(this)
128
+ this.boundMouseUp = this.stopDrag.bind(this)
129
+ this.boundTouchMove = this.onTouchMove.bind(this)
130
+ this.boundTouchEnd = this.stopDrag.bind(this)
131
+ },
132
+ beforeUnmount: function () {
133
+ this.cleanup()
134
+ },
135
+ methods: {
136
+ cleanup: function () {
137
+ document.removeEventListener('mousemove', this.boundMouseMove)
138
+ document.removeEventListener('mouseup', this.boundMouseUp)
139
+ document.removeEventListener('touchmove', this.boundTouchMove)
140
+ document.removeEventListener('touchend', this.boundTouchEnd)
141
+ },
142
+ thumbStyle: function (val) {
143
+ var p = (val - this.min) / (this.max - this.min)
144
+ if (this.orientation === 'vertical') {
145
+ return { bottom: p * 100 + '%' }
146
+ }
147
+ return { left: p * 100 + '%' }
148
+ },
149
+ snap: function (val) {
150
+ var stepped = Math.round((val - this.min) / this.step) * this.step + this.min
151
+ return Math.max(this.min, Math.min(this.max, parseFloat(stepped.toFixed(10))))
152
+ },
153
+ valueFromPointer: function (clientX, clientY) {
154
+ var rect = this.$refs.track.getBoundingClientRect()
155
+ var ratio
156
+ if (this.orientation === 'vertical') {
157
+ ratio = 1 - (clientY - rect.top) / rect.height
158
+ } else {
159
+ ratio = (clientX - rect.left) / rect.width
160
+ }
161
+ ratio = Math.max(0, Math.min(1, ratio))
162
+ return this.snap(this.min + ratio * (this.max - this.min))
163
+ },
164
+ startDrag: function (which) {
165
+ if (this.disabled) return
166
+ this.dragging = which
167
+ document.addEventListener('mousemove', this.boundMouseMove)
168
+ document.addEventListener('mouseup', this.boundMouseUp)
169
+ },
170
+ startDragTouch: function (which) {
171
+ if (this.disabled) return
172
+ this.dragging = which
173
+ document.addEventListener('touchmove', this.boundTouchMove, { passive: false })
174
+ document.addEventListener('touchend', this.boundTouchEnd)
175
+ },
176
+ onMouseMove: function (event) {
177
+ if (!this.dragging) return
178
+ this.applyValue(this.dragging, this.valueFromPointer(event.clientX, event.clientY))
179
+ },
180
+ onTouchMove: function (event) {
181
+ if (!this.dragging) return
182
+ event.preventDefault()
183
+ var t = event.touches[0]
184
+ this.applyValue(this.dragging, this.valueFromPointer(t.clientX, t.clientY))
185
+ },
186
+ stopDrag: function () {
187
+ this.dragging = null
188
+ document.removeEventListener('mousemove', this.boundMouseMove)
189
+ document.removeEventListener('mouseup', this.boundMouseUp)
190
+ document.removeEventListener('touchmove', this.boundTouchMove)
191
+ document.removeEventListener('touchend', this.boundTouchEnd)
192
+ },
193
+ applyValue: function (which, val) {
194
+ if (which === 'single') {
195
+ this.localValue = val
196
+ this.$emit('input', val)
197
+ this.$emit('change', val)
198
+ } else if (which === 'min') {
199
+ var newMin = Math.min(val, this.localRangeMax - this.step)
200
+ this.localRangeMin = this.snap(newMin)
201
+ this.$emit('change', [this.localRangeMin, this.localRangeMax])
202
+ } else if (which === 'max') {
203
+ var newMax = Math.max(val, this.localRangeMin + this.step)
204
+ this.localRangeMax = this.snap(newMax)
205
+ this.$emit('change', [this.localRangeMin, this.localRangeMax])
206
+ }
207
+ },
208
+ onTrackClick: function (event) {
209
+ if (this.disabled) return
210
+ var val = this.valueFromPointer(event.clientX, event.clientY)
211
+ if (!this.range) {
212
+ this.applyValue('single', val)
213
+ return
214
+ }
215
+ var distMin = Math.abs(val - this.localRangeMin)
216
+ var distMax = Math.abs(val - this.localRangeMax)
217
+ this.applyValue(distMin <= distMax ? 'min' : 'max', val)
218
+ },
219
+ onKeydown: function (which, event) {
220
+ if (this.disabled) return
221
+ var key = event.key
222
+ var isIncrease = key === 'ArrowRight' || key === 'ArrowUp'
223
+ var isDecrease = key === 'ArrowLeft' || key === 'ArrowDown'
224
+ var isHome = key === 'Home'
225
+ var isEnd = key === 'End'
226
+ if (!isIncrease && !isDecrease && !isHome && !isEnd) return
227
+ event.preventDefault()
228
+ var current, newVal
229
+ if (which === 'single') {
230
+ current = this.localValue
231
+ newVal = isHome ? this.min : isEnd ? this.max : current + (isIncrease ? this.step : -this.step)
232
+ this.applyValue('single', this.snap(newVal))
233
+ } else if (which === 'min') {
234
+ current = this.localRangeMin
235
+ newVal = isHome
236
+ ? this.min
237
+ : isEnd
238
+ ? this.localRangeMax - this.step
239
+ : current + (isIncrease ? this.step : -this.step)
240
+ this.applyValue('min', this.snap(newVal))
241
+ } else if (which === 'max') {
242
+ current = this.localRangeMax
243
+ newVal = isHome
244
+ ? this.localRangeMin + this.step
245
+ : isEnd
246
+ ? this.max
247
+ : current + (isIncrease ? this.step : -this.step)
248
+ this.applyValue('max', this.snap(newVal))
249
+ }
250
+ }
251
+ }
252
+ }
253
+ </script>
254
+
255
+ <style src="./slider.css" scoped></style>
@@ -0,0 +1,89 @@
1
+ .ui-slider {
2
+ display: flex;
3
+ align-items: center;
4
+ width: 100%;
5
+ min-width: 120px;
6
+ padding: var(--spacing-xs) 0;
7
+ user-select: none;
8
+ -webkit-user-select: none;
9
+ }
10
+
11
+ .ui-slider--vertical {
12
+ flex-direction: column;
13
+ width: auto;
14
+ min-width: unset;
15
+ min-height: 120px;
16
+ height: 100%;
17
+ padding: 0 var(--spacing-xs);
18
+ }
19
+
20
+ .ui-slider--disabled {
21
+ opacity: 0.4;
22
+ pointer-events: none;
23
+ }
24
+
25
+ .ui-slider__track {
26
+ position: relative;
27
+ flex: 1;
28
+ height: 6px;
29
+ background: var(--tertiary-bg);
30
+ border-radius: var(--radius-infinite);
31
+ cursor: pointer;
32
+ }
33
+
34
+ .ui-slider--vertical .ui-slider__track {
35
+ flex: 1;
36
+ width: 6px;
37
+ height: auto;
38
+ }
39
+
40
+ .ui-slider__fill {
41
+ position: absolute;
42
+ top: 0;
43
+ bottom: 0;
44
+ background: var(--primary-brand-bg);
45
+ border-radius: var(--radius-infinite);
46
+ pointer-events: none;
47
+ }
48
+
49
+ .ui-slider--vertical .ui-slider__fill {
50
+ top: auto;
51
+ left: 0;
52
+ right: 0;
53
+ }
54
+
55
+ .ui-slider__thumb {
56
+ position: absolute;
57
+ top: 50%;
58
+ width: 14px;
59
+ height: 14px;
60
+ background: var(--primary-brand-bg);
61
+ border: 1.5px solid var(--inverse-fg);
62
+ border-radius: var(--radius-infinite);
63
+ box-shadow: var(--shadow-xs);
64
+ transform: translate(-50%, -50%);
65
+ cursor: grab;
66
+ outline: none;
67
+ z-index: 1;
68
+ transition: box-shadow 0.1s ease;
69
+ }
70
+
71
+ .ui-slider--vertical .ui-slider__thumb {
72
+ top: auto;
73
+ left: 50%;
74
+ transform: translate(-50%, 50%);
75
+ }
76
+
77
+ .ui-slider__thumb:hover {
78
+ box-shadow:
79
+ var(--shadow-xs),
80
+ 0 0 0 5px color-mix(in srgb, var(--primary-brand-bg) 20%, transparent);
81
+ }
82
+
83
+ .ui-slider__thumb:focus-visible {
84
+ box-shadow: var(--shadow-xs), var(--shadow-focus-ring);
85
+ }
86
+
87
+ .ui-slider__thumb:active {
88
+ cursor: grabbing;
89
+ }
@@ -0,0 +1,47 @@
1
+ <template>
2
+ <span class="ui-spinner" :class="[`ui-spinner--${size}`, `ui-spinner--${type}`]" role="status" :aria-label="label">
3
+ <svg
4
+ xmlns="http://www.w3.org/2000/svg"
5
+ width="24"
6
+ height="24"
7
+ viewBox="0 0 24 24"
8
+ fill="none"
9
+ stroke="currentColor"
10
+ stroke-width="1.75"
11
+ stroke-linecap="round"
12
+ stroke-linejoin="round"
13
+ class="lucide lucide-loader-circle-icon lucide-loader-circle ui-spinner__svg"
14
+ >
15
+ <path d="M21 12a9 9 0 1 1-6.219-8.56" />
16
+ </svg>
17
+ </span>
18
+ </template>
19
+
20
+ <script>
21
+ export default {
22
+ name: 'Spinner',
23
+ props: {
24
+ size: {
25
+ type: String,
26
+ default: 'sm',
27
+ validator: function (v) {
28
+ return ['sm', 'md', 'lg'].indexOf(v) !== -1
29
+ }
30
+ },
31
+ type: {
32
+ type: String,
33
+ default: 'default',
34
+ validator: function (v) {
35
+ return ['default', 'mirrored'].indexOf(v) !== -1
36
+ }
37
+ },
38
+ label: {
39
+ type: String,
40
+ default: 'Loading'
41
+ }
42
+ },
43
+ emits: []
44
+ }
45
+ </script>
46
+
47
+ <style src="./spinner.css" scoped></style>
@@ -0,0 +1,48 @@
1
+ .ui-spinner {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+ flex-shrink: 0;
6
+ }
7
+
8
+ .ui-spinner--sm {
9
+ width: 16px;
10
+ height: 16px;
11
+ }
12
+
13
+ .ui-spinner--md {
14
+ width: 24px;
15
+ height: 24px;
16
+ }
17
+
18
+ .ui-spinner--lg {
19
+ width: 32px;
20
+ height: 32px;
21
+ }
22
+
23
+ .ui-spinner__svg {
24
+ width: 100%;
25
+ height: 100%;
26
+ animation: ui-spinner-spin 0.7s linear infinite;
27
+ }
28
+
29
+ .ui-spinner--mirrored .ui-spinner__svg {
30
+ animation-direction: reverse;
31
+ }
32
+
33
+ .ui-spinner__track {
34
+ stroke: var(--tertiary-bg);
35
+ }
36
+
37
+ .ui-spinner__arc {
38
+ stroke: currentColor;
39
+ }
40
+
41
+ @keyframes ui-spinner-spin {
42
+ from {
43
+ transform: rotate(0deg);
44
+ }
45
+ to {
46
+ transform: rotate(360deg);
47
+ }
48
+ }
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <button
3
+ class="ui-switch"
4
+ :class="{ 'ui-switch--on': value }"
5
+ role="switch"
6
+ type="button"
7
+ :aria-checked="value ? 'true' : 'false'"
8
+ :disabled="disabled || undefined"
9
+ @click="toggle"
10
+ >
11
+ <span class="ui-switch__thumb" />
12
+ </button>
13
+ </template>
14
+
15
+ <script>
16
+ export default {
17
+ props: {
18
+ value: { type: Boolean, default: false },
19
+ disabled: { type: Boolean, default: false }
20
+ },
21
+ emits: ['change', 'input'],
22
+ methods: {
23
+ toggle: function () {
24
+ var next = !this.value
25
+ this.$emit('input', next)
26
+ this.$emit('change', next)
27
+ }
28
+ }
29
+ }
30
+ </script>
31
+
32
+ <style src="./switch.css" scoped></style>
@@ -0,0 +1,46 @@
1
+ .ui-switch {
2
+ position: relative;
3
+ display: inline-flex;
4
+ align-items: center;
5
+ flex-shrink: 0;
6
+ width: 33px;
7
+ height: 18px;
8
+ border-radius: var(--radius-infinite);
9
+ background: var(--border-primary);
10
+ border: none;
11
+ padding: 0;
12
+ cursor: pointer;
13
+ transition: background 0.15s ease;
14
+ box-shadow: var(--shadow-xs);
15
+ outline: none;
16
+ }
17
+
18
+ .ui-switch--on {
19
+ background: var(--primary-brand-bg);
20
+ }
21
+
22
+ .ui-switch:disabled {
23
+ opacity: 0.4;
24
+ cursor: not-allowed;
25
+ }
26
+
27
+ .ui-switch:focus-visible {
28
+ box-shadow: var(--shadow-xs), var(--shadow-focus-ring);
29
+ }
30
+
31
+ .ui-switch__thumb {
32
+ position: absolute;
33
+ top: 1px;
34
+ left: 1px;
35
+ width: 16px;
36
+ height: 16px;
37
+ border-radius: 50%;
38
+ background: var(--inverse-fg);
39
+ box-shadow: var(--shadow-xs);
40
+ transition: transform 0.15s ease;
41
+ pointer-events: none;
42
+ }
43
+
44
+ .ui-switch--on .ui-switch__thumb {
45
+ transform: translateX(15px);
46
+ }
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <div class="ui-switch-group" :class="[`ui-switch-group--${layout}`, { 'ui-switch-group--disabled': disabled }]">
3
+ <WkSwitch :value="value" :disabled="disabled" @change="$emit('change', $event)" @input="$emit('input', $event)" />
4
+ <span class="ui-switch-group__label"
5
+ ><slot>{{ label }}</slot></span
6
+ >
7
+ </div>
8
+ </template>
9
+
10
+ <script>
11
+ import WkSwitch from '../switch/Switch.vue'
12
+
13
+ export default {
14
+ name: 'SwitchGroup',
15
+ components: { WkSwitch },
16
+ props: {
17
+ value: { type: Boolean, default: false },
18
+ disabled: { type: Boolean, default: false },
19
+ layout: {
20
+ type: String,
21
+ default: 'inline',
22
+ validator: function (v) {
23
+ return ['inline', 'block'].indexOf(v) !== -1
24
+ }
25
+ },
26
+ label: { type: String, default: '' }
27
+ },
28
+ emits: ['change', 'input']
29
+ }
30
+ </script>
31
+
32
+ <style src="./switch_group.css" scoped></style>
@@ -0,0 +1,28 @@
1
+ .ui-switch-group {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ gap: var(--spacing-xs);
5
+ cursor: pointer;
6
+ }
7
+
8
+ .ui-switch-group--block {
9
+ display: flex;
10
+ width: 100%;
11
+ }
12
+
13
+ .ui-switch-group--block .ui-switch-group__label {
14
+ flex: 1;
15
+ min-width: 0;
16
+ }
17
+
18
+ .ui-switch-group--disabled {
19
+ cursor: not-allowed;
20
+ }
21
+
22
+ .ui-switch-group__label {
23
+ font-family: var(--font-family-body);
24
+ font-size: var(--paragraph-small-font-size);
25
+ line-height: var(--paragraph-small-line-height);
26
+ color: var(--secondary-fg);
27
+ user-select: none;
28
+ }
@@ -0,0 +1,57 @@
1
+ <template>
2
+ <div class="ui-tabs" :class="`ui-tabs--${size}`">
3
+ <button
4
+ v-for="tab in tabs"
5
+ :key="tab.value"
6
+ type="button"
7
+ class="ui-tabs__item"
8
+ :class="{
9
+ 'ui-tabs__item--active': tab.value === value,
10
+ 'ui-tabs__item--disabled': tab.disabled
11
+ }"
12
+ :disabled="tab.disabled || undefined"
13
+ @click="select(tab.value)"
14
+ >
15
+ <span v-if="hasIconSlot" class="ui-tabs__icon"><slot name="tab-icon" :tab="tab" /></span>
16
+ <span v-if="tab.label" class="ui-tabs__label">{{ tab.label }}</span>
17
+ <span v-if="tab.counter > 0" class="ui-tabs__counter">{{ tab.counter }}</span>
18
+ </button>
19
+ </div>
20
+ </template>
21
+
22
+ <script>
23
+ export default {
24
+ name: 'Tabs',
25
+ props: {
26
+ value: { type: [String, Number], default: null },
27
+ tabs: {
28
+ type: Array,
29
+ default: function () {
30
+ return []
31
+ }
32
+ },
33
+ size: {
34
+ type: String,
35
+ default: 'sm',
36
+ validator: function (v) {
37
+ return ['mini', 'sm', 'md', 'lg'].includes(v)
38
+ }
39
+ }
40
+ },
41
+ emits: ['input', 'change'],
42
+ computed: {
43
+ hasIconSlot: function () {
44
+ return !!((this.$scopedSlots && this.$scopedSlots['tab-icon']) || this.$slots['tab-icon'])
45
+ }
46
+ },
47
+ methods: {
48
+ select: function (val) {
49
+ if (val === this.value) return
50
+ this.$emit('input', val)
51
+ this.$emit('change', val)
52
+ }
53
+ }
54
+ }
55
+ </script>
56
+
57
+ <style src="./tabs.css" scoped></style>