@saasmakers/ui 2.0.69 → 2.0.70

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.
@@ -68,6 +68,7 @@ const { highlightedIndex, onArrowKey, onHighlight, resetHighlight } = useChipNav
68
68
  shouldIgnoreHorizontal: (direction) => {
69
69
  const input = inputRef.value
70
70
  const cursorAtStart = input ? input.selectionStart === 0 && input.selectionEnd === 0 : true
71
+
71
72
  const cursorAtEnd = input
72
73
  ? input.selectionStart === input.value.length && input.selectionEnd === input.value.length
73
74
  : true
@@ -93,10 +94,15 @@ function onBackspace() {
93
94
  }
94
95
  }
95
96
 
97
+ function onChipMouseDown(event: MouseEvent) {
98
+ event.preventDefault()
99
+ }
100
+
96
101
  function onClose() {
97
102
  if (opened.value) {
98
103
  opened.value = false
99
104
  searchRaw.value = ''
105
+
100
106
  resetHighlight()
101
107
  }
102
108
  }
@@ -109,6 +115,7 @@ async function onCreate() {
109
115
  emit('create', label)
110
116
 
111
117
  searchRaw.value = ''
118
+
112
119
  resetHighlight()
113
120
 
114
121
  await nextTick()
@@ -132,13 +139,10 @@ function onEnter() {
132
139
  }
133
140
  }
134
141
 
