bloko-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.
Files changed (74) hide show
  1. package/README.md +58 -0
  2. package/dist/components/Accordion.svelte +107 -0
  3. package/dist/components/Accordion.svelte.d.ts +14 -0
  4. package/dist/components/Alert.svelte +136 -0
  5. package/dist/components/Alert.svelte.d.ts +11 -0
  6. package/dist/components/Avatar.svelte +82 -0
  7. package/dist/components/Avatar.svelte.d.ts +9 -0
  8. package/dist/components/Badge.svelte +61 -0
  9. package/dist/components/Badge.svelte.d.ts +8 -0
  10. package/dist/components/Breadcrumb.svelte +74 -0
  11. package/dist/components/Breadcrumb.svelte.d.ts +10 -0
  12. package/dist/components/Button.svelte +114 -0
  13. package/dist/components/Button.svelte.d.ts +12 -0
  14. package/dist/components/Card.svelte +49 -0
  15. package/dist/components/Card.svelte.d.ts +9 -0
  16. package/dist/components/Checkbox.svelte +108 -0
  17. package/dist/components/Checkbox.svelte.d.ts +10 -0
  18. package/dist/components/ContextMenu.svelte +132 -0
  19. package/dist/components/ContextMenu.svelte.d.ts +17 -0
  20. package/dist/components/Divider.svelte +55 -0
  21. package/dist/components/Divider.svelte.d.ts +7 -0
  22. package/dist/components/Dropdown.svelte +156 -0
  23. package/dist/components/Dropdown.svelte.d.ts +17 -0
  24. package/dist/components/EmptyState.svelte +79 -0
  25. package/dist/components/EmptyState.svelte.d.ts +10 -0
  26. package/dist/components/IconButton.svelte +88 -0
  27. package/dist/components/IconButton.svelte.d.ts +12 -0
  28. package/dist/components/Input.svelte +87 -0
  29. package/dist/components/Input.svelte.d.ts +15 -0
  30. package/dist/components/LangValue.svelte +124 -0
  31. package/dist/components/LangValue.svelte.d.ts +8 -0
  32. package/dist/components/Modal.svelte +136 -0
  33. package/dist/components/Modal.svelte.d.ts +10 -0
  34. package/dist/components/NumberInput.svelte +143 -0
  35. package/dist/components/NumberInput.svelte.d.ts +12 -0
  36. package/dist/components/Pagination.svelte +83 -0
  37. package/dist/components/Pagination.svelte.d.ts +9 -0
  38. package/dist/components/Popover.svelte +95 -0
  39. package/dist/components/Popover.svelte.d.ts +9 -0
  40. package/dist/components/Progress.svelte +55 -0
  41. package/dist/components/Progress.svelte.d.ts +9 -0
  42. package/dist/components/RadioGroup.svelte +111 -0
  43. package/dist/components/RadioGroup.svelte.d.ts +15 -0
  44. package/dist/components/SearchInput.svelte +121 -0
  45. package/dist/components/SearchInput.svelte.d.ts +10 -0
  46. package/dist/components/Select.svelte +82 -0
  47. package/dist/components/Select.svelte.d.ts +15 -0
  48. package/dist/components/Sidebar.svelte +97 -0
  49. package/dist/components/Sidebar.svelte.d.ts +13 -0
  50. package/dist/components/Skeleton.svelte +47 -0
  51. package/dist/components/Skeleton.svelte.d.ts +9 -0
  52. package/dist/components/Spinner.svelte +58 -0
  53. package/dist/components/Spinner.svelte.d.ts +7 -0
  54. package/dist/components/Switch.svelte +102 -0
  55. package/dist/components/Switch.svelte.d.ts +9 -0
  56. package/dist/components/Table.svelte +78 -0
  57. package/dist/components/Table.svelte.d.ts +6 -0
  58. package/dist/components/Tabs.svelte +74 -0
  59. package/dist/components/Tabs.svelte.d.ts +12 -0
  60. package/dist/components/Tag.svelte +75 -0
  61. package/dist/components/Tag.svelte.d.ts +9 -0
  62. package/dist/components/Textarea.svelte +63 -0
  63. package/dist/components/Textarea.svelte.d.ts +11 -0
  64. package/dist/components/Toast.svelte +103 -0
  65. package/dist/components/Toast.svelte.d.ts +10 -0
  66. package/dist/components/Tooltip.svelte +75 -0
  67. package/dist/components/Tooltip.svelte.d.ts +9 -0
  68. package/dist/components/TopNav.svelte +72 -0
  69. package/dist/components/TopNav.svelte.d.ts +12 -0
  70. package/dist/components/TruncatedText.svelte +46 -0
  71. package/dist/components/TruncatedText.svelte.d.ts +9 -0
  72. package/dist/index.d.ts +35 -0
  73. package/dist/index.js +36 -0
  74. package/package.json +63 -0
