@privyid/persona 0.21.0 → 0.22.0

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 (118) hide show
  1. package/dist/components/accordion/Accordion.vue +1 -1
  2. package/dist/components/accordion/AccordionItem.vue +6 -6
  3. package/dist/components/badge/Badge.vue +21 -3
  4. package/dist/components/banner/Banner.vue +5 -0
  5. package/dist/components/banner/Banner.vue.d.ts +9 -0
  6. package/dist/components/button/Button.vue +18 -18
  7. package/dist/components/calendar/adapter/adapter.d.ts +1 -8
  8. package/dist/components/calendar/adapter/adapter.mjs +0 -10
  9. package/dist/components/calendar/adapter/date.mjs +2 -2
  10. package/dist/components/calendar/adapter/month.mjs +2 -2
  11. package/dist/components/card/CardSection.vue +1 -0
  12. package/dist/components/carousel/Carousel.vue.d.ts +6 -6
  13. package/dist/components/chart/ChartSet.vue.d.ts +2 -2
  14. package/dist/components/chart/ChartVal.vue.d.ts +4 -4
  15. package/dist/components/checkbox/Checkbox.vue +98 -112
  16. package/dist/components/checkbox/icon/IconCheckbox.vue +13 -0
  17. package/dist/components/checkbox/icon/IconInderteminate.vue +12 -0
  18. package/dist/components/contextual-bar/ContextualBar.vue +67 -19
  19. package/dist/components/contextual-bar/ContextualBar.vue.d.ts +3 -3
  20. package/dist/components/contextual-bar/index.d.ts +1 -1
  21. package/dist/components/cropper/Cropper.vue.d.ts +8 -8
  22. package/dist/components/datepicker/Datepicker.vue +2 -0
  23. package/dist/components/datepicker/Datepicker.vue.d.ts +1 -1
  24. package/dist/components/dialog/Dialog.vue +2 -0
  25. package/dist/components/dialog/index.d.ts +2 -0
  26. package/dist/components/divider/Divider.vue +1 -1
  27. package/dist/components/dropdown/Dropdown.vue +303 -222
  28. package/dist/components/dropzone/Dropzone.vue.d.ts +3 -3
  29. package/dist/components/filterbar/pinned/PinnedDate.vue +2 -0
  30. package/dist/components/filterbar/pinned/PinnedDate.vue.d.ts +1 -1
  31. package/dist/components/filterbar/pinned/PinnedMultiselect.vue +10 -6
  32. package/dist/components/filterbar/pinned/PinnedSelect.vue +11 -7
  33. package/dist/components/filterbar/pinned/PinnedSelect.vue.d.ts +3 -3
  34. package/dist/components/filterbar/pinned/PinnedToggle.vue.d.ts +7 -7
  35. package/dist/components/global/store.d.ts +2 -1
  36. package/dist/components/heading/Heading.vue.d.ts +1 -1
  37. package/dist/components/input/Input.vue +16 -5
  38. package/dist/components/input/Input.vue.d.ts +4 -3
  39. package/dist/components/input/index.d.ts +1 -1
  40. package/dist/components/input-file/InputFile.vue.d.ts +3 -3
  41. package/dist/components/input-pin/InputPin.vue.d.ts +2 -2
  42. package/dist/components/input-range/InputRange.vue.d.ts +6 -6
  43. package/dist/components/label/Label.vue +9 -8
  44. package/dist/components/label/Label.vue.d.ts +1 -1
  45. package/dist/components/main/Main.vue +4 -2
  46. package/dist/components/markdown/index.d.ts +6 -1
  47. package/dist/components/markdown/index.mjs +8 -2
  48. package/dist/components/meta.json +135 -0
  49. package/dist/components/modal/Modal.vue +215 -12
  50. package/dist/components/modal/Modal.vue.d.ts +55 -1
  51. package/dist/components/modal/index.d.ts +1 -1
  52. package/dist/components/nav/Nav.vue +5 -1
  53. package/dist/components/nav/NavItemDropdown.vue.d.ts +1 -1
  54. package/dist/components/nav/NavSubItem.vue +6 -6
  55. package/dist/components/navbar/Navbar.vue.d.ts +1 -1
  56. package/dist/components/navbar/NavbarBrand.vue +1 -1
  57. package/dist/components/pdf-helipad/PdfHelipad.vue +101 -85
  58. package/dist/components/pdf-helipad/utils/use-drag.d.ts +2 -7
  59. package/dist/components/pdf-helipad/utils/use-drag.mjs +1 -1
  60. package/dist/components/pdf-object/utils/use-drag.d.ts +1 -0
  61. package/dist/components/pdf-object/utils/use-drag.mjs +1 -1
  62. package/dist/components/pdf-viewer/PdfViewer.vue.d.ts +4 -4
  63. package/dist/components/progress-indicator/ProgressIndicator.vue.d.ts +2 -2
  64. package/dist/components/progressbar/Progressbar.vue.d.ts +7 -7
  65. package/dist/components/radio/Radio.vue.d.ts +4 -4
  66. package/dist/components/ringbar/Ringbar.vue.d.ts +6 -6
  67. package/dist/components/select/Select.vue +396 -214
  68. package/dist/components/select/SelectInput.vue +102 -0
  69. package/dist/components/select/SelectTags.vue +57 -0
  70. package/dist/components/select/adapter/adapter.d.ts +1 -0
  71. package/dist/components/select/adapter/async-adapter.d.ts +13 -1
  72. package/dist/components/select/adapter/async-adapter.mjs +8 -15
  73. package/dist/components/select/index.d.ts +2 -0
  74. package/dist/components/select/index.mjs +4 -1
  75. package/dist/components/sheet/Sheet.vue +2 -3
  76. package/dist/components/sidebar/Sidebar.vue +101 -116
  77. package/dist/components/sidebar/SidebarBrand.vue +1 -1
  78. package/dist/components/sidebar/SidebarContent.vue +27 -0
  79. package/dist/components/sidebar/SidebarNav.vue +60 -84
  80. package/dist/components/sidebar-menu/SidebarMenu.vue +57 -204
  81. package/dist/components/sidebar-menu/SidebarMenuItem.vue +70 -0
  82. package/dist/components/signature-text/SignatureText.vue.d.ts +4 -4
  83. package/dist/components/steps/StepSlider.vue +2 -2
  84. package/dist/components/strengthbar/Strengthbar.vue.d.ts +8 -8
  85. package/dist/components/table-flex/TableFlex.vue +3 -5
  86. package/dist/components/table-static/TableStatic.vue +118 -111
  87. package/dist/components/table-static/TableStaticRoot.vue +42 -0
  88. package/dist/components/tabs/Tab.vue +13 -15
  89. package/dist/components/tabs/TabContent.vue +64 -23
  90. package/dist/components/tabs/Tabs.vue +93 -75
  91. package/dist/components/text/Text.vue +15 -7
  92. package/dist/components/text/Text.vue.d.ts +11 -2
  93. package/dist/components/text/index.d.ts +1 -0
  94. package/dist/components/textarea/Textarea.vue.d.ts +5 -5
  95. package/dist/components/toggle/Toggle.vue +12 -1
  96. package/dist/components/toggle/Toggle.vue.d.ts +16 -7
  97. package/dist/components/tooltip/index.mjs +1 -1
  98. package/dist/components/tooltip/utils/create-handler.mjs +1 -1
  99. package/dist/components/tour/TourDialog.vue +6 -0
  100. package/dist/components/truncate/Truncate.vue +1 -1
  101. package/dist/components/truncate/Truncate.vue.d.ts +2 -2
  102. package/dist/components/utils/date.d.ts +21 -0
  103. package/dist/components/utils/date.mjs +15 -0
  104. package/dist/components/utils/vnode.mjs +1 -1
  105. package/dist/core/index.d.ts +1 -0
  106. package/dist/core/index.mjs +4 -0
  107. package/dist/module.json +1 -1
  108. package/package.json +17 -17
  109. package/dist/components/checkbox/Checkbox.vue.d.ts +0 -84
  110. package/dist/components/dropdown/Dropdown.vue.d.ts +0 -147
  111. package/dist/components/pdf-helipad/PdfHelipad.vue.d.ts +0 -45
  112. package/dist/components/select/Select.vue.d.ts +0 -157
  113. package/dist/components/sidebar/Sidebar.vue.d.ts +0 -80
  114. package/dist/components/sidebar/SidebarNav.vue.d.ts +0 -66
  115. package/dist/components/sidebar-menu/SidebarMenu.vue.d.ts +0 -91
  116. package/dist/components/tabs/Tab.vue.d.ts +0 -23
  117. package/dist/components/tabs/TabContent.vue.d.ts +0 -14
  118. package/dist/components/tabs/Tabs.vue.d.ts +0 -80
