@veritree/ui 0.89.5 → 0.90.0

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": "@veritree/ui",
3
- "version": "0.89.5",
3
+ "version": "0.90.0",
4
4
  "description": "veritree ui library",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -1,53 +1,15 @@
1
1
  <template>
2
- <!-- :href="href" -->
3
2
  <component
4
3
  :is="tag"
5
4
  :to="to"
6
5
  :href="href || to"
7
6
  :type="type"
8
7
  :disabled="isDisabled"
9
- :class="[
10
- // default styles
11
- headless ? 'button' : isIcon ? null : 'button-base',
12
- // variant styles
13
- headless
14
- ? `button--${variant}`
15
- : isPrimary
16
- ? 'button--primary'
17
- : isSecondary
18
- ? isGhost
19
- ? 'border-gray-500 text-gray-100 hover:bg-white hover:text-gray-700'
20
- : 'button--secondary'
21
- : isTertiary
22
- ? 'button--tertiary'
23
- : isDark
24
- ? 'button--dark'
25
- : isIcon
26
- ? 'button--icon'
27
- : null,
28
- // sizes styles
29
- headless
30
- ? `button--${size}`
31
- : isLarge
32
- ? isIcon
33
- ? 'h-8 w-8'
34
- : 'button--large'
35
- : isSmall
36
- ? isIcon
37
- ? 'h-6 w-6 p-1'
38
- : 'button--small'
39
- : null,
40
- isDisabled ? (isIcon ? '[&_svg]:text-gray-400' : null) : null,
41
- ]"
8
+ :class="buttonClasses"
42
9
  v-on="$listeners"
43
10
  >
44
11
  <VTSpinner v-if="busy" class="absolute inset-0 m-auto" />
45
- <span
46
- :class="[
47
- headless ? null : 'mx-auto inline-flex items-center gap-2 self-center',
48
- headless && busy ? 'button--busy' : busy ? 'invisible' : null,
49
- ]"
50
- >
12
+ <span :class="spanClasses">
51
13
  <!-- @slot Use this slot for the button content -->
52
14
  <slot></slot>
53
15
  </span>
