@swr-data-lab/components 1.5.3 → 1.7.0

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.
Files changed (42) hide show
  1. package/.storybook/main.ts +13 -16
  2. package/.storybook/preview.ts +3 -0
  3. package/.storybook/vitest.setup.ts +9 -0
  4. package/package.json +8 -5
  5. package/src/Autocomplete/Autocomplete.stories.svelte +61 -0
  6. package/src/Autocomplete/Autocomplete.svelte +9 -7
  7. package/src/Button/Button.svelte +14 -10
  8. package/src/Card/Card.stories.svelte +5 -20
  9. package/src/Card/Card.svelte +17 -4
  10. package/src/ChartFooter/ChartFooter.mdx +17 -0
  11. package/src/ChartFooter/ChartFooter.stories.svelte +12 -20
  12. package/src/ChartFooter/ChartFooter.svelte +30 -22
  13. package/src/ChartHeader/ChartHeader.mdx +15 -0
  14. package/src/ChartHeader/ChartHeader.stories.svelte +14 -11
  15. package/src/ChartHeader/ChartHeader.svelte +19 -13
  16. package/src/DesignTokens/DesignTokens.mdx +15 -9
  17. package/src/DesignTokens/DesignTokens.svelte +3 -1
  18. package/src/DesignTokens/index.js +8 -1
  19. package/src/HighlightCard/HighlightCard.stories.svelte +5 -20
  20. package/src/HighlightCard/HighlightCard.svelte +15 -11
  21. package/src/Input/Input.svelte +1 -1
  22. package/src/Intro.mdx +2 -2
  23. package/src/Logotype/Logotype.stories.svelte +16 -0
  24. package/src/Logotype/Logotype.svelte +1 -0
  25. package/src/Middot/Middot.stories.svelte +16 -0
  26. package/src/Select/Select.mdx +25 -0
  27. package/src/Select/Select.stories.svelte +87 -147
  28. package/src/Select/Select.svelte +65 -73
  29. package/src/Select/Select.types.ts +8 -0
  30. package/src/Select/SelectStoriesTemplate.svelte +35 -0
  31. package/src/Switcher/Switcher.mdx +13 -0
  32. package/src/Switcher/Switcher.stories.svelte +50 -0
  33. package/src/Switcher/Switcher.svelte +38 -23
  34. package/src/index.js +1 -0
  35. package/src/styles/base.scss +52 -5
  36. package/vitest.workspace.ts +32 -0
  37. package/src/Autocomplete/Autocomplete.stories.js +0 -61
  38. package/src/Container/Container.svelte +0 -12
  39. package/src/Container/index.js +0 -2
  40. package/src/Switcher/Switcher.stories.js +0 -38
  41. package/src/styles/_typography.scss +0 -49
  42. package/src/styles/_vars.scss +0 -30
@@ -0,0 +1,13 @@
1
+ import { Story, Meta, Primary, Controls, Stories} from '@storybook/blocks';
2
+
3
+ import * as SwictherStories from './Switcher.stories.svelte';
4
+
5
+ <Meta of={SwictherStories}/>
6
+
7
+ # Switcher
8
+
9
+ Radio-like form component to choose exactly one of a given set of options.
10
+
11
+ <Controls/>
12
+
13
+ <Stories/>
@@ -0,0 +1,50 @@
1
+ <script context="module">
2
+ import { defineMeta } from '@storybook/addon-svelte-csf';
3
+ import Switcher from './Switcher.svelte';
4
+ import DesignTokens from '../DesignTokens/DesignTokens.svelte';
5
+ import { userEvent, within, expect } from '@storybook/test';
6
+
7
+ const { Story } = defineMeta({
8
+ title: 'Form/Switcher',
9
+ component: Switcher
10
+ });
11
+ </script>
12
+
13
+ <Story name="Two Options">
14
+ <DesignTokens>
15
+ <Switcher
16
+ options={['Option A', 'Option B']}
17
+ groupName="two-options"
18
+ value="Option A"
19
+ size="default"
20
+ label="Label"
21
+ />
22
+ </DesignTokens>
23
+ </Story>
24
+
25
+ <Story
26
+ name="Four Options"
27
+ play={async ({ canvasElement, step }) => {
28
+ const canvas = within(canvasElement);
29
+ await step('Clicking selects the expected option', async () => {
30
+ const optionA = canvas.getByLabelText('Apples');
31
+ const optionB = canvas.getByLabelText('Bananas');
32
+ await userEvent.click(optionA);
33
+ expect(optionA).toBeChecked();
34
+ expect(optionB).not.toBeChecked();
35
+ await userEvent.click(optionB);
36
+ expect(optionB).toBeChecked();
37
+ expect(optionA).not.toBeChecked();
38
+ });
39
+ }}
40
+ >
41
+ <DesignTokens>
42
+ <Switcher
43
+ options={['Apples', 'Oranges', 'Bananas', 'Peaches']}
44
+ groupName="four-options"
45
+ value="Oranges"
46
+ label="Label"
47
+ size="small"
48
+ />
49
+ </DesignTokens>
50
+ </Story>
@@ -1,14 +1,31 @@
1
1
  <script lang="ts">
