@veritree/ui 0.21.1-1 → 0.21.1-3

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.21.1-1",
3
+ "version": "0.21.1-3",
4
4
  "description": "veritree ui library",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -11,7 +11,7 @@
11
11
  ? 'button'
12
12
  : isIcon
13
13
  ? 'inline-flex items-center justify-center rounded-full [&_svg]:max-h-full [&_svg]:max-w-full'
14
- : 'inline-flex rounded border border-solid px-4 text-sm font-semibold leading-none no-underline transition-all',
14
+ : 'relative inline-flex rounded border border-solid px-4 text-sm font-semibold leading-none no-underline transition-all',
15
15
  // variant styles
16
16
  headless
17
17
  ? `button--${variant}`
@@ -32,10 +32,6 @@ export default {
32
32
  return `dropdown-menu-content-${this.api().id}`;
33
33
  },
34
34
 
35
- dark() {
36
- return this.api().isDark;
37
- },
38
-
39
35
  headless() {
40
36
  return this.api().isHeadless;
41
37
  },
@@ -61,13 +57,13 @@ export default {
61
57
  e.stopPropagation();
62
58
 
63
59
  if (this.visible && !this.$el.contains(e.target)) {
64
- this.componentTrigger.onClick();
60
+ this.componentTrigger.cancel();
65
61
  }
66
62
  });
67
63
  },
68
64
 
69
65
  destroyed() {
70
- document.removeEventListener('click', this.componentTrigger.onClick);
66
+ document.removeEventListener('click', this.componentTrigger.cancel);
71
67
  },
72
68
 
