@saasmakers/ui 0.1.60 → 0.1.62

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,123 @@
1
+ <script lang="ts" setup>
2
+ import type { FieldTextarea } from '../../types/fields'
3
+
4
+ const props = withDefaults(defineProps<FieldTextarea>(), {
5
+ autofocus: false,
6
+ background: 'gray',
7
+ border: true,
8
+ description: '',
9
+ disabled: false,
10
+ fullWidth: true,
11
+ hideError: false,
12
+ label: '',
13
+ labelIcon: undefined,
14
+ loading: false,
15
+ modelValue: '',
16
+ padding: true,
17
+ placeholder: '',
18
+ required: false,
19
+ resize: false,
20
+ rows: 3,
21
+ size: 'base',
22
+ validation: undefined,
23
+ })
24
+
25
+ const emit = defineEmits<{
26
+ 'blur': [event: FocusEvent, value: string]
27
+ 'click': [event: MouseEvent, value: string]
28
+ 'update:modelValue': [value: string]
29
+ }>()
30
+
31
+ const textarea = ref<HTMLTextAreaElement>()
32
+ const uuid = ref(`${Math.floor((1 + Math.random()) * 0x100000)}`)
33
+
34
+ const { isDesktopBrowser } = useDevice()
35
+
36
+ const value = computed({
37
+ get() {
38
+ return `${props.modelValue}`
39
+ },
40
+ set(value) {
41
+ emit('update:modelValue', value)
42
+ },
43
+ })
44
+
45
+ onMounted(() => {
46
+ if (props.autofocus && textarea.value && isDesktopBrowser.value) {
47
+ textarea.value.focus()
48
+ }
49
+ })
50
+
51
+ function onFieldBlur(event: FocusEvent) {
52
+ const value = textarea.value?.value || ''
53
+
54
+ emit('blur', event, value)
55
+ }
56
+
57
+ function onFieldClick(event: MouseEvent) {
58
+ const value = textarea.value?.value || ''
59
+
60
+ emit('click', event, value)
61
+ }
62
+
63
+ function onFieldInput() {
64
+ const value = textarea.value?.value || ''
65
+
66
+ emit('update:modelValue', value)
67
+ }
68
+ </script>
69
+
70
+ <template>
71
+ <div
72
+ class="relative flex flex-col"
73
+ :class="{ 'w-full': fullWidth }"
74
+ >
75
+ <FieldLabel
76
+ v-if="label"
77
+ :disabled="disabled"
78
+ :for-field="uuid"
79
+ has-margin-bottom
80
+ :icon="labelIcon"
81
+ :label="label"
82
+ :required="required"
83
+ :size="size"
84
+ />
85
+
86
+ <textarea
87
+ :id="uuid"
88
+ ref="textarea"
89
+ v-model="value"
90
+ 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 focus:placeholder-gray-900 hover:placeholder-gray-900 dark:focus:placeholder-gray-100 dark:hover:placeholder-gray-100"
91
+ :class="{
92
+ 'p-2.5': padding,
93
+ 'p-0': !padding,
94
+ 'resize-none': !resize,
95
+
96
+ 'bg-gray-100 dark:bg-gray-900': background === 'gray',
97
+ 'bg-white dark:bg-gray-900': background === 'white',
98
+
99
+ 'border shadow-sm border-gray-200 dark:border-gray-800 hover:border-gray-300 dark:hover:border-gray-700 focus:border-gray-400 dark:focus:border-gray-600': border,
100
+ 'border-0': !border,
101
+
102
+ 'text-xs': size === 'xs',
103
+ 'text-sm': size === 'sm',
104
+ 'text-base': size === 'base',
105
+ 'text-lg': size === 'lg',
106
+ }"
107
+ data-enable-grammarly="false"
108
+ :placeholder="placeholder"
109
+ :rows="rows"
110
+ spellcheck="false"
111
+ @blur="onFieldBlur"
112
+ @click="onFieldClick"
113
+ @input="onFieldInput"
114
+ />
115
+
116
+ <FieldMessage
117
+ :description="description"
118
+ :hide-error="hideError"
119
+ :size="size"
120
+ :validation="validation"
121
+ />
122
+ </div>
123
+ </template>
@@ -0,0 +1,73 @@
1
+ <script lang="ts" setup>
2
+ import type { FieldTime } from '../../types/fields'
3
+
4
+ const props = withDefaults(defineProps<FieldTime>(), {
5
+ background: 'gray',
6
+ description: '',
7
+ disabled: false,
8
+ hideError: true,
9
+ icon: undefined,
10
+ id: undefined,
11
+ label: '',
12
+ labelIcon: undefined,
13
+ modelValue: '',
14
+ name: undefined,
15
+ required: false,
16
+ size: 'base',
17
+ validation: undefined,
18
+ })
19
+
20
+ const emit = defineEmits<{
21
+ 'blur': [event: FocusEvent, value: string, name?: string]
22
+ 'update:modelValue': [value: string, name?: string]
23
+ }>()
24
+
25
+ const root = ref<HTMLDivElement>()
26
+ const uuid = ref(`${Math.floor((1 + Math.random()) * 0x100000)}`)
27
+
28
+ function onFieldBlur(event: FocusEvent) {
29
+ emit('blur', event, props.modelValue, props.name)
30
+ }
31
+
32
+ function onFieldInput() {
33
+ const value = root.value?.querySelector('input')?.value || ''
34
+
35
+ emit('update:modelValue', value, props.name)
36
+ }
37
+ </script>
38
+
39
+ <template>
40
+ <div ref="root">
41
+ <FieldLabel
42
+ v-if="label"
43
+ :disabled="disabled"
44
+ :for-field="uuid"
45
+ has-margin-bottom
46
+ :icon="labelIcon"
47
+ :label="label"
48
+ :required="required"
49
+ :size="size"
50
+ />
51
+
52
+ <div class="item-center h-[42px] flex overflow-hidden border border-gray-200 rounded-lg pl-3 pr-2 dark:border-gray-800 focus-within:border-gray-400 hover:border-gray-300 dark:focus-within:border-gray-600 dark:hover:border-gray-700">
53
+ <input
54
+ :id="`${id}`"
55
+ class="text-sm outline-none"
56
+ :class="{
57
+ 'bg-gray-100 dark:bg-gray-900': background === 'gray',
58
+ 'bg-white dark:bg-gray-900': background === 'white',
59
+ }"
60
+ type="time"
61
+ @blur="onFieldBlur"
62
+ @input="onFieldInput"
63
+ >
64
+ </div>
65
+
66
+ <FieldMessage
67
+ :description="description"
68
+ :hide-error="hideError"
69
+ :size="size"
70
+ :validation="validation"
71
+ />
72
+ </div>
73
+ </template>
@@ -0,0 +1,11 @@
1
+ export default function useDevice() {
2
+ const isDesktopBrowser = computed(() => {
3
+ if (typeof navigator === 'undefined') {
4
+ return true
5
+ }
6
+
7
+ return !navigator.userAgentData?.mobile
8
+ })
9
+
10
+ return { isDesktopBrowser }
11
+ }
@@ -1,5 +1,12 @@
1
1
  import numbroLib from 'numbro'