2
- export let label: string = '';
3
-
4
- // The options available in the switcher.
5
- export let options: string[] = [];
6
-
7
- // Machine-readable name for the form field. Should be unique to other fields in the form.
8
- export let groupName: string = '';
2
+ interface SwitcherProps {
3
+ /**
4
+ * Human-readable label for the input.
5
+ */
6
+ label: string;
7
+ options: string[];
8
+ /**
9
+ * Machine-readable name for the input. Should be unique across the document.
10
+ */
11
+ groupName: string;
12
+ /**
13
+ * Type size
14
+ */
15
+ size?: 'default' | 'small';
16
+ /**
17
+ * The currently-selected option
18
+ */
19
+ value: string | null;
20
+ }
9
21
 
10
- // The currently selected option
11
- export let value: string = options[0];
22
+ let {
23
+ label,
24
+ options,
25
+ groupName,
26
+ size = 'default',
27
+ value = $bindable(null)
28
+ }: SwitcherProps = $props();
12
29
 
13
30
  function optionToID(o: string) {
14
31
  // TODO: This should use $id() when it comes out, so
@@ -18,12 +35,7 @@
18
35
  }
19
36
  </script>
20
37
 
21
- <!--
22
- Radio-like form component to choose exactly one of a given set of options.
23
- @component
24
- -->
25
-
26
- <fieldset class="container">
38
+ <fieldset class="container" class:small={size === 'small'}>
27
39
  <legend>{label}</legend>
28
40
  <ul>
