@miozu/jera 0.0.2 → 0.4.2

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 (82) hide show
  1. package/CLAUDE.md +734 -0
  2. package/README.md +219 -1
  3. package/llms.txt +97 -0
  4. package/package.json +54 -14
  5. package/src/actions/index.js +375 -0
  6. package/src/components/docs/CodeBlock.svelte +203 -0
  7. package/src/components/docs/DocSection.svelte +120 -0
  8. package/src/components/docs/PropsTable.svelte +136 -0
  9. package/src/components/docs/SplitPane.svelte +98 -0
  10. package/src/components/docs/index.js +14 -0
  11. package/src/components/feedback/Alert.svelte +234 -0
  12. package/src/components/feedback/EmptyState.svelte +179 -0
  13. package/src/components/feedback/ProgressBar.svelte +116 -0
  14. package/src/components/feedback/Skeleton.svelte +107 -0
  15. package/src/components/feedback/Spinner.svelte +77 -0
  16. package/src/components/feedback/Toast.svelte +261 -0
  17. package/src/components/forms/Checkbox.svelte +147 -0
  18. package/src/components/forms/Dropzone.svelte +248 -0
  19. package/src/components/forms/FileUpload.svelte +266 -0
  20. package/src/components/forms/IconInput.svelte +184 -0
  21. package/src/components/forms/Input.svelte +121 -0
  22. package/src/components/forms/NumberInput.svelte +225 -0
  23. package/src/components/forms/PinInput.svelte +169 -0
  24. package/src/components/forms/Radio.svelte +143 -0
  25. package/src/components/forms/RadioGroup.svelte +62 -0
  26. package/src/components/forms/RangeSlider.svelte +212 -0
  27. package/src/components/forms/SearchInput.svelte +175 -0
  28. package/src/components/forms/Select.svelte +324 -0
  29. package/src/components/forms/Switch.svelte +159 -0
  30. package/src/components/forms/Textarea.svelte +122 -0
  31. package/src/components/navigation/Accordion.svelte +65 -0
  32. package/src/components/navigation/AccordionItem.svelte +146 -0
  33. package/src/components/navigation/NavigationContainer.svelte +344 -0
  34. package/src/components/navigation/Sidebar.svelte +334 -0
  35. package/src/components/navigation/SidebarAccountGroup.svelte +495 -0
  36. package/src/components/navigation/SidebarAccountItem.svelte +492 -0
  37. package/src/components/navigation/SidebarGroup.svelte +230 -0
  38. package/src/components/navigation/SidebarGroupSwitcher.svelte +262 -0
  39. package/src/components/navigation/SidebarItem.svelte +210 -0
  40. package/src/components/navigation/SidebarNavigationItem.svelte +470 -0
  41. package/src/components/navigation/SidebarPopover.svelte +145 -0
  42. package/src/components/navigation/SidebarSearch.svelte +236 -0
  43. package/src/components/navigation/SidebarSection.svelte +158 -0
  44. package/src/components/navigation/SidebarToggle.svelte +86 -0
  45. package/src/components/navigation/Tabs.svelte +239 -0
  46. package/src/components/navigation/WorkspaceMenu.svelte +416 -0
  47. package/src/components/navigation/blocks/NavigationAccountGroup.svelte +396 -0
  48. package/src/components/navigation/blocks/NavigationCustomBlock.svelte +74 -0
  49. package/src/components/navigation/blocks/NavigationGroupSwitcher.svelte +277 -0
  50. package/src/components/navigation/blocks/NavigationSearch.svelte +300 -0
  51. package/src/components/navigation/blocks/NavigationSection.svelte +230 -0
  52. package/src/components/navigation/index.js +22 -0
  53. package/src/components/overlays/ConfirmDialog.svelte +272 -0
  54. package/src/components/overlays/Dropdown.svelte +153 -0
  55. package/src/components/overlays/DropdownDivider.svelte +23 -0
  56. package/src/components/overlays/DropdownItem.svelte +97 -0
  57. package/src/components/overlays/Modal.svelte +232 -0
  58. package/src/components/overlays/Popover.svelte +206 -0
  59. package/src/components/primitives/Avatar.svelte +132 -0
  60. package/src/components/primitives/Badge.svelte +118 -0
  61. package/src/components/primitives/Button.svelte +214 -0
  62. package/src/components/primitives/Card.svelte +104 -0
  63. package/src/components/primitives/Divider.svelte +105 -0
  64. package/src/components/primitives/LazyImage.svelte +104 -0
  65. package/src/components/primitives/Link.svelte +122 -0
  66. package/src/components/primitives/Stat.svelte +197 -0
  67. package/src/components/primitives/StatusBadge.svelte +122 -0
  68. package/src/index.js +183 -0
  69. package/src/tokens/colors.css +157 -0
  70. package/src/tokens/effects.css +128 -0
  71. package/src/tokens/index.css +81 -0
  72. package/src/tokens/spacing.css +49 -0
  73. package/src/tokens/typography.css +79 -0
  74. package/src/utils/cn.svelte.js +175 -0
  75. package/src/utils/highlighter.js +124 -0
  76. package/src/utils/index.js +22 -0
  77. package/src/utils/navigation.svelte.js +423 -0
  78. package/src/utils/reactive.svelte.js +328 -0
  79. package/src/utils/sidebar.svelte.js +211 -0
  80. package/jera.js +0 -135
  81. package/www/components/jera/Input/Input.svelte +0 -63
  82. package/www/components/jera/Input/index.js +0 -1
