@swr-data-lab/components 1.0.9 → 1.0.11

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/package.json CHANGED
@@ -1,59 +1,64 @@
1
1
  {
2
- "name": "@swr-data-lab/components",
3
- "description": "SWR Data Lab component library",
4
- "author": "SWR Data Lab",
5
- "publishConfig": {
6
- "access": "restricted"
7
- },
8
- "scripts": {
9
- "dev": "vite dev",
10
- "build": "vite build",
11
- "preview": "vite preview",
12
- "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
13
- "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
14
- "storybook": "storybook dev -p 6006",
15
- "start": "storybook dev -p 6006",
16
- "build-storybook": "storybook build --disable-telemetry",
17
- "test-storybook": "test-storybook --browsers chromium firefox",
18
- "test-storybook:ci": "concurrently -k -s first -n \"Storybook,Test\" -c \"magenta,blue\" \"npm run build-storybook --quiet && npx http-server storybook-static --port 6006 --silent\" \"wait-on tcp:6006 && npm run test-storybook\"",
19
- "semantic-release": "semantic-release"
20
- },
21
- "devDependencies": {
22
- "@chromatic-com/storybook": "^2.0.2",
23
- "@semantic-release/changelog": "^6.0.3",
24
- "@semantic-release/git": "^10.0.1",
25
- "@semantic-release/npm": "^12.0.1",
26
- "@storybook/addon-essentials": "^8.3.0",
27
- "@storybook/addon-interactions": "^8.3.0",
28
- "@storybook/addon-links": "^8.3.0",
29
- "@storybook/addon-svelte-csf": "^4.1.7",
30
- "@storybook/blocks": "^8.3.0",
31
- "@storybook/builder-vite": "^8.3.0",
32
- "@storybook/svelte": "^8.3.0",
33
- "@storybook/sveltekit": "^8.3.0",
34
- "@storybook/test": "^8.3.0",
35
- "@storybook/test-runner": "^0.19.1",
36
- "@sveltejs/adapter-auto": "^3.0.0",
37
- "@sveltejs/kit": "^2.0.0",
38
- "@sveltejs/vite-plugin-svelte": "^3.0.0",
39
- "concurrently": "^9.0.1",
40
- "http-server": "^14.1.1",
41
- "sass-embedded": "^1.78.0",
42
- "semantic-release": "^24.1.2",
43
- "storybook": "^8.3.0",
44
- "svelte": "^4.2.7",
45
- "svelte-check": "^4.0.0",
46
- "typescript": "^5.0.0",
47
- "vite": "^5.0.3",
48
- "wait-on": "^8.0.1"
49
- },
50
- "type": "module",
51
- "release": {
52
- "plugins": [
53
- "@semantic-release/commit-analyzer",
54
- "@semantic-release/release-notes-generator",
55
- "@semantic-release/npm"
56
- ]
57
- },
58
- "version": "1.0.9"
2
+ "name": "@swr-data-lab/components",
3
+ "description": "SWR Data Lab component library",
4
+ "author": "SWR Data Lab",
5
+ "publishConfig": {
6
+ "access": "restricted"
7
+ },
8
+ "scripts": {
9
+ "dev": "vite dev",
10
+ "build": "vite build",
11
+ "preview": "vite preview",
12
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
13
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
14
+ "storybook": "storybook dev -p 6006",
15
+ "start": "storybook dev -p 6006",
16
+ "build-storybook": "storybook build --disable-telemetry",
17
+ "test-storybook": "test-storybook --browsers chromium firefox",
18
+ "test-storybook:ci": "concurrently -k -s first -n \"Storybook,Test\" -c \"magenta,blue\" \"npm run build-storybook --quiet && npx http-server storybook-static --port 6006 --silent\" \"wait-on tcp:6006 && npm run test-storybook\"",
19
+ "semantic-release": "semantic-release"
20
+ },
21
+ "devDependencies": {
22
+ "@chromatic-com/storybook": "^2.0.2",
23
+ "@semantic-release/changelog": "^6.0.3",
24
+ "@semantic-release/git": "^10.0.1",
25
+ "@semantic-release/npm": "^12.0.1",
26
+ "@storybook/addon-essentials": "^8.3.0",
27
+ "@storybook/addon-interactions": "^8.3.0",
28
+ "@storybook/addon-links": "^8.3.0",
29
+ "@storybook/addon-svelte-csf": "^4.1.7",
30
+ "@storybook/blocks": "^8.3.0",
31
+ "@storybook/builder-vite": "^8.3.0",
32
+ "@storybook/svelte": "^8.3.0",
33
+ "@storybook/sveltekit": "^8.3.0",
34
+ "@storybook/test": "^8.3.0",
35
+ "@storybook/test-runner": "^0.19.1",
36
+ "@sveltejs/adapter-auto": "^3.0.0",
37
+ "@sveltejs/kit": "^2.0.0",
38
+ "@sveltejs/vite-plugin-svelte": "^3.0.0",
39
+ "concurrently": "^9.0.1",
40
+ "http-server": "^14.1.1",
41
+ "sass-embedded": "^1.78.0",
42
+ "semantic-release": "^24.1.2",
43
+ "storybook": "^8.3.0",
44
+ "svelte": "^4.2.7",
45
+ "svelte-check": "^4.0.0",
46
+ "typescript": "^5.0.0",
47
+ "vite": "^5.0.3",
48
+ "wait-on": "^8.0.1"
49
+ },
50
+ "type": "module",
51
+ "release": {
52
+ "plugins": [
53
+ "@semantic-release/commit-analyzer",
54
+ "@semantic-release/release-notes-generator",
55
+ "@semantic-release/npm"
56
+ ]
57
+ },
58
+ "exports": {
59
+ ".": {
60
+ "svelte": "./src/index.js"
61
+ }
62
+ },
63
+ "version": "1.0.11"
59
64
  }