@@ -1,23 +1,55 @@
1
1
  <template>
2
2
  <Dropdown
3
+ ref="dropdown"
3
4
  v-model="isOpen"
4
5
  class="select"
5
6
  data-testid="select"
6
7
  aria-label="select"
7
8
  :disabled="disabled"
8
- :class="classNames">
9
+ :divider="divider"
10
+ :menu-size="menuSize"
11
+ :menu-class="menuClass"
12
+ :class="classNames"
13
+ :no-animation="noAnimation"
14
+ @show="onOpened"
15
+ @hide="onClosed">
9
16
  <template #activator>
10
- <p-input
11
- v-model="search"
12
- data-testid="select-search"
13
- class="select__search"
17
+ <SelectInput
18
+ data-testid="select-activator"
19
+ class="select__activator"
14
20
  :size="size"
15
21
  :placeholder="placeholder"
16
22
  :disabled="disabled"
17
23
  :readonly="readonly"
18
- :clearable="clearable"
19
- @clear.prevent="onClear"
24
+ :error="error"
20
25
  @focus="onFocus">
26
+ <template #default>
27
+ <template v-if="hasValue">
28
+ <slot
29
+ name="selected"
30
+ :item="localModel"
31
+ :multiple="multiple">
32
+ <template v-if="props.multiple && Array.isArray(localModel)">
33
+ <SelectTags
34
+ :items="localModel"
35
+ :display-limit="displayLimit"
36
+ :limit-text="limitText" />
37
+ </template>
38
+ <template v-else-if="!Array.isArray(localModel)">
39
+ {{ localModel?.text }}
40
+ </template>
41
+ </slot>
42
+ </template>
43
+ <template v-else>
44
+ <div data-testid="select-placeholder">
45
+ <slot name="placeholder">
46
+ <span class="input__form__placeholder">
47
+ {{ placeholder }}
48
+ </span>
49
+ </slot>
50
+ </div>
51
+ </template>
52
+ </template>
21
53
  <template