135
- function onChipMouseDown(event: MouseEvent) {
136
- event.preventDefault()
137
- }
138
-
139
142
  async function onOpen() {
140
143
  if (!props.disabled && !opened.value) {
141
144
  opened.value = true
145
+
142
146
  resetHighlight()
143
147
 
144
148
  await nextTick()
@@ -157,6 +161,7 @@ function onRemove(item: Item) {
157
161
  async function onSelect(item: Item) {
158
162
  modelValue.value = [...modelValue.value, item]
159
163
  searchRaw.value = ''
164
+
160
165
  resetHighlight()
161
166
 
162
167
  await nextTick()
@@ -208,9 +213,9 @@ function readField(item: Item, field: string) {
208
213
  <BaseChip
209
214
  v-for="item in modelValue"
210
215
  :key="getItemKey(item)"
211
- :ariaLabel="t('remove', { label: getItemText(item) })"
212
- normal-case
213
- removable
216
+ :aria-label="t('remove', { label: getItemText(item) })"
217
+
218
+ removable normal-case
214
219
  variant="filled"
215
220
  @mousedown="onChipMouseDown"
216
221
  @click="onRemove(item)"
@@ -220,7 +225,7 @@ function readField(item: Item, field: string) {
220
225
 
221
226
  <BaseChip
222
227
  v-if="!opened"
223
- :ariaLabel="t('add')"
228
+ :aria-label="t('add')"
224
229
  :disabled="disabled"
225
230
  :icon="getLayerIcon('plus')"
226
231
  icon-leading
@@ -271,7 +276,7 @@ function readField(item: Item, field: string) {
271
276
  :id="`${id}-option-${index}`"
272
277
  :key="getItemKey(item)"
273
278
  :active="index === highlightedIndex"
274
- :ariaSelected="index === highlightedIndex"
279
+ :aria-selected="index === highlightedIndex"
275
280
  as="div"
276
281
  max-width
277
282
  normal-case
@@ -288,7 +293,7 @@ function readField(item: Item, field: string) {
288
293
  v-if="canCreate"
289
294
  :id="`${id}-create`"
290
295
  :active="highlightedIndex === createOptionIndex"
291
- :ariaSelected="highlightedIndex === createOptionIndex"
296
+ :aria-selected="highlightedIndex === createOptionIndex"
292
297
  as="div"
293
298
  max-width
294
299
  :icon="getLayerIcon('plus')"
@@ -175,6 +175,7 @@ watch(opened, (isOpened) => {
175
175
 
176
176
  nextTick(() => {
177
177
  chipListRef.value?.focus()
178
+
178
179
  panelRef.value?.scrollIntoView({
179
180
  behavior: prefersReducedMotion.value === 'reduce' ? 'auto' : 'smooth',
180
181
  block: 'nearest',
@@ -199,6 +200,14 @@ function closePanel() {
199
200
  calendarOpen.value = false
200
201
  }
201
202
 
203
+ function isDayDisabled(date: Date) {
204
+ return isBeforeDay(date, props.min)
205
+ }
206
+
207
+ function isPresetSelected(preset: FieldDatePreset) {
208
+ return modelValue.value ? isSameDay(preset.date, modelValue.value) : false
209
+ }
210
+
202
211
  function onChipEnter() {
203
212
  const index = highlightedIndex.value
204
213
 
@@ -242,28 +251,6 @@ function onChipMouseDown(event: MouseEvent) {
242
251
  event.preventDefault()
243
252
  }
244
253
 
245
- function resolveInitialChipHighlight() {
246
- const selectedIndex = computedPresets.value.findIndex(preset => isPresetSelected(preset))
247
-
248
- if (selectedIndex >= 0) {
249
- return selectedIndex
250
- }
251
-
252
- if (calendarOpen.value) {
253
- return chooseChipIndex.value
254
- }
255
-
256
- return 0
257
- }
258
-
259
- function isDayDisabled(date: Date) {
260
- return isBeforeDay(date, props.min)
261
- }
262
-
263
- function isPresetSelected(preset: FieldDatePreset) {
264
- return modelValue.value ? isSameDay(preset.date, modelValue.value) : false
265
- }
266
-
267
254
  function onClearClick(event: MouseEvent) {
268
255
  event.stopPropagation()
269
256
 
@@ -272,6 +259,16 @@ function onClearClick(event: MouseEvent) {
272
259
  closePanel()
273
260
  }
274
261
 
262
+ function onCloseCalendar() {
263
+ calendarOpen.value = false
264
+
265
+ resetHighlight(chooseChipIndex.value)
266
+
267
+ nextTick(() => {
268
+ chipListRef.value?.focus()
269
+ })
270
+ }
271
+
275
272
  function onContainerClick() {
276
273
  if (!props.disabled) {
277
274
  opened.value = !opened.value
@@ -292,15 +289,6 @@ function onDayClick(date: Date) {
292
289
  }
293
290
  }
294
291
 
295
- function onCloseCalendar() {
296
- calendarOpen.value = false
297
- resetHighlight(chooseChipIndex.value)
298
-
299
- nextTick(() => {
300
- chipListRef.value?.focus()
301
- })
302
- }
303
-
304
292
  function onDayKeyDown(event: KeyboardEvent, date: Date, index: number) {
305
293
  if (event.key === 'Escape') {
306
294
  event.preventDefault()
@@ -339,14 +327,6 @@ function onDayKeyDown(event: KeyboardEvent, date: Date, index: number) {
339
327
  }
340
328
  }
341
329
 
342
- function syncFocusedDayIndex() {
343
- const selectedIndex = calendarCells.value.findIndex(cell => modelValue.value && isSameDay(cell.date, modelValue.value))
344
-
345
- focusedDayIndex.value = selectedIndex >= 0
346
- ? selectedIndex
347
- : calendarCells.value.findIndex(cell => cell.inMonth)
348
- }
349
-
350
330
  function onNextMonth() {
351
331
  viewMonth.value = new Date(viewMonth.value.getFullYear(), viewMonth.value.getMonth() + 1, 1)
352
332
 
@@ -358,6 +338,7 @@ function onNextMonth() {
358
338
 
359
339
  function onOpenCalendar() {
360
340
  calendarOpen.value = true
341
+
361
342
  resetHighlight(chooseChipIndex.value)
362
343
  syncFocusedDayIndex()
363
344
 
@@ -384,11 +365,31 @@ function onPreviousMonth() {
384
365
  })
385
366
  }
386
367
 
368
+ function resolveInitialChipHighlight() {
369
+ const selectedIndex = computedPresets.value.findIndex(preset => isPresetSelected(preset))
370
+
371
+ if (selectedIndex >= 0) {
372
+ return selectedIndex
373
+ }
374
+
375
+ if (calendarOpen.value) {
376
+ return chooseChipIndex.value
377
+ }
378
+
379
+ return 0
380
+ }
381
+
387
382
  function selectDate(date: Date) {
388
383
  modelValue.value = startOfLocalDay(date)
389
384
 
390
385
  closePanel()
391
386
  }
387
+
388
+ function syncFocusedDayIndex() {
389
+ const selectedIndex = calendarCells.value.findIndex(cell => modelValue.value && isSameDay(cell.date, modelValue.value))
390
+
391
+ focusedDayIndex.value = selectedIndex >= 0 ? selectedIndex : calendarCells.value.findIndex(cell => cell.inMonth)
392
+ }
392
393
  </script>
393
394
 
394
395
  <template>
@@ -405,7 +406,7 @@ function selectDate(date: Date) {
405
406
  />
406
407
 
407
408
  <div
408
- class="field-uppercase select-none overflow-hidden base-box"
409
+ class="select-none overflow-hidden base-box field-uppercase"
409
410
  :class="{
410
411
  'field-disabled': disabled,
411
412
  'base-border-interactive-focus-within': !disabled,
@@ -438,7 +439,7 @@ function selectDate(date: Date) {
438
439
  />
439
440
 
440
441
  <div
441
- class="min-w-0 flex-1 truncate font-medium tracking-tight uppercase leading-normal"
442
+ class="min-w-0 flex-1 truncate font-medium leading-normal tracking-tight uppercase"
442
443
  :class="{
443
444
  'pr-2': modelValue,
444
445
  'text-xs': size === 'sm',
@@ -466,7 +467,7 @@ function selectDate(date: Date) {
466
467
  <button
467
468
  v-if="modelValue"
468
469
  :aria-label="t('clear')"
469
- class="base-control-hover mr-3 inline-flex shrink-0 items-center self-center justify-center rounded-full p-1 text-gray-600 outline-none transition-[transform,colors] hover:scale-105 dark:text-gray-400"
470
+ class="mr-3 inline-flex shrink-0 items-center self-center justify-center rounded-full base-control-hover p-1 text-gray-600 outline-none transition-[transform,colors] hover:scale-105 dark:text-gray-400"
470
471
  type="button"
471
472
  @click="onClearClick"
472
473
  >
@@ -506,7 +507,7 @@ function selectDate(date: Date) {
506
507
  :key="preset.id"
507
508
  :active="index === highlightedIndex"
508
509
  active-highlight="indigo"
509
- :ariaSelected="index === highlightedIndex"
510
+ :aria-selected="index === highlightedIndex"
510
511
  as="div"
511
512
  hoverable
512
513
  max-width
@@ -516,14 +517,16 @@ function selectDate(date: Date) {
516
517
  @mousedown="onChipMouseDown"
517
518
  @mouseenter="onHighlight(index)"
518
519
  >
519
- {{ preset.label }}<template v-if="preset.sub"> · {{ preset.sub }}</template>
520
+ {{ preset.label }}<template v-if="preset.sub">
521
+ · {{ preset.sub }}
522
+ </template>
520
523
  </BaseChip>
521
524
 
522
525
  <BaseChip
523
526
  :id="`${id}-preset-${chooseChipIndex}`"
524
527
  :active="highlightedIndex === chooseChipIndex"
525
528
  active-highlight="indigo"
526
- :ariaSelected="highlightedIndex === chooseChipIndex"
529
+ :aria-selected="highlightedIndex === chooseChipIndex"
527
530
  as="div"
528
531
  hoverable
529
532
  max-width
@@ -544,10 +547,10 @@ function selectDate(date: Date) {
544
547
  :aria-label="monthLabel"
545
548
  @keydown.escape.prevent="onCloseCalendar"
546
549
  >
547
- <div class="mb-0.5 grid grid-cols-7 gap-px">
550
+ <div class="grid grid-cols-7 mb-0.5 gap-px">
548
551
  <button
549
552
  :aria-label="t('prevMonth')"
550
- class="base-bg-hover min-h-7 min-w-7 inline-flex cursor-pointer items-center justify-center rounded-md outline-none transition-colors"
553
+ class="min-h-7 min-w-7 inline-flex cursor-pointer items-center justify-center rounded-md base-bg-hover outline-none transition-colors"
551
554
  type="button"
552
555
  @click="onPreviousMonth"
553
556
  >
@@ -558,13 +561,13 @@ function selectDate(date: Date) {
558
561
  />
559
562
  </button>
560
563
 
561
- <span class="col-span-5 flex min-h-7 items-center justify-center text-xs text-gray-900 font-bold uppercase dark:text-gray-100">
564
+ <span class="col-span-5 min-h-7 flex items-center justify-center text-xs text-gray-900 font-bold uppercase dark:text-gray-100">
562
565
  {{ monthLabel }}
563
566
  </span>
564
567
 
565
568
  <button
566
569
  :aria-label="t('nextMonth')"
567
- class="base-bg-hover min-h-7 min-w-7 inline-flex cursor-pointer items-center justify-center rounded-md outline-none transition-colors"
570
+ class="min-h-7 min-w-7 inline-flex cursor-pointer items-center justify-center rounded-md base-bg-hover outline-none transition-colors"
568
571
  type="button"
569
572
  @click="onNextMonth"
570
573
  >
@@ -1,7 +1,12 @@
1
1
  import type { Locale } from '@saasmakers/shared'
2
2
  import { resolveLocaleCode } from '../utils/dateField'
3
3
 
4
- export type RelativeDateKey = 'inDays' | 'overdue' | 'today' | 'tomorrow' | 'yesterday'
4
+ export type RelativeDateKey
5
+ = | 'inDays'
6
+ | 'overdue'
7
+ | 'today'
8
+ | 'tomorrow'
9
+ | 'yesterday'
5
10
 
6
11
  export interface RelativeDateMessages {
7
12
  inDays: string
@@ -12,77 +17,77 @@ export interface RelativeDateMessages {
12
17
  }
13
18
 
14
19
  export const relativeDateMessages: Record<Locale, RelativeDateMessages> = {
15
- de: {
20
+ 'de': {
16
21
  inDays: 'In {count} Tag | In {count} Tagen',
17
22
  overdue: 'Überfällig | {count} Tag überfällig | {count} Tage überfällig',
18
23
  today: 'Heute',
19
24
  tomorrow: 'Morgen',
20
25
  yesterday: 'Gestern',
21
26
  },
22
- en: {
27
+ 'en': {
23
28
  inDays: 'In {count} day | In {count} days',
24
29
  overdue: 'Overdue | {count} day overdue | {count} days overdue',
25
30
  today: 'Today',
26
31
  tomorrow: 'Tomorrow',
27
32
  yesterday: 'Yesterday',
28
33
  },
29
- es: {
34
+ 'es': {
30
35
  inDays: 'En {count} día | En {count} días',
31
36
  overdue: 'Atrasado | {count} día de retraso | {count} días de retraso',
32
37
  today: 'Hoy',
33
38
  tomorrow: 'Mañana',
34
39
  yesterday: 'Ayer',
35
40
  },
36
- fr: {
41
+ 'fr': {
37
42
  inDays: 'Dans {count} j | Dans {count} j',
38
43
  overdue: 'En retard | En retard de {count} j | En retard de {count} j',
39
44
  today: 'Aujourd\'hui',
40
45
  tomorrow: 'Demain',
41
46
  yesterday: 'Hier',
42
47
  },
43
- id: {
48
+ 'id': {
44
49
  inDays: 'Dalam {count} hari | Dalam {count} hari',
45
50
  overdue: 'Terlambat | Terlambat {count} hari | Terlambat {count} hari',
46
51
  today: 'Hari ini',
47
52
  tomorrow: 'Besok',
48
53
  yesterday: 'Kemarin',
49
54
  },
50
- it: {
55
+ 'it': {
51
56
  inDays: 'Tra {count} giorno | Tra {count} giorni',
52
57
  overdue: 'In ritardo | In ritardo di {count} g | In ritardo di {count} g',
53
58
  today: 'Oggi',
54
59
  tomorrow: 'Domani',
55
60
  yesterday: 'Ieri',
56
61
  },
57
- ja: {
62
+ 'ja': {
58
63
  inDays: 'あと{count}日 | あと{count}日',
59
64
  overdue: '期限切れ | {count}日遅れ | {count}日遅れ',
60
65
  today: '今日',
61
66
  tomorrow: '明日',
62
67
  yesterday: '昨日',
63
68
  },
64
- ko: {
69
+ 'ko': {
65
70
  inDays: '{count}일 후 | {count}일 후',
66
71
  overdue: '기한 지남 | {count}일 지남 | {count}일 지남',
67
72
  today: '오늘',
68
73
  tomorrow: '내일',
69
74
  yesterday: '어제',
70
75
  },
71
- nl: {
76
+ 'nl': {
72
77
  inDays: 'Over {count} dag | Over {count} dagen',
73
78
  overdue: 'Te laat | {count} dag te laat | {count} dagen te laat',
74
79
  today: 'Vandaag',
75
80
  tomorrow: 'Morgen',
76
81
  yesterday: 'Gisteren',
77
82
  },
78
- pl: {
83
+ 'pl': {
79
84
  inDays: 'Za {count} dzień | Za {count} dni',
80
85
  overdue: 'Po terminie | {count} dzień po terminie | {count} dni po terminie',
81
86
  today: 'Dziś',
82
87
  tomorrow: 'Jutro',
83
88
  yesterday: 'Wczoraj',
84
89
  },
85
- pt: {
90
+ 'pt': {
86
91
  inDays: 'Daqui a {count} dia | Daqui a {count} dias',
87
92
  overdue: 'Em atraso | {count} dia de atraso | {count} dias de atraso',
88
93
  today: 'Hoje',
@@ -96,7 +101,7 @@ export const relativeDateMessages: Record<Locale, RelativeDateMessages> = {
96
101
  tomorrow: 'Amanhã',
97
102
  yesterday: 'Ontem',
98
103
  },
99
- vi: {
104
+ 'vi': {
100
105
  inDays: 'Trong {count} ngày | Trong {count} ngày',
101
106
  overdue: 'Quá hạn | Quá hạn {count} ngày | Quá hạn {count} ngày',
102
107
  today: 'Hôm nay',
@@ -105,22 +110,6 @@ export const relativeDateMessages: Record<Locale, RelativeDateMessages> = {
105
110
  },
106
111
  }
107
112
 
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
113
  export function getRelativeDateMessage(localeValue: unknown, key: RelativeDateKey, count?: number) {
125
114
  const messages = relativeDateMessages[resolveRelativeDateLocale(localeValue)]
126
115
  const rawMessage = messages[key]
@@ -130,9 +119,26 @@ export function getRelativeDateMessage(localeValue: unknown, key: RelativeDateKe
130
119
  }
131
120
 
132
121
  const forms = rawMessage.split('|').map(form => form.trim())
122
+
133
123
  const template = forms.length === 1
134
124
  ? forms[0]
135
125
  : count === 1 ? forms[1] ?? forms[0] : forms[2] ?? forms[1] ?? forms[0]
136
126
 
137
127
  return template?.replace(/\{count\}/g, String(count)) ?? rawMessage
138
128
  }
129
+
130
+ function resolveRelativeDateLocale(localeValue: unknown): Locale {
131
+ const localeCode = resolveLocaleCode(localeValue)
132
+
133
+ if (localeCode in relativeDateMessages) {
134
+ return localeCode as Locale
135
+ }
136
+
137
+ const languageCode = localeCode.split('-')[0]
138
+
139
+ if (languageCode && languageCode in relativeDateMessages) {
140
+ return languageCode as Locale
141
+ }
142
+
143
+ return 'en'
144
+ }
@@ -109,6 +109,15 @@ export type BaseCharacterCharacter
109
109
 
110
110
  export type BaseCharacterSize = 'base' | 'lg' | 'sm' | 'xs'
111
111
 
112
+ export interface BaseChart {
113
+ data?: ChartistBarChartData | ChartistLineChartData | ChartistPieChartData
114
+ fullWidth?: boolean
115
+ options?: ChartistOptions
116
+ type?: BaseChartType
117
+ }
118
+
119
+ export type BaseChartType = 'bar' | 'line' | 'pie'
120
+
112
121
  export interface BaseChip {
113
122
  active?: boolean
114
123
  activeHighlight?: BaseChipActiveHighlight
@@ -135,15 +144,6 @@ export type BaseChipAs = 'button' | 'div'
135
144
 
136
145
  export type BaseChipVariant = 'dashed' | 'filled' | 'outline'
137
146
 
138
- export interface BaseChart {
139
- data?: ChartistBarChartData | ChartistLineChartData | ChartistPieChartData
140
- fullWidth?: boolean
141
- options?: ChartistOptions
142
- type?: BaseChartType
143
- }
144
-
145
- export type BaseChartType = 'bar' | 'line' | 'pie'
146
-
147
147
  export interface BaseCircle {
148
148
  color?: BaseCircleColor
149
149
  }
@@ -33,12 +33,12 @@ 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 BaseChart = import('./bases').BaseChart
37
+ type BaseChartType = import('./bases').BaseChartType
36
38
  type BaseChip = import('./bases').BaseChip
37
39
  type BaseChipActiveHighlight = import('./bases').BaseChipActiveHighlight
38
40
  type BaseChipAs = import('./bases').BaseChipAs
39
41
  type BaseChipVariant = import('./bases').BaseChipVariant
40
- type BaseChart = import('./bases').BaseChart
41
- type BaseChartType = import('./bases').BaseChartType
42
42
  type BaseCircle = import('./bases').BaseCircle
43
43
  type BaseCircleColor = import('./bases').BaseCircleColor
44
44
  type BaseColor = import('./bases').BaseColor
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasmakers/ui",
3
- "version": "2.0.69",
3
+ "version": "2.0.70",
4
4
  "private": false,
5
5
  "description": "Reusable Nuxt UI components for SaaS Makers projects",
6
6
  "license": "MIT",