@@ -1,86 +1,90 @@
1
1
  <script lang="ts">
2
- import { createEventDispatcher } from 'svelte';
3
- import Circle from '../assets/icons/times-circle-solid.svg.svelte';
4
-
5
- export let data = [];
6
- export let query = '';
7
- export let placeholder = 'Platzhalter';
8
-
9
-
10
- const sortData = (a, b) => {
11
- return a.value.localeCompare(b.value);
12
- }
13
-
14
- let listRef;
15
- let controlsRef;
16
- let inputRef;
17
- const dispatch = createEventDispatcher();
18
-
19
- let highlightedItemIndex = -1;
20
- $: suggestions = data.sort(sortData).slice(0, 50);
21
- $: isActive = false;
22
-
23
- // Insert clicked item into search input,
24
- // dispatch it as select event and close the dropdown
25
- const handleItemClick = (index) => {
26
- highlightedItemIndex = index;
27
- setSelectedItem(suggestions[highlightedItemIndex]);
28
- };
29
-
30
- const setSelectedItem = (item) => {
31
- query = item.value;
32
- isActive = false;
33
- dispatch('select', { item });
34
- };
35
-
36
- // Register keyboard events
37
- const handleKeyDown = (e) => {
38
- if (e.key === 'ArrowDown') {
39
- e.preventDefault();
40
- highlightedItemIndex =
41
- highlightedItemIndex < suggestions.length - 1 ? highlightedItemIndex + 1 : 0;
42
- const target = listRef.querySelector(`ul li:nth-child(${highlightedItemIndex + 1})`);
43
- target.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
44
- } else if (e.key === 'ArrowUp') {
45
- e.preventDefault();
46
- highlightedItemIndex =
47
- highlightedItemIndex > 0 ? highlightedItemIndex - 1 : suggestions.length - 1;
48
- const target = listRef.querySelector(`ul li:nth-child(${highlightedItemIndex + 1})`);
49
- target.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
50
- } else if (e.key === 'Enter') {
51
- if (highlightedItemIndex > -1){
52
- setSelectedItem(suggestions[highlightedItemIndex]);
53
- isActive = false;
54
- }
55
- }
56
- };
57
-
58
- const handleClear = (e) => {
59
- query = '';
60
- inputRef.focus()
61
- setSuggestions()
62
- dispatch('select', {
63
- item: null
64
- });
65
- };
66
-
67
-
68
- const setSuggestions = () => {
69
- suggestions = data.filter((el) =>{
70
- return el.value.toLowerCase().startsWith(query.toLowerCase())
71
- }).sort(sortData);
72
- }
73
-
74
- // update dropdown list if input value changes
75
- const handleInput = () => {
76
- isActive = true;
77
- if (query.length === 0){
78
- suggestions = data
79
- } else {
80
- setSuggestions()
81
- highlightedItemIndex = -1;
82
- }
83
- }
2
+ import { createEventDispatcher } from 'svelte';
3
+ import Circle from '../assets/times-circle-solid.svg.svelte';
4
+
5
+ export let data = [];
6
+ export let query: string = '';
7
+ export let placeholder: string = 'Platzhalter';
8
+ export let label: string;
9
+ export let name: string;
10
+
11
+ const sortData = (a, b) => {
12
+ return a.value.localeCompare(b.value);
13
+ };
14
+
15
+ let listRef;
16
+ let inputRef;
17
+ let controlsRef;
18
+ const dispatch = createEventDispatcher();
19
+ const maxSuggestions = 100;
20
+
21
+ let highlightedItemIndex = -1;
22
+ $: suggestions = data.sort(sortData).slice(0, maxSuggestions);
23
+ $: isActive = false;
24
+
25
+ // Insert clicked item into search input,
26
+ // dispatch it as select event and close the dropdown
27
+ const handleItemClick = (index) => {
28
+ highlightedItemIndex = index;
29
+ setSelectedItem(suggestions[highlightedItemIndex]);
30
+ };
31
+
32
+ const setSelectedItem = (item) => {
33
+ query = item.value;
34
+ isActive = false;
35
+ dispatch('select', { item });
36
+ };
37
+
38
+ // Register keyboard events
39
+ const handleKeyDown = (e) => {
40
+ if (e.key === 'ArrowDown') {
41
+ e.preventDefault();
42
+ highlightedItemIndex =
43
+ highlightedItemIndex < suggestions.length - 1 ? highlightedItemIndex + 1 : 0;
44
+ const target = listRef.querySelector(`ul li:nth-child(${highlightedItemIndex + 1})`);
45
+ target.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
46
+ } else if (e.key === 'ArrowUp') {
47
+ e.preventDefault();
48
+ highlightedItemIndex =
49
+ highlightedItemIndex > 0 ? highlightedItemIndex - 1 : suggestions.length - 1;
50
+ const target = listRef.querySelector(`ul li:nth-child(${highlightedItemIndex + 1})`);
51
+ target.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
52
+ } else if (e.key === 'Enter') {
53
+ if (highlightedItemIndex > -1) {
54
+ setSelectedItem(suggestions[highlightedItemIndex]);
55
+ isActive = false;
56
+ }
57
+ }
58
+ };
59
+
60
+ const handleClear = () => {
61
+ query = '';
62
+ inputRef.focus();
63
+ setSuggestions();
64
+ dispatch('select', {
65
+ item: null
66
+ });
67
+ };
68
+
69
+ const setSuggestions = () => {
70
+ suggestions = data
71
+ .filter((el) => {
72
+ return el.value.toLowerCase().startsWith(query.toLowerCase());
73
+ })
74
+ .slice(0, maxSuggestions)
75
+ .sort(sortData);
76
+ };
77
+
78
+ // update dropdown list if input value changes
79
+ const handleInput = () => {
80
+ isActive = true;
81
+ if (query.length === 0) {
82
+ suggestions = data;
83
+ } else {
84
+ setSuggestions();
85
+ highlightedItemIndex = -1;
86
+ }
87
+ };
84
88
  </script>
