seblify 0.1.7 → 0.1.8

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sebastian Andresen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,8 +1,17 @@
1
+ [![license](https://img.shields.io/npm/l/seblify.svg)](https://www.npmjs.com/package/seblify)
2
+ [![npm downloads](https://img.shields.io/npm/dm/seblify.svg)](https://www.npmjs.com/package/seblify)
3
+
4
+ [![docs](https://img.shields.io/badge/docs-seblify.com-black.svg)](https://seblify.com)
5
+
1
6
  # Seblify
2
7
 
3
- > First package publish test
8
+ [comment]: <> (==== ========================= ====)
9
+ [comment]: <> (=== AUTOGENERATED - DO NOT EDIT ===)
10
+ [comment]: <> (==== ========================= ====)
11
+ [comment]: <> (= edit scripts/readme/template.md =)
12
+ [comment]: <> (==== ========================= ====)
4
13
 
5
- Svelte component library for Seblify.
14
+ Svelte UI component library for building themed interfaces.
6
15
 
7
16
  ## Installation
8
17
 
@@ -16,3 +25,210 @@ npm install seblify
16
25
  import { Button, Badge } from 'seblify';
17
26
  import 'seblify/theme.css';
18
27
  ```
28
+
29
+ ## Components
30
+
31
+ [![components-stable](https://img.shields.io/badge/stable-0%20components-brightgreen.svg)](https://seblify.com/components)
32
+ [![components-beta](https://img.shields.io/badge/beta-0%20components-yellow.svg)](https://seblify.com/components)
33
+ [![components-draft](https://img.shields.io/badge/draft-24%20components-lightgrey.svg)](https://seblify.com/components)
34
+
35
+ Explore the supported components in this library. Components are grouped by purpose and linked to their full documentation, including usage examples, props, accessibility notes, and design-system guidance.
36
+
37
+ ### Quick links
38
+
39
+ - [Input Components](https://seblify.com/sections/action)
40
+ - [Display Components](https://seblify.com/sections/display)
41
+ - [Framework Components](https://seblify.com/sections/framework)
42
+ - [Design System](https://seblify.com/design-system)
43
+
44
+ ---
45
+
46
+ ## Input Components <small>&middot; 6 items</small>
47
+
48
+ Components that let users make choices, submit data, and trigger behavior.
49
+
50
+ <details>
51
+ <summary><strong>Input Fields</strong></summary>
52
+
53
+ Text-like controls for entering structured user input.
54
+
55
+ | Component | Summary | Status |
56
+ | --- | --- | --- |
57
+ | [Pin&nbsp;Input](https://seblify.com/components/pin-input) | A segmented numeric input for short verification codes. | &#x26AA;&nbsp;Draft |
58
+
59
+
60
+ ---
61
+ </details>
62
+
63
+ <br />
64
+
65
+ <details>
66
+ <summary><strong>Selectable</strong></summary>
67
+
68
+ Controls for selecting boolean, range, or option-based values.
69
+
70
+ | Component | Summary | Status |
71
+ | --- | --- | --- |
72
+ | [Checkbox](https://seblify.com/components/checkbox) | A boolean selection control for one option in a form or settings flow. | &#x26AA;&nbsp;Draft |
73
+ | [SegmentControl](https://seblify.com/components/segment-control) | A compact single-selection control for switching between a small set of options. | &#x26AA;&nbsp;Draft |
74
+ | [Slider](https://seblify.com/components/slider) | A range input for choosing an approximate numeric value. | &#x26AA;&nbsp;Draft |
75
+ | [Switch](https://seblify.com/components/switch) | A two-state control for immediately turning a setting on or off. | &#x26AA;&nbsp;Draft |
76
+ | [ThemeSwitch](https://seblify.com/components/theme-switch) | A segmented control for selecting system, light, or dark color mode. | &#x26AA;&nbsp;Draft |
77
+
78
+
79
+ ---
80
+ </details>
81
+
82
+ ## Display Components <small>&middot; 8 items</small>
83
+
84
+ Components for showing content, feedback, media, and motion.
85
+
86
+ <details>
87
+ <summary><strong>Annotation</strong></summary>
88
+
89
+ Small attached indicators, labels, and supporting markers.
90
+
91
+ | Component | Summary | Status |
92
+ | --- | --- | --- |
93
+ | [Badge](https://seblify.com/components/badge) | A small attached indicator for counts, labels, and presence states around another item. | &#x26AA;&nbsp;Draft |
94
+ | [Tag](https://seblify.com/components/tag) | A compact text marker for statuses, categories, and item labels. | &#x26AA;&nbsp;Draft |
95
+ | [TagGroup](https://seblify.com/components/tag-group) | A wrapping inline group for tags with the standard tag spacing. | &#x26AA;&nbsp;Draft |
96
+
97
+
98
+ ---
99
+ </details>
100
+
101
+ <br />
102
+
103
+ <details>
104
+ <summary><strong>Loading</strong></summary>
105
+
106
+ Progress indicators and waiting states.
107
+
108
+ | Component | Summary | Status |
109
+ | --- | --- | --- |
110
+ | [Loading&nbsp;Dots](https://seblify.com/components/loading-dots) | A compact animated loading indicator for inline waiting states. | &#x26AA;&nbsp;Draft |
111
+ | [Spinner](https://seblify.com/components/spinner) | A circular loading indicator for indeterminate progress. | &#x26AA;&nbsp;Draft |
112
+
113
+
114
+ ---
115
+ </details>
116
+
117
+ <br />
118
+
119
+ <details>
120
+ <summary><strong>Typography</strong></summary>
121
+
122
+ Text primitives and typographic treatments for readable interfaces.
123
+
124
+ | Component | Summary | Status |
125
+ | --- | --- | --- |
126
+ | [Eyebrow](https://seblify.com/components/eyebrow) | A short contextual label that sits above a heading or dense content block. | &#x26AA;&nbsp;Draft |
127
+ | [Highlight](https://seblify.com/components/highlight) | Highlights case-insensitive text matches inside a plain text string. | &#x26AA;&nbsp;Draft |
128
+
129
+
130
+ ---
131
+ </details>
132
+
133
+ <br />
134
+
135
+ <details>
136
+ <summary><strong>Media</strong></summary>
137
+
138
+ Icons, images, video, and other visual media components.
139
+
140
+ | Component | Summary | Status |
141
+ | --- | --- | --- |
142
+ | [Icon](https://seblify.com/components/icon) | A convenient registry-based icon component for Seblify SVG icons. | &#x26AA;&nbsp;Draft |
143
+
144
+
145
+ ---
146
+ </details>
147
+
148
+ ## Framework Components <small>&middot; 10 items</small>
149
+
150
+ Layout, navigation, overlays, and surface primitives.
151
+
152
+ <details>
153
+ <summary><strong>Align</strong></summary>
154
+
155
+ Small layout primitives for spacing and aligning content.
156
+
157
+ | Component | Summary | Status |
158
+ | --- | --- | --- |
159
+ | [Cluster](https://seblify.com/components/cluster) | A wrapping horizontal layout primitive that spaces items with a configurable gap. | &#x26AA;&nbsp;Draft |
160
+ | [Grid](https://seblify.com/components/grid) | A responsive grid layout primitive with automatic columns or an explicit column count. | &#x26AA;&nbsp;Draft |
161
+ | [Row](https://seblify.com/components/row) | A horizontal layout primitive that spaces items with a configurable gap. | &#x26AA;&nbsp;Draft |
162
+ | [Stack](https://seblify.com/components/stack) | A vertical layout primitive that spaces items with a configurable gap. | &#x26AA;&nbsp;Draft |
163
+
164
+
165
+ ---
166
+ </details>
167
+
168
+ <br />
169
+
170
+ <details>
171
+ <summary><strong>Container</strong></summary>
172
+
173
+ Page and region containers that define app structure.
174
+
175
+ | Component | Summary | Status |
176
+ | --- | --- | --- |
177
+ | [AppShell](https://seblify.com/components/app-shell) | A full-page application frame with sidebar, header, and content regions. | &#x26AA;&nbsp;Draft |
178
+ | [PageHeader](https://seblify.com/components/page-header) | A page-level heading block with optional breadcrumb, eyebrow, summary, and actions. | &#x26AA;&nbsp;Draft |
179
+ | [Sidebar](https://seblify.com/components/sidebar) | A responsive side container for persistent or overlay navigation. | &#x26AA;&nbsp;Draft |
180
+
181
+
182
+ ---
183
+ </details>
184
+
185
+ <br />
186
+
187
+ <details>
188
+ <summary><strong>Navigation</strong></summary>
189
+
190
+ Components that help users understand location and move around.
191
+
192
+ | Component | Summary | Status |
193
+ | --- | --- | --- |
194
+ | [Breadcrumb](https://seblify.com/components/breadcrumb) | A contextual navigation trail for showing page hierarchy. | &#x26AA;&nbsp;Draft |
195
+ | [Sidenav](https://seblify.com/components/sidenav) | A hierarchical side navigation for sections, links, and nested pages. | &#x26AA;&nbsp;Draft |
196
+
197
+
198
+ ---
199
+ </details>
200
+
201
+ <br />
202
+
203
+ <details>
204
+ <summary><strong>Surface</strong></summary>
205
+
206
+ Framing primitives for cards, papers, tiles, and other contained regions.
207
+
208
+ | Component | Summary | Status |
209
+ | --- | --- | --- |
210
+ | [Paper](https://seblify.com/components/paper) | A themed container for grouping content with configurable variant, tone, padding, border, and elevation. | &#x26AA;&nbsp;Draft |
211
+
212
+
213
+ ---
214
+ </details>
215
+
216
+ ## Design System
217
+
218
+ Theme, tokens, and styling guidance for Seblify.
219
+
220
+ | Guide | Summary |
221
+ | --- | --- |
222
+ | [Component&nbsp;API](https://seblify.com/design-system/component-api) | Shared prop naming rules for variants, tones, size, slots, radius, placement, and contextual inheritance. |
223
+ | [Icons](https://seblify.com/design-system/icons) | Browse all generated Seblify icons, grouped automatically from the SVG source folders. |
224
+ | [Theme](https://seblify.com/design-system/theme) | Seblify themes use CSS variables for light, dark, system, and custom color modes. |
225
+
226
+ ## Release Notes <small>&middot; 0.1.8</small>
227
+
228
+ _May 14 2026_ &middot; _1 item updated_
229
+
230
+ Recent changes are summarized below. For the full release history, see the [changelog](https://seblify.com/release-notes).
231
+
232
+ ### [other](https://seblify.com/components/other)
233
+
234
+ - Temporary task note for release note workflow
@@ -1,136 +1,136 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte';
3
-
4
- interface Props {
5
- banners?: Snippet;
6
- children?: Snippet;
7
- drawer?: Snippet;
8
- snackbars?: Snippet;
9
- sidebar?: Snippet;
10
- toasts?: Snippet;
11
- sidebarWidth?: string;
12
- }
13
-
14
- let {
15
- banners,
16
- children,
17
- drawer,
18
- snackbars,
19
- sidebar,
20
- toasts,
21
- sidebarWidth = '280px',
22
- }: Props = $props();
23
- </script>
24
-
25
- <div class="app-shell" style:--sidebar-width={sidebarWidth}>
26
- {#if banners}
27
- <div class="banner-stack" aria-label="Page alerts">
28
- {@render banners()}
29
- </div>
30
- {/if}
31
-
32
- <div class="app-body">
33
- {#if sidebar}
34
- <aside class="sidebar">
35
- {@render sidebar()}
36
- </aside>
37
- {/if}
38
-
39
- <main class="main-content" tabindex="-1">
40
- {@render children?.()}
41
- </main>
42
- </div>
43
-
44
- {#if toasts}
45
- <div class="toast-region" aria-live="polite" aria-label="Confirmations">
46
- {@render toasts()}
47
- </div>
48
- {/if}
49
-
50
- {#if snackbars}
51
- <div class="snackbar-region" aria-live="polite" aria-label="Notifications">
52
- {@render snackbars()}
53
- </div>
54
- {/if}
55
-
56
- {#if drawer}
57
- <div class="drawer-layer">
58
- {@render drawer()}
59
- </div>
60
- {/if}
61
- </div>
62
-
63
- <style>
64
- .app-shell {
65
- display: flex;
66
- flex-direction: column;
67
- min-height: 100vh;
68
- background: var(--app-shell-background, var(--seblify-color-page, #f4f6f8));
69
- color: var(--app-shell-color, var(--seblify-color-text, #172033));
70
- }
71
-
72
- .banner-stack {
73
- position: relative;
74
- z-index: 100;
75
- display: grid;
76
- width: 100%;
77
- }
78
-
79
- .app-body {
80
- flex: 1;
81
- display: grid;
82
- grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
83
- min-height: 0;
84
- }
85
-
86
- .sidebar {
87
- min-width: 0;
88
- background: transparent;
89
- }
90
-
91
- .main-content {
92
- min-width: 0;
93
- }
94
-
95
- .toast-region {
96
- position: fixed;
97
- top: 16px;
98
- left: 50%;
99
- z-index: 650;
100
- display: grid;
101
- gap: 8px;
102
- width: min(420px, calc(100vw - 32px));
103
- transform: translateX(-50%);
104
- }
105
-
106
- .snackbar-region {
107
- position: fixed;
108
- right: 16px;
109
- bottom: 16px;
110
- z-index: 700;
111
- display: grid;
112
- gap: 8px;
113
- width: min(360px, calc(100vw - 32px));
114
- }
115
-
116
- .drawer-layer {
117
- position: fixed;
118
- inset: 0;
119
- z-index: 1000;
120
- pointer-events: none;
121
- }
122
-
123
- .drawer-layer :global(*) {
124
- pointer-events: auto;
125
- }
126
-
127
- @media (max-width: 760px) {
128
- .app-body {
129
- grid-template-columns: 1fr;
130
- }
131
-
132
- .sidebar {
133
- border-bottom: 0;
134
- }
135
- }
136
- </style>
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ banners?: Snippet;
6
+ children?: Snippet;
7
+ drawer?: Snippet;
8
+ snackbars?: Snippet;
9
+ sidebar?: Snippet;
10
+ toasts?: Snippet;
11
+ sidebarWidth?: string;
12
+ }
13
+
14
+ let {
15
+ banners,
16
+ children,
17
+ drawer,
18
+ snackbars,
19
+ sidebar,
20
+ toasts,
21
+ sidebarWidth = '280px',
22
+ }: Props = $props();
23
+ </script>
24
+
25
+ <div class="app-shell" style:--sidebar-width={sidebarWidth}>
26
+ {#if banners}
27
+ <div class="banner-stack" aria-label="Page alerts">
28
+ {@render banners()}
29
+ </div>
30
+ {/if}
31
+
32
+ <div class="app-body">
33
+ {#if sidebar}
34
+ <aside class="sidebar">
35
+ {@render sidebar()}
36
+ </aside>
37
+ {/if}
38
+
39
+ <main class="main-content" tabindex="-1">
40
+ {@render children?.()}
41
+ </main>
42
+ </div>
43
+
44
+ {#if toasts}
45
+ <div class="toast-region" aria-live="polite" aria-label="Confirmations">
46
+ {@render toasts()}
47
+ </div>
48
+ {/if}
49
+
50
+ {#if snackbars}
51
+ <div class="snackbar-region" aria-live="polite" aria-label="Notifications">
52
+ {@render snackbars()}
53
+ </div>
54
+ {/if}
55
+
56
+ {#if drawer}
57
+ <div class="drawer-layer">
58
+ {@render drawer()}
59
+ </div>
60
+ {/if}
61
+ </div>
62
+
63
+ <style>
64
+ .app-shell {
65
+ display: flex;
66
+ flex-direction: column;
67
+ min-height: 100vh;
68
+ background: var(--app-shell-background, var(--seblify-color-page, #f4f6f8));
69
+ color: var(--app-shell-color, var(--seblify-color-text, #172033));
70
+ }
71
+
72
+ .banner-stack {
73
+ position: relative;
74
+ z-index: 100;
75
+ display: grid;
76
+ width: 100%;
77
+ }
78
+
79
+ .app-body {
80
+ flex: 1;
81
+ display: grid;
82
+ grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
83
+ min-height: 0;
84
+ }
85
+
86
+ .sidebar {
87
+ min-width: 0;
88
+ background: transparent;
89
+ }
90
+
91
+ .main-content {
92
+ min-width: 0;
93
+ }
94
+
95
+ .toast-region {
96
+ position: fixed;
97
+ top: 16px;
98
+ left: 50%;
99
+ z-index: 650;
100
+ display: grid;
101
+ gap: 8px;
102
+ width: min(420px, calc(100vw - 32px));
103
+ transform: translateX(-50%);
104
+ }
105
+
106
+ .snackbar-region {
107
+ position: fixed;
108
+ right: 16px;
109
+ bottom: 16px;
110
+ z-index: 700;
111
+ display: grid;
112
+ gap: 8px;
113
+ width: min(360px, calc(100vw - 32px));
114
+ }
115
+
116
+ .drawer-layer {
117
+ position: fixed;
118
+ inset: 0;
119
+ z-index: 1000;
120
+ pointer-events: none;
121
+ }
122
+
123
+ .drawer-layer :global(*) {
124
+ pointer-events: auto;
125
+ }
126
+
127
+ @media (max-width: 760px) {
128
+ .app-body {
129
+ grid-template-columns: 1fr;
130
+ }
131
+
132
+ .sidebar {
133
+ border-bottom: 0;
134
+ }
135
+ }
136
+ </style>
@@ -1,56 +1,56 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte';
3
-
4
- type BannerTone = 'info' | 'success' | 'warning' | 'error';
5
-
6
- interface Props {
7
- children?: Snippet;
8
- tone?: BannerTone;
9
- }
10
-
11
- let { children, tone = 'info' }: Props = $props();
12
- </script>
13
-
14
- <section
15
- class="banner"
16
- class:success={tone === 'success'}
17
- class:warning={tone === 'warning'}
18
- class:error={tone === 'error'}
19
- >
20
- <div class="content">
21
- {@render children?.()}
22
- </div>
23
- </section>
24
-
25
- <style>
26
- .banner {
27
- width: 100%;
28
- border-bottom: 1px solid var(--seblify-color-info-border, #bfd1ea);
29
- background: var(--seblify-color-info-surface, #eaf3ff);
30
- color: var(--seblify-color-info-text, #102f55);
31
- }
32
-
33
- .content {
34
- padding: 10px 16px;
35
- font-size: 14px;
36
- line-height: 1.4;
37
- }
38
-
39
- .success {
40
- border-bottom-color: var(--seblify-color-success-border, #b8ddc7);
41
- background: var(--seblify-color-success-surface, #e8f8ee);
42
- color: var(--seblify-color-success-text, #143d25);
43
- }
44
-
45
- .warning {
46
- border-bottom-color: var(--seblify-color-warning-border, #e8d28f);
47
- background: var(--seblify-color-warning-surface, #fff6d8);
48
- color: var(--seblify-color-warning-text, #4d3900);
49
- }
50
-
51
- .error {
52
- border-bottom-color: var(--seblify-color-error-border, #efb6b6);
53
- background: var(--seblify-color-error-surface, #fff0f0);
54
- color: var(--seblify-color-error-text, #5a1717);
55
- }
56
- </style>
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ type BannerTone = 'info' | 'success' | 'warning' | 'error';
5
+
6
+ interface Props {
7
+ children?: Snippet;
8
+ tone?: BannerTone;
9
+ }
10
+
11
+ let { children, tone = 'info' }: Props = $props();
12
+ </script>
13
+
14
+ <section
15
+ class="banner"
16
+ class:success={tone === 'success'}
17
+ class:warning={tone === 'warning'}
18
+ class:error={tone === 'error'}
19
+ >
20
+ <div class="content">
21
+ {@render children?.()}
22
+ </div>
23
+ </section>
24
+
25
+ <style>
26
+ .banner {
27
+ width: 100%;
28
+ border-bottom: 1px solid var(--seblify-color-info-border, #bfd1ea);
29
+ background: var(--seblify-color-info-surface, #eaf3ff);
30
+ color: var(--seblify-color-info-text, #102f55);
31
+ }
32
+
33
+ .content {
34
+ padding: 10px 16px;
35
+ font-size: 14px;
36
+ line-height: 1.4;
37
+ }
38
+
39
+ .success {
40
+ border-bottom-color: var(--seblify-color-success-border, #b8ddc7);
41
+ background: var(--seblify-color-success-surface, #e8f8ee);
42
+ color: var(--seblify-color-success-text, #143d25);
43
+ }
44
+
45
+ .warning {
46
+ border-bottom-color: var(--seblify-color-warning-border, #e8d28f);
47
+ background: var(--seblify-color-warning-surface, #fff6d8);
48
+ color: var(--seblify-color-warning-text, #4d3900);
49
+ }
50
+
51
+ .error {
52
+ border-bottom-color: var(--seblify-color-error-border, #efb6b6);
53
+ background: var(--seblify-color-error-surface, #fff0f0);
54
+ color: var(--seblify-color-error-text, #5a1717);
55
+ }
56
+ </style>
@@ -1,64 +1,64 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte';
3
-
4
- type ButtonVariant = 'primary' | 'secondary';
5
- type ButtonType = 'button' | 'submit' | 'reset';
6
-
7
- interface Props {
8
- children?: Snippet;
9
- disabled?: boolean;
10
- onclick?: (event: MouseEvent) => void;
11
- type?: ButtonType;
12
- variant?: ButtonVariant;
13
- }
14
-
15
- let {
16
- children,
17
- disabled = false,
18
- onclick,
19
- type = 'button',
20
- variant = 'primary',
21
- }: Props = $props();
22
- </script>
23
-
24
- <button {disabled} {onclick} {type} class:secondary={variant === 'secondary'}>
25
- {@render children?.()}
26
- </button>
27
-
28
- <style>
29
- button {
30
- min-height: 36px;
31
- border: 1px solid var(--seblify-color-fill-accent, #146a6f);
32
- border-radius: 6px;
33
- padding: 0 14px;
34
- background: var(--seblify-color-fill-accent, #146a6f);
35
- color: var(--seblify-color-fill-accent-text, #ffffff);
36
- font: inherit;
37
- font-weight: 600;
38
- cursor: pointer;
39
- }
40
-
41
- button:hover:not(:disabled) {
42
- background: var(--seblify-color-fill-accent-hover, #0d4d52);
43
- }
44
-
45
- button:focus-visible {
46
- outline: 3px solid var(--seblify-color-focus-ring, #9bd4d8);
47
- outline-offset: 2px;
48
- }
49
-
50
- button:disabled {
51
- cursor: not-allowed;
52
- opacity: var(--seblify-opacity-disabled, 0.56);
53
- }
54
-
55
- .secondary {
56
- border-color: var(--seblify-color-border, #c8d2df);
57
- background: var(--seblify-color-surface, #ffffff);
58
- color: var(--seblify-color-text, #172033);
59
- }
60
-
61
- .secondary:hover:not(:disabled) {
62
- background: var(--seblify-color-surface-hover, #f1f4f9);
63
- }
64
- </style>
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ type ButtonVariant = 'primary' | 'secondary';
5
+ type ButtonType = 'button' | 'submit' | 'reset';
6
+
7
+ interface Props {
8
+ children?: Snippet;
9
+ disabled?: boolean;
10
+ onclick?: (event: MouseEvent) => void;
11
+ type?: ButtonType;
12
+ variant?: ButtonVariant;
13
+ }
14
+
15
+ let {
16
+ children,
17
+ disabled = false,
18
+ onclick,
19
+ type = 'button',
20
+ variant = 'primary',
21
+ }: Props = $props();
22
+ </script>
23
+
24
+ <button {disabled} {onclick} {type} class:secondary={variant === 'secondary'}>
25
+ {@render children?.()}
26
+ </button>
27
+
28
+ <style>
29
+ button {
30
+ min-height: 36px;
31
+ border: 1px solid var(--seblify-color-fill-accent, #146a6f);
32
+ border-radius: 6px;
33
+ padding: 0 14px;
34
+ background: var(--seblify-color-fill-accent, #146a6f);
35
+ color: var(--seblify-color-fill-accent-text, #ffffff);
36
+ font: inherit;
37
+ font-weight: 600;
38
+ cursor: pointer;
39
+ }
40
+
41
+ button:hover:not(:disabled) {
42
+ background: var(--seblify-color-fill-accent-hover, #0d4d52);
43
+ }
44
+
45
+ button:focus-visible {
46
+ outline: 3px solid var(--seblify-color-focus-ring, #9bd4d8);
47
+ outline-offset: 2px;
48
+ }
49
+
50
+ button:disabled {
51
+ cursor: not-allowed;
52
+ opacity: var(--seblify-opacity-disabled, 0.56);
53
+ }
54
+
55
+ .secondary {
56
+ border-color: var(--seblify-color-border, #c8d2df);
57
+ background: var(--seblify-color-surface, #ffffff);
58
+ color: var(--seblify-color-text, #172033);
59
+ }
60
+
61
+ .secondary:hover:not(:disabled) {
62
+ background: var(--seblify-color-surface-hover, #f1f4f9);
63
+ }
64
+ </style>
@@ -1,67 +1,67 @@
1
- <script lang="ts">
2
- const iconModules = import.meta.glob("../icons/**/*.svg", {
3
- eager: true,
4
- import: "default"
5
- });
6
-
7
- interface Props {
8
- alt?: string;
9
- name?: string;
10
- size?: number;
11
- }
12
-
13
- let { alt = "", name = "", size = 24 }: Props = $props();
14
-
15
- function normalizeNameToPath(value: unknown): string | null {
16
- const safe = typeof value === "string" ? value.trim() : "";
17
-
18
- if (safe.length === 0) {
19
- return null;
20
- }
21
-
22
- const parts = safe.split("-").filter((part) => part.length > 0);
23
-
24
- if (parts.length < 2) {
25
- return null;
26
- }
27
-
28
- const folder = parts[0];
29
- const file = parts.slice(1).join("-");
30
-
31
- return `../icons/${folder}/${file}.svg`;
32
- }
33
-
34
- let groupedPath = $derived(normalizeNameToPath(name));
35
- let iconPath = $derived(
36
- (groupedPath != null ? iconModules[groupedPath] : undefined) ??
37
- iconModules[`../icons/${name}.svg`] ??
38
- ""
39
- );
40
- </script>
41
-
42
- {#if iconPath}
43
- <span
44
- role={alt ? "img" : undefined}
45
- aria-label={alt || undefined}
46
- aria-hidden={alt ? undefined : "true"}
47
- style:--icon-url={`url('${iconPath}')`}
48
- style:width={`${size / 16}rem`}
49
- style:height={`${size / 16}rem`}
50
- ></span>
51
- {/if}
52
-
53
- <style>
54
- span {
55
- display: inline-block;
56
- flex: 0 0 auto;
57
- background-color: currentColor;
58
- mask-image: var(--icon-url);
59
- mask-position: center;
60
- mask-repeat: no-repeat;
61
- mask-size: contain;
62
- -webkit-mask-image: var(--icon-url);
63
- -webkit-mask-position: center;
64
- -webkit-mask-repeat: no-repeat;
65
- -webkit-mask-size: contain;
66
- }
67
- </style>
1
+ <script lang="ts">
2
+ const iconModules = import.meta.glob("../icons/**/*.svg", {
3
+ eager: true,
4
+ import: "default"
5
+ });
6
+
7
+ interface Props {
8
+ alt?: string;
9
+ name?: string;
10
+ size?: number;
11
+ }
12
+
13
+ let { alt = "", name = "", size = 24 }: Props = $props();
14
+
15
+ function normalizeNameToPath(value: unknown): string | null {
16
+ const safe = typeof value === "string" ? value.trim() : "";
17
+
18
+ if (safe.length === 0) {
19
+ return null;
20
+ }
21
+
22
+ const parts = safe.split("-").filter((part) => part.length > 0);
23
+
24
+ if (parts.length < 2) {
25
+ return null;
26
+ }
27
+
28
+ const folder = parts[0];
29
+ const file = parts.slice(1).join("-");
30
+
31
+ return `../icons/${folder}/${file}.svg`;
32
+ }
33
+
34
+ let groupedPath = $derived(normalizeNameToPath(name));
35
+ let iconPath = $derived(
36
+ (groupedPath != null ? iconModules[groupedPath] : undefined) ??
37
+ iconModules[`../icons/${name}.svg`] ??
38
+ ""
39
+ );
40
+ </script>
41
+
42
+ {#if iconPath}
43
+ <span
44
+ role={alt ? "img" : undefined}
45
+ aria-label={alt || undefined}
46
+ aria-hidden={alt ? undefined : "true"}
47
+ style:--icon-url={`url('${iconPath}')`}
48
+ style:width={`${size / 16}rem`}
49
+ style:height={`${size / 16}rem`}
50
+ ></span>
51
+ {/if}
52
+
53
+ <style>
54
+ span {
55
+ display: inline-block;
56
+ flex: 0 0 auto;
57
+ background-color: currentColor;
58
+ mask-image: var(--icon-url);
59
+ mask-position: center;
60
+ mask-repeat: no-repeat;
61
+ mask-size: contain;
62
+ -webkit-mask-image: var(--icon-url);
63
+ -webkit-mask-position: center;
64
+ -webkit-mask-repeat: no-repeat;
65
+ -webkit-mask-size: contain;
66
+ }
67
+ </style>
@@ -1,106 +1,106 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte';
3
-
4
- interface SidebarNavItem {
5
- active?: boolean;
6
- href?: string;
7
- label: string;
8
- }
9
-
10
- interface Props {
11
- bottomItems?: SidebarNavItem[];
12
- logo?: Snippet;
13
- topItems?: SidebarNavItem[];
14
- }
15
-
16
- let { bottomItems = [], logo, topItems = [] }: Props = $props();
17
- </script>
18
-
19
- <aside class="sidebar">
20
- {#if logo}
21
- <div class="brand">
22
- {@render logo()}
23
- </div>
24
- {/if}
25
-
26
- <nav class="nav-section top" aria-label="Primary navigation">
27
- {#each topItems as item}
28
- <a
29
- class="nav-item"
30
- class:active={item.active}
31
- href={item.href ?? '#'}
32
- aria-current={item.active ? 'page' : undefined}
33
- >
34
- {item.label}
35
- </a>
36
- {/each}
37
- </nav>
38
-
39
- {#if bottomItems.length > 0}
40
- <nav class="nav-section bottom" aria-label="Secondary navigation">
41
- {#each bottomItems as item}
42
- <a
43
- class="nav-item"
44
- class:active={item.active}
45
- href={item.href ?? '#'}
46
- aria-current={item.active ? 'page' : undefined}
47
- >
48
- {item.label}
49
- </a>
50
- {/each}
51
- </nav>
52
- {/if}
53
- </aside>
54
-
55
- <style>
56
- .sidebar {
57
- display: flex;
58
- flex-direction: column;
59
- width: 16.5rem;
60
- max-width: 100%;
61
- min-height: 100%;
62
- background: var(--seblify-color-surface-inverse, #172033);
63
- }
64
-
65
- .brand {
66
- padding: 1.5rem 1rem;
67
- color: var(--seblify-color-text-inverse, #ffffff);
68
- }
69
-
70
- .nav-section {
71
- display: grid;
72
- gap: 0.25rem;
73
- margin: 0 1rem;
74
- }
75
-
76
- .top {
77
- align-content: start;
78
- }
79
-
80
- .bottom {
81
- margin-top: auto;
82
- padding-bottom: 1rem;
83
- }
84
-
85
- .nav-item {
86
- display: block;
87
- width: 100%;
88
- border-radius: 0.375rem;
89
- padding: 0.75rem 1rem;
90
- color: var(--seblify-color-text-inverse, #ffffff);
91
- font-size: 0.875rem;
92
- line-height: 1.25rem;
93
- text-decoration: none;
94
- box-sizing: border-box;
95
- }
96
-
97
- .nav-item:hover {
98
- background: var(--seblify-color-surface-inverse-hover, #263043);
99
- color: var(--seblify-color-text-inverse, #ffffff);
100
- }
101
-
102
- .active {
103
- background: var(--seblify-color-surface-inverse-hover, #263043);
104
- color: var(--seblify-color-text-inverse, #ffffff);
105
- }
106
- </style>
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface SidebarNavItem {
5
+ active?: boolean;
6
+ href?: string;
7
+ label: string;
8
+ }
9
+
10
+ interface Props {
11
+ bottomItems?: SidebarNavItem[];
12
+ logo?: Snippet;
13
+ topItems?: SidebarNavItem[];
14
+ }
15
+
16
+ let { bottomItems = [], logo, topItems = [] }: Props = $props();
17
+ </script>
18
+
19
+ <aside class="sidebar">
20
+ {#if logo}
21
+ <div class="brand">
22
+ {@render logo()}
23
+ </div>
24
+ {/if}
25
+
26
+ <nav class="nav-section top" aria-label="Primary navigation">
27
+ {#each topItems as item}
28
+ <a
29
+ class="nav-item"
30
+ class:active={item.active}
31
+ href={item.href ?? '#'}
32
+ aria-current={item.active ? 'page' : undefined}
33
+ >
34
+ {item.label}
35
+ </a>
36
+ {/each}
37
+ </nav>
38
+
39
+ {#if bottomItems.length > 0}
40
+ <nav class="nav-section bottom" aria-label="Secondary navigation">
41
+ {#each bottomItems as item}
42
+ <a
43
+ class="nav-item"
44
+ class:active={item.active}
45
+ href={item.href ?? '#'}
46
+ aria-current={item.active ? 'page' : undefined}
47
+ >
48
+ {item.label}
49
+ </a>
50
+ {/each}
51
+ </nav>
52
+ {/if}
53
+ </aside>
54
+
55
+ <style>
56
+ .sidebar {
57
+ display: flex;
58
+ flex-direction: column;
59
+ width: 16.5rem;
60
+ max-width: 100%;
61
+ min-height: 100%;
62
+ background: var(--seblify-color-surface-inverse, #172033);
63
+ }
64
+
65
+ .brand {
66
+ padding: 1.5rem 1rem;
67
+ color: var(--seblify-color-text-inverse, #ffffff);
68
+ }
69
+
70
+ .nav-section {
71
+ display: grid;
72
+ gap: 0.25rem;
73
+ margin: 0 1rem;
74
+ }
75
+
76
+ .top {
77
+ align-content: start;
78
+ }
79
+
80
+ .bottom {
81
+ margin-top: auto;
82
+ padding-bottom: 1rem;
83
+ }
84
+
85
+ .nav-item {
86
+ display: block;
87
+ width: 100%;
88
+ border-radius: 0.375rem;
89
+ padding: 0.75rem 1rem;
90
+ color: var(--seblify-color-text-inverse, #ffffff);
91
+ font-size: 0.875rem;
92
+ line-height: 1.25rem;
93
+ text-decoration: none;
94
+ box-sizing: border-box;
95
+ }
96
+
97
+ .nav-item:hover {
98
+ background: var(--seblify-color-surface-inverse-hover, #263043);
99
+ color: var(--seblify-color-text-inverse, #ffffff);
100
+ }
101
+
102
+ .active {
103
+ background: var(--seblify-color-surface-inverse-hover, #263043);
104
+ color: var(--seblify-color-text-inverse, #ffffff);
105
+ }
106
+ </style>
@@ -1,26 +1,26 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte';
3
-
4
- interface Props {
5
- children?: Snippet;
6
- }
7
-
8
- let { children }: Props = $props();
9
- </script>
10
-
11
- <section class="snackbar" role="status">
12
- {@render children?.()}
13
- </section>
14
-
15
- <style>
16
- .snackbar {
17
- border: 1px solid var(--seblify-color-border-inverse, #263043);
18
- border-radius: 6px;
19
- padding: 12px 14px;
20
- background: var(--seblify-color-surface-inverse, #172033);
21
- color: var(--seblify-color-text-inverse, #ffffff);
22
- box-shadow: var(--seblify-shadow-raised, 0 12px 28px rgb(23 32 51 / 22%));
23
- font-size: 14px;
24
- line-height: 1.4;
25
- }
26
- </style>
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ children?: Snippet;
6
+ }
7
+
8
+ let { children }: Props = $props();
9
+ </script>
10
+
11
+ <section class="snackbar" role="status">
12
+ {@render children?.()}
13
+ </section>
14
+
15
+ <style>
16
+ .snackbar {
17
+ border: 1px solid var(--seblify-color-border-inverse, #263043);
18
+ border-radius: 6px;
19
+ padding: 12px 14px;
20
+ background: var(--seblify-color-surface-inverse, #172033);
21
+ color: var(--seblify-color-text-inverse, #ffffff);
22
+ box-shadow: var(--seblify-shadow-raised, 0 12px 28px rgb(23 32 51 / 22%));
23
+ font-size: 14px;
24
+ line-height: 1.4;
25
+ }
26
+ </style>
@@ -1,27 +1,27 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte';
3
-
4
- interface Props {
5
- children?: Snippet;
6
- }
7
-
8
- let { children }: Props = $props();
9
- </script>
10
-
11
- <section class="toast" role="status">
12
- {@render children?.()}
13
- </section>
14
-
15
- <style>
16
- .toast {
17
- border: 1px solid var(--seblify-color-success-border, #b8ddc7);
18
- border-radius: 999px;
19
- padding: 8px 14px;
20
- background: var(--seblify-color-success-surface, #e8f8ee);
21
- color: var(--seblify-color-success-text, #143d25);
22
- box-shadow: var(--seblify-shadow-status, 0 10px 24px rgb(20 61 37 / 14%));
23
- font-size: 14px;
24
- line-height: 1.4;
25
- text-align: center;
26
- }
27
- </style>
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ children?: Snippet;
6
+ }
7
+
8
+ let { children }: Props = $props();
9
+ </script>
10
+
11
+ <section class="toast" role="status">
12
+ {@render children?.()}
13
+ </section>
14
+
15
+ <style>
16
+ .toast {
17
+ border: 1px solid var(--seblify-color-success-border, #b8ddc7);
18
+ border-radius: 999px;
19
+ padding: 8px 14px;
20
+ background: var(--seblify-color-success-surface, #e8f8ee);
21
+ color: var(--seblify-color-success-text, #143d25);
22
+ box-shadow: var(--seblify-shadow-status, 0 10px 24px rgb(20 61 37 / 14%));
23
+ font-size: 14px;
24
+ line-height: 1.4;
25
+ text-align: center;
26
+ }
27
+ </style>
@@ -1,4 +1,4 @@
1
- export type ComponentStatus = 'draft' | 'planned' | 'stable';
1
+ export type ComponentStatus = 'draft' | 'planned' | 'beta' | 'stable' | 'deprecated';
2
2
  export interface ComponentDocExample {
3
3
  id: string;
4
4
  title: string;
package/package.json CHANGED
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "name": "seblify",
3
3
  "private": false,
4
- "version": "0.1.7",
4
+ "license": "MIT",
5
+ "version": "0.1.8",
5
6
  "type": "module",
6
7
  "scripts": {
7
8
  "build": "svelte-package --input src --output dist --tsconfig ./tsconfig.json",
8
9
  "generate:icons": "node ./scripts/generate-icons.mjs",
9
- "change-log:new": "node ./scripts/change-log/document-change.mjs",
10
+ "doc": "node ./scripts/change-log/document-change.mjs",
10
11
  "change-log:validate": "node ./scripts/change-log/validate-pending.mjs",
11
- "prepare-release": "node ./scripts/bump-version.mjs",
12
+ "readme:generate": "node ./scripts/readme/generate-readme.mjs",
13
+ "prepare-release": "node ./scripts/prepare-release.mjs",
12
14
  "prepublishOnly": "pnpm run generate:icons && pnpm run build"
13
15
  },
14
16
  "svelte": "./dist/index.js",
@@ -58,9 +60,26 @@
58
60
  "prompts": "^2.4.2",
59
61
  "yaml": "^2.9.0"
60
62
  },
61
- "homepage": "https://seblify.com",
62
63
  "publishConfig": {
63
64
  "access": "public",
64
65
  "provenance": false
66
+ },
67
+ "description": "Svelte UI component library for building themed interfaces",
68
+ "keywords": [
69
+ "svelte",
70
+ "sveltekit",
71
+ "ui",
72
+ "component",
73
+ "component-library",
74
+ "design-system",
75
+ "theme",
76
+ "theming",
77
+ "css-variables",
78
+ "accessibility",
79
+ "custom-theme"
80
+ ],
81
+ "homepage": "https://seblify.com",
82
+ "bugs": {
83
+ "email": "support.seblify@gmail.com"
65
84
  }
66
85
  }