@vue-interface/btn-dropdown 4.1.1 → 4.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.
@@ -0,0 +1,166 @@
1
+ import { ComponentPublicInstance } from 'vue';
2
+ import { BtnDropdownProps, BtnDropdownSlotProps } from './useDropdownHandler';
3
+ declare function __VLS_template(): {
4
+ attrs: Partial<{}>;
5
+ slots: Readonly<{
6
+ button(props: {
7
+ expanded: BtnDropdownSlotProps["expanded"];
8
+ onBlur: BtnDropdownSlotProps["onBlur"];
9
+ onClickToggle: BtnDropdownSlotProps["onClickToggle"];
10
+ }): any;
11
+ toggle(props: BtnDropdownSlotProps): any;
12
+ default(): any;
13
+ }> & {
14
+ button(props: {
15
+ expanded: BtnDropdownSlotProps["expanded"];
16
+ onBlur: BtnDropdownSlotProps["onBlur"];
17
+ onClickToggle: BtnDropdownSlotProps["onClickToggle"];
18
+ }): any;
19
+ toggle(props: BtnDropdownSlotProps): any;
20
+ default(): any;
21
+ };
22
+ refs: {
23
+ target: HTMLButtonElement;
24
+ menu: ({
25
+ $: import('vue').ComponentInternalInstance;
26
+ $data: {};
27
+ $props: {
28
+ readonly align?: "left" | "right" | undefined;
29
+ readonly show?: boolean | undefined;
30
+ } & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps;
31
+ $attrs: {
32
+ [x: string]: unknown;
33
+ };
34
+ $refs: {
35
+ [x: string]: unknown;
36
+ };
37
+ $slots: Readonly<{
38
+ [name: string]: import('vue').Slot<any> | undefined;
39
+ }>;
40
+ $root: ComponentPublicInstance | null;
41
+ $parent: ComponentPublicInstance | null;
42
+ $host: Element | null;
43
+ $emit: (event: string, ...args: any[]) => void;
44
+ $el: HTMLDivElement;
45
+ $options: import('vue').ComponentOptionsBase<Readonly<{
46
+ align?: "left" | "right";
47
+ show?: boolean;
48
+ }> & Readonly<{}>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, {
49
+ align: "left" | "right";
50
+ }, {}, string, {}, import('vue').GlobalComponents, import('vue').GlobalDirectives, string, import('vue').ComponentProvideOptions> & {
51
+ beforeCreate?: (() => void) | (() => void)[];
52
+ created?: (() => void) | (() => void)[];
53
+ beforeMount?: (() => void) | (() => void)[];
54
+ mounted?: (() => void) | (() => void)[];
55
+ beforeUpdate?: (() => void) | (() => void)[];
56
+ updated?: (() => void) | (() => void)[];
57
+ activated?: (() => void) | (() => void)[];
58
+ deactivated?: (() => void) | (() => void)[];
59
+ beforeDestroy?: (() => void) | (() => void)[];
60
+ beforeUnmount?: (() => void) | (() => void)[];
61
+ destroyed?: (() => void) | (() => void)[];
62
+ unmounted?: (() => void) | (() => void)[];
63
+ renderTracked?: ((e: import('vue').DebuggerEvent) => void) | ((e: import('vue').DebuggerEvent) => void)[];
64
+ renderTriggered?: ((e: import('vue').DebuggerEvent) => void) | ((e: import('vue').DebuggerEvent) => void)[];
65
+ errorCaptured?: ((err: unknown, instance: ComponentPublicInstance | null, info: string) => boolean | void) | ((err: unknown, instance: ComponentPublicInstance | null, info: string) => boolean | void)[];
66
+ };
67
+ $forceUpdate: () => void;
68
+ $nextTick: typeof import('vue').nextTick;
69
+ $watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (...args: [R, R, import('@vue/reactivity').OnCleanup]) => any : (...args: [any, any, import('@vue/reactivity').OnCleanup]) => any, options?: import('vue').WatchOptions): import('vue').WatchStopHandle;
70
+ } & Readonly<{
71
+ align: "left" | "right";
72
+ }> & Omit<Readonly<{
73
+ align?: "left" | "right";
74
+ show?: boolean;
75
+ }> & Readonly<{}>, "align"> & import('vue').ShallowUnwrapRef<{}> & {} & import('vue').ComponentCustomProperties & {} & {
76
+ $slots: {
77
+ default?(_: {}): any;
78
+ };
79
+ }) | null;
80
+ };
81
+ rootEl: HTMLDivElement;
82
+ };
83
+ type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
84
+ declare const __VLS_component: import('vue').DefineComponent<BtnDropdownProps, {
85
+ show: () => void;
86
+ hide: () => void;
87
+ toggle: () => void;
88
+ }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
89
+ show: () => any;
90
+ click: (event: MouseEvent) => any;
91
+ clickToggle: (event: MouseEvent) => any;
92
+ hide: () => any;
93
+ }, string, import('vue').PublicProps, Readonly<BtnDropdownProps> & Readonly<{
94
+ onShow?: (() => any) | undefined;
95
+ onClick?: ((event: MouseEvent) => any) | undefined;
96
+ onClickToggle?: ((event: MouseEvent) => any) | undefined;
97
+ onHide?: (() => any) | undefined;
98
+ }>, {
99
+ caret: boolean;
100
+ variant: string;
101
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
102
+ target: HTMLButtonElement;
103
+ menu: ({
104
+ $: import('vue').ComponentInternalInstance;
105
+ $data: {};
106
+ $props: {
107
+ readonly align?: "left" | "right" | undefined;
108
+ readonly show?: boolean | undefined;
109
+ } & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps;
110
+ $attrs: {
111
+ [x: string]: unknown;
112
+ };
113
+ $refs: {
114
+ [x: string]: unknown;
115
+ };
116
+ $slots: Readonly<{
117
+ [name: string]: import('vue').Slot<any> | undefined;
118
+ }>;
119
+ $root: ComponentPublicInstance | null;
120
+ $parent: ComponentPublicInstance | null;
121
+ $host: Element | null;
122
+ $emit: (event: string, ...args: any[]) => void;
123
+ $el: HTMLDivElement;
124
+ $options: import('vue').ComponentOptionsBase<Readonly<{
125
+ align?: "left" | "right";
126
+ show?: boolean;
127
+ }> & Readonly<{}>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, {
128
+ align: "left" | "right";
129
+ }, {}, string, {}, import('vue').GlobalComponents, import('vue').GlobalDirectives, string, import('vue').ComponentProvideOptions> & {
130
+ beforeCreate?: (() => void) | (() => void)[];
131
+ created?: (() => void) | (() => void)[];
132
+ beforeMount?: (() => void) | (() => void)[];
133
+ mounted?: (() => void) | (() => void)[];
134
+ beforeUpdate?: (() => void) | (() => void)[];
135
+ updated?: (() => void) | (() => void)[];
136
+ activated?: (() => void) | (() => void)[];
137
+ deactivated?: (() => void) | (() => void)[];
138
+ beforeDestroy?: (() => void) | (() => void)[];
139
+ beforeUnmount?: (() => void) | (() => void)[];
140
+ destroyed?: (() => void) | (() => void)[];
141
+ unmounted?: (() => void) | (() => void)[];
142
+ renderTracked?: ((e: import('vue').DebuggerEvent) => void) | ((e: import('vue').DebuggerEvent) => void)[];
143
+ renderTriggered?: ((e: import('vue').DebuggerEvent) => void) | ((e: import('vue').DebuggerEvent) => void)[];
144
+ errorCaptured?: ((err: unknown, instance: ComponentPublicInstance | null, info: string) => boolean | void) | ((err: unknown, instance: ComponentPublicInstance | null, info: string) => boolean | void)[];
145
+ };
146
+ $forceUpdate: () => void;
147
+ $nextTick: typeof import('vue').nextTick;
148
+ $watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (...args: [R, R, import('@vue/reactivity').OnCleanup]) => any : (...args: [any, any, import('@vue/reactivity').OnCleanup]) => any, options?: import('vue').WatchOptions): import('vue').WatchStopHandle;
149
+ } & Readonly<{
150
+ align: "left" | "right";
151
+ }> & Omit<Readonly<{
152
+ align?: "left" | "right";
153
+ show?: boolean;
154
+ }> & Readonly<{}>, "align"> & import('vue').ShallowUnwrapRef<{}> & {} & import('vue').ComponentCustomProperties & {} & {
155
+ $slots: {
156
+ default?(_: {}): any;
157
+ };
158
+ }) | null;
159
+ }, HTMLDivElement>;
160
+ declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
161
+ export default _default;
162
+ type __VLS_WithTemplateSlots<T, S> = T & {
163
+ new (): {
164
+ $slots: S;
165
+ };
166
+ };
@@ -1,7 +1,7 @@
1
1
  import { Placement, Alignment, Middleware, OffsetOptions, Side } from '@floating-ui/dom';
