@teammodlr/ui-kit 2.1.65 → 2.1.67

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.
@@ -1,118 +1,180 @@
1
- <template>
2
- <Teleport to="body">
3
- <div :class="style.root">
4
- <div :class="backdropClasses">
5
- </div>
6
- <div ref="wrapper" :class="style.wrapper">
7
- <div ref="dialog" :class="style.dialog" :style="{
8
- // top: y + 'px',
9
- // left: x + 'px',
10
- zIndex: zIndex,
11
- width: width
12
- }">
13
- <div tabindex="0" aria-hidden="true" style="width: 0px; height: 0px; overflow: hidden; outline: none;"></div>
14
- <div :class="style.content">
15
- <button role="button" :class="style.close">x</button>
16
- <div :class="style.header" ref="handle">
17
- <div :class="style.title">
18
- <slot name="title">
19
- Title
20
- </slot>
21
- </div>
22
- </div>
23
- <div>
24
- <slot></slot>
25
- </div>
26
- <div :class="style.footer">
27
- <slot name="footer"></slot>
28
- </div>
29
- </div>
30
- <div tabindex="0" aria-hidden="true" style="width: 0px; height: 0px; overflow: hidden; outline: none;"></div>
31
- </div>
32
- </div>
33
- </div>
34
-
35
- </Teleport>
36
- </template>
37
- <script lang="ts">
38
- import {computed, defineComponent, type PropType, ref} from "vue";
39
- import {useZIndex} from "../../composables/useZIndex";
40
- import {useDraggable} from "@vueuse/core";
41
- import * as style from "./style";
42
-
43
- export default defineComponent({
44
- name: "Dialog",
45
- props: {
46
- title: {
47
- type: String,
48
- default: ""
49
- },
50
- draggable: {
51
- type: Boolean,
52
- default: true
53
- },
54
- backdrop: {
55
- type: Boolean,
56
- default: false,
57
- },
58
- onClose: {
59
- type: Function as PropType<() => void>,
60
- default: () => {
61
- }
62
- },
63
- zIndex: {
64
- type: Number
65
- },
66
- width: {
67
- type: [Number, String],
68
- default: "500px"
69
- },
70
- transformOrigin: {
71
- type: String as PropType<'center' | 'mouse'>,
72
- default: 'mouse'
73
- },
74
- focusTrap: {
75
- type: Boolean,
76
- default: true
77
- }
78
- },
79
- emits: ['onOpen', 'onClose'],
80
- setup(props, {slots}) {
81
- const wrapper = ref<HTMLElement | null>(null);
82
- const dialog = ref<HTMLElement | null>(null);
83
- const handle = ref<HTMLElement | null>(null);
84
- const {x, y} = useDraggable(dialog, {
85
- handle: handle,
86
- preventDefault: true,
87
- // containerElement: wrapper,
88
- });
89
- const {nextZIndex} = useZIndex();
90
-
91
- const backdropClasses = computed(() => {
92
- return {
93
- [style.backdrop]: true,
94
- [style.backdropColor]: props.backdrop === true
95
- }
96
- });
97
-
98
- const width = computed(() => {
99
- return typeof props.width === "number" ? props.width + "px" : props.width;
100
- });
101
-
102
- const zIndex = ref(props.zIndex ?? nextZIndex());
103
- return {
104
- slots,
105
- wrapper,
106
- dialog,
107
- handle,
108
- zIndex,
109
- width,
110
- x,
111
- y,
112
- style,
113
- backdropClasses,
114
- nextZIndex
115
- };
116
- }
117
- });
118
- </script>
1
+ <template>
2
+ <Teleport to="body">
3
+ <TransitionGroup
4
+ type="animation"
5
+ :enter-active-class="fade.enterActive"
6
+ :leave-active-class="fade.leaveActive"
7
+ :enter-from-class="fade.enterFrom"
8
+ :leave-to-class="fade.leaveTo">
9
+ <div :class="style.root" v-if="open">
10
+ <div :class="backdropClasses" v-if="modal"></div>
11
+ <div ref="wrapper" :class="wrapperClasses">
12
+ <Transition
13
+ type="animation"
14
+ :enter-active-class="modalScale.enterActive"
15
+ :leave-active-class="modalScale.leaveActive"
16
+ :enter-from-class="modalScale.enterFrom"
17
+ :leave-to-class="modalScale.leaveTo"
18
+ @enter="onEnter"
19
+ >
20
+ <div ref="dialog" :style="computedStyle">
21
+ <div tabindex="0" aria-hidden="true"
22
+ style="width: 0px; height: 0px; overflow: hidden; outline: none;"></div>
23
+ <slot v-if="$slots.container" name="container" :close="close"></slot>
24
+ <template v-else>
25
+ <div :class="style.content">
26
+ <button role="button" :class="style.close" @click="close"></button>
27
+ <div :class="style.header" ref="handle">
28
+ <div :class="style.title">
29
+ <slot name="title">
30
+ {{ title }}
31
+ </slot>
32
+ </div>
33
+ </div>
34
+ <div>
35
+ <slot></slot>
36
+ </div>
37
+ <div v-if="$slots.footer" :class="style.footer">
38
+ <slot name="footer"></slot>
39
+ </div>
40
+ </div>
41
+ </template>
42
+ <div tabindex="0" aria-hidden="true"
43
+ style="width: 0px; height: 0px; overflow: hidden; outline: none;"></div>
44
+ </div>
45
+ </Transition>
46
+ </div>
47
+ </div>
48
+ </TransitionGroup>
49
+ </Teleport>
50
+ </template>
51
+
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";
56
+
57
+ import { useZIndex } from "../../composables/useZIndex";
58
+ import { useDraggable } from "@vueuse/core";
59
+ import * as style from "./style";
60
+
61
+ export default defineComponent({
62
+ name: "Dialog",
63
+ props: {
64
+ title: {
65
+ type: String,
66
+ default: ""
67
+ },
68
+ draggable: {
69
+ type: Boolean,
70
+ default: true
71
+ },
72
+ modal: {
73
+ type: Boolean,
74
+ default: false,
75
+ },
76
+ onClose: {
77
+ type: Function,
78
+ default: () => {}
79
+ },
80
+ zIndex: {
81
+ type: Number
82
+ },
83
+ width: {
84
+ type: [Number, String],
85
+ default: "500px"
86
+ },
87
+ focusTrap: {
88
+ type: Boolean,
89
+ default: true
90
+ },
91
+ open: {
92
+ type: Boolean
93
+ }
94
+ },
95
+ emits: ['onOpen', 'onClose', 'update:open'],
96
+ setup(props, { slots, emit }) {
97
+ const wrapper = ref<HTMLElement | null>(null);
98
+ const dialog = ref<HTMLElement | null>(null);
99
+ const handle = ref<HTMLElement | null>(null);
100
+ const { nextZIndex } = useZIndex();
101
+ const zIndex = ref(props.zIndex ?? nextZIndex());
102
+
103
+ const { x, y } = useDraggable(dialog, {
104
+ handle,
105
+ preventDefault: true,
106
+ containerElement: wrapper,
107
+ disabled: computed(() => !props.draggable),
108
+ onStart: onDragStart,
109
+ });
110
+
111
+ const backdropClasses = computed(() => ({
112
+ [style.backdrop]: true,
113
+ [style.backdropColor]: props.modal === true,
114
+ }));
115
+
116
+ const wrapperClasses = computed(() => ({
117
+ [style.wrapper]: true,
118
+ [style.notModal]: !props.modal,
119
+ }));
120
+
121
+ const width = computed(() => (
122
+ typeof props.width === "number" ? `${props.width}px` : props.width
123
+ ));
124
+
125
+ const computedStyle: ComputedRef<CSSProperties> = computed(() => ({
126
+ position: 'fixed',
127
+ left: `${x.value}px`,
128
+ top: `${y.value}px`,
129
+ width: width.value,
130
+ zIndex: zIndex.value
131
+ }));
132
+
133
+ function close() {
134
+ emit('update:open', false);
135
+ emit('onClose');
136
+ }
137
+
138
+ function onEnter() {
139
+ emit('onOpen');
140
+ zIndex.value = nextZIndex();
141
+ }
142
+
143
+ function onDragStart() {
144
+ zIndex.value = nextZIndex();
145
+ }
146
+
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
+ }
153
+ }
154
+
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
+ }
178
+ });
179
+ </script>
180
+
@@ -1,16 +1,23 @@
1
1
  <template>
