uisv 0.0.11 → 0.0.13
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/accordion.svelte +108 -0
- package/dist/components/accordion.svelte.d.ts +58 -0
- package/dist/components/alert.svelte +271 -0
- package/dist/components/alert.svelte.d.ts +23 -0
- package/dist/components/badge.svelte +225 -0
- package/dist/components/badge.svelte.d.ts +19 -0
- package/dist/components/banner.svelte +254 -0
- package/dist/components/banner.svelte.d.ts +23 -0
- package/dist/components/button/button.svelte +105 -0
- package/dist/components/button/button.svelte.d.ts +4 -0
- package/dist/components/button/index.d.ts +48 -0
- package/dist/components/button/index.js +4 -0
- package/dist/components/button/style.d.ts +148 -0
- package/dist/components/button/style.js +248 -0
- package/dist/components/card.svelte +70 -0
- package/dist/components/card.svelte.d.ts +17 -0
- package/dist/components/checkbox-group.svelte +258 -0
- package/dist/components/checkbox-group.svelte.d.ts +26 -0
- package/dist/components/checkbox.svelte +175 -0
- package/dist/components/checkbox.svelte.d.ts +27 -0
- package/dist/components/chip.svelte +82 -0
- package/dist/components/chip.svelte.d.ts +17 -0
- package/dist/components/color-picker.svelte +48 -0
- package/dist/components/color-picker.svelte.d.ts +10 -0
- package/dist/components/h1.svelte +15 -0
- package/dist/components/h1.svelte.d.ts +3 -0
- package/dist/components/h2.svelte +19 -0
- package/dist/components/h2.svelte.d.ts +3 -0
- package/dist/components/h3.svelte +16 -0
- package/dist/components/h3.svelte.d.ts +3 -0
- package/dist/components/h4.svelte +19 -0
- package/dist/components/h4.svelte.d.ts +3 -0
- package/dist/components/h5.svelte +19 -0
- package/dist/components/h5.svelte.d.ts +3 -0
- package/dist/components/h6.svelte +19 -0
- package/dist/components/h6.svelte.d.ts +3 -0
- package/dist/components/index.d.ts +42 -0
- package/dist/components/index.js +42 -0
- package/dist/components/input/index.d.ts +54 -0
- package/dist/components/input/index.js +2 -0
- package/dist/components/input/input.svelte +103 -0
- package/dist/components/input/input.svelte.d.ts +4 -0
- package/dist/components/input/style.d.ts +316 -0
- package/dist/components/input/style.js +128 -0
- package/dist/components/input-time/index.d.ts +375 -0
- package/dist/components/input-time/index.js +144 -0
- package/dist/components/input-time/input-time.svelte +39 -0
- package/dist/components/input-time/input-time.svelte.d.ts +4 -0
- package/dist/components/kbd.svelte +239 -0
- package/dist/components/kbd.svelte.d.ts +40 -0
- package/dist/components/p.svelte +9 -0
- package/dist/components/p.svelte.d.ts +3 -0
- package/dist/components/pin-input.svelte +162 -0
- package/dist/components/pin-input.svelte.d.ts +25 -0
- package/dist/components/placeholder.svelte +34 -0
- package/dist/components/placeholder.svelte.d.ts +3 -0
- package/dist/components/popover.svelte +151 -0
- package/dist/components/popover.svelte.d.ts +88 -0
- package/dist/components/progress.svelte +124 -0
- package/dist/components/progress.svelte.d.ts +21 -0
- package/dist/components/select.svelte +171 -0
- package/dist/components/select.svelte.d.ts +50 -0
- package/dist/components/slider.svelte +172 -0
- package/dist/components/slider.svelte.d.ts +44 -0
- package/dist/components/switch.svelte +180 -0
- package/dist/components/switch.svelte.d.ts +27 -0
- package/dist/components/tabs.svelte +246 -0
- package/dist/components/tabs.svelte.d.ts +34 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/utilities.svelte.d.ts +24 -0
- package/dist/utilities.svelte.js +47 -0
- package/dist/vite.d.ts +51 -0
- package/dist/vite.js +157 -0
- package/package.json +2 -2
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { type PropColor, isComponent, isSnippet } from '../index.js';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
import type { ClassNameValue } from 'tailwind-merge';
|
|
5
|
+
import { tv } from 'tailwind-variants';
|
|
6
|
+
import type { Component } from 'vitest-browser-svelte';
|
|
7
|
+
|
|
8
|
+
export type SwitchProps = {
|
|
9
|
+
value?: boolean;
|
|
10
|
+
color?: PropColor;
|
|
11
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
loading?: boolean;
|
|
14
|
+
loadingicon?: string | Snippet | Component;
|
|
15
|
+
uncheckedicon?: string | Snippet | Component;
|
|
16
|
+
checkedicon?: string | Snippet | Component;
|
|
17
|
+
label?: string | Snippet;
|
|
18
|
+
description?: string | Snippet;
|
|
19
|
+
required?: boolean;
|
|
20
|
+
ui?: {
|
|
21
|
+
root?: ClassNameValue;
|
|
22
|
+
container?: ClassNameValue;
|
|
23
|
+
thumb?: ClassNameValue;
|
|
24
|
+
label?: ClassNameValue;
|
|
25
|
+
description?: ClassNameValue;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<script lang="ts">
|
|
31
|
+
let {
|
|
32
|
+
value = $bindable(false),
|
|
33
|
+
color = 'primary',
|
|
34
|
+
size = 'md',
|
|
35
|
+
disabled,
|
|
36
|
+
loading,
|
|
37
|
+
loadingicon = 'i-lucide-loader-circle',
|
|
38
|
+
uncheckedicon,
|
|
39
|
+
checkedicon,
|
|
40
|
+
label,
|
|
41
|
+
description,
|
|
42
|
+
required,
|
|
43
|
+
ui = {},
|
|
44
|
+
}: SwitchProps = $props();
|
|
45
|
+
|
|
46
|
+
const classes = $derived.by(() =>
|
|
47
|
+
tv({
|
|
48
|
+
slots: {
|
|
49
|
+
root: 'flex-inline gap-2',
|
|
50
|
+
container: 'rounded-full bg-neutral-200 p-0.5 relative transition',
|
|
51
|
+
thumb: [
|
|
52
|
+
'bg-white block rounded-full absolute top-0.5 transition grid place-items-center',
|
|
53
|
+
value ? 'translate-x-full' : 'text-neutral-500',
|
|
54
|
+
],
|
|
55
|
+
icon: 'pi',
|
|
56
|
+
label: 'text-sm',
|
|
57
|
+
description: 'text-sm text-neutral-500',
|
|
58
|
+
},
|
|
59
|
+
variants: {
|
|
60
|
+
color: {
|
|
61
|
+
primary: {
|
|
62
|
+
container: ['', value && 'bg-primary-500 text-primary-500'],
|
|
63
|
+
},
|
|
64
|
+
surface: {
|
|
65
|
+
container: ['', value && 'bg-neutral-900 text-neutral-900'],
|
|
66
|
+
},
|
|
67
|
+
info: {
|
|
68
|
+
container: ['', value && 'bg-info-500 text-info-500'],
|
|
69
|
+
},
|
|
70
|
+
success: {
|
|
71
|
+
container: ['', value && 'bg-success-500 text-success-500'],
|
|
72
|
+
},
|
|
73
|
+
warning: {
|
|
74
|
+
container: ['', value && 'bg-warning-500 text-warning-500'],
|
|
75
|
+
},
|
|
76
|
+
error: {
|
|
77
|
+
container: ['', value && 'bg-error-500 text-error-500'],
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
size: {
|
|
81
|
+
xs: {
|
|
82
|
+
container: 'w-7 min-w-7 h-4',
|
|
83
|
+
thumb: 'size-3',
|
|
84
|
+
icon: 'size-2.5',
|
|
85
|
+
},
|
|
86
|
+
sm: {
|
|
87
|
+
container: 'w-8 min-w-8 h-4.5',
|
|
88
|
+
thumb: 'size-3.5',
|
|
89
|
+
icon: 'size-3',
|
|
90
|
+
},
|
|
91
|
+
md: {
|
|
92
|
+
container: 'w-9 min-w-9 h-5',
|
|
93
|
+
thumb: 'size-4',
|
|
94
|
+
icon: 'size-3.5',
|
|
95
|
+
},
|
|
96
|
+
lg: {
|
|
97
|
+
container: 'w-10 min-w-10 h-5.5',
|
|
98
|
+
thumb: 'size-4.5',
|
|
99
|
+
icon: 'size-4',
|
|
100
|
+
},
|
|
101
|
+
xl: {
|
|
102
|
+
container: 'w-11 min-w-11 h-6',
|
|
103
|
+
thumb: 'size-5',
|
|
104
|
+
icon: 'size-4.5',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
compoundVariants: [],
|
|
109
|
+
})({ color, size }),
|
|
110
|
+
);
|
|
111
|
+
</script>
|
|
112
|
+
|
|
113
|
+
<div
|
|
114
|
+
data-state={value ? 'checked' : 'unchecked'}
|
|
115
|
+
class={classes.root({
|
|
116
|
+
class: [(loading || disabled) && 'opacity-50', ui.thumb],
|
|
117
|
+
})}
|
|
118
|
+
>
|
|
119
|
+
<button
|
|
120
|
+
aria-label="switch"
|
|
121
|
+
data-state={value ? 'checked' : 'unchecked'}
|
|
122
|
+
class={classes.container({ class: [loading && 'cursor-not-allowed', ui.thumb] })}
|
|
123
|
+
onclick={() => {
|
|
124
|
+
console.log('click');
|
|
125
|
+
if (loading) return;
|
|
126
|
+
value = !value;
|
|
127
|
+
}}
|
|
128
|
+
>
|
|
129
|
+
<span data-state={value ? 'checked' : 'unchecked'} class={classes.thumb({ class: ui.thumb })}>
|
|
130
|
+
{@render Icon(uncheckedicon, [(loading || value) && 'opacity-0'])}
|
|
131
|
+
{@render Icon(checkedicon, [(loading || !value) && 'opacity-0'])}
|
|
132
|
+
{@render Icon(loadingicon || 'i-lucide-loader-circle', [
|
|
133
|
+
'animate-spin',
|
|
134
|
+
!loading && 'opacity-0',
|
|
135
|
+
])}
|
|
136
|
+
</span>
|
|
137
|
+
</button>
|
|
138
|
+
|
|
139
|
+
{#if label}
|
|
140
|
+
<span>
|
|
141
|
+
<div
|
|
142
|
+
class={classes.label({
|
|
143
|
+
class: [required ? 'after:content-["*"] after:text-error-500' : '', ui.thumb],
|
|
144
|
+
})}
|
|
145
|
+
>
|
|
146
|
+
{#if typeof label === 'string'}
|
|
147
|
+
{label}
|
|
148
|
+
{:else}
|
|
149
|
+
{@render label()}
|
|
150
|
+
{/if}
|
|
151
|
+
</div>
|
|
152
|
+
|
|
153
|
+
{#if description}
|
|
154
|
+
<div class={classes.description({ class: ui.thumb })}>
|
|
155
|
+
{#if typeof description === 'string'}
|
|
156
|
+
{description}
|
|
157
|
+
{:else}
|
|
158
|
+
{@render description()}
|
|
159
|
+
{/if}
|
|
160
|
+
</div>
|
|
161
|
+
{/if}
|
|
162
|
+
</span>
|
|
163
|
+
{/if}
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
{#snippet Icon(ico?: SwitchProps['checkedicon'], icon_class?: ClassNameValue)}
|
|
167
|
+
<div class={['absolute', icon_class]}>
|
|
168
|
+
{#if typeof ico === 'string'}
|
|
169
|
+
<div
|
|
170
|
+
data-state={value ? 'checked' : 'unchecked'}
|
|
171
|
+
class={classes.icon({ class: [ico] })}
|
|
172
|
+
></div>
|
|
173
|
+
{:else if isSnippet(ico)}
|
|
174
|
+
{@render ico()}
|
|
175
|
+
{:else if isComponent(ico)}
|
|
176
|
+
{@const Iconn = ico}
|
|
177
|
+
<Iconn />
|
|
178
|
+
{/if}
|
|
179
|
+
</div>
|
|
180
|
+
{/snippet}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type PropColor } from '../index.js';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { ClassNameValue } from 'tailwind-merge';
|
|
4
|
+
import type { Component } from 'vitest-browser-svelte';
|
|
5
|
+
export type SwitchProps = {
|
|
6
|
+
value?: boolean;
|
|
7
|
+
color?: PropColor;
|
|
8
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
loading?: boolean;
|
|
11
|
+
loadingicon?: string | Snippet | Component;
|
|
12
|
+
uncheckedicon?: string | Snippet | Component;
|
|
13
|
+
checkedicon?: string | Snippet | Component;
|
|
14
|
+
label?: string | Snippet;
|
|
15
|
+
description?: string | Snippet;
|
|
16
|
+
required?: boolean;
|
|
17
|
+
ui?: {
|
|
18
|
+
root?: ClassNameValue;
|
|
19
|
+
container?: ClassNameValue;
|
|
20
|
+
thumb?: ClassNameValue;
|
|
21
|
+
label?: ClassNameValue;
|
|
22
|
+
description?: ClassNameValue;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
declare const Switch: import("svelte").Component<SwitchProps, {}, "value">;
|
|
26
|
+
type Switch = ReturnType<typeof Switch>;
|
|
27
|
+
export default Switch;
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { Tabs } from 'bits-ui';
|
|
3
|
+
import { isComponent, isSnippet, useElementRects, type PropColor } from '../index.js';
|
|
4
|
+
import type { ClassNameValue } from 'tailwind-merge';
|
|
5
|
+
import { tv } from 'tailwind-variants';
|
|
6
|
+
import { type Component, type Snippet } from 'svelte';
|
|
7
|
+
import Icon from '@iconify/svelte';
|
|
8
|
+
import { ElementRect } from 'runed';
|
|
9
|
+
|
|
10
|
+
export type TabItem =
|
|
11
|
+
| string
|
|
12
|
+
| {
|
|
13
|
+
label: string;
|
|
14
|
+
icon?: string | Component | Snippet;
|
|
15
|
+
iconposition?: 'before' | 'after';
|
|
16
|
+
content?: string | Component;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type TabsProps = {
|
|
20
|
+
value?: number;
|
|
21
|
+
items: TabItem[];
|
|
22
|
+
color?: PropColor;
|
|
23
|
+
variant?: 'link' | 'pill';
|
|
24
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
orientation?: 'vertical' | 'horizontal';
|
|
27
|
+
ui?: {
|
|
28
|
+
root?: ClassNameValue;
|
|
29
|
+
item?: ClassNameValue;
|
|
30
|
+
list?: ClassNameValue;
|
|
31
|
+
content?: ClassNameValue;
|
|
32
|
+
icon?: ClassNameValue;
|
|
33
|
+
indicator?: ClassNameValue;
|
|
34
|
+
};
|
|
35
|
+
[k: `content_${string}`]: Snippet<[{ item: TabItem; value: number }]>;
|
|
36
|
+
};
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<script lang="ts">
|
|
40
|
+
let {
|
|
41
|
+
value = $bindable(0),
|
|
42
|
+
items = [],
|
|
43
|
+
color = 'primary',
|
|
44
|
+
variant = 'pill',
|
|
45
|
+
size = 'md',
|
|
46
|
+
disabled,
|
|
47
|
+
orientation = 'horizontal',
|
|
48
|
+
ui = {},
|
|
49
|
+
...rest
|
|
50
|
+
}: TabsProps = $props();
|
|
51
|
+
|
|
52
|
+
let container_el = $state<HTMLElement | null>(null);
|
|
53
|
+
const container_rect = new ElementRect(() => container_el);
|
|
54
|
+
let item_els = $state<HTMLElement[]>([]);
|
|
55
|
+
const rects = useElementRects(() => item_els);
|
|
56
|
+
const rect = $derived.by(() => {
|
|
57
|
+
const result = { w: 0, h: 0, l: 0, t: 0 };
|
|
58
|
+
|
|
59
|
+
if (rects[value]) {
|
|
60
|
+
result.w = rects[value].width;
|
|
61
|
+
result.l = rects[value].left - container_rect.left;
|
|
62
|
+
result.h = rects[value].height;
|
|
63
|
+
result.t = rects[value].top - container_rect.top;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return result;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const classes = $derived.by(() =>
|
|
70
|
+
tv({
|
|
71
|
+
slots: {
|
|
72
|
+
root: '',
|
|
73
|
+
list: 'flex relative p-1',
|
|
74
|
+
item: 'flex items-center justify-center text-muted data-[state="inactive"]:hover:(text-highlighted) font-medium z-1 transition-all',
|
|
75
|
+
icon: '',
|
|
76
|
+
content: 'mt-2',
|
|
77
|
+
indicator: 'absolute z-0 transition-all duration-200 rounded-md w---width',
|
|
78
|
+
},
|
|
79
|
+
variants: {
|
|
80
|
+
variant: {
|
|
81
|
+
pill: {
|
|
82
|
+
list: 'bg-surface-elevated rounded-lg',
|
|
83
|
+
item: 'flex-1 data-[state="active"]:(text-inverted)',
|
|
84
|
+
trigger: 'flex-1',
|
|
85
|
+
indicator: 'rounded-md shadow-xs',
|
|
86
|
+
},
|
|
87
|
+
link: {
|
|
88
|
+
list: 'border-b border-surface-accented',
|
|
89
|
+
item: '',
|
|
90
|
+
indicator: 'rounded-full -bottom-px',
|
|
91
|
+
trigger: 'focus:outline-none',
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
color: {
|
|
95
|
+
primary: {
|
|
96
|
+
item: 'data-[variant="link"]:data-[state="active"]:text-primary-500',
|
|
97
|
+
indicator: 'bg-primary-500',
|
|
98
|
+
},
|
|
99
|
+
surface: {
|
|
100
|
+
item: 'data-[variant="link"]:data-[state="active"]:text-surface-500',
|
|
101
|
+
indicator: 'bg-surface-900',
|
|
102
|
+
},
|
|
103
|
+
info: {
|
|
104
|
+
item: 'data-[variant="link"]:data-[state="active"]:text-info-500',
|
|
105
|
+
indicator: 'bg-info-500',
|
|
106
|
+
},
|
|
107
|
+
success: {
|
|
108
|
+
item: 'data-[variant="link"]:data-[state="active"]:text-success-500',
|
|
109
|
+
indicator: 'bg-success-500',
|
|
110
|
+
},
|
|
111
|
+
warning: {
|
|
112
|
+
item: 'data-[variant="link"]:data-[state="active"]:text-warning-500',
|
|
113
|
+
indicator: 'bg-warning-500',
|
|
114
|
+
},
|
|
115
|
+
error: {
|
|
116
|
+
item: 'data-[variant="link"]:data-[state="active"]:text-error-500',
|
|
117
|
+
indicator: 'bg-error-500',
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
size: {
|
|
121
|
+
xs: {
|
|
122
|
+
list: 'text-xs',
|
|
123
|
+
item: 'min-h-6 gap-1 px-2',
|
|
124
|
+
icon: 'size-4',
|
|
125
|
+
},
|
|
126
|
+
sm: {
|
|
127
|
+
list: 'text-xs',
|
|
128
|
+
item: 'min-h-7 gap-1 px-3',
|
|
129
|
+
icon: 'size-4',
|
|
130
|
+
},
|
|
131
|
+
md: {
|
|
132
|
+
list: 'text-sm',
|
|
133
|
+
item: 'min-h-8 gap-2 px-4',
|
|
134
|
+
icon: 'size-5',
|
|
135
|
+
},
|
|
136
|
+
lg: {
|
|
137
|
+
list: 'text-sm',
|
|
138
|
+
item: 'min-h-9 gap-2 px-4',
|
|
139
|
+
icon: 'size-5',
|
|
140
|
+
},
|
|
141
|
+
xl: {
|
|
142
|
+
list: '',
|
|
143
|
+
item: 'min-h-10 gap-4 px-5',
|
|
144
|
+
icon: 'size-6',
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
orientation: {
|
|
148
|
+
horizontal: {
|
|
149
|
+
indicator: 'h-px left---left',
|
|
150
|
+
},
|
|
151
|
+
vertical: {
|
|
152
|
+
root: '',
|
|
153
|
+
list: 'flex-col',
|
|
154
|
+
indicator: 'h-(--height) top-(--top)',
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
compoundVariants: [
|
|
159
|
+
{ size: 'xs', variant: 'pill', class: { indicator: 'h-6' } },
|
|
160
|
+
{ size: 'sm', variant: 'pill', class: { indicator: 'h-7' } },
|
|
161
|
+
{ size: 'md', variant: 'pill', class: { indicator: 'h-8' } },
|
|
162
|
+
{ size: 'lg', variant: 'pill', class: { indicator: 'h-9' } },
|
|
163
|
+
{ size: 'xl', variant: 'pill', class: { indicator: 'h-10' } },
|
|
164
|
+
{
|
|
165
|
+
size: 'xs',
|
|
166
|
+
variant: 'link',
|
|
167
|
+
orientation: 'vertical',
|
|
168
|
+
class: { indicator: 'h-6' },
|
|
169
|
+
},
|
|
170
|
+
{ size: 'sm', variant: 'link', orientation: 'vertical', class: { indicator: 'h-7' } },
|
|
171
|
+
{ size: 'md', variant: 'link', orientation: 'vertical', class: { indicator: 'h-8' } },
|
|
172
|
+
{ size: 'lg', variant: 'link', orientation: 'vertical', class: { indicator: 'h-9' } },
|
|
173
|
+
{ size: 'xl', variant: 'link', orientation: 'vertical', class: { indicator: 'h-10' } },
|
|
174
|
+
{
|
|
175
|
+
orientation: 'vertical',
|
|
176
|
+
variant: 'link',
|
|
177
|
+
class: { list: 'border-b-0 border-l', indicator: 'w-px -left-px' },
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
})({ color, size, orientation, variant }),
|
|
181
|
+
);
|
|
182
|
+
</script>
|
|
183
|
+
|
|
184
|
+
<Tabs.Root
|
|
185
|
+
{disabled}
|
|
186
|
+
bind:value={() => value.toString(), (v) => (value = parseInt(v))}
|
|
187
|
+
class={classes.root({ class: ui.root })}
|
|
188
|
+
{orientation}
|
|
189
|
+
>
|
|
190
|
+
<Tabs.List bind:ref={container_el} class={classes.list({ class: ui.list })}>
|
|
191
|
+
{#each items as item, idx (idx)}
|
|
192
|
+
{@const label = typeof item === 'string' ? item : item.label}
|
|
193
|
+
|
|
194
|
+
<Tabs.Trigger
|
|
195
|
+
bind:ref={
|
|
196
|
+
() => {
|
|
197
|
+
if (item_els[idx]) return item_els[idx];
|
|
198
|
+
if (typeof document !== 'undefined') return document.createElement('div');
|
|
199
|
+
},
|
|
200
|
+
(v) => {
|
|
201
|
+
if (v) item_els[idx] = v;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
value={idx.toString()}
|
|
205
|
+
class={classes.item({ class: ui.item })}
|
|
206
|
+
data-variant={variant}
|
|
207
|
+
>
|
|
208
|
+
{@render RenderIcon(typeof item === 'string' ? undefined : item.icon)}
|
|
209
|
+
|
|
210
|
+
{label}
|
|
211
|
+
</Tabs.Trigger>
|
|
212
|
+
{/each}
|
|
213
|
+
|
|
214
|
+
<span
|
|
215
|
+
class={classes.indicator({ class: ui.indicator })}
|
|
216
|
+
style:--width="{rect.w}px"
|
|
217
|
+
style:--left="{rect.l}px"
|
|
218
|
+
style:--height="{rect.w}px"
|
|
219
|
+
style:--top="{rect.t}px"
|
|
220
|
+
></span>
|
|
221
|
+
</Tabs.List>
|
|
222
|
+
{#each items as item, idx (idx)}
|
|
223
|
+
{#if typeof item === 'object' && item.content}
|
|
224
|
+
{@const Content = item.content}
|
|
225
|
+
<Tabs.Content value={idx.toString()} class={classes.content({ class: ui.content })}>
|
|
226
|
+
{#if `content_${idx}` in rest}
|
|
227
|
+
{@render rest[`content_${idx}`]({ item, value: idx })}
|
|
228
|
+
{:else if typeof Content === 'string'}
|
|
229
|
+
{Content}
|
|
230
|
+
{:else if isComponent(Content)}
|
|
231
|
+
<Content />
|
|
232
|
+
{/if}
|
|
233
|
+
</Tabs.Content>
|
|
234
|
+
{/if}
|
|
235
|
+
{/each}
|
|
236
|
+
</Tabs.Root>
|
|
237
|
+
|
|
238
|
+
{#snippet RenderIcon(IconProp?: string | Component | Snippet)}
|
|
239
|
+
{#if isSnippet(IconProp)}
|
|
240
|
+
{@render IconProp()}
|
|
241
|
+
{:else if isComponent(IconProp)}
|
|
242
|
+
<IconProp class={classes.icon({ class: ui.icon })} />
|
|
243
|
+
{:else if typeof IconProp === 'string'}
|
|
244
|
+
<Icon icon={IconProp} class={classes.icon({ class: ui.icon })} />
|
|
245
|
+
{/if}
|
|
246
|
+
{/snippet}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Tabs } from 'bits-ui';
|
|
2
|
+
import { type PropColor } from '../index.js';
|
|
3
|
+
import type { ClassNameValue } from 'tailwind-merge';
|
|
4
|
+
import { type Component, type Snippet } from 'svelte';
|
|
5
|
+
export type TabItem = string | {
|
|
6
|
+
label: string;
|
|
7
|
+
icon?: string | Component | Snippet;
|
|
8
|
+
iconposition?: 'before' | 'after';
|
|
9
|
+
content?: string | Component;
|
|
10
|
+
};
|
|
11
|
+
export type TabsProps = {
|
|
12
|
+
value?: number;
|
|
13
|
+
items: TabItem[];
|
|
14
|
+
color?: PropColor;
|
|
15
|
+
variant?: 'link' | 'pill';
|
|
16
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
orientation?: 'vertical' | 'horizontal';
|
|
19
|
+
ui?: {
|
|
20
|
+
root?: ClassNameValue;
|
|
21
|
+
item?: ClassNameValue;
|
|
22
|
+
list?: ClassNameValue;
|
|
23
|
+
content?: ClassNameValue;
|
|
24
|
+
icon?: ClassNameValue;
|
|
25
|
+
indicator?: ClassNameValue;
|
|
26
|
+
};
|
|
27
|
+
[k: `content_${string}`]: Snippet<[{
|
|
28
|
+
item: TabItem;
|
|
29
|
+
value: number;
|
|
30
|
+
}]>;
|
|
31
|
+
};
|
|
32
|
+
declare const Tabs: Component<TabsProps, {}, "value">;
|
|
33
|
+
type Tabs = ReturnType<typeof Tabs>;
|
|
34
|
+
export default Tabs;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Component, Snippet } from 'svelte';
|
|
2
|
+
import { type MaybeGetter, type ElementSizeOptions } from 'runed';
|
|
3
|
+
/**
|
|
4
|
+
* Checks if a value is a Svelte component
|
|
5
|
+
* @param v - The value to check
|
|
6
|
+
* @returns true if the value is a component, false otherwise
|
|
7
|
+
*/
|
|
8
|
+
export declare const isComponent: (v: unknown) => v is Component;
|
|
9
|
+
/**
|
|
10
|
+
* Checks if a value is a Svelte snippet
|
|
11
|
+
* @param v - The value to check
|
|
12
|
+
* @returns true if the value is a snippet, false otherwise
|
|
13
|
+
*/
|
|
14
|
+
export declare const isSnippet: (v: unknown) => v is Snippet;
|
|
15
|
+
/**
|
|
16
|
+
* Returns a reactive value holding the dom rect of `node`s.
|
|
17
|
+
*
|
|
18
|
+
* Accepts an `options` object with the following properties:
|
|
19
|
+
* - `initialSize`: The initial size of the element. Defaults to `{ width: 0, height: 0 }`.
|
|
20
|
+
* - `box`: The box model to use. Can be either `"content-box"` or `"border-box"`. Defaults to `"border-box"`.
|
|
21
|
+
*
|
|
22
|
+
* @returns an array of dom rects.
|
|
23
|
+
*/
|
|
24
|
+
export declare function useElementRects(nodes: MaybeGetter<HTMLElement[]>, options?: ElementSizeOptions): DOMRect[];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { extract, useMutationObserver, useResizeObserver, } from 'runed';
|
|
2
|
+
/**
|
|
3
|
+
* Checks if a value is a Svelte component
|
|
4
|
+
* @param v - The value to check
|
|
5
|
+
* @returns true if the value is a component, false otherwise
|
|
6
|
+
*/
|
|
7
|
+
export const isComponent = (v) => {
|
|
8
|
+
return typeof v === 'function' || (typeof v === 'object' && v !== null && !('$$render' in v));
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Checks if a value is a Svelte snippet
|
|
12
|
+
* @param v - The value to check
|
|
13
|
+
* @returns true if the value is a snippet, false otherwise
|
|
14
|
+
*/
|
|
15
|
+
export const isSnippet = (v) => {
|
|
16
|
+
return typeof v === 'object' && v !== null && '$$render' in v;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Returns a reactive value holding the dom rect of `node`s.
|
|
20
|
+
*
|
|
21
|
+
* Accepts an `options` object with the following properties:
|
|
22
|
+
* - `initialSize`: The initial size of the element. Defaults to `{ width: 0, height: 0 }`.
|
|
23
|
+
* - `box`: The box model to use. Can be either `"content-box"` or `"border-box"`. Defaults to `"border-box"`.
|
|
24
|
+
*
|
|
25
|
+
* @returns an array of dom rects.
|
|
26
|
+
*/
|
|
27
|
+
export function useElementRects(nodes, options = {}) {
|
|
28
|
+
const rects = $state(extract(nodes).map((v) => v.getBoundingClientRect()));
|
|
29
|
+
const elements = $derived(extract(nodes));
|
|
30
|
+
const update = () => {
|
|
31
|
+
if (!elements || elements.length === 0)
|
|
32
|
+
return;
|
|
33
|
+
elements.forEach((el, idx) => (rects[idx] = el.getBoundingClientRect()));
|
|
34
|
+
};
|
|
35
|
+
$effect(() => {
|
|
36
|
+
const stops = [];
|
|
37
|
+
elements.forEach((v) => {
|
|
38
|
+
stops.push(useResizeObserver(() => v, update, { window: options.window }).stop);
|
|
39
|
+
stops.push(useMutationObserver(() => v, update, {
|
|
40
|
+
attributeFilter: ['style', 'class'],
|
|
41
|
+
window: options.window,
|
|
42
|
+
}).stop);
|
|
43
|
+
});
|
|
44
|
+
return () => stops.forEach((v) => v());
|
|
45
|
+
});
|
|
46
|
+
return rects;
|
|
47
|
+
}
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { presetIcons } from 'unocss';
|
|
2
|
+
import { type WebFontsOptions } from '@unocss/preset-web-fonts';
|
|
3
|
+
import type { PropColor } from './index.js';
|
|
4
|
+
export type Colors = Record<string, string | Record<string, string>>;
|
|
5
|
+
export type NestedObject<K extends string, V> = {
|
|
6
|
+
[key in K]: NestedObject<K, V> | V;
|
|
7
|
+
};
|
|
8
|
+
export type PluginOptions = {
|
|
9
|
+
/**
|
|
10
|
+
* Colors as UnoCSS color name, hex color, or UnoCSS theme color object
|
|
11
|
+
* @example
|
|
12
|
+
* {
|
|
13
|
+
* primary: 'orange',
|
|
14
|
+
* surface: 'neutral',
|
|
15
|
+
* info: '#00F',
|
|
16
|
+
* success: '#0F0',
|
|
17
|
+
* warning: 'FF0',
|
|
18
|
+
* error: {
|
|
19
|
+
* 50: '#fef2f2';
|
|
20
|
+
* 100: '#fee2e2';
|
|
21
|
+
* 200: '#fecaca';
|
|
22
|
+
* 300: '#fca5a5';
|
|
23
|
+
* 400: '#f87171';
|
|
24
|
+
* 500: '#ef4444';
|
|
25
|
+
* 600: '#dc2626';
|
|
26
|
+
* 700: '#b91c1c';
|
|
27
|
+
* 800: '#991b1b';
|
|
28
|
+
* 900: '#7f1d1d';
|
|
29
|
+
* 950: '#450a0a';
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
*/
|
|
33
|
+
colors?: Partial<Record<PropColor, string | Record<number, string>>>;
|
|
34
|
+
/**
|
|
35
|
+
* UnoCSS theme object for shared configuration between rules
|
|
36
|
+
*/
|
|
37
|
+
theme?: object;
|
|
38
|
+
/**
|
|
39
|
+
* Options for the UnoCSS web fonts preset
|
|
40
|
+
*/
|
|
41
|
+
fonts?: WebFontsOptions;
|
|
42
|
+
/**
|
|
43
|
+
* Corner radius for every* component
|
|
44
|
+
*/
|
|
45
|
+
radius?: number;
|
|
46
|
+
/**
|
|
47
|
+
* Options for the UnoCSS icon preset
|
|
48
|
+
*/
|
|
49
|
+
icons?: Parameters<typeof presetIcons>[0];
|
|
50
|
+
};
|
|
51
|
+
export declare function uisv(options: PluginOptions): import("vite").Plugin<any>[][];
|