vueless 0.0.112 → 0.0.113

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.
@@ -0,0 +1,53 @@
1
+ import { unref } from "vue";
2
+
3
+ function clickOutside(target, handler, options) {
4
+ const { capture = true } = options;
5
+
6
+ let shouldListen = true;
7
+
8
+ const el = unref(target);
9
+
10
+ function onClick(event) {
11
+ if (!el || el === event.target || event.composedPath().includes(el)) return;
12
+
13
+ if (!shouldListen) {
14
+ shouldListen = true;
15
+
16
+ return;
17
+ }
18
+
19
+ handler(event);
20
+ }
21
+
22
+ function onPointerdown(event) {
23
+ shouldListen = !!(el && !event.composedPath().includes(el));
24
+ }
25
+
26
+ window.addEventListener("click", onClick, { passive: true, capture });
27
+ window.addEventListener("pointerdown", onPointerdown, { passive: true });
28
+
29
+ function removeEvents() {
30
+ window.removeEventListener("click", onClick, { capture, passive: true });
31
+ window.removeEventListener("pointerdown", onPointerdown, { passive: true });
32
+ }
33
+
34
+ return removeEvents;
35
+ }
36
+
37
+ export default {
38
+ mounted(el, binding) {
39
+ const capture = !binding.modifiers.bubble;
40
+
41
+ if (typeof binding.value === "function") {
42
+ el._clickOutsideRemove = clickOutside(el, binding.value, { capture });
43
+ } else {
44
+ const [handler, options] = binding.value;
45
+
46
+ el._clickOutsideRemove = clickOutside(el, handler, Object.assign({ capture }, options));
47
+ }
48
+ },
49
+
50
+ unmounted(el) {
51
+ el._clickOutsideRemove();
52
+ },
53
+ };
@@ -21,11 +21,13 @@ export default {
21
21
  mounted(el, bindings) {
22
22
  tippy(el, merge(mergedSettings, bindings.value || {}));
23
23
  },
24
+
24
25
  updated(el, bindings) {
25
26
  if (!el._tippy) return;
26
27
 
27
28
  el._tippy.setProps(merge(mergedSettings, bindings.value || {}));
28
29
  },
30
+
29
31
  unmounted(el) {
30
32
  if (!el._tippy) return;
31
33
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vueless",
3
- "version": "0.0.112",
3
+ "version": "0.0.113",
4
4
  "license": "MIT",
5
5
  "description": "Vue Styleless Component Framework.",
6
6
  "homepage": "https://vueless.com",
@@ -1,8 +1,7 @@
1
1
  <template>
2
- <div v-bind="wrapperAttrs">
2
+ <div v-click-outside="hideOptions" v-bind="wrapperAttrs">
3
3
  <UBadge
4
4
  :id="id"
5
- ref="badgeRef"
6
5
  :label="label"
7
6
  :size="size"
8
7
  :color="color"
@@ -10,8 +9,7 @@
10
9
  :variant="variant"
11
10
  :data-cy="`${dataCy}-badge`"
12
11
  v-bind="badgeAttrs"
13
- @click.stop="onClickBadge"
14
- @blur="onBlurBadge"
12
+ @click="onClickBadge"
15
13
  >
16
14
  <template #right>
17
15
  <UIcon
@@ -26,26 +24,32 @@
26
24
  </template>
27
25
  </UBadge>
28
26
 
29
- <div v-if="isShownOptions && hasSlotContent($slots['default'])" v-bind="listWrapperAttrs">
27
+ <div
28
+ v-if="isShownOptions && hasSlotContent($slots['default'])"
29
+ v-bind="listWrapperAttrs"
30
+ @click="onClickList"
31
+ >
30
32
  <!-- @slot Use it to add dropdown list. -->
31
33
  <slot />
32
34
  </div>
33
35
 
34
36
  <UDropdownList
35
37
  v-if="isShownOptions && !hasSlotContent($slots['default'])"
36
- v-model="selectValue"
38
+ v-model="selectedItem"
37
39
  :size="size"
38
40
  :options="options"
39
41
  :value-key="valueKey"
40
42
  :label-key="labelKey"
41
43
  :data-cy="`${dataCy}-item`"
42
44
  v-bind="listAttrs"
45
+ @mousedown.stop
46
+ @click.stop="onClickList"
43
47
  />
44
48
  </div>
45
49
  </template>
46
50
 
47
51
  <script setup>
48
- import { computed, onMounted, onUnmounted, provide, ref, watch } from "vue";
52
+ import { computed, provide, ref, watch } from "vue";
49
53
 
50
54
  import UIcon from "../ui.image-icon";
51
55
  import UBadge from "../ui.text-badge";
@@ -53,6 +57,8 @@ import UDropdownList from "../ui.dropdown-list";
53
57
 
54
58
  import UIService, { getRandomId } from "../service.ui";
55
59
 
60
+ import vClickOutside from "../directive.clickOutside";
61
+
56
62
  import defaultConfig from "./configs/default.config";
57
63
  import { UDropdownBadge } from "./constants";
58
64
  import { useAttrs } from "./composables/attrs.composable";
@@ -61,14 +67,6 @@ import { useAttrs } from "./composables/attrs.composable";
61
67
  defineOptions({ name: "UDropdownBadge", inheritAttrs: false });
62
68
 
63
69
  const props = defineProps({
64
- /**
65
- * Selected value.
66
- */
67
- modelValue: {
68
- type: [String, Number],
69
- default: "",
70
- },
71
-
72
70
  /**
73
71
  * Badge label.
74
72
  */
@@ -189,25 +187,16 @@ const props = defineProps({
189
187
  },
190
188
  });
191
189
 
192
- provide("hideDropdownOptions", () => hideOptions);
190
+ const emit = defineEmits(["select"]);
193
191
 
194
- const emit = defineEmits(["update:modelValue"]);
192
+ provide("hideDropdownOptions", () => hideOptions);
195
193
 
196
194
  const isShownOptions = ref(false);
197
-
198
- const badgeRef = ref(null);
195
+ const selectedItem = ref("");
199
196
 
200
197
  const { config, listWrapperAttrs, wrapperAttrs, badgeAttrs, listAttrs, iconAttrs, hasSlotContent } =
201
198
  useAttrs(props, { isShownOptions });
202
199
 
203
- const selectValue = computed({
204
- get: () => props.modelValue,
205
- set: (value) => {
206
- isShownOptions.value = false;
207
- emit("update:modelValue", value);
208
- },
209
- });
210
-
211
200
  const iconSize = computed(() => {
212
201
  const sizes = {
213
202
  sm: "xs",
@@ -218,10 +207,9 @@ const iconSize = computed(() => {
218
207
  return sizes[props.size];
219
208
  });
220
209
 
221
- watch(() => props.modelValue, hideOptions);
222
-
223
- onMounted(() => window.addEventListener("click", onClickOutside));
224
- onUnmounted(() => window.removeEventListener("click", onClickOutside));
210
+ watch(selectedItem, () => {
211
+ emit("select", selectedItem.value);
212
+ });
225
213
 
226
214
  function onClickBadge() {
227
215
  isShownOptions.value = !isShownOptions.value;
@@ -231,17 +219,7 @@ function hideOptions() {
231
219
  isShownOptions.value = false;
232
220
  }
233
221
 
234
- function onClickOutside(event) {
235
- if (!badgeRef.value?.wrapperRef?.contains(event.target)) {
236
- hideOptions();
237
- }
238
- }
239
-
240
- function onBlurBadge(event) {
241
- setTimeout(() => {
242
- if (!event.target.isEqualNode(event.relatedTarget) && event.relatedTarget) {
243
- hideOptions();
244
- }
245
- }, 100);
222
+ function onClickList() {
223
+ hideOptions();
246
224
  }
247
225
  </script>
@@ -1,8 +1,7 @@
1
1
  <template>
2
- <div v-bind="wrapperAttrs">
2
+ <div v-click-outside="hideOptions" v-bind="wrapperAttrs">
3
3
  <UButton
4
4
  :id="id"
5
- ref="buttonRef"
6
5
  :label="label"
7
6
  :size="size"
8
7
  :variant="variant"
@@ -13,8 +12,7 @@
13
12
  :disabled="disabled"
14
13
  :data-cy="`${dataCy}-button`"
15
14
  v-bind="buttonAttrs"
16
- @click.stop="onClickButton"
17
- @blur="onBlurButton"
15
+ @click="onClickButton"
18
16
  >
19
17
  <template #right>
20
18
  <UIcon
@@ -29,14 +27,18 @@
29
27
  </template>
30
28
  </UButton>
31
29
 
32
- <div v-if="isShownOptions && hasSlotContent($slots['default'])" v-bind="listWrapperAttrs">
30
+ <div
31
+ v-if="isShownOptions && hasSlotContent($slots['default'])"
32
+ v-bind="listWrapperAttrs"
33
+ @click="onClickList"
34
+ >
33
35
  <!-- @slot Use it to add dropdown list. -->
34
36
  <slot />
35
37
  </div>
36
38
 
37
39
  <UDropdownList
38
40
  v-if="isShownOptions && !hasSlotContent($slots['default'])"
39
- v-model="selectValue"
41
+ v-model="selectedItem"
40
42
  :size="size"
41
43
  :options="options"
42
44
  :value-key="valueKey"
@@ -45,13 +47,13 @@
45
47
  tabindex="-1"
46
48
  v-bind="listAttrs"
47
49
  @mousedown.stop
48
- @click.stop
50
+ @click.stop="onClickList"
49
51
  />
50
52
  </div>
51
53
  </template>
52
54
 
53
55
  <script setup>
54
- import { computed, onMounted, onUnmounted, provide, ref, watch } from "vue";
56
+ import { computed, provide, ref, watch } from "vue";
55
57
 
56
58
  import UIcon from "../ui.image-icon";
57
59
  import UButton from "../ui.button";
@@ -59,6 +61,8 @@ import UDropdownList from "../ui.dropdown-list";
59
61
 
60
62
  import UIService, { getRandomId } from "../service.ui";
61
63
 
64
+ import vClickOutside from "../directive.clickOutside";
65
+
62
66
  import defaultConfig from "./configs/default.config";
63
67
  import { useAttrs } from "./composables/attrs.composable";
64
68
  import { UDropdownButton, BUTTON_VARIANT } from "./constants";
@@ -218,12 +222,12 @@ const props = defineProps({
218
222
  },
219
223
  });
220
224
 
221
- provide("hideDropdownOptions", () => hideOptions);
225
+ const emit = defineEmits(["select"]);
222
226
 
223
- const emit = defineEmits(["update:modelValue"]);
227
+ provide("hideDropdownOptions", () => hideOptions);
224
228
 
225
229
  const isShownOptions = ref(false);
226
- const buttonRef = ref(null);
230
+ const selectedItem = ref("");
227
231
 
228
232
  const {
229
233
  config,
@@ -235,14 +239,6 @@ const {
235
239
  hasSlotContent,
236
240
  } = useAttrs(props, { isShownOptions });
237
241
 
238
- const selectValue = computed({
239
- get: () => props.modelValue,
240
- set: (value) => {
241
- isShownOptions.value = false;
242
- emit("update:modelValue", value);
243
- },
244
- });
245
-
246
242
  const iconColor = computed(() => {
247
243
  return props.variant === BUTTON_VARIANT.primary ? "white" : props.color;
248
244
  });
@@ -257,10 +253,9 @@ const iconSize = computed(() => {
257
253
  return sizes[props.size];
258
254
  });
259
255
 
260
- watch(() => props.modelValue, hideOptions);
261
-
262
- onMounted(() => window.addEventListener("click", onClickOutside));
263
- onUnmounted(() => window.removeEventListener("click", onClickOutside));
256
+ watch(selectedItem, () => {
257
+ emit("select", selectedItem.value);
258
+ });
264
259
 
265
260
  function onClickButton() {
266
261
  isShownOptions.value = !isShownOptions.value;
@@ -270,17 +265,7 @@ function hideOptions() {
270
265
  isShownOptions.value = false;
271
266
  }
272
267
 
273
- function onClickOutside(event) {
274
- if (!buttonRef.value?.buttonRef?.contains(event.target)) {
275
- hideOptions();
276
- }
277
- }
278
-
279
- function onBlurButton(event) {
280
- setTimeout(() => {
281
- if (!event.target.isEqualNode(event.relatedTarget) && event.relatedTarget) {
282
- hideOptions();
283
- }
284
- }, 100);
268
+ function onClickList() {
269
+ hideOptions();
285
270
  }
286
271
  </script>
@@ -1,9 +1,8 @@
1
1
  <template>
2
- <div v-bind="wrapperAttrs">
2
+ <div v-click-outside="hideOptions" v-bind="wrapperAttrs">
3
3
  <div v-bind="triggerAttrs">
4
4
  <ULink
5
5
  :id="id"
6
- ref="linkRef"
7
6
  :label="label"
8
7
  :size="size"
9
8
  :color="color"
@@ -13,43 +12,50 @@
13
12
  :no-ring="noRing"
14
13
  :data-cy="`${dataCy}-link`"
15
14
  v-bind="linkAttrs"
16
- @click.stop="onClickLink"
17
- @blur="onBlurLink"
15
+ @click="onClickLink"
18
16
  >
19
17
  <template #right>
20
18
  <UIcon
21
19
  v-if="!noIcon"
22
20
  internal
21
+ interactive
23
22
  :name="config.iconName"
24
23
  :size="iconSize"
25
24
  :color="color"
26
25
  :data-cy="`${dataCy}-caret`"
27
26
  v-bind="iconAttrs"
27
+ @click.stop="onClickLink"
28
28
  />
29
29
  </template>
30
30
  </ULink>
31
31
  </div>
32
32
 
33
- <div v-if="isShownOptions && hasSlotContent($slots['default'])" v-bind="listWrapperAttrs">
33
+ <div
34
+ v-if="isShownOptions && hasSlotContent($slots['default'])"
35
+ v-bind="listWrapperAttrs"
36
+ @click="onClickList"
37
+ >
34
38
  <!-- @slot Use it to add dropdown list. -->
35
39
  <slot />
36
40
  </div>
37
41
 
38
42
  <UDropdownList
39
43
  v-if="isShownOptions && !hasSlotContent($slots['default'])"
40
- v-model="selectValue"
44
+ v-model="selectedItem"
41
45
  :size="size"
42
46
  :options="options"
43
47
  :value-key="valueKey"
44
48
  :label-key="labelKey"
45
49
  :data-cy="`${dataCy}-item`"
46
50
  v-bind="listAttrs"
51
+ @mousedown.stop
52
+ @click.stop="onClickList"
47
53
  />
48
54
  </div>
49
55
  </template>
50
56
 
51
57
  <script setup>
52
- import { computed, onMounted, onUnmounted, provide, ref, watch } from "vue";
58
+ import { computed, provide, ref, watch } from "vue";
53
59
 
54
60
  import UIcon from "../ui.image-icon";
55
61
  import ULink from "../ui.button-link";
@@ -57,6 +63,8 @@ import UDropdownList from "../ui.dropdown-list";
57
63
 
58
64
  import UIService, { getRandomId } from "../service.ui";
59
65
 
66
+ import vClickOutside from "../directive.clickOutside";
67
+
60
68
  import { UDropdownLink } from "./constants";
61
69
  import defaultConfig from "./configs/default.config";
62
70
  import { useAttrs } from "./composables/attrs.composable";
@@ -65,14 +73,6 @@ import { useAttrs } from "./composables/attrs.composable";
65
73
  defineOptions({ name: "UDropdownLink", inheritAttrs: false });
66
74
 
67
75
  const props = defineProps({
68
- /**
69
- * Selected value.
70
- */
71
- modelValue: {
72
- type: [String, Number],
73
- default: "",
74
- },
75
-
76
76
  /**
77
77
  * Link label.
78
78
  */
@@ -207,13 +207,12 @@ const props = defineProps({
207
207
  },
208
208
  });
209
209
 
210
- provide("hideDropdownOptions", () => hideOptions());
210
+ const emit = defineEmits(["select"]);
211
211
 
212
- const emit = defineEmits(["update:modelValue"]);
212
+ provide("hideDropdownOptions", () => hideOptions());
213
213
 
214
214
  const isShownOptions = ref(false);
215
-
216
- const linkRef = ref(null);
215
+ const selectedItem = ref("");
217
216
 
218
217
  const {
219
218
  config,
@@ -226,14 +225,6 @@ const {
226
225
  hasSlotContent,
227
226
  } = useAttrs(props, { isShownOptions });
228
227
 
229
- const selectValue = computed({
230
- get: () => props.modelValue,
231
- set: (value) => {
232
- isShownOptions.value = false;
233
- emit("update:modelValue", value);
234
- },
235
- });
236
-
237
228
  const iconSize = computed(() => {
238
229
  const sizes = {
239
230
  xs: "2xs",
@@ -245,10 +236,9 @@ const iconSize = computed(() => {
245
236
  return sizes[props.size];
246
237
  });
247
238
 
248
- watch(() => props.modelValue, hideOptions);
249
-
250
- onMounted(() => window.addEventListener("click", onClickOutside));
251
- onUnmounted(() => window.removeEventListener("click", onClickOutside));
239
+ watch(selectedItem, () => {
240
+ emit("select", selectedItem.value);
241
+ });
252
242
 
253
243
  function onClickLink() {
254
244
  isShownOptions.value = !isShownOptions.value;
@@ -258,17 +248,7 @@ function hideOptions() {
258
248
  isShownOptions.value = false;
259
249
  }
260
250
 
261
- function onClickOutside(event) {
262
- if (!linkRef.value?.wrapperRef?.contains(event.target)) {
263
- hideOptions();
264
- }
265
- }
266
-
267
- function onBlurLink(event) {
268
- setTimeout(() => {
269
- if (!event.target.isEqualNode(event.relatedTarget) && event.relatedTarget) {
270
- hideOptions();
271
- }
272
- }, 100);
251
+ function onClickList() {
252
+ hideOptions();
273
253
  }
274
254
  </script>
package/web-types.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "framework": "vue",
3
3
  "name": "vueless",
4
- "version": "0.0.112",
4
+ "version": "0.0.113",
5
5
  "contributions": {
6
6
  "html": {
7
7
  "description-markup": "markdown",
@@ -1994,15 +1994,6 @@
1994
1994
  "name": "UDropdownBadge",
1995
1995
  "description": "",
1996
1996
  "attributes": [
1997
- {
1998
- "name": "modelValue",
1999
- "description": "Selected value.",
2000
- "value": {
2001
- "kind": "expression",
2002
- "type": "string|number"
2003
- },
2004
- "default": "\"\""
2005
- },
2006
1997
  {
2007
1998
  "name": "label",
2008
1999
  "description": "Badge label.",
@@ -2132,7 +2123,7 @@
2132
2123
  ],
2133
2124
  "events": [
2134
2125
  {
2135
- "name": "update:modelValue"
2126
+ "name": "select"
2136
2127
  }
2137
2128
  ],
2138
2129
  "slots": [
@@ -2315,7 +2306,7 @@
2315
2306
  ],
2316
2307
  "events": [
2317
2308
  {
2318
- "name": "update:modelValue"
2309
+ "name": "select"
2319
2310
  }
2320
2311
  ],
2321
2312
  "slots": [
@@ -2380,15 +2371,6 @@
2380
2371
  "name": "UDropdownLink",
2381
2372
  "description": "",
2382
2373
  "attributes": [
2383
- {
2384
- "name": "modelValue",
2385
- "description": "Selected value.",
2386
- "value": {
2387
- "kind": "expression",
2388
- "type": "string|number"
2389
- },
2390
- "default": "\"\""
2391
- },
2392
2374
  {
2393
2375
  "name": "label",
2394
2376
  "description": "Link label.",
@@ -2536,7 +2518,7 @@
2536
2518
  ],
2537
2519
  "events": [
2538
2520
  {
2539
- "name": "update:modelValue"
2521
+ "name": "select"
2540
2522
  }
2541
2523
  ],
2542
2524
  "slots": [