@pequity/squirrel 6.0.14 → 6.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/chunks/p-action-bar.js +4 -4
- package/dist/cjs/chunks/p-btn.js +204 -0
- package/dist/cjs/chunks/p-select-btn.js +8 -8
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/p-btn.js +2 -169
- package/dist/es/chunks/p-action-bar.js +8 -8
- package/dist/es/chunks/p-btn.js +205 -0
- package/dist/es/chunks/p-select-btn.js +9 -9
- package/dist/es/index.js +62 -62
- package/dist/es/p-btn.js +2 -169
- package/dist/squirrel/components/p-btn/p-btn.vue.d.ts +106 -46
- package/dist/squirrel/components/p-card/p-card.vue.d.ts +27 -14
- package/dist/squirrel/components/p-checkbox/p-checkbox.vue.d.ts +43 -12
- package/dist/squirrel/components/p-close-btn/p-close-btn.vue.d.ts +1 -1
- package/dist/squirrel/components/p-drawer/p-drawer.vue.d.ts +1 -1
- package/dist/squirrel/components/p-dropdown-select/p-dropdown-select.vue.d.ts +15 -422
- package/dist/squirrel/components/p-file-upload/p-file-upload.vue.d.ts +1 -3
- package/dist/squirrel/components/p-info-icon/p-info-icon.vue.d.ts +13 -11
- package/dist/squirrel/components/p-inline-date-picker/p-inline-date-picker.vue.d.ts +39 -14
- package/dist/squirrel/components/p-input/p-input.vue.d.ts +2 -2
- package/dist/squirrel/components/p-input-number/p-input-number.vue.d.ts +2 -2
- package/dist/squirrel/components/p-input-search/p-input-search.vue.d.ts +2 -2
- package/dist/squirrel/components/p-link/p-link.vue.d.ts +17 -13
- package/dist/squirrel/components/p-loading/p-loading.vue.d.ts +1 -3
- package/dist/squirrel/components/p-modal/p-modal.vue.d.ts +240 -22
- package/dist/squirrel/components/p-pagination-info/p-pagination-info.vue.d.ts +77 -10
- package/dist/squirrel/components/p-select/p-select.vue.d.ts +116 -14
- package/dist/squirrel/components/p-select-btn/p-select-btn.vue.d.ts +37 -13
- package/dist/squirrel/components/p-select-list/p-select-list.vue.d.ts +14 -418
- package/dist/squirrel/components/p-table/p-table.vue.d.ts +61 -19
- package/dist/squirrel/components/p-table-header-cell/p-table-header-cell.vue.d.ts +2 -2
- package/dist/squirrel/components/p-table-loader/p-table-loader.vue.d.ts +1 -1
- package/dist/squirrel/components/p-table-td/p-table-td.vue.d.ts +23 -11
- package/dist/squirrel/components/p-tabs/p-tabs.vue.d.ts +1 -1
- package/dist/squirrel/components/p-textarea/p-textarea.vue.d.ts +1 -1
- package/dist/squirrel/components/p-toggle/p-toggle.vue.d.ts +1 -1
- package/dist/squirrel/utils/inputClassesMixin.d.ts +1 -1
- package/package.json +25 -24
- package/squirrel/components/p-btn/p-btn.spec.js +229 -161
- package/squirrel/components/p-btn/p-btn.stories.js +32 -8
- package/squirrel/components/p-btn/p-btn.vue +106 -73
- package/squirrel/components/p-dropdown/p-dropdown.vue +0 -1
- package/squirrel/components/p-inline-date-picker/p-inline-date-picker.vue +1 -1
- package/squirrel/components/p-select-btn/p-select-btn.spec.js +24 -5
- package/squirrel/components/p-select-btn/p-select-btn.stories.js +45 -4
- package/squirrel/components/p-select-btn/p-select-btn.vue +3 -3
|
@@ -21,25 +21,36 @@
|
|
|
21
21
|
:disabled="!!$attrs.disabled || loading ? true : null"
|
|
22
22
|
:aria-disabled="$attrs.disabled"
|
|
23
23
|
>
|
|
24
|
-
<div :class="{ invisible: loading }"
|
|
24
|
+
<div :class="[{ invisible: loading }, classes.content]">
|
|
25
|
+
<PIcon v-if="icon" :icon="icon" :class="classes.icon" />
|
|
26
|
+
<span class="slot-wrapper empty:hidden">
|
|
27
|
+
<slot></slot>
|
|
28
|
+
</span>
|
|
29
|
+
<PIcon v-if="iconRight" :icon="iconRight" :class="classes.icon" />
|
|
30
|
+
</div>
|
|
25
31
|
<PRingLoader v-if="loading" :size="loaderSize" :class="classes.loader" />
|
|
26
32
|
</Component>
|
|
27
33
|
</template>
|
|
28
34
|
|
|
29
35
|
<script lang="ts">
|
|
30
36
|
import { type Size, SIZES } from '@squirrel/components/p-btn/p-btn.types';
|
|
37
|
+
import PIcon from '@squirrel/components/p-icon/p-icon.vue';
|
|
31
38
|
import PRingLoader from '@squirrel/components/p-ring-loader/p-ring-loader.vue';
|
|
32
39
|
import { isExternalLink } from '@squirrel/utils/link';
|
|
33
40
|
import { sanitizeUrl } from '@squirrel/utils/sanitization';
|
|
34
41
|
import { tv, type VariantProps } from 'tailwind-variants';
|
|
35
|
-
import {
|
|
36
|
-
import { type RouteLocationRaw
|
|
42
|
+
import { computed, type PropType } from 'vue';
|
|
43
|
+
import { type RouteLocationRaw } from 'vue-router';
|
|
44
|
+
|
|
45
|
+
type Icon = InstanceType<typeof PIcon>['$props']['icon'];
|
|
37
46
|
|
|
38
47
|
const btnClasses = {
|
|
39
48
|
slots: {
|
|
40
49
|
button:
|
|
41
50
|
'relative inline-block rounded font-medium outline-none disabled:pointer-events-none disabled:cursor-default disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:cursor-default aria-disabled:opacity-50',
|
|
51
|
+
content: 'flex items-center justify-center has-[.slot-wrapper:empty]:gap-0',
|
|
42
52
|
loader: 'absolute bottom-0 left-0 right-0 top-0 flex items-center justify-center font-medium',
|
|
53
|
+
icon: 'shrink-0',
|
|
43
54
|
},
|
|
44
55
|
variants: {
|
|
45
56
|
type: {
|
|
@@ -72,9 +83,21 @@ const btnClasses = {
|
|
|
72
83
|
'secondary-ghost-dark': { button: 'text-white hover:bg-p-purple-50', loader: 'text-p-blue-15' },
|
|
73
84
|
},
|
|
74
85
|
size: {
|
|
75
|
-
sm: {
|
|
76
|
-
|
|
77
|
-
|
|
86
|
+
sm: {
|
|
87
|
+
button: 'px-3 has-[.slot-wrapper:empty]:px-1.5 py-1.5 text-sm leading-5',
|
|
88
|
+
content: 'gap-1',
|
|
89
|
+
icon: 'text-[20px]',
|
|
90
|
+
},
|
|
91
|
+
md: {
|
|
92
|
+
button: 'px-6 has-[.slot-wrapper:empty]:px-2.5 has-[.slot-wrapper:empty]:py-2.5 py-2 text-base',
|
|
93
|
+
content: 'gap-2',
|
|
94
|
+
icon: 'text-xl',
|
|
95
|
+
},
|
|
96
|
+
lg: {
|
|
97
|
+
button: 'px-6 has-[.slot-wrapper:empty]:px-3 py-3 text-lg leading-7',
|
|
98
|
+
content: 'gap-2.5',
|
|
99
|
+
icon: 'text-2xl',
|
|
100
|
+
},
|
|
78
101
|
},
|
|
79
102
|
},
|
|
80
103
|
defaultVariants: {
|
|
@@ -84,87 +107,97 @@ const btnClasses = {
|
|
|
84
107
|
} as const;
|
|
85
108
|
|
|
86
109
|
const btn = tv(btnClasses);
|
|
110
|
+
|
|
87
111
|
const BUTTON_TYPES = Object.keys(btnClasses.variants.type);
|
|
88
112
|
const BUTTON_NATIVE_TYPES = ['button', 'submit', 'reset'] as const;
|
|
89
113
|
const LOADER_SIZES = { sm: 24, md: 30, lg: 40 } as const satisfies { [key in Size]: number };
|
|
90
114
|
|
|
91
115
|
type ButtonNativeType = (typeof BUTTON_NATIVE_TYPES)[number];
|
|
92
116
|
type ButtonType = NonNullable<VariantProps<typeof btn>['type']>;
|
|
117
|
+
</script>
|
|
93
118
|
|
|
94
|
-
|
|
119
|
+
<script setup lang="ts">
|
|
120
|
+
defineOptions({
|
|
95
121
|
name: 'PBtn',
|
|
96
|
-
components: {
|
|
97
|
-
PRingLoader,
|
|
98
|
-
RouterLink,
|
|
99
|
-
},
|
|
100
122
|
inheritAttrs: false,
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* The button native type e.g button, submit, reset
|
|
114
|
-
*/
|
|
115
|
-
nativeType: {
|
|
116
|
-
type: String as PropType<ButtonNativeType>,
|
|
117
|
-
default: 'button',
|
|
118
|
-
validator(value: ButtonNativeType) {
|
|
119
|
-
return BUTTON_NATIVE_TYPES.includes(value);
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
/**
|
|
123
|
-
* The button size e.g sm, md, lg
|
|
124
|
-
*/
|
|
125
|
-
size: {
|
|
126
|
-
type: String as PropType<Size>,
|
|
127
|
-
default: 'md',
|
|
128
|
-
validator(value: Size) {
|
|
129
|
-
return SIZES.includes(value);
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
/**
|
|
133
|
-
* Whether the button is loading
|
|
134
|
-
*/
|
|
135
|
-
loading: {
|
|
136
|
-
type: Boolean,
|
|
137
|
-
default: false,
|
|
138
|
-
},
|
|
139
|
-
/**
|
|
140
|
-
* Whether the button is selected (sets aria-selected attribute)
|
|
141
|
-
*/
|
|
142
|
-
selected: {
|
|
143
|
-
type: Boolean,
|
|
144
|
-
default: false,
|
|
145
|
-
},
|
|
146
|
-
/**
|
|
147
|
-
* Exactly as the `to` prop in `RouterLink`, when used, it renders a link that triggers a navigation on click.
|
|
148
|
-
* See https://router.vuejs.org/api/#RouteLocationRaw
|
|
149
|
-
*/
|
|
150
|
-
to: {
|
|
151
|
-
type: [Object, String] as PropType<RouteLocationRaw>,
|
|
152
|
-
default: '',
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const props = defineProps({
|
|
126
|
+
/**
|
|
127
|
+
* The button style e.g primary, secondary, primary-outline, secondary-outline, error, success, primary-link
|
|
128
|
+
*/
|
|
129
|
+
type: {
|
|
130
|
+
type: String as PropType<ButtonType>,
|
|
131
|
+
default: 'primary',
|
|
132
|
+
validator(value: ButtonType) {
|
|
133
|
+
return BUTTON_TYPES.includes(value);
|
|
153
134
|
},
|
|
154
135
|
},
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
136
|
+
/**
|
|
137
|
+
* The button native type e.g button, submit, reset
|
|
138
|
+
*/
|
|
139
|
+
nativeType: {
|
|
140
|
+
type: String as PropType<ButtonNativeType>,
|
|
141
|
+
default: 'button',
|
|
142
|
+
validator(value: ButtonNativeType) {
|
|
143
|
+
return BUTTON_NATIVE_TYPES.includes(value);
|
|
160
144
|
},
|
|
161
|
-
|
|
162
|
-
|
|
145
|
+
},
|
|
146
|
+
/**
|
|
147
|
+
* The button size e.g sm, md, lg
|
|
148
|
+
*/
|
|
149
|
+
size: {
|
|
150
|
+
type: String as PropType<Size>,
|
|
151
|
+
default: 'md',
|
|
152
|
+
validator(value: Size) {
|
|
153
|
+
return SIZES.includes(value);
|
|
163
154
|
},
|
|
164
155
|
},
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
156
|
+
/**
|
|
157
|
+
* Whether the button is loading
|
|
158
|
+
*/
|
|
159
|
+
loading: {
|
|
160
|
+
type: Boolean,
|
|
161
|
+
default: false,
|
|
162
|
+
},
|
|
163
|
+
/**
|
|
164
|
+
* Whether the button is selected (sets aria-selected attribute)
|
|
165
|
+
*/
|
|
166
|
+
selected: {
|
|
167
|
+
type: Boolean,
|
|
168
|
+
default: false,
|
|
169
|
+
},
|
|
170
|
+
/**
|
|
171
|
+
* Exactly as the `to` prop in `RouterLink`, when used, it renders a link that triggers a navigation on click.
|
|
172
|
+
* See https://router.vuejs.org/api/#RouteLocationRaw
|
|
173
|
+
*/
|
|
174
|
+
to: {
|
|
175
|
+
type: [Object, String] as PropType<RouteLocationRaw>,
|
|
176
|
+
default: '',
|
|
168
177
|
},
|
|
178
|
+
/**
|
|
179
|
+
* The icon to display on the button
|
|
180
|
+
*/
|
|
181
|
+
icon: {
|
|
182
|
+
type: String as PropType<Icon>,
|
|
183
|
+
default: '',
|
|
184
|
+
},
|
|
185
|
+
iconRight: {
|
|
186
|
+
type: String as PropType<Icon>,
|
|
187
|
+
default: '',
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const classes = computed(() => {
|
|
192
|
+
const { button, content, loader, icon } = btn({
|
|
193
|
+
type: props.type,
|
|
194
|
+
size: props.size,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
return { button: button(), content: content(), loader: loader(), icon: icon() };
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const loaderSize = computed(() => {
|
|
201
|
+
return Number(`${LOADER_SIZES[props.size]}`);
|
|
169
202
|
});
|
|
170
203
|
</script>
|
|
@@ -45,7 +45,7 @@ const attrs = useAttrs();
|
|
|
45
45
|
const { labelClasses, errorMsgClasses } = useInputClasses(props);
|
|
46
46
|
|
|
47
47
|
// Computed
|
|
48
|
-
const datePickerProps = computed(() => {
|
|
48
|
+
const datePickerProps = computed<VueDatePickerProps>(() => {
|
|
49
49
|
const { modelValue: _, ...propsWithoutModelValue } = props;
|
|
50
50
|
const { class: classes, style, ...attrsWithoutClassAndStyle } = attrs;
|
|
51
51
|
|
|
@@ -134,7 +134,7 @@ describe('PSelectBtn.vue', () => {
|
|
|
134
134
|
},
|
|
135
135
|
});
|
|
136
136
|
|
|
137
|
-
const buttonDivs =
|
|
137
|
+
const buttonDivs = wrapper.findAll('div.inline-flex');
|
|
138
138
|
|
|
139
139
|
buttonDivs.forEach((buttonDiv, i) => {
|
|
140
140
|
expect(buttonDiv.attributes()['data-tooltip']).toBe(items[i].textCustom);
|
|
@@ -213,6 +213,25 @@ describe('PSelectBtn.vue', () => {
|
|
|
213
213
|
});
|
|
214
214
|
});
|
|
215
215
|
|
|
216
|
+
it('renders auto-width buttons', async () => {
|
|
217
|
+
const wrapper = createWrapperFor(PSelectBtn, {
|
|
218
|
+
props: {
|
|
219
|
+
items,
|
|
220
|
+
itemValue: 'valueCustom',
|
|
221
|
+
itemText: 'textCustom',
|
|
222
|
+
modelValue: 2,
|
|
223
|
+
grow: false,
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const buttons = await wrapper.findAll('button');
|
|
228
|
+
|
|
229
|
+
expect(wrapper.classes()).toContain('flex');
|
|
230
|
+
buttons.forEach((button) => {
|
|
231
|
+
expect(button.classes()).not.toContain('flex-1');
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
|
|
216
235
|
it('removes padding from buttons', async () => {
|
|
217
236
|
const wrapper = createWrapperFor(PSelectBtn, {
|
|
218
237
|
props: {
|
|
@@ -224,11 +243,11 @@ describe('PSelectBtn.vue', () => {
|
|
|
224
243
|
},
|
|
225
244
|
});
|
|
226
245
|
|
|
227
|
-
const
|
|
246
|
+
const buttonDivs = wrapper.findAll('div.inline-flex');
|
|
228
247
|
|
|
229
|
-
|
|
230
|
-
expect(
|
|
231
|
-
expect(
|
|
248
|
+
buttonDivs.forEach((buttonDiv) => {
|
|
249
|
+
expect(buttonDiv.classes()).toContain('*:px-0');
|
|
250
|
+
expect(buttonDiv.classes()).toContain('*:py-0');
|
|
232
251
|
});
|
|
233
252
|
});
|
|
234
253
|
|
|
@@ -52,9 +52,11 @@ export const Default = {
|
|
|
52
52
|
play: async ({ canvasElement }) => {
|
|
53
53
|
const canvas = within(canvasElement);
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
const btn = canvas.getByRole('button', { name: /Aleksandr Chappel/i });
|
|
56
56
|
|
|
57
|
-
await
|
|
57
|
+
await userEvent.click(btn);
|
|
58
|
+
|
|
59
|
+
await expect(btn.getAttribute('aria-selected')).toBe('true');
|
|
58
60
|
},
|
|
59
61
|
};
|
|
60
62
|
|
|
@@ -72,9 +74,9 @@ export const DisabledOption = {
|
|
|
72
74
|
play: async ({ canvasElement }) => {
|
|
73
75
|
const canvas = within(canvasElement);
|
|
74
76
|
|
|
75
|
-
const
|
|
77
|
+
const disabledBtn = canvas.getByRole('button', { name: /Van Deyes/i });
|
|
76
78
|
|
|
77
|
-
await expect(
|
|
79
|
+
await expect(disabledBtn.hasAttribute('disabled')).toBe(true);
|
|
78
80
|
await expect(canvas.getByText(/Meris/i).parentNode.hasAttribute('disabled')).toBe(false);
|
|
79
81
|
await expect(canvas.getByText(/Chick/i).parentNode.hasAttribute('disabled')).toBe(false);
|
|
80
82
|
},
|
|
@@ -245,3 +247,42 @@ export const MultipleSelected = {
|
|
|
245
247
|
},
|
|
246
248
|
},
|
|
247
249
|
};
|
|
250
|
+
|
|
251
|
+
export const WithIcons = {
|
|
252
|
+
args: {
|
|
253
|
+
items: [
|
|
254
|
+
{ value: 1, text: 'Aleksandr Chappel', icon: 'archive' },
|
|
255
|
+
{ value: 2, text: 'Van Deyes', icon: 'edit' },
|
|
256
|
+
{ value: 3, text: 'Meris Hardman', icon: 'delete' },
|
|
257
|
+
{ value: 4, text: 'Chick Catto', icon: 'send' },
|
|
258
|
+
{ value: 5, text: "Alys O'Flynn", icon: 'settings' },
|
|
259
|
+
],
|
|
260
|
+
},
|
|
261
|
+
parameters: {
|
|
262
|
+
docs: {
|
|
263
|
+
description: {
|
|
264
|
+
story: 'We can pass an `icon` attribute to the list of options to add an icon to an option.',
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
export const WithIconsOnly = {
|
|
271
|
+
args: {
|
|
272
|
+
items: [
|
|
273
|
+
{ value: 1, icon: 'archive' },
|
|
274
|
+
{ value: 2, icon: 'edit' },
|
|
275
|
+
{ value: 3, icon: 'delete' },
|
|
276
|
+
{ value: 4, icon: 'send' },
|
|
277
|
+
{ value: 5, icon: 'settings' },
|
|
278
|
+
],
|
|
279
|
+
},
|
|
280
|
+
parameters: {
|
|
281
|
+
docs: {
|
|
282
|
+
description: {
|
|
283
|
+
story:
|
|
284
|
+
'We can pass an `icon` attribute without a `text` attribute to the list of options to only display an icon.',
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div class="flex">
|
|
3
3
|
<div
|
|
4
4
|
v-for="(item, index) in items"
|
|
5
|
-
:key="item[itemValue]
|
|
5
|
+
:key="String(item[itemValue])"
|
|
6
6
|
v-tooltip="{ content: tooltipText(item) }"
|
|
7
7
|
:class="['inline-flex', { '*:px-0 *:py-0': noPadding, grow }]"
|
|
8
8
|
>
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
:size="size"
|
|
11
11
|
type="secondary-outline-blue"
|
|
12
12
|
:disabled="item.disabled"
|
|
13
|
+
:icon="String(item.icon)"
|
|
13
14
|
:class="{
|
|
14
15
|
'rounded-none': index !== 0 && index !== items.length - 1 && items.length > 1,
|
|
15
16
|
'rounded-br-none rounded-tr-none': index === 0 && items.length > 1,
|
|
@@ -31,7 +32,6 @@ import { type Size } from '@squirrel/components/p-btn/p-btn.types';
|
|
|
31
32
|
import PBtn from '@squirrel/components/p-btn/p-btn.vue';
|
|
32
33
|
|
|
33
34
|
type BtnGroupItem = Record<string, string | number | boolean>;
|
|
34
|
-
type Key = string | number;
|
|
35
35
|
|
|
36
36
|
type Props = {
|
|
37
37
|
modelValue?: string | number | null | BtnGroupItem[];
|