@saasmakers/ui 2.0.68 → 2.0.69

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.
@@ -385,11 +385,11 @@ function selectOption(event: MouseEvent, value: string) {
385
385
  :key="option.value"
386
386
  class="flex cursor-pointer items-center outline-none"
387
387
  :class="{
388
- 'base-border-b px-3 hover:bg-gray-100 dark:hover:bg-gray-800 last:border-b-0': computedColumns.length < 2,
388
+ 'base-border-b base-bg-hover px-3 last:border-b-0': computedColumns.length < 2,
389
389
  'h-10': size === 'sm' && computedColumns.length < 2,
390
390
  'h-12': size === 'base' && computedColumns.length < 2,
391
391
  'h-14': size === 'lg' && computedColumns.length < 2,
392
- 'px-2 py-1 hover:bg-gray-100 dark:hover:bg-gray-800 last:mb-2': computedColumns.length >= 2,
392
+ 'base-bg-hover px-2 py-1 last:mb-2': computedColumns.length >= 2,
393
393
  'font-medium underline': option.value === selectedOption?.value,
394
394
  'text-gray-900 dark:text-gray-100': option.value === selectedOption?.value,
395
395
  'bg-white dark:bg-gray-900': selectedOption && option.value !== selectedOption.value,
@@ -0,0 +1,178 @@
1
+ export type ChipNavigationDirection = 'down' | 'left' | 'right' | 'up'
2
+
3
+ export default function useChipNavigation(options: {
4
+ containerRef: Ref<HTMLElement | undefined>
5
+ count: MaybeRefOrGetter<number>
6
+ role?: string
7
+ shouldIgnoreHorizontal?: (direction: 'left' | 'right') => boolean
8
+ }) {
9
+ const highlightedIndex = ref(0)
10
+ const chipRole = options.role ?? 'option'
11
+
12
+ const chipCount = computed(() => {
13
+ return toValue(options.count)
14
+ })
15
+
16
+ watch(chipCount, () => {
17
+ const lastIndex = Math.max(0, chipCount.value - 1)
18
+
19
+ if (highlightedIndex.value > lastIndex) {
20
+ highlightedIndex.value = lastIndex
21
+ }
22
+ })
23
+
24
+ function getChipElements() {
25
+ if (!options.containerRef.value) {
26
+ return []
27
+ }
28
+
29
+ return Array.from(options.containerRef.value.querySelectorAll<HTMLElement>(`[role="${chipRole}"]`))
30
+ }
31
+
32
+ function getChipRects() {
33
+ return getChipElements().map((element, index) => ({
34
+ index,
35
+ rect: element.getBoundingClientRect(),
36
+ }))
37
+ }
38
+
39
+ function moveHighlight(direction: ChipNavigationDirection) {
40
+ const chipRects = getChipRects()
41
+
42
+ if (chipRects.length === 0) {
43
+ return
44
+ }
45
+
46
+ const currentIndex = Math.min(highlightedIndex.value, chipRects.length - 1)
47
+ const current = chipRects[currentIndex]!
48
+
49
+ if (direction === 'left' || direction === 'right') {
50
+ const sameRowChips = chipRects.filter((chip) => {
51
+ return Math.abs(chip.rect.top - current.rect.top) <= Math.min(chip.rect.height, current.rect.height) / 2
52
+ })
53
+
54
+ if (direction === 'right') {
55
+ const rightChips = sameRowChips
56
+ .filter(chip => chip.rect.left > current.rect.left + 1)
57
+ .sort((first, second) => first.rect.left - second.rect.left)
58
+
59
+ if (rightChips.length > 0) {
60
+ highlightedIndex.value = rightChips[0]!.index
61
+ }
62
+ else {
63
+ const nextRowChips = chipRects
64
+ .filter(chip => chip.rect.top > current.rect.bottom - 1)
65
+ .sort((first, second) => first.rect.top - second.rect.top || first.rect.left - second.rect.left)
66
+
67
+ if (nextRowChips.length > 0) {
68
+ const nextRowTop = nextRowChips[0]!.rect.top
69
+ const firstInNextRow = nextRowChips.find(chip => Math.abs(chip.rect.top - nextRowTop) <= 4)
70
+
71
+ if (firstInNextRow) {
72
+ highlightedIndex.value = firstInNextRow.index
73
+ }
74
+ }
75
+ }
76
+ }
77
+ else {
78
+ const leftChips = sameRowChips
79
+ .filter(chip => chip.rect.right < current.rect.right - 1)
80
+ .sort((first, second) => second.rect.left - first.rect.left)
81
+
82
+ if (leftChips.length > 0) {
83
+ highlightedIndex.value = leftChips[0]!.index
84
+ }
85
+ else {
86
+ const previousRowChips = chipRects
87
+ .filter(chip => chip.rect.bottom < current.rect.top + 1)
88
+ .sort((first, second) => second.rect.top - first.rect.top || second.rect.left - first.rect.left)
89
+
90
+ if (previousRowChips.length > 0) {
91
+ const previousRowTop = previousRowChips[0]!.rect.top
92
+
93
+ const lastInPreviousRow = previousRowChips
94
+ .filter(chip => Math.abs(chip.rect.top - previousRowTop) <= 4)
95
+ .sort((first, second) => second.rect.left - first.rect.left)[0]
96
+
97
+ if (lastInPreviousRow) {
98
+ highlightedIndex.value = lastInPreviousRow.index
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ else {
105
+ const currentCenterX = current.rect.left + current.rect.width / 2
106
+
107
+ const rowChips = chipRects.filter((chip) => {
108
+ if (direction === 'down') {
109
+ return chip.rect.top > current.rect.top + 1
110
+ }
111
+
112
+ return chip.rect.bottom < current.rect.bottom - 1
113
+ })
114
+
115
+ if (rowChips.length === 0) {
116
+ return
117
+ }
118
+
119
+ const targetRowTop = direction === 'down'
120
+ ? Math.min(...rowChips.map(chip => chip.rect.top))
121
+ : Math.max(...rowChips.map(chip => chip.rect.top))
122
+
123
+ const targetRowChips = rowChips.filter(chip => Math.abs(chip.rect.top - targetRowTop) <= 4)
124
+
125
+ let closestIndex: number | undefined
126
+ let closestDistance: number | undefined
127
+
128
+ for (const chip of targetRowChips) {
129
+ const centerX = chip.rect.left + chip.rect.width / 2
130
+ const distance = Math.abs(centerX - currentCenterX)
131
+
132
+ if (closestDistance === undefined || distance < closestDistance) {
133
+ closestDistance = distance
134
+ closestIndex = chip.index
135
+ }
136
+ }
137
+
138
+ if (closestIndex !== undefined) {
139
+ highlightedIndex.value = closestIndex
140
+ }
141
+ }
142
+
143
+ nextTick(() => {
144
+ getChipElements()[highlightedIndex.value]?.scrollIntoView({
145
+ block: 'nearest',
146
+ inline: 'nearest',
147
+ })
148
+ })
149
+ }
150
+
151
+ function onArrowKey(event: KeyboardEvent, direction: ChipNavigationDirection) {
152
+ if (chipCount.value === 0) {
153
+ return
154
+ }
155
+
156
+ if ((direction === 'left' || direction === 'right') && options.shouldIgnoreHorizontal?.(direction)) {
157
+ return
158
+ }
159
+
160
+ event.preventDefault()
161
+ moveHighlight(direction)
162
+ }
163
+
164
+ function onHighlight(index: number) {
165
+ highlightedIndex.value = index
166
+ }
167
+
168
+ function resetHighlight(index = 0) {
169
+ highlightedIndex.value = index
170
+ }
171
+
172
+ return {
173
+ highlightedIndex,
174
+ onArrowKey,
175
+ onHighlight,
176
+ resetHighlight,
177
+ }
178
+ }
@@ -0,0 +1,97 @@
1
+ import { getRelativeDateMessage } from '../i18n/relativeDate'
2
+ import { getDayDiff, resolveLocaleCode, startOfLocalDay } from '../utils/dateField'
3
+
4
+ export default function useRelativeDate(
5
+ date: MaybeRefOrGetter<Date | null | undefined>,
6
+ options?: {
7
+ today?: MaybeRefOrGetter<Date>
8
+ },
9
+ ) {
10
+ const { locale } = useI18n()
11
+ const resolvedDate = computed(() => coerceDate(toValue(date)))
12
+
13
+ const resolvedToday = computed(() => {
14
+ const today = coerceDate(toValue(options?.today)) ?? new Date()
15
+
16
+ return startOfLocalDay(today)
17
+ })
18
+
19
+ const dayDiff = computed(() => {
20
+ const currentDate = resolvedDate.value
21
+
22
+ if (!currentDate) {
23
+ return null
24
+ }
25
+
26
+ return getDayDiff(resolvedToday.value, currentDate)
27
+ })
28
+
29
+ const isOverdue = computed(() => {
30
+ const diff = dayDiff.value
31
+
32
+ return diff !== null && diff < 0
33
+ })
34
+
35
+ const relativeLabel = computed(() => {
36
+ const diff = dayDiff.value
37
+ const currentDate = resolvedDate.value
38
+
39
+ if (diff === null || !currentDate) {
40
+ return ''
41
+ }
42
+
43
+ if (diff === 0) {
44
+ return getRelativeDateMessage(locale.value, 'today')
45
+ }
46
+
47
+ if (diff === 1) {
48
+ return getRelativeDateMessage(locale.value, 'tomorrow')
49
+ }
50
+
51
+ if (diff === -1) {
52
+ return getRelativeDateMessage(locale.value, 'yesterday')
53
+ }
54
+
55
+ if (diff < -1) {
56
+ return getRelativeDateMessage(locale.value, 'overdue', Math.abs(diff))
57
+ }
58
+
59
+ if (diff >= 2 && diff <= 6) {
60
+ return new Intl.DateTimeFormat(resolveLocaleCode(locale.value), { weekday: 'long' }).format(currentDate)
61
+ }
62
+
63
+ return getRelativeDateMessage(locale.value, 'inDays', diff)
64
+ })
65
+
66
+ const absoluteLabel = computed(() => {
67
+ const currentDate = resolvedDate.value
68
+
69
+ if (!currentDate) {
70
+ return ''
71
+ }
72
+
73
+ return currentDate.toLocaleDateString(resolveLocaleCode(locale.value), {
74
+ day: 'numeric',
75
+ month: 'long',
76
+ year: 'numeric',
77
+ })
78
+ })
79
+
80
+ return {
81
+ absoluteLabel,
82
+ isOverdue,
83
+ relativeLabel,
84
+ }
85
+ }
86
+
87
+ function coerceDate(value: unknown): Date | null {
88
+ if (!value) {
89
+ return null
90
+ }
91
+
92
+ if (value instanceof Date) {
93
+ return Number.isNaN(value.getTime()) ? null : value
94
+ }
95
+
96
+ return null
97
+ }
@@ -0,0 +1,138 @@
1
+ import type { Locale } from '@saasmakers/shared'
2
+ import { resolveLocaleCode } from '../utils/dateField'
3
+
4
+ export type RelativeDateKey = 'inDays' | 'overdue' | 'today' | 'tomorrow' | 'yesterday'
5
+
6
+ export interface RelativeDateMessages {
7
+ inDays: string
8
+ overdue: string
9
+ today: string
10
+ tomorrow: string
11
+ yesterday: string
12
+ }
13
+
14
+ export const relativeDateMessages: Record<Locale, RelativeDateMessages> = {
15
+ de: {
16
+ inDays: 'In {count} Tag | In {count} Tagen',
17
+ overdue: 'Überfällig | {count} Tag überfällig | {count} Tage überfällig',
18
+ today: 'Heute',
19
+ tomorrow: 'Morgen',
20
+ yesterday: 'Gestern',
21
+ },
22
+ en: {
23
+ inDays: 'In {count} day | In {count} days',
24
+ overdue: 'Overdue | {count} day overdue | {count} days overdue',
25
+ today: 'Today',
26
+ tomorrow: 'Tomorrow',
27
+ yesterday: 'Yesterday',
28
+ },
29
+ es: {
30
+ inDays: 'En {count} día | En {count} días',
31
+ overdue: 'Atrasado | {count} día de retraso | {count} días de retraso',
32
+ today: 'Hoy',
33
+ tomorrow: 'Mañana',
34
+ yesterday: 'Ayer',
35
+ },
36
+ fr: {
37
+ inDays: 'Dans {count} j | Dans {count} j',
38
+ overdue: 'En retard | En retard de {count} j | En retard de {count} j',
39
+ today: 'Aujourd\'hui',
40
+ tomorrow: 'Demain',
41
+ yesterday: 'Hier',
42
+ },
43
+ id: {
44
+ inDays: 'Dalam {count} hari | Dalam {count} hari',
45
+ overdue: 'Terlambat | Terlambat {count} hari | Terlambat {count} hari',
46
+ today: 'Hari ini',
47
+ tomorrow: 'Besok',
48
+ yesterday: 'Kemarin',
49
+ },
50
+ it: {
51
+ inDays: 'Tra {count} giorno | Tra {count} giorni',
52
+ overdue: 'In ritardo | In ritardo di {count} g | In ritardo di {count} g',
53
+ today: 'Oggi',
54
+ tomorrow: 'Domani',
55
+ yesterday: 'Ieri',
56
+ },
57
+ ja: {
58
+ inDays: 'あと{count}日 | あと{count}日',
59
+ overdue: '期限切れ | {count}日遅れ | {count}日遅れ',
60
+ today: '今日',
61
+ tomorrow: '明日',
62
+ yesterday: '昨日',
63
+ },
64
+ ko: {
65
+ inDays: '{count}일 후 | {count}일 후',
66
+ overdue: '기한 지남 | {count}일 지남 | {count}일 지남',
67
+ today: '오늘',
68
+ tomorrow: '내일',
69
+ yesterday: '어제',
70
+ },
71
+ nl: {
72
+ inDays: 'Over {count} dag | Over {count} dagen',
73
+ overdue: 'Te laat | {count} dag te laat | {count} dagen te laat',
74
+ today: 'Vandaag',
75
+ tomorrow: 'Morgen',
76
+ yesterday: 'Gisteren',
77
+ },
78
+ pl: {
79
+ inDays: 'Za {count} dzień | Za {count} dni',
80
+ overdue: 'Po terminie | {count} dzień po terminie | {count} dni po terminie',
81
+ today: 'Dziś',
82
+ tomorrow: 'Jutro',
83
+ yesterday: 'Wczoraj',
84
+ },
85
+ pt: {
86
+ inDays: 'Daqui a {count} dia | Daqui a {count} dias',
87
+ overdue: 'Em atraso | {count} dia de atraso | {count} dias de atraso',
88
+ today: 'Hoje',
89
+ tomorrow: 'Amanhã',
90
+ yesterday: 'Ontem',
91
+ },
92
+ 'pt-BR': {
93
+ inDays: 'Em {count} dia | Em {count} dias',
94
+ overdue: 'Atrasado | {count} dia de atraso | {count} dias de atraso',
95
+ today: 'Hoje',
96
+ tomorrow: 'Amanhã',
97
+ yesterday: 'Ontem',
98
+ },
99
+ vi: {
100
+ inDays: 'Trong {count} ngày | Trong {count} ngày',
101
+ overdue: 'Quá hạn | Quá hạn {count} ngày | Quá hạn {count} ngày',
102
+ today: 'Hôm nay',
103
+ tomorrow: 'Ngày mai',
104
+ yesterday: 'Hôm qua',
105
+ },
106
+ }
107
+
108
+ function resolveRelativeDateLocale(localeValue: unknown): Locale {
109
+ const localeCode = resolveLocaleCode(localeValue)
110
+
111
+ if (localeCode in relativeDateMessages) {
112
+ return localeCode as Locale
113
+ }
114
+
115
+ const languageCode = localeCode.split('-')[0]
116
+
117
+ if (languageCode && languageCode in relativeDateMessages) {
118
+ return languageCode as Locale
119
+ }
120
+
121
+ return 'en'
122
+ }
123
+
124
+ export function getRelativeDateMessage(localeValue: unknown, key: RelativeDateKey, count?: number) {
125
+ const messages = relativeDateMessages[resolveRelativeDateLocale(localeValue)]
126
+ const rawMessage = messages[key]
127
+
128
+ if (key === 'today' || key === 'tomorrow' || key === 'yesterday' || count === undefined) {
129
+ return rawMessage
130
+ }
131
+
132
+ const forms = rawMessage.split('|').map(form => form.trim())
133
+ const template = forms.length === 1
134
+ ? forms[0]
135
+ : count === 1 ? forms[1] ?? forms[0] : forms[2] ?? forms[1] ?? forms[0]
136
+
137
+ return template?.replace(/\{count\}/g, String(count)) ?? rawMessage
138
+ }
@@ -109,6 +109,32 @@ export type BaseCharacterCharacter
109
109
 
110
110
  export type BaseCharacterSize = 'base' | 'lg' | 'sm' | 'xs'
111
111
 
112
+ export interface BaseChip {
113
+ active?: boolean
114
+ activeHighlight?: BaseChipActiveHighlight
115
+ ariaLabel?: string
116
+ ariaSelected?: boolean
117
+ as?: BaseChipAs
118
+ disabled?: boolean
119
+ hoverable?: boolean
120
+ icon?: string
121
+ iconLeading?: boolean
122
+ iconSize?: BaseSize
123
+ id?: string
124
+ maxWidth?: boolean
125
+ normalCase?: boolean
126
+ removable?: boolean
127
+ role?: string
128
+ text?: BaseTextText
129
+ variant?: BaseChipVariant
130
+ }
131
+
132
+ export type BaseChipActiveHighlight = 'gray' | 'indigo'
133
+
134
+ export type BaseChipAs = 'button' | 'div'
135
+
136
+ export type BaseChipVariant = 'dashed' | 'filled' | 'outline'
137
+
112
138
  export interface BaseChart {
113
139
  data?: ChartistBarChartData | ChartistLineChartData | ChartistPieChartData
114
140
  fullWidth?: boolean
@@ -56,6 +56,30 @@ export interface FieldCombobox<Item = Record<string, unknown>> {
56
56
  validation?: VuelidateValidation
57
57
  }
58
58
 
59
+ export interface FieldDate {
60
+ background?: FieldBackground
61
+ description?: BaseTextText
62
+ disabled?: boolean
63
+ hideError?: boolean
64
+ label?: BaseTextText
65
+ labelIcon?: string
66
+ min?: Date
67
+ modelValue: Date | null
68
+ placeholder?: string
69
+ presets?: FieldDatePreset[]
70
+ required?: boolean
71
+ size?: FieldSize
72
+ validation?: VuelidateValidation
73
+ weekStartsOn?: number
74
+ }
75
+
76
+ export interface FieldDatePreset {
77
+ date: Date
78
+ id: string
79
+ label: string
80
+ sub?: string
81
+ }
82
+
59
83
  export interface FieldDays {
60
84
  disabled?: boolean
61
85
  modelValue: number[]
@@ -33,6 +33,10 @@ declare global {
33
33
  type BaseCharacter = import('./bases').BaseCharacter
34
34
  type BaseCharacterCharacter = import('./bases').BaseCharacterCharacter
35
35
  type BaseCharacterSize = import('./bases').BaseCharacterSize
36
+ type BaseChip = import('./bases').BaseChip
37
+ type BaseChipActiveHighlight = import('./bases').BaseChipActiveHighlight
38
+ type BaseChipAs = import('./bases').BaseChipAs
39
+ type BaseChipVariant = import('./bases').BaseChipVariant
36
40
  type BaseChart = import('./bases').BaseChart
37
41
  type BaseChartType = import('./bases').BaseChartType
38
42
  type BaseCircle = import('./bases').BaseCircle
@@ -96,6 +100,8 @@ declare global {
96
100
  type FieldBackground = import('./fields').FieldBackground
97
101
  type FieldCheckbox = import('./fields').FieldCheckbox
98
102
  type FieldCombobox<Item = Record<string, unknown>> = import('./fields').FieldCombobox<Item>
103
+ type FieldDate = import('./fields').FieldDate
104
+ type FieldDatePreset = import('./fields').FieldDatePreset
99
105
  type FieldDays = import('./fields').FieldDays
100
106
  type FieldEmojis = import('./fields').FieldEmojis
101
107
  type FieldInput = import('./fields').FieldInput
@@ -0,0 +1,104 @@
1
+ export interface CalendarCell {
2
+ date: Date
3
+ inMonth: boolean
4
+ }
5
+
6
+ export function buildCalendarGrid(params: {
7
+ viewMonth: Date
8
+ weekStartsOn?: number
9
+ }): CalendarCell[] {
10
+ const weekStartsOn = params.weekStartsOn ?? 1
11
+ const year = params.viewMonth.getFullYear()
12
+ const month = params.viewMonth.getMonth()
13
+ const firstOfMonth = new Date(year, month, 1)
14
+ const firstWeekday = firstOfMonth.getDay()
15
+ const offset = (firstWeekday - weekStartsOn + 7) % 7
16
+ const gridStart = new Date(year, month, 1 - offset)
17
+
18
+ return Array.from({ length: 42 }, (_, index) => {
19
+ const date = new Date(gridStart)
20
+
21
+ date.setDate(gridStart.getDate() + index)
22
+
23
+ return {
24
+ date,
25
+ inMonth: date.getMonth() === month,
26
+ }
27
+ })
28
+ }
29
+
30
+ export function formatMonthLabel(date: Date, locale: string) {
31
+ const formatted = new Intl.DateTimeFormat(locale, {
32
+ month: 'long',
33
+ year: 'numeric',
34
+ }).format(date)
35
+
36
+ return formatted.charAt(0).toUpperCase() + formatted.slice(1)
37
+ }
38
+
39
+ export function formatPresetSub(date: Date, locale: string) {
40
+ return new Intl.DateTimeFormat(locale, {
41
+ day: 'numeric',
42
+ weekday: 'short',
43
+ }).format(date)
44
+ }
45
+
46
+ export function getDayDiff(from: Date, to: Date) {
47
+ const millisecondsPerDay = 86_400_000
48
+
49
+ return Math.round((startOfLocalDay(to).getTime() - startOfLocalDay(from).getTime()) / millisecondsPerDay)
50
+ }
51
+
52
+ export function getNextMonday(from: Date) {
53
+ const weekday = from.getDay()
54
+ const daysUntilNextMonday = ((1 - weekday + 7) % 7) || 7
55
+ const nextMonday = new Date(from)
56
+
57
+ nextMonday.setDate(from.getDate() + daysUntilNextMonday)
58
+
59
+ return startOfLocalDay(nextMonday)
60
+ }
61
+
62
+ export function getNextSaturday(from: Date) {
63
+ const weekday = from.getDay()
64
+ const daysUntilSaturday = weekday === 0 ? 6 : (6 - weekday + 7) % 7 || 7
65
+ const nextSaturday = new Date(from)
66
+
67
+ nextSaturday.setDate(from.getDate() + daysUntilSaturday)
68
+
69
+ return startOfLocalDay(nextSaturday)
70
+ }
71
+
72
+ export function isBeforeDay(date: Date, min?: Date) {
73
+ if (!min) {
74
+ return false
75
+ }
76
+
77
+ return startOfLocalDay(date).getTime() < startOfLocalDay(min).getTime()
78
+ }
79
+
80
+ export function isSameDay(first: Date, second: Date) {
81
+ return startOfLocalDay(first).getTime() === startOfLocalDay(second).getTime()
82
+ }
83
+
84
+ export function resolveLocaleCode(localeValue: unknown): string {
85
+ if (typeof localeValue === 'string') {
86
+ return localeValue
87
+ }
88
+
89
+ if (localeValue && typeof localeValue === 'object') {
90
+ if ('code' in localeValue && typeof localeValue.code === 'string') {
91
+ return localeValue.code
92
+ }
93
+
94
+ if ('language' in localeValue && typeof localeValue.language === 'string') {
95
+ return localeValue.language.split('-')[0] ?? 'en'
96
+ }
97
+ }
98
+
99
+ return 'en'
100
+ }
101
+
102
+ export function startOfLocalDay(date: Date) {
103
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate())
104
+ }
@@ -13,6 +13,7 @@ export const layerIcons = {
13
13
  arrowRight: 'solar:alt-arrow-right-bold',
14
14
  arrowUp: 'solar:alt-arrow-up-bold',
15
15
  back: 'hugeicons:arrow-turn-backward',
16
+ calendar: 'hugeicons:calendar-03',
16
17
  check: 'mdi:check',
17
18
  checkCircle: 'hugeicons:checkmark-circle-02',
18
19
  chevronLeft: 'hugeicons:arrow-left-01',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasmakers/ui",
3
- "version": "2.0.68",
3
+ "version": "2.0.69",
4
4
  "private": false,
5
5
  "description": "Reusable Nuxt UI components for SaaS Makers projects",
6
6
  "license": "MIT",
package/uno.config.ts CHANGED
@@ -37,6 +37,8 @@ export const shortcuts: Record<string, string> = {
37
37
  'base-bg': 'bg-white dark:bg-gray-900',
38
38
  'base-box': 'border shadow-sm base-border rounded-lg',
39
39
  'base-highlight-indigo': 'border border-indigo-600/35 bg-indigo-600/[0.08] shadow-indigo-600/15 dark:border-indigo-400/35 dark:bg-indigo-400/[0.08] dark:shadow-indigo-400/15',
40
+ 'base-bg-hover': 'hover:bg-gray-50 dark:hover:bg-white/5',
41
+ 'base-control-hover': 'base-bg-hover hover:text-gray-900 dark:hover:text-gray-100',
40
42
  'base-surface': 'border base-border base-bg shadow-sm',
41
43
  'field-disabled': 'opacity-50 cursor-not-allowed',
42
44
  'field-uppercase': 'uppercase [&_*]:uppercase [&_input::placeholder]:uppercase',