@@ -0,0 +1,159 @@
1
+ <!--
2
+ @component Switch
3
+
4
+ An accessible toggle switch for boolean values.
5
+
6
+ @example
7
+ <Switch bind:checked={enabled}>Enable notifications</Switch>
8
+
9
+ @example
10
+ <Switch bind:checked={darkMode} size="lg" />
11
+ -->
12
+ <script>
13
+ import { cn } from '../../utils/cn.svelte.js';
14
+ import { generateId } from '../../utils/reactive.svelte.js';
15
+
16
+ let {
17
+ checked = $bindable(false),
18
+ disabled = false,
19
+ size = 'md',
20
+ name = '',
21
+ id,
22
+ class: className = '',
23
+ children,
24
+ onchange,
25
+ ...rest
26
+ } = $props();
27
+
28
+ const inputId = id || generateId();
29
+
30
+ // Size classes map to CSS classes defined below
31
+ const sizeClass = $derived(`switch-${size}`);
32
+ </script>
33
+
34
+ <label
35
+ class={cn('switch-wrapper', disabled && 'switch-disabled', className)}
36
+ for={inputId}
37
+ >
38
+ <input
39
+ type="checkbox"
40
+ role="switch"
41
+ id={inputId}
42
+ {name}
43
+ {disabled}
44
+ bind:checked
45
+ {onchange}
46
+ class="switch-input"
47
+ aria-checked={checked}
48
+ {...rest}
49
+ />
50
+
51
+ <span class={cn('switch-track', sizeClass, checked && 'switch-track-checked')}>
52
+ <span class={cn('switch-thumb', checked && 'switch-thumb-checked')} />
53
+ </span>
54
+
55
+ {#if children}
56
+ <span class="switch-label">
57
+ {@render children()}
58
+ </span>
59
+ {/if}
60
+ </label>
61
+
62
+ <style>
63
+ .switch-wrapper {
64
+ display: inline-flex;
65
+ align-items: center;
66
+ gap: var(--space-2);
67
+ cursor: pointer;
68
+ user-select: none;
69
+ }
70
+
71
+ .switch-disabled {
72
+ opacity: 0.5;
73
+ cursor: not-allowed;
74
+ }
75
+
76
+ .switch-input {
77
+ position: absolute;
78
+ width: 1px;
79
+ height: 1px;
80
+ padding: 0;
81
+ margin: -1px;
82
+ overflow: hidden;
83
+ clip: rect(0, 0, 0, 0);
84
+ white-space: nowrap;
85
+ border: 0;
86
+ }
87
+
88
+ .switch-track {
89
+ position: relative;
90
+ display: inline-flex;
91
+ align-items: center;
92
+ flex-shrink: 0;
93
+ border-radius: var(--radius-full);
94
+ background-color: var(--color-base03);
95
+ transition: var(--transition-colors);
96
+ }
97
+
98
+ .switch-track-checked {
99
+ background-color: var(--color-base0D);
100
+ }
101
+
102
+ .switch-input:focus-visible + .switch-track {
103
+ outline: 2px solid var(--color-base0D);
104
+ outline-offset: 2px;
105
+ }
106
+
107
+ .switch-thumb {
108
+ position: absolute;
109
+ left: 2px;
110
+ border-radius: var(--radius-full);
111
+ background-color: white;
112
+ box-shadow: var(--shadow-sm);
113
+ transition: transform var(--duration-fast) var(--ease-out);
114
+ }
115
+
116
+ .switch-label {
117
+ font-size: var(--text-sm);
118
+ color: var(--color-base05);
119
+ }
120
+
121
+ /* Size variants - Small */
122
+ .switch-sm {
123
+ width: 2rem;
124
+ height: 1rem;
125
+ }
126
+ .switch-sm .switch-thumb {
127
+ width: 0.75rem;
128
+ height: 0.75rem;
129
+ }
130
+ .switch-sm .switch-thumb-checked {
131
+ transform: translateX(1rem);
132
+ }
133
+
134
+ /* Size variants - Medium (default) */
135
+ .switch-md {
136
+ width: 2.5rem;
137
+ height: 1.25rem;
138
+ }
139
+ .switch-md .switch-thumb {
140
+ width: 1rem;
141
+ height: 1rem;
142
+ }
143
+ .switch-md .switch-thumb-checked {
144
+ transform: translateX(1.25rem);
145
+ }
146
+
147
+ /* Size variants - Large */
148
+ .switch-lg {
149
+ width: 3rem;
150
+ height: 1.5rem;
151
+ }
152
+ .switch-lg .switch-thumb {
153
+ width: 1.25rem;
154
+ height: 1.25rem;
155
+ }
156
+ .switch-lg .switch-thumb-checked {
157
+ transform: translateX(1.5rem);
158
+ }
159
+ </style>
@@ -0,0 +1,122 @@
1
+ <!--
2
+ @component Textarea
3
+
4
+ A multi-line text input component.
5
+
6
+ @example
7
+ <Textarea bind:value={description} placeholder="Enter description" rows={4} />
8
+
9
+ @example
10
+ // Auto-resize based on content
11
+ <Textarea bind:value={notes} autoResize />
12
+ -->
13
+ <script>
14
+ import { cn } from '../../utils/cn.svelte.js';
15
+
16
+ let {
17
+ value = $bindable(''),
18
+ ref = $bindable(),
19
+ placeholder = '',
20
+ disabled = false,
21
+ required = false,
22
+ name = '',
23
+ id = '',
24
+ rows = 3,
25
+ maxlength,
26
+ minlength,
27
+ autoResize = false,
28
+ class: className = '',
29
+ unstyled = false,
30
+ error = false,
31
+ oninput,
32
+ onchange,
33
+ onkeydown,
34
+ onfocus,
35
+ onblur,
36
+ ...rest
37
+ } = $props();
38
+
39
+ const textareaClass = $derived(
40
+ unstyled ? className : cn(
41
+ 'textarea-base',
42
+ autoResize && 'textarea-auto-resize',
43
+ error && 'textarea-error',
44
+ className
45
+ )
46
+ );
47
+
48
+ function handleInput(e) {
49
+ if (autoResize && ref) {
50
+ ref.style.height = 'auto';
51
+ ref.style.height = ref.scrollHeight + 'px';
52
+ }
53
+ oninput?.(e);
54
+ }
55
+ </script>
56
+
57
+ <textarea
58
+ class={textareaClass}
59
+ bind:this={ref}
60
+ bind:value
61
+ {id}
62
+ {name}
63
+ {rows}
64
+ {placeholder}
65
+ {disabled}
66
+ {required}
67
+ {maxlength}
68
+ {minlength}
69
+ aria-invalid={error || undefined}
70
+ oninput={handleInput}
71
+ {onchange}
72
+ {onkeydown}
73
+ {onfocus}
74
+ {onblur}
75
+ {...rest}
76
+ ></textarea>
77
+
78
+ <style>
79
+ .textarea-base {
80
+ width: 100%;
81
+ padding: var(--space-2) var(--space-3);
82
+ font-size: var(--text-sm);
83
+ line-height: 1.5;
84
+ color: var(--color-base07);
85
+ background-color: var(--color-base00);
86
+ border: 1px solid var(--color-base02);
87
+ border-radius: var(--radius-lg);
88
+ transition: var(--transition-colors);
89
+ resize: vertical;
90
+ font-family: inherit;
91
+ }
92
+
93
+ .textarea-base::placeholder {
94
+ color: var(--color-base04);
95
+ }
96
+
97
+ .textarea-base:focus {
98
+ outline: none;
99
+ border-color: var(--color-base0D);
100
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-base0D) 20%, transparent);
101
+ }
102
+
103
+ .textarea-base:disabled {
104
+ opacity: 0.5;
105
+ cursor: not-allowed;
106
+ resize: none;
107
+ }
108
+
109
+ .textarea-auto-resize {
110
+ resize: none;
111
+ overflow: hidden;
112
+ }
113
+
114
+ .textarea-error {
115
+ border-color: var(--color-base08);
116
+ }
117
+
118
+ .textarea-error:focus {
119
+ border-color: var(--color-base08);
120
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-base08) 20%, transparent);
121
+ }
122
+ </style>
@@ -0,0 +1,65 @@
1
+ <!--
2
+ @component Accordion
3
+
4
+ Collapsible content sections.
5
+
6
+ @example Single item
7
+ <Accordion>
8
+ <AccordionItem title="Section 1">
9
+ Content for section 1
10
+ </AccordionItem>
11
+ <AccordionItem title="Section 2">
12
+ Content for section 2
13
+ </AccordionItem>
14
+ </Accordion>
15
+
16
+ @example Controlled
17
+ <Accordion bind:expanded={openSections} multiple>
18
+ ...
19
+ </Accordion>
20
+ -->
21
+ <script>
22
+ import { setContext } from 'svelte';
23
+
24
+ let {
25
+ expanded = $bindable([]),
26
+ multiple = false,
27
+ children,
28
+ class: className = ''
29
+ } = $props();
30
+
31
+ function toggle(id) {
32
+ if (multiple) {
33
+ if (expanded.includes(id)) {
34
+ expanded = expanded.filter(i => i !== id);
35
+ } else {
36
+ expanded = [...expanded, id];
37
+ }
38
+ } else {
39
+ expanded = expanded.includes(id) ? [] : [id];
40
+ }
41
+ }
42
+
43
+ function isExpanded(id) {
44
+ return expanded.includes(id);
45
+ }
46
+
47
+ setContext('accordion', {
48
+ toggle,
49
+ isExpanded: (id) => expanded.includes(id)
50
+ });
51
+ </script>
52
+
53
+ <div class="accordion {className}">
54
+ {@render children?.()}
55
+ </div>
56
+
57
+ <style>
58
+ .accordion {
59
+ display: flex;
60
+ flex-direction: column;
61
+ border: 1px solid var(--color-base03);
62
+ border-radius: 0.5rem;
63
+ overflow: hidden;
64
+ }
65
+ </style>
@@ -0,0 +1,146 @@
1
+ <!--
2
+ @component AccordionItem
3
+
4
+ Individual accordion section. Must be used inside Accordion.
5
+
6
+ @example
7
+ <AccordionItem id="section-1" title="Click to expand">
8
+ Hidden content here
9
+ </AccordionItem>
10
+ -->
11
+ <script>
12
+ import { getContext } from 'svelte';
13
+ import { slide } from 'svelte/transition';
14
+
15
+ let {
16
+ id,
17
+ title = '',
18
+ disabled = false,
19
+ children,
20
+ class: className = ''
21
+ } = $props();
22
+
23
+ const accordion = getContext('accordion');
24
+
25
+ // Generate id if not provided
26
+ const itemId = id || `accordion-${Math.random().toString(36).slice(2, 9)}`;
27
+
28
+ const isOpen = $derived(accordion?.isExpanded(itemId) ?? false);
29
+
30
+ function handleClick() {
31
+ if (!disabled && accordion) {
32
+ accordion.toggle(itemId);
33
+ }
34
+ }
35
+
36
+ function handleKeydown(e) {
37
+ if (e.key === 'Enter' || e.key === ' ') {
38
+ e.preventDefault();
39
+ handleClick();
40
+ }
41
+ }
42
+ </script>
43
+
44
+ <div class="accordion-item {className}" class:accordion-item-disabled={disabled}>
45
+ <button
46
+ type="button"
47
+ class="accordion-trigger"
48
+ class:accordion-trigger-open={isOpen}
49
+ aria-expanded={isOpen}
50
+ aria-controls="content-{itemId}"
51
+ aria-disabled={disabled}
52
+ onclick={handleClick}
53
+ onkeydown={handleKeydown}
54
+ >
55
+ <span class="accordion-title">{title}</span>
56
+ <svg
57
+ class="accordion-icon"
58
+ class:accordion-icon-open={isOpen}
59
+ width="16"
60
+ height="16"
61
+ viewBox="0 0 24 24"
62
+ fill="none"
63
+ stroke="currentColor"
64
+ stroke-width="2"
65
+ stroke-linecap="round"
66
+ stroke-linejoin="round"
67
+ >
68
+ <polyline points="6 9 12 15 18 9"></polyline>
69
+ </svg>
70
+ </button>
71
+
72
+ {#if isOpen}
73
+ <div
74
+ id="content-{itemId}"
75
+ class="accordion-content"
76
+ transition:slide={{ duration: 200 }}
77
+ >
78
+ <div class="accordion-body">
79
+ {@render children?.()}
80
+ </div>
81
+ </div>
82
+ {/if}
83
+ </div>
84
+
85
+ <style>
86
+ .accordion-item {
87
+ border-bottom: 1px solid var(--color-base03);
88
+ }
89
+
90
+ .accordion-item:last-child {
91
+ border-bottom: none;
92
+ }
93
+
94
+ .accordion-item-disabled {
95
+ opacity: 0.5;
96
+ }
97
+
98
+ .accordion-trigger {
99
+ display: flex;
100
+ align-items: center;
101
+ justify-content: space-between;
102
+ width: 100%;
103
+ padding: 1rem;
104
+ background: transparent;
105
+ border: none;
106
+ font-size: 0.9375rem;
107
+ font-weight: 500;
108
+ color: var(--color-base07);
109
+ cursor: pointer;
110
+ text-align: left;
111
+ transition: background 0.15s ease;
112
+ }
113
+
114
+ .accordion-trigger:hover:not([aria-disabled="true"]) {
115
+ background: var(--color-base01);
116
+ }
117
+
118
+ .accordion-trigger-open {
119
+ background: var(--color-base01);
120
+ }
121
+
122
+ .accordion-title {
123
+ flex: 1;
124
+ }
125
+
126
+ .accordion-icon {
127
+ flex-shrink: 0;
128
+ color: var(--color-base05);
129
+ transition: transform 0.2s ease;
130
+ }
131
+
132
+ .accordion-icon-open {
133
+ transform: rotate(180deg);
134
+ }
135
+
136
+ .accordion-content {
137
+ overflow: hidden;
138
+ }
139
+
140
+ .accordion-body {
141
+ padding: 0 1rem 1rem 1rem;
142
+ font-size: 0.875rem;
143
+ color: var(--color-base05);
144
+ line-height: 1.6;
145
+ }
146
+ </style>