Skip to content

Commit ba2207e

Browse files
eirikbackerunekinn
authored andcommitted
feat(Skeleton): text wrapping (#2569)
- Fixes [#2518](#2518) - Discussed with design ✅
1 parent e5c80c5 commit ba2207e

File tree

4 files changed

+51
-54
lines changed

4 files changed

+51
-54
lines changed

packages/css/skeleton.css

+5-17
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,18 @@
1919
}
2020

2121
&[data-variant='text'] {
22-
animation: none;
2322
border-radius: var(--ds-border-radius-full);
24-
height: auto;
25-
position: relative; /* So we can position ::after */
26-
27-
/* Render with ::after so we can add some space to top and bottom */
28-
&::after {
29-
content: '';
30-
animation: var(--dsc-skeleton-animation);
31-
border-radius: inherit;
32-
inset: 20% 0;
33-
position: absolute;
34-
}
35-
36-
&:empty::before {
37-
content: '\00a0'; /* Add non breaking space if empty so we follow line height */
38-
}
23+
box-decoration-break: clone;
24+
display: inline;
25+
font-size: 0.8em; /* Scale down font to have larger gap between lines */
26+
letter-spacing: 0.1em; /* But scale up letter-spacing to have circa same line-length */
3927
}
4028

4129
/* When having children, let them define size */
4230
&:not(:empty) {
4331
width: fit-content;
4432
height: fit-content;
45-
color: transparent !important;
33+
color: transparent;
4634

4735
& > * {
4836
visibility: hidden;

packages/react/src/components/loaders/Skeleton/Skeleton.mdx

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Du kan bygge opp komponenter og seksjoner av siden din ved å bruke disse som by
2323
### Skalering av komponenten
2424

2525
Alle varianter av skeleton har `height` og `width` props, som kan brukes til å manuelt sette størrelser. Du kan oppgi størrelsene i `px`, `%`, eller andre enheter som kan settes direkte på style.
26-
For `Skeleton variant="text"` holder det ofte å sette kun `width`, da høyden automatisk skaleres etter tekst-størrelsen til `parent`-elementet.
26+
For `Skeleton variant="text"` holder det ofte å sette kun `width` til det antallet bokstaver du antar vil oppstå, da høyden automatisk skaleres etter tekstinnholdet.
2727

2828
I de fleste tilfeller er manuell setting av høyde og bredde nok, men du kan også sette andre elementer til å rendres som skeleton, gjennom å bruke propen `asChild`. Dette er hovedsaklig tenkt brukt for typografi komponenter.
2929

@@ -36,6 +36,6 @@ Skeleton vil også tilpasse seg etter `children` som du sender inn til komponent
3636
## Text
3737

3838
`Skeleton variant="text"` skalerer automatisk etter den lokale fontstørrelsen, enten den kommer fra `parent`, `children` , eller fordi typografi-komponenter er satt til Skeletons gjennom `asChild`-propen.
39-
For best mulig resultat anbefaler vi at du bruker flere `Skeleton variant="text"` komponenter for å representere en blokk med tekst, én for hver linje.
39+
For best mulig resultat anbefaler vi at du bruker flere `Skeleton variant="text"` med `width` til det antallet bokstaver du antar vil oppstå.
4040

4141
<Canvas of={SkeletonStories.TextExample} />

packages/react/src/components/loaders/Skeleton/Skeleton.stories.tsx

+32-32
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ type Story = StoryObj<typeof Skeleton>;
99
export default {
1010
title: 'Komponenter/Loaders/Skeleton',
1111
component: Skeleton,
12+
parameters: {
13+
a11y: {
14+
config: {
15+
// Disable a11y empty heading rule as we intentionally set aria-hidden="true" on the Skeleton component inside Headings
16+
rules: [{ id: 'empty-heading', selector: ':has(.ds-skeleton)' }],
17+
},
18+
},
19+
},
1220
} as Meta;
1321

1422
export const Preview: Story = {
@@ -29,7 +37,7 @@ export const Components: StoryFn<typeof Text> = () => {
2937
>
3038
<Skeleton variant='circle' width='50px' height='50px' />
3139
<Skeleton variant='rectangle' width='100px' height='50px' />
32-
<Skeleton variant='text' width='50px' height='16px' />
40+
<Skeleton variant='text' width='10' />
3341
</div>
3442
);
3543
};
@@ -51,13 +59,11 @@ export const UsageExample: StoryFn<typeof Skeleton> = () => {
5159
}}
5260
>
5361
<Skeleton variant='circle' width='30px' height='30px' />
54-
<Heading asChild size='md'>
62+
<Heading size='md'>
5563
<Skeleton variant='text'>En medium tittel</Skeleton>
5664
</Heading>
5765
</div>
58-
<Skeleton variant='text' />
59-
<Skeleton variant='text' />
60-
<Skeleton variant='text' width='80%' />
66+
<Skeleton variant='text' width='140' />
6167
</div>
6268
);
6369
};
@@ -79,16 +85,16 @@ export const Children: StoryFn<typeof Skeleton> = () => {
7985
export const As: StoryFn<typeof Skeleton> = () => {
8086
return (
8187
<>
82-
<Heading size='lg' asChild>
88+
<Heading size='lg'>
8389
<Skeleton variant='text'>Her er en heading</Skeleton>
8490
</Heading>
85-
<Paragraph asChild>
91+
<Paragraph>
8692
<Skeleton variant='text'>
8793
Her er en paragraf-komponent som blir rendret som en Skeleton
8894
variant="text".
8995
</Skeleton>
9096
</Paragraph>
91-
<Paragraph asChild>
97+
<Paragraph>
9298
<Skeleton variant='text'>
9399
Se hvordan Skeleton da overskriver stylingen til det enkelte
94100
elementet.
@@ -98,27 +104,21 @@ export const As: StoryFn<typeof Skeleton> = () => {
98104
);
99105
};
100106

101-
export const TextExample: StoryFn<typeof Text> = () => {
102-
return (
103-
<>
104-
<div style={{ display: 'flex', gap: '20px' }}>
105-
<div style={{ width: '140px' }}>
106-
<Heading size='md'>Heading</Heading>
107-
<Paragraph size='sm'>
108-
Her er en paragraf som går over flere linjer
109-
</Paragraph>
110-
</div>
111-
<div style={{ width: '140px' }}>
112-
<Heading size='md' asChild>
113-
<Skeleton variant='text'>Heading</Skeleton>
114-
</Heading>
115-
<Paragraph size='sm'>
116-
<Skeleton variant='text' />
117-
<Skeleton variant='text' />
118-
<Skeleton variant='text' width={80} />
119-
</Paragraph>
120-
</div>
121-
</div>
122-
</>
123-
);
124-
};
107+
export const TextExample: StoryFn<typeof Text> = () => (
108+
<div style={{ display: 'flex', gap: '20px', maxWidth: 300 }}>
109+
<div>
110+
<Heading size='md'>Heading</Heading>
111+
<Paragraph size='sm'>
112+
Her er en paragraf som går over flere linjer
113+
</Paragraph>
114+
</div>
115+
<div>
116+
<Heading size='md'>
117+
<Skeleton variant='text'>Heading</Skeleton>
118+
</Heading>
119+
<Paragraph size='sm'>
120+
<Skeleton variant='text' width={40} />
121+
</Paragraph>
122+
</div>
123+
</div>
124+
);

packages/react/src/components/loaders/Skeleton/Skeleton.tsx

+12-3
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,18 @@ export type SkeletonProps = {
2020
* @default 'rectangle'
2121
* */
2222
variant?: 'rectangle' | 'circle' | 'text';
23-
} & HTMLAttributes<HTMLSpanElement>;
23+
} & HTMLAttributes<HTMLSpanElement> &
24+
(
25+
| { variant: 'text'; characters?: number }
26+
| { variant?: 'rectangle' | 'circle'; characters?: never }
27+
);
2428

2529
export const Skeleton = forwardRef<HTMLSpanElement, SkeletonProps>(
2630
function Skeleton(
2731
{
2832
asChild,
2933
className,
34+
children,
3035
height,
3136
style,
3237
variant = 'rectangle',
@@ -36,6 +41,8 @@ export const Skeleton = forwardRef<HTMLSpanElement, SkeletonProps>(
3641
ref,
3742
) {
3843
const Component = asChild ? Slot : 'span';
44+
const isText = variant === 'text';
45+
const childrenText = isText && '-'.repeat(Number(width) || 1); // s followed by a &shy; makes the most average character length
3946
const animationRef = useSynchronizedAnimation<HTMLSpanElement>(
4047
'ds-skeleton-opacity-fade',
4148
);
@@ -47,9 +54,11 @@ export const Skeleton = forwardRef<HTMLSpanElement, SkeletonProps>(
4754
className={cl('ds-skeleton', className)}
4855
data-variant={variant}
4956
ref={mergedRefs}
50-
style={{ width, height, ...style }}
57+
style={isText ? style : { width, height, ...style }}
5158
{...rest}
52-
/>
59+
>
60+
{children || childrenText}
61+
</Component>
5362
);
5463
},
5564
);

0 commit comments

Comments
 (0)