@veritree/ui 0.1.9 → 0.2.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/index.js CHANGED
@@ -12,10 +12,10 @@ import VTInputUpload from './src/Input/VTInputUpload.vue';
12
12
 
13
13
  import VTTextarea from './src/Textarea/VTTextarea.vue';
14
14
 
15
- // import VTListbox from './src/Listbox/VTListbox.vue';
16
- // import VTListboxButton from './src/Listbox/VTListboxButton.vue';
17
- // import VTListboxOption from './src/Listbox/VTListboxOption.vue';
18
- // import VTListboxOptions from './src/Listbox/VTListboxOptions.vue';
15
+ import VTListbox from './src/Listbox/VTListbox.vue';
16
+ import VTListboxButton from './src/Listbox/VTListboxButton.vue';
17
+ import VTListboxOption from './src/Listbox/VTListboxOption.vue';
18
+ import VTListboxOptions from './src/Listbox/VTListboxOptions.vue';
19
19
 
20
20
  import VTModal from './src/Modal/VTModal.vue';
21
21
 
@@ -40,10 +40,10 @@ export {
40
40
  VTInputFile,
41
41
  VTInputUpload,
42
42
  VTTextarea,
43
- // VTListbox,
44
- // VTListboxButton,
45
- // VTListboxOption,
46
- // VTListboxOptions,
43
+ VTListbox,
44
+ VTListboxButton,
45
+ VTListboxOption,
46
+ VTListboxOptions,
47
47
  VTModal,
48
48
  VTAccordion,
49
49
  VTAccordionButton,
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "@veritree/ui",
3
+ "version": "0.1.9",
4
+ "lockfileVersion": 1,
5
+ "requires": true,
6
+ "dependencies": {
7
+ "@veritree/icons": {
8
+ "version": "0.12.0",
9
+ "resolved": "https://registry.npmjs.org/@veritree/icons/-/icons-0.12.0.tgz",
10
+ "integrity": "sha512-vunUKzvS9neslSf3R3y6RYQrcfRpxmp8PnhWWe2peYiyElLIJcb7zAsfCZ+I0Fg5PQ6GZG6StqWy0WF7MJ7VOg=="
11
+ }
12
+ }
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veritree/ui",
3
- "version": "0.1.9",
3
+ "version": "0.2.0",
4
4
  "description": "veritree ui library",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -11,6 +11,6 @@
11
11
  "access": "public"
12
12
  },
13
13
  "dependencies": {
14
- "@veritree/icons": "^0.12.0"
14
+ "@veritree/icons": "^0.19.0"
15
15
  }
16
16
  }
