@ibis-design/svelte 0.7.1 → 0.8.0

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.
Files changed (2) hide show
  1. package/README.md +365 -50
  2. package/package.json +49 -49
package/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # @ibis-design/svelte
2
2
 
3
- Svelte 5 component library for the IBIS design system. Provides primitives (Button, Card) and full layout shells (AuthLayout, AppLayout, DashboardLayout) styled via CSS custom properties from `@ibis-design/css`.
3
+ Svelte 5 component library for the IBIS design system—buttons, inputs, feedback, and app shellsstyled with tokens from [@ibis-design/css](https://www.npmjs.com/package/@ibis-design/css).
4
4
 
5
5
  ## Requirements
6
6
 
7
- - **Svelte 5** (runes and snippets; no slots).
8
- - **@ibis-design/css** design tokens. Load the stylesheet once and set `data-theme` on `<html>` (`ib-light`, `ib-dark`, `alc-light`, `alc-dark`).
7
+ - **Svelte 5** (runes, snippets; not compatible with Svelte 4 slots API)
8
+ - **@ibis-design/css** (peer dependency for tokens and component styles)
9
9
 
10
10
  ## Installation
11
11
 
@@ -13,85 +13,365 @@ Svelte 5 component library for the IBIS design system. Provides primitives (Butt
13
13
  npm install @ibis-design/svelte @ibis-design/css
14
14
  ```
15
15
 
16
- ## Token CSS
16
+ ## App setup
17
17
 
18
- Import tokens and set the theme on the document root:
18
+ Load tokens once at the root of your app and set the theme on `<html>`.
19
19
 
20
20
  ```svelte
21
- <script>
21
+ <!-- src/routes/+layout.svelte (SvelteKit) or App.svelte -->
22
+ <script lang="ts">
22
23
  import '@ibis-design/css';
24
+ import { onMount } from 'svelte';
23
25
 
24
- if (typeof document !== 'undefined') {
25
- document.documentElement.dataset.theme = 'ib-light'; // or alc-dark, etc.
26
- }
26
+ onMount(() => {
27
+ document.documentElement.dataset.theme = 'ib-light';
28
+ });
27
29
  </script>
30
+
31
+ <slot />
28
32
  ```
29
33
 
30
- Without the CSS import and `data-theme`, components will not resolve design-system variables.
34
+ ```svelte
35
+ <script lang="ts">
36
+ import { Button, TextInput, Banner } from '@ibis-design/svelte';
37
+ </script>
38
+
39
+ <Button variant="primary" size="md">Continue</Button>
40
+ ```
31
41
 
32
- ### Canonical variable names
42
+ | `data-theme` | Brand | Mode |
43
+ |--------------|-------|------|
44
+ | `ib-light` | Ibis | Light |
45
+ | `ib-dark` | Ibis | Dark |
46
+ | `alc-light` | Alchemy | Light |
47
+ | `alc-dark` | Alchemy | Dark |
33
48
 
34
- Use semantic tokens from the active theme, for example:
49
+ Switch at runtime: `document.documentElement.dataset.theme = 'alc-dark'`.
35
50
 
36
- - `--font-size-body-sm` (not legacy `normal-text` names)
37
- - `--color-brand-secondary` for secondary actions
38
- - `--shadow-focus-default` for focus rings
39
- - `--border-radius-md`, `--border-color-button`
51
+ ---
40
52
 
41
- ### Component styles
53
+ ## Components
42
54
 
43
- Svelte components load their presentation CSS from `@ibis-design/css` automatically. You do not need a separate component CSS import unless you use `.ibis-*` class names outside these components (see [@ibis-design/css](https://www.npmjs.com/package/@ibis-design/css) component entry points).
55
+ All components use **snippets** for labels and rich content (Svelte 5). Put text between tags or pass a `label` prop when available.
44
56
 
45
- ## Usage
57
+ ### Button
46
58
 
47
- ### Primitives
59
+ Primary actions, form submit, and secondary cancel flows.
48
60
 
49
- **Button** use the `children` snippet for the label:
61
+ | Prop | Type | Default | Description |
62
+ |------|------|---------|-------------|
63
+ | `variant` | `'primary' \| 'secondary'` | `'primary'` | Visual style |
64
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Padding and type size |
65
+ | `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | Native button type |
66
+ | `disabled` | `boolean` | `false` | Disables interaction |
67
+ | `loading` | `boolean` | `false` | Spinner + disabled |
68
+ | `skeleton` | `boolean` | `false` | Placeholder shimmer |
69
+ | `iconOnly` | `boolean` | `false` | Square icon button |
70
+ | `label` | `string` | — | Text if no children snippet |
50
71
 
51
72
  ```svelte
52
73
  <script>
53
74
  import { Button } from '@ibis-design/svelte';
54
75
  </script>
55
76
 
56
- <Button variant="primary" size="md">Submit</Button>
77
+ <Button variant="primary" size="md">Submit payment</Button>
57
78
  <Button variant="secondary" size="sm">Cancel</Button>
79
+ <Button type="submit" loading={isSaving}>Saving…</Button>
80
+ <Button iconOnly aria-label="Search">🔍</Button>
58
81
  ```
59
82
 
60
- **Card** — use the `children` snippet for content:
83
+ ---
84
+
85
+ ### TextInput
86
+
87
+ Labeled text fields with help, error, prefix/suffix, and prepend blocks.
88
+
89
+ | Prop | Type | Default | Description |
90
+ |------|------|---------|-------------|
91
+ | `label` | `string` | — | Field label |
92
+ | `inputSize` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size scale |
93
+ | `invalid` | `boolean` | `false` | Error styling |
94
+ | `error` | `string` | — | Shown when `invalid` |
95
+ | `description` | `string` | — | Below label |
96
+ | `helpText` | `string` | — | Below field |
97
+ | `loading` | `boolean` | `false` | Loading state |
98
+ | `prefixSnippet` / `suffixSnippet` | `Snippet` | — | Icons inside field |
99
+ | `prependSnippet` | `Snippet` | — | Block before field |
100
+ | `bind:value` | `string` | — | Input value |
61
101
 
62
102
  ```svelte
63
103
  <script>
64
- import { Card } from '@ibis-design/svelte';
104
+ import { TextInput } from '@ibis-design/svelte';
105
+
106
+ let email = $state('');
107
+ let emailError = $state('');
65
108
  </script>
66
109
 
67
- <Card>
68
- <p>Card content</p>
69
- </Card>
110
+ <TextInput
111
+ label="Email"
112
+ type="email"
113
+ placeholder="you@example.com"
114
+ description="Used for receipts."
115
+ helpText="We never share your email."
116
+ bind:value={email}
117
+ />
118
+
119
+ <TextInput
120
+ label="Amount"
121
+ invalid={!!emailError}
122
+ error={emailError}
123
+ bind:value={email}
124
+ />
70
125
  ```
71
126
 
72
- ### Layouts
127
+ ---
73
128
 
74
- Layouts use **snippets** (Svelte 5). Pass snippet props for header, sidebar, and main content. Content between the component tags is the `children` snippet.
129
+ ### TextArea
75
130
 
76
- **AppLayout** generic app shell with optional header, sidebar, main, and footer:
131
+ Multi-line input; same sizing and validation props as `TextInput` (`inputSize`, `invalid`, `error`, `loading`, `rows`).
77
132
 
78
133
  ```svelte
79
134
  <script>
80
- import { AppLayout } from '@ibis-design/svelte';
135
+ import { TextArea } from '@ibis-design/svelte';
136
+ let notes = $state('');
137
+ </script>
138
+
139
+ <TextArea label="Notes" rows={4} placeholder="Optional details…" bind:value={notes} />
140
+ ```
141
+
142
+ ---
143
+
144
+ ### Checkbox
81
145
 
82
- // Define snippets and pass as props; content between tags is children
146
+ | Prop | Type | Default | Description |
147
+ |------|------|---------|-------------|
148
+ | `label` | `string` | — | Label text |
149
+ | `bind:checked` | `boolean` | `false` | Checked state |
150
+ | `inputSize` | `'sm' \| 'md' \| 'lg'` | `'md'` | Control size |
151
+ | `disabled` | `boolean` | `false` | |
152
+ | `invalid` | `boolean` | `false` | |
153
+ | `description` / `helpText` / `error` | `string` | — | Helper copy |
154
+ | `checkboxSnippet` | `Snippet` | — | Custom check icon |
155
+
156
+ ```svelte
157
+ <script>
158
+ import { Checkbox } from '@ibis-design/svelte';
159
+ let accepted = $state(false);
83
160
  </script>
84
161
 
85
- <AppLayout
86
- header={headerSnippet}
87
- sidebar={sidebarSnippet}
88
- footer={footerSnippet}
89
- >
90
- <p>Main page content</p>
91
- </AppLayout>
162
+ <Checkbox
163
+ label="I accept the terms"
164
+ description="Required to open an account."
165
+ bind:checked={accepted}
166
+ />
92
167
  ```
93
168
 
94
- With inline snippets:
169
+ ---
170
+
171
+ ### Radio
172
+
173
+ | Prop | Type | Default | Description |
174
+ |------|------|---------|-------------|
175
+ | `label` | `string` | — | Option label |
176
+ | `value` | `string \| number` | **required** | Option value |
177
+ | `group` | `string \| number` | — | Selected value (`bind:group`) |
178
+ | `name` | `string` | — | Radio group name |
179
+ | `inputSize` | `'sm' \| 'md' \| 'lg'` | `'md'` | |
180
+ | `disabled` / `invalid` | `boolean` | | |
181
+
182
+ ```svelte
183
+ <script>
184
+ import { Radio } from '@ibis-design/svelte';
185
+ let accountType = $state('personal');
186
+ </script>
187
+
188
+ <Radio name="account" label="Personal" value="personal" bind:group={accountType} />
189
+ <Radio name="account" label="Business" value="business" bind:group={accountType} />
190
+ ```
191
+
192
+ ---
193
+
194
+ ### Switch
195
+
196
+ Toggle for settings; uses `bind:checked`.
197
+
198
+ ```svelte
199
+ <script>
200
+ import { Switch } from '@ibis-design/svelte';
201
+ let enabled = $state(true);
202
+ </script>
203
+
204
+ <Switch label="Notifications" bind:checked={enabled} />
205
+ ```
206
+
207
+ ---
208
+
209
+ ### Dropdown
210
+
211
+ Select-style control with `options: { label, value }[]` and `bind:value`.
212
+
213
+ ```svelte
214
+ <script>
215
+ import { Dropdown } from '@ibis-design/svelte';
216
+
217
+ let currency = $state('usd');
218
+ const options = [
219
+ { label: 'US Dollar', value: 'usd' },
220
+ { label: 'Euro', value: 'eur' },
221
+ ];
222
+ </script>
223
+
224
+ <Dropdown label="Currency" {options} bind:value={currency} placeholder="Choose currency" />
225
+ ```
226
+
227
+ ---
228
+
229
+ ### DropdownButton
230
+
231
+ Menu anchored to a button; pass `menu` snippet with a `close` callback.
232
+
233
+ ```svelte
234
+ <script>
235
+ import { DropdownButton } from '@ibis-design/svelte';
236
+ </script>
237
+
238
+ <DropdownButton label="Account">
239
+ {#snippet menu(close)}
240
+ <button type="button" class="ibis-dropdown-menu__item" onclick={close}>Profile</button>
241
+ <button type="button" class="ibis-dropdown-menu__item" onclick={close}>Sign out</button>
242
+ {/snippet}
243
+ </DropdownButton>
244
+ ```
245
+
246
+ ---
247
+
248
+ ### Chips
249
+
250
+ Filter or toggle chips; supports `bind:selected`, `loading`, `skeleton`, and icon snippets.
251
+
252
+ ```svelte
253
+ <script>
254
+ import { Chips } from '@ibis-design/svelte';
255
+ let active = $state(false);
256
+ </script>
257
+
258
+ <Chips label="Pending" bind:selected={active} />
259
+ <Chips label="With icon" iconText="★" size="sm" />
260
+ ```
261
+
262
+ ---
263
+
264
+ ### PillTab & PillTabs
265
+
266
+ Segmented control built on radio inputs. Wrap tabs in `PillTabs`; share `name` and `bind:group`.
267
+
268
+ ```svelte
269
+ <script>
270
+ import { PillTabs, PillTab } from '@ibis-design/svelte';
271
+ let tab = $state('overview');
272
+ </script>
273
+
274
+ <PillTabs>
275
+ <PillTab name="main" label="Overview" value="overview" bind:group={tab} />
276
+ <PillTab name="main" label="Activity" value="activity" bind:group={tab} />
277
+ <PillTab name="main" label="Settings" value="settings" bind:group={tab} />
278
+ </PillTabs>
279
+ ```
280
+
281
+ ---
282
+
283
+ ### TextLink
284
+
285
+ Styled anchor with underline modes and optional icons.
286
+
287
+ | Prop | Type | Default |
288
+ |------|------|---------|
289
+ | `href` | `string` | — |
290
+ | `underline` | `'always' \| 'hover' \| 'none'` | `'hover'` |
291
+ | `linkSize` | `'sm' \| 'md' \| 'lg'` | `'md'` |
292
+ | `disabled` / `loading` / `skeleton` | `boolean` | |
293
+
294
+ ```svelte
295
+ <script>
296
+ import { TextLink } from '@ibis-design/svelte';
297
+ </script>
298
+
299
+ <TextLink href="/help" underline="hover">Need help?</TextLink>
300
+ ```
301
+
302
+ ---
303
+
304
+ ### Banner
305
+
306
+ Inline page-level message. Types: `success`, `error`, `default`. Optional `closable`, `loading`, `icon` snippet.
307
+
308
+ ```svelte
309
+ <script>
310
+ import { Banner } from '@ibis-design/svelte';
311
+ </script>
312
+
313
+ <Banner type="success" title="Transfer complete" message="Funds will arrive in 1–2 days." closable />
314
+ <Banner type="error" title="Payment failed">
315
+ {#snippet children()}
316
+ Check your card details and try again.
317
+ {/snippet}
318
+ </Banner>
319
+ ```
320
+
321
+ ---
322
+
323
+ ### Toaster
324
+
325
+ Compact toast-style message. Types: `success`, `error`, `accent`, `default`.
326
+
327
+ ```svelte
328
+ <script>
329
+ import { Toaster } from '@ibis-design/svelte';
330
+ </script>
331
+
332
+ <Toaster type="accent" title="Session expiring" message="Sign in again to continue." closable />
333
+ ```
334
+
335
+ ---
336
+
337
+ ### TipIndicator
338
+
339
+ Hover/focus tooltip on an indicator. **Requires** `text` prop.
340
+
341
+ ```svelte
342
+ <script>
343
+ import { TipIndicator } from '@ibis-design/svelte';
344
+ </script>
345
+
346
+ <TipIndicator text="International transfers may include fees." position="top" width="240" />
347
+ ```
348
+
349
+ ---
350
+
351
+ ### Card
352
+
353
+ Simple surfaced container (styles ship with the component).
354
+
355
+ ```svelte
356
+ <script>
357
+ import { Card } from '@ibis-design/svelte';
358
+ </script>
359
+
360
+ <Card>
361
+ <h2>Account summary</h2>
362
+ <p>Balance and recent activity.</p>
363
+ </Card>
364
+ ```
365
+
366
+ ---
367
+
368
+ ## Layouts
369
+
370
+ Layouts use **snippet props** for regions. Content between the layout tags is the main `children` area.
371
+
372
+ ### AppLayout
373
+
374
+ Optional `header`, `sidebar`, `footer` snippets.
95
375
 
96
376
  ```svelte
97
377
  <script>
@@ -99,33 +379,68 @@ With inline snippets:
99
379
  </script>
100
380
 
101
381
  {#snippet header()}
102
- <nav>App header</nav>
382
+ <nav>My app</nav>
103
383
  {/snippet}
384
+
104
385
  {#snippet sidebar()}
105
- <aside>Sidebar</aside>
386
+ <aside>Navigation</aside>
106
387
  {/snippet}
107
388
 
108
- <AppLayout header={header} sidebar={sidebar}>
109
- <p>Main content</p>
389
+ <AppLayout {header} {sidebar}>
390
+ <h1>Dashboard</h1>
391
+ <p>Main content.</p>
110
392
  </AppLayout>
111
393
  ```
112
394
 
113
- **AuthLayout** — centered single-column layout for login/signup:
395
+ ### AuthLayout
396
+
397
+ Centered column for sign-in / sign-up.
114
398
 
115
399
  ```svelte
116
400
  <script>
117
401
  import { AuthLayout } from '@ibis-design/svelte';
118
402
  </script>
119
403
 
120
- <AuthLayout logo={logoSnippet} footer={footerSnippet}>
121
- <form>Login form</form>
404
+ <AuthLayout>
405
+ <form>
406
+ <h1>Sign in</h1>
407
+ <!-- fields -->
408
+ </form>
122
409
  </AuthLayout>
123
410
  ```
124
411
 
125
- **DashboardLayout** — dashboard shell with themed header and sidebar (same snippet props as AppLayout).
412
+ ### DashboardLayout
413
+
414
+ Dashboard shell with themed header and sidebar (same snippet API as `AppLayout`).
415
+
416
+ ```svelte
417
+ <script>
418
+ import { DashboardLayout } from '@ibis-design/svelte';
419
+ </script>
420
+
421
+ {#snippet header()}
422
+ <header>Dashboard</header>
423
+ {/snippet}
424
+
425
+ <DashboardLayout {header}>
426
+ <p>Widgets and charts.</p>
427
+ </DashboardLayout>
428
+ ```
429
+
430
+ ---
431
+
432
+ ## Vanilla HTML / other frameworks
433
+
434
+ Component **classes** and tokens live in `@ibis-design/css`. Use this package when you want ready-made Svelte 5 components; use the CSS package directly for React, Vue, or plain HTML. See the [@ibis-design/css README](https://www.npmjs.com/package/@ibis-design/css) for `.ibis-*` markup examples.
435
+
436
+ ---
126
437
 
127
438
  ## Exports
128
439
 
129
- - **Components:** `Button`, `Card`, `AuthLayout`, `AppLayout`, `DashboardLayout`
130
- - **Types:** `ButtonVariant`, `ButtonSize`, `AuthLayoutProps`, `AppLayoutProps`, `DashboardLayoutProps` (from `@ibis-design/svelte`)
440
+ **Components:** `Button`, `DropdownButton`, `PillTab`, `PillTabs`, `TextInput`, `TextArea`, `Checkbox`, `Radio`, `Switch`, `Dropdown`, `Chips`, `TextLink`, `Banner`, `Toaster`, `TipIndicator`, `Card`, `Tooltip`, `AuthLayout`, `AppLayout`, `DashboardLayout`
131
441
 
442
+ **Types:** `ButtonVariant`, `ButtonSize`, `AuthLayoutProps`, `AppLayoutProps`, `DashboardLayoutProps`
443
+
444
+ ```ts
445
+ import { Button, type ButtonVariant } from '@ibis-design/svelte';
446
+ ```
package/package.json CHANGED
@@ -1,49 +1,49 @@
1
- {
2
- "name": "@ibis-design/svelte",
3
- "version": "0.7.1",
4
- "description": "Svelte component library for the IBIS design system.",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "module": "./dist/index.js",
8
- "types": "./dist/index.d.ts",
9
- "svelte": "./dist/index.js",
10
- "exports": {
11
- ".": {
12
- "types": "./dist/index.d.ts",
13
- "svelte": "./dist/index.js",
14
- "import": "./dist/index.js",
15
- "default": "./dist/index.js"
16
- }
17
- },
18
- "files": [
19
- "dist"
20
- ],
21
- "sideEffects": [
22
- "**/*.css"
23
- ],
24
- "peerDependencies": {
25
- "@ibis-design/css": "^0.7.1",
26
- "svelte": "^5.54.0"
27
- },
28
- "devDependencies": {
29
- "@ibis-design/css": "0.7.1",
30
- "@sveltejs/adapter-auto": "7.0.1",
31
- "@sveltejs/kit": "2.60.1",
32
- "@sveltejs/package": "2.5.7",
33
- "@sveltejs/vite-plugin-svelte": "^7.1.2",
34
- "@types/node": "25.9.0",
35
- "svelte": "5.55.8",
36
- "svelte-check": "^4.4.8",
37
- "typescript": "^5.9.3",
38
- "vite": "^8.0.13"
39
- },
40
- "scripts": {
41
- "build": "svelte-kit sync && svelte-package",
42
- "prepublishOnly": "npm run build",
43
- "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
44
- "dev": "svelte-package -w"
45
- },
46
- "dependencies": {
47
- "@solar-icons/svelte": "^1.1.1"
48
- }
49
- }
1
+ {
2
+ "name": "@ibis-design/svelte",
3
+ "version": "0.8.0",
4
+ "description": "Svelte component library for the IBIS design system.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "svelte": "./dist/index.js",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "svelte": "./dist/index.js",
14
+ "import": "./dist/index.js",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "sideEffects": [
22
+ "**/*.css"
23
+ ],
24
+ "peerDependencies": {
25
+ "@ibis-design/css": "^0.8.0",
26
+ "svelte": "^5.54.0"
27
+ },
28
+ "devDependencies": {
29
+ "@ibis-design/css": "0.8.0",
30
+ "@sveltejs/adapter-auto": "7.0.1",
31
+ "@sveltejs/kit": "2.60.1",
32
+ "@sveltejs/package": "2.5.7",
33
+ "@sveltejs/vite-plugin-svelte": "^7.1.2",
34
+ "@types/node": "25.9.1",
35
+ "svelte": "5.55.9",
36
+ "svelte-check": "^4.4.8",
37
+ "typescript": "^5.9.3",
38
+ "vite": "^8.0.13"
39
+ },
40
+ "scripts": {
41
+ "build": "svelte-kit sync && svelte-package",
42
+ "prepublishOnly": "npm run build",
43
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
44
+ "dev": "svelte-package -w"
45
+ },
46
+ "dependencies": {
47
+ "@solar-icons/svelte": "^1.1.1"
48
+ }
49
+ }