@pequity/squirrel 8.3.3 → 8.3.5

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/index.js CHANGED
@@ -166,7 +166,9 @@ const _sfc_main$4 = /* @__PURE__ */ vue.defineComponent({
166
166
  const file = filesToUpload[i];
167
167
  const fileName = file.name || file.url;
168
168
  if (res.length + files.value.length >= props.maxNumberOfFiles) {
169
- toast.error(`You can only upload a maximum of ${props.maxNumberOfFiles} ${fileWord.value}.`);
169
+ if (!(props.multiple && props.maxNumberOfFiles === 1)) {
170
+ toast.error(`You can only upload a maximum of ${props.maxNumberOfFiles} ${fileWord.value}.`);
171
+ }
170
172
  break;
171
173
  }
172
174
  if (!fileName) {
@@ -870,7 +872,7 @@ const _sfc_main$1 = /* @__PURE__ */ vue.defineComponent({
870
872
  ref: (el) => updateThsRefs(el, i),
871
873
  key: col.id,
872
874
  "data-col-id": col.id
873
- }, col.thAttrs, {
875
+ }, { ref_for: true }, col.thAttrs, {
874
876
  style: col.style,
875
877
  class: "bg-surface"
876
878
  }), [
@@ -886,9 +888,8 @@ const _sfc_main$1 = /* @__PURE__ */ vue.defineComponent({
886
888
  "show-filter-icon": col.filterable || col.sortable,
887
889
  "tooltip-text": col.tooltip,
888
890
  class: [{ "pl-2": i === 1 && _ctx.isFirstColFixed, "pr-2": i === _ctx.cols.length && _ctx.isLastColFixed }, "grow"],
889
- "text-color": headerCellTextColor(col),
890
- ref_for: true
891
- }, col.headerCellAttrs, {
891
+ "text-color": headerCellTextColor(col)
892
+ }, { ref_for: true }, col.headerCellAttrs, {
892
893
  onClickFilterIcon: ($event) => _ctx.$emit("click-filter-icon", $event, col)
893
894
  }), null, 16, ["text", "filter-active", "show-filter-icon", "tooltip-text", "class", "text-color", "onClickFilterIcon"])
894
895
  ]),
@@ -32,15 +32,22 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
32
32
  const style = vue.computed(() => {
33
33
  return allAttrs.style;
34
34
  });
35
+ const isDisabled = vue.computed(() => {
36
+ return "disabled" in allAttrs && allAttrs.disabled !== false;
37
+ });
35
38
  return (_ctx, _cache) => {
36
39
  return vue.openBlock(), vue.createElementBlock("label", {
37
- class: vue.normalizeClass(["inline-flex items-center", [{ hidden: _ctx.$attrs.hidden }, _ctx.$attrs.class]]),
40
+ class: vue.normalizeClass(["inline-flex items-center", [
41
+ { hidden: _ctx.$attrs.hidden },
42
+ _ctx.$attrs.class,
43
+ { "cursor-not-allowed opacity-50": isDisabled.value, "cursor-pointer": !isDisabled.value }
44
+ ]]),
38
45
  style: vue.normalizeStyle(style.value)
39
46
  }, [
40
47
  vue.renderSlot(_ctx.$slots, "label-before", {}, void 0, true),
41
48
  vue.createElementVNode("input", vue.mergeProps({
42
49
  type: "checkbox",
43
- class: "h-4 w-4 shrink-0 appearance-none rounded border border-p-gray-30 bg-surface duration-100 ease-in-out checked:border-none checked:bg-primary disabled:opacity-50"
50
+ class: "h-4 w-4 shrink-0 appearance-none rounded border border-p-gray-30 bg-surface duration-100 ease-in-out checked:border-none checked:bg-primary"
44
51
  }, attrs.value, {
45
52
  checked: __props.modelValue,
46
53
  onChange: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update:modelValue", $event.target.checked))
@@ -52,5 +59,5 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
52
59
  };
53
60
  }
54
61
  });
55
- const pCheckbox = /* @__PURE__ */ _pluginVue_exportHelper._export_sfc(_sfc_main, [["__scopeId", "data-v-81cd6154"]]);
62
+ const pCheckbox = /* @__PURE__ */ _pluginVue_exportHelper._export_sfc(_sfc_main, [["__scopeId", "data-v-b394a2f0"]]);
56
63
  module.exports = pCheckbox;
package/dist/es/index.js CHANGED
@@ -166,7 +166,9 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
166
166
  const file = filesToUpload[i2];
167
167
  const fileName = file.name || file.url;
168
168
  if (res.length + files.value.length >= props.maxNumberOfFiles) {
169
- toast.error(`You can only upload a maximum of ${props.maxNumberOfFiles} ${fileWord.value}.`);
169
+ if (!(props.multiple && props.maxNumberOfFiles === 1)) {
170
+ toast.error(`You can only upload a maximum of ${props.maxNumberOfFiles} ${fileWord.value}.`);
171
+ }
170
172
  break;
171
173
  }
172
174
  if (!fileName) {
@@ -870,7 +872,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
870
872
  ref: (el) => updateThsRefs(el, i2),
871
873
  key: col.id,
872
874
  "data-col-id": col.id
873
- }, col.thAttrs, {
875
+ }, { ref_for: true }, col.thAttrs, {
874
876
  style: col.style,
875
877
  class: "bg-surface"
876
878
  }), [
@@ -886,9 +888,8 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
886
888
  "show-filter-icon": col.filterable || col.sortable,
887
889
  "tooltip-text": col.tooltip,
888
890
  class: [{ "pl-2": i2 === 1 && _ctx.isFirstColFixed, "pr-2": i2 === _ctx.cols.length && _ctx.isLastColFixed }, "grow"],
889
- "text-color": headerCellTextColor(col),
890
- ref_for: true
891
- }, col.headerCellAttrs, {
891
+ "text-color": headerCellTextColor(col)
892
+ }, { ref_for: true }, col.headerCellAttrs, {
892
893
  onClickFilterIcon: ($event) => _ctx.$emit("click-filter-icon", $event, col)
893
894
  }), null, 16, ["text", "filter-active", "show-filter-icon", "tooltip-text", "class", "text-color", "onClickFilterIcon"])
