Repository: marigold-ui/marigold
Pull request #2575 (2022-10-20 13:00:12)

feat: <XLoader> component for loading states

changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: e38a209308e922d6cf57d229ceb0e4aa0099615d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/master/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/marigold-ui/marigold/new/reservix-loader?filename=.changeset/eighty-fans-approve.md&value=---%0A%22%40marigold%2Fdocs%22%3A%20patch%0A%22%40marigold%2Fcomponents%22%3A%20patch%0A---%0A%0Afeat%3A%20%3CXLoader%3E%20component%20for%20loading%20states%0A)



Patch:
diff --git a/.changeset/eighty-fans-approve.md b/.changeset/eighty-fans-approve.md
new file mode 100644
index 000000000..f0bcfe415
--- /dev/null
+++ b/.changeset/eighty-fans-approve.md
@@ -0,0 +1,6 @@
+---
+"@marigold/docs": patch
+"@marigold/components": patch
+---
+
+feat: <XLoader> component for loading states
diff --git a/docs/src/demos/components/XLoader/XLoader-props.demo.tsx b/docs/src/demos/components/XLoader/XLoader-props.demo.tsx
new file mode 100644
index 000000000..69f559580
--- /dev/null
+++ b/docs/src/demos/components/XLoader/XLoader-props.demo.tsx
@@ -0,0 +1,9 @@
+import { Inline, XLoader } from '@marigold/components';
+
+export const XLoaderWithProps = () => (
+  <Inline space="medium">
+    <XLoader fill="primary" size={100} />
+    <XLoader fill="secondary" size={100} />
+    <XLoader fill="black" size={100} />
+  </Inline>
+);
diff --git a/docs/src/demos/components/XLoader/XLoader.demo.tsx b/docs/src/demos/components/XLoader/XLoader.demo.tsx
new file mode 100644
index 000000000..6beed4406
--- /dev/null
+++ b/docs/src/demos/components/XLoader/XLoader.demo.tsx
@@ -0,0 +1,3 @@
+import { XLoader } from '@marigold/components';
+
+export const BasicXLoader = () => <XLoader />;
diff --git a/docs/src/demos/components/XLoader/index.ts b/docs/src/demos/components/XLoader/index.ts
new file mode 100644
index 000000000..03335cd72
--- /dev/null
+++ b/docs/src/demos/components/XLoader/index.ts
@@ -0,0 +1,2 @@
+export * from './XLoader-props.demo';
+export * from './XLoader.demo';
diff --git a/docs/src/demos/components/index.ts b/docs/src/demos/components/index.ts
index fe4bf1cde..19c667edc 100644
--- a/docs/src/demos/components/index.ts
+++ b/docs/src/demos/components/index.ts
@@ -45,3 +45,4 @@ export * from './TextArea';
 export * from './TextField';
 export * from './Tooltip';
 export * from './VisuallyHidden';
