@makolabs/ripple 0.0.1-dev.9 → 0.0.3

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 (78) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/storage/BaseAdapter.d.ts +20 -0
  3. package/dist/adapters/storage/BaseAdapter.js +171 -0
  4. package/dist/adapters/storage/S3Adapter.d.ts +21 -0
  5. package/dist/adapters/storage/S3Adapter.js +194 -0
  6. package/dist/adapters/storage/index.d.ts +3 -0
  7. package/dist/adapters/storage/index.js +3 -0
  8. package/dist/adapters/storage/types.d.ts +102 -0
  9. package/dist/adapters/storage/types.js +4 -0
  10. package/dist/charts/Chart.svelte +59 -47
  11. package/dist/charts/Chart.svelte.d.ts +1 -1
  12. package/dist/drawer/drawer.js +3 -3
  13. package/dist/elements/accordion/Accordion.svelte +98 -0
  14. package/dist/elements/accordion/Accordion.svelte.d.ts +4 -0
  15. package/dist/elements/accordion/accordion.d.ts +227 -0
  16. package/dist/elements/accordion/accordion.js +138 -0
  17. package/dist/elements/alert/Alert.svelte +7 -3
  18. package/dist/elements/dropdown/Dropdown.svelte +74 -107
  19. package/dist/elements/dropdown/Select.svelte +81 -62
  20. package/dist/elements/dropdown/dropdown.js +1 -1
  21. package/dist/elements/dropdown/select.js +8 -8
  22. package/dist/elements/file-upload/FileUpload.svelte +17 -95
  23. package/dist/elements/file-upload/FilesPreview.svelte +93 -0
  24. package/dist/elements/file-upload/FilesPreview.svelte.d.ts +4 -0
  25. package/dist/elements/progress/Progress.svelte +83 -25
  26. package/dist/file-browser/FileBrowser.svelte +877 -0
  27. package/dist/file-browser/FileBrowser.svelte.d.ts +14 -0
  28. package/dist/file-browser/index.d.ts +1 -0
  29. package/dist/file-browser/index.js +1 -0
  30. package/dist/filters/CompactFilters.svelte +147 -0
  31. package/dist/filters/CompactFilters.svelte.d.ts +4 -0
  32. package/dist/filters/index.d.ts +1 -0
  33. package/dist/filters/index.js +1 -0
  34. package/dist/forms/Checkbox.svelte +2 -2
  35. package/dist/forms/DateRange.svelte +21 -21
  36. package/dist/forms/Input.svelte +3 -3
  37. package/dist/forms/NumberInput.svelte +1 -1
  38. package/dist/forms/RadioInputs.svelte +3 -3
  39. package/dist/forms/Tags.svelte +5 -5
  40. package/dist/forms/Toggle.svelte +3 -3
  41. package/dist/forms/slider.js +4 -4
  42. package/dist/header/PageHeader.svelte +49 -11
  43. package/dist/index.d.ts +256 -143
  44. package/dist/index.js +19 -2
  45. package/dist/layout/card/MetricCard.svelte +64 -0
  46. package/dist/layout/card/MetricCard.svelte.d.ts +4 -0
  47. package/dist/layout/card/StatsCard.svelte +4 -3
  48. package/dist/layout/card/StatsCard.svelte.d.ts +1 -1
  49. package/dist/layout/card/metric-card.d.ts +49 -0
  50. package/dist/layout/card/metric-card.js +10 -0
  51. package/dist/layout/card/stats-card.d.ts +0 -15
  52. package/dist/layout/card/stats-card.js +1 -1
  53. package/dist/layout/sidebar/NavGroup.svelte +1 -7
  54. package/dist/layout/sidebar/NavItem.svelte +2 -2
  55. package/dist/layout/sidebar/Sidebar.svelte +103 -49
  56. package/dist/layout/table/Table.svelte +465 -88
  57. package/dist/layout/table/Table.svelte.d.ts +1 -1
  58. package/dist/layout/table/table.d.ts +0 -47
  59. package/dist/layout/table/table.js +0 -8
  60. package/dist/layout/tabs/Tab.svelte +9 -6
  61. package/dist/layout/tabs/Tab.svelte.d.ts +1 -1
  62. package/dist/layout/tabs/TabContent.svelte +1 -2
  63. package/dist/layout/tabs/TabContent.svelte.d.ts +1 -1
  64. package/dist/layout/tabs/TabGroup.svelte +10 -5
  65. package/dist/layout/tabs/TabGroup.svelte.d.ts +2 -2
  66. package/dist/layout/tabs/tabs.d.ts +61 -76
  67. package/dist/layout/tabs/tabs.js +170 -28
  68. package/dist/modal/Modal.svelte +3 -3
  69. package/dist/modal/modal.js +3 -3
  70. package/dist/utils/Portal.svelte +108 -0
  71. package/dist/utils/Portal.svelte.d.ts +8 -0
  72. package/dist/utils/dateUtils.d.ts +7 -0
  73. package/dist/utils/dateUtils.js +26 -0
  74. package/dist/variants.d.ts +11 -1
  75. package/dist/variants.js +17 -0
  76. package/package.json +4 -3
  77. package/dist/header/pageheaders.d.ts +0 -10
  78. package/dist/header/pageheaders.js +0 -1
