@pequity/squirrel 1.0.24 → 1.0.25

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
@@ -12,10 +12,10 @@ Install the package and its dependencies using pnpm:
12
12
  pnpm i @pequity/squirrel @popperjs/core @tanstack/vue-virtual dayjs floating-vue lodash-es v-calendar vue-currency-input ue-toastification@2.0.0-rc.5
13
13
  ```
14
14
 
15
- Add the Squirrel CSS to your project's `main.ts` file:
15
+ Import the Squirrel CSS to your project's `main.css` file:
16
16
 
17
- ```ts
18
- import '@pequity/squirrel/assets/squirrel.css';
17
+ ```css
18
+ @import '@pequity/squirrel/assets/squirrel.css';
19
19
  ```
20
20
 
21
21
  Add the "Inter" font to your project's `index.html` file:
@@ -61,6 +61,57 @@ If you are using Jest for unit testing, you will need to add the following to yo
61
61
  }
62
62
  ```
63
63
 
64
+ ## Developing Squirrel components while working on a consumer project
65
+
66
+ When working on a consumer project that relies on Squirrel components and requires experimentation and adjustments, our goal is to promptly test changes without the need to edit the library directly within the `node_modules` folder or publish a new version of it. To facilitate this process, we can utilize [Vite aliases](https://vitejs.dev/config/shared-options.html#resolve-alias) and point the entry point of the library to the _source code_ of the library that resides inside the `squirrel` directory within the Squirrel repo.
67
+
68
+ After we're happy with the changes, we can then commit them to the Squirrel repository and publish a new version.
69
+
70
+ ### Setting up Vite aliases for local development
71
+
72
+ First you'll need to have the Squirrel repository cloned to your local machine.
73
+
74
+ Then, in your consumer project's `.env.local` file, add an `VUE_APP_SQUIRREL_LOCAL_PATH` variable that points to the `squirrel` folder inside the Squirrel repository:
75
+
76
+ > Make sure to replace `/home/user/development/pequity/squirrel/squirrel` with the actual path to the `squirrel` folder in your local Squirrel repository.
77
+
78
+ ```bash
79
+ # Map squirrel path for local development - uncomment when you need to work on Squirrel components locally
80
+ # VUE_APP_SQUIRREL_LOCAL_PATH=/home/user/development/pequity/squirrel/squirrel
81
+ ```
82
+
83
+ Finally, in your project's `vite.config` file, add the following:
84
+
85
+ > Heads up! The `vite.config.mts` file of the `pequity/frontendv2` already includes the following configuration.
86
+
87
+ ```js
88
+ import { defineConfig, searchForWorkspaceRoot } from 'vite';
89
+
90
+ const squirrelLocalPath = process.env.VUE_APP_SQUIRREL_LOCAL_PATH;
91
+
92
+ export default defineConfig({
93
+ // Other Vite config options...
94
+ resolve: {
95
+ alias: {
96
+ ...(squirrelLocalPath && {
97
+ '@squirrel': squirrelLocalPath,
98
+ '@pequity/squirrel': squirrelLocalPath,
99
+ }),
100
+ },
101
+ },
102
+ ...(squirrelLocalPath && {
103
+ server: {
104
+ fs: {
105
+ allow: [searchForWorkspaceRoot(process.cwd()), squirrelLocalPath],
106
+ },
107
+ },
108
+ }),
109
+ });
110
+ ```
111
+
112
+ Now, when you want to work on Squirrel components, you can uncomment the `VUE_APP_SQUIRREL_LOCAL_PATH` in your `.env.local` file and restart the dev server.
113
+ The Squirrel components will be loaded from the local `<squirrel_repo_path>/squirrel` folder instead of the `node_modules` folder and HMR will work as expected.
114
+
64
115
  ## Contributing
65
116
 
66
117
  ---
@@ -22,21 +22,6 @@ const _sfc_main = vue.defineComponent({
22
22
  type: Boolean,
23
23
  default: true
24
24
  },
25
- /**
26
- * The selector that the arrow navigation function will use to
27
- * match the items in the list.
28
- */
29
- itemSelector: {
30
- type: String,
31
- default: ".dropdown-item:not(.disabled), .dropdown-item:not(:disabled)"
32
- },
33
- /**
34
- * The CSS class of the "focused" dropdown item
35
- */
36
- itemFocusClass: {
37
- type: String,
38
- default: "focus"
39
- },
40
25
  /**
41
26
  * v-tooltip wraps the popper trigger with a div that has `display: inline-block` set by default.
42
27
  * This prop is used to override the CSS style of that wrapper div
@@ -21,21 +21,6 @@ const _sfc_main = defineComponent({
21
21
  type: Boolean,
22
22
  default: true
23
23
  },
24
- /**
25
- * The selector that the arrow navigation function will use to
26
- * match the items in the list.
27
- */
28
- itemSelector: {
29
- type: String,
30
- default: ".dropdown-item:not(.disabled), .dropdown-item:not(:disabled)"
31
- },
32
- /**
33
- * The CSS class of the "focused" dropdown item
34
- */
35
- itemFocusClass: {
36
- type: String,
37
- default: "focus"
38
- },
39
24
  /**
40
25
  * v-tooltip wraps the popper trigger with a div that has `display: inline-block` set by default.
41
26
  * This prop is used to override the CSS style of that wrapper div
@@ -16,21 +16,6 @@ declare const _default: import("vue").DefineComponent<{
16
16
  type: BooleanConstructor;
17
17
  default: boolean;
18
18
  };
19
- /**
20
- * The selector that the arrow navigation function will use to
21
- * match the items in the list.
22
- */
23
- itemSelector: {
24
- type: StringConstructor;
25
- default: string;
26
- };
27
- /**
28
- * The CSS class of the "focused" dropdown item
29
- */
30
- itemFocusClass: {
31
- type: StringConstructor;
32
- default: string;
33
- };
34
19
  /**
35
20
  * v-tooltip wraps the popper trigger with a div that has `display: inline-block` set by default.
36
21
  * This prop is used to override the CSS style of that wrapper div
@@ -81,21 +66,6 @@ declare const _default: import("vue").DefineComponent<{
81
66
  type: BooleanConstructor;
82
67
  default: boolean;
83
68
  };
84
- /**
85
- * The selector that the arrow navigation function will use to
86
- * match the items in the list.
87
- */
88
- itemSelector: {
89
- type: StringConstructor;
90
- default: string;
91
- };
92
- /**
93
- * The CSS class of the "focused" dropdown item
94
- */
95
- itemFocusClass: {
96
- type: StringConstructor;
97
- default: string;
98
- };
99
69
  /**
100
70
  * v-tooltip wraps the popper trigger with a div that has `display: inline-block` set by default.
101
71
  * This prop is used to override the CSS style of that wrapper div
@@ -115,8 +85,6 @@ declare const _default: import("vue").DefineComponent<{
115
85
  default: null;
116
86
  };
117
87
  }>>, {
118
- itemSelector: string;
119
- itemFocusClass: string;
120
88
  reference: HTMLElement | null | undefined;
121
89
  enableArrowNavigation: boolean;
122
90
  enableCloseOnEsc: boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pequity/squirrel",
3
3
  "description": "Squirrel component library",
4
- "version": "1.0.24",
4
+ "version": "1.0.25",
5
5
  "packageManager": "pnpm@8.9.2",
6
6
  "type": "module",
7
7
  "scripts": {
@@ -0,0 +1,95 @@
1
+ import PChips from '@squirrel/components/p-chips/p-chips.vue';
2
+ import { createWrapperFor } from '@tests/jest.helpers';
3
+
4
+ const createItems = (itemText) => {
5
+ itemText = itemText || 'text';
6
+
7
+ return [
8
+ { [itemText]: 'item 1', value: 1 },
9
+ { [itemText]: 'item 2', value: 2 },
10
+ { [itemText]: 'item 3', value: 3 },
11
+ { [itemText]: 'item 4', value: 4 },
12
+ ];
13
+ };
14
+
15
+ describe('PChips.vue', () => {
16
+ it('renders correctly', async () => {
17
+ const items = createItems();
18
+
19
+ const wrapper = createWrapperFor(PChips, {
20
+ props: { items },
21
+ slots: { before: 'before slot', after: 'after slot' },
22
+ });
23
+
24
+ await wrapper.setData({ maxChipsDisplayed: 4 });
25
+
26
+ const container = wrapper.find('.flex.divide-x');
27
+ const beforeEl = container.element.previousElementSibling;
28
+ const afterEl = container.element.nextElementSibling;
29
+ const beforeSlot = wrapper.findByText('before slot');
30
+ const afterSlot = wrapper.findByText('after slot');
31
+
32
+ const chips = container.findAll('.flex.cursor-pointer');
33
+
34
+ chips.forEach((chip, i) => {
35
+ expect(chip.text()).toBe(items[i].text);
36
+ });
37
+
38
+ const additional = wrapper.findByText('+0');
39
+ expect(additional.attributes('style')).toEqual(`display: none;`);
40
+ expect(beforeSlot.element).toBe(beforeEl);
41
+ expect(afterSlot.element).toBe(afterEl);
42
+ });
43
+
44
+ it('displays additional chips number', async () => {
45
+ const items = createItems();
46
+
47
+ const wrapper = createWrapperFor(PChips, {
48
+ props: { items },
49
+ });
50
+
51
+ await wrapper.setData({ maxChipsDisplayed: 2 });
52
+
53
+ const chips = wrapper.findAll('.flex.cursor-pointer');
54
+ const additional = wrapper.findByText('+2');
55
+
56
+ expect(chips.length).toBe(2);
57
+ expect(additional.attributes('style')).toBe(undefined);
58
+ });
59
+
60
+ it('displays chips with custom item text', async () => {
61
+ const items = createItems('name');
62
+
63
+ const wrapper = createWrapperFor(PChips, {
64
+ props: { items, itemText: 'name' },
65
+ });
66
+
67
+ await wrapper.setData({ maxChipsDisplayed: 4 });
68
+
69
+ const chips = wrapper.findAll('.flex.cursor-pointer');
70
+
71
+ chips.forEach((chip, i) => {
72
+ expect(chip.text()).toBe(items[i].name);
73
+ });
74
+ });
75
+
76
+ it('emits events when clicking on chips', async () => {
77
+ const items = createItems();
78
+
79
+ const wrapper = createWrapperFor(PChips, {
80
+ props: { items },
81
+ });
82
+
83
+ await wrapper.setData({ maxChipsDisplayed: 2 });
84
+
85
+ const chips = wrapper.findAll('.flex.cursor-pointer');
86
+ const chip = chips[0];
87
+ const additional = wrapper.findByText('+2');
88
+
89
+ await chip.trigger('click');
90
+ await additional.trigger('click');
91
+
92
+ expect(wrapper.emitted()['click:chip'][0][0]).toEqual(items[0]);
93
+ expect(wrapper.emitted()['click:overflow']).toBeTruthy();
94
+ });
95
+ });
@@ -0,0 +1,164 @@
1
+ import PDropdown from '@squirrel/components/p-dropdown/p-dropdown.vue';
2
+ import { createWrapperFor } from '@tests/jest.helpers';
3
+ import { setupListKeyboardNavigation } from '@squirrel/utils/listKeyboardNavigation';
4
+
5
+ jest.mock('@squirrel/utils/listKeyboardNavigation', () => {
6
+ return {
7
+ setupListKeyboardNavigation: jest.fn(),
8
+ };
9
+ });
10
+
11
+ const destroyFn = jest.fn();
12
+ const initFn = jest.fn();
13
+
14
+ const createMockedKbdNavigationSvc = () => {
15
+ return {
16
+ destroy: destroyFn,
17
+ init: initFn,
18
+ };
19
+ };
20
+
21
+ const Popper = {
22
+ template: `<div class="popper"><slot /></div>`,
23
+ };
24
+
25
+ const PopperContent = {
26
+ template: `<div class="popper-content"><slot /></div>`,
27
+ };
28
+
29
+ const createVDropdownStub = () => {
30
+ return {
31
+ template: `
32
+ <div ref="vPopper">
33
+ <Popper ref="popper">
34
+ <slot />
35
+ </Popper>
36
+ <PopperContent ref="popperContent">
37
+ <slot name="popper" />
38
+ </PopperContent>
39
+ </div>
40
+ `,
41
+ components: {
42
+ Popper,
43
+ PopperContent,
44
+ },
45
+ mounted() {
46
+ this.$emit('show');
47
+ },
48
+ beforeUnmount() {
49
+ this.$emit('hide');
50
+ },
51
+ };
52
+ };
53
+
54
+ describe('PDropdown.vue', () => {
55
+ afterEach(() => {
56
+ jest.clearAllMocks();
57
+ });
58
+
59
+ it('renders correctly', async () => {
60
+ const wrapper = createWrapperFor(PDropdown, {
61
+ props: {
62
+ enableArrowNavigation: false,
63
+ enableCloseOnEsc: false,
64
+ triggerStyle: {
65
+ width: '200px',
66
+ display: 'flex',
67
+ },
68
+ },
69
+ slots: {
70
+ default: `<button>Open popper</button>`,
71
+ popper: `<div>Dropdown content</div>`,
72
+ },
73
+ global: {
74
+ stubs: {
75
+ VDropdown: createVDropdownStub(),
76
+ },
77
+ },
78
+ });
79
+
80
+ const popper = wrapper.find('.popper');
81
+ const popperContent = wrapper.find('.popper-content');
82
+
83
+ expect(popper.attributes().style).toBe('width: 200px; display: flex;');
84
+ expect(popper.text()).toBe('Open popper');
85
+ expect(popperContent.text()).toBe('Dropdown content');
86
+ });
87
+
88
+ it(`sets the correct defaults`, async () => {
89
+ const wrapper = createWrapperFor(PDropdown, {
90
+ props: {
91
+ enableArrowNavigation: false,
92
+ enableCloseOnEsc: false,
93
+ },
94
+ slots: {
95
+ default: `<button>Open popper</button>`,
96
+ popper: `<div>Dropdown content</div>`,
97
+ },
98
+ global: {
99
+ stubs: {
100
+ VDropdown: createVDropdownStub(),
101
+ },
102
+ },
103
+ });
104
+
105
+ const res = {
106
+ triggers: 'click',
107
+ 'auto-hide': 'true',
108
+ theme: 'p-dropdown-theme',
109
+ 'popper-class': 'dropdown',
110
+ placement: 'bottom-start',
111
+ distance: '4',
112
+ delay: '0',
113
+ handleresize: 'true',
114
+ };
115
+
116
+ expect(wrapper.attributes()).toEqual(res);
117
+ });
118
+
119
+ it('initializes the keyboard navigation svc', async () => {
120
+ setupListKeyboardNavigation.mockImplementation(() => createMockedKbdNavigationSvc());
121
+
122
+ createWrapperFor(PDropdown, {
123
+ props: {
124
+ enableArrowNavigation: true,
125
+ enableCloseOnEsc: false,
126
+ },
127
+ slots: {
128
+ default: `<button>Open popper</button>`,
129
+ popper: `<div>Dropdown content</div>`,
130
+ },
131
+ global: {
132
+ stubs: {
133
+ VDropdown: createVDropdownStub(),
134
+ },
135
+ },
136
+ });
137
+
138
+ expect(setupListKeyboardNavigation).toHaveBeenCalledTimes(1);
139
+ });
140
+
141
+ it('destroys the keyboard navigation svc', async () => {
142
+ setupListKeyboardNavigation.mockImplementation(() => createMockedKbdNavigationSvc());
143
+
144
+ const wrapper = createWrapperFor(PDropdown, {
145
+ props: {
146
+ enableArrowNavigation: true,
147
+ enableCloseOnEsc: false,
148
+ },
149
+ slots: {
150
+ default: `<button>Open popper</button>`,
151
+ popper: `<div>Dropdown content</div>`,
152
+ },
153
+ global: {
154
+ stubs: {
155
+ VDropdown: createVDropdownStub(),
156
+ },
157
+ },
158
+ });
159
+
160
+ wrapper.unmount();
161
+
162
+ expect(destroyFn).toHaveBeenCalled();
163
+ });
164
+ });
@@ -128,21 +128,6 @@ export default defineComponent({
128
128
  type: Boolean,
129
129
  default: true,
130
130
  },
131
- /**
132
- * The selector that the arrow navigation function will use to
133
- * match the items in the list.
134
- */
135
- itemSelector: {
136
- type: String,
137
- default: '.dropdown-item:not(.disabled), .dropdown-item:not(:disabled)',
138
- },
139
- /**
140
- * The CSS class of the "focused" dropdown item
141
- */
142
- itemFocusClass: {
143
- type: String,
144
- default: 'focus',
145
- },
146
131
  /**
147
132
  * v-tooltip wraps the popper trigger with a div that has `display: inline-block` set by default.
148
133
  * This prop is used to override the CSS style of that wrapper div
@@ -0,0 +1,89 @@
1
+ import { createApp, nextTick, ref } from 'vue';
2
+ import { usePTableColResize } from '@squirrel/components/p-table/usePTableColResize';
3
+
4
+ const withSetup = (composable) => {
5
+ let result;
6
+
7
+ const app = createApp({
8
+ setup() {
9
+ result = composable();
10
+ return () => {};
11
+ },
12
+ });
13
+
14
+ app.mount(document.createElement('div'));
15
+
16
+ return result;
17
+ };
18
+
19
+ describe('usePTableColResize', () => {
20
+ it('should resize the column when colResize is called', () => {
21
+ const options = {
22
+ enabled: ref(true),
23
+ ths: ref([{ offsetWidth: 100, getBoundingClientRect: () => ({ width: 100 }) }]),
24
+ };
25
+
26
+ const { isColResizing, colResizingIndex, colResizeHandleLeft, colResizingWidth, colResize } = withSetup(() =>
27
+ usePTableColResize(options)
28
+ );
29
+
30
+ isColResizing.value = true;
31
+ colResizingIndex.value = 0;
32
+
33
+ const event = new MouseEvent('mousemove', { clientX: 150 });
34
+ colResize(event);
35
+
36
+ expect(colResizeHandleLeft.value).toBe('150px');
37
+ expect(colResizingWidth.value).toBe(80);
38
+ });
39
+
40
+ it('should start column resizing when colResizeStart is called', () => {
41
+ const options = {
42
+ enabled: ref(true),
43
+ ths: ref([{ offsetWidth: 100 }, { offsetWidth: 200 }]),
44
+ };
45
+ const { colResizeStart, isColResizing, colResizingWidth, colResizingIndex } = withSetup(() =>
46
+ usePTableColResize(options)
47
+ );
48
+
49
+ const event = new MouseEvent('mousedown', { detail: 1 });
50
+ colResizeStart(event, 1);
51
+
52
+ expect(isColResizing.value).toBe(true);
53
+ expect(colResizingWidth.value).toBe(200);
54
+ expect(colResizingIndex.value).toBe(1);
55
+ });
56
+
57
+ it('should stop column resizing when colResizeStop is called', () => {
58
+ const options = {
59
+ enabled: ref(true),
60
+ ths: ref([{ offsetWidth: 100 }]),
61
+ };
62
+ const { colResizeStop, isColResizing } = withSetup(() => usePTableColResize(options));
63
+
64
+ colResizeStop();
65
+
66
+ expect(isColResizing.value).toBe(false);
67
+ });
68
+
69
+ it('should fit column width to data when colResizeFitToData is called', async () => {
70
+ const options = {
71
+ enabled: ref(true),
72
+ ths: ref([
73
+ {
74
+ closest: () => ({
75
+ querySelectorAll: () => [{ offsetWidth: 100, getBoundingClientRect: () => ({ width: 150 }) }],
76
+ }),
77
+ },
78
+ ]),
79
+ };
80
+ const { colResizeFitToData, isColResizing, colResizingWidth } = withSetup(() => usePTableColResize(options));
81
+
82
+ colResizeFitToData(0);
83
+
84
+ await nextTick();
85
+
86
+ expect(isColResizing.value).toBe(false);
87
+ expect(colResizingWidth.value).toBe(150);
88
+ });
89
+ });