+export * from './XLoader';
diff --git a/docs/src/pages/components/xloader.mdx b/docs/src/pages/components/xloader.mdx
new file mode 100644
index 000000000..c960f79eb
--- /dev/null
+++ b/docs/src/pages/components/xloader.mdx
@@ -0,0 +1,66 @@
+---
+title: XLoader
+group: Content
+caption: Should be used for loading state.
+github: https://github.com/marigold-ui/marigold/blob/main/packages/components/src/XLoader/XLoader.tsx
+edit: https://github.com/marigold-ui/marigold/blob/main/docs/src/pages/components/xloader.mdx
+switchTheme: true
+---
+
+The `<XLoader>` component, is a simple `<SVG>` that should be used for loading states.
+It should be displayed when the user is waiting for an upcoming event.
+
+You can use all regular attributes of the `<SVG>`.
+
+<Preview>
+  <BasicXLoader />
+</Preview>
+
+## Usage
+
+### Import
+
+To import the component you just have to use this code below.
+
+```tsx onlyCode
+import { XLoader } from '@marigold/components';
+```
+
+### Appearance
+
+<AppearanceTable component={title} />
+
+### Props
+
+<PropsTable
+  props={[
+    {
+      property: 'fill',
+      type: 'string',
+      description: 'Set the color of the loader.',
+      default: 'none',
+    },
+    {
+      property: 'size',
+      type: 'string | number',
+      description: 'Set the width and height of the loader.',
+      default: '150',
+    },
+    {
+      property: '...',
+      type: '',
+      description: 'Yes! You can use all regular properties of svg!',
+      default: '',
+    },
+  ]}
+/>
+
+## Examples
+
+### Use case name
+
+In this Example you can see how to use the `fill` and `size` property of the `<XLoader>`.
+
+```tsx preview file=components/XLoader/XLoader-props.demo.tsx
+
+```
diff --git a/packages/components/src/XLoader/XLoader.stories.tsx b/packages/components/src/XLoader/XLoader.stories.tsx
new file mode 100644
index 000000000..e4e8369e1
--- /dev/null
+++ b/packages/components/src/XLoader/XLoader.stories.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import type { Meta, ComponentStory } from '@storybook/react';
+import { XLoader } from './XLoader';
+
+export default {
+  title: 'Components/XLoader',
+  argTypes: {
+    size: {
+      control: {
+        type: 'text',
+      },
+      table: {
+        defaultValue: {
+          summary: 150,
+        },
+      },
+    },
+    fill: {
+      control: {
+        type: 'text',
+      },
+      table: {
+        defaultValue: {},
+      },
+    },
+  },
+} as Meta;
+
+export const Basic: ComponentStory<typeof XLoader> = args => (
+  <XLoader {...args} />
+);
diff --git a/packages/components/src/XLoader/XLoader.tsx b/packages/components/src/XLoader/XLoader.tsx
new file mode 100644
index 000000000..e6ce4cedd
--- /dev/null
+++ b/packages/components/src/XLoader/XLoader.tsx
@@ -0,0 +1,158 @@
+import { SVG, SVGProps } from '@marigold/system';
+import React, { forwardRef } from 'react';
+
+export const XLoader = forwardRef<SVGElement, SVGProps>((props, ref) => (
+  <SVG
+    id="XLoader"
+    xmlns="http://www.w3.org/2000/svg"
+    size={150}
+    viewBox="0 0 150 150"
+    {...props}
+    {...ref}
+  >
+    <path id="XMLID_1_" d="M35.3 27h26.5l54 74.1H88.7z" />
+    <path
+      id="XMLID_5_"
+      d="M124.3 12.8h-.7c-2.7 0-4.9-2.2-4.9-4.9v-.7c0-2.7 2.2-4.9 4.9-4.9h.7c2.7 0 4.9 2.2 4.9 4.9v.7c0 2.7-2.2 4.9-4.9 4.9z"
+    >
+      <animate
+        attributeName="opacity"
+        attributeType="XML"
+        values="1; .01; 1; 1; 1;"
+        begin="1.1s"
+        dur="2.5s"
+        repeatCount="indefinite"
+      />
+    </path>
+    <path
+      id="XMLID_18_"
+      d="M115.9 24.4h-.7c-2.7 0-4.9-2.2-4.9-4.9v-.7c0-2.7 2.2-4.9 4.9-4.9h.7c2.7 0 4.9 2.2 4.9 4.9v.7c0 2.7-2.2 4.9-4.9 4.9z"
+    >
+      <animate
+        attributeName="opacity"
+        attributeType="XML"
+        values="1; .01; 1; 1; 1;"
+        begin="0.9s"
+        dur="2.5s"
+        repeatCount="indefinite"
+      />
+    </path>
+    <path
+      id="XMLID_19_"
+      d="M107.5 35.9h-.7c-2.7 0-4.9-2.2-4.9-4.9v-.7c0-2.7 2.2-4.9 4.9-4.9h.7c2.7 0 4.9 2.2 4.9 4.9v.7c0 2.7-2.2 4.9-4.9 4.9z"
+    >
+      <animate
+        attributeName="opacity"
+        attributeType="XML"
+        values="1; .01; 1; 1; 1;"
+        begin="0.8s"
+        dur="2.5s"
+        repeatCount="indefinite"
+      />
+    </path>
+    <path
+      id="XMLID_20_"
+      d="M99.1 47.5h-.7c-2.7 0-4.9-2.2-4.9-4.9v-.7c0-2.7 2.2-4.9 4.9-4.9h.7c2.7 0 4.9 2.2 4.9 4.9v.7c0 2.7-2.2 4.9-4.9 4.9z"
+    >
+      <animate
+        attributeName="opacity"
+        attributeType="XML"
+        values="1; .01; 1; 1;"
+        begin="0.7s"
+        dur="2.5s"
+        repeatCount="indefinite"
+      />
+    </path>
+    <path
+      id="XMLID_21_"
+      d="M90.7 59H90c-2.7 0-4.9-2.2-4.9-4.9v-.7c0-2.7 2.2-4.9 4.9-4.9h.7c2.7 0 4.9 2.2 4.9 4.9v.7c0 2.8-2.2 4.9-4.9 4.9z"
+    >
+      <animate
+        attributeName="opacity"
+        attributeType="XML"
+        values="1; .01; 1; 1; 1;"
+        begin="0.6s"
+        dur="2.5s"
+        repeatCount="indefinite"
+      />
+    </path>
+    <path
+      id="XMLID_22_"
+      d="M68 89.8h-.7c-2.7 0-4.9-2.2-4.9-4.9v-.7c0-2.7 2.2-4.9 4.9-4.9h.7c2.7 0 4.9 2.2 4.9 4.9v.8c0 2.6-2.2 4.8-4.9 4.8z"
+    >
+      <animate
+        attributeName="opacity"
+        attributeType="XML"
+        values="1; .01; 1; 1; 1;"
+        begin="0.5s"
+        dur="2.5s"
+        repeatCount="indefinite"
+      />
+    </path>
+    <path
+      id="XMLID_23_"
+      d="M59.6 101.4h-.7c-2.7 0-4.9-2.2-4.9-4.9v-.7c0-2.7 2.2-4.9 4.9-4.9h.7c2.7 0 4.9 2.2 4.9 4.9v.7c0 2.7-2.2 4.9-4.9 4.9z"
+    >
+      <animate
+        attributeName="opacity"
+        attributeType="XML"
+        values="1; .01; 1; 1; 1;"
+        begin="0.4s"
+        dur="2.5s"
+        repeatCount="indefinite"
+      />
+    </path>
+    <path
+      id="XMLID_24_"
+      d="M51.2 112.9h-.7c-2.7 0-4.9-2.2-4.9-4.9v-.7c0-2.7 2.2-4.9 4.9-4.9h.7c2.7 0 4.9 2.2 4.9 4.9v.7c-.1 2.8-2.2 4.9-4.9 4.9z"
+    >
+      <animate
+        attributeName="opacity"
+        attributeType="XML"
+        values="1; .01; 1; 1; 1;"
+        begin="0.3s"
+        dur="2.5s"
+        repeatCount="indefinite"
+      />
+    </path>
+    <path
+      id="XMLID_25_"
+      d="M42.8 124.5h-.7c-2.7 0-4.9-2.2-4.9-4.9v-.7c0-2.7 2.2-4.9 4.9-4.9h.7c2.7 0 4.9 2.2 4.9 4.9v.7c-.1 2.7-2.2 4.9-4.9 4.9z"
+    >
+      <animate
+        attributeName="opacity"
+        attributeType="XML"
+        values="1; .01; 1; 1; 1;"
+        begin="0.2s"
+        dur="2.5s"
+        repeatCount="indefinite"
+      />
+    </path>
+    <path
+      id="XMLID_26_"
+      d="M34.4 136h-.7c-2.7 0-4.9-2.2-4.9-4.9v-.7c0-2.7 2.2-4.9 4.9-4.9h.7c2.7 0 4.9 2.2 4.9 4.9v.7c-.1 2.7-2.2 4.9-4.9 4.9z"
+    >
+      <animate
+        attributeName="opacity"
+        attributeType="XML"
+        values="1; .01; 1; 1; 1;"
+        begin="0.1s"
+        dur="2.5s"
+        repeatCount="indefinite"
+      />
+    </path>
+    <path
+      id="XMLID_27_"
+      d="M26 147.6h-.7c-2.7 0-4.9-2.2-4.9-4.9v-.7c0-2.7 2.2-4.9 4.9-4.9h.7c2.7 0 4.9 2.2 4.9 4.9v.7c-.1 2.8-2.2 4.9-4.9 4.9z"
+    >
+      <animate
+        attributeName="opacity"
+        attributeType="XML"
+        values="1; .01; 1; 1; 1;"
+        begin="0.1s"
+        dur="2.5s"
+        repeatCount="indefinite"
+      />
+    </path>
+  </SVG>
+));
diff --git a/packages/components/src/XLoader/index.ts b/packages/components/src/XLoader/index.ts
new file mode 100644
index 000000000..8a995523a
--- /dev/null
+++ b/packages/components/src/XLoader/index.ts
@@ -0,0 +1,1 @@
+export * from './XLoader';
diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts
index 89029df93..932ae459d 100644
--- a/packages/components/src/index.ts
+++ b/packages/components/src/index.ts
@@ -42,3 +42,4 @@ export * from './TextField';
 export * from './Tiles';
 export * from './Tooltip';
 export * from './VisuallyHidden';
