@reshape-biotech/design-system 2.7.36 → 2.7.38
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/components/activity/Activity.svelte +6 -4
- package/dist/components/button/Button.svelte +2 -1
- package/dist/components/card/Card.svelte +7 -5
- package/dist/components/card/CardWrapper.svelte +10 -13
- package/dist/components/checkbox/Checkbox.svelte +3 -2
- package/dist/components/combobox/components/combobox-content.svelte +2 -1
- package/dist/components/datepicker/DatePicker.svelte +8 -5
- package/dist/components/divider/Divider.svelte +7 -3
- package/dist/components/drawer/components/drawer-content.svelte +2 -1
- package/dist/components/drawer/components/drawer-title.svelte +2 -1
- package/dist/components/dropdown/components/dropdown-item.svelte +2 -1
- package/dist/components/dropdown/components/dropdown-sub-trigger.svelte +2 -1
- package/dist/components/graphs/scatterplot/Scatterplot.stories.svelte +119 -50
- package/dist/components/graphs/scatterplot/Scatterplot.svelte +99 -80
- package/dist/components/graphs/scatterplot/Scatterplot.svelte.d.ts +1 -1
- package/dist/components/icon-button/IconButton.svelte +3 -2
- package/dist/components/input/Input.svelte +2 -1
- package/dist/components/label/Label.svelte +3 -1
- package/dist/components/list/List.svelte +4 -1
- package/dist/components/markdown/Markdown.svelte +2 -1
- package/dist/components/segmented-control-buttons/ControlButton.svelte +7 -1
- package/dist/components/segmented-control-buttons/SegmentedControlButtons.svelte +2 -1
- package/dist/components/select/components/MultiSelectTrigger.svelte +5 -2
- package/dist/components/select/components/SelectItem.svelte +2 -1
- package/dist/components/select/components/SelectTrigger.svelte +2 -1
- package/dist/components/skeleton-loader/SkeletonLoader.svelte +6 -1
- package/dist/components/slider/Slider.svelte +6 -3
- package/dist/components/status-badge/StatusBadge.svelte +4 -2
- package/dist/components/status-badge/StatusBadge.svelte.d.ts +1 -0
- package/dist/components/table/Table.svelte +2 -1
- package/dist/components/table/components/TBody.svelte +2 -1
- package/dist/components/table/components/THead.svelte +2 -1
- package/dist/components/table/components/Td.svelte +2 -1
- package/dist/components/table/components/Th.svelte +2 -1
- package/dist/components/table/components/Tr.svelte +2 -1
- package/dist/components/tabs/components/Tab.svelte +2 -1
- package/dist/components/tabs/components/Tabs.svelte +2 -1
- package/dist/components/tag/Tag.svelte +3 -2
- package/dist/components/tooltip/Tooltip.svelte +2 -1
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import ActivityIcon from './ActivityIcon.svelte';
|
|
4
4
|
import type { ActivityIconType } from './ActivityIcon.svelte';
|
|
5
5
|
import { DateTime } from 'luxon';
|
|
6
|
+
import { twMerge } from 'tailwind-merge';
|
|
6
7
|
|
|
7
8
|
type Activity = {
|
|
8
9
|
activity_type?: string;
|
|
@@ -54,13 +55,14 @@
|
|
|
54
55
|
let { class: className = '', activity }: Props = $props();
|
|
55
56
|
</script>
|
|
56
57
|
|
|
57
|
-
<div class={
|
|
58
|
+
<div class={twMerge('group flex items-stretch gap-3', className)}>
|
|
58
59
|
<div class="flex min-h-12 flex-col items-center gap-1.5">
|
|
59
60
|
<div class="bg-neutral w-0.5 grow group-first:invisible"></div>
|
|
60
61
|
<div
|
|
61
|
-
class=
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
class={twMerge(
|
|
63
|
+
'text-secondary flex h-5 w-5 shrink-0 items-center justify-center rounded p-0.5',
|
|
64
|
+
ACTIVITY_BACKGROUND[activity.icon]
|
|
65
|
+
)}
|
|
64
66
|
>
|
|
65
67
|
<ActivityIcon icon={activity.icon} />
|
|
66
68
|
</div>
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
</script>
|
|
13
13
|
|
|
14
14
|
<script lang="ts">
|
|
15
|
+
import { twMerge } from 'tailwind-merge';
|
|
15
16
|
import Spinner from '../spinner/Spinner.svelte';
|
|
16
17
|
import type { Snippet } from 'svelte';
|
|
17
18
|
|
|
@@ -66,7 +67,7 @@
|
|
|
66
67
|
{id}
|
|
67
68
|
{tabindex}
|
|
68
69
|
class:cursor-wait={loading}
|
|
69
|
-
class=
|
|
70
|
+
class={twMerge('button', variantClass, sizeClass, className)}
|
|
70
71
|
data-testid={dataTestId}
|
|
71
72
|
class:rounded
|
|
72
73
|
class:disabled
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
4
|
|
|
4
5
|
type Props = {
|
|
5
6
|
Header?: Snippet;
|
|
@@ -19,19 +20,20 @@
|
|
|
19
20
|
</script>
|
|
20
21
|
|
|
21
22
|
<div
|
|
22
|
-
class=
|
|
23
|
+
class={twMerge(
|
|
24
|
+
'overflow-hidden rounded-[10px] border border-static bg-surface shadow-container',
|
|
25
|
+
additionalClasses
|
|
26
|
+
)}
|
|
23
27
|
>
|
|
24
28
|
{#if Header}
|
|
25
29
|
<header
|
|
26
|
-
class=
|
|
27
|
-
class:border-b={headerBorder}
|
|
28
|
-
class:border-static={headerBorder}
|
|
30
|
+
class={twMerge('flex min-h-12 items-center px-4', headerBorder && 'border-b border-static')}
|
|
29
31
|
>
|
|
30
32
|
{@render Header()}
|
|
31
33
|
</header>
|
|
32
34
|
{/if}
|
|
33
35
|
{#if children}
|
|
34
|
-
<div class={`p-${padding}`}>
|
|
36
|
+
<div class={twMerge(`p-${padding}`)}>
|
|
35
37
|
{@render children()}
|
|
36
38
|
</div>
|
|
37
39
|
{/if}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { ClassValue } from 'svelte/elements';
|
|
4
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
5
|
|
|
5
6
|
type Props = {
|
|
6
7
|
Header?: Snippet;
|
|
@@ -19,28 +20,24 @@
|
|
|
19
20
|
}: Props = $props();
|
|
20
21
|
</script>
|
|
21
22
|
|
|
22
|
-
<div class={
|
|
23
|
+
<div class={twMerge('wrapper', variant, additionalClasses)}>
|
|
23
24
|
{#if Header}
|
|
24
25
|
<header
|
|
25
|
-
class={
|
|
26
|
+
class={twMerge(
|
|
26
27
|
'flex w-full items-center justify-between',
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
},
|
|
31
|
-
]}
|
|
28
|
+
variant === 'default' && 'min-h-10 px-4',
|
|
29
|
+
variant === 'compact' && 'min-h-8 px-3'
|
|
30
|
+
)}
|
|
32
31
|
>
|
|
33
32
|
{@render Header()}
|
|
34
33
|
</header>
|
|
35
34
|
{/if}
|
|
36
35
|
<div
|
|
37
|
-
class={
|
|
36
|
+
class={twMerge(
|
|
38
37
|
'flex w-full flex-col !overflow-hidden [&>*]:w-full',
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
},
|
|
43
|
-
]}
|
|
38
|
+
variant === 'default' && 'gap-1 [&>*]:rounded-xl',
|
|
39
|
+
variant === 'compact' && 'gap-0.5 [&>*]:rounded-[10px]'
|
|
40
|
+
)}
|
|
44
41
|
>
|
|
45
42
|
{@render children()}
|
|
46
43
|
</div>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
2
3
|
import Check from 'phosphor-svelte/lib/Check';
|
|
3
4
|
import Minus from 'phosphor-svelte/lib/Minus';
|
|
4
5
|
import { Icon } from '../icons/index.js';
|
|
@@ -6,13 +7,13 @@
|
|
|
6
7
|
|
|
7
8
|
export type CheckboxProps = CheckboxRootProps;
|
|
8
9
|
|
|
9
|
-
let { checked = $bindable(false), onCheckedChange, name, ...props }: CheckboxProps = $props();
|
|
10
|
+
let { checked = $bindable(false), onCheckedChange, name, class: className, ...props }: CheckboxProps = $props();
|
|
10
11
|
</script>
|
|
11
12
|
|
|
12
13
|
<Checkbox.Root bind:checked {onCheckedChange} {...props}>
|
|
13
14
|
{#snippet children({ checked, indeterminate })}
|
|
14
15
|
<div
|
|
15
|
-
class={
|
|
16
|
+
class={twMerge('flex items-center justify-center rounded border border-static', checked && 'bg-dark-accent-inverse-hover', className)}
|
|
16
17
|
>
|
|
17
18
|
{#if checked}
|
|
18
19
|
<Icon class="text-primary-inverse" icon={Check} />
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { Combobox } from 'bits-ui';
|
|
6
6
|
import type { ComboboxContentProps } from '../types';
|
|
7
7
|
import { fade } from 'svelte/transition';
|
|
8
|
+
import { twMerge } from 'tailwind-merge';
|
|
8
9
|
|
|
9
10
|
let {
|
|
10
11
|
children,
|
|
@@ -30,7 +31,7 @@
|
|
|
30
31
|
<Icon icon={CaretUp} color="tertiary" />
|
|
31
32
|
</Combobox.ScrollUpButton>
|
|
32
33
|
<Combobox.Viewport class="overflow-y-auto">
|
|
33
|
-
<div class=
|
|
34
|
+
<div class={twMerge(paddedContent ? 'p-1' : '', 'empty:p-0')}>
|
|
34
35
|
{@render children()}
|
|
35
36
|
</div>
|
|
36
37
|
</Combobox.Viewport>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import CaretRight from 'phosphor-svelte/lib/CaretRight';
|
|
4
4
|
import { Icon } from '../icons/index.js';
|
|
5
5
|
import { run } from 'svelte/legacy';
|
|
6
|
+
import { twMerge } from 'tailwind-merge';
|
|
6
7
|
|
|
7
8
|
import { DateTime, type MonthNumbers } from 'luxon';
|
|
8
9
|
|
|
@@ -125,11 +126,13 @@
|
|
|
125
126
|
{#if dayOfMonth > 0}
|
|
126
127
|
<div class="date-container">
|
|
127
128
|
<p
|
|
128
|
-
class={
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
class={twMerge(
|
|
130
|
+
'date',
|
|
131
|
+
dayOfMonth === selectedDay &&
|
|
132
|
+
selectedMonth === shownMonth &&
|
|
133
|
+
selectedYear === shownYear &&
|
|
134
|
+
'selected-date'
|
|
135
|
+
)}
|
|
133
136
|
>
|
|
134
137
|
<button
|
|
135
138
|
onclick={() => {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
2
4
|
interface Props {
|
|
3
5
|
class?: string;
|
|
4
6
|
vertical?: boolean;
|
|
@@ -9,7 +11,9 @@
|
|
|
9
11
|
</script>
|
|
10
12
|
|
|
11
13
|
<div
|
|
12
|
-
class={
|
|
13
|
-
vertical ? 'h-full w-0 border-l' : 'h-0 w-full border-b'
|
|
14
|
-
|
|
14
|
+
class={twMerge(
|
|
15
|
+
vertical ? 'h-full w-0 border-l' : 'h-0 w-full border-b',
|
|
16
|
+
inverse ? 'border-static-inverse' : 'border-static',
|
|
17
|
+
className
|
|
18
|
+
)}
|
|
15
19
|
></div>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { Icon } from '../../icons/index.js';
|
|
4
4
|
import { Dialog } from 'bits-ui';
|
|
5
5
|
import { fly } from 'svelte/transition';
|
|
6
|
+
import { twMerge } from 'tailwind-merge';
|
|
6
7
|
import type { DrawerContentProps } from '../types';
|
|
7
8
|
import Overlay from './drawer-overlay.svelte';
|
|
8
9
|
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
|
|
21
22
|
const baseClasses = 'fixed top-0 h-screen z-50 w-[460px] flex flex-col bg-surface shadow-lg';
|
|
22
23
|
const sideClasses = side === 'left' ? 'left-0' : 'right-0';
|
|
23
|
-
const finalClasses =
|
|
24
|
+
const finalClasses = twMerge(baseClasses, sideClasses, className);
|
|
24
25
|
|
|
25
26
|
const getTransitionParams = (side: 'left' | 'right') => ({
|
|
26
27
|
x: side === 'left' ? -300 : 300,
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Dialog } from 'bits-ui';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
4
|
import type { DrawerTitleProps } from '../types';
|
|
4
5
|
|
|
5
6
|
let { children, class: className = '', icon, ...restProps }: DrawerTitleProps = $props();
|
|
6
7
|
|
|
7
8
|
const baseClasses = 'text-xl font-semibold tracking-tight text-primary';
|
|
8
|
-
const finalClasses =
|
|
9
|
+
const finalClasses = twMerge(baseClasses, className);
|
|
9
10
|
</script>
|
|
10
11
|
|
|
11
12
|
<div class="space-y-6">
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { DropdownMenu } from 'bits-ui';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
4
|
import type { DropdownItemProps } from '../types';
|
|
4
5
|
|
|
5
6
|
let {
|
|
@@ -18,7 +19,7 @@
|
|
|
18
19
|
{:else}
|
|
19
20
|
<div
|
|
20
21
|
{...props}
|
|
21
|
-
class=
|
|
22
|
+
class={twMerge('dropdown-item flex gap-2 cursor-pointer items-center rounded-md px-2.5 py-2 min-h-10 text-sm outline-none transition-colors hover:bg-neutral focus:bg-neutral data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_a]:no-underline', className)}
|
|
22
23
|
>
|
|
23
24
|
{@render children?.()}
|
|
24
25
|
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { DropdownMenu } from 'bits-ui';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
4
|
import CaretRight from 'phosphor-svelte/lib/CaretRight';
|
|
4
5
|
import CaretLeft from 'phosphor-svelte/lib/CaretLeft';
|
|
5
6
|
import { Icon } from '../../icons/index.js';
|
|
@@ -17,7 +18,7 @@
|
|
|
17
18
|
{:else}
|
|
18
19
|
<div
|
|
19
20
|
{...props}
|
|
20
|
-
class=
|
|
21
|
+
class={twMerge('dropdown-sub-trigger flex h-9 cursor-pointer items-center justify-between gap-2 rounded-md px-2 py-1.5 text-sm outline-none transition-colors hover:bg-neutral focus:bg-neutral data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_a]:no-underline', className)}
|
|
21
22
|
>
|
|
22
23
|
{#if !hideChevron && side === 'left'}
|
|
23
24
|
<Icon color="tertiary" icon={chevronIcon} size={14} class="mr-2" />
|
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
});
|
|
11
11
|
|
|
12
12
|
const data: DataPoint[] = [
|
|
13
|
-
{ value: [10
|
|
14
|
-
{ value: [8
|
|
15
|
-
{ value: [13
|
|
16
|
-
{ value: [9
|
|
17
|
-
{ value: [12
|
|
18
|
-
{ value: [14
|
|
13
|
+
{ value: [10, 8], metadata: { id: '1' } },
|
|
14
|
+
{ value: [8, 7], metadata: { id: '2' } },
|
|
15
|
+
{ value: [13, 8], metadata: { id: '3' } },
|
|
16
|
+
{ value: [9, 9], metadata: { id: '4' } },
|
|
17
|
+
{ value: [12, 8], metadata: { id: '5' } },
|
|
18
|
+
{ value: [14, 8], metadata: { id: '6' } },
|
|
19
19
|
];
|
|
20
20
|
|
|
21
21
|
const errorBarsData: DataPoint[] = data.map((d) => ({
|
|
@@ -28,78 +28,147 @@
|
|
|
28
28
|
[12, 14],
|
|
29
29
|
];
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
function handleMouseOver(params: echarts.ECElementEvent) {}
|
|
34
|
-
|
|
35
|
-
function handleMouseOut() {}
|
|
31
|
+
let tooltipState = $state({ visible: false, x: 0, y: 0, point: null as DataPoint | null });
|
|
36
32
|
</script>
|
|
37
33
|
|
|
38
34
|
<Story name="Base" asChild>
|
|
39
35
|
<div class="h-[400px] w-full">
|
|
40
|
-
<Scatterplot
|
|
41
|
-
{data}
|
|
42
|
-
xAxisName="Manual count"
|
|
43
|
-
yAxisName="Analysis count"
|
|
44
|
-
onitemclick={handleItemClick}
|
|
45
|
-
onmouseover={handleMouseOver}
|
|
46
|
-
onmouseout={handleMouseOut}
|
|
47
|
-
/>
|
|
36
|
+
<Scatterplot {data} xAxisName="X axis" yAxisName="Y axis" />
|
|
48
37
|
</div>
|
|
49
38
|
</Story>
|
|
50
39
|
|
|
51
|
-
<Story name="With
|
|
40
|
+
<Story name="With reference line" asChild>
|
|
52
41
|
<div class="h-[400px] w-full">
|
|
53
|
-
<Scatterplot
|
|
54
|
-
{data}
|
|
55
|
-
{lineData}
|
|
56
|
-
xAxisName="Manual count"
|
|
57
|
-
yAxisName="Analysis count"
|
|
58
|
-
onitemclick={handleItemClick}
|
|
59
|
-
onmouseover={handleMouseOver}
|
|
60
|
-
onmouseout={handleMouseOut}
|
|
61
|
-
/>
|
|
42
|
+
<Scatterplot {data} {lineData} xAxisName="X axis" yAxisName="Y axis" />
|
|
62
43
|
</div>
|
|
63
44
|
</Story>
|
|
64
|
-
|
|
45
|
+
|
|
46
|
+
<Story name="With error bars" asChild>
|
|
47
|
+
<div class="h-[400px] w-full">
|
|
48
|
+
<Scatterplot data={errorBarsData} {lineData} xAxisName="X axis" yAxisName="Y axis" />
|
|
49
|
+
</div>
|
|
50
|
+
</Story>
|
|
51
|
+
|
|
52
|
+
<Story name="With confidence band" asChild>
|
|
65
53
|
<div class="h-[400px] w-full">
|
|
66
54
|
<Scatterplot
|
|
67
55
|
data={errorBarsData}
|
|
68
56
|
{lineData}
|
|
69
|
-
xAxisName="
|
|
70
|
-
yAxisName="
|
|
71
|
-
|
|
72
|
-
onmouseover={handleMouseOver}
|
|
73
|
-
onmouseout={handleMouseOut}
|
|
57
|
+
xAxisName="X axis"
|
|
58
|
+
yAxisName="Y axis"
|
|
59
|
+
showConfidenceBand
|
|
74
60
|
/>
|
|
75
61
|
</div>
|
|
76
62
|
</Story>
|
|
77
|
-
|
|
63
|
+
|
|
64
|
+
<Story name="With legend" asChild>
|
|
78
65
|
<div class="h-[400px] w-full">
|
|
79
66
|
<Scatterplot
|
|
80
|
-
data
|
|
67
|
+
{data}
|
|
81
68
|
{lineData}
|
|
82
|
-
xAxisName="
|
|
83
|
-
yAxisName="
|
|
69
|
+
xAxisName="X axis"
|
|
70
|
+
yAxisName="Y axis"
|
|
84
71
|
showConfidenceBand
|
|
85
|
-
|
|
86
|
-
onmouseover={handleMouseOver}
|
|
87
|
-
onmouseout={handleMouseOut}
|
|
72
|
+
showLegend
|
|
88
73
|
/>
|
|
89
74
|
</div>
|
|
90
75
|
</Story>
|
|
91
|
-
|
|
76
|
+
|
|
77
|
+
<Story name="With groups" asChild>
|
|
78
|
+
{@const data: DataPoint[] = [
|
|
79
|
+
{ value: [8, 7], metadata: { id: 'A' } },
|
|
80
|
+
{ value: [8, 10], metadata: { id: 'A' } },
|
|
81
|
+
{ value: [15, 14], metadata: { id: 'B' } },
|
|
82
|
+
{ value: [23, 21], metadata: { id: 'C' } },
|
|
83
|
+
{ value: [23, 25], metadata: { id: 'C' } },
|
|
84
|
+
{ value: [23, 22], metadata: { id: 'C' } },
|
|
85
|
+
{ value: [35, 32], metadata: { id: 'D' } },
|
|
86
|
+
{ value: [35, 39], metadata: { id: 'D' }, disagreement: true },
|
|
87
|
+
{ value: [42, 41], metadata: { id: 'E' } },
|
|
88
|
+
{ value: [42, 44], metadata: { id: 'E' } },
|
|
89
|
+
{ value: [56, 58], metadata: { id: 'F' } },
|
|
90
|
+
]}
|
|
91
|
+
{@const groups = [[0, 1], [2], [3, 4, 5], [6, 7], [8, 9], [10]]}
|
|
92
|
+
{@const lineData: [[number, number], [number, number]] = [[0, 0], [65, 65]]}
|
|
92
93
|
<div class="h-[400px] w-full">
|
|
93
94
|
<Scatterplot
|
|
94
95
|
{data}
|
|
96
|
+
{groups}
|
|
95
97
|
{lineData}
|
|
96
|
-
xAxisName="
|
|
97
|
-
yAxisName="
|
|
98
|
+
xAxisName="X axis"
|
|
99
|
+
yAxisName="Y axis"
|
|
98
100
|
showConfidenceBand
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
onmouseover={(params) => {
|
|
102
|
+
tooltipState.visible = true;
|
|
103
|
+
tooltipState.x = (params.event?.event as MouseEvent)?.offsetX ?? 0;
|
|
104
|
+
tooltipState.y = (params.event?.event as MouseEvent)?.offsetY ?? 0;
|
|
105
|
+
tooltipState.point = params.data;
|
|
106
|
+
}}
|
|
107
|
+
onmouseout={() => {
|
|
108
|
+
tooltipState.visible = false;
|
|
109
|
+
tooltipState.point = null;
|
|
110
|
+
}}
|
|
111
|
+
>
|
|
112
|
+
{#if tooltipState.visible && tooltipState.point}
|
|
113
|
+
<div
|
|
114
|
+
class="pointer-events-none absolute z-50 rounded border bg-white p-2 text-xs shadow-lg"
|
|
115
|
+
style="left: {tooltipState.x + 10}px; top: {tooltipState.y + 10}px;"
|
|
116
|
+
>
|
|
117
|
+
<div class="font-medium">ID: {tooltipState.point.metadata.id}</div>
|
|
118
|
+
<div>X: {tooltipState.point.value[0]}</div>
|
|
119
|
+
<div>Y: {tooltipState.point.value[1]}</div>
|
|
120
|
+
</div>
|
|
121
|
+
{/if}
|
|
122
|
+
</Scatterplot>
|
|
123
|
+
</div>
|
|
124
|
+
</Story>
|
|
125
|
+
|
|
126
|
+
<Story name="Overlapping groups" asChild>
|
|
127
|
+
{@const data: DataPoint[] = [
|
|
128
|
+
{ value: [12, 9], metadata: { id: 'A' } },
|
|
129
|
+
{ value: [12, 15], metadata: { id: 'A' } },
|
|
130
|
+
{ value: [12, 12], metadata: { id: 'B' } },
|
|
131
|
+
{ value: [12, 18], metadata: { id: 'B' } },
|
|
132
|
+
{ value: [12, 14], metadata: { id: 'B' } },
|
|
133
|
+
{ value: [31, 27], metadata: { id: 'C' } },
|
|
134
|
+
{ value: [31, 34], metadata: { id: 'C' } },
|
|
135
|
+
{ value: [31, 30], metadata: { id: 'D' } },
|
|
136
|
+
]}
|
|
137
|
+
{@const groups = [
|
|
138
|
+
[0, 1],
|
|
139
|
+
[2, 3, 4],
|
|
140
|
+
[5, 6],
|
|
141
|
+
[7],
|
|
142
|
+
]}
|
|
143
|
+
{@const lineData: [[number, number], [number, number]] = [[0, 0], [40, 40]]}
|
|
144
|
+
<div class="h-[400px] w-full">
|
|
145
|
+
<Scatterplot
|
|
146
|
+
{data}
|
|
147
|
+
{groups}
|
|
148
|
+
{lineData}
|
|
149
|
+
xAxisName="X axis"
|
|
150
|
+
yAxisName="Y axis"
|
|
151
|
+
onmouseover={(params) => {
|
|
152
|
+
tooltipState.visible = true;
|
|
153
|
+
tooltipState.x = (params.event?.event as MouseEvent)?.offsetX ?? 0;
|
|
154
|
+
tooltipState.y = (params.event?.event as MouseEvent)?.offsetY ?? 0;
|
|
155
|
+
tooltipState.point = params.data;
|
|
156
|
+
}}
|
|
157
|
+
onmouseout={() => {
|
|
158
|
+
tooltipState.visible = false;
|
|
159
|
+
tooltipState.point = null;
|
|
160
|
+
}}
|
|
161
|
+
>
|
|
162
|
+
{#if tooltipState.visible && tooltipState.point}
|
|
163
|
+
<div
|
|
164
|
+
class="pointer-events-none absolute z-50 rounded border bg-white p-2 text-xs shadow-lg"
|
|
165
|
+
style="left: {tooltipState.x + 10}px; top: {tooltipState.y + 10}px;"
|
|
166
|
+
>
|
|
167
|
+
<div class="font-medium">ID: {tooltipState.point.metadata.id}</div>
|
|
168
|
+
<div>X: {tooltipState.point.value[0]}</div>
|
|
169
|
+
<div>Y: {tooltipState.point.value[1]}</div>
|
|
170
|
+
</div>
|
|
171
|
+
{/if}
|
|
172
|
+
</Scatterplot>
|
|
104
173
|
</div>
|
|
105
174
|
</Story>
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
export type DataPoint = {
|
|
17
17
|
value: [number, number];
|
|
18
18
|
metadata: any;
|
|
19
|
-
error_value?: number;
|
|
20
19
|
disagreement?: boolean | null;
|
|
21
20
|
highlighted?: boolean | null;
|
|
22
21
|
};
|
|
@@ -31,9 +30,15 @@
|
|
|
31
30
|
type: 'point' | 'line' | 'area';
|
|
32
31
|
};
|
|
33
32
|
|
|
33
|
+
type LineSegment = {
|
|
34
|
+
points: [number, number][];
|
|
35
|
+
disagreement?: boolean;
|
|
36
|
+
};
|
|
37
|
+
|
|
34
38
|
type ScatterPlotProps = {
|
|
35
39
|
data: DataPoint[];
|
|
36
40
|
lineData?: [[number, number], [number, number]];
|
|
41
|
+
groups?: number[][];
|
|
37
42
|
showConfidenceBand?: boolean;
|
|
38
43
|
showLegend?: boolean;
|
|
39
44
|
onitemclick?: (params: ScatterPlotEchartsEvent) => void;
|
|
@@ -58,10 +63,55 @@
|
|
|
58
63
|
{ label: 'Perfect agreement', color: backgroundColor['lilac-inverse'], type: 'line' },
|
|
59
64
|
],
|
|
60
65
|
highlightIndex = null,
|
|
66
|
+
groups = [],
|
|
61
67
|
children,
|
|
62
68
|
...props
|
|
63
69
|
}: ScatterPlotProps = $props();
|
|
64
70
|
|
|
71
|
+
let hoveredGroupIndices = $state<number[] | null>(null);
|
|
72
|
+
|
|
73
|
+
const findGroupForIndex = (idx: number): number[] | null => {
|
|
74
|
+
if (groups.length === 0) return null;
|
|
75
|
+
return groups.find((g) => g.includes(idx)) ?? null;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const highlightedIndices = $derived.by((): number[] | null => {
|
|
79
|
+
if (hoveredGroupIndices !== null) return hoveredGroupIndices;
|
|
80
|
+
if (highlightIndex !== null) {
|
|
81
|
+
const group = findGroupForIndex(highlightIndex);
|
|
82
|
+
return group ?? [highlightIndex];
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const groupLines = $derived.by((): LineSegment[] => {
|
|
88
|
+
if (groups.length === 0) return [];
|
|
89
|
+
|
|
90
|
+
return groups
|
|
91
|
+
.filter((g) => g.length > 1)
|
|
92
|
+
.map((groupIndices) => {
|
|
93
|
+
const points = groupIndices.map((i) => data[i]?.value).filter(Boolean) as [
|
|
94
|
+
number,
|
|
95
|
+
number,
|
|
96
|
+
][];
|
|
97
|
+
const hasDisagreement = groupIndices.some((i) => data[i]?.disagreement);
|
|
98
|
+
return { points, disagreement: hasDisagreement };
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const groupedDisagreement = $derived.by((): boolean[] => {
|
|
103
|
+
const result = data.map((d) => d.disagreement ?? false);
|
|
104
|
+
for (const groupIndices of groups) {
|
|
105
|
+
const hasDisagreement = groupIndices.some((i) => data[i]?.disagreement);
|
|
106
|
+
if (hasDisagreement) {
|
|
107
|
+
for (const i of groupIndices) {
|
|
108
|
+
result[i] = true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
});
|
|
114
|
+
|
|
65
115
|
const displayedLegendItems: LegendItem[] = $derived([
|
|
66
116
|
...legendItems,
|
|
67
117
|
...(showConfidenceBand
|
|
@@ -82,75 +132,44 @@
|
|
|
82
132
|
}
|
|
83
133
|
|
|
84
134
|
function handleMouseOver(params: ScatterPlotEchartsEvent) {
|
|
135
|
+
const hoveredIdx = params.dataIndex;
|
|
136
|
+
if (hoveredIdx !== undefined && hoveredIdx >= 0) {
|
|
137
|
+
const group = findGroupForIndex(hoveredIdx);
|
|
138
|
+
hoveredGroupIndices = group ?? [hoveredIdx];
|
|
139
|
+
}
|
|
85
140
|
onmouseover?.(params);
|
|
86
141
|
}
|
|
87
142
|
|
|
88
143
|
function handleMouseOut() {
|
|
144
|
+
hoveredGroupIndices = null;
|
|
89
145
|
onmouseout?.();
|
|
90
146
|
}
|
|
91
147
|
|
|
92
|
-
|
|
93
|
-
function renderErrorBarItem(
|
|
94
|
-
params: CustomSeriesRenderItemParams,
|
|
95
|
-
api: CustomSeriesRenderItemAPI
|
|
96
|
-
) {
|
|
148
|
+
function renderLineItem(params: CustomSeriesRenderItemParams, api: CustomSeriesRenderItemAPI) {
|
|
97
149
|
const xValue = api.value(0) as number;
|
|
98
|
-
const
|
|
99
|
-
const
|
|
150
|
+
const yMin = api.value(1) as number;
|
|
151
|
+
const yMax = api.value(2) as number;
|
|
100
152
|
const disagreement = api.value(3) as number;
|
|
101
153
|
|
|
102
|
-
const
|
|
103
|
-
const
|
|
154
|
+
const topPoint = api.coord([xValue, yMax]);
|
|
155
|
+
const bottomPoint = api.coord([xValue, yMin]);
|
|
104
156
|
|
|
105
|
-
if (!
|
|
157
|
+
if (!topPoint || !bottomPoint) {
|
|
106
158
|
return undefined;
|
|
107
159
|
}
|
|
108
160
|
|
|
109
|
-
// calculate a dynamic width for the caps based on the x-axis scale
|
|
110
|
-
const sizeValue = api.size?.([1, 0]);
|
|
111
|
-
const baseWidth = Array.isArray(sizeValue) ? sizeValue[0] : 10;
|
|
112
|
-
const halfWidth = Math.min((baseWidth ?? 10) * 1.5, 3);
|
|
113
|
-
const style = {
|
|
114
|
-
stroke: disagreement ? textColor['icon-tertiary'] : backgroundColor['blue-inverse'],
|
|
115
|
-
};
|
|
116
|
-
|
|
117
161
|
return {
|
|
118
|
-
type: '
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
style,
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
type: 'line' as const,
|
|
133
|
-
transition: 'shape' as const,
|
|
134
|
-
shape: {
|
|
135
|
-
x1: highPoint[0],
|
|
136
|
-
y1: highPoint[1],
|
|
137
|
-
x2: lowPoint[0],
|
|
138
|
-
y2: lowPoint[1],
|
|
139
|
-
},
|
|
140
|
-
style,
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
type: 'line' as const,
|
|
144
|
-
transition: 'shape' as const,
|
|
145
|
-
shape: {
|
|
146
|
-
x1: lowPoint[0] - halfWidth,
|
|
147
|
-
y1: lowPoint[1],
|
|
148
|
-
x2: lowPoint[0] + halfWidth,
|
|
149
|
-
y2: lowPoint[1],
|
|
150
|
-
},
|
|
151
|
-
style,
|
|
152
|
-
},
|
|
153
|
-
],
|
|
162
|
+
type: 'line' as const,
|
|
163
|
+
shape: {
|
|
164
|
+
x1: topPoint[0],
|
|
165
|
+
y1: topPoint[1],
|
|
166
|
+
x2: bottomPoint[0],
|
|
167
|
+
y2: bottomPoint[1],
|
|
168
|
+
},
|
|
169
|
+
style: {
|
|
170
|
+
stroke: disagreement ? textColor['icon-tertiary'] : backgroundColor['blue-inverse'],
|
|
171
|
+
lineWidth: 1.5,
|
|
172
|
+
},
|
|
154
173
|
};
|
|
155
174
|
}
|
|
156
175
|
|
|
@@ -158,9 +177,6 @@
|
|
|
158
177
|
|
|
159
178
|
function getChartOptions(): EChartsOption {
|
|
160
179
|
const series: SeriesOption[] = [];
|
|
161
|
-
const errorBarData = data
|
|
162
|
-
.filter((d) => d.error_value != 0)
|
|
163
|
-
.map((d) => [...d.value, d.error_value, d.disagreement ? 1 : 0]);
|
|
164
180
|
|
|
165
181
|
if (props.lineData && props.lineData.length > 0) {
|
|
166
182
|
const extendedLineData = [
|
|
@@ -226,36 +242,32 @@
|
|
|
226
242
|
type: 'scatter',
|
|
227
243
|
itemStyle: {
|
|
228
244
|
color: (params: any) =>
|
|
229
|
-
params
|
|
245
|
+
groupedDisagreement[params.dataIndex]
|
|
246
|
+
? textColor['icon-tertiary']
|
|
247
|
+
: backgroundColor['blue-inverse'],
|
|
230
248
|
opacity: 1,
|
|
231
249
|
},
|
|
232
250
|
emphasis: {
|
|
233
|
-
|
|
234
|
-
color: (params: any) => {
|
|
235
|
-
const point = params?.data as DataPoint;
|
|
236
|
-
return point?.disagreement
|
|
237
|
-
? textColor['icon-tertiary']
|
|
238
|
-
: backgroundColor['blue-inverse'];
|
|
239
|
-
},
|
|
240
|
-
opacity: 1,
|
|
241
|
-
},
|
|
251
|
+
disabled: true,
|
|
242
252
|
},
|
|
243
253
|
animation: false,
|
|
244
254
|
});
|
|
245
255
|
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
?
|
|
249
|
-
|
|
256
|
+
const highlightPoints =
|
|
257
|
+
highlightedIndices !== null
|
|
258
|
+
? highlightedIndices
|
|
259
|
+
.filter((i) => i >= 0 && i < data.length)
|
|
260
|
+
.map((i) => ({ point: data[i], index: i }))
|
|
261
|
+
: [];
|
|
250
262
|
series.push({
|
|
251
263
|
id: 'highlight-overlay',
|
|
252
264
|
type: 'scatter',
|
|
253
|
-
data:
|
|
265
|
+
data: highlightPoints.map((h) => h.point),
|
|
254
266
|
symbolSize: 16,
|
|
255
267
|
itemStyle: {
|
|
256
268
|
color: (params: any) => {
|
|
257
|
-
const
|
|
258
|
-
return
|
|
269
|
+
const originalIndex = highlightPoints[params.dataIndex]?.index;
|
|
270
|
+
return groupedDisagreement[originalIndex]
|
|
259
271
|
? backgroundColor['neutral-hover']
|
|
260
272
|
: backgroundColor['blue-hover'];
|
|
261
273
|
},
|
|
@@ -264,16 +276,23 @@
|
|
|
264
276
|
silent: true,
|
|
265
277
|
});
|
|
266
278
|
|
|
267
|
-
if (
|
|
279
|
+
if (groupLines.length > 0) {
|
|
280
|
+
const linesData = groupLines.map((line) => {
|
|
281
|
+
const yValues = line.points.map((p: [number, number]) => p[1]);
|
|
282
|
+
const xValue = line.points[0][0];
|
|
283
|
+
return [xValue, Math.min(...yValues), Math.max(...yValues), line.disagreement ? 1 : 0];
|
|
284
|
+
});
|
|
285
|
+
|
|
268
286
|
series.push({
|
|
269
287
|
type: 'custom',
|
|
270
|
-
name: '
|
|
288
|
+
name: 'lines',
|
|
271
289
|
silent: true,
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
290
|
+
renderItem: renderLineItem,
|
|
291
|
+
data: linesData,
|
|
292
|
+
z: -1,
|
|
275
293
|
});
|
|
276
294
|
}
|
|
295
|
+
|
|
277
296
|
return {
|
|
278
297
|
xAxis: {
|
|
279
298
|
type: 'value',
|
|
@@ -4,7 +4,6 @@ import type { Snippet } from 'svelte';
|
|
|
4
4
|
export type DataPoint = {
|
|
5
5
|
value: [number, number];
|
|
6
6
|
metadata: any;
|
|
7
|
-
error_value?: number;
|
|
8
7
|
disagreement?: boolean | null;
|
|
9
8
|
highlighted?: boolean | null;
|
|
10
9
|
};
|
|
@@ -19,6 +18,7 @@ type LegendItem = {
|
|
|
19
18
|
type ScatterPlotProps = {
|
|
20
19
|
data: DataPoint[];
|
|
21
20
|
lineData?: [[number, number], [number, number]];
|
|
21
|
+
groups?: number[][];
|
|
22
22
|
showConfidenceBand?: boolean;
|
|
23
23
|
showLegend?: boolean;
|
|
24
24
|
onitemclick?: (params: ScatterPlotEchartsEvent) => void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
2
3
|
import type { Snippet } from 'svelte';
|
|
3
4
|
import { Spinner } from '../spinner/';
|
|
4
5
|
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
@@ -50,7 +51,7 @@
|
|
|
50
51
|
}}
|
|
51
52
|
{type}
|
|
52
53
|
{disabled}
|
|
53
|
-
class=
|
|
54
|
+
class={twMerge(sizeClass, variantClass, 'disabled', className)}
|
|
54
55
|
class:rounded
|
|
55
56
|
{...rest}
|
|
56
57
|
>
|
|
@@ -66,7 +67,7 @@
|
|
|
66
67
|
{type}
|
|
67
68
|
{disabled}
|
|
68
69
|
{tabindex}
|
|
69
|
-
class=
|
|
70
|
+
class={twMerge(sizeClass, variantClass, className)}
|
|
70
71
|
class:rounded
|
|
71
72
|
{...rest}
|
|
72
73
|
>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
2
3
|
import X from 'phosphor-svelte/lib/X';
|
|
3
4
|
import { Icon } from '../icons/index.js';
|
|
4
5
|
import type { Snippet } from 'svelte';
|
|
@@ -91,7 +92,7 @@
|
|
|
91
92
|
|
|
92
93
|
<div class="flex-1">
|
|
93
94
|
<div
|
|
94
|
-
class=
|
|
95
|
+
class={twMerge('flex w-full items-center gap-1 transition-colors', `size-${size}`, className)}
|
|
95
96
|
class:!border-error={!valid}
|
|
96
97
|
class:primary={variant === 'primary'}
|
|
97
98
|
class:secondary={variant === 'secondary'}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
2
4
|
interface Props {
|
|
3
5
|
forId: string;
|
|
4
6
|
text: string;
|
|
@@ -9,7 +11,7 @@
|
|
|
9
11
|
const { forId, text, required = false, class: className }: Props = $props();
|
|
10
12
|
</script>
|
|
11
13
|
|
|
12
|
-
<label for={forId} class=
|
|
14
|
+
<label for={forId} class={twMerge('block text-sm text-secondary', className)}>
|
|
13
15
|
{text}
|
|
14
16
|
{#if required}
|
|
15
17
|
<span class="ml-0.5 text-danger">*</span>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts" generics="T">
|
|
2
2
|
import type { Overflow } from '../../tailwind';
|
|
3
3
|
import type { Snippet } from 'svelte';
|
|
4
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
5
|
|
|
5
6
|
type Props = {
|
|
6
7
|
items: T[];
|
|
@@ -11,7 +12,9 @@
|
|
|
11
12
|
let { items, item, overflow = 'overflow-y-auto', variant = 'default' }: Props = $props();
|
|
12
13
|
</script>
|
|
13
14
|
|
|
14
|
-
<div
|
|
15
|
+
<div
|
|
16
|
+
class={twMerge('listStyles', variant === 'compact' ? 'compact' : 'default', overflow)}
|
|
17
|
+
>
|
|
15
18
|
{#each items as currentItem, i}
|
|
16
19
|
<div class="item">
|
|
17
20
|
{@render item(currentItem)}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { marked } from 'marked';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
4
|
interface Props {
|
|
4
5
|
markdown: string;
|
|
5
6
|
variant?: 'light' | 'dark';
|
|
@@ -8,6 +9,6 @@
|
|
|
8
9
|
let { markdown, variant = 'light' }: Props = $props();
|
|
9
10
|
</script>
|
|
10
11
|
|
|
11
|
-
<div class=
|
|
12
|
+
<div class={twMerge('prose prose-slate text-sm', variant === 'dark' && 'dark:prose-invert')}>
|
|
12
13
|
{@html marked.parse(markdown ?? '')}
|
|
13
14
|
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
4
|
|
|
4
5
|
type Color = 'primary' | 'secondary';
|
|
5
6
|
|
|
@@ -32,7 +33,12 @@
|
|
|
32
33
|
<div class="join-item flex h-full flex-1">
|
|
33
34
|
<button
|
|
34
35
|
{onclick}
|
|
35
|
-
class={
|
|
36
|
+
class={twMerge(
|
|
37
|
+
'control-button flex flex-1 items-center justify-center gap-2 rounded-md text-sm leading-4',
|
|
38
|
+
colors[color],
|
|
39
|
+
color,
|
|
40
|
+
className
|
|
41
|
+
)}
|
|
36
42
|
class:active
|
|
37
43
|
type="button"
|
|
38
44
|
{disabled}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
4
|
import ControlButton from './ControlButton.svelte';
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
@@ -16,6 +17,6 @@
|
|
|
16
17
|
};
|
|
17
18
|
</script>
|
|
18
19
|
|
|
19
|
-
<div class={
|
|
20
|
+
<div class={twMerge('join flex gap-1 rounded-lg bg-neutral p-1', sizes[size], size, className)}>
|
|
20
21
|
{@render children?.({ ControlButton })}
|
|
21
22
|
</div>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import Icon from '../../icons/Icon.svelte';
|
|
4
4
|
import * as Select from '../index';
|
|
5
5
|
import IconButton from '../../icon-button/IconButton.svelte';
|
|
6
|
+
import { twMerge } from 'tailwind-merge';
|
|
6
7
|
|
|
7
8
|
type ItemType = {
|
|
8
9
|
value: string;
|
|
@@ -30,8 +31,10 @@
|
|
|
30
31
|
</script>
|
|
31
32
|
|
|
32
33
|
<Select.Trigger
|
|
33
|
-
class={
|
|
34
|
-
|
|
34
|
+
class={twMerge(
|
|
35
|
+
'flex h-fit min-h-10 w-full items-center justify-between rounded-lg border border-input bg-surface py-1 text-sm placeholder:text-tertiary focus:outline-none disabled:cursor-not-allowed disabled:border-transparent disabled:bg-neutral disabled:opacity-75',
|
|
36
|
+
className
|
|
37
|
+
)}
|
|
35
38
|
{...restProps}
|
|
36
39
|
>
|
|
37
40
|
{#if selectedValues.length === 0}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import Check from 'phosphor-svelte/lib/Check';
|
|
3
3
|
import { Icon } from '../../icons/index.js';
|
|
4
4
|
import { Select as SelectPrimitive } from 'bits-ui';
|
|
5
|
+
import { twMerge } from 'tailwind-merge';
|
|
5
6
|
import type { ItemProps, ItemSlotProps } from '../types';
|
|
6
7
|
|
|
7
8
|
import type { Snippet } from 'svelte';
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
`;
|
|
22
23
|
</script>
|
|
23
24
|
|
|
24
|
-
<SelectPrimitive.Item {...restProps} class={baseClasses
|
|
25
|
+
<SelectPrimitive.Item {...restProps} class={twMerge(baseClasses, className)}>
|
|
25
26
|
{#snippet children(params: ItemSlotProps)}
|
|
26
27
|
{#if children}
|
|
27
28
|
{@render children(params)}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import CaretDown from 'phosphor-svelte/lib/CaretDown';
|
|
3
3
|
import { Icon } from '../../icons/index.js';
|
|
4
4
|
import { Select as SelectPrimitive } from 'bits-ui';
|
|
5
|
+
import { twMerge } from 'tailwind-merge';
|
|
5
6
|
import type { TriggerProps, IconSnippet } from '../types';
|
|
6
7
|
|
|
7
8
|
import type { Snippet } from 'svelte';
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
|
|
38
39
|
<SelectPrimitive.Trigger
|
|
39
40
|
{...restProps}
|
|
40
|
-
class={
|
|
41
|
+
class={twMerge(baseClasses, className)}
|
|
41
42
|
aria-label={placeholder}
|
|
42
43
|
>
|
|
43
44
|
<div class="flex-1 truncate text-left">
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import Skeleton from './components/Skeleton.svelte';
|
|
4
4
|
import SkeletonImage from './components/SkeletonImage.svelte';
|
|
5
|
+
import { twMerge } from 'tailwind-merge';
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
7
8
|
class?: string;
|
|
@@ -12,6 +13,10 @@
|
|
|
12
13
|
let { class: className = '', dataTestId = '', children }: Props = $props();
|
|
13
14
|
</script>
|
|
14
15
|
|
|
15
|
-
<div
|
|
16
|
+
<div
|
|
17
|
+
role="status"
|
|
18
|
+
class={twMerge('h-full w-full animate-pulse', className)}
|
|
19
|
+
data-testid={dataTestId}
|
|
20
|
+
>
|
|
16
21
|
{@render children?.({ Skeleton, SkeletonImage })}
|
|
17
22
|
</div>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import CaretUpDown from 'phosphor-svelte/lib/CaretUpDown';
|
|
3
3
|
import { Icon } from '../icons/index.js';
|
|
4
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
5
|
|
|
5
6
|
let className = '';
|
|
6
7
|
export { className as class };
|
|
@@ -31,10 +32,12 @@
|
|
|
31
32
|
}
|
|
32
33
|
</script>
|
|
33
34
|
|
|
34
|
-
<div
|
|
35
|
+
<div
|
|
36
|
+
class={twMerge('relative flex h-10 items-center', disabled && 'opacity-40', className)}
|
|
37
|
+
>
|
|
35
38
|
<div class="track-overlay"></div>
|
|
36
39
|
<div
|
|
37
|
-
class=
|
|
40
|
+
class={twMerge('pointer-events-none absolute h-2.5 rounded-full', bufferColorClass)}
|
|
38
41
|
style="
|
|
39
42
|
width: {calculatePosition(buffer - bufferMin)} + 1rem);
|
|
40
43
|
left: {calculatePosition(bufferMin)}
|
|
@@ -42,7 +45,7 @@
|
|
|
42
45
|
></div>
|
|
43
46
|
{#if showFilled}
|
|
44
47
|
<div
|
|
45
|
-
class=
|
|
48
|
+
class={twMerge('absolute h-2.5 rounded-full', filledColorClass)}
|
|
46
49
|
style="width: {calculatePosition(value)} + 1rem);left: 0;"
|
|
47
50
|
></div>
|
|
48
51
|
{/if}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
4
|
|
|
4
5
|
interface Props {
|
|
5
6
|
// we can add dynamic classes because they are safelisted in tailwind-safelist.txt
|
|
@@ -9,6 +10,7 @@
|
|
|
9
10
|
progress?: Snippet;
|
|
10
11
|
icon?: Snippet;
|
|
11
12
|
iconOnly?: boolean;
|
|
13
|
+
class?: string;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
let {
|
|
@@ -18,14 +20,14 @@
|
|
|
18
20
|
progress,
|
|
19
21
|
icon,
|
|
20
22
|
iconOnly: propIconOnly = false,
|
|
23
|
+
class: className,
|
|
21
24
|
}: Props = $props();
|
|
22
25
|
|
|
23
26
|
let iconOnly = $derived((content === undefined && progress === undefined) || propIconOnly);
|
|
24
27
|
</script>
|
|
25
28
|
|
|
26
29
|
<div
|
|
27
|
-
class={`badge badge-${type} badge-${size}
|
|
28
|
-
class:badge-icon-only={iconOnly}
|
|
30
|
+
class={twMerge(`badge badge-${type} badge-${size}`, iconOnly && 'badge-icon-only', className)}
|
|
29
31
|
data-testid="status-badge"
|
|
30
32
|
>
|
|
31
33
|
{#if icon}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
2
3
|
import type { Snippet } from 'svelte';
|
|
3
4
|
import Td from './components/Td.svelte';
|
|
4
5
|
import Th from './components/Th.svelte';
|
|
@@ -32,7 +33,7 @@
|
|
|
32
33
|
</script>
|
|
33
34
|
|
|
34
35
|
<div class="w-full rounded-xl border border-static bg-surface px-5 py-2 shadow-container">
|
|
35
|
-
<table class={
|
|
36
|
+
<table class={twMerge('w-full table-fixed sm:table-auto', `xl:table-${tableLayout}`)}>
|
|
36
37
|
{@render children?.({ THead: THead, TBody: TBody, Tr: Tr, Th: Th, Td: Td })}
|
|
37
38
|
</table>
|
|
38
39
|
</div>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
2
3
|
import type { Snippet } from 'svelte';
|
|
3
4
|
|
|
4
5
|
interface Props {
|
|
@@ -9,6 +10,6 @@
|
|
|
9
10
|
let { class: className = '', children }: Props = $props();
|
|
10
11
|
</script>
|
|
11
12
|
|
|
12
|
-
<tbody class={
|
|
13
|
+
<tbody class={twMerge(className)}>
|
|
13
14
|
{@render children?.()}
|
|
14
15
|
</tbody>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
2
3
|
import type { Snippet } from 'svelte';
|
|
3
4
|
|
|
4
5
|
interface Props {
|
|
@@ -9,6 +10,6 @@
|
|
|
9
10
|
let { class: className = '', children }: Props = $props();
|
|
10
11
|
</script>
|
|
11
12
|
|
|
12
|
-
<thead class={
|
|
13
|
+
<thead class={twMerge(className)}>
|
|
13
14
|
{@render children?.()}
|
|
14
15
|
</thead>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
2
3
|
import type { Snippet } from 'svelte';
|
|
3
4
|
|
|
4
5
|
interface Props {
|
|
@@ -10,6 +11,6 @@
|
|
|
10
11
|
let { dataTestId = '', align = 'left', children }: Props = $props();
|
|
11
12
|
</script>
|
|
12
13
|
|
|
13
|
-
<td data-testid={dataTestId} class={`text-${align} text-sm font-normal
|
|
14
|
+
<td data-testid={dataTestId} class={twMerge(`text-${align}`, 'text-sm font-normal')}>
|
|
14
15
|
{@render children?.()}
|
|
15
16
|
</td>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
2
3
|
import type { Width } from '../../../tailwind';
|
|
3
4
|
import type { Snippet } from 'svelte';
|
|
4
5
|
|
|
@@ -10,6 +11,6 @@
|
|
|
10
11
|
let { class: className = '', children }: Props = $props();
|
|
11
12
|
</script>
|
|
12
13
|
|
|
13
|
-
<th class={
|
|
14
|
+
<th class={twMerge('text-left text-xs font-medium text-tertiary', className)}>
|
|
14
15
|
{@render children?.()}
|
|
15
16
|
</th>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
2
3
|
import type { Snippet } from 'svelte';
|
|
3
4
|
|
|
4
5
|
interface Props {
|
|
@@ -10,7 +11,7 @@
|
|
|
10
11
|
let { disabled = false, children, class: className = '' }: Props = $props();
|
|
11
12
|
</script>
|
|
12
13
|
|
|
13
|
-
<tr class={
|
|
14
|
+
<tr class={twMerge('border-static py-2 [&.disabled]:text-tertiary', className)} class:disabled>
|
|
14
15
|
{@render children?.()}
|
|
15
16
|
</tr>
|
|
16
17
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
4
|
import Button from '../../button/Button.svelte';
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
@@ -16,7 +17,7 @@
|
|
|
16
17
|
{onclick}
|
|
17
18
|
variant="transparent"
|
|
18
19
|
size="sm"
|
|
19
|
-
class={
|
|
20
|
+
class={twMerge('tab !h-full', active && 'active', className)}
|
|
20
21
|
>
|
|
21
22
|
{@render children?.()}
|
|
22
23
|
</Button>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
4
|
|
|
4
5
|
type Size = 'sm' | 'md' | 'lg';
|
|
5
6
|
type Variant = 'primary' | 'secondary' | 'transparent';
|
|
@@ -29,7 +30,7 @@
|
|
|
29
30
|
|
|
30
31
|
<div
|
|
31
32
|
role="tablist"
|
|
32
|
-
class={
|
|
33
|
+
class={twMerge('flex', sizes[size], variant, fullWidth ? 'w-full [&>*]:flex-1' : 'w-fit [&>*]:flex-none', className)}
|
|
33
34
|
>
|
|
34
35
|
{@render children?.({ variant })}
|
|
35
36
|
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
4
|
import { Tooltip } from '../tooltip/';
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
@@ -82,14 +83,14 @@
|
|
|
82
83
|
{#snippet renderTag()}
|
|
83
84
|
{#if onclick}
|
|
84
85
|
<button
|
|
85
|
-
class=
|
|
86
|
+
class={twMerge('outer', variantClassName, sizeClassName, buttonClassVariant, 'hover:cursor-pointer', className)}
|
|
86
87
|
title={tooltip}
|
|
87
88
|
{onclick}
|
|
88
89
|
>
|
|
89
90
|
{@render children()}
|
|
90
91
|
</button>
|
|
91
92
|
{:else}
|
|
92
|
-
<div class=
|
|
93
|
+
<div class={twMerge('outer', variantClassName, sizeClassName, 'no-underline', className)} title={tooltip}>
|
|
93
94
|
{@render children()}
|
|
94
95
|
</div>
|
|
95
96
|
{/if}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Tooltip } from 'bits-ui';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
4
|
import type { Snippet } from 'svelte';
|
|
4
5
|
import { backgroundColor } from '../../tokens';
|
|
5
6
|
|
|
@@ -50,7 +51,7 @@
|
|
|
50
51
|
{side}
|
|
51
52
|
{align}
|
|
52
53
|
sideOffset={8}
|
|
53
|
-
class={
|
|
54
|
+
class={twMerge('z-50 max-w-xs text-wrap rounded-md bg-base-inverse px-2 py-1 text-left text-sm font-normal text-primary-inverse shadow-menu', className)}
|
|
54
55
|
>
|
|
55
56
|
{#if content}
|
|
56
57
|
{@render content()}
|