73
69
  methods: {
@@ -88,8 +84,6 @@ export default {
88
84
  this.visible = false;
89
85
 
90
86
  this.$nextTick(() => {
91
- this.componentTrigger.focus();
92
- this.componentTrigger.hideExpanded();
93
87
  this.component.clearActive();
94
88
  this.$emit('hidden');
95
89
  });
@@ -87,10 +87,6 @@ export default {
87
87
  componentTrigger() {
88
88
  return this.api().componentTrigger;
89
89
  },
90
-
91
- componentContent() {
92
- return this.api().componentContent;
93
- },
94
90
  },
95
91
 
96
92
  mounted() {
@@ -169,12 +165,11 @@ export default {
169
165
  this.items[goToIndex].focus();
170
166
  },
171
167
 
172
- /**
173
- * Hides content/menu and focus on trigger
174
- */
175
168
  leaveMenu() {
176
- if (this.componentContent) this.componentContent.hide();
177
- if (this.componentTrigger) this.componentTrigger.focus();
169
+ if (this.componentTrigger) {
170
+ this.componentTrigger.cancel();
171
+ this.componentTrigger.focus();
172
+ }
178
173
  },
179
174
 
180
175
  onKeyEsc() {
@@ -4,8 +4,8 @@
4
4
  :aria-haspopup="hasPopup"
5
5
  :aria-expanded="expanded"
6
6
  :aria-controls="controls"
7
- @keydown.down.prevent="onKeyArrowDown"
8
- @keydown.up.prevent="onKeyArrowUp"
7
+ @keydown.down.prevent="onKeyDownOrUp"
8
+ @keydown.up.prevent="onKeyDownOrUp"
9
9
  @keydown.esc.stop="onKeyesc"
10
10
  >
11
11
  <slot></slot>
@@ -49,14 +49,20 @@ export default {
49
49
  },
50
50
  },
51
51
 
52
+ watch: {
53
+ expanded() {
54
+ this.toggleAriaHasPopup();
55
+ if (this.expanded) {
56
+ }
57
+ },
58
+ },
59
+
52
60
  mounted() {
53
61
  const trigger = {
54
- toggleExpanded: this.toggleExpanded,
55
- hideExpanded: this.hideExpanded,
62
+ id: this.id,
56
63
  el: this.$el,
64
+ cancel: this.cancel,
57
65
  focus: this.focus,
58
- id: this.id,
59
- onClick: this.onClick,
60
66
  };
61
67
 
62
68
  this.api().registerTrigger(trigger);
@@ -90,128 +96,88 @@ export default {
90
96
  });
91
97
  },
92
98
 
93
- /**
94
- * Shows content/menu if not already visible
95
- */
96
- showContent() {
97
- this.expanded = true;
98
- this.componentContent.show();
99
- },
99
+ init(e) {
100
+ if (!this.componentContent) {
101
+ return;
102
+ }
100
103
 
101
- /**
102
- * Focus slot element if it exists and toggle expanded
103
- */
104
- focus() {
105
- if (this.trigger) this.trigger.focus();
106
- },
104
+ if (this.expanded) {
105
+ this.cancel();
106
+ return;
107
+ }
107
108
 
108
- //
109
- toggleExpanded() {
110
- if (!this.expanded) return;
111
- this.expanded = false;
112
- },
109
+ this.expanded = true;
113
110
 
114
- /**
115
- * Sets aria expanded attribute/state to false
116
- */
117
- hideExpanded() {
118
- this.expanded = false;
111
+ // delay stop propagation to close other visible
112
+ // dropdowns and delay click event to control
113
+ // this dropdown visibility
114
+ setTimeout(() => e.stopImmediatePropagation(), 50);
115
+ setTimeout(() => this.showComponentContent(), 100);
119
116
  },
120
117
 
121
- /**
122
- * Toggles aria popup/controls attribute/state
123
- */
124
- toggleHasPopup() {
125
- if (!this.componentContent) return;
126
-
127
- this.hasPopup = !this.hasPopup;
128
-
129
- if (!this.hasPopup) {
130
- this.controls = null;
118
+ cancel() {
119
+ if (!this.componentContent) {
131
120
  return;
132
121
  }
133
122
 
134
- this.controls = this.componentContent.id;
123
+ this.expanded = false;
124
+
125
+ this.hideComponentContent();
135
126
  },
136
127
 
137
- /**
138
- * 1. Set aria expanded attribute/state to false
139
- * 2. Close the menu
140
- */
141
- hide() {
142
- this.hideExpanded();
128
+ focus() {
129
+ if (this.trigger) this.trigger.focus();
130
+ },
143
131
 
144
- this.$nextTick(() => {
145
- this.componentContent.hide();
146
- });
132
+ showComponentContent() {
133
+ this.componentContent.show();
147
134
  },
148
135
 
149
- /**
150
- * On click, do the following:
151
- *
152
- * 1. Toggle aria expanded attribute/state
153
- * 2. Open the menu if it's closed
154
- * 3. Close the menu if it's open
155
- */
156
- onClick(e) {
157
- if (!this.componentContent) return;
136
+ hideComponentContent() {
137
+ this.componentContent.hide();
138
+ },
158
139
 
140
+ toggleAriaHasPopup() {
159
141
  if (this.expanded) {
160
- this.componentContent.hide();
142
+ this.hasPopup = this.componentContent !== null;
143
+ this.controls = this.hasPopup ? this.componentContent.id : null;
144
+
161
145
  return;
162
146
  }
163
147
 
164
- // delay stop propagation to close other visible
165
- // dropdowns and delay click event to control
166
- // this dropdown visibility
167
- setTimeout(() => e.stopImmediatePropagation(), 50);
168
- setTimeout(() => this.showContent(), 100);
148
+ this.hasPopup = null;
149
+ this.controls = null;
169
150
  },
170
151
 
171
- /**
172
- * On key arrow down, do the following:
173
- *
174
- * 1. if the menu is not expanded, expand it and focus the first menu item
175
- * 2. if the menu is expanded, focus the first menu item
176
- */
177
- onKeyArrowDown() {
178
- if (!this.componentContent) return;
179
-
180
- this.showContent();
181
-
182
- // settimeout here is delaying the focusing the element
183
- // since it is not rendered yet. All items will only
184
- // be available when the content is fully visible.
185
- this.$nextTick(() => {
186
- setTimeout(() => this.firstMenuItem.focus(), 150);
187
- });
152
+ onClick(e) {
153
+ this.init(e);
188
154
  },
189
155
 
190
- /**
191
- * On key arrow up, do the following:
192
- *
193
- * 1. if the menu is not expanded, expand it and focus the last menu item
194
- * 2. if the menu is expanded, focus the last menu item
195
- */
196
- onKeyArrowUp() {
197
- if (!this.componentContent) return;
156
+ onKeyDownOrUp(e) {
157
+ if (!this.expanded) {
158
+ this.$el.click(e);
159
+ }
198
160
 
199
- this.showContent();
161
+ const keyCode = e.code;
162
+ const listItemPosition =
163
+ keyCode === 'ArrowDown'
164
+ ? 'firstMenuItem'
165
+ : keyCode === 'ArrowUp'
166
+ ? 'lastMenuItem'
167
+ : null;
200
168
 
201
169
  // settimeout here is delaying the focusing the element
202
170
  // since it is not rendered yet. All items will only
203
171
  // be available when the content is fully visible.
204
172
  this.$nextTick(() => {
205
- setTimeout(() => this.lastMenuItem.focus(), 150);
173
+ setTimeout(() => this[listItemPosition].focus(), 100);
206
174
  });
207
175
  },
208
176
 
209
- onKeyesc() {
210
- if (!this.componentContent) return;
211
-
212
- if (this.expanded) {
213
- this.componentContent.hide();
214
- }
177
+ // change it to a better name or move the methods inside to another function
178
+ onKeyEsc() {
179
+ this.cancel();
180
+ this.focus();
215
181
  },
216
182
  },
217
183
  };
@@ -4,7 +4,7 @@
4
4
  :class="[
5
5
  headless
6
6
  ? 'form-control'
7
- : 'border border-solid py-2 px-3 rounded text-inherit',
7
+ : 'border border-solid py-2 px-3 rounded text-inherit max-w-full',
8
8
  headless
9
9
  ? `form-control--${variant}`
10
10
  : isError
@@ -33,14 +33,14 @@ export default {
33
33
  type: [String, Number, Object, Array],
34
34
  default: null,
35
35
  },
36
- variant: {
37
- type: [String, Object, Function],
38
- default: '',
39
- },
40
36
  headless: {
41
37
  type: Boolean,
42
38
  default: false,
43
39
  },
40
+ variant: {
41
+ type: [String, Object, Function],
42
+ default: '',
43
+ },
44
44
  },
45
45
 
46
46
  computed: {
@@ -57,10 +57,6 @@ export default {
57
57
  componentTrigger() {
58
58
  return this.api().componentTrigger;
59
59
  },
60
-
61
- search() {
62
- return this.api().search;
63
- },
64
60
  },
65
61
 
66
62
  mounted() {
@@ -82,36 +78,37 @@ export default {
82
78
  e.stopPropagation();
83
79
 
84
80
  if (this.visible && !this.$el.contains(e.target)) {
85
- this.componentTrigger.onClick();
81
+ this.componentTrigger.cancel();
86
82
  }
87
83
  });
88
84
  },
89
85
 
90
86
  destroyed() {
91
87
  // T-162 Create a directive or mixin for this
92
- document.removeEventListener('click', this.componentTrigger.onClick);
88
+ document.removeEventListener('click', this.componentTrigger.cancel);
93
89
  },
94
90
 
95
91
  methods: {
96
92
  show() {
97
- if (this.visible) return;
93
+ if (this.visible) {
94
+ return;
95
+ }
98
96
 
99
97
  this.visible = true;
100
98
 
101
99
  this.$nextTick(() => {
102
100
  this.component.setActive();
103
- if (this.search) this.search.el.focus();
104
101
  });
105
102
  },
106
103
 
107
104
  hide() {
108
- if (!this.visible) return;
105
+ if (!this.visible) {
106
+ return;
107
+ }
109
108
 
110
109
  this.visible = false;
111
110
 
112
111
  this.$nextTick(() => {
113
- this.componentTrigger.focus();
114
- this.componentTrigger.toggleExpanded();
115
112
  this.component.clearActive();
116
113
  });
117
114
  },
@@ -196,7 +196,10 @@ export default {
196
196
  * Hides componentContent/menu and focus on componentTrigger
197
197
  */
198
198
  leaveMenu() {
199
- if (this.componentContent) this.componentContent.hide();
199
+ if (this.componentTrigger) {
200
+ this.componentTrigger.cancel();
201
+ this.componentTrigger.focus();
202
+ }
200
203
  },
201
204
 
202
205
  onKeyEsc() {
@@ -4,6 +4,7 @@
4
4
  :class="{ 'listbox-search': headless, 'form-control mb-1': !headless }"
5
5
  type="text"
6
6
  @input="onChange"
7
+ @click.stop
7
8
  @keydown.down.prevent="focusNextItem"
8
9
  @keydown.up.prevent="focusPreviousItem"
9
10
  @keydown.home.prevent="focusFirstItem"
@@ -58,6 +59,7 @@ export default {
58
59
  };
59
60
 
60
61
  this.api().registerSearch(search);
62
+ this.$nextTick(() => setTimeout(() => this.$el.focus(), 150));
61
63
  },
62
64
 
63
65
  beforeDestroy() {
@@ -3,18 +3,20 @@
3
3
  :id="id"
4
4
  :aria-expanded="expanded"
5
5
  :aria-haspopup="hasPopup"
6
- :class="{
7
- 'listbox-button': headless,
8
- 'flex w-full justify-between rounded-md border border-solid py-2 px-3':
9
- !headless,
10
- 'border-gray-300 text-gray-500': !dark && !headless,
11
- 'border-white/70 text-white focus-visible:ring-2 focus-visible:ring-white':
12
- dark && !headless,
13
- }"
6
+ :class="[
7
+ headless
8
+ ? 'listbox-button'
9
+ : 'flex w-full justify-between border border-solid py-2 px-3 rounded text-inherit max-w-full',
10
+ headless
11
+ ? `listbox-button--${variant}`
12
+ : isError
13
+ ? 'border-error-300'
14
+ : 'border-gray-300',
15
+ ]"
14
16
  type="button"
15
17
  @click.prevent="onClick"
16
- @keydown.down.prevent="onKeyArrowDown"
17
- @keydown.up.prevent="onKeyArrowUp"
18
+ @keydown.down.prevent="onKeyDownOrUp"
19
+ @keydown.up.prevent="onKeyDownOrUp"
18
20
  @keydown.esc.stop="onKeyEsc"
19
21
  >
20
22
  <span
@@ -49,10 +51,18 @@ export default {
49
51
  inject: ['api'],
50
52
 
51
53
  props: {
54
+ disabled: {
55
+ type: Boolean,
56
+ default: false,
57
+ },
52
58
  headless: {
53
59
  type: Boolean,
54
60
  default: false,
55
61
  },
62
+ variant: {
63
+ type: [String, Object, Function],
64
+ default: '',
65
+ },
56
66
  },
57
67
 
58
68
  data() {
@@ -67,8 +77,8 @@ export default {
67
77
  return `listbox-trigger-${this.api().id}`;
68
78
  },
69
79
 
70
- dark() {
71
- return this.api().isDark;
80
+ isError() {
81
+ return this.variant === 'error';
72
82
  },
73
83
 
74
84
  componentContent() {
@@ -90,101 +100,86 @@ export default {
90
100
 
91
101
  mounted() {
92
102
  const trigger = {
93
- toggleExpanded: this.toggleExpanded,
94
103
  el: this.$el,
104
+ cancel: this.cancel,
95
105
  focus: this.focus,
96
106
  id: this.id,
97
- onClick: this.onClick,
98
107
  };
99
108
 
100
109
  this.api().registerTrigger(trigger);
101
110
  },
102
111
 
103
112
  methods: {
104
- /**
105
- * Shows content/menu if not already visible
106
- */
107
- showContent() {
108
- this.expanded = true;
109
- this.componentContent.show();
110
- },
111
-
112
- focus() {
113
- this.$el.focus();
114
- },
115
-
116
- toggleExpanded() {
117
- if (!this.expanded) return;
118
- this.expanded = false;
119
- },
120
-
121
- /**
122
- * On click, do the following:
123
- *
124
- * 1. Toggle aria expanded attribute/state
125
- * 2. Open the menu if it's closed
126
- * 3. Close the menu if it's open
127
- */
128
- onClick(e) {
129
- if (!this.componentContent) return;
113
+ init(e) {
114
+ if (!this.componentContent) {
115
+ return;
116
+ }
130
117
 
131
118
  if (this.expanded) {
132
- this.componentContent.hide();
119
+ this.cancel();
133
120
  return;
134
121
  }
135
122
 
123
+ this.expanded = true;
124
+
136
125
  // delay stop propagation to close other visible
137
126
  // dropdowns and delay click event to control
138
127
  // this dropdown visibility
139
128
  setTimeout(() => e.stopImmediatePropagation(), 50);
140
- setTimeout(() => this.showContent(), 100);
129
+ setTimeout(() => this.showComponentContent(), 100);
130
+ },
131
+
132
+ cancel() {
133
+ if (!this.componentContent) {
134
+ return;
135
+ }
136
+
137
+ this.expanded = false;
138
+
139
+ this.hideComponentContent();
141
140
  },
142
141
 
143
- /**
144
- * On key arrow down, do the following:
145
- *
146
- * 1. if the menu is not expanded, expand it and focus the first menu item
147
- * 2. if the menu is expanded, focus the first menu item
148
- */
149
- onKeyArrowDown() {
150
- if (!this.componentContent) return;
142
+ focus() {
143
+ this.$el.focus();
144
+ },
151
145
 
152
- this.showContent();
146
+ showComponentContent() {
147
+ this.componentContent.show();
148
+ },
153
149
 
154
- // settimeout here is delaying the focusing the element
155
- // since it is not rendered yet. All items will only
156
- // be available when the content is fully visible.
157
- this.$nextTick(() => {
158
- setTimeout(() => this.firstMenuItem.focus(), 150);
159
- });
150
+ hideComponentContent() {
151
+ this.componentContent.hide();
160
152
  },
161
153
 
162
- /**
163
- * On key arrow up, do the following:
164
- *
165
- * 1. if the menu is not expanded, expand it and focus the last menu item
166
- * 2. if the menu is expanded, focus the last menu item
167
- */
168
- onKeyArrowUp() {
169
- if (!this.componentContent) return;
154
+ onClick(e) {
155
+ this.init(e);
156
+ },
170
157
 
171
- this.showContent();
158
+ onKeyDownOrUp(e) {
159
+ if (!this.expanded) {
160
+ this.$el.click(e);
161
+ }
162
+
163
+ const keyCode = e.code;
164
+ const listItemPosition =
165
+ keyCode === 'ArrowDown'
166
+ ? 'firstMenuItem'
167
+ : keyCode === 'ArrowUp'
168
+ ? 'lastMenuItem'
169
+ : null;
172
170
 
173
171
  // settimeout here is delaying the focusing the element
174
172
  // since it is not rendered yet. All items will only
175
173
  // be available when the content is fully visible.
176
174
  this.$nextTick(() => {
177
- setTimeout(() => this.lastMenuItem.focus(), 150);
175
+ setTimeout(() => this[listItemPosition].focus(), 100);
178
176
  });
179
177
  },
180
178
 
179
+ // change it to a better name or move the methods inside to another function
181
180
  onKeyEsc() {
182
- if (!this.componentContent) return;
183
-
184
- if (this.expanded) {
185
- this.toggleExpanded();
186
- this.componentContent.hide();
187
- }
181
+ this.cancel();
182
+ this.focus();
188
183
  },
189
184
  },
190
185
  };