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,143 @@
1
+ .ui-accordion-item {
2
+ display: flex;
3
+ flex-direction: column;
4
+ background: var(--card);
5
+ border-bottom: 1px solid var(--border-primary);
6
+ }
7
+
8
+ .ui-accordion-item--bordered {
9
+ border-bottom: 0;
10
+ border-top: 1px solid var(--border-primary);
11
+ border-left: 1px solid var(--border-primary);
12
+ border-right: 1px solid var(--border-primary);
13
+ }
14
+
15
+ .ui-accordion-item--bordered:last-child {
16
+ border-bottom: 1px solid var(--border-primary);
17
+ border-bottom-left-radius: var(--rounded-3xl);
18
+ border-bottom-right-radius: var(--rounded-3xl);
19
+ }
20
+
21
+ .ui-accordion-item--bordered:first-child {
22
+ border-top-left-radius: var(--rounded-3xl);
23
+ border-top-right-radius: var(--rounded-3xl);
24
+ }
25
+
26
+ .ui-accordion-item--disabled {
27
+ opacity: 0.5;
28
+ }
29
+
30
+ .ui-accordion-item__trigger {
31
+ display: flex;
32
+ align-items: center;
33
+ gap: var(--spacing-md);
34
+ width: 100%;
35
+ margin: 0;
36
+ padding: var(--spacing-sm) 0;
37
+ background: transparent;
38
+ border: 0;
39
+ border-radius: inherit;
40
+ outline: none;
41
+ cursor: pointer;
42
+ font-family: inherit;
43
+ color: var(--primary-fg);
44
+ text-align: left;
45
+ -webkit-appearance: none;
46
+ appearance: none;
47
+ }
48
+
49
+ .ui-accordion-item--bordered .ui-accordion-item__trigger {
50
+ padding: var(--spacing-sm) var(--spacing-md);
51
+ }
52
+
53
+ .ui-accordion-item__trigger:disabled {
54
+ cursor: not-allowed;
55
+ }
56
+
57
+ .ui-accordion-item__trigger:focus-visible {
58
+ box-shadow: var(--shadow-focus-ring);
59
+ }
60
+
61
+ .ui-accordion-item__label-row {
62
+ display: flex;
63
+ flex: 1 1 0;
64
+ align-items: center;
65
+ gap: var(--spacing-xs);
66
+ min-width: 0;
67
+ }
68
+
69
+ .ui-accordion-item__label {
70
+ flex: 1 1 0;
71
+ min-width: 0;
72
+ font-family: var(--paragraph-small-font-family);
73
+ font-size: var(--paragraph-small-font-size);
74
+ line-height: var(--paragraph-small-line-height);
75
+ letter-spacing: var(--paragraph-small-letter-spacing);
76
+ font-weight: var(--paragraph-medium-font-weight);
77
+ color: var(--primary-fg);
78
+ }
79
+
80
+ .ui-accordion-item__badge {
81
+ display: inline-flex;
82
+ align-items: center;
83
+ justify-content: center;
84
+ flex-shrink: 0;
85
+ gap: var(--spacing-2xs);
86
+ padding: var(--spacing-3xs) var(--spacing-xs);
87
+ background: var(--outline);
88
+ border: 1px solid var(--border-primary);
89
+ border-radius: var(--rounded-lg);
90
+ font-family: var(--paragraph-mini-font-family);
91
+ font-size: var(--paragraph-mini-font-size);
92
+ line-height: var(--paragraph-mini-line-height);
93
+ letter-spacing: var(--paragraph-mini-letter-spacing);
94
+ font-weight: var(--paragraph-bold-font-weight);
95
+ color: var(--primary-fg);
96
+ white-space: nowrap;
97
+ }
98
+
99
+ .ui-accordion-item__append {
100
+ flex-shrink: 0;
101
+ font-family: var(--paragraph-small-font-family);
102
+ font-size: var(--paragraph-small-font-size);
103
+ line-height: var(--paragraph-small-line-height);
104
+ letter-spacing: var(--paragraph-small-letter-spacing);
105
+ font-weight: var(--paragraph-font-weight);
106
+ color: var(--muted-fg);
107
+ white-space: nowrap;
108
+ }
109
+
110
+ .ui-accordion-item__icon {
111
+ display: inline-flex;
112
+ align-items: center;
113
+ justify-content: center;
114
+ flex-shrink: 0;
115
+ width: 16px;
116
+ height: 16px;
117
+ color: var(--primary-fg);
118
+ transition: transform 0.2s ease;
119
+ }
120
+
121
+ .ui-accordion-item__icon svg {
122
+ display: block;
123
+ width: 100%;
124
+ height: 100%;
125
+ }
126
+
127
+ .ui-accordion-item__icon--open {
128
+ transform: rotate(180deg);
129
+ }
130
+
131
+ .ui-accordion-item__content {
132
+ padding: 0 0 var(--spacing-md);
133
+ font-family: var(--paragraph-small-font-family);
134
+ font-size: var(--paragraph-small-font-size);
135
+ line-height: var(--paragraph-small-line-height);
136
+ letter-spacing: var(--paragraph-small-letter-spacing);
137
+ font-weight: var(--paragraph-font-weight);
138
+ color: var(--primary-fg);
139
+ }
140
+
141
+ .ui-accordion-item--bordered .ui-accordion-item__content {
142
+ padding: 0 var(--spacing-md) var(--spacing-md);
143
+ }
@@ -0,0 +1,82 @@
1
+ <template>
2
+ <Dialog
3
+ :open="isOpen"
4
+ :show-header="false"
5
+ :footer="true"
6
+ :footer-align="'right'"
7
+ :footer-divider="true"
8
+ :centered="true"
9
+ :mask="mask"
10
+ :mask-closable="maskClosable"
11
+ :keyboard="keyboard"
12
+ :append-to-body="appendToBody"
13
+ :z-index="zIndex"
14
+ @change="setOpen"
15
+ @after-close="$emit('after-close')"
16
+ >
17
+ <div class="ui-alert-dialog-body">
18
+ <div class="ui-alert-dialog-title">
19
+ <slot name="title">{{ title }}</slot>
20
+ </div>
21
+ <div class="ui-alert-dialog-description">
22
+ <slot>{{ description }}</slot>
23
+ </div>
24
+ </div>
25
+ <template #footer>
26
+ <slot name="footer">
27
+ <Button :variant="cancelVariant" class="ui-alert-dialog-btn" @click="handleCancel">{{ cancelText }}</Button>
28
+ <Button :variant="okVariant" :loading="confirmLoading" class="ui-alert-dialog-btn" @click="handleOk">{{
29
+ okText
30
+ }}</Button>
31
+ </slot>
32
+ </template>
33
+ </Dialog>
34
+ </template>
35
+
36
+ <script>
37
+ import Dialog from '../dialog/Dialog.vue'
38
+ import Button from '../button/Button.vue'
39
+
40
+ export default {
41
+ name: 'AlertDialog',
42
+ components: { Dialog, Button },
43
+ model: { prop: 'open', event: 'change' },
44
+ props: {
45
+ open: { type: Boolean, default: false },
46
+ modelValue: { type: Boolean, default: undefined },
47
+ title: { type: String, default: '' },
48
+ description: { type: String, default: '' },
49
+ okText: { type: String, default: 'Continue' },
50
+ cancelText: { type: String, default: 'Cancel' },
51
+ okVariant: { type: String, default: 'primary' },
52
+ cancelVariant: { type: String, default: 'outline' },
53
+ confirmLoading: { type: Boolean, default: false },
54
+ mask: { type: Boolean, default: true },
55
+ maskClosable: { type: Boolean, default: false },
56
+ keyboard: { type: Boolean, default: false },
57
+ appendToBody: { type: Boolean, default: true },
58
+ zIndex: { type: [Number, String], default: 1000 }
59
+ },
60
+ emits: ['change', 'update:modelValue', 'ok', 'cancel', 'after-close'],
61
+ computed: {
62
+ isOpen() {
63
+ return this.modelValue !== undefined ? this.modelValue : this.open
64
+ }
65
+ },
66
+ methods: {
67
+ setOpen(v) {
68
+ this.$emit('change', v)
69
+ this.$emit('update:modelValue', v)
70
+ },
71
+ handleOk(e) {
72
+ this.$emit('ok', e)
73
+ },
74
+ handleCancel(e) {
75
+ this.$emit('cancel', e)
76
+ this.setOpen(false)
77
+ }
78
+ }
79
+ }
80
+ </script>
81
+
82
+ <style src="./alert-dialog.css" scoped></style>
@@ -0,0 +1,33 @@
1
+ .ui-alert-dialog-body {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--spacing-sm);
5
+ }
6
+
7
+ .ui-alert-dialog-title {
8
+ font-family: var(--heading-4-font-family);
9
+ font-size: var(--heading-4-font-size);
10
+ line-height: var(--heading-4-line-height);
11
+ font-weight: var(--heading-4-font-weight);
12
+ letter-spacing: var(--heading-4-letter-spacing);
13
+ color: var(--primary-fg);
14
+ }
15
+
16
+ .ui-alert-dialog-description {
17
+ font-family: var(--paragraph-small-font-family);
18
+ font-size: var(--paragraph-small-font-size);
19
+ line-height: var(--paragraph-small-line-height);
20
+ letter-spacing: var(--paragraph-small-letter-spacing);
21
+ color: var(--muted-fg);
22
+ }
23
+
24
+ @media (max-width: 767px) {
25
+ .ui-alert-dialog-body {
26
+ text-align: center;
27
+ }
28
+
29
+ .ui-alert-dialog-btn {
30
+ flex: 1 0 0;
31
+ min-width: 0;
32
+ }
33
+ }
@@ -34,10 +34,10 @@ export default {
34
34
  emits: [],
35
35
  computed: {
36
36
  hasIconLeft() {
37
- return !!((this.$scopedSlots && this.$scopedSlots['icon-left']) || this.$slots['icon-left'])
37
+ return !!this.$slots['icon-left']
38
38
  },
39
39
  hasIconRight() {
40
- return !!((this.$scopedSlots && this.$scopedSlots['icon-right']) || this.$slots['icon-right'])
40
+ return !!this.$slots['icon-right']
41
41
  }
42
42
  }
43
43
  }