+export * from './XLoader';


Test patch:
diff --git a/packages/components/src/XLoader/XLoader.test.tsx b/packages/components/src/XLoader/XLoader.test.tsx
new file mode 100644
index 000000000..0df8e4dd6
--- /dev/null
+++ b/packages/components/src/XLoader/XLoader.test.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import { XLoader } from './XLoader';
+import { ThemeProvider } from '@marigold/system';
+
+const theme = {
+  sizes: {
+    none: 0,
+    small: 100,
+  },
+  colors: {
+    red: '#ffa8a8',
+  },
+};
+
+test('renders loader', () => {
+  render(
+    <ThemeProvider theme={theme}>
+      <XLoader data-testid="loader" />
+    </ThemeProvider>
+  );
+  const loader = screen.getByTestId('loader');
+  expect(loader instanceof SVGElement).toBeTruthy();
+});
+
+test('renders loader with differnet size', () => {
+  render(
+    <ThemeProvider theme={theme}>
+      <XLoader data-testid="loader" size="small" />
+    </ThemeProvider>
+  );
+  const loader = screen.getByTestId('loader');
+  expect(loader).toHaveStyle(`width: ${theme.sizes['small']}px`);
+  expect(loader).toHaveStyle(`height: ${theme.sizes['small']}px`);
+});
+
+test('renders loader with differnet color', () => {
+  render(
+    <ThemeProvider theme={theme}>
+      <XLoader data-testid="loader" fill="red" />
+    </ThemeProvider>
+  );
+  const loader = screen.getByTestId('loader');
+  expect(loader).toHaveStyle(`fill: ${theme.colors.red}`);
+});