@@ -0,0 +1,14 @@
1
+ import type { StorageAdapter, FileAction } from '../adapters/storage/index.js';
2
+ type $$ComponentProps = {
3
+ adapter: StorageAdapter;
4
+ startPath?: string;
5
+ actions?: FileAction[];
6
+ selectedFiles?: string[];
7
+ infoSection?: (props: {
8
+ selectedFiles: string[];
9
+ navToFileFolder: (fileKey: string) => void;
10
+ }) => any;
11
+ };
12
+ declare const FileBrowser: import("svelte").Component<$$ComponentProps, {}, "selectedFiles">;
13
+ type FileBrowser = ReturnType<typeof FileBrowser>;
14
+ export default FileBrowser;
@@ -0,0 +1 @@
1
+ export { default as FileBrowser } from './FileBrowser.svelte';
@@ -0,0 +1 @@
1
+ export { default as FileBrowser } from './FileBrowser.svelte';
@@ -0,0 +1,147 @@
1
+ <script lang="ts">
2
+ import { cn } from '../helper/cls.js';
3
+ import type { FilterTab, CompactFiltersProps } from '../index.js';
4
+
5
+ // Props definition
6
+ let {
7
+ filterGroups = [],
8
+ isExpanded = $bindable(false),
9
+ title = 'Filters',
10
+ class: className,
11
+ summaryClass,
12
+ expandedClass,
13
+ FilterIcon
14
+ }: CompactFiltersProps = $props();
15
+
16
+ // Toggle expanded state
17
+ function toggleExpanded() {
18
+ isExpanded = !isExpanded;
19
+ }
20
+
21
+ // Helper to get the label of the selected filter
22
+ function getSelectedLabel(tabs: FilterTab[], selectedValue: string): string {
23
+ const tab = tabs.find((tab) => tab.value === selectedValue);
24
+ return tab ? tab.label : 'All';
25
+ }
26
+ </script>
27
+
28
+ {#snippet DefaultFilterIcon()}
29
+ <svg
30
+ width="16"
31
+ height="16"
32
+ viewBox="0 0 24 24"
33
+ fill="none"
34
+ stroke="currentColor"
35
+ stroke-width="2"
36
+ stroke-linecap="round"
37
+ stroke-linejoin="round"
38
+ >
39
+ <polygon points="22,3 2,3 10,12.46 10,19 14,21 14,12.46"></polygon>
40
+ </svg>
41
+ {/snippet}
42
+
43
+ {#snippet DefaultChevronDown()}
44
+ <svg
45
+ width="18"
46
+ height="18"
47
+ viewBox="0 0 24 24"
48
+ fill="none"
49
+ stroke="currentColor"
50
+ stroke-width="2"
51
+ stroke-linecap="round"
52
+ stroke-linejoin="round"
53
+ >
54
+ <polyline points="6,9 12,15 18,9"></polyline>
55
+ </svg>
56
+ {/snippet}
57
+
58
+ {#snippet DefaultChevronUp()}
59
+ <svg
60
+ width="18"
61
+ height="18"
62
+ viewBox="0 0 24 24"
63
+ fill="none"
64
+ stroke="currentColor"
65
+ stroke-width="2"
66
+ stroke-linecap="round"
67
+ stroke-linejoin="round"
68
+ >
69
+ <polyline points="18,15 12,9 6,15"></polyline>
70
+ </svg>
71
+ {/snippet}
72
+
73
+ <div class={cn('rounded-lg border border-gray-200 bg-white p-3 shadow-sm', className)}>
74
+ <button
75
+ onclick={toggleExpanded}
76
+ class="mb-2 flex min-w-full cursor-pointer items-center justify-between"
77
+ >
78
+ <div class="flex items-center gap-2">
79
+ {#if FilterIcon}
80
+ <FilterIcon size={16} class="text-gray-500" />
81
+ {:else}
82
+ <span class="text-gray-500">
83
+ {@render DefaultFilterIcon()}
84
+ </span>
85
+ {/if}
86
+ <span class="text-sm font-medium">{title}</span>
87
+ </div>
88
+ <div
89
+ class="rounded-md p-1 text-gray-500 hover:bg-gray-100 hover:text-gray-700"
90
+ aria-label={isExpanded ? `Collapse ${title.toLowerCase()}` : `Expand ${title.toLowerCase()}`}
91
+ >
92
+ {#if isExpanded}
93
+ <span>{@render DefaultChevronUp()}</span>
94
+ {:else}
95
+ <span>{@render DefaultChevronDown()}</span>
96
+ {/if}
97
+ </div>
98
+ </button>
99
+
100
+ {#if !isExpanded}
101
+ <!-- Summary of selected filters when collapsed -->
102
+ <div class={cn('flex flex-wrap gap-2', summaryClass)}>
103
+ {#each filterGroups as group}
104
+ {#if group.tabs.length > 0}
105
+ <div
106
+ class="bg-primary-50 text-primary-700 border-primary-200 flex items-center gap-1 rounded-full border px-3 py-1 text-xs"
107
+ >
108
+ <span class="font-medium">{group.label}:</span>
109
+ {getSelectedLabel(group.tabs, group.selectedValue)}
110
+ </div>
111
+ {/if}
112
+ {/each}
113
+ </div>
114
+ {:else}
115
+ <div class={cn('flex flex-col gap-2', expandedClass)}>
116
+ {#each filterGroups as group, index}
117
+ {#if group.tabs.length > 0}
118
+ <div
119
+ class={cn(
120
+ 'flex items-center gap-2 pb-2',
121
+ index > 0 ? 'border-t border-gray-100 pt-2' : ''
122
+ )}
123
+ >
124
+ <div class={cn('text-xs font-medium text-gray-500', group.minWidth || 'min-w-[70px]')}>
125
+ {group.label}
126
+ </div>
127
+ <div class="flex flex-wrap gap-2">
128
+ {#each group.tabs as tab}
129
+ <button
130
+ onclick={() => group.onChange(tab.value)}
131
+ class={cn(
132
+ 'rounded-full border px-3 py-1 text-xs font-medium whitespace-nowrap',
133
+ group.selectedValue === tab.value
134
+ ? 'bg-primary-50 text-primary-700 border-primary-200'
135
+ : 'border-gray-200 text-gray-700 hover:bg-gray-50'
136
+ )}
137
+ >
138
+ {tab.label}
139
+ </button>
140
+ {/each}
141
+ </div>
142
+ </div>
143
+ {/if}
144
+ {/each}
145
+ </div>
146
+ {/if}
147
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { CompactFiltersProps } from '../index.js';
2
+ declare const CompactFilters: import("svelte").Component<CompactFiltersProps, {}, "isExpanded">;
3
+ type CompactFilters = ReturnType<typeof CompactFilters>;
4
+ export default CompactFilters;
@@ -0,0 +1 @@
1
+ export { default as CompactFilters } from './CompactFilters.svelte';
@@ -0,0 +1 @@
1
+ export { default as CompactFilters } from './CompactFilters.svelte';
@@ -13,7 +13,7 @@
13
13
  }: CheckboxProps = $props();
14
14
 
15
15
  const checkboxClass = $derived(
16
- cn('w-4 h-4 rounded text-primary-600 border-gray-300 focus:ring-primary-500', {
16
+ cn('w-4 h-4 rounded text-primary-600 border-default-300 focus:ring-primary-500', {
17
17
  'opacity-50 cursor-not-allowed': disabled,
18
18
  'accent-danger-500': errors.length
19
19
  })
@@ -21,7 +21,7 @@
21
21
 
22
22
  const labelClass = $derived(
23
23
  cn('text-sm font-medium', {
24
- 'text-gray-700': !errors.length,
24
+ 'text-default-700': !errors.length,
25
25
  'text-danger-600': errors.length
26
26
  })
27
27
  );
@@ -245,24 +245,24 @@
245
245
  {id}
246
246
  type="button"
247
247
  class={cn(
248
- 'flex w-full items-center justify-between rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm',
248
+ 'flex w-full items-center justify-between rounded-md border border-default-300 bg-white px-3 py-2 text-sm shadow-sm',
249
249
  disabled
250
- ? 'cursor-not-allowed bg-gray-100 text-gray-400'
251
- : 'focus:border-primary-500 focus:ring-primary-500 hover:border-gray-400 focus:ring-2'
250
+ ? 'cursor-not-allowed bg-default-100 text-default-400'
251
+ : 'focus:border-primary-500 focus:ring-primary-500 hover:border-default-400 focus:ring-2'
252
252
  )}
253
253
  onclick={toggleDatepicker}
254
254
  aria-haspopup="true"
255
255
  aria-expanded={isOpen}
256
256
  {disabled}
257
257
  >
258
- <span class={startDate && endDate ? 'text-gray-900' : 'text-gray-500'}>
258
+ <span class={startDate && endDate ? 'text-default-900' : 'text-default-500'}>
259
259
  {startDate && endDate
260
260
  ? `${formatDate(startDate)} - ${formatDate(endDate)}`
261
261
  : startDate
262
262
  ? `${formatDate(startDate)} - Select end date`
263
263
  : placeholder}
264
264
  </span>
265
- <svg class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
265
+ <svg class="h-5 w-5 text-default-400" viewBox="0 0 20 20" fill="currentColor">
266
266
  <path
267
267
  fill-rule="evenodd"
268
268
  d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z"
@@ -274,7 +274,7 @@
274
274
  {#if startDate || endDate}
275
275
  <button
276
276
  type="button"
277
- class="absolute top-1/2 right-10 -translate-y-1/2 text-gray-400 hover:text-gray-500"
277
+ class="absolute top-1/2 right-10 -translate-y-1/2 text-default-400 hover:text-default-500"
278
278
  onclick={clearDates}
279
279
  aria-label="Clear dates"
280
280
  >
@@ -298,7 +298,7 @@
298
298
  <button
299
299
  type="button"
300
300
  aria-label="Previous month"
301
- class="inline-flex items-center rounded-md p-1 text-sm text-gray-500 hover:bg-gray-100"
301
+ class="inline-flex items-center rounded-md p-1 text-sm text-default-500 hover:bg-default-100"
302
302
  onclick={prevMonth}
303
303
  >
304
304
  <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
@@ -311,7 +311,7 @@
311
311
  </button>
312
312
  <button
313
313
  type="button"
314
- class="inline-flex items-center rounded-md px-2 py-1 text-sm font-medium text-gray-700 hover:bg-gray-100"
314
+ class="inline-flex items-center rounded-md px-2 py-1 text-sm font-medium text-default-700 hover:bg-default-100"
315
315
  onclick={showMonths}
316
316
  >
317
317
  {getMonthName(viewDate.getMonth())}
@@ -320,7 +320,7 @@
320
320
  <button
321
321
  type="button"
322
322
  aria-label="Next month"
323
- class="inline-flex items-center rounded-md p-1 text-sm text-gray-500 hover:bg-gray-100"
323
+ class="inline-flex items-center rounded-md p-1 text-sm text-default-500 hover:bg-default-100"
324
324
  onclick={nextMonth}
325
325
  >
326
326
  <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
@@ -335,7 +335,7 @@
335
335
  <button
336
336
  type="button"
337
337
  aria-label="Previous year"
338
- class="inline-flex items-center rounded-md p-1 text-sm text-gray-500 hover:bg-gray-100"
338
+ class="inline-flex items-center rounded-md p-1 text-sm text-default-500 hover:bg-default-100"
339
339
  onclick={() =>
340
340
  (viewDate = new Date(viewDate.getFullYear() - 1, viewDate.getMonth(), 1))}
341
341
  >
@@ -350,7 +350,7 @@
350
350
  <button
351
351
  type="button"
352
352
  aria-label="Current year"
353
- class="inline-flex items-center rounded-md px-2 py-1 text-sm font-medium text-gray-700"
353
+ class="inline-flex items-center rounded-md px-2 py-1 text-sm font-medium text-default-700"
354
354
  onclick={showYears}
355
355
  >
356
356
  {viewDate.getFullYear()}
@@ -358,7 +358,7 @@
358
358
  <button
359
359
  type="button"
360
360
  aria-label="Next year"
361
- class="inline-flex items-center rounded-md p-1 text-sm text-gray-500 hover:bg-gray-100"
361
+ class="inline-flex items-center rounded-md p-1 text-sm text-default-500 hover:bg-default-100"
362
362
  onclick={() =>
363
363
  (viewDate = new Date(viewDate.getFullYear() + 1, viewDate.getMonth(), 1))}
364
364
  >
@@ -374,7 +374,7 @@
374
374
  <button
375
375
  type="button"
376
376
  aria-label="Previous year"
377
- class="inline-flex items-center rounded-md p-1 text-sm text-gray-500 hover:bg-gray-100"
377
+ class="inline-flex items-center rounded-md p-1 text-sm text-default-500 hover:bg-default-100"
378
378
  onclick={() =>
379
379
  (viewDate = new Date(viewDate.getFullYear() - 12, viewDate.getMonth(), 1))}
380
380
  >
@@ -389,14 +389,14 @@
389
389
  <button
390
390
  type="button"
391
391
  aria-label="Current year range"
392
- class="inline-flex items-center rounded-md px-2 py-1 text-sm font-medium text-gray-700"
392
+ class="inline-flex items-center rounded-md px-2 py-1 text-sm font-medium text-default-700"
393
393
  >
394
394
  {viewDate.getFullYear() - 6} - {viewDate.getFullYear() + 5}
395
395
  </button>
396
396
  <button
397
397
  type="button"
398
398
  aria-label="Next year"
399
- class="inline-flex items-center rounded-md p-1 text-sm text-gray-500 hover:bg-gray-100"
399
+ class="inline-flex items-center rounded-md p-1 text-sm text-default-500 hover:bg-default-100"
400
400
  onclick={() =>
401
401
  (viewDate = new Date(viewDate.getFullYear() + 12, viewDate.getMonth(), 1))}
402
402
  >
@@ -412,7 +412,7 @@
412
412
  </div>
413
413
 
414
414
  {#if viewMode === 'days'}
415
- <div class="mb-1 grid grid-cols-7 gap-1 text-center text-xs font-medium text-gray-500">
415
+ <div class="mb-1 grid grid-cols-7 gap-1 text-center text-xs font-medium text-default-500">
416
416
  <div>Su</div>
417
417
  <div>Mo</div>
418
418
  <div>Tu</div>
@@ -427,10 +427,10 @@
427
427
  type="button"
428
428
  class={cn(
429
429
  'flex h-8 w-8 items-center justify-center rounded-full text-sm font-medium',
430
- isDisabled ? 'cursor-not-allowed text-gray-300' : 'hover:bg-gray-100',
430
+ isDisabled ? 'cursor-not-allowed text-default-300' : 'hover:bg-default-100',
431
431
  isSelected ? 'bg-primary-500 hover:bg-primary-600 text-white' : '',
432
432
  isInRange && !isSelected ? 'bg-primary-100 text-primary-800' : '',
433
- !isCurrentMonth && !isSelected && !isInRange ? 'text-gray-400' : '',
433
+ !isCurrentMonth && !isSelected && !isInRange ? 'text-default-400' : '',
434
434
  isToday && !isSelected ? 'border-primary-500 border' : ''
435
435
  )}
436
436
  onclick={() => handleDateClick(date)}
@@ -450,7 +450,7 @@
450
450
  'flex items-center justify-center rounded-md px-2 py-1 text-sm font-medium',
451
451
  viewDate.getMonth() === month
452
452
  ? 'bg-primary-500 text-white'
453
- : 'text-gray-700 hover:bg-gray-100'
453
+ : 'text-default-700 hover:bg-default-100'
454
454
  )}
455
455
  onclick={() => selectMonth(month)}
456
456
  >
@@ -468,7 +468,7 @@
468
468
  'flex items-center justify-center rounded-md px-2 py-1 text-sm font-medium',
469
469
  viewDate.getFullYear() === year
470
470
  ? 'bg-primary-500 text-white'
471
- : 'text-gray-700 hover:bg-gray-100'
471
+ : 'text-default-700 hover:bg-default-100'
472
472
  )}
473
473
  onclick={() => selectYear(year)}
474
474
  >
@@ -479,7 +479,7 @@
479
479
  {/if}
480
480
 
481
481
  {#if startDate || endDate}
482
- <div class="mt-4 flex justify-between border-t border-gray-200 pt-3 text-xs text-gray-500">
482
+ <div class="mt-4 flex justify-between border-t border-default-200 pt-3 text-xs text-default-500">
483
483
  <div>
484
484
  {startDate ? `${startLabel}: ${formatDate(startDate)}` : ''}
485
485
  </div>
@@ -22,7 +22,7 @@
22
22
  cn(
23
23
  'transition-colors',
24
24
  {
25
- 'border rounded-lg shadow-sm w-full bg-white px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-offset-2':
25
+ 'border rounded-lg shadow-xs w-full bg-white px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-offset-2':
26
26
  BASIC_TYPES.includes(type),
27
27
  'w-full bg-white px-3 py-2 text-sm resize-y min-h-[100px]': type === 'textarea',
28
28
  'border-red-300 focus:border-red-500 focus:ring-red-500': errors.length,
@@ -34,7 +34,7 @@
34
34
  'h-12 text-lg': size === Size.LG
35
35
  }
36
36
  : {}),
37
- 'border-gray-300 focus:border-primary-500 focus:ring-primary-500': !errors.length
37
+ 'border-default-300 focus:border-primary-500 focus:ring-primary-500': !errors.length
38
38
  },
39
39
  className
40
40
  )
@@ -76,7 +76,7 @@
76
76
  class={cn(
77
77
  'block w-full text-sm font-medium',
78
78
  {
79
- 'text-gray-700': !errors.length,
79
+ 'text-default-700': !errors.length,
80
80
  'text-red-600': errors.length
81
81
  },
82
82
  extraClass
@@ -79,7 +79,7 @@
79
79
 
80
80
  <div class="space-y-1">
81
81
  {#if label}
82
- <label for={name} class="block text-sm font-medium text-gray-700">{label}</label>
82
+ <label for={name} class="block text-sm font-medium text-default-700">{label}</label>
83
83
  {/if}
84
84
  <div class={containerClass} bind:this={containerRef}>
85
85
  <svg
@@ -16,7 +16,7 @@
16
16
  const containerClass = $derived(cn('space-y-2', className));
17
17
 
18
18
  const radioClass = $derived(
19
- cn('w-4 h-4 text-primary-600 border-gray-300 focus:ring-primary-500', {
19
+ cn('w-4 h-4 text-primary-600 border-default-300 focus:ring-primary-500', {
20
20
  'opacity-50 cursor-not-allowed': disabled,
21
21
  'border-red-300 focus:ring-red-500': errors.length
22
22
  })
@@ -24,7 +24,7 @@
24
24
 
25
25
  const labelClass = $derived(
26
26
  cn('block text-sm font-medium', {
27
- 'text-gray-700': !errors.length,
27
+ 'text-default-700': !errors.length,
28
28
  'text-red-600': errors.length
29
29
  })
30
30
  );
@@ -48,7 +48,7 @@
48
48
  {required}
49
49
  aria-describedby={errors.length ? `${name}-errors` : undefined}
50
50
  />
51
- <label for={`${name}-${option.value}`} class="text-sm text-gray-700">
51
+ <label for={`${name}-${option.value}`} class="text-sm text-default-700">
52
52
  {option.label}
53
53
  </label>
54
54
  </div>
@@ -106,7 +106,7 @@
106
106
  const containerClass = $derived(
107
107
  cn(
108
108
  'relative flex flex-wrap gap-2 rounded-lg border bg-white shadow-sm px-3 py-2',
109
- 'border-gray-300 focus-within:border-primary-500 focus-within:ring-2 focus-within:ring-primary-500 focus-within:ring-offset-2',
109
+ 'border-default-300 focus-within:border-primary-500 focus-within:ring-2 focus-within:ring-primary-500 focus-within:ring-offset-2',
110
110
  {
111
111
  'border-red-300 focus-within:border-red-500 focus-within:ring-red-500': errors?.length
112
112
  },
@@ -116,21 +116,21 @@
116
116
 
117
117
  const suggestionClass = $derived(
118
118
  cn(
119
- 'absolute top-[calc(100%+8px)] right-0 left-0 z-50 max-h-[200px] overflow-auto rounded-lg border border-gray-300 bg-white shadow-lg'
119
+ 'absolute top-[calc(100%+8px)] right-0 left-0 z-50 max-h-[200px] overflow-auto rounded-lg border border-default-300 bg-white shadow-lg'
120
120
  )
121
121
  );
122
122
 
123
123
  const suggestionItemClass = $derived((isHighlighted: boolean) =>
124
124
  cn(
125
125
  'flex w-full cursor-pointer items-center px-3 py-2 text-sm transition-colors',
126
- isHighlighted && 'bg-gray-50'
126
+ isHighlighted && 'bg-default-50'
127
127
  )
128
128
  );
129
129
  </script>
130
130
 
131
131
  <div class="space-y-1">
132
132
  {#if label}
133
- <label for={name} class="block text-sm font-medium text-gray-700">{label}</label>
133
+ <label for={name} class="block text-sm font-medium text-default-700">{label}</label>
134
134
  {/if}
135
135
  <div class={containerClass} onfocusout={handleFocusOut}>
136
136
  {#each value as tag}
@@ -144,7 +144,7 @@
144
144
  {name}
145
145
  id={name}
146
146
  {placeholder}
147
- class={cn('min-w-[120px] flex-1 bg-transparent outline-none placeholder:text-gray-400', {
147
+ class={cn('min-w-[120px] flex-1 bg-transparent outline-none placeholder:text-default-400', {
148
148
  'text-sm': size === Size.SM,
149
149
  'text-base': size === Size.BASE,
150
150
  'text-lg': size === Size.LG
@@ -13,7 +13,7 @@
13
13
  color = Color.PRIMARY,
14
14
  value = $bindable(false),
15
15
  errors = [],
16
- offColor = 'bg-gray-200',
16
+ offColor = 'bg-default-200',
17
17
  onColor,
18
18
  ...restProps
19
19
  }: ToggleProps = $props();
@@ -27,7 +27,7 @@
27
27
  [Color.DANGER]: 'bg-red-500',
28
28
  [Color.WARNING]: 'bg-yellow-500',
29
29
  [Color.INFO]: 'bg-blue-500',
30
- [Color.DEFAULT]: 'bg-gray-800'
30
+ [Color.DEFAULT]: 'bg-default-800'
31
31
  }[color]
32
32
  );
33
33
 
@@ -80,7 +80,7 @@
80
80
 
81
81
  const labelClasses = $derived(
82
82
  cn('text-sm font-medium', {
83
- 'text-gray-700': !errors.length,
83
+ 'text-default-700': !errors.length,
84
84
  'text-red-600': errors.length,
85
85
  'opacity-50': disabled
86
86
  })
@@ -3,16 +3,16 @@ import { Color, Size } from '../variants.js';
3
3
  export const slider = tv({
4
4
  slots: {
5
5
  base: 'relative w-full',
6
- track: 'absolute h-2 w-full rounded-full bg-gray-200 cursor-pointer',
6
+ track: 'absolute h-2 w-full rounded-full bg-default-200 cursor-pointer',
7
7
  range: 'absolute h-full rounded-full bg-primary-500',
8
8
  thumb: [
9
9
  'absolute top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-white border-2 border-primary-500',
10
10
  'focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2',
11
11
  'hover:scale-110 transition-transform cursor-pointer'
12
12
  ],
13
- mark: 'absolute text-sm text-gray-500 -translate-x-1/2',
14
- label: 'mb-2 block text-sm font-medium text-gray-700',
15
- value: 'mt-1 text-sm text-gray-500'
13
+ mark: 'absolute text-sm text-default-500 -translate-x-1/2',
14
+ label: 'mb-2 block text-sm font-medium text-default-700',
15
+ value: 'mt-1 text-sm text-default-500'
16
16
  },
17
17
  variants: {
18
18
  size: {
@@ -5,26 +5,64 @@
5
5
 
6
6
  let {
7
7
  title,
8
+ subtitle,
8
9
  breadcrumbs = [],
9
10
  children,
10
11
  class: className = '',
11
- titleclass: titleClassName = ''
12
+ titleclass: titleClassName = '',
13
+ layout = 'vertical'
12
14
  }: PageHeaderProps = $props();
13
15
 
14
16
  const defaultTitleClasses =
15
- 'font-bold text-default-900 sm:tracking-tight sm:truncate text-2xl/7 sm:text-3xl mt-1';
16
- const headerClasses = $derived(cn('space-y-3', className));
17
+ 'font-bold text-default-900 sm:tracking-tight sm:truncate text-2xl/7 sm:text-3xl';
18
+
17
19
  const hasBreadcrumbs = $derived(breadcrumbs && breadcrumbs.length > 0);
18
20
  const titleClasses = $derived(cn(defaultTitleClasses, titleClassName));
19
21
  </script>
20
22
 
21
- <div class={headerClasses}>
22
- <div class="flex-1 min-w-0">
23
- {#if hasBreadcrumbs}
24
- <Breadcrumbs items={breadcrumbs} />
25
- {/if}
26
- <h2 class={titleClasses}>{title}</h2>
27
- </div>
23
+ <div class="pb-4">
24
+ {#if layout === 'horizontal'}
25
+ <div
26
+ class="flex flex-col space-y-3 md:flex-row md:items-start md:justify-between md:space-y-0 {className}"
27
+ >
28
+ <!-- Title and subtitle grouped together as one unit -->
29
+ <div class="min-w-0 flex-1 gap-4">
30
+ {#if hasBreadcrumbs}
31
+ <Breadcrumbs items={breadcrumbs} />
32
+ {/if}
33
+ <h2 class={titleClasses}>{title}</h2>
34
+ {#if subtitle}
35
+ <p class="text-default-500 mt-2 text-sm">{subtitle}</p>
36
+ {/if}
37
+ </div>
38
+
39
+ <!-- Actions area - responsive positioning -->
40
+ {#if children}
41
+ <div class="flex-shrink-0 md:ml-6">
42
+ {@render children()}
43
+ </div>
44
+ {/if}
45
+ </div>
46
+ {:else}
47
+ <!-- Vertical layout - title/subtitle unit first, children unit below -->
48
+ <div class={className}>
49
+ <!-- Title and subtitle grouped together -->
50
+ <div class="min-w-0 gap-4">
51
+ {#if hasBreadcrumbs}
52
+ <Breadcrumbs items={breadcrumbs} />
53
+ {/if}
54
+ <h2 class={titleClasses}>{title}</h2>
55
+ {#if subtitle}
56
+ <p class="text-default-500 mt-2 text-sm">{subtitle}</p>
57
+ {/if}
58
+ </div>
28
59
 
29
- {@render children?.()}
60
+ <!-- Children as separate unit below -->
61
+ {#if children}
62
+ <div class="mt-4">
63
+ {@render children()}
64
+ </div>
65
+ {/if}
66
+ </div>
67
+ {/if}
30
68
  </div>