@bspk/ui 1.1.11 → 1.1.13
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/EmptyState.d.ts +7 -1
- package/dist/EmptyState.js +2 -2
- package/dist/EmptyState.js.map +1 -1
- package/dist/Skeleton.d.ts +47 -8
- package/dist/Skeleton.js +34 -8
- package/dist/Skeleton.js.map +1 -1
- package/dist/skeleton.css +4 -2
- package/meta-types.ts +5 -2
- package/meta.ts +8 -0
- package/package.json +1 -1
- package/src/EmptyState.tsx +9 -3
- package/src/Skeleton.tsx +60 -14
- package/src/skeleton.scss +52 -13
package/dist/EmptyState.d.ts
CHANGED
|
@@ -15,6 +15,12 @@ export type EmptyStateProps = {
|
|
|
15
15
|
* @required
|
|
16
16
|
*/
|
|
17
17
|
body: string;
|
|
18
|
+
/**
|
|
19
|
+
* The text alignment of the body.
|
|
20
|
+
*
|
|
21
|
+
* @default center
|
|
22
|
+
*/
|
|
23
|
+
bodyAlign?: 'center' | 'left' | 'right';
|
|
18
24
|
/**
|
|
19
25
|
* This property may be undefined or an object containing required CallToActionButton properties.
|
|
20
26
|
*
|
|
@@ -27,7 +33,7 @@ export type EmptyStateProps = {
|
|
|
27
33
|
*
|
|
28
34
|
* @name EmptyState
|
|
29
35
|
*/
|
|
30
|
-
declare function EmptyState({ children, header, body, callToAction }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
|
|
36
|
+
declare function EmptyState({ children, header, body, callToAction, bodyAlign }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
|
|
31
37
|
declare namespace EmptyState {
|
|
32
38
|
var bspkName: string;
|
|
33
39
|
}
|
package/dist/EmptyState.js
CHANGED
|
@@ -7,11 +7,11 @@ import { Txt } from './Txt';
|
|
|
7
7
|
*
|
|
8
8
|
* @name EmptyState
|
|
9
9
|
*/
|
|
10
|
-
function EmptyState({ children, header, body, callToAction }) {
|
|
10
|
+
function EmptyState({ children, header, body, callToAction, bodyAlign = 'center' }) {
|
|
11
11
|
return (_jsxs(Layout, { align: "center", column: true, "data-bspk": "empty-state", style: {
|
|
12
12
|
margin: 'var(--spacing-sizing-04)',
|
|
13
13
|
maxWidth: '500px',
|
|
14
|
-
}, children: [children, _jsxs(Layout, { align: "center", column: true, gap: "4", children: [_jsx(Txt, { as: "
|
|
14
|
+
}, children: [children, _jsxs(Layout, { align: "center", column: true, gap: "4", children: [_jsx(Txt, { as: "header", variant: "heading-h5", children: header }), _jsx(Txt, { as: "p", style: { textAlign: bodyAlign }, variant: "body-base", children: body })] }), callToAction && (_jsx(Button, { label: callToAction.label, onClick: callToAction.onClick, size: callToAction.size || 'medium', variant: "primary" }))] }));
|
|
15
15
|
}
|
|
16
16
|
EmptyState.bspkName = 'EmptyState';
|
|
17
17
|
export { EmptyState };
|
package/dist/EmptyState.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmptyState.js","sourceRoot":"","sources":["../src/EmptyState.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"EmptyState.js","sourceRoot":"","sources":["../src/EmptyState.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAiC5B;;;;GAIG;AACH,SAAS,UAAU,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,GAAG,QAAQ,EAAmB;IAC/F,OAAO,CACH,MAAC,MAAM,IACH,KAAK,EAAC,QAAQ,EACd,MAAM,qBACI,aAAa,EACvB,KAAK,EAAE;YACH,MAAM,EAAE,0BAA0B;YAClC,QAAQ,EAAE,OAAO;SACpB,aAEA,QAAQ,EACT,MAAC,MAAM,IAAC,KAAK,EAAC,QAAQ,EAAC,MAAM,QAAC,GAAG,EAAC,GAAG,aACjC,KAAC,GAAG,IAAC,EAAE,EAAC,QAAQ,EAAC,OAAO,EAAC,YAAY,YAChC,MAAM,GACL,EACN,KAAC,GAAG,IAAC,EAAE,EAAC,GAAG,EAAC,KAAK,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,OAAO,EAAC,WAAW,YAC3D,IAAI,GACH,IACD,EACR,YAAY,IAAI,CACb,KAAC,MAAM,IACH,KAAK,EAAE,YAAY,CAAC,KAAK,EACzB,OAAO,EAAE,YAAY,CAAC,OAAO,EAC7B,IAAI,EAAE,YAAY,CAAC,IAAI,IAAI,QAAQ,EACnC,OAAO,EAAC,SAAS,GACnB,CACL,IACI,CACZ,CAAC;AACN,CAAC;AAED,UAAU,CAAC,QAAQ,GAAG,YAAY,CAAC;AAEnC,OAAO,EAAE,UAAU,EAAE,CAAC"}
|
package/dist/Skeleton.d.ts
CHANGED
|
@@ -1,26 +1,65 @@
|
|
|
1
1
|
import './skeleton.scss';
|
|
2
2
|
import { TxtVariant } from './utils/txtVariants';
|
|
3
|
-
export type SkeletonVariant = TxtVariant | 'other';
|
|
4
3
|
export type SkeletonProps = {
|
|
5
4
|
/**
|
|
6
|
-
* The
|
|
5
|
+
* The variant of the skeleton that best hints the content being loaded.
|
|
7
6
|
*
|
|
8
|
-
* @default
|
|
7
|
+
* @default text
|
|
9
8
|
*/
|
|
10
|
-
variant?:
|
|
9
|
+
variant?: 'circular' | 'photo' | 'profile' | 'rectangular' | 'text' | 'thumbnail';
|
|
11
10
|
/**
|
|
12
|
-
* The
|
|
11
|
+
* The variant of the text being loaded. This is only used when variant is 'text'.
|
|
13
12
|
*
|
|
14
|
-
* @default
|
|
13
|
+
* @default body-base
|
|
15
14
|
*/
|
|
16
|
-
|
|
15
|
+
textVariant?: TxtVariant;
|
|
16
|
+
/**
|
|
17
|
+
* The number of lines showing. This is only used when variant is 'text'.
|
|
18
|
+
*
|
|
19
|
+
* @default 3
|
|
20
|
+
*/
|
|
21
|
+
textLines?: number;
|
|
22
|
+
/**
|
|
23
|
+
* The width of the skeleton. This is ignored when variant is 'text', 'profile', or 'thumbnail'.
|
|
24
|
+
*
|
|
25
|
+
* @default 200
|
|
26
|
+
*/
|
|
27
|
+
width?: number | string;
|
|
28
|
+
/**
|
|
29
|
+
* The height of the skeleton. This is ignored when variant is 'text', 'profile', or 'thumbnail'.
|
|
30
|
+
*
|
|
31
|
+
* @default 100
|
|
32
|
+
*/
|
|
33
|
+
height?: number | string;
|
|
17
34
|
};
|
|
18
35
|
/**
|
|
19
36
|
* A visual placeholder for an element while it is in a loading state.
|
|
20
37
|
*
|
|
38
|
+
* The data for your components might not be immediately available. You can improve the perceived responsiveness of the
|
|
39
|
+
* page by using skeletons. It feels like things are happening immediately, then the information is incrementally
|
|
40
|
+
* displayed on the screen.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* function Example() {
|
|
44
|
+
* return item ? (
|
|
45
|
+
* <img
|
|
46
|
+
* style={{
|
|
47
|
+
* width: 210,
|
|
48
|
+
* height: 118,
|
|
49
|
+
* }}
|
|
50
|
+
* alt={item.title}
|
|
51
|
+
* src={item.src}
|
|
52
|
+
* />
|
|
53
|
+
* ) : (
|
|
54
|
+
* <Skeleton variant="photo" width={210} height={118} />
|
|
55
|
+
* );
|
|
56
|
+
* }
|
|
57
|
+
*
|
|
58
|
+
* @exampleDescription This example shows a skeleton loading state for an image but can be used for any element.
|
|
59
|
+
*
|
|
21
60
|
* @name Skeleton
|
|
22
61
|
*/
|
|
23
|
-
declare function Skeleton({
|
|
62
|
+
declare function Skeleton({ width, height, textLines, textVariant: textSize, variant, }: SkeletonProps): import("react/jsx-runtime").JSX.Element;
|
|
24
63
|
declare namespace Skeleton {
|
|
25
64
|
var bspkName: string;
|
|
26
65
|
}
|
package/dist/Skeleton.js
CHANGED
|
@@ -1,20 +1,46 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { styleAdd } from './utils/styleAdd';
|
|
3
3
|
styleAdd(`[data-bspk=skeleton]{/*!
|
|
4
|
-
--margin: is set via inline style
|
|
4
|
+
--text-margin: is set via inline style
|
|
5
|
+
--text-height: is set via inline style
|
|
5
6
|
--height: is set via inline style
|
|
6
|
-
|
|
7
|
+
--width: is set via inline style
|
|
8
|
+
*/display:flex;flex-direction:column;gap:var(--text-margin);animation:skeleton-pulse 1.5s infinite;background:var(--foreground-neutral-skeleton-element)}@keyframes skeleton-pulse{0%{opacity:.8}50%{opacity:.4}100%{opacity:.8}}[data-bspk=skeleton][data-variant=rectangular],[data-bspk=skeleton][data-variant=photo]{min-width:var(--spacing-sizing-08);min-height:var(--spacing-sizing-08);height:var(--height, var(--width));width:var(--width, var(--height));border-radius:var(--radius-small)}[data-bspk=skeleton][data-variant=photo]{border-radius:var(--radius-medium)}[data-bspk=skeleton][data-variant=circular]{border-radius:100%;width:var(--width);aspect-ratio:1/1}[data-bspk=skeleton][data-variant=profile]{border-radius:100%;width:var(--spacing-sizing-10);aspect-ratio:1/1}[data-bspk=skeleton][data-variant=thumbnail]{width:var(--spacing-sizing-12);height:var(--spacing-sizing-12);border-radius:var(--radius-small)}[data-bspk=skeleton][data-variant=text]{background:rgba(0,0,0,0);min-height:unset;max-height:unset;width:100%;height:fit-content}[data-bspk=skeleton][data-variant=text] [data-line]{width:100%;background:var(--foreground-neutral-skeleton-element);border-radius:var(--radius-small);height:var(--text-height)}[data-bspk=skeleton][data-variant=text]:has([data-line]:nth-child(2)) [data-line]:last-child{width:80%}`);;
|
|
7
9
|
/**
|
|
8
10
|
* A visual placeholder for an element while it is in a loading state.
|
|
9
11
|
*
|
|
12
|
+
* The data for your components might not be immediately available. You can improve the perceived responsiveness of the
|
|
13
|
+
* page by using skeletons. It feels like things are happening immediately, then the information is incrementally
|
|
14
|
+
* displayed on the screen.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* function Example() {
|
|
18
|
+
* return item ? (
|
|
19
|
+
* <img
|
|
20
|
+
* style={{
|
|
21
|
+
* width: 210,
|
|
22
|
+
* height: 118,
|
|
23
|
+
* }}
|
|
24
|
+
* alt={item.title}
|
|
25
|
+
* src={item.src}
|
|
26
|
+
* />
|
|
27
|
+
* ) : (
|
|
28
|
+
* <Skeleton variant="photo" width={210} height={118} />
|
|
29
|
+
* );
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
* @exampleDescription This example shows a skeleton loading state for an image but can be used for any element.
|
|
33
|
+
*
|
|
10
34
|
* @name Skeleton
|
|
11
35
|
*/
|
|
12
|
-
function Skeleton({
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
'--
|
|
16
|
-
'--
|
|
17
|
-
|
|
36
|
+
function Skeleton({ width = 100, height = 100, textLines, textVariant: textSize, variant = 'rectangular', }) {
|
|
37
|
+
return (_jsx("div", { "data-bspk": "skeleton", "data-variant": variant, style: {
|
|
38
|
+
'--height': typeof height === 'number' ? `${height}px` : height,
|
|
39
|
+
'--text-height': `var(--${textSize}-size)`,
|
|
40
|
+
'--text-margin': `calc(var(--${textSize}-line-height) - var(--${textSize}-size))`,
|
|
41
|
+
'--width': typeof width === 'number' ? `${width}px` : width,
|
|
42
|
+
}, children: variant === 'text' &&
|
|
43
|
+
[...Array(Math.max(1, textLines || 0))].map((_, index) => _jsx("div", { "data-line": true }, index)) }));
|
|
18
44
|
}
|
|
19
45
|
Skeleton.bspkName = 'Skeleton';
|
|
20
46
|
export { Skeleton };
|
package/dist/Skeleton.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Skeleton.js","sourceRoot":"","sources":["../src/Skeleton.tsx"],"names":[],"mappings":";AAAA,OAAO,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"Skeleton.js","sourceRoot":"","sources":["../src/Skeleton.tsx"],"names":[],"mappings":";AAAA,OAAO,iBAAiB,CAAC;AAsCzB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,SAAS,QAAQ,CAAC,EACd,KAAK,GAAG,GAAG,EACX,MAAM,GAAG,GAAG,EACZ,SAAS,EACT,WAAW,EAAE,QAAQ,EACrB,OAAO,GAAG,aAAa,GACX;IACZ,OAAO,CACH,2BACc,UAAU,kBACN,OAAO,EACrB,KAAK,EACD;YACI,UAAU,EAAE,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM;YAC/D,eAAe,EAAE,SAAS,QAAQ,QAAQ;YAC1C,eAAe,EAAE,cAAc,QAAQ,yBAAyB,QAAQ,SAAS;YACjF,SAAS,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK;SAC7C,YAGrB,OAAO,KAAK,MAAM;YACf,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,mCAAoB,KAAK,CAAI,CAAC,GAC1F,CACT,CAAC;AACN,CAAC;AAED,QAAQ,CAAC,QAAQ,GAAG,UAAU,CAAC;AAE/B,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
package/dist/skeleton.css
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
[data-bspk=skeleton]{/*!
|
|
2
|
-
--margin: is set via inline style
|
|
2
|
+
--text-margin: is set via inline style
|
|
3
|
+
--text-height: is set via inline style
|
|
3
4
|
--height: is set via inline style
|
|
4
|
-
|
|
5
|
+
--width: is set via inline style
|
|
6
|
+
*/display:flex;flex-direction:column;gap:var(--text-margin);animation:skeleton-pulse 1.5s infinite;background:var(--foreground-neutral-skeleton-element)}@keyframes skeleton-pulse{0%{opacity:.8}50%{opacity:.4}100%{opacity:.8}}[data-bspk=skeleton][data-variant=rectangular],[data-bspk=skeleton][data-variant=photo]{min-width:var(--spacing-sizing-08);min-height:var(--spacing-sizing-08);height:var(--height, var(--width));width:var(--width, var(--height));border-radius:var(--radius-small)}[data-bspk=skeleton][data-variant=photo]{border-radius:var(--radius-medium)}[data-bspk=skeleton][data-variant=circular]{border-radius:100%;width:var(--width);aspect-ratio:1/1}[data-bspk=skeleton][data-variant=profile]{border-radius:100%;width:var(--spacing-sizing-10);aspect-ratio:1/1}[data-bspk=skeleton][data-variant=thumbnail]{width:var(--spacing-sizing-12);height:var(--spacing-sizing-12);border-radius:var(--radius-small)}[data-bspk=skeleton][data-variant=text]{background:rgba(0,0,0,0);min-height:unset;max-height:unset;width:100%;height:fit-content}[data-bspk=skeleton][data-variant=text] [data-line]{width:100%;background:var(--foreground-neutral-skeleton-element);border-radius:var(--radius-small);height:var(--text-height)}[data-bspk=skeleton][data-variant=text]:has([data-line]:nth-child(2)) [data-line]:last-child{width:80%}
|
package/meta-types.ts
CHANGED
|
@@ -6,11 +6,11 @@ export type BaseMeta = {
|
|
|
6
6
|
name: string;
|
|
7
7
|
description?: string;
|
|
8
8
|
file?: string;
|
|
9
|
+
example?: string;
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
export type TypeMeta = BaseMeta & {
|
|
12
13
|
id: string;
|
|
13
|
-
example?: string;
|
|
14
14
|
references?: string[];
|
|
15
15
|
properties?: TypeProperty[];
|
|
16
16
|
};
|
|
@@ -35,12 +35,15 @@ export type ComponentMeta = BaseMeta & {
|
|
|
35
35
|
modified: string;
|
|
36
36
|
css: string;
|
|
37
37
|
hasTouchTarget: boolean;
|
|
38
|
+
usage?: {
|
|
39
|
+
code: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
};
|
|
38
42
|
};
|
|
39
43
|
|
|
40
44
|
export type UtilityMeta = BaseMeta & {
|
|
41
45
|
param?: string;
|
|
42
46
|
returns?: string;
|
|
43
|
-
example?: string;
|
|
44
47
|
};
|
|
45
48
|
|
|
46
49
|
/** Copyright 2025 Anywhere Real Estate - CC BY 4.0 */
|
package/meta.ts
CHANGED
|
@@ -169,6 +169,13 @@ function generateComponentMeta({
|
|
|
169
169
|
|
|
170
170
|
const css = fs.existsSync(cssPath) ? fs.readFileSync(cssPath, { encoding: 'utf-8' }) : '';
|
|
171
171
|
|
|
172
|
+
const usage = componentDoc.example
|
|
173
|
+
? {
|
|
174
|
+
code: componentDoc.example,
|
|
175
|
+
description: componentDoc.exampleDescription,
|
|
176
|
+
}
|
|
177
|
+
: undefined;
|
|
178
|
+
|
|
172
179
|
return {
|
|
173
180
|
description: componentDoc.description,
|
|
174
181
|
file: componentFile.split(componentsDir)[1],
|
|
@@ -176,6 +183,7 @@ function generateComponentMeta({
|
|
|
176
183
|
slug,
|
|
177
184
|
dependencies,
|
|
178
185
|
modified: stats.mtime.toISOString(),
|
|
186
|
+
usage,
|
|
179
187
|
css,
|
|
180
188
|
hasTouchTarget: css.includes('data-touch-target'),
|
|
181
189
|
};
|
package/package.json
CHANGED
package/src/EmptyState.tsx
CHANGED
|
@@ -21,6 +21,12 @@ export type EmptyStateProps = {
|
|
|
21
21
|
* @required
|
|
22
22
|
*/
|
|
23
23
|
body: string;
|
|
24
|
+
/**
|
|
25
|
+
* The text alignment of the body.
|
|
26
|
+
*
|
|
27
|
+
* @default center
|
|
28
|
+
*/
|
|
29
|
+
bodyAlign?: 'center' | 'left' | 'right';
|
|
24
30
|
/**
|
|
25
31
|
* This property may be undefined or an object containing required CallToActionButton properties.
|
|
26
32
|
*
|
|
@@ -34,7 +40,7 @@ export type EmptyStateProps = {
|
|
|
34
40
|
*
|
|
35
41
|
* @name EmptyState
|
|
36
42
|
*/
|
|
37
|
-
function EmptyState({ children, header, body, callToAction }: EmptyStateProps) {
|
|
43
|
+
function EmptyState({ children, header, body, callToAction, bodyAlign = 'center' }: EmptyStateProps) {
|
|
38
44
|
return (
|
|
39
45
|
<Layout
|
|
40
46
|
align="center"
|
|
@@ -47,10 +53,10 @@ function EmptyState({ children, header, body, callToAction }: EmptyStateProps) {
|
|
|
47
53
|
>
|
|
48
54
|
{children}
|
|
49
55
|
<Layout align="center" column gap="4">
|
|
50
|
-
<Txt as="
|
|
56
|
+
<Txt as="header" variant="heading-h5">
|
|
51
57
|
{header}
|
|
52
58
|
</Txt>
|
|
53
|
-
<Txt as="
|
|
59
|
+
<Txt as="p" style={{ textAlign: bodyAlign }} variant="body-base">
|
|
54
60
|
{body}
|
|
55
61
|
</Txt>
|
|
56
62
|
</Layout>
|
package/src/Skeleton.tsx
CHANGED
|
@@ -3,42 +3,88 @@ import { CSSProperties } from 'react';
|
|
|
3
3
|
|
|
4
4
|
import { TxtVariant } from './utils/txtVariants';
|
|
5
5
|
|
|
6
|
-
export type SkeletonVariant = TxtVariant | 'other';
|
|
7
|
-
|
|
8
6
|
export type SkeletonProps = {
|
|
9
7
|
/**
|
|
10
|
-
* The
|
|
8
|
+
* The variant of the skeleton that best hints the content being loaded.
|
|
9
|
+
*
|
|
10
|
+
* @default text
|
|
11
|
+
*/
|
|
12
|
+
variant?: 'circular' | 'photo' | 'profile' | 'rectangular' | 'text' | 'thumbnail';
|
|
13
|
+
/**
|
|
14
|
+
* The variant of the text being loaded. This is only used when variant is 'text'.
|
|
15
|
+
*
|
|
16
|
+
* @default body-base
|
|
17
|
+
*/
|
|
18
|
+
textVariant?: TxtVariant;
|
|
19
|
+
/**
|
|
20
|
+
* The number of lines showing. This is only used when variant is 'text'.
|
|
11
21
|
*
|
|
12
|
-
* @default
|
|
22
|
+
* @default 3
|
|
13
23
|
*/
|
|
14
|
-
|
|
24
|
+
textLines?: number;
|
|
15
25
|
/**
|
|
16
|
-
* The
|
|
26
|
+
* The width of the skeleton. This is ignored when variant is 'text', 'profile', or 'thumbnail'.
|
|
17
27
|
*
|
|
18
|
-
* @default
|
|
28
|
+
* @default 200
|
|
19
29
|
*/
|
|
20
|
-
|
|
30
|
+
width?: number | string;
|
|
31
|
+
/**
|
|
32
|
+
* The height of the skeleton. This is ignored when variant is 'text', 'profile', or 'thumbnail'.
|
|
33
|
+
*
|
|
34
|
+
* @default 100
|
|
35
|
+
*/
|
|
36
|
+
height?: number | string;
|
|
21
37
|
};
|
|
22
38
|
|
|
23
39
|
/**
|
|
24
40
|
* A visual placeholder for an element while it is in a loading state.
|
|
25
41
|
*
|
|
42
|
+
* The data for your components might not be immediately available. You can improve the perceived responsiveness of the
|
|
43
|
+
* page by using skeletons. It feels like things are happening immediately, then the information is incrementally
|
|
44
|
+
* displayed on the screen.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* function Example() {
|
|
48
|
+
* return item ? (
|
|
49
|
+
* <img
|
|
50
|
+
* style={{
|
|
51
|
+
* width: 210,
|
|
52
|
+
* height: 118,
|
|
53
|
+
* }}
|
|
54
|
+
* alt={item.title}
|
|
55
|
+
* src={item.src}
|
|
56
|
+
* />
|
|
57
|
+
* ) : (
|
|
58
|
+
* <Skeleton variant="photo" width={210} height={118} />
|
|
59
|
+
* );
|
|
60
|
+
* }
|
|
61
|
+
*
|
|
62
|
+
* @exampleDescription This example shows a skeleton loading state for an image but can be used for any element.
|
|
63
|
+
*
|
|
26
64
|
* @name Skeleton
|
|
27
65
|
*/
|
|
28
|
-
function Skeleton({
|
|
29
|
-
|
|
30
|
-
|
|
66
|
+
function Skeleton({
|
|
67
|
+
width = 100,
|
|
68
|
+
height = 100,
|
|
69
|
+
textLines,
|
|
70
|
+
textVariant: textSize,
|
|
71
|
+
variant = 'rectangular',
|
|
72
|
+
}: SkeletonProps) {
|
|
31
73
|
return (
|
|
32
74
|
<div
|
|
33
75
|
data-bspk="skeleton"
|
|
76
|
+
data-variant={variant}
|
|
34
77
|
style={
|
|
35
78
|
{
|
|
36
|
-
'--
|
|
37
|
-
'--height': `var(--${
|
|
79
|
+
'--height': typeof height === 'number' ? `${height}px` : height,
|
|
80
|
+
'--text-height': `var(--${textSize}-size)`,
|
|
81
|
+
'--text-margin': `calc(var(--${textSize}-line-height) - var(--${textSize}-size))`,
|
|
82
|
+
'--width': typeof width === 'number' ? `${width}px` : width,
|
|
38
83
|
} as CSSProperties
|
|
39
84
|
}
|
|
40
85
|
>
|
|
41
|
-
{variant
|
|
86
|
+
{variant === 'text' &&
|
|
87
|
+
[...Array(Math.max(1, textLines || 0))].map((_, index) => <div data-line key={index} />)}
|
|
42
88
|
</div>
|
|
43
89
|
);
|
|
44
90
|
}
|
package/src/skeleton.scss
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
[data-bspk='skeleton'] {
|
|
2
2
|
/*!
|
|
3
|
-
--margin: is set via inline style
|
|
3
|
+
--text-margin: is set via inline style
|
|
4
|
+
--text-height: is set via inline style
|
|
4
5
|
--height: is set via inline style
|
|
6
|
+
--width: is set via inline style
|
|
5
7
|
*/
|
|
6
8
|
|
|
7
|
-
width: 100%;
|
|
8
9
|
display: flex;
|
|
9
10
|
flex-direction: column;
|
|
10
|
-
gap: var(--margin);
|
|
11
|
+
gap: var(--text-margin);
|
|
11
12
|
animation: skeleton-pulse 1.5s infinite;
|
|
13
|
+
background: var(--foreground-neutral-skeleton-element);
|
|
12
14
|
|
|
13
15
|
@keyframes skeleton-pulse {
|
|
14
16
|
0% {
|
|
@@ -24,20 +26,57 @@
|
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
&[data-variant='rectangular'],
|
|
30
|
+
&[data-variant='photo'] {
|
|
31
|
+
min-width: var(--spacing-sizing-08);
|
|
32
|
+
min-height: var(--spacing-sizing-08);
|
|
33
|
+
height: var(--height, var(--width));
|
|
34
|
+
width: var(--width, var(--height));
|
|
33
35
|
border-radius: var(--radius-small);
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
[data-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
&[data-variant='photo'] {
|
|
39
|
+
border-radius: var(--radius-medium);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&[data-variant='circular'] {
|
|
43
|
+
border-radius: 100%;
|
|
44
|
+
width: var(--width);
|
|
45
|
+
aspect-ratio: 1/1;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&[data-variant='profile'] {
|
|
49
|
+
border-radius: 100%;
|
|
50
|
+
width: var(--spacing-sizing-10);
|
|
51
|
+
aspect-ratio: 1/1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&[data-variant='thumbnail'] {
|
|
55
|
+
width: var(--spacing-sizing-12);
|
|
56
|
+
height: var(--spacing-sizing-12);
|
|
39
57
|
border-radius: var(--radius-small);
|
|
40
|
-
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
&[data-variant='text'] {
|
|
61
|
+
background: transparent;
|
|
62
|
+
min-height: unset;
|
|
63
|
+
max-height: unset;
|
|
64
|
+
width: 100%;
|
|
65
|
+
height: fit-content;
|
|
66
|
+
|
|
67
|
+
[data-line] {
|
|
68
|
+
width: 100%;
|
|
69
|
+
background: var(--foreground-neutral-skeleton-element);
|
|
70
|
+
border-radius: var(--radius-small);
|
|
71
|
+
height: var(--text-height);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// if there are 2 lines or more, make the last line 80% width
|
|
75
|
+
&:has([data-line]:nth-child(2)) {
|
|
76
|
+
[data-line]:last-child {
|
|
77
|
+
width: 80%;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
41
80
|
}
|
|
42
81
|
}
|
|
43
82
|
|