@orochibraru/ui 1.0.0 → 1.0.1
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 +84 -3
- package/dist/components/blocks/accent-toggle.svelte +7 -3
- package/dist/components/blocks/accent-toggle.svelte.d.ts +1 -1
- package/dist/components/blocks/bottom-nav.svelte +1 -1
- package/dist/components/blocks/command-palette.svelte +268 -0
- package/dist/components/blocks/command-palette.svelte.d.ts +37 -0
- package/dist/components/blocks/error-page.svelte +23 -7
- package/dist/components/blocks/error-page.svelte.d.ts +4 -0
- package/dist/components/blocks/fab.svelte +1 -1
- package/dist/components/blocks/install-prompt.svelte +14 -8
- package/dist/components/blocks/install-prompt.svelte.d.ts +2 -1
- package/dist/components/blocks/music-player/labelled-slider.svelte +3 -12
- package/dist/components/blocks/music-player/labelled-slider.svelte.d.ts +1 -2
- package/dist/components/blocks/music-player.svelte +13 -12
- package/dist/components/blocks/otp-field.svelte +77 -33
- package/dist/components/blocks/otp-field.svelte.d.ts +7 -0
- package/dist/components/blocks/password-input.svelte +56 -16
- package/dist/components/blocks/password-input.svelte.d.ts +3 -0
- package/dist/components/blocks/stepper/stepper-phone-header.svelte +93 -0
- package/dist/components/blocks/stepper/stepper-phone-header.svelte.d.ts +13 -0
- package/dist/components/blocks/stepper.svelte +175 -0
- package/dist/components/blocks/stepper.svelte.d.ts +30 -0
- package/dist/components/blocks/time-range-picker.svelte +229 -0
- package/dist/components/blocks/time-range-picker.svelte.d.ts +33 -0
- package/dist/components/blocks/time-series-chart/data-table.svelte +43 -0
- package/dist/components/blocks/time-series-chart/data-table.svelte.d.ts +15 -0
- package/dist/components/blocks/time-series-chart/legend.svelte +23 -0
- package/dist/components/blocks/time-series-chart/legend.svelte.d.ts +10 -0
- package/dist/components/blocks/time-series-chart/marks.svelte +118 -0
- package/dist/components/blocks/time-series-chart/marks.svelte.d.ts +29 -0
- package/dist/components/blocks/time-series-chart/messages.d.ts +13 -0
- package/dist/components/blocks/time-series-chart/messages.js +12 -0
- package/dist/components/blocks/time-series-chart/readout.svelte +44 -0
- package/dist/components/blocks/time-series-chart/readout.svelte.d.ts +15 -0
- package/dist/components/blocks/time-series-chart/scale.d.ts +24 -0
- package/dist/components/blocks/time-series-chart/scale.js +136 -0
- package/dist/components/blocks/time-series-chart/time.d.ts +7 -0
- package/dist/components/blocks/time-series-chart/time.js +96 -0
- package/dist/components/blocks/time-series-chart.svelte +492 -0
- package/dist/components/blocks/time-series-chart.svelte.d.ts +18 -0
- package/dist/components/blocks/top-loading-bar.svelte +1 -1
- package/dist/components/blocks/video-player/center-controls.svelte +7 -7
- package/dist/components/blocks/video-player/control-bar.svelte +41 -35
- package/dist/components/blocks/video-player/control-button.svelte +1 -1
- package/dist/components/blocks/video-player/option-menu.svelte +1 -1
- package/dist/components/blocks/video-player/scrub-bar.svelte +39 -12
- package/dist/components/blocks/video-player/scrub-bar.svelte.d.ts +2 -0
- package/dist/components/blocks/video-player.svelte +2 -2
- package/dist/components/kit/accordion.svelte +70 -0
- package/dist/components/kit/accordion.svelte.d.ts +37 -0
- package/dist/components/kit/avatar-group.svelte +84 -0
- package/dist/components/kit/avatar-group.svelte.d.ts +14 -0
- package/dist/components/kit/bar-list.svelte +104 -0
- package/dist/components/kit/bar-list.svelte.d.ts +22 -0
- package/dist/components/kit/breadcrumbs.svelte +102 -0
- package/dist/components/kit/breadcrumbs.svelte.d.ts +14 -0
- package/dist/components/kit/checkbox-list.svelte +98 -0
- package/dist/components/kit/checkbox-list.svelte.d.ts +15 -0
- package/dist/components/kit/checkbox.svelte +84 -0
- package/dist/components/kit/checkbox.svelte.d.ts +8 -0
- package/dist/components/kit/confirm-dialog.svelte +127 -0
- package/dist/components/kit/confirm-dialog.svelte.d.ts +19 -0
- package/dist/components/kit/data-table.svelte +280 -0
- package/dist/components/kit/data-table.svelte.d.ts +46 -0
- package/dist/components/kit/date-field.svelte +210 -0
- package/dist/components/kit/date-field.svelte.d.ts +14 -0
- package/dist/components/kit/field-frame.svelte +71 -0
- package/dist/components/kit/field-frame.svelte.d.ts +26 -0
- package/dist/components/kit/fieldset-frame.svelte +69 -0
- package/dist/components/kit/fieldset-frame.svelte.d.ts +14 -0
- package/dist/components/kit/file-dropzone/files.d.ts +14 -0
- package/dist/components/kit/file-dropzone/files.js +69 -0
- package/dist/components/kit/file-dropzone.svelte +253 -0
- package/dist/components/kit/file-dropzone.svelte.d.ts +25 -0
- package/dist/components/kit/form.svelte +335 -0
- package/dist/components/kit/form.svelte.d.ts +61 -0
- package/dist/components/kit/input.svelte +73 -0
- package/dist/components/kit/input.svelte.d.ts +9 -0
- package/dist/components/kit/menu.svelte +163 -0
- package/dist/components/kit/menu.svelte.d.ts +28 -0
- package/dist/components/kit/pagination.svelte +134 -0
- package/dist/components/kit/pagination.svelte.d.ts +17 -0
- package/dist/components/kit/radio-list.svelte +131 -0
- package/dist/components/kit/radio-list.svelte.d.ts +15 -0
- package/dist/components/kit/segmented-control/segment.svelte +47 -0
- package/dist/components/kit/segmented-control/segment.svelte.d.ts +11 -0
- package/dist/components/kit/segmented-control.svelte +70 -0
- package/dist/components/kit/segmented-control.svelte.d.ts +16 -0
- package/dist/components/kit/select.svelte +244 -0
- package/dist/components/kit/select.svelte.d.ts +26 -0
- package/dist/components/kit/status-badge.svelte +54 -0
- package/dist/components/kit/status-badge.svelte.d.ts +31 -0
- package/dist/components/kit/switch.svelte +84 -0
- package/dist/components/kit/switch.svelte.d.ts +8 -0
- package/dist/components/kit/tabs.svelte +86 -0
- package/dist/components/kit/tabs.svelte.d.ts +20 -0
- package/dist/components/kit/textarea.svelte +92 -0
- package/dist/components/kit/textarea.svelte.d.ts +11 -0
- package/dist/components/ui/drawer/drawer-content.svelte +1 -1
- package/dist/components/ui/input-group/input-group-input.svelte.d.ts +1 -1
- package/dist/components/ui/sidebar/sidebar-input.svelte.d.ts +1 -1
- package/dist/components/ui/sonner/sonner.svelte +2 -4
- package/dist/mcp-content.json +1 -1
- package/dist/mcp.js +11 -11
- package/dist/server/hooks.d.ts +9 -0
- package/dist/server/hooks.js +41 -0
- package/dist/server/logger.d.ts +39 -0
- package/dist/server/logger.js +144 -0
- package/dist/server/telemetry.d.ts +23 -0
- package/dist/server/telemetry.js +82 -0
- package/dist/theme.css +18 -6
- package/package.json +40 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Component } from "svelte";
|
|
2
|
+
import { type FieldProps } from "./field-frame.svelte";
|
|
3
|
+
interface Option {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
icon?: Component<{
|
|
7
|
+
class?: string;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
type Props = FieldProps & {
|
|
11
|
+
options: readonly Option[];
|
|
12
|
+
value?: string;
|
|
13
|
+
};
|
|
14
|
+
declare const SegmentedControl: Component<Props, {}, "value">;
|
|
15
|
+
type SegmentedControl = ReturnType<typeof SegmentedControl>;
|
|
16
|
+
export default SegmentedControl;
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Component } from "svelte";
|
|
3
|
+
|
|
4
|
+
export interface SelectOption {
|
|
5
|
+
value: string;
|
|
6
|
+
label: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
icon?: Component<{ class?: string }>;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
}
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<script lang="ts">
|
|
14
|
+
import ChevronsUpDownIcon from "@lucide/svelte/icons/chevrons-up-down";
|
|
15
|
+
import { MediaQuery } from "svelte/reactivity";
|
|
16
|
+
|
|
17
|
+
import * as Command from "../ui/command/index.js";
|
|
18
|
+
import * as Drawer from "../ui/drawer/index.js";
|
|
19
|
+
import * as Popover from "../ui/popover/index.js";
|
|
20
|
+
import * as Select from "../ui/select/index.js";
|
|
21
|
+
import { cn } from "../../utils.js";
|
|
22
|
+
|
|
23
|
+
import FieldFrame, { errorList, type FieldProps } from "./field-frame.svelte";
|
|
24
|
+
|
|
25
|
+
const defaultMessages = {
|
|
26
|
+
placeholder: "Select an option",
|
|
27
|
+
search: "Search…",
|
|
28
|
+
empty: "No results.",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type Props = FieldProps & {
|
|
32
|
+
options: SelectOption[];
|
|
33
|
+
value?: string;
|
|
34
|
+
placeholder?: string;
|
|
35
|
+
searchable?: boolean;
|
|
36
|
+
onValueChange?: (value: string) => void;
|
|
37
|
+
messages?: Partial<typeof defaultMessages>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
let {
|
|
41
|
+
options,
|
|
42
|
+
value = $bindable(""),
|
|
43
|
+
placeholder,
|
|
44
|
+
searchable = false,
|
|
45
|
+
onValueChange,
|
|
46
|
+
messages = {},
|
|
47
|
+
name,
|
|
48
|
+
label,
|
|
49
|
+
description,
|
|
50
|
+
error,
|
|
51
|
+
required = false,
|
|
52
|
+
disabled = false,
|
|
53
|
+
id,
|
|
54
|
+
class: className,
|
|
55
|
+
}: Props = $props();
|
|
56
|
+
|
|
57
|
+
const desktop = new MediaQuery("(min-width: 768px)");
|
|
58
|
+
const nested = Drawer.isInsideDrawer();
|
|
59
|
+
const generatedId = $props.id();
|
|
60
|
+
|
|
61
|
+
let open = $state(false);
|
|
62
|
+
let query = $state("");
|
|
63
|
+
|
|
64
|
+
const text = $derived({ ...defaultMessages, ...messages });
|
|
65
|
+
const triggerId = $derived(id ?? generatedId);
|
|
66
|
+
const invalid = $derived(errorList(error).length > 0);
|
|
67
|
+
const describedBy = $derived(
|
|
68
|
+
invalid
|
|
69
|
+
? `${triggerId}-error`
|
|
70
|
+
: description
|
|
71
|
+
? `${triggerId}-description`
|
|
72
|
+
: undefined,
|
|
73
|
+
);
|
|
74
|
+
const selected = $derived(options.find((option) => option.value === value));
|
|
75
|
+
const triggerClass =
|
|
76
|
+
"border-input dark:bg-input/30 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 flex h-11 w-full items-center gap-2 rounded-md border bg-white px-3 text-left text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-3 aria-invalid:ring-3 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm";
|
|
77
|
+
|
|
78
|
+
function pick(next: string) {
|
|
79
|
+
value = next;
|
|
80
|
+
open = false;
|
|
81
|
+
query = "";
|
|
82
|
+
onValueChange?.(next);
|
|
83
|
+
}
|
|
84
|
+
</script>
|
|
85
|
+
|
|
86
|
+
{#snippet optionContent(option: SelectOption)}
|
|
87
|
+
{#if option.icon}
|
|
88
|
+
<option.icon class="text-muted-foreground size-4 shrink-0" />
|
|
89
|
+
{/if}
|
|
90
|
+
<span class="grid min-w-0 flex-1 text-left">
|
|
91
|
+
<span class="truncate">{option.label}</span>
|
|
92
|
+
{#if option.description}
|
|
93
|
+
<span class="text-muted-foreground truncate text-xs font-normal"
|
|
94
|
+
>{option.description}</span
|
|
95
|
+
>
|
|
96
|
+
{/if}
|
|
97
|
+
</span>
|
|
98
|
+
{/snippet}
|
|
99
|
+
|
|
100
|
+
{#snippet summary(chevron: boolean)}
|
|
101
|
+
{#if selected?.icon}
|
|
102
|
+
<selected.icon class="text-muted-foreground size-4 shrink-0" />
|
|
103
|
+
{/if}
|
|
104
|
+
<span
|
|
105
|
+
class={cn("min-w-0 flex-1 truncate", !selected && "text-muted-foreground")}
|
|
106
|
+
>{selected?.label ?? placeholder ?? text.placeholder}</span
|
|
107
|
+
>
|
|
108
|
+
{#if chevron}
|
|
109
|
+
<ChevronsUpDownIcon class="size-4 shrink-0 opacity-50" />
|
|
110
|
+
{/if}
|
|
111
|
+
{/snippet}
|
|
112
|
+
|
|
113
|
+
{#snippet list(itemClass: string, touch: boolean)}
|
|
114
|
+
{#if searchable}
|
|
115
|
+
<Command.Input
|
|
116
|
+
placeholder={text.search}
|
|
117
|
+
bind:value={query}
|
|
118
|
+
wrapperClass={touch ? "px-0 pt-0 pb-3" : undefined}
|
|
119
|
+
groupClass={touch
|
|
120
|
+
? "h-12! rounded-xl! *:data-[slot=input-group-addon]:pl-3!"
|
|
121
|
+
: undefined}
|
|
122
|
+
class="text-base md:text-sm"
|
|
123
|
+
/>
|
|
124
|
+
{/if}
|
|
125
|
+
<Command.List class="max-h-[min(60dvh,20rem)] max-md:max-h-[55dvh]">
|
|
126
|
+
{#if searchable}
|
|
127
|
+
<Command.Empty>{text.empty}</Command.Empty>
|
|
128
|
+
{/if}
|
|
129
|
+
{#each options as option (option.value)}
|
|
130
|
+
<Command.Item
|
|
131
|
+
value={option.value}
|
|
132
|
+
keywords={[option.label, option.description ?? ""]}
|
|
133
|
+
disabled={option.disabled}
|
|
134
|
+
data-checked={option.value === value}
|
|
135
|
+
onSelect={() => pick(option.value)}
|
|
136
|
+
class={itemClass}
|
|
137
|
+
>
|
|
138
|
+
{@render optionContent(option)}
|
|
139
|
+
</Command.Item>
|
|
140
|
+
{/each}
|
|
141
|
+
</Command.List>
|
|
142
|
+
{/snippet}
|
|
143
|
+
|
|
144
|
+
{#snippet drawerContent()}
|
|
145
|
+
<Drawer.Content id="{triggerId}-drawer">
|
|
146
|
+
<Drawer.Header class="px-5 text-left">
|
|
147
|
+
<Drawer.Title>{label ?? placeholder ?? text.placeholder}</Drawer.Title>
|
|
148
|
+
</Drawer.Header>
|
|
149
|
+
<Command.Root class="bg-transparent px-3">
|
|
150
|
+
{@render list("min-h-12 rounded-xl px-3 text-base", true)}
|
|
151
|
+
</Command.Root>
|
|
152
|
+
</Drawer.Content>
|
|
153
|
+
{/snippet}
|
|
154
|
+
|
|
155
|
+
<FieldFrame
|
|
156
|
+
id={triggerId}
|
|
157
|
+
{label}
|
|
158
|
+
{description}
|
|
159
|
+
{error}
|
|
160
|
+
{required}
|
|
161
|
+
class={className}
|
|
162
|
+
>
|
|
163
|
+
{#if name}
|
|
164
|
+
<input type="hidden" {name} {value} {disabled} />
|
|
165
|
+
{/if}
|
|
166
|
+
{#if !desktop.current}
|
|
167
|
+
<button
|
|
168
|
+
type="button"
|
|
169
|
+
id={triggerId}
|
|
170
|
+
{disabled}
|
|
171
|
+
class={triggerClass}
|
|
172
|
+
role="combobox"
|
|
173
|
+
aria-haspopup="dialog"
|
|
174
|
+
aria-expanded={open}
|
|
175
|
+
aria-controls="{triggerId}-drawer"
|
|
176
|
+
aria-invalid={invalid || undefined}
|
|
177
|
+
aria-describedby={describedBy}
|
|
178
|
+
aria-required={required || undefined}
|
|
179
|
+
onclick={() => (open = true)}
|
|
180
|
+
>
|
|
181
|
+
{@render summary(true)}
|
|
182
|
+
</button>
|
|
183
|
+
{#if nested}
|
|
184
|
+
<Drawer.NestedRoot bind:open>{@render drawerContent()}</Drawer.NestedRoot>
|
|
185
|
+
{:else}
|
|
186
|
+
<Drawer.Root bind:open>{@render drawerContent()}</Drawer.Root>
|
|
187
|
+
{/if}
|
|
188
|
+
{:else if !searchable}
|
|
189
|
+
<Select.Root
|
|
190
|
+
type="single"
|
|
191
|
+
{disabled}
|
|
192
|
+
bind:value
|
|
193
|
+
onValueChange={(next) => onValueChange?.(next)}
|
|
194
|
+
>
|
|
195
|
+
<Select.Trigger
|
|
196
|
+
id={triggerId}
|
|
197
|
+
aria-invalid={invalid || undefined}
|
|
198
|
+
aria-describedby={describedBy}
|
|
199
|
+
aria-required={required || undefined}
|
|
200
|
+
class={cn(triggerClass, "data-[size=default]:h-11")}
|
|
201
|
+
>
|
|
202
|
+
{@render summary(false)}
|
|
203
|
+
</Select.Trigger>
|
|
204
|
+
<Select.Content>
|
|
205
|
+
{#each options as option (option.value)}
|
|
206
|
+
<Select.Item
|
|
207
|
+
value={option.value}
|
|
208
|
+
label={option.label}
|
|
209
|
+
disabled={option.disabled}
|
|
210
|
+
>
|
|
211
|
+
{@render optionContent(option)}
|
|
212
|
+
</Select.Item>
|
|
213
|
+
{/each}
|
|
214
|
+
</Select.Content>
|
|
215
|
+
</Select.Root>
|
|
216
|
+
{:else}
|
|
217
|
+
<Popover.Root
|
|
218
|
+
bind:open
|
|
219
|
+
onOpenChange={(next) => {
|
|
220
|
+
if (!next) query = "";
|
|
221
|
+
}}
|
|
222
|
+
>
|
|
223
|
+
<Popover.Trigger
|
|
224
|
+
id={triggerId}
|
|
225
|
+
{disabled}
|
|
226
|
+
role="combobox"
|
|
227
|
+
aria-invalid={invalid || undefined}
|
|
228
|
+
aria-describedby={describedBy}
|
|
229
|
+
aria-required={required || undefined}
|
|
230
|
+
class={triggerClass}
|
|
231
|
+
>
|
|
232
|
+
{@render summary(true)}
|
|
233
|
+
</Popover.Trigger>
|
|
234
|
+
<Popover.Content
|
|
235
|
+
align="start"
|
|
236
|
+
class="w-(--bits-popover-anchor-width) min-w-64 rounded-xl p-0"
|
|
237
|
+
>
|
|
238
|
+
<Command.Root class="bg-transparent">
|
|
239
|
+
{@render list("", false)}
|
|
240
|
+
</Command.Root>
|
|
241
|
+
</Popover.Content>
|
|
242
|
+
</Popover.Root>
|
|
243
|
+
{/if}
|
|
244
|
+
</FieldFrame>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Component } from "svelte";
|
|
2
|
+
export interface SelectOption {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
icon?: Component<{
|
|
7
|
+
class?: string;
|
|
8
|
+
}>;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
}
|
|
11
|
+
import * as Select from "../ui/select/index.js";
|
|
12
|
+
import { type FieldProps } from "./field-frame.svelte";
|
|
13
|
+
declare const Select: Component<FieldProps & {
|
|
14
|
+
options: SelectOption[];
|
|
15
|
+
value?: string;
|
|
16
|
+
placeholder?: string;
|
|
17
|
+
searchable?: boolean;
|
|
18
|
+
onValueChange?: (value: string) => void;
|
|
19
|
+
messages?: Partial<{
|
|
20
|
+
placeholder: string;
|
|
21
|
+
search: string;
|
|
22
|
+
empty: string;
|
|
23
|
+
}>;
|
|
24
|
+
}, {}, "value">;
|
|
25
|
+
type Select = ReturnType<typeof Select>;
|
|
26
|
+
export default Select;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
export type StatusTone =
|
|
3
|
+
"neutral" | "positive" | "warning" | "negative" | "info";
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<script lang="ts" generics="Status extends string">
|
|
7
|
+
import { cn } from "../../utils.js";
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
status: Status;
|
|
11
|
+
tones?: Partial<Record<Status, StatusTone>>;
|
|
12
|
+
labels?: Partial<Record<Status, string>>;
|
|
13
|
+
pulse?: boolean;
|
|
14
|
+
class?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const {
|
|
18
|
+
status,
|
|
19
|
+
tones = {},
|
|
20
|
+
labels = {},
|
|
21
|
+
pulse = false,
|
|
22
|
+
class: className,
|
|
23
|
+
}: Props = $props();
|
|
24
|
+
|
|
25
|
+
const toneClasses: Record<StatusTone, string> = {
|
|
26
|
+
neutral: "border-border bg-muted text-muted-foreground",
|
|
27
|
+
positive: "border-positive/25 bg-positive/10 text-positive",
|
|
28
|
+
warning:
|
|
29
|
+
"border-amber-500/25 bg-amber-500/10 text-amber-700 dark:text-amber-300",
|
|
30
|
+
negative: "border-negative/25 bg-negative/10 text-negative",
|
|
31
|
+
info: "border-sky-500/25 bg-sky-500/10 text-sky-700 dark:text-sky-300",
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const tone = $derived(tones[status] ?? "neutral");
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<span
|
|
38
|
+
data-tone={tone}
|
|
39
|
+
class={cn(
|
|
40
|
+
"inline-flex h-6 w-fit shrink-0 items-center gap-1.5 rounded-full border px-2.5 text-xs font-medium whitespace-nowrap",
|
|
41
|
+
toneClasses[tone],
|
|
42
|
+
className,
|
|
43
|
+
)}
|
|
44
|
+
>
|
|
45
|
+
<span class="relative flex size-1.5 shrink-0" aria-hidden="true">
|
|
46
|
+
{#if pulse}
|
|
47
|
+
<span
|
|
48
|
+
class="absolute inset-0 rounded-full bg-current opacity-60 motion-safe:animate-ping"
|
|
49
|
+
></span>
|
|
50
|
+
{/if}
|
|
51
|
+
<span class="relative size-1.5 rounded-full bg-current"></span>
|
|
52
|
+
</span>
|
|
53
|
+
{labels[status] ?? status}
|
|
54
|
+
</span>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type StatusTone = "neutral" | "positive" | "warning" | "negative" | "info";
|
|
2
|
+
declare function $$render<Status extends string>(): {
|
|
3
|
+
props: {
|
|
4
|
+
status: Status;
|
|
5
|
+
tones?: Partial<Record<Status, StatusTone>>;
|
|
6
|
+
labels?: Partial<Record<Status, string>>;
|
|
7
|
+
pulse?: boolean;
|
|
8
|
+
class?: string;
|
|
9
|
+
};
|
|
10
|
+
exports: {};
|
|
11
|
+
bindings: "";
|
|
12
|
+
slots: {};
|
|
13
|
+
events: {};
|
|
14
|
+
};
|
|
15
|
+
declare class __sveltets_Render<Status extends string> {
|
|
16
|
+
props(): ReturnType<typeof $$render<Status>>['props'];
|
|
17
|
+
events(): ReturnType<typeof $$render<Status>>['events'];
|
|
18
|
+
slots(): ReturnType<typeof $$render<Status>>['slots'];
|
|
19
|
+
bindings(): "";
|
|
20
|
+
exports(): {};
|
|
21
|
+
}
|
|
22
|
+
interface $$IsomorphicComponent {
|
|
23
|
+
new <Status extends string>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<Status>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<Status>['props']>, ReturnType<__sveltets_Render<Status>['events']>, ReturnType<__sveltets_Render<Status>['slots']>> & {
|
|
24
|
+
$$bindings?: ReturnType<__sveltets_Render<Status>['bindings']>;
|
|
25
|
+
} & ReturnType<__sveltets_Render<Status>['exports']>;
|
|
26
|
+
<Status extends string>(internal: unknown, props: ReturnType<__sveltets_Render<Status>['props']> & {}): ReturnType<__sveltets_Render<Status>['exports']>;
|
|
27
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
28
|
+
}
|
|
29
|
+
declare const StatusBadge: $$IsomorphicComponent;
|
|
30
|
+
type StatusBadge<Status extends string> = InstanceType<typeof StatusBadge<Status>>;
|
|
31
|
+
export default StatusBadge;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as Field from "../ui/field/index.js";
|
|
3
|
+
import { Switch } from "../ui/switch/index.js";
|
|
4
|
+
import { cn } from "../../utils.js";
|
|
5
|
+
|
|
6
|
+
import { errorList, type FieldProps } from "./field-frame.svelte";
|
|
7
|
+
|
|
8
|
+
type Props = FieldProps & {
|
|
9
|
+
checked?: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
checked = $bindable(false),
|
|
14
|
+
name,
|
|
15
|
+
label,
|
|
16
|
+
description,
|
|
17
|
+
error,
|
|
18
|
+
required = false,
|
|
19
|
+
disabled = false,
|
|
20
|
+
id,
|
|
21
|
+
class: className,
|
|
22
|
+
}: Props = $props();
|
|
23
|
+
|
|
24
|
+
const generatedId = $props.id();
|
|
25
|
+
const switchId = $derived(id ?? generatedId);
|
|
26
|
+
const errors = $derived(errorList(error));
|
|
27
|
+
const invalid = $derived(errors.length > 0);
|
|
28
|
+
const describedBy = $derived(
|
|
29
|
+
invalid
|
|
30
|
+
? `${switchId}-error`
|
|
31
|
+
: description
|
|
32
|
+
? `${switchId}-description`
|
|
33
|
+
: undefined,
|
|
34
|
+
);
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<div
|
|
38
|
+
class={cn("flex w-full flex-col", className)}
|
|
39
|
+
data-invalid={invalid || undefined}
|
|
40
|
+
>
|
|
41
|
+
<div
|
|
42
|
+
class="group/row relative flex min-h-11 items-start justify-between gap-4 py-2.5 has-disabled:opacity-50"
|
|
43
|
+
>
|
|
44
|
+
<span class="min-w-0 flex-1">
|
|
45
|
+
{#if label}
|
|
46
|
+
<label
|
|
47
|
+
for={switchId}
|
|
48
|
+
class={cn(
|
|
49
|
+
"block cursor-pointer font-medium after:absolute after:inset-0 group-has-disabled/row:cursor-not-allowed",
|
|
50
|
+
invalid && "text-destructive",
|
|
51
|
+
)}
|
|
52
|
+
>
|
|
53
|
+
{label}
|
|
54
|
+
{#if required}
|
|
55
|
+
<span class="text-destructive" aria-hidden="true">*</span>
|
|
56
|
+
{/if}
|
|
57
|
+
</label>
|
|
58
|
+
{/if}
|
|
59
|
+
{#if description && !invalid}
|
|
60
|
+
<span
|
|
61
|
+
id="{switchId}-description"
|
|
62
|
+
class="text-muted-foreground mt-0.5 block text-sm">{description}</span
|
|
63
|
+
>
|
|
64
|
+
{/if}
|
|
65
|
+
</span>
|
|
66
|
+
<Switch
|
|
67
|
+
id={switchId}
|
|
68
|
+
{name}
|
|
69
|
+
value="true"
|
|
70
|
+
{required}
|
|
71
|
+
{disabled}
|
|
72
|
+
bind:checked
|
|
73
|
+
aria-invalid={invalid || undefined}
|
|
74
|
+
aria-describedby={describedBy}
|
|
75
|
+
class="z-10 mt-0.5 shrink-0"
|
|
76
|
+
/>
|
|
77
|
+
</div>
|
|
78
|
+
{#if invalid}
|
|
79
|
+
<Field.Error
|
|
80
|
+
id="{switchId}-error"
|
|
81
|
+
errors={errors.map((message) => ({ message }))}
|
|
82
|
+
/>
|
|
83
|
+
{/if}
|
|
84
|
+
</div>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Switch } from "../ui/switch/index.js";
|
|
2
|
+
import { type FieldProps } from "./field-frame.svelte";
|
|
3
|
+
type Props = FieldProps & {
|
|
4
|
+
checked?: boolean;
|
|
5
|
+
};
|
|
6
|
+
declare const Switch: import("svelte").Component<Props, {}, "checked">;
|
|
7
|
+
type Switch = ReturnType<typeof Switch>;
|
|
8
|
+
export default Switch;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Component, Snippet } from "svelte";
|
|
3
|
+
|
|
4
|
+
export interface TabItem {
|
|
5
|
+
value: string;
|
|
6
|
+
label: string;
|
|
7
|
+
icon?: Component<{ class?: string }>;
|
|
8
|
+
badge?: string | number;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
}
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<script lang="ts">
|
|
14
|
+
import { Tabs as TabsPrimitive } from "bits-ui";
|
|
15
|
+
import { untrack } from "svelte";
|
|
16
|
+
|
|
17
|
+
import * as Tabs from "../ui/tabs/index.js";
|
|
18
|
+
import { cn } from "../../utils.js";
|
|
19
|
+
|
|
20
|
+
interface Props {
|
|
21
|
+
items: TabItem[];
|
|
22
|
+
value?: string;
|
|
23
|
+
class?: string;
|
|
24
|
+
children: Snippet<[string]>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let {
|
|
28
|
+
items,
|
|
29
|
+
value = $bindable(),
|
|
30
|
+
class: className,
|
|
31
|
+
children,
|
|
32
|
+
}: Props = $props();
|
|
33
|
+
|
|
34
|
+
value ??= untrack(() => items[0]?.value);
|
|
35
|
+
|
|
36
|
+
const active = $derived(value ?? items[0]?.value ?? "");
|
|
37
|
+
|
|
38
|
+
let list = $state<HTMLElement | null>(null);
|
|
39
|
+
|
|
40
|
+
$effect(() => {
|
|
41
|
+
list
|
|
42
|
+
?.querySelector(`[data-value="${CSS.escape(active)}"]`)
|
|
43
|
+
?.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
44
|
+
});
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<Tabs.Root
|
|
48
|
+
bind:value={() => active, (next) => (value = next)}
|
|
49
|
+
class={cn("w-full gap-4", className)}
|
|
50
|
+
>
|
|
51
|
+
<div class="no-scrollbar w-full overflow-x-auto py-1">
|
|
52
|
+
<TabsPrimitive.List
|
|
53
|
+
bind:ref={list}
|
|
54
|
+
class="glass flex w-max min-w-full gap-1 rounded-full p-1 md:min-w-0"
|
|
55
|
+
>
|
|
56
|
+
{#each items as item (item.value)}
|
|
57
|
+
{@const selected = item.value === active}
|
|
58
|
+
<TabsPrimitive.Trigger
|
|
59
|
+
value={item.value}
|
|
60
|
+
disabled={item.disabled}
|
|
61
|
+
class="text-muted-foreground hover:bg-accent/70 hover:text-foreground data-active:bg-primary data-active:text-primary-foreground data-active:glow focus-visible:ring-ring/50 flex h-11 shrink-0 grow items-center justify-center gap-2 rounded-full px-4 text-sm font-medium whitespace-nowrap transition-[color,background-color,box-shadow] outline-none focus-visible:ring-3 disabled:pointer-events-none disabled:opacity-50 md:h-9 md:grow-0"
|
|
62
|
+
>
|
|
63
|
+
{#if item.icon}
|
|
64
|
+
<item.icon class="size-4" />
|
|
65
|
+
{/if}
|
|
66
|
+
{item.label}
|
|
67
|
+
{#if item.badge !== undefined}
|
|
68
|
+
<span
|
|
69
|
+
class={cn(
|
|
70
|
+
"min-w-5 rounded-full px-1.5 text-center text-xs leading-5 tabular-nums",
|
|
71
|
+
selected
|
|
72
|
+
? "bg-primary-foreground/20 text-primary-foreground"
|
|
73
|
+
: "bg-muted text-muted-foreground",
|
|
74
|
+
)}
|
|
75
|
+
>
|
|
76
|
+
{item.badge}
|
|
77
|
+
</span>
|
|
78
|
+
{/if}
|
|
79
|
+
</TabsPrimitive.Trigger>
|
|
80
|
+
{/each}
|
|
81
|
+
</TabsPrimitive.List>
|
|
82
|
+
</div>
|
|
83
|
+
<Tabs.Content value={active}>
|
|
84
|
+
{@render children(active)}
|
|
85
|
+
</Tabs.Content>
|
|
86
|
+
</Tabs.Root>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Component, Snippet } from "svelte";
|
|
2
|
+
export interface TabItem {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
icon?: Component<{
|
|
6
|
+
class?: string;
|
|
7
|
+
}>;
|
|
8
|
+
badge?: string | number;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
}
|
|
11
|
+
import * as Tabs from "../ui/tabs/index.js";
|
|
12
|
+
interface Props {
|
|
13
|
+
items: TabItem[];
|
|
14
|
+
value?: string;
|
|
15
|
+
class?: string;
|
|
16
|
+
children: Snippet<[string]>;
|
|
17
|
+
}
|
|
18
|
+
declare const Tabs: Component<Props, {}, "value">;
|
|
19
|
+
type Tabs = ReturnType<typeof Tabs>;
|
|
20
|
+
export default Tabs;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLTextareaAttributes } from "svelte/elements";
|
|
3
|
+
|
|
4
|
+
import { Textarea } from "../ui/textarea/index.js";
|
|
5
|
+
import { cn } from "../../utils.js";
|
|
6
|
+
|
|
7
|
+
import FieldFrame, { errorList, type FieldProps } from "./field-frame.svelte";
|
|
8
|
+
|
|
9
|
+
const defaultMessages = {
|
|
10
|
+
characters: "characters",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type Props = FieldProps &
|
|
14
|
+
Omit<HTMLTextareaAttributes, "value" | "class" | "id" | "name"> & {
|
|
15
|
+
value?: string;
|
|
16
|
+
messages?: Partial<typeof defaultMessages>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
value = $bindable(""),
|
|
21
|
+
name,
|
|
22
|
+
label,
|
|
23
|
+
description,
|
|
24
|
+
error,
|
|
25
|
+
required = false,
|
|
26
|
+
disabled = false,
|
|
27
|
+
id,
|
|
28
|
+
class: className,
|
|
29
|
+
rows,
|
|
30
|
+
maxlength,
|
|
31
|
+
messages = {},
|
|
32
|
+
...rest
|
|
33
|
+
}: Props = $props();
|
|
34
|
+
|
|
35
|
+
const text = $derived({ ...defaultMessages, ...messages });
|
|
36
|
+
const generatedId = $props.id();
|
|
37
|
+
const textareaId = $derived(id ?? generatedId);
|
|
38
|
+
const invalid = $derived(errorList(error).length > 0);
|
|
39
|
+
const counted = $derived(maxlength !== undefined && maxlength !== null);
|
|
40
|
+
const describedBy = $derived(
|
|
41
|
+
[
|
|
42
|
+
invalid
|
|
43
|
+
? `${textareaId}-error`
|
|
44
|
+
: description
|
|
45
|
+
? `${textareaId}-description`
|
|
46
|
+
: undefined,
|
|
47
|
+
counted ? `${textareaId}-counter` : undefined,
|
|
48
|
+
]
|
|
49
|
+
.filter(Boolean)
|
|
50
|
+
.join(" ") || undefined,
|
|
51
|
+
);
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<FieldFrame
|
|
55
|
+
id={textareaId}
|
|
56
|
+
{label}
|
|
57
|
+
{description}
|
|
58
|
+
{error}
|
|
59
|
+
{required}
|
|
60
|
+
class={className}
|
|
61
|
+
>
|
|
62
|
+
<div class="grid gap-1.5">
|
|
63
|
+
<Textarea
|
|
64
|
+
{...rest}
|
|
65
|
+
id={textareaId}
|
|
66
|
+
{name}
|
|
67
|
+
{rows}
|
|
68
|
+
{maxlength}
|
|
69
|
+
{required}
|
|
70
|
+
{disabled}
|
|
71
|
+
aria-invalid={invalid || undefined}
|
|
72
|
+
aria-describedby={describedBy}
|
|
73
|
+
bind:value
|
|
74
|
+
class={cn(
|
|
75
|
+
"px-3 py-2.5",
|
|
76
|
+
rows === undefined ? "min-h-24" : "field-sizing-fixed min-h-0",
|
|
77
|
+
)}
|
|
78
|
+
/>
|
|
79
|
+
{#if counted}
|
|
80
|
+
<p
|
|
81
|
+
id="{textareaId}-counter"
|
|
82
|
+
class={cn(
|
|
83
|
+
"text-muted-foreground text-right text-xs tabular-nums",
|
|
84
|
+
(value ?? "").length >= Number(maxlength) && "text-destructive",
|
|
85
|
+
)}
|
|
86
|
+
>
|
|
87
|
+
{(value ?? "").length}/{maxlength}
|
|
88
|
+
<span class="sr-only">{text.characters}</span>
|
|
89
|
+
</p>
|
|
90
|
+
{/if}
|
|
91
|
+
</div>
|
|
92
|
+
</FieldFrame>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { HTMLTextareaAttributes } from "svelte/elements";
|
|
2
|
+
import { Textarea } from "../ui/textarea/index.js";
|
|
3
|
+
import { type FieldProps } from "./field-frame.svelte";
|
|
4
|
+
declare const Textarea: import("svelte").Component<FieldProps & Omit<HTMLTextareaAttributes, "id" | "name" | "value" | "class"> & {
|
|
5
|
+
value?: string;
|
|
6
|
+
messages?: Partial<{
|
|
7
|
+
characters: string;
|
|
8
|
+
}>;
|
|
9
|
+
}, {}, "value">;
|
|
10
|
+
type Textarea = ReturnType<typeof Textarea>;
|
|
11
|
+
export default Textarea;
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
bind:ref
|
|
26
26
|
data-slot="drawer-content"
|
|
27
27
|
class={cn(
|
|
28
|
-
"bg-popover text-popover-foreground border-border border shadow-[0_-12px_48px_-16px_var(--glass-shadow)] group/drawer-content after:hidden! fixed z-50 flex h-auto flex-col text-sm data-[vaul-drawer-direction=bottom]:right-[max(0.5rem,
|
|
28
|
+
"bg-popover text-popover-foreground border-border border shadow-[0_-12px_48px_-16px_var(--glass-shadow)] group/drawer-content after:hidden! fixed z-50 flex h-auto flex-col text-sm data-[vaul-drawer-direction=bottom]:right-[max(0.5rem,var(--safe-right))] data-[vaul-drawer-direction=bottom]:bottom-2 data-[vaul-drawer-direction=bottom]:left-[max(0.5rem,var(--safe-left))] data-[vaul-drawer-direction=bottom]:max-h-[calc(100dvh-var(--safe-top)-1.5rem)] data-[vaul-drawer-direction=bottom]:rounded-[2.25rem] data-[vaul-drawer-direction=bottom]:pb-[max(0.5rem,calc(var(--safe-bottom)-0.5rem))] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:inset-s-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:rounded-r-xl data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:inset-e-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:rounded-l-xl data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=right]:sm:max-w-sm data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-xl data-[vaul-drawer-direction=top]:border-b",
|
|
29
29
|
className,
|
|
30
30
|
)}
|
|
31
31
|
{...restProps}
|