@aspect-ops/exon-ui 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Badge/Badge.svelte +60 -0
- package/dist/components/Badge/Badge.svelte.d.ts +9 -0
- package/dist/components/Badge/index.d.ts +2 -0
- package/dist/components/Badge/index.js +1 -0
- package/dist/components/BottomNav/BottomNav.svelte +128 -0
- package/dist/components/BottomNav/BottomNav.svelte.d.ts +8 -0
- package/dist/components/BottomNav/BottomNavItem.svelte +133 -0
- package/dist/components/BottomNav/BottomNavItem.svelte.d.ts +8 -0
- package/dist/components/Breadcrumbs/BreadcrumbItem.svelte +65 -0
- package/dist/components/Breadcrumbs/BreadcrumbItem.svelte.d.ts +7 -0
- package/dist/components/Breadcrumbs/BreadcrumbSeparator.svelte +27 -0
- package/dist/components/Breadcrumbs/BreadcrumbSeparator.svelte.d.ts +7 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.svelte +114 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.svelte.d.ts +8 -0
- package/dist/components/Button/Button.svelte +209 -0
- package/dist/components/Button/Button.svelte.d.ts +14 -0
- package/dist/components/Button/index.d.ts +2 -0
- package/dist/components/Button/index.js +1 -0
- package/dist/components/Checkbox/Checkbox.svelte +166 -0
- package/dist/components/Checkbox/Checkbox.svelte.d.ts +16 -0
- package/dist/components/Checkbox/CheckboxGroup.svelte +55 -0
- package/dist/components/Checkbox/CheckboxGroup.svelte.d.ts +12 -0
- package/dist/components/Checkbox/index.d.ts +2 -0
- package/dist/components/Checkbox/index.js +2 -0
- package/dist/components/FormField/FormField.svelte +101 -0
- package/dist/components/FormField/FormField.svelte.d.ts +13 -0
- package/dist/components/FormField/index.d.ts +1 -0
- package/dist/components/FormField/index.js +1 -0
- package/dist/components/Icon/Icon.svelte +47 -0
- package/dist/components/Icon/Icon.svelte.d.ts +11 -0
- package/dist/components/Icon/index.d.ts +2 -0
- package/dist/components/Icon/index.js +1 -0
- package/dist/components/Link/Link.svelte +56 -0
- package/dist/components/Link/Link.svelte.d.ts +9 -0
- package/dist/components/Link/index.d.ts +2 -0
- package/dist/components/Link/index.js +1 -0
- package/dist/components/Menu/Menu.svelte +14 -0
- package/dist/components/Menu/Menu.svelte.d.ts +7 -0
- package/dist/components/Menu/MenuContent.svelte +71 -0
- package/dist/components/Menu/MenuContent.svelte.d.ts +10 -0
- package/dist/components/Menu/MenuItem.svelte +73 -0
- package/dist/components/Menu/MenuItem.svelte.d.ts +7 -0
- package/dist/components/Menu/MenuSeparator.svelte +19 -0
- package/dist/components/Menu/MenuSeparator.svelte.d.ts +6 -0
- package/dist/components/Menu/MenuSub.svelte +14 -0
- package/dist/components/Menu/MenuSub.svelte.d.ts +7 -0
- package/dist/components/Menu/MenuSubContent.svelte +60 -0
- package/dist/components/Menu/MenuSubContent.svelte.d.ts +7 -0
- package/dist/components/Menu/MenuSubTrigger.svelte +84 -0
- package/dist/components/Menu/MenuSubTrigger.svelte.d.ts +7 -0
- package/dist/components/Menu/MenuTrigger.svelte +32 -0
- package/dist/components/Menu/MenuTrigger.svelte.d.ts +7 -0
- package/dist/components/Navbar/NavItem.svelte +99 -0
- package/dist/components/Navbar/NavItem.svelte.d.ts +8 -0
- package/dist/components/Navbar/Navbar.svelte +243 -0
- package/dist/components/Navbar/Navbar.svelte.d.ts +10 -0
- package/dist/components/Radio/Radio.svelte +93 -0
- package/dist/components/Radio/Radio.svelte.d.ts +10 -0
- package/dist/components/Radio/RadioGroup.svelte +72 -0
- package/dist/components/Radio/RadioGroup.svelte.d.ts +14 -0
- package/dist/components/Radio/index.d.ts +2 -0
- package/dist/components/Radio/index.js +2 -0
- package/dist/components/Select/Select.svelte +251 -0
- package/dist/components/Select/Select.svelte.d.ts +17 -0
- package/dist/components/Select/index.d.ts +1 -0
- package/dist/components/Select/index.js +1 -0
- package/dist/components/Sidebar/Sidebar.svelte +48 -0
- package/dist/components/Sidebar/Sidebar.svelte.d.ts +7 -0
- package/dist/components/Sidebar/SidebarGroup.svelte +141 -0
- package/dist/components/Sidebar/SidebarGroup.svelte.d.ts +7 -0
- package/dist/components/Sidebar/SidebarItem.svelte +151 -0
- package/dist/components/Sidebar/SidebarItem.svelte.d.ts +8 -0
- package/dist/components/Switch/Switch.svelte +120 -0
- package/dist/components/Switch/Switch.svelte.d.ts +13 -0
- package/dist/components/Switch/index.d.ts +1 -0
- package/dist/components/Switch/index.js +1 -0
- package/dist/components/Tabs/TabContent.svelte +91 -0
- package/dist/components/Tabs/TabContent.svelte.d.ts +7 -0
- package/dist/components/Tabs/TabList.svelte +46 -0
- package/dist/components/Tabs/TabList.svelte.d.ts +7 -0
- package/dist/components/Tabs/TabTrigger.svelte +68 -0
- package/dist/components/Tabs/TabTrigger.svelte.d.ts +7 -0
- package/dist/components/Tabs/Tabs.svelte +69 -0
- package/dist/components/Tabs/Tabs.svelte.d.ts +7 -0
- package/dist/components/TextInput/TextInput.svelte +200 -0
- package/dist/components/TextInput/TextInput.svelte.d.ts +35 -0
- package/dist/components/TextInput/index.d.ts +1 -0
- package/dist/components/TextInput/index.js +1 -0
- package/dist/components/Textarea/Textarea.svelte +198 -0
- package/dist/components/Textarea/Textarea.svelte.d.ts +33 -0
- package/dist/components/Textarea/index.d.ts +1 -0
- package/dist/components/Textarea/index.js +1 -0
- package/dist/components/Typography/Typography.svelte +99 -0
- package/dist/components/Typography/Typography.svelte.d.ts +10 -0
- package/dist/components/Typography/index.d.ts +2 -0
- package/dist/components/Typography/index.js +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +41 -0
- package/dist/styles/tokens.css +431 -0
- package/dist/test-setup.d.ts +1 -0
- package/dist/test-setup.js +1 -0
- package/dist/types/index.d.ts +129 -0
- package/dist/types/index.js +1 -0
- package/dist/types/navigation.d.ts +118 -0
- package/dist/types/navigation.js +1 -0
- package/package.json +130 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { InputSize, SelectOption } from '../../types/index.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
value?: string;
|
|
4
|
+
options: SelectOption[];
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
id?: string;
|
|
8
|
+
size?: InputSize;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
required?: boolean;
|
|
11
|
+
error?: boolean;
|
|
12
|
+
class?: string;
|
|
13
|
+
onchange?: (value: string) => void;
|
|
14
|
+
}
|
|
15
|
+
declare const Select: import("svelte").Component<Props, {}, "value">;
|
|
16
|
+
type Select = ReturnType<typeof Select>;
|
|
17
|
+
export default Select;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Select } from './Select.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Select } from './Select.svelte';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { SidebarProps } from '../../types/index.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends SidebarProps {
|
|
5
|
+
children?: import('svelte').Snippet;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let { collapsed = $bindable(false), class: className = '', children }: Props = $props();
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<aside
|
|
12
|
+
class="sidebar {className}"
|
|
13
|
+
class:sidebar--collapsed={collapsed}
|
|
14
|
+
aria-label="Sidebar navigation"
|
|
15
|
+
>
|
|
16
|
+
<nav class="sidebar__nav">
|
|
17
|
+
{#if children}
|
|
18
|
+
{@render children()}
|
|
19
|
+
{/if}
|
|
20
|
+
</nav>
|
|
21
|
+
</aside>
|
|
22
|
+
|
|
23
|
+
<style>
|
|
24
|
+
.sidebar {
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
width: var(--sidebar-width, 16rem);
|
|
28
|
+
min-height: 100%;
|
|
29
|
+
background: var(--color-bg, #ffffff);
|
|
30
|
+
border-right: 1px solid var(--color-border, #e5e7eb);
|
|
31
|
+
font-family: inherit;
|
|
32
|
+
transition: width var(--transition-normal, 200ms ease);
|
|
33
|
+
overflow: hidden;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.sidebar--collapsed {
|
|
37
|
+
width: var(--sidebar-collapsed-width, 4rem);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.sidebar__nav {
|
|
41
|
+
display: flex;
|
|
42
|
+
flex-direction: column;
|
|
43
|
+
gap: var(--space-xs, 0.25rem);
|
|
44
|
+
padding: var(--space-sm, 0.5rem);
|
|
45
|
+
overflow-y: auto;
|
|
46
|
+
overflow-x: hidden;
|
|
47
|
+
}
|
|
48
|
+
</style>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SidebarProps } from '../../types/index.js';
|
|
2
|
+
interface Props extends SidebarProps {
|
|
3
|
+
children?: import('svelte').Snippet;
|
|
4
|
+
}
|
|
5
|
+
declare const Sidebar: import("svelte").Component<Props, {}, "collapsed">;
|
|
6
|
+
type Sidebar = ReturnType<typeof Sidebar>;
|
|
7
|
+
export default Sidebar;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { SidebarGroupProps } from '../../types/index.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends SidebarGroupProps {
|
|
5
|
+
children?: import('svelte').Snippet;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
label,
|
|
10
|
+
collapsible = false,
|
|
11
|
+
defaultCollapsed = false,
|
|
12
|
+
class: className = '',
|
|
13
|
+
children
|
|
14
|
+
}: Props = $props();
|
|
15
|
+
|
|
16
|
+
let collapsed = $state<boolean>();
|
|
17
|
+
$effect(() => {
|
|
18
|
+
collapsed = defaultCollapsed;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
function toggleCollapse() {
|
|
22
|
+
if (collapsible) {
|
|
23
|
+
collapsed = !collapsed;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<div class="sidebar-group {className}">
|
|
29
|
+
{#if label}
|
|
30
|
+
{#if collapsible}
|
|
31
|
+
<button
|
|
32
|
+
type="button"
|
|
33
|
+
class="sidebar-group__header sidebar-group__header--collapsible"
|
|
34
|
+
onclick={toggleCollapse}
|
|
35
|
+
aria-expanded={!collapsed}
|
|
36
|
+
>
|
|
37
|
+
<span class="sidebar-group__label">{label}</span>
|
|
38
|
+
<span class="sidebar-group__chevron" class:sidebar-group__chevron--collapsed={collapsed}>
|
|
39
|
+
<svg
|
|
40
|
+
width="12"
|
|
41
|
+
height="12"
|
|
42
|
+
viewBox="0 0 12 12"
|
|
43
|
+
fill="none"
|
|
44
|
+
stroke="currentColor"
|
|
45
|
+
stroke-width="2"
|
|
46
|
+
stroke-linecap="round"
|
|
47
|
+
>
|
|
48
|
+
<path d="M3 4.5L6 7.5L9 4.5" />
|
|
49
|
+
</svg>
|
|
50
|
+
</span>
|
|
51
|
+
</button>
|
|
52
|
+
{:else}
|
|
53
|
+
<div class="sidebar-group__header">
|
|
54
|
+
<span class="sidebar-group__label">{label}</span>
|
|
55
|
+
</div>
|
|
56
|
+
{/if}
|
|
57
|
+
{/if}
|
|
58
|
+
|
|
59
|
+
<div class="sidebar-group__content" class:sidebar-group__content--collapsed={collapsed}>
|
|
60
|
+
{#if children}
|
|
61
|
+
{@render children()}
|
|
62
|
+
{/if}
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<style>
|
|
67
|
+
.sidebar-group {
|
|
68
|
+
display: flex;
|
|
69
|
+
flex-direction: column;
|
|
70
|
+
gap: var(--space-2xs, 0.125rem);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
:global(.sidebar-group + .sidebar-group) {
|
|
74
|
+
margin-top: var(--space-md, 1rem);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.sidebar-group__header {
|
|
78
|
+
display: flex;
|
|
79
|
+
align-items: center;
|
|
80
|
+
justify-content: space-between;
|
|
81
|
+
gap: var(--space-xs, 0.25rem);
|
|
82
|
+
padding: var(--space-xs, 0.25rem) var(--space-md, 1rem);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.sidebar-group__header--collapsible {
|
|
86
|
+
width: 100%;
|
|
87
|
+
background: transparent;
|
|
88
|
+
border: none;
|
|
89
|
+
cursor: pointer;
|
|
90
|
+
border-radius: var(--radius-sm, 0.25rem);
|
|
91
|
+
transition: background-color var(--transition-fast, 150ms ease);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.sidebar-group__header--collapsible:hover {
|
|
95
|
+
background: var(--color-bg-muted, #f3f4f6);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.sidebar-group__header--collapsible:focus-visible {
|
|
99
|
+
outline: 2px solid var(--color-primary, #3b82f6);
|
|
100
|
+
outline-offset: -2px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.sidebar-group__label {
|
|
104
|
+
font-size: var(--text-xs, 0.75rem);
|
|
105
|
+
font-weight: 600;
|
|
106
|
+
text-transform: uppercase;
|
|
107
|
+
letter-spacing: 0.05em;
|
|
108
|
+
color: var(--color-text-muted, #6b7280);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.sidebar-group__chevron {
|
|
112
|
+
display: inline-flex;
|
|
113
|
+
align-items: center;
|
|
114
|
+
justify-content: center;
|
|
115
|
+
color: var(--color-text-muted, #6b7280);
|
|
116
|
+
transition: transform var(--transition-fast, 150ms ease);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.sidebar-group__chevron--collapsed {
|
|
120
|
+
transform: rotate(-90deg);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.sidebar-group__content {
|
|
124
|
+
display: flex;
|
|
125
|
+
flex-direction: column;
|
|
126
|
+
gap: var(--space-2xs, 0.125rem);
|
|
127
|
+
overflow: hidden;
|
|
128
|
+
transition: max-height var(--transition-normal, 200ms ease);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.sidebar-group__content--collapsed {
|
|
132
|
+
max-height: 0;
|
|
133
|
+
opacity: 0;
|
|
134
|
+
pointer-events: none;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* Hide group labels when sidebar is collapsed */
|
|
138
|
+
:global(.sidebar--collapsed) .sidebar-group__header {
|
|
139
|
+
display: none;
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SidebarGroupProps } from '../../types/index.js';
|
|
2
|
+
interface Props extends SidebarGroupProps {
|
|
3
|
+
children?: import('svelte').Snippet;
|
|
4
|
+
}
|
|
5
|
+
declare const SidebarGroup: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type SidebarGroup = ReturnType<typeof SidebarGroup>;
|
|
7
|
+
export default SidebarGroup;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { SidebarItemProps } from '../../types/index.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends SidebarItemProps {
|
|
5
|
+
onclick?: () => void;
|
|
6
|
+
children?: import('svelte').Snippet;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
label,
|
|
11
|
+
href,
|
|
12
|
+
icon,
|
|
13
|
+
active = false,
|
|
14
|
+
badge,
|
|
15
|
+
indentLevel = 0,
|
|
16
|
+
class: className = '',
|
|
17
|
+
onclick,
|
|
18
|
+
children
|
|
19
|
+
}: Props = $props();
|
|
20
|
+
|
|
21
|
+
const paddingLeft = $derived(`calc(var(--space-md, 1rem) + ${indentLevel * 1}rem)`);
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
{#if href}
|
|
25
|
+
<a
|
|
26
|
+
{href}
|
|
27
|
+
class="sidebar-item {className}"
|
|
28
|
+
class:sidebar-item--active={active}
|
|
29
|
+
style:padding-left={paddingLeft}
|
|
30
|
+
aria-current={active ? 'page' : undefined}
|
|
31
|
+
>
|
|
32
|
+
{#if icon}
|
|
33
|
+
<span class="sidebar-item__icon">{icon}</span>
|
|
34
|
+
{/if}
|
|
35
|
+
<span class="sidebar-item__label">
|
|
36
|
+
{#if children}
|
|
37
|
+
{@render children()}
|
|
38
|
+
{:else}
|
|
39
|
+
{label}
|
|
40
|
+
{/if}
|
|
41
|
+
</span>
|
|
42
|
+
{#if badge !== undefined && badge > 0}
|
|
43
|
+
<span class="sidebar-item__badge">{badge > 99 ? '99+' : badge}</span>
|
|
44
|
+
{/if}
|
|
45
|
+
</a>
|
|
46
|
+
{:else}
|
|
47
|
+
<button
|
|
48
|
+
type="button"
|
|
49
|
+
class="sidebar-item {className}"
|
|
50
|
+
class:sidebar-item--active={active}
|
|
51
|
+
style:padding-left={paddingLeft}
|
|
52
|
+
aria-current={active ? 'page' : undefined}
|
|
53
|
+
{onclick}
|
|
54
|
+
>
|
|
55
|
+
{#if icon}
|
|
56
|
+
<span class="sidebar-item__icon">{icon}</span>
|
|
57
|
+
{/if}
|
|
58
|
+
<span class="sidebar-item__label">
|
|
59
|
+
{#if children}
|
|
60
|
+
{@render children()}
|
|
61
|
+
{:else}
|
|
62
|
+
{label}
|
|
63
|
+
{/if}
|
|
64
|
+
</span>
|
|
65
|
+
{#if badge !== undefined && badge > 0}
|
|
66
|
+
<span class="sidebar-item__badge">{badge > 99 ? '99+' : badge}</span>
|
|
67
|
+
{/if}
|
|
68
|
+
</button>
|
|
69
|
+
{/if}
|
|
70
|
+
|
|
71
|
+
<style>
|
|
72
|
+
.sidebar-item {
|
|
73
|
+
display: flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
gap: var(--space-sm, 0.5rem);
|
|
76
|
+
/* Touch target minimum (F20) */
|
|
77
|
+
min-height: var(--touch-target-min, 44px);
|
|
78
|
+
padding: var(--space-sm, 0.5rem) var(--space-md, 1rem);
|
|
79
|
+
background: transparent;
|
|
80
|
+
border: none;
|
|
81
|
+
border-radius: var(--radius-sm, 0.25rem);
|
|
82
|
+
color: var(--color-text-muted, #6b7280);
|
|
83
|
+
font-size: var(--text-sm, 0.875rem);
|
|
84
|
+
text-decoration: none;
|
|
85
|
+
text-align: left;
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
transition: all var(--transition-fast, 150ms ease);
|
|
88
|
+
-webkit-tap-highlight-color: transparent;
|
|
89
|
+
white-space: nowrap;
|
|
90
|
+
overflow: hidden;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.sidebar-item:hover {
|
|
94
|
+
color: var(--color-text, #1f2937);
|
|
95
|
+
background: var(--color-bg-muted, #f3f4f6);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.sidebar-item:focus-visible {
|
|
99
|
+
outline: 2px solid var(--color-primary, #3b82f6);
|
|
100
|
+
outline-offset: -2px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.sidebar-item--active {
|
|
104
|
+
color: var(--color-primary, #3b82f6);
|
|
105
|
+
background: var(--color-primary-bg, #eff6ff);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.sidebar-item--active:hover {
|
|
109
|
+
color: var(--color-primary, #3b82f6);
|
|
110
|
+
background: var(--color-primary-bg, #eff6ff);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.sidebar-item__icon {
|
|
114
|
+
display: inline-flex;
|
|
115
|
+
align-items: center;
|
|
116
|
+
justify-content: center;
|
|
117
|
+
flex-shrink: 0;
|
|
118
|
+
width: 1.5rem;
|
|
119
|
+
font-size: 1.25rem;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.sidebar-item__label {
|
|
123
|
+
flex: 1;
|
|
124
|
+
min-width: 0;
|
|
125
|
+
overflow: hidden;
|
|
126
|
+
text-overflow: ellipsis;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* Hide label when sidebar is collapsed */
|
|
130
|
+
:global(.sidebar--collapsed) .sidebar-item__label {
|
|
131
|
+
display: none;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
:global(.sidebar--collapsed) .sidebar-item__badge {
|
|
135
|
+
display: none;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.sidebar-item__badge {
|
|
139
|
+
flex-shrink: 0;
|
|
140
|
+
min-width: 1.25rem;
|
|
141
|
+
height: 1.25rem;
|
|
142
|
+
padding: 0 var(--space-2xs, 0.125rem);
|
|
143
|
+
background: var(--color-primary, #3b82f6);
|
|
144
|
+
color: var(--color-text-inverse, #ffffff);
|
|
145
|
+
font-size: var(--text-xs, 0.75rem);
|
|
146
|
+
font-weight: 600;
|
|
147
|
+
line-height: 1.25rem;
|
|
148
|
+
text-align: center;
|
|
149
|
+
border-radius: var(--radius-full, 9999px);
|
|
150
|
+
}
|
|
151
|
+
</style>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SidebarItemProps } from '../../types/index.js';
|
|
2
|
+
interface Props extends SidebarItemProps {
|
|
3
|
+
onclick?: () => void;
|
|
4
|
+
children?: import('svelte').Snippet;
|
|
5
|
+
}
|
|
6
|
+
declare const SidebarItem: import("svelte").Component<Props, {}, "">;
|
|
7
|
+
type SidebarItem = ReturnType<typeof SidebarItem>;
|
|
8
|
+
export default SidebarItem;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Switch as SwitchPrimitive } from 'bits-ui';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
checked?: boolean;
|
|
6
|
+
name?: string;
|
|
7
|
+
id?: string;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
required?: boolean;
|
|
10
|
+
class?: string;
|
|
11
|
+
onchange?: (checked: boolean) => void;
|
|
12
|
+
children?: import('svelte').Snippet;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let {
|
|
16
|
+
checked = $bindable(false),
|
|
17
|
+
name,
|
|
18
|
+
id,
|
|
19
|
+
disabled = false,
|
|
20
|
+
required = false,
|
|
21
|
+
class: className = '',
|
|
22
|
+
onchange,
|
|
23
|
+
children
|
|
24
|
+
}: Props = $props();
|
|
25
|
+
|
|
26
|
+
function handleCheckedChange(newChecked: boolean) {
|
|
27
|
+
checked = newChecked;
|
|
28
|
+
onchange?.(newChecked);
|
|
29
|
+
}
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<div class="switch-wrapper {className}">
|
|
33
|
+
<SwitchPrimitive.Root
|
|
34
|
+
class="switch {disabled ? 'switch--disabled' : ''}"
|
|
35
|
+
{checked}
|
|
36
|
+
{name}
|
|
37
|
+
{id}
|
|
38
|
+
{disabled}
|
|
39
|
+
{required}
|
|
40
|
+
aria-required={required}
|
|
41
|
+
onCheckedChange={handleCheckedChange}
|
|
42
|
+
>
|
|
43
|
+
<SwitchPrimitive.Thumb class="switch__thumb" />
|
|
44
|
+
</SwitchPrimitive.Root>
|
|
45
|
+
|
|
46
|
+
{#if children}
|
|
47
|
+
<label for={id} class="switch__label" class:switch__label--disabled={disabled}>
|
|
48
|
+
{@render children()}
|
|
49
|
+
</label>
|
|
50
|
+
{/if}
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<style>
|
|
54
|
+
.switch-wrapper {
|
|
55
|
+
display: inline-flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
gap: var(--space-sm, 0.5rem);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
:global(.switch) {
|
|
61
|
+
position: relative;
|
|
62
|
+
display: inline-flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
width: 2.75rem;
|
|
65
|
+
height: 1.5rem;
|
|
66
|
+
min-width: 2.75rem;
|
|
67
|
+
min-height: 1.5rem;
|
|
68
|
+
padding: 2px;
|
|
69
|
+
border: none;
|
|
70
|
+
border-radius: 9999px;
|
|
71
|
+
background: var(--color-bg-muted, #e5e7eb);
|
|
72
|
+
cursor: pointer;
|
|
73
|
+
transition: background var(--transition-fast, 150ms ease);
|
|
74
|
+
-webkit-tap-highlight-color: transparent;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
:global(.switch:focus-visible) {
|
|
78
|
+
outline: none;
|
|
79
|
+
box-shadow: 0 0 0 3px var(--color-primary-alpha, rgba(59, 130, 246, 0.1));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
:global(.switch[data-state='checked']) {
|
|
83
|
+
background: var(--color-primary, #3b82f6);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
:global(.switch--disabled) {
|
|
87
|
+
opacity: 0.5;
|
|
88
|
+
cursor: not-allowed;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
:global(.switch__thumb) {
|
|
92
|
+
display: block;
|
|
93
|
+
width: 1.25rem;
|
|
94
|
+
height: 1.25rem;
|
|
95
|
+
border-radius: 50%;
|
|
96
|
+
background: var(--color-bg, #ffffff);
|
|
97
|
+
box-shadow: var(--shadow-sm, 0 1px 2px rgba(0, 0, 0, 0.1));
|
|
98
|
+
transition: transform var(--transition-fast, 150ms ease);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
:global(.switch[data-state='checked'] .switch__thumb) {
|
|
102
|
+
transform: translateX(1.25rem);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.switch__label {
|
|
106
|
+
font-family: inherit;
|
|
107
|
+
font-size: var(--text-sm, 0.875rem);
|
|
108
|
+
color: var(--color-text, #1f2937);
|
|
109
|
+
cursor: pointer;
|
|
110
|
+
user-select: none;
|
|
111
|
+
min-height: var(--touch-target-min, 44px);
|
|
112
|
+
display: flex;
|
|
113
|
+
align-items: center;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.switch__label--disabled {
|
|
117
|
+
opacity: 0.5;
|
|
118
|
+
cursor: not-allowed;
|
|
119
|
+
}
|
|
120
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
checked?: boolean;
|
|
3
|
+
name?: string;
|
|
4
|
+
id?: string;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
required?: boolean;
|
|
7
|
+
class?: string;
|
|
8
|
+
onchange?: (checked: boolean) => void;
|
|
9
|
+
children?: import('svelte').Snippet;
|
|
10
|
+
}
|
|
11
|
+
declare const Switch: import("svelte").Component<Props, {}, "checked">;
|
|
12
|
+
type Switch = ReturnType<typeof Switch>;
|
|
13
|
+
export default Switch;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Switch } from './Switch.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Switch } from './Switch.svelte';
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Tabs as TabsPrimitive } from 'bits-ui';
|
|
3
|
+
import type { TabContentProps } from '../../types/index.js';
|
|
4
|
+
import type { Action } from 'svelte/action';
|
|
5
|
+
|
|
6
|
+
interface Props extends TabContentProps {
|
|
7
|
+
children?: import('svelte').Snippet;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let { value, lazy = false, class: className = '', children }: Props = $props();
|
|
11
|
+
|
|
12
|
+
// Track if this content has ever been rendered (for lazy loading)
|
|
13
|
+
let hasRendered = $state(false);
|
|
14
|
+
|
|
15
|
+
// Action to watch for when content becomes active
|
|
16
|
+
const watchActive: Action<HTMLElement> = (node) => {
|
|
17
|
+
if (!lazy || hasRendered) return;
|
|
18
|
+
|
|
19
|
+
// Find the TabsPrimitive.Content child element
|
|
20
|
+
const contentElement = node.querySelector('[data-state]');
|
|
21
|
+
if (!contentElement) return;
|
|
22
|
+
|
|
23
|
+
// Check initial state
|
|
24
|
+
if (contentElement.getAttribute('data-state') === 'active') {
|
|
25
|
+
hasRendered = true;
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Watch for state changes
|
|
30
|
+
const observer = new MutationObserver((mutations) => {
|
|
31
|
+
for (const mutation of mutations) {
|
|
32
|
+
if (
|
|
33
|
+
mutation.type === 'attributes' &&
|
|
34
|
+
mutation.attributeName === 'data-state' &&
|
|
35
|
+
contentElement.getAttribute('data-state') === 'active'
|
|
36
|
+
) {
|
|
37
|
+
hasRendered = true;
|
|
38
|
+
observer.disconnect();
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
observer.observe(contentElement, {
|
|
45
|
+
attributes: true,
|
|
46
|
+
attributeFilter: ['data-state']
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
destroy() {
|
|
51
|
+
observer.disconnect();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
<div use:watchActive class="tab-content-wrapper">
|
|
58
|
+
<TabsPrimitive.Content {value} class="tab-content {className}">
|
|
59
|
+
{#if !lazy || hasRendered}
|
|
60
|
+
{#if children}
|
|
61
|
+
{@render children()}
|
|
62
|
+
{/if}
|
|
63
|
+
{/if}
|
|
64
|
+
</TabsPrimitive.Content>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<style>
|
|
68
|
+
.tab-content-wrapper {
|
|
69
|
+
display: contents;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
:global(.tab-content) {
|
|
73
|
+
font-family: inherit;
|
|
74
|
+
padding: var(--space-md, 1rem);
|
|
75
|
+
animation: fadeIn var(--transition-normal, 200ms ease);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
:global(.tab-content:focus-visible) {
|
|
79
|
+
outline: 2px solid var(--color-primary, #3b82f6);
|
|
80
|
+
outline-offset: 2px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@keyframes fadeIn {
|
|
84
|
+
from {
|
|
85
|
+
opacity: 0;
|
|
86
|
+
}
|
|
87
|
+
to {
|
|
88
|
+
opacity: 1;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
</style>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TabContentProps } from '../../types/index.js';
|
|
2
|
+
interface Props extends TabContentProps {
|
|
3
|
+
children?: import('svelte').Snippet;
|
|
4
|
+
}
|
|
5
|
+
declare const TabContent: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type TabContent = ReturnType<typeof TabContent>;
|
|
7
|
+
export default TabContent;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Tabs as TabsPrimitive } from 'bits-ui';
|
|
3
|
+
import type { TabListProps } from '../../types/index.js';
|
|
4
|
+
|
|
5
|
+
interface Props extends TabListProps {
|
|
6
|
+
children?: import('svelte').Snippet;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let { scrollable = false, class: className = '', children }: Props = $props();
|
|
10
|
+
|
|
11
|
+
const scrollableClass = $derived(scrollable ? 'tab-list--scrollable' : '');
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<TabsPrimitive.List class="tab-list {scrollableClass} {className}">
|
|
15
|
+
{#if children}
|
|
16
|
+
{@render children()}
|
|
17
|
+
{/if}
|
|
18
|
+
</TabsPrimitive.List>
|
|
19
|
+
|
|
20
|
+
<style>
|
|
21
|
+
:global(.tab-list) {
|
|
22
|
+
font-family: inherit;
|
|
23
|
+
display: flex;
|
|
24
|
+
gap: var(--space-xs, 0.25rem);
|
|
25
|
+
border-bottom: 1px solid var(--color-border, #e5e7eb);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
:global(.tab-list[data-orientation='vertical']) {
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
border-bottom: none;
|
|
31
|
+
border-right: 1px solid var(--color-border, #e5e7eb);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Scrollable styles - only applies to horizontal orientation */
|
|
35
|
+
:global(.tab-list--scrollable[data-orientation='horizontal']) {
|
|
36
|
+
overflow-x: auto;
|
|
37
|
+
overflow-y: hidden;
|
|
38
|
+
-webkit-overflow-scrolling: touch;
|
|
39
|
+
scrollbar-width: none; /* Firefox */
|
|
40
|
+
-ms-overflow-style: none; /* IE/Edge */
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
:global(.tab-list--scrollable[data-orientation='horizontal']::-webkit-scrollbar) {
|
|
44
|
+
display: none; /* Chrome/Safari */
|
|
45
|
+
}
|
|
46
|
+
</style>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TabListProps } from '../../types/index.js';
|
|
2
|
+
interface Props extends TabListProps {
|
|
3
|
+
children?: import('svelte').Snippet;
|
|
4
|
+
}
|
|
5
|
+
declare const TabList: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type TabList = ReturnType<typeof TabList>;
|
|
7
|
+
export default TabList;
|