@@ -78,6 +40,11 @@ export default {
78
40
  variant: {
79
41
  type: String,
80
42
  default: 'primary',
43
+ validator(value) {
44
+ return ['primary', 'secondary', 'tertiary', 'dark', 'icon'].includes(
45
+ value,
46
+ );
47
+ },
81
48
  },
82
49
 
83
50
  /**
@@ -90,6 +57,9 @@ export default {
90
57
  size: {
91
58
  type: String,
92
59
  default: 'large',
60
+ validator(value) {
61
+ return ['small', 'large'].includes(value);
62
+ },
93
63
  },
94
64
 
95
65
  /**
@@ -156,37 +126,99 @@ export default {
156
126
 
157
127
  appearance: {
158
128
  type: String,
159
- default: 'normal', // normal or ghost
129
+ default: 'normal',
130
+ validator(value) {
131
+ return ['normal', 'ghost'].includes(value);
132
+ },
133
+ },
134
+
135
+ version: {
136
+ type: String,
137
+ default: '1',
160
138
  },
161
139
  },
162
140
 
163
141
  computed: {
164
- isPrimary() {
165
- return this.variant === 'primary';
166
- },
142
+ buttonClasses() {
143
+ const classes = [];
167
144
 
168
- isSecondary() {
169
- return this.variant === 'secondary';
170
- },
145
+ if (this.headless) {
146
+ // Headless mode - use semantic classes
147
+ classes.push('button');
148
+ classes.push(`button--${this.variant}`);
149
+ classes.push(`button--${this.size}`);
150
+ } else {
151
+ // Default mode - use component styles
171
152
 
172
- isTertiary() {
173
- return this.variant === 'tertiary';
174
- },
153
+ // Default styles
154
+ if (!this.isIcon) {
155
+ classes.push('button-base');
156
+ }
175
157
 
176
- isDark() {
177
- return this.variant === 'dark';
178
- },
158
+ // Variant styles
159
+ if (this.variant === 'primary') {
160
+ classes.push('button--primary');
161
+ }
179
162
 
180
- isIcon() {
181
- return this.variant === 'icon';
163
+ if (this.variant === 'secondary') {
164
+ classes.push('button--secondary');
165
+ }
166
+
167
+ if (this.variant === 'tertiary') {
168
+ classes.push('button--tertiary');
169
+ }
170
+
171
+ if (this.variant === 'dark') {
172
+ classes.push('button--dark');
173
+ }
174
+
175
+ if (this.isIcon) {
176
+ classes.push('button--icon');
177
+ }
178
+
179
+ // Ghost appearance can be applied to any variant
180
+ if (this.isGhost) {
181
+ classes.push('button--ghost');
182
+ }
183
+
184
+ // Size styles
185
+ if (this.size === 'large') {
186
+ classes.push(this.isIcon ? 'h-8 w-8' : 'button--large');
187
+ } else if (this.size === 'small') {
188
+ classes.push(this.isIcon ? 'h-6 w-6 p-1' : 'button--small');
189
+ }
190
+
191
+ if (this.version && this.version !== '1') {
192
+ classes.push(`button--version-${this.version}`);
193
+ }
194
+ }
195
+
196
+ // Disabled state (applies to both headless and non-headless)
197
+ if (this.isDisabled && this.isIcon) {
198
+ classes.push('[&_svg]:text-gray-400');
199
+ }
200
+
201
+ return classes.filter(Boolean);
182
202
  },
183
203
 
184
- isLarge() {
185
- return this.size === 'large';
204
+ spanClasses() {
205
+ const classes = [];
206
+
207
+ if (!this.headless) {
208
+ classes.push('mx-auto inline-flex items-center gap-2 self-center');
209
+ }
210
+
211
+ if (this.headless && this.busy) {
212
+ classes.push('button--busy');
213
+ } else if (this.busy) {
214
+ classes.push('invisible');
215
+ }
216
+
217
+ return classes.filter(Boolean);
186
218
  },
187
219
 
188
- isSmall() {
189
- return this.size === 'small';
220
+ isIcon() {
221
+ return this.variant === 'icon';
190
222
  },
191
223
 
192
224
  isDisabled() {
@@ -102,6 +102,7 @@ export default {
102
102
  },
103
103
 
104
104
  setVisible(visible) {
105
+ console.log('setVisible', visible);
105
106
  this.visible = visible;
106
107
  },
107
108
  },
@@ -34,6 +34,7 @@ export default {
34
34
  id() {
35
35
  return this.apiDetails().idSummary;
36
36
  },
37
+
37
38
  ariaControls() {
38
39
  return this.apiDetails().idContent;
39
40
  },
@@ -1,12 +1,14 @@
1
1
  <template>
2
- <span
3
- :class="[
4
- headless ? 'disclosure-icon' : 'shrink-0 transition-all',
5
- headless ? null : expanded ? 'rotate-180' : 'rotate-0',
6
- ]"
2
+ <component
3
+ :is="as"
4
+ :class="iconClasses"
5
+ :aria-expanded="as === 'button' ? expanded : undefined"
6
+ @click.stop="onClick"
7
+ @keydown.enter="onClick"
8
+ @keydown.space.prevent="onClick"
7
9
  >
8
10
  <slot><IconChevronDown /></slot>
9
- </span>
11
+ </component>
10
12
  </template>
11
13
 
12
14
  <script>
@@ -20,12 +22,41 @@ export default {
20
22
  type: Boolean,
21
23
  default: false,
22
24
  },
25
+ as: {
26
+ type: String,
27
+ default: 'span',
28
+ validator(value) {
29
+ return ['span', 'button', 'div', 'a'].includes(value);
30
+ },
31
+ },
23
32
  },
24
33
 
25
34
  computed: {
35
+ iconClasses() {
36
+ const classes = [];
37
+
38
+ if (this.headless) {
39
+ classes.push('disclosure-icon');
40
+ } else {
41
+ classes.push('shrink-0 transition-all');
42
+ classes.push(this.expanded ? 'rotate-180' : 'rotate-0');
43
+ }
44
+
45
+ return classes.filter(Boolean);
46
+ },
47
+
26
48
  expanded() {
27
49
  return this.apiDetails().visible;
28
50
  },
29
51
  },
52
+
53
+ methods: {
54
+ onClick() {
55
+ // Only handle click if rendered as a button
56
+ if (this.as === 'button') {
57
+ this.apiDetails().setVisible(!this.expanded);
58
+ }
59
+ },
60
+ },
30
61
  };
31
62
  </script>