@valerius_petrini/corekit-ui 0.1.62 → 0.1.64

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.
Files changed (47) hide show
  1. package/dist/components/Analytics.svelte +4 -0
  2. package/dist/components/Button.svelte +10 -5
  3. package/dist/components/Card.svelte +1 -1
  4. package/dist/components/Combobox.svelte +207 -0
  5. package/dist/components/Combobox.svelte.d.ts +4 -0
  6. package/dist/components/Input.svelte +46 -148
  7. package/dist/components/KBD.svelte +23 -0
  8. package/dist/components/KBD.svelte.d.ts +3 -0
  9. package/dist/components/Loader.svelte +35 -0
  10. package/dist/components/Loader.svelte.d.ts +4 -0
  11. package/dist/components/NavbarDropdown.svelte +82 -0
  12. package/dist/components/NavbarDropdown.svelte.d.ts +4 -0
  13. package/dist/components/NavbarSeparator.svelte +11 -1
  14. package/dist/components/NavbarSeparator.svelte.d.ts +3 -25
  15. package/dist/components/SEO.svelte +27 -17
  16. package/dist/components/Select.svelte +63 -23
  17. package/dist/components/Select.svelte.d.ts +1 -1
  18. package/dist/components/Tooltip.svelte +124 -0
  19. package/dist/components/Tooltip.svelte.d.ts +4 -0
  20. package/dist/components/helper/BaseInput.svelte +105 -0
  21. package/dist/components/helper/BaseInput.svelte.d.ts +4 -0
  22. package/dist/components/helper/NumberInput.svelte +79 -0
  23. package/dist/components/helper/NumberInput.svelte.d.ts +11 -0
  24. package/dist/index.d.ts +3 -0
  25. package/dist/index.js +3 -0
  26. package/dist/styles/color.d.ts +1 -1
  27. package/dist/styles/color.js +56 -28
  28. package/dist/styles/layout.css +7 -0
  29. package/dist/styles/posititon.d.ts +1 -0
  30. package/dist/styles/size.d.ts +1 -1
  31. package/dist/styles/size.js +36 -12
  32. package/dist/types/Button.d.ts +1 -0
  33. package/dist/types/Input.d.ts +20 -5
  34. package/dist/types/Input.js +1 -0
  35. package/dist/types/Loader.d.ts +5 -0
  36. package/dist/types/{Select.js → Loader.js} +0 -1
  37. package/dist/types/Navbar.d.ts +14 -1
  38. package/dist/types/Navbar.js +5 -1
  39. package/dist/types/SEO.d.ts +1 -1
  40. package/dist/types/Tooltip.d.ts +7 -0
  41. package/dist/types/Tooltip.js +1 -0
  42. package/dist/utils/debounce.d.ts +1 -0
  43. package/dist/utils/debounce.js +7 -0
  44. package/dist/utils/link.d.ts +2 -2
  45. package/dist/utils/link.js +2 -2
  46. package/package.json +1 -1
  47. package/dist/types/Select.d.ts +0 -12