894
895
  ]),
@@ -31,15 +31,22 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
31
31
  const style = computed(() => {
32
32
  return allAttrs.style;
33
33
  });
34
+ const isDisabled = computed(() => {
35
+ return "disabled" in allAttrs && allAttrs.disabled !== false;
36
+ });
34
37
  return (_ctx, _cache) => {
35
38
  return openBlock(), createElementBlock("label", {
36
- class: normalizeClass(["inline-flex items-center", [{ hidden: _ctx.$attrs.hidden }, _ctx.$attrs.class]]),
39
+ class: normalizeClass(["inline-flex items-center", [
40
+ { hidden: _ctx.$attrs.hidden },
41
+ _ctx.$attrs.class,
42
+ { "cursor-not-allowed opacity-50": isDisabled.value, "cursor-pointer": !isDisabled.value }
43
+ ]]),
37
44
  style: normalizeStyle(style.value)
38
45
  }, [
39
46
  renderSlot(_ctx.$slots, "label-before", {}, void 0, true),
40
47
  createElementVNode("input", mergeProps({
41
48
  type: "checkbox",
42
- class: "h-4 w-4 shrink-0 appearance-none rounded border border-p-gray-30 bg-surface duration-100 ease-in-out checked:border-none checked:bg-primary disabled:opacity-50"
49
+ class: "h-4 w-4 shrink-0 appearance-none rounded border border-p-gray-30 bg-surface duration-100 ease-in-out checked:border-none checked:bg-primary"
43
50
  }, attrs.value, {
44
51
  checked: __props.modelValue,
45
52
  onChange: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update:modelValue", $event.target.checked))
@@ -51,7 +58,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
51
58
  };
52
59
  }
53
60
  });
54
- const pCheckbox = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-81cd6154"]]);
61
+ const pCheckbox = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-b394a2f0"]]);
55
62
  export {
56
63
  pCheckbox as default
57
64
  };
package/dist/squirrel.css CHANGED
@@ -191,7 +191,7 @@ div[id^=popper_].dropdown .v-popper__inner .dropdown-menu .dropdown-divider {
191
191
  --tw-content: "";
192
192
  content: var(--tw-content);
193
193
  }
194
- input[type='checkbox'][data-v-81cd6154]:checked {
194
+ input[type='checkbox'][data-v-b394a2f0]:checked {
195
195
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3E%3C/svg%3E");
196
196
  }
197
197
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pequity/squirrel",
3
3
  "description": "Squirrel component library",
4
- "version": "8.3.3",
4
+ "version": "8.3.5",
5
5
  "packageManager": "pnpm@10.6.4",
6
6
  "type": "module",
7
7
  "scripts": {
@@ -71,7 +71,7 @@
71
71
  "@types/node": "^22.15.21",
72
72
  "@vitejs/plugin-vue": "^5.2.4",
73
73
  "@vitest/coverage-v8": "^3.1.4",
74
- "@vue/compiler-sfc": "3.5.14",
74
+ "@vue/compiler-sfc": "3.5.15",
75
75
  "@vue/test-utils": "^2.4.6",
76
76
  "@vuepic/vue-datepicker": "11.0.2",
77
77
  "autoprefixer": "^10.4.21",
@@ -91,14 +91,14 @@
91
91
  "resolve-tspaths": "^0.8.23",
92
92
  "rimraf": "^6.0.1",
93
93
  "sass": "^1.89.0",
94
- "semantic-release": "^24.2.4",
94
+ "semantic-release": "^24.2.5",
95
95
  "storybook": "^8.6.14",
96
96
  "svgo": "^3.3.2",
97
97
  "tailwindcss": "^3.4.17",
98
98
  "typescript": "5.8.3",
99
99
  "vite": "^6.3.5",
100
100
  "vitest": "^3.1.4",
101
- "vue": "3.5.14",
101
+ "vue": "3.5.15",
102
102
  "vue-currency-input": "3.2.1",
103
103
  "vue-router": "4.5.1",
104
104
  "vue-toastification": "2.0.0-rc.5",
@@ -14,7 +14,6 @@ const checkboxClasses = [
14
14
  'ease-in-out',
15
15
  'checked:border-none',
16
16
  'checked:bg-primary',
17
- 'disabled:opacity-50',
18
17
  ];
19
18
 
20
19
  describe('PCheckbox.vue', () => {
@@ -39,4 +38,20 @@ describe('PCheckbox.vue', () => {
39
38
  expect(input.classes()).toEqual(checkboxClasses);
40
39
  expect(input.attributes().disabled).toBeDefined();
41
40
  });
41
+
42
+ it('applies correct styling to label based on disabled state', async () => {
43
+ const enabledWrapper = createWrapperFor(PCheckbox, { props: { checked: true } });
44
+ const disabledWrapper = createWrapperFor(PCheckbox, { props: { checked: true, disabled: true } });
45
+
46
+ const enabledLabel = await enabledWrapper.find('label');
47
+ const disabledLabel = await disabledWrapper.find('label');
48
+
49
+ expect(enabledLabel.classes()).toContain('cursor-pointer');
50
+ expect(enabledLabel.classes()).not.toContain('cursor-not-allowed');
51
+ expect(enabledLabel.classes()).not.toContain('opacity-50');
52
+
53
+ expect(disabledLabel.classes()).toContain('cursor-not-allowed');
54
+ expect(disabledLabel.classes()).toContain('opacity-50');
55
+ expect(disabledLabel.classes()).not.toContain('cursor-pointer');
56
+ });
42
57
  });
@@ -1,9 +1,17 @@
1
1
  <template>
2
- <label class="inline-flex items-center" :class="[{ hidden: $attrs.hidden }, $attrs.class]" :style="style">
2
+ <label
3
+ class="inline-flex items-center"
4
+ :class="[
5
+ { hidden: $attrs.hidden },
6
+ $attrs.class,
7
+ { 'cursor-not-allowed opacity-50': isDisabled, 'cursor-pointer': !isDisabled },
8
+ ]"
9
+ :style="style"
10
+ >
3
11
  <slot name="label-before"></slot>
4
12
  <input
5
13
  type="checkbox"
6
- class="h-4 w-4 shrink-0 appearance-none rounded border border-p-gray-30 bg-surface duration-100 ease-in-out checked:border-none checked:bg-primary disabled:opacity-50"
14
+ class="h-4 w-4 shrink-0 appearance-none rounded border border-p-gray-30 bg-surface duration-100 ease-in-out checked:border-none checked:bg-primary"
7
15
  v-bind="attrs"
8
16
  :checked="modelValue"
9
17
  @change="$emit('update:modelValue', ($event.target as HTMLInputElement).checked)"
@@ -48,6 +56,10 @@ const attrs = computed(() => {
48
56
  const style = computed(() => {
49
57
  return allAttrs.style as StyleValue;
50
58
  });
59
+
60
+ const isDisabled = computed(() => {
61
+ return 'disabled' in allAttrs && allAttrs.disabled !== false;
62
+ });
51
63
  </script>
52
64
 
53
65
  <style lang="css" scoped>
@@ -1,11 +1,26 @@
1
1
  import PFileUpload from '@squirrel/components/p-file-upload/p-file-upload.vue';
2
+ import { expect } from '@storybook/test';
2
3
  import { createWrapperFor } from '@tests/vitest.helpers';
4
+ import { vi } from 'vitest';
5
+
6
+ // Mocking the toastification library
7
+ const toastError = vi.fn();
8
+
9
+ vi.mock('vue-toastification', () => {
10
+ return {
11
+ useToast: () => {
12
+ return {
13
+ error: toastError,
14
+ };
15
+ },
16
+ };
17
+ });
3
18
 
4
- const createFile = () => {
5
- const file = new File(['filename'], 'filename.txt', {
19
+ const createFile = (fileName = 'filename') => {
20
+ const file = new File([fileName], `${fileName}.txt`, {
6
21
  type: 'text/plain',
7
- name: 'filename.txt',
8
- url: 'https://www.pequity.com/filename.txt',
22
+ name: `${fileName}.txt`,
23
+ url: `https://www.pequity.com/${fileName}.txt`,
9
24
  });
10
25
 
11
26
  return file;
@@ -131,4 +146,46 @@ describe('PFileUpload.vue', () => {
131
146
 
132
147
  expect(wrapper.findAll('div.truncate').length).toBe(3);
133
148
  });
149
+
150
+ it('shows a toast when maxNumberOfFiles is exceeded', async () => {
151
+ const file1 = createFile('file1');
152
+ const file2 = createFile('file2');
153
+
154
+ const wrapper = createWrapperFor({
155
+ components: { PFileUpload },
156
+ data() {
157
+ return {
158
+ files: [file1, file2],
159
+ };
160
+ },
161
+ template: `
162
+ <PFileUpload v-model="files" :multiple="true" :max-number-of-files="2" />
163
+ `,
164
+ });
165
+
166
+ expect(wrapper.find('div[title="file1.txt"]').exists()).toBe(true);
167
+ expect(wrapper.find('div[title="file2.txt"]').exists()).toBe(true);
168
+
169
+ expect(toastError).toHaveBeenCalledWith('You can only upload a maximum of 2 files.');
170
+ });
171
+
172
+ it('does not show a toast when multiple is true and maxNumberOfFiles is 1', async () => {
173
+ const file1 = createFile('file1');
174
+
175
+ const wrapper = createWrapperFor({
176
+ components: { PFileUpload },
177
+ data() {
178
+ return {
179
+ files: [file1],
180
+ };
181
+ },
182
+ template: `
183
+ <PFileUpload v-model="files" :multiple="true" :max-number-of-files="1" />
184
+ `,
185
+ });
186
+
187
+ expect(wrapper.find('div[title="file1.txt"]').exists()).toBe(true);
188
+
189
+ expect(toastError).not.toHaveBeenCalled();
190
+ });
134
191
  });
@@ -166,7 +166,11 @@ const validateFiles = (filesToUpload: FileUploadFile[]) => {
166
166
 
167
167
  // Bail if we reached the max number of files
168
168
  if (res.length + files.value.length >= props.maxNumberOfFiles) {
169
- toast.error(`You can only upload a maximum of ${props.maxNumberOfFiles} ${fileWord.value}.`);
169
+ // Show a toast - except for the contradictory config (multiple: true with maxNumberOfFiles: 1)
170
+ if (!(props.multiple && props.maxNumberOfFiles === 1)) {
171
+ toast.error(`You can only upload a maximum of ${props.maxNumberOfFiles} ${fileWord.value}.`);
172
+ }
173
+
170
174
  break;
171
175
  }
172
176