@marianmeres/stuic 2.5.0 → 2.6.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/dist/actions/popover/README.md +145 -0
- package/dist/actions/tooltip/README.md +132 -0
- package/dist/components/AlertConfirmPrompt/README.md +139 -0
- package/dist/components/AnimatedElipsis/README.md +42 -0
- package/dist/components/AppShell/README.md +99 -0
- package/dist/components/Backdrop/README.md +81 -0
- package/dist/components/Button/README.md +83 -0
- package/dist/components/ButtonGroupRadio/README.md +94 -0
- package/dist/components/Circle/README.md +70 -0
- package/dist/components/ColorScheme/README.md +64 -0
- package/dist/components/CommandMenu/README.md +97 -0
- package/dist/components/DismissibleMessage/README.md +91 -0
- package/dist/components/Drawer/README.md +110 -0
- package/dist/components/HoverExpandableWidth/README.md +81 -0
- package/dist/components/Input/README.md +192 -0
- package/dist/components/KbdShortcut/README.md +81 -0
- package/dist/components/Modal/README.md +117 -0
- package/dist/components/ModalDialog/README.md +103 -0
- package/dist/components/Notifications/README.md +144 -0
- package/dist/components/Progress/README.md +71 -0
- package/dist/components/SlidingPanels/README.md +123 -0
- package/dist/components/Spinner/README.md +80 -0
- package/dist/components/Switch/README.md +113 -0
- package/dist/components/Thc/README.md +113 -0
- package/dist/components/TwCheck/README.md +54 -0
- package/dist/components/TypeaheadInput/README.md +116 -0
- package/dist/components/X/README.md +69 -0
- package/package.json +1 -1
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Input
|
|
2
|
+
|
|
3
|
+
A comprehensive form input system with multiple field components, validation support, and flexible layouts.
|
|
4
|
+
|
|
5
|
+
## Components
|
|
6
|
+
|
|
7
|
+
| Component | Description |
|
|
8
|
+
|-----------|-------------|
|
|
9
|
+
| `FieldInput` | Text, email, password, number, and other input types |
|
|
10
|
+
| `FieldTextarea` | Multi-line text input with auto-grow |
|
|
11
|
+
| `FieldSelect` | Dropdown select with option groups |
|
|
12
|
+
| `FieldCheckbox` | Single checkbox with label |
|
|
13
|
+
| `FieldRadios` | Radio button group |
|
|
14
|
+
| `FieldSwitch` | Toggle switch field |
|
|
15
|
+
| `FieldFile` | File upload input |
|
|
16
|
+
| `FieldAssets` | Asset/image upload with preview |
|
|
17
|
+
| `FieldLikeButton` | Like/favorite toggle button |
|
|
18
|
+
| `Fieldset` | Fieldset with legend |
|
|
19
|
+
|
|
20
|
+
## Common Props (FieldInput, FieldTextarea, FieldSelect)
|
|
21
|
+
|
|
22
|
+
| Prop | Type | Default | Description |
|
|
23
|
+
|------|------|---------|-------------|
|
|
24
|
+
| `value` | `string \| number` | - | Field value (bindable) |
|
|
25
|
+
| `input` | `HTMLInputElement` | - | Element reference (bindable) |
|
|
26
|
+
| `label` | `Snippet \| THC` | - | Field label |
|
|
27
|
+
| `description` | `Snippet \| THC` | - | Help text below field |
|
|
28
|
+
| `id` | `string` | auto | Element ID |
|
|
29
|
+
| `renderSize` | `"sm" \| "md" \| "lg"` | `"md"` | Visual size |
|
|
30
|
+
| `required` | `boolean` | `false` | Mark as required |
|
|
31
|
+
| `disabled` | `boolean` | `false` | Disable field |
|
|
32
|
+
| `validate` | `boolean \| ValidateOptions` | - | Enable validation |
|
|
33
|
+
| `labelLeft` | `boolean` | `false` | Position label on left |
|
|
34
|
+
| `labelLeftWidth` | `"normal" \| "wide"` | `"normal"` | Left label width |
|
|
35
|
+
| `useTrim` | `boolean` | `true` | Auto-trim whitespace |
|
|
36
|
+
| `class` | `string` | - | Container CSS |
|
|
37
|
+
| `classInput` | `string` | - | Input element CSS |
|
|
38
|
+
| `classLabel` | `string` | - | Label CSS |
|
|
39
|
+
|
|
40
|
+
## Slot Props
|
|
41
|
+
|
|
42
|
+
| Prop | Type | Description |
|
|
43
|
+
|------|------|-------------|
|
|
44
|
+
| `labelAfter` | `Snippet \| THC` | Content after label |
|
|
45
|
+
| `inputBefore` | `Snippet \| THC` | Content before input (inside wrapper) |
|
|
46
|
+
| `inputAfter` | `Snippet \| THC` | Content after input (inside wrapper) |
|
|
47
|
+
| `inputBelow` | `Snippet \| THC` | Content below input |
|
|
48
|
+
| `below` | `Snippet \| THC` | Content below entire field |
|
|
49
|
+
|
|
50
|
+
## Usage
|
|
51
|
+
|
|
52
|
+
### Basic Text Input
|
|
53
|
+
|
|
54
|
+
```svelte
|
|
55
|
+
<script lang="ts">
|
|
56
|
+
import { FieldInput } from 'stuic';
|
|
57
|
+
|
|
58
|
+
let name = $state('');
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
<FieldInput
|
|
62
|
+
label="Name"
|
|
63
|
+
bind:value={name}
|
|
64
|
+
placeholder="Enter your name"
|
|
65
|
+
required
|
|
66
|
+
/>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### With Validation
|
|
70
|
+
|
|
71
|
+
```svelte
|
|
72
|
+
<FieldInput
|
|
73
|
+
label="Email"
|
|
74
|
+
type="email"
|
|
75
|
+
bind:value={email}
|
|
76
|
+
validate
|
|
77
|
+
required
|
|
78
|
+
/>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Select Field
|
|
82
|
+
|
|
83
|
+
```svelte
|
|
84
|
+
<script lang="ts">
|
|
85
|
+
import { FieldSelect } from 'stuic';
|
|
86
|
+
|
|
87
|
+
let country = $state('');
|
|
88
|
+
</script>
|
|
89
|
+
|
|
90
|
+
<FieldSelect
|
|
91
|
+
label="Country"
|
|
92
|
+
bind:value={country}
|
|
93
|
+
options={[
|
|
94
|
+
{ label: 'United States', value: 'us' },
|
|
95
|
+
{ label: 'Canada', value: 'ca' },
|
|
96
|
+
{ label: 'Mexico', value: 'mx' }
|
|
97
|
+
]}
|
|
98
|
+
/>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Grouped Select Options
|
|
102
|
+
|
|
103
|
+
```svelte
|
|
104
|
+
<FieldSelect
|
|
105
|
+
label="City"
|
|
106
|
+
options={[
|
|
107
|
+
{ label: 'New York', value: 'ny', optgroup: 'USA' },
|
|
108
|
+
{ label: 'Los Angeles', value: 'la', optgroup: 'USA' },
|
|
109
|
+
{ label: 'Toronto', value: 'to', optgroup: 'Canada' }
|
|
110
|
+
]}
|
|
111
|
+
/>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Textarea with Auto-grow
|
|
115
|
+
|
|
116
|
+
```svelte
|
|
117
|
+
<script lang="ts">
|
|
118
|
+
import { FieldTextarea } from 'stuic';
|
|
119
|
+
|
|
120
|
+
let message = $state('');
|
|
121
|
+
</script>
|
|
122
|
+
|
|
123
|
+
<FieldTextarea
|
|
124
|
+
label="Message"
|
|
125
|
+
bind:value={message}
|
|
126
|
+
useAutogrow
|
|
127
|
+
rows={3}
|
|
128
|
+
/>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Checkbox
|
|
132
|
+
|
|
133
|
+
```svelte
|
|
134
|
+
<script lang="ts">
|
|
135
|
+
import { FieldCheckbox } from 'stuic';
|
|
136
|
+
|
|
137
|
+
let agreed = $state(false);
|
|
138
|
+
</script>
|
|
139
|
+
|
|
140
|
+
<FieldCheckbox
|
|
141
|
+
label="I agree to the terms"
|
|
142
|
+
bind:checked={agreed}
|
|
143
|
+
required
|
|
144
|
+
/>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Input with Addons
|
|
148
|
+
|
|
149
|
+
```svelte
|
|
150
|
+
<FieldInput
|
|
151
|
+
label="Price"
|
|
152
|
+
type="number"
|
|
153
|
+
bind:value={price}
|
|
154
|
+
>
|
|
155
|
+
{#snippet inputBefore()}
|
|
156
|
+
<span class="px-3 text-gray-500">$</span>
|
|
157
|
+
{/snippet}
|
|
158
|
+
{#snippet inputAfter()}
|
|
159
|
+
<span class="px-3 text-gray-500">.00</span>
|
|
160
|
+
{/snippet}
|
|
161
|
+
</FieldInput>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Left-aligned Label
|
|
165
|
+
|
|
166
|
+
```svelte
|
|
167
|
+
<FieldInput
|
|
168
|
+
label="Username"
|
|
169
|
+
bind:value={username}
|
|
170
|
+
labelLeft
|
|
171
|
+
labelLeftWidth="wide"
|
|
172
|
+
/>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Validation
|
|
176
|
+
|
|
177
|
+
Validation is handled by the `validate` action. Pass `validate={true}` for default HTML5 validation, or pass options:
|
|
178
|
+
|
|
179
|
+
```svelte
|
|
180
|
+
<FieldInput
|
|
181
|
+
label="Custom"
|
|
182
|
+
bind:value={val}
|
|
183
|
+
validate={{
|
|
184
|
+
validatorFn: (el) => {
|
|
185
|
+
if (el.value.length < 3) {
|
|
186
|
+
return { valid: false, message: 'Min 3 characters' };
|
|
187
|
+
}
|
|
188
|
+
return { valid: true };
|
|
189
|
+
}
|
|
190
|
+
}}
|
|
191
|
+
/>
|
|
192
|
+
```
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# KbdShortcut
|
|
2
|
+
|
|
3
|
+
Display keyboard shortcuts with platform-aware modifier key symbols. Automatically shows the correct symbols for macOS (⌘, ⌥, ⇧) vs Windows/Linux (Win, Ctrl, Alt).
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
|------|------|---------|-------------|
|
|
9
|
+
| `keys` | `string` | - | The key(s) to display (e.g., `"K"`, `"Enter"`) |
|
|
10
|
+
| `metas` | `KnownMeta[]` | `[]` | Array of modifier keys |
|
|
11
|
+
| `forcedOs` | `"mac" \| "win" \| "linux"` | - | Force specific OS symbols |
|
|
12
|
+
| `class` | `string` | - | CSS classes |
|
|
13
|
+
|
|
14
|
+
## Meta Keys
|
|
15
|
+
|
|
16
|
+
| Meta | macOS | Windows/Linux |
|
|
17
|
+
|------|-------|---------------|
|
|
18
|
+
| `cmd` | ⌘ | ⊞ |
|
|
19
|
+
| `meta` | ⌘ | ⊞ |
|
|
20
|
+
| `win` | ⌘ | ⊞ |
|
|
21
|
+
| `opt` | ⌥ | Alt |
|
|
22
|
+
| `alt` | ⌥ | Alt |
|
|
23
|
+
| `shift` | ⇧ | ⇧ |
|
|
24
|
+
| `ctrl` | ⌃ | Ctrl |
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
### Basic Shortcut
|
|
29
|
+
|
|
30
|
+
```svelte
|
|
31
|
+
<script lang="ts">
|
|
32
|
+
import { KbdShortcut } from 'stuic';
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<KbdShortcut metas={['cmd']} keys="K" />
|
|
36
|
+
<!-- macOS: ⌘K -->
|
|
37
|
+
<!-- Windows: ⊞K -->
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Multiple Modifiers
|
|
41
|
+
|
|
42
|
+
```svelte
|
|
43
|
+
<KbdShortcut metas={['cmd', 'shift']} keys="P" />
|
|
44
|
+
<!-- macOS: ⌘⇧P -->
|
|
45
|
+
<!-- Windows: ⊞⇧P -->
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Key Only
|
|
49
|
+
|
|
50
|
+
```svelte
|
|
51
|
+
<KbdShortcut keys="Enter" />
|
|
52
|
+
<!-- Displays: Enter -->
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Force Specific OS
|
|
56
|
+
|
|
57
|
+
```svelte
|
|
58
|
+
<KbdShortcut metas={['cmd']} keys="S" forcedOs="mac" />
|
|
59
|
+
<!-- Always shows: ⌘S -->
|
|
60
|
+
|
|
61
|
+
<KbdShortcut metas={['cmd']} keys="S" forcedOs="win" />
|
|
62
|
+
<!-- Always shows: ⊞S -->
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### In Context
|
|
66
|
+
|
|
67
|
+
```svelte
|
|
68
|
+
<p>
|
|
69
|
+
Press <KbdShortcut metas={['cmd']} keys="K" /> to open search
|
|
70
|
+
</p>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Custom Styling
|
|
74
|
+
|
|
75
|
+
```svelte
|
|
76
|
+
<KbdShortcut
|
|
77
|
+
metas={['cmd', 'shift']}
|
|
78
|
+
keys="Z"
|
|
79
|
+
class="bg-gray-100 px-2 py-1"
|
|
80
|
+
/>
|
|
81
|
+
```
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Modal
|
|
2
|
+
|
|
3
|
+
A centered modal dialog with optional header and footer sections. Built on top of `Backdrop` with focus trap and scroll locking.
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
|------|------|---------|-------------|
|
|
9
|
+
| `visible` | `boolean` | `false` | Controls visibility (bindable) |
|
|
10
|
+
| `focusTrap` | `boolean \| FocusTrapOptions` | `true` | Enable focus trapping |
|
|
11
|
+
| `transitionDuration` | `number` | `100` | Fade transition duration (ms) |
|
|
12
|
+
| `onEscape` | `() => void` | - | Callback on Escape key |
|
|
13
|
+
| `noScrollLock` | `boolean` | `false` | Disable body scroll lock |
|
|
14
|
+
| `classBackdrop` | `string` | - | CSS for backdrop overlay |
|
|
15
|
+
| `classInner` | `string` | - | CSS for inner width container |
|
|
16
|
+
| `class` | `string` | - | CSS for modal box |
|
|
17
|
+
| `classHeader` | `string` | - | CSS for header section |
|
|
18
|
+
| `classMain` | `string` | - | CSS for main content |
|
|
19
|
+
| `classFooter` | `string` | - | CSS for footer section |
|
|
20
|
+
| `labelledby` | `string` | - | ARIA labelledby ID |
|
|
21
|
+
| `describedby` | `string` | - | ARIA describedby ID |
|
|
22
|
+
| `el` | `HTMLDivElement` | - | Modal element reference (bindable) |
|
|
23
|
+
| `elBackdrop` | `HTMLDivElement` | - | Backdrop element reference (bindable) |
|
|
24
|
+
|
|
25
|
+
## Snippets
|
|
26
|
+
|
|
27
|
+
| Snippet | Description |
|
|
28
|
+
|---------|-------------|
|
|
29
|
+
| `header` | Optional header section |
|
|
30
|
+
| `children` | Main modal content |
|
|
31
|
+
| `footer` | Optional footer section |
|
|
32
|
+
|
|
33
|
+
## Methods
|
|
34
|
+
|
|
35
|
+
| Method | Description |
|
|
36
|
+
|--------|-------------|
|
|
37
|
+
| `open(opener?)` | Open modal, optionally track opener element |
|
|
38
|
+
| `close()` | Close modal |
|
|
39
|
+
| `setOpener(el)` | Set element to refocus when closed |
|
|
40
|
+
| `visibility()` | Returns object with `visible` getter |
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
### Basic Modal
|
|
45
|
+
|
|
46
|
+
```svelte
|
|
47
|
+
<script lang="ts">
|
|
48
|
+
import { Modal } from 'stuic';
|
|
49
|
+
|
|
50
|
+
let modal: Modal;
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<button onclick={(e) => modal.open(e)}>Open Modal</button>
|
|
54
|
+
|
|
55
|
+
<Modal
|
|
56
|
+
bind:this={modal}
|
|
57
|
+
onEscape={() => modal.close()}
|
|
58
|
+
>
|
|
59
|
+
<div class="p-6">
|
|
60
|
+
<h2>Modal Title</h2>
|
|
61
|
+
<p>Modal content goes here.</p>
|
|
62
|
+
<button onclick={() => modal.close()}>Close</button>
|
|
63
|
+
</div>
|
|
64
|
+
</Modal>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### With Header and Footer
|
|
68
|
+
|
|
69
|
+
```svelte
|
|
70
|
+
<Modal bind:this={modal} onEscape={() => modal.close()}>
|
|
71
|
+
{#snippet header()}
|
|
72
|
+
<div class="p-4 border-b">
|
|
73
|
+
<h2>Confirm Action</h2>
|
|
74
|
+
</div>
|
|
75
|
+
{/snippet}
|
|
76
|
+
|
|
77
|
+
<div class="p-6">
|
|
78
|
+
Are you sure you want to proceed?
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
{#snippet footer()}
|
|
82
|
+
<div class="p-4 border-t flex justify-end gap-2">
|
|
83
|
+
<button onclick={() => modal.close()}>Cancel</button>
|
|
84
|
+
<button onclick={handleConfirm}>Confirm</button>
|
|
85
|
+
</div>
|
|
86
|
+
{/snippet}
|
|
87
|
+
</Modal>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### With Visibility Binding
|
|
91
|
+
|
|
92
|
+
```svelte
|
|
93
|
+
<script lang="ts">
|
|
94
|
+
let visible = $state(false);
|
|
95
|
+
</script>
|
|
96
|
+
|
|
97
|
+
<button onclick={() => visible = true}>Open</button>
|
|
98
|
+
|
|
99
|
+
<Modal
|
|
100
|
+
bind:visible
|
|
101
|
+
onEscape={() => visible = false}
|
|
102
|
+
>
|
|
103
|
+
<div class="p-6">Content</div>
|
|
104
|
+
</Modal>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Custom Sizing
|
|
108
|
+
|
|
109
|
+
```svelte
|
|
110
|
+
<Modal
|
|
111
|
+
bind:this={modal}
|
|
112
|
+
classInner="max-w-lg"
|
|
113
|
+
class="rounded-lg"
|
|
114
|
+
>
|
|
115
|
+
<div class="p-6">Smaller modal</div>
|
|
116
|
+
</Modal>
|
|
117
|
+
```
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# ModalDialog
|
|
2
|
+
|
|
3
|
+
A modal component using the native HTML `<dialog>` element with `showModal()`. Provides built-in backdrop, focus management, and accessibility.
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
|------|------|---------|-------------|
|
|
9
|
+
| `noClickOutsideClose` | `boolean` | `false` | Disable close on outside click |
|
|
10
|
+
| `noEscapeClose` | `boolean` | `false` | Disable close on Escape key |
|
|
11
|
+
| `preEscapeClose` | `() => any` | - | Hook before Escape close (return `false` to prevent) |
|
|
12
|
+
| `preClose` | `() => any` | - | Hook before any close (return `false` to prevent) |
|
|
13
|
+
| `type` | `string` | - | Optional UI hint (added as `data-type` attribute) |
|
|
14
|
+
| `class` | `string` | - | CSS for content box |
|
|
15
|
+
| `classDialog` | `string` | - | CSS for dialog element |
|
|
16
|
+
|
|
17
|
+
## Methods
|
|
18
|
+
|
|
19
|
+
| Method | Description |
|
|
20
|
+
|--------|-------------|
|
|
21
|
+
| `open(opener?)` | Open modal with `showModal()`, optionally track opener |
|
|
22
|
+
| `close()` | Close modal |
|
|
23
|
+
| `setOpener(el)` | Set element to refocus when closed |
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
### Basic Dialog
|
|
28
|
+
|
|
29
|
+
```svelte
|
|
30
|
+
<script lang="ts">
|
|
31
|
+
import { ModalDialog } from 'stuic';
|
|
32
|
+
|
|
33
|
+
let dialog: ModalDialog;
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<button onclick={(e) => dialog.open(e)}>Open Dialog</button>
|
|
37
|
+
|
|
38
|
+
<ModalDialog bind:this={dialog} class="p-6 rounded-lg max-w-md">
|
|
39
|
+
<h2>Dialog Title</h2>
|
|
40
|
+
<p>This uses the native dialog element.</p>
|
|
41
|
+
<button onclick={() => dialog.close()}>Close</button>
|
|
42
|
+
</ModalDialog>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### With Pre-close Validation
|
|
46
|
+
|
|
47
|
+
```svelte
|
|
48
|
+
<script lang="ts">
|
|
49
|
+
let hasUnsavedChanges = $state(false);
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<ModalDialog
|
|
53
|
+
bind:this={dialog}
|
|
54
|
+
preClose={() => {
|
|
55
|
+
if (hasUnsavedChanges) {
|
|
56
|
+
return confirm('Discard unsaved changes?');
|
|
57
|
+
}
|
|
58
|
+
}}
|
|
59
|
+
class="p-6 rounded-lg"
|
|
60
|
+
>
|
|
61
|
+
<form>
|
|
62
|
+
<input oninput={() => hasUnsavedChanges = true} />
|
|
63
|
+
<button type="button" onclick={() => dialog.close()}>Close</button>
|
|
64
|
+
</form>
|
|
65
|
+
</ModalDialog>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Prevent Outside Click Close
|
|
69
|
+
|
|
70
|
+
```svelte
|
|
71
|
+
<ModalDialog
|
|
72
|
+
bind:this={dialog}
|
|
73
|
+
noClickOutsideClose
|
|
74
|
+
class="p-6 rounded-lg"
|
|
75
|
+
>
|
|
76
|
+
<p>Click outside won't close this dialog.</p>
|
|
77
|
+
<button onclick={() => dialog.close()}>Close</button>
|
|
78
|
+
</ModalDialog>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Async Pre-close Hook
|
|
82
|
+
|
|
83
|
+
```svelte
|
|
84
|
+
<ModalDialog
|
|
85
|
+
bind:this={dialog}
|
|
86
|
+
preEscapeClose={async () => {
|
|
87
|
+
const shouldClose = await confirmAction();
|
|
88
|
+
return shouldClose;
|
|
89
|
+
}}
|
|
90
|
+
>
|
|
91
|
+
Content
|
|
92
|
+
</ModalDialog>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Differences from Modal
|
|
96
|
+
|
|
97
|
+
| Feature | Modal | ModalDialog |
|
|
98
|
+
|---------|-------|-------------|
|
|
99
|
+
| Implementation | Custom backdrop | Native `<dialog>` |
|
|
100
|
+
| Backdrop | Via `Backdrop` component | Native `::backdrop` |
|
|
101
|
+
| Browser support | All modern | Requires `<dialog>` support |
|
|
102
|
+
| Stacking | Manual z-index | Top layer (always on top) |
|
|
103
|
+
| Accessibility | Manual ARIA | Built-in |
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Notifications
|
|
2
|
+
|
|
3
|
+
A toast notification system with auto-disposal, deduplication, progress indicators, and flexible positioning.
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
|------|------|---------|-------------|
|
|
9
|
+
| `notifications` | `NotificationsStack` | - | Stack instance (required) |
|
|
10
|
+
| `posX` | `"left" \| "center" \| "right"` | `"right"` | Horizontal position (desktop) |
|
|
11
|
+
| `posY` | `"top" \| "center" \| "bottom"` | `"top"` | Vertical position (desktop) |
|
|
12
|
+
| `posXMobile` | `"left" \| "center" \| "right"` | `"center"` | Horizontal position (mobile) |
|
|
13
|
+
| `posYMobile` | `"top" \| "center" \| "bottom"` | `"top"` | Vertical position (mobile) |
|
|
14
|
+
| `themeInfo` | `TW_COLORS` | `"neutral"` | Color theme for info notifications |
|
|
15
|
+
| `themeError` | `TW_COLORS` | `"red"` | Color theme for error notifications |
|
|
16
|
+
| `themeWarn` | `TW_COLORS` | `"yellow"` | Color theme for warning notifications |
|
|
17
|
+
| `themeSuccess` | `TW_COLORS` | `"green"` | Color theme for success notifications |
|
|
18
|
+
| `noTheme` | `boolean` | `false` | Disable color theming |
|
|
19
|
+
| `noIcons` | `boolean` | `false` | Hide notification icons |
|
|
20
|
+
| `noProgress` | `boolean` | `false` | Hide TTL progress bar |
|
|
21
|
+
| `noXButton` | `boolean` | `false` | Hide close button |
|
|
22
|
+
| `duration` | `number` | `200` | Fade transition duration (ms) |
|
|
23
|
+
| `forceAsHtml` | `boolean` | - | Render content as HTML |
|
|
24
|
+
| `iconFns` | `Record<type, () => string>` | - | Custom icon functions |
|
|
25
|
+
|
|
26
|
+
## NotificationsStack API
|
|
27
|
+
|
|
28
|
+
### Constructor Options
|
|
29
|
+
|
|
30
|
+
| Option | Type | Default | Description |
|
|
31
|
+
|--------|------|---------|-------------|
|
|
32
|
+
| `maxCapacity` | `number` | `5` | Maximum notifications in queue |
|
|
33
|
+
| `defaultTtl` | `number` | `3000` | Default time-to-live (ms) |
|
|
34
|
+
| `extraTtlPerChar` | `number` | `20` | Extra TTL per content character |
|
|
35
|
+
| `sortOrder` | `"asc" \| "desc"` | `"asc"` | Stack sort order |
|
|
36
|
+
| `disposeInterval` | `number` | `500` | Auto-dispose check interval (ms) |
|
|
37
|
+
|
|
38
|
+
### Methods
|
|
39
|
+
|
|
40
|
+
| Method | Description |
|
|
41
|
+
|--------|-------------|
|
|
42
|
+
| `info(content, opts?)` | Add info notification |
|
|
43
|
+
| `success(content, opts?)` | Add success notification |
|
|
44
|
+
| `warn(content, opts?)` | Add warning notification |
|
|
45
|
+
| `error(content, opts?)` | Add error notification |
|
|
46
|
+
| `removeById(id)` | Remove notification by ID |
|
|
47
|
+
| `reset()` | Clear all notifications |
|
|
48
|
+
| `destroy()` | Cleanup and stop ticker |
|
|
49
|
+
|
|
50
|
+
### Notification Options
|
|
51
|
+
|
|
52
|
+
| Option | Type | Description |
|
|
53
|
+
|--------|------|-------------|
|
|
54
|
+
| `id` | `string \| number` | Unique ID (auto-generated from content if omitted) |
|
|
55
|
+
| `ttl` | `number` | Time-to-live in ms (0 = no auto-dismiss) |
|
|
56
|
+
| `iconFn` | `(() => string) \| false` | Custom icon or `false` to hide |
|
|
57
|
+
| `forceAsHtml` | `boolean` | Render content as HTML |
|
|
58
|
+
|
|
59
|
+
## Usage
|
|
60
|
+
|
|
61
|
+
### Basic Setup
|
|
62
|
+
|
|
63
|
+
```svelte
|
|
64
|
+
<script lang="ts">
|
|
65
|
+
import { Notifications, NotificationsStack } from 'stuic';
|
|
66
|
+
|
|
67
|
+
const notifications = new NotificationsStack();
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<Notifications {notifications} />
|
|
71
|
+
|
|
72
|
+
<button onclick={() => notifications.info('Hello!')}>
|
|
73
|
+
Show Info
|
|
74
|
+
</button>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Different Types
|
|
78
|
+
|
|
79
|
+
```svelte
|
|
80
|
+
<script lang="ts">
|
|
81
|
+
notifications.info('Information message');
|
|
82
|
+
notifications.success('Operation successful!');
|
|
83
|
+
notifications.warn('Warning: check this');
|
|
84
|
+
notifications.error('An error occurred');
|
|
85
|
+
</script>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Custom TTL
|
|
89
|
+
|
|
90
|
+
```svelte
|
|
91
|
+
<script lang="ts">
|
|
92
|
+
// Auto-dismiss after 10 seconds
|
|
93
|
+
notifications.info('Long message', { ttl: 10000 });
|
|
94
|
+
|
|
95
|
+
// Never auto-dismiss
|
|
96
|
+
notifications.error('Critical error', { ttl: 0 });
|
|
97
|
+
</script>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Deduplication
|
|
101
|
+
|
|
102
|
+
```svelte
|
|
103
|
+
<script lang="ts">
|
|
104
|
+
// Same content = same ID = increments count instead of duplicating
|
|
105
|
+
notifications.info('Save completed');
|
|
106
|
+
notifications.info('Save completed'); // Shows "2" badge
|
|
107
|
+
</script>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Custom Positioning
|
|
111
|
+
|
|
112
|
+
```svelte
|
|
113
|
+
<Notifications
|
|
114
|
+
{notifications}
|
|
115
|
+
posX="left"
|
|
116
|
+
posY="bottom"
|
|
117
|
+
posXMobile="center"
|
|
118
|
+
posYMobile="bottom"
|
|
119
|
+
/>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Custom Stack Options
|
|
123
|
+
|
|
124
|
+
```svelte
|
|
125
|
+
<script lang="ts">
|
|
126
|
+
const notifications = new NotificationsStack([], {
|
|
127
|
+
maxCapacity: 3,
|
|
128
|
+
defaultTtl: 5000,
|
|
129
|
+
sortOrder: 'desc'
|
|
130
|
+
});
|
|
131
|
+
</script>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Cleanup
|
|
135
|
+
|
|
136
|
+
```svelte
|
|
137
|
+
<script lang="ts">
|
|
138
|
+
import { onDestroy } from 'svelte';
|
|
139
|
+
|
|
140
|
+
const notifications = new NotificationsStack();
|
|
141
|
+
|
|
142
|
+
onDestroy(() => notifications.destroy());
|
|
143
|
+
</script>
|
|
144
|
+
```
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Progress
|
|
2
|
+
|
|
3
|
+
A progress indicator available as either a horizontal bar or circular display.
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
|------|------|---------|-------------|
|
|
9
|
+
| `type` | `"bar" \| "circle"` | `"bar"` | Display type |
|
|
10
|
+
| `progress` | `number` | `0` | Progress value (0-100) |
|
|
11
|
+
| `class` | `string` | - | CSS for container |
|
|
12
|
+
| `classBar` | `string` | - | CSS for progress bar fill (bar type only) |
|
|
13
|
+
| `styleBar` | `string` | - | Inline styles for bar fill |
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### Basic Bar
|
|
18
|
+
|
|
19
|
+
```svelte
|
|
20
|
+
<script lang="ts">
|
|
21
|
+
import { Progress } from 'stuic';
|
|
22
|
+
|
|
23
|
+
let progress = $state(0);
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<Progress {progress} />
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Circle Progress
|
|
30
|
+
|
|
31
|
+
```svelte
|
|
32
|
+
<Progress type="circle" progress={75} class="size-16" />
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Animated Progress
|
|
36
|
+
|
|
37
|
+
```svelte
|
|
38
|
+
<script lang="ts">
|
|
39
|
+
let progress = $state(0);
|
|
40
|
+
|
|
41
|
+
function start() {
|
|
42
|
+
progress = 0;
|
|
43
|
+
const interval = setInterval(() => {
|
|
44
|
+
progress += 10;
|
|
45
|
+
if (progress >= 100) clearInterval(interval);
|
|
46
|
+
}, 300);
|
|
47
|
+
}
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<Progress {progress} />
|
|
51
|
+
<button onclick={start}>Start</button>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Custom Styling
|
|
55
|
+
|
|
56
|
+
```svelte
|
|
57
|
+
<Progress
|
|
58
|
+
progress={60}
|
|
59
|
+
class="h-2 bg-gray-200 rounded-full"
|
|
60
|
+
classBar="bg-blue-500 rounded-full"
|
|
61
|
+
/>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### With Transition
|
|
65
|
+
|
|
66
|
+
```svelte
|
|
67
|
+
<Progress
|
|
68
|
+
progress={value}
|
|
69
|
+
classBar="transition-all duration-300"
|
|
70
|
+
/>
|
|
71
|
+
```
|