@mkatogui/uds-svelte 0.2.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.
Files changed (36) hide show
  1. package/README.md +100 -0
  2. package/package.json +27 -0
  3. package/src/components/Accordion.svelte +99 -0
  4. package/src/components/Alert.svelte +67 -0
  5. package/src/components/Avatar.svelte +62 -0
  6. package/src/components/Badge.svelte +50 -0
  7. package/src/components/Breadcrumb.svelte +60 -0
  8. package/src/components/Button.svelte +53 -0
  9. package/src/components/Checkbox.svelte +62 -0
  10. package/src/components/CodeBlock.svelte +90 -0
  11. package/src/components/CommandPalette.svelte +133 -0
  12. package/src/components/DataTable.svelte +140 -0
  13. package/src/components/DatePicker.svelte +73 -0
  14. package/src/components/DropdownMenu.svelte +113 -0
  15. package/src/components/FeatureCard.svelte +63 -0
  16. package/src/components/FileUpload.svelte +120 -0
  17. package/src/components/Footer.svelte +72 -0
  18. package/src/components/FormInput.svelte +102 -0
  19. package/src/components/HeroSection.svelte +65 -0
  20. package/src/components/Modal.svelte +67 -0
  21. package/src/components/NavigationBar.svelte +56 -0
  22. package/src/components/Pagination.svelte +115 -0
  23. package/src/components/PricingTable.svelte +89 -0
  24. package/src/components/ProgressIndicator.svelte +86 -0
  25. package/src/components/Radio.svelte +64 -0
  26. package/src/components/Select.svelte +85 -0
  27. package/src/components/SideNavigation.svelte +130 -0
  28. package/src/components/Skeleton.svelte +53 -0
  29. package/src/components/SocialProofBar.svelte +90 -0
  30. package/src/components/Tabs.svelte +100 -0
  31. package/src/components/TestimonialCard.svelte +71 -0
  32. package/src/components/Toast.svelte +83 -0
  33. package/src/components/ToggleSwitch.svelte +61 -0
  34. package/src/components/Tooltip.svelte +67 -0
  35. package/src/index.d.ts +553 -0
  36. package/src/index.js +32 -0
