From 5252d7c35cc04c23795fbd167efe2acbc150db28 Mon Sep 17 00:00:00 2001 From: eirikbacker Date: Tue, 17 Sep 2024 10:38:41 +0200 Subject: [PATCH] fix(Skeleton): css alignment --- packages/css/skeleton.css | 73 +++++++++---------- .../loaders/Skeleton/Circle/Circle.test.tsx | 15 ---- .../loaders/Skeleton/Circle/Circle.tsx | 44 ----------- .../Skeleton/Rectangle/Rectangle.test.tsx | 15 ---- .../loaders/Skeleton/Rectangle/Rectangle.tsx | 44 ----------- .../loaders/Skeleton/Skeletons.test.tsx | 31 ++++++++ .../components/loaders/Skeleton/Skeletons.tsx | 63 ++++++++++++++++ .../loaders/Skeleton/Text/Text.test.tsx | 15 ---- .../components/loaders/Skeleton/Text/Text.tsx | 44 ----------- .../src/components/loaders/Skeleton/index.ts | 30 ++------ 10 files changed, 136 insertions(+), 238 deletions(-) delete mode 100644 packages/react/src/components/loaders/Skeleton/Circle/Circle.test.tsx delete mode 100644 packages/react/src/components/loaders/Skeleton/Circle/Circle.tsx delete mode 100644 packages/react/src/components/loaders/Skeleton/Rectangle/Rectangle.test.tsx delete mode 100644 packages/react/src/components/loaders/Skeleton/Rectangle/Rectangle.tsx create mode 100644 packages/react/src/components/loaders/Skeleton/Skeletons.test.tsx create mode 100644 packages/react/src/components/loaders/Skeleton/Skeletons.tsx delete mode 100644 packages/react/src/components/loaders/Skeleton/Text/Text.test.tsx delete mode 100644 packages/react/src/components/loaders/Skeleton/Text/Text.tsx diff --git a/packages/css/skeleton.css b/packages/css/skeleton.css index 4699cc62f2..006645a4e4 100644 --- a/packages/css/skeleton.css +++ b/packages/css/skeleton.css @@ -2,58 +2,55 @@ --dsc-skeleton-animation-duration: 0.8s; --dsc-skeleton-background: var(--ds-color-neutral-surface-default); + animation: ds-skeleton-opacity-fade var(--dsc-skeleton-animation-duration) linear infinite alternate; + background: var(--dsc-skeleton-background); height: 1.3em; pointer-events: none; user-select: none; - background-color: var(--dsc-skeleton-background); - animation: ds-skeleton-opacity-fade var(--dsc-skeleton-animation-duration) linear infinite alternate; -} -.ds-skeleton--circle { - width: 1.3em; - border-radius: var(--ds-border-radius-full); - aspect-ratio: 1 / 1; -} + &[data-type='circle'] { + width: 1.3em; + border-radius: var(--ds-border-radius-full); + aspect-ratio: 1 / 1; + } -.ds-skeleton--rectangle { - width: 100%; - border-radius: min(1rem, var(--ds-border-radius-lg)); -} + &[data-type='rectangle'] { + width: 100%; + border-radius: min(1rem, var(--ds-border-radius-lg)); + } -.ds-skeleton--text { - width: 100%; - height: auto; - transform-origin: 0 55%; - transform: scale(1, 0.6); - border-radius: var(--ds-border-radius-full); -} + &[data-type='text'] { + width: 100%; + height: auto; + transform-origin: 0 55%; + transform: scale(1, 0.6); + border-radius: var(--ds-border-radius-full); -.ds-skeleton--text:empty::before { - content: '\00a0'; -} + &:empty::before { + content: '\00a0'; + } + } -.ds-skeleton--has-children { - width: fit-content; - height: fit-content; - color: transparent !important; -} + /* When having children, let them define size */ + &:not(:empty) { + width: fit-content; + height: fit-content; + color: transparent !important; -.ds-skeleton--has-children > * { - visibility: hidden; -} + & > * { + visibility: hidden; + } + } -@media (prefers-reduced-motion: reduce) { - .ds-skeleton { - --dsc-skeleton-animation-duration: 1.6s; + @media (prefers-reduced-motion: reduce) { + & { + --dsc-skeleton-animation-duration: 1.6s; + } } } @keyframes ds-skeleton-opacity-fade { - 0% { - opacity: 1; - } - - 100% { + to { opacity: 0.4; } } diff --git a/packages/react/src/components/loaders/Skeleton/Circle/Circle.test.tsx b/packages/react/src/components/loaders/Skeleton/Circle/Circle.test.tsx deleted file mode 100644 index d877c49e1d..0000000000 --- a/packages/react/src/components/loaders/Skeleton/Circle/Circle.test.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { render, screen } from '@testing-library/react'; - -import { Skeleton } from '..'; - -beforeAll(() => { - document.getAnimations = () => []; -}); - -describe('Skeleton.Circle', () => { - it('should render skeleton', () => { - render(); - - expect(screen.getByTestId('skeleton-circle')); - }); -}); diff --git a/packages/react/src/components/loaders/Skeleton/Circle/Circle.tsx b/packages/react/src/components/loaders/Skeleton/Circle/Circle.tsx deleted file mode 100644 index fb417114ad..0000000000 --- a/packages/react/src/components/loaders/Skeleton/Circle/Circle.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import cl from 'clsx/lite'; -import type { HTMLAttributes } from 'react'; - -import { useSynchronizedAnimation } from '../../../../utilities'; - -export type CircleProps = { - /** The width of the component */ - width?: string | number; - /** The height of the component */ - height?: string | number; -} & HTMLAttributes; - -/** Skeleton component used for indicating loading elements of circular shape */ -export const Circle = ({ - width, - height, - className, - children, - style, - ...rest -}: CircleProps) => { - const ref = useSynchronizedAnimation( - 'ds-skeleton-opacity-fade', - ); - - return ( -
- {children} -
- ); -}; - -Circle.displayName = 'SkeletonCircle'; diff --git a/packages/react/src/components/loaders/Skeleton/Rectangle/Rectangle.test.tsx b/packages/react/src/components/loaders/Skeleton/Rectangle/Rectangle.test.tsx deleted file mode 100644 index 4448a56891..0000000000 --- a/packages/react/src/components/loaders/Skeleton/Rectangle/Rectangle.test.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { render, screen } from '@testing-library/react'; - -import { Skeleton } from '..'; - -beforeAll(() => { - document.getAnimations = () => []; -}); - -describe('Skeleton.Rectangle', () => { - it('should render skeleton', () => { - render(); - - expect(screen.getByTestId('skeleton-rectangle')); - }); -}); diff --git a/packages/react/src/components/loaders/Skeleton/Rectangle/Rectangle.tsx b/packages/react/src/components/loaders/Skeleton/Rectangle/Rectangle.tsx deleted file mode 100644 index 9afccb73ca..0000000000 --- a/packages/react/src/components/loaders/Skeleton/Rectangle/Rectangle.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import cl from 'clsx/lite'; -import type { HTMLAttributes } from 'react'; - -import { useSynchronizedAnimation } from '../../../../utilities'; - -export type RectangleProps = { - /** The width of the component */ - width?: string | number; - /** The height of the component */ - height?: string | number; -} & HTMLAttributes; - -/** Skeleton component used for indicating loading elements of rectangle shape */ -export const Rectangle = ({ - width, - height, - className, - children, - style, - ...rest -}: RectangleProps) => { - const ref = useSynchronizedAnimation( - 'ds-skeleton-opacity-fade', - ); - - return ( -
- {children} -
- ); -}; - -Rectangle.displayName = 'SkeletonRectangle'; diff --git a/packages/react/src/components/loaders/Skeleton/Skeletons.test.tsx b/packages/react/src/components/loaders/Skeleton/Skeletons.test.tsx new file mode 100644 index 0000000000..a4e09f821b --- /dev/null +++ b/packages/react/src/components/loaders/Skeleton/Skeletons.test.tsx @@ -0,0 +1,31 @@ +import { render, screen } from '@testing-library/react'; + +import { Skeleton } from '.'; + +beforeAll(() => { + document.getAnimations = () => []; +}); + +describe('Skeleton.Text', () => { + it('should render skeleton', () => { + render(); + + expect(screen.getByTestId('skeleton-text')); + }); +}); + +describe('Skeleton.Circle', () => { + it('should render skeleton', () => { + render(); + + expect(screen.getByTestId('skeleton-circle')); + }); +}); + +describe('Skeleton.Rectangle', () => { + it('should render skeleton', () => { + render(); + + expect(screen.getByTestId('skeleton-rectangle')); + }); +}); diff --git a/packages/react/src/components/loaders/Skeleton/Skeletons.tsx b/packages/react/src/components/loaders/Skeleton/Skeletons.tsx new file mode 100644 index 0000000000..7543257b45 --- /dev/null +++ b/packages/react/src/components/loaders/Skeleton/Skeletons.tsx @@ -0,0 +1,63 @@ +import { useMergeRefs } from '@floating-ui/react'; +import { Slot } from '@radix-ui/react-slot'; +import cl from 'clsx/lite'; +import { type ForwardedRef, type HTMLAttributes, forwardRef } from 'react'; + +import { useSynchronizedAnimation } from '../../../utilities'; + +type SkeletonProps = { + /** + * Change the default rendered element for the one passed as a child, merging their props and behavior. + * @default false + */ + asChild?: boolean; + /** The width of the component */ + width?: string | number; + /** The height of the component */ + height?: string | number; +} & HTMLAttributes; + +const render = ( + type: string, + { asChild, className, width, height, style, ...rest }: SkeletonProps, + ref: ForwardedRef, +) => { + const Component = asChild ? Slot : 'span'; + const animationRef = useSynchronizedAnimation( + 'ds-skeleton-opacity-fade', + ); + const mergedRefs = useMergeRefs([animationRef, ref]); + + return ( +