@@ -54,10 +54,7 @@
54
54
 
55
55
  .ui-badge:focus-visible {
56
56
  outline: none;
57
- box-shadow: var(--shadow-focus-ring);
58
- }
59
- .ui-badge--destructive:focus-visible {
60
- box-shadow: var(--shadow-focus-ring-error);
57
+ box-shadow: 0 0 0 3px var(--focus-ring);
61
58
  }
62
59
 
63
60
  .ui-badge__icon {
@@ -0,0 +1,85 @@
1
+ <template>
2
+ <nav class="ui-breadcrumb" aria-label="breadcrumb">
3
+ <ol class="ui-breadcrumb__list">
4
+ <slot>
5
+ <li v-for="(item, index) in items" :key="index" class="ui-breadcrumb__row">
6
+ <span v-if="index > 0" class="ui-breadcrumb__separator" aria-hidden="true">
7
+ <slot name="separator" :type="separator">
8
+ <svg
9
+ v-if="separator === 'slash'"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ width="14"
12
+ height="14"
13
+ viewBox="0 0 14 14"
14
+ fill="none"
15
+ >
16
+ <g clip-path="url(#clip0_3182_3913)">
17
+ <path
18
+ d="M12.524 0.857389C12.6948 0.686535 12.9718 0.686535 13.1426 0.857389C13.3135 1.02824 13.3135 1.30519 13.1426 1.47604L1.47598 13.1427C1.30513 13.3136 1.02818 13.3136 0.857328 13.1427C0.686473 12.9719 0.686473 12.6949 0.857328 12.5241L12.524 0.857389Z"
19
+ fill="#5C5C5C"
20
+ />
21
+ </g>
22
+ <defs>
23
+ <clipPath id="clip0_3182_3913">
24
+ <rect width="14" height="14" fill="white" />
25
+ </clipPath>
26
+ </defs>
27
+ </svg>
28
+ <svg v-else xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="none">
29
+ <path
30
+ d="M4.88882 3.13888C5.08815 2.93955 5.41182 2.93955 5.61115 3.13888L9.11115 6.63888C9.31048 6.83821 9.31048 7.16188 9.11115 7.36121L5.61115 10.8612C5.41182 11.0605 5.08815 11.0605 4.88882 10.8612C4.68949 10.6619 4.68949 10.3382 4.88882 10.1389L8.02765 7.00004L4.88882 3.86121C4.68949 3.66188 4.68949 3.33821 4.88882 3.13888Z"
31
+ fill="#5C5C5C"
32
+ />
33
+ </svg>
34
+ </slot>
35
+ </span>
36
+ <component
37
+ :is="getTag(item)"
38
+ v-if="!isActive(item, index)"
39
+ :href="item.href"
40
+ class="ui-breadcrumb__link"
41
+ @click="onItemClick(item, index, $event)"
42
+ >
43
+ <span v-if="item.icon" class="ui-breadcrumb__icon" v-html="item.icon"></span>
44
+ <span v-if="item.label" class="ui-breadcrumb__label">{{ item.label }}</span>
45
+ </component>
46
+ <span v-else class="ui-breadcrumb__current" aria-current="page">
47
+ <span v-if="item.icon" class="ui-breadcrumb__icon" v-html="item.icon"></span>
48
+ <span v-if="item.label" class="ui-breadcrumb__label">{{ item.label }}</span>
49
+ </span>
50
+ </li>
51
+ </slot>
52
+ </ol>
53
+ </nav>
54
+ </template>
55
+
56
+ <script>
57
+ export default {
58
+ name: 'Breadcrumb',
59
+ props: {
60
+ items: {
61
+ type: Array,
62
+ default: () => []
63
+ },
64
+ separator: {
65
+ type: String,
66
+ default: 'chevron',
67
+ validator: v => ['chevron', 'slash'].includes(v)
68
+ }
69
+ },
70
+ emits: ['click'],
71
+ methods: {
72
+ isActive(item, index) {
73
+ return index === this.items.length - 1
74
+ },
75
+ onItemClick(item, index, e) {
76
+ this.$emit('click', item, index, e)
77
+ },
78
+ getTag(item) {
79
+ return item.href ? 'a' : 'span'
80
+ }
81
+ }
82
+ }
83
+ </script>
84
+
85
+ <style src="./breadcrumb.css" scoped></style>
@@ -0,0 +1,90 @@
1
+ .ui-breadcrumb {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ }
5
+
6
+ .ui-breadcrumb__list {
7
+ display: inline-flex;
8
+ align-items: center;
9
+ flex-wrap: wrap;
10
+ gap: var(--spacing-2xs);
11
+ margin: 0;
12
+ padding: 0;
13
+ list-style: none;
14
+ }
15
+
16
+ .ui-breadcrumb__row {
17
+ display: inline-flex;
18
+ align-items: center;
19
+ gap: var(--spacing-2xs);
20
+ list-style: none;
21
+ }
22
+
23
+ .ui-breadcrumb__separator {
24
+ display: inline-flex;
25
+ align-items: center;
26
+ justify-content: center;
27
+ flex-shrink: 0;
28
+ width: 14px;
29
+ height: 14px;
30
+ color: var(--muted-fg);
31
+ }
32
+
33
+ .ui-breadcrumb__separator svg {
34
+ display: block;
35
+ width: 14px;
36
+ height: 14px;
37
+ }
38
+
39
+ .ui-breadcrumb__link,
40
+ .ui-breadcrumb__current {
41
+ display: inline-flex;
42
+ align-items: center;
43
+ gap: var(--spacing-2xs);
44
+ font-family: var(--paragraph-small-font-family);
45
+ font-size: var(--paragraph-small-font-size);
46
+ line-height: var(--paragraph-small-line-height);
47
+ letter-spacing: var(--paragraph-small-letter-spacing);
48
+ font-weight: var(--paragraph-font-weight);
49
+ border-radius: var(--rounded-sm);
50
+ }
51
+
52
+ .ui-breadcrumb__link {
53
+ color: var(--muted-fg);
54
+ text-decoration: none;
55
+ cursor: pointer;
56
+ transition: color 0.15s ease;
57
+ }
58
+
59
+ .ui-breadcrumb__link:hover {
60
+ color: var(--primary-fg);
61
+ }
62
+
63
+ .ui-breadcrumb__link:focus-visible {
64
+ outline: none;
65
+ box-shadow: var(--shadow-focus-ring);
66
+ }
67
+
68
+ .ui-breadcrumb__current {
69
+ color: var(--primary-fg);
70
+ font-weight: var(--paragraph-medium-font-weight);
71
+ }
72
+
73
+ .ui-breadcrumb__icon {
74
+ display: inline-flex;
75
+ align-items: center;
76
+ justify-content: center;
77
+ flex-shrink: 0;
78
+ width: 16px;
79
+ height: 16px;
80
+ }
81
+
82
+ .ui-breadcrumb__icon svg {
83
+ display: block;
84
+ width: 16px;
85
+ height: 16px;
86
+ }
87
+
88
+ .ui-breadcrumb__label {
89
+ white-space: nowrap;
90
+ }
@@ -1,32 +1,99 @@
1
1
  <template>
2
- <button :class="['ui-btn', `ui-btn--${type}`, `ui-btn--${size}`]" :disabled="disabled" @click="handleClick">
3
- <slot></slot>
2
+ <button
3
+ :class="[
4
+ 'ui-btn',
5
+ `ui-btn--${variant}`,
6
+ `ui-btn--${size}`,
7
+ `ui-btn--round-${roundness}`,
8
+ isIconOnly && 'ui-btn--icon-only',
9
+ loading && 'ui-btn--loading'
10
+ ]"
11
+ :type="htmlType"
12
+ :disabled="disabled || loading"
13
+ @click="handleClick"
14
+ >
15
+ <!-- Left Icon / Spinner -->
16
+ <Spinner v-if="loading" size="sm" type="mirrored" />
17
+
18
+ <template v-if="showLeftIcon">
19
+ <span v-if="hasIconOnly" class="ui-btn__icon">
20
+ <slot name="icon"></slot>
21
+ </span>
22
+ <span v-if="hasIconLeft" class="ui-btn__icon">
23
+ <slot name="icon-left"></slot>
24
+ </span>
25
+ </template>
26
+
27
+ <!-- Label -->
28
+ <span v-if="!isIconOnly && (hasDefaultSlot || label)" class="ui-btn__label">
29
+ <slot>{{ label }}</slot>
30
+ </span>
31
+
32
+ <!-- Right Icon -->
33
+ <span v-if="hasIconRight" class="ui-btn__icon">
34
+ <slot name="icon-right"></slot>
35
+ </span>
4
36
  </button>
