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,49 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ padding?: 'none' | 'sm' | 'md' | 'lg';
6
+ hoverable?: boolean;
7
+ children: Snippet;
8
+ }
9
+
10
+ let { padding = 'md', hoverable = false, children }: Props = $props();
11
+ </script>
12
+
13
+ <div class="card padding-{padding}" class:hoverable>
14
+ {@render children()}
15
+ </div>
16
+
17
+ <style>
18
+ .card {
19
+ background: white;
20
+ border: 1px solid #e4e4e7;
21
+ border-radius: 8px;
22
+ }
23
+
24
+ .card.padding-none {
25
+ padding: 0;
26
+ }
27
+
28
+ .card.padding-sm {
29
+ padding: 12px;
30
+ }
31
+
32
+ .card.padding-md {
33
+ padding: 16px;
34
+ }
35
+
36
+ .card.padding-lg {
37
+ padding: 24px;
38
+ }
39
+
40
+ .card.hoverable {
41
+ cursor: pointer;
42
+ transition: all 0.15s ease;
43
+ }
44
+
45
+ .card.hoverable:hover {
46
+ border-color: #d4d4d8;
47
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
48
+ }
49
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ padding?: 'none' | 'sm' | 'md' | 'lg';
4
+ hoverable?: boolean;
5
+ children: Snippet;
6
+ }
7
+ declare const Card: import("svelte").Component<Props, {}, "">;
8
+ type Card = ReturnType<typeof Card>;
9
+ export default Card;
@@ -0,0 +1,108 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ checked?: boolean;
4
+ label?: string;
5
+ disabled?: boolean;
6
+ indeterminate?: boolean;
7
+ onchange?: (checked: boolean) => void;
8
+ }
9
+
10
+ let {
11
+ checked = $bindable(false),
12
+ label,
13
+ disabled = false,
14
+ indeterminate = false,
15
+ onchange
16
+ }: Props = $props();
17
+
18
+ function handleChange(e: Event) {
19
+ const target = e.target as HTMLInputElement;
20
+ checked = target.checked;
21
+ onchange?.(checked);
22
+ }
23
+ </script>
24
+
25
+ <label class="checkbox" class:disabled>
26
+ <input
27
+ type="checkbox"
28
+ {checked}
29
+ {disabled}
30
+ indeterminate={indeterminate}
31
+ onchange={handleChange}
32
+ />
33
+ <span class="checkmark" class:indeterminate></span>
34
+ {#if label}
35
+ <span class="label">{label}</span>
36
+ {/if}
37
+ </label>
38
+
39
+ <style>
40
+ .checkbox {
41
+ display: inline-flex;
42
+ align-items: center;
43
+ gap: 6px;
44
+ cursor: pointer;
45
+ font-size: 12px;
46
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
47
+ color: #333;
48
+ }
49
+
50
+ .checkbox.disabled {
51
+ cursor: not-allowed;
52
+ opacity: 0.5;
53
+ }
54
+
55
+ input {
56
+ position: absolute;
57
+ opacity: 0;
58
+ width: 0;
59
+ height: 0;
60
+ }
61
+
62
+ .checkmark {
63
+ width: 14px;
64
+ height: 14px;
65
+ border: 1px solid #d4d4d8;
66
+ border-radius: 3px;
67
+ background: white;
68
+ display: flex;
69
+ align-items: center;
70
+ justify-content: center;
71
+ transition: all 0.1s;
72
+ }
73
+
74
+ input:checked + .checkmark {
75
+ background: #18181b;
76
+ border-color: #18181b;
77
+ }
78
+
79
+ input:checked + .checkmark::after {
80
+ content: '';
81
+ width: 4px;
82
+ height: 7px;
83
+ border: solid white;
84
+ border-width: 0 1.5px 1.5px 0;
85
+ transform: rotate(45deg) translateY(-1px);
86
+ }
87
+
88
+ .checkmark.indeterminate {
89
+ background: #18181b;
90
+ border-color: #18181b;
91
+ }
92
+
93
+ .checkmark.indeterminate::after {
94
+ content: '';
95
+ width: 8px;
96
+ height: 1.5px;
97
+ background: white;
98
+ }
99
+
100
+ input:focus-visible + .checkmark {
101
+ outline: 2px solid #6366f1;
102
+ outline-offset: 1px;
103
+ }
104
+
105
+ .label {
106
+ user-select: none;
107
+ }
108
+ </style>
@@ -0,0 +1,10 @@
1
+ interface Props {
2
+ checked?: boolean;
3
+ label?: string;
4
+ disabled?: boolean;
5
+ indeterminate?: boolean;
6
+ onchange?: (checked: boolean) => void;
7
+ }
8
+ declare const Checkbox: import("svelte").Component<Props, {}, "checked">;
9
+ type Checkbox = ReturnType<typeof Checkbox>;
10
+ export default Checkbox;
@@ -0,0 +1,132 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface MenuItem {
5
+ label: string;
6
+ value?: string;
7
+ icon?: string;
8
+ destructive?: boolean;
9
+ disabled?: boolean;
10
+ separator?: boolean;
11
+ }
12
+
13
+ interface Props {
14
+ items: MenuItem[];
15
+ onselect?: (item: MenuItem) => void;
16
+ children: Snippet;
17
+ }
18
+
19
+ let { items, onselect, children }: Props = $props();
20
+
21
+ let open = $state(false);
22
+ let x = $state(0);
23
+ let y = $state(0);
24
+
25
+ function handleContextMenu(event: MouseEvent) {
26
+ event.preventDefault();
27
+ x = event.clientX;
28
+ y = event.clientY;
29
+ open = true;
30
+ }
31
+
32
+ function handleClick() {
33
+ if (open) {
34
+ open = false;
35
+ }
36
+ }
37
+
38
+ function handleKeydown(event: KeyboardEvent) {
39
+ if (event.key === 'Escape') {
40
+ open = false;
41
+ }
42
+ }
43
+
44
+ function select(item: MenuItem) {
45
+ if (item.disabled || item.separator) return;
46
+ onselect?.(item);
47
+ open = false;
48
+ }
49
+ </script>
50
+
51
+ <svelte:window onclick={handleClick} onkeydown={handleKeydown} />
52
+
53
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
54
+ <div class="context-menu-wrapper" oncontextmenu={handleContextMenu}>
55
+ {@render children()}
56
+ </div>
57
+
58
+ {#if open}
59
+ <div class="context-menu" style="left: {x}px; top: {y}px;" role="menu">
60
+ {#each items as item}
61
+ {#if item.separator}
62
+ <div class="separator"></div>
63
+ {:else}
64
+ <button
65
+ type="button"
66
+ role="menuitem"
67
+ class="item"
68
+ class:destructive={item.destructive}
69
+ class:disabled={item.disabled}
70
+ onclick={() => select(item)}
71
+ disabled={item.disabled}
72
+ >
73
+ {item.label}
74
+ </button>
75
+ {/if}
76
+ {/each}
77
+ </div>
78
+ {/if}
79
+
80
+ <style>
81
+ .context-menu-wrapper {
82
+ display: contents;
83
+ }
84
+
85
+ .context-menu {
86
+ position: fixed;
87
+ min-width: 160px;
88
+ padding: 4px;
89
+ background: white;
90
+ border: 1px solid #e4e4e7;
91
+ border-radius: 6px;
92
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
93
+ z-index: 100;
94
+ }
95
+
96
+ .item {
97
+ display: block;
98
+ width: 100%;
99
+ padding: 8px 12px;
100
+ font-size: 12px;
101
+ color: #3f3f46;
102
+ text-align: left;
103
+ background: none;
104
+ border: none;
105
+ border-radius: 4px;
106
+ cursor: pointer;
107
+ transition: background-color 0.1s ease;
108
+ }
109
+
110
+ .item:hover:not(.disabled) {
111
+ background: #f4f4f5;
112
+ }
113
+
114
+ .item.destructive {
115
+ color: #dc2626;
116
+ }
117
+
118
+ .item.destructive:hover:not(.disabled) {
119
+ background: #fef2f2;
120
+ }
121
+
122
+ .item.disabled {
123
+ color: #a1a1aa;
124
+ cursor: not-allowed;
125
+ }
126
+
127
+ .separator {
128
+ height: 1px;
129
+ margin: 4px 8px;
130
+ background: #e4e4e7;
131
+ }
132
+ </style>
@@ -0,0 +1,17 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface MenuItem {
3
+ label: string;
4
+ value?: string;
5
+ icon?: string;
6
+ destructive?: boolean;
7
+ disabled?: boolean;
8
+ separator?: boolean;
9
+ }
10
+ interface Props {
11
+ items: MenuItem[];
12
+ onselect?: (item: MenuItem) => void;
13
+ children: Snippet;
14
+ }
15
+ declare const ContextMenu: import("svelte").Component<Props, {}, "">;
16
+ type ContextMenu = ReturnType<typeof ContextMenu>;
17
+ export default ContextMenu;
@@ -0,0 +1,55 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ orientation?: 'horizontal' | 'vertical';
4
+ spacing?: 'none' | 'sm' | 'md' | 'lg';
5
+ }
6
+
7
+ let { orientation = 'horizontal', spacing = 'md' }: Props = $props();
8
+ </script>
9
+
10
+ <div class="divider {orientation} spacing-{spacing}"></div>
11
+
12
+ <style>
13
+ .divider {
14
+ background: #e4e4e7;
15
+ flex-shrink: 0;
16
+ }
17
+
18
+ .divider.horizontal {
19
+ height: 1px;
20
+ width: 100%;
21
+ }
22
+
23
+ .divider.vertical {
24
+ width: 1px;
25
+ align-self: stretch;
26
+ }
27
+
28
+ .divider.spacing-none {
29
+ margin: 0;
30
+ }
31
+
32
+ .divider.horizontal.spacing-sm {
33
+ margin: 8px 0;
34
+ }
35
+
36
+ .divider.horizontal.spacing-md {
37
+ margin: 16px 0;
38
+ }
39
+
40
+ .divider.horizontal.spacing-lg {
41
+ margin: 24px 0;
42
+ }
43
+
44
+ .divider.vertical.spacing-sm {
45
+ margin: 0 8px;
46
+ }
47
+
48
+ .divider.vertical.spacing-md {
49
+ margin: 0 16px;
50
+ }
51
+
52
+ .divider.vertical.spacing-lg {
53
+ margin: 0 24px;
54
+ }
55
+ </style>
@@ -0,0 +1,7 @@
1
+ interface Props {
2
+ orientation?: 'horizontal' | 'vertical';
3
+ spacing?: 'none' | 'sm' | 'md' | 'lg';
4
+ }
5
+ declare const Divider: import("svelte").Component<Props, {}, "">;
6
+ type Divider = ReturnType<typeof Divider>;
7
+ export default Divider;
@@ -0,0 +1,156 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface MenuItem {
5
+ label: string;
6
+ value?: string;
7
+ icon?: string;
8
+ destructive?: boolean;
9
+ disabled?: boolean;
10
+ }
11
+
12
+ interface Props {
13
+ items: MenuItem[];
14
+ trigger?: Snippet;
15
+ label?: string;
16
+ onselect?: (item: MenuItem) => void;
17
+ }
18
+
19
+ let { items, trigger, label = 'Menu', onselect }: Props = $props();
20
+
21
+ let open = $state(false);
22
+ let buttonEl: HTMLButtonElement;
23
+
24
+ function toggle() {
25
+ open = !open;
26
+ }
27
+
28
+ function select(item: MenuItem) {
29
+ if (item.disabled) return;
30
+ onselect?.(item);
31
+ open = false;
32
+ }
33
+
34
+ function handleKeydown(event: KeyboardEvent) {
35
+ if (event.key === 'Escape') {
36
+ open = false;
37
+ buttonEl?.focus();
38
+ }
39
+ }
40
+
41
+ function handleClickOutside(event: MouseEvent) {
42
+ if (open && buttonEl && !buttonEl.contains(event.target as Node)) {
43
+ open = false;
44
+ }
45
+ }
46
+ </script>
47
+
48
+ <svelte:window onclick={handleClickOutside} onkeydown={handleKeydown} />
49
+
50
+ <div class="dropdown">
51
+ <button
52
+ bind:this={buttonEl}
53
+ type="button"
54
+ class="trigger"
55
+ aria-haspopup="true"
56
+ aria-expanded={open}
57
+ onclick={toggle}
58
+ >
59
+ {#if trigger}
60
+ {@render trigger()}
61
+ {:else}
62
+ {label}
63
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
64
+ <path d="M6 9l6 6 6-6" />
65
+ </svg>
66
+ {/if}
67
+ </button>
68
+
69
+ {#if open}
70
+ <div class="menu" role="menu">
71
+ {#each items as item}
72
+ <button
73
+ type="button"
74
+ role="menuitem"
75
+ class="item"
76
+ class:destructive={item.destructive}
77
+ class:disabled={item.disabled}
78
+ onclick={() => select(item)}
79
+ disabled={item.disabled}
80
+ >
81
+ {item.label}
82
+ </button>
83
+ {/each}
84
+ </div>
85
+ {/if}
86
+ </div>
87
+
88
+ <style>
89
+ .dropdown {
90
+ position: relative;
91
+ display: inline-block;
92
+ }
93
+
94
+ .trigger {
95
+ display: inline-flex;
96
+ align-items: center;
97
+ gap: 4px;
98
+ padding: 6px 10px;
99
+ font-size: 12px;
100
+ color: #3f3f46;
101
+ background: white;
102
+ border: 1px solid #e4e4e7;
103
+ border-radius: 4px;
104
+ cursor: pointer;
105
+ transition: all 0.15s ease;
106
+ }
107
+
108
+ .trigger:hover {
109
+ background: #fafafa;
110
+ border-color: #d4d4d8;
111
+ }
112
+
113
+ .menu {
114
+ position: absolute;
115
+ top: 100%;
116
+ left: 0;
117
+ margin-top: 4px;
118
+ min-width: 140px;
119
+ background: white;
120
+ border: 1px solid #e4e4e7;
121
+ border-radius: 6px;
122
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
123
+ z-index: 50;
124
+ overflow: hidden;
125
+ }
126
+
127
+ .item {
128
+ display: block;
129
+ width: 100%;
130
+ padding: 8px 12px;
131
+ font-size: 12px;
132
+ color: #3f3f46;
133
+ text-align: left;
134
+ background: none;
135
+ border: none;
136
+ cursor: pointer;
137
+ transition: background-color 0.1s ease;
138
+ }
139
+
140
+ .item:hover:not(.disabled) {
141
+ background: #f4f4f5;
142
+ }
143
+
144
+ .item.destructive {
145
+ color: #dc2626;
146
+ }
147
+
148
+ .item.destructive:hover:not(.disabled) {
149
+ background: #fef2f2;
150
+ }
151
+
152
+ .item.disabled {
153
+ color: #a1a1aa;
154
+ cursor: not-allowed;
155
+ }
156
+ </style>
@@ -0,0 +1,17 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface MenuItem {
3
+ label: string;
4
+ value?: string;
5
+ icon?: string;
6
+ destructive?: boolean;
7
+ disabled?: boolean;
8
+ }
9
+ interface Props {
10
+ items: MenuItem[];
11
+ trigger?: Snippet;
12
+ label?: string;
13
+ onselect?: (item: MenuItem) => void;
14
+ }
15
+ declare const Dropdown: import("svelte").Component<Props, {}, "">;
16
+ type Dropdown = ReturnType<typeof Dropdown>;
17
+ export default Dropdown;
@@ -0,0 +1,79 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ title?: string;
6
+ description?: string;
7
+ icon?: 'empty' | 'search' | 'error';
8
+ children?: Snippet;
9
+ }
10
+
11
+ let {
12
+ title = 'No data',
13
+ description,
14
+ icon = 'empty',
15
+ children
16
+ }: Props = $props();
17
+ </script>
18
+
19
+ <div class="empty-state">
20
+ <div class="icon">
21
+ {#if icon === 'empty'}
22
+ <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
23
+ <path d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
24
+ </svg>
25
+ {:else if icon === 'search'}
26
+ <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
27
+ <circle cx="11" cy="11" r="8" />
28
+ <path d="M21 21l-4.35-4.35" />
29
+ </svg>
30
+ {:else if icon === 'error'}
31
+ <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
32
+ <circle cx="12" cy="12" r="10" />
33
+ <path d="M12 8v4m0 4h.01" />
34
+ </svg>
35
+ {/if}
36
+ </div>
37
+ <h3 class="title">{title}</h3>
38
+ {#if description}
39
+ <p class="description">{description}</p>
40
+ {/if}
41
+ {#if children}
42
+ <div class="actions">
43
+ {@render children()}
44
+ </div>
45
+ {/if}
46
+ </div>
47
+
48
+ <style>
49
+ .empty-state {
50
+ display: flex;
51
+ flex-direction: column;
52
+ align-items: center;
53
+ justify-content: center;
54
+ padding: 32px;
55
+ text-align: center;
56
+ }
57
+
58
+ .icon {
59
+ color: #a1a1aa;
60
+ margin-bottom: 12px;
61
+ }
62
+
63
+ .title {
64
+ margin: 0;
65
+ font-size: 14px;
66
+ font-weight: 500;
67
+ color: #3f3f46;
68
+ }
69
+
70
+ .description {
71
+ margin: 4px 0 0;
72
+ font-size: 12px;
73
+ color: #71717a;
74
+ }
75
+
76
+ .actions {
77
+ margin-top: 16px;
78
+ }
79
+ </style>
@@ -0,0 +1,10 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ title?: string;
4
+ description?: string;
5
+ icon?: 'empty' | 'search' | 'error';
6
+ children?: Snippet;
7
+ }
8
+ declare const EmptyState: import("svelte").Component<Props, {}, "">;
9
+ type EmptyState = ReturnType<typeof EmptyState>;
10
+ export default EmptyState;