@saasmakers/ui 2.0.26 → 2.0.28

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.
@@ -0,0 +1,17 @@
1
+ <script lang="ts" setup>
2
+ import type { BaseCircle } from '../../types/bases'
3
+
4
+ withDefaults(defineProps<BaseCircle>(), { color: 'indigo' })
5
+ </script>
6
+
7
+ <template>
8
+ <span
9
+ class="inline-block size-2.5 shrink-0 rounded-full"
10
+ :class="{
11
+ 'bg-red-500': color === 'red',
12
+ 'bg-amber-500': color === 'amber',
13
+ 'bg-indigo-500': color === 'indigo',
14
+ 'bg-green-500': color === 'green',
15
+ }"
16
+ />
17
+ </template>
@@ -45,7 +45,7 @@ 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 flex-1 cursor-pointer items-center justify-center text-xs"
48
+ class="flex flex-1 cursor-pointer select-none items-center justify-center text-xs"
49
49
  :class="{
50
50
  'flex-col sm:flex-row': orientation === 'responsive',
51
51
  'flex-col': orientation === 'vertical',
@@ -71,6 +71,17 @@ function onTabClick(event: MouseEvent, tabValue: string) {
71
71
  :to="tab.to"
72
72
  @click="onTabClick($event, tab.value)"
73
73
  >
74
+ <BaseCircle
75
+ v-if="tab.circle"
76
+ class="flex-initial"
77
+ :class="{
78
+ 'mb-1 sm:mb-0 sm:mr-1.5': orientation === 'responsive',
79
+ 'mr-1.5': orientation === 'horizontal',
80
+ 'mb-1': orientation === 'vertical',
81
+ }"
82
+ :color="tab.circle"
83
+ />
84
+
74
85
  <BaseIcon
75
86
  v-if="tab.icon"
76
87
  class="flex-initial"
@@ -84,7 +95,7 @@ function onTabClick(event: MouseEvent, tabValue: string) {
84
95
  />
85
96
 
86
97
  <span
87
- class="whitespace-nowrap flex-initial"
98
+ class="whitespace-nowrap font-medium flex-initial"
88
99
  :class="{
89
100
  'text-2xs sm:text-xs': orientation === 'responsive',
90
101
  'text-2xs': orientation === 'vertical',
@@ -0,0 +1,56 @@
1
+ <script lang="ts" setup>
2
+ import type { LayoutBackdrop } from '../../types/layout'
3
+
4
+ defineOptions({ inheritAttrs: false })
5
+
6
+ const props = withDefaults(defineProps<LayoutBackdrop>(), {
7
+ dragTransition: false,
8
+ opacity: undefined,
9
+ transitionless: false,
10
+ zIndex: 60,
11
+ })
12
+
13
+ const emit = defineEmits<{
14
+ click: [event: MouseEvent]
15
+ }>()
16
+
17
+ const visible = defineModel<boolean>({ default: false })
18
+
19
+ const backdropStyle = computed(() => {
20
+ if (props.opacity === undefined) {
21
+ return { zIndex: props.zIndex }
22
+ }
23
+
24
+ return {
25
+ opacity: props.opacity,
26
+ zIndex: props.zIndex,
27
+ }
28
+ })
29
+ </script>
30
+
31
+ <template>
32
+ <ClientOnly>
33
+ <Teleport to="body">
34
+ <Transition
35
+ enter-active-class="transition-opacity duration-300 ease motion-reduce:transition-none motion-reduce:duration-0"
36
+ enter-from-class="opacity-0 motion-reduce:opacity-100"
37
+ enter-to-class="opacity-100"
38
+ leave-active-class="transition-opacity duration-300 ease motion-reduce:transition-none motion-reduce:duration-0"
39
+ leave-from-class="opacity-100"
40
+ leave-to-class="opacity-0 motion-reduce:opacity-100"
41
+ >
42
+ <div
43
+ v-if="visible"
44
+ aria-hidden="true"
45
+ class="layout-backdrop fixed inset-0 bg-black/50"
46
+ :class="{
47
+ 'transition-none motion-reduce:transition-none': transitionless,
48
+ 'transition-opacity duration-200 ease motion-reduce:transition-none motion-reduce:duration-0': dragTransition,
49
+ }"
50
+ :style="backdropStyle"
51
+ @click="emit('click', $event)"
52
+ />
53
+ </Transition>
54
+ </Teleport>
55
+ </ClientOnly>
56
+ </template>
@@ -177,31 +177,16 @@ watch(visible, (isVisible) => {
177
177
  </script>
178
178
 
179
179
  <template>
180
+ <LayoutBackdrop
181
+ v-model="visible"
182
+ :drag-transition="!drag.isDragging && (drag.closing || drag.offset > 0)"
183
+ :opacity="drag.closing ? 0 : drag.offset > 0 ? Math.max(0, 1 - drag.offset / (panelRef?.offsetHeight ?? 320)) : undefined"
184
+ :transitionless="drag.isDragging"
185
+ @click="onClose"
186
+ />
187
+
180
188
  <ClientOnly>
181
189
  <Teleport to="body">
182
- <Transition
183
- enter-active-class="transition-opacity duration-300 ease motion-reduce:transition-none motion-reduce:duration-0"
184
- enter-from-class="opacity-0 motion-reduce:opacity-100"
185
- enter-to-class="opacity-100"
186
- leave-active-class="transition-opacity duration-300 ease motion-reduce:transition-none motion-reduce:duration-0"
187
- leave-from-class="opacity-100"
188
- leave-to-class="opacity-0 motion-reduce:opacity-100"
189
- >
190
- <div
191
- v-if="visible"
192
- aria-hidden="true"
193
- class="layout-bottom-sheet fixed inset-0 z-[60] bg-black/50"
194
- :class="{
195
- 'transition-none motion-reduce:transition-none': drag.isDragging,
196
- 'transition-opacity duration-200 ease motion-reduce:transition-none motion-reduce:duration-0': !drag.isDragging && (drag.closing || drag.offset > 0),
197
- }"
198
- :style="{
199
- opacity: drag.closing ? 0 : drag.offset > 0 ? Math.max(0, 1 - drag.offset / (panelRef?.offsetHeight ?? 320)) : undefined,
200
- }"
201
- @click="onClose"
202
- />
203
- </Transition>
204
-
205
190
  <Transition
