@pequity/squirrel 7.1.2 → 7.1.3
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.
- package/dist/cjs/chunks/p-dropdown-select.js +75 -18
- package/dist/es/chunks/p-dropdown-select.js +76 -19
- package/dist/squirrel/components/p-dropdown-select/p-dropdown-select.vue.d.ts +15 -0
- package/package.json +1 -1
- package/squirrel/components/p-dropdown-select/p-dropdown-select.spec.js +107 -0
- package/squirrel/components/p-dropdown-select/p-dropdown-select.stories.js +21 -0
- package/squirrel/components/p-dropdown-select/p-dropdown-select.vue +52 -7
|
@@ -12,16 +12,28 @@ const lodashEs = require("lodash-es");
|
|
|
12
12
|
const _imports_0 = "data:image/svg+xml,%3csvg%20width='18'%20height='12'%20viewBox='0%200%2018%2012'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M16.1383%200.166992L6.30411%209.83366L1.69828%205.27533L0.526611%206.46033L5.71578%2011.597C5.87174%2011.7509%206.08205%2011.8372%206.3012%2011.8372C6.52034%2011.8372%206.73065%2011.7509%206.88661%2011.597L17.3033%201.35366L16.1383%200.166992Z'%20fill='%231A123B'%20/%3e%3c/svg%3e";
|
|
13
13
|
const _hoisted_1 = ["data-has-error"];
|
|
14
14
|
const _hoisted_2 = { class: "truncate text-left text-p-gray-40" };
|
|
15
|
-
const _hoisted_3 = {
|
|
15
|
+
const _hoisted_3 = {
|
|
16
|
+
key: 0,
|
|
17
|
+
class: "flex flex-wrap gap-1.5 pr-8"
|
|
18
|
+
};
|
|
16
19
|
const _hoisted_4 = {
|
|
20
|
+
class: "max-w-[200px] truncate",
|
|
21
|
+
"data-test": "pill-text"
|
|
22
|
+
};
|
|
23
|
+
const _hoisted_5 = ["onClick"];
|
|
24
|
+
const _hoisted_6 = {
|
|
25
|
+
key: 1,
|
|
26
|
+
class: "truncate text-left"
|
|
27
|
+
};
|
|
28
|
+
const _hoisted_7 = {
|
|
17
29
|
key: 0,
|
|
18
30
|
class: "mt-3 px-3"
|
|
19
31
|
};
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
32
|
+
const _hoisted_8 = { class: "text-p-purple-60" };
|
|
33
|
+
const _hoisted_9 = { class: "flex flex-row" };
|
|
34
|
+
const _hoisted_10 = ["onClick"];
|
|
35
|
+
const _hoisted_11 = ["title"];
|
|
36
|
+
const _hoisted_12 = {
|
|
25
37
|
key: 0,
|
|
26
38
|
class: "ml-auto fill-p-purple-60 pl-2",
|
|
27
39
|
src: _imports_0
|
|
@@ -167,6 +179,13 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
167
179
|
creatable: {
|
|
168
180
|
type: Boolean,
|
|
169
181
|
default: false
|
|
182
|
+
},
|
|
183
|
+
/**
|
|
184
|
+
* Shows selected items as pills in the button when multiple selection is enabled
|
|
185
|
+
*/
|
|
186
|
+
pills: {
|
|
187
|
+
type: Boolean,
|
|
188
|
+
default: false
|
|
170
189
|
}
|
|
171
190
|
},
|
|
172
191
|
emits: ["update:modelValue", "select", "create"],
|
|
@@ -184,9 +203,19 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
184
203
|
enableArrowNavigation: false
|
|
185
204
|
};
|
|
186
205
|
const CLEAR_BUTTON_SPACING = {
|
|
187
|
-
sm: "right-8",
|
|
188
|
-
md: "right-9",
|
|
189
|
-
lg: "right-10"
|
|
206
|
+
sm: "right-8 text-sm top-[0.3rem]",
|
|
207
|
+
md: "right-9 text-base top-[0.5rem]",
|
|
208
|
+
lg: "right-10 text-lg top-[0.7rem]"
|
|
209
|
+
};
|
|
210
|
+
const PILL_SIZE = {
|
|
211
|
+
sm: "text-sm",
|
|
212
|
+
md: "text-base",
|
|
213
|
+
lg: "text-lg"
|
|
214
|
+
};
|
|
215
|
+
const PILL_SELECT_SPACING = {
|
|
216
|
+
sm: "min-h-[2rem] py-1 bg-[position:right_1rem_top_0.7rem]",
|
|
217
|
+
md: "min-h-[2.5rem] py-2 bg-[position:right_1rem_top_0.9rem]",
|
|
218
|
+
lg: "min-h-[3rem] py-2 bg-[position:right_1rem_top_1.1rem]"
|
|
190
219
|
};
|
|
191
220
|
const width = vue.ref("auto");
|
|
192
221
|
const listItemStyle = vue.ref({ paddingTop: 0, paddingBottom: 0 });
|
|
@@ -304,15 +333,15 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
304
333
|
"p-select-list": "",
|
|
305
334
|
role: "listbox"
|
|
306
335
|
}), [
|
|
307
|
-
__props.multiple || __props.searchable ? (vue.openBlock(), vue.createElementBlock("div",
|
|
336
|
+
__props.multiple || __props.searchable ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_7, [
|
|
308
337
|
__props.multiple ? (vue.openBlock(), vue.createElementBlock("div", {
|
|
309
338
|
key: 0,
|
|
310
339
|
ref_key: "actionsContainer",
|
|
311
340
|
ref: actionsContainer,
|
|
312
341
|
class: "flex flex-row justify-between text-xs font-semibold text-primary"
|
|
313
342
|
}, [
|
|
314
|
-
vue.createElementVNode("p",
|
|
315
|
-
vue.createElementVNode("div",
|
|
343
|
+
vue.createElementVNode("p", _hoisted_8, vue.toDisplayString(vue.unref(computedItems).length) + " items", 1),
|
|
344
|
+
vue.createElementVNode("div", _hoisted_9, [
|
|
316
345
|
vue.unref(computedItems).length === vue.unref(internalItems).length ? (vue.openBlock(), vue.createElementBlock("a", {
|
|
317
346
|
key: 0,
|
|
318
347
|
class: vue.normalizeClass([
|
|
@@ -399,11 +428,11 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
399
428
|
class: vue.normalizeClass({ "bg-p-blue-20": index === 1 })
|
|
400
429
|
}, vue.toDisplayString(str), 3);
|
|
401
430
|
}), 128))
|
|
402
|
-
], 8,
|
|
431
|
+
], 8, _hoisted_11)
|
|
403
432
|
]),
|
|
404
|
-
vue.unref(isSelected)(vue.unref(getValue)(row.index)) ? (vue.openBlock(), vue.createElementBlock("img",
|
|
433
|
+
vue.unref(isSelected)(vue.unref(getValue)(row.index)) ? (vue.openBlock(), vue.createElementBlock("img", _hoisted_12)) : vue.createCommentVNode("", true)
|
|
405
434
|
], 2)
|
|
406
|
-
], 14,
|
|
435
|
+
], 14, _hoisted_10)), [
|
|
407
436
|
[_directive_close_popper, !__props.multiple]
|
|
408
437
|
])
|
|
409
438
|
], 4);
|
|
@@ -434,7 +463,13 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
434
463
|
vue.createElementVNode("button", vue.mergeProps(attrs.value, {
|
|
435
464
|
ref: "button",
|
|
436
465
|
type: "button",
|
|
437
|
-
class: [
|
|
466
|
+
class: [
|
|
467
|
+
"w-full",
|
|
468
|
+
vue.unref(selectClasses),
|
|
469
|
+
dropdownShow.value ? "border-primary" : "",
|
|
470
|
+
{ "box-border h-auto items-start": __props.multiple && __props.pills && vue.unref(selectedItems).length > 0 },
|
|
471
|
+
PILL_SELECT_SPACING[__props.size]
|
|
472
|
+
],
|
|
438
473
|
role: "button",
|
|
439
474
|
"aria-haspopup": "listbox",
|
|
440
475
|
onClick: _cache[1] || (_cache[1] = ($event) => dropdownShow.value = !dropdownShow.value)
|
|
@@ -445,11 +480,33 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
445
480
|
key: 1,
|
|
446
481
|
item: __props.multiple ? vue.unref(selectedItems) : vue.unref(selectedItems)[0]
|
|
447
482
|
}, () => [
|
|
448
|
-
|
|
483
|
+
__props.multiple && __props.pills ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3, [
|
|
484
|
+
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(selectedItems), (item) => {
|
|
485
|
+
return vue.openBlock(), vue.createElementBlock("div", {
|
|
486
|
+
key: String(item[__props.itemValue]),
|
|
487
|
+
class: vue.normalizeClass(["flex items-center gap-1 rounded bg-p-gray-10 px-2 text-p-gray-50", [PILL_SIZE[__props.size]]]),
|
|
488
|
+
"data-test": "selected-pill"
|
|
489
|
+
}, [
|
|
490
|
+
vue.createElementVNode("span", _hoisted_4, vue.toDisplayString(item[__props.itemText]), 1),
|
|
491
|
+
vue.createElementVNode("button", {
|
|
492
|
+
type: "button",
|
|
493
|
+
class: "flex items-center justify-center text-p-gray-40 hover:text-p-gray-60",
|
|
494
|
+
"aria-label": "Remove item",
|
|
495
|
+
"data-test": "pill-remove",
|
|
496
|
+
onClick: vue.withModifiers(($event) => vue.unref(select)($event, item[__props.itemValue]), ["stop"])
|
|
497
|
+
}, [
|
|
498
|
+
vue.createVNode(pIcon_vue_vue_type_script_setup_true_lang._sfc_main, {
|
|
499
|
+
icon: "fe:close",
|
|
500
|
+
class: "h-3.5 w-3.5"
|
|
501
|
+
})
|
|
502
|
+
], 8, _hoisted_5)
|
|
503
|
+
], 2);
|
|
504
|
+
}), 128))
|
|
505
|
+
])) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_6, vue.toDisplayString(__props.multiple ? vue.unref(selectedItems).length === selectableItemsCount.value ? "All options selected" : `${vue.unref(selectedItems).length} option${vue.unref(selectedItems).length > 1 ? "s" : ""} selected` : vue.unref(selectedItems)[0][__props.itemText]), 1))
|
|
449
506
|
]),
|
|
450
507
|
__props.clearable && vue.unref(selectedItems).length ? (vue.openBlock(), vue.createElementBlock("button", {
|
|
451
508
|
key: 2,
|
|
452
|
-
class: vue.normalizeClass(["absolute
|
|
509
|
+
class: vue.normalizeClass(["absolute right-9 flex h-6 items-center justify-center text-base text-p-gray-40 hover:text-p-gray-60", [CLEAR_BUTTON_SPACING[__props.size]]]),
|
|
453
510
|
"aria-label": "Clear selection",
|
|
454
511
|
onClick: _cache[0] || (_cache[0] = vue.withModifiers(
|
|
455
512
|
//@ts-ignore
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineComponent, ref, useAttrs, computed, watch, onMounted, onUnmounted, resolveDirective, createElementBlock, openBlock, normalizeStyle, normalizeClass, unref, createCommentVNode, createVNode, withDirectives, toDisplayString, mergeProps, withCtx, createElementVNode, renderSlot,
|
|
1
|
+
import { defineComponent, ref, useAttrs, computed, watch, onMounted, onUnmounted, resolveDirective, createElementBlock, openBlock, normalizeStyle, normalizeClass, unref, createCommentVNode, createVNode, withDirectives, toDisplayString, mergeProps, withCtx, createElementVNode, renderSlot, Fragment, renderList, withModifiers, isRef, createTextVNode, vShow } from "vue";
|
|
2
2
|
import PDropdown from "../p-dropdown.js";
|
|
3
3
|
import { _ as _sfc_main$1 } from "./p-icon.js";
|
|
4
4
|
import PInputSearch from "../p-input-search.js";
|
|
@@ -11,16 +11,28 @@ import { omit } from "lodash-es";
|
|
|
11
11
|
const _imports_0 = "data:image/svg+xml,%3csvg%20width='18'%20height='12'%20viewBox='0%200%2018%2012'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M16.1383%200.166992L6.30411%209.83366L1.69828%205.27533L0.526611%206.46033L5.71578%2011.597C5.87174%2011.7509%206.08205%2011.8372%206.3012%2011.8372C6.52034%2011.8372%206.73065%2011.7509%206.88661%2011.597L17.3033%201.35366L16.1383%200.166992Z'%20fill='%231A123B'%20/%3e%3c/svg%3e";
|
|
12
12
|
const _hoisted_1 = ["data-has-error"];
|
|
13
13
|
const _hoisted_2 = { class: "truncate text-left text-p-gray-40" };
|
|
14
|
-
const _hoisted_3 = {
|
|
14
|
+
const _hoisted_3 = {
|
|
15
|
+
key: 0,
|
|
16
|
+
class: "flex flex-wrap gap-1.5 pr-8"
|
|
17
|
+
};
|
|
15
18
|
const _hoisted_4 = {
|
|
19
|
+
class: "max-w-[200px] truncate",
|
|
20
|
+
"data-test": "pill-text"
|
|
21
|
+
};
|
|
22
|
+
const _hoisted_5 = ["onClick"];
|
|
23
|
+
const _hoisted_6 = {
|
|
24
|
+
key: 1,
|
|
25
|
+
class: "truncate text-left"
|
|
26
|
+
};
|
|
27
|
+
const _hoisted_7 = {
|
|
16
28
|
key: 0,
|
|
17
29
|
class: "mt-3 px-3"
|
|
18
30
|
};
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
31
|
+
const _hoisted_8 = { class: "text-p-purple-60" };
|
|
32
|
+
const _hoisted_9 = { class: "flex flex-row" };
|
|
33
|
+
const _hoisted_10 = ["onClick"];
|
|
34
|
+
const _hoisted_11 = ["title"];
|
|
35
|
+
const _hoisted_12 = {
|
|
24
36
|
key: 0,
|
|
25
37
|
class: "ml-auto fill-p-purple-60 pl-2",
|
|
26
38
|
src: _imports_0
|
|
@@ -166,6 +178,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
166
178
|
creatable: {
|
|
167
179
|
type: Boolean,
|
|
168
180
|
default: false
|
|
181
|
+
},
|
|
182
|
+
/**
|
|
183
|
+
* Shows selected items as pills in the button when multiple selection is enabled
|
|
184
|
+
*/
|
|
185
|
+
pills: {
|
|
186
|
+
type: Boolean,
|
|
187
|
+
default: false
|
|
169
188
|
}
|
|
170
189
|
},
|
|
171
190
|
emits: ["update:modelValue", "select", "create"],
|
|
@@ -183,9 +202,19 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
183
202
|
enableArrowNavigation: false
|
|
184
203
|
};
|
|
185
204
|
const CLEAR_BUTTON_SPACING = {
|
|
186
|
-
sm: "right-8",
|
|
187
|
-
md: "right-9",
|
|
188
|
-
lg: "right-10"
|
|
205
|
+
sm: "right-8 text-sm top-[0.3rem]",
|
|
206
|
+
md: "right-9 text-base top-[0.5rem]",
|
|
207
|
+
lg: "right-10 text-lg top-[0.7rem]"
|
|
208
|
+
};
|
|
209
|
+
const PILL_SIZE = {
|
|
210
|
+
sm: "text-sm",
|
|
211
|
+
md: "text-base",
|
|
212
|
+
lg: "text-lg"
|
|
213
|
+
};
|
|
214
|
+
const PILL_SELECT_SPACING = {
|
|
215
|
+
sm: "min-h-[2rem] py-1 bg-[position:right_1rem_top_0.7rem]",
|
|
216
|
+
md: "min-h-[2.5rem] py-2 bg-[position:right_1rem_top_0.9rem]",
|
|
217
|
+
lg: "min-h-[3rem] py-2 bg-[position:right_1rem_top_1.1rem]"
|
|
189
218
|
};
|
|
190
219
|
const width = ref("auto");
|
|
191
220
|
const listItemStyle = ref({ paddingTop: 0, paddingBottom: 0 });
|
|
@@ -303,15 +332,15 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
303
332
|
"p-select-list": "",
|
|
304
333
|
role: "listbox"
|
|
305
334
|
}), [
|
|
306
|
-
__props.multiple || __props.searchable ? (openBlock(), createElementBlock("div",
|
|
335
|
+
__props.multiple || __props.searchable ? (openBlock(), createElementBlock("div", _hoisted_7, [
|
|
307
336
|
__props.multiple ? (openBlock(), createElementBlock("div", {
|
|
308
337
|
key: 0,
|
|
309
338
|
ref_key: "actionsContainer",
|
|
310
339
|
ref: actionsContainer,
|
|
311
340
|
class: "flex flex-row justify-between text-xs font-semibold text-primary"
|
|
312
341
|
}, [
|
|
313
|
-
createElementVNode("p",
|
|
314
|
-
createElementVNode("div",
|
|
342
|
+
createElementVNode("p", _hoisted_8, toDisplayString(unref(computedItems).length) + " items", 1),
|
|
343
|
+
createElementVNode("div", _hoisted_9, [
|
|
315
344
|
unref(computedItems).length === unref(internalItems).length ? (openBlock(), createElementBlock("a", {
|
|
316
345
|
key: 0,
|
|
317
346
|
class: normalizeClass([
|
|
@@ -398,11 +427,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
398
427
|
class: normalizeClass({ "bg-p-blue-20": index === 1 })
|
|
399
428
|
}, toDisplayString(str), 3);
|
|
400
429
|
}), 128))
|
|
401
|
-
], 8,
|
|
430
|
+
], 8, _hoisted_11)
|
|
402
431
|
]),
|
|
403
|
-
unref(isSelected)(unref(getValue)(row.index)) ? (openBlock(), createElementBlock("img",
|
|
432
|
+
unref(isSelected)(unref(getValue)(row.index)) ? (openBlock(), createElementBlock("img", _hoisted_12)) : createCommentVNode("", true)
|
|
404
433
|
], 2)
|
|
405
|
-
], 14,
|
|
434
|
+
], 14, _hoisted_10)), [
|
|
406
435
|
[_directive_close_popper, !__props.multiple]
|
|
407
436
|
])
|
|
408
437
|
], 4);
|
|
@@ -433,7 +462,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
433
462
|
createElementVNode("button", mergeProps(attrs.value, {
|
|
434
463
|
ref: "button",
|
|
435
464
|
type: "button",
|
|
436
|
-
class: [
|
|
465
|
+
class: [
|
|
466
|
+
"w-full",
|
|
467
|
+
unref(selectClasses),
|
|
468
|
+
dropdownShow.value ? "border-primary" : "",
|
|
469
|
+
{ "box-border h-auto items-start": __props.multiple && __props.pills && unref(selectedItems).length > 0 },
|
|
470
|
+
PILL_SELECT_SPACING[__props.size]
|
|
471
|
+
],
|
|
437
472
|
role: "button",
|
|
438
473
|
"aria-haspopup": "listbox",
|
|
439
474
|
onClick: _cache[1] || (_cache[1] = ($event) => dropdownShow.value = !dropdownShow.value)
|
|
@@ -444,11 +479,33 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
444
479
|
key: 1,
|
|
445
480
|
item: __props.multiple ? unref(selectedItems) : unref(selectedItems)[0]
|
|
446
481
|
}, () => [
|
|
447
|
-
|
|
482
|
+
__props.multiple && __props.pills ? (openBlock(), createElementBlock("div", _hoisted_3, [
|
|
483
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(selectedItems), (item) => {
|
|
484
|
+
return openBlock(), createElementBlock("div", {
|
|
485
|
+
key: String(item[__props.itemValue]),
|
|
486
|
+
class: normalizeClass(["flex items-center gap-1 rounded bg-p-gray-10 px-2 text-p-gray-50", [PILL_SIZE[__props.size]]]),
|
|
487
|
+
"data-test": "selected-pill"
|
|
488
|
+
}, [
|
|
489
|
+
createElementVNode("span", _hoisted_4, toDisplayString(item[__props.itemText]), 1),
|
|
490
|
+
createElementVNode("button", {
|
|
491
|
+
type: "button",
|
|
492
|
+
class: "flex items-center justify-center text-p-gray-40 hover:text-p-gray-60",
|
|
493
|
+
"aria-label": "Remove item",
|
|
494
|
+
"data-test": "pill-remove",
|
|
495
|
+
onClick: withModifiers(($event) => unref(select)($event, item[__props.itemValue]), ["stop"])
|
|
496
|
+
}, [
|
|
497
|
+
createVNode(_sfc_main$1, {
|
|
498
|
+
icon: "fe:close",
|
|
499
|
+
class: "h-3.5 w-3.5"
|
|
500
|
+
})
|
|
501
|
+
], 8, _hoisted_5)
|
|
502
|
+
], 2);
|
|
503
|
+
}), 128))
|
|
504
|
+
])) : (openBlock(), createElementBlock("div", _hoisted_6, toDisplayString(__props.multiple ? unref(selectedItems).length === selectableItemsCount.value ? "All options selected" : `${unref(selectedItems).length} option${unref(selectedItems).length > 1 ? "s" : ""} selected` : unref(selectedItems)[0][__props.itemText]), 1))
|
|
448
505
|
]),
|
|
449
506
|
__props.clearable && unref(selectedItems).length ? (openBlock(), createElementBlock("button", {
|
|
450
507
|
key: 2,
|
|
451
|
-
class: normalizeClass(["absolute
|
|
508
|
+
class: normalizeClass(["absolute right-9 flex h-6 items-center justify-center text-base text-p-gray-40 hover:text-p-gray-60", [CLEAR_BUTTON_SPACING[__props.size]]]),
|
|
452
509
|
"aria-label": "Clear selection",
|
|
453
510
|
onClick: _cache[0] || (_cache[0] = withModifiers(
|
|
454
511
|
//@ts-ignore
|
|
@@ -148,6 +148,13 @@ declare const __VLS_component: import("vue").DefineComponent<import("vue").Extra
|
|
|
148
148
|
type: BooleanConstructor;
|
|
149
149
|
default: boolean;
|
|
150
150
|
};
|
|
151
|
+
/**
|
|
152
|
+
* Shows selected items as pills in the button when multiple selection is enabled
|
|
153
|
+
*/
|
|
154
|
+
pills: {
|
|
155
|
+
type: BooleanConstructor;
|
|
156
|
+
default: boolean;
|
|
157
|
+
};
|
|
151
158
|
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
152
159
|
select: (...args: any[]) => void;
|
|
153
160
|
"update:modelValue": (...args: any[]) => void;
|
|
@@ -286,6 +293,13 @@ declare const __VLS_component: import("vue").DefineComponent<import("vue").Extra
|
|
|
286
293
|
type: BooleanConstructor;
|
|
287
294
|
default: boolean;
|
|
288
295
|
};
|
|
296
|
+
/**
|
|
297
|
+
* Shows selected items as pills in the button when multiple selection is enabled
|
|
298
|
+
*/
|
|
299
|
+
pills: {
|
|
300
|
+
type: BooleanConstructor;
|
|
301
|
+
default: boolean;
|
|
302
|
+
};
|
|
289
303
|
}>> & Readonly<{
|
|
290
304
|
onSelect?: ((...args: any[]) => any) | undefined;
|
|
291
305
|
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
|
@@ -314,6 +328,7 @@ declare const __VLS_component: import("vue").DefineComponent<import("vue").Extra
|
|
|
314
328
|
selectedTopShown: boolean;
|
|
315
329
|
disabledBy: string;
|
|
316
330
|
creatable: boolean;
|
|
331
|
+
pills: boolean;
|
|
317
332
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
318
333
|
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
319
334
|
export default _default;
|
package/package.json
CHANGED
|
@@ -857,4 +857,111 @@ describe('PDropdownSelect.vue', () => {
|
|
|
857
857
|
cleanup(wrapper);
|
|
858
858
|
});
|
|
859
859
|
});
|
|
860
|
+
|
|
861
|
+
describe('pills functionality', () => {
|
|
862
|
+
it('renders selected items as pills when pills prop is true and multiple is true', async () => {
|
|
863
|
+
useVirtualizer.mockImplementation(() => createMockedVirtualizer(20));
|
|
864
|
+
|
|
865
|
+
const wrapper = createWrapper({ selected: [4, 5] }, { multiple: true, pills: true });
|
|
866
|
+
|
|
867
|
+
const button = wrapper.find('button');
|
|
868
|
+
const pillsContainer = button.find('div.flex.flex-wrap.gap-1\\.5');
|
|
869
|
+
expect(pillsContainer.exists()).toBe(true);
|
|
870
|
+
|
|
871
|
+
const pills = wrapper.findAll('[data-test="selected-pill"]');
|
|
872
|
+
expect(pills.length).toBe(2);
|
|
873
|
+
expect(pills[0].find('[data-test="pill-text"]').text()).toBe('d39ad899-709e-4ed1-b48f-3ef160a617b1');
|
|
874
|
+
expect(pills[1].find('[data-test="pill-text"]').text()).toBe('42e1aeff-2147-485d-9265-fd79abc897b5');
|
|
875
|
+
|
|
876
|
+
cleanup(wrapper);
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
it('does not render pills when pills prop is false', async () => {
|
|
880
|
+
useVirtualizer.mockImplementation(() => createMockedVirtualizer(20));
|
|
881
|
+
|
|
882
|
+
const wrapper = createWrapper({ selected: [4, 5] }, { multiple: true, pills: false });
|
|
883
|
+
|
|
884
|
+
const button = wrapper.find('button');
|
|
885
|
+
const pills = wrapper.findAll('[data-test="selected-pill"]');
|
|
886
|
+
expect(pills.length).toBe(0);
|
|
887
|
+
expect(button.text()).toBe('2 options selected');
|
|
888
|
+
|
|
889
|
+
cleanup(wrapper);
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
it('does not render pills when multiple is false, regardless of pills prop', async () => {
|
|
893
|
+
useVirtualizer.mockImplementation(() => createMockedVirtualizer(20));
|
|
894
|
+
|
|
895
|
+
const wrapper = createWrapper({ selected: 4 }, { multiple: false, pills: true });
|
|
896
|
+
|
|
897
|
+
const button = wrapper.find('button');
|
|
898
|
+
const pills = wrapper.findAll('[data-test="selected-pill"]');
|
|
899
|
+
expect(pills.length).toBe(0);
|
|
900
|
+
expect(button.text()).toBe('d39ad899-709e-4ed1-b48f-3ef160a617b1');
|
|
901
|
+
|
|
902
|
+
cleanup(wrapper);
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
it('allows removing individual items by clicking the pill close button', async () => {
|
|
906
|
+
useVirtualizer.mockImplementation(() => createMockedVirtualizer(20));
|
|
907
|
+
|
|
908
|
+
const wrapper = createWrapper({ selected: [4, 5] }, { multiple: true, pills: true });
|
|
909
|
+
|
|
910
|
+
const pills = wrapper.findAll('[data-test="selected-pill"]');
|
|
911
|
+
const closeButton = pills[0].find('[data-test="pill-remove"]');
|
|
912
|
+
await closeButton.trigger('click');
|
|
913
|
+
|
|
914
|
+
expect(wrapper.vm.$data.selected).toEqual([5]);
|
|
915
|
+
expect(wrapper.findAll('[data-test="selected-pill"]').length).toBe(1);
|
|
916
|
+
|
|
917
|
+
cleanup(wrapper);
|
|
918
|
+
});
|
|
919
|
+
|
|
920
|
+
it('shows pills with correct layout', async () => {
|
|
921
|
+
useVirtualizer.mockImplementation(() => createMockedVirtualizer(20));
|
|
922
|
+
|
|
923
|
+
const wrapper = createWrapper({ selected: [4, 5] }, { multiple: true, pills: true });
|
|
924
|
+
|
|
925
|
+
const button = wrapper.find('button');
|
|
926
|
+
expect(button.classes()).toContain('h-auto');
|
|
927
|
+
expect(button.classes()).toContain('min-h-[2.5rem]');
|
|
928
|
+
expect(button.classes()).toContain('items-start');
|
|
929
|
+
expect(button.classes()).toContain('py-2');
|
|
930
|
+
|
|
931
|
+
const pillsContainer = wrapper.find('div.flex.flex-wrap.gap-1\\.5');
|
|
932
|
+
expect(pillsContainer.exists()).toBe(true);
|
|
933
|
+
|
|
934
|
+
cleanup(wrapper);
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
it('truncates long text in pills', async () => {
|
|
938
|
+
useVirtualizer.mockImplementation(() => createMockedVirtualizer(20));
|
|
939
|
+
|
|
940
|
+
const wrapper = createWrapper({ selected: [4, 5] }, { multiple: true, pills: true });
|
|
941
|
+
|
|
942
|
+
const pillText = wrapper.find('[data-test="pill-text"]');
|
|
943
|
+
expect(pillText.classes()).toContain('max-w-[200px]');
|
|
944
|
+
expect(pillText.classes()).toContain('truncate');
|
|
945
|
+
|
|
946
|
+
cleanup(wrapper);
|
|
947
|
+
});
|
|
948
|
+
|
|
949
|
+
it('maintains pills after dropdown interaction', async () => {
|
|
950
|
+
useVirtualizer.mockImplementation(() => createMockedVirtualizer(20));
|
|
951
|
+
|
|
952
|
+
const wrapper = createWrapper({ selected: [4, 5] }, { multiple: true, pills: true });
|
|
953
|
+
|
|
954
|
+
const button = wrapper.find('button');
|
|
955
|
+
await button.trigger('click');
|
|
956
|
+
|
|
957
|
+
const item = wrapper.findAll('[p-select-list-option-item]')[6];
|
|
958
|
+
await item.trigger('click');
|
|
959
|
+
|
|
960
|
+
const pills = wrapper.findAll('[data-test="selected-pill"]');
|
|
961
|
+
expect(pills.length).toBe(3);
|
|
962
|
+
expect(wrapper.vm.$data.selected).toEqual([4, 5, 7]);
|
|
963
|
+
|
|
964
|
+
cleanup(wrapper);
|
|
965
|
+
});
|
|
966
|
+
});
|
|
860
967
|
});
|
|
@@ -280,6 +280,27 @@ export const MultipleSearchable = {
|
|
|
280
280
|
},
|
|
281
281
|
};
|
|
282
282
|
|
|
283
|
+
export const MultipleWithPills = {
|
|
284
|
+
render: createRenderFunction({ selectedVal: [33, 34, 36] }),
|
|
285
|
+
parameters: {
|
|
286
|
+
docs: {
|
|
287
|
+
description: {
|
|
288
|
+
story: 'Multiple selection with selected items displayed as pills in the button',
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
args: {
|
|
293
|
+
...Default.args,
|
|
294
|
+
label: 'Multiple with pills',
|
|
295
|
+
items: items4,
|
|
296
|
+
multiple: true,
|
|
297
|
+
searchable: true,
|
|
298
|
+
pills: true,
|
|
299
|
+
placeholder: 'Select an item from the list',
|
|
300
|
+
placeholderSearch: 'Search an item...',
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
|
|
283
304
|
export const SelectedOnTop = {
|
|
284
305
|
render: createRenderFunction({ selectedVal: [33, 34, 36] }),
|
|
285
306
|
args: {
|
|
@@ -19,7 +19,13 @@
|
|
|
19
19
|
v-bind="attrs"
|
|
20
20
|
ref="button"
|
|
21
21
|
type="button"
|
|
22
|
-
:class="[
|
|
22
|
+
:class="[
|
|
23
|
+
'w-full',
|
|
24
|
+
selectClasses,
|
|
25
|
+
dropdownShow ? 'border-primary' : '',
|
|
26
|
+
{ 'box-border h-auto items-start': multiple && pills && selectedItems.length > 0 },
|
|
27
|
+
PILL_SELECT_SPACING[size],
|
|
28
|
+
]"
|
|
23
29
|
role="button"
|
|
24
30
|
aria-haspopup="listbox"
|
|
25
31
|
@click="dropdownShow = !dropdownShow"
|
|
@@ -30,7 +36,27 @@
|
|
|
30
36
|
</div>
|
|
31
37
|
</slot>
|
|
32
38
|
<slot v-else name="selected-item" :item="multiple ? selectedItems : selectedItems[0]">
|
|
33
|
-
<div class="
|
|
39
|
+
<div v-if="multiple && pills" class="flex flex-wrap gap-1.5 pr-8">
|
|
40
|
+
<div
|
|
41
|
+
v-for="item in selectedItems"
|
|
42
|
+
:key="String(item[itemValue])"
|
|
43
|
+
class="flex items-center gap-1 rounded bg-p-gray-10 px-2 text-p-gray-50"
|
|
44
|
+
:class="[PILL_SIZE[size]]"
|
|
45
|
+
data-test="selected-pill"
|
|
46
|
+
>
|
|
47
|
+
<span class="max-w-[200px] truncate" data-test="pill-text">{{ item[itemText] }}</span>
|
|
48
|
+
<button
|
|
49
|
+
type="button"
|
|
50
|
+
class="flex items-center justify-center text-p-gray-40 hover:text-p-gray-60"
|
|
51
|
+
aria-label="Remove item"
|
|
52
|
+
data-test="pill-remove"
|
|
53
|
+
@click.stop="select($event, item[itemValue])"
|
|
54
|
+
>
|
|
55
|
+
<PIcon icon="fe:close" class="h-3.5 w-3.5" />
|
|
56
|
+
</button>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
<div v-else class="truncate text-left">
|
|
34
60
|
{{
|
|
35
61
|
multiple
|
|
36
62
|
? selectedItems.length === selectableItemsCount
|
|
@@ -43,8 +69,8 @@
|
|
|
43
69
|
<!-- Clear selection button -->
|
|
44
70
|
<button
|
|
45
71
|
v-if="clearable && selectedItems.length"
|
|
46
|
-
class="absolute
|
|
47
|
-
:class="[
|
|
72
|
+
class="absolute right-9 flex h-6 items-center justify-center text-base text-p-gray-40 hover:text-p-gray-60"
|
|
73
|
+
:class="[CLEAR_BUTTON_SPACING[size]]"
|
|
48
74
|
aria-label="Clear selection"
|
|
49
75
|
@click.stop="clearAll"
|
|
50
76
|
>
|
|
@@ -349,6 +375,13 @@ const props = defineProps({
|
|
|
349
375
|
type: Boolean,
|
|
350
376
|
default: false,
|
|
351
377
|
},
|
|
378
|
+
/**
|
|
379
|
+
* Shows selected items as pills in the button when multiple selection is enabled
|
|
380
|
+
*/
|
|
381
|
+
pills: {
|
|
382
|
+
type: Boolean,
|
|
383
|
+
default: false,
|
|
384
|
+
},
|
|
352
385
|
});
|
|
353
386
|
|
|
354
387
|
// Async helpers
|
|
@@ -366,9 +399,21 @@ const P_DROPDOWN_DEFAULTS = {
|
|
|
366
399
|
};
|
|
367
400
|
|
|
368
401
|
const CLEAR_BUTTON_SPACING = {
|
|
369
|
-
sm: 'right-8',
|
|
370
|
-
md: 'right-9',
|
|
371
|
-
lg: 'right-10',
|
|
402
|
+
sm: 'right-8 text-sm top-[0.3rem]',
|
|
403
|
+
md: 'right-9 text-base top-[0.5rem]',
|
|
404
|
+
lg: 'right-10 text-lg top-[0.7rem]',
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
const PILL_SIZE = {
|
|
408
|
+
sm: 'text-sm',
|
|
409
|
+
md: 'text-base',
|
|
410
|
+
lg: 'text-lg',
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
const PILL_SELECT_SPACING = {
|
|
414
|
+
sm: 'min-h-[2rem] py-1 bg-[position:right_1rem_top_0.7rem]',
|
|
415
|
+
md: 'min-h-[2.5rem] py-2 bg-[position:right_1rem_top_0.9rem]',
|
|
416
|
+
lg: 'min-h-[3rem] py-2 bg-[position:right_1rem_top_1.1rem]',
|
|
372
417
|
};
|
|
373
418
|
|
|
374
419
|
const width = ref('auto');
|