sprintify-ui 0.10.24 → 0.10.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/dist/sprintify-ui.es.js +2994 -2944
- package/dist/types/components/BaseTabItem.vue.d.ts +23 -5
- package/dist/types/components/BaseTabs.vue.d.ts +13 -2
- package/package.json +1 -1
- package/src/components/BaseTabItem.vue +90 -11
- package/src/components/BaseTabs.stories.js +74 -3
- package/src/components/BaseTabs.vue +34 -2
|
@@ -1,32 +1,50 @@
|
|
|
1
|
+
import { ComputedRef } from 'vue';
|
|
1
2
|
import { NavigationFailure, RouteLocationRaw } from 'vue-router';
|
|
2
3
|
type __VLS_Props = {
|
|
3
|
-
|
|
4
|
+
id?: string;
|
|
5
|
+
to?: RouteLocationRaw;
|
|
4
6
|
disabled?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* The strategy to determine if the tab is active. Only used when the
|
|
9
|
+
* `to` prop is provided.
|
|
10
|
+
* - `default`: The tab is active if the route matches the path.
|
|
11
|
+
* - `exact`: The tab is active if the route matches the path exactly.
|
|
12
|
+
*/
|
|
5
13
|
activeStrategy?: 'default' | 'exact';
|
|
6
14
|
};
|
|
7
|
-
declare
|
|
15
|
+
declare const idInternal: ComputedRef<string>;
|
|
16
|
+
declare const currentTabId: ComputedRef<string | null>;
|
|
17
|
+
declare function onClick(navigate?: () => Promise<void | NavigationFailure> | null): Promise<void | NavigationFailure> | null | undefined;
|
|
8
18
|
declare function isActiveInternal(isActive: boolean, isExactActive: boolean): boolean;
|
|
9
19
|
declare const baseTabItemRef: import("vue").Ref<HTMLElement | null, HTMLElement | null>;
|
|
10
|
-
declare const sizeClassOuter:
|
|
11
|
-
declare const sizeClassInner:
|
|
20
|
+
declare const sizeClassOuter: ComputedRef<string>;
|
|
21
|
+
declare const sizeClassInner: ComputedRef<"" | "text-xs py-1 px-1 font-normal" | "text-sm py-1 px-2 font-normal" | "text-sm py-1.5 px-2 font-normal" | "text-base py-1.5 px-3 font-normal">;
|
|
12
22
|
declare const __VLS_ctx: InstanceType<__VLS_PickNotAny<typeof __VLS_self, new () => {}>>;
|
|
13
23
|
declare var __VLS_5: {
|
|
14
24
|
active: boolean;
|
|
15
|
-
};
|
|
25
|
+
}, __VLS_7: {};
|
|
16
26
|
type __VLS_Slots = __VLS_PrettifyGlobal<__VLS_OmitStringIndex<typeof __VLS_ctx.$slots> & {
|
|
17
27
|
default?: (props: typeof __VLS_5) => any;
|
|
28
|
+
} & {
|
|
29
|
+
default?: (props: typeof __VLS_7) => any;
|
|
18
30
|
}>;
|
|
19
31
|
declare const __VLS_self: import("vue").DefineComponent<__VLS_Props, {
|
|
32
|
+
idInternal: typeof idInternal;
|
|
33
|
+
currentTabId: typeof currentTabId;
|
|
20
34
|
onClick: typeof onClick;
|
|
21
35
|
isActiveInternal: typeof isActiveInternal;
|
|
22
36
|
baseTabItemRef: typeof baseTabItemRef;
|
|
23
37
|
sizeClassOuter: typeof sizeClassOuter;
|
|
24
38
|
sizeClassInner: typeof sizeClassInner;
|
|
25
39
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
40
|
+
to: RouteLocationRaw;
|
|
41
|
+
id: string;
|
|
26
42
|
disabled: boolean;
|
|
27
43
|
activeStrategy: "default" | "exact";
|
|
28
44
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
29
45
|
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
46
|
+
to: RouteLocationRaw;
|
|
47
|
+
id: string;
|
|
30
48
|
disabled: boolean;
|
|
31
49
|
activeStrategy: "default" | "exact";
|
|
32
50
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
type __VLS_Props = {
|
|
2
|
+
modelValue?: string | number | null | undefined;
|
|
2
3
|
size?: 'xs' | 'sm' | 'md' | 'lg';
|
|
3
4
|
};
|
|
4
5
|
declare const scrollable: import("vue").Ref<HTMLElement | null, HTMLElement | null>;
|
|
@@ -11,11 +12,21 @@ type __VLS_Slots = __VLS_PrettifyGlobal<__VLS_OmitStringIndex<typeof __VLS_ctx.$
|
|
|
11
12
|
declare const __VLS_self: import("vue").DefineComponent<__VLS_Props, {
|
|
12
13
|
scrollable: typeof scrollable;
|
|
13
14
|
lineRef: typeof lineRef;
|
|
14
|
-
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
15
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
16
|
+
"update:modelValue": (...args: any[]) => void;
|
|
17
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
18
|
+
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
|
19
|
+
}>, {
|
|
15
20
|
size: "xs" | "sm" | "md" | "lg";
|
|
21
|
+
modelValue: string | number | null;
|
|
16
22
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
17
|
-
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
23
|
+
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
24
|
+
"update:modelValue": (...args: any[]) => void;
|
|
25
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
26
|
+
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
|
27
|
+
}>, {
|
|
18
28
|
size: "xs" | "sm" | "md" | "lg";
|
|
29
|
+
modelValue: string | number | null;
|
|
19
30
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
20
31
|
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
21
32
|
export default _default;
|
package/package.json
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
class="[&:first-child_a]:pl-0 [&:last-child_a]:pr-0"
|
|
5
5
|
>
|
|
6
6
|
<RouterLink
|
|
7
|
+
v-if="to"
|
|
7
8
|
v-slot="{ href, navigate, isActive, isExactActive }"
|
|
8
9
|
:to="to"
|
|
9
10
|
custom
|
|
@@ -16,7 +17,6 @@
|
|
|
16
17
|
isActiveInternal(isActive, isExactActive)
|
|
17
18
|
? 'active text-primary-600'
|
|
18
19
|
: 'text-slate-600 hover:text-slate-900',
|
|
19
|
-
disabled ? 'cursor-not-allowed opacity-60' : '',
|
|
20
20
|
sizeClassOuter,
|
|
21
21
|
]"
|
|
22
22
|
@click.prevent="onClick(navigate)"
|
|
@@ -35,40 +35,104 @@
|
|
|
35
35
|
</div>
|
|
36
36
|
</a>
|
|
37
37
|
</RouterLink>
|
|
38
|
+
<button
|
|
39
|
+
v-else
|
|
40
|
+
type="button"
|
|
41
|
+
:disabled="disabled"
|
|
42
|
+
class="group inline-block rounded-t-lg"
|
|
43
|
+
:class="[
|
|
44
|
+
currentTabId === idInternal
|
|
45
|
+
? 'active text-primary-600'
|
|
46
|
+
: 'text-slate-600 hover:text-slate-900',
|
|
47
|
+
sizeClassOuter,
|
|
48
|
+
]"
|
|
49
|
+
@click="onClick()"
|
|
50
|
+
>
|
|
51
|
+
<div class="relative flex py-1">
|
|
52
|
+
<div
|
|
53
|
+
:class="[
|
|
54
|
+
'whitespace-nowrap rounded-md group-hover:bg-black group-hover:bg-opacity-5',
|
|
55
|
+
sizeClassInner
|
|
56
|
+
]"
|
|
57
|
+
>
|
|
58
|
+
<div class="base-tab-item-slot">
|
|
59
|
+
<slot />
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</button>
|
|
38
64
|
</li>
|
|
39
65
|
</template>
|
|
40
66
|
|
|
41
67
|
<script lang="ts" setup>
|
|
42
68
|
import { useElementBounding } from '@vueuse/core';
|
|
69
|
+
import { uniqueId } from 'lodash';
|
|
70
|
+
import { ComputedRef } from 'vue';
|
|
43
71
|
import { NavigationFailure, RouteLocationRaw } from 'vue-router';
|
|
44
72
|
|
|
73
|
+
const router = useRouter();
|
|
74
|
+
|
|
45
75
|
const props = withDefaults(
|
|
46
76
|
defineProps<{
|
|
47
|
-
|
|
77
|
+
id?: string;
|
|
78
|
+
to?: RouteLocationRaw;
|
|
48
79
|
disabled?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* The strategy to determine if the tab is active. Only used when the
|
|
82
|
+
* `to` prop is provided.
|
|
83
|
+
* - `default`: The tab is active if the route matches the path.
|
|
84
|
+
* - `exact`: The tab is active if the route matches the path exactly.
|
|
85
|
+
*/
|
|
49
86
|
activeStrategy?: 'default' | 'exact';
|
|
50
87
|
}>(),
|
|
51
88
|
{
|
|
89
|
+
id: undefined,
|
|
90
|
+
to: undefined,
|
|
52
91
|
disabled: false,
|
|
53
92
|
activeStrategy: 'default',
|
|
54
93
|
}
|
|
55
94
|
);
|
|
56
95
|
|
|
96
|
+
const idInternal = computed(() => {
|
|
97
|
+
if (props.id) {
|
|
98
|
+
return props.id;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!router || !props.to) {
|
|
102
|
+
return uniqueId() + '';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const route = router.resolve(props.to);
|
|
106
|
+
const path = route.fullPath;
|
|
107
|
+
|
|
108
|
+
return path;
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const currentTabId = inject<ComputedRef<string | null>>('tabs:currentTabId', computed(() => null));
|
|
112
|
+
const updateTabId = inject<((tabId: string) => void)>('tabs:updateTabId');
|
|
113
|
+
|
|
57
114
|
const size = inject('tabs:size', ref<'xs' | 'sm' | 'md' | 'lg'>('md'));
|
|
58
|
-
const animate = inject('tabs:animate', () => { });
|
|
59
115
|
|
|
60
|
-
function onClick(navigate
|
|
116
|
+
function onClick(navigate?: () => Promise<void | NavigationFailure> | null) {
|
|
61
117
|
if (props.disabled) {
|
|
62
118
|
return;
|
|
63
119
|
}
|
|
64
120
|
|
|
65
|
-
|
|
121
|
+
if (updateTabId) {
|
|
122
|
+
updateTabId(idInternal.value);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (navigate) {
|
|
126
|
+
return navigate();
|
|
127
|
+
}
|
|
66
128
|
}
|
|
67
129
|
|
|
68
130
|
function isActiveInternal(isActive: boolean, isExactActive: boolean) {
|
|
69
131
|
return props.activeStrategy == 'default' ? isActive : isExactActive;
|
|
70
132
|
}
|
|
71
133
|
|
|
134
|
+
// Animate
|
|
135
|
+
|
|
72
136
|
const baseTabItemRef = ref<HTMLElement | null>(null);
|
|
73
137
|
|
|
74
138
|
const { x, y, width } = useElementBounding(baseTabItemRef);
|
|
@@ -80,20 +144,35 @@ watch(
|
|
|
80
144
|
}
|
|
81
145
|
);
|
|
82
146
|
|
|
147
|
+
const animate = inject('tabs:animate', () => { });
|
|
148
|
+
|
|
149
|
+
// Classes
|
|
83
150
|
|
|
84
151
|
const sizeClassOuter = computed(() => {
|
|
152
|
+
|
|
153
|
+
const classes = [];
|
|
154
|
+
|
|
155
|
+
if (props.disabled) {
|
|
156
|
+
classes.push('cursor-not-allowed opacity-60');
|
|
157
|
+
}
|
|
158
|
+
|
|
85
159
|
switch (size.value) {
|
|
86
160
|
case 'xs':
|
|
87
|
-
|
|
161
|
+
classes.push('px-1');
|
|
162
|
+
break;
|
|
88
163
|
case 'sm':
|
|
89
|
-
|
|
164
|
+
classes.push('px-1.5');
|
|
165
|
+
break;
|
|
90
166
|
case 'md':
|
|
91
|
-
|
|
167
|
+
classes.push('px-2');
|
|
168
|
+
break;
|
|
92
169
|
case 'lg':
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return '';
|
|
170
|
+
classes.push('px-3');
|
|
171
|
+
break;
|
|
96
172
|
}
|
|
173
|
+
|
|
174
|
+
return classes.join(' ');
|
|
175
|
+
|
|
97
176
|
});
|
|
98
177
|
|
|
99
178
|
const sizeClassInner = computed(() => {
|
|
@@ -23,16 +23,18 @@ const Template = (args) => ({
|
|
|
23
23
|
setup() {
|
|
24
24
|
const label = ref("Home");
|
|
25
25
|
|
|
26
|
+
const modelValue = ref("setup");
|
|
27
|
+
|
|
26
28
|
setInterval(() => {
|
|
27
29
|
label.value = Math.random().toString(36).substring(7);
|
|
28
30
|
}, 1000);
|
|
29
31
|
|
|
30
|
-
return { args, label };
|
|
32
|
+
return { args, label, modelValue };
|
|
31
33
|
},
|
|
32
34
|
template: `
|
|
33
35
|
<div class="bg-slate-100 py-10">
|
|
34
36
|
<BaseContainer>
|
|
35
|
-
<BaseTabs v-bind="args">
|
|
37
|
+
<BaseTabs v-model="modelValue" v-bind="args">
|
|
36
38
|
<BaseTabItem to="/" v-slot="{active}">
|
|
37
39
|
<div class="flex items-center">
|
|
38
40
|
<span class="mr-1">{{ label }}</span>
|
|
@@ -62,7 +64,9 @@ const Template = (args) => ({
|
|
|
62
64
|
<div class="mt-10">
|
|
63
65
|
<BaseCard>
|
|
64
66
|
<BaseCardRow>
|
|
65
|
-
{{ $route.path }}
|
|
67
|
+
path: {{ $route.path }}
|
|
68
|
+
<br>
|
|
69
|
+
id: {{ modelValue }}
|
|
66
70
|
</BaseCardRow>
|
|
67
71
|
</BaseCard>
|
|
68
72
|
</div>
|
|
@@ -93,3 +97,70 @@ export const SizeLG = Template.bind({});
|
|
|
93
97
|
SizeLG.args = {
|
|
94
98
|
size: "lg",
|
|
95
99
|
};
|
|
100
|
+
|
|
101
|
+
const TemplateStatic = (args) => ({
|
|
102
|
+
components: {
|
|
103
|
+
BaseTabs,
|
|
104
|
+
BaseTabItem,
|
|
105
|
+
BaseContainer,
|
|
106
|
+
BaseCard,
|
|
107
|
+
BaseCardRow,
|
|
108
|
+
BaseCounter,
|
|
109
|
+
},
|
|
110
|
+
setup() {
|
|
111
|
+
const label = ref("Home");
|
|
112
|
+
|
|
113
|
+
const modelValue = ref("setup");
|
|
114
|
+
|
|
115
|
+
setInterval(() => {
|
|
116
|
+
label.value = Math.random().toString(36).substring(7);
|
|
117
|
+
}, 1000);
|
|
118
|
+
|
|
119
|
+
return { args, label, modelValue };
|
|
120
|
+
},
|
|
121
|
+
template: `
|
|
122
|
+
<div class="bg-slate-100 py-10">
|
|
123
|
+
<BaseContainer>
|
|
124
|
+
<BaseTabs v-model="modelValue" v-bind="args">
|
|
125
|
+
<BaseTabItem id="home" v-slot="{active}">
|
|
126
|
+
<div class="flex items-center">
|
|
127
|
+
<span class="mr-1">{{ label }}</span>
|
|
128
|
+
<BaseCounter
|
|
129
|
+
:size="['lg', 'md'].includes(args.size) ? 'sm' : 'xs'"
|
|
130
|
+
:color="active ? 'primary' : 'light'"
|
|
131
|
+
:count="1"
|
|
132
|
+
></BaseCounter>
|
|
133
|
+
</div>
|
|
134
|
+
</BaseTabItem>
|
|
135
|
+
<BaseTabItem id="setup">
|
|
136
|
+
Setup
|
|
137
|
+
</BaseTabItem>
|
|
138
|
+
<BaseTabItem id="settings">
|
|
139
|
+
Settings
|
|
140
|
+
</BaseTabItem>
|
|
141
|
+
<BaseTabItem id="articles">
|
|
142
|
+
Articles
|
|
143
|
+
</BaseTabItem>
|
|
144
|
+
<BaseTabItem id="misc">
|
|
145
|
+
Miscellaneous
|
|
146
|
+
</BaseTabItem>
|
|
147
|
+
<BaseTabItem id="users">
|
|
148
|
+
Users
|
|
149
|
+
</BaseTabItem>
|
|
150
|
+
</BaseTabs>
|
|
151
|
+
|
|
152
|
+
<div class="mt-10">
|
|
153
|
+
<BaseCard>
|
|
154
|
+
<BaseCardRow>
|
|
155
|
+
id: {{ modelValue }}
|
|
156
|
+
</BaseCardRow>
|
|
157
|
+
</BaseCard>
|
|
158
|
+
</div>
|
|
159
|
+
</BaseContainer>
|
|
160
|
+
</div>
|
|
161
|
+
`,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
export const Static = TemplateStatic.bind({});
|
|
165
|
+
Static.args = {
|
|
166
|
+
};
|
|
@@ -29,23 +29,55 @@ import { debounce } from 'lodash';
|
|
|
29
29
|
|
|
30
30
|
const props = withDefaults(
|
|
31
31
|
defineProps<{
|
|
32
|
+
modelValue?: string | number | null | undefined;
|
|
32
33
|
size?: 'xs' | 'sm' | 'md' | 'lg';
|
|
33
34
|
}>(),
|
|
34
35
|
{
|
|
36
|
+
modelValue: null,
|
|
35
37
|
size: 'md',
|
|
36
38
|
}
|
|
37
39
|
);
|
|
38
40
|
|
|
39
41
|
const route = useRoute();
|
|
42
|
+
|
|
40
43
|
const scrollable = ref<HTMLElement | null>(null);
|
|
41
44
|
|
|
45
|
+
const emit = defineEmits(['update:modelValue']);
|
|
46
|
+
|
|
42
47
|
watch(
|
|
43
48
|
() => route.fullPath,
|
|
44
49
|
() => {
|
|
45
50
|
nextTick(() => {
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
updateTab();
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
{ immediate: true }
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
watch(
|
|
58
|
+
() => props.modelValue,
|
|
59
|
+
() => {
|
|
60
|
+
nextTick(() => {
|
|
61
|
+
updateTab();
|
|
48
62
|
});
|
|
63
|
+
},
|
|
64
|
+
{ immediate: true }
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
function updateTab() {
|
|
68
|
+
scrollToCenter();
|
|
69
|
+
animateLine();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
provide(
|
|
73
|
+
'tabs:currentTabId',
|
|
74
|
+
computed(() => props.modelValue)
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
provide(
|
|
78
|
+
'tabs:updateTabId',
|
|
79
|
+
(tabId: string) => {
|
|
80
|
+
emit('update:modelValue', tabId);
|
|
49
81
|
}
|
|
50
82
|
);
|
|
51
83
|
|