85
89
 
86
90
  <!--
@@ -93,140 +97,140 @@ Data should be provided as array of objects. Each object contains the informatio
93
97
  @component
94
98
  -->
95
99
 
96
- <div class="autocomplete">
97
- <input
98
- type="text"
99
- {placeholder}
100
- autocomplete="off"
101
- autocorrect="off"
102
- autocapitalize="off"
103
- data-testid="autocomplete-input"
104
- bind:this={inputRef}
105
- on:keydown={handleKeyDown}
106
- bind:value={query}
107
- on:input={handleInput}
108
- on:focus={() => {
109
- isActive = true;
110
- }}
111
- on:blur={(e) => {
112
- if (listRef.contains(e.relatedTarget)){
113
- window.setTimeout(()=>{
114
- isActive = false;
115
- }, 100)
116
- } else if (!controlsRef.contains(e.relatedTarget)){
117
- isActive = false
118
- }
119
- }}
120
- />
121
-
122
- <ul tabindex="-1" bind:this={listRef} class:active={isActive}>
123
- {#each suggestions as item, i (item.value)}
124
- <li>
125
- <button
126
- class={`item ${i === highlightedItemIndex ? 'active' : ''}`}
127
- tabindex="-1"
128
- type="button"
129
- on:click={(e) => {
130
- e.preventDefault();
131
- handleItemClick(i);
132
- }}
133
- >
134
- {item.label}
135
- </button>
136
- </li>
137
- {/each}
138
- </ul>
139
- <div class="controls" bind:this={controlsRef}>
140
- <button type="button" on:click={handleClear} class="clear" class:active={query.length > 0}>
141
- <Circle />
142
- </button>
143
- </div>
100
+ <div class="autocomplete" class:active={isActive}>
101
+ <label for={name}>{label}</label>
102
+ <input
103
+ type="text"
104
+ {name}
105
+ {placeholder}
106
+ autocomplete="off"
107
+ autocorrect="off"
108
+ autocapitalize="off"
109
+ data-testid="autocomplete-input"
110
+ bind:this={inputRef}
111
+ on:keydown={handleKeyDown}
112
+ bind:value={query}
113
+ on:input={handleInput}
114
+ on:focus={() => {
115
+ isActive = true;
116
+ }}
117
+ on:blur={(e) => {
118
+ if (listRef.contains(e.relatedTarget)) {
119
+ window.setTimeout(() => {
120
+ isActive = false;
121
+ }, 100);
122
+ } else if (!controlsRef.contains(e.relatedTarget)) {
123
+ isActive = false;
124
+ }
125
+ }}
126
+ />
127
+
128
+ <ul tabindex="-1" bind:this={listRef}>
129
+ {#each suggestions as item, i (item.value)}
130
+ <li>
131
+ <button
132
+ class={`item ${i === highlightedItemIndex ? 'active' : ''}`}
133
+ tabindex="-1"
134
+ type="button"
135
+ on:click={(e) => {
136
+ e.preventDefault();
137
+ handleItemClick(i);
138
+ }}
139
+ >
140
+ {item.label}
141
+ </button>
142
+ </li>
143
+ {/each}
144
+ </ul>
145
+ <div class="controls" bind:this={controlsRef}>
146
+ <button type="button" on:click={handleClear} class="clear" class:active={query.length > 0}>
147
+ <Circle />
148
+ </button>
149
+ </div>
144
150
  </div>
145
151
 
146
152
  <style lang="scss">
147
- @import '../styles/scss/base.scss';
148
-
149
- .autocomplete {
150
- position: relative;
151
- display: block;
152
- color: white;
153
-
154
- input {
155
- @extend %copy;
156
- border: 1px solid black;
157
- border-radius: $border-radius-input;
158
- background: transparent;
159
- padding: 0 0.5em;
160
- height: $input-height;
161
- margin: 0;
162
- display: block;
163
- width: 100%;
164
- &:focus-visible {
165
- border-bottom-right-radius: 0;
166
- border-bottom-left-radius: 0;
167
- }
168
- }
169
- input[type='text'] {
170
- text-size-adjust: none;
171
- }
172
-
173
- ul {
174
- position: absolute;
175
- top: 100%;
176
- border: 1px solid black;
177
- border-bottom-left-radius: $border-radius-input;
178
- border-bottom-right-radius: $border-radius-input;
179
- border-top: 0;
180
- left: 0;
181
- right: 0;
182
- max-height: 10rem;
183
- overflow-y: scroll;
184
- z-index: 1000;
185
- opacity: 0;
186
- transition: 100ms;
187
- pointer-events: none;
188
- &:empty {
189
- box-shadow: none;
190
- }
191
- &.active {
192
- opacity: 1;
193
- pointer-events: all;
194
- }
195
-
196
- .item {
197
- @extend %caption;
198
- padding: 0.5em;
199
- width: 100%;
200
- background: transparent;
201
- border: 0;
202
- text-align: left;
203
- border-bottom: 1px solid rgba(black, 0.5);
204
- cursor: pointer;
205
- &.active, &:hover {
206
- text-decoration: underline;
207
- background-color: rgba(black, .1);
208
- }
209
- }
210
- }
211
-
212
- .clear {
213
- position: absolute;
214
- transform: translateY(-50%);
215
- top: 50%;
216
- right: 0.75rem;
217
- width: 1.2rem;
218
- height: 1.2rem;
219
- background: transparent;
220
- border: 0;
221
- display: none;
222
- &.active {
223
- display: block;
224
- }
225
- &:hover,
226
- &:focus {
227
- color: $orange--1;
228
- cursor: pointer;
229
- }
230
- }
231
- }
153
+ @import '../styles/base.scss';
154
+
155
+ .autocomplete {
156
+ position: relative;
157
+ display: block;
158
+ color: white;
159
+
160
+ label {
161
+ @extend %form-label;
162
+ }
163
+
164
+ input {
165
+ @extend %form-input;
166
+ }
167
+
168
+ ul {
169
+ position: absolute;
170
+ top: 100%;
171
+ border: 1px solid currentColor;
172
+ background: $reanimation-violetblue;
173
+ border-bottom-left-radius: $border-radius-input;
174
+ border-bottom-right-radius: $border-radius-input;
175
+ border-top: 0;
176
+ left: 0;
177
+ right: 0;
178
+ max-height: 10rem;
179
+ overflow-y: scroll;
180
+ z-index: 1000;
181
+ opacity: 0;
182
+ transition: 100ms;
183
+ pointer-events: none;
184
+ &:empty {
185
+ box-shadow: none;
186
+ }
187
+
188
+ .item {
189
+ @extend %caption;
190
+ padding: 0.5em;
191
+ width: 100%;
192
+ background: transparent;
193
+ border: 0;
194
+ text-align: left;
195
+ color: currentColor;
196
+ border-bottom: 1px solid rgba(white, 0.25);
197
+ cursor: pointer;
198
+ &.active,
199
+ &:hover {
200
+ text-decoration: underline;
201
+ background-color: rgba(white, 0.05);
202
+ }
203
+ }
204
+ }
205
+
206
+ .clear {
207
+ position: absolute;
208
+ top: 50%;
209
+ right: 0.75rem;
210
+ width: 1.2rem;
211
+ height: 1.2rem;
212
+ background: transparent;
213
+ border: 0;
214
+ display: none;
215
+ color: white;
216
+ &.active {
217
+ display: block;
218
+ }
219
+ &:hover,
220
+ &:focus {
221
+ color: $orange;
222
+ cursor: pointer;
223
+ }
224
+ }
225
+ &.active {
226
+ ul {
227
+ opacity: 1;
228
+ pointer-events: all;
229
+ }
230
+ input {
231
+ border-bottom-right-radius: 0;
232
+ border-bottom-left-radius: 0;
233
+ }
234
+ }
235
+ }
232
236
  </style>
@@ -1,2 +1,2 @@
1
- import AutoComplete from "./Autocomplete.svelte"
2
- export default AutoComplete
1
+ import Autocomplete from './Autocomplete.svelte';
2
+ export default Autocomplete;
@@ -0,0 +1,45 @@
1
+ <script lang="ts">
2
+ export let as: string = 'button';
3
+ export let label: string = '';
4
+ export let href: string = '';
5
+ export let disabled: boolean = false;
6
+ </script>
7
+
8
+ {#if as === 'a'}
9
+ <a class="button" class:disabled {href}>{label}</a>
10
+ {:else}
11
+ <button class="button" on:click {disabled}>{label}</button>
12
+ {/if}
13
+
14
+ <style lang="scss">
15
+ @import '../styles/base.scss';
16
+ .button {
17
+ @extend %copy-bold;
18
+ background: $reanimation-violet;
19
+ display: inline-flex;
20
+ align-items: center;
21
+ justify-self: flex-start;
22
+ padding: 0.25em 1.25em;
23
+ padding-bottom: 0.35em;
24
+ color: white;
25
+ border: 1px solid rgba(white, 0.1);
26
+ box-shadow: 0px 0px 10px rgba(black, 0.05);
27
+ border-radius: $border-radius-input;
28
+ text-shadow: 0px 0px 5px rgba(black, 0.05);
29
+ font-size: 1.2rem;
30
+ text-decoration: none;
31
+ @include bp($break-tablet) {
32
+ font-size: 1.4rem;
33
+ }
34
+ &:hover,
35
+ &:focus-visible {
36
+ text-decoration: underline;
37
+ text-underline-offset: 0.15em;
38
+ }
39
+ &.disabled,
40
+ &:disabled {
41
+ opacity: 0.5;
42
+ /* pointer-events: none; */
43
+ }
44
+ }
45
+ </style>
@@ -0,0 +1,2 @@
1
+ import Button from './Button.svelte';
2
+ export default Button;
@@ -0,0 +1,19 @@
1
+ <div class="card">
2
+ <slot />
3
+ </div>
4
+
5
+ <style lang="scss">
6
+ @import '../styles/base.scss';
7
+ .card {
8
+ width: auto;
9
+ max-width: $app-max-width;
10
+ color: white;
11
+ background: $reanimation-violetblue;
12
+ border-radius: $border-radius-container;
13
+ margin: 0 1rem;
14
+ padding: 1.5rem;
15
+ @include bp($break-tablet) {
16
+ padding: 2.5rem;
17
+ }
18
+ }
19
+ </style>
@@ -0,0 +1,2 @@
1
+ import Card from './Card.svelte';
2
+ export default Card;