2
2
  import { UseFloatingReturn } from '@floating-ui/vue';
3
3
  import { DropdownMenu } from '@vue-interface/dropdown-menu';
4
- import { ComputedRef, Ref, EmitFn, HTMLAttributes } from 'vue';
4
+ import { ComponentPublicInstance, ComputedRef, Ref, EmitFn, HTMLAttributes } from 'vue';
5
5
  type LiteralUnion<T extends U, U = string> = T | (U & Record<never, never>);
6
6
  export type BtnGroupSizes = 'btn-group-xs' | 'btn-group-sm' | 'btn-group-md' | 'btn-group-lg' | 'btn-group-xl' | 'btn-group-2xl' | 'btn-group-3xl' | 'btn-group-4xl';
7
7
  export type BtnDropdownProps = {
@@ -26,8 +26,14 @@ export type BtnDropdownEvents = {
26
26
  show: [];
27
27
  hide: [];
28
28
  };
29
+ export type BtnDropdownSlotProps = {
30
+ target: (el: Element | ComponentPublicInstance | null) => void;
31
+ expanded: boolean;
32
+ onBlur: (e: FocusEvent) => void;
33
+ onClickToggle: (e: MouseEvent) => void;
34
+ };
29
35
  export type UseDropdownHandler = {
30
- target: Ref<HTMLElement | undefined>;
36
+ target: Ref<Element | ComponentPublicInstance | null>;
31
37
  menu: Ref<InstanceType<typeof DropdownMenu> | undefined>;
32
38
  alignment: ComputedRef<Alignment>;
33
39
  expanded: Ref<boolean>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vue-interface/btn-dropdown",
3
- "version": "4.1.1",
3
+ "version": "4.1.3",
4
4
  "description": "A Vue button dropdown component.",
5
5
  "type": "module",
6
6
  "main": "./dist/btn-dropdown.umd.cjs",
@@ -49,7 +49,10 @@
49
49
  "@floating-ui/vue": "^1.1.6",
50
50
  "vue": "^3.3.4",
51
51
  "@vue-interface/btn": "5.0.5",
52
- "@vue-interface/dropdown-menu": "3.0.6"
52
+ "@vue-interface/dropdown-menu": "3.0.7"
53
+ },
54
+ "devDependencies": {
55
+ "vue-component-type-helpers": "^3.2.2"
53
56
  },
54
57
  "scripts": {
55
58
  "dev": "vite",
@@ -1,7 +1,9 @@
1
1
  <script setup lang="ts">
2
+ import { useTemplateRef } from 'vue';
3
+ import { type ComponentExposed } from 'vue-component-type-helpers';
2
4
  import BtnDropdownSingle from './BtnDropdownSingle.vue';
3
5
  import BtnDropdownSplit from './BtnDropdownSplit.vue';
4
- import { BtnDropdownEvents, BtnDropdownProps } from './useDropdownHandler';
6
+ import { BtnDropdownEvents, BtnDropdownProps, BtnDropdownSlotProps } from './useDropdownHandler';
5
7
 
6
8
  const props = withDefaults(defineProps<{
7
9
  split?: boolean
@@ -11,10 +13,26 @@ const props = withDefaults(defineProps<{
11
13
  });
12
14
 
13
15
  const emit = defineEmits<BtnDropdownEvents>();
16
+
17
+ const el = useTemplateRef<ComponentExposed<typeof BtnDropdownSingle | typeof BtnDropdownSplit>>('el');
18
+
19
+ defineExpose({
20
+ hide: () => el.value?.hide(),
21
+ show: () => el.value?.show(),
22
+ toggle: () => el.value?.toggle(),
23
+ });
24
+
25
+ defineSlots<{
26
+ button(props: BtnDropdownSlotProps): any;
27
+ toggle(props: BtnDropdownSlotProps): any;
28
+ split(props: BtnDropdownSlotProps): any;
29
+ default(): any;
30
+ }>();
14
31
  </script>
15
32
 
16
33
  <template>
17
34
  <Component
35
+ ref="el"
18
36
  :is="!split ? BtnDropdownSingle : BtnDropdownSplit"
19
37
  v-bind="props"
20
38
  @click="(e: MouseEvent) => emit('click', e)"
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { DropdownMenu } from '@vue-interface/dropdown-menu';
3
- import { BtnDropdownEvents, BtnDropdownProps, useDropdownHandler } from './useDropdownHandler';
3
+ import { ComponentPublicInstance } from 'vue';
4
+ import { BtnDropdownEvents, BtnDropdownProps, BtnDropdownSlotProps, useDropdownHandler } from './useDropdownHandler';
4
5
 
5
6
  const props = withDefaults(defineProps<BtnDropdownProps>(), {
6
7
  caret: true,
@@ -29,6 +30,11 @@ defineExpose({
29
30
  hide,
30
31
  toggle,
31
32
  });
33
+
34
+ defineSlots<{
35
+ button(props: BtnDropdownSlotProps): any;
36
+ default(): any;
37
+ }>();
32
38
  </script>
33
39
 
34
40
  <template>
@@ -37,7 +43,12 @@ defineExpose({
37
43
  :class="classes">
38
44
  <slot
39
45
  name="button"
40
- v-bind="{ target: (el: HTMLElement) => target = el, expanded, onBlur, onClickToggle }">
46
+ v-bind="{
47
+ target: (el: Element | ComponentPublicInstance | null) => target = el,
48
+ expanded,
49
+ onBlur,
50
+ onClickToggle
51
+ }">
41
52
  <button
42
53
  ref="target"
43
54
  type="button"
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { DropdownMenu } from '@vue-interface/dropdown-menu';
3
- import { BtnDropdownEvents, BtnDropdownProps, useDropdownHandler } from './useDropdownHandler';
3
+ import { ComponentPublicInstance } from 'vue';
4
+ import { BtnDropdownEvents, BtnDropdownProps, BtnDropdownSlotProps, useDropdownHandler } from './useDropdownHandler';
4
5
 
5
6
  const props = withDefaults(defineProps<BtnDropdownProps>(), {
6
7
  caret: true,
@@ -29,6 +30,16 @@ defineExpose({
29
30
  hide,
30
31
  toggle,
31
32
  });
33
+
34
+ defineSlots<{
35
+ button(props: {
36
+ expanded: BtnDropdownSlotProps['expanded'],
37
+ onBlur: BtnDropdownSlotProps['onBlur'],
38
+ onClickToggle: BtnDropdownSlotProps['onClickToggle']
39
+ }): any;
40
+ toggle(props: BtnDropdownSlotProps): any;
41
+ default(): any;
42
+ }>();
32
43
  </script>
33
44
 
34
45
  <template>
@@ -52,7 +63,12 @@ defineExpose({
52
63
  <div class="btn-group">
53
64
  <slot
54
65
  name="toggle"
55
- v-bind="{ target: (el: HTMLElement) => target = el, expanded, onBlur, onClickToggle }">
66
+ v-bind="{
67
+ target: (el: Element | ComponentPublicInstance | null) => target = el,
68
+ expanded,
69
+ onBlur,
70
+ onClickToggle
71
+ }">
56
72
  <button
57
73
  ref="target"
58
74
  type="button"
@@ -1,7 +1,7 @@
1
1
  import { flip, offset, Placement, type Alignment, type Middleware, type OffsetOptions, type Side } from '@floating-ui/dom';
2
2
  import { useFloating, UseFloatingReturn } from '@floating-ui/vue';
3
3
  import { DropdownMenu } from '@vue-interface/dropdown-menu';
4
- import { computed, ComputedRef, Ref, ref, watchEffect, type EmitFn, type HTMLAttributes } from 'vue';
4
+ import { ComponentPublicInstance, computed, ComputedRef, Ref, ref, watchEffect, type EmitFn, type HTMLAttributes } from 'vue';
5
5
 
6
6
  type LiteralUnion<T extends U, U = string> = T | (U & Record<never, never>);
7
7
 
@@ -38,8 +38,15 @@ export type BtnDropdownEvents = {
38
38
  hide: []
39
39
  }
40
40
 
41
+ export type BtnDropdownSlotProps = {
42
+ target: (el: Element | ComponentPublicInstance | null) => void;
43
+ expanded: boolean;
44
+ onBlur: (e: FocusEvent) => void;
45
+ onClickToggle: (e: MouseEvent) => void;
46
+ };
47
+
41
48
  export type UseDropdownHandler = {
42
- target: Ref<HTMLElement|undefined>;
49
+ target: Ref<Element|ComponentPublicInstance|null>;
43
50
  menu: Ref<InstanceType<typeof DropdownMenu>|undefined>;
44
51
  alignment: ComputedRef<Alignment>;
45
52
  expanded: Ref<boolean>;
@@ -58,7 +65,7 @@ export type UseDropdownHandler = {
58
65
  }
59
66
 
60
67
  export function useDropdownHandler(props: BtnDropdownProps, emit: EmitFn<BtnDropdownEvents>): UseDropdownHandler {
61
- const target = ref<HTMLElement>();
68
+ const target = ref<Element|ComponentPublicInstance|null>(null);
62
69
  const menu = ref<InstanceType<typeof DropdownMenu>>();
63
70
  const expanded = ref(false);
64
71
 
@@ -137,7 +144,9 @@ export function useDropdownHandler(props: BtnDropdownProps, emit: EmitFn<BtnDrop
137
144
  function hide() {
138
145
  expanded.value = false;
139
146
 
140
- target.value?.blur();
147
+ if(target.value instanceof HTMLElement) {
148
+ target.value?.blur();
149
+ }
141
150
 
142
151
  emit('hide');
143
152
  }
@@ -164,7 +173,7 @@ export function useDropdownHandler(props: BtnDropdownProps, emit: EmitFn<BtnDrop
164
173
  }
165
174
 
166
175
  function onBlur(e: FocusEvent) {
167
- if(!(e.relatedTarget instanceof HTMLElement)) {
176
+ if(!(e.relatedTarget instanceof HTMLElement) || !(target.value instanceof Element)) {
168
177
  hide();
169
178
 
170
179
  return;