@teammodlr/ui-kit 2.1.68 → 2.1.69

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": "@teammodlr/ui-kit",
3
- "version": "2.1.68",
3
+ "version": "2.1.69",
4
4
  "description": "",
5
5
  "main": "lib/index.cjs.js",
6
6
  "module": "lib/index.es.js",
@@ -5,8 +5,9 @@
5
5
  :enter-active-class="fade.enterActive"
6
6
  :leave-active-class="fade.leaveActive"
7
7
  :enter-from-class="fade.enterFrom"
8
- :leave-to-class="fade.leaveTo">
9
- <div :class="style.root" v-if="open">
8
+ :leave-to-class="fade.leaveTo"
9
+ >
10
+ <div :class="style.root" v-if="open" :style="{ zIndex: zIndex, position: 'fixed', inset: '0', pointerEvents: modal ? 'all' : 'none' }">
10
11
  <div :class="backdropClasses" v-if="modal"></div>
11
12
  <div ref="wrapper" :class="wrapperClasses">
12
13
  <Transition
@@ -27,7 +28,7 @@
27
28
  <div :class="style.header" ref="handle">
28
29
  <div :class="style.title">
29
30
  <slot name="title">
30
- {{ title }}
31
+ {{ resolvedTitle }}
31
32
  </slot>
32
33
  </div>
33
34
  </div>
@@ -48,26 +49,33 @@
48
49
  </TransitionGroup>
49
50
  </Teleport>
50
51
  </template>
51
-
52
52
  <script lang="ts">
53
- import { fade, modalScale } from '../../styles/transitions.css';
54
- import {computed, defineComponent, ref, watch, nextTick, type CSSProperties} from "vue";
55
- import type { ComputedRef } from "vue";
53
+ import {fade, modalScale} from '../../styles/transitions.css';
54
+ import {
55
+ computed,
56
+ defineComponent,
57
+ ref,
58
+ watch,
59
+ nextTick,
60
+ isRef,
61
+ type CSSProperties, type PropType, type Ref,
62
+ } from 'vue';
63
+ import type {ComputedRef} from 'vue';
56
64
 
57
- import { useZIndex } from "../../composables/useZIndex";
58
- import { useDraggable } from "@vueuse/core";
59
- import * as style from "./style";
65
+ import {useZIndex} from '../../composables/useZIndex';
66
+ import {useDraggable} from '@vueuse/core';
67
+ import * as style from './style';
60
68
 
