svelte-toggle-switch 2.0.0 → 2.1.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,69 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [2.1.0] - 2026-01-02
9
+
10
+ ### Added
11
+ - **Event Dispatchers**: Added `on:change`, `on:focus`, and `on:blur` event handlers for better integration with frameworks and form libraries
12
+ - **Custom Text Labels**: New `onText` and `offText` props to customize the text displayed in the inner design (default: "ON"/"OFF")
13
+ - **Form Validation Support**:
14
+ - `helperText` prop - Display helper text below the switch
15
+ - `errorText` prop - Display error message when validation fails
16
+ - `required` prop - Mark the switch as required
17
+ - `error` prop - Show error state with red styling
18
+ - `name` prop - Form field name for submission
19
+ - **New Color Schemes**: Added `yellow`, `indigo`, and `teal` color schemes (now 9 total color schemes)
20
+ - **Enhanced Accessibility**:
21
+ - `tabIndex` prop for custom keyboard navigation order
22
+ - `aria-required` and `aria-invalid` attributes for form validation
23
+ - Improved screen reader support with helper text announcements
24
+ - **Demo Application**: Comprehensive SvelteKit demo with interactive playground at svelte-toggle-switch.ishansasika.dev
25
+ - Live preview with all props
26
+ - Real-time code generation
27
+ - 15+ quick example presets
28
+ - Icon picker with 10+ preset icons
29
+ - Complete documentation
30
+
31
+ ### Changed
32
+ - Updated component to dispatch custom events with detailed payload
33
+ - Multi-select now dispatches change events properly
34
+ - Helper text and error text display dynamically below all switch designs
35
+ - Error state now includes visual border color change
36
+
37
+ ### Fixed
38
+ - Multi-select change events now trigger correctly
39
+ - Focus and blur events properly propagate
40
+ - ARIA attributes correctly reference helper text for screen readers
41
+
42
+ ## [2.0.0] - 2025-12-14
43
+
44
+ ### Added
45
+ - Complete rewrite with TypeScript support
46
+ - 5 design variants (slider/ios, inner, modern, material, multi)
47
+ - 6 color schemes (blue, green, red, purple, orange, pink)
48
+ - 5 size variants (xs, sm, md, lg, xl)
49
+ - Custom icon support with showIcons, onIcon, and offIcon props
50
+ - Comprehensive accessibility with ARIA attributes
51
+ - Loading and disabled states
52
+ - Shadow and outline visual effects
53
+ - Customizable animations (duration and easing)
54
+ - Label positioning (left/right)
55
+ - Multi-option mode with radio group styling
56
+
57
+ ### Breaking Changes
58
+ - Migrated from Svelte 4 to Svelte 5 with runes support
59
+ - Component props now use TypeScript types
60
+ - Removed deprecated v1.x props
61
+
62
+ ## [1.0.0] - 2022-05-29
63
+
64
+ ### Added
65
+ - Initial release
66
+ - Basic toggle switch functionality
67
+ - iOS-style design
68
+ - ON/OFF states
69
+ - Simple customization options
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "svelte-toggle-switch",
3
3
  "private": false,
4
- "version": "2.0.0",
4
+ "version": "2.1.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -34,9 +34,11 @@
34
34
  "svelte component",
35
35
  "ui component",
36
36
  "accessible",
37
- "typescript"
37
+ "typescript",
38
+ "form validation",
39
+ "events"
38
40
  ],
39
- "author": "Ishan Karunaratne <ishansasika@gmail.com> (https://ishansasika.mn.co/)",
41
+ "author": "Ishan Karunaratne <ishansasika@gmail.com> (https://ishansasika.dev)",
40
42
  "license": "MIT",
41
- "homepage": "https://github.com/ishansasika/svelte-toggle-switch#readme"
43
+ "homepage": "https://svelte-toggle-switch.ishansasika.dev"
42
44
  }
@@ -1,4 +1,8 @@
1
1
  <script lang="ts">
2
+ import { createEventDispatcher } from 'svelte';
3
+
4
+ const dispatch = createEventDispatcher();
5
+
2
6
  // Core Props
3
7
  export let value: boolean | string = false;
4
8
  export let label: string = '';
@@ -11,7 +15,7 @@
11
15
  export let size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | number = 'md';
12
16
  export let color: string = '#007AFF';
13
17
  export let offColor: string = '#E5E7EB';
14
- export let colorScheme: 'blue' | 'green' | 'red' | 'purple' | 'orange' | 'pink' | 'custom' = 'blue';
18
+ export let colorScheme: 'blue' | 'green' | 'red' | 'purple' | 'orange' | 'pink' | 'yellow' | 'indigo' | 'teal' | 'custom' = 'blue';
15
19
 