2
2
 
3
+ export function normalizeText(text: string) {
4
+ return text
5
+ .toLowerCase()
6
+ .normalize('NFD')
7
+ .replace(/[\u0300-\u036F]/g, '')
8
+ }
9
+
3
10
  export function numbro(number: '∞' | number | undefined, format?: string) {
4
11
  if (!number && number !== 0) {
5
12
  return ''
@@ -0,0 +1,179 @@
1
+ export type FieldBackground = 'gray' | 'white'
2
+
3
+ export type FieldSize = 'base' | 'lg' | 'sm' | 'xs'
4
+
5
+ export type FieldStatus = 'default' | 'error' | 'info' | 'success' | 'warning'
6
+
7
+ export interface FieldCheckbox {
8
+ description?: BaseTextText
9
+ disabled?: boolean
10
+ fullWidth?: boolean
11
+ hideError?: boolean
12
+ label?: BaseTextText
13
+ labelIcon?: BaseIconValue
14
+ lineThrough?: boolean
15
+ loading?: boolean
16
+ modelValue?: boolean
17
+ required?: boolean
18
+ size?: FieldSize
19
+ truncate?: boolean
20
+ uppercase?: boolean
21
+ validation?: VuelidateValidation
22
+ }
23
+
24
+ export interface FieldDays {
25
+ modelValue?: number[]
26
+ }
27
+
28
+ export interface FieldEmojis {
29
+ modelValue?: string
30
+ }
31
+
32
+ export interface FieldInput {
33
+ alignment?: FieldInputAlignment
34
+ autocomplete?: boolean
35
+ autofocus?: boolean
36
+ background?: FieldBackground
37
+ border?: FieldInputBorder
38
+ description?: BaseTextText
39
+ disabled?: boolean
40
+ fullWidth?: boolean
41
+ hideError?: boolean
42
+ label?: BaseTextText
43
+ labelIcon?: BaseIconValue
44
+ lineThrough?: boolean
45
+ loading?: boolean
46
+ lowercaseOnly?: boolean
47
+ max?: number
48
+ min?: number
49
+ modelValue?: number | string
50
+ placeholder?: string
51
+ required?: boolean
52
+ size?: FieldSize
53
+ type?: FieldInputType
54
+ uppercase?: boolean
55
+ validation?: VuelidateValidation
56
+ }
57
+
58
+ export type FieldInputAlignment = 'center' | 'left' | 'right'
59
+
60
+ export type FieldInputBorder = 'bottom' | 'full' | 'none'
61
+
62
+ export type FieldInputType = 'currency' | 'date' | 'datetime-local' | 'email' | 'month' | 'number' | 'password' | 'search' | 'tel' | 'text' | 'time' | 'url' | 'week'
63
+
64
+ export interface FieldLabel {
65
+ disabled?: boolean
66
+ forField?: string
67
+ hasMarginBottom?: boolean
68
+ hasMarginLeft?: boolean
69
+ icon?: BaseIconValue
70
+ label: BaseTextText
71
+ lineThrough?: boolean
72
+ loading?: boolean
73
+ required?: boolean
74
+ size?: FieldSize
75
+ truncate?: boolean
76
+ }
77
+
78
+ export interface FieldMessage {
79
+ description?: BaseTextText
80
+ hideError?: boolean
81
+ size?: FieldSize
82
+ validation?: VuelidateValidation
83
+ }
84
+
85
+ export interface FieldSelect {
86
+ border?: FieldSelectBorder
87
+ caret?: boolean
88
+ columns?: FieldSelectColumn[]
89
+ description?: BaseTextText
90
+ direction?: FieldSelectDirection
91
+ disabled?: boolean
92
+ hideError?: boolean
93
+ label?: BaseTextText
94
+ labelIcon?: BaseIconValue
95
+ maxHeight?: FieldSelectMaxHeight
96
+ modelValue?: number | string
97
+ openOnHover?: boolean
98
+ options?: FieldSelectOption[]
99
+ padding?: boolean
100
+ placeholder?: string
101
+ required?: boolean
102
+ size?: FieldSize
103
+ validation?: VuelidateValidation
104
+ }
105
+
106
+ export interface FieldSelectColumn {
107
+ options: FieldSelectOption[]
108
+ title?: string
109
+ }
110
+
111
+ export interface FieldSelectOption {
112
+ icon?: BaseIconValue
113
+ text: string
114
+ value: number | string
115
+ }
116
+
117
+ export type FieldSelectBorder = 'bottom' | 'full' | 'none'
118
+
119
+ export type FieldSelectDirection = 'bottom' | 'top'
120
+
121
+ export type FieldSelectMaxHeight = 'lg' | 'md' | 'sm' | 'xs'
122
+
123
+ export interface FieldTabs {
124
+ minimizeOnMobile?: boolean
125
+ modelValue?: Array<number | string> | number | string
126
+ multiple?: boolean
127
+ size?: FieldSize
128
+ tabs: FieldTabsTab[]
129
+ theme?: FieldTabsTheme
130
+ }
131
+
132
+ export interface FieldTabsTab {
133
+ activeColor?: BaseColor
134
+ icon?: BaseIconValue
135
+ label: string
136
+ to?: RouteLocationNamedI18n
137
+ value: number | string
138
+ }
139
+
140
+ export type FieldTabsAction = 'added' | 'removed'
141
+
142
+ export type FieldTabsTheme = 'border' | 'rounded'
143
+
144
+ export interface FieldTextarea {
145
+ autofocus?: boolean
146
+ background?: FieldBackground
147
+ border?: boolean
148
+ description?: BaseTextText
149
+ disabled?: boolean
150
+ fullWidth?: boolean
151
+ hideError?: boolean
152
+ label?: BaseTextText
153
+ labelIcon?: BaseIconValue
154
+ loading?: boolean
155
+ modelValue?: string
156
+ padding?: boolean
157
+ placeholder?: string
158
+ required?: boolean
159
+ resize?: boolean
160
+ rows?: number
161
+ size?: FieldSize
162
+ validation?: VuelidateValidation
163
+ }
164
+
165
+ export interface FieldTime {
166
+ background?: FieldBackground
167
+ description?: BaseTextText
168
+ disabled?: boolean
169
+ hideError?: boolean
170
+ icon?: BaseIconValue
171
+ id: number | string
172
+ label?: BaseTextText
173
+ labelIcon?: BaseIconValue
174
+ modelValue?: string
175
+ name?: string
176
+ required?: boolean
177
+ size?: FieldSize
178
+ validation?: VuelidateValidation
179
+ }
@@ -1,4 +1,5 @@
1
1
  import type * as Bases from './bases'
2
+ import type * as Fields from './fields'
2
3
 
3
4
  declare global {
4
5
  // Libraries
@@ -7,23 +8,26 @@ declare global {
7
8
  type ChartistOptions = import('chartist').Options
8
9
  type ChartistPieChartData = import('chartist').PieChartData
9
10
  type RouteLocationNamedI18n = import('vue-router').RouteLocationNamedI18n
11
+ type VuelidateValidation = import('@vuelidate/core').BaseValidation
10
12
 
11
13
  // Bases
14
+ type BaseBackground = Bases.BaseBackground
15
+ type BaseColor = Bases.BaseColor
16
+ type BaseSize = Bases.BaseSize
17
+ type BaseStatus = Bases.BaseStatus
12
18
  type BaseAlert = Bases.BaseAlert
13
19
  type BaseAvatar = Bases.BaseAvatar
14
- type BaseBackground = Bases.BaseBackground
15
- type BaseBordered = Bases.BaseBordered
16
20
  type BaseBorderedColor = Bases.BaseBorderedColor
17
21
  type BaseButton = Bases.BaseButton
18
22
  type BaseButtonRounded = Bases.BaseButtonRounded
19
23
  type BaseButtonSize = Bases.BaseButtonSize
20
24
  type BaseButtonType = Bases.BaseButtonType
25
+ type BaseBordered = Bases.BaseBordered
21
26
  type BaseCharacter = Bases.BaseCharacter
22
27
  type BaseCharacterCharacter = Bases.BaseCharacterCharacter
23
28
  type BaseCharacterSize = Bases.BaseCharacterSize
24
29
  type BaseChart = Bases.BaseChart
25
30
  type BaseChartType = Bases.BaseChartType
26
- type BaseColor = Bases.BaseColor
27
31
  type BaseDivider = Bases.BaseDivider
28
32
  type BaseDividerBorderStyle = Bases.BaseDividerBorderStyle
29
33
  type BaseDividerSize = Bases.BaseDividerSize
@@ -44,17 +48,54 @@ declare global {
44
48
  type BaseParagraph = Bases.BaseParagraph
45
49
  type BaseParagraphAlignment = Bases.BaseParagraphAlignment
46
50
  type BaseParagraphSize = Bases.BaseParagraphSize
51
+ type BasePower = Bases.BasePower
52
+ type BasePowerPower = Bases.BasePowerPower
53
+ type BasePowerSize = Bases.BasePowerSize
47
54
  type BaseQuote = Bases.BaseQuote
48
55
  type BaseQuoteBackground = Bases.BaseQuoteBackground
49
56
  type BaseQuoteSize = Bases.BaseQuoteSize
50
- type BaseSize = Bases.BaseSize
51
57
  type BaseSpinner = Bases.BaseSpinner
52
- type BaseStatus = Bases.BaseStatus
58
+ type BaseTag = Bases.BaseTag
59
+ type BaseTagSize = Bases.BaseTagSize
60
+ type BaseTags = Bases.BaseTags
53
61
  type BaseText = Bases.BaseText
54
62
  type BaseTextText = Bases.BaseTextText
55
63
  type BaseToast = Bases.BaseToast
56
- type BaseToasts = Bases.BaseToasts
57
- type BaseToastsAlignment = Bases.BaseToastsAlignment
64
+
65
+ // Fields
66
+ type FieldBackground = Fields.FieldBackground
67
+ type FieldSize = Fields.FieldSize
68
+ type FieldStatus = Fields.FieldStatus
69
+ type FieldCheckbox = Fields.FieldCheckbox
70
+ type FieldDays = Fields.FieldDays
71
+ type FieldEmojis = Fields.FieldEmojis
72
+ type FieldInput = Fields.FieldInput
73
+ type FieldInputAlignment = Fields.FieldInputAlignment
74
+ type FieldInputBorder = Fields.FieldInputBorder
75
+ type FieldInputType = Fields.FieldInputType
76
+ type FieldLabel = Fields.FieldLabel
77
+ type FieldMessage = Fields.FieldMessage
78
+ type FieldSelect = Fields.FieldSelect
79
+ type FieldSelectColumn = Fields.FieldSelectColumn
80
+ type FieldSelectOption = Fields.FieldSelectOption
81
+ type FieldSelectBorder = Fields.FieldSelectBorder
82
+ type FieldSelectDirection = Fields.FieldSelectDirection
83
+ type FieldSelectMaxHeight = Fields.FieldSelectMaxHeight
84
+ type FieldTabs = Fields.FieldTabs
85
+ type FieldTabsTab = Fields.FieldTabsTab
86
+ type FieldTabsAction = Fields.FieldTabsAction
87
+ type FieldTabsTheme = Fields.FieldTabsTheme
88
+ type FieldTextarea = Fields.FieldTextarea
89
+ type FieldTime = Fields.FieldTime
90
+
91
+ // Navigator
92
+ interface Navigator {
93
+ userAgentData?: {
94
+ brands?: Array<{ brand: string, version: string }>
95
+ mobile?: boolean
96
+ platform?: string
97
+ }
98
+ }
58
99
  }
59
100
 
60
101
  export * from './bases'
package/nuxt.config.ts CHANGED
@@ -21,6 +21,10 @@ export default defineNuxtConfig({
21
21
  path: 'components/bases',
22
22
  pathPrefix: false,
23
23
  },
24
+ {
25
+ path: 'components/fields',
26
+ pathPrefix: false,
27
+ },
24
28
  {
25
29
  path: 'components/layout',
26
30
  pathPrefix: false,
@@ -35,14 +39,15 @@ export default defineNuxtConfig({
35
39
  ],
36
40
 
37
41
  modules: [
42
+ '@nuxt/icon',
38
43
  '@nuxtjs/color-mode',
39
44
  '@nuxtjs/i18n',
40
- '@nuxt/icon',
41
- '@pinia/nuxt',
42
- '@unocss/nuxt',
43
45
  '@nuxtjs/plausible',
44
46
  '@nuxtjs/robots',
45
47
  '@nuxtjs/sitemap',
48
+ '@pinia/nuxt',
49
+ '@unocss/nuxt',
50
+ '@vueuse/nuxt',
46
51
  'floating-vue/nuxt',
47
52
  'motion-v/nuxt',
48
53
  ],
@@ -75,7 +80,6 @@ export default defineNuxtConfig({
75
80
  plausible: {
76
81
  apiHost: 'https://plausible.saasmakers.dev',
77
82
  autoOutboundTracking: true,
78
- domain: 'resilience.club',
79
83
  ignoreSubDomains: true,
80
84
  proxy: true,
81
85
  },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@saasmakers/ui",
3
3
  "type": "module",
4
- "version": "0.1.60",
4
+ "version": "0.1.62",
5
5
  "private": false,
6
6
  "description": "Reusable Nuxt UI components for SaaS Makers projects",
7
7
  "license": "MIT",
@@ -39,8 +39,14 @@
39
39
  "@nuxtjs/robots": "5.5.6",
40
40
  "@nuxtjs/sitemap": "7.4.7",
41
41
  "@pinia/nuxt": "0.11.2",
42
+ "@saasmakers/shared": "workspace:*",
42
43
  "@unocss/nuxt": "66.5.4",
43
44
  "@unocss/reset": "66.5.10",
45
+ "@vuelidate/core": "2.0.3",
46
+ "@vuelidate/validators": "2.0.4",
47
+ "@vueuse/components": "14.0.0",
48
+ "@vueuse/core": "14.1.0",
49
+ "@vueuse/nuxt": "14.0.0",
44
50
  "chartist": "1.5.0",
45
51
  "floating-vue": "5.2.2",
46
52
  "lottie-web": "5.13.0",