22
54
  v-if="!noCaret"
23
55
  #append>
@@ -31,6 +63,22 @@
31
63
  @click="toggleOpen" />
32
64
  </slot>
33
65
  </template>
66
+ </SelectInput>
67
+ </template>
68
+
69
+ <template #prepend>
70
+ <p-input
71
+ v-if="searchable"
72
+ ref="input"
73
+ v-model="keyword"
74
+ data-testid="select-search"
75
+ class="select__search no--error"
76
+ :size="size"
77
+ :placeholder="searchText"
78
+ :clearable="true">
79
+ <template #append>
80
+ <IconSearch class="select__search-icon" />
81
+ </template>
34
82
  </p-input>
35
83
  </template>
36
84
 
@@ -46,9 +94,23 @@
46
94
 
47
95
  <template v-else>
48
96
  <DropdownHeader
49
- v-if="sectionLabel"
97
+ v-if="sectionLabel || clearable"
50
98
  data-testid="select-label">
51
- {{ sectionLabel }}
99
+ <template #default>
100
+ {{ sectionLabel }}
101
+ </template>
102
+
103
+ <template
104
+ v-if="clearable"
105
+ #action>
106
+ <p-text
107
+ data-testid="select-clear"
108
+ variant="caption2"
109
+ href="javascript:void"
110
+ @click.prevent="onClear">
111
+ {{ clearLabel }}
112
+ </p-text>
113
+ </template>
52
114
  </DropdownHeader>
53
115
  <DropdownItem
54
116
  v-for="(item, i) in items"
@@ -56,7 +118,7 @@
56
118
  data-testid="select-item"
57
119
  :class="{ selected: isSelected(item) }"
58
120
  :disabled="Boolean(item.disabled)"
59
- @click="select(item)">
121
+ @click.prevent="setValue(item)">
60
122
  <div class="select__option">
61
123
  <div class="select__option-text">
62
124
  <slot
@@ -66,8 +128,10 @@
66
128
  {{ item.text }}
67
129
  </slot>
68
130
  </div>
69
- <IconCheck
70
- class="select__option-checked" />
131
+ <div class="select__option-checked">
132
+ <IconCheckbox v-if="multiple" />
133
+ <IconCheck v-else />
134
+ </div>
71
135
  </div>
