@pequity/squirrel 1.0.23 → 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 +55 -4
- package/dist/cjs/p-btn.js +2 -190
- package/dist/cjs/p-dropdown.js +0 -15
- package/dist/es/p-btn.js +2 -190
- package/dist/es/p-dropdown.js +0 -15
- package/dist/squirrel/components/p-dropdown/p-dropdown.vue.d.ts +0 -32
- package/package.json +10 -8
- package/squirrel/components/p-chips/p-chips.spec.js +95 -0
- package/squirrel/components/p-dropdown/p-dropdown.spec.js +164 -0
- package/squirrel/components/p-dropdown/p-dropdown.vue +0 -15
- package/squirrel/components/p-table/usePTableColResize.spec.js +89 -0
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
|
-
|
|
15
|
+
Import the Squirrel CSS to your project's `main.css` file:
|
|
16
16
|
|
|
17
|
-
```
|
|
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:
|
|
@@ -56,11 +56,62 @@ If you are using Jest for unit testing, you will need to add the following to yo
|
|
|
56
56
|
```js
|
|
57
57
|
{
|
|
58
58
|
moduleNameMapper: {
|
|
59
|
-
'^@pequity/squirrel$': '<rootDir>/node_modules/@pequity/squirrel/dist/
|
|
59
|
+
'^@pequity/squirrel$': '<rootDir>/node_modules/@pequity/squirrel/dist/cjs',
|
|
60
60
|
}
|
|
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
|
---
|
package/dist/cjs/p-btn.js
CHANGED
|
@@ -2,196 +2,8 @@
|
|
|
2
2
|
const pRingLoader_vue_vue_type_script_setup_true_lang = require("./chunks/p-ring-loader.js");
|
|
3
3
|
const tailwind = require("./tailwind.js");
|
|
4
4
|
const vue = require("vue");
|
|
5
|
+
const vueRouter = require("vue-router");
|
|
5
6
|
const _pluginVue_exportHelper = require("./chunks/_plugin-vue_export-helper.js");
|
|
6
|
-
/*!
|
|
7
|
-
* vue-router v4.3.0
|
|
8
|
-
* (c) 2024 Eduardo San Martin Morote
|
|
9
|
-
* @license MIT
|
|
10
|
-
*/
|
|
11
|
-
const isBrowser = typeof document !== "undefined";
|
|
12
|
-
const noop = () => {
|
|
13
|
-
};
|
|
14
|
-
const isArray = Array.isArray;
|
|
15
|
-
function isSameRouteRecord(a, b) {
|
|
16
|
-
return (a.aliasOf || a) === (b.aliasOf || b);
|
|
17
|
-
}
|
|
18
|
-
function isSameRouteLocationParams(a, b) {
|
|
19
|
-
if (Object.keys(a).length !== Object.keys(b).length)
|
|
20
|
-
return false;
|
|
21
|
-
for (const key in a) {
|
|
22
|
-
if (!isSameRouteLocationParamsValue(a[key], b[key]))
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
function isSameRouteLocationParamsValue(a, b) {
|
|
28
|
-
return isArray(a) ? isEquivalentArray(a, b) : isArray(b) ? isEquivalentArray(b, a) : a === b;
|
|
29
|
-
}
|
|
30
|
-
function isEquivalentArray(a, b) {
|
|
31
|
-
return isArray(b) ? a.length === b.length && a.every((value, i) => value === b[i]) : a.length === 1 && a[0] === b;
|
|
32
|
-
}
|
|
33
|
-
var NavigationType;
|
|
34
|
-
(function(NavigationType2) {
|
|
35
|
-
NavigationType2["pop"] = "pop";
|
|
36
|
-
NavigationType2["push"] = "push";
|
|
37
|
-
})(NavigationType || (NavigationType = {}));
|
|
38
|
-
var NavigationDirection;
|
|
39
|
-
(function(NavigationDirection2) {
|
|
40
|
-
NavigationDirection2["back"] = "back";
|
|
41
|
-
NavigationDirection2["forward"] = "forward";
|
|
42
|
-
NavigationDirection2["unknown"] = "";
|
|
43
|
-
})(NavigationDirection || (NavigationDirection = {}));
|
|
44
|
-
Symbol(process.env.NODE_ENV !== "production" ? "navigation failure" : "");
|
|
45
|
-
var NavigationFailureType;
|
|
46
|
-
(function(NavigationFailureType2) {
|
|
47
|
-
NavigationFailureType2[NavigationFailureType2["aborted"] = 4] = "aborted";
|
|
48
|
-
NavigationFailureType2[NavigationFailureType2["cancelled"] = 8] = "cancelled";
|
|
49
|
-
NavigationFailureType2[NavigationFailureType2["duplicated"] = 16] = "duplicated";
|
|
50
|
-
})(NavigationFailureType || (NavigationFailureType = {}));
|
|
51
|
-
Symbol(process.env.NODE_ENV !== "production" ? "router view location matched" : "");
|
|
52
|
-
Symbol(process.env.NODE_ENV !== "production" ? "router view depth" : "");
|
|
53
|
-
const routerKey = Symbol(process.env.NODE_ENV !== "production" ? "router" : "");
|
|
54
|
-
const routeLocationKey = Symbol(process.env.NODE_ENV !== "production" ? "route location" : "");
|
|
55
|
-
Symbol(process.env.NODE_ENV !== "production" ? "router view location" : "");
|
|
56
|
-
function useLink(props) {
|
|
57
|
-
const router = vue.inject(routerKey);
|
|
58
|
-
const currentRoute = vue.inject(routeLocationKey);
|
|
59
|
-
const route = vue.computed(() => router.resolve(vue.unref(props.to)));
|
|
60
|
-
const activeRecordIndex = vue.computed(() => {
|
|
61
|
-
const { matched } = route.value;
|
|
62
|
-
const { length } = matched;
|
|
63
|
-
const routeMatched = matched[length - 1];
|
|
64
|
-
const currentMatched = currentRoute.matched;
|
|
65
|
-
if (!routeMatched || !currentMatched.length)
|
|
66
|
-
return -1;
|
|
67
|
-
const index = currentMatched.findIndex(isSameRouteRecord.bind(null, routeMatched));
|
|
68
|
-
if (index > -1)
|
|
69
|
-
return index;
|
|
70
|
-
const parentRecordPath = getOriginalPath(matched[length - 2]);
|
|
71
|
-
return (
|
|
72
|
-
// we are dealing with nested routes
|
|
73
|
-
length > 1 && // if the parent and matched route have the same path, this link is
|
|
74
|
-
// referring to the empty child. Or we currently are on a different
|
|
75
|
-
// child of the same parent
|
|
76
|
-
getOriginalPath(routeMatched) === parentRecordPath && // avoid comparing the child with its parent
|
|
77
|
-
currentMatched[currentMatched.length - 1].path !== parentRecordPath ? currentMatched.findIndex(isSameRouteRecord.bind(null, matched[length - 2])) : index
|
|
78
|
-
);
|
|
79
|
-
});
|
|
80
|
-
const isActive = vue.computed(() => activeRecordIndex.value > -1 && includesParams(currentRoute.params, route.value.params));
|
|
81
|
-
const isExactActive = vue.computed(() => activeRecordIndex.value > -1 && activeRecordIndex.value === currentRoute.matched.length - 1 && isSameRouteLocationParams(currentRoute.params, route.value.params));
|
|
82
|
-
function navigate(e = {}) {
|
|
83
|
-
if (guardEvent(e)) {
|
|
84
|
-
return router[vue.unref(props.replace) ? "replace" : "push"](
|
|
85
|
-
vue.unref(props.to)
|
|
86
|
-
// avoid uncaught errors are they are logged anyway
|
|
87
|
-
).catch(noop);
|
|
88
|
-
}
|
|
89
|
-
return Promise.resolve();
|
|
90
|
-
}
|
|
91
|
-
if ((process.env.NODE_ENV !== "production" || false) && isBrowser) {
|
|
92
|
-
const instance = vue.getCurrentInstance();
|
|
93
|
-
if (instance) {
|
|
94
|
-
const linkContextDevtools = {
|
|
95
|
-
route: route.value,
|
|
96
|
-
isActive: isActive.value,
|
|
97
|
-
isExactActive: isExactActive.value
|
|
98
|
-
};
|
|
99
|
-
instance.__vrl_devtools = instance.__vrl_devtools || [];
|
|
100
|
-
instance.__vrl_devtools.push(linkContextDevtools);
|
|
101
|
-
vue.watchEffect(() => {
|
|
102
|
-
linkContextDevtools.route = route.value;
|
|
103
|
-
linkContextDevtools.isActive = isActive.value;
|
|
104
|
-
linkContextDevtools.isExactActive = isExactActive.value;
|
|
105
|
-
}, { flush: "post" });
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return {
|
|
109
|
-
route,
|
|
110
|
-
href: vue.computed(() => route.value.href),
|
|
111
|
-
isActive,
|
|
112
|
-
isExactActive,
|
|
113
|
-
navigate
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
const RouterLinkImpl = /* @__PURE__ */ vue.defineComponent({
|
|
117
|
-
name: "RouterLink",
|
|
118
|
-
compatConfig: { MODE: 3 },
|
|
119
|
-
props: {
|
|
120
|
-
to: {
|
|
121
|
-
type: [String, Object],
|
|
122
|
-
required: true
|
|
123
|
-
},
|
|
124
|
-
replace: Boolean,
|
|
125
|
-
activeClass: String,
|
|
126
|
-
// inactiveClass: String,
|
|
127
|
-
exactActiveClass: String,
|
|
128
|
-
custom: Boolean,
|
|
129
|
-
ariaCurrentValue: {
|
|
130
|
-
type: String,
|
|
131
|
-
default: "page"
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
useLink,
|
|
135
|
-
setup(props, { slots }) {
|
|
136
|
-
const link = vue.reactive(useLink(props));
|
|
137
|
-
const { options } = vue.inject(routerKey);
|
|
138
|
-
const elClass = vue.computed(() => ({
|
|
139
|
-
[getLinkClass(props.activeClass, options.linkActiveClass, "router-link-active")]: link.isActive,
|
|
140
|
-
// [getLinkClass(
|
|
141
|
-
// props.inactiveClass,
|
|
142
|
-
// options.linkInactiveClass,
|
|
143
|
-
// 'router-link-inactive'
|
|
144
|
-
// )]: !link.isExactActive,
|
|
145
|
-
[getLinkClass(props.exactActiveClass, options.linkExactActiveClass, "router-link-exact-active")]: link.isExactActive
|
|
146
|
-
}));
|
|
147
|
-
return () => {
|
|
148
|
-
const children = slots.default && slots.default(link);
|
|
149
|
-
return props.custom ? children : vue.h("a", {
|
|
150
|
-
"aria-current": link.isExactActive ? props.ariaCurrentValue : null,
|
|
151
|
-
href: link.href,
|
|
152
|
-
// this would override user added attrs but Vue will still add
|
|
153
|
-
// the listener, so we end up triggering both
|
|
154
|
-
onClick: link.navigate,
|
|
155
|
-
class: elClass.value
|
|
156
|
-
}, children);
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
const RouterLink = RouterLinkImpl;
|
|
161
|
-
function guardEvent(e) {
|
|
162
|
-
if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey)
|
|
163
|
-
return;
|
|
164
|
-
if (e.defaultPrevented)
|
|
165
|
-
return;
|
|
166
|
-
if (e.button !== void 0 && e.button !== 0)
|
|
167
|
-
return;
|
|
168
|
-
if (e.currentTarget && e.currentTarget.getAttribute) {
|
|
169
|
-
const target = e.currentTarget.getAttribute("target");
|
|
170
|
-
if (/\b_blank\b/i.test(target))
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
if (e.preventDefault)
|
|
174
|
-
e.preventDefault();
|
|
175
|
-
return true;
|
|
176
|
-
}
|
|
177
|
-
function includesParams(outer, inner) {
|
|
178
|
-
for (const key in inner) {
|
|
179
|
-
const innerValue = inner[key];
|
|
180
|
-
const outerValue = outer[key];
|
|
181
|
-
if (typeof innerValue === "string") {
|
|
182
|
-
if (innerValue !== outerValue)
|
|
183
|
-
return false;
|
|
184
|
-
} else {
|
|
185
|
-
if (!isArray(outerValue) || outerValue.length !== innerValue.length || innerValue.some((value, i) => value !== outerValue[i]))
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
return true;
|
|
190
|
-
}
|
|
191
|
-
function getOriginalPath(record) {
|
|
192
|
-
return record ? record.aliasOf ? record.aliasOf.path : record.path : "";
|
|
193
|
-
}
|
|
194
|
-
const getLinkClass = (propClass, globalClass, defaultClass) => propClass != null ? propClass : globalClass != null ? globalClass : defaultClass;
|
|
195
7
|
const BUTTON_TYPES = {
|
|
196
8
|
PRIMARY: "primary",
|
|
197
9
|
SECONDARY: "secondary",
|
|
@@ -244,7 +56,7 @@ const _sfc_main = vue.defineComponent({
|
|
|
244
56
|
name: "PBtn",
|
|
245
57
|
components: {
|
|
246
58
|
PRingLoader: pRingLoader_vue_vue_type_script_setup_true_lang._sfc_main,
|
|
247
|
-
RouterLink
|
|
59
|
+
RouterLink: vueRouter.RouterLink
|
|
248
60
|
},
|
|
249
61
|
inheritAttrs: false,
|
|
250
62
|
props: {
|
package/dist/cjs/p-dropdown.js
CHANGED
|
@@ -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
|
package/dist/es/p-btn.js
CHANGED
|
@@ -1,196 +1,8 @@
|
|
|
1
1
|
import { _ as _sfc_main$1 } from "./chunks/p-ring-loader.js";
|
|
2
2
|
import { getColorDeep } from "./tailwind.js";
|
|
3
|
-
import { defineComponent,
|
|
3
|
+
import { defineComponent, resolveComponent, openBlock, createElementBlock, mergeProps, renderSlot, createBlock, resolveDynamicComponent, withCtx, createElementVNode, normalizeClass, normalizeStyle, createCommentVNode } from "vue";
|
|
4
|
+
import { RouterLink } from "vue-router";
|
|
4
5
|
import { _ as _export_sfc } from "./chunks/_plugin-vue_export-helper.js";
|
|
5
|
-
/*!
|
|
6
|
-
* vue-router v4.3.0
|
|
7
|
-
* (c) 2024 Eduardo San Martin Morote
|
|
8
|
-
* @license MIT
|
|
9
|
-
*/
|
|
10
|
-
const isBrowser = typeof document !== "undefined";
|
|
11
|
-
const noop = () => {
|
|
12
|
-
};
|
|
13
|
-
const isArray = Array.isArray;
|
|
14
|
-
function isSameRouteRecord(a, b) {
|
|
15
|
-
return (a.aliasOf || a) === (b.aliasOf || b);
|
|
16
|
-
}
|
|
17
|
-
function isSameRouteLocationParams(a, b) {
|
|
18
|
-
if (Object.keys(a).length !== Object.keys(b).length)
|
|
19
|
-
return false;
|
|
20
|
-
for (const key in a) {
|
|
21
|
-
if (!isSameRouteLocationParamsValue(a[key], b[key]))
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
return true;
|
|
25
|
-
}
|
|
26
|
-
function isSameRouteLocationParamsValue(a, b) {
|
|
27
|
-
return isArray(a) ? isEquivalentArray(a, b) : isArray(b) ? isEquivalentArray(b, a) : a === b;
|
|
28
|
-
}
|
|
29
|
-
function isEquivalentArray(a, b) {
|
|
30
|
-
return isArray(b) ? a.length === b.length && a.every((value, i) => value === b[i]) : a.length === 1 && a[0] === b;
|
|
31
|
-
}
|
|
32
|
-
var NavigationType;
|
|
33
|
-
(function(NavigationType2) {
|
|
34
|
-
NavigationType2["pop"] = "pop";
|
|
35
|
-
NavigationType2["push"] = "push";
|
|
36
|
-
})(NavigationType || (NavigationType = {}));
|
|
37
|
-
var NavigationDirection;
|
|
38
|
-
(function(NavigationDirection2) {
|
|
39
|
-
NavigationDirection2["back"] = "back";
|
|
40
|
-
NavigationDirection2["forward"] = "forward";
|
|
41
|
-
NavigationDirection2["unknown"] = "";
|
|
42
|
-
})(NavigationDirection || (NavigationDirection = {}));
|
|
43
|
-
Symbol(process.env.NODE_ENV !== "production" ? "navigation failure" : "");
|
|
44
|
-
var NavigationFailureType;
|
|
45
|
-
(function(NavigationFailureType2) {
|
|
46
|
-
NavigationFailureType2[NavigationFailureType2["aborted"] = 4] = "aborted";
|
|
47
|
-
NavigationFailureType2[NavigationFailureType2["cancelled"] = 8] = "cancelled";
|
|
48
|
-
NavigationFailureType2[NavigationFailureType2["duplicated"] = 16] = "duplicated";
|
|
49
|
-
})(NavigationFailureType || (NavigationFailureType = {}));
|
|
50
|
-
Symbol(process.env.NODE_ENV !== "production" ? "router view location matched" : "");
|
|
51
|
-
Symbol(process.env.NODE_ENV !== "production" ? "router view depth" : "");
|
|
52
|
-
const routerKey = Symbol(process.env.NODE_ENV !== "production" ? "router" : "");
|
|
53
|
-
const routeLocationKey = Symbol(process.env.NODE_ENV !== "production" ? "route location" : "");
|
|
54
|
-
Symbol(process.env.NODE_ENV !== "production" ? "router view location" : "");
|
|
55
|
-
function useLink(props) {
|
|
56
|
-
const router = inject(routerKey);
|
|
57
|
-
const currentRoute = inject(routeLocationKey);
|
|
58
|
-
const route = computed(() => router.resolve(unref(props.to)));
|
|
59
|
-
const activeRecordIndex = computed(() => {
|
|
60
|
-
const { matched } = route.value;
|
|
61
|
-
const { length } = matched;
|
|
62
|
-
const routeMatched = matched[length - 1];
|
|
63
|
-
const currentMatched = currentRoute.matched;
|
|
64
|
-
if (!routeMatched || !currentMatched.length)
|
|
65
|
-
return -1;
|
|
66
|
-
const index = currentMatched.findIndex(isSameRouteRecord.bind(null, routeMatched));
|
|
67
|
-
if (index > -1)
|
|
68
|
-
return index;
|
|
69
|
-
const parentRecordPath = getOriginalPath(matched[length - 2]);
|
|
70
|
-
return (
|
|
71
|
-
// we are dealing with nested routes
|
|
72
|
-
length > 1 && // if the parent and matched route have the same path, this link is
|
|
73
|
-
// referring to the empty child. Or we currently are on a different
|
|
74
|
-
// child of the same parent
|
|
75
|
-
getOriginalPath(routeMatched) === parentRecordPath && // avoid comparing the child with its parent
|
|
76
|
-
currentMatched[currentMatched.length - 1].path !== parentRecordPath ? currentMatched.findIndex(isSameRouteRecord.bind(null, matched[length - 2])) : index
|
|
77
|
-
);
|
|
78
|
-
});
|
|
79
|
-
const isActive = computed(() => activeRecordIndex.value > -1 && includesParams(currentRoute.params, route.value.params));
|
|
80
|
-
const isExactActive = computed(() => activeRecordIndex.value > -1 && activeRecordIndex.value === currentRoute.matched.length - 1 && isSameRouteLocationParams(currentRoute.params, route.value.params));
|
|
81
|
-
function navigate(e = {}) {
|
|
82
|
-
if (guardEvent(e)) {
|
|
83
|
-
return router[unref(props.replace) ? "replace" : "push"](
|
|
84
|
-
unref(props.to)
|
|
85
|
-
// avoid uncaught errors are they are logged anyway
|
|
86
|
-
).catch(noop);
|
|
87
|
-
}
|
|
88
|
-
return Promise.resolve();
|
|
89
|
-
}
|
|
90
|
-
if ((process.env.NODE_ENV !== "production" || false) && isBrowser) {
|
|
91
|
-
const instance = getCurrentInstance();
|
|
92
|
-
if (instance) {
|
|
93
|
-
const linkContextDevtools = {
|
|
94
|
-
route: route.value,
|
|
95
|
-
isActive: isActive.value,
|
|
96
|
-
isExactActive: isExactActive.value
|
|
97
|
-
};
|
|
98
|
-
instance.__vrl_devtools = instance.__vrl_devtools || [];
|
|
99
|
-
instance.__vrl_devtools.push(linkContextDevtools);
|
|
100
|
-
watchEffect(() => {
|
|
101
|
-
linkContextDevtools.route = route.value;
|
|
102
|
-
linkContextDevtools.isActive = isActive.value;
|
|
103
|
-
linkContextDevtools.isExactActive = isExactActive.value;
|
|
104
|
-
}, { flush: "post" });
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return {
|
|
108
|
-
route,
|
|
109
|
-
href: computed(() => route.value.href),
|
|
110
|
-
isActive,
|
|
111
|
-
isExactActive,
|
|
112
|
-
navigate
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
const RouterLinkImpl = /* @__PURE__ */ defineComponent({
|
|
116
|
-
name: "RouterLink",
|
|
117
|
-
compatConfig: { MODE: 3 },
|
|
118
|
-
props: {
|
|
119
|
-
to: {
|
|
120
|
-
type: [String, Object],
|
|
121
|
-
required: true
|
|
122
|
-
},
|
|
123
|
-
replace: Boolean,
|
|
124
|
-
activeClass: String,
|
|
125
|
-
// inactiveClass: String,
|
|
126
|
-
exactActiveClass: String,
|
|
127
|
-
custom: Boolean,
|
|
128
|
-
ariaCurrentValue: {
|
|
129
|
-
type: String,
|
|
130
|
-
default: "page"
|
|
131
|
-
}
|
|
132
|
-
},
|
|
133
|
-
useLink,
|
|
134
|
-
setup(props, { slots }) {
|
|
135
|
-
const link = reactive(useLink(props));
|
|
136
|
-
const { options } = inject(routerKey);
|
|
137
|
-
const elClass = computed(() => ({
|
|
138
|
-
[getLinkClass(props.activeClass, options.linkActiveClass, "router-link-active")]: link.isActive,
|
|
139
|
-
// [getLinkClass(
|
|
140
|
-
// props.inactiveClass,
|
|
141
|
-
// options.linkInactiveClass,
|
|
142
|
-
// 'router-link-inactive'
|
|
143
|
-
// )]: !link.isExactActive,
|
|
144
|
-
[getLinkClass(props.exactActiveClass, options.linkExactActiveClass, "router-link-exact-active")]: link.isExactActive
|
|
145
|
-
}));
|
|
146
|
-
return () => {
|
|
147
|
-
const children = slots.default && slots.default(link);
|
|
148
|
-
return props.custom ? children : h("a", {
|
|
149
|
-
"aria-current": link.isExactActive ? props.ariaCurrentValue : null,
|
|
150
|
-
href: link.href,
|
|
151
|
-
// this would override user added attrs but Vue will still add
|
|
152
|
-
// the listener, so we end up triggering both
|
|
153
|
-
onClick: link.navigate,
|
|
154
|
-
class: elClass.value
|
|
155
|
-
}, children);
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
const RouterLink = RouterLinkImpl;
|
|
160
|
-
function guardEvent(e) {
|
|
161
|
-
if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey)
|
|
162
|
-
return;
|
|
163
|
-
if (e.defaultPrevented)
|
|
164
|
-
return;
|
|
165
|
-
if (e.button !== void 0 && e.button !== 0)
|
|
166
|
-
return;
|
|
167
|
-
if (e.currentTarget && e.currentTarget.getAttribute) {
|
|
168
|
-
const target = e.currentTarget.getAttribute("target");
|
|
169
|
-
if (/\b_blank\b/i.test(target))
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
if (e.preventDefault)
|
|
173
|
-
e.preventDefault();
|
|
174
|
-
return true;
|
|
175
|
-
}
|
|
176
|
-
function includesParams(outer, inner) {
|
|
177
|
-
for (const key in inner) {
|
|
178
|
-
const innerValue = inner[key];
|
|
179
|
-
const outerValue = outer[key];
|
|
180
|
-
if (typeof innerValue === "string") {
|
|
181
|
-
if (innerValue !== outerValue)
|
|
182
|
-
return false;
|
|
183
|
-
} else {
|
|
184
|
-
if (!isArray(outerValue) || outerValue.length !== innerValue.length || innerValue.some((value, i) => value !== outerValue[i]))
|
|
185
|
-
return false;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return true;
|
|
189
|
-
}
|
|
190
|
-
function getOriginalPath(record) {
|
|
191
|
-
return record ? record.aliasOf ? record.aliasOf.path : record.path : "";
|
|
192
|
-
}
|
|
193
|
-
const getLinkClass = (propClass, globalClass, defaultClass) => propClass != null ? propClass : globalClass != null ? globalClass : defaultClass;
|
|
194
6
|
const BUTTON_TYPES = {
|
|
195
7
|
PRIMARY: "primary",
|
|
196
8
|
SECONDARY: "secondary",
|
package/dist/es/p-dropdown.js
CHANGED
|
@@ -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.
|
|
4
|
+
"version": "1.0.25",
|
|
5
5
|
"packageManager": "pnpm@8.9.2",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
@@ -39,13 +39,14 @@
|
|
|
39
39
|
"module": "./dist/es/index.js",
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@popperjs/core": "2.11.8",
|
|
42
|
-
"@tanstack/vue-virtual": "3.
|
|
42
|
+
"@tanstack/vue-virtual": "3.3.0",
|
|
43
43
|
"dayjs": "1.11.10",
|
|
44
44
|
"floating-vue": "5.2.2",
|
|
45
45
|
"lodash-es": "4.17.21",
|
|
46
46
|
"v-calendar": "3.1.2",
|
|
47
|
-
"vue": "3.4.
|
|
47
|
+
"vue": "3.4.23",
|
|
48
48
|
"vue-currency-input": "3.1.0",
|
|
49
|
+
"vue-router": "4.3.0",
|
|
49
50
|
"vue-toastification": "2.0.0-rc.5"
|
|
50
51
|
},
|
|
51
52
|
"peerDependencies": {
|
|
@@ -57,13 +58,14 @@
|
|
|
57
58
|
"v-calendar": "^3.1.2",
|
|
58
59
|
"vue": "^3.4.21",
|
|
59
60
|
"vue-currency-input": "^3.1.0",
|
|
61
|
+
"vue-router": "^4.3.0",
|
|
60
62
|
"vue-toastification": "^2.0.0-rc.5"
|
|
61
63
|
},
|
|
62
64
|
"devDependencies": {
|
|
63
65
|
"@babel/core": "^7.24.4",
|
|
64
66
|
"@babel/preset-env": "^7.24.4",
|
|
65
|
-
"@commitlint/cli": "^19.2.
|
|
66
|
-
"@commitlint/config-conventional": "^19.
|
|
67
|
+
"@commitlint/cli": "^19.2.2",
|
|
68
|
+
"@commitlint/config-conventional": "^19.2.2",
|
|
67
69
|
"@pequity/eslint-config": "^0.0.12",
|
|
68
70
|
"@semantic-release/changelog": "^6.0.3",
|
|
69
71
|
"@semantic-release/git": "^10.0.1",
|
|
@@ -85,7 +87,7 @@
|
|
|
85
87
|
"@types/lodash-es": "^4.17.12",
|
|
86
88
|
"@types/node": "^20.12.7",
|
|
87
89
|
"@vitejs/plugin-vue": "^5.0.4",
|
|
88
|
-
"@vue/compiler-sfc": "3.4.
|
|
90
|
+
"@vue/compiler-sfc": "3.4.23",
|
|
89
91
|
"@vue/test-utils": "^2.4.5",
|
|
90
92
|
"@vue/vue3-jest": "^29.2.6",
|
|
91
93
|
"autoprefixer": "^10.4.19",
|
|
@@ -100,7 +102,7 @@
|
|
|
100
102
|
"make-coverage-badge": "^1.2.0",
|
|
101
103
|
"postcss": "^8.4.38",
|
|
102
104
|
"prettier": "^3.2.5",
|
|
103
|
-
"prettier-plugin-tailwindcss": "^0.5.
|
|
105
|
+
"prettier-plugin-tailwindcss": "^0.5.14",
|
|
104
106
|
"resolve-tspaths": "^0.8.18",
|
|
105
107
|
"rimraf": "^5.0.5",
|
|
106
108
|
"sass": "^1.75.0",
|
|
@@ -110,7 +112,7 @@
|
|
|
110
112
|
"tailwindcss": "^3.4.3",
|
|
111
113
|
"ts-jest": "^29.1.2",
|
|
112
114
|
"typescript": "5.4.5",
|
|
113
|
-
"vite": "^5.2.
|
|
115
|
+
"vite": "^5.2.9",
|
|
114
116
|
"vue-router": "^4.3.0",
|
|
115
117
|
"vue-tsc": "2.0.13"
|
|
116
118
|
}
|
|
@@ -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
|
+
});
|