Skip to content

Commit 05d0afa

Browse files
brojorjd-solanki
andauthored
fix(typography): preserve typographyHeader reactivity (#49)
Co-authored-by: JD Solanki <jdsolanki0001@gmail.com>
1 parent fdce3b0 commit 05d0afa

File tree

4 files changed

+37
-73
lines changed

4 files changed

+37
-73
lines changed

packages/anu-vue/src/components/list/AList.tsx

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ import { useLayer, useProps as useLayerProps } from '@/composables/useLayer'
66

77
import { AAvatar, isAvatarUsed } from '@/components/avatar'
88
import type { AvatarOnlyProps } from '@/components/avatar/props'
9+
import type { ConfigurableValue } from '@/composables/useConfigurable'
10+
import { useConfigurable } from '@/composables/useConfigurable'
911

1012
// TODO: Reuse the existing props and its types. Maybe if we create AListItem component then we can reuse prop types.
1113
interface ListItem extends AvatarOnlyProps {
12-
title: string | string[]
13-
subtitle?: string | string[]
14-
text: string | string[]
14+
title: ConfigurableValue
15+
subtitle?: ConfigurableValue
16+
text: ConfigurableValue
1517
src?: string
1618
value?: any
1719
disable?: boolean
@@ -107,19 +109,11 @@ export const AList = defineComponent({
107109
// 👉 List items
108110
const listItems = computed(() => props.items.map((listItem, itemIndex) => {
109111
// ℹ️ Reduce the size of title to 1rem. We did the same in ACard as well.
110-
let titleProp: string[] | undefined
111-
if (listItem.title) {
112-
// if title property is string
113-
if (typeof listItem.title === 'string') {
114-
titleProp = [listItem.title, 'text-base']
115-
}
116-
117-
// title property is array
118-
else {
119-
const [textContent, textClasses] = listItem.title
120-
titleProp = [textContent, `${textClasses} uno-layer-base-text-sm`]
121-
}
122-
}
112+
const _titleProp = useConfigurable(listItem.title)
113+
if (Array.isArray(_titleProp.value.classes))
114+
_titleProp.value.classes = [..._titleProp.value.classes, 'uno-layer-base-text-base']
115+
else
116+
_titleProp.value.classes += ' uno-layer-base-text-base'
123117

124118
const isActive = computed(() => options.value[itemIndex].isSelected)
125119

@@ -149,7 +143,7 @@ export const AList = defineComponent({
149143
? avatarRenderer(listItem.content, listItem.src, listItem.alt, listItem.icon, listItem.$avatar)
150144
: null
151145
}
152-
<ATypography class="flex-grow" title={titleProp} subtitle={listItem.subtitle} text={listItem.text}></ATypography>
146+
<ATypography class="flex-grow" title={Object.values(_titleProp.value) as ConfigurableValue} subtitle={listItem.subtitle} text={listItem.text}></ATypography>
153147
{
154148
slots.append
155149
? slots.append({ listItem, itemIndex })

packages/anu-vue/src/components/typography/ATypography.tsx

Lines changed: 13 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { computed, defineComponent } from 'vue'
1+
import { defineComponent, toRef } from 'vue'
2+
import { useConfigurable } from '@/composables/useConfigurable'
23
import { useTypographyProps } from '@/composables/useTypography'
34

45
export const ATypography = defineComponent({
@@ -7,71 +8,37 @@ export const ATypography = defineComponent({
78
...useTypographyProps(),
89
},
910
setup(props, { slots }) {
10-
const title = computed(() => {
11-
const [titleContent, titleClasses] = props.title === undefined
12-
? []
13-
: typeof props.title === 'string'
14-
? [props.title]
15-
: props.title
11+
const title = useConfigurable(toRef(props, 'title'))
12+
const subtitle = useConfigurable(toRef(props, 'subtitle'))
13+
const text = useConfigurable(toRef(props, 'text'))
1614

17-
return {
18-
titleContent,
19-
titleClasses,
20-
}
21-
})
22-
23-
// const [subtitleContent, subtitleClasses] = computed(() => props.subtitle === undefined
24-
const subtitle = computed(() => {
25-
const [subtitleContent, subtitleClasses] = props.subtitle === undefined
26-
? []
27-
: typeof props.subtitle === 'string'
28-
? [props.subtitle]
29-
: props.subtitle
30-
31-
return {
32-
subtitleContent,
33-
subtitleClasses,
34-
}
35-
})
36-
37-
const text = computed(() => {
38-
const [textContent, textClasses] = props.text === undefined
39-
? []
40-
: typeof props.text === 'string'
41-
? [props.text]
42-
: props.text
43-
44-
return {
45-
textContent,
46-
textClasses,
47-
}
48-
})
49-
50-
const typographyHeader = <div class="flex justify-between">
15+
// TODO: Remove class block and use commented tag defaults instead of span once VitePress allow style isolation
16+
return () => {
17+
const typographyHeader = <div class="flex justify-between">
5118
<div class="flex-grow">
5219
{
5320
slots.title || props.title
54-
? <props.titleTag class={['font-medium block em:uno-layer-base-text-lg uno-layer-base-text-[hsla(var(--a-typography-title-color),var(--a-typography-title-opacity))]', title.value.titleClasses]}>{slots.title ? slots.title() : title.value.titleContent}</props.titleTag>
21+
? <props.titleTag {...title.value.attrs} class={['font-medium block em:uno-layer-base-text-lg uno-layer-base-text-[hsla(var(--a-typography-title-color),var(--a-typography-title-opacity))]', title.value.classes]}>{slots.title ? slots.title() : title.value.content}</props.titleTag>
5522
: null
5623
}
5724
{
5825
slots.subtitle || props.subtitle
59-
? <props.subtitleTag class={['block em:uno-layer-base-text-sm uno-layer-base-text-[hsla(var(--a-typography-subtitle-color),var(--a-typography-subtitle-opacity))]', subtitle.value.subtitleClasses]}>{slots.subtitle ? slots.subtitle() : subtitle.value.subtitleContent}</props.subtitleTag>
26+
? <props.subtitleTag {...subtitle.value.attrs} class={['block em:uno-layer-base-text-sm uno-layer-base-text-[hsla(var(--a-typography-subtitle-color),var(--a-typography-subtitle-opacity))]', subtitle.value.classes]}>{slots.subtitle ? slots.subtitle() : subtitle.value.content}</props.subtitleTag>
6027
: null
6128
}
6229
</div>
6330
{slots.headerRight?.()}
6431
</div>
6532

66-
// TODO: Remove class block and use commented tag defaults instead of span once VitePress allow style isolation
67-
return () => <div class="uno-layer-base-text-base gap-4 flex flex-col">
33+
return <div class="uno-layer-base-text-base gap-4 flex flex-col">
6834
{slots.title || props.title || slots.subtitle || props.subtitle || slots.headerRight ? typographyHeader : null}
6935
{
7036
slots.default || props.text
71-
? <props.textTag class={['em:uno-layer-base-text-base uno-layer-base-text-[hsla(var(--a-typography-text-color),var(--a-typography-text-opacity))]', text.value.textClasses]}>{slots.default ? slots.default() : text.value.textContent}</props.textTag>
37+
? <props.textTag {...text.value.attrs} class={['em:uno-layer-base-text-base uno-layer-base-text-[hsla(var(--a-typography-text-color),var(--a-typography-text-opacity))]', text.value.classes]}>{slots.default ? slots.default() : text.value.content}</props.textTag>
7238
: null
7339
}
7440
</div>
41+
}
7542
},
7643
})
7744

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import type { MaybeRef } from '@vueuse/core'
22
import { resolveUnref } from '@vueuse/core'
3+
import { computed } from 'vue'
34

45
// ℹ️ We might need generic here in future
56

67
export type ContentType = string | number | undefined
7-
export type ClassStyleType = string | { string: boolean } | undefined
8-
export type ClassStyleAttr = ClassStyleType | ClassStyleType[]
9-
export type AttrsType = { string: any } | undefined
10-
export type ConfigurableValue = undefined | ContentType | [ContentType, ClassStyleAttr] | [ContentType, ClassStyleAttr, AttrsType]
8+
export type Class = string | Record<string, boolean> | undefined
9+
export type ClassAttr = Class | Class[]
10+
export type AttrsType = Record<string, any> | undefined
11+
export type ConfigurableValue = undefined | ContentType | [ContentType, ClassAttr] | [ContentType, ClassAttr, AttrsType]
1112

12-
export const useConfigurable = (value: MaybeRef<ConfigurableValue>): { content: ContentType; classes: ClassStyleAttr; attrs: AttrsType } => {
13+
export const useConfigurable = (value: MaybeRef<ConfigurableValue>) => computed(() => {
1314
const _value = resolveUnref(value)
1415

1516
const [content, classes, attrs] = _value === undefined
@@ -19,4 +20,5 @@ export const useConfigurable = (value: MaybeRef<ConfigurableValue>): { content:
1920
: _value
2021

2122
return { content, classes, attrs }
22-
}
23+
},
24+
)

packages/anu-vue/src/composables/useTypography.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
import type { ComponentObjectPropsOptions, PropType, Slots, ToRefs } from 'vue'
2+
import type { ConfigurableValue } from '@/composables/useConfigurable'
23

34
export const useTypographyProps = (propOverrides?: Partial<ComponentObjectPropsOptions>) => {
45
const props = {
56

67
/**
78
* Typography title
89
*/
9-
title: [String, Array] as PropType<string | string[]>,
10+
title: [String, Array] as PropType<ConfigurableValue>,
1011

1112
/**
1213
* Typography subtitle
1314
*/
14-
subtitle: [String, Array] as PropType<string | string[]>,
15+
subtitle: [String, Array] as PropType<ConfigurableValue>,
1516

1617
/**
1718
* Typography text content
1819
*/
19-
text: [String, Array] as PropType<string | string[]>,
20+
text: [String, Array] as PropType<ConfigurableValue>,
2021

2122
/**
2223
* Tag to use for title of the card
@@ -54,7 +55,7 @@ export const useTypographyProps = (propOverrides?: Partial<ComponentObjectPropsO
5455
return props
5556
}
5657

57-
// Thanks: https://masteringjs.io/tutorials/fundamentals/filter-object
58+
// Thanks: <https://masteringjs.io/tutorials/fundamentals/filter-object>
5859
// TODO(TS): improve typing so that it only returns the typography types. Omit using `Partial`
5960
export const extractTypographyProp = <T>(props: ToRefs<T>): Partial<ToRefs<T>> => {
6061
return Object.fromEntries(

0 commit comments

Comments
 (0)