@pequity/squirrel 6.0.6 → 6.0.7

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/README.md CHANGED
@@ -76,7 +76,7 @@ Import and use the components you need in your Vue 3 project:
76
76
  </template>
77
77
 
78
78
  <script setup lang="ts">
79
- import { PBtn, PRingLoader } from '@pequity/squirrel';
79
+ import { PBtn } from '@pequity/squirrel';
80
80
  </script>
81
81
  ```
82
82
 
@@ -111,7 +111,7 @@ Then, in your consumer project's `.env.local` file, add an `VUE_APP_SQUIRREL_LOC
111
111
 
112
112
  Finally, in your project's `vite.config` file, add the following:
113
113
 
114
- > Heads up! The `vite.config.mts` file of the `pequity/frontendv2` already includes the following configuration.
114
+ > Heads up! The `vite.config.ts` file of the `pequity/frontendv2` already includes the following configuration.
115
115
 
116
116
  ```js
117
117
  import { defineConfig, searchForWorkspaceRoot } from 'vite';
@@ -420,7 +420,7 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
420
420
  }, () => [
421
421
  vue.createElementVNode("div", _hoisted_3, vue.toDisplayString(__props.multiple && vue.unref(selectedItems).length > 1 ? `${vue.unref(selectedItems).length} option${vue.unref(selectedItems).length > 1 ? "s" : ""} selected` : vue.unref(selectedItems)[0][__props.itemText]), 1)
422
422
  ]),
423
- __props.clearable && vue.unref(internalValue).length ? (vue.openBlock(), vue.createElementBlock("button", {
423
+ __props.clearable && vue.unref(selectedItems).length ? (vue.openBlock(), vue.createElementBlock("button", {
424
424
  key: 2,
425
425
  class: vue.normalizeClass(["absolute top-1/2 flex -translate-y-1/2 items-center justify-center text-p-gray-40 hover:text-p-gray-60", [vue.unref(pSelectList.SIZES)[__props.size], CLEAR_BUTTON_SPACING[__props.size]]]),
426
426
  "aria-label": "Clear selection",
@@ -217,12 +217,17 @@ const useSelectList = (props, inputSearch, virtualizerRef, emit) => {
217
217
  emit("update:modelValue", toArrOfObjIfNeeded(toEmit));
218
218
  };
219
219
  const clearAll = () => {
220
- if (!props.multiple) return;
221
220
  search.value = "";
222
- const disabledItemsValues = internalItems.value.filter((item) => isDisabled(item)).map((item) => item[props.itemValue]);
223
- const selectedItemsValues = internalValue.value;
224
- const selectedDisabledItems = lodashEs.intersection(disabledItemsValues, selectedItemsValues);
225
- emit("update:modelValue", toArrOfObjIfNeeded(selectedDisabledItems));
221
+ if (props.multiple) {
222
+ const disabledItemsValues = internalItems.value.filter((item) => isDisabled(item)).map((item) => item[props.itemValue]);
223
+ const selectedItemsValues = internalValue.value;
224
+ const selectedDisabledItems = lodashEs.intersection(disabledItemsValues, selectedItemsValues);
225
+ emit("update:modelValue", toArrOfObjIfNeeded(selectedDisabledItems));
226
+ } else {
227
+ if (!isDisabled(selectedItems.value[0])) {
228
+ emit("update:modelValue", null);
229
+ }
230
+ }
226
231
  };
227
232
  vue.watch(
228
233
  () => props.items,
@@ -419,7 +419,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
419
419
  }, () => [
420
420
  createElementVNode("div", _hoisted_3, toDisplayString(__props.multiple && unref(selectedItems).length > 1 ? `${unref(selectedItems).length} option${unref(selectedItems).length > 1 ? "s" : ""} selected` : unref(selectedItems)[0][__props.itemText]), 1)
421
421
  ]),
422
- __props.clearable && unref(internalValue).length ? (openBlock(), createElementBlock("button", {
422
+ __props.clearable && unref(selectedItems).length ? (openBlock(), createElementBlock("button", {
423
423
  key: 2,
424
424
  class: normalizeClass(["absolute top-1/2 flex -translate-y-1/2 items-center justify-center text-p-gray-40 hover:text-p-gray-60", [unref(SIZES)[__props.size], CLEAR_BUTTON_SPACING[__props.size]]]),
425
425
  "aria-label": "Clear selection",
@@ -215,12 +215,17 @@ const useSelectList = (props, inputSearch, virtualizerRef, emit) => {
215
215
  emit("update:modelValue", toArrOfObjIfNeeded(toEmit));
216
216
  };
217
217
  const clearAll = () => {
218
- if (!props.multiple) return;
219
218
  search.value = "";
220
- const disabledItemsValues = internalItems.value.filter((item) => isDisabled(item)).map((item) => item[props.itemValue]);
221
- const selectedItemsValues = internalValue.value;
222
- const selectedDisabledItems = intersection(disabledItemsValues, selectedItemsValues);
223
- emit("update:modelValue", toArrOfObjIfNeeded(selectedDisabledItems));
219
+ if (props.multiple) {
220
+ const disabledItemsValues = internalItems.value.filter((item) => isDisabled(item)).map((item) => item[props.itemValue]);
221
+ const selectedItemsValues = internalValue.value;
222
+ const selectedDisabledItems = intersection(disabledItemsValues, selectedItemsValues);
223
+ emit("update:modelValue", toArrOfObjIfNeeded(selectedDisabledItems));
224
+ } else {
225
+ if (!isDisabled(selectedItems.value[0])) {
226
+ emit("update:modelValue", null);
227
+ }
228
+ }
224
229
  };
225
230
  watch(
226
231
  () => props.items,
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@pequity/squirrel",
3
3
  "description": "Squirrel component library",
4
- "version": "6.0.6",
5
- "packageManager": "pnpm@9.15.3",
4
+ "version": "6.0.7",
5
+ "packageManager": "pnpm@9.15.4",
6
6
  "type": "module",
7
7
  "scripts": {
8
8
  "preinstall": "npx only-allow pnpm",
@@ -53,54 +53,54 @@
53
53
  "@playwright/test": "^1.49.1",
54
54
  "@semantic-release/changelog": "^6.0.3",
55
55
  "@semantic-release/git": "^10.0.1",
56
- "@storybook/addon-a11y": "^8.4.7",
57
- "@storybook/addon-actions": "^8.4.7",
58
- "@storybook/addon-essentials": "^8.4.7",
59
- "@storybook/addon-interactions": "^8.4.7",
60
- "@storybook/addon-links": "^8.4.7",
61
- "@storybook/blocks": "^8.4.7",
62
- "@storybook/manager-api": "^8.4.7",
63
- "@storybook/test": "^8.4.7",
56
+ "@storybook/addon-a11y": "^8.5.0",
57
+ "@storybook/addon-actions": "^8.5.0",
58
+ "@storybook/addon-essentials": "^8.5.0",
59
+ "@storybook/addon-interactions": "^8.5.0",
60
+ "@storybook/addon-links": "^8.5.0",
61
+ "@storybook/blocks": "^8.5.0",
62
+ "@storybook/manager-api": "^8.5.0",
63
+ "@storybook/test": "^8.5.0",
64
64
  "@storybook/test-runner": "^0.21.0",
65
- "@storybook/theming": "^8.4.7",
66
- "@storybook/vue3": "^8.4.7",
67
- "@storybook/vue3-vite": "^8.4.7",
65
+ "@storybook/theming": "^8.5.0",
66
+ "@storybook/vue3": "^8.5.0",
67
+ "@storybook/vue3-vite": "^8.5.0",
68
68
  "@tanstack/vue-virtual": "3.11.2",
69
69
  "@types/jsdom": "^21.1.7",
70
70
  "@types/lodash-es": "^4.17.12",
71
- "@types/node": "^22.10.5",
71
+ "@types/node": "^22.10.7",
72
72
  "@vitejs/plugin-vue": "^5.2.1",
73
- "@vitest/coverage-v8": "^2.1.8",
73
+ "@vitest/coverage-v8": "^3.0.3",
74
74
  "@vue/compiler-sfc": "3.5.13",
75
75
  "@vue/test-utils": "^2.4.6",
76
76
  "@vuepic/vue-datepicker": "11.0.1",
77
77
  "autoprefixer": "^10.4.20",
78
78
  "dayjs": "1.11.13",
79
- "eslint": "^9.17.0",
79
+ "eslint": "^9.18.0",
80
80
  "eslint-plugin-storybook": "^0.11.2",
81
81
  "floating-vue": "5.2.2",
82
82
  "glob": "^11.0.1",
83
83
  "husky": "^9.1.7",
84
84
  "iconify-icon": "^2.3.0",
85
85
  "jsdom": "^26.0.0",
86
- "lint-staged": "^15.3.0",
86
+ "lint-staged": "^15.4.1",
87
87
  "lodash-es": "4.17.21",
88
88
  "make-coverage-badge": "^1.2.0",
89
- "postcss": "^8.4.49",
89
+ "postcss": "^8.5.1",
90
90
  "prettier": "^3.4.2",
91
- "prettier-plugin-tailwindcss": "^0.6.9",
91
+ "prettier-plugin-tailwindcss": "^0.6.10",
92
92
  "resolve-tspaths": "^0.8.23",
93
93
  "rimraf": "^6.0.1",
94
- "sass": "^1.83.1",
94
+ "sass": "^1.83.4",
95
95
  "semantic-release": "^24.2.1",
96
- "storybook": "^8.4.7",
96
+ "storybook": "^8.5.0",
97
97
  "svgo": "^3.3.2",
98
98
  "tailwindcss": "^3.4.17",
99
99
  "typescript": "5.7.3",
100
- "vite": "^6.0.7",
101
- "vitest": "^2.1.8",
100
+ "vite": "^6.0.11",
101
+ "vitest": "^3.0.3",
102
102
  "vue": "3.5.13",
103
- "vue-currency-input": "3.1.0",
103
+ "vue-currency-input": "3.2.1",
104
104
  "vue-router": "4.5.0",
105
105
  "vue-toastification": "2.0.0-rc.5",
106
106
  "vue-tsc": "2.2.0"
@@ -653,6 +653,17 @@ describe('PDropdownSelect.vue', () => {
653
653
  cleanup(wrapper);
654
654
  });
655
655
 
656
+ it('does not render clear button when there is no value selected', async () => {
657
+ useVirtualizer.mockImplementation(() => createMockedVirtualizer(20));
658
+
659
+ const wrapper = createWrapper({ selected: null }, { clearable: true });
660
+
661
+ const clearButton = wrapper.find('button[aria-label="Clear selection"]');
662
+ expect(clearButton.exists()).toBe(false);
663
+
664
+ cleanup(wrapper);
665
+ });
666
+
656
667
  it('clears multiple selections when clearable is true', async () => {
657
668
  useVirtualizer.mockImplementation(() => createMockedVirtualizer(20));
658
669
 
@@ -666,4 +677,40 @@ describe('PDropdownSelect.vue', () => {
666
677
 
667
678
  cleanup(wrapper);
668
679
  });
680
+
681
+ it('clears a single selection select when clearable is true', async () => {
682
+ useVirtualizer.mockImplementation(() => createMockedVirtualizer(10));
683
+
684
+ const items = cloneDeep(filterListItems).slice(0, 10);
685
+ items[0].disabled = false;
686
+ const wrapper = createWrapper({ selected: 1, items }, { multiple: false, clearable: true });
687
+
688
+ expect(wrapper.vm.$data.selected).toEqual(1);
689
+
690
+ const clearButton = wrapper.find('button[aria-label="Clear selection"]');
691
+ expect(clearButton.exists()).toBe(true);
692
+
693
+ await clearButton.trigger('click');
694
+ expect(wrapper.vm.$data.selected).toEqual(null);
695
+
696
+ cleanup(wrapper);
697
+ });
698
+
699
+ it('does not clear a single selection select when the item is disabled', async () => {
700
+ useVirtualizer.mockImplementation(() => createMockedVirtualizer(10));
701
+
702
+ const items = cloneDeep(filterListItems).slice(0, 10);
703
+ items[0].disabled = true;
704
+ const wrapper = createWrapper({ selected: 1, items }, { multiple: false, clearable: true });
705
+
706
+ expect(wrapper.vm.$data.selected).toEqual(1);
707
+
708
+ const clearButton = wrapper.find('button[aria-label="Clear selection"]');
709
+ expect(clearButton.exists()).toBe(true);
710
+
711
+ await clearButton.trigger('click');
712
+ expect(wrapper.vm.$data.selected).toEqual(1);
713
+
714
+ cleanup(wrapper);
715
+ });
669
716
  });
@@ -38,9 +38,9 @@
38
38
  }}
39
39
  </div>
40
40
  </slot>
41
- <!-- Add clear button -->
41
+ <!-- Clear selection button -->
42
42
  <button
43
- v-if="clearable && internalValue.length"
43
+ v-if="clearable && selectedItems.length"
44
44
  class="absolute top-1/2 flex -translate-y-1/2 items-center justify-center text-p-gray-40 hover:text-p-gray-60"
45
45
  :class="[SIZES[size], CLEAR_BUTTON_SPACING[size]]"
46
46
  aria-label="Clear selection"
@@ -299,20 +299,24 @@ export const useSelectList = (props: Props, inputSearch: InputSearch, virtualize
299
299
  };
300
300
 
301
301
  const clearAll = () => {
302
- if (!props.multiple) return;
303
-
304
302
  search.value = '';
305
303
 
306
304
  // We cannot clear disabled items that are selected
307
- const disabledItemsValues = internalItems.value
308
- .filter((item) => isDisabled(item))
309
- .map((item) => item[props.itemValue]);
305
+ if (props.multiple) {
306
+ const disabledItemsValues = internalItems.value
307
+ .filter((item) => isDisabled(item))
308
+ .map((item) => item[props.itemValue]);
310
309
 
311
- const selectedItemsValues = internalValue.value;
310
+ const selectedItemsValues = internalValue.value;
312
311
 
313
- const selectedDisabledItems = intersection(disabledItemsValues, selectedItemsValues);
312
+ const selectedDisabledItems = intersection(disabledItemsValues, selectedItemsValues);
314
313
 
315
- emit('update:modelValue', toArrOfObjIfNeeded(selectedDisabledItems));
314
+ emit('update:modelValue', toArrOfObjIfNeeded(selectedDisabledItems));
315
+ } else {
316
+ if (!isDisabled(selectedItems.value[0])) {
317
+ emit('update:modelValue', null);
318
+ }
319
+ }
316
320
  };
317
321
 
318
322
  // Watch