design-system-next 2.11.20 → 2.11.22
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/design-system-next.es.js +7842 -7635
- package/dist/design-system-next.es.js.gz +0 -0
- package/dist/design-system-next.umd.js +12 -12
- package/dist/design-system-next.umd.js.gz +0 -0
- package/dist/main.css +1 -1
- package/dist/main.css.gz +0 -0
- package/dist/package.json.d.ts +1 -1
- package/package.json +1 -1
- package/src/App.vue +1 -49
- package/src/components/lozenge/lozenge.ts +16 -0
- package/src/components/lozenge/lozenge.vue +22 -13
- package/src/components/lozenge/use-lozenge.ts +58 -27
- package/src/components/sidenav/sidenav.ts +14 -0
- package/src/components/sidenav/sidenav.vue +36 -6
- package/src/components/sidenav/use-sidenav.ts +16 -3
|
@@ -1,31 +1,40 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :class="lozengeClasses.wrapperClasses">
|
|
3
|
-
<div v-if="visible && !loading" :class="lozengeClasses.baseClasses">
|
|
4
|
-
<div :class="lozengeClasses.toneClasses">
|
|
5
|
-
<div v-if="$slots.icon" class="spr-flex spr-h-3 spr-w-3 spr-items-center spr-overflow-hidden">
|
|
6
|
-
<slot name="icon"
|
|
2
|
+
<div :class="['spr-lozenge__wrapper', lozengeClasses.wrapperClasses]">
|
|
3
|
+
<div v-if="visible && !loading" :class="['spr-lozenge__base', lozengeClasses.baseClasses]">
|
|
4
|
+
<div :class="['spr-lozenge__tone',lozengeClasses.toneClasses]" :tabindex="props.interactive || props.dropdown ? 0 : -1">
|
|
5
|
+
<div v-if="$slots.icon || props.icon" class="spr-lozenge__prefix-icon spr-flex spr-h-3 spr-w-3 spr-items-center spr-overflow-hidden">
|
|
6
|
+
<slot name="icon">
|
|
7
|
+
<icon :icon="props.icon" />
|
|
8
|
+
</slot>
|
|
7
9
|
</div>
|
|
8
10
|
|
|
9
|
-
<div v-if="$slots.avatar" class="spr-
|
|
10
|
-
<slot name="avatar"
|
|
11
|
+
<div v-if="$slots.avatar || props.url" class="spr-lozenge__avatar">
|
|
12
|
+
<slot name="avatar">
|
|
13
|
+
<div v-if="url" class="spr-h-4 spr-w-4 spr-overflow-hidden">
|
|
14
|
+
<img class="spr-h-full spr-w-full spr-rounded-full spr-object-cover" :src="url" alt="avatar" />
|
|
15
|
+
</div>
|
|
16
|
+
</slot>
|
|
11
17
|
</div>
|
|
12
18
|
|
|
13
|
-
<
|
|
14
|
-
<img class="spr-h-full spr-w-full spr-rounded-full spr-object-cover" :src="url" alt="avatar" />
|
|
15
|
-
</div>
|
|
19
|
+
<span class="spr-lozenge__label spr-label-xs-medium">{{ label }}</span>
|
|
16
20
|
|
|
17
|
-
<div
|
|
21
|
+
<div v-if="$slots.postfixIcon || props.postfixIcon || props.dropdown" class="spr-lozenge__prefix-icon spr-flex spr-h-3 spr-w-3 spr-items-center spr-overflow-hidden">
|
|
22
|
+
<slot name="postfixIcon">
|
|
23
|
+
<icon v-if="props.postfixIcon" :icon="props.postfixIcon" />
|
|
24
|
+
<icon v-else icon="ph:caret-down-fill" />
|
|
25
|
+
</slot>
|
|
26
|
+
</div>
|
|
18
27
|
</div>
|
|
19
28
|
</div>
|
|
20
|
-
<div v-if="visible && loading" :class="lozengeClasses.baseClasses" />
|
|
29
|
+
<div v-if="visible && loading" :class="['spr-lozenge__loading', lozengeClasses.baseClasses]" />
|
|
21
30
|
</div>
|
|
22
31
|
</template>
|
|
23
32
|
|
|
24
33
|
<script lang="ts" setup>
|
|
25
34
|
import { lozengePropTypes } from './lozenge';
|
|
26
35
|
import { useLozenge } from './use-lozenge';
|
|
36
|
+
import { Icon } from '@iconify/vue';
|
|
27
37
|
|
|
28
38
|
const props = defineProps(lozengePropTypes);
|
|
29
|
-
|
|
30
39
|
const { lozengeClasses } = useLozenge(props);
|
|
31
40
|
</script>
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { toRefs, computed, ComputedRef } from 'vue';
|
|
2
|
-
|
|
1
|
+
import { toRefs, computed, ComputedRef, useSlots } from 'vue';
|
|
3
2
|
import classNames from 'classnames';
|
|
4
|
-
|
|
5
3
|
import type { LozengePropTypes } from './lozenge';
|
|
6
4
|
|
|
7
5
|
interface LozengeClasses {
|
|
@@ -11,7 +9,9 @@ interface LozengeClasses {
|
|
|
11
9
|
}
|
|
12
10
|
|
|
13
11
|
export const useLozenge = (props: LozengePropTypes) => {
|
|
14
|
-
const { tone, fill, loading } = toRefs(props);
|
|
12
|
+
const { tone, fill, loading, interactive, url, dropdown } = toRefs(props);
|
|
13
|
+
const slots = useSlots();
|
|
14
|
+
const isInteractive = computed(() => interactive.value || dropdown.value);
|
|
15
15
|
|
|
16
16
|
const lozengeClasses: ComputedRef<LozengeClasses> = computed(() => {
|
|
17
17
|
const wrapperClasses = classNames({
|
|
@@ -25,31 +25,62 @@ export const useLozenge = (props: LozengePropTypes) => {
|
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
const toneClasses = classNames(
|
|
28
|
-
'spr-
|
|
28
|
+
'spr-box-border spr-h-[20px] spr-inline-flex spr-items-center spr-gap-size-spacing-6xs spr-rounded-md spr-border-solid spr-p-size-spacing-5xs spr-text-xs spr-uppercase',
|
|
29
29
|
{
|
|
30
|
-
'spr-
|
|
31
|
-
|
|
32
|
-
'spr-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
'spr-text-
|
|
37
|
-
'spr-
|
|
38
|
-
|
|
39
|
-
'spr-text-
|
|
40
|
-
|
|
41
|
-
|
|
30
|
+
'spr-h-[20px]': !url.value,
|
|
31
|
+
'spr-h-[24px]': url.value || slots.avatar,
|
|
32
|
+
'spr-border': !fill.value,
|
|
33
|
+
'spr-cursor-pointer': isInteractive.value,
|
|
34
|
+
// #region - Styles for hollow lozenge
|
|
35
|
+
// Pending
|
|
36
|
+
'spr-text-mango-800 spr-background-color-pending-weak spr-border-mango-800': tone.value === 'pending' && !fill.value,
|
|
37
|
+
'hover:spr-bg-[#FFF89E] active:spr-bg-[#FFF56B]': tone.value === 'pending' && !fill.value && isInteractive.value,
|
|
38
|
+
// Information
|
|
39
|
+
'spr-text-blueberry-800 spr-background-color-information-weak spr-border-blueberry-800': tone.value === 'information' && !fill.value,
|
|
40
|
+
'hover:spr-bg-[#ADD6FF] active:spr-bg-[#7ABDFF]': tone.value === 'information' && !fill.value && isInteractive.value,
|
|
41
|
+
// Success
|
|
42
|
+
'spr-text-kangkong-800 spr-background-color-success-weak spr-border-kangkong-800': tone.value === 'success' && !fill.value,
|
|
43
|
+
'hover:spr-bg-[#AFF8C6] active:spr-bg-[#80F4A4]': tone.value === 'success' && !fill.value && isInteractive.value,
|
|
44
|
+
// Neutral
|
|
45
|
+
'spr-text-mushroom-800 spr-background-color-base spr-border-mushroom-800': tone.value === 'neutral' && !fill.value,
|
|
46
|
+
'hover:spr-bg-[#D3D9D9] active:spr-bg-[#B8C1C1]': tone.value === 'neutral' && !fill.value && isInteractive.value,
|
|
47
|
+
// Danger
|
|
48
|
+
'spr-text-tomato-800 spr-background-color-danger-weak spr-border-tomato-800': tone.value === 'danger' && !fill.value,
|
|
49
|
+
'hover:spr-bg-[#FCB0B3] active:spr-bg-[#FB7F83]': tone.value === 'danger' && !fill.value && isInteractive.value,
|
|
50
|
+
// Caution
|
|
51
|
+
'spr-text-carrot-800 spr-background-color-caution-weak spr-border-carrot-800': tone.value === 'caution' && !fill.value,
|
|
52
|
+
'hover:spr-bg-[#FFE79E] active:spr-bg-[#FFDA6B]': tone.value === 'caution' && !fill.value && isInteractive.value,
|
|
53
|
+
// Plain
|
|
54
|
+
'spr-text-color-strong spr-border-color-base spr-background-color': tone.value === 'plain' && !fill.value,
|
|
55
|
+
'hover:spr-bg-[#E6E6E6] active:spr-bg-[#CCCCCC]': tone.value === 'plain' && !fill.value && isInteractive.value,
|
|
56
|
+
// #endregion - Styles for hollow (!fill) lozenge
|
|
42
57
|
|
|
43
|
-
|
|
44
|
-
'spr-
|
|
45
|
-
|
|
46
|
-
'spr-
|
|
47
|
-
|
|
48
|
-
'spr-background-color-base
|
|
49
|
-
'spr-background-color-
|
|
50
|
-
|
|
51
|
-
'spr-background-color-
|
|
52
|
-
'spr-
|
|
58
|
+
// #region - Styles for filled lozenge
|
|
59
|
+
'spr-border-0': fill.value,
|
|
60
|
+
'spr-text-color-strong': fill.value && (tone.value === 'pending' || tone.value === 'neutral' || tone.value === 'caution' || tone.value === 'plain'),
|
|
61
|
+
'spr-text-color-inverted-strong': fill.value && (tone.value === 'information' || tone.value === 'success' || tone.value === 'danger'),
|
|
62
|
+
// Pending
|
|
63
|
+
'spr-background-color-pending-base': tone.value === 'pending' && fill.value,
|
|
64
|
+
'hover:spr-background-color-pending-hover active:spr-background-color-pending-pressed': tone.value === 'pending' && fill.value && isInteractive.value,
|
|
65
|
+
// Information
|
|
66
|
+
'spr-background-color-information-base': tone.value === 'information' && fill.value,
|
|
67
|
+
'hover:spr-background-color-information-hover active:spr-background-color-information-pressed': tone.value === 'information' && fill.value && isInteractive.value,
|
|
68
|
+
// Success
|
|
69
|
+
'spr-background-color-success-base': tone.value === 'success' && fill.value,
|
|
70
|
+
'hover:spr-background-color-success-hover active:spr-background-color-success-pressed': tone.value === 'success' && fill.value && isInteractive.value,
|
|
71
|
+
// Neutral
|
|
72
|
+
'spr-background-color-base': tone.value === 'neutral' && fill.value,
|
|
73
|
+
'hover:spr-background-color-surface active:spr-background-color-pressed': tone.value === 'neutral' && fill.value && isInteractive.value,
|
|
74
|
+
// Danger
|
|
75
|
+
'spr-background-color-danger-base': tone.value === 'danger' && fill.value,
|
|
76
|
+
'hover:spr-background-color-danger-hover active:spr-background-color-danger-pressed': tone.value === 'danger' && fill.value && isInteractive.value,
|
|
77
|
+
// Caution
|
|
78
|
+
'spr-background-color-caution-base': tone.value === 'caution' && fill.value,
|
|
79
|
+
'hover:spr-background-color-caution-hover active:spr-background-color-caution-pressed': tone.value === 'caution' && fill.value && isInteractive.value,
|
|
80
|
+
// Plain
|
|
81
|
+
'spr-background-color': tone.value === 'plain' && fill.value,
|
|
82
|
+
'hover:spr-background-color-hover active:spr-background-color-pressed': tone.value === 'plain' && fill.value && isInteractive.value,
|
|
83
|
+
// #endregion - Styles for filled lozenge
|
|
53
84
|
},
|
|
54
85
|
);
|
|
55
86
|
|
|
@@ -32,6 +32,7 @@ export type ParentLinkItem = {
|
|
|
32
32
|
menuLinks: MenuLink[];
|
|
33
33
|
submenuLinks?: SubmenuLink[];
|
|
34
34
|
hidden?: boolean;
|
|
35
|
+
attributes?: Attributes[];
|
|
35
36
|
};
|
|
36
37
|
|
|
37
38
|
export type MenuLink = {
|
|
@@ -43,6 +44,7 @@ export type MenuLinkItem = {
|
|
|
43
44
|
title: string;
|
|
44
45
|
hidden: boolean;
|
|
45
46
|
redirect: Redirect;
|
|
47
|
+
attributes?: Attributes[];
|
|
46
48
|
submenuLinks: SubmenuLink[];
|
|
47
49
|
};
|
|
48
50
|
|
|
@@ -55,6 +57,7 @@ export type SubmenuLinkItem = {
|
|
|
55
57
|
title: string;
|
|
56
58
|
hidden: boolean;
|
|
57
59
|
redirect: Redirect;
|
|
60
|
+
attributes?: Attributes[];
|
|
58
61
|
};
|
|
59
62
|
|
|
60
63
|
export type Redirect = {
|
|
@@ -85,6 +88,16 @@ export interface NavItem {
|
|
|
85
88
|
children?: NavItem[] | null;
|
|
86
89
|
groupName?: string | null;
|
|
87
90
|
hidden?: boolean;
|
|
91
|
+
attributes?: Attributes[] | null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export type Attributes = {
|
|
95
|
+
name: string;
|
|
96
|
+
value: unknown | string | number | boolean | AttrLozenge;
|
|
97
|
+
};
|
|
98
|
+
type AttrLozenge = {
|
|
99
|
+
label: string;
|
|
100
|
+
tone?: string;
|
|
88
101
|
}
|
|
89
102
|
|
|
90
103
|
export interface MappedNavItem {
|
|
@@ -95,6 +108,7 @@ export interface MappedNavItem {
|
|
|
95
108
|
isAbsoluteURL: boolean;
|
|
96
109
|
link: string;
|
|
97
110
|
};
|
|
111
|
+
attributes?: AttrLozenge | unknown [];
|
|
98
112
|
menuLinks?: {
|
|
99
113
|
menuHeading: string;
|
|
100
114
|
items: MappedNavItem[];
|
|
@@ -241,10 +241,20 @@
|
|
|
241
241
|
class="spr-background-color-brand-base spr-absolute spr-left-0 spr-top-0 spr-h-full spr-w-[2px]"
|
|
242
242
|
></div>
|
|
243
243
|
<span>{{ menuLinkItem.title }}</span>
|
|
244
|
-
<
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
244
|
+
<div class="spr-flex spr-items-center spr-gap-1">
|
|
245
|
+
<template v-for="(attr, i) in menuLinkItem?.attributes" :key="i">
|
|
246
|
+
<spr-lozenge
|
|
247
|
+
v-if="attr?.name === 'lozenge' && attr?.value"
|
|
248
|
+
:label="(attr.value && typeof attr?.value === 'object' && 'label' in attr.value) ? String(attr.value.label) : ''"
|
|
249
|
+
:tone="getLozengeTone(attr)"
|
|
250
|
+
fill
|
|
251
|
+
/>
|
|
252
|
+
</template>
|
|
253
|
+
<Icon
|
|
254
|
+
icon="ph:caret-right"
|
|
255
|
+
class="spr-h-[16px] spr-w-[16px] spr-transform spr-font-normal spr-transition-transform spr-duration-300"
|
|
256
|
+
/>
|
|
257
|
+
</div>
|
|
248
258
|
</div>
|
|
249
259
|
<!-- #endregion - Menu links -->
|
|
250
260
|
|
|
@@ -301,6 +311,16 @@
|
|
|
301
311
|
class="spr-background-color-brand-base spr-absolute spr-left-0 spr-top-0 spr-h-full spr-w-[2px]"
|
|
302
312
|
></div>
|
|
303
313
|
<span>{{ submenuLinkItem.title }}</span>
|
|
314
|
+
<div class="spr-flex spr-items-center spr-gap-1">
|
|
315
|
+
<template v-for="(attr, i) in submenuLinkItem?.attributes" :key="i">
|
|
316
|
+
<spr-lozenge
|
|
317
|
+
v-if="attr?.name === 'lozenge' && attr?.value"
|
|
318
|
+
:label="(attr.value && typeof attr?.value === 'object' && 'label' in attr.value) ? String(attr.value.label) : ''"
|
|
319
|
+
:tone="getLozengeTone(attr)"
|
|
320
|
+
fill
|
|
321
|
+
/>
|
|
322
|
+
</template>
|
|
323
|
+
</div>
|
|
304
324
|
</div>
|
|
305
325
|
<!-- #endregion - Submenu Links -->
|
|
306
326
|
</template>
|
|
@@ -330,6 +350,14 @@
|
|
|
330
350
|
class="spr-background-color-brand-base spr-absolute spr-left-0 spr-top-0 spr-h-full spr-w-[2px]"
|
|
331
351
|
></div>
|
|
332
352
|
<span>{{ menuLinkItem.title }}</span>
|
|
353
|
+
<template v-for="(attr, i) in menuLinkItem?.attributes" :key="i">
|
|
354
|
+
<spr-lozenge
|
|
355
|
+
v-if="attr?.name === 'lozenge' && attr?.value"
|
|
356
|
+
:label="(attr.value && typeof attr?.value === 'object' && 'label' in attr.value) ? String(attr.value.label) : ''"
|
|
357
|
+
:tone="getLozengeTone(attr)"
|
|
358
|
+
fill
|
|
359
|
+
/>
|
|
360
|
+
</template>
|
|
333
361
|
</div>
|
|
334
362
|
</template>
|
|
335
363
|
<!-- #endregion - Menu link only -->
|
|
@@ -765,7 +793,7 @@
|
|
|
765
793
|
@click="isUserMenuVisible = !isUserMenuVisible"
|
|
766
794
|
>
|
|
767
795
|
<template v-if="props.userMenu.profileImage && !userProfileError">
|
|
768
|
-
<img :src="props.userMenu.profileImage" alt="profile
|
|
796
|
+
<img :src="props.userMenu.profileImage" alt="profile" @error="userProfileError = true" />
|
|
769
797
|
</template>
|
|
770
798
|
<template v-else>
|
|
771
799
|
<span>{{ getUserInitials(props.userMenu.name) }}</span>
|
|
@@ -788,7 +816,7 @@
|
|
|
788
816
|
]"
|
|
789
817
|
>
|
|
790
818
|
<template v-if="props.userMenu.profileImage && !userProfileError">
|
|
791
|
-
<img :src="props.userMenu.profileImage" alt="profile
|
|
819
|
+
<img :src="props.userMenu.profileImage" alt="profile" @error="userProfileError = true" />
|
|
792
820
|
</template>
|
|
793
821
|
<template v-else>
|
|
794
822
|
<span>{{ getUserInitials(props.userMenu.name) }}</span>
|
|
@@ -847,6 +875,7 @@ import { useSidenav } from './use-sidenav';
|
|
|
847
875
|
|
|
848
876
|
import SprTooltip from '../tooltip/tooltip.vue';
|
|
849
877
|
import SprBadge from '../badge/badge.vue';
|
|
878
|
+
import SprLozenge from '../lozenge/lozenge.vue';
|
|
850
879
|
|
|
851
880
|
const props = defineProps(sidenavPropTypes);
|
|
852
881
|
const emit = defineEmits(sidenavEmitTypes);
|
|
@@ -859,5 +888,6 @@ const {
|
|
|
859
888
|
getUserInitials,
|
|
860
889
|
handleRedirect,
|
|
861
890
|
generateId,
|
|
891
|
+
getLozengeTone,
|
|
862
892
|
} = useSidenav(props, emit);
|
|
863
893
|
</script>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ref,
|
|
1
|
+
import { ref, onMounted } from 'vue';
|
|
2
2
|
|
|
3
3
|
import type { SetupContext } from 'vue';
|
|
4
|
-
import type { SidenavPropTypes, SidenavEmitTypes, ParentLinkItem, NavLinks, NavItem, MenuLinkItem } from './sidenav';
|
|
4
|
+
import type { SidenavPropTypes, SidenavEmitTypes, ParentLinkItem, NavLinks, NavItem, MenuLinkItem, Attributes } from './sidenav';
|
|
5
5
|
|
|
6
6
|
interface ObjectItem {
|
|
7
7
|
redirect?: {
|
|
@@ -17,7 +17,8 @@ interface ObjectItem {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const useSidenav = (props: SidenavPropTypes, emit: SetupContext<SidenavEmitTypes>['emit']) => {
|
|
20
|
-
|
|
20
|
+
// Create a separate reactive reference for the navigation data
|
|
21
|
+
const navLinks = ref<NavLinks>({ top: [], bottom: [] });
|
|
21
22
|
|
|
22
23
|
const isQuckActionMenuVisible = ref(false);
|
|
23
24
|
const isUserMenuVisible = ref(false);
|
|
@@ -148,6 +149,7 @@ export const useSidenav = (props: SidenavPropTypes, emit: SetupContext<SidenavEm
|
|
|
148
149
|
subMenuHeading: string;
|
|
149
150
|
items: ParentLinkItem[];
|
|
150
151
|
}[],
|
|
152
|
+
attributes: item.attributes || [],
|
|
151
153
|
};
|
|
152
154
|
};
|
|
153
155
|
|
|
@@ -180,9 +182,19 @@ export const useSidenav = (props: SidenavPropTypes, emit: SetupContext<SidenavEm
|
|
|
180
182
|
return transformedData;
|
|
181
183
|
};
|
|
182
184
|
|
|
185
|
+
const getLozengeTone = (attr: Attributes) => {
|
|
186
|
+
if (typeof attr === 'object' && attr !== null && 'tone' in attr && typeof attr.tone === 'string' && ['danger', 'information', 'plain', 'pending', 'success', 'neutral', 'caution'].includes(attr.tone)) {
|
|
187
|
+
return attr.tone as 'danger' | 'information' | 'plain' | 'pending' | 'success' | 'neutral' | 'caution';
|
|
188
|
+
}
|
|
189
|
+
return 'success'; // Default tone
|
|
190
|
+
};
|
|
191
|
+
|
|
183
192
|
onMounted(async () => {
|
|
184
193
|
if (props.isNavApi) {
|
|
185
194
|
navLinks.value = await transformedNavItems(props.navLinks);
|
|
195
|
+
} else {
|
|
196
|
+
// Use the original navLinks from props
|
|
197
|
+
navLinks.value = props.navLinks;
|
|
186
198
|
}
|
|
187
199
|
});
|
|
188
200
|
|
|
@@ -195,5 +207,6 @@ export const useSidenav = (props: SidenavPropTypes, emit: SetupContext<SidenavEm
|
|
|
195
207
|
handleRedirect,
|
|
196
208
|
generateId,
|
|
197
209
|
transformedNavItems,
|
|
210
|
+
getLozengeTone
|
|
198
211
|
};
|
|
199
212
|
};
|