plasma-svelte 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 (95) hide show
  1. package/README.md +65 -0
  2. package/dist/accordion/Accordion.svelte +28 -0
  3. package/dist/accordion/Accordion.svelte.d.ts +8 -0
  4. package/dist/accordion/AccordionItem.svelte +193 -0
  5. package/dist/accordion/AccordionItem.svelte.d.ts +14 -0
  6. package/dist/avatar/Avatar.svelte +178 -0
  7. package/dist/avatar/Avatar.svelte.d.ts +16 -0
  8. package/dist/badge/Badge.svelte +162 -0
  9. package/dist/badge/Badge.svelte.d.ts +16 -0
  10. package/dist/breadcrumb/Breadcrumb.svelte +59 -0
  11. package/dist/breadcrumb/Breadcrumb.svelte.d.ts +9 -0
  12. package/dist/breadcrumb/BreadcrumbItem.svelte +151 -0
  13. package/dist/breadcrumb/BreadcrumbItem.svelte.d.ts +14 -0
  14. package/dist/button/Button.svelte +274 -0
  15. package/dist/button/Button.svelte.d.ts +22 -0
  16. package/dist/button/ButtonGroup.svelte +98 -0
  17. package/dist/button/ButtonGroup.svelte.d.ts +12 -0
  18. package/dist/card/Card.svelte +191 -0
  19. package/dist/card/Card.svelte.d.ts +18 -0
  20. package/dist/checkbox/Checkbox.svelte +199 -0
  21. package/dist/checkbox/Checkbox.svelte.d.ts +12 -0
  22. package/dist/datepicker/DatePicker.svelte +509 -0
  23. package/dist/datepicker/DatePicker.svelte.d.ts +14 -0
  24. package/dist/divider/Divider.svelte +112 -0
  25. package/dist/divider/Divider.svelte.d.ts +13 -0
  26. package/dist/drawer/Drawer.svelte +330 -0
  27. package/dist/drawer/Drawer.svelte.d.ts +21 -0
  28. package/dist/dropzone/DropZone.svelte +282 -0
  29. package/dist/dropzone/DropZone.svelte.d.ts +17 -0
  30. package/dist/emptystate/EmptyState.svelte +169 -0
  31. package/dist/emptystate/EmptyState.svelte.d.ts +15 -0
  32. package/dist/headerbar/HeaderBar.svelte +210 -0
  33. package/dist/headerbar/HeaderBar.svelte.d.ts +17 -0
  34. package/dist/index.d.ts +44 -0
  35. package/dist/index.js +44 -0
  36. package/dist/input/Input.svelte +227 -0
  37. package/dist/input/Input.svelte.d.ts +14 -0
  38. package/dist/layout/Flex.svelte +110 -0
  39. package/dist/layout/Flex.svelte.d.ts +20 -0
  40. package/dist/layout/Grid.svelte +78 -0
  41. package/dist/layout/Grid.svelte.d.ts +19 -0
  42. package/dist/layout/Space.svelte +64 -0
  43. package/dist/layout/Space.svelte.d.ts +16 -0
  44. package/dist/layout/utils.d.ts +2 -0
  45. package/dist/layout/utils.js +19 -0
  46. package/dist/menu/Menu.svelte +156 -0
  47. package/dist/menu/Menu.svelte.d.ts +14 -0
  48. package/dist/menu/MenuDivider.svelte +19 -0
  49. package/dist/menu/MenuDivider.svelte.d.ts +6 -0
  50. package/dist/menu/MenuItem.svelte +126 -0
  51. package/dist/menu/MenuItem.svelte.d.ts +13 -0
  52. package/dist/message/InlineMessage.svelte +226 -0
  53. package/dist/message/InlineMessage.svelte.d.ts +15 -0
  54. package/dist/modal/ConfirmDialog.svelte +151 -0
  55. package/dist/modal/ConfirmDialog.svelte.d.ts +19 -0
  56. package/dist/modal/Modal.svelte +279 -0
  57. package/dist/modal/Modal.svelte.d.ts +18 -0
  58. package/dist/pagination/Pagination.svelte +258 -0
  59. package/dist/pagination/Pagination.svelte.d.ts +16 -0
  60. package/dist/progress/ProgressBar.svelte +179 -0
  61. package/dist/progress/ProgressBar.svelte.d.ts +15 -0
  62. package/dist/radio/Radio.svelte +161 -0
  63. package/dist/radio/Radio.svelte.d.ts +13 -0
  64. package/dist/searchfield/SearchField.svelte +246 -0
  65. package/dist/searchfield/SearchField.svelte.d.ts +15 -0
  66. package/dist/select/Select.svelte +392 -0
  67. package/dist/select/Select.svelte.d.ts +20 -0
  68. package/dist/sidebar/Sidebar.svelte +78 -0
  69. package/dist/sidebar/Sidebar.svelte.d.ts +11 -0
  70. package/dist/sidebar/SidebarGroup.svelte +51 -0
  71. package/dist/sidebar/SidebarGroup.svelte.d.ts +9 -0
  72. package/dist/sidebar/SidebarItem.svelte +185 -0
  73. package/dist/sidebar/SidebarItem.svelte.d.ts +16 -0
  74. package/dist/slider/Slider.svelte +204 -0
  75. package/dist/slider/Slider.svelte.d.ts +16 -0
  76. package/dist/spinbox/SpinBox.svelte +299 -0
  77. package/dist/spinbox/SpinBox.svelte.d.ts +20 -0
  78. package/dist/spinner/Spinner.svelte +130 -0
  79. package/dist/spinner/Spinner.svelte.d.ts +11 -0
  80. package/dist/style/base.css +178 -0
  81. package/dist/style/index.css +2 -0
  82. package/dist/style/token.css +230 -0
  83. package/dist/switch/Switch.svelte +199 -0
  84. package/dist/switch/Switch.svelte.d.ts +13 -0
  85. package/dist/table/Table.svelte +305 -0
  86. package/dist/table/Table.svelte.d.ts +32 -0
  87. package/dist/tabs/Tabs.svelte +216 -0
  88. package/dist/tabs/Tabs.svelte.d.ts +21 -0
  89. package/dist/textarea/TextArea.svelte +114 -0
  90. package/dist/textarea/TextArea.svelte.d.ts +14 -0
  91. package/dist/timepicker/TimePicker.svelte +452 -0
  92. package/dist/timepicker/TimePicker.svelte.d.ts +16 -0
  93. package/dist/tooltip/Tooltip.svelte +122 -0
  94. package/dist/tooltip/Tooltip.svelte.d.ts +12 -0
  95. package/package.json +66 -0
