@saasmakers/ui 1.4.52 → 1.4.53

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.
@@ -35,7 +35,6 @@ defineSlots<{
35
35
  }"
36
36
  size="xs"
37
37
  :text="title"
38
- uppercase
39
38
  />
40
39
 
41
40
  <div
@@ -10,6 +10,7 @@ const props = withDefaults(defineProps<BaseCard>(), {
10
10
  details: '',
11
11
  detailsIcon: undefined,
12
12
  direction: 'horizontal',
13
+ disabled: false,
13
14
  emoji: undefined,
14
15
  hasBackground: true,
15
16
  hasChevron: false,
@@ -17,6 +18,7 @@ const props = withDefaults(defineProps<BaseCard>(), {
17
18
  id: undefined,
18
19
  image: '',
19
20
  isSelected: false,
21
+ size: 'base',
20
22
  title: undefined,
21
23
  titleIcon: undefined,
22
24
  to: undefined,
@@ -43,25 +45,32 @@ const hasAvatarBox = computed<boolean>(() => {
43
45
  })
44
46
 
45
47
  const isClickable = computed(() => {
46
- return props.to || props.clickable
48
+ return !props.disabled && (props.to || props.clickable)
47
49
  })
48
50
 
49
51
  function onClick(event: MouseEvent) {
52
+ if (props.disabled) {
53
+ return
54
+ }
55
+
50
56
  emit('click', event, props.id)
51
57
  }
52
58
  </script>
53
59
 
54
60
  <template>
55
61
  <component
56
- :is="to ? NuxtLinkLocale : 'div'"
62
+ :is="to && !disabled ? NuxtLinkLocale : 'div'"
57
63
  class="group flex flex-col"
58
64
  :class="{
59
65
  'cursor-pointer': isClickable,
60
- 'border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 shadow-sm p-1.5 pr-2.5': hasBackground,
66
+ 'pointer-events-none': disabled,
67
+ 'opacity-50': disabled,
68
+ 'border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 shadow-sm p-1.5 pr-2.5': hasBackground && size === 'base',
69
+ 'border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 shadow-sm p-2.5 pr-4': hasBackground && size === 'lg',
61
70
  'hover:border-gray-300 dark:hover:border-gray-700': hasBackground && isClickable,
62
71
  'rounded-xl': hasBackground,
63
72
  }"
64
- :to="to"
73
+ :to="disabled ? undefined : to"
65
74
  @click="onClick"
66
75
  >
67
76
  <div
@@ -76,20 +85,28 @@ function onClick(event: MouseEvent) {
76
85
 
77
86
  <span
78
87
  v-if="hasAvatarBox"
79
- class="relative z-10 h-9 w-9 flex items-center justify-center flex-initial"
88
+ class="relative z-10 flex items-center justify-center flex-initial"
80
89
  :class="{
81
90
  'border shadow-inner': !avatar && !image,
82
91
  'rounded-lg': !avatar && !image,
83
92
  'border-gray-200 dark:border-gray-800 bg-gray-100 dark:bg-gray-900': !avatar && !image,
84
- 'mr-2': direction === 'horizontal',
85
- 'mb-1': direction === 'vertical',
93
+ 'mr-2': direction === 'horizontal' && size === 'base',
94
+ 'mr-3': direction === 'horizontal' && size === 'lg',
95
+ 'mb-1': direction === 'vertical' && size === 'base',
96
+ 'mb-1.5': direction === 'vertical' && size === 'lg',
97
+ 'h-9 w-9': size === 'base',
98
+ 'h-11 w-11': size === 'lg',
86
99
  }"
87
100
  >
88
101
  <slot name="innerBoxLeft" />
89
102
 
90
103
  <BaseAvatar
91
104
  v-if="avatar"
92
- class="h-10 w-10 rounded-lg flex-initial"
105
+ class="rounded-lg flex-initial"
106
+ :class="{
107
+ 'h-10 w-10': size === 'base',
108
+ 'h-12 w-12': size === 'lg',
109
+ }"
93
110
  :src="avatar"
94
111
  />
95
112
 
@@ -98,18 +115,26 @@ function onClick(event: MouseEvent) {
98
115
  class="m-0.5"
99
116
  :emoji="emoji"
100
117
  :has-box="false"
118
+ :size="size === 'lg' ? 'lg' : 'base'"
101
119
  />
102
120
 
103
121
  <BaseIcon
104
122
  v-else-if="icon"
105
- class="text-lg"
123
+ :class="{
124
+ 'text-lg': size === 'base',
125
+ 'text-2xl': size === 'lg',
126
+ }"
106
127
  :color="color"
107
128
  :icon="icon"
108
129
  />
109
130
 
110
131
  <img
111
132
  v-else-if="image"
112
- class="h-9 w-9 rounded-lg object-cover shadow-sm drag-none flex-initial"
133
+ class="rounded-lg object-cover shadow-sm drag-none flex-initial"
134
+ :class="{
135
+ 'h-9 w-9': size === 'base',
136
+ 'h-11 w-11': size === 'lg',
137
+ }"
113
138
  :alt="title"
114
139
  loading="lazy"
115
140
  :src="image"
@@ -124,17 +149,24 @@ function onClick(event: MouseEvent) {
124
149
  <div
125
150
  class="min-w-0 flex flex-1 flex-col justify-center leading-snug"
126
151
  :class="{
127
- 'mr-4': direction === 'horizontal',
152
+ 'mr-4': direction === 'horizontal' && size === 'base',
153
+ 'mr-5': direction === 'horizontal' && size === 'lg',
128
154
  'items-center': direction === 'vertical',
129
155
  }"
130
156
  >
131
- <div class="w-full flex flex-col gap-0">
157
+ <div
158
+ class="w-full flex flex-col"
159
+ :class="{
160
+ 'gap-0': size === 'base',
161
+ 'gap-0.5': size === 'lg',
162
+ }"
163
+ >
132
164
  <BaseIcon
