-
Notifications
You must be signed in to change notification settings - Fork 101
Expand file tree
/
Copy pathButton.svelte
More file actions
204 lines (175 loc) · 4.69 KB
/
Button.svelte
File metadata and controls
204 lines (175 loc) · 4.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
<script module lang="ts">
import type { HTMLButtonAttributes } from "svelte/elements";
import type { Snippet } from "svelte";
import Loader from "../Loader/Loader.svelte";
export type Brand = "" | "facebook" | "github" | "google";
export type Size = "" | "xs" | "sm" | "lg";
export type Variant = "" | "danger" | "featured" | "tonal";
export type Weight = "" | "clear";
export interface Props extends HTMLButtonAttributes {
/**
* Applies styling appropriate for the given brand
* @type {"" | "facebook" | "github" | "google"} Brand
* @name test
*/
branding?: Brand;
/**
* The size of the button
* @type {"" | "xs" | "sm" | "md"} Size
*/
size?: Size;
/**
* The weight of the button
* @type {"" | "danger" | "featured" | "tonal"}
*/
variant?: Variant;
/**
* The weight of the button
* @type {"" | "clear"}
*/
weight?: Weight;
/**
* Render the button as a link with the given href
*/
href?: string | undefined;
/**
* Boolean describing if the button is disabled
*/
disabled?: boolean;
/**
* Modifier describing if the button should include an appropriately-styled caret
*/
dropdown?: boolean;
// TODO: we could easily infer this from the presence of an icon child
/**
* Boolean describing if the button contains an icon
*/
icon?: boolean;
/**
* Modifier describing if the button should be styled as a link
*/
link?: boolean;
/**
* Modifier describing if a loading spinner should be showed
*/
loading?: boolean;
/**
* The i18n loading text
*/
i18nLoadingText?: string;
/**
* Modifier describing if the button is selected
*/
selected?: boolean;
/**
* Modifier describing if all button styles should be removed including its focus state
*/
unset?: boolean;
/**
* Additional CSS classes added to the element
*/
class?: string;
/**
* Snippet for the button content
*/
children: Snippet;
/**
* Optional badge to display on the button
*/
badge?: `${number}`;
}
</script>
<script lang="ts">
const {
branding = "",
size = "",
variant = "",
weight = "",
href = undefined,
disabled = false,
dropdown = false,
icon = false,
link = false,
loading = false,
i18nLoadingText = "Loading…",
selected = false,
unset = false,
class: className = "",
children,
badge,
...restProps
}: Props = $props();
const getClasses = (
className: string,
branding: Brand,
size: Size,
variant: Variant,
weight: Weight,
dropdown: boolean,
link: boolean,
icon: boolean,
unset: boolean,
selected: boolean
) => {
const base = "s-btn";
let classes = base;
const suffixes = [branding, size, variant, weight];
if (className) {
classes += " " + className;
}
suffixes.forEach((suffix) => {
if (suffix) {
classes += ` ${base}__${suffix}`;
}
});
if (dropdown) {
classes += ` ${base}__dropdown`;
}
if (link) {
classes += ` ${base}__link`;
}
if (icon) {
classes += ` ${base}__icon`;
}
if (unset) {
classes += ` ${base}__unset`;
}
if (selected) {
classes += ` is-selected`;
}
return classes;
};
const classes = $derived(
getClasses(
className,
branding,
size,
variant,
weight,
dropdown,
link,
icon,
unset,
selected
)
);
</script>
<svelte:element
this={href ? "a" : "button"}
{href}
class={classes}
disabled={(!href && disabled) || null}
aria-disabled={href && disabled ? "true" : null}
{...restProps}
>{#if loading}<Loader
size="sm"
label={i18nLoadingText}
/>{/if}{#if !badge}{@render children()}{:else}
{@render children()}
<span class="s-btn--badge">
<span class="s-btn--number">
{badge}
</span>
</span>
{/if}
</svelte:element>