@reshape-biotech/design-system 2.7.33 → 2.7.35
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/app.css +7 -0
- package/dist/components/button/Button.svelte +1 -1
- package/dist/components/combobox/Combobox.stories.svelte +124 -1
- package/dist/components/combobox/components/combobox-content.svelte +3 -1
- package/dist/components/dropdown/Dropdown.stories.svelte +20 -0
- package/dist/components/dropdown/components/dropdown-content.svelte +1 -1
- package/dist/components/dropdown/components/dropdown-sub-content.svelte +1 -1
- package/dist/components/input/Input.svelte +1 -1
- package/dist/components/modal/Modal.stories.svelte +58 -37
- package/dist/components/modal/components/modal-bottom.svelte +14 -6
- package/dist/components/modal/components/modal-close.svelte +12 -3
- package/dist/components/modal/components/modal-content.svelte +3 -8
- package/dist/components/modal/components/modal-description.svelte +15 -0
- package/dist/components/modal/components/modal-description.svelte.d.ts +4 -0
- package/dist/components/modal/components/modal-scroll-content.svelte +14 -0
- package/dist/components/modal/components/modal-scroll-content.svelte.d.ts +4 -0
- package/dist/components/modal/components/modal-title.svelte +31 -12
- package/dist/components/modal/index.d.ts +3 -3
- package/dist/components/modal/index.js +3 -2
- package/dist/components/modal/types.d.ts +12 -2
- package/dist/components/select/Select.stories.svelte +70 -0
- package/dist/components/select/components/SelectContent.svelte +2 -2
- package/dist/tailwind.preset.d.ts +22 -0
- package/dist/tailwind.preset.js +3 -0
- package/dist/tokens.d.ts +11 -1
- package/dist/tokens.js +14 -4
- package/package.json +1 -1
package/dist/app.css
CHANGED
|
@@ -112,4 +112,11 @@
|
|
|
112
112
|
html:has(.drawer-auto-gutter .drawer-toggle:checked) {
|
|
113
113
|
scrollbar-gutter: auto;
|
|
114
114
|
}
|
|
115
|
+
|
|
116
|
+
/* Global focus styles using brand colors */
|
|
117
|
+
*:focus-visible {
|
|
118
|
+
outline: 2px solid theme('borderColor.hover');
|
|
119
|
+
outline-offset: 1px;
|
|
120
|
+
border-radius: theme('borderRadius.lg');
|
|
121
|
+
}
|
|
115
122
|
}
|
|
@@ -111,6 +111,62 @@
|
|
|
111
111
|
let customAnchorSingle = $state<HTMLElement>(null!);
|
|
112
112
|
let customAnchorGrouped = $state<HTMLElement>(null!);
|
|
113
113
|
let customAnchorCustom = $state<HTMLElement>(null!);
|
|
114
|
+
|
|
115
|
+
// Generate a long list of countries for scrolling demo
|
|
116
|
+
const countries = [
|
|
117
|
+
{ value: 'us', label: 'United States' },
|
|
118
|
+
{ value: 'uk', label: 'United Kingdom' },
|
|
119
|
+
{ value: 'ca', label: 'Canada' },
|
|
120
|
+
{ value: 'au', label: 'Australia' },
|
|
121
|
+
{ value: 'de', label: 'Germany' },
|
|
122
|
+
{ value: 'fr', label: 'France' },
|
|
123
|
+
{ value: 'it', label: 'Italy' },
|
|
124
|
+
{ value: 'es', label: 'Spain' },
|
|
125
|
+
{ value: 'jp', label: 'Japan' },
|
|
126
|
+
{ value: 'cn', label: 'China' },
|
|
127
|
+
{ value: 'in', label: 'India' },
|
|
128
|
+
{ value: 'br', label: 'Brazil' },
|
|
129
|
+
{ value: 'mx', label: 'Mexico' },
|
|
130
|
+
{ value: 'za', label: 'South Africa' },
|
|
131
|
+
{ value: 'eg', label: 'Egypt' },
|
|
132
|
+
{ value: 'ng', label: 'Nigeria' },
|
|
133
|
+
{ value: 'ar', label: 'Argentina' },
|
|
134
|
+
{ value: 'cl', label: 'Chile' },
|
|
135
|
+
{ value: 'co', label: 'Colombia' },
|
|
136
|
+
{ value: 'pe', label: 'Peru' },
|
|
137
|
+
{ value: 'se', label: 'Sweden' },
|
|
138
|
+
{ value: 'no', label: 'Norway' },
|
|
139
|
+
{ value: 'dk', label: 'Denmark' },
|
|
140
|
+
{ value: 'fi', label: 'Finland' },
|
|
141
|
+
{ value: 'pl', label: 'Poland' },
|
|
142
|
+
{ value: 'nl', label: 'Netherlands' },
|
|
143
|
+
{ value: 'be', label: 'Belgium' },
|
|
144
|
+
{ value: 'ch', label: 'Switzerland' },
|
|
145
|
+
{ value: 'at', label: 'Austria' },
|
|
146
|
+
{ value: 'gr', label: 'Greece' },
|
|
147
|
+
{ value: 'pt', label: 'Portugal' },
|
|
148
|
+
{ value: 'ie', label: 'Ireland' },
|
|
149
|
+
{ value: 'nz', label: 'New Zealand' },
|
|
150
|
+
{ value: 'sg', label: 'Singapore' },
|
|
151
|
+
{ value: 'my', label: 'Malaysia' },
|
|
152
|
+
{ value: 'th', label: 'Thailand' },
|
|
153
|
+
{ value: 'id', label: 'Indonesia' },
|
|
154
|
+
{ value: 'ph', label: 'Philippines' },
|
|
155
|
+
{ value: 'vn', label: 'Vietnam' },
|
|
156
|
+
{ value: 'kr', label: 'South Korea' },
|
|
157
|
+
];
|
|
158
|
+
|
|
159
|
+
let searchValueCountries = $state('');
|
|
160
|
+
let selectedCountries = $state<string[]>([]);
|
|
161
|
+
let customAnchorCountries = $state<HTMLElement>(null!);
|
|
162
|
+
|
|
163
|
+
const filteredCountries = $derived(
|
|
164
|
+
searchValueCountries === ''
|
|
165
|
+
? countries
|
|
166
|
+
: countries.filter((country) =>
|
|
167
|
+
country.label.toLowerCase().includes(searchValueCountries.toLowerCase())
|
|
168
|
+
)
|
|
169
|
+
);
|
|
114
170
|
</script>
|
|
115
171
|
|
|
116
172
|
<Story name="Multiple Selection" asChild>
|
|
@@ -265,7 +321,7 @@
|
|
|
265
321
|
/>
|
|
266
322
|
<Divider />
|
|
267
323
|
</div>
|
|
268
|
-
<div class="flex
|
|
324
|
+
<div class="flex flex-grow flex-col">
|
|
269
325
|
{#if searchValueGrouped === ''}
|
|
270
326
|
{#each categories as category}
|
|
271
327
|
<Combobox.Group>
|
|
@@ -307,6 +363,73 @@
|
|
|
307
363
|
</Combobox.Root>
|
|
308
364
|
</Story>
|
|
309
365
|
|
|
366
|
+
<Story name="Long List with Scrolling (80vh max-height)" asChild>
|
|
367
|
+
<Combobox.Root
|
|
368
|
+
onOpenChange={(o) => {
|
|
369
|
+
if (!o) searchValueCountries = '';
|
|
370
|
+
}}
|
|
371
|
+
type="multiple"
|
|
372
|
+
name="countriesSelection"
|
|
373
|
+
items={filteredCountries}
|
|
374
|
+
bind:value={selectedCountries}
|
|
375
|
+
>
|
|
376
|
+
<div class="flex flex-wrap gap-2">
|
|
377
|
+
{#each selectedCountries as country}
|
|
378
|
+
<Tag>
|
|
379
|
+
{country}
|
|
380
|
+
</Tag>
|
|
381
|
+
{/each}
|
|
382
|
+
</div>
|
|
383
|
+
<Combobox.Trigger>
|
|
384
|
+
<div bind:this={customAnchorCountries}>
|
|
385
|
+
<Button variant="primary" size="sm">
|
|
386
|
+
<Icon>
|
|
387
|
+
{#snippet children(props)}
|
|
388
|
+
<List {...props} />
|
|
389
|
+
{/snippet}
|
|
390
|
+
</Icon>
|
|
391
|
+
Select countries
|
|
392
|
+
</Button>
|
|
393
|
+
</div>
|
|
394
|
+
</Combobox.Trigger>
|
|
395
|
+
<Combobox.Content
|
|
396
|
+
class="flex flex-col justify-between"
|
|
397
|
+
customAnchor={customAnchorCountries}
|
|
398
|
+
>
|
|
399
|
+
<div>
|
|
400
|
+
<Combobox.Input
|
|
401
|
+
placeholder="Search for a country"
|
|
402
|
+
oninput={(e: Event) => (searchValueCountries = (e.target as HTMLInputElement).value)}
|
|
403
|
+
autofocus
|
|
404
|
+
/>
|
|
405
|
+
<Divider />
|
|
406
|
+
</div>
|
|
407
|
+
<div class="flex flex-grow flex-col">
|
|
408
|
+
{#if filteredCountries.length > 0}
|
|
409
|
+
<Combobox.Group>
|
|
410
|
+
<Combobox.GroupHeading>Countries</Combobox.GroupHeading>
|
|
411
|
+
{#each filteredCountries as country (country.value)}
|
|
412
|
+
<Combobox.Item value={country.value} label={country.label}>
|
|
413
|
+
{#snippet children({ selected })}
|
|
414
|
+
{country.label}
|
|
415
|
+
{#if selected}
|
|
416
|
+
<Combobox.Indicator />
|
|
417
|
+
{/if}
|
|
418
|
+
{/snippet}
|
|
419
|
+
</Combobox.Item>
|
|
420
|
+
{/each}
|
|
421
|
+
</Combobox.Group>
|
|
422
|
+
{:else}
|
|
423
|
+
<span class="block px-5 py-2 text-sm text-muted-foreground"> No results found </span>
|
|
424
|
+
{/if}
|
|
425
|
+
</div>
|
|
426
|
+
</Combobox.Content>
|
|
427
|
+
<div class="mt-4 rounded bg-blue-50 p-2 text-xs text-blue-700">
|
|
428
|
+
This story demonstrates the 80vh max-height with overflow scrolling for long lists (40 countries).
|
|
429
|
+
</div>
|
|
430
|
+
</Combobox.Root>
|
|
431
|
+
</Story>
|
|
432
|
+
|
|
310
433
|
<Story
|
|
311
434
|
name="Interaction Test"
|
|
312
435
|
asChild
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
<Combobox.ScrollUpButton class="flex justify-center">
|
|
29
29
|
<Icon icon={CaretUp} />
|
|
30
30
|
</Combobox.ScrollUpButton>
|
|
31
|
-
<Combobox.Viewport class={paddedContent ? 'p-1' : ''}>
|
|
31
|
+
<Combobox.Viewport class="{paddedContent ? 'p-1' : ''} overflow-y-auto">
|
|
32
32
|
{@render children()}
|
|
33
33
|
</Combobox.Viewport>
|
|
34
34
|
<Combobox.ScrollDownButton class="flex justify-center">
|
|
@@ -64,6 +64,8 @@
|
|
|
64
64
|
|
|
65
65
|
z-index: 1;
|
|
66
66
|
|
|
67
|
+
max-height: 80vh;
|
|
68
|
+
|
|
67
69
|
width: 100%;
|
|
68
70
|
|
|
69
71
|
border-radius: 0.75rem;
|
|
@@ -561,6 +561,26 @@
|
|
|
561
561
|
</div>
|
|
562
562
|
</Story>
|
|
563
563
|
|
|
564
|
+
<Story name="Long Menu with Scrolling (80vh max-height)">
|
|
565
|
+
<div class="py-12">
|
|
566
|
+
<Dropdown.Root open>
|
|
567
|
+
<Dropdown.Trigger>Actions Menu (30 items)</Dropdown.Trigger>
|
|
568
|
+
<Dropdown.Portal>
|
|
569
|
+
<Dropdown.Content>
|
|
570
|
+
{#each Array.from({ length: 30 }, (_, i) => i + 1) as num}
|
|
571
|
+
<Dropdown.Item onSelect={() => console.log(`Action ${num} clicked`)}>
|
|
572
|
+
<p>Action {num}</p>
|
|
573
|
+
</Dropdown.Item>
|
|
574
|
+
{/each}
|
|
575
|
+
</Dropdown.Content>
|
|
576
|
+
</Dropdown.Portal>
|
|
577
|
+
</Dropdown.Root>
|
|
578
|
+
<div class="mt-4 rounded bg-blue-50 p-2 text-xs text-blue-700">
|
|
579
|
+
This story demonstrates the 80vh max-height with overflow scrolling for long menus (30 items).
|
|
580
|
+
</div>
|
|
581
|
+
</div>
|
|
582
|
+
</Story>
|
|
583
|
+
|
|
564
584
|
<Story
|
|
565
585
|
name="Interaction Test"
|
|
566
586
|
asChild
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
</script>
|
|
24
24
|
|
|
25
25
|
<DropdownMenu.Content
|
|
26
|
-
class="z-10 flex flex-col {gap} rounded-md p-1 shadow-menu {variantClass} {widthClass} {className}"
|
|
26
|
+
class="z-10 flex flex-col {gap} rounded-md p-1 shadow-menu max-h-[80vh] overflow-y-auto {variantClass} {widthClass} {className}"
|
|
27
27
|
{...restProps}
|
|
28
28
|
>
|
|
29
29
|
{@render children()}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
</script>
|
|
20
20
|
|
|
21
21
|
<DropdownMenu.SubContent
|
|
22
|
-
class="z-10 {gap} flex flex-col rounded-md p-1 shadow-menu {variantClass} {className}"
|
|
22
|
+
class="z-10 {gap} flex flex-col rounded-md p-1 shadow-menu max-h-[80vh] overflow-y-auto {variantClass} {className}"
|
|
23
23
|
{...restProps}
|
|
24
24
|
>
|
|
25
25
|
{@render children()}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
2
|
import Warning from 'phosphor-svelte/lib/Warning';
|
|
3
|
+
import SealCheck from 'phosphor-svelte/lib/SealCheck';
|
|
3
4
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
4
5
|
import { Root as ModalRootForMeta } from './index';
|
|
5
6
|
import * as Modal from './index';
|
|
@@ -29,10 +30,10 @@
|
|
|
29
30
|
</Modal.Trigger>
|
|
30
31
|
<Modal.Content>
|
|
31
32
|
<Modal.Title>Edit Profile</Modal.Title>
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
<Modal.Description>
|
|
34
|
+
Make changes to your profile here. Click save when you're done.
|
|
35
|
+
</Modal.Description>
|
|
36
|
+
<div class="space-y-4 py-2">
|
|
36
37
|
<div class="space-y-2">
|
|
37
38
|
<label class="text-sm font-medium" for="name">Name</label>
|
|
38
39
|
<input id="name" class="w-full rounded border border-input px-3 py-2" value="John Doe" />
|
|
@@ -61,7 +62,7 @@
|
|
|
61
62
|
</Modal.Trigger>
|
|
62
63
|
<Modal.Content>
|
|
63
64
|
<Modal.Title>Are you absolutely sure?</Modal.Title>
|
|
64
|
-
<Modal.Description
|
|
65
|
+
<Modal.Description>
|
|
65
66
|
This action cannot be undone. This will permanently delete your account and remove your data
|
|
66
67
|
from our servers.
|
|
67
68
|
</Modal.Description>
|
|
@@ -75,16 +76,16 @@
|
|
|
75
76
|
</Modal.Root>
|
|
76
77
|
</Story>
|
|
77
78
|
|
|
78
|
-
<Story name="Alert Modal
|
|
79
|
+
<Story name="Alert Modal" asChild>
|
|
79
80
|
<Modal.Root open>
|
|
80
81
|
<Modal.Trigger>
|
|
81
82
|
<Button variant="primary">Open Alert Modal</Button>
|
|
82
83
|
</Modal.Trigger>
|
|
83
|
-
<Modal.Content
|
|
84
|
+
<Modal.Content withClose={false}>
|
|
84
85
|
<Modal.Title>
|
|
85
86
|
{#snippet icon()}
|
|
86
87
|
<div class="flex h-12 w-12 items-center justify-center rounded-lg bg-danger p-2">
|
|
87
|
-
<Icon class="
|
|
88
|
+
<Icon class="text-icon-danger" size={24}>
|
|
88
89
|
{#snippet children(props)}
|
|
89
90
|
<Warning {...props} />
|
|
90
91
|
{/snippet}
|
|
@@ -93,9 +94,8 @@
|
|
|
93
94
|
{/snippet}
|
|
94
95
|
Delete this job?
|
|
95
96
|
</Modal.Title>
|
|
96
|
-
<Modal.Description
|
|
97
|
-
|
|
98
|
-
be undone.
|
|
97
|
+
<Modal.Description>
|
|
98
|
+
This modal doesn't have a close button. You must select one of the action buttons below.
|
|
99
99
|
</Modal.Description>
|
|
100
100
|
|
|
101
101
|
<Modal.Bottom>
|
|
@@ -106,6 +106,46 @@
|
|
|
106
106
|
</Modal.Root>
|
|
107
107
|
</Story>
|
|
108
108
|
|
|
109
|
+
<Story name="Sticky Header" asChild>
|
|
110
|
+
<Modal.Root open>
|
|
111
|
+
<Modal.Trigger>
|
|
112
|
+
<Button variant="primary">Modal with Sticky Header</Button>
|
|
113
|
+
</Modal.Trigger>
|
|
114
|
+
<Modal.Content class="flex flex-col p-0" withClose={true}>
|
|
115
|
+
<Modal.Title sticky>
|
|
116
|
+
{#snippet icon()}
|
|
117
|
+
<Icon class="h-5 w-5 text-icon-secondary">
|
|
118
|
+
{#snippet children(props)}
|
|
119
|
+
<SealCheck {...props} />
|
|
120
|
+
{/snippet}
|
|
121
|
+
</Icon>
|
|
122
|
+
{/snippet}
|
|
123
|
+
Sticky Header
|
|
124
|
+
</Modal.Title>
|
|
125
|
+
<Modal.ScrollContent>
|
|
126
|
+
<h4 class="font-semibold">Information</h4>
|
|
127
|
+
<p class="text-sm text-secondary mt-2">
|
|
128
|
+
This is content to demonstrate scrolling. The sticky header and footer will remain visible
|
|
129
|
+
at the top and bottom as you scroll through this modal content.
|
|
130
|
+
</p>
|
|
131
|
+
<div class="space-y-2 mt-4">
|
|
132
|
+
{#each Array(10) as _, i}
|
|
133
|
+
<div class="bg-surface rounded-lg p-3 border border-input">
|
|
134
|
+
<p class="text-sm">Item {i + 1}</p>
|
|
135
|
+
<p class="text-xs text-secondary mt-1">
|
|
136
|
+
This is item number {i + 1} in the list. Continue scrolling to see more items.
|
|
137
|
+
</p>
|
|
138
|
+
</div>
|
|
139
|
+
{/each}
|
|
140
|
+
</div>
|
|
141
|
+
</Modal.ScrollContent>
|
|
142
|
+
<Modal.Bottom sticky>
|
|
143
|
+
<Modal.Close variant="primary">Continue</Modal.Close>
|
|
144
|
+
</Modal.Bottom>
|
|
145
|
+
</Modal.Content>
|
|
146
|
+
</Modal.Root>
|
|
147
|
+
</Story>
|
|
148
|
+
|
|
109
149
|
<Story name="Custom Button Rendering" asChild>
|
|
110
150
|
<Modal.Root open>
|
|
111
151
|
<Modal.Trigger>
|
|
@@ -113,7 +153,7 @@
|
|
|
113
153
|
</Modal.Trigger>
|
|
114
154
|
<Modal.Content>
|
|
115
155
|
<Modal.Title>Custom Button Rendering</Modal.Title>
|
|
116
|
-
<Modal.Description
|
|
156
|
+
<Modal.Description>
|
|
117
157
|
This modal demonstrates rendering custom buttons within Modal.Close components for proper
|
|
118
158
|
functionality.
|
|
119
159
|
</Modal.Description>
|
|
@@ -130,32 +170,13 @@
|
|
|
130
170
|
</Modal.Root>
|
|
131
171
|
</Story>
|
|
132
172
|
|
|
133
|
-
<Story name="No Close Button" asChild>
|
|
134
|
-
<Modal.Root open>
|
|
135
|
-
<Modal.Trigger>
|
|
136
|
-
<Button variant="primary">Open Modal (No Close)</Button>
|
|
137
|
-
</Modal.Trigger>
|
|
138
|
-
<Modal.Content withClose={false}>
|
|
139
|
-
<Modal.Title>Alert</Modal.Title>
|
|
140
|
-
<div class="space-y-4">
|
|
141
|
-
<p class="text-sm text-secondary">
|
|
142
|
-
This modal doesn't have a close button. You must use the action buttons below.
|
|
143
|
-
</p>
|
|
144
|
-
</div>
|
|
145
|
-
<Modal.Bottom>
|
|
146
|
-
<Modal.Close variant="secondary">Cancel</Modal.Close>
|
|
147
|
-
<Modal.Close variant="primary">Continue</Modal.Close>
|
|
148
|
-
</Modal.Bottom>
|
|
149
|
-
</Modal.Content>
|
|
150
|
-
</Modal.Root>
|
|
151
|
-
</Story>
|
|
152
173
|
|
|
153
174
|
<Story name="Custom Styling" asChild>
|
|
154
175
|
<Modal.Root open>
|
|
155
176
|
<Modal.Trigger>
|
|
156
177
|
<Button variant="primary">Open Custom Modal</Button>
|
|
157
178
|
</Modal.Trigger>
|
|
158
|
-
<Modal.Content class="
|
|
179
|
+
<Modal.Content class="w-2xs bg-accent-inverse" withClose={false}>
|
|
159
180
|
<Modal.Title class="text-xl text-primary-inverse">Custom Styled Modal</Modal.Title>
|
|
160
181
|
<div class="space-y-4 pt-4">
|
|
161
182
|
<p class="text-sm text-secondary-inverse">
|
|
@@ -167,7 +188,7 @@
|
|
|
167
188
|
</div>
|
|
168
189
|
</div>
|
|
169
190
|
<Modal.Bottom>
|
|
170
|
-
<Modal.Close variant="secondary">Close</Modal.Close>
|
|
191
|
+
<Modal.Close variant="secondary-inverse">Close</Modal.Close>
|
|
171
192
|
</Modal.Bottom>
|
|
172
193
|
</Modal.Content>
|
|
173
194
|
</Modal.Root>
|
|
@@ -226,10 +247,10 @@
|
|
|
226
247
|
</Modal.Trigger>
|
|
227
248
|
<Modal.Content withPortal={false}>
|
|
228
249
|
<Modal.Title>Edit Profile</Modal.Title>
|
|
229
|
-
<
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
250
|
+
<Modal.Description>
|
|
251
|
+
Make changes to your profile here. Click save when you're done.
|
|
252
|
+
</Modal.Description>
|
|
253
|
+
<div class="space-y-4 py-2">
|
|
233
254
|
<div class="space-y-2">
|
|
234
255
|
<label class="text-sm font-medium" for="name">Name</label>
|
|
235
256
|
<input id="name" class="w-full rounded border border-input px-3 py-2" value="John Doe" />
|
|
@@ -2,14 +2,22 @@
|
|
|
2
2
|
import { twMerge } from 'tailwind-merge';
|
|
3
3
|
import type { ModalBottomProps } from '../types';
|
|
4
4
|
|
|
5
|
-
let { children, class: className = '', ...restProps }: ModalBottomProps = $props();
|
|
5
|
+
let { children, class: className = '', sticky = false, ...restProps }: ModalBottomProps = $props();
|
|
6
6
|
|
|
7
|
-
const baseClasses = '
|
|
7
|
+
const baseClasses = '-mx-5';
|
|
8
8
|
const finalClasses = twMerge(baseClasses, className);
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
<div class=
|
|
13
|
-
|
|
11
|
+
{#if sticky}
|
|
12
|
+
<div class={twMerge('sticky bottom-0 z-10 w-full shrink-0 bg-surface border-t border-static', className)} {...restProps}>
|
|
13
|
+
<div class="flex justify-end gap-4 px-4 py-3 w-full">
|
|
14
|
+
{@render children()}
|
|
15
|
+
</div>
|
|
14
16
|
</div>
|
|
15
|
-
|
|
17
|
+
{:else}
|
|
18
|
+
<div class={finalClasses} {...restProps}>
|
|
19
|
+
<div class="flex justify-end gap-4 px-5 pt-4 pb-0">
|
|
20
|
+
{@render children()}
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
{/if}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Dialog } from 'bits-ui';
|
|
3
|
+
import X from 'phosphor-svelte/lib/X';
|
|
3
4
|
import Button from '../../button/Button.svelte';
|
|
5
|
+
import { IconButton } from '../../icon-button';
|
|
6
|
+
import { Icon } from '../../icons';
|
|
4
7
|
import type { ModalCloseProps } from '../types';
|
|
5
8
|
|
|
6
9
|
let {
|
|
@@ -13,7 +16,13 @@
|
|
|
13
16
|
</script>
|
|
14
17
|
|
|
15
18
|
<Dialog.Close class={className} {...restProps} {disabled}>
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
|
|
19
|
+
{#if children}
|
|
20
|
+
<Button {variant} {disabled} tabindex={-1}>
|
|
21
|
+
{@render children()}
|
|
22
|
+
</Button>
|
|
23
|
+
{:else}
|
|
24
|
+
<IconButton variant="transparent" size="sm" {disabled} tabindex={-1} rounded={false}>
|
|
25
|
+
<Icon icon={X} />
|
|
26
|
+
</IconButton>
|
|
27
|
+
{/if}
|
|
19
28
|
</Dialog.Close>
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import X from 'phosphor-svelte/lib/X';
|
|
3
|
-
import { Icon } from '../../icons/index.js';
|
|
4
2
|
import { Dialog } from 'bits-ui';
|
|
5
3
|
import { scale } from 'svelte/transition';
|
|
6
4
|
import { twMerge } from 'tailwind-merge';
|
|
7
5
|
import type { ModalContentProps } from '../types';
|
|
8
6
|
import Overlay from './modal-overlay.svelte';
|
|
7
|
+
import Close from './modal-close.svelte';
|
|
9
8
|
|
|
10
9
|
let {
|
|
11
10
|
children,
|
|
@@ -17,17 +16,13 @@
|
|
|
17
16
|
}: ModalContentProps = $props();
|
|
18
17
|
|
|
19
18
|
const baseClasses =
|
|
20
|
-
'fixed left-1/2 top-1/2 z-50
|
|
19
|
+
'fixed left-1/2 top-1/2 z-50 flex flex-col w-[calc(100%-2rem)] max-w-lg -translate-x-1/2 -translate-y-1/2 p-5 bg-surface shadow-menu rounded-xl overflow-hidden max-h-[calc(100vh-4rem)]';
|
|
21
20
|
const finalClasses = twMerge(baseClasses, className);
|
|
22
21
|
</script>
|
|
23
22
|
|
|
24
23
|
{#snippet withCloseButton()}
|
|
25
24
|
{#if withClose}
|
|
26
|
-
<
|
|
27
|
-
class="ring-offset-background focus:ring-ring absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none"
|
|
28
|
-
>
|
|
29
|
-
<Icon icon={X} />
|
|
30
|
-
</Dialog.Close>
|
|
25
|
+
<Close class="absolute right-2 top-2 z-20" />
|
|
31
26
|
{/if}
|
|
32
27
|
{/snippet}
|
|
33
28
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Dialog } from 'bits-ui';
|
|
3
|
+
import type { ModalDescriptionProps } from '../types';
|
|
4
|
+
import { twMerge } from 'tailwind-merge';
|
|
5
|
+
|
|
6
|
+
let { children, class: className = '', ...restProps }: ModalDescriptionProps = $props();
|
|
7
|
+
|
|
8
|
+
const baseClasses = 'text-sm text-secondary py-2';
|
|
9
|
+
const finalClasses = twMerge(baseClasses, className);
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<Dialog.Description class={finalClasses} {...restProps}>
|
|
13
|
+
{@render children()}
|
|
14
|
+
</Dialog.Description>
|
|
15
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
import type { ModalScrollContentProps } from '../types';
|
|
4
|
+
|
|
5
|
+
let { children, class: className = '', ...restProps }: ModalScrollContentProps = $props();
|
|
6
|
+
|
|
7
|
+
const baseClasses = 'flex-1 overflow-y-auto min-h-0 p-5';
|
|
8
|
+
const finalClasses = twMerge(baseClasses, className);
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<div class={finalClasses} tabindex="-1" {...restProps}>
|
|
12
|
+
{@render children()}
|
|
13
|
+
</div>
|
|
14
|
+
|
|
@@ -3,19 +3,38 @@
|
|
|
3
3
|
import type { ModalTitleProps } from '../types';
|
|
4
4
|
import { twMerge } from 'tailwind-merge';
|
|
5
5
|
|
|
6
|
-
let { children, class: className = '', icon, ...restProps }: ModalTitleProps = $props();
|
|
6
|
+
let { children, class: className = '', icon, sticky = false, ...restProps }: ModalTitleProps = $props();
|
|
7
7
|
|
|
8
|
-
const baseClasses =
|
|
9
|
-
|
|
8
|
+
const baseClasses = $derived(sticky
|
|
9
|
+
? 'text-base font-semibold tracking-tight text-primary'
|
|
10
|
+
: 'text-xl font-semibold tracking-tight text-primary');
|
|
11
|
+
const finalClasses = $derived(twMerge(baseClasses, className));
|
|
10
12
|
</script>
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<div class="flex justify-
|
|
15
|
-
|
|
14
|
+
{#if sticky}
|
|
15
|
+
<div class="sticky top-0 z-10 w-full h-12 shrink-0 bg-surface border-b border-static">
|
|
16
|
+
<div class="flex h-12 items-center justify-between overflow-hidden px-4 py-2 w-full">
|
|
17
|
+
<div class="flex gap-2 items-center relative shrink-0">
|
|
18
|
+
{#if icon}
|
|
19
|
+
<div class="relative shrink-0 text-icon-secondary">
|
|
20
|
+
{@render icon()}
|
|
21
|
+
</div>
|
|
22
|
+
{/if}
|
|
23
|
+
<Dialog.Title class={finalClasses} {...restProps}>
|
|
24
|
+
{@render children()}
|
|
25
|
+
</Dialog.Title>
|
|
26
|
+
</div>
|
|
16
27
|
</div>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
</div>
|
|
29
|
+
{:else}
|
|
30
|
+
<div class="space-y-5">
|
|
31
|
+
{#if icon}
|
|
32
|
+
<div class="flex justify-start">
|
|
33
|
+
{@render icon()}
|
|
34
|
+
</div>
|
|
35
|
+
{/if}
|
|
36
|
+
<Dialog.Title class={finalClasses} {...restProps}>
|
|
37
|
+
{@render children()}
|
|
38
|
+
</Dialog.Title>
|
|
39
|
+
</div>
|
|
40
|
+
{/if}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { Dialog } from 'bits-ui';
|
|
2
1
|
import Content from './components/modal-content.svelte';
|
|
3
2
|
import Overlay from './components/modal-overlay.svelte';
|
|
4
3
|
import Trigger from './components/modal-trigger.svelte';
|
|
5
4
|
import Title from './components/modal-title.svelte';
|
|
5
|
+
import Description from './components/modal-description.svelte';
|
|
6
|
+
import ScrollContent from './components/modal-scroll-content.svelte';
|
|
6
7
|
import Bottom from './components/modal-bottom.svelte';
|
|
7
8
|
import Close from './components/modal-close.svelte';
|
|
8
9
|
export declare const Root: import("svelte").Component<import("bits-ui").AlertDialogRootPropsWithoutHTML, {}, "open">;
|
|
9
10
|
export declare const Portal: import("svelte").Component<import("bits-ui").PortalProps, {}, "">;
|
|
10
|
-
export
|
|
11
|
-
export { Content, Overlay, Trigger, Title, Bottom, Close };
|
|
11
|
+
export { Content, Overlay, Trigger, Title, Description, ScrollContent, Bottom, Close };
|
|
12
12
|
export * from './types';
|
|
@@ -4,12 +4,13 @@ import Content from './components/modal-content.svelte';
|
|
|
4
4
|
import Overlay from './components/modal-overlay.svelte';
|
|
5
5
|
import Trigger from './components/modal-trigger.svelte';
|
|
6
6
|
import Title from './components/modal-title.svelte';
|
|
7
|
+
import Description from './components/modal-description.svelte';
|
|
8
|
+
import ScrollContent from './components/modal-scroll-content.svelte';
|
|
7
9
|
import Bottom from './components/modal-bottom.svelte';
|
|
8
10
|
import Close from './components/modal-close.svelte';
|
|
9
11
|
// Re-export Dialog primitives
|
|
10
12
|
export const Root = Dialog.Root;
|
|
11
13
|
export const Portal = Dialog.Portal;
|
|
12
|
-
export const Description = Dialog.Description;
|
|
13
14
|
// Export custom components
|
|
14
|
-
export { Content, Overlay, Trigger, Title, Bottom, Close };
|
|
15
|
+
export { Content, Overlay, Trigger, Title, Description, ScrollContent, Bottom, Close };
|
|
15
16
|
export * from './types';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type DialogContentProps as BitsDialogContentProps, type DialogOverlayProps as BitsDialogOverlayProps, type DialogTriggerProps as BitsDialogTriggerProps, type DialogTitleProps as BitsDialogTitleProps, type DialogCloseProps as BitsDialogCloseProps } from 'bits-ui';
|
|
1
|
+
import { type DialogContentProps as BitsDialogContentProps, type DialogOverlayProps as BitsDialogOverlayProps, type DialogTriggerProps as BitsDialogTriggerProps, type DialogTitleProps as BitsDialogTitleProps, type DialogDescriptionProps as BitsDialogDescriptionProps, type DialogCloseProps as BitsDialogCloseProps } from 'bits-ui';
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
4
|
import type { ButtonVariant } from '../button/Button.svelte';
|
|
@@ -18,13 +18,23 @@ export type ModalTitleProps = {
|
|
|
18
18
|
children: Snippet;
|
|
19
19
|
class?: string;
|
|
20
20
|
icon?: Snippet;
|
|
21
|
+
sticky?: boolean;
|
|
21
22
|
} & BitsDialogTitleProps;
|
|
23
|
+
export type ModalDescriptionProps = {
|
|
24
|
+
children: Snippet;
|
|
25
|
+
class?: string;
|
|
26
|
+
} & BitsDialogDescriptionProps;
|
|
27
|
+
export type ModalScrollContentProps = {
|
|
28
|
+
children: Snippet;
|
|
29
|
+
class?: string;
|
|
30
|
+
} & HTMLAttributes<HTMLDivElement>;
|
|
22
31
|
export type ModalBottomProps = {
|
|
23
32
|
children: Snippet;
|
|
24
33
|
class?: string;
|
|
34
|
+
sticky?: boolean;
|
|
25
35
|
} & HTMLAttributes<HTMLDivElement>;
|
|
26
36
|
export type ModalCloseProps = {
|
|
27
|
-
children
|
|
37
|
+
children?: Snippet;
|
|
28
38
|
class?: string;
|
|
29
39
|
variant?: ButtonVariant;
|
|
30
40
|
onclick?: (event: MouseEvent) => void;
|
|
@@ -53,6 +53,51 @@
|
|
|
53
53
|
(v) => v !== itemValue
|
|
54
54
|
);
|
|
55
55
|
};
|
|
56
|
+
|
|
57
|
+
// Generate a long list of countries to test scrolling
|
|
58
|
+
const countries = [
|
|
59
|
+
{ value: 'us', label: 'United States' },
|
|
60
|
+
{ value: 'uk', label: 'United Kingdom' },
|
|
61
|
+
{ value: 'ca', label: 'Canada' },
|
|
62
|
+
{ value: 'au', label: 'Australia' },
|
|
63
|
+
{ value: 'de', label: 'Germany' },
|
|
64
|
+
{ value: 'fr', label: 'France' },
|
|
65
|
+
{ value: 'it', label: 'Italy' },
|
|
66
|
+
{ value: 'es', label: 'Spain' },
|
|
67
|
+
{ value: 'jp', label: 'Japan' },
|
|
68
|
+
{ value: 'cn', label: 'China' },
|
|
69
|
+
{ value: 'in', label: 'India' },
|
|
70
|
+
{ value: 'br', label: 'Brazil' },
|
|
71
|
+
{ value: 'mx', label: 'Mexico' },
|
|
72
|
+
{ value: 'za', label: 'South Africa' },
|
|
73
|
+
{ value: 'eg', label: 'Egypt' },
|
|
74
|
+
{ value: 'ng', label: 'Nigeria' },
|
|
75
|
+
{ value: 'ar', label: 'Argentina' },
|
|
76
|
+
{ value: 'cl', label: 'Chile' },
|
|
77
|
+
{ value: 'co', label: 'Colombia' },
|
|
78
|
+
{ value: 'pe', label: 'Peru' },
|
|
79
|
+
{ value: 'se', label: 'Sweden' },
|
|
80
|
+
{ value: 'no', label: 'Norway' },
|
|
81
|
+
{ value: 'dk', label: 'Denmark' },
|
|
82
|
+
{ value: 'fi', label: 'Finland' },
|
|
83
|
+
{ value: 'pl', label: 'Poland' },
|
|
84
|
+
{ value: 'nl', label: 'Netherlands' },
|
|
85
|
+
{ value: 'be', label: 'Belgium' },
|
|
86
|
+
{ value: 'ch', label: 'Switzerland' },
|
|
87
|
+
{ value: 'at', label: 'Austria' },
|
|
88
|
+
{ value: 'gr', label: 'Greece' },
|
|
89
|
+
{ value: 'pt', label: 'Portugal' },
|
|
90
|
+
{ value: 'ie', label: 'Ireland' },
|
|
91
|
+
{ value: 'nz', label: 'New Zealand' },
|
|
92
|
+
{ value: 'sg', label: 'Singapore' },
|
|
93
|
+
{ value: 'my', label: 'Malaysia' },
|
|
94
|
+
{ value: 'th', label: 'Thailand' },
|
|
95
|
+
{ value: 'id', label: 'Indonesia' },
|
|
96
|
+
{ value: 'ph', label: 'Philippines' },
|
|
97
|
+
{ value: 'vn', label: 'Vietnam' },
|
|
98
|
+
{ value: 'kr', label: 'South Korea' },
|
|
99
|
+
];
|
|
100
|
+
let selectedCountry = $state<string | undefined>(undefined);
|
|
56
101
|
</script>
|
|
57
102
|
|
|
58
103
|
<Story name="Default (Single Select)" asChild>
|
|
@@ -217,3 +262,28 @@
|
|
|
217
262
|
</div>
|
|
218
263
|
</div>
|
|
219
264
|
</Story>
|
|
265
|
+
|
|
266
|
+
<Story name="Long List with Scrolling (80vh max-height)" asChild>
|
|
267
|
+
<div class="p-4">
|
|
268
|
+
<Select.Root bind:value={selectedCountry} items={countries} type="single">
|
|
269
|
+
<Select.Trigger
|
|
270
|
+
class="w-[250px]"
|
|
271
|
+
placeholder={'Select a country'}
|
|
272
|
+
displayValue={countries.find((c) => c.value === selectedCountry)?.label}
|
|
273
|
+
/>
|
|
274
|
+
<Select.Portal>
|
|
275
|
+
<Select.Content>
|
|
276
|
+
{#each countries as item (item.value)}
|
|
277
|
+
<Select.Item value={item.value} label={item.label} />
|
|
278
|
+
{/each}
|
|
279
|
+
</Select.Content>
|
|
280
|
+
</Select.Portal>
|
|
281
|
+
</Select.Root>
|
|
282
|
+
<div class="mt-2 rounded bg-gray-100 p-2 text-sm">
|
|
283
|
+
Selected: {selectedCountry ?? 'Nothing'}
|
|
284
|
+
</div>
|
|
285
|
+
<div class="mt-2 rounded bg-blue-50 p-2 text-xs text-blue-700">
|
|
286
|
+
This story demonstrates the 80vh max-height with overflow scrolling for long lists (40 items).
|
|
287
|
+
</div>
|
|
288
|
+
</div>
|
|
289
|
+
</Story>
|
|
@@ -21,14 +21,14 @@
|
|
|
21
21
|
{...restProps}
|
|
22
22
|
{sideOffset}
|
|
23
23
|
class={twMerge(
|
|
24
|
-
'relative z-50 w-[var(--bits-select-anchor-width)] min-w-[8rem] overflow-hidden rounded-lg bg-surface text-primary shadow-menu',
|
|
24
|
+
'relative z-50 w-[var(--bits-select-anchor-width)] min-w-[8rem] max-h-[80vh] overflow-hidden rounded-lg bg-surface text-primary shadow-menu',
|
|
25
25
|
className
|
|
26
26
|
)}
|
|
27
27
|
>
|
|
28
28
|
<SelectPrimitive.ScrollUpButton class="flex justify-center">
|
|
29
29
|
<Icon color="tertiary" icon={CaretUp} />
|
|
30
30
|
</SelectPrimitive.ScrollUpButton>
|
|
31
|
-
<SelectPrimitive.Viewport class="p-1 ">
|
|
31
|
+
<SelectPrimitive.Viewport class="p-1 overflow-y-auto">
|
|
32
32
|
{@render children()}
|
|
33
33
|
</SelectPrimitive.Viewport>
|
|
34
34
|
<SelectPrimitive.ScrollDownButton class="flex justify-center">
|
|
@@ -494,6 +494,28 @@ declare const config: {
|
|
|
494
494
|
hover: string;
|
|
495
495
|
focus: string;
|
|
496
496
|
};
|
|
497
|
+
ringColor: {
|
|
498
|
+
'dark-static': string;
|
|
499
|
+
'dark-input': string;
|
|
500
|
+
'dark-interactive': string;
|
|
501
|
+
'dark-hover': string;
|
|
502
|
+
'dark-focus': string;
|
|
503
|
+
'dark-danger': string;
|
|
504
|
+
static: string;
|
|
505
|
+
input: string;
|
|
506
|
+
interactive: string;
|
|
507
|
+
hover: string;
|
|
508
|
+
focus: string;
|
|
509
|
+
danger: string;
|
|
510
|
+
'static-inverse': string;
|
|
511
|
+
'interactive-inverse': string;
|
|
512
|
+
'blue-inverse': string;
|
|
513
|
+
'orange-inverse': string;
|
|
514
|
+
'pink-inverse': string;
|
|
515
|
+
'lime-inverse': string;
|
|
516
|
+
white: string;
|
|
517
|
+
axis: string;
|
|
518
|
+
};
|
|
497
519
|
fontFamily: {
|
|
498
520
|
mono: string[];
|
|
499
521
|
sans: string[];
|
package/dist/tailwind.preset.js
CHANGED
package/dist/tokens.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { colors } from './tokens/colors';
|
|
2
|
-
export type OutputName = 'cfu' | 'halo' | 'seed' | 'seedling' | 'leaf' | 'insect' | 'egg' | 'food' | 'positive' | 'negative' | 'review' | 'tntc' | 'contaminated' | 'countable' | 'full_growth' | 'reduced_growth' | 'dotted_growth';
|
|
2
|
+
export type OutputName = 'cfu' | 'halo' | 'seed' | 'seedling' | 'leaf' | 'insect' | 'egg' | 'food' | 'positive' | 'negative' | 'review' | 'tntc' | 'contaminated' | 'countable' | 'full_growth' | 'reduced_growth' | 'dotted_growth' | 'root' | 'shoot';
|
|
3
3
|
declare const annotationOutputFadedFillColors: {
|
|
4
4
|
[K in OutputName]: string;
|
|
5
5
|
};
|
|
@@ -750,6 +750,8 @@ export declare const tokens: {
|
|
|
750
750
|
full_growth: any;
|
|
751
751
|
reduced_growth: any;
|
|
752
752
|
dotted_growth: any;
|
|
753
|
+
root: any;
|
|
754
|
+
shoot: any;
|
|
753
755
|
};
|
|
754
756
|
annotationOutputFillColors: {
|
|
755
757
|
cfu: string;
|
|
@@ -769,6 +771,8 @@ export declare const tokens: {
|
|
|
769
771
|
full_growth: string;
|
|
770
772
|
reduced_growth: string;
|
|
771
773
|
dotted_growth: string;
|
|
774
|
+
root: string;
|
|
775
|
+
shoot: string;
|
|
772
776
|
};
|
|
773
777
|
annotationOutputFadedFillColors: {
|
|
774
778
|
cfu: string;
|
|
@@ -788,6 +792,8 @@ export declare const tokens: {
|
|
|
788
792
|
full_growth: string;
|
|
789
793
|
reduced_growth: string;
|
|
790
794
|
dotted_growth: string;
|
|
795
|
+
root: string;
|
|
796
|
+
shoot: string;
|
|
791
797
|
};
|
|
792
798
|
annotationOutputStrokeColors: {
|
|
793
799
|
cfu: string;
|
|
@@ -807,6 +813,8 @@ export declare const tokens: {
|
|
|
807
813
|
full_growth: string;
|
|
808
814
|
reduced_growth: string;
|
|
809
815
|
dotted_growth: string;
|
|
816
|
+
root: string;
|
|
817
|
+
shoot: string;
|
|
810
818
|
};
|
|
811
819
|
annotationOutputFadedStrokeColors: {
|
|
812
820
|
cfu: string;
|
|
@@ -826,5 +834,7 @@ export declare const tokens: {
|
|
|
826
834
|
full_growth: string;
|
|
827
835
|
reduced_growth: string;
|
|
828
836
|
dotted_growth: string;
|
|
837
|
+
root: string;
|
|
838
|
+
shoot: string;
|
|
829
839
|
};
|
|
830
840
|
};
|
package/dist/tokens.js
CHANGED
|
@@ -43,7 +43,7 @@ const lightBorderColor = {
|
|
|
43
43
|
static: colors.base.midnight[8],
|
|
44
44
|
input: colors.base.midnight[10],
|
|
45
45
|
interactive: colors.base.midnight[15],
|
|
46
|
-
hover: colors.periwinkle[5][
|
|
46
|
+
hover: colors.periwinkle[5][50],
|
|
47
47
|
focus: colors.periwinkle[5].default,
|
|
48
48
|
danger: colors.red[5].default,
|
|
49
49
|
'static-inverse': colors.base.white[10],
|
|
@@ -143,11 +143,11 @@ const lightChartColor = {
|
|
|
143
143
|
const annotationOutputBaseColors = {
|
|
144
144
|
cfu: colors.periwinkle[5],
|
|
145
145
|
halo: colors.yellow[5],
|
|
146
|
-
seed: colors.
|
|
146
|
+
seed: colors.orange[5],
|
|
147
147
|
seedling: colors.lime[5],
|
|
148
148
|
leaf: colors.green[5],
|
|
149
|
-
insect: colors.orange[
|
|
150
|
-
egg: colors.
|
|
149
|
+
insect: colors.orange[5],
|
|
150
|
+
egg: colors.blue[5],
|
|
151
151
|
food: colors.pear[5],
|
|
152
152
|
positive: colors.red[5],
|
|
153
153
|
negative: colors.gray[4],
|
|
@@ -158,6 +158,8 @@ const annotationOutputBaseColors = {
|
|
|
158
158
|
full_growth: colors.gray[4],
|
|
159
159
|
reduced_growth: colors.gray[4],
|
|
160
160
|
dotted_growth: colors.gray[4],
|
|
161
|
+
root: colors.periwinkle[5],
|
|
162
|
+
shoot: colors.blue[5],
|
|
161
163
|
};
|
|
162
164
|
const annotationOutputFillColors = {
|
|
163
165
|
cfu: annotationOutputBaseColors.cfu[25],
|
|
@@ -177,6 +179,8 @@ const annotationOutputFillColors = {
|
|
|
177
179
|
full_growth: annotationOutputBaseColors.full_growth[25],
|
|
178
180
|
reduced_growth: annotationOutputBaseColors.reduced_growth[25],
|
|
179
181
|
dotted_growth: annotationOutputBaseColors.dotted_growth[25],
|
|
182
|
+
root: annotationOutputBaseColors.root[25],
|
|
183
|
+
shoot: annotationOutputBaseColors.shoot[25],
|
|
180
184
|
};
|
|
181
185
|
const annotationOutputFadedFillColors = {
|
|
182
186
|
cfu: annotationOutputBaseColors.cfu[10],
|
|
@@ -196,6 +200,8 @@ const annotationOutputFadedFillColors = {
|
|
|
196
200
|
full_growth: annotationOutputBaseColors.full_growth[10],
|
|
197
201
|
reduced_growth: annotationOutputBaseColors.reduced_growth[10],
|
|
198
202
|
dotted_growth: annotationOutputBaseColors.dotted_growth[10],
|
|
203
|
+
root: annotationOutputBaseColors.root[10],
|
|
204
|
+
shoot: annotationOutputBaseColors.shoot[10],
|
|
199
205
|
};
|
|
200
206
|
const annotationOutputStrokeColors = {
|
|
201
207
|
cfu: annotationOutputBaseColors.cfu.default,
|
|
@@ -215,6 +221,8 @@ const annotationOutputStrokeColors = {
|
|
|
215
221
|
full_growth: annotationOutputBaseColors.full_growth.default,
|
|
216
222
|
reduced_growth: annotationOutputBaseColors.reduced_growth.default,
|
|
217
223
|
dotted_growth: annotationOutputBaseColors.dotted_growth.default,
|
|
224
|
+
root: annotationOutputBaseColors.root.default,
|
|
225
|
+
shoot: annotationOutputBaseColors.shoot.default,
|
|
218
226
|
};
|
|
219
227
|
const annotationOutputFadedStrokeColors = {
|
|
220
228
|
cfu: annotationOutputBaseColors.cfu[50],
|
|
@@ -234,6 +242,8 @@ const annotationOutputFadedStrokeColors = {
|
|
|
234
242
|
full_growth: annotationOutputBaseColors.full_growth[50],
|
|
235
243
|
reduced_growth: annotationOutputBaseColors.reduced_growth[50],
|
|
236
244
|
dotted_growth: annotationOutputBaseColors.dotted_growth[50],
|
|
245
|
+
root: annotationOutputBaseColors.root[50],
|
|
246
|
+
shoot: annotationOutputBaseColors.shoot[50],
|
|
237
247
|
};
|
|
238
248
|
const darkTextColor = {
|
|
239
249
|
'dark-primary': colors.base.white.default,
|