@makolabs/ripple 3.0.5 → 3.0.6
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.
- package/dist/ai/CodeRenderer.svelte +1 -1
- package/dist/ai/MessageBox.svelte +1 -1
- package/dist/ai/ai-types.d.ts +11 -0
- package/dist/button/button.js +5 -5
- package/dist/elements/badge/badge.js +2 -2
- package/dist/elements/dropdown/Select.svelte +1 -1
- package/dist/elements/dropdown/dropdown.js +18 -18
- package/dist/elements/popover/Popover.svelte +1 -1
- package/dist/elements/spinner/spinner.js +5 -5
- package/dist/file-browser/FileBrowser.svelte +5 -3
- package/dist/forms/DateRange.svelte +2 -2
- package/dist/forms/MarketSelector.svelte +3 -2
- package/dist/forms/NumberInput.svelte +2 -2
- package/dist/forms/SegmentedControl.svelte +9 -7
- package/dist/forms/date-picker/DatePicker.svelte +1 -1
- package/dist/forms/form-size.js +11 -11
- package/dist/forms/form-types.d.ts +8 -2
- package/dist/forms/market/FlagSvg.svelte +38 -0
- package/dist/forms/market/FlagSvg.svelte.d.ts +8 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/layout/activity-list/ActivityList.svelte +1 -1
- package/dist/layout/activity-list/activity-list-types.d.ts +10 -0
- package/dist/layout/activity-list/activity-list.js +1 -1
- package/dist/layout/sidebar/Sidebar.svelte +1 -1
- package/dist/layout/table/Table.svelte +28 -16
- package/dist/layout/table/table-types.d.ts +9 -0
- package/dist/layout/table/table.js +13 -13
- package/dist/layout/tabs/tabs.js +5 -5
- package/dist/user-management/UserViewModal.svelte +1 -1
- package/package.json +1 -1
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
</span>
|
|
119
119
|
<button
|
|
120
120
|
onclick={copyCode}
|
|
121
|
-
class="flex items-center gap-1.5 rounded px-2 py-1 text-xs transition-all duration-200 {copied
|
|
121
|
+
class="flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs transition-all duration-200 {copied
|
|
122
122
|
? 'border border-green-500 bg-green-500/10 text-green-400'
|
|
123
123
|
: 'text-default-400 hover:bg-default-700 hover:text-default-200'}"
|
|
124
124
|
title={copied ? 'Copied!' : 'Copy code'}
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
bind:this={copyButtonRef}
|
|
167
167
|
onclick={handleCopyClick}
|
|
168
168
|
ondblclick={handleCopyDoubleClick}
|
|
169
|
-
class="bg-default-100 text-default-600 hover:bg-default-200 hover:text-default-800 flex items-center gap-1 rounded-md px-3 py-1 text-xs font-medium opacity-0 transition-opacity duration-200 group-hover:opacity-100"
|
|
169
|
+
class="bg-default-100 text-default-600 hover:bg-default-200 hover:text-default-800 flex cursor-pointer items-center gap-1 rounded-md px-3 py-1 text-xs font-medium opacity-0 transition-opacity duration-200 group-hover:opacity-100"
|
|
170
170
|
title="Click: Copy markdown • Double-click: Copy rich text"
|
|
171
171
|
>
|
|
172
172
|
{#if showCopied}
|
package/dist/ai/ai-types.d.ts
CHANGED
|
@@ -114,6 +114,17 @@ export interface FileBrowserProps {
|
|
|
114
114
|
* @default true
|
|
115
115
|
*/
|
|
116
116
|
allowFolderNavigation?: boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Per-row selectability gate. Return `false` to prevent the row's
|
|
119
|
+
* checkbox from rendering — the file still appears in the list but
|
|
120
|
+
* can't be selected. When omitted every file is selectable.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```svelte
|
|
124
|
+
* <FileBrowser {adapter} isSelectable={(f) => !f.isFolder && f.size > 0} />
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
isSelectable?: (file: FileItem) => boolean;
|
|
117
128
|
/** Additional CSS classes for the outer container. */
|
|
118
129
|
class?: ClassValue;
|
|
119
130
|
/**
|
package/dist/button/button.js
CHANGED
|
@@ -22,11 +22,11 @@ export const buttonVariants = tv({
|
|
|
22
22
|
[Color.DANGER]: 'bg-danger-600 text-white hover:bg-danger-700 focus-visible:ring-danger-500'
|
|
23
23
|
},
|
|
24
24
|
size: {
|
|
25
|
-
[Size.XS]: 'h-
|
|
26
|
-
[Size.SM]: 'h-
|
|
27
|
-
[Size.MD]: 'h-
|
|
28
|
-
[Size.LG]: 'h-
|
|
29
|
-
[Size.XL]: 'h-
|
|
25
|
+
[Size.XS]: 'h-6 px-2 text-[10px]',
|
|
26
|
+
[Size.SM]: 'h-7 px-2.5 text-[11px]',
|
|
27
|
+
[Size.MD]: 'h-8 px-3 text-xs',
|
|
28
|
+
[Size.LG]: 'h-9 px-4 text-sm',
|
|
29
|
+
[Size.XL]: 'h-11 px-5 text-base',
|
|
30
30
|
[Size.XXL]: 'h-14 px-8 text-xl'
|
|
31
31
|
},
|
|
32
32
|
rounded: {
|
|
@@ -8,11 +8,11 @@ export const badge = tv({
|
|
|
8
8
|
variants: {
|
|
9
9
|
size: {
|
|
10
10
|
[Size.XS]: {
|
|
11
|
-
base: 'h-4 px-1.5 text-
|
|
11
|
+
base: 'h-4 px-1.5 text-[10px] rounded gap-0.5',
|
|
12
12
|
icon: 'h-2.5 w-2.5'
|
|
13
13
|
},
|
|
14
14
|
[Size.SM]: {
|
|
15
|
-
base: 'h-5 px-2 text-
|
|
15
|
+
base: 'h-5 px-2 text-[11px] rounded gap-1',
|
|
16
16
|
icon: 'h-3 w-3'
|
|
17
17
|
},
|
|
18
18
|
[Size.MD]: {
|
|
@@ -427,7 +427,7 @@
|
|
|
427
427
|
{#if open && isMobile}
|
|
428
428
|
<button
|
|
429
429
|
type="button"
|
|
430
|
-
class="fixed inset-0 z-[9998] bg-black/40 backdrop-blur-sm"
|
|
430
|
+
class="fixed inset-0 z-[9998] cursor-pointer bg-black/40 backdrop-blur-sm"
|
|
431
431
|
aria-label="Close"
|
|
432
432
|
onclick={() => (open = false)}
|
|
433
433
|
></button>
|
|
@@ -29,32 +29,32 @@ export const dropdownMenu = tv({
|
|
|
29
29
|
},
|
|
30
30
|
size: {
|
|
31
31
|
[Size.XS]: {
|
|
32
|
-
trigger: 'px-
|
|
33
|
-
item: 'px-2
|
|
34
|
-
itemIcon: 'mr-1.5 size-3
|
|
35
|
-
header: 'px-2
|
|
36
|
-
headerTitle: 'text-
|
|
37
|
-
headerSubtitle: 'text-
|
|
32
|
+
trigger: 'px-1.5 py-0.5 text-[10px]',
|
|
33
|
+
item: 'px-2 py-1 text-[10px]',
|
|
34
|
+
itemIcon: 'mr-1.5 size-3',
|
|
35
|
+
header: 'px-2 py-1',
|
|
36
|
+
headerTitle: 'text-[10px]',
|
|
37
|
+
headerSubtitle: 'text-[10px]'
|
|
38
38
|
},
|
|
39
39
|
[Size.SM]: {
|
|
40
|
+
trigger: 'px-2 py-1 text-[11px]',
|
|
41
|
+
item: 'px-2.5 py-1.5 text-[11px]',
|
|
42
|
+
itemIcon: 'mr-2 size-3.5',
|
|
43
|
+
header: 'px-2.5 py-1.5',
|
|
44
|
+
headerTitle: 'text-[11px]',
|
|
45
|
+
headerSubtitle: 'text-[11px]'
|
|
46
|
+
},
|
|
47
|
+
[Size.MD]: {
|
|
40
48
|
trigger: 'px-2.5 py-1.5 text-xs',
|
|
41
|
-
item: 'px-3 py-
|
|
42
|
-
itemIcon: 'mr-2 size-4',
|
|
49
|
+
item: 'px-3 py-2 text-xs',
|
|
50
|
+
itemIcon: 'mr-2.5 size-4',
|
|
43
51
|
header: 'px-3 py-2',
|
|
44
52
|
headerTitle: 'text-xs',
|
|
45
53
|
headerSubtitle: 'text-xs'
|
|
46
54
|
},
|
|
47
|
-
[Size.MD]: {
|
|
48
|
-
trigger: 'px-3 py-2 text-sm',
|
|
49
|
-
item: 'px-4 py-2 text-sm',
|
|
50
|
-
itemIcon: 'mr-3 size-5',
|
|
51
|
-
header: 'px-4 py-3',
|
|
52
|
-
headerTitle: 'text-sm',
|
|
53
|
-
headerSubtitle: 'text-sm'
|
|
54
|
-
},
|
|
55
55
|
[Size.LG]: {
|
|
56
|
-
trigger: 'px-
|
|
57
|
-
item: 'px-
|
|
56
|
+
trigger: 'px-3 py-2 text-sm',
|
|
57
|
+
item: 'px-4 py-2.5 text-sm',
|
|
58
58
|
itemIcon: 'mr-3 size-6',
|
|
59
59
|
header: 'px-5 py-3.5',
|
|
60
60
|
headerTitle: 'text-base',
|
|
@@ -234,7 +234,7 @@
|
|
|
234
234
|
{#if open && useSheet}
|
|
235
235
|
<button
|
|
236
236
|
type="button"
|
|
237
|
-
class="fixed inset-0 z-[9998] bg-black/40 backdrop-blur-sm"
|
|
237
|
+
class="fixed inset-0 z-[9998] cursor-pointer bg-black/40 backdrop-blur-sm"
|
|
238
238
|
aria-label="Close"
|
|
239
239
|
onclick={closeOnOutsideClick ? close : undefined}
|
|
240
240
|
></button>
|
|
@@ -8,11 +8,11 @@ export const spinner = tv({
|
|
|
8
8
|
},
|
|
9
9
|
variants: {
|
|
10
10
|
size: {
|
|
11
|
-
[Size.XS]: { svg: 'h-3 w-3', label: 'text-
|
|
12
|
-
[Size.SM]: { svg: 'h-4 w-4', label: 'text-
|
|
13
|
-
[Size.MD]: { svg: 'h-5 w-5', label: 'text-
|
|
14
|
-
[Size.LG]: { svg: 'h-6 w-6', label: 'text-
|
|
15
|
-
[Size.XL]: { svg: 'h-8 w-8', label: 'text-
|
|
11
|
+
[Size.XS]: { svg: 'h-3 w-3', label: 'text-[10px]' },
|
|
12
|
+
[Size.SM]: { svg: 'h-4 w-4', label: 'text-[11px]' },
|
|
13
|
+
[Size.MD]: { svg: 'h-5 w-5', label: 'text-xs' },
|
|
14
|
+
[Size.LG]: { svg: 'h-6 w-6', label: 'text-sm' },
|
|
15
|
+
[Size.XL]: { svg: 'h-8 w-8', label: 'text-base' },
|
|
16
16
|
[Size.XXL]: { svg: 'h-12 w-12', label: 'text-xl' }
|
|
17
17
|
},
|
|
18
18
|
color: {
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
infoSection,
|
|
20
20
|
selectAllScope = 'page',
|
|
21
21
|
allowFolderNavigation = true,
|
|
22
|
+
isSelectable,
|
|
22
23
|
height = 'h-[500px]',
|
|
23
24
|
class: className = '',
|
|
24
25
|
selectedItems = $bindable<FileItem[]>([]),
|
|
@@ -780,7 +781,7 @@
|
|
|
780
781
|
<div class="flex min-w-0 flex-1 items-center">
|
|
781
782
|
{#if breadcrumbs.length > 1}
|
|
782
783
|
<button
|
|
783
|
-
class="text-default-600 hover:bg-default-100 mr-1 rounded-full px-2 py-1"
|
|
784
|
+
class="text-default-600 hover:bg-default-100 mr-1 cursor-pointer rounded-full px-2 py-1"
|
|
784
785
|
onclick={navigateUp}
|
|
785
786
|
title="Go up"
|
|
786
787
|
aria-label="Navigate to parent folder"
|
|
@@ -898,7 +899,7 @@
|
|
|
898
899
|
/>
|
|
899
900
|
{#if searchQuery}
|
|
900
901
|
<button
|
|
901
|
-
class="text-default-400 hover:text-default-600 absolute right-1 text-xs"
|
|
902
|
+
class="text-default-400 hover:text-default-600 absolute right-1 cursor-pointer text-xs"
|
|
902
903
|
onclick={clearSearch}
|
|
903
904
|
title="Clear search"
|
|
904
905
|
>
|
|
@@ -908,7 +909,7 @@
|
|
|
908
909
|
</div>
|
|
909
910
|
<button
|
|
910
911
|
onclick={handleSearch}
|
|
911
|
-
class="bg-default-200 hover:bg-default-300 rounded px-2 py-1 text-xs"
|
|
912
|
+
class="bg-default-200 hover:bg-default-300 cursor-pointer rounded px-2 py-1 text-xs"
|
|
912
913
|
>
|
|
913
914
|
Search
|
|
914
915
|
</button>
|
|
@@ -955,6 +956,7 @@
|
|
|
955
956
|
}}
|
|
956
957
|
onsort={handleSort}
|
|
957
958
|
selectable={true}
|
|
959
|
+
isRowSelectable={isSelectable}
|
|
958
960
|
{selectAllScope}
|
|
959
961
|
{onselect}
|
|
960
962
|
{selected}
|
|
@@ -345,7 +345,7 @@
|
|
|
345
345
|
<Portal target={datePickerRef}>
|
|
346
346
|
<button
|
|
347
347
|
type="button"
|
|
348
|
-
class="fixed inset-0 z-[9998] bg-black/40 backdrop-blur-sm"
|
|
348
|
+
class="fixed inset-0 z-[9998] cursor-pointer bg-black/40 backdrop-blur-sm"
|
|
349
349
|
aria-label="Close"
|
|
350
350
|
onclick={() => (isOpen = false)}
|
|
351
351
|
></button>
|
|
@@ -455,7 +455,7 @@
|
|
|
455
455
|
</button>
|
|
456
456
|
<button
|
|
457
457
|
type="button"
|
|
458
|
-
class="text-default-700 inline-flex items-center rounded-md px-2 py-1 text-sm font-medium"
|
|
458
|
+
class="text-default-700 inline-flex cursor-pointer items-center rounded-md px-2 py-1 text-sm font-medium"
|
|
459
459
|
>{viewDate.getFullYear() - 6} - {viewDate.getFullYear() + 5}</button
|
|
460
460
|
>
|
|
461
461
|
<button
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Color, Size } from '../variants.js';
|
|
3
3
|
import SegmentedControl from './SegmentedControl.svelte';
|
|
4
4
|
import { COUNTRY_NAMES } from './market/country-data.js';
|
|
5
|
-
import
|
|
5
|
+
import FlagSvg from './market/FlagSvg.svelte';
|
|
6
6
|
import type { CountryCode } from './market/country-data.js';
|
|
7
7
|
import type { MarketSelectorProps } from './market/market-selector-types.js';
|
|
8
8
|
import type { SegmentedOption } from '../index.js';
|
|
@@ -37,7 +37,8 @@
|
|
|
37
37
|
value: code,
|
|
38
38
|
label: code,
|
|
39
39
|
title: COUNTRY_NAMES[code],
|
|
40
|
-
prefix: effectiveShowFlags ?
|
|
40
|
+
prefix: effectiveShowFlags ? (FlagSvg as SegmentedOption['prefix']) : undefined,
|
|
41
|
+
prefixProps: effectiveShowFlags ? { code } : undefined
|
|
41
42
|
}));
|
|
42
43
|
});
|
|
43
44
|
|
|
@@ -153,7 +153,7 @@
|
|
|
153
153
|
unit to pick from. Otherwise the unit is static text below. -->
|
|
154
154
|
<button
|
|
155
155
|
type="button"
|
|
156
|
-
class="hover:bg-default-100 flex items-center gap-1 rounded px-1"
|
|
156
|
+
class="hover:bg-default-100 flex cursor-pointer items-center gap-1 rounded px-1"
|
|
157
157
|
data-testid={buildTestId('numberinput', 'unit', testId)}
|
|
158
158
|
onclick={handleUnitToggle}
|
|
159
159
|
{disabled}
|
|
@@ -191,7 +191,7 @@
|
|
|
191
191
|
{#each units as unitOption (unitOption.value)}
|
|
192
192
|
<button
|
|
193
193
|
type="button"
|
|
194
|
-
class="hover:bg-default-100 w-full px-3 py-1.5 text-left text-sm"
|
|
194
|
+
class="hover:bg-default-100 w-full cursor-pointer px-3 py-1.5 text-left text-sm"
|
|
195
195
|
class:bg-default-50={unit === unitOption.value}
|
|
196
196
|
onclick={() => handleUnitSelect(unitOption.value)}
|
|
197
197
|
>
|
|
@@ -155,14 +155,16 @@
|
|
|
155
155
|
onkeydown={(e) => handleSegmentKeydown(e, index)}
|
|
156
156
|
>
|
|
157
157
|
{#if option.prefix}
|
|
158
|
-
<span class="
|
|
158
|
+
<span class="leading-none" aria-hidden="true">
|
|
159
|
+
{#if typeof option.prefix === 'string'}
|
|
160
|
+
{option.prefix}
|
|
161
|
+
{:else}
|
|
162
|
+
{@const PrefixComponent = option.prefix}
|
|
163
|
+
<PrefixComponent {...option.prefixProps} />
|
|
164
|
+
{/if}
|
|
165
|
+
</span>
|
|
159
166
|
{/if}
|
|
160
|
-
<span
|
|
161
|
-
class={cn(
|
|
162
|
-
!compact && (size === Size.XS || size === Size.SM) && 'text-sm',
|
|
163
|
-
compact && 'sr-only'
|
|
164
|
-
)}
|
|
165
|
-
>
|
|
167
|
+
<span class={cn(compact && 'sr-only')}>
|
|
166
168
|
{option.label}
|
|
167
169
|
</span>
|
|
168
170
|
</button>
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
type="button"
|
|
100
100
|
onclick={clear}
|
|
101
101
|
aria-label="Clear date"
|
|
102
|
-
class="text-default-400 hover:text-default-700 flex size-5 items-center justify-center rounded"
|
|
102
|
+
class="text-default-400 hover:text-default-700 flex size-5 cursor-pointer items-center justify-center rounded"
|
|
103
103
|
>
|
|
104
104
|
<svg class="size-3" viewBox="0 0 12 12" fill="none" aria-hidden="true">
|
|
105
105
|
<path
|
package/dist/forms/form-size.js
CHANGED
|
@@ -22,29 +22,29 @@ const xl = {
|
|
|
22
22
|
};
|
|
23
23
|
export const formSizeTokens = {
|
|
24
24
|
[Size.XS]: {
|
|
25
|
-
height: 'h-
|
|
26
|
-
padX: 'px-1',
|
|
27
|
-
padY: 'py-0',
|
|
28
|
-
text: 'text-
|
|
25
|
+
height: 'h-6',
|
|
26
|
+
padX: 'px-1.5',
|
|
27
|
+
padY: 'py-0.5',
|
|
28
|
+
text: 'text-[10px]',
|
|
29
29
|
gap: 'gap-1',
|
|
30
30
|
iconSize: 'size-3',
|
|
31
31
|
radius: 'rounded-sm',
|
|
32
32
|
shadow: 'shadow-none'
|
|
33
33
|
},
|
|
34
34
|
[Size.SM]: {
|
|
35
|
-
height: 'h-
|
|
36
|
-
padX: 'px-
|
|
37
|
-
padY: 'py-
|
|
38
|
-
text: 'text-
|
|
35
|
+
height: 'h-7',
|
|
36
|
+
padX: 'px-2',
|
|
37
|
+
padY: 'py-1',
|
|
38
|
+
text: 'text-[11px]',
|
|
39
39
|
gap: 'gap-1',
|
|
40
40
|
iconSize: 'size-3',
|
|
41
41
|
radius: 'rounded',
|
|
42
42
|
shadow: 'shadow-xs'
|
|
43
43
|
},
|
|
44
44
|
[Size.MD]: {
|
|
45
|
-
height: 'h-
|
|
46
|
-
padX: 'px-2',
|
|
47
|
-
padY: 'py-1',
|
|
45
|
+
height: 'h-8',
|
|
46
|
+
padX: 'px-2.5',
|
|
47
|
+
padY: 'py-1.5',
|
|
48
48
|
text: 'text-xs',
|
|
49
49
|
gap: 'gap-1.5',
|
|
50
50
|
iconSize: 'size-3.5',
|
|
@@ -581,8 +581,14 @@ export interface SliderProps {
|
|
|
581
581
|
* Unlike `TabGroup`, segments are purely a control (no panels).
|
|
582
582
|
*/
|
|
583
583
|
export type SegmentedOption = RadioOption & {
|
|
584
|
-
/**
|
|
585
|
-
|
|
584
|
+
/**
|
|
585
|
+
* Content rendered before the label. Pass a string (e.g. emoji) or
|
|
586
|
+
* a Svelte component (e.g. `FlagSvg` for SVG country flags).
|
|
587
|
+
* When a component, pass its props via `prefixProps`.
|
|
588
|
+
*/
|
|
589
|
+
prefix?: string | Component;
|
|
590
|
+
/** Props forwarded to the `prefix` component (ignored for strings). */
|
|
591
|
+
prefixProps?: Record<string, any>;
|
|
586
592
|
/** Native `title` attribute on the segment button (hover tooltip). */
|
|
587
593
|
title?: string;
|
|
588
594
|
disabled?: boolean;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../../helper/cls.js';
|
|
3
|
+
|
|
4
|
+
let {
|
|
5
|
+
code,
|
|
6
|
+
class: className = ''
|
|
7
|
+
}: {
|
|
8
|
+
/** ISO 3166-1 alpha-2 country code (e.g. 'DE', 'US'). */
|
|
9
|
+
code: string;
|
|
10
|
+
class?: string;
|
|
11
|
+
} = $props();
|
|
12
|
+
|
|
13
|
+
const lc = $derived(code.toLowerCase());
|
|
14
|
+
|
|
15
|
+
// flagcdn.com serves public-domain SVG flags — no API key, no CORS issues,
|
|
16
|
+
// cached aggressively by browsers. Falls back to a neutral gray placeholder
|
|
17
|
+
// if the image fails to load.
|
|
18
|
+
let failed = $state(false);
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
{#if !failed}
|
|
22
|
+
<img
|
|
23
|
+
src="https://flagcdn.com/{lc}.svg"
|
|
24
|
+
alt={code}
|
|
25
|
+
class={cn('inline-block h-3 w-4 rounded-sm object-cover', className)}
|
|
26
|
+
loading="lazy"
|
|
27
|
+
onerror={() => (failed = true)}
|
|
28
|
+
/>
|
|
29
|
+
{:else}
|
|
30
|
+
<span
|
|
31
|
+
class={cn(
|
|
32
|
+
'bg-default-200 text-default-500 inline-flex h-3 w-4 items-center justify-center rounded-sm text-[8px]',
|
|
33
|
+
className
|
|
34
|
+
)}
|
|
35
|
+
>
|
|
36
|
+
{code}
|
|
37
|
+
</span>
|
|
38
|
+
{/if}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
/** ISO 3166-1 alpha-2 country code (e.g. 'DE', 'US'). */
|
|
3
|
+
code: string;
|
|
4
|
+
class?: string;
|
|
5
|
+
};
|
|
6
|
+
declare const FlagSvg: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type FlagSvg = ReturnType<typeof FlagSvg>;
|
|
8
|
+
export default FlagSvg;
|
package/dist/index.d.ts
CHANGED
|
@@ -129,6 +129,7 @@ export { default as MonthPicker } from './forms/month-picker/MonthPicker.svelte'
|
|
|
129
129
|
export { default as Tags } from './forms/Tags.svelte';
|
|
130
130
|
export { default as SegmentedControl } from './forms/SegmentedControl.svelte';
|
|
131
131
|
export { default as MarketSelector } from './forms/MarketSelector.svelte';
|
|
132
|
+
export { default as FlagSvg } from './forms/market/FlagSvg.svelte';
|
|
132
133
|
export { dropdownMenu } from './elements/dropdown/dropdown.js';
|
|
133
134
|
export { badge } from './elements/badge/badge.js';
|
|
134
135
|
export { buttonVariants } from './button/button.js';
|
package/dist/index.js
CHANGED
|
@@ -116,6 +116,7 @@ export { default as MonthPicker } from './forms/month-picker/MonthPicker.svelte'
|
|
|
116
116
|
export { default as Tags } from './forms/Tags.svelte';
|
|
117
117
|
export { default as SegmentedControl } from './forms/SegmentedControl.svelte';
|
|
118
118
|
export { default as MarketSelector } from './forms/MarketSelector.svelte';
|
|
119
|
+
export { default as FlagSvg } from './forms/market/FlagSvg.svelte';
|
|
119
120
|
// ============================================================================
|
|
120
121
|
// Component Variant Utilities
|
|
121
122
|
// ============================================================================
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
<div class="min-w-0 flex-1" data-activity-custom="">
|
|
109
109
|
{@render customContent?.(activityItem, index)}
|
|
110
110
|
</div>
|
|
111
|
-
{:else if timeline && activityItem.subtitle}
|
|
111
|
+
{:else if timeline && activityItem.subtitle && activityItem.timelineStyle === 'bubble'}
|
|
112
112
|
<div class="min-w-0 flex-1">
|
|
113
113
|
<div class="flex items-start justify-between gap-3">
|
|
114
114
|
<div
|
|
@@ -76,6 +76,16 @@ export type ActivityItem = {
|
|
|
76
76
|
* inside the snippet.
|
|
77
77
|
*/
|
|
78
78
|
custom?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Controls how the row renders when the parent list has `timeline`
|
|
81
|
+
* mode enabled and a `subtitle` is present.
|
|
82
|
+
* - `'flat'` — inline text, no card wrapper (default)
|
|
83
|
+
* - `'bubble'` — white rounded card with a ring border (comment style)
|
|
84
|
+
*
|
|
85
|
+
* Has no effect when `timeline` is false on the parent list.
|
|
86
|
+
* @default 'flat'
|
|
87
|
+
*/
|
|
88
|
+
timelineStyle?: 'flat' | 'bubble';
|
|
79
89
|
};
|
|
80
90
|
/** Density variants specific to ActivityList. */
|
|
81
91
|
export type ActivityListSize = 'sm' | 'md';
|
|
@@ -6,7 +6,7 @@ export const activityList = tv({
|
|
|
6
6
|
header: '',
|
|
7
7
|
title: 'font-medium text-default-900',
|
|
8
8
|
content: 'divide-y divide-default-200',
|
|
9
|
-
item: 'relative flex items-
|
|
9
|
+
item: 'relative flex items-center hover:bg-default-50 transition-colors',
|
|
10
10
|
accentBar: 'absolute inset-y-0 left-0 w-[3px]',
|
|
11
11
|
timelineLine: 'absolute top-0 bottom-0 w-[2px] bg-default-200',
|
|
12
12
|
iconWrapper: 'relative z-10 flex shrink-0 items-center justify-center rounded-full ring-4 ring-white',
|
|
@@ -155,7 +155,7 @@
|
|
|
155
155
|
type="button"
|
|
156
156
|
onclick={toggle}
|
|
157
157
|
aria-label="Close navigation"
|
|
158
|
-
class="fixed inset-0 z-40 bg-black/50 backdrop-blur-sm md:hidden"
|
|
158
|
+
class="fixed inset-0 z-40 cursor-pointer bg-black/50 backdrop-blur-sm md:hidden"
|
|
159
159
|
></button>
|
|
160
160
|
{/if}
|
|
161
161
|
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
let {
|
|
14
14
|
data = [],
|
|
15
15
|
columns = [],
|
|
16
|
+
size = 'md',
|
|
16
17
|
bordered: externalBordered,
|
|
17
18
|
striped = false,
|
|
18
19
|
pageSize = 10,
|
|
@@ -49,6 +50,7 @@
|
|
|
49
50
|
selectAllScope = 'page',
|
|
50
51
|
rowKey,
|
|
51
52
|
expandable = false,
|
|
53
|
+
isRowSelectable,
|
|
52
54
|
testId
|
|
53
55
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
54
56
|
}: TableProps<any> = $props();
|
|
@@ -100,6 +102,7 @@
|
|
|
100
102
|
sortIcon: sortIconBaseClass
|
|
101
103
|
} = $derived(
|
|
102
104
|
table({
|
|
105
|
+
size,
|
|
103
106
|
bordered,
|
|
104
107
|
striped
|
|
105
108
|
})
|
|
@@ -234,8 +237,12 @@
|
|
|
234
237
|
return rowIdentity(a) === rowIdentity(b);
|
|
235
238
|
}
|
|
236
239
|
|
|
240
|
+
function canSelectRow(row: DataRow): boolean {
|
|
241
|
+
return !isRowSelectable || isRowSelectable(row);
|
|
242
|
+
}
|
|
243
|
+
|
|
237
244
|
function toggleRowSelection(row: DataRow) {
|
|
238
|
-
if (!selectable) return;
|
|
245
|
+
if (!selectable || !canSelectRow(row)) return;
|
|
239
246
|
|
|
240
247
|
const index = selected.findIndex((r) => sameRow(r, row));
|
|
241
248
|
if (index === -1) {
|
|
@@ -280,7 +287,7 @@
|
|
|
280
287
|
|
|
281
288
|
function handleSelectAll() {
|
|
282
289
|
const pageData = getPaginatedData();
|
|
283
|
-
const scopeData = selectAllScope === 'all' ? data : pageData;
|
|
290
|
+
const scopeData = (selectAllScope === 'all' ? data : pageData).filter(canSelectRow);
|
|
284
291
|
const allSelected = scopeData.every((r) => isRowSelected(r));
|
|
285
292
|
if (allSelected) {
|
|
286
293
|
if (selectAllScope === 'all') {
|
|
@@ -290,11 +297,11 @@
|
|
|
290
297
|
}
|
|
291
298
|
} else {
|
|
292
299
|
if (selectAllScope === 'all') {
|
|
293
|
-
selected = [...data];
|
|
300
|
+
selected = [...data.filter(canSelectRow)];
|
|
294
301
|
} else {
|
|
295
302
|
const newSelected = [...selected];
|
|
296
303
|
for (const r of pageData) {
|
|
297
|
-
if (!isRowSelected(r)) {
|
|
304
|
+
if (canSelectRow(r) && !isRowSelected(r)) {
|
|
298
305
|
newSelected.push(r);
|
|
299
306
|
}
|
|
300
307
|
}
|
|
@@ -310,6 +317,9 @@
|
|
|
310
317
|
}
|
|
311
318
|
|
|
312
319
|
function handleRowClick(row: DataRow, index: number) {
|
|
320
|
+
if (selectable && canSelectRow(row)) {
|
|
321
|
+
toggleRowSelection(row);
|
|
322
|
+
}
|
|
313
323
|
onrowclick?.(row, index);
|
|
314
324
|
}
|
|
315
325
|
|
|
@@ -490,7 +500,7 @@
|
|
|
490
500
|
<tr
|
|
491
501
|
class={cn(trClasses, rowClass(row, rowIndex), {
|
|
492
502
|
'bg-primary-100': selectable && isRowSelected(row),
|
|
493
|
-
'cursor-pointer': onrowclick
|
|
503
|
+
'cursor-pointer': onrowclick || (selectable && canSelectRow(row))
|
|
494
504
|
})}
|
|
495
505
|
onclick={() => handleRowClick(row, rowIndex)}
|
|
496
506
|
aria-selected={selectable && isRowSelected(row)}
|
|
@@ -500,7 +510,7 @@
|
|
|
500
510
|
<td class={cn(tdClasses, 'w-10')}>
|
|
501
511
|
<button
|
|
502
512
|
type="button"
|
|
503
|
-
class="text-default-400 hover:text-default-600 flex items-center justify-center transition-transform"
|
|
513
|
+
class="text-default-400 hover:text-default-600 flex cursor-pointer items-center justify-center transition-transform"
|
|
504
514
|
onclick={(e) => {
|
|
505
515
|
e.stopPropagation();
|
|
506
516
|
toggleRowExpanded(row, rowIndex);
|
|
@@ -527,16 +537,18 @@
|
|
|
527
537
|
{/if}
|
|
528
538
|
{#if selectable}
|
|
529
539
|
<td class={cn(tdClasses, 'text-center')}>
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
e
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
+
{#if canSelectRow(row)}
|
|
541
|
+
<input
|
|
542
|
+
type="checkbox"
|
|
543
|
+
checked={isRowSelected(row)}
|
|
544
|
+
onclick={(e) => {
|
|
545
|
+
e.stopPropagation();
|
|
546
|
+
toggleRowSelection(row);
|
|
547
|
+
}}
|
|
548
|
+
aria-label={`Select row ${rowIndex + 1}`}
|
|
549
|
+
data-testid={buildTestId('table', 'row-select', testId, rowIndex)}
|
|
550
|
+
/>
|
|
551
|
+
{/if}
|
|
540
552
|
</td>
|
|
541
553
|
{/if}
|
|
542
554
|
|
|
@@ -114,6 +114,8 @@ export type TableProps<T = DataRow> = {
|
|
|
114
114
|
data: T[];
|
|
115
115
|
/** Column definitions — see `TableColumn`. */
|
|
116
116
|
columns: TableColumn<T>[];
|
|
117
|
+
/** Cell/header density. @default 'md' */
|
|
118
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
|
117
119
|
/** Show horizontal/vertical borders. @default true (unless a title/subtitle is set) */
|
|
118
120
|
bordered?: boolean;
|
|
119
121
|
/** Alternate row backgrounds. @default false */
|
|
@@ -160,6 +162,13 @@ export type TableProps<T = DataRow> = {
|
|
|
160
162
|
onpagechange?: (page: number) => void;
|
|
161
163
|
/** Per-row dynamic classes (e.g. tint by status). */
|
|
162
164
|
rowClass?: (row: T, index: number) => ClassValue;
|
|
165
|
+
/**
|
|
166
|
+
* Per-row selectability gate. Return `false` to hide the checkbox
|
|
167
|
+
* for that row. When omitted every row is selectable (if `selectable`
|
|
168
|
+
* is true). Doesn't affect `select all` — unselectable rows are
|
|
169
|
+
* excluded automatically.
|
|
170
|
+
*/
|
|
171
|
+
isRowSelectable?: (row: T) => boolean;
|
|
163
172
|
/** Show a skeleton placeholder instead of rows while loading. @default false */
|
|
164
173
|
loading?: boolean;
|
|
165
174
|
/** Expanded-row content snippet. Only used when `expandable` is true. */
|
|
@@ -8,7 +8,7 @@ export const table = tv({
|
|
|
8
8
|
thead: '',
|
|
9
9
|
tbody: 'divide-y divide-default-200',
|
|
10
10
|
tr: 'transition-colors hover:bg-default-50',
|
|
11
|
-
th: 'text-xs font-medium tracking-wider text-gray-500
|
|
11
|
+
th: 'text-xs font-medium tracking-wider text-gray-500 whitespace-nowrap',
|
|
12
12
|
td: 'whitespace-nowrap',
|
|
13
13
|
footer: 'p-4',
|
|
14
14
|
pagination: 'flex items-center justify-between',
|
|
@@ -19,28 +19,28 @@ export const table = tv({
|
|
|
19
19
|
variants: {
|
|
20
20
|
size: {
|
|
21
21
|
xs: {
|
|
22
|
-
th: 'px-
|
|
23
|
-
td: 'px-
|
|
22
|
+
th: 'px-1.5 py-1 text-[10px]',
|
|
23
|
+
td: 'px-1.5 py-1 text-[10px]'
|
|
24
24
|
},
|
|
25
25
|
sm: {
|
|
26
|
-
th: 'px-
|
|
27
|
-
td: 'px-
|
|
26
|
+
th: 'px-2 py-1.5 text-[11px]',
|
|
27
|
+
td: 'px-2 py-1.5 text-[11px]'
|
|
28
28
|
},
|
|
29
29
|
md: {
|
|
30
|
-
th: 'px-
|
|
31
|
-
td: 'px-
|
|
30
|
+
th: 'px-2.5 py-2 text-xs',
|
|
31
|
+
td: 'px-2.5 py-2 text-xs'
|
|
32
32
|
},
|
|
33
33
|
lg: {
|
|
34
|
-
th: 'px-
|
|
35
|
-
td: 'px-
|
|
34
|
+
th: 'px-4 py-3 text-sm',
|
|
35
|
+
td: 'px-4 py-3 text-sm'
|
|
36
36
|
},
|
|
37
37
|
xl: {
|
|
38
|
-
th: 'px-
|
|
39
|
-
td: 'px-
|
|
38
|
+
th: 'px-6 py-4 text-base',
|
|
39
|
+
td: 'px-6 py-4 text-base'
|
|
40
40
|
},
|
|
41
41
|
'2xl': {
|
|
42
|
-
th: 'px-
|
|
43
|
-
td: 'px-
|
|
42
|
+
th: 'px-8 py-5 text-lg',
|
|
43
|
+
td: 'px-8 py-5 text-lg'
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
color: {
|
package/dist/layout/tabs/tabs.js
CHANGED
|
@@ -25,16 +25,16 @@ export const tabs = tv({
|
|
|
25
25
|
},
|
|
26
26
|
size: {
|
|
27
27
|
[Size.XS]: {
|
|
28
|
-
trigger: 'px-
|
|
28
|
+
trigger: 'px-1.5 py-0.5 text-[10px]'
|
|
29
29
|
},
|
|
30
30
|
[Size.SM]: {
|
|
31
|
-
trigger: 'px-2 py-1 text-
|
|
31
|
+
trigger: 'px-2 py-1 text-[11px]'
|
|
32
32
|
},
|
|
33
33
|
[Size.MD]: {
|
|
34
|
-
trigger: 'px-
|
|
34
|
+
trigger: 'px-2.5 py-1.5 text-xs'
|
|
35
35
|
},
|
|
36
36
|
[Size.LG]: {
|
|
37
|
-
trigger: 'px-
|
|
37
|
+
trigger: 'px-3 py-2 text-sm'
|
|
38
38
|
},
|
|
39
39
|
[Size.XL]: {
|
|
40
40
|
trigger: 'px-5 py-3 text-lg'
|
|
@@ -47,7 +47,7 @@ export const tabs = tv({
|
|
|
47
47
|
line: {},
|
|
48
48
|
pill: {
|
|
49
49
|
list: 'flex flex-nowrap border-none gap-2 p-1 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
|
|
50
|
-
trigger: 'inline-flex items-center shrink-0 whitespace-nowrap
|
|
50
|
+
trigger: 'inline-flex items-center shrink-0 whitespace-nowrap transition-all duration-200 ease-in-out cursor-pointer rounded-full border-0'
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
53
|
selected: {
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
<button
|
|
167
167
|
type="button"
|
|
168
168
|
onclick={toggleApiKeyVisibility}
|
|
169
|
-
class="bg-default-50 text-default-500 hover:text-default-700 absolute top-1/2 right-3 -translate-y-1/2"
|
|
169
|
+
class="bg-default-50 text-default-500 hover:text-default-700 absolute top-1/2 right-3 -translate-y-1/2 cursor-pointer"
|
|
170
170
|
aria-label={showApiKey ? 'Hide API key' : 'Show API key'}
|
|
171
171
|
>
|
|
172
172
|
{#if showApiKey}
|