@pequity/squirrel 8.3.5 → 8.4.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-tabs-pills.js +44 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/p-tabs-pills.js +3 -0
- package/dist/es/chunks/p-tabs-pills.js +45 -0
- package/dist/es/index.js +4 -2
- package/dist/es/p-tabs-pills.js +4 -0
- package/dist/squirrel/components/index.d.ts +2 -1
- package/dist/squirrel/components/p-tabs-pills/p-tabs-pills.vue.d.ts +21 -0
- package/package.json +23 -29
- package/squirrel/components/index.ts +2 -0
- package/squirrel/components/p-action-bar/p-action-bar.stories.js +2 -2
- package/squirrel/components/p-alert/p-alert.stories.js +1 -1
- package/squirrel/components/p-btn/p-btn.stories.js +2 -2
- package/squirrel/components/p-checkbox/p-checkbox.stories.js +1 -1
- package/squirrel/components/p-close-btn/p-close-btn.stories.js +2 -2
- package/squirrel/components/p-file-upload/p-file-upload.spec.js +1 -1
- package/squirrel/components/p-input-number/p-input-number.spec.js +1 -1
- package/squirrel/components/p-ring-loader/p-ring-loader.spec.js +1 -1
- package/squirrel/components/p-select-btn/p-select-btn.stories.js +1 -1
- package/squirrel/components/p-select-pill/p-select-pill.stories.js +1 -1
- package/squirrel/components/p-table-header-cell/p-table-header-cell.stories.js +1 -1
- package/squirrel/components/p-tabs/p-tabs.stories.js +1 -1
- package/squirrel/components/p-tabs-pills/p-tabs-pills.spec.js +117 -0
- package/squirrel/components/p-tabs-pills/p-tabs-pills.stories.js +139 -0
- package/squirrel/components/p-tabs-pills/p-tabs-pills.vue +60 -0
- package/squirrel/components/p-toggle/p-toggle.spec.js +1 -1
- package/squirrel/composables/useInputClasses.spec.js +1 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const vue = require("vue");
|
|
3
|
+
const _hoisted_1 = {
|
|
4
|
+
class: "flex h-6 w-fit flex-row space-x-1 overflow-x-auto rounded bg-p-gray-10 p-1 text-sm font-medium text-p-gray-50",
|
|
5
|
+
"aria-label": "Tabs Pills",
|
|
6
|
+
role: "tablist",
|
|
7
|
+
"aria-orientation": "horizontal"
|
|
8
|
+
};
|
|
9
|
+
const _hoisted_2 = ["disabled", "aria-selected", "data-tab", "aria-controls", "onClick"];
|
|
10
|
+
const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
11
|
+
...{
|
|
12
|
+
name: "PTabsPills"
|
|
13
|
+
},
|
|
14
|
+
__name: "p-tabs-pills",
|
|
15
|
+
props: {
|
|
16
|
+
modelValue: { type: [String, Number, Boolean], default: "" },
|
|
17
|
+
items: { default: () => [] },
|
|
18
|
+
itemText: { default: "text" },
|
|
19
|
+
itemValue: { default: "value" }
|
|
20
|
+
},
|
|
21
|
+
emits: ["update:modelValue"],
|
|
22
|
+
setup(__props) {
|
|
23
|
+
return (_ctx, _cache) => {
|
|
24
|
+
return vue.openBlock(), vue.createElementBlock("nav", _hoisted_1, [
|
|
25
|
+
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(_ctx.items, (tab) => {
|
|
26
|
+
return vue.openBlock(), vue.createElementBlock("button", {
|
|
27
|
+
key: String(tab[_ctx.itemValue]),
|
|
28
|
+
type: "button",
|
|
29
|
+
class: vue.normalizeClass(["rounded px-2 pb-px leading-none transition-all duration-300", [
|
|
30
|
+
tab.disabled ? "text-p-gray-30" : tab[_ctx.itemValue] === _ctx.modelValue ? "bg-night text-surface hover:bg-night hover:text-surface" : "hover:text-p-gray-70"
|
|
31
|
+
]]),
|
|
32
|
+
disabled: !!tab.disabled,
|
|
33
|
+
role: "tab",
|
|
34
|
+
"aria-selected": tab[_ctx.itemValue] === _ctx.modelValue,
|
|
35
|
+
"data-tab": `#${tab[_ctx.itemValue]}`,
|
|
36
|
+
"aria-controls": String(tab[_ctx.itemValue]),
|
|
37
|
+
onClick: ($event) => _ctx.$emit("update:modelValue", tab[_ctx.itemValue])
|
|
38
|
+
}, vue.toDisplayString(tab[_ctx.itemText]), 11, _hoisted_2);
|
|
39
|
+
}), 128))
|
|
40
|
+
]);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
exports._sfc_main = _sfc_main;
|
package/dist/cjs/index.js
CHANGED
|
@@ -52,6 +52,7 @@ const pTableFilterIcon = require("./p-table-filter-icon.js");
|
|
|
52
52
|
const pTableLoader_vue_vue_type_script_setup_true_lang = require("./chunks/p-table-loader.js");
|
|
53
53
|
const pTableSort = require("./p-table-sort.js");
|
|
54
54
|
const pTabs_vue_vue_type_script_setup_true_lang = require("./chunks/p-tabs.js");
|
|
55
|
+
const pTabsPills_vue_vue_type_script_setup_true_lang = require("./chunks/p-tabs-pills.js");
|
|
55
56
|
const pTextarea_vue_vue_type_script_setup_true_lang = require("./chunks/p-textarea.js");
|
|
56
57
|
const pToggle = require("./p-toggle.js");
|
|
57
58
|
const config = require("./config.js");
|
|
@@ -1086,6 +1087,7 @@ exports.PFilterIcon = pTableFilterIcon;
|
|
|
1086
1087
|
exports.PTableLoader = pTableLoader_vue_vue_type_script_setup_true_lang._sfc_main;
|
|
1087
1088
|
exports.SORTING_TYPES = pTableSort.SORTING_TYPES;
|
|
1088
1089
|
exports.PTabs = pTabs_vue_vue_type_script_setup_true_lang._sfc_main;
|
|
1090
|
+
exports.PTabsPills = pTabsPills_vue_vue_type_script_setup_true_lang._sfc_main;
|
|
1089
1091
|
exports.PTextarea = pTextarea_vue_vue_type_script_setup_true_lang._sfc_main;
|
|
1090
1092
|
exports.PToggle = pToggle;
|
|
1091
1093
|
exports.squirrelTailwindConfig = config.squirrelTailwindConfig;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { defineComponent, createElementBlock, openBlock, Fragment, renderList, normalizeClass, toDisplayString } from "vue";
|
|
2
|
+
const _hoisted_1 = {
|
|
3
|
+
class: "flex h-6 w-fit flex-row space-x-1 overflow-x-auto rounded bg-p-gray-10 p-1 text-sm font-medium text-p-gray-50",
|
|
4
|
+
"aria-label": "Tabs Pills",
|
|
5
|
+
role: "tablist",
|
|
6
|
+
"aria-orientation": "horizontal"
|
|
7
|
+
};
|
|
8
|
+
const _hoisted_2 = ["disabled", "aria-selected", "data-tab", "aria-controls", "onClick"];
|
|
9
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
10
|
+
...{
|
|
11
|
+
name: "PTabsPills"
|
|
12
|
+
},
|
|
13
|
+
__name: "p-tabs-pills",
|
|
14
|
+
props: {
|
|
15
|
+
modelValue: { type: [String, Number, Boolean], default: "" },
|
|
16
|
+
items: { default: () => [] },
|
|
17
|
+
itemText: { default: "text" },
|
|
18
|
+
itemValue: { default: "value" }
|
|
19
|
+
},
|
|
20
|
+
emits: ["update:modelValue"],
|
|
21
|
+
setup(__props) {
|
|
22
|
+
return (_ctx, _cache) => {
|
|
23
|
+
return openBlock(), createElementBlock("nav", _hoisted_1, [
|
|
24
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.items, (tab) => {
|
|
25
|
+
return openBlock(), createElementBlock("button", {
|
|
26
|
+
key: String(tab[_ctx.itemValue]),
|
|
27
|
+
type: "button",
|
|
28
|
+
class: normalizeClass(["rounded px-2 pb-px leading-none transition-all duration-300", [
|
|
29
|
+
tab.disabled ? "text-p-gray-30" : tab[_ctx.itemValue] === _ctx.modelValue ? "bg-night text-surface hover:bg-night hover:text-surface" : "hover:text-p-gray-70"
|
|
30
|
+
]]),
|
|
31
|
+
disabled: !!tab.disabled,
|
|
32
|
+
role: "tab",
|
|
33
|
+
"aria-selected": tab[_ctx.itemValue] === _ctx.modelValue,
|
|
34
|
+
"data-tab": `#${tab[_ctx.itemValue]}`,
|
|
35
|
+
"aria-controls": String(tab[_ctx.itemValue]),
|
|
36
|
+
onClick: ($event) => _ctx.$emit("update:modelValue", tab[_ctx.itemValue])
|
|
37
|
+
}, toDisplayString(tab[_ctx.itemText]), 11, _hoisted_2);
|
|
38
|
+
}), 128))
|
|
39
|
+
]);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
export {
|
|
44
|
+
_sfc_main as _
|
|
45
|
+
};
|
package/dist/es/index.js
CHANGED
|
@@ -52,7 +52,8 @@ import { default as default11 } from "./p-table-filter-icon.js";
|
|
|
52
52
|
import { _ as _20 } from "./chunks/p-table-loader.js";
|
|
53
53
|
import { SORTING_TYPES } from "./p-table-sort.js";
|
|
54
54
|
import { _ as _21 } from "./chunks/p-tabs.js";
|
|
55
|
-
import { _ as _22 } from "./chunks/p-
|
|
55
|
+
import { _ as _22 } from "./chunks/p-tabs-pills.js";
|
|
56
|
+
import { _ as _23 } from "./chunks/p-textarea.js";
|
|
56
57
|
import { default as default12 } from "./p-toggle.js";
|
|
57
58
|
import { squirrelTailwindConfig } from "./config.js";
|
|
58
59
|
import { S } from "./chunks/p-btn.types.js";
|
|
@@ -1079,7 +1080,8 @@ export {
|
|
|
1079
1080
|
_sfc_main as PTableSort,
|
|
1080
1081
|
PTableTd,
|
|
1081
1082
|
_21 as PTabs,
|
|
1082
|
-
_22 as
|
|
1083
|
+
_22 as PTabsPills,
|
|
1084
|
+
_23 as PTextarea,
|
|
1083
1085
|
default12 as PToggle,
|
|
1084
1086
|
P_ICON_ALIASES,
|
|
1085
1087
|
S as SIZES,
|
|
@@ -50,6 +50,7 @@ import { SORTING_TYPES, type SortingType, type SortingTypeWithoutNoSorting } fro
|
|
|
50
50
|
import PTableSort from './p-table-sort/p-table-sort.vue';
|
|
51
51
|
import PTableTd from './p-table-td/p-table-td.vue';
|
|
52
52
|
import PTabs from './p-tabs/p-tabs.vue';
|
|
53
|
+
import PTabsPills from './p-tabs-pills/p-tabs-pills.vue';
|
|
53
54
|
import PTextarea from './p-textarea/p-textarea.vue';
|
|
54
55
|
import PToggle from './p-toggle/p-toggle.vue';
|
|
55
|
-
export { colsInjectionKey, FileUploadFile, HeaderCellAttrs, isColsResizableInjectionKey, isFirstColFixedInjectionKey, isLastColFixedInjectionKey, MIN_WIDTH_COL_RESIZE, P_ICON_ALIASES, PActionBar, PActionBarAction, PAlert, PAvatar, PBtn, PCard, PCheckbox, PChips, PCloseBtn, PDatePicker, PDrawer, PDropdown, PDropdownSelect, PFileUpload, PFilterIcon, PIcon, PIconAlias, PInfoIcon, PInlineDatePicker, PInput, PInputNumber, PInputPercent, PInputSearch, PLink, PLoading, PModal, PPagination, PPaginationInfo, PProgressBar, PRingLoader, PSelect, PSelectBtn, PSelectList, PSelectPill, PSkeletonLoader, PSteps, PTable, PTableHeaderCell, PTableLoader, PTableSort, PTableTd, PTabs, PTextarea, PToggle, Size, SORTING_TYPES, SortingType, SortingTypeWithoutNoSorting, StepItem, TableCol, ThAttrs, usePLoading, usePModal, usePTableColResize, usePTableRowVirtualizer, useSelectList, };
|
|
56
|
+
export { colsInjectionKey, FileUploadFile, HeaderCellAttrs, isColsResizableInjectionKey, isFirstColFixedInjectionKey, isLastColFixedInjectionKey, MIN_WIDTH_COL_RESIZE, P_ICON_ALIASES, PActionBar, PActionBarAction, PAlert, PAvatar, PBtn, PCard, PCheckbox, PChips, PCloseBtn, PDatePicker, PDrawer, PDropdown, PDropdownSelect, PFileUpload, PFilterIcon, PIcon, PIconAlias, PInfoIcon, PInlineDatePicker, PInput, PInputNumber, PInputPercent, PInputSearch, PLink, PLoading, PModal, PPagination, PPaginationInfo, PProgressBar, PRingLoader, PSelect, PSelectBtn, PSelectList, PSelectPill, PSkeletonLoader, PSteps, PTable, PTableHeaderCell, PTableLoader, PTableSort, PTableTd, PTabs, PTabsPills, PTextarea, PToggle, Size, SORTING_TYPES, SortingType, SortingTypeWithoutNoSorting, StepItem, TableCol, ThAttrs, usePLoading, usePModal, usePTableColResize, usePTableRowVirtualizer, useSelectList, };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type Value = string | number | boolean;
|
|
2
|
+
type Option = {
|
|
3
|
+
[key: string]: Value;
|
|
4
|
+
};
|
|
5
|
+
type Props = {
|
|
6
|
+
modelValue?: Value;
|
|
7
|
+
items?: readonly Option[];
|
|
8
|
+
itemText?: string;
|
|
9
|
+
itemValue?: string;
|
|
10
|
+
};
|
|
11
|
+
declare const _default: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
12
|
+
"update:modelValue": (val: Value) => any;
|
|
13
|
+
}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
|
|
14
|
+
"onUpdate:modelValue"?: ((val: Value) => any) | undefined;
|
|
15
|
+
}>, {
|
|
16
|
+
modelValue: Value;
|
|
17
|
+
items: readonly Option[];
|
|
18
|
+
itemText: string;
|
|
19
|
+
itemValue: string;
|
|
20
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
|
+
export default _default;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pequity/squirrel",
|
|
3
3
|
"description": "Squirrel component library",
|
|
4
|
-
"version": "8.
|
|
4
|
+
"version": "8.4.0",
|
|
5
5
|
"packageManager": "pnpm@10.6.4",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
@@ -49,56 +49,50 @@
|
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@commitlint/cli": "^19.8.1",
|
|
51
51
|
"@commitlint/config-conventional": "^19.8.1",
|
|
52
|
-
"@pequity/eslint-config": "^2.0.
|
|
53
|
-
"@playwright/test": "^1.
|
|
52
|
+
"@pequity/eslint-config": "^2.0.2",
|
|
53
|
+
"@playwright/test": "^1.53.0",
|
|
54
54
|
"@semantic-release/changelog": "^6.0.3",
|
|
55
55
|
"@semantic-release/git": "^10.0.1",
|
|
56
|
-
"@storybook/addon-a11y": "^
|
|
57
|
-
"@storybook/addon-
|
|
58
|
-
"@storybook/addon-
|
|
59
|
-
"@storybook/
|
|
60
|
-
"@storybook/
|
|
61
|
-
"@storybook/
|
|
62
|
-
"@
|
|
63
|
-
"@storybook/test": "^8.6.14",
|
|
64
|
-
"@storybook/test-runner": "^0.22.0",
|
|
65
|
-
"@storybook/theming": "^8.6.14",
|
|
66
|
-
"@storybook/vue3": "^8.6.14",
|
|
67
|
-
"@storybook/vue3-vite": "^8.6.14",
|
|
68
|
-
"@tanstack/vue-virtual": "3.13.9",
|
|
56
|
+
"@storybook/addon-a11y": "^9.0.10",
|
|
57
|
+
"@storybook/addon-docs": "^9.0.10",
|
|
58
|
+
"@storybook/addon-links": "^9.0.10",
|
|
59
|
+
"@storybook/test-runner": "^0.23.0",
|
|
60
|
+
"@storybook/vue3": "^9.0.10",
|
|
61
|
+
"@storybook/vue3-vite": "^9.0.10",
|
|
62
|
+
"@tanstack/vue-virtual": "3.13.10",
|
|
69
63
|
"@types/jsdom": "^21.1.7",
|
|
70
64
|
"@types/lodash-es": "^4.17.12",
|
|
71
|
-
"@types/node": "^
|
|
65
|
+
"@types/node": "^24.0.3",
|
|
72
66
|
"@vitejs/plugin-vue": "^5.2.4",
|
|
73
|
-
"@vitest/coverage-v8": "^3.
|
|
74
|
-
"@vue/compiler-sfc": "3.5.
|
|
67
|
+
"@vitest/coverage-v8": "^3.2.3",
|
|
68
|
+
"@vue/compiler-sfc": "3.5.16",
|
|
75
69
|
"@vue/test-utils": "^2.4.6",
|
|
76
70
|
"@vuepic/vue-datepicker": "11.0.2",
|
|
77
71
|
"autoprefixer": "^10.4.21",
|
|
78
|
-
"eslint": "^9.
|
|
79
|
-
"eslint-plugin-storybook": "^0.
|
|
72
|
+
"eslint": "^9.29.0",
|
|
73
|
+
"eslint-plugin-storybook": "^9.0.10",
|
|
80
74
|
"floating-vue": "5.2.2",
|
|
81
|
-
"glob": "^11.0.
|
|
75
|
+
"glob": "^11.0.3",
|
|
82
76
|
"husky": "^9.1.7",
|
|
83
77
|
"iconify-icon": "^3.0.0",
|
|
84
78
|
"jsdom": "^26.1.0",
|
|
85
|
-
"lint-staged": "^16.
|
|
79
|
+
"lint-staged": "^16.1.2",
|
|
86
80
|
"lodash-es": "4.17.21",
|
|
87
81
|
"make-coverage-badge": "^1.2.0",
|
|
88
|
-
"postcss": "^8.5.
|
|
82
|
+
"postcss": "^8.5.6",
|
|
89
83
|
"prettier": "^3.5.3",
|
|
90
|
-
"prettier-plugin-tailwindcss": "^0.6.
|
|
84
|
+
"prettier-plugin-tailwindcss": "^0.6.12",
|
|
91
85
|
"resolve-tspaths": "^0.8.23",
|
|
92
86
|
"rimraf": "^6.0.1",
|
|
93
|
-
"sass": "^1.89.
|
|
87
|
+
"sass": "^1.89.2",
|
|
94
88
|
"semantic-release": "^24.2.5",
|
|
95
|
-
"storybook": "^
|
|
89
|
+
"storybook": "^9.0.10",
|
|
96
90
|
"svgo": "^3.3.2",
|
|
97
91
|
"tailwindcss": "^3.4.17",
|
|
98
92
|
"typescript": "5.8.3",
|
|
99
93
|
"vite": "^6.3.5",
|
|
100
|
-
"vitest": "^3.
|
|
101
|
-
"vue": "3.5.
|
|
94
|
+
"vitest": "^3.2.3",
|
|
95
|
+
"vue": "3.5.16",
|
|
102
96
|
"vue-currency-input": "3.2.1",
|
|
103
97
|
"vue-router": "4.5.1",
|
|
104
98
|
"vue-toastification": "2.0.0-rc.5",
|
|
@@ -63,6 +63,7 @@ import {
|
|
|
63
63
|
import PTableSort from '@squirrel/components/p-table-sort/p-table-sort.vue';
|
|
64
64
|
import PTableTd from '@squirrel/components/p-table-td/p-table-td.vue';
|
|
65
65
|
import PTabs from '@squirrel/components/p-tabs/p-tabs.vue';
|
|
66
|
+
import PTabsPills from '@squirrel/components/p-tabs-pills/p-tabs-pills.vue';
|
|
66
67
|
import PTextarea from '@squirrel/components/p-textarea/p-textarea.vue';
|
|
67
68
|
import PToggle from '@squirrel/components/p-toggle/p-toggle.vue';
|
|
68
69
|
|
|
@@ -117,6 +118,7 @@ export {
|
|
|
117
118
|
PTableSort,
|
|
118
119
|
PTableTd,
|
|
119
120
|
PTabs,
|
|
121
|
+
PTabsPills,
|
|
120
122
|
PTextarea,
|
|
121
123
|
PToggle,
|
|
122
124
|
Size,
|
|
@@ -2,8 +2,8 @@ import PaginateLeftIcon from '@squirrel/assets/pagination-left-icon.svg?inline';
|
|
|
2
2
|
import PaginateRightIcon from '@squirrel/assets/pagination-right-icon.svg?inline';
|
|
3
3
|
import PActionBar from '@squirrel/components/p-action-bar/p-action-bar.vue';
|
|
4
4
|
import PBtn from '@squirrel/components/p-btn/p-btn.vue';
|
|
5
|
-
import { action } from '
|
|
6
|
-
import { expect, fn, userEvent, waitFor, within } from '
|
|
5
|
+
import { action } from 'storybook/actions';
|
|
6
|
+
import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
|
|
7
7
|
|
|
8
8
|
const actionBarActions = [
|
|
9
9
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import PBtn from '@squirrel/components/p-btn/p-btn.vue';
|
|
2
|
-
import { action } from '
|
|
3
|
-
import { expect, within } from '
|
|
2
|
+
import { action } from 'storybook/actions';
|
|
3
|
+
import { expect, within } from 'storybook/test';
|
|
4
4
|
|
|
5
5
|
// You can also import an `md` file and use it as a story's description
|
|
6
6
|
// import PBtnReadme from './PBtn.readme.md';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import PCloseBtn from '@squirrel/components/p-close-btn/p-close-btn.vue';
|
|
2
|
-
import { action } from '
|
|
3
|
-
import { expect, within } from '
|
|
2
|
+
import { action } from 'storybook/actions';
|
|
3
|
+
import { expect, within } from 'storybook/test';
|
|
4
4
|
|
|
5
5
|
export default {
|
|
6
6
|
title: 'Components/PCloseBtn',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import PFileUpload from '@squirrel/components/p-file-upload/p-file-upload.vue';
|
|
2
|
-
import { expect } from '@storybook/test';
|
|
3
2
|
import { createWrapperFor } from '@tests/vitest.helpers';
|
|
3
|
+
import { expect } from 'storybook/test';
|
|
4
4
|
import { vi } from 'vitest';
|
|
5
5
|
|
|
6
6
|
// Mocking the toastification library
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import PInputNumber from '@squirrel/components/p-input-number/p-input-number.vue';
|
|
2
|
-
import { expect } from '@storybook/test';
|
|
3
2
|
import { createWrapperFor } from '@tests/vitest.helpers';
|
|
3
|
+
import { expect } from 'storybook/test';
|
|
4
4
|
|
|
5
5
|
const baseClasses = () => [
|
|
6
6
|
'text-night',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import PRingLoader from '@squirrel/components/p-ring-loader/p-ring-loader.vue';
|
|
2
|
-
import { expect } from '@storybook/test';
|
|
3
2
|
import { createWrapperFor } from '@tests/vitest.helpers';
|
|
3
|
+
import { expect } from 'storybook/test';
|
|
4
4
|
|
|
5
5
|
describe('PRingLoader.vue', () => {
|
|
6
6
|
it('renders correctly with custom props', async () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fieldArgTypes } from '@root/stories/common/field';
|
|
2
2
|
import PSelectBtn from '@squirrel/components/p-select-btn/p-select-btn.vue';
|
|
3
|
-
import { expect, userEvent, within } from '
|
|
3
|
+
import { expect, userEvent, within } from 'storybook/test';
|
|
4
4
|
import { ref } from 'vue';
|
|
5
5
|
|
|
6
6
|
const selectItems = [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fieldArgTypes } from '@root/stories/common/field';
|
|
2
2
|
import { getCSSTransitionDuration, sleep } from '@root/stories/common/helpers';
|
|
3
3
|
import PSelectPill from '@squirrel/components/p-select-pill/p-select-pill.vue';
|
|
4
|
-
import { expect, userEvent, within } from '
|
|
4
|
+
import { expect, userEvent, within } from 'storybook/test';
|
|
5
5
|
import { ref } from 'vue';
|
|
6
6
|
|
|
7
7
|
const ACTIVE_CLASS = 'text-p-purple-60';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import PaginateRightIcon from '@squirrel/assets/pagination-right-icon.svg?inline';
|
|
2
2
|
import PTabs from '@squirrel/components/p-tabs/p-tabs.vue';
|
|
3
|
-
import { action } from '
|
|
3
|
+
import { action } from 'storybook/actions';
|
|
4
4
|
|
|
5
5
|
export default {
|
|
6
6
|
title: 'Components/PTabs',
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import PTabsPills from '@squirrel/components/p-tabs-pills/p-tabs-pills.vue';
|
|
2
|
+
import { createWrapperFor } from '@tests/vitest.helpers';
|
|
3
|
+
|
|
4
|
+
const ACTIVE_CLASSES = ['bg-night', 'text-surface', 'hover:bg-night', 'hover:text-surface'];
|
|
5
|
+
|
|
6
|
+
const createTabItems = () => [
|
|
7
|
+
{ value: 'tab1', text: 'Home' },
|
|
8
|
+
{ value: 'tab2', text: 'Profile' },
|
|
9
|
+
{ value: 'tab3', text: 'Messages' },
|
|
10
|
+
{ value: 'tab4', text: 'About' },
|
|
11
|
+
{ value: 'tab5', text: 'Settings' },
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
const createWrapper = (props = {}) => {
|
|
15
|
+
return createWrapperFor(PTabsPills, {
|
|
16
|
+
props: {
|
|
17
|
+
items: createTabItems(),
|
|
18
|
+
...props,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
describe('PTabsPills.vue', () => {
|
|
24
|
+
it('renders correctly', async () => {
|
|
25
|
+
const wrapper = createWrapper();
|
|
26
|
+
const buttons = await wrapper.findAll('button');
|
|
27
|
+
|
|
28
|
+
buttons.forEach((button) => {
|
|
29
|
+
ACTIVE_CLASSES.forEach((className) => {
|
|
30
|
+
expect(button.classes()).not.toContain(className);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
expect(buttons.length).toBe(5);
|
|
34
|
+
expect(buttons[1].text()).toBe(createTabItems()[1].text);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it(`updates the value bound with v-model`, async () => {
|
|
38
|
+
const wrapper = createWrapperFor({
|
|
39
|
+
data() {
|
|
40
|
+
return {
|
|
41
|
+
selected: 'tab1',
|
|
42
|
+
items: createTabItems(),
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
template: '<PTabsPills :items="items" v-model="selected" />',
|
|
46
|
+
components: { PTabsPills },
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
await wrapper.setData({ selected: 'tab4' });
|
|
50
|
+
|
|
51
|
+
const selected = wrapper.findAll('button')[3];
|
|
52
|
+
|
|
53
|
+
ACTIVE_CLASSES.forEach((className) => {
|
|
54
|
+
expect(selected.classes()).toContain(className);
|
|
55
|
+
});
|
|
56
|
+
expect(selected.attributes('aria-selected')).toBe('true');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it(`updates the value bound with v-model when an option is clicked`, async () => {
|
|
60
|
+
const wrapper = createWrapperFor({
|
|
61
|
+
data() {
|
|
62
|
+
return {
|
|
63
|
+
selected: 'tab1',
|
|
64
|
+
items: createTabItems(),
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
template: '<PTabsPills :items="items" v-model="selected" />',
|
|
68
|
+
components: { PTabsPills },
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
await wrapper.findAll('button')[3].trigger('click');
|
|
72
|
+
|
|
73
|
+
const selected = wrapper.findAll('button')[3];
|
|
74
|
+
|
|
75
|
+
ACTIVE_CLASSES.forEach((className) => {
|
|
76
|
+
expect(selected.classes()).toContain(className);
|
|
77
|
+
});
|
|
78
|
+
expect(selected.attributes('aria-selected')).toBe('true');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('works with custom itemValue and itemText', async () => {
|
|
82
|
+
const tabItems = createTabItems();
|
|
83
|
+
|
|
84
|
+
const wrapper = createWrapper({
|
|
85
|
+
items: tabItems.map((item) => ({ customValue: item.value, customText: item.text })),
|
|
86
|
+
itemValue: 'customValue',
|
|
87
|
+
itemText: 'customText',
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const buttons = await wrapper.findAll('button');
|
|
91
|
+
|
|
92
|
+
expect(buttons.length).toBe(5);
|
|
93
|
+
|
|
94
|
+
buttons.forEach((button, i) => {
|
|
95
|
+
expect(button.text()).toBe(tabItems[i].text);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it(`disables an option based on the disabled attribute`, async () => {
|
|
100
|
+
const wrapper = createWrapper({
|
|
101
|
+
items: createTabItems().map((item, i) => ({ ...item, disabled: i === 2 })),
|
|
102
|
+
modelValue: 'tab1',
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const buttons = await wrapper.findAll('button');
|
|
106
|
+
|
|
107
|
+
buttons.forEach((button, i) => {
|
|
108
|
+
if (i === 2) {
|
|
109
|
+
expect(button.element.disabled).toBe(true);
|
|
110
|
+
expect(button.classes()).toContain('text-p-gray-30');
|
|
111
|
+
} else {
|
|
112
|
+
expect(button.element.disabled).toBe(false);
|
|
113
|
+
expect(button.classes()).not.toContain('text-p-gray-30');
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import PTabsPills from '@squirrel/components/p-tabs-pills/p-tabs-pills.vue';
|
|
2
|
+
import { expect, userEvent, within } from 'storybook/test';
|
|
3
|
+
import { ref } from 'vue';
|
|
4
|
+
|
|
5
|
+
const ACTIVE_CLASSES = ['bg-night', 'text-surface', 'hover:bg-night', 'hover:text-surface'];
|
|
6
|
+
|
|
7
|
+
const DISABLED_CLASSES = ['text-p-gray-30'];
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
title: 'Components/PTabsPills',
|
|
11
|
+
component: PTabsPills,
|
|
12
|
+
tags: ['autodocs'],
|
|
13
|
+
render: (args) => ({
|
|
14
|
+
components: { PTabsPills },
|
|
15
|
+
setup() {
|
|
16
|
+
const selected = ref('tab1');
|
|
17
|
+
|
|
18
|
+
return { args, selected };
|
|
19
|
+
},
|
|
20
|
+
template: `
|
|
21
|
+
<PTabsPills v-model="selected" v-bind="args" />
|
|
22
|
+
<div class="mt-2">Selected: {{ selected }}</div>
|
|
23
|
+
`,
|
|
24
|
+
}),
|
|
25
|
+
parameters: {
|
|
26
|
+
docs: {
|
|
27
|
+
description: {
|
|
28
|
+
component: `PTabsPills can be used as a tab or button group that allows the user to select an option from a list of options.`,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const Default = {
|
|
35
|
+
args: {
|
|
36
|
+
items: [
|
|
37
|
+
{ value: 'tab1', text: 'Home' },
|
|
38
|
+
{ value: 'tab2', text: 'Profile' },
|
|
39
|
+
{ value: 'tab3', text: 'Messages' },
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
play: async ({ canvasElement }) => {
|
|
43
|
+
const canvas = within(canvasElement);
|
|
44
|
+
|
|
45
|
+
await userEvent.click(canvas.getByText(/Profile/i));
|
|
46
|
+
|
|
47
|
+
const button = canvas.getByText(/Profile/i).closest('button');
|
|
48
|
+
ACTIVE_CLASSES.forEach((className) => {
|
|
49
|
+
expect(button.classList).toContain(className);
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const CustomValueAndText = {
|
|
55
|
+
args: {
|
|
56
|
+
items: [
|
|
57
|
+
{ myValue: 'tab1', myText: 'Home' },
|
|
58
|
+
{ myValue: 'tab2', myText: 'Profile' },
|
|
59
|
+
{ myValue: 'tab3', myText: 'Messages' },
|
|
60
|
+
],
|
|
61
|
+
itemValue: 'myValue',
|
|
62
|
+
itemText: 'myText',
|
|
63
|
+
},
|
|
64
|
+
parameters: {
|
|
65
|
+
docs: {
|
|
66
|
+
description: {
|
|
67
|
+
story: 'You can customize the property names used for value and text using `itemValue` and `itemText` props.',
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
play: async ({ canvasElement }) => {
|
|
72
|
+
const canvas = within(canvasElement);
|
|
73
|
+
|
|
74
|
+
await userEvent.click(canvas.getByText(/Profile/i));
|
|
75
|
+
|
|
76
|
+
const button = canvas.getByText(/Profile/i).closest('button');
|
|
77
|
+
ACTIVE_CLASSES.forEach((className) => {
|
|
78
|
+
expect(button.classList).toContain(className);
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const DisabledItems = {
|
|
84
|
+
args: {
|
|
85
|
+
items: [
|
|
86
|
+
{ myValue: 'tab1', myText: 'Home', disabled: false },
|
|
87
|
+
{ myValue: 'tab2', myText: 'Profile', disabled: true },
|
|
88
|
+
{ myValue: 'tab3', myText: 'About', disabled: true },
|
|
89
|
+
{ myValue: 'tab4', myText: 'Messages', disabled: false },
|
|
90
|
+
],
|
|
91
|
+
itemValue: 'myValue',
|
|
92
|
+
itemText: 'myText',
|
|
93
|
+
},
|
|
94
|
+
parameters: {
|
|
95
|
+
docs: {
|
|
96
|
+
description: {
|
|
97
|
+
story: 'You can disable specific tabs by adding a `disabled` property to the items.',
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
play: async ({ canvasElement }) => {
|
|
102
|
+
const canvas = within(canvasElement);
|
|
103
|
+
|
|
104
|
+
// Check that disabled buttons have disabled classes
|
|
105
|
+
const disabledButtons = [
|
|
106
|
+
canvas.getByText(/Profile/i).closest('button'),
|
|
107
|
+
canvas.getByText(/About/i).closest('button'),
|
|
108
|
+
];
|
|
109
|
+
disabledButtons.forEach((button) => {
|
|
110
|
+
DISABLED_CLASSES.forEach((className) => {
|
|
111
|
+
expect(button.classList).toContain(className);
|
|
112
|
+
});
|
|
113
|
+
ACTIVE_CLASSES.forEach((className) => {
|
|
114
|
+
expect(button.classList).not.toContain(className);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Try to click a disabled button
|
|
119
|
+
await userEvent.click(canvas.getByText(/Profile/i));
|
|
120
|
+
|
|
121
|
+
// Check that disabled button still has disabled classes and not active classes
|
|
122
|
+
const disabledButton = canvas.getByText(/Profile/i).closest('button');
|
|
123
|
+
DISABLED_CLASSES.forEach((className) => {
|
|
124
|
+
expect(disabledButton.classList).toContain(className);
|
|
125
|
+
});
|
|
126
|
+
ACTIVE_CLASSES.forEach((className) => {
|
|
127
|
+
expect(disabledButton.classList).not.toContain(className);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Check that Home button still has active classes
|
|
131
|
+
const homeButton = canvas.getByText(/Home/i).closest('button');
|
|
132
|
+
ACTIVE_CLASSES.forEach((className) => {
|
|
133
|
+
expect(homeButton.classList).toContain(className);
|
|
134
|
+
});
|
|
135
|
+
DISABLED_CLASSES.forEach((className) => {
|
|
136
|
+
expect(homeButton.classList).not.toContain(className);
|
|
137
|
+
});
|
|
138
|
+
},
|
|
139
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<nav
|
|
3
|
+
class="flex h-6 w-fit flex-row space-x-1 overflow-x-auto rounded bg-p-gray-10 p-1 text-sm font-medium text-p-gray-50"
|
|
4
|
+
aria-label="Tabs Pills"
|
|
5
|
+
role="tablist"
|
|
6
|
+
aria-orientation="horizontal"
|
|
7
|
+
>
|
|
8
|
+
<button
|
|
9
|
+
v-for="tab in items"
|
|
10
|
+
:key="String(tab[itemValue])"
|
|
11
|
+
type="button"
|
|
12
|
+
class="rounded px-2 pb-px leading-none transition-all duration-300"
|
|
13
|
+
:class="[
|
|
14
|
+
tab.disabled
|
|
15
|
+
? 'text-p-gray-30'
|
|
16
|
+
: tab[itemValue] === modelValue
|
|
17
|
+
? 'bg-night text-surface hover:bg-night hover:text-surface'
|
|
18
|
+
: 'hover:text-p-gray-70',
|
|
19
|
+
]"
|
|
20
|
+
:disabled="!!tab.disabled"
|
|
21
|
+
role="tab"
|
|
22
|
+
:aria-selected="tab[itemValue] === modelValue"
|
|
23
|
+
:data-tab="`#${tab[itemValue]}`"
|
|
24
|
+
:aria-controls="String(tab[itemValue])"
|
|
25
|
+
@click="$emit('update:modelValue', tab[itemValue])"
|
|
26
|
+
>
|
|
27
|
+
{{ tab[itemText] }}
|
|
28
|
+
</button>
|
|
29
|
+
</nav>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script setup lang="ts">
|
|
33
|
+
defineOptions({
|
|
34
|
+
name: 'PTabsPills',
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
type Value = string | number | boolean;
|
|
38
|
+
|
|
39
|
+
type Option = {
|
|
40
|
+
[key: string]: Value;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
type Props = {
|
|
44
|
+
modelValue?: Value;
|
|
45
|
+
items?: readonly Option[];
|
|
46
|
+
itemText?: string;
|
|
47
|
+
itemValue?: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
withDefaults(defineProps<Props>(), {
|
|
51
|
+
modelValue: '',
|
|
52
|
+
items: () => [],
|
|
53
|
+
itemValue: 'value',
|
|
54
|
+
itemText: 'text',
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
defineEmits<{
|
|
58
|
+
'update:modelValue': [val: Value];
|
|
59
|
+
}>();
|
|
60
|
+
</script>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import PToggle from '@squirrel/components/p-toggle/p-toggle.vue';
|
|
2
|
-
import { expect } from '@storybook/test';
|
|
3
2
|
import { createWrapperFor } from '@tests/vitest.helpers';
|
|
3
|
+
import { expect } from 'storybook/test';
|
|
4
4
|
|
|
5
5
|
describe('PToggle.vue', () => {
|
|
6
6
|
it('renders correctly', async () => {
|