61
69
  export default defineComponent({
62
- name: "Dialog",
70
+ name: 'Dialog',
63
71
  props: {
64
72
  title: {
65
- type: String,
66
- default: ""
73
+ type: [String, Object] as PropType<string | Ref<string>>,
74
+ default: '',
67
75
  },
68
76
  draggable: {
69
77
  type: Boolean,
70
- default: true
78
+ default: true,
71
79
  },
72
80
  modal: {
73
81
  type: Boolean,
@@ -75,32 +83,36 @@ export default defineComponent({
75
83
  },
76
84
  onClose: {
77
85
  type: Function,
78
- default: () => {}
86
+ default: () => {
87
+ },
79
88
  },
80
89
  zIndex: {
81
- type: Number
90
+ type: Number,
82
91
  },
83
92
  width: {
84
93
  type: [Number, String],
85
- default: "500px"
94
+ default: '500px',
86
95
  },
87
96
  focusTrap: {
88
97
  type: Boolean,
89
- default: true
98
+ default: true,
90
99
  },
91
100
  open: {
92
- type: Boolean
93
- }
101
+ type: Boolean,
102
+ default: false,
103
+ },
94
104
  },
95
105
  emits: ['onOpen', 'onClose', 'update:open'],
96
- setup(props, { slots, emit }) {
106
+ setup(props, {emit, expose}) {
97
107
  const wrapper = ref<HTMLElement | null>(null);
98
108
  const dialog = ref<HTMLElement | null>(null);
99
109
  const handle = ref<HTMLElement | null>(null);
100
- const { nextZIndex } = useZIndex();
110
+ const {nextZIndex} = useZIndex();
101
111
  const zIndex = ref(props.zIndex ?? nextZIndex());
102
112
 
103
- const { x, y } = useDraggable(dialog, {
113
+ const isOpen = ref<boolean>(props.open);
114
+
115
+ const {x, y} = useDraggable(dialog, {
104
116
  handle,
105
117
  preventDefault: true,
106
118
  containerElement: wrapper,
@@ -108,6 +120,10 @@ export default defineComponent({
108
120
  onStart: onDragStart,
109
121
  });
110
122
 
123
+ const resolvedTitle = computed(() =>
124
+ isRef(props.title) ? props.title.value : props.title
125
+ );
126
+
111
127
  const backdropClasses = computed(() => ({
112
128
  [style.backdrop]: true,
113
129
  [style.backdropColor]: props.modal === true,
@@ -118,21 +134,25 @@ export default defineComponent({
118
134
  [style.notModal]: !props.modal,
119
135
  }));
120
136
 
121
- const width = computed(() => (
122
- typeof props.width === "number" ? `${props.width}px` : props.width
123
- ));
137
+ const width = computed(() =>
138
+ typeof props.width === 'number' ? `${props.width}px` : props.width,
139
+ );
124
140
 
125
141
  const computedStyle: ComputedRef<CSSProperties> = computed(() => ({
126
142
  position: 'fixed',
127
143
  left: `${x.value}px`,
128
144
  top: `${y.value}px`,
129
145
  width: width.value,
130
- zIndex: zIndex.value
146
+ zIndex: zIndex.value,
131
147
  }));
132
148
 
133
149
  function close() {
150
+ isOpen.value = false;
134
151
  emit('update:open', false);
135
152
  emit('onClose');
153
+ if (props.onClose) {
154
+ props.onClose();
155
+ }
136
156
  }
137
157
 
138
158
  function onEnter() {
@@ -140,41 +160,51 @@ export default defineComponent({
140
160
  zIndex.value = nextZIndex();
141
161
  }
142
162
 
143
- function onDragStart() {
144
- zIndex.value = nextZIndex();
145
- }
163
+ function onDragStart() {
164
+ zIndex.value = nextZIndex();
165
+ }
166
+
167
+ function centerDialog() {
168
+ if (dialog.value) {
169
+ const boundingRect = dialog.value.getBoundingClientRect();
170
+ x.value = (window.innerWidth - boundingRect.width) / 2;
171
+ y.value = (window.innerHeight - boundingRect.height) / 2;
172
+ }
173
+ }
146
174
 
147
- function centerDialog() {
148
- if (dialog.value) {
149
- const boundingRect = dialog.value.getBoundingClientRect();
150
- x.value = (window.innerWidth - boundingRect.width) / 2;
151
- y.value = (window.innerHeight - boundingRect.height) / 2;
152
- }
175
+ watch(
176
+ () => props.open,
177
+ async (newVal) => {
178
+ isOpen.value = newVal;
179
+ if (newVal) {
180
+ await nextTick();
181
+ centerDialog();
153
182
  }
183
+ },
184
+ {immediate: true},
185
+ );
154
186
 
155
- watch(() => props.open, async (newVal) => {
156
- if (newVal) {
157
- await nextTick();
158
- centerDialog();
159
- }
160
- }, { immediate: true });
161
-
162
- return {
163
- slots,
164
- wrapper,
165
- dialog,
166
- handle,
167
- zIndex,
168
- fade,
169
- modalScale,
170
- style,
171
- computedStyle,
172
- backdropClasses,
173
- wrapperClasses,
174
- close,
175
- onEnter,
176
- };
177
- }
187
+ // Expose methods to parent components
188
+ expose({
189
+ close,
178
190
  });
179
- </script>
180
191
 
192
+ return {
193
+ wrapper,
194
+ dialog,
195
+ handle,
196
+ zIndex,
197
+ fade,
198
+ modalScale,
199
+ style,
200
+ computedStyle,
201
+ backdropClasses,
202
+ resolvedTitle,
203
+ wrapperClasses,
204
+ isOpen,
205
+ close,
206
+ onEnter,
207
+ };
208
+ },
209
+ });
210
+ </script>
@@ -0,0 +1,97 @@
1
+ <template>
2
+ <slot/>
3
+ <template v-if="Object.keys(dialogMap).length > 0">
4
+ <Teleport to="body">
5
+ <MDialog
6
+ v-for="dialog in Object.values(dialogMap)"
7
+ :key="dialog.key"
8
+ v-bind="dialog.options"
9
+ ref="setDialogRef(dialog.key)"
10
+ @close="remove(dialog.key)"
11
+ >
12
+ <MRenderer v-if="dialog.options.render" :h="dialog.options.render" :props="dialog.options.props" />
13
+ </MDialog>
14
+ </Teleport>
15
+ </template>
16
+ </template>
17
+ <script lang="ts">
18
+ import {defineComponent, reactive, provide, ref} from 'vue';
19
+ import type {DialogApiInjection, DialogOptions, DialogReactive} from './types';
20
+ import MDialog from '../dialog/Dialog.vue';
21
+ import MRenderer from '../renderer/renderer';
22
+
23
+ export default defineComponent({
24
+ name: 'DialogProvider',
25
+ components: {
26
+ MDialog,
27
+ MRenderer,
28
+ },
29
+ setup() {
30
+ const dialogMap = reactive<Record<string, DialogReactive>>({});
31
+ const dialogRefs = ref<Record<string, any>>({});
32
+
33
+ function setDialogRef(key: string) {
34
+ return (el: any) => {
35
+ if (el) {
36
+ dialogRefs.value[key] = el;
37
+ } else {
38
+ delete dialogRefs.value[key];
39
+ }
40
+ };
41
+ }
42
+
43
+ function create(key: string, options: DialogOptions = {}): DialogReactive {
44
+ if (dialogMap[key]) {
45
+ // Merge new options into existing reactive options
46
+ Object.assign(dialogMap[key].options, options);
47
+ return dialogMap[key];
48
+ }
49
+
50
+ // Make options reactive
51
+ const reactiveOptions = reactive(options);
52
+
53
+ const dialog: DialogReactive = {
54
+ key,
55
+ options: reactiveOptions,
56
+ open: () => {
57
+ const dialogComponent = dialogRefs.value[key];
58
+ if (dialogComponent && dialogComponent.open) {
59
+ dialogComponent.open();
60
+ } else {
61
+ dialog.options.open = true;
62
+ }
63
+ },
64
+ close: () => {
65
+ const dialogComponent = dialogRefs.value[key];
66
+ if (dialogComponent && dialogComponent.close) {
67
+ dialogComponent.close();
68
+ } else {
69
+ remove(key);
70
+ }
71
+ },
72
+ };
73
+
74
+ dialogMap[key] = dialog;
75
+ return dialog;
76
+ }
77
+
78
+ function remove(key: string) {
79
+ delete dialogMap[key];
80
+ delete dialogRefs.value[key];
81
+ }
82
+
83
+ const api: DialogApiInjection = {
84
+ create,
85
+ remove,
86
+ };
87
+
88
+ provide('m-dialog', api);
89
+
90
+ return {
91
+ dialogMap,
92
+ remove,
93
+ setDialogRef,
94
+ };
95
+ },
96
+ });
97
+ </script>
@@ -0,0 +1,51 @@
1
+ <template>
2
+ <div>
3
+ <button @click="showDialog">Show Dialog</button>
4
+ <button @click="showDialog2">Show Dialog 2</button>
5
+ {{ testTitle }}
6
+ </div>
7
+ </template>
8
+
9
+ <script lang="ts" setup>
10
+ import {ref, h} from 'vue';
11
+ import {useDialog} from '../useDialog';
12
+
13
+ const dialog = useDialog();
14
+ const testTitle = ref('This is a test');
15
+
16
+ function renderMessage({message}: { message: string }) {
17
+ return h('p', [
18
+ 'Here are ',
19
+ h('span', {style: 'color: red'}, [message]),
20
+ ' that using render function',
21
+ ]);
22
+ }
23
+
24
+ function showDialog() {
25
+ dialog.create('hello', {
26
+ title: testTitle,
27
+ render: renderMessage,
28
+ props: {message: testTitle},
29
+ open: true,
30
+ });
31
+
32
+ setTimeout(() => {
33
+ testTitle.value = 'changed';
34
+ }, 4000);
35
+ }
36
+
37
+ function showDialog2() {
38
+ dialog.create('hello-two', {
39
+ title: "Hello Second Dialog",
40
+ render: renderMessage,
41
+ props: {message: testTitle},
42
+ open: true,
43
+ modal: false,
44
+ draggable: true
45
+ });
46
+
47
+ setTimeout(() => {
48
+ testTitle.value = 'changed again';
49
+ }, 4000);
50
+ }
51
+ </script>
@@ -0,0 +1,26 @@
1
+ import MDialogProvider from '../DialogProvider.vue';
2
+ import { MDialogProviderBasic } from './index';
3
+
4
+ const Template = (args: any) => ({
5
+ components: {
6
+ MDialogProvider,
7
+ MDialogProviderBasic
8
+ },
9
+ setup() {
10
+ return {
11
+ args
12
+ }
13
+ },
14
+ template: `
15
+ <m-dialog-provider v-bind="args">
16
+ <MDialogProviderBasic />
17
+ </m-dialog-provider>
18
+ `
19
+ });
20
+
21
+ export default {
22
+ component: MDialogProvider,
23
+ title: 'Components/DialogProvider'
24
+ };
25
+
26
+ export const Primary = Template.bind({});
@@ -0,0 +1 @@
1
+ export { default as MDialogProviderBasic } from './basic.vue';
@@ -0,0 +1,25 @@
1
+ import type { Ref, VNodeChild } from 'vue';
2
+
3
+ export type DialogContent = VNodeChild;
4
+
5
+ export interface DialogOptions {
6
+ title?: string | Ref<string>;
7
+ render?: (props: any) => VNodeChild;
8
+ props?: { [key: string]: any };
9
+ onClose?: () => void;
10
+ open?: boolean;
11
+ draggable?: boolean;
12
+ modal?: boolean;
13
+ }
14
+
15
+ export interface DialogReactive {
16
+ key: string;
17
+ options: DialogOptions;
18
+ open: () => void;
19
+ close: () => void;
20
+ }
21
+
22
+ export interface DialogApiInjection {
23
+ create: (key: string, options?: DialogOptions) => DialogReactive;
24
+ remove: (key: string) => void;
25
+ }
@@ -0,0 +1,14 @@
1
+ import { inject } from 'vue';
2
+ import type { DialogApiInjection} from "./types";
3
+
4
+ export function useDialog(): DialogApiInjection {
5
+ const api = inject('m-dialog', null);
6
+
7
+ if (api === null) {
8
+ throw new Error(
9
+ `m-dialog api is not provided, ensure component is wrapped in <m-dialog-provider />`
10
+ )
11
+ }
12
+
13
+ return api;
14
+ }
@@ -48,4 +48,5 @@ export { default as MVirtualScroll } from './virtualscroll/VirtualScroll.vue';
48
48
  export { default as MConfirm } from './confirm/Confirm.vue';
49
49
  export { default as MConfirmProvider } from './confirm/ConfirmProvider.vue';
50
50
  export { default as MDialog } from './dialog/Dialog.vue';
51
+ export { default as MDialogProvider } from './dialogprovider/DialogProvider.vue';
51
52
  export { default as MTree } from './tree/Tree.vue';
@@ -28,7 +28,6 @@
28
28
  import {
29
29
  ref,
30
30
  reactive,
31
- Teleport,
32
31
  defineComponent,
33
32
  provide,
34
33
  computed
@@ -43,11 +42,8 @@ import type {
43
42
  } from './types';
44
43
  import type { PropType } from 'vue';
45
44
  import MMessage from './Message.vue';
46
- import { useId } from '../../composables/useCachedUid';
47
45
  import * as style from './style';
48
46
  import { modalScale } from '../../styles/transitions.css';
49
- import { useIsServer } from '../../composables/useIsServer';
50
- export type MessageProviderInst = MessageApiInjection;
51
47
 
52
48
  interface PrivateMessageReactive extends MessageReactive {
53
49
  key: string;
@@ -1,4 +1,5 @@
1
1
  export { useMessage } from '../components/messageprovider/useMessage';
2
+ export { useDialog } from '../components/dialogprovider/useDialog';
2
3
  export { useConfirm } from '../components/confirm/useConfirm';
3
4
  export { usePopper } from './usePopper';
4
5
  export { useZIndex } from './useZIndex';