vunor 0.0.2

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.
Files changed (60) hide show
  1. package/README.md +33 -0
  2. package/dist/theme.d.ts +133 -0
  3. package/dist/theme.mjs +1149 -0
  4. package/dist/vite.d.ts +5 -0
  5. package/dist/vite.mjs +13 -0
  6. package/package.json +83 -0
  7. package/src/components/AppLayout/AppLayout.vue +114 -0
  8. package/src/components/Button/Button.vue +49 -0
  9. package/src/components/Button/ButtonBase.vue +43 -0
  10. package/src/components/Button/index.ts +1 -0
  11. package/src/components/Button/shortcuts.ts +29 -0
  12. package/src/components/Card/Card.vue +47 -0
  13. package/src/components/Card/CardHeader.vue +26 -0
  14. package/src/components/Card/CardInner.vue +5 -0
  15. package/src/components/Card/index.ts +3 -0
  16. package/src/components/Card/pi.ts +46 -0
  17. package/src/components/Card/shortcuts.ts +19 -0
  18. package/src/components/Checkbox/Checkbox.vue +59 -0
  19. package/src/components/Checkbox/index.ts +1 -0
  20. package/src/components/Checkbox/shortcuts.ts +27 -0
  21. package/src/components/Combobox/Combobox.vue +502 -0
  22. package/src/components/Combobox/index.ts +2 -0
  23. package/src/components/Combobox/shortcuts.ts +12 -0
  24. package/src/components/Combobox/types.ts +33 -0
  25. package/src/components/Icon/Icon.vue +9 -0
  26. package/src/components/Icon/index.ts +1 -0
  27. package/src/components/Input/Input.vue +109 -0
  28. package/src/components/Input/InputShell.vue +133 -0
  29. package/src/components/Input/index.ts +4 -0
  30. package/src/components/Input/pi.ts +18 -0
  31. package/src/components/Input/types.ts +52 -0
  32. package/src/components/Input/utils.ts +108 -0
  33. package/src/components/Label/Label.vue +6 -0
  34. package/src/components/Label/index.ts +1 -0
  35. package/src/components/Loading/LoadingIndicator.vue +23 -0
  36. package/src/components/Loading/index.ts +1 -0
  37. package/src/components/Loading/shortcuts.ts +9 -0
  38. package/src/components/Menu/Menu.vue +100 -0
  39. package/src/components/Menu/MenuItem.vue +20 -0
  40. package/src/components/Menu/index.ts +2 -0
  41. package/src/components/Menu/shortcuts.ts +6 -0
  42. package/src/components/OverflowContainer/OverflowContainer.vue +120 -0
  43. package/src/components/OverflowContainer/index.ts +1 -0
  44. package/src/components/Pagination/Pagination.vue +71 -0
  45. package/src/components/Popover/Popover.vue +58 -0
  46. package/src/components/Popover/index.ts +1 -0
  47. package/src/components/RadioGroup/RadioGroup.vue +83 -0
  48. package/src/components/RadioGroup/index.ts +1 -0
  49. package/src/components/RadioGroup/shortcuts.ts +34 -0
  50. package/src/components/Select/Select.vue +93 -0
  51. package/src/components/Select/SelectBase.vue +148 -0
  52. package/src/components/Select/index.ts +3 -0
  53. package/src/components/Select/shortcuts.ts +30 -0
  54. package/src/components/Select/types.ts +30 -0
  55. package/src/components/Slider/Slider.vue +73 -0
  56. package/src/components/Slider/index.ts +1 -0
  57. package/src/components/Slider/shortcuts.ts +23 -0
  58. package/src/components/shortcuts.ts +21 -0
  59. package/src/components/utils/index.ts +1 -0
  60. package/src/components/utils/provide-inject.ts +39 -0