@@ -0,0 +1,88 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ variant?: 'default' | 'ghost' | 'destructive';
6
+ size?: 'sm' | 'md';
7
+ disabled?: boolean;
8
+ title?: string;
9
+ onclick?: () => void;
10
+ children: Snippet;
11
+ }
12
+
13
+ let {
14
+ variant = 'default',
15
+ size = 'md',
16
+ disabled = false,
17
+ title,
18
+ onclick,
19
+ children
20
+ }: Props = $props();
21
+ </script>
22
+
23
+ <button
24
+ type="button"
25
+ class="icon-button {variant} {size}"
26
+ {disabled}
27
+ {title}
28
+ {onclick}
29
+ aria-label={title}
30
+ >
31
+ {@render children()}
32
+ </button>
33
+
34
+ <style>
35
+ .icon-button {
36
+ display: inline-flex;
37
+ align-items: center;
38
+ justify-content: center;
39
+ border: none;
40
+ border-radius: 4px;
41
+ cursor: pointer;
42
+ transition: all 0.15s ease;
43
+ }
44
+
45
+ .icon-button.sm {
46
+ width: 24px;
47
+ height: 24px;
48
+ }
49
+
50
+ .icon-button.md {
51
+ width: 28px;
52
+ height: 28px;
53
+ }
54
+
55
+ .icon-button.default {
56
+ background: #f4f4f5;
57
+ color: #3f3f46;
58
+ }
59
+
60
+ .icon-button.default:hover:not(:disabled) {
61
+ background: #e4e4e7;
62
+ }
63
+
64
+ .icon-button.ghost {
65
+ background: transparent;
66
+ color: #71717a;
67
+ }
68
+
69
+ .icon-button.ghost:hover:not(:disabled) {
70
+ background: #f4f4f5;
71
+ color: #3f3f46;
72
+ }
73
+
74
+ .icon-button.destructive {
75
+ background: transparent;
76
+ color: #71717a;
77
+ }
78
+
79
+ .icon-button.destructive:hover:not(:disabled) {
80
+ background: #fef2f2;
81
+ color: #dc2626;
82
+ }
83
+
84
+ .icon-button:disabled {
85
+ opacity: 0.5;
86
+ cursor: not-allowed;
87
+ }
88
+ </style>
@@ -0,0 +1,12 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ variant?: 'default' | 'ghost' | 'destructive';
4
+ size?: 'sm' | 'md';
5
+ disabled?: boolean;
6
+ title?: string;
7
+ onclick?: () => void;
8
+ children: Snippet;
9
+ }
10
+ declare const IconButton: import("svelte").Component<Props, {}, "">;
11
+ type IconButton = ReturnType<typeof IconButton>;
12
+ export default IconButton;
@@ -0,0 +1,87 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ type?: 'text' | 'password' | 'email' | 'number' | 'search';
4
+ value?: string;
5
+ placeholder?: string;
6
+ disabled?: boolean;
7
+ readonly?: boolean;
8
+ size?: 'sm' | 'md';
9
+ mono?: boolean;
10
+ oninput?: (e: Event) => void;
11
+ onchange?: (e: Event) => void;
12
+ onkeydown?: (e: KeyboardEvent) => void;
13
+ }
14
+
15
+ let {
16
+ type = 'text',
17
+ value = $bindable(''),
18
+ placeholder = '',
19
+ disabled = false,
20
+ readonly = false,
21
+ size = 'sm',
22
+ mono = false,
23
+ oninput,
24
+ onchange,
25
+ onkeydown
26
+ }: Props = $props();
27
+ </script>
28
+
29
+ <input
30
+ class="input input-{size}"
31
+ class:mono
32
+ {type}
33
+ bind:value
34
+ {placeholder}
35
+ {disabled}
36
+ {readonly}
37
+ {oninput}
38
+ {onchange}
39
+ {onkeydown}
40
+ />
41
+
42
+ <style>
43
+ .input {
44
+ width: 100%;
45
+ border: 1px solid #e2e2e2;
46
+ border-radius: 4px;
47
+ font-size: 12px;
48
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
49
+ color: #333;
50
+ background: white;
51
+ transition: border-color 0.1s;
52
+ }
53
+
54
+ .input::placeholder {
55
+ color: #a1a1aa;
56
+ }
57
+
58
+ .input:focus {
59
+ outline: none;
60
+ border-color: #18181b;
61
+ }
62
+
63
+ .input:disabled {
64
+ background: #fafafa;
65
+ color: #a1a1aa;
66
+ cursor: not-allowed;
67
+ }
68
+
69
+ .input:read-only {
70
+ background: #fafafa;
71
+ }
72
+
73
+ .input-sm {
74
+ height: 24px;
75
+ padding: 0 8px;
76
+ }
77
+
78
+ .input-md {
79
+ height: 28px;
80
+ padding: 0 10px;
81
+ }
82
+
83
+ .mono {
84
+ font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
85
+ font-size: 11px;
86
+ }
87
+ </style>
@@ -0,0 +1,15 @@
1
+ interface Props {
2
+ type?: 'text' | 'password' | 'email' | 'number' | 'search';
3
+ value?: string;
4
+ placeholder?: string;
5
+ disabled?: boolean;
6
+ readonly?: boolean;
7
+ size?: 'sm' | 'md';
8
+ mono?: boolean;
9
+ oninput?: (e: Event) => void;
10
+ onchange?: (e: Event) => void;
11
+ onkeydown?: (e: KeyboardEvent) => void;
12
+ }
13
+ declare const Input: import("svelte").Component<Props, {}, "value">;
14
+ type Input = ReturnType<typeof Input>;
15
+ export default Input;
@@ -0,0 +1,124 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ value: Record<string, string>;
4
+ display?: 'inline' | 'stacked' | 'primary';
5
+ primaryLang?: string;
6
+ }
7
+
8
+ let {
9
+ value,
10
+ display = 'stacked',
11
+ primaryLang = 'en'
12
+ }: Props = $props();
13
+
14
+ let langs = $derived(Object.keys(value));
15
+ let primaryValue = $derived(value[primaryLang] || value[langs[0]] || '');
16
+ let otherCount = $derived(langs.length - 1);
17
+ </script>
18
+
19
+ {#if display === 'inline'}
20
+ <div class="lang-value inline">
21
+ {#each langs as lang}
22
+ <span class="entry">
23
+ <span class="lang">{lang}</span>
24
+ <span class="text">{value[lang]}</span>
25
+ </span>
26
+ {/each}
27
+ </div>
28
+ {:else if display === 'stacked'}
29
+ <div class="lang-value stacked">
30
+ {#each langs as lang}
31
+ <div class="entry">
32
+ <span class="lang">{lang}</span>
33
+ <span class="text">{value[lang]}</span>
34
+ </div>
35
+ {/each}
36
+ </div>
37
+ {:else if display === 'primary'}
38
+ <div class="lang-value primary">
39
+ <span class="text">{primaryValue}</span>
40
+ {#if otherCount > 0}
41
+ <span class="more" title={langs.filter(l => l !== primaryLang).map(l => `${l}: ${value[l]}`).join('\n')}>
42
+ +{otherCount}
43
+ </span>
44
+ {/if}
45
+ </div>
46
+ {/if}
47
+
48
+ <style>
49
+ .lang-value {
50
+ font-size: 12px;
51
+ }
52
+
53
+ /* Inline display */
54
+ .lang-value.inline {
55
+ display: flex;
56
+ flex-wrap: wrap;
57
+ gap: 8px;
58
+ }
59
+
60
+ .lang-value.inline .entry {
61
+ display: inline-flex;
62
+ align-items: center;
63
+ gap: 4px;
64
+ }
65
+
66
+ .lang-value.inline .lang {
67
+ font-size: 9px;
68
+ font-weight: 600;
69
+ text-transform: uppercase;
70
+ color: white;
71
+ background: #71717a;
72
+ padding: 1px 4px;
73
+ border-radius: 2px;
74
+ }
75
+
76
+ .lang-value.inline .text {
77
+ color: #3f3f46;
78
+ }
79
+
80
+ /* Stacked display */
81
+ .lang-value.stacked {
82
+ display: flex;
83
+ flex-direction: column;
84
+ gap: 2px;
85
+ }
86
+
87
+ .lang-value.stacked .entry {
88
+ display: flex;
89
+ align-items: baseline;
90
+ gap: 6px;
91
+ }
92
+
93
+ .lang-value.stacked .lang {
94
+ font-size: 9px;
95
+ font-weight: 500;
96
+ text-transform: uppercase;
97
+ color: #a1a1aa;
98
+ min-width: 18px;
99
+ }
100
+
101
+ .lang-value.stacked .text {
102
+ color: #3f3f46;
103
+ }
104
+
105
+ /* Primary display */
106
+ .lang-value.primary {
107
+ display: inline-flex;
108
+ align-items: center;
109
+ gap: 6px;
110
+ }
111
+
112
+ .lang-value.primary .text {
113
+ color: #3f3f46;
114
+ }
115
+
116
+ .lang-value.primary .more {
117
+ font-size: 10px;
118
+ color: #71717a;
119
+ background: #f4f4f5;
120
+ padding: 1px 5px;
121
+ border-radius: 3px;
122
+ cursor: help;
123
+ }
124
+ </style>
@@ -0,0 +1,8 @@
1
+ interface Props {
2
+ value: Record<string, string>;
3
+ display?: 'inline' | 'stacked' | 'primary';
4
+ primaryLang?: string;
5
+ }
6
+ declare const LangValue: import("svelte").Component<Props, {}, "">;
7
+ type LangValue = ReturnType<typeof LangValue>;
8
+ export default LangValue;
@@ -0,0 +1,136 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ open?: boolean;
4
+ title?: string;
5
+ onclose?: () => void;
6
+ children?: import('svelte').Snippet;
7
+ footer?: import('svelte').Snippet;
8
+ }
9
+
10
+ let {
11
+ open = $bindable(false),
12
+ title,
13
+ onclose,
14
+ children,
15
+ footer
16
+ }: Props = $props();
17
+
18
+ function handleBackdropClick(e: MouseEvent) {
19
+ if (e.target === e.currentTarget) {
20
+ close();
21
+ }
22
+ }
23
+
24
+ function handleKeydown(e: KeyboardEvent) {
25
+ if (e.key === 'Escape') {
26
+ close();
27
+ }
28
+ }
29
+
30
+ function close() {
31
+ open = false;
32
+ onclose?.();
33
+ }
34
+ </script>
35
+
36
+ <svelte:window onkeydown={handleKeydown} />
37
+
38
+ {#if open}
39
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
40
+ <div class="backdrop" onclick={handleBackdropClick} onkeydown={handleKeydown} role="dialog" aria-modal="true" tabindex="-1">
41
+ <div class="modal">
42
+ {#if title}
43
+ <div class="header">
44
+ <h2>{title}</h2>
45
+ <button class="close" onclick={close} aria-label="Close">
46
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
47
+ <path d="M18 6L6 18M6 6l12 12" />
48
+ </svg>
49
+ </button>
50
+ </div>
51
+ {/if}
52
+ <div class="content">
53
+ {#if children}
54
+ {@render children()}
55
+ {/if}
56
+ </div>
57
+ {#if footer}
58
+ <div class="footer">
59
+ {@render footer()}
60
+ </div>
61
+ {/if}
62
+ </div>
63
+ </div>
64
+ {/if}
65
+
66
+ <style>
67
+ .backdrop {
68
+ position: fixed;
69
+ inset: 0;
70
+ background: rgba(0, 0, 0, 0.4);
71
+ display: flex;
72
+ align-items: center;
73
+ justify-content: center;
74
+ z-index: 1000;
75
+ }
76
+
77
+ .modal {
78
+ background: white;
79
+ border-radius: 6px;
80
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
81
+ min-width: 320px;
82
+ max-width: 90vw;
83
+ max-height: 90vh;
84
+ display: flex;
85
+ flex-direction: column;
86
+ }
87
+
88
+ .header {
89
+ display: flex;
90
+ align-items: center;
91
+ justify-content: space-between;
92
+ padding: 12px 16px;
93
+ border-bottom: 1px solid #e2e2e2;
94
+ }
95
+
96
+ .header h2 {
97
+ margin: 0;
98
+ font-size: 14px;
99
+ font-weight: 600;
100
+ color: #18181b;
101
+ }
102
+
103
+ .close {
104
+ display: flex;
105
+ align-items: center;
106
+ justify-content: center;
107
+ width: 24px;
108
+ height: 24px;
109
+ border: none;
110
+ background: none;
111
+ color: #71717a;
112
+ cursor: pointer;
113
+ border-radius: 4px;
114
+ }
115
+
116
+ .close:hover {
117
+ background: #f4f4f5;
118
+ color: #18181b;
119
+ }
120
+
121
+ .content {
122
+ padding: 16px;
123
+ overflow-y: auto;
124
+ font-size: 13px;
125
+ color: #3f3f46;
126
+ line-height: 1.5;
127
+ }
128
+
129
+ .footer {
130
+ display: flex;
131
+ gap: 8px;
132
+ justify-content: flex-end;
133
+ padding: 12px 16px;
134
+ border-top: 1px solid #e2e2e2;
135
+ }
136
+ </style>
@@ -0,0 +1,10 @@
1
+ interface Props {
2
+ open?: boolean;
3
+ title?: string;
4
+ onclose?: () => void;
5
+ children?: import('svelte').Snippet;
6
+ footer?: import('svelte').Snippet;
7
+ }
8
+ declare const Modal: import("svelte").Component<Props, {}, "open">;
9
+ type Modal = ReturnType<typeof Modal>;
10
+ export default Modal;
@@ -0,0 +1,143 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ value?: number;
4
+ min?: number;
5
+ max?: number;
6
+ step?: number;
7
+ disabled?: boolean;
8
+ size?: 'sm' | 'md';
9
+ onchange?: (value: number) => void;
10
+ }
11
+
12
+ let {
13
+ value = $bindable(0),
14
+ min,
15
+ max,
16
+ step = 1,
17
+ disabled = false,
18
+ size = 'md',
19
+ onchange
20
+ }: Props = $props();
21
+
22
+ function increment() {
23
+ if (disabled) return;
24
+ const newValue = value + step;
25
+ if (max !== undefined && newValue > max) return;
26
+ value = newValue;
27
+ onchange?.(value);
28
+ }
29
+
30
+ function decrement() {
31
+ if (disabled) return;
32
+ const newValue = value - step;
33
+ if (min !== undefined && newValue < min) return;
34
+ value = newValue;
35
+ onchange?.(value);
36
+ }
37
+
38
+ function handleInput(event: Event) {
39
+ const target = event.target as HTMLInputElement;
40
+ const parsed = parseFloat(target.value);
41
+ if (!isNaN(parsed)) {
42
+ value = parsed;
43
+ onchange?.(value);
44
+ }
45
+ }
46
+ </script>
47
+
48
+ <div class="number-input {size}" class:disabled>
49
+ <button class="btn decrement" onclick={decrement} {disabled} aria-label="Decrease">
50
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
51
+ <path d="M5 12h14" />
52
+ </svg>
53
+ </button>
54
+ <input
55
+ type="number"
56
+ {value}
57
+ {min}
58
+ {max}
59
+ {step}
60
+ {disabled}
61
+ oninput={handleInput}
62
+ />
63
+ <button class="btn increment" onclick={increment} {disabled} aria-label="Increase">
64
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
65
+ <path d="M12 5v14M5 12h14" />
66
+ </svg>
67
+ </button>
68
+ </div>
69
+
70
+ <style>
71
+ .number-input {
72
+ display: inline-flex;
73
+ align-items: center;
74
+ border: 1px solid #e4e4e7;
75
+ border-radius: 4px;
76
+ overflow: hidden;
77
+ }
78
+
79
+ .number-input.sm {
80
+ height: 28px;
81
+ }
82
+
83
+ .number-input.md {
84
+ height: 32px;
85
+ }
86
+
87
+ .number-input.disabled {
88
+ opacity: 0.5;
89
+ }
90
+
91
+ .btn {
92
+ display: flex;
93
+ align-items: center;
94
+ justify-content: center;
95
+ width: 28px;
96
+ height: 100%;
97
+ padding: 0;
98
+ color: #71717a;
99
+ background: #fafafa;
100
+ border: none;
101
+ cursor: pointer;
102
+ transition: all 0.15s ease;
103
+ }
104
+
105
+ .btn:hover:not(:disabled) {
106
+ background: #f4f4f5;
107
+ color: #3f3f46;
108
+ }
109
+
110
+ .btn:disabled {
111
+ cursor: not-allowed;
112
+ }
113
+
114
+ input {
115
+ width: 60px;
116
+ height: 100%;
117
+ padding: 0 8px;
118
+ font-size: 12px;
119
+ font-family: monospace;
120
+ color: #18181b;
121
+ text-align: center;
122
+ background: white;
123
+ border: none;
124
+ border-left: 1px solid #e4e4e7;
125
+ border-right: 1px solid #e4e4e7;
126
+ outline: none;
127
+ -moz-appearance: textfield;
128
+ }
129
+
130
+ input::-webkit-outer-spin-button,
131
+ input::-webkit-inner-spin-button {
132
+ -webkit-appearance: none;
133
+ margin: 0;
134
+ }
135
+
136
+ input:focus {
137
+ background: #fafafa;
138
+ }
139
+
140
+ input:disabled {
141
+ cursor: not-allowed;
142
+ }
143
+ </style>
@@ -0,0 +1,12 @@
1
+ interface Props {
2
+ value?: number;
3
+ min?: number;
4
+ max?: number;
5
+ step?: number;
6
+ disabled?: boolean;
7
+ size?: 'sm' | 'md';
8
+ onchange?: (value: number) => void;
9
+ }
10
+ declare const NumberInput: import("svelte").Component<Props, {}, "value">;
11
+ type NumberInput = ReturnType<typeof NumberInput>;
12
+ export default NumberInput;