@saasmakers/ui 1.4.54 → 1.4.56

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.
@@ -7,9 +7,6 @@ const props = withDefaults(defineProps<BaseCard>(), {
7
7
  clickable: true,
8
8
  color: 'gray',
9
9
  description: '',
10
- details: '',
11
- detailsIcon: undefined,
12
- direction: 'horizontal',
13
10
  disabled: false,
14
11
  emoji: undefined,
15
12
  hasBackground: true,
@@ -18,6 +15,7 @@ const props = withDefaults(defineProps<BaseCard>(), {
18
15
  id: undefined,
19
16
  image: '',
20
17
  isSelected: false,
18
+ orientation: 'horizontal',
21
19
  size: 'base',
22
20
  title: undefined,
23
21
  titleIcon: undefined,
@@ -30,7 +28,6 @@ const emit = defineEmits<{
30
28
 
31
29
  defineSlots<{
32
30
  default?: () => VNode[]
33
- detailsLeft?: () => VNode[]
34
31
  innerBoxLeft?: () => VNode[]
35
32
  innerBoxRight?: () => VNode[]
36
33
  outerBoxLeft?: () => VNode[]
@@ -45,14 +42,10 @@ const hasAvatarBox = computed<boolean>(() => {
45
42
  })
46
43
 
47
44
  const isClickable = computed(() => {
48
- return !props.disabled && (props.to || props.clickable)
45
+ return props.to || props.clickable
49
46
  })
50
47
 
51
48
  function onClick(event: MouseEvent) {
52
- if (props.disabled) {
53
- return
54
- }
55
-
56
49
  emit('click', event, props.id)
57
50
  }
58
51
  </script>
@@ -64,10 +57,11 @@ function onClick(event: MouseEvent) {
64
57
  :class="{
65
58
  'cursor-default': !isClickable,
66
59
  'cursor-pointer': isClickable,
67
- 'pointer-events-none': disabled,
68
60
  'opacity-50': disabled,
69
- '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',
70
- '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
+ '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' && orientation === 'horizontal',
62
+ 'border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 shadow-sm p-2.5 pr-4': hasBackground && size === 'lg' && orientation === 'horizontal',
63
+ 'border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 shadow-sm p-3': hasBackground && size === 'base' && orientation === 'vertical',
64
+ 'border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 shadow-sm p-4': hasBackground && size === 'lg' && orientation === 'vertical',
71
65
  'hover:border-gray-300 dark:hover:border-gray-700': hasBackground && isClickable,
72
66
  'rounded-xl': hasBackground,
73
67
  }"
@@ -77,8 +71,8 @@ function onClick(event: MouseEvent) {
77
71
  <div
78
72
  class="flex overflow-hidden"
79
73
  :class="{
80
- 'flex-row items-center text-left': direction === 'horizontal',
81
- 'flex-col text-center': direction === 'vertical',
74
+ 'flex-row items-center text-left': orientation === 'horizontal',
75
+ 'flex-col items-center text-center': orientation === 'vertical',
82
76
  }"
83
77
  >
84
78
  <span class="flex justify-center">
@@ -89,24 +83,31 @@ function onClick(event: MouseEvent) {
89
83
  class="relative z-10 flex items-center justify-center flex-initial"
90
84
  :class="{
91
85
  'border shadow-inner': !avatar && !image,
92
- 'rounded-lg': !avatar && !image,
86
+ 'rounded-lg': !avatar && !image && orientation === 'horizontal',
87
+ 'rounded-full': !avatar && !image && orientation === 'vertical',
93
88
  'border-gray-200 dark:border-gray-800 bg-gray-100 dark:bg-gray-900': !avatar && !image,
94
- 'mr-2': direction === 'horizontal' && size === 'base',
95
- 'mr-3': direction === 'horizontal' && size === 'lg',
96
- 'mb-1': direction === 'vertical' && size === 'base',
97
- 'mb-1.5': direction === 'vertical' && size === 'lg',
98
- 'h-9 w-9': size === 'base',
99
- 'h-11 w-11': size === 'lg',
89
+ 'mr-2': orientation === 'horizontal' && size === 'base',
90
+ 'mr-3': orientation === 'horizontal' && size === 'lg',
91
+ 'mb-2': orientation === 'vertical' && size === 'base',
92
+ 'mb-3': orientation === 'vertical' && size === 'lg',
93
+ 'h-9 w-9': size === 'base' && orientation === 'horizontal',
94
+ 'h-11 w-11': size === 'lg' && orientation === 'horizontal',
95
+ 'h-20 w-20': size === 'base' && orientation === 'vertical',
96
+ 'h-24 w-24': size === 'lg' && orientation === 'vertical',
100
97
  }"
101
98
  >
102
99
  <slot name="innerBoxLeft" />
103
100
 
104
101
  <BaseAvatar
105
102
  v-if="avatar"
106
- class="rounded-lg flex-initial"
103
+ class="flex-initial"
107
104
  :class="{
108
- 'h-10 w-10': size === 'base',
109
- 'h-12 w-12': size === 'lg',
105
+ 'rounded-lg': orientation === 'horizontal',
106
+ 'rounded-full': orientation === 'vertical',
107
+ 'h-10 w-10': size === 'base' && orientation === 'horizontal',
108
+ 'h-12 w-12': size === 'lg' && orientation === 'horizontal',
109
+ 'h-20 w-20': size === 'base' && orientation === 'vertical',
110
+ 'h-24 w-24': size === 'lg' && orientation === 'vertical',
110
111
  }"
111
112
  :src="avatar"
112
113
  />
@@ -131,10 +132,15 @@ function onClick(event: MouseEvent) {
131
132
 
132
133
  <img
133
134
  v-else-if="image"
134
- class="rounded-lg object-cover shadow-sm drag-none flex-initial"
135
+ class="select-none object-cover shadow-sm transition-[filter] duration-300 drag-none flex-initial"
135
136
  :class="{
136
- 'h-9 w-9': size === 'base',
137
- 'h-11 w-11': size === 'lg',
137
+ 'rounded-lg': orientation === 'horizontal',
138
+ 'rounded-full': orientation === 'vertical',
139
+ 'h-9 w-9': size === 'base' && orientation === 'horizontal',
140
+ 'h-11 w-11': size === 'lg' && orientation === 'horizontal',
141
+ 'h-20 w-20': size === 'base' && orientation === 'vertical',
142
+ 'h-24 w-24': size === 'lg' && orientation === 'vertical',
143
+ 'grayscale': disabled,
138
144
  }"
139
145
  :alt="title"
140
146
  loading="lazy"
@@ -148,11 +154,13 @@ function onClick(event: MouseEvent) {
148
154
  </span>
149
155
 
150
156
  <div
151
- class="min-w-0 flex flex-1 flex-col justify-center leading-snug"
157
+ class="min-w-0 flex flex-col justify-center leading-snug"
152
158
  :class="{
153
- 'mr-4': direction === 'horizontal' && size === 'base',
154
- 'mr-5': direction === 'horizontal' && size === 'lg',
155
- 'items-center': direction === 'vertical',
159
+ 'flex-1': orientation === 'horizontal',
160
+ 'w-full': orientation === 'vertical',
161
+ 'mr-4': orientation === 'horizontal' && size === 'base',
162
+ 'mr-5': orientation === 'horizontal' && size === 'lg',
163
+ 'items-center': orientation === 'vertical',
156
164
  }"
157
165
  >
158
166
  <div
@@ -160,6 +168,8 @@ function onClick(event: MouseEvent) {
160
168
  :class="{
161
169
  'gap-0': size === 'base',
162
170
  'gap-0.5': size === 'lg',
171
+ 'gap-1': orientation === 'vertical' && size === 'base',
172
+ 'gap-1.5': orientation === 'vertical' && size === 'lg',
163
173
  }"
164
174
  >
165
175
  <BaseIcon
@@ -169,7 +179,7 @@ function onClick(event: MouseEvent) {
169
179
  :icon="titleIcon"
170
180
  :size="size === 'lg' ? 'base' : 'sm'"
171
181
  :text="title"
172
- truncate
182
+ :truncate="orientation === 'horizontal'"
173
183
  />
174
184
 
175
185
  <BaseText
@@ -180,18 +190,6 @@ function onClick(event: MouseEvent) {
180
190
  :text="description"
181
191
  />
182
192
  </div>
183
-
184
- <div class="flex items-center">
185
- <slot name="detailsLeft" />
186
-
187
- <BaseIcon
188
- v-if="details"
189
- class="mt-0.5 whitespace-nowrap text-gray-700 font-semibold tracking-tighter dark:text-gray-300"
190
- :icon="detailsIcon"
191
- :size="size === 'lg' ? 'xs' : '2xs'"
192
- :text="details"
193
- />
194
- </div>
195
193
  </div>
196
194
 
197
195
  <BaseIcon
@@ -206,7 +204,7 @@ function onClick(event: MouseEvent) {
206
204
  />
207
205
 
208
206
  <BaseIcon
209
- v-else-if="to || hasChevron"
207
+ v-else-if="orientation === 'horizontal' && (to || hasChevron)"
210
208
  class="self-center text-gray-500 flex-initial dark:text-gray-500"
211
209
  :class="{
212
210
  'group-hover:text-gray-900 dark:group-hover:text-gray-100': isClickable,
@@ -6,8 +6,8 @@ const props = withDefaults(defineProps<BaseDivider>(), {
6
6
  hideNext: false,
7
7
  hidePrevious: false,
8
8
  loading: false,
9
- margin: 6,
10
9
  navigable: false,
10
+ pill: false,
11
11
  size: 'base',
12
12
  title: '',
13
13
  })
@@ -28,18 +28,10 @@ function onNavigate(event: MouseEvent, direction: BaseDividerNavigateDirection)
28
28
 
29
29
  <template>
30
30
  <div
31
+ class="my-6"
31
32
  :class="{
32
- 'my-3': margin === 3,
33
- 'my-4': margin === 4,
34
- 'my-5': margin === 5,
35
- 'my-6': margin === 6,
36
- 'my-7': margin === 7,
37
- 'my-8': margin === 8,
38
- 'my-10': margin === 10,
39
- 'my-12': margin === 12,
40
- 'my-16': margin === 16,
41
- 'my-20': margin === 20,
42
- 'mx-auto max-w-xs': size === 'sm',
33
+ 'mx-auto max-w-xs': size === 'sm' && !pill,
34
+ 'mx-auto w-full max-w-sm': pill,
43
35
  }"
44
36
  >
45
37
  <div
@@ -53,7 +45,11 @@ function onNavigate(event: MouseEvent, direction: BaseDividerNavigateDirection)
53
45
 
54
46
  <div
55
47
  v-else
56
- class="grid grid-cols-[1fr_auto_1fr] items-center"
48
+ class="grid items-center"
49
+ :class="{
50
+ 'grid-cols-[minmax(1.5rem,1fr)_auto_minmax(1.5rem,1fr)]': pill,
51
+ 'grid-cols-[1fr_auto_1fr]': !pill,
52
+ }"
57
53
  >
58
54
  <div class="flex items-center">
59
55
  <BaseIcon
@@ -67,17 +63,24 @@ function onNavigate(event: MouseEvent, direction: BaseDividerNavigateDirection)
67
63
  />
68
64
 
69
65
  <div
70
- class="flex-1 border-t border-gray-300 dark:border-gray-700"
66
+ class="flex-1 border-t"
71
67
  :class="{
72
68
  'border-dashed': borderStyle === 'dashed',
73
69
  'border-dotted': borderStyle === 'dotted',
70
+ 'border-gray-900 dark:border-gray-300': pill,
71
+ 'border-gray-300 dark:border-gray-700': !pill,
74
72
  }"
75
73
  style="height: 1px"
76
74
  />
77
75
  </div>
78
76
 
77
+ <span
78
+ v-if="pill && title && !loading"
79
+ class="mx-3 rounded-full bg-gray-900 px-3 py-1 text-xs text-white font-medium tracking-wide uppercase dark:bg-gray-100 dark:text-gray-900"
80
+ >{{ title }}</span>
81
+
79
82
  <BaseText
80
- v-if="loading || title"
83
+ v-else-if="loading || title"
81
84
  class="px-4 text-center"
82
85
  :size="navigable ? 'xs' : 'sm'"
83
86
  :text="loading ? t('loading') : title"
@@ -85,10 +88,12 @@ function onNavigate(event: MouseEvent, direction: BaseDividerNavigateDirection)
85
88
 
86
89
  <div class="flex items-center">
87
90
  <div
88
- class="flex-1 border-t border-gray-300 dark:border-gray-700"
91
+ class="flex-1 border-t"
89
92
  :class="{
90
93
  'border-dashed': borderStyle === 'dashed',
91
94
  'border-dotted': borderStyle === 'dotted',
95
+ 'border-gray-900 dark:border-gray-300': pill,
96
+ 'border-gray-300 dark:border-gray-700': !pill,
92
97
  }"
93
98
  style="height: 1px"
94
99
  />
@@ -28,7 +28,7 @@ const { t } = useI18n()
28
28
  const { getIcon } = useLayerIcons()
29
29
 
30
30
  const isClickable = computed(() => {
31
- return props.clickable || props.to
31
+ return props.clickable || props.to || props.confirmation
32
32
  })
33
33
 
34
34
  const statusIcon = computed<string | undefined>(() => {
@@ -80,10 +80,6 @@ const finalColor = computed(() => {
80
80
  })
81
81
 
82
82
  function onClick(event: MouseEvent) {
83
- if (!isClickable.value) {
84
- return
85
- }
86
-
87
83
  if (props.confirmation) {
88
84
  if (confirming.value) {
89
85
  emit('confirm', event)
@@ -4,7 +4,7 @@ import type { FieldTabs, FieldTabsAction } from '../../types/fields'
4
4
 
5
5
  withDefaults(defineProps<Omit<FieldTabs, 'modelValue'>>(), {
6
6
  disabled: false,
7
- minimizeOnMobile: false,
7
+ orientation: 'horizontal',
8
8
  size: 'base',
9
9
  tabs: undefined,
10
10
  theme: 'rounded',
@@ -45,12 +45,12 @@ function onTabClick(event: MouseEvent, tabValue: string) {
45
45
  :is="tab.to ? NuxtLinkLocale : 'div'"
46
46
  v-for="tab in tabs"
47
47
  :key="tab.value"
48
- class="flex cursor-pointer items-center justify-center text-xs"
48
+ class="flex flex-1 cursor-pointer items-center justify-center text-xs"
49
49
  :class="{
50
+ 'flex-col sm:flex-row': orientation === 'responsive',
51
+ 'flex-col': orientation === 'vertical',
50
52
  'text-gray-900 dark:text-gray-100': isTabActive(tab.value),
51
53
  'text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100': !isTabActive(tab.value) && !disabled,
52
- 'flex-1': !minimizeOnMobile || !isTabActive(tab.value),
53
- 'flex-2 sm:flex-1': minimizeOnMobile && isTabActive(tab.value),
54
54
  'py-1.5 px-2.5': size === 'xs' && theme === 'rounded',
55
55
  'py-2 px-3': size === 'sm' && theme === 'rounded',
56
56
  'py-2.5 px-3.5': size === 'base' && theme === 'rounded' || size === 'xs' && theme === 'border',
@@ -69,14 +69,22 @@ function onTabClick(event: MouseEvent, tabValue: string) {
69
69
  >
70
70
  <BaseIcon
71
71
  v-if="tab.icon"
72
- class="mr-1.5 flex-initial"
72
+ class="flex-initial"
73
+ :class="{
74
+ 'mb-1 sm:mb-0 sm:mr-1.5': orientation === 'responsive',
75
+ 'mr-1.5': orientation === 'horizontal',
76
+ 'mb-1': orientation === 'vertical',
77
+ }"
73
78
  :color="isTabActive(tab.value) ? tab.activeColor : 'black'"
74
79
  :icon="tab.icon"
75
80
  />
76
81
 
77
82
  <span
78
- class="flex-initial"
79
- :class="{ 'hidden sm:inline': minimizeOnMobile && !isTabActive(tab.value) }"
83
+ class="whitespace-nowrap flex-initial"
84
+ :class="{
85
+ 'text-2xs sm:text-xs': orientation === 'responsive',
86
+ 'text-2xs': orientation === 'vertical',
87
+ }"
80
88
  >
81
89
  {{ tab.label }}
82
90
  </span>
@@ -5,6 +5,7 @@ withDefaults(defineProps<LayoutBottomSheet>(), { title: undefined })
5
5
 
6
6
  defineSlots<{
7
7
  default?: () => VNode[]
8
+ hero?: () => VNode[]
8
9
  }>()
9
10
 
10
11
  const closeThresholdRatio = 0.25
@@ -214,7 +215,7 @@ watch(visible, (isVisible) => {
214
215
  ref="panelRef"
215
216
  :aria-label="title"
216
217
  aria-modal="true"
217
- class="layout-bottom-sheet fixed bottom-0 left-0 right-0 z-[60] mx-auto max-h-[85dvh] max-w-screen-md flex flex-col rounded-t-2xl bg-white text-gray-900 shadow-lg safe-bottom dark:bg-gray-900 dark:text-gray-100"
218
+ class="layout-bottom-sheet fixed bottom-0 left-0 right-0 z-[60] mx-auto max-h-[85dvh] max-w-screen-md flex flex-col rounded-t-2xl bg-white text-gray-900 shadow-lg outline-none safe-bottom dark:bg-gray-900 dark:text-gray-100"
218
219
  :class="{
219
220
  'transition-none motion-reduce:transition-none': drag.isDragging,
220
221
  'transition-transform duration-200 ease motion-reduce:transition-none motion-reduce:duration-0': !drag.isDragging && (drag.closing || drag.offset > 0),
@@ -236,9 +237,11 @@ watch(visible, (isVisible) => {
236
237
  <div class="h-1.5 w-10 rounded-full bg-gray-300 dark:bg-gray-700" />
237
238
  </div>
238
239
 
240
+ <slot name="hero" />
241
+
239
242
  <div
240
243
  ref="contentRef"
241
- class="min-h-0 flex-1 overflow-y-auto px-5 pb-4"
244
+ class="min-h-0 flex-1 overflow-y-auto px-5 pb-8"
242
245
  @pointercancel="onPointerUp"
243
246
  @pointerdown="onContentPointerDown"
244
247
  @pointermove="onPointerMove"
@@ -52,7 +52,7 @@ function onClose() {
52
52
  ref="panelRef"
53
53
  :aria-label="title"
54
54
  aria-modal="true"
55
- class="pointer-events-auto max-h-[85dvh] max-w-md w-full overflow-y-auto rounded-2xl bg-white p-5 text-gray-900 shadow-lg dark:bg-gray-900 dark:text-gray-100"
55
+ class="pointer-events-auto max-h-[85dvh] max-w-md w-full overflow-y-auto rounded-2xl bg-white p-5 text-gray-900 shadow-lg outline-none dark:bg-gray-900 dark:text-gray-100"
56
56
  role="dialog"
57
57
  tabindex="-1"
58
58
  >
@@ -77,9 +77,6 @@ export interface BaseCard {
77
77
  clickable?: boolean
78
78
  color?: BaseColor
79
79
  description?: string
80
- details?: string
81
- detailsIcon?: string
82
- direction?: BaseCardDirection
83
80
  disabled?: boolean
84
81
  emoji?: string
85
82
  hasBackground?: boolean
@@ -88,13 +85,14 @@ export interface BaseCard {
88
85
  id?: number | string
89
86
  image?: string
90
87
  isSelected?: boolean
88
+ orientation?: BaseCardOrientation
91
89
  size?: BaseCardSize
92
90
  title?: string
93
91
  titleIcon?: string
94
92
  to?: RouteLocationNamedI18n
95
93
  }
96
94
 
97
- export type BaseCardDirection = 'horizontal' | 'vertical'
95
+ export type BaseCardOrientation = 'horizontal' | 'vertical'
98
96
 
99
97
  export type BaseCardSize = 'base' | 'lg'
100
98
 
@@ -136,8 +134,8 @@ export interface BaseDivider {
136
134
  hideNext?: boolean
137
135
  hidePrevious?: boolean
138
136
  loading?: boolean
139
- margin?: number
140
137
  navigable?: boolean
138
+ pill?: boolean
141
139
  size?: BaseDividerSize
142
140
  title?: string
143
141
  }
@@ -167,8 +167,8 @@ export type FieldStatus
167
167
 
168
168
  export interface FieldTabs {
169
169
  disabled?: boolean
170
- minimizeOnMobile?: boolean
171
170
  modelValue: string
171
+ orientation?: FieldTabsOrientation
172
172
  size?: FieldSize
173
173
  tabs: FieldTabsTab[]
174
174
  theme?: FieldTabsTheme
@@ -176,6 +176,8 @@ export interface FieldTabs {
176
176
 
177
177
  export type FieldTabsAction = 'added' | 'removed'
178
178
 
179
+ export type FieldTabsOrientation = 'horizontal' | 'responsive' | 'vertical'
180
+
179
181
  export interface FieldTabsTab {
180
182
  activeColor?: BaseColor
181
183
  icon?: string
@@ -13,7 +13,7 @@ declare global {
13
13
  type BaseButtonSize = import('./bases').BaseButtonSize
14
14
  type BaseButtonType = import('./bases').BaseButtonType
15
15
  type BaseCard = import('./bases').BaseCard
16
- type BaseCardDirection = import('./bases').BaseCardDirection
16
+ type BaseCardOrientation = import('./bases').BaseCardOrientation
17
17
  type BaseCardSize = import('./bases').BaseCardSize
18
18
  type BaseCharacter = import('./bases').BaseCharacter
19
19
  type BaseCharacterCharacter = import('./bases').BaseCharacterCharacter
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasmakers/ui",
3
- "version": "1.4.54",
3
+ "version": "1.4.56",
4
4
  "private": false,
5
5
  "description": "Reusable Nuxt UI components for SaaS Makers projects",
6
6
  "license": "MIT",
package/uno.config.ts CHANGED
@@ -12,7 +12,9 @@ export const rules: [string, Record<string, string>][] = [
12
12
  '-ms-user-drag': 'none',
13
13
  '-webkit-tap-highlight-color': 'transparent',
14
14
  '-webkit-user-drag': 'none',
15
+ '-webkit-user-select': 'none',
15
16
  'user-drag': 'none',
17
+ 'user-select': 'none',
16
18
  },
17
19
  ],
18
20
  ['flex-initial', { flex: '0 0 auto' }],