@saasmakers/ui 2.0.22 → 2.0.23
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/app/components/bases/BaseAction.vue +0 -1
- package/app/components/bases/BaseButton.vue +2 -4
- package/app/components/fields/FieldAvatar.vue +1 -1
- package/app/components/fields/FieldInput.vue +0 -2
- package/app/components/fields/FieldLabel.vue +2 -4
- package/app/components/layout/LayoutBottomSheet.vue +1 -1
- package/app/composables/useDialog.ts +7 -48
- package/app/types/fields.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { NuxtLinkLocale } from '#components'
|
|
3
|
-
import type { BaseButton
|
|
4
|
-
|
|
5
|
-
const fixedSizeButtonShapes = ['square', 'circle'] satisfies BaseButtonShape[]
|
|
3
|
+
import type { BaseButton } from '../../types/bases'
|
|
6
4
|
|
|
7
5
|
const props = withDefaults(defineProps<BaseButton>(), {
|
|
8
6
|
background: true,
|
|
@@ -36,7 +34,7 @@ const confirming = ref(false)
|
|
|
36
34
|
const { t } = useI18n()
|
|
37
35
|
|
|
38
36
|
const hasFixedSize = computed(() => {
|
|
39
|
-
return
|
|
37
|
+
return props.shape === 'square' || props.shape === 'circle'
|
|
40
38
|
})
|
|
41
39
|
|
|
42
40
|
function onClick(event: MouseEvent) {
|
|
@@ -128,7 +128,7 @@ function onOpenFilePicker() {
|
|
|
128
128
|
|
|
129
129
|
<BaseText
|
|
130
130
|
class="min-w-0 flex-1 text-gray-900 dark:text-gray-100"
|
|
131
|
-
:size="({ base: 'sm', lg: 'base', sm: 'xs'
|
|
131
|
+
:size="({ base: 'sm', lg: 'base', sm: 'xs' } as const)[size]"
|
|
132
132
|
:text="loading ? t('actionLoading') : (action || t('action'))"
|
|
133
133
|
/>
|
|
134
134
|
</div>
|
|
@@ -166,7 +166,6 @@ defineExpose({ blur, focus })
|
|
|
166
166
|
<div
|
|
167
167
|
class="flex items-center"
|
|
168
168
|
:class="{
|
|
169
|
-
'h-8': size === 'xs',
|
|
170
169
|
'h-10': size === 'sm',
|
|
171
170
|
'h-12': size === 'base',
|
|
172
171
|
'h-14': size === 'lg',
|
|
@@ -200,7 +199,6 @@ defineExpose({ blur, focus })
|
|
|
200
199
|
'px-10': border === 'bottom' && type !== 'password',
|
|
201
200
|
'border-0 p-0': border === 'none' && type !== 'password',
|
|
202
201
|
'border-0 pr-9': border === 'none' && type === 'password',
|
|
203
|
-
'text-2xs': size === 'xs',
|
|
204
202
|
'text-xs': size === 'sm',
|
|
205
203
|
'text-sm': size === 'base',
|
|
206
204
|
'text-base': size === 'lg',
|
|
@@ -27,10 +27,10 @@ const textSize = computed<BaseSize>(() => {
|
|
|
27
27
|
switch (props.size) {
|
|
28
28
|
case 'lg':
|
|
29
29
|
return 'base'
|
|
30
|
+
case 'base':
|
|
31
|
+
return 'sm'
|
|
30
32
|
case 'sm':
|
|
31
33
|
return 'xs'
|
|
32
|
-
case 'xs':
|
|
33
|
-
return '2xs'
|
|
34
34
|
default:
|
|
35
35
|
return 'sm'
|
|
36
36
|
}
|
|
@@ -71,11 +71,9 @@ function onKeyDown(event: KeyboardEvent) {
|
|
|
71
71
|
'text-gray-500 dark:text-gray-500 line-through': lineThrough,
|
|
72
72
|
'hover:text-black dark:hover:text-white': isClickable && !lineThrough,
|
|
73
73
|
'w-0 truncate': truncate,
|
|
74
|
-
'mb-1.5': size === 'xs' && hasMarginBottom,
|
|
75
74
|
'mb-2': size === 'sm' && hasMarginBottom,
|
|
76
75
|
'mb-2.5': size === 'base' && hasMarginBottom,
|
|
77
76
|
'mb-3': size === 'lg' && hasMarginBottom,
|
|
78
|
-
'ml-1': size === 'xs' && hasMarginLeft,
|
|
79
77
|
'ml-1.5': size === 'sm' && hasMarginLeft,
|
|
80
78
|
'ml-2': size === 'base' && hasMarginLeft,
|
|
81
79
|
'ml-2.5': size === 'lg' && hasMarginLeft,
|
|
@@ -14,7 +14,7 @@ const dragMoveThreshold = 8
|
|
|
14
14
|
const visible = defineModel<boolean>({ default: false })
|
|
15
15
|
const contentRef = ref<HTMLElement>()
|
|
16
16
|
const panelRef = ref<HTMLElement>()
|
|
17
|
-
const { release: onAfterLeave } = useDialog(visible, panelRef
|
|
17
|
+
const { release: onAfterLeave } = useDialog(visible, panelRef)
|
|
18
18
|
|
|
19
19
|
const drag = reactive({
|
|
20
20
|
closing: false,
|
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
interface UseDialogOptions {
|
|
2
|
-
ignoreClass: string
|
|
3
|
-
}
|
|
4
|
-
|
|
5
1
|
export default function useDialog(
|
|
6
2
|
visible: Ref<boolean>,
|
|
7
3
|
panelRef: Ref<HTMLElement | undefined>,
|
|
8
|
-
options: UseDialogOptions,
|
|
9
4
|
) {
|
|
10
5
|
const focusableSelector = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
11
|
-
const fixedElementPadding = new Map<HTMLElement, string>()
|
|
12
6
|
|
|
13
|
-
let
|
|
14
|
-
let savedBodyPaddingRight = ''
|
|
7
|
+
let savedRootOverflow = ''
|
|
15
8
|
|
|
16
9
|
function getFocusableElements(container: HTMLElement) {
|
|
17
10
|
return Array.from(container.querySelectorAll<HTMLElement>(focusableSelector))
|
|
@@ -20,39 +13,12 @@ export default function useDialog(
|
|
|
20
13
|
})
|
|
21
14
|
}
|
|
22
15
|
|
|
16
|
+
// Rely on the global `scrollbar-gutter: stable` (html/body) to keep the gutter
|
|
17
|
+
// reserved while the scroll container is locked, so no manual padding
|
|
18
|
+
// compensation is needed and no horizontal layout shift occurs.
|
|
23
19
|
function lockBodyScroll() {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
savedBodyOverflow = document.body.style.overflow
|
|
27
|
-
savedBodyPaddingRight = document.body.style.paddingRight
|
|
28
|
-
document.body.style.overflow = 'hidden'
|
|
29
|
-
|
|
30
|
-
if (scrollbarWidth > 0) {
|
|
31
|
-
document.body.style.paddingRight = `${scrollbarWidth}px`
|
|
32
|
-
|
|
33
|
-
for (const element of document.querySelectorAll('body *')) {
|
|
34
|
-
if (!(element instanceof HTMLElement)) {
|
|
35
|
-
continue
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Skip the dialog's own teleported elements so they are not padded.
|
|
39
|
-
if (element.classList.contains(options.ignoreClass)) {
|
|
40
|
-
continue
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const { position } = getComputedStyle(element)
|
|
44
|
-
|
|
45
|
-
if (position !== 'fixed' && position !== 'sticky') {
|
|
46
|
-
continue
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
fixedElementPadding.set(element, element.style.paddingRight)
|
|
50
|
-
|
|
51
|
-
const currentPadding = Number.parseFloat(getComputedStyle(element).paddingRight) || 0
|
|
52
|
-
|
|
53
|
-
element.style.paddingRight = `${currentPadding + scrollbarWidth}px`
|
|
54
|
-
}
|
|
55
|
-
}
|
|
20
|
+
savedRootOverflow = document.documentElement.style.overflow
|
|
21
|
+
document.documentElement.style.overflow = 'hidden'
|
|
56
22
|
}
|
|
57
23
|
|
|
58
24
|
function onFocusTrap(event: KeyboardEvent) {
|
|
@@ -90,14 +56,7 @@ export default function useDialog(
|
|
|
90
56
|
}
|
|
91
57
|
|
|
92
58
|
function unlockBodyScroll() {
|
|
93
|
-
document.
|
|
94
|
-
document.body.style.paddingRight = savedBodyPaddingRight
|
|
95
|
-
|
|
96
|
-
for (const [element, paddingRight] of fixedElementPadding) {
|
|
97
|
-
element.style.paddingRight = paddingRight
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
fixedElementPadding.clear()
|
|
59
|
+
document.documentElement.style.overflow = savedRootOverflow
|
|
101
60
|
}
|
|
102
61
|
|
|
103
62
|
// Restores scroll lock and focus trap once the leave transition has finished.
|
package/app/types/fields.d.ts
CHANGED