@@ -0,0 +1,305 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+ import type { HTMLTableAttributes } from "svelte/elements";
4
+
5
+ export interface TableColumn<T = any> {
6
+ key: string;
7
+ title: string;
8
+ width?: string;
9
+ align?: "left" | "center" | "right";
10
+ sortable?: boolean;
11
+ render?: Snippet<[T, number]>;
12
+ }
13
+
14
+ type TableDensity = "compact" | "default" | "spacious";
15
+
16
+ interface Props<T = any> extends HTMLTableAttributes {
17
+ columns?: TableColumn<T>[];
18
+ data?: T[];
19
+ striped?: boolean;
20
+ bordered?: boolean;
21
+ hoverable?: boolean;
22
+ density?: TableDensity;
23
+ selectedKey?: string;
24
+ selectedId?: string | number;
25
+ sortKey?: string;
26
+ sortOrder?: "asc" | "desc";
27
+ children?: Snippet;
28
+ headerSnippet?: Snippet;
29
+ rowSnippet?: Snippet<[T, number]>;
30
+ emptySnippet?: Snippet;
31
+ onrowclick?: (row: T, index: number) => void;
32
+ onsort?: (key: string, order: "asc" | "desc") => void;
33
+ }
34
+
35
+ let {
36
+ columns = [],
37
+ data = [],
38
+ striped = true,
39
+ bordered = false,
40
+ hoverable = true,
41
+ density = "default",
42
+ selectedKey = "id",
43
+ selectedId = $bindable(undefined),
44
+ sortKey = $bindable(""),
45
+ sortOrder = $bindable("asc"),
46
+ children,
47
+ headerSnippet,
48
+ rowSnippet,
49
+ emptySnippet,
50
+ onrowclick,
51
+ onsort,
52
+ class: customClass = "",
53
+ ...restProps
54
+ }: Props = $props();
55
+
56
+ function handleSort(key: string, sortable?: boolean) {
57
+ if (!sortable) return;
58
+ if (sortKey === key) {
59
+ sortOrder = sortOrder === "asc" ? "desc" : "asc";
60
+ } else {
61
+ sortKey = key;
62
+ sortOrder = "asc";
63
+ }
64
+ onsort?.(sortKey, sortOrder);
65
+ }
66
+
67
+ function handleRowClick(row: any, index: number) {
68
+ if (selectedKey && row && row[selectedKey] !== undefined) {
69
+ selectedId = row[selectedKey];
70
+ }
71
+ onrowclick?.(row, index);
72
+ }
73
+ </script>
74
+
75
+ <div
76
+ class="plasma-table-container"
77
+ class:plasma-table-container--bordered={bordered}
78
+ >
79
+ <table
80
+ class="plasma-table plasma-table--{density} {customClass}"
81
+ class:plasma-table--striped={striped}
82
+ class:plasma-table--hoverable={hoverable}
83
+ class:plasma-table--bordered={bordered}
84
+ {...restProps}
85
+ >
86
+ {#if headerSnippet}
87
+ <thead>
88
+ {@render headerSnippet()}
89
+ </thead>
90
+ {:else if columns.length > 0}
91
+ <thead>
92
+ <tr>
93
+ {#each columns as col}
94
+ <th
95
+ style="{col.width
96
+ ? `width: ${col.width};`
97
+ : ''} text-align: {col.align || 'left'};"
98
+ class:plasma-th--sortable={col.sortable}
99
+ class:plasma-th--sorted={sortKey === col.key}
100
+ onclick={() => handleSort(col.key, col.sortable)}
101
+ >
102
+ <div
103
+ class="plasma-th-content"
104
+ style="justify-content: {col.align === 'right'
105
+ ? 'flex-end'
106
+ : col.align === 'center'
107
+ ? 'center'
108
+ : 'flex-start'};"
109
+ >
110
+ <span>{col.title}</span>
111
+ {#if col.sortable}
112
+ <span class="plasma-sort-indicator">
113
+ {#if sortKey === col.key}
114
+ {sortOrder === "asc" ? "▲" : "▼"}
115
+ {:else}
116
+ <span class="plasma-sort-indicator--idle">▲</span>
117
+ {/if}
118
+ </span>
119
+ {/if}
120
+ </div>
121
+ </th>
122
+ {/each}
123
+ </tr>
124
+ </thead>
125
+ {/if}
126
+
127
+ <tbody>
128
+ {#if children}
129
+ {@render children()}
130
+ {:else if data.length > 0}
131
+ {#each data as row, idx}
132
+ {@const isSelected =
133
+ selectedId !== undefined && row[selectedKey] === selectedId}
134
+ <tr
135
+ class:plasma-tr--selected={isSelected}
136
+ onclick={() => handleRowClick(row, idx)}
137
+ >
138
+ {#if rowSnippet}
139
+ {@render rowSnippet(row, idx)}
140
+ {:else}
141
+ {#each columns as col}
142
+ <td style="text-align: {col.align || 'left'};">
143
+ {#if col.render}
144
+ {@render col.render(row, idx)}
145
+ {:else}
146
+ {row[col.key] ?? ""}
147
+ {/if}
148
+ </td>
149
+ {/each}
150
+ {/if}
151
+ </tr>
152
+ {/each}
153
+ {:else}
154
+ <tr>
155
+ <td colspan={columns.length || 1} class="plasma-table-empty">
156
+ {#if emptySnippet}
157
+ {@render emptySnippet()}
158
+ {:else}
159
+ No data available
160
+ {/if}
161
+ </td>
162
+ </tr>
163
+ {/if}
164
+ </tbody>
165
+ </table>
166
+ </div>
167
+
168
+ <style>
169
+ .plasma-table-container {
170
+ width: 100%;
171
+ overflow-x: auto;
172
+ background-color: var(--plasma-color-view-bg);
173
+ border: 1px solid var(--plasma-color-border-subtle);
174
+ border-radius: var(--plasma-radius-md);
175
+ box-sizing: border-box;
176
+ scrollbar-width: thin;
177
+ scrollbar-color: var(--plasma-color-border) transparent;
178
+ }
179
+
180
+ .plasma-table-container--bordered {
181
+ border-color: var(--plasma-color-border);
182
+ }
183
+
184
+ .plasma-table {
185
+ width: 100%;
186
+ border-collapse: collapse;
187
+ font-family: var(--plasma-font-sans);
188
+ font-size: var(--plasma-font-size-base);
189
+ color: var(--plasma-color-text);
190
+ text-align: left;
191
+ box-sizing: border-box;
192
+ }
193
+
194
+ /* --------------------------------------------------------------------------
195
+ Header Styling (QHeaderView)
196
+ -------------------------------------------------------------------------- */
197
+ .plasma-table thead {
198
+ background-color: var(--plasma-color-surface);
199
+ border-bottom: 1px solid var(--plasma-color-border);
200
+ position: sticky;
201
+ top: 0;
202
+ z-index: 2;
203
+ }
204
+
205
+ .plasma-table th {
206
+ padding: var(--plasma-space-sm) var(--plasma-space-md);
207
+ font-size: var(--plasma-font-size-sm);
208
+ font-weight: var(--plasma-font-weight-bold);
209
+ color: var(--plasma-color-text);
210
+ user-select: none;
211
+ border-bottom: 1px solid var(--plasma-color-border);
212
+ transition: var(--plasma-transition-fast);
213
+ }
214
+
215
+ .plasma-th--sortable {
216
+ cursor: pointer;
217
+ }
218
+
219
+ .plasma-th--sortable:hover {
220
+ background-color: var(--plasma-color-surface-hover);
221
+ color: var(--plasma-color-highlight);
222
+ }
223
+
224
+ .plasma-th-content {
225
+ display: inline-flex;
226
+ align-items: center;
227
+ gap: 6px;
228
+ width: 100%;
229
+ }
230
+
231
+ .plasma-sort-indicator {
232
+ font-size: 10px;
233
+ color: var(--plasma-color-highlight);
234
+ }
235
+
236
+ .plasma-sort-indicator--idle {
237
+ color: var(--plasma-color-text-muted);
238
+ opacity: 0.3;
239
+ }
240
+
241
+ /* --------------------------------------------------------------------------
242
+ Body & Cell Rows
243
+ -------------------------------------------------------------------------- */
244
+ .plasma-table td {
245
+ padding: var(--plasma-space-sm) var(--plasma-space-md);
246
+ border-bottom: 1px solid var(--plasma-color-border-subtle);
247
+ transition: var(--plasma-transition-fast);
248
+ }
249
+
250
+ /* Density */
251
+ .plasma-table--compact td,
252
+ .plasma-table--compact th {
253
+ padding: 4px var(--plasma-space-sm);
254
+ font-size: var(--plasma-font-size-xs);
255
+ }
256
+
257
+ .plasma-table--default td,
258
+ .plasma-table--default th {
259
+ padding: 8px var(--plasma-space-md);
260
+ }
261
+
262
+ .plasma-table--spacious td,
263
+ .plasma-table--spacious th {
264
+ padding: 12px var(--plasma-space-lg);
265
+ }
266
+
267
+ /* Zebra Striping */
268
+ .plasma-table--striped tbody tr:nth-child(even):not(.plasma-tr--selected) {
269
+ background-color: var(--plasma-color-surface-sunken);
270
+ }
271
+
272
+ /* Hover */
273
+ .plasma-table--hoverable tbody tr:hover:not(.plasma-tr--selected) {
274
+ background-color: var(--plasma-color-surface-hover);
275
+ }
276
+
277
+ /* KDE Active Row Selection */
278
+ .plasma-tr--selected {
279
+ position: relative;
280
+ background-color: var(--plasma-color-highlight-soft) !important;
281
+ color: var(--plasma-color-highlight);
282
+ font-weight: var(--plasma-font-weight-medium);
283
+ }
284
+
285
+ .plasma-tr--selected td:first-child {
286
+ box-shadow: inset 2px 0 0 var(--plasma-color-highlight);
287
+ }
288
+
289
+ /* Bordered table lines */
290
+ .plasma-table--bordered th,
291
+ .plasma-table--bordered td {
292
+ border-right: 1px solid var(--plasma-color-border-subtle);
293
+ }
294
+
295
+ .plasma-table--bordered th:last-child,
296
+ .plasma-table--bordered td:last-child {
297
+ border-right: none;
298
+ }
299
+
300
+ .plasma-table-empty {
301
+ text-align: center;
302
+ padding: var(--plasma-space-xl) !important;
303
+ color: var(--plasma-color-text-muted);
304
+ }
305
+ </style>
@@ -0,0 +1,32 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLTableAttributes } from "svelte/elements";
3
+ export interface TableColumn<T = any> {
4
+ key: string;
5
+ title: string;
6
+ width?: string;
7
+ align?: "left" | "center" | "right";
8
+ sortable?: boolean;
9
+ render?: Snippet<[T, number]>;
10
+ }
11
+ type TableDensity = "compact" | "default" | "spacious";
12
+ interface Props<T = any> extends HTMLTableAttributes {
13
+ columns?: TableColumn<T>[];
14
+ data?: T[];
15
+ striped?: boolean;
16
+ bordered?: boolean;
17
+ hoverable?: boolean;
18
+ density?: TableDensity;
19
+ selectedKey?: string;
20
+ selectedId?: string | number;
21
+ sortKey?: string;
22
+ sortOrder?: "asc" | "desc";
23
+ children?: Snippet;
24
+ headerSnippet?: Snippet;
25
+ rowSnippet?: Snippet<[T, number]>;
26
+ emptySnippet?: Snippet;
27
+ onrowclick?: (row: T, index: number) => void;
28
+ onsort?: (key: string, order: "asc" | "desc") => void;
29
+ }
30
+ declare const Table: import("svelte").Component<Props<any>, {}, "selectedId" | "sortKey" | "sortOrder">;
31
+ type Table = ReturnType<typeof Table>;
32
+ export default Table;
@@ -0,0 +1,216 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+
5
+ export interface TabItem {
6
+ id: string;
7
+ label: string;
8
+ badge?: string | number;
9
+ disabled?: boolean;
10
+ icon?: Snippet;
11
+ }
12
+
13
+ type TabsVariant = "line" | "pill";
14
+ type TabsSize = "sm" | "md" | "lg";
15
+
16
+ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "onchange"> {
17
+ items: TabItem[];
18
+ activeId?: string;
19
+ variant?: TabsVariant;
20
+ size?: TabsSize;
21
+ onchange?: (id: string) => void;
22
+ }
23
+
24
+
25
+ let {
26
+ items,
27
+ activeId = $bindable(items[0]?.id ?? ""),
28
+ variant = "line",
29
+ size = "md",
30
+ onchange,
31
+ class: customClass = "",
32
+ ...restProps
33
+ }: Props = $props();
34
+
35
+ function selectTab(id: string, disabled?: boolean) {
36
+ if (disabled) return;
37
+ activeId = id;
38
+ onchange?.(id);
39
+ }
40
+ </script>
41
+
42
+ <div
43
+ class="plasma-tabs plasma-tabs--{variant} plasma-tabs--{size} {customClass}"
44
+ role="tablist"
45
+ {...restProps}
46
+ >
47
+ {#each items as item}
48
+ {@const isActive = activeId === item.id}
49
+ <button
50
+ type="button"
51
+ role="tab"
52
+ aria-selected={isActive}
53
+ disabled={item.disabled}
54
+ class="plasma-tab"
55
+ class:plasma-tab--active={isActive}
56
+ class:plasma-tab--disabled={item.disabled}
57
+ onclick={() => selectTab(item.id, item.disabled)}
58
+ >
59
+ {#if item.icon}
60
+ <span class="plasma-tab-icon">
61
+ {@render item.icon()}
62
+ </span>
63
+ {/if}
64
+
65
+ <span class="plasma-tab-label">{item.label}</span>
66
+
67
+ {#if item.badge !== undefined}
68
+ <span class="plasma-tab-badge">{item.badge}</span>
69
+ {/if}
70
+
71
+ {#if variant === "line" && isActive}
72
+ <span class="plasma-tab-indicator"></span>
73
+ {/if}
74
+ </button>
75
+ {/each}
76
+ </div>
77
+
78
+ <style>
79
+ .plasma-tabs {
80
+ display: inline-flex;
81
+ align-items: center;
82
+ box-sizing: border-box;
83
+ font-family: var(--plasma-font-sans);
84
+ }
85
+
86
+ /* --------------------------------------------------------------------------
87
+ Line Variant (Classic KDE Breeze Tab Bar)
88
+ -------------------------------------------------------------------------- */
89
+ .plasma-tabs--line {
90
+ border-bottom: 1px solid var(--plasma-color-border-subtle);
91
+ gap: var(--plasma-space-xs);
92
+ width: 100%;
93
+ }
94
+
95
+ .plasma-tabs--line .plasma-tab {
96
+ position: relative;
97
+ display: inline-flex;
98
+ align-items: center;
99
+ justify-content: center;
100
+ gap: var(--plasma-space-xs);
101
+ background: transparent;
102
+ border: none;
103
+ color: var(--plasma-color-text-muted);
104
+ font-weight: var(--plasma-font-weight-medium);
105
+ cursor: pointer;
106
+ transition: var(--plasma-transition-fast);
107
+ padding: 0 var(--plasma-space-md);
108
+ }
109
+
110
+ .plasma-tabs--line .plasma-tab:hover:not(.plasma-tab--disabled) {
111
+ color: var(--plasma-color-text);
112
+ }
113
+
114
+ .plasma-tabs--line .plasma-tab--active {
115
+ color: var(--plasma-color-highlight);
116
+ }
117
+
118
+ .plasma-tabs--line .plasma-tab-indicator {
119
+ position: absolute;
120
+ bottom: -1px;
121
+ left: 0;
122
+ right: 0;
123
+ height: 2px;
124
+ background-color: var(--plasma-color-highlight);
125
+ border-radius: 1px;
126
+ }
127
+
128
+ /* --------------------------------------------------------------------------
129
+ Pill / Segmented Variant (Toolbar Switcher)
130
+ -------------------------------------------------------------------------- */
131
+ .plasma-tabs--pill {
132
+ background-color: var(--plasma-color-surface-sunken);
133
+ border: 1px solid var(--plasma-color-border-subtle);
134
+ border-radius: var(--plasma-radius-md);
135
+ padding: 2px;
136
+ gap: 2px;
137
+ }
138
+
139
+ .plasma-tabs--pill .plasma-tab {
140
+ position: relative;
141
+ display: inline-flex;
142
+ align-items: center;
143
+ justify-content: center;
144
+ gap: var(--plasma-space-xs);
145
+ background: transparent;
146
+ border: none;
147
+ border-radius: calc(var(--plasma-radius-md) - 2px);
148
+ color: var(--plasma-color-text-muted);
149
+ font-weight: var(--plasma-font-weight-medium);
150
+ cursor: pointer;
151
+ transition: var(--plasma-transition-fast);
152
+ }
153
+
154
+ .plasma-tabs--pill .plasma-tab:hover:not(.plasma-tab--disabled) {
155
+ color: var(--plasma-color-text);
156
+ background-color: var(--plasma-color-surface-hover);
157
+ }
158
+
159
+ .plasma-tabs--pill .plasma-tab--active {
160
+ background-color: var(--plasma-color-surface);
161
+ color: var(--plasma-color-text);
162
+ box-shadow: var(--plasma-shadow-xs);
163
+ }
164
+
165
+ /* --------------------------------------------------------------------------
166
+ Sizing
167
+ -------------------------------------------------------------------------- */
168
+ .plasma-tabs--sm .plasma-tab {
169
+ height: var(--plasma-control-height-sm);
170
+ font-size: var(--plasma-font-size-xs);
171
+ padding: 0 var(--plasma-space-sm);
172
+ }
173
+
174
+ .plasma-tabs--md .plasma-tab {
175
+ height: var(--plasma-control-height-md);
176
+ font-size: var(--plasma-font-size-base);
177
+ padding: 0 var(--plasma-space-md);
178
+ }
179
+
180
+ .plasma-tabs--lg .plasma-tab {
181
+ height: var(--plasma-control-height-lg);
182
+ font-size: var(--plasma-font-size-md);
183
+ padding: 0 var(--plasma-space-lg);
184
+ }
185
+
186
+ /* Disabled & Focus */
187
+ .plasma-tab--disabled {
188
+ opacity: 0.4;
189
+ cursor: not-allowed;
190
+ }
191
+
192
+ .plasma-tab:focus-visible {
193
+ outline: 2px solid var(--plasma-color-highlight);
194
+ outline-offset: 1px;
195
+ }
196
+
197
+ /* Badge */
198
+ .plasma-tab-badge {
199
+ font-size: 11px;
200
+ line-height: 1;
201
+ padding: 2px 6px;
202
+ border-radius: var(--plasma-radius-full);
203
+ background-color: var(--plasma-color-surface-sunken);
204
+ color: var(--plasma-color-text-muted);
205
+ }
206
+
207
+ .plasma-tab--active .plasma-tab-badge {
208
+ background-color: var(--plasma-color-highlight-soft);
209
+ color: var(--plasma-color-highlight);
210
+ }
211
+
212
+ .plasma-tab-icon {
213
+ display: inline-flex;
214
+ align-items: center;
215
+ }
216
+ </style>
@@ -0,0 +1,21 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ export interface TabItem {
4
+ id: string;
5
+ label: string;
6
+ badge?: string | number;
7
+ disabled?: boolean;
8
+ icon?: Snippet;
9
+ }
10
+ type TabsVariant = "line" | "pill";
11
+ type TabsSize = "sm" | "md" | "lg";
12
+ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "onchange"> {
13
+ items: TabItem[];
14
+ activeId?: string;
15
+ variant?: TabsVariant;
16
+ size?: TabsSize;
17
+ onchange?: (id: string) => void;
18
+ }
19
+ declare const Tabs: import("svelte").Component<Props, {}, "activeId">;
20
+ type Tabs = ReturnType<typeof Tabs>;
21
+ export default Tabs;
@@ -0,0 +1,114 @@
1
+ <script lang="ts">
2
+ import type { HTMLTextareaAttributes } from "svelte/elements";
3
+
4
+ type TextAreaResize = "none" | "vertical" | "horizontal" | "both";
5
+
6
+ interface Props extends HTMLTextareaAttributes {
7
+ value?: string;
8
+ placeholder?: string;
9
+ rows?: number;
10
+ resize?: TextAreaResize;
11
+ disabled?: boolean;
12
+ readonly?: boolean;
13
+ invalid?: boolean;
14
+ }
15
+
16
+ let {
17
+ value = $bindable(""),
18
+ placeholder = "",
19
+ rows = 4,
20
+ resize = "vertical",
21
+ disabled = false,
22
+ readonly = false,
23
+ invalid = false,
24
+ class: customClass = "",
25
+ id,
26
+ ...restProps
27
+ }: Props = $props();
28
+ </script>
29
+
30
+ <div
31
+ class="plasma-textarea-container {customClass}"
32
+ class:plasma-textarea--disabled={disabled}
33
+ class:plasma-textarea--readonly={readonly}
34
+ class:plasma-textarea--invalid={invalid}
35
+ >
36
+ <textarea
37
+ {id}
38
+ bind:value
39
+ {placeholder}
40
+ {rows}
41
+ {disabled}
42
+ {readonly}
43
+ style="resize: {resize};"
44
+ class="plasma-textarea-field"
45
+ {...restProps}
46
+ ></textarea>
47
+ </div>
48
+
49
+ <style>
50
+ .plasma-textarea-container {
51
+ position: relative;
52
+ display: inline-flex;
53
+ width: 100%;
54
+ box-sizing: border-box;
55
+ font-family: var(--plasma-font-sans);
56
+ background-color: var(--plasma-color-view-bg);
57
+ border: 1px solid var(--plasma-color-border);
58
+ border-radius: var(--plasma-radius-md);
59
+ color: var(--plasma-color-text);
60
+ transition: var(--plasma-transition-fast);
61
+ }
62
+
63
+ .plasma-textarea-container:hover:not(.plasma-textarea--disabled):not(:focus-within) {
64
+ border-color: var(--plasma-color-border-hover);
65
+ }
66
+
67
+ .plasma-textarea-container:focus-within:not(.plasma-textarea--disabled) {
68
+ border-color: var(--plasma-color-highlight);
69
+ box-shadow: var(--plasma-shadow-focus);
70
+ }
71
+
72
+ .plasma-textarea--invalid {
73
+ border-color: var(--plasma-color-negative);
74
+ }
75
+
76
+ .plasma-textarea--invalid:focus-within {
77
+ box-shadow: 0 0 0 2px rgba(218, 68, 83, 0.35);
78
+ }
79
+
80
+ .plasma-textarea--disabled {
81
+ opacity: 0.45;
82
+ cursor: not-allowed;
83
+ background-color: var(--plasma-color-surface-sunken);
84
+ }
85
+
86
+ .plasma-textarea--disabled .plasma-textarea-field {
87
+ cursor: not-allowed;
88
+ }
89
+
90
+ .plasma-textarea--readonly {
91
+ background-color: var(--plasma-color-surface-sunken);
92
+ }
93
+
94
+ .plasma-textarea-field {
95
+ width: 100%;
96
+ min-height: 80px;
97
+ padding: var(--plasma-space-sm) var(--plasma-space-md);
98
+ border: none;
99
+ outline: none;
100
+ background: transparent;
101
+ color: inherit;
102
+ font-family: inherit;
103
+ font-size: var(--plasma-font-size-base);
104
+ line-height: var(--plasma-line-height-base);
105
+ box-sizing: border-box;
106
+ scrollbar-width: thin;
107
+ scrollbar-color: var(--plasma-color-border) transparent;
108
+ }
109
+
110
+ .plasma-textarea-field::placeholder {
111
+ color: var(--plasma-color-text-muted);
112
+ opacity: 0.75;
113
+ }
114
+ </style>
@@ -0,0 +1,14 @@
1
+ import type { HTMLTextareaAttributes } from "svelte/elements";
2
+ type TextAreaResize = "none" | "vertical" | "horizontal" | "both";
3
+ interface Props extends HTMLTextareaAttributes {
4
+ value?: string;
5
+ placeholder?: string;
6
+ rows?: number;
7
+ resize?: TextAreaResize;
8
+ disabled?: boolean;
9
+ readonly?: boolean;
10
+ invalid?: boolean;
11
+ }
12
+ declare const TextArea: import("svelte").Component<Props, {}, "value">;
13
+ type TextArea = ReturnType<typeof TextArea>;
14
+ export default TextArea;