5
37
  </template>
6
38
 
7
39
  <script>
40
+ import Spinner from '../spinner/Spinner.vue'
41
+
8
42
  export default {
9
43
  name: 'Button',
44
+ components: {
45
+ Spinner
46
+ },
10
47
  props: {
11
- type: {
48
+ variant: {
12
49
  type: String,
13
50
  default: 'primary',
14
- validator: value => ['primary', 'secondary', 'danger', 'success'].includes(value)
51
+ validator: v => ['primary', 'neutral', 'secondary', 'outline', 'ghost', 'destructive', 'link'].includes(v)
15
52
  },
16
53
  size: {
17
54
  type: String,
18
- default: 'medium',
19
- validator: value => ['small', 'medium', 'large'].includes(value)
55
+ default: 'md',
56
+ validator: v => ['xs', 'sm', 'md', 'lg', 'xl'].includes(v)
57
+ },
58
+ roundness: {
59
+ type: String,
60
+ default: 'default',
61
+ validator: v => ['default', 'round'].includes(v)
20
62
  },
21
- disabled: {
22
- type: Boolean,
23
- default: false
63
+ label: { type: String, default: '' },
64
+ disabled: { type: Boolean, default: false },
65
+ loading: { type: Boolean, default: false },
66
+ htmlType: {
67
+ type: String,
68
+ default: 'button',
69
+ validator: v => ['button', 'submit', 'reset'].includes(v)
24
70
  }
25
71
  },
26
72
  emits: ['click'],
73
+ computed: {
74
+ hasIconLeft() {
75
+ return !!this.$slots['icon-left']
76
+ },
77
+ hasIconRight() {
78
+ return !this.loading && !!this.$slots['icon-right']
79
+ },
80
+ hasIconOnly() {
81
+ return !!this.$slots['icon']
82
+ },
83
+ hasDefaultSlot() {
84
+ return !!this.$slots['default']
85
+ },
86
+ isIconOnly() {
87
+ const iconCount = [this.hasIconOnly, this.hasIconLeft, this.hasIconRight].filter(Boolean).length
88
+ return !this.label && !this.hasDefaultSlot && iconCount === 1
89
+ },
90
+ showLeftIcon() {
91
+ return !this.loading && (this.hasIconLeft || this.hasIconOnly)
92
+ }
93
+ },
27
94
  methods: {
28
95
  handleClick(e) {
29
- if (!this.disabled) {
96
+ if (!this.disabled && !this.loading) {
30
97
  this.$emit('click', e)
31
98
  }
32
99
  }