@bobbykim/manguito-theme 0.3.0 → 0.5.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/index.ts +20 -1
- package/lib/collapse/Collapse.vue +89 -0
- package/lib/collapse/index.types.ts +3 -0
- package/lib/directives/index.ts +78 -0
- package/lib/dropdown/DropdownContainer.vue +47 -0
- package/lib/dropdown/DropdownContent.vue +70 -0
- package/lib/dropdown/index.types.ts +4 -0
- package/lib/modal/Modal.vue +188 -0
- package/lib/nav/HamburgerMenu.vue +121 -0
- package/lib/sidebar/Sidebar.vue +213 -0
- package/package.json +2 -2
- package/theme/index.ts +12 -3
- package/theme/theme.ts +21 -1
- package/theme/theme.types.ts +6 -4
- package/themeVariables.cjs +12 -1
package/index.ts
CHANGED
|
@@ -5,9 +5,16 @@ import GenerateMCLClass, {
|
|
|
5
5
|
scaleType,
|
|
6
6
|
} from './theme'
|
|
7
7
|
import type { ClassType, InputType } from './theme/index.js'
|
|
8
|
+
// base components
|
|
9
|
+
import DropdownContainer from './lib/dropdown/DropdownContainer.vue'
|
|
10
|
+
import DropdownContent from './lib/dropdown/DropdownContent.vue'
|
|
11
|
+
import Collapse from './lib/collapse/Collapse.vue'
|
|
12
|
+
import Sidebar from './lib/sidebar/Sidebar.vue'
|
|
13
|
+
import Modal from './lib/modal/Modal.vue'
|
|
14
|
+
|
|
15
|
+
import HamburgerMenu from './lib/nav/HamburgerMenu.vue'
|
|
8
16
|
|
|
9
17
|
const generateClass = (type: ClassType, value: InputType): string => {
|
|
10
|
-
console.log('running generate class')
|
|
11
18
|
const mclGenerate = new GenerateMCLClass(type, value)
|
|
12
19
|
if ((<string[]>(<unknown>colorType)).includes(type)) {
|
|
13
20
|
return mclGenerate.generateColorClass()
|
|
@@ -26,3 +33,15 @@ const generateClass = (type: ClassType, value: InputType): string => {
|
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
export default generateClass
|
|
36
|
+
|
|
37
|
+
export {
|
|
38
|
+
DropdownContainer,
|
|
39
|
+
DropdownContent,
|
|
40
|
+
Collapse,
|
|
41
|
+
HamburgerMenu,
|
|
42
|
+
Sidebar,
|
|
43
|
+
Modal,
|
|
44
|
+
}
|
|
45
|
+
export * from './lib/directives'
|
|
46
|
+
export * from './theme/theme.types'
|
|
47
|
+
export * from './lib/collapse/index.types'
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, watch, Transition } from 'vue'
|
|
3
|
+
import type { CollapseEvent } from './index.types'
|
|
4
|
+
const props = withDefaults(
|
|
5
|
+
defineProps<{
|
|
6
|
+
collapseId: string
|
|
7
|
+
accordion?: string
|
|
8
|
+
className?: string
|
|
9
|
+
visible?: boolean
|
|
10
|
+
}>(),
|
|
11
|
+
{
|
|
12
|
+
className: '',
|
|
13
|
+
visible: false,
|
|
14
|
+
}
|
|
15
|
+
)
|
|
16
|
+
const emit = defineEmits(['toggle'])
|
|
17
|
+
const toggle = ref<boolean>(props.visible)
|
|
18
|
+
|
|
19
|
+
const handleToggleEvent = (e: Event): void => {
|
|
20
|
+
toggle.value = !toggle.value
|
|
21
|
+
emit('toggle', { ...e, visible: toggle.value } as CollapseEvent)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @TransitionFunctions
|
|
26
|
+
* @param {HTMLElement} el - passed any since transition handlers don't accept HTMLElement (accepts Element)
|
|
27
|
+
*/
|
|
28
|
+
const onEnter = (el: any) => {
|
|
29
|
+
el.style.height = 'auto'
|
|
30
|
+
el.style.opacity = '0'
|
|
31
|
+
const endWidth = getComputedStyle(el).height
|
|
32
|
+
el.style.height = '0px'
|
|
33
|
+
el.offsetHeight // force repaint
|
|
34
|
+
el.style.height = endWidth
|
|
35
|
+
el.style.opacity = '1'
|
|
36
|
+
}
|
|
37
|
+
const onAfterEnter = (el: any) => {
|
|
38
|
+
el.style.height = 'auto'
|
|
39
|
+
el.style.opacity = '1'
|
|
40
|
+
}
|
|
41
|
+
const onLeave = (el: any) => {
|
|
42
|
+
el.style.height = getComputedStyle(el).height
|
|
43
|
+
el.offsetHeight // force repaint
|
|
44
|
+
el.style.height = '0px'
|
|
45
|
+
el.style.opacity = '0'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
watch(
|
|
49
|
+
() => props.visible,
|
|
50
|
+
(newValue) => {
|
|
51
|
+
toggle.value = newValue
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<template>
|
|
57
|
+
<div>
|
|
58
|
+
<button
|
|
59
|
+
:id="collapseId"
|
|
60
|
+
@click="handleToggleEvent"
|
|
61
|
+
class="hidden"
|
|
62
|
+
:accordion="accordion"
|
|
63
|
+
:visible="toggle"
|
|
64
|
+
></button>
|
|
65
|
+
<transition
|
|
66
|
+
name="collapse"
|
|
67
|
+
tag="div"
|
|
68
|
+
@enter="onEnter"
|
|
69
|
+
@after-enter="onAfterEnter"
|
|
70
|
+
@leave="onLeave"
|
|
71
|
+
class="overflow-hidden"
|
|
72
|
+
>
|
|
73
|
+
<div v-show="toggle">
|
|
74
|
+
<div :class="[className]">
|
|
75
|
+
<slot />
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</transition>
|
|
79
|
+
</div>
|
|
80
|
+
</template>
|
|
81
|
+
|
|
82
|
+
<style scoped lang="scss">
|
|
83
|
+
.collapse-enter-active,
|
|
84
|
+
.collapse-leave-active {
|
|
85
|
+
transition-property: height, opacity;
|
|
86
|
+
transition-duration: 500ms;
|
|
87
|
+
transition-timing-function: ease;
|
|
88
|
+
}
|
|
89
|
+
</style>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Directive } from 'vue'
|
|
2
|
+
|
|
3
|
+
export const vClickOutside: Directive = {
|
|
4
|
+
mounted(el, binding) {
|
|
5
|
+
el.__ClickOutsideHandler = (event: Event) => {
|
|
6
|
+
if (!(el === event.target || el.contains(event.target))) {
|
|
7
|
+
binding.value(event)
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
document.body.addEventListener('click', el.__ClickOutsideHandler)
|
|
11
|
+
},
|
|
12
|
+
unmounted(el) {
|
|
13
|
+
document.body.removeEventListener('click', el.__ClickOutsideHandler)
|
|
14
|
+
},
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const vToggle: Directive = {
|
|
18
|
+
mounted(el, binding) {
|
|
19
|
+
el.__ClickToggleHandler = (e: Event): void => {
|
|
20
|
+
const eTarget = e.target as HTMLElement
|
|
21
|
+
let target: HTMLElement
|
|
22
|
+
if (eTarget.tagName === 'A') {
|
|
23
|
+
const targetId = eTarget.getAttribute('href')
|
|
24
|
+
const formattedTargetId =
|
|
25
|
+
targetId?.charAt(0) === '#' ? targetId.substring(1) : targetId
|
|
26
|
+
target = document.getElementById(formattedTargetId as string)!
|
|
27
|
+
} else {
|
|
28
|
+
target = document.getElementById(binding.arg as string)!
|
|
29
|
+
}
|
|
30
|
+
target.click()
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
el.addEventListener('click', el.__ClickToggleHandler)
|
|
34
|
+
},
|
|
35
|
+
unmounted(el) {
|
|
36
|
+
el.removeEventListener('click', el.__ClickToggleHandler)
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const vCollapse: Directive = {
|
|
41
|
+
mounted(el, binding) {
|
|
42
|
+
el.__HandleToggler = (event: Event): void => {
|
|
43
|
+
const eTarget = event.target as HTMLElement
|
|
44
|
+
let target: HTMLElement
|
|
45
|
+
if (eTarget.tagName === 'A') {
|
|
46
|
+
const targetId = eTarget.getAttribute('href')
|
|
47
|
+
const formattedTargetId =
|
|
48
|
+
targetId?.charAt(0) === '#' ? targetId.substring(1) : targetId
|
|
49
|
+
target = document.getElementById(formattedTargetId as string)!
|
|
50
|
+
} else {
|
|
51
|
+
target = document.getElementById(binding.arg as string) as HTMLElement
|
|
52
|
+
}
|
|
53
|
+
if (!target.hasAttribute('accordion')) {
|
|
54
|
+
// run when it is not accordion component case
|
|
55
|
+
target.click()
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
const accordionName = target.getAttribute('accordion')
|
|
59
|
+
const accordionList: NodeListOf<HTMLElement> = document.querySelectorAll(
|
|
60
|
+
`button[accordion="${accordionName}"]`
|
|
61
|
+
)
|
|
62
|
+
// loop through each accordion items and handle reaction for each case
|
|
63
|
+
for (let i = 0; i < accordionList.length; i++) {
|
|
64
|
+
const isVisible = accordionList[i].getAttribute('visible')
|
|
65
|
+
if (accordionList[i].id !== target.id && isVisible === 'true') {
|
|
66
|
+
accordionList[i].click()
|
|
67
|
+
}
|
|
68
|
+
if (accordionList[i].id === target.id) {
|
|
69
|
+
accordionList[i].click()
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
el.addEventListener('click', el.__HandleToggler)
|
|
74
|
+
},
|
|
75
|
+
unmounted(el) {
|
|
76
|
+
el.removeEventListener('click', el.__HandleToggler)
|
|
77
|
+
},
|
|
78
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { reactive, provide, ref, onMounted } from 'vue'
|
|
3
|
+
import type { InjectType } from './index.types'
|
|
4
|
+
import { vClickOutside } from '../directives'
|
|
5
|
+
|
|
6
|
+
const emit = defineEmits(['click-outside', 'toggle'])
|
|
7
|
+
const dropdownTarget = ref()
|
|
8
|
+
const dropdownState = reactive<InjectType>({
|
|
9
|
+
active: false,
|
|
10
|
+
buttonHeight: 0,
|
|
11
|
+
})
|
|
12
|
+
provide('dropdownState', dropdownState)
|
|
13
|
+
const toggle = (e: Event): void => {
|
|
14
|
+
dropdownState.active = !dropdownState.active
|
|
15
|
+
emit('toggle', e)
|
|
16
|
+
}
|
|
17
|
+
const onClickOutside = (e: Event): void => {
|
|
18
|
+
dropdownState.active = false
|
|
19
|
+
emit('click-outside', e)
|
|
20
|
+
}
|
|
21
|
+
const onEscape = (): void => {
|
|
22
|
+
dropdownState.active = false
|
|
23
|
+
}
|
|
24
|
+
onMounted(() => {
|
|
25
|
+
if (typeof window !== undefined) {
|
|
26
|
+
dropdownState.buttonHeight = dropdownTarget.value.scrollHeight
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<div
|
|
33
|
+
class="relative"
|
|
34
|
+
ref="dropdownTarget"
|
|
35
|
+
v-click-outside="onClickOutside"
|
|
36
|
+
@keyup.esc="onEscape"
|
|
37
|
+
>
|
|
38
|
+
<slot
|
|
39
|
+
name="toggler"
|
|
40
|
+
:toggle="toggle"
|
|
41
|
+
:dropdown-state="dropdownState.active"
|
|
42
|
+
/>
|
|
43
|
+
<slot></slot>
|
|
44
|
+
</div>
|
|
45
|
+
</template>
|
|
46
|
+
|
|
47
|
+
<style lang="scss" scoped></style>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, ref, inject, Transition } from 'vue'
|
|
3
|
+
import { InjectType } from './index.types'
|
|
4
|
+
|
|
5
|
+
const props = withDefaults(
|
|
6
|
+
defineProps<{
|
|
7
|
+
className?: string
|
|
8
|
+
}>(),
|
|
9
|
+
{
|
|
10
|
+
className: '',
|
|
11
|
+
}
|
|
12
|
+
)
|
|
13
|
+
const contentRef = ref<HTMLAreaElement>()
|
|
14
|
+
const dropdownState = inject<InjectType>('dropdownState', {
|
|
15
|
+
active: false,
|
|
16
|
+
buttonHeight: 0,
|
|
17
|
+
})
|
|
18
|
+
const active = computed<boolean>(() => {
|
|
19
|
+
return dropdownState.active
|
|
20
|
+
})
|
|
21
|
+
const handleItemClick = () => {
|
|
22
|
+
dropdownState.active = false
|
|
23
|
+
}
|
|
24
|
+
const buttonHeight = computed(() => {
|
|
25
|
+
return { '--button-height': `${dropdownState.buttonHeight}px` }
|
|
26
|
+
})
|
|
27
|
+
const dropdownDirection = computed<string | undefined>(() => {
|
|
28
|
+
if (typeof window === undefined) {
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
if (!dropdownState.active || !contentRef.value) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
if (
|
|
35
|
+
window.innerHeight - contentRef.value.getBoundingClientRect().bottom <
|
|
36
|
+
0
|
|
37
|
+
) {
|
|
38
|
+
return 'dropup-bottom'
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<template>
|
|
44
|
+
<transition name="dropdown-content">
|
|
45
|
+
<div
|
|
46
|
+
v-if="active"
|
|
47
|
+
ref="contentRef"
|
|
48
|
+
class="absolute my-2xs max-w-[14rem] w-max overflow-hidden"
|
|
49
|
+
:class="[dropdownDirection, className]"
|
|
50
|
+
:style="buttonHeight"
|
|
51
|
+
>
|
|
52
|
+
<slot :item-click="handleItemClick" />
|
|
53
|
+
</div>
|
|
54
|
+
</transition>
|
|
55
|
+
</template>
|
|
56
|
+
|
|
57
|
+
<style scoped lang="scss">
|
|
58
|
+
.dropup-bottom {
|
|
59
|
+
bottom: var(--button-height);
|
|
60
|
+
}
|
|
61
|
+
.dropdown-content-enter-active,
|
|
62
|
+
.dropdown-content-leave-active {
|
|
63
|
+
transition: all 0.3s;
|
|
64
|
+
}
|
|
65
|
+
.dropdown-content-enter-from,
|
|
66
|
+
.dropdown-content-leave-to {
|
|
67
|
+
opacity: 0;
|
|
68
|
+
transform: translateY(-10px);
|
|
69
|
+
}
|
|
70
|
+
</style>
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, computed, watch, Transition } from 'vue'
|
|
3
|
+
import generateClass, {
|
|
4
|
+
ColorPalette,
|
|
5
|
+
vClickOutside,
|
|
6
|
+
VerticalAlignment,
|
|
7
|
+
} from '../../'
|
|
8
|
+
|
|
9
|
+
const props = withDefaults(
|
|
10
|
+
defineProps<{
|
|
11
|
+
modalId: string
|
|
12
|
+
title?: string
|
|
13
|
+
titleColor?: ColorPalette
|
|
14
|
+
className?: string
|
|
15
|
+
visible?: boolean
|
|
16
|
+
noBackdrop?: boolean
|
|
17
|
+
noHeader?: boolean
|
|
18
|
+
color?: ColorPalette
|
|
19
|
+
backdropColor?: ColorPalette
|
|
20
|
+
placement?: VerticalAlignment
|
|
21
|
+
}>(),
|
|
22
|
+
{
|
|
23
|
+
titleColor: 'dark-3',
|
|
24
|
+
className: '',
|
|
25
|
+
visible: false,
|
|
26
|
+
noBackdrop: false,
|
|
27
|
+
noHeader: false,
|
|
28
|
+
color: 'light-1',
|
|
29
|
+
backdropColor: 'dark-4',
|
|
30
|
+
placement: 'center',
|
|
31
|
+
}
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
const emit = defineEmits(['toggle', 'close'])
|
|
35
|
+
const toggle = ref<boolean>(props.visible)
|
|
36
|
+
const toggleComplete = ref<boolean>(false)
|
|
37
|
+
|
|
38
|
+
const handleToggleEvent = (e: Event): void => {
|
|
39
|
+
toggle.value = !toggle.value
|
|
40
|
+
emit('toggle', e)
|
|
41
|
+
}
|
|
42
|
+
const openModal = (): void => {
|
|
43
|
+
toggle.value = true
|
|
44
|
+
}
|
|
45
|
+
const closeModal = (e: Event): void => {
|
|
46
|
+
if (toggleComplete.value === true) {
|
|
47
|
+
toggle.value = false
|
|
48
|
+
emit('close', e)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const handlePlacementVar = computed(() => {
|
|
52
|
+
let placementVariable: number
|
|
53
|
+
if (props.placement === 'top') {
|
|
54
|
+
placementVariable = 25
|
|
55
|
+
} else if (props.placement === 'bottom') {
|
|
56
|
+
placementVariable = 75
|
|
57
|
+
} else {
|
|
58
|
+
placementVariable = 50
|
|
59
|
+
}
|
|
60
|
+
return { '--vertical-placement': placementVariable + '%' }
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @TransitionFunctions
|
|
65
|
+
* Handle toggleComplete value after completion of animation
|
|
66
|
+
*/
|
|
67
|
+
const onAfterEnter = () => {
|
|
68
|
+
toggleComplete.value = true
|
|
69
|
+
}
|
|
70
|
+
const onAfterLeave = () => {
|
|
71
|
+
toggleComplete.value = false
|
|
72
|
+
}
|
|
73
|
+
watch(
|
|
74
|
+
() => props.visible,
|
|
75
|
+
(newValue) => {
|
|
76
|
+
toggle.value = newValue
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
defineExpose({
|
|
80
|
+
toggle: handleToggleEvent,
|
|
81
|
+
close: closeModal,
|
|
82
|
+
open: openModal,
|
|
83
|
+
})
|
|
84
|
+
</script>
|
|
85
|
+
|
|
86
|
+
<template>
|
|
87
|
+
<div :style="handlePlacementVar">
|
|
88
|
+
<button :id="modalId" @click="handleToggleEvent" class="hidden"></button>
|
|
89
|
+
<Transition name="fade" appear tag="div" v-if="!noBackdrop">
|
|
90
|
+
<section
|
|
91
|
+
v-if="toggle"
|
|
92
|
+
@click="closeModal"
|
|
93
|
+
class="fixed inset-0 overflow-y-auto bg-opacity-70 backdrop-blur z-[100]"
|
|
94
|
+
:class="generateClass('BGCOLOR', backdropColor)"
|
|
95
|
+
></section>
|
|
96
|
+
</Transition>
|
|
97
|
+
<Transition
|
|
98
|
+
name="slide-down"
|
|
99
|
+
tag="div"
|
|
100
|
+
@after-enter="onAfterEnter"
|
|
101
|
+
@after-leave="onAfterLeave"
|
|
102
|
+
appear
|
|
103
|
+
>
|
|
104
|
+
<div
|
|
105
|
+
v-if="toggle"
|
|
106
|
+
class="vertical-placement fixed w-full max-w-md z-[110] px-xs"
|
|
107
|
+
>
|
|
108
|
+
<div
|
|
109
|
+
v-click-outside="closeModal"
|
|
110
|
+
:class="[generateClass('BGCOLOR', color), className]"
|
|
111
|
+
class="relative overscroll-contain overflow-y-scroll max-h-[80vh] md:max-h-[60vh]"
|
|
112
|
+
>
|
|
113
|
+
<div v-if="!noHeader" class="sticky top-0">
|
|
114
|
+
<slot name="header" :close="closeModal" :status="toggle">
|
|
115
|
+
<div
|
|
116
|
+
class="flex justify-between items-center p-xs border-b-2"
|
|
117
|
+
:class="generateClass('BGCOLOR', color)"
|
|
118
|
+
>
|
|
119
|
+
<h3
|
|
120
|
+
v-if="title"
|
|
121
|
+
class="h3-md"
|
|
122
|
+
:class="generateClass('TEXTCOLOR', titleColor)"
|
|
123
|
+
>
|
|
124
|
+
{{ title }}
|
|
125
|
+
</h3>
|
|
126
|
+
<button @click="closeModal">
|
|
127
|
+
<svg
|
|
128
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
129
|
+
height="1em"
|
|
130
|
+
viewBox="0 0 384 512"
|
|
131
|
+
class="hover:opacity-75 focus:opacity-75 transition-opacity duration-300 ease-in h-sm"
|
|
132
|
+
:class="[generateClass('SVGFILL', titleColor)]"
|
|
133
|
+
>
|
|
134
|
+
<!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
|
|
135
|
+
<path
|
|
136
|
+
d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"
|
|
137
|
+
/>
|
|
138
|
+
</svg>
|
|
139
|
+
</button>
|
|
140
|
+
</div>
|
|
141
|
+
</slot>
|
|
142
|
+
</div>
|
|
143
|
+
<slot name="body" :close="closeModal" :status="toggle" />
|
|
144
|
+
<div class="sticky bottom-0">
|
|
145
|
+
<slot name="footer" :close="closeModal" :status="toggle" />
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
</Transition>
|
|
150
|
+
</div>
|
|
151
|
+
</template>
|
|
152
|
+
|
|
153
|
+
<style scoped lang="scss">
|
|
154
|
+
.vertical-placement {
|
|
155
|
+
top: var(--vertical-placement);
|
|
156
|
+
left: 50%;
|
|
157
|
+
transform: translateY(calc(-1 * var(--vertical-placement))) translateX(-50%);
|
|
158
|
+
}
|
|
159
|
+
.fade-enter-active,
|
|
160
|
+
.fade-leave-active {
|
|
161
|
+
transition-property: opacity;
|
|
162
|
+
transition-duration: 300ms;
|
|
163
|
+
transition-timing-function: linear;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.fade-enter-from,
|
|
167
|
+
.fade-leave-to {
|
|
168
|
+
opacity: 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.slide-down-enter-active {
|
|
172
|
+
animation: slide-down 300ms ease;
|
|
173
|
+
}
|
|
174
|
+
.slide-down-leave-active {
|
|
175
|
+
animation: slide-down reverse 300ms ease;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@keyframes slide-down {
|
|
179
|
+
0% {
|
|
180
|
+
opacity: 0;
|
|
181
|
+
transform: translateY(-100%) translateX(-50%);
|
|
182
|
+
}
|
|
183
|
+
100% {
|
|
184
|
+
opacity: 1;
|
|
185
|
+
transform: translateY(calc(-1 * var(--vertical-placement))) translateX(-50%);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
</style>
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import type { ColorPalette } from '@bobbykim/manguito-theme'
|
|
4
|
+
import generateClass from '../../index'
|
|
5
|
+
|
|
6
|
+
const props = withDefaults(
|
|
7
|
+
defineProps<{
|
|
8
|
+
color?: ColorPalette
|
|
9
|
+
displayBorder?: boolean
|
|
10
|
+
toggle: boolean
|
|
11
|
+
navColor: ColorPalette
|
|
12
|
+
}>(),
|
|
13
|
+
{
|
|
14
|
+
color: 'dark-2',
|
|
15
|
+
displayBorder: true,
|
|
16
|
+
}
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
const emit = defineEmits(['hbg-click'])
|
|
20
|
+
|
|
21
|
+
const handleButtonToggle = (e: Event): void => {
|
|
22
|
+
emit('hbg-click', e)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const hamburgetButtonState = computed({
|
|
26
|
+
get() {
|
|
27
|
+
return props.toggle
|
|
28
|
+
},
|
|
29
|
+
set(value) {
|
|
30
|
+
return value
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const getBorderClass = (
|
|
35
|
+
bColor: ColorPalette,
|
|
36
|
+
border: boolean,
|
|
37
|
+
nColor: ColorPalette
|
|
38
|
+
): string => {
|
|
39
|
+
/**
|
|
40
|
+
* @bColor - color
|
|
41
|
+
* @border - displayBorder
|
|
42
|
+
* @nColor - navColor
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
const classArray: string[] = [
|
|
46
|
+
generateClass('RINGCOLOR', bColor),
|
|
47
|
+
generateClass('OFFSETRING', nColor),
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
if (border) {
|
|
51
|
+
classArray.push(generateClass('BORDER', bColor))
|
|
52
|
+
classArray.push('border')
|
|
53
|
+
}
|
|
54
|
+
return classArray.join(' ')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const getHamburgerButtonClass = (color: ColorPalette): string => {
|
|
58
|
+
/**
|
|
59
|
+
* @color - color
|
|
60
|
+
*/
|
|
61
|
+
const classArray: string[] = [
|
|
62
|
+
generateClass('BGCOLOR', color),
|
|
63
|
+
generateClass('BEFOREBG', color),
|
|
64
|
+
generateClass('AFTERBG', color),
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
return classArray.join(' ')
|
|
68
|
+
}
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<template>
|
|
72
|
+
<button
|
|
73
|
+
class="p-3xs rounded-md aspect-square outline-none focus:ring-4 ring-offset-2 transition-all duration-300 ease-linear hover:opacity-70 focus:opacity-70 hamburger__button"
|
|
74
|
+
:class="getBorderClass(color, displayBorder, navColor)"
|
|
75
|
+
@click="handleButtonToggle"
|
|
76
|
+
>
|
|
77
|
+
<input
|
|
78
|
+
type="checkbox"
|
|
79
|
+
v-model="hamburgetButtonState"
|
|
80
|
+
class="hidden hamburger__checkbox"
|
|
81
|
+
/>
|
|
82
|
+
<div
|
|
83
|
+
class="relative h-[3px] w-sm hamburger__icon before:w-sm after:w-sm before:h-[3px] after:h-[3px] transition-all duration-300 ease-linear"
|
|
84
|
+
:class="getHamburgerButtonClass(color)"
|
|
85
|
+
></div>
|
|
86
|
+
</button>
|
|
87
|
+
</template>
|
|
88
|
+
|
|
89
|
+
<style lang="scss" scoped>
|
|
90
|
+
.hamburger__icon {
|
|
91
|
+
&::before,
|
|
92
|
+
&::after {
|
|
93
|
+
position: absolute;
|
|
94
|
+
left: 0;
|
|
95
|
+
transition: all 0.3s linear;
|
|
96
|
+
}
|
|
97
|
+
&::before {
|
|
98
|
+
top: -0.5rem;
|
|
99
|
+
}
|
|
100
|
+
&::after {
|
|
101
|
+
top: 0.5rem;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
.hamburger__button {
|
|
105
|
+
&:focus .hamburger__icon,
|
|
106
|
+
&:hover .hamburger__icon {
|
|
107
|
+
scale: 1.05;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
.hamburger__checkbox:checked + .hamburger__icon {
|
|
111
|
+
background-color: transparent;
|
|
112
|
+
}
|
|
113
|
+
.hamburger__checkbox:checked + .hamburger__icon::before {
|
|
114
|
+
top: 0;
|
|
115
|
+
transform: rotate(135deg);
|
|
116
|
+
}
|
|
117
|
+
.hamburger__checkbox:checked + .hamburger__icon::after {
|
|
118
|
+
top: 0;
|
|
119
|
+
transform: rotate(-135deg);
|
|
120
|
+
}
|
|
121
|
+
</style>
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, computed, watch, Transition } from 'vue'
|
|
3
|
+
import generateClass, { ColorPalette, vClickOutside, DirectionX } from '../../'
|
|
4
|
+
|
|
5
|
+
const props = withDefaults(
|
|
6
|
+
defineProps<{
|
|
7
|
+
sidebarId: string
|
|
8
|
+
title?: string
|
|
9
|
+
titleColor?: ColorPalette
|
|
10
|
+
className?: string
|
|
11
|
+
visible?: boolean
|
|
12
|
+
noBackdrop?: boolean
|
|
13
|
+
noHeader?: boolean
|
|
14
|
+
color?: ColorPalette
|
|
15
|
+
backdropColor?: ColorPalette
|
|
16
|
+
placement?: DirectionX
|
|
17
|
+
width?: string | number
|
|
18
|
+
}>(),
|
|
19
|
+
{
|
|
20
|
+
titleColor: 'dark-3',
|
|
21
|
+
className: '',
|
|
22
|
+
visible: false,
|
|
23
|
+
noBackdrop: false,
|
|
24
|
+
noHeader: false,
|
|
25
|
+
color: 'light-1',
|
|
26
|
+
backdropColor: 'dark-4',
|
|
27
|
+
placement: 'left',
|
|
28
|
+
width: 300,
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
const emit = defineEmits(['toggle', 'close'])
|
|
33
|
+
const toggle = ref<boolean>(props.visible)
|
|
34
|
+
const toggleComplete = ref<boolean>(false)
|
|
35
|
+
const headerRef = ref<HTMLElement>()
|
|
36
|
+
const footerRef = ref<HTMLElement>()
|
|
37
|
+
|
|
38
|
+
const handleToggleEvent = (e: Event): void => {
|
|
39
|
+
toggle.value = !toggle.value
|
|
40
|
+
emit('toggle', e)
|
|
41
|
+
}
|
|
42
|
+
const openSidebar = (): void => {
|
|
43
|
+
toggle.value = true
|
|
44
|
+
}
|
|
45
|
+
const closeSidebar = (e: Event): void => {
|
|
46
|
+
if (toggleComplete.value === true) {
|
|
47
|
+
toggle.value = false
|
|
48
|
+
emit('close', e)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const handleStyleVariables = computed(() => {
|
|
52
|
+
return {
|
|
53
|
+
'--sidebar-width': `${props.width}px`,
|
|
54
|
+
'--header-height':
|
|
55
|
+
headerRef.value && toggle.value
|
|
56
|
+
? headerRef.value.scrollHeight + 'px'
|
|
57
|
+
: '0px',
|
|
58
|
+
'--footer-height':
|
|
59
|
+
footerRef.value && toggle.value
|
|
60
|
+
? footerRef.value.scrollHeight + 'px'
|
|
61
|
+
: '0px',
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
const sidebarClass = computed(() => {
|
|
65
|
+
return props.placement === 'left' ? 'sidebar-left' : 'sidebar-right'
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @TransitionFunctions
|
|
70
|
+
* Handle toggleComplete value after completion of animation
|
|
71
|
+
*/
|
|
72
|
+
const onAfterEnter = () => {
|
|
73
|
+
toggleComplete.value = true
|
|
74
|
+
}
|
|
75
|
+
const onAfterLeave = () => {
|
|
76
|
+
toggleComplete.value = false
|
|
77
|
+
}
|
|
78
|
+
watch(
|
|
79
|
+
() => props.visible,
|
|
80
|
+
(newValue) => {
|
|
81
|
+
toggle.value = newValue
|
|
82
|
+
}
|
|
83
|
+
)
|
|
84
|
+
defineExpose({
|
|
85
|
+
toggle: handleToggleEvent,
|
|
86
|
+
open: openSidebar,
|
|
87
|
+
close: closeSidebar,
|
|
88
|
+
})
|
|
89
|
+
</script>
|
|
90
|
+
|
|
91
|
+
<template>
|
|
92
|
+
<div :style="handleStyleVariables">
|
|
93
|
+
<button :id="sidebarId" @click="handleToggleEvent" class="hidden"></button>
|
|
94
|
+
<Transition name="fade" appear tag="div" v-if="!noBackdrop">
|
|
95
|
+
<section
|
|
96
|
+
v-if="toggle"
|
|
97
|
+
@click="closeSidebar"
|
|
98
|
+
class="fixed inset-0 overflow-y-auto bg-opacity-70 backdrop-blur z-[100]"
|
|
99
|
+
:class="generateClass('BGCOLOR', backdropColor)"
|
|
100
|
+
></section>
|
|
101
|
+
</Transition>
|
|
102
|
+
<Transition
|
|
103
|
+
:name="sidebarClass"
|
|
104
|
+
@after-enter="onAfterEnter"
|
|
105
|
+
@after-leave="onAfterLeave"
|
|
106
|
+
appear
|
|
107
|
+
>
|
|
108
|
+
<div
|
|
109
|
+
v-if="toggle"
|
|
110
|
+
v-click-outside="closeSidebar"
|
|
111
|
+
class="sidebar-body fixed h-full overflow-hidden inset-y-0 shadow z-[110]"
|
|
112
|
+
:class="[placement === 'left' ? 'left-0' : 'right-0']"
|
|
113
|
+
>
|
|
114
|
+
<div
|
|
115
|
+
class="relative h-full overscroll-contain overflow-y-scroll"
|
|
116
|
+
:class="[generateClass('BGCOLOR', color), className]"
|
|
117
|
+
>
|
|
118
|
+
<div v-if="!noHeader" class="sticky top-0" ref="headerRef">
|
|
119
|
+
<slot name="header" :close="closeSidebar" :status="toggle">
|
|
120
|
+
<div
|
|
121
|
+
class="flex justify-between items-center p-xs"
|
|
122
|
+
:class="generateClass('BGCOLOR', color)"
|
|
123
|
+
>
|
|
124
|
+
<h3
|
|
125
|
+
v-if="title"
|
|
126
|
+
class="h3-md"
|
|
127
|
+
:class="generateClass('TEXTCOLOR', titleColor)"
|
|
128
|
+
>
|
|
129
|
+
{{ title }}
|
|
130
|
+
</h3>
|
|
131
|
+
<button @click="closeSidebar">
|
|
132
|
+
<svg
|
|
133
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
134
|
+
height="1em"
|
|
135
|
+
viewBox="0 0 384 512"
|
|
136
|
+
class="hover:opacity-75 focus:opacity-75 transition-opacity duration-300 ease-in h-sm"
|
|
137
|
+
:class="[generateClass('SVGFILL', titleColor)]"
|
|
138
|
+
>
|
|
139
|
+
<!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
|
|
140
|
+
<path
|
|
141
|
+
d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"
|
|
142
|
+
/>
|
|
143
|
+
</svg>
|
|
144
|
+
</button>
|
|
145
|
+
</div>
|
|
146
|
+
</slot>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<div class="sidebar-body-height">
|
|
150
|
+
<slot name="body" :close="closeSidebar" :status="toggle" />
|
|
151
|
+
</div>
|
|
152
|
+
|
|
153
|
+
<div class="sticky bottom-0" ref="footerRef">
|
|
154
|
+
<slot name="footer" :close="closeSidebar" :status="toggle" />
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
</Transition>
|
|
159
|
+
</div>
|
|
160
|
+
</template>
|
|
161
|
+
|
|
162
|
+
<style scoped lang="scss">
|
|
163
|
+
.sidebar-body {
|
|
164
|
+
width: 100%;
|
|
165
|
+
}
|
|
166
|
+
.sidebar-body-height {
|
|
167
|
+
min-height: calc(100vh - var(--header-height) - var(--footer-height));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.fade-enter-active,
|
|
171
|
+
.fade-leave-active {
|
|
172
|
+
transition-property: opacity;
|
|
173
|
+
transition-duration: 300ms;
|
|
174
|
+
transition-timing-function: linear;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.fade-enter-from,
|
|
178
|
+
.fade-leave-to {
|
|
179
|
+
opacity: 0;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.sidebar-left-enter-active,
|
|
183
|
+
.sidebar-left-leave-active,
|
|
184
|
+
.sidebar-right-enter-active,
|
|
185
|
+
.sidebar-right-leave-active {
|
|
186
|
+
transition-property: transform, opacity;
|
|
187
|
+
transition-duration: 300ms;
|
|
188
|
+
transition-timing-function: linear;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.sidebar-left-enter-from,
|
|
192
|
+
.sidebar-left-leave-to {
|
|
193
|
+
transform: translateX(-100%);
|
|
194
|
+
}
|
|
195
|
+
.sidebar-right-enter-from,
|
|
196
|
+
.sidebar-right-leave-to {
|
|
197
|
+
transform: translateX(100%);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
@media screen and (min-width: 768px) {
|
|
201
|
+
.sidebar-body {
|
|
202
|
+
width: var(--sidebar-width);
|
|
203
|
+
}
|
|
204
|
+
.sidebar-left-enter-from,
|
|
205
|
+
.sidebar-left-leave-to {
|
|
206
|
+
transform: translateX(calc(-1 * var(--sidebar-width)));
|
|
207
|
+
}
|
|
208
|
+
.sidebar-right-enter-from,
|
|
209
|
+
.sidebar-right-leave-to {
|
|
210
|
+
transform: translateX(var(--sidebar-width));
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
</style>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobbykim/manguito-theme",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.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": "c095c399687fa416347eaec8a6d2003a39fc19ac"
|
|
21
21
|
}
|
package/theme/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
Range,
|
|
8
8
|
OpacityRange,
|
|
9
9
|
SpacingLevel,
|
|
10
|
-
|
|
10
|
+
Alignment,
|
|
11
11
|
} from './theme.types'
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -21,6 +21,7 @@ export const colorType = [
|
|
|
21
21
|
'BEFOREBG',
|
|
22
22
|
'AFTERBG',
|
|
23
23
|
'HVBGCOLOR',
|
|
24
|
+
'FCBGCOLOR',
|
|
24
25
|
'ACTIVEBG',
|
|
25
26
|
'TEXTCOLOR',
|
|
26
27
|
'HVTEXTCOLOR',
|
|
@@ -101,7 +102,7 @@ export type InputType =
|
|
|
101
102
|
| Range<1, 12>
|
|
102
103
|
| OpacityRange
|
|
103
104
|
| SpacingLevel
|
|
104
|
-
|
|
|
105
|
+
| Alignment
|
|
105
106
|
|
|
106
107
|
class GenerateMCLClass extends MCLTheme {
|
|
107
108
|
classType: ClassType
|
|
@@ -119,6 +120,8 @@ class GenerateMCLClass extends MCLTheme {
|
|
|
119
120
|
return this.getBgColorClass()
|
|
120
121
|
case 'HVBGCOLOR':
|
|
121
122
|
return this.getHoverBgColorClass()
|
|
123
|
+
case 'FCBGCOLOR':
|
|
124
|
+
return this.getFocusBgColorClass()
|
|
122
125
|
case 'BEFOREBG':
|
|
123
126
|
return this.getBeforeBgColorClass()
|
|
124
127
|
case 'AFTERBG':
|
|
@@ -274,6 +277,12 @@ class GenerateMCLClass extends MCLTheme {
|
|
|
274
277
|
}
|
|
275
278
|
return MCLTheme.hoverBgColor[this.classValue as ColorPalette]
|
|
276
279
|
}
|
|
280
|
+
getFocusBgColorClass(): string {
|
|
281
|
+
if (!this.validateColorType) {
|
|
282
|
+
return ' '
|
|
283
|
+
}
|
|
284
|
+
return MCLTheme.focusBgColor[this.classValue as ColorPalette]
|
|
285
|
+
}
|
|
277
286
|
getBeforeBgColorClass(): string {
|
|
278
287
|
if (!this.validateColorType) {
|
|
279
288
|
return ' '
|
|
@@ -440,7 +449,7 @@ class GenerateMCLClass extends MCLTheme {
|
|
|
440
449
|
}
|
|
441
450
|
// handle text align classes
|
|
442
451
|
getTextAlignClass(): string {
|
|
443
|
-
return MCLTheme.textAlign[this.classValue as
|
|
452
|
+
return MCLTheme.textAlign[this.classValue as Alignment]
|
|
444
453
|
}
|
|
445
454
|
// handle border width classes
|
|
446
455
|
getBorderWidthClass(): string {
|
package/theme/theme.ts
CHANGED
|
@@ -60,7 +60,7 @@ abstract class MCLTheme {
|
|
|
60
60
|
white: 'bg-white',
|
|
61
61
|
transparent: 'bg-transparent',
|
|
62
62
|
}
|
|
63
|
-
// hover bg color class
|
|
63
|
+
// hover: bg color class
|
|
64
64
|
protected static hoverBgColor: ColorClass = {
|
|
65
65
|
primary: 'hover:bg-primary',
|
|
66
66
|
secondary: 'hover:bg-secondary',
|
|
@@ -80,6 +80,26 @@ abstract class MCLTheme {
|
|
|
80
80
|
white: 'hover:bg-white',
|
|
81
81
|
transparent: 'hover:bg-transparent',
|
|
82
82
|
}
|
|
83
|
+
// focus: bg color class
|
|
84
|
+
protected static focusBgColor: ColorClass = {
|
|
85
|
+
primary: 'focus:bg-primary',
|
|
86
|
+
secondary: 'focus:bg-secondary',
|
|
87
|
+
success: 'focus:bg-success',
|
|
88
|
+
danger: 'focus:bg-danger',
|
|
89
|
+
info: 'focus:bg-info',
|
|
90
|
+
warning: 'focus:bg-warning',
|
|
91
|
+
'light-1': 'focus:bg-light-1',
|
|
92
|
+
'light-2': 'focus:bg-light-2',
|
|
93
|
+
'light-3': 'focus:bg-light-3',
|
|
94
|
+
'light-4': 'focus:bg-light-4',
|
|
95
|
+
'dark-1': 'focus:bg-dark-1',
|
|
96
|
+
'dark-2': 'focus:bg-dark-2',
|
|
97
|
+
'dark-3': 'focus:bg-dark-3',
|
|
98
|
+
'dark-4': 'focus:bg-dark-4',
|
|
99
|
+
black: 'focus:bg-black',
|
|
100
|
+
white: 'focus:bg-white',
|
|
101
|
+
transparent: 'focus:bg-transparent',
|
|
102
|
+
}
|
|
83
103
|
// ::before bg color class
|
|
84
104
|
protected static beforeBgColor: ColorClass = {
|
|
85
105
|
primary: 'before:bg-primary',
|
package/theme/theme.types.ts
CHANGED
|
@@ -37,12 +37,15 @@ export type HeadingSize = 'sm' | 'md' | 'lg' | 'xl'
|
|
|
37
37
|
export type BodyText = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
|
|
38
38
|
// Font weight
|
|
39
39
|
export type FontWeight = 'light' | 'normal' | 'bold'
|
|
40
|
-
//
|
|
41
|
-
export type
|
|
40
|
+
// alignment
|
|
41
|
+
export type Alignment = 'left' | 'center' | 'right'
|
|
42
|
+
export type VerticalAlignment = 'top' | 'center' | 'bottom'
|
|
42
43
|
// link targets
|
|
43
44
|
export type CtaTarget = '_self' | '_blank'
|
|
44
45
|
// Highlight positions
|
|
45
|
-
export type
|
|
46
|
+
export type Direction = 'left' | 'right' | 'top' | 'bottom'
|
|
47
|
+
export type DirectionY = 'top' | 'bottom'
|
|
48
|
+
export type DirectionX = 'left' | 'right'
|
|
46
49
|
// available ranges
|
|
47
50
|
type _RangeArray<
|
|
48
51
|
T extends number,
|
|
@@ -60,7 +63,6 @@ export type Range<T extends number, R extends number> = IntRange<
|
|
|
60
63
|
|
|
61
64
|
export type ButtonSize = 'small' | 'medium' | 'large'
|
|
62
65
|
export type OpacityRange = 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 | 100
|
|
63
|
-
export type Directions = 'left' | 'right'
|
|
64
66
|
export type ColumnWidth = 25 | 50 | 75 | 100
|
|
65
67
|
export type CrossOrigin = 'use-credentials' | 'anonymous'
|
|
66
68
|
export type InputType = 'text' | 'email' | 'password'
|
package/themeVariables.cjs
CHANGED
|
@@ -70,7 +70,7 @@ const mclTheme = plugin.withOptions(
|
|
|
70
70
|
},
|
|
71
71
|
},
|
|
72
72
|
[`.btn.btn-invert.btn-${e(key)}`]: {
|
|
73
|
-
[`@apply border-2 bg-
|
|
73
|
+
[`@apply border-2 bg-transparent border-${key} text-${key}`]: {},
|
|
74
74
|
'&:hover': {
|
|
75
75
|
[`@apply bg-${key} text-white bg-opacity-100`]: {},
|
|
76
76
|
},
|
|
@@ -83,6 +83,11 @@ const mclTheme = plugin.withOptions(
|
|
|
83
83
|
'@apply ring-0': {},
|
|
84
84
|
},
|
|
85
85
|
},
|
|
86
|
+
[`.btn.btn-${e(key)}.btn-no-ring`]: {
|
|
87
|
+
'&:focus': {
|
|
88
|
+
'@apply ring-0': {},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
86
91
|
[`.btn.btn-progress.btn-${e(key)}`]: {
|
|
87
92
|
[`@apply before:bg-${key} border-${key} text-${key} bg-transparent`]:
|
|
88
93
|
{},
|
|
@@ -364,6 +369,12 @@ const mclTheme = plugin.withOptions(
|
|
|
364
369
|
'@apply ring-0': {},
|
|
365
370
|
},
|
|
366
371
|
},
|
|
372
|
+
'.btn.btn-no-ring': {
|
|
373
|
+
'@apply ring-offset-0': {},
|
|
374
|
+
'&:focus': {
|
|
375
|
+
'@apply ring-0': {},
|
|
376
|
+
},
|
|
377
|
+
},
|
|
367
378
|
'.btn.btn-invert': {
|
|
368
379
|
'@apply border-2 border-primary text-primary bg-white': {},
|
|
369
380
|
'&:hover': {
|