svelora 3.0.6 → 3.0.7
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/BentoGrid/BentoCard.svelte +45 -0
- package/dist/BentoGrid/BentoCard.svelte.d.ts +4 -0
- package/dist/BentoGrid/BentoGrid.svelte +9 -0
- package/dist/BentoGrid/BentoGrid.svelte.d.ts +4 -0
- package/dist/BentoGrid/bento-grid.types.d.ts +47 -0
- package/dist/BentoGrid/bento-grid.types.js +1 -0
- package/dist/BentoGrid/bento-grid.variants.d.ts +30 -0
- package/dist/BentoGrid/bento-grid.variants.js +16 -0
- package/dist/BentoGrid/index.d.ts +5 -0
- package/dist/BentoGrid/index.js +5 -0
- package/dist/Chart/Chart.svelte +47 -0
- package/dist/Chart/Chart.svelte.d.ts +4 -0
- package/dist/Chart/chart.types.d.ts +20 -0
- package/dist/Chart/chart.types.js +1 -0
- package/dist/Chart/chart.variants.d.ts +3 -0
- package/dist/Chart/chart.variants.js +4 -0
- package/dist/Chart/index.d.ts +4 -0
- package/dist/Chart/index.js +4 -0
- package/dist/Chat/ChatBubble.svelte +30 -0
- package/dist/Chat/ChatBubble.svelte.d.ts +4 -0
- package/dist/Chat/ChatInput.svelte +50 -0
- package/dist/Chat/ChatInput.svelte.d.ts +4 -0
- package/dist/Chat/ChatMessage.svelte +15 -0
- package/dist/Chat/ChatMessage.svelte.d.ts +4 -0
- package/dist/Chat/chat.types.d.ts +63 -0
- package/dist/Chat/chat.types.js +1 -0
- package/dist/Chat/chat.variants.d.ts +117 -0
- package/dist/Chat/chat.variants.js +47 -0
- package/dist/Chat/index.d.ts +6 -0
- package/dist/Chat/index.js +6 -0
- package/dist/ColorPicker/ColorPicker.svelte +109 -0
- package/dist/ColorPicker/ColorPicker.svelte.d.ts +4 -0
- package/dist/ColorPicker/color-picker.types.d.ts +26 -0
- package/dist/ColorPicker/color-picker.types.js +1 -0
- package/dist/ColorPicker/color-picker.variants.d.ts +69 -0
- package/dist/ColorPicker/color-picker.variants.js +13 -0
- package/dist/ColorPicker/index.d.ts +4 -0
- package/dist/ColorPicker/index.js +4 -0
- package/dist/DateRangePicker/DateRangePicker.svelte +59 -0
- package/dist/DateRangePicker/DateRangePicker.svelte.d.ts +4 -0
- package/dist/DateRangePicker/date-range-picker.types.d.ts +34 -0
- package/dist/DateRangePicker/date-range-picker.types.js +1 -0
- package/dist/DateRangePicker/date-range-picker.variants.d.ts +39 -0
- package/dist/DateRangePicker/date-range-picker.variants.js +20 -0
- package/dist/DateRangePicker/index.d.ts +4 -0
- package/dist/DateRangePicker/index.js +4 -0
- package/dist/List/List.svelte +14 -0
- package/dist/List/List.svelte.d.ts +4 -0
- package/dist/List/ListItem.svelte +64 -0
- package/dist/List/ListItem.svelte.d.ts +4 -0
- package/dist/List/index.d.ts +5 -0
- package/dist/List/index.js +5 -0
- package/dist/List/list.types.d.ts +62 -0
- package/dist/List/list.types.js +1 -0
- package/dist/List/list.variants.d.ts +99 -0
- package/dist/List/list.variants.js +42 -0
- package/dist/Marquee/Marquee.svelte +50 -0
- package/dist/Marquee/Marquee.svelte.d.ts +4 -0
- package/dist/Marquee/index.d.ts +4 -0
- package/dist/Marquee/index.js +4 -0
- package/dist/Marquee/marquee.types.d.ts +38 -0
- package/dist/Marquee/marquee.types.js +1 -0
- package/dist/Marquee/marquee.variants.d.ts +78 -0
- package/dist/Marquee/marquee.variants.js +28 -0
- package/dist/Menu/Menu.svelte +134 -0
- package/dist/Menu/Menu.svelte.d.ts +4 -0
- package/dist/Menu/index.d.ts +4 -0
- package/dist/Menu/index.js +4 -0
- package/dist/Menu/menu.types.d.ts +82 -0
- package/dist/Menu/menu.types.js +1 -0
- package/dist/Menu/menu.variants.d.ts +46 -0
- package/dist/Menu/menu.variants.js +32 -0
- package/dist/NumberTicker/NumberTicker.svelte +59 -0
- package/dist/NumberTicker/NumberTicker.svelte.d.ts +4 -0
- package/dist/NumberTicker/index.d.ts +4 -0
- package/dist/NumberTicker/index.js +4 -0
- package/dist/NumberTicker/number-ticker.types.d.ts +26 -0
- package/dist/NumberTicker/number-ticker.types.js +1 -0
- package/dist/NumberTicker/number-ticker.variants.d.ts +27 -0
- package/dist/NumberTicker/number-ticker.variants.js +6 -0
- package/dist/PasswordInput/PasswordInput.svelte +74 -0
- package/dist/PasswordInput/PasswordInput.svelte.d.ts +4 -0
- package/dist/PasswordInput/index.d.ts +4 -0
- package/dist/PasswordInput/index.js +4 -0
- package/dist/PasswordInput/password-input.types.d.ts +18 -0
- package/dist/PasswordInput/password-input.types.js +1 -0
- package/dist/PasswordInput/password-input.variants.d.ts +57 -0
- package/dist/PasswordInput/password-input.variants.js +11 -0
- package/dist/Prose/Prose.svelte +13 -0
- package/dist/Prose/Prose.svelte.d.ts +4 -0
- package/dist/Prose/index.d.ts +4 -0
- package/dist/Prose/index.js +4 -0
- package/dist/Prose/prose.types.d.ts +22 -0
- package/dist/Prose/prose.types.js +1 -0
- package/dist/Prose/prose.variants.d.ts +45 -0
- package/dist/Prose/prose.variants.js +45 -0
- package/dist/Rating/Rating.svelte +93 -0
- package/dist/Rating/Rating.svelte.d.ts +4 -0
- package/dist/Rating/index.d.ts +4 -0
- package/dist/Rating/index.js +4 -0
- package/dist/Rating/rating.types.d.ts +59 -0
- package/dist/Rating/rating.types.js +1 -0
- package/dist/Rating/rating.variants.d.ts +93 -0
- package/dist/Rating/rating.variants.js +32 -0
- package/dist/Resizable/Resizable.svelte +9 -0
- package/dist/Resizable/Resizable.svelte.d.ts +4 -0
- package/dist/Resizable/index.d.ts +4 -0
- package/dist/Resizable/index.js +4 -0
- package/dist/Resizable/resizable.types.d.ts +18 -0
- package/dist/Resizable/resizable.types.js +1 -0
- package/dist/Resizable/resizable.variants.d.ts +48 -0
- package/dist/Resizable/resizable.variants.js +17 -0
- package/dist/ScrollArea/ScrollArea.svelte +54 -0
- package/dist/ScrollArea/ScrollArea.svelte.d.ts +4 -0
- package/dist/ScrollArea/index.d.ts +4 -0
- package/dist/ScrollArea/index.js +4 -0
- package/dist/ScrollArea/scroll-area.types.d.ts +27 -0
- package/dist/ScrollArea/scroll-area.types.js +1 -0
- package/dist/ScrollArea/scroll-area.variants.d.ts +45 -0
- package/dist/ScrollArea/scroll-area.variants.js +27 -0
- package/dist/Sidebar/Sidebar.svelte +30 -0
- package/dist/Sidebar/Sidebar.svelte.d.ts +4 -0
- package/dist/Sidebar/index.d.ts +4 -0
- package/dist/Sidebar/index.js +4 -0
- package/dist/Sidebar/sidebar.types.d.ts +31 -0
- package/dist/Sidebar/sidebar.types.js +1 -0
- package/dist/Sidebar/sidebar.variants.d.ts +69 -0
- package/dist/Sidebar/sidebar.variants.js +23 -0
- package/dist/Spotlight/Spotlight.svelte +31 -0
- package/dist/Spotlight/Spotlight.svelte.d.ts +4 -0
- package/dist/Spotlight/index.d.ts +4 -0
- package/dist/Spotlight/index.js +4 -0
- package/dist/Spotlight/spotlight.types.d.ts +22 -0
- package/dist/Spotlight/spotlight.types.js +1 -0
- package/dist/Spotlight/spotlight.variants.d.ts +39 -0
- package/dist/Spotlight/spotlight.variants.js +8 -0
- package/dist/TagsInput/TagsInput.svelte +100 -0
- package/dist/TagsInput/TagsInput.svelte.d.ts +4 -0
- package/dist/TagsInput/index.d.ts +4 -0
- package/dist/TagsInput/index.js +4 -0
- package/dist/TagsInput/tags-input.types.d.ts +32 -0
- package/dist/TagsInput/tags-input.types.js +1 -0
- package/dist/TagsInput/tags-input.variants.d.ts +45 -0
- package/dist/TagsInput/tags-input.variants.js +22 -0
- package/dist/TreeView/TreeView.svelte +95 -0
- package/dist/TreeView/TreeView.svelte.d.ts +4 -0
- package/dist/TreeView/index.d.ts +4 -0
- package/dist/TreeView/index.js +4 -0
- package/dist/TreeView/tree-view.types.d.ts +68 -0
- package/dist/TreeView/tree-view.types.js +1 -0
- package/dist/TreeView/tree-view.variants.d.ts +69 -0
- package/dist/TreeView/tree-view.variants.js +30 -0
- package/dist/docs/navigation.js +108 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +18 -0
- package/dist/mcp/svelora-docs.data.json +39 -3
- package/package.json +8 -6
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script lang="ts">import { twMerge } from "tailwind-merge";
|
|
2
|
+
import { onMount } from "svelte";
|
|
3
|
+
import { numberTickerVariants } from "./number-ticker.variants.js";
|
|
4
|
+
let { value, duration = 2e3, decimals = 0, delay = 0, class: className, ...restProps } = $props();
|
|
5
|
+
let styles = $derived(numberTickerVariants());
|
|
6
|
+
let displayValue = $state(0);
|
|
7
|
+
let isVisible = $state(false);
|
|
8
|
+
let nodeRef = $state(null);
|
|
9
|
+
// Easing function (easeOutExpo)
|
|
10
|
+
const easeOutExpo = (x) => {
|
|
11
|
+
return x === 1 ? 1 : 1 - 2 ** (-10 * x);
|
|
12
|
+
};
|
|
13
|
+
onMount(() => {
|
|
14
|
+
if (!nodeRef) return;
|
|
15
|
+
let startTime = null;
|
|
16
|
+
let animationFrame;
|
|
17
|
+
const animate = (timestamp) => {
|
|
18
|
+
if (!startTime) startTime = timestamp;
|
|
19
|
+
const progress = timestamp - startTime;
|
|
20
|
+
if (progress < duration) {
|
|
21
|
+
const percentage = progress / duration;
|
|
22
|
+
const easedProgress = easeOutExpo(percentage);
|
|
23
|
+
displayValue = value * easedProgress;
|
|
24
|
+
animationFrame = requestAnimationFrame(animate);
|
|
25
|
+
} else {
|
|
26
|
+
displayValue = value;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const observer = new IntersectionObserver((entries) => {
|
|
30
|
+
if (entries[0].isIntersecting && !isVisible) {
|
|
31
|
+
isVisible = true;
|
|
32
|
+
setTimeout(() => {
|
|
33
|
+
animationFrame = requestAnimationFrame(animate);
|
|
34
|
+
}, delay);
|
|
35
|
+
}
|
|
36
|
+
}, { threshold: .1 });
|
|
37
|
+
observer.observe(nodeRef);
|
|
38
|
+
return () => {
|
|
39
|
+
observer.disconnect();
|
|
40
|
+
if (animationFrame) cancelAnimationFrame(animationFrame);
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
// Re-animate if value changes significantly (optional)
|
|
44
|
+
$effect(() => {
|
|
45
|
+
if (isVisible && value !== undefined) {}
|
|
46
|
+
});
|
|
47
|
+
let formattedValue = $derived(new Intl.NumberFormat("en-US", {
|
|
48
|
+
minimumFractionDigits: decimals,
|
|
49
|
+
maximumFractionDigits: decimals
|
|
50
|
+
}).format(displayValue));
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<span
|
|
54
|
+
bind:this={nodeRef}
|
|
55
|
+
class={twMerge(styles.base() as string, className)}
|
|
56
|
+
{...restProps}
|
|
57
|
+
>
|
|
58
|
+
{formattedValue}
|
|
59
|
+
</span>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
export interface NumberTickerProps extends HTMLAttributes<HTMLSpanElement> {
|
|
3
|
+
/**
|
|
4
|
+
* The target number to animate to.
|
|
5
|
+
*/
|
|
6
|
+
value: number;
|
|
7
|
+
/**
|
|
8
|
+
* Duration of the animation in milliseconds.
|
|
9
|
+
* @default 2000
|
|
10
|
+
*/
|
|
11
|
+
duration?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Whether to show decimal places.
|
|
14
|
+
* @default 0
|
|
15
|
+
*/
|
|
16
|
+
decimals?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Start delay in milliseconds.
|
|
19
|
+
* @default 0
|
|
20
|
+
*/
|
|
21
|
+
delay?: number;
|
|
22
|
+
/**
|
|
23
|
+
* Additional CSS classes.
|
|
24
|
+
*/
|
|
25
|
+
class?: string;
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type VariantProps } from 'tailwind-variants';
|
|
2
|
+
export declare const numberTickerVariants: import("tailwind-variants").TVReturnType<{
|
|
3
|
+
[key: string]: {
|
|
4
|
+
[key: string]: import("tailwind-merge").ClassNameValue | {
|
|
5
|
+
base?: import("tailwind-merge").ClassNameValue;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
} | {
|
|
9
|
+
[x: string]: {
|
|
10
|
+
[x: string]: import("tailwind-merge").ClassNameValue | {
|
|
11
|
+
base?: import("tailwind-merge").ClassNameValue;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
} | {}, {
|
|
15
|
+
base: string;
|
|
16
|
+
}, undefined, {
|
|
17
|
+
[key: string]: {
|
|
18
|
+
[key: string]: import("tailwind-merge").ClassNameValue | {
|
|
19
|
+
base?: import("tailwind-merge").ClassNameValue;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
} | {}, {
|
|
23
|
+
base: string;
|
|
24
|
+
}, import("tailwind-variants").TVReturnType<unknown, {
|
|
25
|
+
base: string;
|
|
26
|
+
}, undefined, unknown, unknown, undefined>>;
|
|
27
|
+
export type NumberTickerVariantProps = VariantProps<typeof numberTickerVariants>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<script lang="ts">import { twMerge } from "tailwind-merge";
|
|
2
|
+
import Icon from "../Icon/Icon.svelte";
|
|
3
|
+
import Input from "../Input/Input.svelte";
|
|
4
|
+
import { passwordInputVariants } from "./password-input.variants.js";
|
|
5
|
+
let { value = $bindable(""), showStrength = false, strengthFn, strengthLabels = [
|
|
6
|
+
"Very Weak",
|
|
7
|
+
"Weak",
|
|
8
|
+
"Fair",
|
|
9
|
+
"Good",
|
|
10
|
+
"Strong"
|
|
11
|
+
], class: className, ...restProps } = $props();
|
|
12
|
+
let styles = $derived(passwordInputVariants());
|
|
13
|
+
let isVisible = $state(false);
|
|
14
|
+
function toggleVisibility() {
|
|
15
|
+
isVisible = !isVisible;
|
|
16
|
+
}
|
|
17
|
+
// Basic strength calculation if none provided
|
|
18
|
+
function calculateStrength(pwd) {
|
|
19
|
+
if (!pwd) return -1;
|
|
20
|
+
let score = 0;
|
|
21
|
+
if (pwd.length > 8) score += 1;
|
|
22
|
+
if (/[A-Z]/.test(pwd) && /[a-z]/.test(pwd)) score += 1;
|
|
23
|
+
if (/[0-9]/.test(pwd)) score += 1;
|
|
24
|
+
if (/[^A-Za-z0-9]/.test(pwd)) score += 1;
|
|
25
|
+
return score;
|
|
26
|
+
}
|
|
27
|
+
let strength = $derived(strengthFn ? strengthFn(String(value ?? "")) : calculateStrength(String(value ?? "")));
|
|
28
|
+
// Colors for the 4 segments based on current strength
|
|
29
|
+
function getSegmentColor(index, currentStrength) {
|
|
30
|
+
if (currentStrength === -1 || index > currentStrength) return "bg-surface-200 dark:bg-surface-700";
|
|
31
|
+
if (currentStrength === 0) return "bg-error-500";
|
|
32
|
+
if (currentStrength === 1) return "bg-warning-500";
|
|
33
|
+
if (currentStrength === 2) return "bg-success-400";
|
|
34
|
+
return "bg-success-500";
|
|
35
|
+
}
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<div class={twMerge(styles.wrapper() as string, className)}>
|
|
39
|
+
<div class={styles.inputWrapper() as string}>
|
|
40
|
+
<Input
|
|
41
|
+
{...restProps as any}
|
|
42
|
+
bind:value
|
|
43
|
+
type={isVisible ? 'text' : 'password'}
|
|
44
|
+
class="w-full pr-10"
|
|
45
|
+
/>
|
|
46
|
+
|
|
47
|
+
<button
|
|
48
|
+
type="button"
|
|
49
|
+
class={styles.toggleBtn() as string}
|
|
50
|
+
onclick={toggleVisibility}
|
|
51
|
+
tabindex="-1"
|
|
52
|
+
aria-label={isVisible ? 'Hide password' : 'Show password'}
|
|
53
|
+
>
|
|
54
|
+
{#if isVisible}
|
|
55
|
+
<Icon name="lucide:eye-off" class="w-5 h-5" />
|
|
56
|
+
{:else}
|
|
57
|
+
<Icon name="lucide:eye" class="w-5 h-5" />
|
|
58
|
+
{/if}
|
|
59
|
+
</button>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
{#if showStrength && String(value ?? '').length > 0}
|
|
63
|
+
<div>
|
|
64
|
+
<div class={styles.meterWrapper() as string}>
|
|
65
|
+
{#each Array(4) as _, i}
|
|
66
|
+
<div class={twMerge(styles.meterSegment() as string, getSegmentColor(i, strength))}></div>
|
|
67
|
+
{/each}
|
|
68
|
+
</div>
|
|
69
|
+
<div class={styles.strengthText() as string}>
|
|
70
|
+
{strengthLabels[Math.max(0, strength)]}
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
{/if}
|
|
74
|
+
</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { InputProps } from '../Input/input.types.js';
|
|
2
|
+
export interface PasswordInputProps extends Omit<InputProps, 'type'> {
|
|
3
|
+
/**
|
|
4
|
+
* Whether to show the password strength meter.
|
|
5
|
+
* @default false
|
|
6
|
+
*/
|
|
7
|
+
showStrength?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Custom function to calculate password strength (0 to 4).
|
|
10
|
+
* 0 = Very Weak, 4 = Very Strong.
|
|
11
|
+
*/
|
|
12
|
+
strengthFn?: (password: string) => number;
|
|
13
|
+
/**
|
|
14
|
+
* Labels for the strength levels (0-4).
|
|
15
|
+
* @default ['Very Weak', 'Weak', 'Fair', 'Good', 'Strong']
|
|
16
|
+
*/
|
|
17
|
+
strengthLabels?: [string, string, string, string, string];
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type VariantProps } from 'tailwind-variants';
|
|
2
|
+
export declare const passwordInputVariants: import("tailwind-variants").TVReturnType<{
|
|
3
|
+
[key: string]: {
|
|
4
|
+
[key: string]: import("tailwind-merge").ClassNameValue | {
|
|
5
|
+
wrapper?: import("tailwind-merge").ClassNameValue;
|
|
6
|
+
inputWrapper?: import("tailwind-merge").ClassNameValue;
|
|
7
|
+
toggleBtn?: import("tailwind-merge").ClassNameValue;
|
|
8
|
+
meterWrapper?: import("tailwind-merge").ClassNameValue;
|
|
9
|
+
meterSegment?: import("tailwind-merge").ClassNameValue;
|
|
10
|
+
strengthText?: import("tailwind-merge").ClassNameValue;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
} | {
|
|
14
|
+
[x: string]: {
|
|
15
|
+
[x: string]: import("tailwind-merge").ClassNameValue | {
|
|
16
|
+
wrapper?: import("tailwind-merge").ClassNameValue;
|
|
17
|
+
inputWrapper?: import("tailwind-merge").ClassNameValue;
|
|
18
|
+
toggleBtn?: import("tailwind-merge").ClassNameValue;
|
|
19
|
+
meterWrapper?: import("tailwind-merge").ClassNameValue;
|
|
20
|
+
meterSegment?: import("tailwind-merge").ClassNameValue;
|
|
21
|
+
strengthText?: import("tailwind-merge").ClassNameValue;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
} | {}, {
|
|
25
|
+
wrapper: string;
|
|
26
|
+
inputWrapper: string;
|
|
27
|
+
toggleBtn: string;
|
|
28
|
+
meterWrapper: string;
|
|
29
|
+
meterSegment: string;
|
|
30
|
+
strengthText: string;
|
|
31
|
+
}, undefined, {
|
|
32
|
+
[key: string]: {
|
|
33
|
+
[key: string]: import("tailwind-merge").ClassNameValue | {
|
|
34
|
+
wrapper?: import("tailwind-merge").ClassNameValue;
|
|
35
|
+
inputWrapper?: import("tailwind-merge").ClassNameValue;
|
|
36
|
+
toggleBtn?: import("tailwind-merge").ClassNameValue;
|
|
37
|
+
meterWrapper?: import("tailwind-merge").ClassNameValue;
|
|
38
|
+
meterSegment?: import("tailwind-merge").ClassNameValue;
|
|
39
|
+
strengthText?: import("tailwind-merge").ClassNameValue;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
} | {}, {
|
|
43
|
+
wrapper: string;
|
|
44
|
+
inputWrapper: string;
|
|
45
|
+
toggleBtn: string;
|
|
46
|
+
meterWrapper: string;
|
|
47
|
+
meterSegment: string;
|
|
48
|
+
strengthText: string;
|
|
49
|
+
}, import("tailwind-variants").TVReturnType<unknown, {
|
|
50
|
+
wrapper: string;
|
|
51
|
+
inputWrapper: string;
|
|
52
|
+
toggleBtn: string;
|
|
53
|
+
meterWrapper: string;
|
|
54
|
+
meterSegment: string;
|
|
55
|
+
strengthText: string;
|
|
56
|
+
}, undefined, unknown, unknown, undefined>>;
|
|
57
|
+
export type PasswordInputVariantProps = VariantProps<typeof passwordInputVariants>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { tv } from 'tailwind-variants';
|
|
2
|
+
export const passwordInputVariants = tv({
|
|
3
|
+
slots: {
|
|
4
|
+
wrapper: 'relative flex flex-col gap-2 w-full',
|
|
5
|
+
inputWrapper: 'relative flex items-center w-full',
|
|
6
|
+
toggleBtn: 'absolute right-3 text-surface-500 hover:text-surface-700 dark:hover:text-surface-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary rounded-sm transition-colors',
|
|
7
|
+
meterWrapper: 'flex gap-1 h-1.5 w-full mt-1',
|
|
8
|
+
meterSegment: 'flex-1 rounded-full transition-colors duration-300',
|
|
9
|
+
strengthText: 'text-xs text-surface-500 dark:text-surface-400 mt-1 text-right'
|
|
10
|
+
}
|
|
11
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<script lang="ts">import { twMerge } from "tailwind-merge";
|
|
2
|
+
import { proseVariants } from "./prose.variants.js";
|
|
3
|
+
let { size = "base", html, class: className, children, ...restProps } = $props();
|
|
4
|
+
let styles = $derived(proseVariants({ size }));
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<div class={twMerge(styles.base() as string, className)} {...restProps}>
|
|
8
|
+
{#if html}
|
|
9
|
+
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
10
|
+
{@html html}
|
|
11
|
+
{/if}
|
|
12
|
+
{@render children?.()}
|
|
13
|
+
</div>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import type { ProseVariantProps } from './prose.variants.js';
|
|
4
|
+
export interface ProseProps extends HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
/**
|
|
6
|
+
* Size of the typography text.
|
|
7
|
+
* @default 'base'
|
|
8
|
+
*/
|
|
9
|
+
size?: ProseVariantProps['size'];
|
|
10
|
+
/**
|
|
11
|
+
* Html string to render. Usually coming from a markdown parser.
|
|
12
|
+
*/
|
|
13
|
+
html?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Additional CSS classes.
|
|
16
|
+
*/
|
|
17
|
+
class?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Content inside the prose container.
|
|
20
|
+
*/
|
|
21
|
+
children?: Snippet;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type VariantProps } from 'tailwind-variants';
|
|
2
|
+
export declare const proseVariants: import("tailwind-variants").TVReturnType<{
|
|
3
|
+
size: {
|
|
4
|
+
sm: {
|
|
5
|
+
base: string;
|
|
6
|
+
};
|
|
7
|
+
base: {
|
|
8
|
+
base: string;
|
|
9
|
+
};
|
|
10
|
+
lg: {
|
|
11
|
+
base: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
}, {
|
|
15
|
+
base: string[];
|
|
16
|
+
}, undefined, {
|
|
17
|
+
size: {
|
|
18
|
+
sm: {
|
|
19
|
+
base: string;
|
|
20
|
+
};
|
|
21
|
+
base: {
|
|
22
|
+
base: string;
|
|
23
|
+
};
|
|
24
|
+
lg: {
|
|
25
|
+
base: string;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
}, {
|
|
29
|
+
base: string[];
|
|
30
|
+
}, import("tailwind-variants").TVReturnType<{
|
|
31
|
+
size: {
|
|
32
|
+
sm: {
|
|
33
|
+
base: string;
|
|
34
|
+
};
|
|
35
|
+
base: {
|
|
36
|
+
base: string;
|
|
37
|
+
};
|
|
38
|
+
lg: {
|
|
39
|
+
base: string;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
}, {
|
|
43
|
+
base: string[];
|
|
44
|
+
}, undefined, unknown, unknown, undefined>>;
|
|
45
|
+
export type ProseVariantProps = VariantProps<typeof proseVariants>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { tv } from 'tailwind-variants';
|
|
2
|
+
export const proseVariants = tv({
|
|
3
|
+
slots: {
|
|
4
|
+
base: [
|
|
5
|
+
'text-surface-900 dark:text-surface-50 max-w-none',
|
|
6
|
+
// Paragraphs
|
|
7
|
+
'[&_p]:leading-7 [&_p]:mb-6 [&_p:last-child]:mb-0',
|
|
8
|
+
// Headings
|
|
9
|
+
'[&_h1]:text-4xl [&_h1]:font-extrabold [&_h1]:tracking-tight [&_h1]:mt-0 [&_h1]:mb-6',
|
|
10
|
+
'[&_h2]:text-3xl [&_h2]:font-semibold [&_h2]:tracking-tight [&_h2]:mt-10 [&_h2]:mb-4',
|
|
11
|
+
'[&_h3]:text-2xl [&_h3]:font-semibold [&_h3]:tracking-tight [&_h3]:mt-8 [&_h3]:mb-4',
|
|
12
|
+
'[&_h4]:text-xl [&_h4]:font-semibold [&_h4]:tracking-tight [&_h4]:mt-8 [&_h4]:mb-4',
|
|
13
|
+
// Links
|
|
14
|
+
'[&_a]:font-medium [&_a]:text-primary-600 dark:[&_a]:text-primary-400 [&_a]:underline [&_a]:underline-offset-4 hover:[&_a]:text-primary-500',
|
|
15
|
+
// Blockquotes
|
|
16
|
+
'[&_blockquote]:mt-6 [&_blockquote]:mb-6 [&_blockquote]:border-l-4 [&_blockquote]:border-primary-500 [&_blockquote]:pl-6 [&_blockquote]:italic [&_blockquote]:text-surface-700 dark:[&_blockquote]:text-surface-300',
|
|
17
|
+
// Lists
|
|
18
|
+
'[&_ul]:my-6 [&_ul]:ml-6 [&_ul]:list-disc [&_ul>li]:mt-2',
|
|
19
|
+
'[&_ol]:my-6 [&_ol]:ml-6 [&_ol]:list-decimal [&_ol>li]:mt-2',
|
|
20
|
+
// Code & Pre
|
|
21
|
+
'[&_code]:relative [&_code]:rounded [&_code]:bg-surface-200 dark:[&_code]:bg-surface-800 [&_code]:px-[0.3rem] [&_code]:py-[0.2rem] [&_code]:font-mono [&_code]:text-sm [&_code]:font-semibold',
|
|
22
|
+
'[&_pre]:mb-6 [&_pre]:mt-6 [&_pre]:overflow-x-auto [&_pre]:rounded-lg [&_pre]:bg-surface-900 [&_pre]:py-4 [&_pre]:dark:bg-surface-800',
|
|
23
|
+
'[&_pre_code]:bg-transparent [&_pre_code]:p-0 [&_pre_code]:text-surface-50 [&_pre_code]:font-normal',
|
|
24
|
+
// Images & Media
|
|
25
|
+
'[&_img]:rounded-lg [&_img]:border [&_img]:border-outline-variant [&_video]:rounded-lg',
|
|
26
|
+
// Tables
|
|
27
|
+
'[&_table]:w-full [&_table]:my-6 [&_table]:overflow-y-auto [&_table]:text-left',
|
|
28
|
+
'[&_th]:border [&_th]:border-outline-variant [&_th]:px-4 [&_th]:py-2 [&_th]:font-semibold [&_th]:bg-surface-100 dark:[&_th]:bg-surface-800',
|
|
29
|
+
'[&_td]:border [&_td]:border-outline-variant [&_td]:px-4 [&_td]:py-2',
|
|
30
|
+
'[&_tr:nth-child(even)]:bg-surface-50 dark:[&_tr:nth-child(even)]:bg-surface-900/50',
|
|
31
|
+
// HR
|
|
32
|
+
'[&_hr]:my-8 [&_hr]:border-outline-variant'
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
variants: {
|
|
36
|
+
size: {
|
|
37
|
+
sm: { base: 'text-sm [&_h1]:text-3xl [&_h2]:text-2xl [&_h3]:text-xl' },
|
|
38
|
+
base: { base: 'text-base' },
|
|
39
|
+
lg: { base: 'text-lg [&_h1]:text-5xl [&_h2]:text-4xl [&_h3]:text-3xl' }
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
defaultVariants: {
|
|
43
|
+
size: 'base'
|
|
44
|
+
}
|
|
45
|
+
});
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<script lang="ts">import { twMerge } from "tailwind-merge";
|
|
2
|
+
import Icon from "../Icon/Icon.svelte";
|
|
3
|
+
import { ratingVariants } from "./rating.variants.js";
|
|
4
|
+
let { value = $bindable(0), max = 5, size = "md", allowHalf = false, disabled = false, readonly = false, iconFull = "lucide:star", iconEmpty = "lucide:star", activeColor = "text-warning-500 fill-warning-500", inactiveColor = "text-surface-300 dark:text-surface-600", class: className, onchange, ...restProps } = $props();
|
|
5
|
+
let styles = $derived(ratingVariants({
|
|
6
|
+
size,
|
|
7
|
+
disabled,
|
|
8
|
+
readonly
|
|
9
|
+
}));
|
|
10
|
+
let hoverValue = $state(null);
|
|
11
|
+
// Calculate array of stars
|
|
12
|
+
let stars = $derived(Array.from({ length: max }, (_, i) => i + 1));
|
|
13
|
+
function handleMouseMove(e, index) {
|
|
14
|
+
if (disabled || readonly) return;
|
|
15
|
+
if (allowHalf) {
|
|
16
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
17
|
+
const x = e.clientX - rect.left;
|
|
18
|
+
const isHalf = x < rect.width / 2;
|
|
19
|
+
hoverValue = isHalf ? index - .5 : index;
|
|
20
|
+
} else {
|
|
21
|
+
hoverValue = index;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function handleMouseLeave() {
|
|
25
|
+
if (disabled || readonly) return;
|
|
26
|
+
hoverValue = null;
|
|
27
|
+
}
|
|
28
|
+
function handleClick(index) {
|
|
29
|
+
if (disabled || readonly) return;
|
|
30
|
+
value = hoverValue ?? index;
|
|
31
|
+
onchange?.(value);
|
|
32
|
+
}
|
|
33
|
+
function handleKeyDown(e, index) {
|
|
34
|
+
if (disabled || readonly) return;
|
|
35
|
+
let newValue = value;
|
|
36
|
+
if (e.key === "ArrowRight" || e.key === "ArrowUp") {
|
|
37
|
+
newValue = Math.min(max, value + (allowHalf ? .5 : 1));
|
|
38
|
+
} else if (e.key === "ArrowLeft" || e.key === "ArrowDown") {
|
|
39
|
+
newValue = Math.max(0, value - (allowHalf ? .5 : 1));
|
|
40
|
+
} else if (e.key === "Enter" || e.key === " ") {
|
|
41
|
+
newValue = index;
|
|
42
|
+
} else {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
e.preventDefault();
|
|
46
|
+
value = newValue;
|
|
47
|
+
onchange?.(value);
|
|
48
|
+
}
|
|
49
|
+
function getStarState(index) {
|
|
50
|
+
const currentValue = hoverValue ?? value;
|
|
51
|
+
if (currentValue >= index) return "full";
|
|
52
|
+
if (allowHalf && currentValue >= index - .5) return "half";
|
|
53
|
+
return "empty";
|
|
54
|
+
}
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
<div
|
|
58
|
+
class={twMerge(styles.base() as string, className)}
|
|
59
|
+
onmouseleave={handleMouseLeave}
|
|
60
|
+
{...restProps}
|
|
61
|
+
role="radiogroup"
|
|
62
|
+
>
|
|
63
|
+
{#each stars as starIndex}
|
|
64
|
+
{@const state = getStarState(starIndex)}
|
|
65
|
+
|
|
66
|
+
<button
|
|
67
|
+
type="button"
|
|
68
|
+
role="radio"
|
|
69
|
+
aria-checked={value >= starIndex}
|
|
70
|
+
aria-label={`Rate ${starIndex} out of ${max} stars`}
|
|
71
|
+
class={styles.starWrapper() as string}
|
|
72
|
+
disabled={disabled || readonly}
|
|
73
|
+
tabindex={disabled || readonly ? -1 : 0}
|
|
74
|
+
onmousemove={(e) => handleMouseMove(e, starIndex)}
|
|
75
|
+
onclick={() => handleClick(starIndex)}
|
|
76
|
+
onkeydown={(e) => handleKeyDown(e, starIndex)}
|
|
77
|
+
>
|
|
78
|
+
{#if state === 'full'}
|
|
79
|
+
<Icon name={iconFull} class={twMerge(styles.star() as string, activeColor)} />
|
|
80
|
+
{:else if state === 'half'}
|
|
81
|
+
<!-- Simple half star implementation using CSS clip-path or two icons -->
|
|
82
|
+
<div class="relative">
|
|
83
|
+
<Icon name={iconEmpty} class={twMerge(styles.star() as string, inactiveColor)} />
|
|
84
|
+
<div class="absolute inset-0 overflow-hidden w-1/2">
|
|
85
|
+
<Icon name={iconFull} class={twMerge(styles.star() as string, activeColor)} />
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
{:else}
|
|
89
|
+
<Icon name={iconEmpty} class={twMerge(styles.star() as string, inactiveColor)} />
|
|
90
|
+
{/if}
|
|
91
|
+
</button>
|
|
92
|
+
{/each}
|
|
93
|
+
</div>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
import type { RatingVariantProps } from './rating.variants.js';
|
|
3
|
+
export interface RatingProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onchange'> {
|
|
4
|
+
/**
|
|
5
|
+
* The current rating value.
|
|
6
|
+
*/
|
|
7
|
+
value?: number;
|
|
8
|
+
/**
|
|
9
|
+
* The maximum rating value (number of stars).
|
|
10
|
+
* @default 5
|
|
11
|
+
*/
|
|
12
|
+
max?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Size of the stars.
|
|
15
|
+
* @default 'md'
|
|
16
|
+
*/
|
|
17
|
+
size?: RatingVariantProps['size'];
|
|
18
|
+
/**
|
|
19
|
+
* Whether the rating allows half-star selection.
|
|
20
|
+
* @default false
|
|
21
|
+
*/
|
|
22
|
+
allowHalf?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Whether the rating is disabled.
|
|
25
|
+
*/
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Whether the rating is read-only (cannot be changed by user).
|
|
29
|
+
*/
|
|
30
|
+
readonly?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Icon to use for the full star.
|
|
33
|
+
* @default 'lucide:star'
|
|
34
|
+
*/
|
|
35
|
+
iconFull?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Icon to use for the empty star.
|
|
38
|
+
* @default 'lucide:star'
|
|
39
|
+
*/
|
|
40
|
+
iconEmpty?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Color class for the active/filled stars.
|
|
43
|
+
* @default 'text-warning-500 fill-warning-500'
|
|
44
|
+
*/
|
|
45
|
+
activeColor?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Color class for the inactive/empty stars.
|
|
48
|
+
* @default 'text-surface-300 dark:text-surface-600'
|
|
49
|
+
*/
|
|
50
|
+
inactiveColor?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Additional CSS classes.
|
|
53
|
+
*/
|
|
54
|
+
class?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Event fired when the rating changes.
|
|
57
|
+
*/
|
|
58
|
+
onchange?: (value: number) => void;
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|