@@ -0,0 +1,502 @@
1
+ <script setup lang="ts" generic="T extends TComboboxItem = TComboboxItem">
2
+ import type { TComboboxProps, TComboboxItem } from './types'
3
+ import type { TInputProps, TInputShellProps, TInputEmits } from '../Input/types'
4
+ import { createReusableTemplate } from '@vueuse/core'
5
+ import { useInputShellProps, useInputProps } from '../Input/utils'
6
+
7
+ const [DefineContentTemplate, UseContentTemplate] = createReusableTemplate()
8
+ const [DefineRootTemplate, UseRootTemplate] = createReusableTemplate()
9
+ const [DefineInputShellTemplate, UseInputShellTemplate] = createReusableTemplate()
10
+ const [DefineItemsTemplate, UseItemsTemplate] = createReusableTemplate()
11
+
12
+ const props = withDefaults(
13
+ defineProps<Omit<TInputProps & TInputShellProps, 'active'> & TComboboxProps<T>>(),
14
+ {
15
+ sideOffset: 2,
16
+ popupPosition: 'popper',
17
+ dropdownIcon: 'i--chevron-down',
18
+ }
19
+ )
20
+ defineEmits<TInputEmits>()
21
+
22
+ const forwardProps = computed(() => {
23
+ if (props.groupItem) {
24
+ return useInputShellProps()?.value
25
+ }
26
+ return useInputProps()?.value
27
+ })
28
+ const shellProps = computed(() => {
29
+ return useInputShellProps()?.value
30
+ })
31
+
32
+ const modelOpen = defineModel<boolean>('open')
33
+ const modelValue = defineModel<string | string[]>()
34
+
35
+ const groups = computed(() => {
36
+ if (Array.isArray(props.items)) {
37
+ return [
38
+ {
39
+ grp: '',
40
+ items: props.items.map(item =>
41
+ typeof item === 'string' ? ({ value: item, label: item } as T) : item
42
+ ),
43
+ },
44
+ ]
45
+ } else {
46
+ const r = [] as { grp: string; items: T[] }[]
47
+ for (const [key, val] of Object.entries(props.items)) {
48
+ r.push({
49
+ grp: key,
50
+ items: val.map(item =>
51
+ typeof item === 'string' ? ({ value: item, label: item } as T) : item
52
+ ),
53
+ })
54
+ }
55
+ return r
56
+ }
57
+ })
58
+
59
+ const flatItems = computed(() => {
60
+ const r = [] as T[]
61
+ for (const grp of groups.value) {
62
+ for (const item of grp.items) {
63
+ r.push(item)
64
+ }
65
+ }
66
+ return r
67
+ })
68
+
69
+ const flatItemsMap = computed(() => {
70
+ const r = new Map<string | number | null | undefined, T>()
71
+ for (const item of flatItems.value) {
72
+ r.set(item.value, item)
73
+ }
74
+ return r
75
+ })
76
+
77
+ function isItemSelected(v?: string | null) {
78
+ return Array.isArray(modelValue.value)
79
+ ? modelValue.value.includes(v as string)
80
+ : modelValue.value === v
81
+ }
82
+
83
+ const selectedItems = computed(() => {
84
+ if (modelValue.value && Array.isArray(modelValue.value)) {
85
+ return modelValue.value.map(v => flatItemsMap.value.get(v)!) as T[]
86
+ } else {
87
+ const item = flatItemsMap.value.get(modelValue.value)
88
+ if (item) {
89
+ return [item] as T[]
90
+ }
91
+ }
92
+ return [] as T[]
93
+ })
94
+
95
+ const selectedLabels = computed<string>(() => {
96
+ if (!modelValue.value && (modelValue.value as unknown as number) !== 0) return ''
97
+ return selectedItems.value
98
+ .filter(item => !!item)
99
+ .map(item => item.label || item.value)
100
+ .join(', ')
101
+ })
102
+
103
+ function isItemDisabled(val: string | null | undefined) {
104
+ return props.disabledValues?.includes(val)
105
+ }
106
+
107
+ const displayValue = computed(() => flatItemsMap.value.get(modelValue.value as string)?.label || '')
108
+
109
+ const input = computed(
110
+ () => inputTemplate.value?.$el.querySelector('input') as HTMLInputElement | undefined
111
+ )
112
+
113
+ async function openPopup() {
114
+ if (!props.readonly && !props.disabled && !usePopover.value) {
115
+ modelOpen.value = !modelOpen.value
116
+ await nextTick()
117
+ if (input.value) {
118
+ const el = input.value
119
+ if (el) {
120
+ const valueLength = el.value.length
121
+ el.focus()
122
+ el.setSelectionRange(valueLength, valueLength)
123
+ }
124
+ }
125
+ }
126
+ }
127
+
128
+ function handleHomeEnd(event: KeyboardEvent) {
129
+ const target = event.target as HTMLInputElement
130
+ const length = event.key === 'Home' ? 0 : target.value.length
131
+ if (event.shiftKey) {
132
+ target.setSelectionRange(
133
+ event.key === 'Home' ? 0 : target.selectionEnd ?? target.value.length,
134
+ event.key === 'Home' ? target.selectionStart ?? 0 : target.value.length
135
+ )
136
+ } else {
137
+ target.setSelectionRange(length, length)
138
+ }
139
+ }
140
+
141
+ const searchTerm = ref('')
142
+
143
+ const usePopover = computed(() => props.multiple)
144
+ if (usePopover.value) {
145
+ modelOpen.value = true
146
+ }
147
+ watch([usePopover], () => {
148
+ if (usePopover.value) {
149
+ modelOpen.value = true
150
+ }
151
+ })
152
+
153
+ const sideOffsetHack = ref(false)
154
+ const _sideOffset = computed<number>(() => (sideOffsetHack.value ? -1 : props.sideOffset))
155
+
156
+ watch([modelOpen], async () => {
157
+ sideOffsetHack.value = true
158
+ await nextTick()
159
+ sideOffsetHack.value = false
160
+ })
161
+
162
+ const popoverProps = computed(() => ({
163
+ class: {
164
+ [typeof props.popupClass === 'string' ? props.popupClass : '']: true,
165
+ 'select-content group/i8 rounded': true,
166
+ ...(typeof props.popupClass === 'object' ? props.popupClass : {}),
167
+ },
168
+ dataDesign: props.popupRound ? 'round' : undefined,
169
+ style: {
170
+ 'min-width': 'var(--radix-popper-anchor-width)',
171
+ },
172
+ side: props.side,
173
+ sideOffset: _sideOffset.value,
174
+ updatePositionStrategy: props.updatePositionStrategy,
175
+ bodyLock: props.bodyLock,
176
+ }))
177
+
178
+ const comboboxContentProps = computed(() => {
179
+ if (usePopover.value) return {}
180
+ return popoverProps.value
181
+ })
182
+ const popoverContentProps = computed(() => {
183
+ if (usePopover.value) return popoverProps.value
184
+ return {}
185
+ })
186
+ const popupOpen = ref(false)
187
+ watch(popupOpen, () => {
188
+ if (popupOpen.value) {
189
+ modelOpen.value = true
190
+ }
191
+ })
192
+ watch(modelOpen, () => {
193
+ if (usePopover.value) {
194
+ popupOpen.value = !!modelOpen.value
195
+ }
196
+ })
197
+ const inputTemplate = ref<{ $el: HTMLDivElement }>()
198
+ async function focusOnInput() {
199
+ await nextTick()
200
+ input.value?.focus({
201
+ preventScroll: true,
202
+ })
203
+ }
204
+ async function clearValue() {
205
+ modelValue.value = undefined
206
+ await nextTick()
207
+ input.value?.focus()
208
+ }
209
+
210
+ const focused = ref(false)
211
+ function onFocus() {
212
+ focused.value = true
213
+ }
214
+ function onBlur() {
215
+ focused.value = false
216
+ }
217
+ function onKeydown(event: KeyboardEvent) {
218
+ if (props.disabled || props.readonly) {
219
+ return
220
+ }
221
+ if (['Enter', 'Space'].includes(event.code)) {
222
+ popupOpen.value = true
223
+ } else if (/Key[a-zA-Z0-9]/.test(event.code)) {
224
+ popupOpen.value = true
225
+ }
226
+ }
227
+ </script>
228
+
229
+ <template>
230
+ <!-- reusabe templates start -->
231
+ <DefineContentTemplate>
232
+ <ComboboxContent v-bind="comboboxContentProps" :position="usePopover ? 'inline' : 'popper'">
233
+ <ComboboxViewport class="">
234
+ <ComboboxEmpty class="select-grp-label">
235
+ <slot name="empty">
236
+ <span>No Options</span>
237
+ </slot>
238
+ </ComboboxEmpty>
239
+
240
+ <ComboboxGroup v-for="(g, grpIndex) of groups" :key="grpIndex">
241
+ <ComboboxSeparator v-if="grpIndex > 0" class="select-separator" />
242
+ <ComboboxLabel class="select-grp-label" v-if="!!g.grp">
243
+ <slot name="group-label" v-bind="g">
244
+ <span>{{ g.grp }}</span>
245
+ </slot>
246
+ </ComboboxLabel>
247
+
248
+ <ComboboxItem
249
+ v-for="(item, index) in g.items"
250
+ :key="index"
251
+ class="select-item relative"
252
+ :value="String(item.value)"
253
+ :disabled="disabled || item.disabled || isItemDisabled(item.value)"
254
+ :aria-disabled="disabled || item.disabled || isItemDisabled(item.value)"
255
+ @click="focusOnInput"
256
+ >
257
+ <span>
258
+ <slot name="item" v-bind="item" :selected="isItemSelected(item.value)">
259
+ <VuCheckbox
260
+ v-if="checkboxItems"
261
+ readonly
262
+ :label="item.label"
263
+ :model-value="isItemSelected(item.value)"
264
+ />
265
+ <template v-else>
266
+ {{ item.label }}
267
+ </template>
268
+ </slot>
269
+ </span>
270
+ </ComboboxItem>
271
+ </ComboboxGroup>
272
+ </ComboboxViewport>
273
+ </ComboboxContent>
274
+ </DefineContentTemplate>
275
+
276
+ <DefineRootTemplate v-slot="templateProps">
277
+ <ComboboxRoot
278
+ :class="templateProps.class"
279
+ class="relative w-full h-full"
280
+ v-model="modelValue"
281
+ :default-open="usePopover"
282
+ v-model:open="modelOpen"
283
+ v-model:search-term="searchTerm"
284
+ :display-value="() => displayValue"
285
+ :disabled
286
+ :required
287
+ :multiple
288
+ :as-child="usePopover || groupItem"
289
+ >
290
+ <DefineInputShellTemplate>
291
+ <!-- prettier-ignore-attribute v-model -->
292
+ <VuInputShell
293
+ @click="openPopup"
294
+ :active="modelOpen"
295
+ v-model="(modelValue as string)"
296
+ v-bind="shellProps"
297
+ :type="usePopover ? 'text' : shellProps?.type"
298
+ :label="usePopover ? '' : shellProps?.label"
299
+ :placeholder="usePopover ? 'Search' : shellProps?.placeholder"
300
+ :design="usePopover ? 'filled' : shellProps?.design"
301
+ :icon-append="usePopover ? undefined : dropdownIcon"
302
+ :icon-prepend="usePopover ? 'i--search' : shellProps?.iconPrepend"
303
+ :class="usePopover ? 'i8-no-border' : 'i8-combobox'"
304
+ @append-click="openPopup"
305
+ :data-expanded="usePopover ? undefined : modelOpen"
306
+ >
307
+ <template v-slot="slotProps">
308
+ <ComboboxInput as-child class="i8-input">
309
+ <input
310
+ class="i8-input"
311
+ ref="input"
312
+ v-bind="slotProps"
313
+ @focus="slotProps.onFocus"
314
+ @blur="slotProps.onBlur"
315
+ @keydown.home.end="handleHomeEnd"
316
+ />
317
+ </ComboboxInput>
318
+ </template>
319
+
320
+ <template #prepend v-if="!usePopover && !!$slots.prepend">
321
+ <slot name="prepend"></slot>
322
+ </template>
323
+
324
+ <template #append v-if="!usePopover && !!$slots.append">
325
+ <slot name="append"></slot>
326
+ </template>
327
+ </VuInputShell>
328
+ </DefineInputShellTemplate>
329
+
330
+ <div v-if="usePopover" class="sticky top-0 z-1 bg-current/100 border-b-1px">
331
+ <UseInputShellTemplate ref="inputTemplate" />
332
+ </div>
333
+ <ComboboxAnchor v-else as-child>
334
+ <UseInputShellTemplate ref="inputTemplate" />
335
+ </ComboboxAnchor>
336
+
337
+ <UseContentTemplate v-if="usePopover" />
338
+ <ComboboxPortal v-else as-child>
339
+ <UseContentTemplate />
340
+ </ComboboxPortal>
341
+ </ComboboxRoot>
342
+ </DefineRootTemplate>
343
+
344
+ <!-- reusabe templates end -->
345
+
346
+ <template v-if="readonly || disabled">
347
+ <!-- prettier-ignore-attribute v-model -->
348
+ <VuInputShell
349
+ v-if="groupItem"
350
+ v-bind="shellProps"
351
+ v-model="(modelValue as string)"
352
+ :class
353
+ :icon-append="props.iconAppend || dropdownIcon"
354
+ >
355
+ <template #prepend v-if="!!$slots.prepend">
356
+ <slot name="prepend"></slot>
357
+ </template>
358
+
359
+ <template #append v-if="!!$slots.append">
360
+ <slot name="append"></slot>
361
+ </template>
362
+ </VuInputShell>
363
+ <!-- prettier-ignore-attribute v-model -->
364
+ <VuInput
365
+ v-else
366
+ v-bind="forwardProps"
367
+ v-model="(modelValue as string)"
368
+ :class
369
+ :icon-append="props.iconAppend || dropdownIcon"
370
+ >
371
+ <template #before v-if="!!$slots.before">
372
+ <slot name="before"></slot>
373
+ </template>
374
+ <template #after v-if="!!$slots.after">
375
+ <slot name="after"></slot>
376
+ </template>
377
+
378
+ <template #prepend v-if="!!$slots.prepend">
379
+ <slot name="prepend"></slot>
380
+ </template>
381
+ <template #append v-if="!!$slots.append">
382
+ <slot name="append"></slot>
383
+ </template>
384
+ </VuInput>
385
+ </template>
386
+
387
+ <template v-else-if="usePopover">
388
+ <PopoverRoot v-model:open="popupOpen">
389
+ <DefineItemsTemplate>
390
+ <slot name="selected-items" :items="selectedItems">
391
+ <div class="combobox-multi-input">
392
+ <div class="combobox-multi-items">
393
+ {{ selectedLabels }}
394
+ </div>
395
+ </div>
396
+ </slot>
397
+ </DefineItemsTemplate>
398
+
399
+ <PopoverTrigger v-if="groupItem" as-child :data-expanded="popupOpen" class="i8-combobox">
400
+ <VuInputShell
401
+ class="combobox-embedded-input"
402
+ tabindex="0"
403
+ @keydown="onKeydown"
404
+ @focus="onFocus"
405
+ @blur="onBlur"
406
+ v-bind="forwardProps"
407
+ :model-value="selectedLabels"
408
+ readonly
409
+ :icon-append="dropdownIcon"
410
+ @append-click="popupOpen = !popupOpen"
411
+ :class
412
+ :active="popupOpen || focused"
413
+ >
414
+ <template>
415
+ <UseItemsTemplate />
416
+ </template>
417
+
418
+ <template #prepend v-if="!!$slots.prepend">
419
+ <slot name="prepend"></slot>
420
+ </template>
421
+ <template #append v-if="!!$slots.append">
422
+ <slot name="append"></slot>
423
+ </template>
424
+ </VuInputShell>
425
+ </PopoverTrigger>
426
+ <VuInput
427
+ v-else
428
+ v-bind="forwardProps"
429
+ :model-value="selectedLabels"
430
+ :class
431
+ :active="popupOpen"
432
+ :data-expanded="popupOpen"
433
+ class="i8-combobox"
434
+ >
435
+ <template v-slot="slotProps">
436
+ <PopoverTrigger as-child>
437
+ <VuInputShell
438
+ class="combobox-embedded-input"
439
+ tabindex="0"
440
+ @keydown="onKeydown"
441
+ @focus="onFocus"
442
+ @blur="onBlur"
443
+ v-bind="slotProps"
444
+ readonly
445
+ :icon-append="dropdownIcon"
446
+ @append-click="popupOpen = !popupOpen"
447
+ :model-value="selectedLabels"
448
+ :active="popupOpen || focused"
449
+ >
450
+ <UseItemsTemplate />
451
+
452
+ <template #prepend v-if="!!$slots.prepend">
453
+ <slot name="prepend"></slot>
454
+ </template>
455
+ <template v-slot:append="{ iconAppend }">
456
+ <div class="flex gap-$s">
457
+ <VuIcon
458
+ v-if="!!selectedLabels && !readonly && !disabled"
459
+ name="i--clear"
460
+ @click.stop="clearValue"
461
+ class="combobox-c8-icon"
462
+ />
463
+ <VuIcon :name="dropdownIcon" class="combobox-c8-icon" />
464
+ </div>
465
+ </template>
466
+ </VuInputShell>
467
+ </PopoverTrigger>
468
+ </template>
469
+
470
+ <template #before v-if="!!$slots.before">
471
+ <slot name="before"></slot>
472
+ </template>
473
+ <template #after v-if="!!$slots.after">
474
+ <slot name="after"></slot>
475
+ </template>
476
+ </VuInput>
477
+
478
+ <PopoverPortal>
479
+ <PopoverContent
480
+ v-bind="popoverContentProps"
481
+ avoidCollisions
482
+ :collision-padding="50"
483
+ :style="{
484
+ 'max-height': 'var(--radix-popper-available-height)',
485
+ 'overflow': 'auto',
486
+ }"
487
+ >
488
+ <UseRootTemplate />
489
+ </PopoverContent>
490
+ </PopoverPortal>
491
+ </PopoverRoot>
492
+ </template>
493
+
494
+ <template v-else>
495
+ <UseRootTemplate v-if="groupItem" :class />
496
+
497
+ <!-- prettier-ignore-attribute v-model -->
498
+ <VuInput v-else v-bind="forwardProps" v-model="(modelValue as string)" :class>
499
+ <UseRootTemplate />
500
+ </VuInput>
501
+ </template>
502
+ </template>
@@ -0,0 +1,2 @@
1
+ export { default as VuCombobox } from './Combobox.vue'
2
+ export * from './types'
@@ -0,0 +1,12 @@
1
+ import { scFromObject } from '../../theme/utils/shortcut-obj'
2
+
3
+ export const comboboxShortcuts = {
4
+ 'combobox-multi-input': 'i8-input relative flex items-center',
5
+ 'combobox-multi-items':
6
+ 'text-ellipsis overflow-hidden whitespace-nowrap absolute max-w-full pr-$m lh-1em',
7
+ 'combobox-embedded-input': 'text-left outline-0 outline-offset-0',
8
+ 'combobox-c8-icon': scFromObject({
9
+ '': 'hover:current-icon-scope-color-500 hover:icon-current cursor-pointer',
10
+ 'group-[[aria-expanded=true]]/i8:': '-scale-100',
11
+ }),
12
+ }
@@ -0,0 +1,33 @@
1
+ export interface TComboboxItem {
2
+ icon?: string
3
+ search?: string
4
+ value: string | null | undefined
5
+ label?: string
6
+ disabled?: boolean
7
+ }
8
+
9
+ export type TComboboxItems<T extends TComboboxItem = TComboboxItem> =
10
+ | Array<T | string>
11
+ | Record<string, Array<T | string>>
12
+
13
+ export interface TComboboxProps<T extends TComboboxItem> {
14
+ disabledValues?: Array<string | null | undefined>
15
+ defaultValue?: string | null | undefined
16
+ popupClass?: string | Record<string, boolean>
17
+ popupRound?: boolean
18
+ valueClass?: string | Record<string, boolean>
19
+ iconClass?: string | Record<string, boolean>
20
+ class?: string | Record<string, boolean>
21
+ items: TComboboxItems<T>
22
+ disabled?: boolean
23
+ placeholder?: string
24
+ popupPosition?: 'inline' | 'popper'
25
+ side?: 'top' | 'right' | 'bottom' | 'left'
26
+ sideOffset?: number
27
+ sticky?: 'partial' | 'always'
28
+ updatePositionStrategy?: 'always' | 'optimized'
29
+ bodyLock?: boolean
30
+ multiple?: boolean
31
+ checkboxItems?: boolean
32
+ dropdownIcon?: string
33
+ }
@@ -0,0 +1,9 @@
1
+ <script setup lang="ts">
2
+ defineProps<{
3
+ name: string
4
+ }>()
5
+ </script>
6
+
7
+ <template>
8
+ <div :class="name" class="icon-color"></div>
9
+ </template>
@@ -0,0 +1 @@
1
+ export { default as VuIcon } from './Icon.vue'
@@ -0,0 +1,109 @@
1
+ <script setup lang="ts">
2
+ import { useInputPi } from './pi'
3
+ import type { TInputProps, TInputEmits } from './types'
4
+ import { useInputShellProps } from './utils'
5
+
6
+ withDefaults(defineProps<TInputProps>(), {
7
+ groupTemplate: 'repeat(1, 1fr)',
8
+ })
9
+ const shellProps = useInputShellProps()
10
+ const modelValue = defineModel<string | number>()
11
+
12
+ const { focused } = useInputPi().provide()
13
+
14
+ const emit = defineEmits<TInputEmits>()
15
+ </script>
16
+
17
+ <template>
18
+ <div
19
+ class="group/i8"
20
+ :class="{
21
+ 'i8-flat': design === 'flat',
22
+ 'i8-filled': design === 'filled' || design === 'round',
23
+ 'i8-round': design === 'round',
24
+ 'scope-error': !!error,
25
+ }"
26
+ :data-error="!!error"
27
+ :data-group-active="focused || active"
28
+ >
29
+ <div class="flex w-full">
30
+ <div
31
+ class="i8-before"
32
+ :class="{
33
+ 'i8-icon-clickable': !!onBeforeClick,
34
+ }"
35
+ v-if="$slots.before || !!iconBefore"
36
+ >
37
+ <slot name="before">
38
+ <VuIcon :name="iconBefore!" @click="emit('beforeClick', $event)" />
39
+ </slot>
40
+ </div>
41
+
42
+ <div class="w-full relative">
43
+ <div class="i8-stack-label" v-if="!!label && stackLabel">
44
+ <VuLabel>{{ label }}</VuLabel>
45
+ </div>
46
+
47
+ <div
48
+ class="w-full"
49
+ :style="{
50
+ 'display': 'grid',
51
+ 'grid-template-columns': groupTemplate,
52
+ 'grid-auto-flow': 'column',
53
+ 'grid-auto-columns': '1fr',
54
+ }"
55
+ @click="emit('click', $event)"
56
+ :class="{
57
+ 'cursor-pointer': !!onClick,
58
+ }"
59
+ >
60
+ <slot v-bind="shellProps!">
61
+ <VuInputShell v-model="modelValue" v-bind="shellProps!">
62
+ <template #overlay v-if="!!$slots.overlay">
63
+ <slot name="overlay"></slot>
64
+ </template>
65
+ <template #prepend v-if="!!$slots.prepend">
66
+ <slot name="prepend"></slot>
67
+ </template>
68
+ <template v-if="!!$slots.input" v-slot="slotScope">
69
+ <slot name="input" v-bind="slotScope"> </slot>
70
+ </template>
71
+
72
+ <template #append v-if="!!$slots.append">
73
+ <slot name="append"></slot>
74
+ </template>
75
+ </VuInputShell>
76
+ </slot>
77
+ </div>
78
+
79
+ <div :class="stackLabel ? 'i8-hint-wrapper-stack' : 'i8-hint-wrapper'">
80
+ <div class="i8-hint">
81
+ <slot v-if="$slots.error || (typeof error === 'string' && error.length)" name="error">
82
+ <span class="text-error-500">
83
+ {{ error }}
84
+ </span>
85
+ </slot>
86
+ <slot v-else-if="!!hint || $slots.hint" name="hint">
87
+ <span>{{ hint }}</span>
88
+ </slot>
89
+ </div>
90
+ <div class="i8-counter" v-if="!!maxlength || $slots.counter">
91
+ <slot name="counter"> {{ String(modelValue || '').length || 0 }}/{{ maxlength }} </slot>
92
+ </div>
93
+ </div>
94
+ </div>
95
+
96
+ <div
97
+ class="i8-after"
98
+ :class="{
99
+ 'i8-icon-clickable': !!onAfterClick,
100
+ }"
101
+ v-if="$slots.after || !!iconAfter"
102
+ >
103
+ <slot name="after">
104
+ <VuIcon :name="iconAfter!" @click="emit('afterClick', $event)" />
105
+ </slot>
106
+ </div>
107
+ </div>
108
+ </div>
109
+ </template>