206
191
  enter-active-class="transition-transform duration-300 ease motion-reduce:transition-none motion-reduce:duration-0"
207
192
  enter-from-class="translate-y-full motion-reduce:translate-y-0"
@@ -17,24 +17,13 @@ function onClose() {
17
17
  </script>
18
18
 
19
19
  <template>
20
+ <LayoutBackdrop
21
+ v-model="visible"
22
+ @click="onClose"
23
+ />
24
+
20
25
  <ClientOnly>
21
26
  <Teleport to="body">
22
- <Transition
23
- enter-active-class="transition-opacity duration-300 ease motion-reduce:transition-none motion-reduce:duration-0"
24
- enter-from-class="opacity-0 motion-reduce:opacity-100"
25
- enter-to-class="opacity-100"
26
- leave-active-class="transition-opacity duration-300 ease motion-reduce:transition-none motion-reduce:duration-0"
27
- leave-from-class="opacity-100"
28
- leave-to-class="opacity-0 motion-reduce:opacity-100"
29
- >
30
- <div
31
- v-if="visible"
32
- aria-hidden="true"
33
- class="layout-modal fixed inset-0 z-[60] bg-black/50"
34
- @click="onClose"
35
- />
36
- </Transition>
37
-
38
27
  <Transition
39
28
  enter-active-class="transition duration-200 ease motion-reduce:transition-none motion-reduce:duration-0"
40
29
  enter-from-class="opacity-0 scale-95 motion-reduce:scale-100 motion-reduce:opacity-100"
@@ -128,6 +128,12 @@ export interface BaseChart {
128
128
 
129
129
  export type BaseChartType = 'bar' | 'line' | 'pie'
130
130
 
131
+ export interface BaseCircle {
132
+ color?: BaseCircleColor
133
+ }
134
+
135
+ export type BaseCircleColor = 'amber' | 'green' | 'indigo' | 'red'
136
+
131
137
  export type BaseColor
132
138
  = | 'black'
133
139
  | 'gray'
@@ -224,25 +230,6 @@ export type BaseMetricPerformance = 'down' | 'equal' | 'up'
224
230
 
225
231
  export type BaseMetricSize = 'base' | 'sm'
226
232
 
227
- export interface BaseOverlay {
228
- active?: boolean
229
- clickable?: boolean
230
- fixed?: boolean
231
- hasClose?: boolean
232
- opacity?: BaseOverlayOpacity
233
- position?: BaseOverlayPosition
234
- }
235
-
236
- export type BaseOverlayOpacity
237
- = | 0
238
- | 25
239
- | 50
240
- | 75
241
- | 95
242
- | 100
243
-
244
- export type BaseOverlayPosition = 'absolute' | 'fixed'
245
-
246
233
  export interface BaseParagraph {
247
234
  alignment?: BaseAlignment
248
235
  size?: BaseParagraphSize
@@ -179,6 +179,7 @@ export type FieldTabsOrientation = 'horizontal' | 'responsive' | 'vertical'
179
179
 
180
180
  export interface FieldTabsTab {
181
181
  activeColor?: BaseColor
182
+ circle?: BaseCircleColor
182
183
  icon?: string
183
184
  label: string
184
185
  to?: RouteLocationNamedI18n
@@ -36,6 +36,8 @@ declare global {
36
36
  type BaseCharacterSize = import('./bases').BaseCharacterSize
37
37
  type BaseChart = import('./bases').BaseChart
38
38
  type BaseChartType = import('./bases').BaseChartType
39
+ type BaseCircle = import('./bases').BaseCircle
40
+ type BaseCircleColor = import('./bases').BaseCircleColor
39
41
  type BaseColor = import('./bases').BaseColor
40
42
  type BaseDivider = import('./bases').BaseDivider
41
43
  type BaseDividerBorderStyle = import('./bases').BaseDividerBorderStyle
@@ -53,9 +55,6 @@ declare global {
53
55
  type BaseMetricAlignment = import('./bases').BaseMetricAlignment
54
56
  type BaseMetricPerformance = import('./bases').BaseMetricPerformance
55
57
  type BaseMetricSize = import('./bases').BaseMetricSize
56
- type BaseOverlay = import('./bases').BaseOverlay
57
- type BaseOverlayOpacity = import('./bases').BaseOverlayOpacity
58
- type BaseOverlayPosition = import('./bases').BaseOverlayPosition
59
58
  type BaseParagraph = import('./bases').BaseParagraph
60
59
  type BaseParagraphAlignment = import('./bases').BaseParagraphAlignment
61
60
  type BaseParagraphSize = import('./bases').BaseParagraphSize
@@ -115,6 +114,7 @@ declare global {
115
114
 
116
115
  // Layout
117
116
  type LayoutApps = import('./layout').LayoutApps
117
+ type LayoutBackdrop = import('./layout').LayoutBackdrop
118
118
  type LayoutBottomSheet = import('./layout').LayoutBottomSheet
119
119
  type LayoutModal = import('./layout').LayoutModal
120
120
 
@@ -3,6 +3,13 @@ export interface LayoutApps {
3
3
  playStoreId?: string
4
4
  }
5
5
 
6
+ export interface LayoutBackdrop {
7
+ dragTransition?: boolean
8
+ opacity?: number
9
+ transitionless?: boolean
10
+ zIndex?: number
11
+ }
12
+
6
13
  export interface LayoutBottomSheet {
7
14
  title?: string
8
15
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasmakers/ui",
3
- "version": "2.0.26",
3
+ "version": "2.0.28",
4
4
  "private": false,
5
5
  "description": "Reusable Nuxt UI components for SaaS Makers projects",
6
6
  "license": "MIT",
@@ -1,97 +0,0 @@
1
- <script lang="ts" setup>
2
- import { onKeyStroke } from '@vueuse/core'
3
- import { Motion } from 'motion-v'
4
- import type { BaseOverlay } from '../../types/bases'
5
-
6
- const props = withDefaults(defineProps<BaseOverlay>(), {
7
- active: true,
8
- clickable: true,
9
- fixed: true,
10
- hasClose: true,
11
- opacity: 75,
12
- position: 'absolute',
13
- })
14
-
15
- const emit = defineEmits<{
16
- click: [event: MouseEvent]
17
- close: [event: KeyboardEvent | MouseEvent]
18
- }>()
19
-
20
- defineSlots<{
21
- default?: () => VNode[]
22
- }>()
23
-
24
- const isClickable = computed(() => {
25
- return props.clickable || props.hasClose
26
- })
27
-
28
- function onClick(event: MouseEvent) {
29
- emit('click', event)
30
- }
31
-
32
- function onClose(event: KeyboardEvent | MouseEvent) {
33
- emit('close', event)
34
- }
35
-
36
- function onKeyDown(event: KeyboardEvent) {
37
- if (isClickable.value) {
38
- (event.currentTarget as HTMLElement).click()
39
- }
40
- }
41
-
42
- onKeyStroke('Escape', (event) => {
43
- event.preventDefault()
44
- onClose(event)
45
- })
46
- </script>
47
-
48
- <template>
49
- <div
50
- :class="{
51
- 'fixed inset-0': fixed,
52
- 'cursor-pointer': isClickable,
53
- }"
54
- role="button"
55
- tabindex="0"
56
- @click="onClick"
57
- @keydown.enter="onKeyDown"
58
- @keydown.space.prevent="onKeyDown"
59
- >
60
- <BaseIcon
61
- v-if="hasClose"
62
- class="pointer-events-auto absolute right-4 top-4 z-50 text-gray-200 dark:text-gray-800"
63
- clickable
64
- :icon="getLayerIcon('close')"
65
- @click="onClose"
66
- />
67
-
68
- <div
69
- v-if="$slots.default"
70
- class="relative z-50 h-full w-full"
71
- >
72
- <slot />
73
- </div>
74
-
75
- <Motion
76
- :animate="fadeIn.animate"
77
- as="span"
78
- class="absolute inset-0 z-40"
79
- :initial="fadeIn.initial"
80
- >
81
- <div
82
- class="inset-0 bg-gray-900 dark:bg-gray-100"
83
- :class="{
84
- 'h-0 w-0': !active,
85
- 'opacity-0': opacity === 0,
86
- 'opacity-25': opacity === 25,
87
- 'opacity-50': opacity === 50,
88
- 'opacity-75': opacity === 75,
89
- 'opacity-95': opacity === 95,
90
- 'opacity-100': opacity === 100,
91
- 'absolute': position === 'absolute',
92
- 'fixed': position === 'fixed',
93
- }"
94
- />
95
- </Motion>
96
- </div>
97
- </template>