@reshape-biotech/design-system 2.7.50 → 2.7.52
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/components/button/Button.stories.svelte +37 -35
- package/dist/components/button/Button.svelte +18 -13
- package/dist/components/button/Button.svelte.d.ts +1 -1
- package/dist/components/icon-button/IconButton.stories.svelte +72 -28
- package/dist/components/icon-button/IconButton.stories.svelte.d.ts +1 -1
- package/dist/components/icon-button/IconButton.svelte +80 -84
- package/dist/components/icon-button/IconButton.svelte.d.ts +10 -4
- package/dist/components/input/Input.stories.svelte +42 -10
- package/dist/components/input/Input.stories.svelte.d.ts +2 -17
- package/dist/components/input/Input.svelte +18 -18
- package/dist/components/input/Input.svelte.d.ts +2 -2
- package/dist/components/nav/Nav.svelte +1 -0
- package/dist/components/toast/Toast.stories.svelte +3 -24
- package/dist/components/toast/Toast.svelte +22 -40
- package/dist/safelist-source.d.ts +1 -1
- package/dist/safelist-source.js +2 -2
- package/dist/safelist.css +1 -1
- package/dist/tailwind.preset.d.ts +2 -0
- package/dist/tokens/colors.d.ts +1 -0
- package/dist/tokens/colors.js +8 -7
- package/dist/tokens.d.ts +13 -0
- package/dist/tokens.js +8 -2
- package/package.json +1 -1
|
@@ -27,23 +27,19 @@
|
|
|
27
27
|
</script>
|
|
28
28
|
|
|
29
29
|
<Story name="Variants" asChild>
|
|
30
|
-
<div class="flex flex-col
|
|
30
|
+
<div class="flex flex-col">
|
|
31
31
|
{#each variants as variant}
|
|
32
32
|
{#if variant === 'secondary-inverse' || variant === 'transparent-inverse'}
|
|
33
|
-
<div class="bg-
|
|
34
|
-
<p>{variant}</p>
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
<Button variant={variant as ButtonVariant} rounded>Button</Button>
|
|
38
|
-
</div>
|
|
33
|
+
<div class="grid grid-cols-3 items-center justify-center gap-4 bg-surface-inverse px-8 py-6 text-primary-inverse">
|
|
34
|
+
<p class="text-secondary-inverse">{variant}</p>
|
|
35
|
+
<Button variant={variant as ButtonVariant} class="w-fit">Button</Button>
|
|
36
|
+
<Button variant={variant as ButtonVariant} class="w-fit" rounded>Button</Button>
|
|
39
37
|
</div>
|
|
40
38
|
{:else}
|
|
41
|
-
<div>
|
|
42
|
-
<p>{variant}</p>
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
<Button variant={variant as ButtonVariant} rounded>Button</Button>
|
|
46
|
-
</div>
|
|
39
|
+
<div class="grid grid-cols-3 items-center justify-center gap-4 px-8 py-6">
|
|
40
|
+
<p class="text-secondary">{variant}</p>
|
|
41
|
+
<Button variant={variant as ButtonVariant} class="w-fit">Button</Button>
|
|
42
|
+
<Button variant={variant as ButtonVariant} class="w-fit" rounded>Button</Button>
|
|
47
43
|
</div>
|
|
48
44
|
{/if}
|
|
49
45
|
{/each}
|
|
@@ -51,46 +47,52 @@
|
|
|
51
47
|
</Story>
|
|
52
48
|
|
|
53
49
|
<Story name="Sizes" asChild>
|
|
54
|
-
<div class="flex flex-col
|
|
50
|
+
<div class="flex flex-col">
|
|
55
51
|
{#each sizes as size}
|
|
56
|
-
<div>
|
|
57
|
-
<p>{size}</p>
|
|
58
|
-
<Button variant="primary" size={size as ButtonSize}>Button</Button>
|
|
52
|
+
<div class="grid grid-cols-3 items-center justify-center gap-4 px-8 py-6">
|
|
53
|
+
<p class="text-secondary">{size}</p>
|
|
54
|
+
<Button variant="primary" size={size as ButtonSize} class="w-fit">Button</Button>
|
|
55
|
+
<Button variant="primary" size={size as ButtonSize} class="w-fit" rounded>Button</Button>
|
|
59
56
|
</div>
|
|
60
57
|
{/each}
|
|
61
58
|
</div>
|
|
62
59
|
</Story>
|
|
63
60
|
|
|
64
61
|
<Story name="Disabled" asChild>
|
|
65
|
-
<div class="flex flex-col
|
|
62
|
+
<div class="flex flex-col">
|
|
66
63
|
{#each variants as variant}
|
|
67
64
|
{#if variant === 'secondary-inverse' || variant === 'transparent-inverse'}
|
|
68
|
-
<div class="bg-
|
|
69
|
-
<p>{variant}</p>
|
|
70
|
-
<
|
|
71
|
-
|
|
72
|
-
<Button variant={variant as ButtonVariant} rounded disabled>Button</Button>
|
|
73
|
-
</div>
|
|
65
|
+
<div class="grid grid-cols-3 items-center justify-center gap-4 bg-surface-inverse px-8 py-6 text-primary-inverse">
|
|
66
|
+
<p class="text-secondary-inverse">{variant}</p>
|
|
67
|
+
<Button variant={variant as ButtonVariant} class="w-fit" disabled>Button</Button>
|
|
68
|
+
<Button variant={variant as ButtonVariant} class="w-fit" rounded disabled>Button</Button>
|
|
74
69
|
</div>
|
|
75
70
|
{:else}
|
|
76
|
-
<div>
|
|
77
|
-
<p>{variant}</p>
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
<Button variant={variant as ButtonVariant} rounded disabled>Button</Button>
|
|
81
|
-
</div>
|
|
71
|
+
<div class="grid grid-cols-3 items-center justify-center gap-4 px-8 py-6">
|
|
72
|
+
<p class="text-secondary">{variant}</p>
|
|
73
|
+
<Button variant={variant as ButtonVariant} class="w-fit" disabled>Button</Button>
|
|
74
|
+
<Button variant={variant as ButtonVariant} class="w-fit" rounded disabled>Button</Button>
|
|
82
75
|
</div>
|
|
83
76
|
{/if}
|
|
84
77
|
{/each}
|
|
85
78
|
</div>
|
|
86
79
|
</Story>
|
|
87
80
|
<Story name="Loading" asChild>
|
|
88
|
-
<div class="flex flex-col
|
|
81
|
+
<div class="flex flex-col">
|
|
89
82
|
{#each variants as variant}
|
|
90
|
-
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
83
|
+
{#if variant === 'secondary-inverse' || variant === 'transparent-inverse'}
|
|
84
|
+
<div class="grid grid-cols-3 items-center justify-center gap-4 bg-surface-inverse px-8 py-6 text-primary-inverse">
|
|
85
|
+
<p class="text-secondary-inverse">{variant}</p>
|
|
86
|
+
<Button variant={variant as ButtonVariant} class="w-fit" loading>Button</Button>
|
|
87
|
+
<Button variant={variant as ButtonVariant} class="w-fit" rounded loading>Button</Button>
|
|
88
|
+
</div>
|
|
89
|
+
{:else}
|
|
90
|
+
<div class="grid grid-cols-3 items-center justify-center gap-4 px-8 py-6">
|
|
91
|
+
<p class="text-secondary">{variant}</p>
|
|
92
|
+
<Button variant={variant as ButtonVariant} class="w-fit" loading>Button</Button>
|
|
93
|
+
<Button variant={variant as ButtonVariant} class="w-fit" rounded loading>Button</Button>
|
|
94
|
+
</div>
|
|
95
|
+
{/if}
|
|
94
96
|
{/each}
|
|
95
97
|
</div>
|
|
96
98
|
</Story>
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
type?: 'button' | 'submit' | 'reset' | null | undefined;
|
|
23
23
|
loading?: boolean;
|
|
24
24
|
disabled?: boolean;
|
|
25
|
-
accessibilityLabel?: string;
|
|
25
|
+
accessibilityLabel?: string | undefined;
|
|
26
26
|
size?: ButtonSize;
|
|
27
27
|
id?: string | undefined;
|
|
28
28
|
tabindex?: number | undefined;
|
|
@@ -34,11 +34,12 @@
|
|
|
34
34
|
|
|
35
35
|
let {
|
|
36
36
|
class: className = '',
|
|
37
|
-
onClick
|
|
37
|
+
onClick,
|
|
38
|
+
onclick: onclickProp,
|
|
38
39
|
type = 'button',
|
|
39
40
|
loading = false,
|
|
40
41
|
disabled = false,
|
|
41
|
-
accessibilityLabel =
|
|
42
|
+
accessibilityLabel = undefined,
|
|
42
43
|
size = 'md',
|
|
43
44
|
id = undefined,
|
|
44
45
|
tabindex = undefined,
|
|
@@ -57,7 +58,8 @@
|
|
|
57
58
|
aria-label={accessibilityLabel}
|
|
58
59
|
onclick={(e) => {
|
|
59
60
|
if (!loading && !disabled) {
|
|
60
|
-
onClick(e);
|
|
61
|
+
onClick?.(e);
|
|
62
|
+
onclickProp?.(e);
|
|
61
63
|
} else {
|
|
62
64
|
e.preventDefault();
|
|
63
65
|
}
|
|
@@ -70,7 +72,6 @@
|
|
|
70
72
|
class={twMerge('button', variantClass, sizeClass, className)}
|
|
71
73
|
data-testid={dataTestId}
|
|
72
74
|
class:rounded
|
|
73
|
-
class:disabled
|
|
74
75
|
{...rest}
|
|
75
76
|
>
|
|
76
77
|
{#if loading}
|
|
@@ -83,7 +84,7 @@
|
|
|
83
84
|
<style>
|
|
84
85
|
@reference "../../app.css";
|
|
85
86
|
.button {
|
|
86
|
-
@apply inline-flex items-center justify-center gap-2 truncate text-nowrap rounded-lg border border-transparent text-sm font-medium transition-colors disabled:cursor-not-allowed;
|
|
87
|
+
@apply inline-flex items-center justify-center gap-2 truncate text-nowrap rounded-lg border border-transparent text-sm font-medium transition-colors hover:cursor-pointer disabled:cursor-not-allowed;
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
.rounded {
|
|
@@ -92,23 +93,27 @@
|
|
|
92
93
|
|
|
93
94
|
/* Size variants */
|
|
94
95
|
.btn-size-xs {
|
|
95
|
-
@apply h-7 rounded-md px-2;
|
|
96
|
+
@apply h-7 rounded-md px-2 text-label;
|
|
96
97
|
}
|
|
97
98
|
.btn-size-sm {
|
|
98
99
|
@apply h-8 px-3;
|
|
99
100
|
}
|
|
100
101
|
.btn-size-md {
|
|
101
|
-
@apply h-
|
|
102
|
+
@apply h-9 px-4;
|
|
102
103
|
}
|
|
103
104
|
.btn-size-lg {
|
|
104
|
-
@apply h-
|
|
105
|
+
@apply h-10 px-5;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Gradient sheen */
|
|
109
|
+
.btn-primary, .btn-danger {
|
|
110
|
+
@apply bg-origin-border bg-gradient-to-b from-white/5 to-transparent to-75% disabled:bg-none;
|
|
105
111
|
}
|
|
106
112
|
|
|
107
113
|
/* Button variants */
|
|
108
114
|
.btn-primary {
|
|
109
|
-
@apply border-input bg-accent-inverse text-primary-inverse shadow-
|
|
115
|
+
@apply border-input bg-accent-inverse text-primary-inverse shadow-button hover:bg-accent-inverse-hover disabled:border-transparent disabled:bg-neutral disabled:text-tertiary disabled:hover:bg-neutral;
|
|
110
116
|
}
|
|
111
|
-
|
|
112
117
|
.btn-secondary {
|
|
113
118
|
@apply bg-neutral text-primary hover:bg-neutral-hover active:bg-neutral disabled:border-transparent disabled:bg-neutral disabled:text-tertiary disabled:hover:bg-neutral;
|
|
114
119
|
}
|
|
@@ -116,10 +121,10 @@
|
|
|
116
121
|
@apply bg-transparent text-inherit hover:bg-neutral disabled:bg-transparent disabled:text-tertiary disabled:hover:bg-transparent;
|
|
117
122
|
}
|
|
118
123
|
.btn-danger {
|
|
119
|
-
@apply border-input bg-danger-inverse text-primary-inverse shadow-
|
|
124
|
+
@apply border-input bg-danger-inverse text-primary-inverse shadow-button hover:bg-danger-inverse-hover disabled:border-transparent disabled:bg-neutral disabled:text-tertiary disabled:hover:bg-neutral;
|
|
120
125
|
}
|
|
121
126
|
.btn-outline {
|
|
122
|
-
@apply border-input bg-surface text-primary shadow-
|
|
127
|
+
@apply border-input bg-surface text-primary shadow-button hover:bg-surface-secondary hover:text-primary disabled:border-static disabled:bg-transparent disabled:text-tertiary disabled:shadow-none;
|
|
123
128
|
}
|
|
124
129
|
.btn-secondary-inverse {
|
|
125
130
|
@apply bg-neutral-inverse text-primary-inverse hover:bg-neutral-inverse-hover active:bg-neutral-inverse disabled:border-transparent disabled:bg-neutral-inverse disabled:text-tertiary disabled:hover:bg-neutral-inverse;
|
|
@@ -8,7 +8,7 @@ interface Props extends HTMLButtonAttributes {
|
|
|
8
8
|
type?: 'button' | 'submit' | 'reset' | null | undefined;
|
|
9
9
|
loading?: boolean;
|
|
10
10
|
disabled?: boolean;
|
|
11
|
-
accessibilityLabel?: string;
|
|
11
|
+
accessibilityLabel?: string | undefined;
|
|
12
12
|
size?: ButtonSize;
|
|
13
13
|
id?: string | undefined;
|
|
14
14
|
tabindex?: number | undefined;
|
|
@@ -1,50 +1,94 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
2
|
import Plus from 'phosphor-svelte/lib/Plus';
|
|
3
3
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
4
|
-
import IconButton from '
|
|
4
|
+
import IconButton, { type IconButtonVariant, type IconButtonSize } from './IconButton.svelte';
|
|
5
5
|
|
|
6
6
|
const { Story } = defineMeta({
|
|
7
7
|
component: IconButton,
|
|
8
8
|
title: 'Components/IconButton',
|
|
9
9
|
tags: ['autodocs'],
|
|
10
10
|
});
|
|
11
|
+
|
|
12
|
+
const variants: IconButtonVariant[] = [
|
|
13
|
+
'primary',
|
|
14
|
+
'secondary',
|
|
15
|
+
'danger',
|
|
16
|
+
'transparent',
|
|
17
|
+
'outline',
|
|
18
|
+
'secondary-inverse',
|
|
19
|
+
'transparent-inverse',
|
|
20
|
+
];
|
|
21
|
+
const sizes: IconButtonSize[] = ['xs', 'sm', 'md', 'lg'];
|
|
11
22
|
</script>
|
|
12
23
|
|
|
13
|
-
<Story name="
|
|
14
|
-
<div class="flex flex-col
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
<Story name="Variants" asChild>
|
|
25
|
+
<div class="flex flex-col">
|
|
26
|
+
{#each variants as variant}
|
|
27
|
+
{#if variant === 'secondary-inverse' || variant === 'transparent-inverse'}
|
|
28
|
+
<div class="grid grid-cols-3 items-center justify-center gap-4 bg-surface-inverse px-8 py-6 text-primary-inverse">
|
|
29
|
+
<p class="text-secondary-inverse">{variant}</p>
|
|
30
|
+
<IconButton {variant} rounded={false} accessibilityLabel={variant}><Plus /></IconButton>
|
|
31
|
+
<IconButton {variant} rounded accessibilityLabel={variant}><Plus /></IconButton>
|
|
32
|
+
</div>
|
|
33
|
+
{:else}
|
|
34
|
+
<div class="grid grid-cols-3 items-center justify-center gap-4 px-8 py-6">
|
|
35
|
+
<p class="text-secondary">{variant}</p>
|
|
36
|
+
<IconButton {variant} rounded={false} accessibilityLabel={variant}><Plus /></IconButton>
|
|
37
|
+
<IconButton {variant} rounded accessibilityLabel={variant}><Plus /></IconButton>
|
|
38
|
+
</div>
|
|
39
|
+
{/if}
|
|
40
|
+
{/each}
|
|
19
41
|
</div>
|
|
20
42
|
</Story>
|
|
21
43
|
|
|
22
44
|
<Story name="Sizes" asChild>
|
|
23
|
-
<div class="flex flex-col
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
<IconButton aria-label="Add" variant="primary" rounded={false}><Plus /></IconButton>
|
|
32
|
-
<IconButton aria-label="Add" variant="secondary" rounded={false}><Plus /></IconButton>
|
|
33
|
-
<IconButton aria-label="Add" variant="danger" rounded={false}><Plus /></IconButton>
|
|
34
|
-
<IconButton aria-label="Add" variant="transparent" rounded={false}><Plus /></IconButton>
|
|
45
|
+
<div class="flex flex-col">
|
|
46
|
+
{#each sizes as size}
|
|
47
|
+
<div class="grid grid-cols-3 items-center justify-center gap-4 px-8 py-6">
|
|
48
|
+
<p class="text-secondary">{size}</p>
|
|
49
|
+
<IconButton variant="primary" {size} rounded={false} accessibilityLabel={size}><Plus /></IconButton>
|
|
50
|
+
<IconButton variant="primary" {size} rounded accessibilityLabel={size}><Plus /></IconButton>
|
|
51
|
+
</div>
|
|
52
|
+
{/each}
|
|
35
53
|
</div>
|
|
36
54
|
</Story>
|
|
37
55
|
|
|
38
|
-
<Story name="Not rounded sizes" asChild>
|
|
39
|
-
<div class="flex flex-col gap-2">
|
|
40
|
-
<IconButton aria-label="Add" variant="secondary" size="xs" rounded={false}><Plus /></IconButton>
|
|
41
|
-
<IconButton aria-label="Add" variant="secondary" size="sm" rounded={false}><Plus /></IconButton>
|
|
42
|
-
<IconButton aria-label="Add" variant="secondary" size="md" rounded={false}><Plus /></IconButton>
|
|
43
|
-
</div>
|
|
44
|
-
</Story>
|
|
45
56
|
<Story name="Disabled" asChild>
|
|
46
|
-
<
|
|
57
|
+
<div class="flex flex-col">
|
|
58
|
+
{#each variants as variant}
|
|
59
|
+
{#if variant === 'secondary-inverse' || variant === 'transparent-inverse'}
|
|
60
|
+
<div class="grid grid-cols-3 items-center justify-center gap-4 bg-surface-inverse px-8 py-6 text-primary-inverse">
|
|
61
|
+
<p class="text-secondary-inverse">{variant}</p>
|
|
62
|
+
<IconButton {variant} rounded={false} disabled accessibilityLabel={variant}><Plus /></IconButton>
|
|
63
|
+
<IconButton {variant} rounded disabled accessibilityLabel={variant}><Plus /></IconButton>
|
|
64
|
+
</div>
|
|
65
|
+
{:else}
|
|
66
|
+
<div class="grid grid-cols-3 items-center justify-center gap-4 px-8 py-6">
|
|
67
|
+
<p class="text-secondary">{variant}</p>
|
|
68
|
+
<IconButton {variant} rounded={false} disabled accessibilityLabel={variant}><Plus /></IconButton>
|
|
69
|
+
<IconButton {variant} rounded disabled accessibilityLabel={variant}><Plus /></IconButton>
|
|
70
|
+
</div>
|
|
71
|
+
{/if}
|
|
72
|
+
{/each}
|
|
73
|
+
</div>
|
|
47
74
|
</Story>
|
|
75
|
+
|
|
48
76
|
<Story name="Loading" asChild>
|
|
49
|
-
<
|
|
77
|
+
<div class="flex flex-col">
|
|
78
|
+
{#each variants as variant}
|
|
79
|
+
{#if variant === 'secondary-inverse' || variant === 'transparent-inverse'}
|
|
80
|
+
<div class="grid grid-cols-3 items-center justify-center gap-4 bg-surface-inverse px-8 py-6 text-primary-inverse">
|
|
81
|
+
<p class="text-secondary-inverse">{variant}</p>
|
|
82
|
+
<IconButton {variant} rounded={false} loading accessibilityLabel={variant}><Plus /></IconButton>
|
|
83
|
+
<IconButton {variant} rounded loading accessibilityLabel={variant}><Plus /></IconButton>
|
|
84
|
+
</div>
|
|
85
|
+
{:else}
|
|
86
|
+
<div class="grid grid-cols-3 items-center justify-center gap-4 px-8 py-6">
|
|
87
|
+
<p class="text-secondary">{variant}</p>
|
|
88
|
+
<IconButton {variant} rounded={false} loading accessibilityLabel={variant}><Plus /></IconButton>
|
|
89
|
+
<IconButton {variant} rounded loading accessibilityLabel={variant}><Plus /></IconButton>
|
|
90
|
+
</div>
|
|
91
|
+
{/if}
|
|
92
|
+
{/each}
|
|
93
|
+
</div>
|
|
50
94
|
</Story>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import IconButton from '
|
|
1
|
+
import IconButton from './IconButton.svelte';
|
|
2
2
|
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
3
|
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
4
|
$$bindings?: Bindings;
|
|
@@ -1,142 +1,138 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
import type { Snippet } from 'svelte';
|
|
4
|
-
import { Spinner } from '../spinner/';
|
|
5
|
-
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
6
|
-
|
|
7
|
-
type Variant =
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
export type IconButtonVariant =
|
|
8
3
|
| 'primary'
|
|
9
4
|
| 'secondary'
|
|
10
5
|
| 'transparent'
|
|
11
6
|
| 'outline'
|
|
12
|
-
| 'accent'
|
|
13
7
|
| 'danger'
|
|
14
8
|
| 'secondary-inverse'
|
|
15
9
|
| 'transparent-inverse';
|
|
10
|
+
export type IconButtonSize = 'xs' | 'sm' | 'md' | 'lg';
|
|
11
|
+
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<script lang="ts">
|
|
15
|
+
import { twMerge } from 'tailwind-merge';
|
|
16
|
+
import Spinner from '../spinner/Spinner.svelte';
|
|
17
|
+
import { IconContext } from 'phosphor-svelte';
|
|
18
|
+
import type { Snippet } from 'svelte';
|
|
16
19
|
|
|
17
|
-
// Combine custom props with standard HTML button attributes,
|
|
18
|
-
// omitting ones we handle explicitly (like 'class', 'onclick')
|
|
19
20
|
interface Props extends HTMLButtonAttributes {
|
|
20
|
-
|
|
21
|
+
class?: string;
|
|
22
|
+
onClick?: (event?: MouseEvent) => void;
|
|
21
23
|
type?: 'button' | 'submit' | 'reset' | null | undefined;
|
|
22
24
|
loading?: boolean;
|
|
23
|
-
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
accessibilityLabel?: string | undefined;
|
|
27
|
+
size?: IconButtonSize;
|
|
28
|
+
tabindex?: number | undefined;
|
|
29
|
+
variant?: IconButtonVariant;
|
|
24
30
|
children?: Snippet;
|
|
25
31
|
rounded?: boolean;
|
|
26
32
|
}
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
const sizeClasses: Record<IconButtonSize, string> = {
|
|
35
|
+
xs: 'size-xs size-7 rounded-md',
|
|
36
|
+
sm: 'size-sm size-8',
|
|
37
|
+
md: 'size-md size-9',
|
|
38
|
+
lg: 'size-lg size-10',
|
|
39
|
+
};
|
|
40
|
+
|
|
29
41
|
let {
|
|
30
|
-
|
|
42
|
+
class: className = '',
|
|
43
|
+
onClick,
|
|
44
|
+
onclick: onclickProp,
|
|
31
45
|
type = 'button',
|
|
32
46
|
loading = false,
|
|
33
47
|
disabled = false,
|
|
48
|
+
accessibilityLabel = undefined,
|
|
34
49
|
size = 'sm',
|
|
50
|
+
tabindex = undefined,
|
|
51
|
+
variant = 'transparent',
|
|
35
52
|
children,
|
|
36
|
-
onclick,
|
|
37
|
-
tabindex,
|
|
38
53
|
rounded = true,
|
|
39
|
-
class: className,
|
|
40
54
|
...rest
|
|
41
55
|
}: Props = $props();
|
|
42
56
|
|
|
43
|
-
let sizeClass = $derived(`size-${size}`);
|
|
44
57
|
let variantClass = $derived(`color-${variant}`);
|
|
58
|
+
let sizeClass = $derived(sizeClasses[size]);
|
|
45
59
|
</script>
|
|
46
60
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
61
|
+
<button
|
|
62
|
+
aria-label={accessibilityLabel}
|
|
63
|
+
onclick={(e) => {
|
|
64
|
+
if (!loading && !disabled) {
|
|
65
|
+
onClick?.(e);
|
|
66
|
+
onclickProp?.(e);
|
|
67
|
+
} else {
|
|
50
68
|
e.preventDefault();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
69
|
+
}
|
|
70
|
+
}}
|
|
71
|
+
{type}
|
|
72
|
+
{disabled}
|
|
73
|
+
{tabindex}
|
|
74
|
+
class:cursor-wait={loading}
|
|
75
|
+
class={twMerge('icon-button', variantClass, sizeClass, className)}
|
|
76
|
+
class:rounded
|
|
77
|
+
{...rest}
|
|
78
|
+
>
|
|
79
|
+
<IconContext values={{ weight: 'bold' }}>
|
|
58
80
|
{#if loading}
|
|
59
81
|
<Spinner />
|
|
60
82
|
{:else}
|
|
61
83
|
{@render children?.()}
|
|
62
84
|
{/if}
|
|
63
|
-
</
|
|
64
|
-
|
|
65
|
-
<button
|
|
66
|
-
{onclick}
|
|
67
|
-
{type}
|
|
68
|
-
{disabled}
|
|
69
|
-
{tabindex}
|
|
70
|
-
class={twMerge(sizeClass, variantClass, className)}
|
|
71
|
-
class:rounded
|
|
72
|
-
{...rest}
|
|
73
|
-
>
|
|
74
|
-
{@render children?.()}
|
|
75
|
-
</button>
|
|
76
|
-
{/if}
|
|
85
|
+
</IconContext>
|
|
86
|
+
</button>
|
|
77
87
|
|
|
78
88
|
<style>
|
|
79
89
|
@reference "../../app.css";
|
|
80
|
-
|
|
81
|
-
|
|
90
|
+
|
|
91
|
+
.icon-button {
|
|
92
|
+
@apply flex shrink-0 cursor-pointer items-center justify-center rounded-lg border border-transparent transition-colors hover:cursor-pointer disabled:cursor-not-allowed;
|
|
82
93
|
}
|
|
83
94
|
.rounded {
|
|
84
95
|
@apply rounded-full!;
|
|
85
96
|
}
|
|
86
|
-
.disabled {
|
|
87
|
-
@apply cursor-not-allowed disabled:bg-neutral disabled:text-tertiary;
|
|
88
|
-
}
|
|
89
97
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
.size-sm {
|
|
97
|
-
@apply size-8;
|
|
98
|
-
:global(svg) {
|
|
99
|
-
@apply size-4;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
.size-md {
|
|
103
|
-
@apply size-10;
|
|
104
|
-
:global(svg) {
|
|
105
|
-
@apply size-4;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
98
|
+
/* Icon sizes per button size */
|
|
99
|
+
.size-xs :global(svg) { @apply size-4; }
|
|
100
|
+
.size-sm :global(svg) { @apply size-4; }
|
|
101
|
+
.size-md :global(svg) { @apply size-4; }
|
|
102
|
+
.size-lg :global(svg) { @apply size-5; }
|
|
108
103
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
:
|
|
112
|
-
@apply size-5;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.color-outline {
|
|
117
|
-
@apply border border-input bg-surface shadow-input hover:bg-neutral;
|
|
104
|
+
/* Gradient sheen on colored fills */
|
|
105
|
+
.color-primary, .color-danger {
|
|
106
|
+
@apply bg-origin-border bg-gradient-to-b from-white/8 to-transparent to-75% disabled:bg-none;
|
|
118
107
|
}
|
|
119
108
|
|
|
109
|
+
/* Variant styles */
|
|
120
110
|
.color-primary {
|
|
121
|
-
@apply bg-accent-inverse text-icon-primary-inverse hover:bg-accent-inverse-hover
|
|
111
|
+
@apply border-input bg-accent-inverse text-icon-primary-inverse shadow-button hover:bg-accent-inverse-hover
|
|
112
|
+
disabled:border-transparent disabled:bg-neutral disabled:text-icon-tertiary disabled:shadow-none disabled:hover:bg-neutral;
|
|
122
113
|
}
|
|
123
114
|
.color-secondary {
|
|
124
|
-
@apply bg-neutral text-icon-primary hover:bg-neutral-hover
|
|
125
|
-
|
|
126
|
-
.color-accent {
|
|
127
|
-
@apply bg-accent text-icon-primary-inverse hover:bg-accent-hover;
|
|
115
|
+
@apply bg-neutral text-icon-primary hover:bg-neutral-hover
|
|
116
|
+
disabled:border-transparent disabled:bg-neutral disabled:text-icon-tertiary disabled:hover:bg-neutral;
|
|
128
117
|
}
|
|
129
118
|
.color-transparent {
|
|
130
|
-
@apply bg-transparent text-icon-secondary hover:bg-neutral hover:text-icon-primary
|
|
119
|
+
@apply bg-transparent text-icon-secondary hover:bg-neutral hover:text-icon-primary
|
|
120
|
+
disabled:bg-transparent disabled:text-icon-tertiary disabled:hover:bg-transparent;
|
|
121
|
+
}
|
|
122
|
+
.color-outline {
|
|
123
|
+
@apply border-input bg-surface shadow-button text-icon-secondary hover:bg-neutral
|
|
124
|
+
disabled:border-static disabled:bg-transparent disabled:text-icon-tertiary disabled:shadow-none;
|
|
131
125
|
}
|
|
132
126
|
.color-danger {
|
|
133
|
-
@apply bg-danger-inverse text-icon-primary-inverse hover:bg-danger-inverse-hover
|
|
127
|
+
@apply border-input bg-danger-inverse text-icon-primary-inverse shadow-button hover:bg-danger-inverse-hover
|
|
128
|
+
disabled:border-transparent disabled:bg-neutral disabled:text-icon-tertiary disabled:shadow-none disabled:hover:bg-neutral;
|
|
134
129
|
}
|
|
135
130
|
.color-secondary-inverse {
|
|
136
|
-
@apply bg-neutral-inverse text-icon-primary-inverse hover:bg-neutral-inverse-hover
|
|
131
|
+
@apply bg-neutral-inverse text-icon-primary-inverse hover:bg-neutral-inverse-hover
|
|
132
|
+
disabled:border-transparent disabled:bg-neutral-inverse disabled:text-icon-tertiary-inverse disabled:hover:bg-neutral-inverse;
|
|
137
133
|
}
|
|
138
|
-
|
|
139
134
|
.color-transparent-inverse {
|
|
140
|
-
@apply bg-transparent text-icon-
|
|
135
|
+
@apply bg-transparent text-icon-secondary-inverse hover:bg-neutral-inverse
|
|
136
|
+
disabled:bg-transparent disabled:text-icon-tertiary-inverse disabled:hover:bg-transparent;
|
|
141
137
|
}
|
|
142
138
|
</style>
|
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
export type IconButtonVariant = 'primary' | 'secondary' | 'transparent' | 'outline' | 'danger' | 'secondary-inverse' | 'transparent-inverse';
|
|
2
|
+
export type IconButtonSize = 'xs' | 'sm' | 'md' | 'lg';
|
|
2
3
|
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
3
|
-
type
|
|
4
|
+
import type { Snippet } from 'svelte';
|
|
4
5
|
interface Props extends HTMLButtonAttributes {
|
|
5
|
-
|
|
6
|
+
class?: string;
|
|
7
|
+
onClick?: (event?: MouseEvent) => void;
|
|
6
8
|
type?: 'button' | 'submit' | 'reset' | null | undefined;
|
|
7
9
|
loading?: boolean;
|
|
8
|
-
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
accessibilityLabel?: string | undefined;
|
|
12
|
+
size?: IconButtonSize;
|
|
13
|
+
tabindex?: number | undefined;
|
|
14
|
+
variant?: IconButtonVariant;
|
|
9
15
|
children?: Snippet;
|
|
10
16
|
rounded?: boolean;
|
|
11
17
|
}
|