@pequity/squirrel 8.0.1 → 8.1.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.
- package/dist/cjs/chunks/p-action-bar.js +6 -9
- package/dist/cjs/chunks/p-steps.js +52 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/p-steps.js +3 -0
- package/dist/cjs/usePLoading.js +7 -1
- package/dist/es/chunks/p-action-bar.js +6 -9
- package/dist/es/chunks/p-steps.js +53 -0
- package/dist/es/index.js +8 -6
- package/dist/es/p-steps.js +4 -0
- package/dist/es/usePLoading.js +7 -1
- package/dist/squirrel/components/index.d.ts +2 -1
- package/dist/squirrel/components/p-alert/p-alert.vue.d.ts +3 -2
- package/dist/squirrel/components/p-btn/p-btn.vue.d.ts +1 -1
- package/dist/squirrel/components/p-card/p-card.vue.d.ts +2 -19
- package/dist/squirrel/components/p-checkbox/p-checkbox.vue.d.ts +2 -37
- package/dist/squirrel/components/p-drawer/p-drawer.vue.d.ts +3 -2
- package/dist/squirrel/components/p-info-icon/p-info-icon.vue.d.ts +2 -9
- package/dist/squirrel/components/p-inline-date-picker/p-inline-date-picker.vue.d.ts +3 -33
- package/dist/squirrel/components/p-input/p-input.vue.d.ts +6 -4
- package/dist/squirrel/components/p-input-number/p-input-number.vue.d.ts +3 -107
- package/dist/squirrel/components/p-link/p-link.vue.d.ts +3 -11
- package/dist/squirrel/components/p-loading/usePLoading.d.ts +1 -0
- package/dist/squirrel/components/p-modal/p-modal.vue.d.ts +2 -227
- package/dist/squirrel/components/p-pagination-info/p-pagination-info.vue.d.ts +2 -74
- package/dist/squirrel/components/p-select/p-select.vue.d.ts +3 -110
- package/dist/squirrel/components/p-select-btn/p-select-btn.vue.d.ts +2 -29
- package/dist/squirrel/components/p-steps/p-steps.vue.d.ts +17 -0
- package/dist/squirrel/components/p-table/p-table.vue.d.ts +10 -5
- package/dist/squirrel/components/p-table-header-cell/p-table-header-cell.vue.d.ts +1 -1
- package/dist/squirrel/components/p-table-td/p-table-td.vue.d.ts +2 -19
- package/dist/squirrel/components/p-textarea/p-textarea.vue.d.ts +3 -72
- package/dist/squirrel/components/p-toggle/p-toggle.vue.d.ts +2 -2
- package/package.json +14 -14
- package/squirrel/components/index.ts +2 -0
- package/squirrel/components/p-action-bar/p-action-bar.spec.ts +17 -11
- package/squirrel/components/p-action-bar/p-action-bar.vue +6 -6
- package/squirrel/components/p-loading/p-loading.spec.js +35 -2
- package/squirrel/components/p-loading/usePLoading.ts +10 -1
- package/squirrel/components/p-steps/__snapshots__/p-steps.spec.js.snap +16 -0
- package/squirrel/components/p-steps/p-steps.spec.js +126 -0
- package/squirrel/components/p-steps/p-steps.stories.js +31 -0
- package/squirrel/components/p-steps/p-steps.vue +47 -0
|
@@ -25,25 +25,30 @@ declare const _default: <T extends Record<string, unknown>>(__VLS_props: NonNull
|
|
|
25
25
|
[x: `prepend-header-cell-${string}`]: ((props: {
|
|
26
26
|
col: TableCol;
|
|
27
27
|
}) => any) | undefined;
|
|
28
|
+
} & {
|
|
28
29
|
[x: `subheader-cell-${string}`]: ((props: {}) => any) | undefined;
|
|
30
|
+
} & {
|
|
29
31
|
[x: `cell-${string}`]: ((props: {
|
|
30
32
|
col: TableCol;
|
|
31
33
|
rowData: T;
|
|
32
34
|
rowIndex: number;
|
|
33
35
|
cellData: unknown;
|
|
34
36
|
}) => any) | undefined;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
} & {
|
|
38
|
+
default?: (props: {}) => any;
|
|
39
|
+
} & {
|
|
40
|
+
row?: (props: {
|
|
37
41
|
rowData: T;
|
|
38
42
|
rowIndex: number;
|
|
39
|
-
}) => any
|
|
40
|
-
|
|
43
|
+
}) => any;
|
|
44
|
+
} & {
|
|
45
|
+
cell?: (props: {
|
|
41
46
|
col: TableCol;
|
|
42
47
|
colIndex: number;
|
|
43
48
|
rowData: T;
|
|
44
49
|
rowIndex: number;
|
|
45
50
|
cellData: unknown;
|
|
46
|
-
}) => any
|
|
51
|
+
}) => any;
|
|
47
52
|
};
|
|
48
53
|
emit: {
|
|
49
54
|
(e: "scroll", val: Event): void;
|
|
@@ -106,7 +106,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
106
106
|
text: string | null;
|
|
107
107
|
}, {}, string, {}, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, import("vue").ComponentProvideOptions> & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps & (new () => {
|
|
108
108
|
$slots: {
|
|
109
|
-
default?: (
|
|
109
|
+
default?: (props: {}) => any;
|
|
110
110
|
};
|
|
111
111
|
});
|
|
112
112
|
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
@@ -1,29 +1,12 @@
|
|
|
1
|
-
import { type Ref } from 'vue';
|
|
2
1
|
type Props = {
|
|
3
2
|
colIndex: number;
|
|
4
3
|
isEditable?: boolean;
|
|
5
4
|
isSelected?: boolean;
|
|
6
5
|
};
|
|
7
|
-
declare const isLastColFixed: Ref<boolean, boolean>;
|
|
8
|
-
declare const isColsResizable: Ref<boolean, boolean>;
|
|
9
|
-
declare const isLastCol: import("vue").ComputedRef<boolean>;
|
|
10
|
-
declare const tdClass: import("vue").ComputedRef<string[]>;
|
|
11
|
-
declare const innerDivClass: import("vue").ComputedRef<string[]>;
|
|
12
|
-
declare const __VLS_ctx: InstanceType<__VLS_PickNotAny<typeof __VLS_self, new () => {}>>;
|
|
13
6
|
declare var __VLS_1: {};
|
|
14
|
-
type __VLS_Slots =
|
|
7
|
+
type __VLS_Slots = {} & {
|
|
15
8
|
default?: (props: typeof __VLS_1) => any;
|
|
16
|
-
}
|
|
17
|
-
declare const __VLS_self: import("vue").DefineComponent<Props, {
|
|
18
|
-
isLastColFixed: typeof isLastColFixed;
|
|
19
|
-
isColsResizable: typeof isColsResizable;
|
|
20
|
-
isLastCol: typeof isLastCol;
|
|
21
|
-
tdClass: typeof tdClass;
|
|
22
|
-
innerDivClass: typeof innerDivClass;
|
|
23
|
-
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
24
|
-
isSelected: boolean;
|
|
25
|
-
isEditable: boolean;
|
|
26
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
};
|
|
27
10
|
declare const __VLS_component: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
28
11
|
isSelected: boolean;
|
|
29
12
|
isEditable: boolean;
|
|
@@ -1,81 +1,12 @@
|
|
|
1
1
|
import { type Size } from '../p-btn/p-btn.types';
|
|
2
|
-
import { type PropType
|
|
3
|
-
declare const labelClasses: import("vue").ComputedRef<string>, textareaClasses: import("vue").ComputedRef<string>, errorMsgClasses: import("vue").ComputedRef<string>;
|
|
4
|
-
declare const attrs: import("vue").ComputedRef<{
|
|
5
|
-
[x: string]: unknown;
|
|
6
|
-
}>;
|
|
7
|
-
declare const style: import("vue").ComputedRef<StyleValue>;
|
|
8
|
-
declare const updateValue: (e: Event) => void;
|
|
9
|
-
declare const __VLS_ctx: InstanceType<__VLS_PickNotAny<typeof __VLS_self, new () => {}>>;
|
|
2
|
+
import { type PropType } from 'vue';
|
|
10
3
|
declare var __VLS_1: {
|
|
11
4
|
label: string;
|
|
12
5
|
labelClasses: string;
|
|
13
6
|
};
|
|
14
|
-
type __VLS_Slots =
|
|
7
|
+
type __VLS_Slots = {} & {
|
|
15
8
|
label?: (props: typeof __VLS_1) => any;
|
|
16
|
-
}
|
|
17
|
-
declare const __VLS_self: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
18
|
-
modelValue: {
|
|
19
|
-
type: PropType<string | number | null>;
|
|
20
|
-
default: string;
|
|
21
|
-
};
|
|
22
|
-
label: {
|
|
23
|
-
type: StringConstructor;
|
|
24
|
-
default: string;
|
|
25
|
-
};
|
|
26
|
-
errorMsg: {
|
|
27
|
-
type: StringConstructor;
|
|
28
|
-
default: string;
|
|
29
|
-
};
|
|
30
|
-
required: {
|
|
31
|
-
type: BooleanConstructor;
|
|
32
|
-
default: boolean;
|
|
33
|
-
};
|
|
34
|
-
size: {
|
|
35
|
-
type: PropType<Size>;
|
|
36
|
-
default: string;
|
|
37
|
-
validator(value: Size): boolean;
|
|
38
|
-
};
|
|
39
|
-
}>, {
|
|
40
|
-
labelClasses: typeof labelClasses;
|
|
41
|
-
textareaClasses: typeof textareaClasses;
|
|
42
|
-
errorMsgClasses: typeof errorMsgClasses;
|
|
43
|
-
attrs: typeof attrs;
|
|
44
|
-
style: typeof style;
|
|
45
|
-
updateValue: typeof updateValue;
|
|
46
|
-
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
47
|
-
"update:modelValue": (...args: any[]) => void;
|
|
48
|
-
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
49
|
-
modelValue: {
|
|
50
|
-
type: PropType<string | number | null>;
|
|
51
|
-
default: string;
|
|
52
|
-
};
|
|
53
|
-
label: {
|
|
54
|
-
type: StringConstructor;
|
|
55
|
-
default: string;
|
|
56
|
-
};
|
|
57
|
-
errorMsg: {
|
|
58
|
-
type: StringConstructor;
|
|
59
|
-
default: string;
|
|
60
|
-
};
|
|
61
|
-
required: {
|
|
62
|
-
type: BooleanConstructor;
|
|
63
|
-
default: boolean;
|
|
64
|
-
};
|
|
65
|
-
size: {
|
|
66
|
-
type: PropType<Size>;
|
|
67
|
-
default: string;
|
|
68
|
-
validator(value: Size): boolean;
|
|
69
|
-
};
|
|
70
|
-
}>> & Readonly<{
|
|
71
|
-
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
|
72
|
-
}>, {
|
|
73
|
-
size: "sm" | "md" | "lg";
|
|
74
|
-
label: string;
|
|
75
|
-
required: boolean;
|
|
76
|
-
modelValue: string | number | null;
|
|
77
|
-
errorMsg: string;
|
|
78
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
9
|
+
};
|
|
79
10
|
declare const __VLS_component: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
80
11
|
modelValue: {
|
|
81
12
|
type: PropType<string | number | null>;
|
|
@@ -55,10 +55,10 @@ declare const _default: __VLS_WithSlots<import("vue").DefineComponent<import("vu
|
|
|
55
55
|
modelValue: boolean;
|
|
56
56
|
errorMsg: string;
|
|
57
57
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>, {
|
|
58
|
-
label?: (
|
|
58
|
+
label?: (props: {
|
|
59
59
|
label: string;
|
|
60
60
|
labelClasses: string;
|
|
61
|
-
}) => any
|
|
61
|
+
}) => any;
|
|
62
62
|
}>;
|
|
63
63
|
export default _default;
|
|
64
64
|
type __VLS_WithSlots<T, S> = T & {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pequity/squirrel",
|
|
3
3
|
"description": "Squirrel component library",
|
|
4
|
-
"version": "8.0
|
|
4
|
+
"version": "8.1.0",
|
|
5
5
|
"packageManager": "pnpm@10.6.4",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"storybook": "storybook dev -p 6006",
|
|
19
19
|
"build-storybook": "storybook build",
|
|
20
20
|
"test-storybook": "test-storybook",
|
|
21
|
-
"quality": "pnpm run lint && pnpm run typecheck &&
|
|
21
|
+
"quality": "pnpm run lint && pnpm run typecheck && vitest run && pnpm run build",
|
|
22
22
|
"prepare": "husky"
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@commitlint/cli": "^19.8.0",
|
|
51
51
|
"@commitlint/config-conventional": "^19.8.0",
|
|
52
52
|
"@pequity/eslint-config": "^2.0.0",
|
|
53
|
-
"@playwright/test": "^1.
|
|
53
|
+
"@playwright/test": "^1.52.0",
|
|
54
54
|
"@semantic-release/changelog": "^6.0.3",
|
|
55
55
|
"@semantic-release/git": "^10.0.1",
|
|
56
56
|
"@storybook/addon-a11y": "^8.6.12",
|
|
@@ -68,21 +68,21 @@
|
|
|
68
68
|
"@tanstack/vue-virtual": "3.13.6",
|
|
69
69
|
"@types/jsdom": "^21.1.7",
|
|
70
70
|
"@types/lodash-es": "^4.17.12",
|
|
71
|
-
"@types/node": "^22.
|
|
71
|
+
"@types/node": "^22.15.2",
|
|
72
72
|
"@vitejs/plugin-vue": "^5.2.3",
|
|
73
|
-
"@vitest/coverage-v8": "^3.1.
|
|
73
|
+
"@vitest/coverage-v8": "^3.1.2",
|
|
74
74
|
"@vue/compiler-sfc": "3.5.13",
|
|
75
75
|
"@vue/test-utils": "^2.4.6",
|
|
76
76
|
"@vuepic/vue-datepicker": "11.0.2",
|
|
77
77
|
"autoprefixer": "^10.4.21",
|
|
78
|
-
"eslint": "^9.
|
|
78
|
+
"eslint": "^9.25.1",
|
|
79
79
|
"eslint-plugin-storybook": "^0.12.0",
|
|
80
80
|
"floating-vue": "5.2.2",
|
|
81
|
-
"glob": "^11.0.
|
|
81
|
+
"glob": "^11.0.2",
|
|
82
82
|
"husky": "^9.1.7",
|
|
83
83
|
"iconify-icon": "^2.3.0",
|
|
84
|
-
"jsdom": "^26.
|
|
85
|
-
"lint-staged": "^15.5.
|
|
84
|
+
"jsdom": "^26.1.0",
|
|
85
|
+
"lint-staged": "^15.5.1",
|
|
86
86
|
"lodash-es": "4.17.21",
|
|
87
87
|
"make-coverage-badge": "^1.2.0",
|
|
88
88
|
"postcss": "^8.5.3",
|
|
@@ -90,19 +90,19 @@
|
|
|
90
90
|
"prettier-plugin-tailwindcss": "^0.6.11",
|
|
91
91
|
"resolve-tspaths": "^0.8.23",
|
|
92
92
|
"rimraf": "^6.0.1",
|
|
93
|
-
"sass": "^1.
|
|
93
|
+
"sass": "^1.87.0",
|
|
94
94
|
"semantic-release": "^24.2.3",
|
|
95
95
|
"storybook": "^8.6.12",
|
|
96
96
|
"svgo": "^3.3.2",
|
|
97
97
|
"tailwindcss": "^3.4.17",
|
|
98
98
|
"typescript": "5.8.3",
|
|
99
|
-
"vite": "^6.
|
|
100
|
-
"vitest": "^3.1.
|
|
99
|
+
"vite": "^6.3.3",
|
|
100
|
+
"vitest": "^3.1.2",
|
|
101
101
|
"vue": "3.5.13",
|
|
102
102
|
"vue-currency-input": "3.2.1",
|
|
103
|
-
"vue-router": "4.5.
|
|
103
|
+
"vue-router": "4.5.1",
|
|
104
104
|
"vue-toastification": "2.0.0-rc.5",
|
|
105
|
-
"vue-tsc": "2.2.
|
|
105
|
+
"vue-tsc": "2.2.10"
|
|
106
106
|
},
|
|
107
107
|
"dependencies": {
|
|
108
108
|
"tailwind-variants": "^1.0.0"
|
|
@@ -37,6 +37,7 @@ import PSelectList from '@squirrel/components/p-select-list/p-select-list.vue';
|
|
|
37
37
|
import { useSelectList } from '@squirrel/components/p-select-list/useSelectList';
|
|
38
38
|
import PSelectPill from '@squirrel/components/p-select-pill/p-select-pill.vue';
|
|
39
39
|
import PSkeletonLoader from '@squirrel/components/p-skeleton-loader/p-skeleton-loader.vue';
|
|
40
|
+
import PSteps from '@squirrel/components/p-steps/p-steps.vue';
|
|
40
41
|
import {
|
|
41
42
|
colsInjectionKey,
|
|
42
43
|
type HeaderCellAttrs,
|
|
@@ -108,6 +109,7 @@ export {
|
|
|
108
109
|
PSelectList,
|
|
109
110
|
PSelectPill,
|
|
110
111
|
PSkeletonLoader,
|
|
112
|
+
PSteps,
|
|
111
113
|
PTable,
|
|
112
114
|
PTableHeaderCell,
|
|
113
115
|
PTableLoader,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import PActionBar from '@squirrel/components/p-action-bar/p-action-bar.vue';
|
|
2
2
|
import { createWrapperFor } from '@tests/vitest.helpers';
|
|
3
|
+
import { type VueWrapper } from '@vue/test-utils';
|
|
3
4
|
import { defineComponent } from 'vue';
|
|
4
5
|
|
|
5
6
|
const createPDropdownStub = () => {
|
|
@@ -77,7 +78,7 @@ describe('PActionBar.vue', () => {
|
|
|
77
78
|
},
|
|
78
79
|
});
|
|
79
80
|
|
|
80
|
-
const mainDiv =
|
|
81
|
+
const mainDiv = wrapper.find('.teleport-stub > .fixed.bottom-6');
|
|
81
82
|
expect(mainDiv.exists()).toBe(true);
|
|
82
83
|
|
|
83
84
|
expect(mainDiv.classes()).toEqual(['fixed', 'bottom-6', 'left-1/2', 'z-[100]', '-translate-x-2/4']);
|
|
@@ -97,14 +98,19 @@ describe('PActionBar.vue', () => {
|
|
|
97
98
|
'text-white',
|
|
98
99
|
]);
|
|
99
100
|
|
|
100
|
-
const
|
|
101
|
+
const buttons = wrapper.findAllComponents({ name: 'PBtn' });
|
|
102
|
+
buttons.forEach((button: VueWrapper) => {
|
|
103
|
+
expect(button.find('.slot-wrapper > div').classes()).toEqual(['flex', 'items-center', 'gap-2', 'px-1']);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const paragraph = wrapper.find('p');
|
|
101
107
|
expect(paragraph.text()).toContain('Hello World');
|
|
102
108
|
|
|
103
|
-
const dismissIcon =
|
|
109
|
+
const dismissIcon = wrapper.find('i.x-white-icon');
|
|
104
110
|
expect(dismissIcon.exists()).toBe(true);
|
|
105
111
|
expect(actionBarDiv.find('.text-xs').text()).toBe('Clear All');
|
|
106
112
|
|
|
107
|
-
const actionBtn =
|
|
113
|
+
const actionBtn = wrapper.find('button.inline-block');
|
|
108
114
|
expect(actionBtn.exists()).toBe(true);
|
|
109
115
|
expect(actionBtn.text()).toContain('Say Hi');
|
|
110
116
|
});
|
|
@@ -125,9 +131,9 @@ describe('PActionBar.vue', () => {
|
|
|
125
131
|
},
|
|
126
132
|
});
|
|
127
133
|
|
|
128
|
-
const mainDiv =
|
|
134
|
+
const mainDiv = wrapper.find('.teleport-stub > .fixed.bottom-6');
|
|
129
135
|
|
|
130
|
-
|
|
136
|
+
mainDiv.find('.p-dropdown-stub > button').trigger('click');
|
|
131
137
|
|
|
132
138
|
await wrapper.vm.$nextTick();
|
|
133
139
|
|
|
@@ -155,7 +161,7 @@ describe('PActionBar.vue', () => {
|
|
|
155
161
|
},
|
|
156
162
|
});
|
|
157
163
|
|
|
158
|
-
const actionBar =
|
|
164
|
+
const actionBar = wrapper.find('.teleport-stub > div');
|
|
159
165
|
|
|
160
166
|
expect(actionBar.attributes('role')).toBe('alertdialog');
|
|
161
167
|
expect(actionBar.attributes('data-testid')).toBe('TestId');
|
|
@@ -168,7 +174,7 @@ describe('PActionBar.vue', () => {
|
|
|
168
174
|
props: { show: true, label: 'Hello World', actions: [{ label: 'Say Hi', name: 'greet' }] },
|
|
169
175
|
});
|
|
170
176
|
|
|
171
|
-
const button =
|
|
177
|
+
const button = wrapper.find('button.inline-flex');
|
|
172
178
|
|
|
173
179
|
await button.trigger('click');
|
|
174
180
|
|
|
@@ -187,15 +193,15 @@ describe('PActionBar.vue', () => {
|
|
|
187
193
|
},
|
|
188
194
|
});
|
|
189
195
|
|
|
190
|
-
const button =
|
|
196
|
+
const button = wrapper.findByText('Say Hi', 'button');
|
|
191
197
|
await button.trigger('click');
|
|
192
198
|
|
|
193
199
|
expect(wrapper.emitted()['click:action'][0]).toEqual(['greet']);
|
|
194
200
|
|
|
195
|
-
const actionMenu =
|
|
201
|
+
const actionMenu = wrapper.findByText('Action menu', 'button');
|
|
196
202
|
await actionMenu.trigger('click');
|
|
197
203
|
|
|
198
|
-
const subAction =
|
|
204
|
+
const subAction = wrapper.findByText('Say Bye', 'button');
|
|
199
205
|
await subAction.trigger('click');
|
|
200
206
|
|
|
201
207
|
expect(wrapper.emitted()['click:action'][1]).toEqual(['bye']);
|
|
@@ -19,17 +19,17 @@
|
|
|
19
19
|
type="secondary-ghost-dark"
|
|
20
20
|
@click="$emit('click:action', actionOrMenu.name)"
|
|
21
21
|
>
|
|
22
|
-
<div class="flex items-center gap-2 px-1
|
|
22
|
+
<div class="flex items-center gap-2 px-1">
|
|
23
23
|
<Component :is="actionOrMenu.icon" v-if="isComponent(actionOrMenu.icon)" class="h-4 w-4" />
|
|
24
|
-
<PIcon v-if="isString(actionOrMenu.icon)" :icon="actionOrMenu.icon" width="
|
|
24
|
+
<PIcon v-if="isString(actionOrMenu.icon)" :icon="actionOrMenu.icon" width="16" />
|
|
25
25
|
<div>{{ actionOrMenu.label }}</div>
|
|
26
26
|
</div>
|
|
27
27
|
</PBtn>
|
|
28
28
|
<PDropdown v-else placement="top" strategy="fixed">
|
|
29
29
|
<PBtn size="sm" type="secondary-ghost-dark">
|
|
30
|
-
<div class="flex items-center gap-2 px-1
|
|
30
|
+
<div class="flex items-center gap-2 px-1">
|
|
31
31
|
<Component :is="actionOrMenu.icon" v-if="isComponent(actionOrMenu.icon)" class="h-4 w-4" />
|
|
32
|
-
<PIcon v-if="isString(actionOrMenu.icon)" :icon="actionOrMenu.icon" width="
|
|
32
|
+
<PIcon v-if="isString(actionOrMenu.icon)" :icon="actionOrMenu.icon" width="16" />
|
|
33
33
|
<div>{{ actionOrMenu.label }}</div>
|
|
34
34
|
</div>
|
|
35
35
|
</PBtn>
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
type="secondary-ghost-dark"
|
|
43
43
|
@click="($emit('click:action', subaction.name), hide())"
|
|
44
44
|
>
|
|
45
|
-
<div class="flex items-center gap-2 px-1
|
|
45
|
+
<div class="flex items-center gap-2 px-1">
|
|
46
46
|
<Component :is="subaction.icon" v-if="isComponent(subaction.icon)" class="h-4 w-4" />
|
|
47
|
-
<PIcon v-if="isString(subaction.icon)" :icon="subaction.icon" width="
|
|
47
|
+
<PIcon v-if="isString(subaction.icon)" :icon="subaction.icon" width="16" />
|
|
48
48
|
<div>{{ subaction.label }}</div>
|
|
49
49
|
</div>
|
|
50
50
|
</PBtn>
|
|
@@ -24,7 +24,7 @@ const createWrapper = (options) => {
|
|
|
24
24
|
<button class="request-1-sec-component" @click="fireRequestComponent(1000)"></button>
|
|
25
25
|
`,
|
|
26
26
|
setup() {
|
|
27
|
-
const { loadingShow, loadingHide, show } = usePLoading(options);
|
|
27
|
+
const { loadingShow, loadingHide, show, isLoading } = usePLoading(options);
|
|
28
28
|
|
|
29
29
|
const fireRequest = async (time) => {
|
|
30
30
|
const id = `default-${time}`;
|
|
@@ -47,7 +47,7 @@ const createWrapper = (options) => {
|
|
|
47
47
|
loadingHide(id);
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
-
return { loadingShow, loadingHide, fireRequest, fireRequestText, fireRequestComponent, show };
|
|
50
|
+
return { loadingShow, loadingHide, fireRequest, fireRequestText, fireRequestComponent, show, isLoading };
|
|
51
51
|
},
|
|
52
52
|
},
|
|
53
53
|
{
|
|
@@ -90,6 +90,39 @@ describe('PLoading.vue', () => {
|
|
|
90
90
|
expect(appWrapper.find('[aria-busy]').exists()).toBe(false);
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
+
it('correctly reports loading state for a single loader', async () => {
|
|
94
|
+
const wrapper = createWrapper({ delay: 0 });
|
|
95
|
+
|
|
96
|
+
await wrapper.find('.request-1-sec').trigger('click');
|
|
97
|
+
|
|
98
|
+
vi.advanceTimersByTime(500);
|
|
99
|
+
await waitNT(appWrapper.vm);
|
|
100
|
+
expect(wrapper.vm.isLoading('default-1000')).toBe(true);
|
|
101
|
+
|
|
102
|
+
vi.advanceTimersByTime(600);
|
|
103
|
+
await waitNT(appWrapper.vm);
|
|
104
|
+
expect(wrapper.vm.isLoading('default-1000')).toBe(false);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('correctly reports loading state for multiple loaders', async () => {
|
|
108
|
+
const wrapper = createWrapper({ delay: 0 });
|
|
109
|
+
|
|
110
|
+
await wrapper.find('.request-1-sec').trigger('click');
|
|
111
|
+
await wrapper.find('.request-3-secs').trigger('click');
|
|
112
|
+
|
|
113
|
+
vi.advanceTimersByTime(500);
|
|
114
|
+
await waitNT(appWrapper.vm);
|
|
115
|
+
expect(wrapper.vm.isLoading()).toBe(true);
|
|
116
|
+
|
|
117
|
+
vi.advanceTimersByTime(1000);
|
|
118
|
+
await waitNT(appWrapper.vm);
|
|
119
|
+
expect(wrapper.vm.isLoading()).toBe(true);
|
|
120
|
+
|
|
121
|
+
vi.advanceTimersByTime(2000);
|
|
122
|
+
await waitNT(appWrapper.vm);
|
|
123
|
+
expect(wrapper.vm.isLoading()).toBe(false);
|
|
124
|
+
});
|
|
125
|
+
|
|
93
126
|
it(`doesn't show the loading indicator when loadingHide gets called before the delay time has passed`, async () => {
|
|
94
127
|
const wrapper = createWrapper({ delay: 1000 });
|
|
95
128
|
|
|
@@ -22,6 +22,7 @@ type UsePLoading = {
|
|
|
22
22
|
props: Ref;
|
|
23
23
|
loadingShow: (loadingItem: LoadingItemOption) => void;
|
|
24
24
|
loadingHide: (id?: LoadingItemOption['id']) => void;
|
|
25
|
+
isLoading: (id?: LoadingItemOption['id']) => boolean;
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
const LOADING_TEXT = 'Loading...';
|
|
@@ -86,6 +87,14 @@ export const usePLoading = (options?: Options): UsePLoading => {
|
|
|
86
87
|
}
|
|
87
88
|
};
|
|
88
89
|
|
|
90
|
+
const isLoading = (id?: LoadingItemOption['id']) => {
|
|
91
|
+
if (id) {
|
|
92
|
+
return loadingItems.value.some((item) => item.id === id);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return loadingItems.value.length > 0;
|
|
96
|
+
};
|
|
97
|
+
|
|
89
98
|
if (scope) {
|
|
90
99
|
onScopeDispose(() => {
|
|
91
100
|
if (loadingItems.value.some((item) => item.clearOnDispose === false)) {
|
|
@@ -102,5 +111,5 @@ export const usePLoading = (options?: Options): UsePLoading => {
|
|
|
102
111
|
});
|
|
103
112
|
}
|
|
104
113
|
|
|
105
|
-
return { show, content, props, loadingShow, loadingHide };
|
|
114
|
+
return { show, content, props, loadingShow, loadingHide, isLoading };
|
|
106
115
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`PSteps.vue > renders correctly 1`] = `
|
|
4
|
+
"<div class="flex items-center gap-2">
|
|
5
|
+
<div class="text-nowrap rounded-full border px-4 py-1 text-sm font-semibold border border-p-blue-50 text-p-blue-50">First</div>
|
|
6
|
+
<div class="flex items-center">
|
|
7
|
+
<iconify-icon icon="material-symbols:arrow-right-alt-rounded" class="text-p-blue-50"></iconify-icon>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="text-nowrap rounded-full border px-4 py-1 text-sm font-semibold border border-p-blue-50 bg-p-blue-50 text-surface">Second</div>
|
|
10
|
+
<div class="flex items-center">
|
|
11
|
+
<iconify-icon icon="material-symbols:arrow-right-alt-rounded" class="text-p-gray-30"></iconify-icon>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="text-nowrap rounded-full border px-4 py-1 text-sm font-semibold border border-p-gray-30 text-p-gray-30">Third</div>
|
|
14
|
+
<!--v-if-->
|
|
15
|
+
</div>"
|
|
16
|
+
`;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import PSteps from '@squirrel/components/p-steps/p-steps.vue';
|
|
2
|
+
import { createWrapperFor } from '@tests/vitest.helpers';
|
|
3
|
+
|
|
4
|
+
describe('PSteps.vue', () => {
|
|
5
|
+
it('renders correctly', () => {
|
|
6
|
+
const wrapper = createWrapperFor(PSteps, {
|
|
7
|
+
props: {
|
|
8
|
+
steps: ['first', 'second', 'third'],
|
|
9
|
+
currentStep: 'second',
|
|
10
|
+
stepTitleMap: {},
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
expect(wrapper.html()).toMatchSnapshot();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('renders the correct number of steps', () => {
|
|
17
|
+
const steps = ['first', 'second', 'third'];
|
|
18
|
+
const wrapper = createWrapperFor(PSteps, {
|
|
19
|
+
props: {
|
|
20
|
+
steps,
|
|
21
|
+
currentStep: 'second',
|
|
22
|
+
stepTitleMap: {},
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const stepElements = wrapper.findAll('.rounded-full.border');
|
|
27
|
+
expect(stepElements.length).toBe(steps.length);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('applies correct classes for current step', () => {
|
|
31
|
+
const wrapper = createWrapperFor(PSteps, {
|
|
32
|
+
props: {
|
|
33
|
+
steps: ['first', 'second', 'third'],
|
|
34
|
+
currentStep: 'second',
|
|
35
|
+
stepTitleMap: {},
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const stepElements = wrapper.findAll('.rounded-full.border');
|
|
40
|
+
|
|
41
|
+
// First step should be completed (blue text)
|
|
42
|
+
expect(stepElements[0].classes()).toContain('text-nowrap');
|
|
43
|
+
expect(stepElements[0].classes()).toContain('text-p-blue-50');
|
|
44
|
+
expect(stepElements[0].classes()).toContain('border-p-blue-50');
|
|
45
|
+
|
|
46
|
+
// Second step should be current (blue background)
|
|
47
|
+
expect(stepElements[1].classes()).toContain('text-nowrap');
|
|
48
|
+
expect(stepElements[1].classes()).toContain('bg-p-blue-50');
|
|
49
|
+
expect(stepElements[1].classes()).toContain('text-surface');
|
|
50
|
+
expect(stepElements[1].classes()).toContain('border-p-blue-50');
|
|
51
|
+
|
|
52
|
+
// Third step should be upcoming (gray)
|
|
53
|
+
expect(stepElements[2].classes()).toContain('text-nowrap');
|
|
54
|
+
expect(stepElements[2].classes()).toContain('text-p-gray-30');
|
|
55
|
+
expect(stepElements[2].classes()).toContain('border-p-gray-30');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('displays step titles from stepTitleMap when provided', () => {
|
|
59
|
+
const wrapper = createWrapperFor(PSteps, {
|
|
60
|
+
props: {
|
|
61
|
+
steps: ['step1', 'step2', 'step3'],
|
|
62
|
+
currentStep: 'step2',
|
|
63
|
+
stepTitleMap: {
|
|
64
|
+
step1: 'Custom Step 1',
|
|
65
|
+
step2: 'Custom Step 2',
|
|
66
|
+
step3: 'Custom Step 3',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const stepElements = wrapper.findAll('.rounded-full.border');
|
|
72
|
+
expect(stepElements[0].text()).toBe('Custom Step 1');
|
|
73
|
+
expect(stepElements[1].text()).toBe('Custom Step 2');
|
|
74
|
+
expect(stepElements[2].text()).toBe('Custom Step 3');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('uses startCase for step titles when stepTitleMap entry is not provided', () => {
|
|
78
|
+
const wrapper = createWrapperFor(PSteps, {
|
|
79
|
+
props: {
|
|
80
|
+
steps: ['firstStep', 'secondStep', 'thirdStep'],
|
|
81
|
+
currentStep: 'secondStep',
|
|
82
|
+
stepTitleMap: {
|
|
83
|
+
secondStep: 'Custom Second',
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const stepElements = wrapper.findAll('.rounded-full.border');
|
|
89
|
+
expect(stepElements[0].text()).toBe('First Step'); // startCase applied
|
|
90
|
+
expect(stepElements[1].text()).toBe('Custom Second'); // from map
|
|
91
|
+
expect(stepElements[2].text()).toBe('Third Step'); // startCase applied
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('renders the correct number of arrows between steps', () => {
|
|
95
|
+
const wrapper = createWrapperFor(PSteps, {
|
|
96
|
+
props: {
|
|
97
|
+
steps: ['first', 'second', 'third', 'fourth'],
|
|
98
|
+
currentStep: 'second',
|
|
99
|
+
stepTitleMap: {},
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// There should be 3 arrows for 4 steps
|
|
104
|
+
const arrowElements = wrapper.findAll('[icon="material-symbols:arrow-right-alt-rounded"]');
|
|
105
|
+
expect(arrowElements.length).toBe(3);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('applies the correct classes to arrows based on current step', () => {
|
|
109
|
+
const wrapper = createWrapperFor(PSteps, {
|
|
110
|
+
props: {
|
|
111
|
+
steps: ['first', 'second', 'third', 'fourth'],
|
|
112
|
+
currentStep: 'second',
|
|
113
|
+
stepTitleMap: {},
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const arrowElements = wrapper.findAll('[icon="material-symbols:arrow-right-alt-rounded"]');
|
|
118
|
+
|
|
119
|
+
// Arrow between first and second step should be colored
|
|
120
|
+
expect(arrowElements[0].classes()).toContain('text-p-blue-50');
|
|
121
|
+
|
|
122
|
+
// Arrow after current step should be gray
|
|
123
|
+
expect(arrowElements[1].classes()).toContain('text-p-gray-30');
|
|
124
|
+
expect(arrowElements[2].classes()).toContain('text-p-gray-30');
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import PSteps from '@squirrel/components/p-steps/p-steps.vue';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
title: 'Components/PSteps',
|
|
5
|
+
component: PSteps,
|
|
6
|
+
tags: ['autodocs'],
|
|
7
|
+
parameters: {
|
|
8
|
+
docs: {
|
|
9
|
+
description: {
|
|
10
|
+
component: 'Steps Component to be used in wizards',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const Default = {
|
|
17
|
+
render: (args) => ({
|
|
18
|
+
components: { PSteps },
|
|
19
|
+
setup() {
|
|
20
|
+
return { args };
|
|
21
|
+
},
|
|
22
|
+
template: `<PSteps v-bind="args" />`,
|
|
23
|
+
}),
|
|
24
|
+
args: {
|
|
25
|
+
steps: ['stepOne', 'stepTwo', 'stepThree', 'stepFour'],
|
|
26
|
+
currentStep: 'stepTwo',
|
|
27
|
+
stepTitleMap: {
|
|
28
|
+
stepTwo: 'Criteria',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|