29
41
  {#each options as o (o)}
@@ -44,21 +56,21 @@ Radio-like form component to choose exactly one of a given set of options.
44
56
  </fieldset>
45
57
 
46
58
  <style lang="scss">
47
- @import '../styles/base.scss';
48
-
49
59
  fieldset {
50
60
  border: 0;
61
+ font-family: var(--swr-sans);
51
62
  }
52
63
 
53
64
  legend {
54
- @extend %form-label;
65
+ font-size: var(--fs-small-2);
66
+ margin-bottom: 0.25em;
55
67
  }
56
68
 
57
69
  ul {
58
70
  width: 100%;
59
71
  display: flex;
60
72
  flex-direction: row;
61
- border-radius: $border-radius-input;
73
+ border-radius: var(--br-small);
62
74
  overflow: hidden;
63
75
  padding: 0;
64
76
  margin: 0;
@@ -80,10 +92,13 @@ Radio-like form component to choose exactly one of a given set of options.
80
92
  position: absolute;
81
93
  left: -999px;
82
94
  }
95
+ .small label {
96
+ font-size: var(--fs-small-1);
97
+ }
83
98
  label {
84
- @extend %copy;
99
+ font-size: var(--fs-base);
100
+ height: 2.5em;
85
101
  line-height: 1;
86
- height: $input-height;
87
102
  cursor: pointer;
88
103
  margin: 0;
89
104
  flex-basis: 0;
@@ -93,7 +108,7 @@ Radio-like form component to choose exactly one of a given set of options.
93
108
  justify-content: center;
94
109
  color: currentColor;
95
110
  position: relative;
96
- transition: $transition-fast;
111
+ transition: var(--fast);
97
112
  text-underline-offset: 0.1em;
98
113
  border-right: 1px solid currentColor;
99
114
  &:hover,
@@ -106,7 +121,7 @@ Radio-like form component to choose exactly one of a given set of options.
106
121
  width: 1em;
107
122
  height: auto;
108
123
  opacity: 0;
109
- transition: $transition-fast;
124
+ transition: var(--fast);
110
125
  display: block;
111
126
  }
112
127
  .is-selected & {
package/src/index.js CHANGED
@@ -6,6 +6,7 @@ export { default as Input } from './Input/Input.svelte';
6
6
  export { default as Button } from './Button/Button.svelte';
7
7
  export { default as Select } from './Select/Select.svelte';
8
8
  export { default as DesignTokens } from './DesignTokens/DesignTokens.svelte';
9
+ export { tokens as tokens } from './DesignTokens/index.js';
9
10
  export { default as ChartHeader } from './ChartHeader/ChartHeader.svelte';
10
11
  export { default as ChartFooter } from './ChartFooter/ChartFooter.svelte';
11
12
  export { default as Middot } from './Middot/Middot.svelte';
@@ -1,8 +1,55 @@
1
- @import 'vars';
2
- @import 'typography';
1
+ $break-phone: 510px;
2
+ $break-tablet: 992px;
3
+ $break-desktop-small: 1200px;
4
+ $break-desktop-large: 1400px;
5
+ $break-desktop-xl: 1400px;
3
6
 
4
- * {
7
+ // TODO drop everything below
8
+
9
+ %caption {
10
+ font-family: var(--swr-sans);
11
+ font-size: 0.9rem;
12
+ line-height: 1;
13
+ letter-spacing: 0.0045em;
14
+ }
15
+
16
+ %caption-bold {
17
+ @extend %caption;
18
+ font-weight: 600;
19
+ }
20
+
21
+ %form-label {
22
+ @extend %caption;
23
+ display: block;
24
+ margin-bottom: 0.5em;
25
+ }
26
+
27
+ %copy {
28
+ font-family: var(--swr-sans);
29
+ font-size: 1.1rem;
30
+ line-height: 1.45;
31
+ letter-spacing: 0.0045em;
32
+ }
33
+
34
+ %copy-bold {
35
+ @extend %copy;
36
+ font-weight: 600;
37
+ }
38
+
39
+ %form-input {
40
+ @extend %copy;
41
+ height: 2.5em;
42
+ width: 100%;
43
+ border: 1px solid currentColor;
44
+ border-radius: var(--br-small);
45
+ background: transparent;
46
+ padding: 0 0.5em;
47
+ padding-top: 0.1em;
48
+ color: currentColor;
5
49
  margin: 0;
6
- padding: 0;
7
- box-sizing: border-box;
50
+ display: block;
51
+ text-size-adjust: none;
52
+ &:focus-visible {
53
+ outline: 4px solid rgba(white, 0.4);
54
+ }
8
55
  }
@@ -0,0 +1,32 @@
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+
4
+ import { defineWorkspace } from 'vitest/config';
5
+
6
+ import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin';
7
+
8
+ const dirname =
9
+ typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
10
+
11
+ // More info at: https://storybook.js.org/docs/writing-tests/test-addon
12
+ export default defineWorkspace([
13
+ 'vite.config.ts',
14
+ {
15
+ extends: 'vite.config.ts',
16
+ plugins: [
17
+ // The plugin will run tests for the stories defined in your Storybook config
18
+ // See options at: https://storybook.js.org/docs/writing-tests/test-addon#storybooktest
19
+ storybookTest({ configDir: path.join(dirname, '.storybook') })
20
+ ],
21
+ test: {
22
+ name: 'storybook',
23
+ browser: {
24
+ enabled: true,
25
+ headless: true,
26
+ name: 'chromium',
27
+ provider: 'playwright'
28
+ },
29
+ setupFiles: ['.storybook/vitest.setup.ts']
30
+ }
31
+ }
32
+ ]);
@@ -1,61 +0,0 @@
1
- import { userEvent, within, expect, fn } from "@storybook/test"
2
- import AutoComplete from "./index.js"
3
-
4
- export default {
5
- title: "Example/Autocomplete",
6
- tags: ["autodocs"],
7
- component: AutoComplete,
8
- }
9
-
10
- const testData = ["Apples", "Oranges", "Pears", "Peaches", "Bananas"].map((el) => {
11
- return {
12
- value: el,
13
- label: el,
14
- details: {},
15
- }
16
- })
17
-
18
- export const Basic = {
19
- args: {
20
- data: testData,
21
- query: "",
22
- placeholder: "Select a fruit",
23
- },
24
- }
25
-
26
- export const Test = {
27
- parameters: {
28
- docs: {
29
- story: {
30
- autoplay: true,
31
- },
32
- },
33
- },
34
- args: {
35
- data: testData,
36
- query: "",
37
- placeholder: "Select a fruit",
38
- },
39
- play: async ({ canvasElement, step }) => {
40
- const canvas = within(canvasElement)
41
- const input = canvas.getByTestId("autocomplete-input")
42
- await step("Select using the mouse", async () => {
43
- await userEvent.click(input)
44
- expect(input).toHaveFocus()
45
- await userEvent.keyboard("ba")
46
- const bananasOption = canvas.getByText("Bananas")
47
- await userEvent.click(bananasOption)
48
- expect(input).toHaveValue("Bananas")
49
- })
50
- await userEvent.clear(input)
51
- await step("Select using the keyboard", async () => {
52
- await userEvent.click(input)
53
- expect(input).toHaveFocus()
54
- await userEvent.keyboard("ap")
55
- await userEvent.keyboard("{ArrowDown}")
56
- await userEvent.keyboard("{Enter}")
57
- expect(input).toHaveValue("Apples")
58
- })
59
- await userEvent.clear(input)
60
- },
61
- }
@@ -1,12 +0,0 @@
1
- <div>
2
- <slot />
3
- </div>
4
-
5
- <style lang="scss">
6
- @import '../styles/base.scss';
7
- :host {
8
- --swr-sans: #{$swr-sans};
9
- --swr-text: #{$swr-text};
10
- --orange: #{$color-activeorange};
11
- }
12
- </style>
@@ -1,2 +0,0 @@
1
- import Container from './Container.svelte';
2
- export default Container;
@@ -1,38 +0,0 @@
1
- import { userEvent, within, expect } from "@storybook/test"
2
- import Switcher from "."
3
-
4
- export default {
5
- title: "Example/Switcher",
6
- tags: ["autodocs"],
7
- component: Switcher,
8
- }
9
-
10
- export const TwoOptions = {
11
- args: {
12
- options: ["Option A", "Option B"],
13
- groupName: "two-options",
14
- value: "Option A",
15
- },
16
- }
17
-
18
- export const FourOptions = {
19
- args: {
20
- options: ["Apples", "Oranges", "Bananas", "Peaches"],
21
- groupName: "four-options",
22
- value: "Oranges",
23
- },
24
- play: async ({ canvasElement, step }) => {
25
- const canvas = within(canvasElement)
26
-
27
- await step("Clicking selects the expected option", async () => {
28
- const optionA = canvas.getByLabelText("Apples")
29
- const optionB = canvas.getByLabelText("Bananas")
30
- await userEvent.click(optionA)
31
- expect(optionA).toBeChecked()
32
- expect(optionB).not.toBeChecked()
33
- await userEvent.click(optionB)
34
- expect(optionB).toBeChecked()
35
- expect(optionA).not.toBeChecked()
36
- })
37
- },
38
- }
@@ -1,49 +0,0 @@
1
- %caption {
2
- font-family: $swr-sans;
3
- font-size: 0.9rem;
4
- line-height: 1;
5
- letter-spacing: 0.0045em;
6
- }
7
-
8
- %caption-bold {
9
- @extend %caption;
10
- font-weight: 600;
11
- }
12
-
13
- %form-label {
14
- @extend %caption;
15
- display: block;
16
- margin-bottom: 0.5em;
17
- }
18
-
19
- %copy {
20
- font-family: $swr-sans;
21
- font-size: 1.1rem;
22
- line-height: 1.45;
23
- letter-spacing: 0.0045em;
24
- }
25
-
26
- %copy-bold {
27
- @extend %copy;
28
- font-weight: 600;
29
- }
30
-
31
- %form-input {
32
- @extend %copy;
33
- height: $input-height;
34
- width: 100%;
35
- border: 1px solid currentColor;
36
- border-radius: $border-radius-input;
37
- background: transparent;
38
- padding: 0 0.5em;
39
- padding-top: 0.1em;
40
- color: currentColor;
41
- height: $input-height;
42
- margin: 0;
43
- display: block;
44
- width: 100%;
45
- text-size-adjust: none;
46
- &:focus-visible {
47
- outline: 4px solid rgba(white, 0.4);
48
- }
49
- }
@@ -1,30 +0,0 @@
1
- $color-black: #0c0c0c;
2
- $color-violetblue: #1d0b40;
3
- $color-violetblue-hover: #2d155d;
4
- $color-violet: #5920c0;
5
- $color-blue: #3053d9;
6
- $color-warmgrey: #dbd5cd;
7
- $color-activeorange: #ff3300;
8
-
9
- $border-radius-container: 8px;
10
- $border-radius-input: 4px;
11
- $input-height: 2.5rem;
12
- $app-max-width: 40rem;
13
-
14
- $swr-sans: 'SWR-VAR-Sans', serif;
15
- $swr-text: 'SWR-VAR-Text', serif;
16
-
17
- $transition-fast: 150ms;
18
-
19
- // Breakpoints
20
- $break-phone: 510px;
21
- $break-tablet: 992px;
22
- $break-desktop-small: 1200px;
23
- $break-desktop-large: 1400px;
24
- $break-desktop-xl: 1400px;
25
-
26
- @mixin bp($point) {
27
- @media (min-width: $point) {
28
- @content;
29
- }
30
- }