2
2
  <div>
3
- <MDialog :draggable="true">
3
+ <MDialog :draggable="true" v-model:open="open" width="1000px" title="Hello World" @onClose="closed">
4
4
  <input type="text" />
5
5
  <input type="text" />
6
6
  <template #footer>
7
7
  Bootom
8
8
  </template>
9
9
  </MDialog>
10
+
11
+ <button @click="open = true">Open</button>
10
12
  </div>
11
13
  </template>
12
14
 
13
15
  <script lang="ts" setup>
14
16
  import { ref } from 'vue'
15
17
 
18
+ const open = ref(false);
19
+
20
+ function closed() {
21
+ console.log('closed');
22
+ }
16
23
  </script>
@@ -35,9 +35,13 @@ export const wrapper = style({
35
35
  bottom: 0,
36
36
  outline: 0,
37
37
  overflow: 'auto',
38
- boxSizing: 'border-box'
38
+ boxSizing: 'border-box',
39
39
  });
40
40
 
41
+ export const notModal = style({
42
+ pointerEvents: 'none'
43
+ })
44
+
41
45
  export const dialog = style({
42
46
  boxSizing: 'border-box',
43
47
  margin: '0 auto',
@@ -53,17 +57,21 @@ export const content = style({
53
57
  position: 'relative',
54
58
  backgroundColor: '#FFF',
55
59
  backgroundClip: 'padding-box',
56
- border: 0,
57
- borderRadius: themeVars.rounded.default,
60
+ border: `1px solid ${themeVars.color.gray[300]}`,
61
+ borderRadius: themeVars.rounded.medium,
58
62
  pointerEvents: 'auto',
59
- padding: `20px 24px`,
60
- boxShadow: `0 6px 16px 0 rgba(0,0,0,.08), 0 3px 6px -4px rgba(0,0,0,.12), 0 9px 28px 8px rgba(0,0,0,.05)`
63
+ boxShadow: `2px 2px 8px rgba(128, 128, 128, 0.1), 0 9px 28px 8px rgba(0,0,0,.05)`
61
64
  });
62
65
 
63
66
  export const header = style({
64
67
  color: themeVars.color.font.default,
65
68
  backgroundColor: '#FFF',
66
- marginBottom: themeVars.space[2]
69
+ marginBottom: themeVars.space[2],
70
+ borderBottom: `1px solid ${themeVars.color.gray[300]}`,
71
+ height: `35px`,
72
+ display: `flex`,
73
+ alignItems: `center`,
74
+ padding: `0px ${themeVars.space[2]}`
67
75
  });
68
76
 
69
77
  export const footer = style({
@@ -80,21 +88,51 @@ export const title = style({
80
88
  wordWrap: 'break-word'
81
89
  });
82
90
 
83
- export const close = style({
84
- position: 'absolute',
85
- top: `17px`,
86
- insetInlineEnd: `17px`,
87
- padding: 0,
88
- background: `0 0`,
89
- borderRadius: themeVars.rounded.small,
90
- width: `22px`,
91
- height: `22px`,
92
- border: 0,
93
- outline: 0,
94
- cursor: `pointer`,
95
- selectors: {
96
- '&:hover': {
97
- backgroundColor: `hsla(0,0%,45.1%,0.1)`
91
+ export const close = style([
92
+ {
93
+ outline: `none ${themeVars.color.gray[300]}`,
94
+ display: 'inline-block',
95
+ position: 'absolute',
96
+ top: themeVars.space[1.5],
97
+ right: themeVars.space[1.5],
98
+ width: '1.5rem',
99
+ height: '1.5rem',
100
+ backgroundColor: 'transparent',
101
+ border: 'none',
102
+ padding: 0,
103
+ cursor: 'pointer',
104
+ transition: 'all 0.2s',
105
+ borderRadius: themeVars.rounded.full,
106
+ marginLeft: themeVars.space[2],
107
+ ':hover': {
108
+ backgroundColor: themeVars.color.gray[150]
109
+ },
110
+ ':focus': {
111
+ backgroundColor: themeVars.color.gray[150]
112
+ },
113
+ '::before': {
114
+ content: '""',
115
+ position: 'absolute',
116
+ top: '50%',
117
+ left: '50%',
118
+ transform: 'translate(-50%, -50%) rotate(45deg)',
119
+ width: '0.8rem',
120
+ height: '2px',
121
+ backgroundColor: themeVars.color.gray[500],
122
+ transformOrigin: 'center',
123
+ transition: 'all 0.2s'
124
+ },
125
+ '::after': {
126
+ content: '""',
127
+ position: 'absolute',
128
+ top: '50%',
129
+ left: '50%',
130
+ transform: 'translate(-50%, -50%) rotate(-45deg)',
131
+ width: '0.8rem',
132
+ height: '2px',
133
+ backgroundColor: themeVars.color.gray[500],
134
+ transformOrigin: 'center',
135
+ transition: 'all 0.2s'
98
136
  }
99
137
  }
100
- });
138
+ ]);