bref-ui 0.0.2 → 0.0.4
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/base/button/button.svelte +332 -0
- package/dist/base/button/button.svelte.d.ts +6 -0
- package/dist/base/button/icon-button.svelte +316 -0
- package/dist/base/button/icon-button.svelte.d.ts +6 -0
- package/dist/base/button/index.d.ts +2 -0
- package/dist/base/button/index.js +2 -0
- package/dist/base/button/types.d.ts +17 -0
- package/dist/base/button/types.js +1 -0
- package/dist/base/icon/icon.svelte +46 -7
- package/dist/base/icon/types.d.ts +2 -0
- package/dist/base/theme/color-tokens.d.ts +13 -15
- package/dist/base/theme/color-tokens.js +47 -90
- package/dist/base/theme/theme.svelte +23 -132
- package/dist/base/theme/types.d.ts +1 -4
- package/dist/internal/demo-button.svelte +80 -0
- package/dist/internal/demo-button.svelte.d.ts +18 -0
- package/dist/internal/demo-icon-button.svelte +76 -0
- package/dist/internal/demo-icon-button.svelte.d.ts +18 -0
- package/dist/internal/demo-theming.svelte +257 -0
- package/dist/internal/demo-theming.svelte.d.ts +3 -0
- package/package.json +4 -4
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import IconButton from '../base/button/icon-button.svelte';
|
|
3
|
+
import DemoSection from './demo-section.svelte';
|
|
4
|
+
import DemoCodeSnippet from './demo-code-snippet.svelte';
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<DemoSection
|
|
8
|
+
title="Icon Buttons"
|
|
9
|
+
id="buttons"
|
|
10
|
+
description="Icon buttons with customizable size, color, variant, and shape."
|
|
11
|
+
>
|
|
12
|
+
<h3>Variants</h3>
|
|
13
|
+
<div>
|
|
14
|
+
<IconButton name="add" variant="filled" onClick={() => {}} />
|
|
15
|
+
<IconButton name="add" variant="soft" onClick={() => {}} />
|
|
16
|
+
<IconButton name="add" variant="ghost" onClick={() => {}} />
|
|
17
|
+
</div>
|
|
18
|
+
<h3>Colors</h3>
|
|
19
|
+
<div>
|
|
20
|
+
<IconButton name="favorite" color="primary" onClick={() => {}} />
|
|
21
|
+
<IconButton name="favorite" color="secondary" onClick={() => {}} />
|
|
22
|
+
<IconButton name="favorite" color="success" onClick={() => {}} />
|
|
23
|
+
<IconButton name="favorite" color="warning" onClick={() => {}} />
|
|
24
|
+
<IconButton name="favorite" color="danger" onClick={() => {}} />
|
|
25
|
+
<IconButton name="favorite" color="info" onClick={() => {}} />
|
|
26
|
+
<IconButton name="favorite" color="foreground" onClick={() => {}} />
|
|
27
|
+
<IconButton name="favorite" color="background" onClick={() => {}} />
|
|
28
|
+
</div>
|
|
29
|
+
<h3>Sizes</h3>
|
|
30
|
+
<div>
|
|
31
|
+
<IconButton name="settings" size="x-small" onClick={() => {}} />
|
|
32
|
+
<IconButton name="settings" size="small" onClick={() => {}} />
|
|
33
|
+
<IconButton name="settings" size="medium" onClick={() => {}} />
|
|
34
|
+
<IconButton name="settings" size="large" onClick={() => {}} />
|
|
35
|
+
<IconButton name="settings" size="x-large" onClick={() => {}} />
|
|
36
|
+
</div>
|
|
37
|
+
<h3>Rounded</h3>
|
|
38
|
+
<div>
|
|
39
|
+
<IconButton name="close" rounded onClick={() => {}} />
|
|
40
|
+
<IconButton name="close" rounded variant="soft" onClick={() => {}} />
|
|
41
|
+
<IconButton name="close" rounded variant="ghost" onClick={() => {}} />
|
|
42
|
+
</div>
|
|
43
|
+
<h3>Filled Icons</h3>
|
|
44
|
+
<div>
|
|
45
|
+
<IconButton name="star" filled onClick={() => {}} />
|
|
46
|
+
<IconButton name="star" filled variant="soft" color="warning" onClick={() => {}} />
|
|
47
|
+
<IconButton name="star" filled variant="ghost" color="warning" onClick={() => {}} />
|
|
48
|
+
</div>
|
|
49
|
+
<h3>Disabled</h3>
|
|
50
|
+
<div>
|
|
51
|
+
<IconButton name="edit" disabled onClick={() => {}} />
|
|
52
|
+
<IconButton name="edit" disabled variant="soft" onClick={() => {}} />
|
|
53
|
+
<IconButton name="edit" disabled variant="ghost" onClick={() => {}} />
|
|
54
|
+
</div>
|
|
55
|
+
<h3>Usage Example</h3>
|
|
56
|
+
<DemoCodeSnippet
|
|
57
|
+
snippet={`<IconButton
|
|
58
|
+
name="favorite"
|
|
59
|
+
filled={true}
|
|
60
|
+
color="danger"
|
|
61
|
+
variant="soft"
|
|
62
|
+
size="large"
|
|
63
|
+
rounded
|
|
64
|
+
onClick={() => handleClick()}
|
|
65
|
+
/>`}
|
|
66
|
+
/>
|
|
67
|
+
</DemoSection>
|
|
68
|
+
|
|
69
|
+
<style>
|
|
70
|
+
div {
|
|
71
|
+
display: flex;
|
|
72
|
+
gap: 1rem;
|
|
73
|
+
align-items: center;
|
|
74
|
+
justify-content: center;
|
|
75
|
+
}
|
|
76
|
+
</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
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> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const DemoIconButton: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type DemoIconButton = InstanceType<typeof DemoIconButton>;
|
|
18
|
+
export default DemoIconButton;
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
initializeThemeMode,
|
|
4
|
+
toggleThemeMode,
|
|
5
|
+
DEFAULT_THEME,
|
|
6
|
+
type ThemeMode
|
|
7
|
+
} from '../base/theme/index.js';
|
|
8
|
+
import Button from '../base/button/button.svelte';
|
|
9
|
+
import DemoSection from './demo-section.svelte';
|
|
10
|
+
import DemoCodeSnippet from './demo-code-snippet.svelte';
|
|
11
|
+
import { untrack } from 'svelte';
|
|
12
|
+
|
|
13
|
+
let themeMode: ThemeMode = $state('light');
|
|
14
|
+
|
|
15
|
+
$effect.pre(() => {
|
|
16
|
+
untrack(() => {
|
|
17
|
+
themeMode = initializeThemeMode();
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const onThemeToggle = () => {
|
|
22
|
+
const newMode = themeMode === 'dark' ? 'light' : 'dark';
|
|
23
|
+
toggleThemeMode(newMode);
|
|
24
|
+
themeMode = newMode;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const paletteColors = Object.entries(DEFAULT_THEME.paletteHex) as [string, string][];
|
|
28
|
+
const surfaceColors = ['background', 'foreground'] as const;
|
|
29
|
+
|
|
30
|
+
const usageSnippet = `<script lang="ts">
|
|
31
|
+
import { Theme } from 'bref/base/theme';
|
|
32
|
+
<\/script>
|
|
33
|
+
|
|
34
|
+
<!-- Use default theme -->
|
|
35
|
+
<Theme />
|
|
36
|
+
|
|
37
|
+
<!-- Or customize with your own colors -->
|
|
38
|
+
<Theme
|
|
39
|
+
paletteHex={{
|
|
40
|
+
primary: '#6366f1',
|
|
41
|
+
secondary: '#ec4899',
|
|
42
|
+
success: '#22c55e',
|
|
43
|
+
warning: '#f59e0b',
|
|
44
|
+
danger: '#ef4444',
|
|
45
|
+
info: '#3b82f6'
|
|
46
|
+
}}
|
|
47
|
+
surfaceHex={{
|
|
48
|
+
background: '#f8fafc',
|
|
49
|
+
foreground: '#1e293b'
|
|
50
|
+
}}
|
|
51
|
+
border={{ widthPx: 1, radiusRem: 0.5, colorHex: '#e2e8f0' }}
|
|
52
|
+
spacingRem={1}
|
|
53
|
+
/>`;
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
{#snippet colorCard(name: string, isSurface: boolean = false)}
|
|
57
|
+
<div class="color-card">
|
|
58
|
+
<div class="color-header">{name}</div>
|
|
59
|
+
<div class="color-variants">
|
|
60
|
+
{#each ['base', 'soft', 'saturated', 'contrast'] as variant}
|
|
61
|
+
{@const cssVar = variant === 'base' ? `--color-${name}` : `--color-${name}-${variant}`}
|
|
62
|
+
{@const contrastVar =
|
|
63
|
+
variant === 'contrast' ? `--color-${name}` : `--color-${name}-contrast`}
|
|
64
|
+
<div class="color-swatch" style="background: var({cssVar}); color: var({contrastVar})">
|
|
65
|
+
<span class="swatch-label">{variant}</span>
|
|
66
|
+
</div>
|
|
67
|
+
{/each}
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
{/snippet}
|
|
71
|
+
|
|
72
|
+
<DemoSection title="Theming" id="theming">
|
|
73
|
+
<p class="intro">
|
|
74
|
+
The theme system provides a flexible, token-based approach to styling with automatic light/dark
|
|
75
|
+
mode support.
|
|
76
|
+
</p>
|
|
77
|
+
|
|
78
|
+
<!-- Theme Mode Toggle -->
|
|
79
|
+
|
|
80
|
+
<h3>Theme Mode</h3>
|
|
81
|
+
<p class="description">
|
|
82
|
+
Toggle between light and dark modes. The system respects <code>prefers-color-scheme</code> by default
|
|
83
|
+
and persists your choice in localStorage.
|
|
84
|
+
</p>
|
|
85
|
+
<Button
|
|
86
|
+
icon={{ name: themeMode === 'dark' ? 'light_mode' : 'dark_mode' }}
|
|
87
|
+
label="Toggle to {themeMode === 'dark' ? 'light' : 'dark'}"
|
|
88
|
+
onClick={onThemeToggle}
|
|
89
|
+
/>
|
|
90
|
+
|
|
91
|
+
<!-- Palette Colors -->
|
|
92
|
+
|
|
93
|
+
<h3>Palette Colors</h3>
|
|
94
|
+
<p class="description">
|
|
95
|
+
Semantic colors that remain consistent across light and dark modes. Each color generates three
|
|
96
|
+
variants: <strong>soft</strong>, <strong>saturated</strong>, and
|
|
97
|
+
<strong>contrast</strong>.
|
|
98
|
+
</p>
|
|
99
|
+
<div class="color-grid">
|
|
100
|
+
{#each paletteColors as [name]}
|
|
101
|
+
{@render colorCard(name)}
|
|
102
|
+
{/each}
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<!-- Surface Colors -->
|
|
106
|
+
|
|
107
|
+
<h3>Surface Colors</h3>
|
|
108
|
+
<p class="description">
|
|
109
|
+
Background and foreground colors that automatically swap between light and dark modes. These
|
|
110
|
+
define the base canvas and text colors.
|
|
111
|
+
</p>
|
|
112
|
+
<div class="color-grid surface-grid">
|
|
113
|
+
{#each surfaceColors as name}
|
|
114
|
+
{@render colorCard(name, true)}
|
|
115
|
+
{/each}
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<!-- Token Generation Logic -->
|
|
119
|
+
|
|
120
|
+
<h3>Token Generation Logic</h3>
|
|
121
|
+
<ul class="bullet-list">
|
|
122
|
+
<li>
|
|
123
|
+
<strong>Soft:</strong> <code>lighten(25%) + desaturate(10%)</code> — A lighter, muted variant ideal
|
|
124
|
+
for backgrounds when using the base as foreground.
|
|
125
|
+
</li>
|
|
126
|
+
<li>
|
|
127
|
+
<strong>Saturated:</strong> <code>darken(15%) + saturate(10%)</code> — A deeper, more intense shade
|
|
128
|
+
for emphasis or active states.
|
|
129
|
+
</li>
|
|
130
|
+
<li>
|
|
131
|
+
<strong>Contrast:</strong> <code>isDark() ? white : black</code> — Automatically picks black or
|
|
132
|
+
white for text/icons ensuring WCAG compliance.
|
|
133
|
+
</li>
|
|
134
|
+
</ul>
|
|
135
|
+
|
|
136
|
+
<!-- Architecture Overview -->
|
|
137
|
+
|
|
138
|
+
<h3>Architecture</h3>
|
|
139
|
+
<ul class="bullet-list">
|
|
140
|
+
<li>
|
|
141
|
+
All tokens are exposed as <code>--color-*</code> custom properties on <code>:root</code>.
|
|
142
|
+
</li>
|
|
143
|
+
<li>
|
|
144
|
+
Surface colors use <code>data-theme</code> attribute with automatic fallback to
|
|
145
|
+
<code>prefers-color-scheme</code>.
|
|
146
|
+
</li>
|
|
147
|
+
<li>User preference is persisted in <code>localStorage</code>.</li>
|
|
148
|
+
<li>
|
|
149
|
+
Hover states are delegated to components using <code>color-mix()</code> for context-aware derivation.
|
|
150
|
+
</li>
|
|
151
|
+
</ul>
|
|
152
|
+
|
|
153
|
+
<!-- Usage -->
|
|
154
|
+
|
|
155
|
+
<h3>Usage</h3>
|
|
156
|
+
<p class="description">
|
|
157
|
+
Add the Theme component at the root of your app. It generates CSS custom properties and handles
|
|
158
|
+
light/dark mode switching.
|
|
159
|
+
</p>
|
|
160
|
+
<DemoCodeSnippet snippet={usageSnippet} />
|
|
161
|
+
</DemoSection>
|
|
162
|
+
|
|
163
|
+
<style>
|
|
164
|
+
.intro {
|
|
165
|
+
text-align: center;
|
|
166
|
+
font-size: 1.1rem;
|
|
167
|
+
max-width: 40rem;
|
|
168
|
+
opacity: 0.8;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
h3 {
|
|
172
|
+
font-size: 1.4rem;
|
|
173
|
+
margin-top: 1.5rem;
|
|
174
|
+
margin-bottom: 0.5rem;
|
|
175
|
+
width: 100%;
|
|
176
|
+
text-align: center;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.description {
|
|
180
|
+
text-align: center;
|
|
181
|
+
max-width: 36rem;
|
|
182
|
+
opacity: 0.7;
|
|
183
|
+
font-size: 0.95rem;
|
|
184
|
+
margin-bottom: 1rem;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
code {
|
|
188
|
+
background: color-mix(in srgb, var(--color-foreground) 10%, transparent);
|
|
189
|
+
padding: 0.15rem 0.4rem;
|
|
190
|
+
border-radius: 0.25rem;
|
|
191
|
+
font-size: 0.85em;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/* Color Grid */
|
|
195
|
+
.color-grid {
|
|
196
|
+
display: grid;
|
|
197
|
+
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
|
198
|
+
gap: 1rem;
|
|
199
|
+
width: 100%;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.surface-grid {
|
|
203
|
+
max-width: 320px;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.color-card {
|
|
207
|
+
display: flex;
|
|
208
|
+
flex-direction: column;
|
|
209
|
+
border-radius: 0.75rem;
|
|
210
|
+
overflow: hidden;
|
|
211
|
+
border: 1px solid color-mix(in srgb, var(--color-foreground) 10%, transparent);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.color-header {
|
|
215
|
+
padding: 0.5rem;
|
|
216
|
+
text-align: center;
|
|
217
|
+
font-weight: 600;
|
|
218
|
+
text-transform: capitalize;
|
|
219
|
+
background: color-mix(in srgb, var(--color-foreground) 5%, transparent);
|
|
220
|
+
font-size: 0.85rem;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.color-variants {
|
|
224
|
+
display: flex;
|
|
225
|
+
flex-direction: column;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.color-swatch {
|
|
229
|
+
display: flex;
|
|
230
|
+
justify-content: space-between;
|
|
231
|
+
align-items: center;
|
|
232
|
+
padding: 0.6rem 0.75rem;
|
|
233
|
+
font-size: 0.75rem;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.swatch-label {
|
|
237
|
+
font-weight: 500;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/* Bullet Lists */
|
|
241
|
+
.bullet-list {
|
|
242
|
+
list-style: disc;
|
|
243
|
+
padding-left: 1.5rem;
|
|
244
|
+
max-width: 40rem;
|
|
245
|
+
text-align: left;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.bullet-list li {
|
|
249
|
+
margin-bottom: 0.5rem;
|
|
250
|
+
font-size: 0.9rem;
|
|
251
|
+
line-height: 1.5;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.bullet-list li:last-child {
|
|
255
|
+
margin-bottom: 0;
|
|
256
|
+
}
|
|
257
|
+
</style>
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bref-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "A truly Svelte-esque UI component library - minimal, flexible, pure CSS, no Tailwind",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "feuerstein",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/
|
|
9
|
+
"url": "git+https://github.com/feuersteiner/bref.git"
|
|
10
10
|
},
|
|
11
|
-
"homepage": "https://github.com/
|
|
11
|
+
"homepage": "https://github.com/feuersteiner/bref#readme",
|
|
12
12
|
"bugs": {
|
|
13
|
-
"url": "https://github.com/
|
|
13
|
+
"url": "https://github.com/feuersteiner/bref/issues"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
16
|
"dev": "vite dev",
|