@@ -0,0 +1,82 @@
1
+ <script lang="ts">
2
+ import { fly } from "svelte/transition";
3
+ import NavbarElement from "./NavbarElement.svelte";
4
+ import { tick } from "svelte";
5
+ import type { NavbarDropdownProps } from "../types/Navbar.js";
6
+
7
+ let {
8
+ children = undefined,
9
+ class: className = "",
10
+ wrapperClass = "",
11
+ label = "",
12
+ element = undefined,
13
+ ...restProps
14
+ }: NavbarDropdownProps = $props();
15
+
16
+ let open = $state(false);
17
+ let dropdownRef: HTMLButtonElement | null = $state(null);
18
+ let wrapperRef: HTMLDivElement | null = $state(null);
19
+ let offsetX = $state(0);
20
+ let flipUp = $state(false);
21
+
22
+ function calculateOverflow() {
23
+ if (!dropdownRef) return;
24
+
25
+ offsetX = 0;
26
+
27
+ const menuRect = dropdownRef.getBoundingClientRect();
28
+ const vw = window.innerWidth;
29
+ const padding = 12;
30
+
31
+ flipUp = menuRect.bottom > window.innerHeight - padding;
32
+
33
+ if (menuRect.right > vw - padding)
34
+ offsetX = -(menuRect.right - (vw - padding));
35
+ else if (menuRect.left < padding)
36
+ offsetX = padding - menuRect.left;
37
+ else
38
+ offsetX = 0;
39
+ }
40
+
41
+ async function toggle() {
42
+ open = !open;
43
+ if (open) {
44
+ await tick();
45
+ calculateOverflow();
46
+ } else {
47
+ offsetX = 0;
48
+ }
49
+ }
50
+
51
+ function handleClickOutside(event: MouseEvent) {
52
+ if (dropdownRef && !dropdownRef.contains(event.target as Node) && wrapperRef && !wrapperRef.contains(event.target as Node)) {
53
+ open = false;
54
+ offsetX = 0;
55
+ }
56
+ }
57
+ </script>
58
+
59
+ <svelte:window onclick={handleClickOutside}/>
60
+
61
+ <div class="relative" bind:this={wrapperRef}>
62
+ <NavbarElement onclick={toggle} class={className} {...restProps} aria-haspopup="true" aria-expanded={open}>
63
+ {label}
64
+ {#if element}
65
+ {@render element()}
66
+ {/if}
67
+ </NavbarElement>
68
+
69
+ {#if open}
70
+ <div
71
+ class="absolute {flipUp ? 'bottom-full' : 'top-full'} left-0 z-100 mt-1 overflow-hidden shadow-lg"
72
+ style="transform: translateX({offsetX}px); visibility: {open ? 'visible' : 'hidden'};">
73
+ <button
74
+ bind:this={dropdownRef}
75
+ transition:fly={{ y: flipUp ? 5 : -5, duration: 200 }}
76
+ class="bg-sub-background p-2 min-w-max flex flex-col *:px-0 rounded border-sub-background-hover border"
77
+ onclick={() => open = false}>
78
+ {@render children?.()}
79
+ </button>
80
+ </div>
81
+ {/if}
82
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { NavbarDropdownProps } from "../types/Navbar.js";
2
+ declare const NavbarDropdown: import("svelte").Component<NavbarDropdownProps, {}, "">;
3
+ type NavbarDropdown = ReturnType<typeof NavbarDropdown>;
4
+ export default NavbarDropdown;
@@ -1 +1,11 @@
1
- <div class="ml-auto"></div>
1
+ <script lang="ts">
2
+ import { NavbarSeparatorClasses, type NavbarSeparatorProps } from "../types/Navbar.js";
3
+
4
+ let {
5
+ variant = "dynamic",
6
+ class: className = "",
7
+ ...restProps
8
+ }: NavbarSeparatorProps = $props();
9
+ </script>
10
+
11
+ <div class={NavbarSeparatorClasses[variant]} {...restProps}></div>
@@ -1,26 +1,4 @@
1
+ import { type NavbarSeparatorProps } from "../types/Navbar.js";
2
+ declare const NavbarSeparator: import("svelte").Component<NavbarSeparatorProps, {}, "">;
3
+ type NavbarSeparator = ReturnType<typeof NavbarSeparator>;
1
4
  export default NavbarSeparator;
2
- type NavbarSeparator = SvelteComponent<{
3
- [x: string]: never;
4
- }, {
5
- [evt: string]: CustomEvent<any>;
6
- }, {}> & {
7
- $$bindings?: string | undefined;
8
- };
9
- declare const NavbarSeparator: $$__sveltets_2_IsomorphicComponent<{
10
- [x: string]: never;
11
- }, {
12
- [evt: string]: CustomEvent<any>;
13
- }, {}, {}, string>;
14
- 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> {
15
- new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
16
- $$bindings?: Bindings;
17
- } & Exports;
18
- (internal: unknown, props: {
19
- $$events?: Events;
20
- $$slots?: Slots;
21
- }): Exports & {
22
- $set?: any;
23
- $on?: any;
24
- };
25
- z_$$bindings?: Bindings;
26
- }
@@ -7,37 +7,47 @@
7
7
  const DEFAULT_IMAGE = "/favicon.png";
8
8
 
9
9
  let {
10
- websiteName,
11
10
  title = DEFAULT_TITLE,
12
11
  description = DEFAULT_DESCRIPTION,
13
- image = DEFAULT_IMAGE
12
+ image = DEFAULT_IMAGE,
13
+ noindex = false,
14
14
  }: SEOProps = $props();
15
15
 
16
- let fullUrl = $derived(`${websiteName}${page.url.pathname.toString()}`);
16
+ let origin = $derived(page.url.origin);
17
+ let fullUrl = $derived(page.url.href);
18
+ let fullImage = $derived(image.startsWith("http") ? image : `${origin}${image}`);
19
+
20
+ let jsonLd = $derived(JSON.stringify({
21
+ "@context": "https://schema.org",
22
+ "@type": "WebSite",
23
+ "name": title,
24
+ "url": fullUrl,
25
+ "logo": fullImage
26
+ }));
17
27
  </script>
18
28
 
19
29
  <svelte:head>
20
30
  <title>{title}</title>
31
+ <link rel="canonical" href={fullUrl}>
21
32
  <meta name="description" content={description}>
22
- <meta property="og_site_name" content={websiteName}>
33
+ {#if noindex}
34
+ <meta name="robots" content="noindex,nofollow">
35
+ {/if}
36
+
37
+ <meta property="og:site_name" content={title}>
23
38
  <meta property="og:url" content={fullUrl}>
24
39
  <meta property="og:type" content="website">
25
- <meta property="og:title" content="{title}">
40
+ <meta property="og:title" content={title}>
26
41
  <meta property="og:description" content={description}>
27
- <meta property="og:image" content={websiteName + image}>
28
-
42
+ <meta property="og:image" content={fullImage}>
43
+ <meta property="og:locale" content="en_US">
44
+
29
45
  <meta name="twitter:card" content="summary_large_image">
30
- <meta property="twitter:domain" content={websiteName}>
46
+ <meta property="twitter:domain" content={page.url.hostname}>
31
47
  <meta property="twitter:url" content={fullUrl}>
32
- <meta name="twitter:title" content="{title}">
48
+ <meta name="twitter:title" content={title}>
33
49
  <meta name="twitter:description" content={description}>
34
- <meta name="twitter:image" content={websiteName + image}>
35
- {@html ` <script type="application/ld+json">{
36
- "@context": "https://schema.org",
37
- "@type": "Website",
38
- "name": "${title}",
39
- "url": "${fullUrl}",
40
- "logo": "${websiteName}${image}" }</script>`}
50
+ <meta name="twitter:image" content={fullImage}>
41
51
 
42
- <meta name="google-site-verification" content="F6vDzwDyZfebc9kWIZlhzpsAm5zhanaPkOArdCZdDSU" />
52
+ {@html `<script type="application/ld+json">${jsonLd}</script>`}
43
53
  </svelte:head>
@@ -1,40 +1,80 @@
1
1
  <script lang="ts">
2
- import type { SelectProps } from "../types/Select.js";
3
2
  import { twMerge } from "tailwind-merge";
4
3
  import Text from "./Text.svelte";
4
+ import { getSizeStyleClass } from "../styles/size.js";
5
+
6
+ import type { SelectProps } from "../types/Input.js";
7
+ import BaseInput from "./helper/BaseInput.svelte";
5
8
 
6
9
  let {
7
10
  children = undefined,
8
11
  class: className = "",
9
12
  label = "",
10
- divClass = "",
11
- optionClass = "",
12
- value = $bindable(),
13
+ labelClass = "",
14
+ divClass = "",
15
+ outerDivClass = "",
13
16
  options = [],
17
+ variant = "default",
18
+ value = $bindable(),
19
+ required = false,
20
+ disabled = false,
21
+ size = "md",
22
+ radius = "md",
14
23
  id = crypto.randomUUID(),
15
24
  ...restProps
16
25
  }: SelectProps = $props();
17
26
 
18
- let defaultSelectClass = "cursor-pointer bg-form-background border-[1px] border-form-border text-main-text z-20 w-full rounded px-1 pt-4 pb-1 text-xs outline-none focus:ring-2 focus:ring-blue-500 transition-all";
19
- let defaultLabelClass = "block text-sub-text rounded-md text-sm font-medium mb-1 absolute transition-all duration-100 pointer-events-none";
20
- let defaultDivClass = "relative w-fit";
21
27
 
22
- let selectedLabelClass = "left-2 z-30 top-0.5 text-[10px]!";
28
+ const sizeClasses = $derived(getSizeStyleClass(size, "form"));
29
+ const labelSizeClass = $derived(getSizeStyleClass(size, "formLabel"));
30
+
31
+ const customStyle = $derived.by(() => {
32
+ const styles: string[] = [];
33
+
34
+ if (typeof size === "number")
35
+ styles.push(`width: ${size}px`);
36
+
37
+ if (typeof radius === "number")
38
+ styles.push(`border-radius: ${radius}px`);
39
+
40
+ return styles.join("; ");
41
+ });
42
+
43
+ let isFocused = $state(true);
44
+
45
+ let defaultClass = "text-main-text w-full outline-none px-0.5 w-full bg-inherit border-0 focus:ring-0 focus-visible:ring-0 rounded-full";
23
46
 
24
- let combinedLabelClass = $derived(twMerge(defaultLabelClass, selectedLabelClass, className));
25
- let combinedSelectClass = $derived(twMerge(defaultSelectClass, className));
26
- let combinedDivClass = $derived(twMerge(defaultDivClass, divClass));
47
+ let defaultInputClassCheck = $derived(variant !== "floating" ? "py-0" : "");
48
+ let combinedClass = $derived(twMerge(defaultClass, sizeClasses, defaultInputClassCheck, labelSizeClass, className));
27
49
  </script>
28
50
 
29
- <div class={combinedDivClass}>
30
- <Text tag="label" for={id} class={combinedLabelClass}>
31
- {label}
32
- </Text>
33
- <select {id} class={combinedSelectClass} {...restProps} bind:value={value}>
34
- {#each options as option}
35
- <option value={option.value} class={optionClass}>
36
- {option.label}
37
- </option>
38
- {/each}
39
- </select>
40
- </div>
51
+ <BaseInput
52
+ {children}
53
+ {className}
54
+ {label}
55
+ {labelClass}
56
+ {divClass}
57
+ {outerDivClass}
58
+ {value}
59
+ {required}
60
+ {disabled}
61
+ {variant}
62
+ {size}
63
+ {radius}
64
+ {isFocused}
65
+ {id}
66
+ {...restProps}>
67
+ {#snippet innerDivElement()}
68
+ <select
69
+ id={id}
70
+ class={combinedClass}
71
+ disabled={disabled}
72
+ bind:value={value}
73
+ style={customStyle}
74
+ {...restProps}>
75
+ {#each options as option}
76
+ <option value={option.value}>{option.label}</option>
77
+ {/each}
78
+ </select>
79
+ {/snippet}
80
+ </BaseInput>
@@ -1,4 +1,4 @@
1
- import type { SelectProps } from "../types/Select.js";
1
+ import type { SelectProps } from "../types/Input.js";
2
2
  declare const Select: import("svelte").Component<SelectProps, {}, "value">;
3
3
  type Select = ReturnType<typeof Select>;
4
4
  export default Select;
@@ -0,0 +1,124 @@
1
+ <script lang="ts">
2
+ import type { TooltipComponent } from "../types/Tooltip.js";
3
+ import { type Snippet } from "svelte";
4
+ import { fly } from "svelte/transition";
5
+
6
+ let {
7
+ text,
8
+ position = "top",
9
+ delay = 0,
10
+ children
11
+ }: TooltipComponent = $props();
12
+
13
+ let visible = $state(false);
14
+ let resolvedPosition: string | null = $state(null);
15
+ let offsetX = $state(0);
16
+ let trigger: HTMLDivElement;
17
+ let tooltip: HTMLDivElement | null = $state(null);
18
+ let timeout: ReturnType<typeof setTimeout>;
19
+ let arrowX = $derived(-offsetX);
20
+
21
+ function calculatePosition() {
22
+ resolvedPosition = position;
23
+ if (!trigger) return;
24
+
25
+ const rect = trigger.getBoundingClientRect();
26
+ const vw = window.innerWidth;
27
+ const vh = window.innerHeight;
28
+
29
+ if (position === "top" && rect.top < 40) resolvedPosition = "bottom";
30
+ else if (position === "bottom" && rect.bottom > vh - 40) resolvedPosition = "top";
31
+ else if (position === "left" && rect.left < 120) resolvedPosition = "right";
32
+ else if (position === "right" && rect.right > vw - 120) resolvedPosition = "left";
33
+ else resolvedPosition = position;
34
+ }
35
+
36
+ function calculateOverflow() {
37
+ if (!tooltip || !trigger) return;
38
+
39
+ const triggerRect = trigger.getBoundingClientRect();
40
+ const tooltipRect = tooltip.getBoundingClientRect();
41
+ const vw = window.innerWidth;
42
+
43
+ const triggerCenter = triggerRect.left + triggerRect.width / 2;
44
+
45
+ const tooltipLeft = triggerCenter - tooltipRect.width / 2;
46
+ const tooltipRight = triggerCenter + tooltipRect.width / 2;
47
+
48
+ const padding = 8;
49
+
50
+ if (tooltipRight > vw - padding)
51
+ offsetX = -(tooltipRight - (vw - padding));
52
+ else if (tooltipLeft < padding)
53
+ offsetX = padding - tooltipLeft;
54
+ else
55
+ offsetX = 0;
56
+ }
57
+
58
+ function show() {
59
+ calculatePosition();
60
+ timeout = setTimeout(() => {
61
+ visible = true;
62
+ requestAnimationFrame(calculateOverflow);
63
+ }, delay);
64
+ }
65
+
66
+ function hide() {
67
+ clearTimeout(timeout);
68
+ visible = false;
69
+ }
70
+
71
+ const positionClasses: Record<string, string> = {
72
+ top: "bottom-full left-1/2 -translate-x-1/2 mb-2",
73
+ bottom: "top-full left-1/2 -translate-x-1/2 mt-2",
74
+ left: "right-full top-1/2 -translate-y-1/2 mr-2",
75
+ right: "left-full top-1/2 -translate-y-1/2 ml-2"
76
+ };
77
+
78
+ const arrowClasses: Record<string, string> = {
79
+ top: "top-full left-1/2 -translate-x-1/2 border-t-form-background",
80
+ bottom: "bottom-full left-1/2 -translate-x-1/2 border-b-form-background",
81
+ left: "left-full top-1/2 -translate-y-1/2 border-l-form-background",
82
+ right: "right-full top-1/2 -translate-y-1/2 border-r-form-background"
83
+ };
84
+
85
+ const flyParams = $derived.by(() => {
86
+ const pos = resolvedPosition || position;
87
+
88
+ const duration = 100;
89
+ const distance = 8;
90
+ if (pos == "top")
91
+ return { y: distance, duration };
92
+ else if (pos == "bottom")
93
+ return { y: -distance, duration };
94
+ const x = pos == "right" ? -distance : distance;
95
+ return { x, duration };
96
+ });
97
+ </script>
98
+
99
+ <div
100
+ bind:this={trigger}
101
+ class="relative inline-flex w-fit h-fit"
102
+ onmouseenter={show}
103
+ onmouseleave={hide}
104
+ role="tooltip">
105
+ {@render children()}
106
+
107
+ {#if visible}
108
+ <div
109
+ bind:this={tooltip}
110
+ style="transform: translateX(calc(-50% + {offsetX}px));"
111
+ class="absolute z-999999 {positionClasses[resolvedPosition || position]} translate-x-0! pointer-events-none">
112
+ <div
113
+ transition:fly={flyParams}
114
+ class="px-2 py-1 text-xs text-main-text bg-form-background rounded whitespace-nowrap">
115
+ {text}
116
+
117
+ <div
118
+ class="absolute {arrowClasses[resolvedPosition || position]} border-4 border-transparent w-0 h-0"
119
+ style="transform: translateX(calc(-50% + {arrowX}px));"
120
+ ></div>
121
+ </div>
122
+ </div>
123
+ {/if}
124
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { TooltipComponent } from "../types/Tooltip.js";
2
+ declare const Tooltip: import("svelte").Component<TooltipComponent, {}, "">;
3
+ type Tooltip = ReturnType<typeof Tooltip>;
4
+ export default Tooltip;
@@ -0,0 +1,105 @@
1
+ <script lang="ts">
2
+ import { twMerge } from "tailwind-merge";
3
+ import type { BaseInputProps } from "../../types/Input.js";
4
+ import Text from "../Text.svelte";
5
+ import { getSizeStyleClass } from "../../styles/size.js";
6
+
7
+ let {
8
+ children = undefined,
9
+ class: className = "",
10
+ label = "",
11
+ labelClass = "",
12
+ divClass = "",
13
+ outerDivClass = "",
14
+ value = $bindable(),
15
+ required = false,
16
+ disabled = false,
17
+ variant = "default",
18
+ size = "md",
19
+ radius = "md",
20
+ isFocused = false,
21
+ icon = undefined,
22
+ id = crypto.randomUUID(),
23
+
24
+ isHovered = $bindable(false),
25
+
26
+ innerDivElement = undefined,
27
+ outerDivElementAfter = undefined,
28
+
29
+ ...restProps
30
+ }: BaseInputProps = $props();
31
+
32
+ const hasContent = $derived(value !== undefined && value !== null && value.toString().length > 0);
33
+
34
+ const customLabelStyle = $derived.by(() => {
35
+ const styles: string[] = [];
36
+
37
+ if (typeof size === "number")
38
+ styles.push(`font-size: ${size / 4}px`);
39
+
40
+ return styles.join("; ");
41
+ });
42
+
43
+ let labelClassIcon = $derived(icon != null && variant === "floating" ? "pl-[32px] pr-2" : "");
44
+
45
+ const defaultLabelClass = "block text-sub-text font-medium mb-1 duration-100 pointer-events-none truncate w-fit";
46
+ const floatingLabelClass = "absolute w-full z-30 top-1/2 transform -translate-y-1/2 px-1.5";
47
+
48
+ const combinedLabelClass = $derived(twMerge(
49
+ defaultLabelClass,
50
+ (variant === "floating") ? floatingLabelClass : "px-0",
51
+ labelClassIcon,
52
+ getSizeStyleClass(size, "formLabel"),
53
+ ((isFocused || hasContent) && variant === "floating") && getSizeStyleClass(size, "formLabelSelected"),
54
+ labelClass
55
+ ));
56
+
57
+ const combinedOuterDivClass = $derived(twMerge(
58
+ "relative flex flex-col bg-transparent border-0 p-0",
59
+ getSizeStyleClass(radius, "radius"),
60
+ size === "full" ? "w-full" : "",
61
+ outerDivClass,
62
+ disabled ? "opacity-50 pointer-events-none" : ""
63
+ ));
64
+
65
+ const combinedDivClass = $derived(twMerge(
66
+ "relative *:transition-all transition-colors flex-center bg-form-background border-[1px] border-form-border focus-within:ring-1 focus-within:ring-blue-500 overflow-hidden",
67
+ getSizeStyleClass(radius, "radius"),
68
+ size === "full" ? "w-full" : "",
69
+ divClass,
70
+ disabled ? "opacity-50 pointer-events-none" : ""
71
+ ));
72
+ </script>
73
+
74
+ {#snippet labelElement()}
75
+ <Text tag="label" for={id} class={combinedLabelClass} style={customLabelStyle}>
76
+ {label}
77
+ {#if required}
78
+ <span class="text-[#E05555]">*</span>
79
+ {/if}
80
+ </Text>
81
+ {/snippet}
82
+
83
+ {#snippet innerDivElementWrapper()}
84
+ <div role="button" tabindex="0" class={combinedDivClass} onmouseenter={() => isHovered = true} onmouseleave={() => isHovered = false}>
85
+ {#if variant === "floating"}
86
+ {@render labelElement()}
87
+ {/if}
88
+ {#if icon}
89
+ {@const Icon = icon}
90
+ <div class="h-5 aspect-square px-1 py-0!">
91
+ <Icon class="h-full aspect-square text-sub-text"></Icon>
92
+ </div>
93
+ {/if}
94
+ {@render innerDivElement?.()}
95
+ </div>
96
+ {/snippet}
97
+
98
+ <div class={combinedOuterDivClass}>
99
+ {#if variant !== "floating"}
100
+ {@render labelElement()}
101
+ {/if}
102
+ {@render innerDivElementWrapper()}
103
+
104
+ {@render outerDivElementAfter?.()}
105
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { BaseInputProps } from "../../types/Input.js";
2
+ declare const BaseInput: import("svelte").Component<BaseInputProps, {}, "value" | "isHovered">;
3
+ type BaseInput = ReturnType<typeof BaseInput>;
4
+ export default BaseInput;
@@ -0,0 +1,79 @@
1
+ <script lang="ts">
2
+ import Button from "../Button.svelte";
3
+ import ChevronUp from "@lucide/svelte/icons/chevron-up";
4
+ import ChevronDown from "@lucide/svelte/icons/chevron-down";
5
+ import { twMerge } from "tailwind-merge";
6
+ import { getSizeStyleClass, type SizeStyle } from "../../styles/size.js";
7
+
8
+ let {
9
+ max = undefined,
10
+ min = undefined,
11
+ step = undefined,
12
+ value = $bindable(),
13
+ isHovered = false,
14
+ size = "md" as SizeStyle,
15
+ ...restProps
16
+ } = $props();
17
+
18
+ function increment() {
19
+ if (max === undefined || value < max) value = (value || 0) + (step || 1);
20
+ }
21
+
22
+ function decrement() {
23
+ if (min === undefined || value > min) value = (value || 0) - (step || 1);
24
+ }
25
+
26
+ let incrementInterval: ReturnType<typeof setInterval> | null = null;
27
+ let decrementInterval: ReturnType<typeof setInterval> | null = null;
28
+
29
+ function startIncrement() {
30
+ increment();
31
+ incrementInterval = setInterval(increment, 100);
32
+ }
33
+
34
+ function stopIncrement() {
35
+ if (incrementInterval) {
36
+ clearInterval(incrementInterval);
37
+ incrementInterval = null;
38
+ }
39
+ }
40
+
41
+ function startDecrement() {
42
+ decrement();
43
+ decrementInterval = setInterval(decrement, 100);
44
+ }
45
+
46
+ function stopDecrement() {
47
+ if (decrementInterval) {
48
+ clearInterval(decrementInterval);
49
+ decrementInterval = null;
50
+ }
51
+ }
52
+
53
+ const numberIconClass = $derived(twMerge(
54
+ getSizeStyleClass(size, "form"),
55
+ "text-sub-text/70 w-fit aspect-auto p-0 flex-center flex-col transition-all duration-150"
56
+ ));
57
+ const numberButtonClass = "py-0! h-1/2 gap-0 px-0.5 hover:bg-form-border aspect-square rounded-none";
58
+ </script>
59
+
60
+ <div class={twMerge(numberIconClass, isHovered ? "opacity-100 scale-100" : "opacity-0 scale-75")}>
61
+ <Button
62
+ size="none" radius="none"
63
+ class={numberButtonClass}
64
+ onmousedown={startIncrement}
65
+ onmouseup={stopIncrement}
66
+ onmouseleave={stopIncrement}
67
+ disabled={max !== undefined && value >= max}>
68
+ <ChevronUp class="w-full h-full"/>
69
+ </Button>
70
+ <Button
71
+ size="none" radius="none"
72
+ class={numberButtonClass}
73
+ onmousedown={startDecrement}
74
+ onmouseup={stopDecrement}
75
+ onmouseleave={stopDecrement}
76
+ disabled={min !== undefined && value <= min}>
77
+ <ChevronDown class="w-full h-full"/>
78
+ </Button>
79
+ </div>
@@ -0,0 +1,11 @@
1
+ import { type SizeStyle } from "../../styles/size.js";
2
+ declare const NumberInput: import("svelte").Component<{
3
+ max?: any;
4
+ min?: any;
5
+ step?: any;
6
+ value?: any;
7
+ isHovered?: boolean;
8
+ size?: SizeStyle;
9
+ } & Record<string, any>, {}, "value">;
10
+ type NumberInput = ReturnType<typeof NumberInput>;
11
+ export default NumberInput;
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export { default as SEO } from "./components/SEO.svelte";
5
5
  export { default as Navbar } from "./components/Navbar.svelte";
6
6
  export { default as NavbarSeparator } from "./components/NavbarSeparator.svelte";
7
7
  export { default as NavbarElement } from "./components/NavbarElement.svelte";
8
+ export { default as NavbarDropdown } from "./components/NavbarDropdown.svelte";
8
9
  export { default as Input } from "./components/Input.svelte";
9
10
  export { default as FileInput } from "./components/FileInput.svelte";
10
11
  export { default as Select } from "./components/Select.svelte";
@@ -17,6 +18,8 @@ export { default as Table } from "./components/Table.svelte";
17
18
  export { default as Toast } from "./components/Toast.svelte";
18
19
  export { default as Toaster } from "./components/Toaster.svelte";
19
20
  export { default as SideNavbar } from "./components/SideNavbar.svelte";
21
+ export { default as Tooltip } from "./components/Tooltip.svelte";
22
+ export { default as Loader } from "./components/Loader.svelte";
20
23
  export { fbmBackground } from "./actions/fbm.ts";
21
24
  export { toast } from "./actions/toast.svelte.ts";
22
25
  export type { TypewriterAction, DisplaySegment } from "./types/Typewriter.ts";