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,83 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ page?: number;
4
+ total: number;
5
+ perPage?: number;
6
+ onchange?: (page: number) => void;
7
+ }
8
+
9
+ let {
10
+ page = $bindable(1),
11
+ total,
12
+ perPage = 10,
13
+ onchange
14
+ }: Props = $props();
15
+
16
+ let totalPages = $derived(Math.ceil(total / perPage));
17
+ let canPrev = $derived(page > 1);
18
+ let canNext = $derived(page < totalPages);
19
+
20
+ function goTo(newPage: number) {
21
+ if (newPage >= 1 && newPage <= totalPages) {
22
+ page = newPage;
23
+ onchange?.(page);
24
+ }
25
+ }
26
+ </script>
27
+
28
+ <div class="pagination">
29
+ <button class="btn" disabled={!canPrev} onclick={() => goTo(page - 1)}>
30
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
31
+ <path d="M15 18l-6-6 6-6" />
32
+ </svg>
33
+ </button>
34
+
35
+ <span class="info">
36
+ {page} / {totalPages}
37
+ </span>
38
+
39
+ <button class="btn" disabled={!canNext} onclick={() => goTo(page + 1)}>
40
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
41
+ <path d="M9 18l6-6-6-6" />
42
+ </svg>
43
+ </button>
44
+ </div>
45
+
46
+ <style>
47
+ .pagination {
48
+ display: flex;
49
+ align-items: center;
50
+ gap: 8px;
51
+ }
52
+
53
+ .btn {
54
+ display: flex;
55
+ align-items: center;
56
+ justify-content: center;
57
+ width: 24px;
58
+ height: 24px;
59
+ border: 1px solid #e2e2e2;
60
+ border-radius: 4px;
61
+ background: white;
62
+ color: #333;
63
+ cursor: pointer;
64
+ }
65
+
66
+ .btn:hover:not(:disabled) {
67
+ background: #fafafa;
68
+ border-color: #d0d0d0;
69
+ }
70
+
71
+ .btn:disabled {
72
+ opacity: 0.4;
73
+ cursor: not-allowed;
74
+ }
75
+
76
+ .info {
77
+ font-size: 12px;
78
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
79
+ color: #71717a;
80
+ min-width: 50px;
81
+ text-align: center;
82
+ }
83
+ </style>
@@ -0,0 +1,9 @@
1
+ interface Props {
2
+ page?: number;
3
+ total: number;
4
+ perPage?: number;
5
+ onchange?: (page: number) => void;
6
+ }
7
+ declare const Pagination: import("svelte").Component<Props, {}, "page">;
8
+ type Pagination = ReturnType<typeof Pagination>;
9
+ export default Pagination;
@@ -0,0 +1,95 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ position?: 'top' | 'bottom' | 'left' | 'right';
6
+ trigger: Snippet;
7
+ children: Snippet;
8
+ }
9
+
10
+ let { position = 'bottom', trigger, children }: Props = $props();
11
+
12
+ let open = $state(false);
13
+ let wrapperEl: HTMLDivElement;
14
+
15
+ function toggle() {
16
+ open = !open;
17
+ }
18
+
19
+ function handleClickOutside(event: MouseEvent) {
20
+ if (open && wrapperEl && !wrapperEl.contains(event.target as Node)) {
21
+ open = false;
22
+ }
23
+ }
24
+
25
+ function handleKeydown(event: KeyboardEvent) {
26
+ if (event.key === 'Escape') {
27
+ open = false;
28
+ }
29
+ }
30
+ </script>
31
+
32
+ <svelte:window onclick={handleClickOutside} onkeydown={handleKeydown} />
33
+
34
+ <div class="popover-wrapper" bind:this={wrapperEl}>
35
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
36
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
37
+ <div class="trigger" onclick={toggle}>
38
+ {@render trigger()}
39
+ </div>
40
+ {#if open}
41
+ <div class="popover {position}">
42
+ {@render children()}
43
+ </div>
44
+ {/if}
45
+ </div>
46
+
47
+ <style>
48
+ .popover-wrapper {
49
+ position: relative;
50
+ display: inline-block;
51
+ }
52
+
53
+ .trigger {
54
+ cursor: pointer;
55
+ }
56
+
57
+ .popover {
58
+ position: absolute;
59
+ min-width: 200px;
60
+ padding: 12px;
61
+ background: white;
62
+ border: 1px solid #e4e4e7;
63
+ border-radius: 6px;
64
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
65
+ z-index: 50;
66
+ }
67
+
68
+ .popover.top {
69
+ bottom: 100%;
70
+ left: 50%;
71
+ transform: translateX(-50%);
72
+ margin-bottom: 8px;
73
+ }
74
+
75
+ .popover.bottom {
76
+ top: 100%;
77
+ left: 50%;
78
+ transform: translateX(-50%);
79
+ margin-top: 8px;
80
+ }
81
+
82
+ .popover.left {
83
+ right: 100%;
84
+ top: 50%;
85
+ transform: translateY(-50%);
86
+ margin-right: 8px;
87
+ }
88
+
89
+ .popover.right {
90
+ left: 100%;
91
+ top: 50%;
92
+ transform: translateY(-50%);
93
+ margin-left: 8px;
94
+ }
95
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ position?: 'top' | 'bottom' | 'left' | 'right';
4
+ trigger: Snippet;
5
+ children: Snippet;
6
+ }
7
+ declare const Popover: import("svelte").Component<Props, {}, "">;
8
+ type Popover = ReturnType<typeof Popover>;
9
+ export default Popover;
@@ -0,0 +1,55 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ value?: number;
4
+ max?: number;
5
+ size?: 'sm' | 'md';
6
+ variant?: 'default' | 'success' | 'warning' | 'error';
7
+ }
8
+
9
+ let { value = 0, max = 100, size = 'md', variant = 'default' }: Props = $props();
10
+
11
+ let percentage = $derived(Math.min(100, Math.max(0, (value / max) * 100)));
12
+ </script>
13
+
14
+ <div class="progress {size}" role="progressbar" aria-valuenow={value} aria-valuemin={0} aria-valuemax={max}>
15
+ <div class="bar {variant}" style="width: {percentage}%"></div>
16
+ </div>
17
+
18
+ <style>
19
+ .progress {
20
+ width: 100%;
21
+ background: #e4e4e7;
22
+ border-radius: 999px;
23
+ overflow: hidden;
24
+ }
25
+
26
+ .progress.sm {
27
+ height: 4px;
28
+ }
29
+
30
+ .progress.md {
31
+ height: 8px;
32
+ }
33
+
34
+ .bar {
35
+ height: 100%;
36
+ border-radius: 999px;
37
+ transition: width 0.3s ease;
38
+ }
39
+
40
+ .bar.default {
41
+ background: #6366f1;
42
+ }
43
+
44
+ .bar.success {
45
+ background: #22c55e;
46
+ }
47
+
48
+ .bar.warning {
49
+ background: #f59e0b;
50
+ }
51
+
52
+ .bar.error {
53
+ background: #ef4444;
54
+ }
55
+ </style>
@@ -0,0 +1,9 @@
1
+ interface Props {
2
+ value?: number;
3
+ max?: number;
4
+ size?: 'sm' | 'md';
5
+ variant?: 'default' | 'success' | 'warning' | 'error';
6
+ }
7
+ declare const Progress: import("svelte").Component<Props, {}, "">;
8
+ type Progress = ReturnType<typeof Progress>;
9
+ export default Progress;
@@ -0,0 +1,111 @@
1
+ <script lang="ts">
2
+ interface Option {
3
+ value: string;
4
+ label: string;
5
+ disabled?: boolean;
6
+ }
7
+
8
+ interface Props {
9
+ options: Option[];
10
+ value?: string;
11
+ name?: string;
12
+ orientation?: 'horizontal' | 'vertical';
13
+ onchange?: (value: string) => void;
14
+ }
15
+
16
+ let {
17
+ options,
18
+ value = $bindable(''),
19
+ name = 'radio-group',
20
+ orientation = 'vertical',
21
+ onchange
22
+ }: Props = $props();
23
+
24
+ function handleChange(optionValue: string) {
25
+ value = optionValue;
26
+ onchange?.(value);
27
+ }
28
+ </script>
29
+
30
+ <div class="radio-group {orientation}" role="radiogroup">
31
+ {#each options as option}
32
+ <label class="radio-option" class:disabled={option.disabled}>
33
+ <input
34
+ type="radio"
35
+ {name}
36
+ value={option.value}
37
+ checked={value === option.value}
38
+ disabled={option.disabled}
39
+ onchange={() => handleChange(option.value)}
40
+ />
41
+ <span class="radio-circle"></span>
42
+ <span class="radio-label">{option.label}</span>
43
+ </label>
44
+ {/each}
45
+ </div>
46
+
47
+ <style>
48
+ .radio-group {
49
+ display: flex;
50
+ gap: 12px;
51
+ }
52
+
53
+ .radio-group.vertical {
54
+ flex-direction: column;
55
+ gap: 8px;
56
+ }
57
+
58
+ .radio-group.horizontal {
59
+ flex-direction: row;
60
+ flex-wrap: wrap;
61
+ }
62
+
63
+ .radio-option {
64
+ display: inline-flex;
65
+ align-items: center;
66
+ gap: 8px;
67
+ cursor: pointer;
68
+ font-size: 12px;
69
+ color: #3f3f46;
70
+ }
71
+
72
+ .radio-option.disabled {
73
+ opacity: 0.5;
74
+ cursor: not-allowed;
75
+ }
76
+
77
+ .radio-option input {
78
+ position: absolute;
79
+ opacity: 0;
80
+ pointer-events: none;
81
+ }
82
+
83
+ .radio-circle {
84
+ width: 16px;
85
+ height: 16px;
86
+ border: 2px solid #d4d4d8;
87
+ border-radius: 50%;
88
+ transition: all 0.15s ease;
89
+ position: relative;
90
+ }
91
+
92
+ .radio-option input:checked + .radio-circle {
93
+ border-color: #6366f1;
94
+ }
95
+
96
+ .radio-option input:checked + .radio-circle::after {
97
+ content: '';
98
+ position: absolute;
99
+ top: 50%;
100
+ left: 50%;
101
+ transform: translate(-50%, -50%);
102
+ width: 8px;
103
+ height: 8px;
104
+ background: #6366f1;
105
+ border-radius: 50%;
106
+ }
107
+
108
+ .radio-option input:focus-visible + .radio-circle {
109
+ box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
110
+ }
111
+ </style>
@@ -0,0 +1,15 @@
1
+ interface Option {
2
+ value: string;
3
+ label: string;
4
+ disabled?: boolean;
5
+ }
6
+ interface Props {
7
+ options: Option[];
8
+ value?: string;
9
+ name?: string;
10
+ orientation?: 'horizontal' | 'vertical';
11
+ onchange?: (value: string) => void;
12
+ }
13
+ declare const RadioGroup: import("svelte").Component<Props, {}, "value">;
14
+ type RadioGroup = ReturnType<typeof RadioGroup>;
15
+ export default RadioGroup;
@@ -0,0 +1,121 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ value?: string;
4
+ placeholder?: string;
5
+ size?: 'sm' | 'md';
6
+ onchange?: (value: string) => void;
7
+ onsearch?: (value: string) => void;
8
+ }
9
+
10
+ let {
11
+ value = $bindable(''),
12
+ placeholder = 'Search...',
13
+ size = 'md',
14
+ onchange,
15
+ onsearch
16
+ }: Props = $props();
17
+
18
+ function handleInput(event: Event) {
19
+ const target = event.target as HTMLInputElement;
20
+ value = target.value;
21
+ onchange?.(value);
22
+ }
23
+
24
+ function handleKeydown(event: KeyboardEvent) {
25
+ if (event.key === 'Enter') {
26
+ onsearch?.(value);
27
+ }
28
+ }
29
+
30
+ function clear() {
31
+ value = '';
32
+ onchange?.('');
33
+ }
34
+ </script>
35
+
36
+ <div class="search-input {size}">
37
+ <svg class="search-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
38
+ <circle cx="11" cy="11" r="8" />
39
+ <path d="M21 21l-4.35-4.35" />
40
+ </svg>
41
+ <input
42
+ type="text"
43
+ {placeholder}
44
+ {value}
45
+ oninput={handleInput}
46
+ onkeydown={handleKeydown}
47
+ />
48
+ {#if value}
49
+ <button class="clear-btn" onclick={clear} aria-label="Clear search">
50
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
51
+ <path d="M18 6L6 18M6 6l12 12" />
52
+ </svg>
53
+ </button>
54
+ {/if}
55
+ </div>
56
+
57
+ <style>
58
+ .search-input {
59
+ position: relative;
60
+ display: inline-flex;
61
+ align-items: center;
62
+ }
63
+
64
+ .search-input.sm {
65
+ height: 28px;
66
+ }
67
+
68
+ .search-input.md {
69
+ height: 32px;
70
+ }
71
+
72
+ .search-icon {
73
+ position: absolute;
74
+ left: 10px;
75
+ color: #a1a1aa;
76
+ pointer-events: none;
77
+ }
78
+
79
+ input {
80
+ width: 100%;
81
+ height: 100%;
82
+ padding: 0 32px 0 32px;
83
+ font-size: 12px;
84
+ color: #18181b;
85
+ background: white;
86
+ border: 1px solid #e4e4e7;
87
+ border-radius: 4px;
88
+ outline: none;
89
+ transition: border-color 0.15s ease;
90
+ }
91
+
92
+ input::placeholder {
93
+ color: #a1a1aa;
94
+ }
95
+
96
+ input:focus {
97
+ border-color: #6366f1;
98
+ }
99
+
100
+ .clear-btn {
101
+ position: absolute;
102
+ right: 6px;
103
+ display: flex;
104
+ align-items: center;
105
+ justify-content: center;
106
+ width: 18px;
107
+ height: 18px;
108
+ padding: 0;
109
+ color: #a1a1aa;
110
+ background: none;
111
+ border: none;
112
+ border-radius: 2px;
113
+ cursor: pointer;
114
+ transition: all 0.15s ease;
115
+ }
116
+
117
+ .clear-btn:hover {
118
+ color: #3f3f46;
119
+ background: #f4f4f5;
120
+ }
121
+ </style>
@@ -0,0 +1,10 @@
1
+ interface Props {
2
+ value?: string;
3
+ placeholder?: string;
4
+ size?: 'sm' | 'md';
5
+ onchange?: (value: string) => void;
6
+ onsearch?: (value: string) => void;
7
+ }
8
+ declare const SearchInput: import("svelte").Component<Props, {}, "value">;
9
+ type SearchInput = ReturnType<typeof SearchInput>;
10
+ export default SearchInput;
@@ -0,0 +1,82 @@
1
+ <script lang="ts">
2
+ interface Option {
3
+ value: string;
4
+ label: string;
5
+ }
6
+
7
+ interface Props {
8
+ options: Option[];
9
+ value?: string;
10
+ placeholder?: string;
11
+ disabled?: boolean;
12
+ size?: 'sm' | 'md';
13
+ onchange?: (value: string) => void;
14
+ }
15
+
16
+ let {
17
+ options,
18
+ value = $bindable(''),
19
+ placeholder = 'Select...',
20
+ disabled = false,
21
+ size = 'sm',
22
+ onchange
23
+ }: Props = $props();
24
+
25
+ function handleChange(e: Event) {
26
+ const target = e.target as HTMLSelectElement;
27
+ value = target.value;
28
+ onchange?.(value);
29
+ }
30
+ </script>
31
+
32
+ <select
33
+ class="select select-{size}"
34
+ {disabled}
35
+ {value}
36
+ onchange={handleChange}
37
+ >
38
+ {#if placeholder}
39
+ <option value="" disabled>{placeholder}</option>
40
+ {/if}
41
+ {#each options as option}
42
+ <option value={option.value}>{option.label}</option>
43
+ {/each}
44
+ </select>
45
+
46
+ <style>
47
+ .select {
48
+ appearance: none;
49
+ background: white;
50
+ border: 1px solid #e2e2e2;
51
+ border-radius: 4px;
52
+ font-size: 12px;
53
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
54
+ color: #333;
55
+ cursor: pointer;
56
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
57
+ background-repeat: no-repeat;
58
+ background-position: right 8px center;
59
+ padding-right: 28px;
60
+ }
61
+
62
+ .select:focus {
63
+ outline: none;
64
+ border-color: #18181b;
65
+ }
66
+
67
+ .select:disabled {
68
+ background-color: #fafafa;
69
+ color: #a1a1aa;
70
+ cursor: not-allowed;
71
+ }
72
+
73
+ .select-sm {
74
+ height: 24px;
75
+ padding: 0 8px;
76
+ }
77
+
78
+ .select-md {
79
+ height: 28px;
80
+ padding: 0 10px;
81
+ }
82
+ </style>
@@ -0,0 +1,15 @@
1
+ interface Option {
2
+ value: string;
3
+ label: string;
4
+ }
5
+ interface Props {
6
+ options: Option[];
7
+ value?: string;
8
+ placeholder?: string;
9
+ disabled?: boolean;
10
+ size?: 'sm' | 'md';
11
+ onchange?: (value: string) => void;
12
+ }
13
+ declare const Select: import("svelte").Component<Props, {}, "value">;
14
+ type Select = ReturnType<typeof Select>;
15
+ export default Select;