urpanels-ui-pack 0.0.11 → 0.0.12

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.
@@ -45,7 +45,7 @@
45
45
  </script>
46
46
 
47
47
  <div
48
- class="bg-white rounded-lg shadow {isCompact ? 'p-3' : 'p-4'} flex flex-col gap-2 {hover ? 'hover:shadow-md transition-shadow' : ''} {className} relative"
48
+ class="bg-white rounded-lg shadow {isCompact ? 'p-3' : 'p-4'} h-full flex flex-col gap-2 {hover ? 'hover:shadow-md transition-shadow' : ''} {className} relative"
49
49
  data-component-name="InfoCard"
50
50
  data-card-id={id}
51
51
  >
@@ -230,13 +230,13 @@
230
230
  {/if}
231
231
 
232
232
  {#if footerActions}
233
- <div class="mt-2 flex flex-wrap gap-2">
233
+ <div class="mt-auto w-full pt-2 flex flex-wrap gap-2">
234
234
  {@render footerActions()}
235
235
  </div>
236
236
  {/if}
237
237
 
238
238
  {#if actionLayout === 'buttons' && hasActions}
239
- <div class="mt-3 flex justify-end gap-2 pt-2 border-t border-gray-100">
239
+ <div class="mt-auto flex justify-end gap-2 pt-2 border-t border-gray-100">
240
240
  {#if onEdit}
241
241
  <button
242
242
  onclick={onEdit}
@@ -5,21 +5,53 @@
5
5
  let {
6
6
  currentPage,
7
7
  totalPages,
8
- pageSize,
9
- totalItems,
8
+ pageSize = 20,
9
+ totalItems = 0,
10
10
  itemName = '',
11
11
  searchTerm = '',
12
12
  onPageChange,
13
13
  showInfo = true,
14
- showPageNumbers = true
14
+ showPageNumbers = true,
15
+ isLoading = false,
16
+ loadingPage = null,
17
+ loadingDirection = null,
18
+ disableDuringLoading = true
15
19
  }: PaginationProps = $props();
16
20
 
17
- const startItem = $derived((currentPage - 1) * pageSize + 1);
18
- const endItem = $derived(Math.min(currentPage * pageSize, totalItems));
21
+ let internalLoading = $state(false);
22
+ let internalLoadingPage: number | null = $state(null);
23
+ let internalLoadingDirection: 'prev' | 'next' | null = $state(null);
19
24
 
20
- function handlePageChange(page: number) {
21
- if (page >= 1 && page <= totalPages) {
22
- onPageChange(page);
25
+ const isBusy = $derived(isLoading || internalLoading);
26
+ const effectiveLoadingPage = $derived(loadingPage ?? internalLoadingPage);
27
+ const effectiveLoadingDirection = $derived(loadingDirection ?? internalLoadingDirection);
28
+
29
+ const startItem = $derived(totalItems > 0 ? (currentPage - 1) * pageSize + 1 : 0);
30
+ const endItem = $derived(totalItems > 0 ? Math.min(currentPage * pageSize, totalItems) : 0);
31
+
32
+ async function handlePageChange(page: number, direction: 'prev' | 'next' | null = null) {
33
+ if (page < 1 || page > totalPages || page === currentPage) {
34
+ return;
35
+ }
36
+
37
+ if (disableDuringLoading && isBusy) {
38
+ return;
39
+ }
40
+
41
+ if (!isLoading) {
42
+ internalLoading = true;
43
+ internalLoadingPage = page;
44
+ internalLoadingDirection = direction;
45
+ }
46
+
47
+ try {
48
+ await Promise.resolve(onPageChange(page));
49
+ } finally {
50
+ if (!isLoading) {
51
+ internalLoading = false;
52
+ internalLoadingPage = null;
53
+ internalLoadingDirection = null;
54
+ }
23
55
  }
24
56
  }
25
57
 
@@ -52,13 +84,16 @@
52
84
 
53
85
  <div class="flex items-center gap-2">
54
86
  <button
55
- onclick={() => handlePageChange(currentPage - 1)}
56
- disabled={currentPage === 1}
57
- class="px-3 py-1 rounded border {currentPage === 1
87
+ onclick={() => handlePageChange(currentPage - 1, 'prev')}
88
+ disabled={currentPage === 1 || (disableDuringLoading && isBusy)}
89
+ class="px-3 py-1 rounded border flex items-center gap-2 {currentPage === 1 || (disableDuringLoading && isBusy)
58
90
  ? 'bg-gray-100 text-gray-400 cursor-not-allowed border-gray-200'
59
91
  : 'bg-white text-blue-600 border-blue-300 hover:bg-blue-50 cursor-pointer'}"
60
92
  >
61
- {t('common.previous')}
93
+ {#if isBusy && (effectiveLoadingDirection === 'prev' || effectiveLoadingPage === currentPage - 1)}
94
+ <span class="h-3.5 w-3.5 animate-spin rounded-full border-2 border-current border-r-transparent"></span>
95
+ {/if}
96
+ <span>‹ {t('common.previous')}</span>
62
97
  </button>
63
98
 
64
99
  {#if showPageNumbers}
@@ -66,11 +101,16 @@
66
101
  {#if shouldShowPageNumber(pageNum)}
67
102
  <button
68
103
  onclick={() => handlePageChange(pageNum)}
69
- class="px-3 py-1 rounded border {currentPage === pageNum
104
+ disabled={disableDuringLoading && isBusy}
105
+ class="px-3 py-1 rounded border min-w-[2.25rem] flex items-center justify-center {currentPage === pageNum
70
106
  ? 'bg-blue-600 text-white border-blue-600 font-semibold'
71
107
  : 'bg-white text-blue-600 border-blue-300 hover:bg-blue-50 cursor-pointer'}"
72
108
  >
73
- {pageNum}
109
+ {#if isBusy && effectiveLoadingPage === pageNum}
110
+ <span class="h-3.5 w-3.5 animate-spin rounded-full border-2 border-current border-r-transparent"></span>
111
+ {:else}
112
+ {pageNum}
113
+ {/if}
74
114
  </button>
75
115
  {:else if shouldShowEllipsis(pageNum)}
76
116
  <span class="text-gray-500">...</span>
@@ -83,13 +123,16 @@
83
123
  {/if}
84
124
 
85
125
  <button
86
- onclick={() => handlePageChange(currentPage + 1)}
87
- disabled={currentPage >= totalPages}
88
- class="px-3 py-1 rounded border {currentPage >= totalPages
126
+ onclick={() => handlePageChange(currentPage + 1, 'next')}
127
+ disabled={currentPage >= totalPages || (disableDuringLoading && isBusy)}
128
+ class="px-3 py-1 rounded border flex items-center gap-2 {currentPage >= totalPages || (disableDuringLoading && isBusy)
89
129
  ? 'bg-gray-100 text-gray-400 cursor-not-allowed border-gray-200'
90
130
  : 'bg-white text-blue-600 border-blue-300 hover:bg-blue-50 cursor-pointer'}"
91
131
  >
92
- {t('common.next')}
132
+ <span>{t('common.next')} ›</span>
133
+ {#if isBusy && (effectiveLoadingDirection === 'next' || effectiveLoadingPage === currentPage + 1)}
134
+ <span class="h-3.5 w-3.5 animate-spin rounded-full border-2 border-current border-r-transparent"></span>
135
+ {/if}
93
136
  </button>
94
137
  </div>
95
138
  </div>
@@ -1,11 +1,15 @@
1
1
  export interface PaginationProps {
2
2
  currentPage: number;
3
3
  totalPages: number;
4
- pageSize: number;
5
- totalItems: number;
6
- onPageChange: (page: number) => void;
4
+ pageSize?: number;
5
+ totalItems?: number;
6
+ onPageChange: (page: number) => void | Promise<void>;
7
7
  itemName?: string;
8
8
  searchTerm?: string;
9
9
  showInfo?: boolean;
10
10
  showPageNumbers?: boolean;
11
+ isLoading?: boolean;
12
+ loadingPage?: number | null;
13
+ loadingDirection?: 'prev' | 'next' | null;
14
+ disableDuringLoading?: boolean;
11
15
  }
@@ -23,6 +23,14 @@
23
23
  onChange?: (value: string) => void;
24
24
  onBlur?: () => void;
25
25
  onFocus?: () => void;
26
+ rootClassName?: string;
27
+ labelClassName?: string;
28
+ inputWrapperClassName?: string;
29
+ inputClassName?: string;
30
+ errorClassName?: string;
31
+ helpClassName?: string;
32
+ prefixClassName?: string;
33
+ suffixClassName?: string;
26
34
  }
27
35
 
28
36
  let {
@@ -46,7 +54,15 @@
46
54
  onInput,
47
55
  onChange,
48
56
  onBlur,
49
- onFocus
57
+ onFocus,
58
+ rootClassName = '',
59
+ labelClassName = '',
60
+ inputWrapperClassName = '',
61
+ inputClassName = '',
62
+ errorClassName = '',
63
+ helpClassName = '',
64
+ prefixClassName = '',
65
+ suffixClassName = ''
50
66
  }: Props = $props();
51
67
 
52
68
  const hasError = $derived(
@@ -63,6 +79,10 @@
63
79
  : 'border-gray-300 focus-within:border-blue-500'
64
80
  );
65
81
 
82
+ const resolvedWrapperStateClass = $derived(
83
+ inputWrapperClassName.trim() ? inputWrapperClassName : inputWrapperClass
84
+ );
85
+
66
86
  function handleInput(e: Event) {
67
87
  const target = e.target as HTMLInputElement;
68
88
  value = target.value;
@@ -76,9 +96,9 @@
76
96
  </script>
77
97
 
78
98
  {#if isActive}
79
- <div class="w-full">
99
+ <div class="w-full {rootClassName}">
80
100
  {#if label}
81
- <label class="mb-1.5 block text-sm font-medium text-gray-700" for={id}>
101
+ <label class="mb-1.5 block text-sm font-medium text-gray-700 {labelClassName}" for={id}>
82
102
  {label}
83
103
  {#if required}
84
104
  <span class="text-red-500 ml-0.5">*</span>
@@ -88,10 +108,10 @@
88
108
 
89
109
  <div class="relative">
90
110
  <div
91
- class="flex items-center border rounded-lg bg-white transition-all duration-200 {inputWrapperClass} {disabled ? 'bg-gray-50 cursor-not-allowed' : ''}"
111
+ class="flex items-center border rounded-lg bg-white transition-all duration-200 {resolvedWrapperStateClass} {disabled ? 'bg-gray-50 cursor-not-allowed' : ''}"
92
112
  >
93
113
  {#if prefix}
94
- <div class="pl-3 flex items-center text-gray-500">
114
+ <div class="pl-3 flex items-center text-gray-500 {prefixClassName}">
95
115
  {@render prefix()}
96
116
  </div>
97
117
  {/if}
@@ -111,11 +131,11 @@
111
131
  onchange={handleChange}
112
132
  onblur={onBlur}
113
133
  onfocus={onFocus}
114
- class="flex-1 w-full px-3 py-2 bg-transparent border-none outline-none rounded-lg focus:outline-none focus:ring-0 focus-visible:outline-none text-gray-900 placeholder-gray-400 disabled:cursor-not-allowed disabled:text-gray-500"
134
+ class="flex-1 w-full px-3 py-2 bg-transparent border-none outline-none rounded-lg focus:outline-none focus:ring-0 focus-visible:outline-none text-gray-900 placeholder-gray-400 disabled:cursor-not-allowed disabled:text-gray-500 {inputClassName}"
115
135
  />
116
136
 
117
137
  {#if suffix}
118
- <div class="pr-3 flex items-center text-gray-500">
138
+ <div class="pr-3 flex items-center text-gray-500 {suffixClassName}">
119
139
  {@render suffix()}
120
140
  </div>
121
141
  {/if}
@@ -123,7 +143,7 @@
123
143
  </div>
124
144
 
125
145
  {#if error}
126
- <p class="mt-1.5 text-sm text-red-600 flex items-center gap-1">
146
+ <p class="mt-1.5 text-sm text-red-600 flex items-center gap-1 {errorClassName}">
127
147
  <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
128
148
  <path
129
149
  fill-rule="evenodd"
@@ -134,7 +154,7 @@
134
154
  {error}
135
155
  </p>
136
156
  {:else if helpText}
137
- <p class="mt-1.5 text-sm text-gray-500">{helpText}</p>
157
+ <p class="mt-1.5 text-sm text-gray-500 {helpClassName}">{helpText}</p>
138
158
  {/if}
139
159
  </div>
140
160
  {/if}
@@ -21,6 +21,14 @@ interface Props {
21
21
  onChange?: (value: string) => void;
22
22
  onBlur?: () => void;
23
23
  onFocus?: () => void;
24
+ rootClassName?: string;
25
+ labelClassName?: string;
26
+ inputWrapperClassName?: string;
27
+ inputClassName?: string;
28
+ errorClassName?: string;
29
+ helpClassName?: string;
30
+ prefixClassName?: string;
31
+ suffixClassName?: string;
24
32
  }
25
33
  declare const InputNumber: import("svelte").Component<Props, {}, "value">;
26
34
  type InputNumber = ReturnType<typeof InputNumber>;
@@ -10,10 +10,18 @@
10
10
  value?: string | null;
11
11
  options: OptionItem[] | string[];
12
12
  required?: boolean;
13
+ disabled?: boolean;
13
14
  isActive?: boolean;
14
15
  validationError?: string;
16
+ error?: string;
15
17
  isNewRecord?: boolean;
16
18
  srOnly?: boolean;
19
+ onInput?: (value: string) => void;
20
+ onChange?: (value: string) => void;
21
+ rootClassName?: string;
22
+ labelClassName?: string;
23
+ selectClassName?: string;
24
+ errorClassName?: string;
17
25
  };
18
26
 
19
27
  let {
@@ -22,16 +30,26 @@
22
30
  value = $bindable(''),
23
31
  options = [],
24
32
  required = false,
33
+ disabled = false,
25
34
  isActive = true,
26
35
  validationError = '',
36
+ error = '',
27
37
  isNewRecord = false,
28
- srOnly = false
38
+ srOnly = false,
39
+ onInput,
40
+ onChange,
41
+ rootClassName = '',
42
+ labelClassName = '',
43
+ selectClassName = '',
44
+ errorClassName = ''
29
45
  }: Props = $props();
30
46
 
31
47
  const hasError = $derived(
32
- isNewRecord && required && validationError && !value
48
+ !!error || (isNewRecord && required && validationError && !value)
33
49
  );
34
50
 
51
+ const resolvedErrorText = $derived(error || validationError);
52
+
35
53
  const normalizedOptions = $derived(() => {
36
54
  if (options.length === 0) return [];
37
55
 
@@ -44,12 +62,23 @@
44
62
 
45
63
  return options as OptionItem[];
46
64
  });
65
+
66
+ function handleInput(e: Event) {
67
+ const target = e.target as HTMLSelectElement;
68
+ value = target.value;
69
+ onInput?.(target.value);
70
+ }
71
+
72
+ function handleChange(e: Event) {
73
+ const target = e.target as HTMLSelectElement;
74
+ onChange?.(target.value);
75
+ }
47
76
  </script>
48
77
 
49
78
  {#if isActive}
50
- <div>
79
+ <div class={rootClassName}>
51
80
  <label
52
- class="block text-sm font-medium mb-1 {srOnly ? 'sr-only' : ''}"
81
+ class="block text-sm font-medium mb-1 {srOnly ? 'sr-only' : ''} {labelClassName}"
53
82
  for={id}
54
83
  >
55
84
  {label}
@@ -59,15 +88,18 @@
59
88
  </label>
60
89
  <select
61
90
  {id}
62
- class="w-full rounded-lg border px-3 py-2.5 bg-white focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition {hasError ? 'border-red-500' : 'border-gray-300'}"
91
+ {disabled}
92
+ class="w-full rounded-lg border px-3 py-2.5 bg-white focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition {hasError ? 'border-red-500' : 'border-gray-300'} {selectClassName}"
63
93
  bind:value
94
+ oninput={handleInput}
95
+ onchange={handleChange}
64
96
  >
65
97
  {#each normalizedOptions() as option}
66
98
  <option value={option.value}>{option.label}</option>
67
99
  {/each}
68
100
  </select>
69
101
  {#if hasError}
70
- <div class="mt-1 text-xs text-red-500">{validationError}</div>
102
+ <div class="mt-1 text-xs text-red-500 {errorClassName}">{resolvedErrorText}</div>
71
103
  {/if}
72
104
  </div>
73
105
  {/if}
@@ -8,10 +8,18 @@ type Props = {
8
8
  value?: string | null;
9
9
  options: OptionItem[] | string[];
10
10
  required?: boolean;
11
+ disabled?: boolean;
11
12
  isActive?: boolean;
12
13
  validationError?: string;
14
+ error?: string;
13
15
  isNewRecord?: boolean;
14
16
  srOnly?: boolean;
17
+ onInput?: (value: string) => void;
18
+ onChange?: (value: string) => void;
19
+ rootClassName?: string;
20
+ labelClassName?: string;
21
+ selectClassName?: string;
22
+ errorClassName?: string;
15
23
  };
16
24
  declare const InputSelect: import("svelte").Component<Props, {}, "value">;
17
25
  type InputSelect = ReturnType<typeof InputSelect>;
@@ -21,6 +21,12 @@
21
21
  onChange?: (value: string) => void;
22
22
  onBlur?: () => void;
23
23
  onFocus?: () => void;
24
+ rootClassName?: string;
25
+ labelClassName?: string;
26
+ inputWrapperClassName?: string;
27
+ inputClassName?: string;
28
+ prefixClassName?: string;
29
+ suffixClassName?: string;
24
30
  }
25
31
 
26
32
  let {
@@ -42,7 +48,13 @@
42
48
  onInput,
43
49
  onChange,
44
50
  onBlur,
45
- onFocus
51
+ onFocus,
52
+ rootClassName = '',
53
+ labelClassName = '',
54
+ inputWrapperClassName = '',
55
+ inputClassName = '',
56
+ prefixClassName = '',
57
+ suffixClassName = ''
46
58
  }: Props = $props();
47
59
 
48
60
  // Input wrapper class based on state
@@ -52,6 +64,10 @@
52
64
  : 'border-gray-300 focus-within:border-blue-500'
53
65
  );
54
66
 
67
+ const resolvedWrapperStateClass = $derived(
68
+ inputWrapperClassName.trim() ? inputWrapperClassName : inputWrapperClass
69
+ );
70
+
55
71
  function handleInput(e: Event) {
56
72
  const target = e.target as HTMLInputElement;
57
73
  value = target.value;
@@ -64,10 +80,10 @@
64
80
  }
65
81
  </script>
66
82
 
67
- <div class="w-full">
83
+ <div class="w-full {rootClassName}">
68
84
  {#if label}
69
85
  <label
70
- class="mb-1.5 block text-sm font-medium text-gray-700"
86
+ class="mb-1.5 block text-sm font-medium text-gray-700 {labelClassName}"
71
87
  for={id}
72
88
  >
73
89
  {label}
@@ -79,10 +95,10 @@
79
95
 
80
96
  <div class="relative">
81
97
  <div
82
- class="flex items-center border rounded-lg bg-white transition-all duration-200 {inputWrapperClass} {disabled ? 'bg-gray-50 cursor-not-allowed' : ''}"
98
+ class="flex items-center border rounded-lg bg-white transition-all duration-200 {resolvedWrapperStateClass} {disabled ? 'bg-gray-50 cursor-not-allowed' : ''}"
83
99
  >
84
100
  {#if prefix}
85
- <div class="pl-3 flex items-center text-gray-500">
101
+ <div class="pl-3 flex items-center text-gray-500 {prefixClassName}">
86
102
  {@render prefix()}
87
103
  </div>
88
104
  {/if}
@@ -102,11 +118,11 @@
102
118
  onchange={handleChange}
103
119
  onblur={onBlur}
104
120
  onfocus={onFocus}
105
- class="flex-1 w-full px-3 py-2 bg-transparent border-none outline-none rounded-lg focus:outline-none focus:ring-0 focus-visible:outline-none text-gray-900 placeholder-gray-400 disabled:cursor-not-allowed disabled:text-gray-500"
121
+ class="flex-1 w-full px-3 py-2 bg-transparent border-none outline-none rounded-lg focus:outline-none focus:ring-0 focus-visible:outline-none text-gray-900 placeholder-gray-400 disabled:cursor-not-allowed disabled:text-gray-500 {inputClassName}"
106
122
  />
107
123
 
108
124
  {#if suffix}
109
- <div class="pr-3 flex items-center text-gray-500">
125
+ <div class="pr-3 flex items-center text-gray-500 {suffixClassName}">
110
126
  {@render suffix()}
111
127
  </div>
112
128
  {/if}
@@ -20,6 +20,12 @@ interface Props {
20
20
  onChange?: (value: string) => void;
21
21
  onBlur?: () => void;
22
22
  onFocus?: () => void;
23
+ rootClassName?: string;
24
+ labelClassName?: string;
25
+ inputWrapperClassName?: string;
26
+ inputClassName?: string;
27
+ prefixClassName?: string;
28
+ suffixClassName?: string;
23
29
  }
24
30
 
25
31
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
@@ -0,0 +1,80 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import type { SectionContainerProps } from './SectionContainer.types';
4
+
5
+ interface Props extends SectionContainerProps {
6
+ children?: Snippet;
7
+ icon?: Snippet;
8
+ headerActions?: Snippet;
9
+ }
10
+
11
+ let {
12
+ title,
13
+ subtitle,
14
+ type = 'type1',
15
+ required = false,
16
+ className = '',
17
+ headerClassName = '',
18
+ contentClassName = '',
19
+ children,
20
+ icon,
21
+ headerActions,
22
+ }: Props = $props();
23
+
24
+ const containerClass = $derived(
25
+ type === 'type1'
26
+ ? 'bg-gradient-to-br from-orange-50 to-amber-50 rounded-xl border-2 border-orange-200 overflow-hidden'
27
+ : 'bg-white rounded-xl border border-gray-200 overflow-hidden'
28
+ );
29
+
30
+ const headerClass = $derived(
31
+ type === 'type1'
32
+ ? 'bg-white/80 backdrop-blur-sm px-4 py-3 border-b border-orange-200'
33
+ : 'bg-white px-4 py-3 border-b border-gray-200'
34
+ );
35
+
36
+ const titleClass = $derived(
37
+ type === 'type1' ? 'text-sm font-semibold text-gray-800' : 'text-sm font-semibold text-gray-800'
38
+ );
39
+
40
+ const contentClass = $derived(type === 'type1' ? 'p-4' : 'p-4');
41
+ </script>
42
+
43
+ <div
44
+ class="{containerClass} {className}"
45
+ data-component-name="SectionContainer"
46
+ data-section-type={type}
47
+ >
48
+ <div class="{headerClass} {headerClassName}">
49
+ <div class="flex items-center justify-between gap-3">
50
+ <div class="flex items-center gap-2 min-w-0">
51
+ {#if icon}
52
+ {@render icon()}
53
+ {/if}
54
+ <div class="min-w-0">
55
+ <h3 class="{titleClass}">
56
+ {title}
57
+ {#if required}
58
+ <span class="text-red-500 ml-0.5">*</span>
59
+ {/if}
60
+ </h3>
61
+ {#if subtitle}
62
+ <p class="text-xs text-gray-600 mt-0.5">{subtitle}</p>
63
+ {/if}
64
+ </div>
65
+ </div>
66
+
67
+ {#if headerActions}
68
+ <div class="flex items-center gap-2 shrink-0">
69
+ {@render headerActions()}
70
+ </div>
71
+ {/if}
72
+ </div>
73
+ </div>
74
+
75
+ <div class="{contentClass} {contentClassName}">
76
+ {#if children}
77
+ {@render children()}
78
+ {/if}
79
+ </div>
80
+ </div>
@@ -0,0 +1,10 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { SectionContainerProps } from './SectionContainer.types';
3
+ interface Props extends SectionContainerProps {
4
+ children?: Snippet;
5
+ icon?: Snippet;
6
+ headerActions?: Snippet;
7
+ }
8
+ declare const SectionContainer: import("svelte").Component<Props, {}, "">;
9
+ type SectionContainer = ReturnType<typeof SectionContainer>;
10
+ export default SectionContainer;
@@ -0,0 +1,10 @@
1
+ export type SectionContainerType = 'type1';
2
+ export interface SectionContainerProps {
3
+ title: string;
4
+ subtitle?: string;
5
+ type?: SectionContainerType;
6
+ required?: boolean;
7
+ className?: string;
8
+ headerClassName?: string;
9
+ contentClassName?: string;
10
+ }
@@ -0,0 +1,2 @@
1
+ export { default as SectionContainer } from './SectionContainer.svelte';
2
+ export type { SectionContainerProps, SectionContainerType } from './SectionContainer.types';
@@ -0,0 +1 @@
1
+ export { default as SectionContainer } from './SectionContainer.svelte';
@@ -1,2 +1,5 @@
1
+ export { HeroCarousel } from './HeroCarousel';
1
2
  export { PreviewSelector } from './PreviewSelector';
2
3
  export type { PreviewItem } from './PreviewSelector';
4
+ export { SectionContainer } from './SectionContainer';
5
+ export type { SectionContainerProps, SectionContainerType } from './SectionContainer';
@@ -1,6 +1,7 @@
1
- // export { HeroCarousel } from './HeroCarousel';
1
+ export { HeroCarousel } from './HeroCarousel';
2
2
  // export { ArticlesGrid } from './ArticlesGrid';
3
3
  // export type { Article } from './ArticlesGrid';
4
4
  // export { FeaturedGalleryGrid } from './FeaturedGalleryGrid';
5
5
  // export type { GalleryItem } from './FeaturedGalleryGrid';
6
6
  export { PreviewSelector } from './PreviewSelector';
7
+ export { SectionContainer } from './SectionContainer';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "urpanels-ui-pack",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "description": "Reusable Svelte 5 UI components for urPanels templates",
5
5
  "type": "module",
6
6
  "license": "MIT",