@mrintel/villain-ui 0.2.2 → 0.3.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/components/buttons/Button.svelte +33 -0
- package/dist/components/buttons/Button.svelte.d.ts +11 -0
- package/dist/components/buttons/ButtonGroup.svelte +30 -0
- package/dist/components/buttons/ButtonGroup.svelte.d.ts +8 -0
- package/dist/components/buttons/FloatingActionButton.svelte +44 -0
- package/dist/components/buttons/FloatingActionButton.svelte.d.ts +11 -0
- package/dist/components/buttons/IconButton.svelte +53 -0
- package/dist/components/buttons/IconButton.svelte.d.ts +13 -0
- package/dist/components/buttons/LinkButton.svelte +37 -0
- package/dist/components/buttons/LinkButton.svelte.d.ts +12 -0
- package/dist/components/buttons/buttonClasses.d.ts +10 -0
- package/dist/components/buttons/buttonClasses.js +10 -0
- package/dist/components/buttons/index.d.ts +5 -0
- package/dist/components/buttons/index.js +5 -0
- package/dist/components/cards/Card.svelte +46 -0
- package/dist/components/cards/Card.svelte.d.ts +11 -0
- package/dist/components/cards/Container.svelte +33 -0
- package/dist/components/cards/Container.svelte.d.ts +10 -0
- package/dist/components/cards/Divider.svelte +52 -0
- package/dist/components/cards/Divider.svelte.d.ts +9 -0
- package/dist/components/cards/Grid.svelte +44 -0
- package/dist/components/cards/Grid.svelte.d.ts +10 -0
- package/dist/components/cards/Panel.svelte +32 -0
- package/dist/components/cards/Panel.svelte.d.ts +10 -0
- package/dist/components/cards/SectionHeader.svelte +38 -0
- package/dist/components/cards/SectionHeader.svelte.d.ts +11 -0
- package/dist/components/cards/index.d.ts +6 -0
- package/dist/components/cards/index.js +6 -0
- package/dist/components/data/Avatar.svelte +67 -0
- package/dist/components/data/Avatar.svelte.d.ts +10 -0
- package/dist/components/data/Badge.svelte +32 -0
- package/dist/components/data/Badge.svelte.d.ts +8 -0
- package/dist/components/data/CodeBlock.svelte +121 -0
- package/dist/components/data/CodeBlock.svelte.d.ts +32 -0
- package/dist/components/data/List.svelte +64 -0
- package/dist/components/data/List.svelte.d.ts +8 -0
- package/dist/components/data/Pagination.svelte +123 -0
- package/dist/components/data/Pagination.svelte.d.ts +9 -0
- package/dist/components/data/Stat.svelte +103 -0
- package/dist/components/data/Stat.svelte.d.ts +11 -0
- package/dist/components/data/Table.svelte +76 -0
- package/dist/components/data/Table.svelte.d.ts +9 -0
- package/dist/components/data/Tag.svelte +53 -0
- package/dist/components/data/Tag.svelte.d.ts +9 -0
- package/dist/components/data/index.d.ts +8 -0
- package/dist/components/data/index.js +8 -0
- package/dist/components/forms/Checkbox.svelte +51 -0
- package/dist/components/forms/Checkbox.svelte.d.ts +10 -0
- package/dist/components/forms/FileUpload.svelte +164 -0
- package/dist/components/forms/FileUpload.svelte.d.ts +22 -0
- package/dist/components/forms/Input.svelte +57 -0
- package/dist/components/forms/Input.svelte.d.ts +13 -0
- package/dist/components/forms/InputGroup.svelte +7 -0
- package/dist/components/forms/InputGroup.svelte.d.ts +20 -0
- package/dist/components/forms/RadioGroup.svelte +87 -0
- package/dist/components/forms/RadioGroup.svelte.d.ts +15 -0
- package/dist/components/forms/RangeSlider.svelte +116 -0
- package/dist/components/forms/RangeSlider.svelte.d.ts +14 -0
- package/dist/components/forms/Select.svelte +71 -0
- package/dist/components/forms/Select.svelte.d.ts +16 -0
- package/dist/components/forms/Switch.svelte +56 -0
- package/dist/components/forms/Switch.svelte.d.ts +10 -0
- package/dist/components/forms/Textarea.svelte +57 -0
- package/dist/components/forms/Textarea.svelte.d.ts +13 -0
- package/dist/components/forms/index.d.ts +9 -0
- package/dist/components/forms/index.js +9 -0
- package/dist/components/navigation/Breadcrumbs.svelte +59 -0
- package/dist/components/navigation/Breadcrumbs.svelte.d.ts +14 -0
- package/dist/components/navigation/ContextMenu.svelte +83 -0
- package/dist/components/navigation/ContextMenu.svelte.d.ts +11 -0
- package/dist/components/navigation/DropdownMenu.svelte +80 -0
- package/dist/components/navigation/DropdownMenu.svelte.d.ts +10 -0
- package/dist/components/navigation/Menu.svelte +48 -0
- package/dist/components/navigation/Menu.svelte.d.ts +15 -0
- package/dist/components/navigation/Navbar.svelte +32 -0
- package/dist/components/navigation/Navbar.svelte.d.ts +9 -0
- package/dist/components/navigation/Sidebar.svelte +35 -0
- package/dist/components/navigation/Sidebar.svelte.d.ts +10 -0
- package/dist/components/navigation/Tabs.svelte +54 -0
- package/dist/components/navigation/Tabs.svelte.d.ts +15 -0
- package/dist/components/navigation/index.d.ts +7 -0
- package/dist/components/navigation/index.js +7 -0
- package/dist/components/overlays/Alert.svelte +99 -0
- package/dist/components/overlays/Alert.svelte.d.ts +11 -0
- package/dist/components/overlays/CommandPalette.svelte +217 -0
- package/dist/components/overlays/CommandPalette.svelte.d.ts +16 -0
- package/dist/components/overlays/Drawer.svelte +167 -0
- package/dist/components/overlays/Drawer.svelte.d.ts +14 -0
- package/dist/components/overlays/Dropdown.svelte +30 -0
- package/dist/components/overlays/Dropdown.svelte.d.ts +9 -0
- package/dist/components/overlays/Modal.svelte +130 -0
- package/dist/components/overlays/Modal.svelte.d.ts +13 -0
- package/dist/components/overlays/Popover.svelte +131 -0
- package/dist/components/overlays/Popover.svelte.d.ts +11 -0
- package/dist/components/overlays/ProgressBar.svelte +45 -0
- package/dist/components/overlays/ProgressBar.svelte.d.ts +10 -0
- package/dist/components/overlays/SkeletonLoader.svelte +82 -0
- package/dist/components/overlays/SkeletonLoader.svelte.d.ts +9 -0
- package/dist/components/overlays/Spinner.svelte +43 -0
- package/dist/components/overlays/Spinner.svelte.d.ts +7 -0
- package/dist/components/overlays/Toast.svelte +140 -0
- package/dist/components/overlays/Toast.svelte.d.ts +13 -0
- package/dist/components/overlays/Tooltip.svelte +115 -0
- package/dist/components/overlays/Tooltip.svelte.d.ts +10 -0
- package/dist/components/overlays/index.d.ts +11 -0
- package/dist/components/overlays/index.js +11 -0
- package/dist/components/typography/Code.svelte +14 -0
- package/dist/components/typography/Code.svelte.d.ts +6 -0
- package/dist/components/typography/Heading.svelte +22 -0
- package/dist/components/typography/Heading.svelte.d.ts +9 -0
- package/dist/components/typography/Text.svelte +24 -0
- package/dist/components/typography/Text.svelte.d.ts +9 -0
- package/dist/components/typography/index.d.ts +3 -0
- package/dist/components/typography/index.js +3 -0
- package/dist/components/utilities/Accordion.svelte +67 -0
- package/dist/components/utilities/Accordion.svelte.d.ts +14 -0
- package/dist/components/utilities/Carousel.svelte +152 -0
- package/dist/components/utilities/Carousel.svelte.d.ts +16 -0
- package/dist/components/utilities/Collapse.svelte +60 -0
- package/dist/components/utilities/Collapse.svelte.d.ts +10 -0
- package/dist/components/utilities/Portal.svelte +72 -0
- package/dist/components/utilities/Portal.svelte.d.ts +21 -0
- package/dist/components/utilities/ScrollArea.svelte +41 -0
- package/dist/components/utilities/ScrollArea.svelte.d.ts +8 -0
- package/dist/components/utilities/index.d.ts +5 -0
- package/dist/components/utilities/index.js +5 -0
- package/dist/index.d.ts +15 -175
- package/dist/index.js +24 -4560
- package/dist/lib/internal/id.d.ts +12 -0
- package/dist/lib/internal/id.js +15 -0
- package/dist/theme.css +218 -0
- package/package.json +6 -5
- package/dist/index.css +0 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
variant?: 'default' | 'accent';
|
|
4
|
+
dismissible?: boolean;
|
|
5
|
+
ondismiss?: () => void;
|
|
6
|
+
children?: import('svelte').Snippet;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let { variant = 'default', dismissible = false, ondismiss, children }: Props = $props();
|
|
10
|
+
|
|
11
|
+
const variantClasses = {
|
|
12
|
+
default:
|
|
13
|
+
'bg-[var(--color-base-2)] text-[var(--color-text-soft)] border-[var(--color-border)]',
|
|
14
|
+
accent:
|
|
15
|
+
'bg-[rgba(127,61,255,0.1)] text-[var(--color-accent-soft)] border-[var(--color-accent)] shadow-[0_0_12px_rgba(127,61,255,0.2)]'
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const classes = $derived(
|
|
19
|
+
`inline-flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-pill)] border font-[var(--font-body)] font-medium text-sm transition-all duration-300 hover:scale-[1.02] ${variantClasses[variant]}`
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
function handleDismiss() {
|
|
23
|
+
ondismiss?.();
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<span class={classes}>
|
|
28
|
+
{@render children?.()}
|
|
29
|
+
|
|
30
|
+
{#if dismissible}
|
|
31
|
+
<button
|
|
32
|
+
class="ml-1 opacity-60 hover:opacity-100 hover:text-[var(--color-text)] transition-all duration-300"
|
|
33
|
+
onclick={handleDismiss}
|
|
34
|
+
aria-label="Remove tag"
|
|
35
|
+
>
|
|
36
|
+
<svg
|
|
37
|
+
width="14"
|
|
38
|
+
height="14"
|
|
39
|
+
viewBox="0 0 14 14"
|
|
40
|
+
fill="none"
|
|
41
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
42
|
+
>
|
|
43
|
+
<path
|
|
44
|
+
d="M10.5 3.5L3.5 10.5M3.5 3.5L10.5 10.5"
|
|
45
|
+
stroke="currentColor"
|
|
46
|
+
stroke-width="1.5"
|
|
47
|
+
stroke-linecap="round"
|
|
48
|
+
stroke-linejoin="round"
|
|
49
|
+
/>
|
|
50
|
+
</svg>
|
|
51
|
+
</button>
|
|
52
|
+
{/if}
|
|
53
|
+
</span>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
variant?: 'default' | 'accent';
|
|
3
|
+
dismissible?: boolean;
|
|
4
|
+
ondismiss?: () => void;
|
|
5
|
+
children?: import('svelte').Snippet;
|
|
6
|
+
}
|
|
7
|
+
declare const Tag: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type Tag = ReturnType<typeof Tag>;
|
|
9
|
+
export default Tag;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { default as Table } from './Table.svelte';
|
|
2
|
+
export { default as Pagination } from './Pagination.svelte';
|
|
3
|
+
export { default as Badge } from './Badge.svelte';
|
|
4
|
+
export { default as Tag } from './Tag.svelte';
|
|
5
|
+
export { default as List } from './List.svelte';
|
|
6
|
+
export { default as Avatar } from './Avatar.svelte';
|
|
7
|
+
export { default as CodeBlock } from './CodeBlock.svelte';
|
|
8
|
+
export { default as Stat } from './Stat.svelte';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { default as Table } from './Table.svelte';
|
|
2
|
+
export { default as Pagination } from './Pagination.svelte';
|
|
3
|
+
export { default as Badge } from './Badge.svelte';
|
|
4
|
+
export { default as Tag } from './Tag.svelte';
|
|
5
|
+
export { default as List } from './List.svelte';
|
|
6
|
+
export { default as Avatar } from './Avatar.svelte';
|
|
7
|
+
export { default as CodeBlock } from './CodeBlock.svelte';
|
|
8
|
+
export { default as Stat } from './Stat.svelte';
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { createId } from '../../lib/internal/id.js';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
checked?: boolean;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
label?: string;
|
|
8
|
+
id?: string;
|
|
9
|
+
onchange?: (event: Event) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
checked = $bindable(false),
|
|
14
|
+
disabled = false,
|
|
15
|
+
label,
|
|
16
|
+
id = createId('checkbox'),
|
|
17
|
+
onchange
|
|
18
|
+
}: Props = $props();
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<label for={id} class="flex items-center gap-2 cursor-pointer {disabled ? 'opacity-50 cursor-not-allowed' : ''}">
|
|
22
|
+
<input
|
|
23
|
+
type="checkbox"
|
|
24
|
+
{id}
|
|
25
|
+
{disabled}
|
|
26
|
+
bind:checked
|
|
27
|
+
onchange={onchange}
|
|
28
|
+
class="w-5 h-5 rounded-sm border-2 border-border-strong bg-transparent appearance-none transition-all duration-200 ease-luxe cursor-pointer checked:bg-accent checked:border-accent checked:accent-glow focus:outline-none focus:ring-2 focus:ring-accent focus:ring-offset-2 focus:ring-offset-base-1 relative {disabled ? 'cursor-not-allowed' : ''}"
|
|
29
|
+
/>
|
|
30
|
+
{#if label}
|
|
31
|
+
<span class="text-text text-sm select-none">
|
|
32
|
+
{label}
|
|
33
|
+
</span>
|
|
34
|
+
{/if}
|
|
35
|
+
</label>
|
|
36
|
+
|
|
37
|
+
<style>
|
|
38
|
+
input[type="checkbox"]:checked::after {
|
|
39
|
+
content: '';
|
|
40
|
+
position: absolute;
|
|
41
|
+
left: 50%;
|
|
42
|
+
top: 50%;
|
|
43
|
+
transform: translate(-50%, -50%);
|
|
44
|
+
width: 10px;
|
|
45
|
+
height: 10px;
|
|
46
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10' fill='none'%3E%3Cpath d='M2 5L4 7L8 3' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
|
47
|
+
background-size: contain;
|
|
48
|
+
background-repeat: no-repeat;
|
|
49
|
+
background-position: center;
|
|
50
|
+
}
|
|
51
|
+
</style>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
checked?: boolean;
|
|
3
|
+
disabled?: boolean;
|
|
4
|
+
label?: string;
|
|
5
|
+
id?: string;
|
|
6
|
+
onchange?: (event: Event) => void;
|
|
7
|
+
}
|
|
8
|
+
declare const Checkbox: import("svelte").Component<Props, {}, "checked">;
|
|
9
|
+
type Checkbox = ReturnType<typeof Checkbox>;
|
|
10
|
+
export default Checkbox;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { createId } from '../../lib/internal/id.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* FileUpload component props.
|
|
6
|
+
*
|
|
7
|
+
* The `onchange` callback receives an event object with the following shape:
|
|
8
|
+
* `{ target: { files: FileList } }` for both drag-and-drop and click-based selection.
|
|
9
|
+
*/
|
|
10
|
+
interface Props {
|
|
11
|
+
files?: FileList | null;
|
|
12
|
+
accept?: string;
|
|
13
|
+
multiple?: boolean;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
label?: string;
|
|
16
|
+
id?: string;
|
|
17
|
+
onchange?: (event: { target: { files: FileList } }) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let {
|
|
21
|
+
files = $bindable(null),
|
|
22
|
+
accept,
|
|
23
|
+
multiple = false,
|
|
24
|
+
disabled = false,
|
|
25
|
+
label,
|
|
26
|
+
id = createId('file-upload'),
|
|
27
|
+
onchange
|
|
28
|
+
}: Props = $props();
|
|
29
|
+
|
|
30
|
+
let isDragging = $state(false);
|
|
31
|
+
let inputElement: HTMLInputElement;
|
|
32
|
+
|
|
33
|
+
function handleDragOver(event: DragEvent) {
|
|
34
|
+
event.preventDefault();
|
|
35
|
+
if (!disabled) {
|
|
36
|
+
isDragging = true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function handleDragLeave() {
|
|
41
|
+
isDragging = false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function handleDrop(event: DragEvent) {
|
|
45
|
+
event.preventDefault();
|
|
46
|
+
isDragging = false;
|
|
47
|
+
|
|
48
|
+
if (!disabled && event.dataTransfer?.files) {
|
|
49
|
+
files = event.dataTransfer.files;
|
|
50
|
+
if (onchange) {
|
|
51
|
+
// Call onchange directly with synthetic event object
|
|
52
|
+
onchange({ target: { files: event.dataTransfer.files } });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function handleClick() {
|
|
58
|
+
if (!disabled) {
|
|
59
|
+
inputElement?.click();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function handleInputChange(event: Event) {
|
|
64
|
+
const input = event.target as HTMLInputElement;
|
|
65
|
+
if (onchange && input.files) {
|
|
66
|
+
// Call onchange with consistent event shape
|
|
67
|
+
onchange({ target: { files: input.files } });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const fileList = $derived(files ? Array.from(files) : []);
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
<div>
|
|
75
|
+
{#if label}
|
|
76
|
+
<div class="text-text-soft text-sm mb-2 block">
|
|
77
|
+
{label}
|
|
78
|
+
</div>
|
|
79
|
+
{/if}
|
|
80
|
+
|
|
81
|
+
<input
|
|
82
|
+
type="file"
|
|
83
|
+
{id}
|
|
84
|
+
{accept}
|
|
85
|
+
{multiple}
|
|
86
|
+
{disabled}
|
|
87
|
+
bind:this={inputElement}
|
|
88
|
+
bind:files
|
|
89
|
+
onchange={handleInputChange}
|
|
90
|
+
class="hidden"
|
|
91
|
+
/>
|
|
92
|
+
|
|
93
|
+
<div
|
|
94
|
+
role="button"
|
|
95
|
+
tabindex={disabled ? -1 : 0}
|
|
96
|
+
aria-label="Click or drag files to upload"
|
|
97
|
+
ondragover={handleDragOver}
|
|
98
|
+
ondragleave={handleDragLeave}
|
|
99
|
+
ondrop={handleDrop}
|
|
100
|
+
onclick={handleClick}
|
|
101
|
+
onkeydown={(e) => e.key === 'Enter' && handleClick()}
|
|
102
|
+
class="glass-panel rounded-lg p-8 text-center cursor-pointer transition-all duration-300 ease-luxe {isDragging ? 'border-2 border-accent accent-glow bg-base-2' : ''} {disabled ? 'opacity-50 cursor-not-allowed pointer-events-none' : ''}"
|
|
103
|
+
>
|
|
104
|
+
<div class="flex flex-col items-center gap-2">
|
|
105
|
+
<svg
|
|
106
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
107
|
+
width="48"
|
|
108
|
+
height="48"
|
|
109
|
+
viewBox="0 0 24 24"
|
|
110
|
+
fill="none"
|
|
111
|
+
stroke="currentColor"
|
|
112
|
+
stroke-width="2"
|
|
113
|
+
stroke-linecap="round"
|
|
114
|
+
stroke-linejoin="round"
|
|
115
|
+
class="text-text-soft"
|
|
116
|
+
>
|
|
117
|
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
|
|
118
|
+
<polyline points="17 8 12 3 7 8" />
|
|
119
|
+
<line x1="12" y1="3" x2="12" y2="15" />
|
|
120
|
+
</svg>
|
|
121
|
+
|
|
122
|
+
<div>
|
|
123
|
+
<p class="text-text text-sm font-medium">
|
|
124
|
+
Click to upload or drag and drop
|
|
125
|
+
</p>
|
|
126
|
+
<p class="text-text-muted text-xs mt-1">
|
|
127
|
+
{accept ? `Accepted formats: ${accept}` : 'Any file type'}
|
|
128
|
+
</p>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
{#if fileList.length > 0}
|
|
134
|
+
<div class="mt-4">
|
|
135
|
+
<p class="text-text-soft text-xs mb-2">
|
|
136
|
+
Selected files:
|
|
137
|
+
</p>
|
|
138
|
+
<ul class="space-y-1">
|
|
139
|
+
{#each fileList as file}
|
|
140
|
+
<li class="text-text text-xs flex items-center gap-2">
|
|
141
|
+
<svg
|
|
142
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
143
|
+
width="12"
|
|
144
|
+
height="12"
|
|
145
|
+
viewBox="0 0 24 24"
|
|
146
|
+
fill="none"
|
|
147
|
+
stroke="currentColor"
|
|
148
|
+
stroke-width="2"
|
|
149
|
+
stroke-linecap="round"
|
|
150
|
+
stroke-linejoin="round"
|
|
151
|
+
>
|
|
152
|
+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
|
|
153
|
+
<polyline points="14 2 14 8 20 8" />
|
|
154
|
+
</svg>
|
|
155
|
+
<span>{file.name}</span>
|
|
156
|
+
<span class="text-text-muted">
|
|
157
|
+
({(file.size / 1024).toFixed(1)} KB)
|
|
158
|
+
</span>
|
|
159
|
+
</li>
|
|
160
|
+
{/each}
|
|
161
|
+
</ul>
|
|
162
|
+
</div>
|
|
163
|
+
{/if}
|
|
164
|
+
</div>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileUpload component props.
|
|
3
|
+
*
|
|
4
|
+
* The `onchange` callback receives an event object with the following shape:
|
|
5
|
+
* `{ target: { files: FileList } }` for both drag-and-drop and click-based selection.
|
|
6
|
+
*/
|
|
7
|
+
interface Props {
|
|
8
|
+
files?: FileList | null;
|
|
9
|
+
accept?: string;
|
|
10
|
+
multiple?: boolean;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
label?: string;
|
|
13
|
+
id?: string;
|
|
14
|
+
onchange?: (event: {
|
|
15
|
+
target: {
|
|
16
|
+
files: FileList;
|
|
17
|
+
};
|
|
18
|
+
}) => void;
|
|
19
|
+
}
|
|
20
|
+
declare const FileUpload: import("svelte").Component<Props, {}, "files">;
|
|
21
|
+
type FileUpload = ReturnType<typeof FileUpload>;
|
|
22
|
+
export default FileUpload;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { createId } from '../../lib/internal/id.js';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url';
|
|
6
|
+
value?: string;
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
error?: boolean;
|
|
10
|
+
label?: string;
|
|
11
|
+
id?: string;
|
|
12
|
+
oninput?: (event: Event) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let {
|
|
16
|
+
type = 'text',
|
|
17
|
+
value = $bindable(''),
|
|
18
|
+
placeholder,
|
|
19
|
+
disabled = false,
|
|
20
|
+
error = false,
|
|
21
|
+
label,
|
|
22
|
+
id = createId('input'),
|
|
23
|
+
oninput
|
|
24
|
+
}: Props = $props();
|
|
25
|
+
|
|
26
|
+
const baseClasses = 'glass-panel rounded-lg px-4 py-3 font-body text-text placeholder:text-text-muted transition-all duration-300 ease-luxe w-full';
|
|
27
|
+
const focusClasses = 'focus:outline-none focus:border-accent focus:accent-glow';
|
|
28
|
+
const errorClasses = error ? 'border-error' : '';
|
|
29
|
+
const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed' : '';
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
{#if label}
|
|
33
|
+
<div>
|
|
34
|
+
<label for={id} class="text-text-soft text-sm mb-2 block">
|
|
35
|
+
{label}
|
|
36
|
+
</label>
|
|
37
|
+
<input
|
|
38
|
+
{type}
|
|
39
|
+
{id}
|
|
40
|
+
{placeholder}
|
|
41
|
+
{disabled}
|
|
42
|
+
bind:value
|
|
43
|
+
oninput={oninput}
|
|
44
|
+
class="{baseClasses} {focusClasses} {errorClasses} {disabledClasses}"
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
47
|
+
{:else}
|
|
48
|
+
<input
|
|
49
|
+
{type}
|
|
50
|
+
{id}
|
|
51
|
+
{placeholder}
|
|
52
|
+
{disabled}
|
|
53
|
+
bind:value
|
|
54
|
+
oninput={oninput}
|
|
55
|
+
class="{baseClasses} {focusClasses} {errorClasses} {disabledClasses}"
|
|
56
|
+
/>
|
|
57
|
+
{/if}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url';
|
|
3
|
+
value?: string;
|
|
4
|
+
placeholder?: string;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
error?: boolean;
|
|
7
|
+
label?: string;
|
|
8
|
+
id?: string;
|
|
9
|
+
oninput?: (event: Event) => void;
|
|
10
|
+
}
|
|
11
|
+
declare const Input: import("svelte").Component<Props, {}, "value">;
|
|
12
|
+
type Input = ReturnType<typeof Input>;
|
|
13
|
+
export default Input;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// No props needed for standard slot usage
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<div class="flex items-stretch rounded-[var(--radius-lg)] overflow-hidden glass-panel [&>*:not(:first-child)]:ml-[-1px] [&>*:not(:first-child):not(:last-child)]:rounded-none [&>*:first-child]:rounded-r-none [&>*:last-child]:rounded-l-none">
|
|
6
|
+
<slot />
|
|
7
|
+
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const InputGroup: $$__sveltets_2_IsomorphicComponent<any, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {
|
|
17
|
+
default: {};
|
|
18
|
+
}, {}, string>;
|
|
19
|
+
type InputGroup = InstanceType<typeof InputGroup>;
|
|
20
|
+
export default InputGroup;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
value?: string;
|
|
4
|
+
options: Array<{ value: string; label: string }>;
|
|
5
|
+
name: string;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
orientation?: 'vertical' | 'horizontal';
|
|
8
|
+
label?: string;
|
|
9
|
+
onchange?: (event: Event) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
value = $bindable(''),
|
|
14
|
+
options,
|
|
15
|
+
name,
|
|
16
|
+
disabled = false,
|
|
17
|
+
orientation = 'vertical',
|
|
18
|
+
label,
|
|
19
|
+
onchange
|
|
20
|
+
}: Props = $props();
|
|
21
|
+
|
|
22
|
+
const containerClasses = $derived(orientation === 'vertical' ? 'flex flex-col gap-3' : 'flex flex-row gap-4');
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
{#if label}
|
|
26
|
+
<fieldset class={disabled ? 'opacity-50' : ''}>
|
|
27
|
+
<legend class="text-[var(--color-text-soft)] text-sm mb-3 block">
|
|
28
|
+
{label}
|
|
29
|
+
</legend>
|
|
30
|
+
<div class={containerClasses}>
|
|
31
|
+
{#each options as option}
|
|
32
|
+
{@const radioId = `${name}-${option.value}`}
|
|
33
|
+
<label for={radioId} class="flex items-center gap-2 cursor-pointer {disabled ? 'cursor-not-allowed' : ''}">
|
|
34
|
+
<input
|
|
35
|
+
type="radio"
|
|
36
|
+
id={radioId}
|
|
37
|
+
{name}
|
|
38
|
+
value={option.value}
|
|
39
|
+
{disabled}
|
|
40
|
+
bind:group={value}
|
|
41
|
+
onchange={onchange}
|
|
42
|
+
class="w-5 h-5 rounded-[var(--radius-pill)] border-2 border-[var(--color-border-strong)] bg-transparent appearance-none transition-all duration-200 ease-[var(--ease-luxe)] cursor-pointer checked:border-[var(--color-accent)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent)] focus:ring-offset-2 focus:ring-offset-[var(--color-base-1)] relative {disabled ? 'cursor-not-allowed' : ''}"
|
|
43
|
+
/>
|
|
44
|
+
<span class="text-[var(--color-text)] text-sm select-none">
|
|
45
|
+
{option.label}
|
|
46
|
+
</span>
|
|
47
|
+
</label>
|
|
48
|
+
{/each}
|
|
49
|
+
</div>
|
|
50
|
+
</fieldset>
|
|
51
|
+
{:else}
|
|
52
|
+
<div class={containerClasses}>
|
|
53
|
+
{#each options as option}
|
|
54
|
+
{@const radioId = `${name}-${option.value}`}
|
|
55
|
+
<label for={radioId} class="flex items-center gap-2 cursor-pointer {disabled ? 'opacity-50 cursor-not-allowed' : ''}">
|
|
56
|
+
<input
|
|
57
|
+
type="radio"
|
|
58
|
+
id={radioId}
|
|
59
|
+
{name}
|
|
60
|
+
value={option.value}
|
|
61
|
+
{disabled}
|
|
62
|
+
bind:group={value}
|
|
63
|
+
onchange={onchange}
|
|
64
|
+
class="w-5 h-5 rounded-[var(--radius-pill)] border-2 border-[var(--color-border-strong)] bg-transparent appearance-none transition-all duration-200 ease-[var(--ease-luxe)] cursor-pointer checked:border-[var(--color-accent)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent)] focus:ring-offset-2 focus:ring-offset-[var(--color-base-1)] relative {disabled ? 'cursor-not-allowed' : ''}"
|
|
65
|
+
/>
|
|
66
|
+
<span class="text-[var(--color-text)] text-sm select-none">
|
|
67
|
+
{option.label}
|
|
68
|
+
</span>
|
|
69
|
+
</label>
|
|
70
|
+
{/each}
|
|
71
|
+
</div>
|
|
72
|
+
{/if}
|
|
73
|
+
|
|
74
|
+
<style>
|
|
75
|
+
input[type="radio"]:checked::after {
|
|
76
|
+
content: '';
|
|
77
|
+
position: absolute;
|
|
78
|
+
left: 50%;
|
|
79
|
+
top: 50%;
|
|
80
|
+
transform: translate(-50%, -50%);
|
|
81
|
+
width: 0.625rem;
|
|
82
|
+
height: 0.625rem;
|
|
83
|
+
border-radius: var(--radius-pill);
|
|
84
|
+
background: var(--color-accent);
|
|
85
|
+
box-shadow: var(--shadow-accent-glow);
|
|
86
|
+
}
|
|
87
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
value?: string;
|
|
3
|
+
options: Array<{
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
}>;
|
|
7
|
+
name: string;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
orientation?: 'vertical' | 'horizontal';
|
|
10
|
+
label?: string;
|
|
11
|
+
onchange?: (event: Event) => void;
|
|
12
|
+
}
|
|
13
|
+
declare const RadioGroup: import("svelte").Component<Props, {}, "value">;
|
|
14
|
+
type RadioGroup = ReturnType<typeof RadioGroup>;
|
|
15
|
+
export default RadioGroup;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { createId } from '../../lib/internal/id.js';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
value?: number;
|
|
6
|
+
min?: number;
|
|
7
|
+
max?: number;
|
|
8
|
+
step?: number;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
label?: string;
|
|
11
|
+
showValue?: boolean;
|
|
12
|
+
id?: string;
|
|
13
|
+
oninput?: (event: Event) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let {
|
|
17
|
+
value = $bindable(0),
|
|
18
|
+
min = 0,
|
|
19
|
+
max = 100,
|
|
20
|
+
step = 1,
|
|
21
|
+
disabled = false,
|
|
22
|
+
label,
|
|
23
|
+
showValue = true,
|
|
24
|
+
id = createId('range'),
|
|
25
|
+
oninput
|
|
26
|
+
}: Props = $props();
|
|
27
|
+
|
|
28
|
+
const percentage = $derived(max === min ? 0 : ((value - min) / (max - min)) * 100);
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<div>
|
|
32
|
+
{#if label || showValue}
|
|
33
|
+
<div class="flex justify-between items-center mb-2">
|
|
34
|
+
{#if label}
|
|
35
|
+
<label for={id} class="text-text-soft text-sm">
|
|
36
|
+
{label}
|
|
37
|
+
</label>
|
|
38
|
+
{/if}
|
|
39
|
+
{#if showValue}
|
|
40
|
+
<span class="text-text-soft text-sm">
|
|
41
|
+
{value}
|
|
42
|
+
</span>
|
|
43
|
+
{/if}
|
|
44
|
+
</div>
|
|
45
|
+
{/if}
|
|
46
|
+
<input
|
|
47
|
+
type="range"
|
|
48
|
+
{id}
|
|
49
|
+
{min}
|
|
50
|
+
{max}
|
|
51
|
+
{step}
|
|
52
|
+
{disabled}
|
|
53
|
+
bind:value
|
|
54
|
+
oninput={oninput}
|
|
55
|
+
aria-valuemin={min}
|
|
56
|
+
aria-valuemax={max}
|
|
57
|
+
aria-valuenow={value}
|
|
58
|
+
class="w-full h-2 rounded-pill appearance-none cursor-pointer transition-opacity duration-200 {disabled ? 'opacity-50 cursor-not-allowed' : ''}"
|
|
59
|
+
style="background: linear-gradient(to right, var(--color-accent) 0%, var(--color-accent) {percentage}%, var(--color-base-3) {percentage}%, var(--color-base-3) 100%); border: 1px solid var(--color-border);"
|
|
60
|
+
/>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<style>
|
|
64
|
+
input[type="range"]::-webkit-slider-thumb {
|
|
65
|
+
appearance: none;
|
|
66
|
+
width: 1.25rem;
|
|
67
|
+
height: 1.25rem;
|
|
68
|
+
border-radius: var(--radius-pill);
|
|
69
|
+
background: var(--color-accent);
|
|
70
|
+
box-shadow: var(--shadow-accent-glow);
|
|
71
|
+
cursor: pointer;
|
|
72
|
+
transition: transform 0.2s var(--ease-luxe);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
input[type="range"]::-webkit-slider-thumb:hover {
|
|
76
|
+
transform: scale(1.1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
input[type="range"]::-moz-range-thumb {
|
|
80
|
+
appearance: none;
|
|
81
|
+
width: 1.25rem;
|
|
82
|
+
height: 1.25rem;
|
|
83
|
+
border-radius: var(--radius-pill);
|
|
84
|
+
background: var(--color-accent);
|
|
85
|
+
box-shadow: var(--shadow-accent-glow);
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
transition: transform 0.2s var(--ease-luxe);
|
|
88
|
+
border: none;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
input[type="range"]::-moz-range-thumb:hover {
|
|
92
|
+
transform: scale(1.1);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
input[type="range"]:focus::-webkit-slider-thumb {
|
|
96
|
+
box-shadow:
|
|
97
|
+
var(--shadow-accent-glow),
|
|
98
|
+
0 0 0 3px var(--color-base-1),
|
|
99
|
+
0 0 0 5px var(--color-accent);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
input[type="range"]:focus::-moz-range-thumb {
|
|
103
|
+
box-shadow:
|
|
104
|
+
var(--shadow-accent-glow),
|
|
105
|
+
0 0 0 3px var(--color-base-1),
|
|
106
|
+
0 0 0 5px var(--color-accent);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
input[type="range"]:disabled::-webkit-slider-thumb {
|
|
110
|
+
cursor: not-allowed;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
input[type="range"]:disabled::-moz-range-thumb {
|
|
114
|
+
cursor: not-allowed;
|
|
115
|
+
}
|
|
116
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
step?: number;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
label?: string;
|
|
8
|
+
showValue?: boolean;
|
|
9
|
+
id?: string;
|
|
10
|
+
oninput?: (event: Event) => void;
|
|
11
|
+
}
|
|
12
|
+
declare const RangeSlider: import("svelte").Component<Props, {}, "value">;
|
|
13
|
+
type RangeSlider = ReturnType<typeof RangeSlider>;
|
|
14
|
+
export default RangeSlider;
|