16
20
  // State Props
17
21
  export let disabled: boolean = false;
@@ -31,6 +35,8 @@
31
35
  export let ariaLabel: string = '';
32
36
  export let ariaDescribedBy: string = '';
33
37
  export let id: string = '';
38
+ export let name: string = '';
39
+ export let tabIndex: number = 0;
34
40
 
35
41
  // Advanced Props
36
42
  export let labelPosition: 'left' | 'right' = 'right';
@@ -38,11 +44,22 @@
38
44
  export let shadow: boolean = false;
39
45
  export let outline: boolean = false;
40
46
 
47
+ // v2.1.0 New Features
48
+ // Custom Text Labels
49
+ export let onText: string = 'ON';
50
+ export let offText: string = 'OFF';
51
+
52
+ // Form Validation
53
+ export let helperText: string = '';
54
+ export let errorText: string = '';
55
+ export let required: boolean = false;
56
+ export let error: boolean = false;
57
+
41
58
  // Internal state
42
59
  let checked: boolean = typeof value === 'boolean' ? value : value === 'on';
43
60
  const uniqueID = id || `switch-${Math.floor(Math.random() * 1000000)}`;
44
61
 
45
- // Color schemes
62
+ // Color schemes (v2.1.0 - added yellow, indigo, teal)
46
63
  const colorSchemes = {
47
64
  blue: '#007AFF',
48
65
  green: '#10B981',
@@ -50,6 +67,9 @@
50
67
  purple: '#8B5CF6',
51
68
  orange: '#F97316',
52
69
  pink: '#EC4899',
70
+ yellow: '#F59E0B',
71
+ indigo: '#6366F1',
72
+ teal: '#14B8A6',
53
73
  custom: color
54
74
  };
55
75
 
@@ -83,7 +103,11 @@
83
103
  if (design !== 'multi') {
84
104
  const newChecked = !checked;
85
105
  checked = newChecked;
86
- value = newChecked ? (typeof value === 'boolean' ? true : 'on') : (typeof value === 'boolean' ? false : 'off');
106
+ const newValue = newChecked ? (typeof value === 'boolean' ? true : 'on') : (typeof value === 'boolean' ? false : 'off');
107
+ value = newValue;
108
+
109
+ // v2.1.0 - Dispatch change event
110
+ dispatch('change', { value: newValue, checked: newChecked });
87
111
  }
88
112
  }
89
113
 
@@ -95,10 +119,28 @@
95
119
  if (design !== 'multi') {
96
120
  const newChecked = !checked;
97
121
  checked = newChecked;
98
- value = newChecked ? (typeof value === 'boolean' ? true : 'on') : (typeof value === 'boolean' ? false : 'off');
122
+ const newValue = newChecked ? (typeof value === 'boolean' ? true : 'on') : (typeof value === 'boolean' ? false : 'off');
123
+ value = newValue;
124
+
125
+ // v2.1.0 - Dispatch change event
126
+ dispatch('change', { value: newValue, checked: newChecked });
99
127
  }
100
128
  }
101
129
  }
130
+
131
+ // v2.1.0 - Focus/Blur event handlers
132
+ function handleFocus(event: FocusEvent) {
133
+ dispatch('focus', { event });
134
+ }
135
+
136
+ function handleBlur(event: FocusEvent) {
137
+ dispatch('blur', { event });
138
+ }
139
+
140
+ // v2.1.0 - Multi-select change handler
141
+ function handleMultiChange() {
142
+ dispatch('change', { value });
143
+ }
102
144
  </script>
103
145
 
