@spaethtech/svelte-ui 0.1.10
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/README.md +81 -0
- package/dist/components/Badge/Badge.svelte +80 -0
- package/dist/components/Badge/Badge.svelte.d.ts +14 -0
- package/dist/components/Badge/index.d.ts +1 -0
- package/dist/components/Badge/index.js +1 -0
- package/dist/components/Button/Button.svelte +172 -0
- package/dist/components/Button/Button.svelte.d.ts +32 -0
- package/dist/components/Button/index.d.ts +1 -0
- package/dist/components/Button/index.js +1 -0
- package/dist/components/Dialog/Dialog.svelte +101 -0
- package/dist/components/Dialog/Dialog.svelte.d.ts +18 -0
- package/dist/components/Dialog/index.d.ts +1 -0
- package/dist/components/Dialog/index.js +1 -0
- package/dist/components/ElementManager/ElementManager.svelte +397 -0
- package/dist/components/ElementManager/ElementManager.svelte.d.ts +43 -0
- package/dist/components/ElementManager/index.d.ts +1 -0
- package/dist/components/ElementManager/index.js +1 -0
- package/dist/components/EmailInput/EmailInput.svelte +47 -0
- package/dist/components/EmailInput/EmailInput.svelte.d.ts +14 -0
- package/dist/components/EmailInput/index.d.ts +1 -0
- package/dist/components/EmailInput/index.js +1 -0
- package/dist/components/Icon/Icon.svelte +74 -0
- package/dist/components/Icon/Icon.svelte.d.ts +13 -0
- package/dist/components/Icon/index.d.ts +1 -0
- package/dist/components/Icon/index.js +1 -0
- package/dist/components/Input/Input.svelte +268 -0
- package/dist/components/Input/Input.svelte.d.ts +18 -0
- package/dist/components/Input/index.d.ts +1 -0
- package/dist/components/Input/index.js +1 -0
- package/dist/components/List/List.svelte +580 -0
- package/dist/components/List/List.svelte.d.ts +38 -0
- package/dist/components/List/index.d.ts +1 -0
- package/dist/components/List/index.js +1 -0
- package/dist/components/ListItem/ListItem.svelte +175 -0
- package/dist/components/ListItem/ListItem.svelte.d.ts +24 -0
- package/dist/components/ListItem/index.d.ts +2 -0
- package/dist/components/ListItem/index.js +2 -0
- package/dist/components/ListView/ListView.svelte +463 -0
- package/dist/components/ListView/ListView.svelte.d.ts +37 -0
- package/dist/components/ListView/index.d.ts +2 -0
- package/dist/components/ListView/index.js +2 -0
- package/dist/components/NodeGraph/BaseNode.d.ts +57 -0
- package/dist/components/NodeGraph/BaseNode.js +30 -0
- package/dist/components/NodeGraph/Edge.svelte +60 -0
- package/dist/components/NodeGraph/Edge.svelte.d.ts +16 -0
- package/dist/components/NodeGraph/ExpressionEvaluator.d.ts +82 -0
- package/dist/components/NodeGraph/ExpressionEvaluator.js +152 -0
- package/dist/components/NodeGraph/Node.svelte +100 -0
- package/dist/components/NodeGraph/Node.svelte.d.ts +10 -0
- package/dist/components/NodeGraph/NodeGraph.svelte +52 -0
- package/dist/components/NodeGraph/NodeGraph.svelte.d.ts +14 -0
- package/dist/components/NodeGraph/NodeInstance.svelte.d.ts +80 -0
- package/dist/components/NodeGraph/NodeInstance.svelte.js +241 -0
- package/dist/components/NodeGraph/NodePort.svelte +75 -0
- package/dist/components/NodeGraph/NodePort.svelte.d.ts +11 -0
- package/dist/components/NodeGraph/decorators.d.ts +81 -0
- package/dist/components/NodeGraph/decorators.js +148 -0
- package/dist/components/NodeGraph/index.d.ts +9 -0
- package/dist/components/NodeGraph/index.js +9 -0
- package/dist/components/NodeGraph/types.d.ts +94 -0
- package/dist/components/NodeGraph/types.js +33 -0
- package/dist/components/NotesEditor/NotesEditor.svelte +203 -0
- package/dist/components/NotesEditor/NotesEditor.svelte.d.ts +9 -0
- package/dist/components/NotesEditor/index.d.ts +1 -0
- package/dist/components/NotesEditor/index.js +1 -0
- package/dist/components/NumberInput/NumberInput.svelte +353 -0
- package/dist/components/NumberInput/NumberInput.svelte.d.ts +26 -0
- package/dist/components/NumberInput/index.d.ts +1 -0
- package/dist/components/NumberInput/index.js +1 -0
- package/dist/components/PasswordInput/PasswordInput.svelte +41 -0
- package/dist/components/PasswordInput/PasswordInput.svelte.d.ts +13 -0
- package/dist/components/PasswordInput/index.d.ts +1 -0
- package/dist/components/PasswordInput/index.js +1 -0
- package/dist/components/Popup/index.d.ts +1 -0
- package/dist/components/Popup/index.js +1 -0
- package/dist/components/Rating/Rating.svelte +77 -0
- package/dist/components/Rating/Rating.svelte.d.ts +7 -0
- package/dist/components/Rating/index.d.ts +1 -0
- package/dist/components/Rating/index.js +1 -0
- package/dist/components/ScrollView/ScrollView.svelte +285 -0
- package/dist/components/ScrollView/ScrollView.svelte.d.ts +19 -0
- package/dist/components/ScrollView/index.d.ts +1 -0
- package/dist/components/ScrollView/index.js +1 -0
- package/dist/components/SearchInput/SearchInput.svelte +50 -0
- package/dist/components/SearchInput/SearchInput.svelte.d.ts +15 -0
- package/dist/components/SearchInput/index.d.ts +1 -0
- package/dist/components/SearchInput/index.js +1 -0
- package/dist/components/Select/Select.svelte +278 -0
- package/dist/components/Select/Select.svelte.d.ts +35 -0
- package/dist/components/Select/index.d.ts +1 -0
- package/dist/components/Select/index.js +1 -0
- package/dist/components/TextArea/TextArea.svelte +734 -0
- package/dist/components/TextArea/TextArea.svelte.d.ts +19 -0
- package/dist/components/TextArea/index.d.ts +1 -0
- package/dist/components/TextArea/index.js +1 -0
- package/dist/components/ThemeSelector/ThemeSelector.svelte +64 -0
- package/dist/components/ThemeSelector/ThemeSelector.svelte.d.ts +3 -0
- package/dist/components/ThemeSelector/index.d.ts +1 -0
- package/dist/components/ThemeSelector/index.js +1 -0
- package/dist/components/TooltipHandler/TooltipHandler.svelte +593 -0
- package/dist/components/TooltipHandler/TooltipHandler.svelte.d.ts +10 -0
- package/dist/components/TooltipHandler/index.d.ts +1 -0
- package/dist/components/TooltipHandler/index.js +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +26 -0
- package/dist/styles/sizes.d.ts +78 -0
- package/dist/styles/sizes.js +120 -0
- package/dist/styles/variants.d.ts +106 -0
- package/dist/styles/variants.js +194 -0
- package/dist/types/ManagerTypes.d.ts +42 -0
- package/dist/types/ManagerTypes.js +1 -0
- package/dist/types/sizes.d.ts +5 -0
- package/dist/types/sizes.js +1 -0
- package/dist/types/variants.d.ts +1 -0
- package/dist/types/variants.js +1 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Svelte UI Component Library
|
|
2
|
+
|
|
3
|
+
A collection of reusable Svelte 5 UI components with Tailwind CSS styling and FontAwesome icon support.
|
|
4
|
+
|
|
5
|
+
See JUNIE.md for how Junie (our autonomous programmer) handles repository rules files like CLAUDE.md and .cursorrules.
|
|
6
|
+
|
|
7
|
+
## Components
|
|
8
|
+
|
|
9
|
+
- **Button** - Flexible button/anchor with variants and icon support
|
|
10
|
+
- **Dialog** - Modal dialog with backdrop handling
|
|
11
|
+
- **Input** - Enhanced text input with icons and validation
|
|
12
|
+
- **Select** - Custom dropdown with keyboard navigation
|
|
13
|
+
- **Rating** - Interactive star rating component
|
|
14
|
+
- **NotesEditor** - Auto-sizing textarea component
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# For local development
|
|
20
|
+
npm install ../path/to/svelte-ui/dist
|
|
21
|
+
|
|
22
|
+
# Or build from source
|
|
23
|
+
cd svelte-ui
|
|
24
|
+
npm install
|
|
25
|
+
npm run package
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Prerequisites
|
|
29
|
+
|
|
30
|
+
Your project must have these peer dependencies installed:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install svelte@^5.0.0 tailwindcss@^4.0.0
|
|
34
|
+
npm install @fortawesome/fontawesome-svg-core@^6.7.0
|
|
35
|
+
npm install @fortawesome/free-solid-svg-icons@^6.7.0
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Setup
|
|
39
|
+
|
|
40
|
+
### 1. Tailwind Configuration
|
|
41
|
+
|
|
42
|
+
Add the component paths to your `tailwind.config.js`:
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
export default {
|
|
46
|
+
content: [
|
|
47
|
+
'./src/**/*.{html,js,svelte,ts}',
|
|
48
|
+
'./node_modules/svelte-ui/**/*.{html,js,svelte,ts}'
|
|
49
|
+
],
|
|
50
|
+
// ... rest of config
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 2. Import Components
|
|
55
|
+
|
|
56
|
+
```svelte
|
|
57
|
+
<script>
|
|
58
|
+
import { Button, Dialog, Input, Select, Rating } from 'svelte-ui';
|
|
59
|
+
import { faSearch, faSave } from '@fortawesome/free-solid-svg-icons';
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<Button text="Click me" variant="primary" />
|
|
63
|
+
<Input bind:value={searchQuery} icon={faSearch} placeholder="Search..." />
|
|
64
|
+
<Select options={myOptions} bind:value={selected} />
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Development
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm run dev # Start demo server
|
|
71
|
+
npm run package # Build library
|
|
72
|
+
npm run check # TypeScript validation
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Demo
|
|
76
|
+
|
|
77
|
+
Run `npm run dev` to see all components in action at http://localhost:5173
|
|
78
|
+
|
|
79
|
+
## License
|
|
80
|
+
|
|
81
|
+
ISC
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Icon from "../Icon/Icon.svelte";
|
|
3
|
+
import type { IconDefinition } from "@fortawesome/free-solid-svg-icons";
|
|
4
|
+
import type { Variant } from "../../types/variants.js";
|
|
5
|
+
import type { Size } from "../../types/sizes.js";
|
|
6
|
+
import {
|
|
7
|
+
getVariantClasses,
|
|
8
|
+
getVariantStyles,
|
|
9
|
+
} from "../../styles/variants.js";
|
|
10
|
+
import {
|
|
11
|
+
badgeSizeClasses,
|
|
12
|
+
componentHeights,
|
|
13
|
+
textSizes,
|
|
14
|
+
} from "../../styles/sizes.js";
|
|
15
|
+
interface Props {
|
|
16
|
+
icon?: IconDefinition;
|
|
17
|
+
text?: string;
|
|
18
|
+
variant?: Variant;
|
|
19
|
+
size?: Size;
|
|
20
|
+
iconPosition?: "left" | "right";
|
|
21
|
+
rounded?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let {
|
|
25
|
+
icon,
|
|
26
|
+
text = "",
|
|
27
|
+
variant = "primary",
|
|
28
|
+
size = "md",
|
|
29
|
+
iconPosition = "left",
|
|
30
|
+
rounded = true,
|
|
31
|
+
}: Props = $props();
|
|
32
|
+
|
|
33
|
+
// Get text and icon adjustments from variant styles
|
|
34
|
+
const textAdjustment = $derived(getVariantStyles(variant).textAdjustment);
|
|
35
|
+
const iconAdjustment = $derived(getVariantStyles(variant).iconAdjustment);
|
|
36
|
+
|
|
37
|
+
// Icon-only badges should be square (w=h)
|
|
38
|
+
const isIconOnly = $derived(icon && !text);
|
|
39
|
+
|
|
40
|
+
// Map sizes to explicit widths (matching heights)
|
|
41
|
+
const squareWidths = {
|
|
42
|
+
sm: "w-7", // matches h-7
|
|
43
|
+
md: "w-8", // matches h-8
|
|
44
|
+
lg: "w-9", // matches h-9
|
|
45
|
+
} as const;
|
|
46
|
+
|
|
47
|
+
const sizeClasses = $derived(
|
|
48
|
+
isIconOnly
|
|
49
|
+
? `${componentHeights[size]} ${textSizes[size]} ${squareWidths[size]}`
|
|
50
|
+
: badgeSizeClasses[size],
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// Ghost variant uses outline (doesn't affect layout) instead of border
|
|
54
|
+
// Other variants don't need borders since they have solid backgrounds
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
{#if text || icon}
|
|
58
|
+
<span
|
|
59
|
+
class="inline-flex items-center justify-center gap-2 select-none {sizeClasses} {getVariantClasses(
|
|
60
|
+
variant,
|
|
61
|
+
{
|
|
62
|
+
includeBorder: true,
|
|
63
|
+
includeIcon: false,
|
|
64
|
+
includeHover: false,
|
|
65
|
+
},
|
|
66
|
+
)} {rounded ? 'rounded-full' : 'rounded'}"
|
|
67
|
+
>
|
|
68
|
+
<span class="flex items-center justify-center gap-2">
|
|
69
|
+
{#if iconPosition === "left" && icon}
|
|
70
|
+
<span class={iconAdjustment}><Icon {icon} /></span>
|
|
71
|
+
{/if}
|
|
72
|
+
{#if text}
|
|
73
|
+
<span class={textAdjustment}>{text}</span>
|
|
74
|
+
{/if}
|
|
75
|
+
{#if iconPosition === "right" && icon}
|
|
76
|
+
<span class={iconAdjustment}><Icon {icon} /></span>
|
|
77
|
+
{/if}
|
|
78
|
+
</span>
|
|
79
|
+
</span>
|
|
80
|
+
{/if}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IconDefinition } from "@fortawesome/free-solid-svg-icons";
|
|
2
|
+
import type { Variant } from "../../types/variants.js";
|
|
3
|
+
import type { Size } from "../../types/sizes.js";
|
|
4
|
+
interface Props {
|
|
5
|
+
icon?: IconDefinition;
|
|
6
|
+
text?: string;
|
|
7
|
+
variant?: Variant;
|
|
8
|
+
size?: Size;
|
|
9
|
+
iconPosition?: "left" | "right";
|
|
10
|
+
rounded?: boolean;
|
|
11
|
+
}
|
|
12
|
+
declare const Badge: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type Badge = ReturnType<typeof Badge>;
|
|
14
|
+
export default Badge;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Badge.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Badge.svelte';
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Icon from "../Icon/Icon.svelte";
|
|
3
|
+
import type { IconDefinition } from "@fortawesome/free-solid-svg-icons";
|
|
4
|
+
import type { Snippet } from "svelte";
|
|
5
|
+
import type { Variant } from "../../types/variants.js";
|
|
6
|
+
import type { Size } from "../../types/sizes.js";
|
|
7
|
+
import {
|
|
8
|
+
getVariantClasses,
|
|
9
|
+
getVariantStyles,
|
|
10
|
+
} from "../../styles/variants.js";
|
|
11
|
+
import {
|
|
12
|
+
buttonSizeClasses,
|
|
13
|
+
getComponentHeight,
|
|
14
|
+
} from "../../styles/sizes.js";
|
|
15
|
+
import { DEV } from "esm-env";
|
|
16
|
+
|
|
17
|
+
interface BaseProps {
|
|
18
|
+
icon?: IconDefinition;
|
|
19
|
+
text?: string;
|
|
20
|
+
variant?: Variant;
|
|
21
|
+
size?: Size;
|
|
22
|
+
iconPosition?: "left" | "right";
|
|
23
|
+
children?: Snippet;
|
|
24
|
+
class?: string;
|
|
25
|
+
title?: string;
|
|
26
|
+
onclick?: (event: MouseEvent) => void;
|
|
27
|
+
onmouseenter?: (event: MouseEvent) => void;
|
|
28
|
+
onmouseleave?: (event: MouseEvent) => void;
|
|
29
|
+
element?: HTMLButtonElement | HTMLAnchorElement;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface ButtonProps extends BaseProps {
|
|
33
|
+
href?: never;
|
|
34
|
+
type?: "button" | "submit" | "reset";
|
|
35
|
+
disabled?: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface AnchorProps extends BaseProps {
|
|
39
|
+
href: string;
|
|
40
|
+
type?: never;
|
|
41
|
+
disabled?: never;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type Props = ButtonProps | AnchorProps;
|
|
45
|
+
|
|
46
|
+
let {
|
|
47
|
+
icon,
|
|
48
|
+
text,
|
|
49
|
+
variant = "secondary",
|
|
50
|
+
size = "md",
|
|
51
|
+
iconPosition = "left",
|
|
52
|
+
children,
|
|
53
|
+
disabled = false,
|
|
54
|
+
type = "button",
|
|
55
|
+
href,
|
|
56
|
+
class: additionalClass = "",
|
|
57
|
+
title,
|
|
58
|
+
onclick,
|
|
59
|
+
onmouseenter,
|
|
60
|
+
onmouseleave,
|
|
61
|
+
element = $bindable(),
|
|
62
|
+
...restProps
|
|
63
|
+
}: Props = $props();
|
|
64
|
+
|
|
65
|
+
// Development warnings for prop conflicts and empty content
|
|
66
|
+
if (DEV) {
|
|
67
|
+
if ((text || icon) && children) {
|
|
68
|
+
console.warn(
|
|
69
|
+
"Button: Props (text/icon) and children provided. Using props, ignoring children.",
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
if (!text && !icon && !children) {
|
|
73
|
+
console.warn(
|
|
74
|
+
"Button: No content provided (text, icon, or children). Button will be empty.",
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Determine content mode and styling
|
|
80
|
+
const hasProps = !!(text || icon);
|
|
81
|
+
const isIconOnly = icon && !text;
|
|
82
|
+
|
|
83
|
+
// Base classes - height is always h-8 (32px), width is h-8 for icon-only
|
|
84
|
+
const baseClasses =
|
|
85
|
+
"inline-flex items-center justify-center h-8 rounded-md text-sm font-medium transition-colors no-underline cursor-pointer focus-visible:[outline:2px_solid_color-mix(in_srgb,var(--color-text)_70%,transparent)] focus-visible:[outline-offset:0px]";
|
|
86
|
+
|
|
87
|
+
// Additional classes for disabled state (only applies to buttons)
|
|
88
|
+
const disabledClasses = href
|
|
89
|
+
? ""
|
|
90
|
+
: "disabled:opacity-50 disabled:cursor-not-allowed";
|
|
91
|
+
|
|
92
|
+
// Size classes - width and padding depend on content
|
|
93
|
+
const sizeClasses = isIconOnly ? "w-8" : "px-4 py-2";
|
|
94
|
+
|
|
95
|
+
// Ghost variant uses outline (doesn't affect layout) instead of border
|
|
96
|
+
// Other variants don't need borders since they have solid backgrounds
|
|
97
|
+
|
|
98
|
+
// Build final classes - reactive to variant changes
|
|
99
|
+
const buttonClasses = $derived(
|
|
100
|
+
[
|
|
101
|
+
baseClasses,
|
|
102
|
+
sizeClasses,
|
|
103
|
+
getVariantClasses(variant, { includeBorder: true }),
|
|
104
|
+
disabledClasses,
|
|
105
|
+
additionalClass,
|
|
106
|
+
]
|
|
107
|
+
.filter(Boolean)
|
|
108
|
+
.join(" "),
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// Get text and icon adjustments from variant styles
|
|
112
|
+
const textAdjustment = $derived(getVariantStyles(variant).textAdjustment);
|
|
113
|
+
const iconAdjustment = $derived(getVariantStyles(variant).iconAdjustment);
|
|
114
|
+
</script>
|
|
115
|
+
|
|
116
|
+
{#if href}
|
|
117
|
+
<a
|
|
118
|
+
bind:this={element}
|
|
119
|
+
{href}
|
|
120
|
+
{title}
|
|
121
|
+
{onclick}
|
|
122
|
+
{onmouseenter}
|
|
123
|
+
{onmouseleave}
|
|
124
|
+
class={buttonClasses}
|
|
125
|
+
{...restProps}
|
|
126
|
+
>
|
|
127
|
+
<div class="flex items-center justify-center gap-2 select-none">
|
|
128
|
+
{#if hasProps}
|
|
129
|
+
{#if iconPosition === "left" && icon}
|
|
130
|
+
<span class={iconAdjustment}><Icon {icon} /></span>
|
|
131
|
+
{/if}
|
|
132
|
+
{#if text}
|
|
133
|
+
<span class={textAdjustment}>{text}</span>
|
|
134
|
+
{/if}
|
|
135
|
+
{#if iconPosition === "right" && icon}
|
|
136
|
+
<span class={iconAdjustment}><Icon {icon} /></span>
|
|
137
|
+
{/if}
|
|
138
|
+
{:else if children}
|
|
139
|
+
{@render children()}
|
|
140
|
+
{/if}
|
|
141
|
+
</div>
|
|
142
|
+
</a>
|
|
143
|
+
{:else}
|
|
144
|
+
<button
|
|
145
|
+
bind:this={element}
|
|
146
|
+
{type}
|
|
147
|
+
{disabled}
|
|
148
|
+
aria-disabled={disabled}
|
|
149
|
+
{title}
|
|
150
|
+
{onclick}
|
|
151
|
+
{onmouseenter}
|
|
152
|
+
{onmouseleave}
|
|
153
|
+
class={buttonClasses}
|
|
154
|
+
{...restProps}
|
|
155
|
+
>
|
|
156
|
+
<div class="flex items-center justify-center gap-2 select-none">
|
|
157
|
+
{#if hasProps}
|
|
158
|
+
{#if iconPosition === "left" && icon}
|
|
159
|
+
<span class={iconAdjustment}><Icon {icon} /></span>
|
|
160
|
+
{/if}
|
|
161
|
+
{#if text}
|
|
162
|
+
<span class={textAdjustment}>{text}</span>
|
|
163
|
+
{/if}
|
|
164
|
+
{#if iconPosition === "right" && icon}
|
|
165
|
+
<span class={iconAdjustment}><Icon {icon} /></span>
|
|
166
|
+
{/if}
|
|
167
|
+
{:else if children}
|
|
168
|
+
{@render children()}
|
|
169
|
+
{/if}
|
|
170
|
+
</div>
|
|
171
|
+
</button>
|
|
172
|
+
{/if}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { IconDefinition } from "@fortawesome/free-solid-svg-icons";
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import type { Variant } from "../../types/variants.js";
|
|
4
|
+
import type { Size } from "../../types/sizes.js";
|
|
5
|
+
interface BaseProps {
|
|
6
|
+
icon?: IconDefinition;
|
|
7
|
+
text?: string;
|
|
8
|
+
variant?: Variant;
|
|
9
|
+
size?: Size;
|
|
10
|
+
iconPosition?: "left" | "right";
|
|
11
|
+
children?: Snippet;
|
|
12
|
+
class?: string;
|
|
13
|
+
title?: string;
|
|
14
|
+
onclick?: (event: MouseEvent) => void;
|
|
15
|
+
onmouseenter?: (event: MouseEvent) => void;
|
|
16
|
+
onmouseleave?: (event: MouseEvent) => void;
|
|
17
|
+
element?: HTMLButtonElement | HTMLAnchorElement;
|
|
18
|
+
}
|
|
19
|
+
interface ButtonProps extends BaseProps {
|
|
20
|
+
href?: never;
|
|
21
|
+
type?: "button" | "submit" | "reset";
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
}
|
|
24
|
+
interface AnchorProps extends BaseProps {
|
|
25
|
+
href: string;
|
|
26
|
+
type?: never;
|
|
27
|
+
disabled?: never;
|
|
28
|
+
}
|
|
29
|
+
export type Props = ButtonProps | AnchorProps;
|
|
30
|
+
declare const Button: import("svelte").Component<Props, {}, "element">;
|
|
31
|
+
type Button = ReturnType<typeof Button>;
|
|
32
|
+
export default Button;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Button.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Button.svelte';
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Button from '../Button/Button.svelte';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
import type { Variant } from '../../types/variants.js';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
isOpen: boolean;
|
|
8
|
+
title?: string;
|
|
9
|
+
message?: string;
|
|
10
|
+
confirmText?: string;
|
|
11
|
+
cancelText?: string;
|
|
12
|
+
onConfirm?: () => void;
|
|
13
|
+
onCancel?: () => void;
|
|
14
|
+
variant?: Variant;
|
|
15
|
+
showConfirm?: boolean;
|
|
16
|
+
showCancel?: boolean;
|
|
17
|
+
children?: Snippet;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let {
|
|
21
|
+
isOpen = $bindable(),
|
|
22
|
+
title = "Dialog",
|
|
23
|
+
message,
|
|
24
|
+
confirmText = "Confirm",
|
|
25
|
+
cancelText = "Cancel",
|
|
26
|
+
onConfirm,
|
|
27
|
+
onCancel,
|
|
28
|
+
variant = "primary",
|
|
29
|
+
showConfirm = true,
|
|
30
|
+
showCancel = true,
|
|
31
|
+
children
|
|
32
|
+
}: Props = $props();
|
|
33
|
+
|
|
34
|
+
function handleConfirm() {
|
|
35
|
+
if (onConfirm) onConfirm();
|
|
36
|
+
isOpen = false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function handleCancel() {
|
|
40
|
+
if (onCancel) onCancel();
|
|
41
|
+
isOpen = false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function handleBackdropClick(event: MouseEvent) {
|
|
45
|
+
if (event.target === event.currentTarget) {
|
|
46
|
+
handleCancel();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function handleKeydown(event: KeyboardEvent) {
|
|
51
|
+
if (event.key === 'Escape') {
|
|
52
|
+
handleCancel();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
<svelte:window on:keydown={handleKeydown} />
|
|
58
|
+
|
|
59
|
+
{#if isOpen}
|
|
60
|
+
<div
|
|
61
|
+
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-[9999]"
|
|
62
|
+
onclick={handleBackdropClick}
|
|
63
|
+
onkeydown={handleKeydown}
|
|
64
|
+
role="dialog"
|
|
65
|
+
aria-modal="true"
|
|
66
|
+
tabindex="-1"
|
|
67
|
+
>
|
|
68
|
+
<div class="[background-color:var(--color-background)] rounded-lg shadow-xl max-w-md w-full mx-4 z-[10000]" style="padding: calc(var(--ui-padding) * 2);">
|
|
69
|
+
<h3 class="text-lg font-medium [color:var(--color-text)]" style="margin-bottom: calc(var(--ui-padding) * 1.5);">
|
|
70
|
+
{title}
|
|
71
|
+
</h3>
|
|
72
|
+
|
|
73
|
+
{#if children}
|
|
74
|
+
{@render children()}
|
|
75
|
+
{:else if message}
|
|
76
|
+
<p class="text-sm [color:var(--color-secondary)]">
|
|
77
|
+
{message}
|
|
78
|
+
</p>
|
|
79
|
+
{/if}
|
|
80
|
+
|
|
81
|
+
{#if showConfirm || showCancel}
|
|
82
|
+
<div class="flex gap-3 justify-end" style="margin-top: calc(var(--ui-padding) * 1.5);">
|
|
83
|
+
{#if showCancel}
|
|
84
|
+
<Button
|
|
85
|
+
text={cancelText}
|
|
86
|
+
onclick={handleCancel}
|
|
87
|
+
variant="secondary"
|
|
88
|
+
/>
|
|
89
|
+
{/if}
|
|
90
|
+
{#if showConfirm}
|
|
91
|
+
<Button
|
|
92
|
+
text={confirmText}
|
|
93
|
+
onclick={handleConfirm}
|
|
94
|
+
variant={variant}
|
|
95
|
+
/>
|
|
96
|
+
{/if}
|
|
97
|
+
</div>
|
|
98
|
+
{/if}
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
{/if}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { Variant } from '../../types/variants.js';
|
|
3
|
+
interface Props {
|
|
4
|
+
isOpen: boolean;
|
|
5
|
+
title?: string;
|
|
6
|
+
message?: string;
|
|
7
|
+
confirmText?: string;
|
|
8
|
+
cancelText?: string;
|
|
9
|
+
onConfirm?: () => void;
|
|
10
|
+
onCancel?: () => void;
|
|
11
|
+
variant?: Variant;
|
|
12
|
+
showConfirm?: boolean;
|
|
13
|
+
showCancel?: boolean;
|
|
14
|
+
children?: Snippet;
|
|
15
|
+
}
|
|
16
|
+
declare const Dialog: import("svelte").Component<Props, {}, "isOpen">;
|
|
17
|
+
type Dialog = ReturnType<typeof Dialog>;
|
|
18
|
+
export default Dialog;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Dialog.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Dialog.svelte';
|