@saasmakers/ui 1.4.55 → 1.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.
@@ -55,7 +55,7 @@ function onClick(event: MouseEvent) {
55
55
  <template>
56
56
  <component
57
57
  :is="to ? NuxtLinkLocale : 'button'"
58
- class="relative inline-block select-none appearance-none border focus-visible:outline-none"
58
+ class="relative inline-block select-none appearance-none border uppercase focus-visible:outline-none"
59
59
  :class="{
60
60
  'flex items-center justify-center': circular,
61
61
  'cursor-not-allowed opacity-50': disabled,
@@ -42,14 +42,10 @@ const hasAvatarBox = computed<boolean>(() => {
42
42
  })
43
43
 
44
44
  const isClickable = computed(() => {
45
- return !props.disabled && (props.to || props.clickable)
45
+ return props.to || props.clickable
46
46
  })
47
47
 
48
48
  function onClick(event: MouseEvent) {
49
- if (props.disabled) {
50
- return
51
- }
52
-
53
49
  emit('click', event, props.id)
54
50
  }
55
51
  </script>
@@ -61,7 +57,6 @@ function onClick(event: MouseEvent) {
61
57
  :class="{
62
58
  'cursor-default': !isClickable,
63
59
  'cursor-pointer': isClickable,
64
- 'pointer-events-none': disabled,
65
60
  'opacity-50': disabled,
66
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',
67
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',
@@ -69,6 +64,7 @@ function onClick(event: MouseEvent) {
69
64
  'border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 shadow-sm p-4': hasBackground && size === 'lg' && orientation === 'vertical',
70
65
  'hover:border-gray-300 dark:hover:border-gray-700': hasBackground && isClickable,
71
66
  'rounded-xl': hasBackground,
67
+ 'relative': orientation === 'vertical',
72
68
  }"
73
69
  :to="disabled ? undefined : to"
74
70
  @click="onClick"
@@ -88,8 +84,7 @@ function onClick(event: MouseEvent) {
88
84
  class="relative z-10 flex items-center justify-center flex-initial"
89
85
  :class="{
90
86
  'border shadow-inner': !avatar && !image,
91
- 'rounded-lg': !avatar && !image && orientation === 'horizontal',
92
- 'rounded-full': !avatar && !image && orientation === 'vertical',
87
+ 'rounded-lg': !avatar && !image,
93
88
  'border-gray-200 dark:border-gray-800 bg-gray-100 dark:bg-gray-900': !avatar && !image,
94
89
  'mr-2': orientation === 'horizontal' && size === 'base',
95
90
  'mr-3': orientation === 'horizontal' && size === 'lg',
@@ -105,10 +100,8 @@ function onClick(event: MouseEvent) {
105
100
 
106
101
  <BaseAvatar
107
102
  v-if="avatar"
108
- class="flex-initial"
103
+ class="rounded-lg flex-initial"
109
104
  :class="{
110
- 'rounded-lg': orientation === 'horizontal',
111
- 'rounded-full': orientation === 'vertical',
112
105
  'h-10 w-10': size === 'base' && orientation === 'horizontal',
113
106
  'h-12 w-12': size === 'lg' && orientation === 'horizontal',
114
107
  'h-20 w-20': size === 'base' && orientation === 'vertical',
@@ -137,10 +130,8 @@ function onClick(event: MouseEvent) {
137
130
 
138
131
  <img
139
132
  v-else-if="image"
140
- class="object-cover shadow-sm transition-[filter] duration-300 drag-none flex-initial"
133
+ class="select-none rounded-lg object-cover shadow-sm transition-[filter] duration-300 drag-none flex-initial"
141
134
  :class="{
142
- 'rounded-lg': orientation === 'horizontal',
143
- 'rounded-full': orientation === 'vertical',
144
135
  'h-9 w-9': size === 'base' && orientation === 'horizontal',
145
136
  'h-11 w-11': size === 'lg' && orientation === 'horizontal',
146
137
  'h-20 w-20': size === 'base' && orientation === 'vertical',
@@ -199,8 +190,11 @@ function onClick(event: MouseEvent) {
199
190
 
200
191
  <BaseIcon
201
192
  v-if="isSelected"
202
- class="mr-1.5 self-center flex-initial"
193
+ class="flex-initial"
203
194
  :class="{
195
+ 'mr-1.5 self-center': orientation === 'horizontal',
196
+ 'absolute right-2 top-2': orientation === 'vertical' && size === 'base',
197
+ 'absolute right-2.5 top-2.5': orientation === 'vertical' && size === 'lg',
204
198
  'text-xl': size === 'base',
205
199
  'text-2xl': size === 'lg',
206
200
  }"
@@ -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 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
  />
@@ -16,7 +16,7 @@ defineSlots<{
16
16
  <template>
17
17
  <component
18
18
  :is="tag"
19
- class="select-text tracking-tight normal-case"
19
+ class="select-text tracking-tight"
20
20
  :class="{
21
21
  'justify-start': alignment === 'left',
22
22
  'justify-center text-center': alignment === 'center',
@@ -14,7 +14,7 @@ defineSlots<{
14
14
 
15
15
  <template>
16
16
  <p
17
- class="select-text font-medium leading-relaxed tracking-tight normal-case"
17
+ class="select-text font-medium leading-relaxed tracking-tight"
18
18
  :class="{
19
19
  'text-center': alignment === 'center',
20
20
  'text-left': alignment === 'left',
@@ -88,7 +88,7 @@ function onClose(event: MouseEvent) {
88
88
  :size="size"
89
89
  />
90
90
 
91
- <div class="flex flex-1 flex-col font-semibold normal-case">
91
+ <div class="flex flex-1 flex-col font-semibold">
92
92
  <div
93
93
  class="rounded-2xl text-left transition duration-300"
94
94
  :class="{
@@ -48,7 +48,7 @@ onKeyStroke(
48
48
  <template>
49
49
  <kbd
50
50
  class="h-3.5 min-w-3.5 inline-flex items-center justify-center border border-current/50 rounded px-0.5 text-2xs leading-none"
51
- :class="{ 'font-mono uppercase': shortcut.toLowerCase() !== 'enter' }"
51
+ :class="{ 'font-mono': shortcut.toLowerCase() !== 'enter' }"
52
52
  >
53
53
  <Icon
54
54
  v-if="shortcut.toLowerCase() === 'enter'"
@@ -21,7 +21,6 @@ const props = withDefaults(defineProps<BaseTag>(), {
21
21
  text: '',
22
22
  to: undefined,
23
23
  truncate: false,
24
- uppercase: true,
25
24
  })
26
25
 
27
26
  const emit = defineEmits<{
@@ -112,7 +111,6 @@ function onRemove(event: MouseEvent) {
112
111
  'cursor-pointer': clickable,
113
112
  'rounded-md': !rounded,
114
113
  'rounded-full': rounded,
115
- 'uppercase': uppercase,
116
114
  'border-gray-200 dark:border-gray-800 bg-gray-200 dark:bg-gray-800 text-gray-800 dark:text-gray-200': (color === 'black' && light && !active) || removable,
117
115
  'border-gray-900 dark:border-gray-100 bg-gray-900 dark:bg-gray-100 text-white dark:text-black': color === 'black' && (!light || active),
118
116
  'border-gray-700 dark:border-gray-300 bg-gray-100 dark:bg-gray-900 text-gray-700 dark:text-gray-300': color === 'gray' && light && !active,
@@ -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 uppercase 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 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-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"
50
+ class="ml-2 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"
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',
@@ -13,7 +13,6 @@ withDefaults(defineProps<Omit<FieldCheckbox, 'modelValue'>>(), {
13
13
  required: false,
14
14
  size: 'base',
15
15
  truncate: false,
16
- uppercase: false,
17
16
  validation: undefined,
18
17
  })
19
18
 
@@ -24,7 +24,6 @@ const props = withDefaults(defineProps<Omit<FieldInput, 'modelValue'>>(), {
24
24
  slugOnly: false,
25
25
  trim: false,
26
26
  type: 'text',
27
- uppercase: false,
28
27
  validation: undefined,
29
28
  })
30
29
 
@@ -179,14 +178,12 @@ defineExpose({ focus })
179
178
  :id="id"
180
179
  ref="input"
181
180
  :autocomplete="autocomplete ? 'on' : 'off'"
182
- class="h-full w-full appearance-none items-center rounded-lg outline-none placeholder-gray-600 dark:placeholder-gray-400"
181
+ class="h-full w-full appearance-none items-center rounded-lg font-medium tracking-tight normal-case outline-none placeholder-gray-600 dark:placeholder-gray-400"
183
182
  :class="{
184
183
  'field-disabled': disabled,
185
184
  'focus:placeholder-gray-900 hover:placeholder-gray-900 dark:focus:placeholder-gray-100 dark:hover:placeholder-gray-100': !disabled,
186
185
  'text-gray-900 dark:text-gray-100': !lineThrough,
187
186
  'text-gray-500 dark:text-gray-500 line-through': lineThrough,
188
- 'font-medium tracking-tight uppercase': uppercase,
189
- 'font-normal': !uppercase,
190
187
  'text-center': alignment === 'center',
191
188
  'text-left': alignment === 'left',
192
189
  'text-right': alignment === 'right',
@@ -37,6 +37,10 @@ const textSize = computed<BaseSize>(() => {
37
37
  })
38
38
 
39
39
  function onClick(event: MouseEvent) {
40
+ if (!isClickable.value) {
41
+ return
42
+ }
43
+
40
44
  emit('click', event)
41
45
  }
42
46
 
@@ -79,7 +83,7 @@ function onKeyDown(event: KeyboardEvent) {
79
83
  :for="forField || undefined"
80
84
  :tabindex="isClickable && !forField ? 0 : undefined"
81
85
  :type="isClickable && !forField ? 'button' : undefined"
82
- @click="isClickable ? onClick : undefined"
86
+ @click="onClick"
83
87
  @keydown="onKeyDown"
84
88
  >
85
89
  <BaseIcon
@@ -247,14 +247,14 @@ function selectOption(event: MouseEvent, value: string) {
247
247
  :icon="selectedOption.icon"
248
248
  />
249
249
 
250
- <span class="flex-1 truncate font-medium uppercase">
250
+ <span class="flex-1 truncate font-medium">
251
251
  {{ selectedOption.text }}
252
252
  </span>
253
253
  </template>
254
254
 
255
255
  <span
256
256
  v-else-if="placeholder"
257
- class="flex-1 truncate text-gray-600 font-medium uppercase dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-gray-100"
257
+ class="flex-1 truncate text-gray-600 font-medium dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-gray-100"
258
258
  >
259
259
  {{ placeholder }}
260
260
  </span>
@@ -67,7 +67,7 @@ function onFieldClick(event: MouseEvent) {
67
67
  ref="textarea"
68
68
  v-model="modelValue"
69
69
  v-bind="{ 'data-enable-grammarly': 'false' }"
70
- class="w-full flex-1 appearance-none rounded-lg text-gray-900 font-medium tracking-tight uppercase outline-none dark:text-gray-100 placeholder-gray-600 dark:placeholder-gray-400"
70
+ class="w-full flex-1 appearance-none rounded-lg text-gray-900 font-medium tracking-tight normal-case outline-none dark:text-gray-100 placeholder-gray-600 dark:placeholder-gray-400"
71
71
  :class="{
72
72
  'field-disabled': disabled,
73
73
  'focus:placeholder-gray-900 hover:placeholder-gray-900 dark:focus:placeholder-gray-100 dark:hover:placeholder-gray-100': !disabled,
@@ -5,6 +5,8 @@ withDefaults(defineProps<LayoutBottomSheet>(), { title: undefined })
5
5
 
6
6
  defineSlots<{
7
7
  default?: () => VNode[]
8
+ footer?: () => VNode[]
9
+ hero?: () => VNode[]
8
10
  }>()
9
11
 
10
12
  const closeThresholdRatio = 0.25
@@ -214,7 +216,7 @@ watch(visible, (isVisible) => {
214
216
  ref="panelRef"
215
217
  :aria-label="title"
216
218
  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"
219
+ 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 app-text shadow-lg outline-none safe-bottom dark:bg-gray-900 dark:text-gray-100"
218
220
  :class="{
219
221
  'transition-none motion-reduce:transition-none': drag.isDragging,
220
222
  'transition-transform duration-200 ease motion-reduce:transition-none motion-reduce:duration-0': !drag.isDragging && (drag.closing || drag.offset > 0),
@@ -236,9 +238,12 @@ watch(visible, (isVisible) => {
236
238
  <div class="h-1.5 w-10 rounded-full bg-gray-300 dark:bg-gray-700" />
237
239
  </div>
238
240
 
241
+ <slot name="hero" />
242
+
239
243
  <div
240
244
  ref="contentRef"
241
- class="min-h-0 flex-1 overflow-y-auto px-5 pb-4"
245
+ class="min-h-0 flex-1 overflow-y-auto px-5"
246
+ :class="$slots.footer ? 'pb-4' : 'pb-6'"
242
247
  @pointercancel="onPointerUp"
243
248
  @pointerdown="onContentPointerDown"
244
249
  @pointermove="onPointerMove"
@@ -246,6 +251,13 @@ watch(visible, (isVisible) => {
246
251
  >
247
252
  <slot />
248
253
  </div>
254
+
255
+ <div
256
+ v-if="$slots.footer"
257
+ class="flex shrink-0 justify-center px-5 pb-6 pt-2"
258
+ >
259
+ <slot name="footer" />
260
+ </div>
249
261
  </div>
250
262
  </Transition>
251
263
  </Teleport>
@@ -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 app-text shadow-lg outline-none dark:bg-gray-900 dark:text-gray-100"
56
56
  role="dialog"
57
57
  tabindex="-1"
58
58
  >
@@ -134,8 +134,8 @@ export interface BaseDivider {
134
134
  hideNext?: boolean
135
135
  hidePrevious?: boolean
136
136
  loading?: boolean
137
- margin?: number
138
137
  navigable?: boolean
138
+ pill?: boolean
139
139
  size?: BaseDividerSize
140
140
  title?: string
141
141
  }
@@ -346,7 +346,6 @@ export interface BaseTag {
346
346
  text: BaseTextText
347
347
  to?: RouteLocationNamedI18n
348
348
  truncate?: boolean
349
- uppercase?: boolean
350
349
  }
351
350
 
352
351
  export interface BaseTags {
@@ -34,7 +34,6 @@ export interface FieldCheckbox {
34
34
  required?: boolean
35
35
  size?: FieldSize
36
36
  truncate?: boolean
37
- uppercase?: boolean
38
37
  validation?: VuelidateValidation
39
38
  }
40
39
 
@@ -72,7 +71,6 @@ export interface FieldInput {
72
71
  slugOnly?: boolean
73
72
  trim?: boolean
74
73
  type?: FieldInputType
75
- uppercase?: boolean
76
74
  validation?: VuelidateValidation
77
75
  }
78
76
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasmakers/ui",
3
- "version": "1.4.55",
3
+ "version": "1.5.0",
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' }],
@@ -22,7 +24,10 @@ export const rules: [string, Record<string, string>][] = [
22
24
  ['safe-bottom', { 'padding-bottom': 'env(safe-area-inset-bottom)' }],
23
25
  ]
24
26
 
25
- export const shortcuts: Record<string, string> = { 'field-disabled': 'opacity-50 cursor-not-allowed' }
27
+ export const shortcuts: Record<string, string> = {
28
+ 'app-text': 'font-bold leading-relaxed tracking-tight uppercase',
29
+ 'field-disabled': 'opacity-50 cursor-not-allowed',
30
+ }
26
31
 
27
32
  export const theme = {
28
33
  container: {