@bobbykim/manguito-theme 0.5.0 → 0.7.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/README.md +1 -3
- package/lib/collapse/Collapse.vue +46 -15
- package/lib/collapse/index.types.ts +1 -1
- package/lib/composables/index.ts +1 -0
- package/lib/composables/observeVisible.ts +24 -0
- package/lib/directives/index.ts +168 -6
- package/lib/directives/index.types.ts +15 -0
- package/lib/modal/Modal.vue +47 -10
- package/lib/sidebar/Sidebar.vue +45 -8
- package/lib/tooltip/index.ts +75 -0
- package/package.json +2 -2
- package/theme/theme.ts +1 -1
- package/themeVariables.cjs +111 -0
- package/tsconfig.json +8 -0
package/README.md
CHANGED
|
@@ -19,9 +19,7 @@ npx tailwindcss init -p
|
|
|
19
19
|
tailwind.config.cjs
|
|
20
20
|
|
|
21
21
|
```cjs
|
|
22
|
-
const {
|
|
23
|
-
mclTheme,
|
|
24
|
-
} = require('./src/components/manguito-theme/themeVariables.cjs')
|
|
22
|
+
const { mclTheme } = require('@bobbykim/manguito-theme/themeVariables.cjs')
|
|
25
23
|
module.exports = {
|
|
26
24
|
content: [
|
|
27
25
|
'./src/**/*.{vue,ts,js,cjs}',
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref, watch, Transition } from 'vue'
|
|
3
|
-
import
|
|
2
|
+
import { ref, watch, Transition, onMounted, onBeforeUnmount } from 'vue'
|
|
3
|
+
import { observeVisibleAttr } from '../composables'
|
|
4
|
+
|
|
4
5
|
const props = withDefaults(
|
|
5
6
|
defineProps<{
|
|
6
|
-
collapseId: string
|
|
7
7
|
accordion?: string
|
|
8
8
|
className?: string
|
|
9
9
|
visible?: boolean
|
|
@@ -13,12 +13,24 @@ const props = withDefaults(
|
|
|
13
13
|
visible: false,
|
|
14
14
|
}
|
|
15
15
|
)
|
|
16
|
-
const emit = defineEmits(['
|
|
16
|
+
const emit = defineEmits(['open', 'close'])
|
|
17
|
+
const collapseRef = ref<HTMLElement | undefined>()
|
|
17
18
|
const toggle = ref<boolean>(props.visible)
|
|
18
19
|
|
|
19
|
-
const
|
|
20
|
+
const toggleCollapse = (): void => {
|
|
20
21
|
toggle.value = !toggle.value
|
|
21
|
-
|
|
22
|
+
}
|
|
23
|
+
const openCollapse = (): void => {
|
|
24
|
+
toggle.value = true
|
|
25
|
+
}
|
|
26
|
+
const closeCollapse = (): void => {
|
|
27
|
+
toggle.value = false
|
|
28
|
+
}
|
|
29
|
+
const emitOpenEvent = () => {
|
|
30
|
+
emit('open', { visible: true })
|
|
31
|
+
}
|
|
32
|
+
const emitCloseEvent = () => {
|
|
33
|
+
emit('close', { visible: false })
|
|
22
34
|
}
|
|
23
35
|
|
|
24
36
|
/**
|
|
@@ -45,30 +57,49 @@ const onLeave = (el: any) => {
|
|
|
45
57
|
el.style.opacity = '0'
|
|
46
58
|
}
|
|
47
59
|
|
|
60
|
+
// set nutation observer watching `visible` attribute in element
|
|
61
|
+
const handleVisibility = (visible: boolean = false) => {
|
|
62
|
+
toggle.value = visible
|
|
63
|
+
}
|
|
64
|
+
const observer = observeVisibleAttr(handleVisibility)
|
|
65
|
+
|
|
48
66
|
watch(
|
|
49
67
|
() => props.visible,
|
|
50
68
|
(newValue) => {
|
|
51
69
|
toggle.value = newValue
|
|
52
70
|
}
|
|
53
71
|
)
|
|
72
|
+
watch(toggle, (newValue) => {
|
|
73
|
+
if (newValue === true) {
|
|
74
|
+
emitOpenEvent()
|
|
75
|
+
} else if (newValue === false) {
|
|
76
|
+
emitCloseEvent()
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
defineExpose({
|
|
80
|
+
toggle: toggleCollapse,
|
|
81
|
+
close: closeCollapse,
|
|
82
|
+
open: openCollapse,
|
|
83
|
+
})
|
|
84
|
+
onMounted(() => {
|
|
85
|
+
if (collapseRef.value) {
|
|
86
|
+
observer.observe(collapseRef.value, { attributes: true })
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
onBeforeUnmount(() => {
|
|
90
|
+
observer.disconnect()
|
|
91
|
+
})
|
|
54
92
|
</script>
|
|
55
93
|
|
|
56
94
|
<template>
|
|
57
|
-
<div>
|
|
58
|
-
<button
|
|
59
|
-
:id="collapseId"
|
|
60
|
-
@click="handleToggleEvent"
|
|
61
|
-
class="hidden"
|
|
62
|
-
:accordion="accordion"
|
|
63
|
-
:visible="toggle"
|
|
64
|
-
></button>
|
|
95
|
+
<div :accordion="accordion" :visible="toggle" ref="collapseRef">
|
|
65
96
|
<transition
|
|
66
97
|
name="collapse"
|
|
67
98
|
tag="div"
|
|
68
99
|
@enter="onEnter"
|
|
69
100
|
@after-enter="onAfterEnter"
|
|
70
101
|
@leave="onLeave"
|
|
71
|
-
class="overflow-
|
|
102
|
+
class="overflow-y-clip"
|
|
72
103
|
>
|
|
73
104
|
<div v-show="toggle">
|
|
74
105
|
<div :class="[className]">
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './observeVisible'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const observeVisibleAttr = (fn: (...args: any[]) => void) => {
|
|
2
|
+
const observer = new MutationObserver((mutations) => {
|
|
3
|
+
let changed = false
|
|
4
|
+
for (let i = 0; i < mutations.length && !changed; i++) {
|
|
5
|
+
const mutation = mutations[i]
|
|
6
|
+
const mutationType = mutation.type
|
|
7
|
+
const mutationAttribute = mutation.attributeName
|
|
8
|
+
const mutationTarget = mutation.target
|
|
9
|
+
if (mutationType === 'attributes') {
|
|
10
|
+
changed = true
|
|
11
|
+
} else if (mutationAttribute === 'visible') {
|
|
12
|
+
changed = true
|
|
13
|
+
}
|
|
14
|
+
if (changed) {
|
|
15
|
+
const visibleAttr =
|
|
16
|
+
(mutationTarget as HTMLElement).getAttribute('visible') === 'true'
|
|
17
|
+
? true
|
|
18
|
+
: false
|
|
19
|
+
fn(visibleAttr)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
return observer
|
|
24
|
+
}
|
package/lib/directives/index.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import { Directive } from 'vue'
|
|
1
|
+
import { Directive, DirectiveBinding, h, render, createVNode } from 'vue'
|
|
2
|
+
import generateClass from '../..'
|
|
3
|
+
import type { Direction } from '../..'
|
|
4
|
+
import tooltip from '../tooltip'
|
|
5
|
+
import type { TooltipElementType, TooltipValueType } from './index.types'
|
|
2
6
|
|
|
3
7
|
export const vClickOutside: Directive = {
|
|
4
8
|
mounted(el, binding) {
|
|
@@ -27,7 +31,15 @@ export const vToggle: Directive = {
|
|
|
27
31
|
} else {
|
|
28
32
|
target = document.getElementById(binding.arg as string)!
|
|
29
33
|
}
|
|
30
|
-
target
|
|
34
|
+
if (!target) {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
if (target.hasAttribute('visible') === false) {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
const targetAttr = target.getAttribute('visible')
|
|
41
|
+
const attrAfterToggle = targetAttr === 'true' ? 'false' : 'true'
|
|
42
|
+
target.setAttribute('visible', attrAfterToggle)
|
|
31
43
|
return
|
|
32
44
|
}
|
|
33
45
|
el.addEventListener('click', el.__ClickToggleHandler)
|
|
@@ -39,6 +51,37 @@ export const vToggle: Directive = {
|
|
|
39
51
|
|
|
40
52
|
export const vCollapse: Directive = {
|
|
41
53
|
mounted(el, binding) {
|
|
54
|
+
// el.__HandleToggler = (event: Event): void => {
|
|
55
|
+
// const eTarget = event.target as HTMLElement
|
|
56
|
+
// let target: HTMLElement
|
|
57
|
+
// if (eTarget.tagName === 'A') {
|
|
58
|
+
// const targetId = eTarget.getAttribute('href')
|
|
59
|
+
// const formattedTargetId =
|
|
60
|
+
// targetId?.charAt(0) === '#' ? targetId.substring(1) : targetId
|
|
61
|
+
// target = document.getElementById(formattedTargetId as string)!
|
|
62
|
+
// } else {
|
|
63
|
+
// target = document.getElementById(binding.arg as string) as HTMLElement
|
|
64
|
+
// }
|
|
65
|
+
// if (!target.hasAttribute('accordion')) {
|
|
66
|
+
// // run when it is not accordion component case
|
|
67
|
+
// target.click()
|
|
68
|
+
// return
|
|
69
|
+
// }
|
|
70
|
+
// const accordionName = target.getAttribute('accordion')
|
|
71
|
+
// const accordionList: NodeListOf<HTMLElement> = document.querySelectorAll(
|
|
72
|
+
// `button[accordion="${accordionName}"]`
|
|
73
|
+
// )
|
|
74
|
+
// // loop through each accordion items and handle reaction for each case
|
|
75
|
+
// for (let i = 0; i < accordionList.length; i++) {
|
|
76
|
+
// const isVisible = accordionList[i].getAttribute('visible')
|
|
77
|
+
// if (accordionList[i].id !== target.id && isVisible === 'true') {
|
|
78
|
+
// accordionList[i].click()
|
|
79
|
+
// }
|
|
80
|
+
// if (accordionList[i].id === target.id) {
|
|
81
|
+
// accordionList[i].click()
|
|
82
|
+
// }
|
|
83
|
+
// }
|
|
84
|
+
// }
|
|
42
85
|
el.__HandleToggler = (event: Event): void => {
|
|
43
86
|
const eTarget = event.target as HTMLElement
|
|
44
87
|
let target: HTMLElement
|
|
@@ -50,23 +93,36 @@ export const vCollapse: Directive = {
|
|
|
50
93
|
} else {
|
|
51
94
|
target = document.getElementById(binding.arg as string) as HTMLElement
|
|
52
95
|
}
|
|
96
|
+
if (!target) {
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
if (target.hasAttribute('visible') === false) {
|
|
100
|
+
return
|
|
101
|
+
}
|
|
53
102
|
if (!target.hasAttribute('accordion')) {
|
|
54
103
|
// run when it is not accordion component case
|
|
55
|
-
target.
|
|
104
|
+
const targetAttr = target.getAttribute('visible')
|
|
105
|
+
const attrAfterToggle = targetAttr === 'true' ? 'false' : 'true'
|
|
106
|
+
target.setAttribute('visible', attrAfterToggle)
|
|
107
|
+
// target.click()
|
|
56
108
|
return
|
|
57
109
|
}
|
|
58
110
|
const accordionName = target.getAttribute('accordion')
|
|
59
111
|
const accordionList: NodeListOf<HTMLElement> = document.querySelectorAll(
|
|
60
|
-
`
|
|
112
|
+
`div[accordion="${accordionName}"]`
|
|
61
113
|
)
|
|
62
114
|
// loop through each accordion items and handle reaction for each case
|
|
63
115
|
for (let i = 0; i < accordionList.length; i++) {
|
|
64
116
|
const isVisible = accordionList[i].getAttribute('visible')
|
|
65
117
|
if (accordionList[i].id !== target.id && isVisible === 'true') {
|
|
66
|
-
accordionList[i].
|
|
118
|
+
accordionList[i].setAttribute('visible', 'false')
|
|
119
|
+
// accordionList[i].click()
|
|
67
120
|
}
|
|
68
121
|
if (accordionList[i].id === target.id) {
|
|
69
|
-
|
|
122
|
+
const targetAttr = target.getAttribute('visible')
|
|
123
|
+
const attrAfterToggle = targetAttr === 'true' ? 'false' : 'true'
|
|
124
|
+
target.setAttribute('visible', attrAfterToggle)
|
|
125
|
+
// accordionList[i].click()
|
|
70
126
|
}
|
|
71
127
|
}
|
|
72
128
|
}
|
|
@@ -76,3 +132,109 @@ export const vCollapse: Directive = {
|
|
|
76
132
|
el.removeEventListener('click', el.__HandleToggler)
|
|
77
133
|
},
|
|
78
134
|
}
|
|
135
|
+
|
|
136
|
+
export const vTooltip: Directive<TooltipElementType, TooltipValueType> = {
|
|
137
|
+
mounted(el, binding) {
|
|
138
|
+
el.__HandleTooltip = (
|
|
139
|
+
el: HTMLElement,
|
|
140
|
+
binding: DirectiveBinding<TooltipValueType>
|
|
141
|
+
) => {
|
|
142
|
+
// parent element class
|
|
143
|
+
el.classList.add('relative', 'group', 'overflow-visible')
|
|
144
|
+
|
|
145
|
+
// handle tooltip text
|
|
146
|
+
let tooltipText: string | null | undefined
|
|
147
|
+
if (el.hasAttribute('title')) {
|
|
148
|
+
tooltipText = el.getAttribute('title')
|
|
149
|
+
}
|
|
150
|
+
if (
|
|
151
|
+
!el.hasAttribute('title') &&
|
|
152
|
+
typeof binding.value !== 'undefined' &&
|
|
153
|
+
typeof binding.value === 'string'
|
|
154
|
+
) {
|
|
155
|
+
tooltipText = binding.value
|
|
156
|
+
}
|
|
157
|
+
if (
|
|
158
|
+
!el.hasAttribute('title') &&
|
|
159
|
+
typeof binding.value !== 'undefined' &&
|
|
160
|
+
typeof binding.value !== 'string' &&
|
|
161
|
+
typeof binding.value.title === 'string'
|
|
162
|
+
) {
|
|
163
|
+
tooltipText = binding.value.title
|
|
164
|
+
}
|
|
165
|
+
// handle tooltip color
|
|
166
|
+
let tooltipColor: string | null | undefined
|
|
167
|
+
if (el.hasAttribute('color')) {
|
|
168
|
+
tooltipColor = el.getAttribute('color')
|
|
169
|
+
}
|
|
170
|
+
if (
|
|
171
|
+
!el.hasAttribute('color') &&
|
|
172
|
+
typeof binding.value !== 'undefined' &&
|
|
173
|
+
typeof binding.value !== 'string' &&
|
|
174
|
+
typeof binding.value.color === 'string'
|
|
175
|
+
) {
|
|
176
|
+
tooltipColor = binding.value.color
|
|
177
|
+
}
|
|
178
|
+
// handle tooltip text color
|
|
179
|
+
let tooltipTextColor: string | null | undefined
|
|
180
|
+
if (el.hasAttribute('text-color')) {
|
|
181
|
+
tooltipTextColor = el.getAttribute('text-color')
|
|
182
|
+
}
|
|
183
|
+
if (
|
|
184
|
+
!el.hasAttribute('text-color') &&
|
|
185
|
+
typeof binding.value !== 'undefined' &&
|
|
186
|
+
typeof binding.value !== 'string' &&
|
|
187
|
+
typeof binding.value.textColor === 'string'
|
|
188
|
+
) {
|
|
189
|
+
tooltipTextColor = binding.value.textColor
|
|
190
|
+
}
|
|
191
|
+
// handle tooltip width
|
|
192
|
+
let tooltipWidth: string | number | null | undefined
|
|
193
|
+
if (el.hasAttribute('width')) {
|
|
194
|
+
tooltipWidth = el.getAttribute('width')
|
|
195
|
+
}
|
|
196
|
+
if (
|
|
197
|
+
!el.hasAttribute('width') &&
|
|
198
|
+
typeof binding.value !== 'undefined' &&
|
|
199
|
+
typeof binding.value !== 'string' &&
|
|
200
|
+
typeof binding.value.width === ('number' || 'string')
|
|
201
|
+
) {
|
|
202
|
+
tooltipWidth = binding.value.width
|
|
203
|
+
}
|
|
204
|
+
// handle custom class names
|
|
205
|
+
let tooltipClassName: string | undefined
|
|
206
|
+
if (
|
|
207
|
+
typeof binding.value !== 'undefined' &&
|
|
208
|
+
typeof binding.value !== 'string' &&
|
|
209
|
+
typeof binding.value.className === 'string'
|
|
210
|
+
) {
|
|
211
|
+
tooltipClassName = binding.value.className
|
|
212
|
+
}
|
|
213
|
+
let tooltipDirection: Direction | undefined
|
|
214
|
+
const modifierArray: string[] = Object.keys(binding.modifiers)
|
|
215
|
+
// handle direction
|
|
216
|
+
if (modifierArray.length > 0) {
|
|
217
|
+
tooltipDirection = modifierArray[0] as Direction
|
|
218
|
+
}
|
|
219
|
+
const vnode = createVNode(tooltip, {
|
|
220
|
+
direction: tooltipDirection,
|
|
221
|
+
title: tooltipText,
|
|
222
|
+
color: tooltipColor,
|
|
223
|
+
textColor: tooltipTextColor,
|
|
224
|
+
width: tooltipWidth,
|
|
225
|
+
customClass: tooltipClassName,
|
|
226
|
+
})
|
|
227
|
+
render(vnode, el)
|
|
228
|
+
}
|
|
229
|
+
el.__UnmountTooltip = (el: Element) => {
|
|
230
|
+
render(null, el)
|
|
231
|
+
}
|
|
232
|
+
el.__HandleTooltip(el, binding)
|
|
233
|
+
},
|
|
234
|
+
updated(el, binding) {
|
|
235
|
+
el.__HandleTooltip(el, binding)
|
|
236
|
+
},
|
|
237
|
+
unmounted(el) {
|
|
238
|
+
el.__UnmountTooltip(el)
|
|
239
|
+
},
|
|
240
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ColorPalette } from '../..'
|
|
2
|
+
|
|
3
|
+
export interface TooltipElementType extends HTMLElement {
|
|
4
|
+
__HandleTooltip: Function
|
|
5
|
+
__UnmountTooltip: Function
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface TooltipValueObjectType {
|
|
9
|
+
title?: string
|
|
10
|
+
color?: ColorPalette
|
|
11
|
+
textColor?: ColorPalette
|
|
12
|
+
width?: number | string
|
|
13
|
+
className?: string
|
|
14
|
+
}
|
|
15
|
+
export type TooltipValueType = TooltipValueObjectType | string
|
package/lib/modal/Modal.vue
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
ref,
|
|
4
|
+
computed,
|
|
5
|
+
watch,
|
|
6
|
+
Transition,
|
|
7
|
+
onMounted,
|
|
8
|
+
onBeforeUnmount,
|
|
9
|
+
} from 'vue'
|
|
3
10
|
import generateClass, {
|
|
4
11
|
ColorPalette,
|
|
5
12
|
vClickOutside,
|
|
6
13
|
VerticalAlignment,
|
|
7
14
|
} from '../../'
|
|
15
|
+
import { observeVisibleAttr } from '../composables'
|
|
8
16
|
|
|
9
17
|
const props = withDefaults(
|
|
10
18
|
defineProps<{
|
|
11
|
-
modalId: string
|
|
12
19
|
title?: string
|
|
13
20
|
titleColor?: ColorPalette
|
|
14
21
|
className?: string
|
|
@@ -31,23 +38,31 @@ const props = withDefaults(
|
|
|
31
38
|
}
|
|
32
39
|
)
|
|
33
40
|
|
|
34
|
-
const emit = defineEmits(['
|
|
41
|
+
const emit = defineEmits(['open', 'close'])
|
|
42
|
+
const modalRef = ref<HTMLElement | undefined>()
|
|
35
43
|
const toggle = ref<boolean>(props.visible)
|
|
36
44
|
const toggleComplete = ref<boolean>(false)
|
|
37
45
|
|
|
38
|
-
const handleToggleEvent = (
|
|
46
|
+
// const handleToggleEvent = (): void => {
|
|
47
|
+
// toggle.value = !toggle.value
|
|
48
|
+
// }
|
|
49
|
+
const toggleModal = (): void => {
|
|
39
50
|
toggle.value = !toggle.value
|
|
40
|
-
emit('toggle', e)
|
|
41
51
|
}
|
|
42
52
|
const openModal = (): void => {
|
|
43
53
|
toggle.value = true
|
|
44
54
|
}
|
|
45
|
-
const closeModal = (
|
|
55
|
+
const closeModal = (): void => {
|
|
46
56
|
if (toggleComplete.value === true) {
|
|
47
57
|
toggle.value = false
|
|
48
|
-
emit('close', e)
|
|
49
58
|
}
|
|
50
59
|
}
|
|
60
|
+
const emitOpenEvent = () => {
|
|
61
|
+
emit('open', { visible: true })
|
|
62
|
+
}
|
|
63
|
+
const emitCloseEvent = () => {
|
|
64
|
+
emit('close', { visible: false })
|
|
65
|
+
}
|
|
51
66
|
const handlePlacementVar = computed(() => {
|
|
52
67
|
let placementVariable: number
|
|
53
68
|
if (props.placement === 'top') {
|
|
@@ -70,22 +85,44 @@ const onAfterEnter = () => {
|
|
|
70
85
|
const onAfterLeave = () => {
|
|
71
86
|
toggleComplete.value = false
|
|
72
87
|
}
|
|
88
|
+
|
|
89
|
+
// set nutation observer watching `visible` attribute in element
|
|
90
|
+
const handleVisibility = (visible: boolean = false) => {
|
|
91
|
+
toggle.value = visible
|
|
92
|
+
}
|
|
93
|
+
const observer = observeVisibleAttr(handleVisibility)
|
|
94
|
+
|
|
73
95
|
watch(
|
|
74
96
|
() => props.visible,
|
|
75
97
|
(newValue) => {
|
|
76
98
|
toggle.value = newValue
|
|
77
99
|
}
|
|
78
100
|
)
|
|
101
|
+
watch(toggle, (newValue) => {
|
|
102
|
+
if (newValue === true) {
|
|
103
|
+
emitOpenEvent()
|
|
104
|
+
} else if (newValue === false && toggleComplete.value === true) {
|
|
105
|
+
emitCloseEvent()
|
|
106
|
+
}
|
|
107
|
+
})
|
|
79
108
|
defineExpose({
|
|
80
|
-
toggle:
|
|
109
|
+
toggle: toggleModal,
|
|
81
110
|
close: closeModal,
|
|
82
111
|
open: openModal,
|
|
83
112
|
})
|
|
113
|
+
onMounted(() => {
|
|
114
|
+
if (modalRef.value) {
|
|
115
|
+
observer.observe(modalRef.value, { attributes: true })
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
onBeforeUnmount(() => {
|
|
119
|
+
observer.disconnect()
|
|
120
|
+
})
|
|
84
121
|
</script>
|
|
85
122
|
|
|
86
123
|
<template>
|
|
87
|
-
<div :style="handlePlacementVar">
|
|
88
|
-
<button :id="modalId" @click="handleToggleEvent" class="hidden"></button>
|
|
124
|
+
<div :style="handlePlacementVar" :visible="toggle" ref="modalRef">
|
|
125
|
+
<!-- <button :id="modalId" @click="handleToggleEvent" class="hidden"></button> -->
|
|
89
126
|
<Transition name="fade" appear tag="div" v-if="!noBackdrop">
|
|
90
127
|
<section
|
|
91
128
|
v-if="toggle"
|
package/lib/sidebar/Sidebar.vue
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
ref,
|
|
4
|
+
computed,
|
|
5
|
+
watch,
|
|
6
|
+
Transition,
|
|
7
|
+
onMounted,
|
|
8
|
+
onBeforeUnmount,
|
|
9
|
+
} from 'vue'
|
|
3
10
|
import generateClass, { ColorPalette, vClickOutside, DirectionX } from '../../'
|
|
11
|
+
import { observeVisibleAttr } from '../composables'
|
|
4
12
|
|
|
5
13
|
const props = withDefaults(
|
|
6
14
|
defineProps<{
|
|
7
|
-
sidebarId: string
|
|
8
15
|
title?: string
|
|
9
16
|
titleColor?: ColorPalette
|
|
10
17
|
className?: string
|
|
@@ -29,15 +36,18 @@ const props = withDefaults(
|
|
|
29
36
|
}
|
|
30
37
|
)
|
|
31
38
|
|
|
32
|
-
const emit = defineEmits(['
|
|
39
|
+
const emit = defineEmits(['open', 'close'])
|
|
33
40
|
const toggle = ref<boolean>(props.visible)
|
|
34
41
|
const toggleComplete = ref<boolean>(false)
|
|
42
|
+
const sidebarRef = ref<HTMLElement | undefined>()
|
|
35
43
|
const headerRef = ref<HTMLElement>()
|
|
36
44
|
const footerRef = ref<HTMLElement>()
|
|
37
45
|
|
|
38
46
|
const handleToggleEvent = (e: Event): void => {
|
|
39
47
|
toggle.value = !toggle.value
|
|
40
|
-
|
|
48
|
+
}
|
|
49
|
+
const toggleSidebar = (): void => {
|
|
50
|
+
toggle.value = !toggle.value
|
|
41
51
|
}
|
|
42
52
|
const openSidebar = (): void => {
|
|
43
53
|
toggle.value = true
|
|
@@ -45,9 +55,14 @@ const openSidebar = (): void => {
|
|
|
45
55
|
const closeSidebar = (e: Event): void => {
|
|
46
56
|
if (toggleComplete.value === true) {
|
|
47
57
|
toggle.value = false
|
|
48
|
-
emit('close', e)
|
|
49
58
|
}
|
|
50
59
|
}
|
|
60
|
+
const emitOpenEvent = () => {
|
|
61
|
+
emit('open', { visible: true })
|
|
62
|
+
}
|
|
63
|
+
const emitCloseEvent = () => {
|
|
64
|
+
emit('close', { visible: false })
|
|
65
|
+
}
|
|
51
66
|
const handleStyleVariables = computed(() => {
|
|
52
67
|
return {
|
|
53
68
|
'--sidebar-width': `${props.width}px`,
|
|
@@ -75,22 +90,44 @@ const onAfterEnter = () => {
|
|
|
75
90
|
const onAfterLeave = () => {
|
|
76
91
|
toggleComplete.value = false
|
|
77
92
|
}
|
|
93
|
+
|
|
94
|
+
// set nutation observer watching `visible` attribute in element
|
|
95
|
+
const handleVisibility = (visible: boolean = false) => {
|
|
96
|
+
toggle.value = visible
|
|
97
|
+
}
|
|
98
|
+
const observer = observeVisibleAttr(handleVisibility)
|
|
99
|
+
|
|
78
100
|
watch(
|
|
79
101
|
() => props.visible,
|
|
80
102
|
(newValue) => {
|
|
81
103
|
toggle.value = newValue
|
|
82
104
|
}
|
|
83
105
|
)
|
|
106
|
+
watch(toggle, (newValue) => {
|
|
107
|
+
if (newValue === true) {
|
|
108
|
+
emitOpenEvent()
|
|
109
|
+
} else if (newValue === false && toggleComplete.value === true) {
|
|
110
|
+
emitCloseEvent()
|
|
111
|
+
}
|
|
112
|
+
})
|
|
84
113
|
defineExpose({
|
|
85
|
-
toggle:
|
|
114
|
+
toggle: toggleSidebar,
|
|
86
115
|
open: openSidebar,
|
|
87
116
|
close: closeSidebar,
|
|
88
117
|
})
|
|
118
|
+
onMounted(() => {
|
|
119
|
+
if (sidebarRef.value) {
|
|
120
|
+
observer.observe(sidebarRef.value, { attributes: true })
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
onBeforeUnmount(() => {
|
|
124
|
+
observer.disconnect()
|
|
125
|
+
})
|
|
89
126
|
</script>
|
|
90
127
|
|
|
91
128
|
<template>
|
|
92
|
-
<div :style="handleStyleVariables">
|
|
93
|
-
<button :id="sidebarId" @click="handleToggleEvent" class="hidden"></button>
|
|
129
|
+
<div :style="handleStyleVariables" :visible="toggle" ref="sidebarRef">
|
|
130
|
+
<!-- <button :id="sidebarId" @click="handleToggleEvent" class="hidden"></button> -->
|
|
94
131
|
<Transition name="fade" appear tag="div" v-if="!noBackdrop">
|
|
95
132
|
<section
|
|
96
133
|
v-if="toggle"
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { PropType, defineComponent, h, computed } from 'vue'
|
|
2
|
+
import type { Direction, ColorPalette } from '../../'
|
|
3
|
+
import generateClass from '../../'
|
|
4
|
+
|
|
5
|
+
export default defineComponent({
|
|
6
|
+
props: {
|
|
7
|
+
direction: {
|
|
8
|
+
type: String as PropType<Direction>,
|
|
9
|
+
default: 'right',
|
|
10
|
+
},
|
|
11
|
+
color: {
|
|
12
|
+
type: String as PropType<ColorPalette>,
|
|
13
|
+
default: 'dark-3',
|
|
14
|
+
},
|
|
15
|
+
textColor: {
|
|
16
|
+
type: String as PropType<ColorPalette>,
|
|
17
|
+
default: 'white',
|
|
18
|
+
},
|
|
19
|
+
width: {
|
|
20
|
+
type: [Number, String],
|
|
21
|
+
default: 80,
|
|
22
|
+
},
|
|
23
|
+
customClass: {
|
|
24
|
+
type: String,
|
|
25
|
+
default: '',
|
|
26
|
+
},
|
|
27
|
+
title: {
|
|
28
|
+
type: String,
|
|
29
|
+
required: true,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
setup(props) {
|
|
33
|
+
const defaultClassList: string =
|
|
34
|
+
'invisible opacity-0 group-hover:visible group-hover:opacity-100 z-[100] tooltip'
|
|
35
|
+
const colorClass = computed<string>(() => {
|
|
36
|
+
/**
|
|
37
|
+
* @param {ColorPalette} color - props
|
|
38
|
+
* @param {ColorPalette} textolor - props
|
|
39
|
+
*/
|
|
40
|
+
const { color, textColor } = props
|
|
41
|
+
const classArray: string[] = [
|
|
42
|
+
generateClass('BGCOLOR', color),
|
|
43
|
+
generateClass('TEXTCOLOR', textColor),
|
|
44
|
+
]
|
|
45
|
+
return classArray.join(' ')
|
|
46
|
+
})
|
|
47
|
+
const tooltipWidth = computed(() => {
|
|
48
|
+
return { width: `${props.width}px` }
|
|
49
|
+
})
|
|
50
|
+
const tooltipDirection = computed<string>(() => {
|
|
51
|
+
switch (props.direction) {
|
|
52
|
+
case 'left':
|
|
53
|
+
return 'tooltip-left'
|
|
54
|
+
case 'top':
|
|
55
|
+
return 'tooltip-top'
|
|
56
|
+
case 'bottom':
|
|
57
|
+
return 'tooltip-bottom'
|
|
58
|
+
default:
|
|
59
|
+
return 'tooltip-right'
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
return () =>
|
|
63
|
+
h('div', {
|
|
64
|
+
class: [
|
|
65
|
+
defaultClassList,
|
|
66
|
+
props.customClass,
|
|
67
|
+
tooltipDirection.value,
|
|
68
|
+
colorClass.value,
|
|
69
|
+
],
|
|
70
|
+
role: 'tooltip',
|
|
71
|
+
innerHTML: props.title,
|
|
72
|
+
style: [tooltipWidth.value],
|
|
73
|
+
})
|
|
74
|
+
},
|
|
75
|
+
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobbykim/manguito-theme",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "main theme file for manguito components library. Other MCL components will need to import this file to run.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -17,5 +17,5 @@
|
|
|
17
17
|
"url": "https://github.com/bobbykim89/manguito-component-library.git"
|
|
18
18
|
},
|
|
19
19
|
"license": "MIT",
|
|
20
|
-
"gitHead": "
|
|
20
|
+
"gitHead": "576d9aa7a55803b0dd7391bf81d00081848135ec"
|
|
21
21
|
}
|
package/theme/theme.ts
CHANGED
package/themeVariables.cjs
CHANGED
|
@@ -141,6 +141,48 @@ const mclTheme = plugin.withOptions(
|
|
|
141
141
|
),
|
|
142
142
|
}
|
|
143
143
|
}, {})
|
|
144
|
+
const tooltipColors = Object.keys(colors).reduce((accumulator, key) => {
|
|
145
|
+
// const invalidKeys = ['current', 'transparent', 'inherit']
|
|
146
|
+
// if (invalidKeys.includes(key)) {
|
|
147
|
+
// return
|
|
148
|
+
// }
|
|
149
|
+
if (typeof colors[key] === 'string') {
|
|
150
|
+
return {
|
|
151
|
+
...accumulator,
|
|
152
|
+
[`.tooltip.tooltip-top.bg-${e(key)}`]: {
|
|
153
|
+
[`@apply after:border-t-${key}`]: {},
|
|
154
|
+
},
|
|
155
|
+
[`.tooltip.tooltip-bottom.bg-${e(key)}`]: {
|
|
156
|
+
[`@apply after:border-b-${key}`]: {},
|
|
157
|
+
},
|
|
158
|
+
[`.tooltip.tooltip-right.bg-${e(key)}`]: {
|
|
159
|
+
[`@apply after:border-r-${key}`]: {},
|
|
160
|
+
},
|
|
161
|
+
[`.tooltip.tooltip-left.bg-${e(key)}`]: {
|
|
162
|
+
[`@apply after:border-l-${key}`]: {},
|
|
163
|
+
},
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const colorShades = Object.keys(colors[key])
|
|
167
|
+
return {
|
|
168
|
+
...accumulator,
|
|
169
|
+
...colorShades.reduce((acc, level) => ({
|
|
170
|
+
...acc,
|
|
171
|
+
[`.tooltip.tooltip-top.bg-${e(key)}-${level}`]: {
|
|
172
|
+
[`@apply after:border-t-${key}-${level}`]: {},
|
|
173
|
+
},
|
|
174
|
+
[`.tooltip.tooltip-bottom.bg-${e(key)}-${level}`]: {
|
|
175
|
+
[`@apply after:border-b-${key}-${level}`]: {},
|
|
176
|
+
},
|
|
177
|
+
[`.tooltip.tooltip-right.bg-${e(key)}-${level}`]: {
|
|
178
|
+
[`@apply after:border-r-${key}-${level}`]: {},
|
|
179
|
+
},
|
|
180
|
+
[`.tooltip.tooltip-left.bg-${e(key)}-${level}`]: {
|
|
181
|
+
[`@apply after:border-l-${key}-${level}`]: {},
|
|
182
|
+
},
|
|
183
|
+
})),
|
|
184
|
+
}
|
|
185
|
+
}, {})
|
|
144
186
|
|
|
145
187
|
addBase({
|
|
146
188
|
body: {
|
|
@@ -417,11 +459,80 @@ const mclTheme = plugin.withOptions(
|
|
|
417
459
|
left: '0',
|
|
418
460
|
},
|
|
419
461
|
},
|
|
462
|
+
'.tooltip': {
|
|
463
|
+
'@apply font-normal text-sm transition-opacity duration-200 p-2xs absolute rounded text-center drop-shadow-md':
|
|
464
|
+
{},
|
|
465
|
+
},
|
|
466
|
+
'.tooltip.tooltip-top': {
|
|
467
|
+
left: '50%',
|
|
468
|
+
bottom: '110%',
|
|
469
|
+
transform: 'translateX(-50%)',
|
|
470
|
+
'&::after': {
|
|
471
|
+
content: '" "',
|
|
472
|
+
position: 'absolute',
|
|
473
|
+
top: '100%',
|
|
474
|
+
left: '50%',
|
|
475
|
+
'margin-left': '-5px',
|
|
476
|
+
'border-width': '5px',
|
|
477
|
+
'border-style': 'solid',
|
|
478
|
+
},
|
|
479
|
+
'@apply after:border-t-dark-3 after:border-x-transparent after:border-b-transparent':
|
|
480
|
+
{},
|
|
481
|
+
},
|
|
482
|
+
'.tooltip.tooltip-bottom': {
|
|
483
|
+
left: '50%',
|
|
484
|
+
top: '110%',
|
|
485
|
+
transform: 'translateX(-50%)',
|
|
486
|
+
'&::after': {
|
|
487
|
+
content: '" "',
|
|
488
|
+
position: 'absolute',
|
|
489
|
+
bottom: '100%',
|
|
490
|
+
left: '50%',
|
|
491
|
+
'margin-left': '-5px',
|
|
492
|
+
'border-width': '5px',
|
|
493
|
+
'border-style': 'solid',
|
|
494
|
+
},
|
|
495
|
+
'@apply after:border-t-transparent after:border-x-transparent after:border-b-dark-3':
|
|
496
|
+
{},
|
|
497
|
+
},
|
|
498
|
+
'.tooltip.tooltip-left': {
|
|
499
|
+
top: '50%',
|
|
500
|
+
right: '110%',
|
|
501
|
+
transform: 'translateY(-50%)',
|
|
502
|
+
'&::after': {
|
|
503
|
+
content: '" "',
|
|
504
|
+
position: 'absolute',
|
|
505
|
+
top: '50%',
|
|
506
|
+
left: '100%',
|
|
507
|
+
'margin-top': '-5px',
|
|
508
|
+
'border-width': '5px',
|
|
509
|
+
'border-style': 'solid',
|
|
510
|
+
},
|
|
511
|
+
'@apply after:border-y-transparent after:border-r-transparent after:border-l-dark-3':
|
|
512
|
+
{},
|
|
513
|
+
},
|
|
514
|
+
'.tooltip.tooltip-right': {
|
|
515
|
+
top: '50%',
|
|
516
|
+
left: '110%',
|
|
517
|
+
transform: 'translateY(-50%)',
|
|
518
|
+
'&::after': {
|
|
519
|
+
content: '" "',
|
|
520
|
+
position: 'absolute',
|
|
521
|
+
top: '50%',
|
|
522
|
+
right: '100%',
|
|
523
|
+
'margin-top': '-5px',
|
|
524
|
+
'border-width': '5px',
|
|
525
|
+
'border-style': 'solid',
|
|
526
|
+
},
|
|
527
|
+
'@apply after:border-y-transparent after:border-l-transparent after:border-r-dark-3':
|
|
528
|
+
{},
|
|
529
|
+
},
|
|
420
530
|
})
|
|
421
531
|
|
|
422
532
|
addUtilities(listColors)
|
|
423
533
|
addUtilities(btnColors)
|
|
424
534
|
addUtilities(linkColors)
|
|
535
|
+
addUtilities(tooltipColors)
|
|
425
536
|
}
|
|
426
537
|
},
|
|
427
538
|
(options = {}) => {
|