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