104
146
  {#if design === 'inner'}
@@ -117,16 +159,22 @@
117
159
  aria-checked={checked}
118
160
  aria-label={ariaLabel || label}
119
161
  aria-labelledby={label ? `${uniqueID}-label` : undefined}
120
- aria-describedby={ariaDescribedBy || undefined}
162
+ aria-describedby={ariaDescribedBy || (helperText || errorText ? `${uniqueID}-helper` : undefined)}
163
+ aria-required={required}
164
+ aria-invalid={error}
121
165
  {disabled}
166
+ tabindex={tabIndex}
122
167
  class="switch switch--inner"
123
168
  class:checked
124
169
  class:loading
125
170
  class:rounded
126
171
  class:shadow
127
172
  class:outline
173
+ class:error
128
174
  on:click={handleClick}
129
175
  on:keydown={handleKeyDown}
176
+ on:focus={handleFocus}
177
+ on:blur={handleBlur}
130
178
  style="
131
179
  --active-color: {activeColor};
132
180
  --off-color: {offColor};
@@ -137,12 +185,17 @@
137
185
  {#if loading}
138
186
  <span class="spinner"></span>
139
187
  {:else}
140
- <span class="switch-text">{checked ? 'ON' : 'OFF'}</span>
188
+ <span class="switch-text">{checked ? onText : offText}</span>
141
189
  {/if}
142
190
  </button>
143
191
  {#if label && labelPosition === 'right'}
144
192
  <span class="switch-label" id="{uniqueID}-label">{label}</span>
145
193
  {/if}
194
+ {#if helperText || errorText}
195
+ <span class="switch-helper-text" id="{uniqueID}-helper" class:error-text={error}>
196
+ {error && errorText ? errorText : helperText}
197
+ </span>
198
+ {/if}
146
199
  </div>
147
200
 
148
201
  {:else if design === 'slider' || design === 'ios'}
@@ -161,15 +214,21 @@
161
214
  aria-checked={checked}
162
215
  aria-label={ariaLabel || label}
163
216
  aria-labelledby={label ? `${uniqueID}-label` : undefined}
164
- aria-describedby={ariaDescribedBy || undefined}
217
+ aria-describedby={ariaDescribedBy || (helperText || errorText ? `${uniqueID}-helper` : undefined)}
218
+ aria-required={required}
219
+ aria-invalid={error}
165
220
  {disabled}
221
+ tabindex={tabIndex}
166
222
  class="switch switch--slider"
167
223
  class:checked
168
224
  class:loading
169
225
  class:shadow
170
226
  class:outline
227
+ class:error
171
228
  on:click={handleClick}
172
229
  on:keydown={handleKeyDown}
230
+ on:focus={handleFocus}
231
+ on:blur={handleBlur}
173
232
  style="
174
233
  --active-color: {activeColor};
175
234
  --off-color: {offColor};
@@ -190,6 +249,11 @@
190
249
  {#if label && labelPosition === 'right'}
191
250
  <span class="switch-label" id="{uniqueID}-label">{label}</span>
192
251
  {/if}
252
+ {#if helperText || errorText}
253
+ <span class="switch-helper-text" id="{uniqueID}-helper" class:error-text={error}>
254
+ {error && errorText ? errorText : helperText}
255
+ </span>
256
+ {/if}
193
257
  </div>
194
258
 
195
259
  {:else if design === 'modern'}
@@ -208,15 +272,21 @@
208
272
  aria-checked={checked}
209
273
  aria-label={ariaLabel || label}
210
274
  aria-labelledby={label ? `${uniqueID}-label` : undefined}
211
- aria-describedby={ariaDescribedBy || undefined}
275
+ aria-describedby={ariaDescribedBy || (helperText || errorText ? `${uniqueID}-helper` : undefined)}
276
+ aria-required={required}
277
+ aria-invalid={error}
212
278
  {disabled}
279
+ tabindex={tabIndex}
213
280
  class="switch switch--modern"
214
281
  class:checked
215
282
  class:loading
216
283
  class:shadow
217
284
  class:outline
285
+ class:error
218
286
  on:click={handleClick}
219
287
  on:keydown={handleKeyDown}
288
+ on:focus={handleFocus}
289
+ on:blur={handleBlur}
220
290
  style="
221
291
  --active-color: {activeColor};
222
292
  --off-color: {offColor};
@@ -243,6 +313,11 @@
243
313
  {#if label && labelPosition === 'right'}
244
314
  <span class="switch-label" id="{uniqueID}-label">{label}</span>
245
315
  {/if}
316
+ {#if helperText || errorText}
317
+ <span class="switch-helper-text" id="{uniqueID}-helper" class:error-text={error}>
318
+ {error && errorText ? errorText : helperText}
319
+ </span>
320
+ {/if}
246
321
  </div>
247
322
 
248
323
  {:else if design === 'material'}
@@ -261,15 +336,21 @@
261
336
  aria-checked={checked}
262
337
  aria-label={ariaLabel || label}
263
338
  aria-labelledby={label ? `${uniqueID}-label` : undefined}
264
- aria-describedby={ariaDescribedBy || undefined}
339
+ aria-describedby={ariaDescribedBy || (helperText || errorText ? `${uniqueID}-helper` : undefined)}
340
+ aria-required={required}
341
+ aria-invalid={error}
265
342
  {disabled}
343
+ tabindex={tabIndex}
266
344
  class="switch switch--material"
267
345
  class:checked
268
346
  class:loading
269
347
  class:shadow
270
348
  class:outline
349
+ class:error
271
350
  on:click={handleClick}
272
351
  on:keydown={handleKeyDown}
352
+ on:focus={handleFocus}
353
+ on:blur={handleBlur}
273
354
  style="
274
355
  --active-color: {activeColor};
275
356
  --off-color: {offColor};
@@ -288,6 +369,11 @@
288
369
  {#if label && labelPosition === 'right'}
289
370
  <span class="switch-label" id="{uniqueID}-label">{label}</span>
290
371
  {/if}
372
+ {#if helperText || errorText}
373
+ <span class="switch-helper-text" id="{uniqueID}-helper" class:error-text={error}>
374
+ {error && errorText ? errorText : helperText}
375
+ </span>
376
+ {/if}
291
377
  </div>
292
378
 
293
379
  {:else if design === 'multi'}
@@ -317,9 +403,13 @@
317
403
  <input
318
404
  type="radio"
319
405
  id="{uniqueID}-{option}"
406
+ {name}
320
407
  value={option}
321
408
  bind:group={value}
409
+ on:change={handleMultiChange}
322
410
  {disabled}
411
+ {required}
412
+ tabindex={tabIndex}
323
413
  class="switch-multi-input"
324
414
  />
325
415
  <label
@@ -333,6 +423,11 @@
333
423
  {/each}
334
424
  </div>
335
425
  </div>
426
+ {#if helperText || errorText}
427
+ <span class="switch-helper-text" id="{uniqueID}-helper" class:error-text={error}>
428
+ {error && errorText ? errorText : helperText}
429
+ </span>
430
+ {/if}
336
431
  </div>
337
432
  {/if}
338
433
 
@@ -367,6 +462,19 @@
367
462
  color: #374151;
368
463
  }
369
464
 
465
+ /* v2.1.0 - Helper Text */
466
+ .switch-helper-text {
467
+ display: block;
468
+ font-size: 0.875em;
469
+ color: #6B7280;
470
+ margin-top: 0.375em;
471
+ line-height: 1.4;
472
+ }
473
+
474
+ .switch-helper-text.error-text {
475
+ color: #EF4444;
476
+ }
477
+
370
478
  /* Base Switch */
371
479
  .switch {
372
480
  position: relative;
@@ -393,6 +501,15 @@
393
501
  border: 1px solid #D1D5DB;
394
502
  }
395
503
 
504
+ /* v2.1.0 - Error State */
505
+ .switch.error {
506
+ border-color: #EF4444;
507
+ }
508
+
509
+ .switch.error:focus-visible {
510
+ outline-color: #EF4444;
511
+ }
512
+
396
513
  /* Inner Design */
397
514
  .switch--inner {
398
515
  padding: 0.4em 0.8em;
Binary file
Binary file
package/CLAUDE.md DELETED
@@ -1,165 +0,0 @@
1
- # CLAUDE.md
2
-
3
- This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
-
5
- ## Project Overview
6
-
7
- This is an NPM package providing a comprehensive, accessible toggle switch component for Svelte applications. The package has been completely rewritten in version 2.0 with TypeScript support, multiple design variants, extensive customization options, and enhanced accessibility features.
8
-
9
- ## Development Commands
10
-
11
- ```bash
12
- # Install dependencies
13
- npm install
14
-
15
- # Start development server with hot reload
16
- npm run dev
17
-
18
- # Build the package for distribution
19
- npm run build
20
-
21
- # Preview production build
22
- npm run preview
23
-
24
- # Run TypeScript type checking
25
- npm run check
26
- ```
27
-
28
- ## Tech Stack
29
-
30
- - **Svelte 5.16.0**: Latest Svelte with runes support
31
- - **TypeScript 5.7.3**: Full type safety
32
- - **Vite 6.0.5**: Fast build tooling
33
- - **svelte-check**: TypeScript checking for Svelte files
34
-
35
- ## Architecture
36
-
37
- ### Component Structure
38
-
39
- The main component is located at `src/lib/Switch.svelte`. This single component supports five distinct design variants controlled by the `design` prop:
40
-
41
- - **slider/ios**: iOS-style toggle switch (default)
42
- - **inner**: Toggle button with visible ON/OFF text
43
- - **modern**: Enhanced slider with optional track icons
44
- - **material**: Google Material Design inspired toggle
45
- - **multi**: Radio group styled as a segmented control
46
-
47
- ### Component API Design
48
-
49
- The component uses a comprehensive props-based API with full TypeScript support:
50
-
51
- #### Core Props
52
- - `value`: Two-way bound state (boolean or string for multi design)
53
- - `label`: Accessible label text
54
- - `design`: Design variant selector
55
-
56
- #### Styling System
57
- - **Color Schemes**: 6 built-in schemes (blue, green, red, purple, orange, pink) + custom
58
- - **Size Variants**: xs, sm, md, lg, xl (mapped to rem values) or custom number
59
- - **Visual Options**: shadow, outline, rounded, labelPosition
60
-
61
- #### State Management
62
- - `disabled`: Prevents interaction, shows disabled UI
63
- - `loading`: Shows spinner animation, prevents interaction
64
- - `readonly`: Prevents changes but shows current state
65
-
66
- #### Icon System
67
- - `showIcons`: Enable icon display
68
- - `onIcon`/`offIcon`: Customizable icons (text/emoji/symbols)
69
- - Icons displayed differently per design variant
70
-
71
- #### Animation Customization
72
- - `animationDuration`: Transition duration in ms (default 300)
73
- - `animationEasing`: CSS easing function (default 'ease-in-out')
74
-
75
- #### Accessibility
76
- - `ariaLabel`: Custom ARIA label
77
- - `ariaDescribedBy`: Links to description element
78
- - `id`: Custom element ID (auto-generated if not provided)
79
-
80
- ### State Management
81
-
82
- The component uses Svelte's reactive statements (`$:`) to sync internal and external state:
83
-
84
- 1. **For slider/inner/modern/material designs**:
85
- - Internal `checked` boolean tracks state
86
- - Syncs with `value` prop (boolean or 'on'/'off' string)
87
- - Two-way binding via `bind:value`
88
-
89
- 2. **For multi design**:
90
- - Uses native radio input `bind:group`
91
- - Value is one of the strings from `options` array
92
- - No internal checked state needed
93
-
94
- 3. **Unique IDs**:
95
- - Auto-generated using `Math.floor(Math.random() * 1000000)`
96
- - Used for ARIA attributes (`aria-labelledby`, `id` attributes)
97
- - Can be overridden via `id` prop
98
-
99
- ### Accessibility Implementation
100
-
101
- Comprehensive ARIA and keyboard support:
102
-
103
- - **ARIA Roles**: `role="switch"` for toggles, `role="radiogroup"` for multi
104
- - **State Attributes**: `aria-checked` reflects current state
105
- - **Labeling**: `aria-labelledby` connects visual labels, `aria-describedby` for descriptions
106
- - **Keyboard Navigation**: Space and Enter keys toggle state
107
- - **Focus Management**: `:focus-visible` for keyboard-only focus rings
108
- - **Disabled State**: Properly communicated to assistive technologies
109
-
110
- ### Styling Architecture
111
-
112
- All styles are scoped within the component using Svelte's `<style>` block:
113
-
114
- - **CSS Custom Properties**: Used for theming (`--active-color`, `--off-color`, `--animation-duration`, `--animation-easing`)
115
- - **Design-Specific Classes**: `.switch--slider`, `.switch--inner`, `.switch--modern`, `.switch--material`, `.switch-multi`
116
- - **State Classes**: `.checked`, `.disabled`, `.loading`, `.shadow`, `.outline`
117
- - **Conditional Rendering**: `{#if design === 'variant'}` blocks for each design
118
- - **No External Dependencies**: Self-contained styling, no CSS framework required
119
-
120
- ### TypeScript Integration
121
-
122
- The component is written in TypeScript (`<script lang="ts">`):
123
-
124
- - All props have explicit type annotations
125
- - Union types for variant options (design, size, colorScheme)
126
- - Event handlers properly typed (MouseEvent, KeyboardEvent)
127
- - Exported types available for consumers
128
-
129
- ### Demo Application
130
-
131
- `src/App.svelte` serves as a comprehensive showcase of all component features:
132
-
133
- - Organized into sections by feature category
134
- - Interactive examples with state display
135
- - Beautiful gradient background with card-based layout
136
- - Responsive design for mobile devices
137
- - Not included in the distributed package (development only)
138
-
139
- ## Build Configuration
140
-
141
- ### Vite Config
142
- - Library mode enabled with entry point `src/lib/Switch.svelte`
143
- - Package name: 'SvelteToggleSwitch'
144
- - Standard Svelte plugin configuration
145
-
146
- ### TypeScript Config
147
- - Extends `@tsconfig/svelte` base configuration
148
- - ESNext target for modern JavaScript
149
- - Includes all `.svelte`, `.ts`, `.js`, and `.d.ts` files in `src/`
150
- - Composite project with references to `tsconfig.node.json`
151
-
152
- ### Package Configuration
153
- - Version 2.0.0 (major rewrite)
154
- - Peer dependency: Svelte 3.x, 4.x, or 5.x
155
- - Development dependencies all on latest versions
156
- - MIT licensed
157
-
158
- ## Key Design Decisions
159
-
160
- 1. **Single Component Approach**: All variants in one component file for easier maintenance
161
- 2. **CSS-in-JS via Custom Properties**: Enables dynamic theming without style duplication
162
- 3. **Progressive Enhancement**: Basic functionality without JavaScript, enhanced with interactivity
163
- 4. **Accessibility First**: ARIA and keyboard support built-in, not added later
164
- 5. **TypeScript Throughout**: Type safety for better DX and fewer runtime errors
165
- 6. **Zero Dependencies**: No runtime dependencies beyond Svelte peer dependency
package/src/App.svelte DELETED
@@ -1,409 +0,0 @@
1
- <script lang="ts">
2
- import Switch from './lib/Switch.svelte';
3
-
4
- // State variables for different examples
5
- let basicSwitch = false;
6
- let colorSwitch = false;
7
- let sizeSwitch = false;
8
- let disabledSwitch = false;
9
- let loadingSwitch = false;
10
- let iconSwitch = false;
11
- let multiSwitch = 'Option 1';
12
- let labelPositionSwitch = true;
13
- let animationSwitch = false;
14
- let innerSwitch = false;
15
- let modernSwitch = false;
16
- let materialSwitch = false;
17
-
18
- // Color schemes
19
- let greenSwitch = false;
20
- let redSwitch = false;
21
- let purpleSwitch = false;
22
- let orangeSwitch = false;
23
- let pinkSwitch = false;
24
-
25
- // Sizes
26
- let xsSwitch = false;
27
- let smSwitch = false;
28
- let mdSwitch = false;
29
- let lgSwitch = false;
30
- let xlSwitch = false;
31
- </script>
32
-
33
- <main>
34
- <header>
35
- <h1>Svelte Toggle Switch</h1>
36
- <p class="subtitle">A comprehensive, accessible toggle switch component for Svelte</p>
37
- </header>
38
-
39
- <section>
40
- <h2>Design Variants</h2>
41
- <div class="grid">
42
- <div class="card">
43
- <h3>Slider (iOS Style)</h3>
44
- <Switch bind:value={basicSwitch} label="Enable notifications" design="slider" />
45
- <p class="state">State: {basicSwitch}</p>
46
- </div>
47
-
48
- <div class="card">
49
- <h3>Inner</h3>
50
- <Switch bind:value={innerSwitch} label="Dark mode" design="inner" />
51
- <p class="state">State: {innerSwitch}</p>
52
- </div>
53
-
54
- <div class="card">
55
- <h3>Modern</h3>
56
- <Switch bind:value={modernSwitch} label="Auto-save" design="modern" />
57
- <p class="state">State: {modernSwitch}</p>
58
- </div>
59
-
60
- <div class="card">
61
- <h3>Material</h3>
62
- <Switch bind:value={materialSwitch} label="Bluetooth" design="material" />
63
- <p class="state">State: {materialSwitch}</p>
64
- </div>
65
- </div>
66
- </section>
67
-
68
- <section>
69
- <h2>Color Schemes</h2>
70
- <div class="grid">
71
- <div class="card">
72
- <h3>Blue (Default)</h3>
73
- <Switch bind:value={colorSwitch} label="Blue theme" colorScheme="blue" />
74
- </div>
75
-
76
- <div class="card">
77
- <h3>Green</h3>
78
- <Switch bind:value={greenSwitch} label="Green theme" colorScheme="green" />
79
- </div>
80
-
81
- <div class="card">
82
- <h3>Red</h3>
83
- <Switch bind:value={redSwitch} label="Red theme" colorScheme="red" />
84
- </div>
85
-
86
- <div class="card">
87
- <h3>Purple</h3>
88
- <Switch bind:value={purpleSwitch} label="Purple theme" colorScheme="purple" />
89
- </div>
90
-
91
- <div class="card">
92
- <h3>Orange</h3>
93
- <Switch bind:value={orangeSwitch} label="Orange theme" colorScheme="orange" />
94
- </div>
95
-
96
- <div class="card">
97
- <h3>Pink</h3>
98
- <Switch bind:value={pinkSwitch} label="Pink theme" colorScheme="pink" />
99
- </div>
100
- </div>
101
- </section>
102
-
103
- <section>
104
- <h2>Size Variants</h2>
105
- <div class="grid">
106
- <div class="card">
107
- <h3>Extra Small</h3>
108
- <Switch bind:value={xsSwitch} label="XS Size" size="xs" />
109
- </div>
110
-
111
- <div class="card">
112
- <h3>Small</h3>
113
- <Switch bind:value={smSwitch} label="Small Size" size="sm" />
114
- </div>
115
-
116
- <div class="card">
117
- <h3>Medium (Default)</h3>
118
- <Switch bind:value={mdSwitch} label="Medium Size" size="md" />
119
- </div>
120
-
121
- <div class="card">
122
- <h3>Large</h3>
123
- <Switch bind:value={lgSwitch} label="Large Size" size="lg" />
124
- </div>
125
-
126
- <div class="card">
127
- <h3>Extra Large</h3>
128
- <Switch bind:value={xlSwitch} label="XL Size" size="xl" />
129
- </div>
130
- </div>
131
- </section>
132
-
133
- <section>
134
- <h2>States</h2>
135
- <div class="grid">
136
- <div class="card">
137
- <h3>Disabled</h3>
138
- <Switch bind:value={disabledSwitch} label="Disabled switch" disabled />
139
- </div>
140
-
141
- <div class="card">
142
- <h3>Loading</h3>
143
- <Switch bind:value={loadingSwitch} label="Loading state" loading />
144
- </div>
145
-
146
- <div class="card">
147
- <h3>Read-only</h3>
148
- <Switch bind:value={disabledSwitch} label="Read-only switch" readonly />
149
- </div>
150
- </div>
151
- </section>
152
-
153
- <section>
154
- <h2>Icon Support</h2>
155
- <div class="grid">
156
- <div class="card">
157
- <h3>Slider with Icons</h3>
158
- <Switch
159
- bind:value={iconSwitch}
160
- label="Wi-Fi"
161
- design="slider"
162
- showIcons={true}
163
- onIcon="✓"
164
- offIcon="✕"
165
- />
166
- </div>
167
-
168
- <div class="card">
169
- <h3>Modern with Custom Icons</h3>
170
- <Switch
171
- bind:value={iconSwitch}
172
- label="Airplane Mode"
173
- design="modern"
174
- showIcons={true}
175
- onIcon="✈"
176
- offIcon="✕"
177
- colorScheme="purple"
178
- />
179
- </div>
180
-
181
- <div class="card">
182
- <h3>Custom Emoji Icons</h3>
183
- <Switch
184
- bind:value={iconSwitch}
185
- label="Theme"
186
- design="slider"
187
- showIcons={true}
188
- onIcon="🌙"
189
- offIcon="☀"
190
- colorScheme="orange"
191
- size="lg"
192
- />
193
- </div>
194
- </div>
195
- </section>
196
-
197
- <section>
198
- <h2>Multi-option Switch</h2>
199
- <div class="card">
200
- <h3>Toggle Group</h3>
201
- <Switch
202
- bind:value={multiSwitch}
203
- label="Select an option"
204
- design="multi"
205
- options={['Option 1', 'Option 2', 'Option 3']}
206
- />
207
- <p class="state">Selected: {multiSwitch}</p>
208
- </div>
209
-
210
- <div class="card">
211
- <h3>View Mode Selector</h3>
212
- <Switch
213
- bind:value={multiSwitch}
214
- label="View"
215
- design="multi"
216
- options={['Grid', 'List']}
217
- size="sm"
218
- colorScheme="green"
219
- />
220
- </div>
221
- </section>
222
-
223
- <section>
224
- <h2>Advanced Features</h2>
225
- <div class="grid">
226
- <div class="card">
227
- <h3>Label Position</h3>
228
- <Switch
229
- bind:value={labelPositionSwitch}
230
- label="Label on left"
231
- labelPosition="left"
232
- />
233
- </div>
234
-
235
- <div class="card">
236
- <h3>With Shadow</h3>
237
- <Switch bind:value={sizeSwitch} label="Shadow effect" shadow />
238
- </div>
239
-
240
- <div class="card">
241
- <h3>With Outline</h3>
242
- <Switch bind:value={sizeSwitch} label="Outline style" outline />
243
- </div>
244
-
245
- <div class="card">
246
- <h3>Custom Animation</h3>
247
- <Switch
248
- bind:value={animationSwitch}
249
- label="Slow animation"
250
- animationDuration={800}
251
- animationEasing="cubic-bezier(0.68, -0.55, 0.265, 1.55)"
252
- colorScheme="pink"
253
- />
254
- </div>
255
-
256
- <div class="card">
257
- <h3>Custom Colors</h3>
258
- <Switch
259
- bind:value={animationSwitch}
260
- label="Custom palette"
261
- colorScheme="custom"
262
- color="#FF6B6B"
263
- offColor="#F0F0F0"
264
- />
265
- </div>
266
- </div>
267
- </section>
268
-
269
- <footer>
270
- <p>Built with Svelte • TypeScript • Vite</p>
271
- <p>
272
- <a href="https://github.com/ishansasika/svelte-toggle-switch" target="_blank" rel="noopener">
273
- View on GitHub
274
- </a>
275
- </p>
276
- </footer>
277
- </main>
278
-
279
- <style>
280
- :root {
281
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
282
- Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
283
- line-height: 1.6;
284
- }
285
-
286
- main {
287
- max-width: 1200px;
288
- margin: 0 auto;
289
- padding: 2rem;
290
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
291
- min-height: 100vh;
292
- }
293
-
294
- header {
295
- text-align: center;
296
- margin-bottom: 3rem;
297
- color: white;
298
- }
299
-
300
- h1 {
301
- font-size: 3rem;
302
- margin: 0;
303
- font-weight: 700;
304
- letter-spacing: -0.02em;
305
- }
306
-
307
- .subtitle {
308
- font-size: 1.25rem;
309
- opacity: 0.9;
310
- margin-top: 0.5rem;
311
- }
312
-
313
- section {
314
- background: white;
315
- border-radius: 1rem;
316
- padding: 2rem;
317
- margin-bottom: 2rem;
318
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
319
- }
320
-
321
- h2 {
322
- margin-top: 0;
323
- color: #1f2937;
324
- font-size: 1.75rem;
325
- margin-bottom: 1.5rem;
326
- border-bottom: 2px solid #e5e7eb;
327
- padding-bottom: 0.5rem;
328
- }
329
-
330
- h3 {
331
- color: #4b5563;
332
- font-size: 1rem;
333
- margin-top: 0;
334
- margin-bottom: 1rem;
335
- font-weight: 600;
336
- }
337
-
338
- .grid {
339
- display: grid;
340
- grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
341
- gap: 1.5rem;
342
- }
343
-
344
- .card {
345
- background: #f9fafb;
346
- padding: 1.5rem;
347
- border-radius: 0.75rem;
348
- border: 1px solid #e5e7eb;
349
- transition: all 0.3s ease;
350
- }
351
-
352
- .card:hover {
353
- border-color: #d1d5db;
354
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
355
- transform: translateY(-2px);
356
- }
357
-
358
- .state {
359
- margin-top: 1rem;
360
- padding: 0.5rem;
361
- background: white;
362
- border-radius: 0.375rem;
363
- font-size: 0.875rem;
364
- color: #6b7280;
365
- font-family: 'Courier New', monospace;
366
- }
367
-
368
- footer {
369
- text-align: center;
370
- color: white;
371
- padding: 2rem 0;
372
- margin-top: 2rem;
373
- }
374
-
375
- footer p {
376
- margin: 0.5rem 0;
377
- }
378
-
379
- footer a {
380
- color: white;
381
- text-decoration: underline;
382
- }
383
-
384
- footer a:hover {
385
- opacity: 0.8;
386
- }
387
-
388
- @media (max-width: 768px) {
389
- main {
390
- padding: 1rem;
391
- }
392
-
393
- h1 {
394
- font-size: 2rem;
395
- }
396
-
397
- .subtitle {
398
- font-size: 1rem;
399
- }
400
-
401
- section {
402
- padding: 1.5rem;
403
- }
404
-
405
- .grid {
406
- grid-template-columns: 1fr;
407
- }
408
- }
409
- </style>
package/src/vite-env.d.ts DELETED
@@ -1,2 +0,0 @@
1
- /// <reference types="svelte" />
2
- /// <reference types="vite/client" />
package/tsconfig.json DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "extends": "@tsconfig/svelte/tsconfig.json",
3
- "compilerOptions": {
4
- "target": "ESNext",
5
- "useDefineForClassFields": true,
6
- "module": "ESNext",
7
- "resolveJsonModule": true,
8
- "allowJs": true,
9
- "checkJs": true,
10
- "isolatedModules": true,
11
- "moduleDetection": "force"
12
- },
13
- "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"]
14
- }
@@ -1,9 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "skipLibCheck": true,
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "allowSyntheticDefaultImports": true
7
- },
8
- "include": ["vite.config.js"]
9
- }