133
165
  v-if="title"
134
166
  class="w-full"
135
167
  :class="{ 'self-center': !hasAvatarBox }"
136
168
  :icon="titleIcon"
137
- size="base"
169
+ :size="size === 'lg' ? 'base' : 'sm'"
138
170
  :text="title"
139
171
  truncate
140
172
  />
@@ -142,8 +174,8 @@ function onClick(event: MouseEvent) {
142
174
  <BaseText
143
175
  v-if="description"
144
176
  block
145
- class="text-gray-600 leading-4 dark:text-gray-400"
146
- size="2xs"
177
+ class="text-gray-600 dark:text-gray-400"
178
+ :size="size === 'lg' ? 'xs' : '2xs'"
147
179
  :text="description"
148
180
  />
149
181
  </div>
@@ -155,7 +187,7 @@ function onClick(event: MouseEvent) {
155
187
  v-if="details"
156
188
  class="mt-0.5 whitespace-nowrap text-gray-700 font-semibold tracking-tighter dark:text-gray-300"
157
189
  :icon="detailsIcon"
158
- size="2xs"
190
+ :size="size === 'lg' ? 'xs' : '2xs'"
159
191
  :text="details"
160
192
  />
161
193
  </div>
@@ -163,14 +195,23 @@ function onClick(event: MouseEvent) {
163
195
 
164
196
  <BaseIcon
165
197
  v-if="isSelected"
166
- class="mr-1.5 self-center text-2xl flex-initial"
198
+ class="mr-1.5 self-center flex-initial"
199
+ :class="{
200
+ 'text-2xl': size === 'base',
201
+ 'text-3xl': size === 'lg',
202
+ }"
167
203
  color="green"
168
204
  :icon="getIcon('checkCircle')"
169
205
  />
170
206
 
171
207
  <BaseIcon
172
208
  v-else-if="to || hasChevron"
173
- class="self-center text-xl text-gray-500 flex-initial dark:text-gray-500 group-hover:text-gray-900 dark:group-hover:text-gray-100"
209
+ class="self-center text-gray-500 flex-initial dark:text-gray-500"
210
+ :class="{
211
+ 'group-hover:text-gray-900 dark:group-hover:text-gray-100': isClickable,
212
+ 'text-xl': size === 'base',
213
+ 'text-2xl': size === 'lg',
214
+ }"
174
215
  :icon="getIcon('chevronRight')"
175
216
  />
176
217
 
@@ -63,7 +63,6 @@ function onNavigate(event: MouseEvent, direction: BaseDividerNavigateDirection)
63
63
  :icon="getIcon('chevronLeft')"
64
64
  size="xs"
65
65
  :text="t('previous')"
66
- :uppercase="false"
67
66
  @click="onNavigate($event, 'previous')"
68
67
  />
69
68
 
@@ -102,7 +101,6 @@ function onNavigate(event: MouseEvent, direction: BaseDividerNavigateDirection)
102
101
  :icon="getIcon('chevronRight')"
103
102
  size="xs"
104
103
  :text="t('next')"
105
- :uppercase="false"
106
104
  @click="onNavigate($event, 'next')"
107
105
  />
108
106
  </div>
@@ -16,7 +16,6 @@ const props = withDefaults(defineProps<BaseIcon>(), {
16
16
  to: undefined,
17
17
  truncate: false,
18
18
  underline: false,
19
- uppercase: true,
20
19
  })
21
20
 
22
21
  const emit = defineEmits<{
@@ -154,7 +153,6 @@ function onKeyDown(event: KeyboardEvent) {
154
153
  :text="confirming ? t('confirm') : text"
155
154
  :truncate="truncate"
156
155
  :underline="underline"
157
- :uppercase="uppercase"
158
156
  />
159
157
  </div>
160
158
  </template>
@@ -8,7 +8,6 @@ const props = withDefaults(defineProps<BaseSpinner>(), {
8
8
  reverse: false,
9
9
  size: 'base',
10
10
  text: '',
11
- uppercase: true,
12
11
  })
13
12
 
14
13
  const emit = defineEmits<{
@@ -80,7 +79,6 @@ function onKeyDown(event: KeyboardEvent) {
80
79
  :reverse="reverse"
81
80
  :size="size"
82
81
  :text="text"
83
- :uppercase="uppercase"
84
82
  />
85
83
  </div>
86
84
  </template>
@@ -16,7 +16,6 @@ const props = withDefaults(defineProps<BaseText>(), {
16
16
  to: undefined,
17
17
  truncate: false,
18
18
  underline: false,
19
- uppercase: false,
20
19
  })
21
20
 
22
21
  const emit = defineEmits<{
@@ -81,7 +80,7 @@ function onShowMore() {
81
80
  'bg-white dark:bg-gray-900': background === 'white',
82
81
  'block': block,
83
82
  'font-bold': bold,
84
- 'font-medium': uppercase || !bold,
83
+ 'font-medium': !bold,
85
84
  'ml-0.5': ['3xs'].includes(size) && !reverse && hasMargin,
86
85
  'ml-1.5': ['2xs', 'xs', 'sm'].includes(size) && !reverse && hasMargin,
87
86
  'ml-2.5': ['xl', '2xl'].includes(size) && !reverse && hasMargin,
@@ -92,23 +91,22 @@ function onShowMore() {
92
91
  'mr-2.5': ['xl', '2xl'].includes(size) && reverse && hasMargin,
93
92
  'mr-2': ['base', 'lg'].includes(size) && reverse && hasMargin,
94
93
  'mr-3': ['3xl', '4xl'].includes(size) && reverse && hasMargin,
95
- 'text-2xl': (size === '2xl' && !uppercase) || (size === '3xl' && uppercase),
96
- 'text-2xs': (size === '2xs') || (size === 'xs' && uppercase),
97
- 'text-3xl': (size === '3xl' && !uppercase) || (size === '4xl' && uppercase),
98
- 'text-3xs': (size === '3xs') && !uppercase,
99
- 'text-4xl': size === '4xl' && !uppercase,
100
- 'text-base': (size === 'base' && !uppercase) || (size === 'lg' && uppercase),
94
+ 'text-2xl': size === '2xl',
95
+ 'text-2xs': size === '2xs',
96
+ 'text-3xl': size === '3xl',
97
+ 'text-3xs': size === '3xs',
98
+ 'text-4xl': size === '4xl',
99
+ 'text-base': size === 'base',
101
100
  'text-center': alignment === 'center',
102
101
  'text-left': alignment === 'left',
103
- 'text-lg': (size === 'lg' && !uppercase) || (size === 'xl' && uppercase),
102
+ 'text-lg': size === 'lg',
104
103
  'text-right': alignment === 'right',
105
- 'text-sm': (size === 'sm' && !uppercase) || (size === 'base' && uppercase),
106
- 'text-xl': (size === 'xl' && !uppercase) || (size === '2xl' && uppercase),
107
- 'text-xs': (size === 'xs' && !uppercase) || (size === 'sm' && uppercase),
104
+ 'text-sm': size === 'sm',
105
+ 'text-xl': size === 'xl',
106
+ 'text-xs': size === 'xs',
108
107
  'truncate': truncate,
109
108
  'underline text-indigo-700 dark:text-indigo-300': !!to,
110
109
  'underline': underline,
111
- 'uppercase': uppercase,
112
110
  'whitespace-nowrap': noWrap,
113
111
  }"
114
112
  :to="to"
@@ -31,7 +31,7 @@ function onClose(event: KeyboardEvent | MouseEvent) {
31
31
 
32
32
  <template>
33
33
  <div
34
- class="group flex select-none items-center border border-gray-200 rounded-full bg-white px-3 py-2 text-base text-gray-800 font-normal shadow-sm transition-colors dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100"
34
+ class="group flex select-none items-center border border-gray-200 rounded-full bg-white px-3 py-2 text-base text-gray-800 font-normal uppercase shadow-sm transition-colors dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100"
35
35
  :class="{ 'cursor-pointer': hasClose }"
36
36
  role="button"
37
37
  tabindex="0"
@@ -47,7 +47,7 @@ function onClose(event: KeyboardEvent | MouseEvent) {
47
47
 
48
48
  <button
49
49
  v-if="action"
50
- class="ml-1.5 min-h-6 inline-flex items-center justify-center gap-1.25 rounded-md px-2 py-0.5 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-offset-white dark:focus-visible:ring-offset-gray-800"
50
+ class="ml-2 min-h-6 inline-flex items-center justify-center gap-1.25 rounded-md px-2 py-0.5 uppercase transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-offset-white dark:focus-visible:ring-offset-gray-800"
51
51
  :class="{
52
52
  'bg-red-100 text-red-700 hover:bg-red-200 focus-visible:ring-red-500 dark:bg-red-400/15 dark:text-red-400 dark:hover:bg-red-400/25': status === 'error',
53
53
  'bg-indigo-100 text-indigo-700 hover:bg-indigo-200 focus-visible:ring-indigo-500 dark:bg-indigo-400/15 dark:text-indigo-400 dark:hover:bg-indigo-400/25': status === 'info',
@@ -58,12 +58,10 @@ function onClose(event: KeyboardEvent | MouseEvent) {
58
58
  @click.stop="onAction"
59
59
  >
60
60
  <BaseText
61
- bold
62
61
  class="pointer-events-none leading-none"
63
62
  no-wrap
64
63
  size="sm"
65
64
  :text="action.label"
66
- uppercase
67
65
  />
68
66
 
69
67
  <BaseShortcut
@@ -23,6 +23,19 @@ const isClickable = computed(() => {
23
23
  return !props.loading && !props.disabled
24
24
  })
25
25
 
26
+ const textSize = computed<BaseSize>(() => {
27
+ switch (props.size) {
28
+ case 'lg':
29
+ return 'base'
30
+ case 'sm':
31
+ return 'xs'
32
+ case 'xs':
33
+ return '2xs'
34
+ default:
35
+ return 'sm'
36
+ }
37
+ })
38
+
26
39
  function onClick(event: MouseEvent) {
27
40
  emit('click', event)
28
41
  }
@@ -71,14 +84,14 @@ function onKeyDown(event: KeyboardEvent) {
71
84
  >
72
85
  <BaseIcon
73
86
  :icon="icon"
74
- :size="size"
87
+ :size="textSize"
75
88
  :text="label"
76
89
  />
77
90
 
78
91
  <BaseText
79
92
  v-if="required"
80
93
  class="ml-1 text-red-700 dark:text-red-300"
81
- :size="size"
94
+ :size="textSize"
82
95
  text="*"
83
96
  />
84
97
  </component>
@@ -120,6 +120,19 @@ function ruleIsInvalid(rule: unknown) {
120
120
 
121
121
  return false
122
122
  }
123
+
124
+ const textSize = computed<BaseSize>(() => {
125
+ switch (props.size) {
126
+ case 'lg':
127
+ return 'sm'
128
+ case 'sm':
129
+ return 'xs'
130
+ case 'xs':
131
+ return '2xs'
132
+ default:
133
+ return 'xs'
134
+ }
135
+ })
123
136
  </script>
124
137
 
125
138
  <template>
@@ -134,7 +147,7 @@ function ruleIsInvalid(rule: unknown) {
134
147
  'mt-3.5': size === 'lg',
135
148
  }"
136
149
  :color="status === 'error' ? 'red' : 'gray'"
137
- size="sm"
150
+ :size="textSize"
138
151
  :text="text"
139
152
  />
140
153
  </template>
@@ -8,7 +8,6 @@ export default function useDialog(
8
8
  options: UseDialogOptions,
9
9
  ) {
10
10
  const focusableSelector = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
11
- const focusTrigger = ref<HTMLElement>()
12
11
  const fixedElementPadding = new Map<HTMLElement, string>()
13
12
 
14
13
  let savedBodyOverflow = ''
@@ -101,21 +100,16 @@ export default function useDialog(
101
100
  fixedElementPadding.clear()
102
101
  }
103
102
 
104
- // Restores the page state once the leave transition has finished.
103
+ // Restores scroll lock and focus trap once the leave transition has finished.
105
104
  function release() {
106
105
  if (import.meta.client) {
107
106
  unlockBodyScroll()
108
107
  window.removeEventListener('keydown', onFocusTrap)
109
- focusTrigger.value?.focus()
110
-
111
- focusTrigger.value = undefined
112
108
  }
113
109
  }
114
110
 
115
111
  watch(visible, async (isVisible) => {
116
112
  if (import.meta.client && isVisible) {
117
- focusTrigger.value = document.activeElement instanceof HTMLElement ? document.activeElement : undefined
118
-
119
113
  lockBodyScroll()
120
114
 
121
115
  await nextTick()
@@ -80,6 +80,7 @@ export interface BaseCard {
80
80
  details?: string
81
81
  detailsIcon?: string
82
82
  direction?: BaseCardDirection
83
+ disabled?: boolean
83
84
  emoji?: string
84
85
  hasBackground?: boolean
85
86
  hasChevron?: boolean
@@ -87,6 +88,7 @@ export interface BaseCard {
87
88
  id?: number | string
88
89
  image?: string
89
90
  isSelected?: boolean
91
+ size?: BaseCardSize
90
92
  title?: string
91
93
  titleIcon?: string
92
94
  to?: RouteLocationNamedI18n
@@ -94,6 +96,8 @@ export interface BaseCard {
94
96
 
95
97
  export type BaseCardDirection = 'horizontal' | 'vertical'
96
98
 
99
+ export type BaseCardSize = 'base' | 'lg'
100
+
97
101
  export interface BaseCharacter {
98
102
  character?: BaseCharacterCharacter
99
103
  size?: BaseCharacterSize
@@ -187,7 +191,6 @@ export interface BaseIcon {
187
191
  to?: RouteLocationNamedI18n
188
192
  truncate?: boolean
189
193
  underline?: boolean
190
- uppercase?: boolean
191
194
  }
192
195
 
193
196
  export interface BaseMessage {
@@ -321,7 +324,6 @@ export interface BaseSpinner {
321
324
  reverse?: boolean
322
325
  size?: BaseSize
323
326
  text?: BaseTextText
324
- uppercase?: boolean
325
327
  }
326
328
 
327
329
  export type BaseStatus = | 'error' | 'info' | 'success' | 'warning'
@@ -382,7 +384,6 @@ export interface BaseText {
382
384
  to?: RouteLocationNamedI18n
383
385
  truncate?: boolean
384
386
  underline?: boolean
385
- uppercase?: boolean
386
387
  }
387
388
 
388
389
  export type BaseTextText = string | {
@@ -14,6 +14,7 @@ declare global {
14
14
  type BaseButtonType = import('./bases').BaseButtonType
15
15
  type BaseCard = import('./bases').BaseCard
16
16
  type BaseCardDirection = import('./bases').BaseCardDirection
17
+ type BaseCardSize = import('./bases').BaseCardSize
17
18
  type BaseCharacter = import('./bases').BaseCharacter
18
19
  type BaseCharacterCharacter = import('./bases').BaseCharacterCharacter
19
20
  type BaseCharacterSize = import('./bases').BaseCharacterSize
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasmakers/ui",
3
- "version": "1.4.52",
3
+ "version": "1.4.53",
4
4
  "private": false,
5
5
  "description": "Reusable Nuxt UI components for SaaS Makers projects",
6
6
  "license": "MIT",