@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 CHANGED
@@ -12,10 +12,10 @@ Install the package and its dependencies using pnpm:
12
12
  pnpm i @pequity/squirrel @popperjs/core @tanstack/vue-virtual dayjs floating-vue lodash-es v-calendar vue-currency-input ue-toastification@2.0.0-rc.5
13
13
  ```
14
14
 
15
- Add the Squirrel CSS to your project's `main.ts` file:
15
+ Import the Squirrel CSS to your project's `main.css` file:
16
16
 
17
- ```ts
18
- import '@pequity/squirrel/assets/squirrel.css';
17
+ ```css
18
+ @import '@pequity/squirrel/assets/squirrel.css';
19
19
  ```
20
20
 
21
21
  Add the "Inter" font to your project's `index.html` file:
@@ -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/squirrel.cjs.js'
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: {
@@ -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, reactive, inject, computed, h, unref, getCurrentInstance, watchEffect, resolveComponent, openBlock, createElementBlock, mergeProps, renderSlot, createBlock, resolveDynamicComponent, withCtx, createElementVNode, normalizeClass, normalizeStyle, createCommentVNode } from "vue";
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",
@@ -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.23",
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.2.1",
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.21",
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.1",
66
- "@commitlint/config-conventional": "^19.1.0",
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.21",
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.13",
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.8",
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
+ });