@@ -0,0 +1,72 @@
1
+ <script lang="ts">
2
+ interface FooterColumn {
3
+ title: string;
4
+ links: { label: string; href: string }[];
5
+ }
6
+
7
+ interface Props {
8
+ variant?: 'simple' | 'multi-column' | 'newsletter' | 'mega-footer';
9
+ size?: 'standard' | 'compact';
10
+ columns?: FooterColumn[];
11
+ copyright?: string;
12
+ class?: string;
13
+ children?: import('svelte').Snippet;
14
+ newsletter?: import('svelte').Snippet;
15
+ legal?: import('svelte').Snippet;
16
+ [key: string]: any;
17
+ }
18
+
19
+ let {
20
+ variant = 'simple',
21
+ size = 'standard',
22
+ columns = [],
23
+ copyright = '',
24
+ class: className = '',
25
+ children,
26
+ newsletter,
27
+ legal,
28
+ ...rest
29
+ }: Props = $props();
30
+
31
+ let classes = $derived(
32
+ [
33
+ 'uds-footer',
34
+ `uds-footer--${variant}`,
35
+ `uds-footer--${size}`,
36
+ className,
37
+ ]
38
+ .filter(Boolean)
39
+ .join(' ')
40
+ );
41
+ </script>
42
+
43
+ <footer class={classes} aria-label="Site footer" {...rest}>
44
+ {#if columns.length > 0}
45
+ <div class="uds-footer__columns">
46
+ {#each columns as column}
47
+ <div class="uds-footer__column">
48
+ <h3 class="uds-footer__column-title">{column.title}</h3>
49
+ <ul class="uds-footer__link-list">
50
+ {#each column.links as link}
51
+ <li><a href={link.href}>{link.label}</a></li>
52
+ {/each}
53
+ </ul>
54
+ </div>
55
+ {/each}
56
+ </div>
57
+ {/if}
58
+ {#if newsletter}
59
+ <div class="uds-footer__newsletter">
60
+ {@render newsletter()}
61
+ </div>
62
+ {/if}
63
+ {@render children?.()}
64
+ {#if legal}
65
+ <div class="uds-footer__legal">
66
+ {@render legal()}
67
+ </div>
68
+ {/if}
69
+ {#if copyright}
70
+ <div class="uds-footer__copyright">{copyright}</div>
71
+ {/if}
72
+ </footer>
@@ -0,0 +1,102 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ variant?: 'text' | 'email' | 'password' | 'number' | 'search' | 'textarea';
4
+ size?: 'sm' | 'md' | 'lg';
5
+ state?: 'default' | 'focus' | 'error' | 'disabled' | 'readonly';
6
+ label?: string;
7
+ helperText?: string;
8
+ errorText?: string;
9
+ required?: boolean;
10
+ disabled?: boolean;
11
+ readonly?: boolean;
12
+ value?: string;
13
+ placeholder?: string;
14
+ id?: string;
15
+ class?: string;
16
+ [key: string]: any;
17
+ }
18
+
19
+ let {
20
+ variant = 'text',
21
+ size = 'md',
22
+ state = 'default',
23
+ label = '',
24
+ helperText = '',
25
+ errorText = '',
26
+ required = false,
27
+ disabled = false,
28
+ readonly: readOnly = false,
29
+ value = $bindable(''),
30
+ placeholder = '',
31
+ id,
32
+ class: className = '',
33
+ ...rest
34
+ }: Props = $props();
35
+
36
+ let inputId = $derived(id || `uds-input-${Math.random().toString(36).slice(2, 9)}`);
37
+ let helperId = $derived(`${inputId}-helper`);
38
+ let errorId = $derived(`${inputId}-error`);
39
+ let isError = $derived(state === 'error' || !!errorText);
40
+
41
+ let classes = $derived(
42
+ [
43
+ 'uds-input',
44
+ `uds-input--${variant}`,
45
+ `uds-input--${size}`,
46
+ isError && 'uds-input--error',
47
+ disabled && 'uds-input--disabled',
48
+ readOnly && 'uds-input--readonly',
49
+ className,
50
+ ]
51
+ .filter(Boolean)
52
+ .join(' ')
53
+ );
54
+
55
+ let describedBy = $derived(
56
+ [errorText && errorId, helperText && helperId].filter(Boolean).join(' ') || undefined
57
+ );
58
+ </script>
59
+
60
+ <div class={classes}>
61
+ {#if label}
62
+ <label class="uds-input__label" for={inputId}>
63
+ {label}
64
+ {#if required}
65
+ <span class="uds-input__required" aria-hidden="true">*</span>
66
+ {/if}
67
+ </label>
68
+ {/if}
69
+ {#if variant === 'textarea'}
70
+ <textarea
71
+ class="uds-input__field"
72
+ id={inputId}
73
+ bind:value
74
+ {placeholder}
75
+ {required}
76
+ {disabled}
77
+ readonly={readOnly}
78
+ aria-invalid={isError || undefined}
79
+ aria-describedby={describedBy}
80
+ {...rest}
81
+ ></textarea>
82
+ {:else}
83
+ <input
84
+ class="uds-input__field"
85
+ type={variant}
86
+ id={inputId}
87
+ bind:value
88
+ {placeholder}
89
+ {required}
90
+ {disabled}
91
+ readonly={readOnly}
92
+ aria-invalid={isError || undefined}
93
+ aria-describedby={describedBy}
94
+ {...rest}
95
+ />
96
+ {/if}
97
+ {#if errorText}
98
+ <p class="uds-input__error" id={errorId} role="alert">{errorText}</p>
99
+ {:else if helperText}
100
+ <p class="uds-input__helper" id={helperId}>{helperText}</p>
101
+ {/if}
102
+ </div>
@@ -0,0 +1,65 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ variant?: 'centered' | 'product-screenshot' | 'video-bg' | 'gradient-mesh' | 'search-forward' | 'split';
4
+ size?: 'full' | 'compact';
5
+ headline?: string;
6
+ subheadline?: string;
7
+ class?: string;
8
+ children?: import('svelte').Snippet;
9
+ cta?: import('svelte').Snippet;
10
+ socialProof?: import('svelte').Snippet;
11
+ visual?: import('svelte').Snippet;
12
+ [key: string]: any;
13
+ }
14
+
15
+ let {
16
+ variant = 'centered',
17
+ size = 'full',
18
+ headline = '',
19
+ subheadline = '',
20
+ class: className = '',
21
+ children,
22
+ cta,
23
+ socialProof,
24
+ visual,
25
+ ...rest
26
+ }: Props = $props();
27
+
28
+ let classes = $derived(
29
+ [
30
+ 'uds-hero',
31
+ `uds-hero--${variant}`,
32
+ `uds-hero--${size}`,
33
+ className,
34
+ ]
35
+ .filter(Boolean)
36
+ .join(' ')
37
+ );
38
+ </script>
39
+
40
+ <section class={classes} {...rest}>
41
+ <div class="uds-hero__content">
42
+ {#if headline}
43
+ <h1 class="uds-hero__headline">{headline}</h1>
44
+ {/if}
45
+ {#if subheadline}
46
+ <p class="uds-hero__subheadline">{subheadline}</p>
47
+ {/if}
48
+ {#if cta}
49
+ <div class="uds-hero__cta">
50
+ {@render cta()}
51
+ </div>
52
+ {/if}
53
+ {#if socialProof}
54
+ <div class="uds-hero__social-proof">
55
+ {@render socialProof()}
56
+ </div>
57
+ {/if}
58
+ {@render children?.()}
59
+ </div>
60
+ {#if visual}
61
+ <div class="uds-hero__visual">
62
+ {@render visual()}
63
+ </div>
64
+ {/if}
65
+ </section>
@@ -0,0 +1,67 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ variant?: 'confirmation' | 'task' | 'alert';
4
+ size?: 'sm' | 'md' | 'lg';
5
+ open?: boolean;
6
+ title?: string;
7
+ onClose?: () => void;
8
+ class?: string;
9
+ children?: import('svelte').Snippet;
10
+ actions?: import('svelte').Snippet;
11
+ [key: string]: any;
12
+ }
13
+
14
+ let {
15
+ variant = 'confirmation',
16
+ size = 'md',
17
+ open = false,
18
+ title = '',
19
+ onClose,
20
+ class: className = '',
21
+ children,
22
+ actions,
23
+ ...rest
24
+ }: Props = $props();
25
+
26
+ let classes = $derived(
27
+ [
28
+ 'uds-modal',
29
+ `uds-modal--${variant}`,
30
+ `uds-modal--${size}`,
31
+ open && 'uds-modal--open',
32
+ className,
33
+ ]
34
+ .filter(Boolean)
35
+ .join(' ')
36
+ );
37
+
38
+ function handleKeydown(event: KeyboardEvent) {
39
+ if (event.key === 'Escape' && open) {
40
+ onClose?.();
41
+ }
42
+ }
43
+ </script>
44
+
45
+ <svelte:window onkeydown={handleKeydown} />
46
+
47
+ {#if open}
48
+ <div class="uds-modal__overlay" onclick={onClose} aria-hidden="true"></div>
49
+ <div class={classes} role="dialog" aria-modal="true" aria-label={title} {...rest}>
50
+ <div class="uds-modal__header">
51
+ {#if title}
52
+ <h2 class="uds-modal__title">{title}</h2>
53
+ {/if}
54
+ <button class="uds-modal__close" onclick={onClose} aria-label="Close dialog">
55
+ <span aria-hidden="true">&times;</span>
56
+ </button>
57
+ </div>
58
+ <div class="uds-modal__body">
59
+ {@render children?.()}
60
+ </div>
61
+ {#if actions}
62
+ <div class="uds-modal__actions">
63
+ {@render actions()}
64
+ </div>
65
+ {/if}
66
+ </div>
67
+ {/if}
@@ -0,0 +1,56 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ variant?: 'standard' | 'minimal' | 'dark' | 'transparent';
4
+ sticky?: boolean;
5
+ blurOnScroll?: boolean;
6
+ megaMenu?: boolean;
7
+ darkModeToggle?: boolean;
8
+ mobileOpen?: boolean;
9
+ class?: string;
10
+ children?: import('svelte').Snippet;
11
+ ctaButton?: import('svelte').Snippet;
12
+ [key: string]: any;
13
+ }
14
+
15
+ let {
16
+ variant = 'standard',
17
+ sticky = false,
18
+ blurOnScroll = false,
19
+ megaMenu = false,
20
+ darkModeToggle = false,
21
+ mobileOpen = false,
22
+ class: className = '',
23
+ children,
24
+ ctaButton,
25
+ ...rest
26
+ }: Props = $props();
27
+
28
+ let classes = $derived(
29
+ [
30
+ 'uds-navbar',
31
+ `uds-navbar--${variant}`,
32
+ sticky && 'uds-navbar--sticky',
33
+ blurOnScroll && 'uds-navbar--blur',
34
+ mobileOpen && 'uds-navbar--mobile-open',
35
+ className,
36
+ ]
37
+ .filter(Boolean)
38
+ .join(' ')
39
+ );
40
+ </script>
41
+
42
+ <nav class={classes} aria-label="Main navigation" {...rest}>
43
+ {@render children?.()}
44
+ {#if ctaButton}
45
+ <div class="uds-navbar__cta">
46
+ {@render ctaButton()}
47
+ </div>
48
+ {/if}
49
+ <button
50
+ class="uds-navbar__mobile-toggle"
51
+ aria-expanded={mobileOpen}
52
+ aria-label="Toggle navigation menu"
53
+ >
54
+ <span class="uds-navbar__hamburger" aria-hidden="true"></span>
55
+ </button>
56
+ </nav>
@@ -0,0 +1,115 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ variant?: 'numbered' | 'simple' | 'load-more' | 'infinite-scroll';
4
+ size?: 'sm' | 'md';
5
+ currentPage?: number;
6
+ totalPages?: number;
7
+ onPageChange?: (page: number) => void;
8
+ class?: string;
9
+ [key: string]: any;
10
+ }
11
+
12
+ let {
13
+ variant = 'numbered',
14
+ size = 'md',
15
+ currentPage = 1,
16
+ totalPages = 1,
17
+ onPageChange,
18
+ class: className = '',
19
+ ...rest
20
+ }: Props = $props();
21
+
22
+ let classes = $derived(
23
+ [
24
+ 'uds-pagination',
25
+ `uds-pagination--${variant}`,
26
+ `uds-pagination--${size}`,
27
+ className,
28
+ ]
29
+ .filter(Boolean)
30
+ .join(' ')
31
+ );
32
+
33
+ let pages = $derived(() => {
34
+ const p: (number | string)[] = [];
35
+ for (let i = 1; i <= totalPages; i++) {
36
+ if (i === 1 || i === totalPages || (i >= currentPage - 1 && i <= currentPage + 1)) {
37
+ p.push(i);
38
+ } else if (p[p.length - 1] !== '...') {
39
+ p.push('...');
40
+ }
41
+ }
42
+ return p;
43
+ });
44
+
45
+ function goTo(page: number) {
46
+ if (page >= 1 && page <= totalPages && page !== currentPage) {
47
+ onPageChange?.(page);
48
+ }
49
+ }
50
+ </script>
51
+
52
+ <nav class={classes} aria-label="Pagination" {...rest}>
53
+ {#if variant === 'simple'}
54
+ <button
55
+ class="uds-pagination__prev"
56
+ disabled={currentPage <= 1}
57
+ onclick={() => goTo(currentPage - 1)}
58
+ aria-label="Previous page"
59
+ >
60
+ Previous
61
+ </button>
62
+ <span class="uds-pagination__info">Page {currentPage} of {totalPages}</span>
63
+ <button
64
+ class="uds-pagination__next"
65
+ disabled={currentPage >= totalPages}
66
+ onclick={() => goTo(currentPage + 1)}
67
+ aria-label="Next page"
68
+ >
69
+ Next
70
+ </button>
71
+ {:else if variant === 'load-more'}
72
+ <button
73
+ class="uds-pagination__load-more"
74
+ disabled={currentPage >= totalPages}
75
+ onclick={() => goTo(currentPage + 1)}
76
+ >
77
+ Load more
78
+ </button>
79
+ {:else}
80
+ <button
81
+ class="uds-pagination__prev"
82
+ disabled={currentPage <= 1}
83
+ onclick={() => goTo(currentPage - 1)}
84
+ aria-label="Previous page"
85
+ >
86
+ &laquo;
87
+ </button>
88
+ <ol class="uds-pagination__list">
89
+ {#each pages() as page}
90
+ {#if typeof page === 'number'}
91
+ <li>
92
+ <button
93
+ class="uds-pagination__page"
94
+ class:uds-pagination__page--active={page === currentPage}
95
+ aria-current={page === currentPage ? 'page' : undefined}
96
+ onclick={() => goTo(page)}
97
+ >
98
+ {page}
99
+ </button>
100
+ </li>
101
+ {:else}
102
+ <li class="uds-pagination__ellipsis" aria-hidden="true">&hellip;</li>
103
+ {/if}
104
+ {/each}
105
+ </ol>
106
+ <button
107
+ class="uds-pagination__next"
108
+ disabled={currentPage >= totalPages}
109
+ onclick={() => goTo(currentPage + 1)}
110
+ aria-label="Next page"
111
+ >
112
+ &raquo;
113
+ </button>
114
+ {/if}
115
+ </nav>
@@ -0,0 +1,89 @@
1
+ <script lang="ts">
2
+ interface PricingPlan {
3
+ name: string;
4
+ price: string;
5
+ period?: string;
6
+ features: string[];
7
+ cta?: string;
8
+ highlighted?: boolean;
9
+ }
10
+
11
+ interface Props {
12
+ variant?: '2-column' | '3-column' | '4-column' | 'toggle';
13
+ size?: 'standard' | 'compact';
14
+ plans?: PricingPlan[];
15
+ highlightedPlan?: string;
16
+ billingPeriod?: 'monthly' | 'annual';
17
+ onToggle?: (period: string) => void;
18
+ class?: string;
19
+ children?: import('svelte').Snippet;
20
+ [key: string]: any;
21
+ }
22
+
23
+ let {
24
+ variant = '3-column',
25
+ size = 'standard',
26
+ plans = [],
27
+ highlightedPlan,
28
+ billingPeriod = 'monthly',
29
+ onToggle,
30
+ class: className = '',
31
+ children,
32
+ ...rest
33
+ }: Props = $props();
34
+
35
+ let classes = $derived(
36
+ [
37
+ 'uds-pricing',
38
+ `uds-pricing--${variant}`,
39
+ `uds-pricing--${size}`,
40
+ className,
41
+ ]
42
+ .filter(Boolean)
43
+ .join(' ')
44
+ );
45
+ </script>
46
+
47
+ <div class={classes} {...rest}>
48
+ {#if variant === 'toggle'}
49
+ <div class="uds-pricing__toggle" role="group" aria-label="Billing period">
50
+ <button
51
+ class="uds-pricing__toggle-btn"
52
+ class:uds-pricing__toggle-btn--active={billingPeriod === 'monthly'}
53
+ onclick={() => onToggle?.('monthly')}
54
+ >
55
+ Monthly
56
+ </button>
57
+ <button
58
+ class="uds-pricing__toggle-btn"
59
+ class:uds-pricing__toggle-btn--active={billingPeriod === 'annual'}
60
+ onclick={() => onToggle?.('annual')}
61
+ >
62
+ Annual
63
+ </button>
64
+ </div>
65
+ {/if}
66
+ <div class="uds-pricing__plans">
67
+ {#each plans as plan}
68
+ <div
69
+ class="uds-pricing__plan"
70
+ class:uds-pricing__plan--highlighted={plan.highlighted || plan.name === highlightedPlan}
71
+ >
72
+ <h3 class="uds-pricing__plan-name">{plan.name}</h3>
73
+ <div class="uds-pricing__plan-price">{plan.price}</div>
74
+ {#if plan.period}
75
+ <div class="uds-pricing__plan-period">{plan.period}</div>
76
+ {/if}
77
+ <ul class="uds-pricing__features">
78
+ {#each plan.features as feature}
79
+ <li class="uds-pricing__feature">{feature}</li>
80
+ {/each}
81
+ </ul>
82
+ {#if plan.cta}
83
+ <button class="uds-pricing__cta">{plan.cta}</button>
84
+ {/if}
85
+ </div>
86
+ {/each}
87
+ </div>
88
+ {@render children?.()}
89
+ </div>
@@ -0,0 +1,86 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ variant?: 'bar' | 'circular' | 'stepper';
4
+ size?: 'sm' | 'md' | 'lg';
5
+ value?: number;
6
+ max?: number;
7
+ label?: string;
8
+ showValue?: boolean;
9
+ indeterminate?: boolean;
10
+ class?: string;
11
+ children?: import('svelte').Snippet;
12
+ [key: string]: any;
13
+ }
14
+
15
+ let {
16
+ variant = 'bar',
17
+ size = 'md',
18
+ value = 0,
19
+ max = 100,
20
+ label = '',
21
+ showValue = false,
22
+ indeterminate = false,
23
+ class: className = '',
24
+ children,
25
+ ...rest
26
+ }: Props = $props();
27
+
28
+ let percentage = $derived(Math.min(Math.round((value / max) * 100), 100));
29
+
30
+ let classes = $derived(
31
+ [
32
+ 'uds-progress',
33
+ `uds-progress--${variant}`,
34
+ `uds-progress--${size}`,
35
+ indeterminate && 'uds-progress--indeterminate',
36
+ className,
37
+ ]
38
+ .filter(Boolean)
39
+ .join(' ')
40
+ );
41
+
42
+ let circumference = $derived(2 * Math.PI * 40);
43
+ let strokeOffset = $derived(circumference - (percentage / 100) * circumference);
44
+ </script>
45
+
46
+ <div
47
+ class={classes}
48
+ role="progressbar"
49
+ aria-valuenow={indeterminate ? undefined : value}
50
+ aria-valuemin={0}
51
+ aria-valuemax={max}
52
+ aria-label={label || undefined}
53
+ {...rest}
54
+ >
55
+ {#if variant === 'bar'}
56
+ <div class="uds-progress__track">
57
+ <div class="uds-progress__fill" style:width={indeterminate ? undefined : `${percentage}%`}></div>
58
+ </div>
59
+ {#if showValue && !indeterminate}
60
+ <span class="uds-progress__value">{percentage}%</span>
61
+ {/if}
62
+ {:else if variant === 'circular'}
63
+ <svg class="uds-progress__svg" viewBox="0 0 100 100">
64
+ <circle class="uds-progress__track-circle" cx="50" cy="50" r="40" fill="none" stroke-width="8" />
65
+ {#if !indeterminate}
66
+ <circle
67
+ class="uds-progress__fill-circle"
68
+ cx="50" cy="50" r="40"
69
+ fill="none"
70
+ stroke-width="8"
71
+ stroke-dasharray={circumference}
72
+ stroke-dashoffset={strokeOffset}
73
+ transform="rotate(-90 50 50)"
74
+ />
75
+ {/if}
76
+ </svg>
77
+ {#if showValue && !indeterminate}
78
+ <span class="uds-progress__value">{percentage}%</span>
79
+ {/if}
80
+ {:else if variant === 'stepper'}
81
+ {@render children?.()}
82
+ {/if}
83
+ {#if label}
84
+ <span class="uds-progress__label">{label}</span>
85
+ {/if}
86
+ </div>