72
136
  </DropdownItem>
73
137
  </template>
@@ -76,9 +140,7 @@
76
140
  <div
77
141
  data-testid="select-loading"
78
142
  class="select__loading">
79
- <IconLoading
80
- width="14"
81
- height="14" />
143
+ <IconLoading />
82
144
  <slot name="loading">
83
145
  <span>{{ loadingText }}</span>
84
146
  </slot>
@@ -87,220 +149,309 @@
87
149
  </Dropdown>
88
150
  </template>
89
151
 
90
- <script>
91
- import Dropdown from "../dropdown/Dropdown.vue";
92
- import DropdownItem from "../dropdown/DropdownItem.vue";
93
- import DropdownHeader from "../dropdown/DropdownHeader.vue";
94
- import pInput from "../input/Input.vue";
95
- import IconArrow from "@privyid/persona-icon/vue/chevron-down/20.vue";
96
- import IconCheck from "@privyid/persona-icon/vue/checkmark-circle-solid/20.vue";
97
- import IconLoading from "../spinner/SpinnerRing.vue";
152
+ <script lang="ts" setup>
153
+ import Dropdown from '../dropdown/Dropdown.vue'
154
+ import DropdownItem from '../dropdown/DropdownItem.vue'
155
+ import DropdownHeader from '../dropdown/DropdownHeader.vue'
156
+ import pInput from '../input/Input.vue'
157
+ import pText from '../text/Text.vue'
158
+ import SelectInput from './SelectInput.vue'
159
+ import SelectTags from './SelectTags.vue'
160
+ import IconArrow from '@privyid/persona-icon/vue/chevron-down/20.vue'
161
+ import IconCheck from '@privyid/persona-icon/vue/checkmark-circle-solid/20.vue'
162
+ import IconSearch from '@privyid/persona-icon/vue/search/20.vue'
163
+ import IconCheckbox from '../checkbox/icon/IconCheckbox.vue'
164
+ import IconLoading from '../spinner/SpinnerRing.vue'
98
165
  import {
99
166
  computed,
100
- defineComponent,
101
- getCurrentInstance,
167
+ PropType,
102
168
  ref,
103
- watch
104
- } from "vue-demi";
105
- import { findSelected } from ".";
106
- import BasicAdapter from "./adapter/basic-adapter";
107
- import useLoading from "../overlay/utils/use-loading";
108
- import { isEqual } from "../utils/value";
109
- import { tryOnMounted } from "@vueuse/shared";
169
+ HTMLAttributes,
170
+ nextTick,
171
+ } from 'vue-demi'
110
172
  import {
111
- onStartTyping
112
- } from "@vueuse/core";
113
- export default defineComponent({
114
- components: {
115
- Dropdown,
116
- DropdownItem,
117
- DropdownHeader,
118
- pInput,
119
- IconArrow,
120
- IconCheck,
121
- IconLoading
173
+ findSelected,
174
+ filterSelected,
175
+ SelectItem,
176
+ } from '.'
177
+ import { Adapter, AdapterContext } from './adapter/adapter'
178
+ import BasicAdapter from './adapter/basic-adapter'
179
+ import useLoading from '../overlay/utils/use-loading'
180
+ import { isEqual } from '../utils/value'
181
+ import { onStartTyping, watchPausable } from '@vueuse/core'
182
+ import { SizeVariant } from '../button'
183
+ import { MenuSizeVariant } from '../dropdown/'
184
+
185
+ defineOptions({
186
+ models: {
187
+ prop : 'modelValue',
188
+ event: 'update:modelValue',
122
189
  },
123
- props: {
124
- modelValue: {
125
- type: [
126
- String,
127
- Number,
128
- Boolean,
129
- Array,
130
- Object,
131
- Date
132
- ],
133
- default: void 0
134
- },
135
- selected: {
136
- type: Object,
137
- default: () => {
138
- return {
139
- text: "",
140
- value: void 0
141
- };
142
- }
143
- },
144
- options: {
145
- type: Array,
146
- default: () => []
147
- },
148
- placeholder: {
149
- type: String,
150
- default: ""
151
- },
152
- emptyText: {
153
- type: String,
154
- default: "No Data"
155
- },
156
- loadingText: {
157
- type: String,
158
- default: "Loading..."
159
- },
160
- adapter: {
161
- type: Object,
162
- default: () => BasicAdapter
163
- },
164
- disabled: {
165
- type: Boolean,
166
- default: false
167
- },
168
- readonly: {
169
- type: Boolean,
170
- default: false
171
- },
172
- error: {
173
- type: Boolean,
174
- default: false
175
- },
176
- clearable: {
177
- type: Boolean,
178
- default: false
179
- },
180
- size: {
181
- type: String,
182
- default: "md"
183
- },
184
- sectionLabel: {
185
- type: String,
186
- default: void 0
187
- },
188
- noCaret: {
189
- type: Boolean,
190
- default: false
191
- }
190
+ })
191
+
192
+ const props = defineProps({
193
+ modelValue: {
194
+ type : undefined,
195
+ default: undefined,
192
196
  },
193
- models: {
194
- prop: "modelValue",
195
- event: "update:modelValue"
197
+ selected: {
198
+ type : [Object, Array] as PropType<SelectItem | SelectItem[]>,
199
+ default: undefined,
196
200
  },
197
- emits: [
198
- "change",
199
- "update:modelValue",
200
- "update:selected",
201
- "userInput"
202
- ],
203
- setup(props, { emit }) {
204
- const vm = getCurrentInstance();
205
- const input = ref();
206
- const keyword = ref("");
207
- const isOpen = ref(false);
208
- const isLoading = useLoading({ elapsed: false });
209
- const context = {
210
- props,
211
- keyword,
212
- isOpen,
213
- isLoading
214
- };
215
- const items = props.adapter.setup(context);
216
- const localModel = ref(findSelected(items.value, props.modelValue));
217
- const toggleOpen = () => {
218
- if (!props.disabled && !props.readonly)
219
- isOpen.value = !isOpen.value;
220
- };
221
- const classNames = computed(() => {
222
- const result = [];
223
- if (isOpen.value)
224
- result.push("select--open");
225
- if (props.disabled)
226
- result.push("select--disabled");
227
- if (props.readonly)
228
- result.push("select--readonly");
229
- if (props.error)
230
- result.push("select--error", "state--error");
231
- return result;
232
- });
233
- const search = computed({
234
- get() {
235
- return isOpen.value ? keyword.value : localModel.value?.text;
236
- },
237
- set(value) {
238
- if (value !== search.value)
239
- keyword.value = value;
240
- }
241
- });
242
- watch(() => props.modelValue, (value) => {
243
- localModel.value = findSelected(items.value, value);
244
- });
245
- function select(item) {
246
- localModel.value = item;
247
- emit("change", item);
248
- emit("update:selected", item);
249
- emit("update:modelValue", item?.value);
250
- if (isOpen.value)
251
- emit("userInput", item);
252
- }
253
- function onFocus() {
254
- if (!props.disabled && !props.readonly)
255
- isOpen.value = true;
256
- }
257
- function onClear() {
258
- if (isOpen.value)
259
- keyword.value = "";
260
- else
261
- select();
262
- }
263
- function isSelected(item) {
264
- return isEqual(item.value, localModel.value?.value);
265
- }
266
- watch(isOpen, (value) => {
267
- if (!value)
268
- keyword.value = "";
269
- }, { flush: "post" });
270
- onStartTyping(() => {
271
- if (isOpen.value && input.value && input.value !== document.activeElement)
272
- input.value.focus();
273
- });
274
- tryOnMounted(() => {
275
- if (vm?.proxy?.$el) {
276
- input.value = vm.proxy.$el.querySelector(".select__search");
201
+ options: {
202
+ type : Array as PropType<string[] | SelectItem[]>,
203
+ default: () => ([]),
204
+ },
205
+ placeholder: {
206
+ type : String,
207
+ default: '\u00A0',
208
+ },
209
+ emptyText: {
210
+ type : String,
211
+ default: 'No Data',
212
+ },
213
+ loadingText: {
214
+ type : String,
215
+ default: 'Loading...',
216
+ },
217
+ searchText: {
218
+ type : String,
219
+ default: 'Search...',
220
+ },
221
+ adapter: {
222
+ type : Object as PropType<Adapter>,
223
+ default: () => BasicAdapter,
224
+ },
225
+ disabled: {
226
+ type : Boolean,
227
+ default: false,
228
+ },
229
+ readonly: {
230
+ type : Boolean,
231
+ default: false,
232
+ },
233
+ error: {
234
+ type : Boolean,
235
+ default: false,
236
+ },
237
+ clearable: {
238
+ type : Boolean,
239
+ default: false,
240
+ },
241
+ clearLabel: {
242
+ type : String,
243
+ default: 'Clear',
244
+ },
245
+ size: {
246
+ type : String as PropType<SizeVariant>,
247
+ default: 'md',
248
+ },
249
+ sectionLabel: {
250
+ type : String,
251
+ default: undefined,
252
+ },
253
+ noCaret: {
254
+ type : Boolean,
255
+ default: false,
256
+ },
257
+ multiple: {
258
+ type : Boolean,
259
+ default: false,
260
+ },
261
+ displayLimit: {
262
+ type : Number,
263
+ default: undefined,
264
+ },
265
+ limitText: {
266
+ type : String,
267
+ default: undefined,
268
+ },
269
+ searchable: {
270
+ type : Boolean,
271
+ default: true,
272
+ },
273
+ menuSize: {
274
+ type : String as PropType<MenuSizeVariant>,
275
+ default: undefined,
276
+ },
277
+ menuClass: {
278
+ type: [
279
+ String,
280
+ Array,
281
+ Object,
282
+ ] as PropType<HTMLAttributes['class']>,
283
+ default: undefined,
284
+ },
285
+ divider: {
286
+ type : Boolean,
287
+ default: false,
288
+ },
289
+ /**
290
+ * For testing only, disable transition animation
291
+ */
292
+ noAnimation: {
293
+ type : Boolean,
294
+ default: false,
295
+ },
296
+ noCloseAfterSelect: {
297
+ type : Boolean,
298
+ default: false,
299
+ },
300
+ })
301
+
302
+ const emit = defineEmits<{
303
+ 'change': [unknown],
304
+ 'update:modelValue': [unknown],
305
+ 'update:selected': [unknown],
306
+ 'userInput': [unknown],
307
+ }>()
308
+
309
+ const input = ref<InstanceType<typeof pInput>>()
310
+ const dropdown = ref<InstanceType<typeof Dropdown>>()
311
+
312
+ const inputEl = computed(() => input.value?.input)
313
+ const menuEl = computed(() => dropdown.value?.menuBody)
314
+
315
+ const keyword = ref('')
316
+ const isOpen = ref(false)
317
+ const isLoading = useLoading({ elapsed: false })
318
+ const context = {
319
+ props,
320
+ keyword,
321
+ isOpen,
322
+ isLoading,
323
+ menuEl,
324
+ } as AdapterContext
325
+
326
+ const items = props.adapter.setup(context)
327
+ const localModel = ref<SelectItem | SelectItem[]>(
328
+ props.multiple
329
+ ? filterSelected(items.value, props.modelValue as unknown[])
330
+ : findSelected(items.value, props.modelValue),
331
+ )
332
+
333
+ const toggleOpen = () => {
334
+ if (!props.disabled && !props.readonly)
335
+ isOpen.value = !isOpen.value
336
+ }
337
+
338
+ const classNames = computed(() => {
339
+ const result: string[] = []
340
+
341
+ if (isOpen.value)
342
+ result.push('select--open')
343
+
344
+ if (props.disabled)
345
+ result.push('select--disabled')
346
+
347
+ if (props.readonly)
348
+ result.push('select--readonly')
349
+
350
+ if (props.multiple)
351
+ result.push('select--multiple')
352
+
353
+ return result
354
+ })
355
+
356
+ const hasValue = computed(() => {
357
+ return props.multiple
358
+ ? Array.isArray(localModel.value) && localModel.value.length > 0
359
+ : (localModel.value as SelectItem)?.value
360
+ })
361
+
362
+ const modelWatcher = watchPausable(() => props.modelValue, (value) => {
363
+ localModel.value = props.multiple
364
+ ? filterSelected(items.value, value as unknown[])
365
+ : findSelected(items.value, value)
366
+ })
367
+
368
+ function setValue (item?: SelectItem) {
369
+ let value: SelectItem | SelectItem[]
370
+
371
+ if (props.multiple) {
372
+ if (item) {
373
+ if (Array.isArray(localModel.value)) {
374
+ value = localModel.value.some((val) => isEqual(val.value, item.value))
375
+ ? localModel.value.filter((val) => !isEqual(val.value, item.value))
376
+ : [...localModel.value, item]
277
377
  }
278
- });
279
- return {
280
- classNames,
281
- isOpen,
282
- isLoading,
283
- search,
284
- items,
285
- toggleOpen,
286
- select,
287
- onFocus,
288
- onClear,
289
- isSelected
290
- };
378
+ } else
379
+ value = []
380
+ } else
381
+ value = item
382
+
383
+ modelWatcher.pause()
384
+
385
+ localModel.value = value
386
+
387
+ emit('change', value)
388
+ emit('update:selected', value)
389
+ emit('update:modelValue',
390
+ props.multiple
391
+ ? (value as SelectItem[]).map((i) => i.value)
392
+ : (value as SelectItem)?.value,
393
+ )
394
+
395
+ if (isOpen.value)
396
+ emit('userInput', value)
397
+
398
+ if (!props.noCloseAfterSelect)
399
+ isOpen.value = false
400
+
401
+ nextTick(() => {
402
+ modelWatcher.resume()
403
+ })
404
+ }
405
+
406
+ function onFocus () {
407
+ if (!props.disabled && !props.readonly)
408
+ isOpen.value = true
409
+ }
410
+
411
+ function onClear () {
412
+ setValue()
413
+ }
414
+
415
+ function isSelected (item: SelectItem) {
416
+ if (!localModel.value)
417
+ return false
418
+
419
+ if (props.multiple && Array.isArray(localModel.value))
420
+ return localModel.value.some((model) => isEqual(item.value, model.value))
421
+
422
+ return isEqual(item.value, (localModel.value as SelectItem).value)
423
+ }
424
+
425
+ function onOpened () {
426
+ inputEl.value?.focus()
427
+ }
428
+
429
+ function onClosed () {
430
+ keyword.value = ''
431
+ }
432
+
433
+ onStartTyping(() => {
434
+ if (isOpen.value && inputEl.value && inputEl.value !== document.activeElement) {
435
+ inputEl.value.select()
436
+ inputEl.value.focus()
291
437
  }
292
- });
438
+ })
293
439
  </script>
294
440
 
295
441
  <style lang="postcss">
296
442
  .select {
443
+ --p-select-min-width: 20ch;
444
+
445
+ &__activator {
446
+ @apply min-w-[var(--p-select-min-width)] items-center flex;
447
+ }
448
+
297
449
  &__search {
298
- @apply pr-8 truncate hover:cursor-default focus:cursor-text;
450
+ @apply pr-8 truncate hover:cursor-default focus:cursor-text rounded-b-none border-t-0 border-x-0;
299
451
 
300
- .state--error &,
301
- .select--error & {
302
- @apply border-danger-emphasis hover:border-danger-emphasis focus:ring-danger focus:border-danger-emphasis;
303
- @apply dark:border-dark-danger-emphasis hover:dark:border-dark-danger-emphasis focus:dark:ring-dark-danger focus:dark:border-dark-danger-emphasis;
452
+ &-icon {
453
+ @apply text-muted;
454
+ @apply dark:text-dark-muted;
304
455
  }
305
456
  }
306
457
 
@@ -342,5 +493,36 @@ export default defineComponent({
342
493
  @apply rotate-180;
343
494
  }
344
495
  }
496
+
497
+ &--multiple {
498
+ .select__option {
499
+ @apply flex-row-reverse;
500
+ }
501
+
502
+ .select__option-checked {
503
+ @apply w-5 h-5 inline-flex flex-shrink-0 border rounded-tn border-subtle items-center justify-center bg-default visible mr-4;
504
+ @apply dark:border-dark-subtle dark:bg-dark-default;
505
+
506
+ > svg {
507
+ @apply w-3 fill-default;
508
+ @apply dark:fill-dark-default;
509
+ }
510
+ }
511
+
512
+ .selected .select__option-checked {
513
+ @apply bg-info-emphasis border-info-emphasis;
514
+ @apply dark:bg-dark-info-emphasis dark:border-dark-info-emphasis;
515
+ }
516
+
517
+ .dropdown__item:disabled:not(.selected) .select__option-checked {
518
+ @apply bg-subtle border-subtle;
519
+ @apply dark:bg-dark-subtle dark:border-dark-subtle;
520
+
521
+ > svg {
522
+ @apply fill-subtle;
523
+ @apply dark:fill-dark-subtle;
524
+ }
525
+ }
526
+ }
345
527
  }
346
528
  </style>