@@ -88,7 +88,7 @@ export default {
88
88
 
89
89
  const unfocusOptions = () => {
90
90
  this.listboxOptions.forEach((option) => {
91
- option.unfocus();
91
+ if (option.focused) option.unfocus();
92
92
  });
93
93
  };
94
94
 
@@ -2,7 +2,7 @@
2
2
  <button
3
3
  :aria-expanded="expanded"
4
4
  aria-haspopup="listbox"
5
- class="Listbox-button debugger"
5
+ class="Listbox-button"
6
6
  :data-theme="theme"
7
7
  type="button"
8
8
  @click.prevent="onClick"
@@ -39,13 +39,12 @@ export default {
39
39
 
40
40
  data() {
41
41
  return {
42
- api: this.api(),
43
42
  expanded: false,
44
43
  };
45
44
  },
46
45
 
47
46
  mounted() {
48
- this.api.registerListboxButton(this);
47
+ this.api().registerListboxButton(this);
49
48
  },
50
49
 
51
50
  methods: {
@@ -59,7 +58,7 @@ export default {
59
58
  },
60
59
 
61
60
  onClick() {
62
- const listbox = this.api.getListbox();
61
+ const listbox = this.api().getListbox();
63
62
  this.expanded ? listbox.hide() : listbox.show();
64
63
 
65
64
  this.toggleExpanded();
@@ -67,7 +66,7 @@ export default {
67
66
 
68
67
  onKeyDown(event) {
69
68
  const key = event.key;
70
- const listbox = this.api.getListbox();
69
+ const listbox = this.api().getListbox();
71
70
 
72
71
  switch (key) {
73
72
  case keys.down:
@@ -1,7 +1,6 @@
1
1
  <template>
2
2
  <li
3
3
  :id="id"
4
- :aria-selected="selected"
5
4
  class="Listbox-option"
6
5
  role="option"
7
6
  @mousedown.prevent="onMouseDown"
@@ -13,6 +12,7 @@
13
12
  </template>
14
13
 
15
14
  <script>
15
+ import { scrollElementIntoView } from '../utils/components';
16
16
  import { genId } from '../utils/ids';
17
17
  import { areObjsEqual, isObj } from '../utils/objects';
18
18
 
@@ -26,36 +26,41 @@ export default {
26
26
  type: [String, Number, Object],
27
27
  required: true,
28
28
  },
29
+ selected: {
30
+ type: Boolean,
31
+ default: false,
32
+ },
29
33
  },
30
34
 
31
35
  data() {
32
36
  return {
33
- api: this.api(),
34
37
  id: `listbox-option-${genId()}`,
35
- selected: false,
36
38
  focused: false,
37
39
  isMousemove: false,
40
+ parent: null,
38
41
  };
39
42
  },
40
43
 
41
44
  watch: {
42
45
  focused(newValue) {
43
- if (newValue) {
44
- if (!this.isMousemove) {
45
- this.$el.scrollIntoView({ block: 'nearest' });
46
- }
46
+ if (!newValue) return;
47
47
 
48
- const listbox = this.api.getListbox();
49
- listbox.updateActiveDescendant(this.id);
50
- }
48
+ if (!this.parent) this.parent = this.api().getListbox();
49
+ if (!this.isMousemove) scrollElementIntoView(this.$el, this.parent.$el);
50
+ this.parent.updateActiveDescendant(this.id);
51
51
  },
52
52
  },
53
53
 
54
54
  mounted() {
55
- this.api.registerOption(this);
55
+ this.api().registerOption(this);
56
+
57
+ if (this.selected) {
58
+ this.select();
59
+ this.focus();
60
+ }
56
61
 
57
62
  // todo: make sure it works with other values than objects
58
- const listboxOptionSelected = this.api.getListboxValue();
63
+ const listboxOptionSelected = this.api().getListboxValue();
59
64
 
60
65
  if (!listboxOptionSelected) {
61
66
  return;
@@ -77,7 +82,7 @@ export default {
77
82
  },
78
83
 
79
84
  beforeDestroy() {
80
- this.api.unregisterOption(this.id);
85
+ this.api().unregisterOption(this.id);
81
86
  },
82
87
 
83
88
  methods: {
@@ -92,15 +97,15 @@ export default {
92
97
  },
93
98
 
94
99
  select() {
95
- this.selected = true;
100
+ this.$el.setAttribute('aria-selected', true);
96
101
  },
97
102
 
98
103
  unselect() {
99
- this.selected = false;
104
+ this.$el.setAttribute('aria-selected', false);
100
105
  },
101
106
 
102
107
  onMouseDown(event) {
103
- if (event.buttons === 1) this.api.selectOption(this);
108
+ if (event.buttons === 1) this.api().selectOption(this);
104
109
  },
105
110
 
106
111
  // Mousemove instead of mouseover to support keyboard navigation.
@@ -108,7 +113,7 @@ export default {
108
113
  // mouseover event gets triggered.
109
114
  onMousemove() {
110
115
  this.isMousemove = true;
111
- this.api.unfocusOptions();
116
+ this.api().unfocusOptions();
112
117
  this.focus();
113
118
  },
114
119
 
@@ -23,7 +23,6 @@ export default {
23
23
 
24
24
  data() {
25
25
  return {
26
- api: this.api(),
27
26
  visible: false,
28
27
  filter: '',
29
28
  };
@@ -37,7 +36,7 @@ export default {
37
36
  this.handleOptionFocus();
38
37
  });
39
38
  } else {
40
- const listboxButton = this.api.getListboxButton();
39
+ const listboxButton = this.api().getListboxButton();
41
40
 
42
41
  this.$nextTick(() => {
43
42
  listboxButton.focus();
@@ -47,7 +46,7 @@ export default {
47
46
  },
48
47
 
49
48
  mounted() {
50
- this.api.registerListbox(this);
49
+ this.api().registerListbox(this);
51
50
  },
52
51
 
53
52
  methods: {
@@ -60,8 +59,8 @@ export default {
60
59
  },
61
60
 
62
61
  handleOptionFocus() {
63
- const selectedIndex = this.api.getFocusedIndex();
64
- if (!selectedIndex) this.api.focusFirstOption();
62
+ const selectedIndex = this.api().getFocusedIndex();
63
+ if (!selectedIndex) this.api().focusFirstOption();
65
64
  },
66
65
 
67
66
  updateActiveDescendant(id) {
@@ -78,31 +77,31 @@ export default {
78
77
  clearTimeout(timer);
79
78
 
80
79
  timer = setTimeout(() => {
81
- this.api.focusOptionByFilter(this.filter);
80
+ this.api().focusOptionByFilter(this.filter);
82
81
  this.filter = '';
83
- }, 300);
82
+ }, 100);
84
83
  }
85
84
 
86
85
  switch (key) {
87
86
  case keys.up:
88
87
  event.preventDefault();
89
- this.api.focusPreviousOption();
88
+ this.api().focusPreviousOption();
90
89
  break;
91
90
  case keys.down:
92
91
  event.preventDefault();
93
- this.api.focusNextOption();
92
+ this.api().focusNextOption();
94
93
  break;
95
94
  case keys.home:
96
95
  event.preventDefault();
97
- this.api.focusFirstOption();
96
+ this.api().focusFirstOption();
98
97
  break;
99
98
  case keys.end:
100
99
  event.preventDefault();
101
- this.api.focusLastOption();
100
+ this.api().focusLastOption();
102
101
  break;
103
102
  case keys.enter:
104
103
  event.preventDefault();
105
- this.api.selectOption();
104
+ this.api().selectOption();
106
105
  break;
107
106
  case keys.escape:
108
107
  this.hide();
@@ -0,0 +1,18 @@
1
+ /**
2
+ *
3
+ * @param {HTMLElement} el
4
+ * @param {HTMLElement} parent
5
+ */
6
+ export const scrollElementIntoView = (el, parent) => {
7
+ // this works better than scrollIntoView
8
+ if (parent.scrollHeight <= parent.clientHeight) return;
9
+
10
+ const scrollBottom = parent.clientHeight + parent.scrollTop;
11
+ const elBottom = el.offsetTop + el.offsetHeight;
12
+
13
+ if (elBottom > scrollBottom) {
14
+ parent.scrollTop = elBottom - parent.clientHeight;
15
+ } else if (el.offsetTop < parent.scrollTop) {
16
+ parent.scrollTop = el.offsetTop;
17
+ }
18
+ };
package/src/utils/ids.js CHANGED
@@ -11,24 +11,3 @@ export const genId = () => {
11
11
  if (!gen) gen = idMaker();
12
12
  return gen.next().value;
13
13
  };
14
-
15
- // Add leading zeros
16
- // export const pad = (num, size) => {
17
- // let s = num + '';
18
-
19
- // while (s.length < size) {
20
- // s = '0' + s;
21
- // }
22
-
23
- // return s;
24
- // };
25
-
26
- export const addZerosToId = (id) => {
27
- let formattedId = null;
28
-
29
- if (id < 10) formattedId = '000' + id;
30
- else if (id < 100) formattedId = '00' + id;
31
- else if (id < 1000) formattedId = '0' + id;
32
-
33
- return '#' + formattedId;
34
- };