@runwisp/ui 0.13.0 → 0.15.0
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/package.json +39 -47
- package/src/astro/CTABand.astro +19 -12
- package/src/astro/Hero.astro +3 -3
- package/src/astro/SiteFooter.astro +4 -4
- package/src/astro/SiteHeader.astro +4 -4
- package/src/lib/actions/portal.ts +0 -3
- package/src/lib/assets/runwisp-logo.svg +1 -8
- package/src/lib/components/AccordionItem.svelte +4 -10
- package/src/lib/components/Alert.svelte +11 -11
- package/src/lib/components/Avatar.svelte +1 -1
- package/src/lib/components/Badge.svelte +13 -13
- package/src/lib/components/Breadcrumb.svelte +3 -3
- package/src/lib/components/Button.svelte +2 -2
- package/src/lib/components/Card.svelte +4 -4
- package/src/lib/components/Checkbox.svelte +12 -10
- package/src/lib/components/CodeBlock.svelte +7 -13
- package/src/lib/components/CronInput.svelte +12 -15
- package/src/lib/components/DataGrid.svelte +14 -13
- package/src/lib/components/Drawer.svelte +9 -9
- package/src/lib/components/Dropdown.svelte +12 -20
- package/src/lib/components/DurationInput.svelte +10 -14
- package/src/lib/components/EmptyState.svelte +1 -1
- package/src/lib/components/ErrorState.svelte +4 -4
- package/src/lib/components/FeatureCard.svelte +4 -4
- package/src/lib/components/FormField.svelte +4 -6
- package/src/lib/components/Heading.svelte +4 -1
- package/src/lib/components/Input.svelte +10 -12
- package/src/lib/components/Kbd.svelte +1 -1
- package/src/lib/components/Link.svelte +2 -3
- package/src/lib/components/LinkButton.svelte +2 -2
- package/src/lib/components/LogConsole.svelte +22 -21
- package/src/lib/components/Logo.svelte +3 -1
- package/src/lib/components/Modal.svelte +9 -11
- package/src/lib/components/PageContainer.svelte +1 -1
- package/src/lib/components/PageHeader.svelte +1 -1
- package/src/lib/components/Pagination.svelte +4 -4
- package/src/lib/components/Popover.svelte +5 -7
- package/src/lib/components/Progress.svelte +6 -4
- package/src/lib/components/Prose.svelte +4 -4
- package/src/lib/components/Radio.svelte +11 -10
- package/src/lib/components/RadioGroup.svelte +3 -5
- package/src/lib/components/Select.svelte +23 -36
- package/src/lib/components/Separator.svelte +4 -1
- package/src/lib/components/Skeleton.svelte +6 -6
- package/src/lib/components/StatusIndicator.svelte +7 -18
- package/src/lib/components/Table.svelte +1 -1
- package/src/lib/components/TableCell.svelte +1 -1
- package/src/lib/components/TableRow.svelte +1 -5
- package/src/lib/components/Tabs.svelte +10 -13
- package/src/lib/components/TaskCard.svelte +7 -4
- package/src/lib/components/Textarea.svelte +10 -11
- package/src/lib/components/ThemeToggle.svelte +1 -1
- package/src/lib/components/ToastContainer.svelte +3 -8
- package/src/lib/components/Toggle.svelte +2 -3
- package/src/lib/components/Tooltip.svelte +12 -10
- package/src/lib/components/button-styles.ts +17 -18
- package/src/lib/components/dashboard/RunDetailPanel.svelte +160 -249
- package/src/lib/components/dashboard/RunFilterPopover.svelte +31 -25
- package/src/lib/components/dashboard/RunsList.svelte +55 -50
- package/src/lib/components/dashboard/run-filters.test.ts +31 -33
- package/src/lib/components/dashboard/run-filters.ts +33 -33
- package/src/lib/components/dashboard/run-helpers.test.ts +42 -17
- package/src/lib/components/dashboard/run-helpers.ts +53 -17
- package/src/lib/components/dashboard/status-config.ts +9 -8
- package/src/lib/theme-tokens.css +179 -114
- package/src/lib/theme.css +49 -35
- package/src/lib/utils/error.ts +0 -3
- package/src/lib/utils/format.test.ts +2 -6
- package/src/lib/utils/format.ts +28 -3
|
@@ -564,8 +564,8 @@
|
|
|
564
564
|
>
|
|
565
565
|
{#if cache.firstAvailableLine > 0}
|
|
566
566
|
<div
|
|
567
|
-
class="absolute right-0 left-0 flex items-center
|
|
568
|
-
style="top: 0px; height: {lineHeight}px;"
|
|
567
|
+
class="absolute right-0 left-0 flex items-center text-term-warn"
|
|
568
|
+
style="top: 0px; height: {lineHeight}px; background-color: color-mix(in srgb, var(--rw-term-warn) 15%, transparent);"
|
|
569
569
|
>
|
|
570
570
|
<div
|
|
571
571
|
class="sticky left-0 z-10 flex-shrink-0 pr-3 text-right select-none"
|
|
@@ -585,10 +585,7 @@
|
|
|
585
585
|
<div
|
|
586
586
|
class="log-line absolute right-0 left-0 flex {wrap
|
|
587
587
|
? 'items-start'
|
|
588
|
-
: 'items-center'}
|
|
589
|
-
line.num
|
|
590
|
-
? 'log-line--flash'
|
|
591
|
-
: ''}"
|
|
588
|
+
: 'items-center'} {flashLine === line.num ? 'log-line--flash' : ''}"
|
|
592
589
|
style="top: {lineTop(line.num)}px; height: {lineHeightPx(line.num)}px;"
|
|
593
590
|
>
|
|
594
591
|
<div
|
|
@@ -783,12 +780,11 @@
|
|
|
783
780
|
|
|
784
781
|
{#if userScrolledUp && cache.totalLines > 0}
|
|
785
782
|
<button
|
|
786
|
-
class="absolute right-4 bottom-12 z-10 flex items-center gap-2 rounded-
|
|
787
|
-
border-[
|
|
783
|
+
class="absolute right-4 bottom-12 z-10 flex items-center gap-2 rounded-[3px] border
|
|
784
|
+
border-[var(--rw-con-gutter)] bg-[var(--rw-con-panel)]
|
|
788
785
|
px-3 py-1.5 text-xs
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
hover:bg-[rgb(255_255_255_/_0.06)] active:scale-95"
|
|
786
|
+
text-[var(--rw-con-text)]
|
|
787
|
+
hover:border-term-teal hover:text-term-teal active:translate-y-[1px]"
|
|
792
788
|
onclick={enableAutoScroll}
|
|
793
789
|
>
|
|
794
790
|
<svg
|
|
@@ -805,8 +801,8 @@
|
|
|
805
801
|
{/if}
|
|
806
802
|
|
|
807
803
|
<div
|
|
808
|
-
class="flex flex-shrink-0 items-center justify-between border-t border-[
|
|
809
|
-
bg-[var(--rw-con-panel)] px-3.5 py-2 text-[11px] text-[var(--rw-con-dim)]"
|
|
804
|
+
class="flex flex-shrink-0 items-center justify-between border-t border-[var(--rw-con-gutter)]
|
|
805
|
+
bg-[var(--rw-con-panel)] px-3.5 py-2 text-[11px] tracking-wide text-[var(--rw-con-dim)]"
|
|
810
806
|
>
|
|
811
807
|
<div class="flex items-center gap-3">
|
|
812
808
|
{#if isStreaming}
|
|
@@ -827,7 +823,7 @@
|
|
|
827
823
|
<span>{formatBytes(cache.totalBytes)}</span>
|
|
828
824
|
{/if}
|
|
829
825
|
{#if isAutoScroll}
|
|
830
|
-
<span class="inline-flex items-center gap-1.5 text-
|
|
826
|
+
<span class="inline-flex items-center gap-1.5 text-term-ok">
|
|
831
827
|
<svg
|
|
832
828
|
class="h-3 w-3"
|
|
833
829
|
viewBox="0 0 24 24"
|
|
@@ -857,15 +853,21 @@
|
|
|
857
853
|
way the approved design closes a finished capture. */
|
|
858
854
|
.sentinel--muted {
|
|
859
855
|
color: var(--rw-con-gutter);
|
|
860
|
-
border-top-color:
|
|
856
|
+
border-top-color: var(--rw-con-gutter);
|
|
861
857
|
}
|
|
862
858
|
.sentinel--warn {
|
|
863
|
-
color:
|
|
864
|
-
border-top-color:
|
|
859
|
+
color: var(--rw-term-warn);
|
|
860
|
+
border-top-color: color-mix(in srgb, var(--rw-term-warn) 30%, transparent);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/* Subtle row hover on the fixed-dark console surface — a faint lift of the
|
|
864
|
+
console text colour, never a theme-flipping fill. */
|
|
865
|
+
.log-line:hover {
|
|
866
|
+
background-color: color-mix(in srgb, var(--rw-con-text) 4%, transparent);
|
|
865
867
|
}
|
|
866
868
|
|
|
867
869
|
.log-line--flash {
|
|
868
|
-
animation: log-line-flash 1.5s
|
|
870
|
+
animation: log-line-flash 1.5s;
|
|
869
871
|
}
|
|
870
872
|
|
|
871
873
|
.frame-toggle {
|
|
@@ -875,12 +877,11 @@
|
|
|
875
877
|
background: transparent;
|
|
876
878
|
border: none;
|
|
877
879
|
padding: 0;
|
|
878
|
-
transition: color 120ms ease;
|
|
879
880
|
}
|
|
880
881
|
|
|
881
882
|
@keyframes log-line-flash {
|
|
882
883
|
0% {
|
|
883
|
-
background-color:
|
|
884
|
+
background-color: color-mix(in srgb, var(--rw-term-warn) 45%, transparent);
|
|
884
885
|
}
|
|
885
886
|
100% {
|
|
886
887
|
background-color: transparent;
|
|
@@ -924,7 +925,7 @@
|
|
|
924
925
|
height: 4px;
|
|
925
926
|
border-radius: 50%;
|
|
926
927
|
background-color: currentColor;
|
|
927
|
-
animation: dot-pulse 1s
|
|
928
|
+
animation: dot-pulse 1s infinite;
|
|
928
929
|
}
|
|
929
930
|
|
|
930
931
|
@keyframes dot-pulse {
|
|
@@ -20,7 +20,9 @@
|
|
|
20
20
|
};
|
|
21
21
|
</script>
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
<!-- The mark is flat currentColor (matching the website's brand mark), so the
|
|
24
|
+
brand teal comes from text-primary and any caller can override it. -->
|
|
25
|
+
<span class="inline-flex text-primary {sizeClasses[size]} {className}" aria-hidden="true">
|
|
24
26
|
<!-- SVG body is a static, repo-vendored asset imported via Vite's ?raw loader. -->
|
|
25
27
|
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
26
28
|
{@html logoSvg}
|
|
@@ -82,25 +82,27 @@
|
|
|
82
82
|
class="
|
|
83
83
|
relative z-10 w-full {sizeClasses[size]}
|
|
84
84
|
flex max-h-[90vh] flex-col
|
|
85
|
-
rounded-
|
|
85
|
+
rounded-[4px] border border-outline bg-surface-overlay shadow-lg
|
|
86
86
|
{className}
|
|
87
87
|
"
|
|
88
88
|
role="dialog"
|
|
89
89
|
aria-modal="true"
|
|
90
90
|
aria-labelledby={title ? "modal-title" : undefined}
|
|
91
91
|
>
|
|
92
|
-
<!-- Header -->
|
|
93
92
|
{#if header}
|
|
94
|
-
<div class="border-b border-outline
|
|
93
|
+
<div class="border-b border-outline px-6 py-4">
|
|
95
94
|
{@render header()}
|
|
96
95
|
</div>
|
|
97
96
|
{:else if title || closable}
|
|
98
97
|
<div
|
|
99
|
-
class="flex items-start justify-between gap-4 border-b border-outline
|
|
98
|
+
class="flex items-start justify-between gap-4 border-b border-outline px-6 py-4"
|
|
100
99
|
>
|
|
101
100
|
<div>
|
|
102
101
|
{#if title}
|
|
103
|
-
<h2
|
|
102
|
+
<h2
|
|
103
|
+
id="modal-title"
|
|
104
|
+
class="font-mono text-lg font-semibold text-on-surface"
|
|
105
|
+
>
|
|
104
106
|
{title}
|
|
105
107
|
</h2>
|
|
106
108
|
{/if}
|
|
@@ -111,7 +113,7 @@
|
|
|
111
113
|
{#if closable}
|
|
112
114
|
<button
|
|
113
115
|
onclick={handleClose}
|
|
114
|
-
class="-m-2 shrink-0 rounded-
|
|
116
|
+
class="-m-2 shrink-0 rounded-[3px] p-2 text-on-surface-faint hover:bg-surface-sunken hover:text-on-surface-muted"
|
|
115
117
|
aria-label="Close"
|
|
116
118
|
>
|
|
117
119
|
<X size={20} />
|
|
@@ -120,18 +122,14 @@
|
|
|
120
122
|
</div>
|
|
121
123
|
{/if}
|
|
122
124
|
|
|
123
|
-
<!-- Body -->
|
|
124
125
|
{#if children}
|
|
125
126
|
<div class="flex-1 overflow-y-auto px-6 py-4">
|
|
126
127
|
{@render children()}
|
|
127
128
|
</div>
|
|
128
129
|
{/if}
|
|
129
130
|
|
|
130
|
-
<!-- Footer -->
|
|
131
131
|
{#if footer}
|
|
132
|
-
<div
|
|
133
|
-
class="rounded-b-2xl border-t border-outline-faint bg-surface-sunken/50 px-6 py-4"
|
|
134
|
-
>
|
|
132
|
+
<div class="rounded-b-[4px] border-t border-outline bg-surface-sunken px-6 py-4">
|
|
135
133
|
{@render footer()}
|
|
136
134
|
</div>
|
|
137
135
|
{/if}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
<div class="flex shrink-0 flex-wrap items-start justify-between gap-3 px-1 {className}">
|
|
18
18
|
<div class="min-w-0">
|
|
19
|
-
<h1 class="text-2xl font-bold tracking-tight text-on-surface">{title}</h1>
|
|
19
|
+
<h1 class="font-mono text-2xl font-bold tracking-tight text-on-surface">{title}</h1>
|
|
20
20
|
{#if subtitle}
|
|
21
21
|
<p class="mt-0.5 text-sm text-on-surface-muted">{subtitle}</p>
|
|
22
22
|
{/if}
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
</script>
|
|
44
44
|
|
|
45
45
|
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between {className}">
|
|
46
|
-
<div class="flex items-center gap-4 text-sm text-on-surface-muted">
|
|
46
|
+
<div class="flex items-center gap-4 font-mono text-sm text-on-surface-muted">
|
|
47
47
|
{#if totalItems === 0}
|
|
48
48
|
<span>No results</span>
|
|
49
49
|
{:else}
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
value={pageSize}
|
|
58
58
|
onchange={handlePageSizeChange}
|
|
59
59
|
class="
|
|
60
|
-
appearance-none rounded-
|
|
61
|
-
|
|
60
|
+
appearance-none rounded-[3px] border border-outline bg-surface-raised py-1 pr-7 pl-2 font-mono
|
|
61
|
+
text-sm text-on-surface-muted shadow-sm hover:border-outline-hover focus:border-ring focus:ring-1 focus:ring-ring focus:outline-none
|
|
62
62
|
"
|
|
63
63
|
>
|
|
64
64
|
{#each pageSizeOptions as size (size)}
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
disabled={safePage <= 1}
|
|
82
82
|
onclick={() => goTo(safePage - 1)}>Prev</Button
|
|
83
83
|
>
|
|
84
|
-
<div class="min-w-[4rem] text-center text-xs text-on-surface-muted">
|
|
84
|
+
<div class="min-w-[4rem] text-center font-mono text-xs text-on-surface-muted">
|
|
85
85
|
Page {safePage} of {totalPages}
|
|
86
86
|
</div>
|
|
87
87
|
<Button
|
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
import type { Placement } from "@floating-ui/dom";
|
|
7
7
|
import { onDestroy } from "svelte";
|
|
8
8
|
import { computePosition, autoUpdate, flip, shift, offset } from "@floating-ui/dom";
|
|
9
|
-
import {
|
|
10
|
-
import { quintOut } from "svelte/easing";
|
|
9
|
+
import { fade } from "svelte/transition";
|
|
11
10
|
import { portal } from "../actions/portal.js";
|
|
12
11
|
|
|
13
12
|
interface Props {
|
|
@@ -139,20 +138,19 @@
|
|
|
139
138
|
<div
|
|
140
139
|
use:portal
|
|
141
140
|
transition:fade={{ duration: 120 }}
|
|
142
|
-
class="fixed inset-0 z-[9998] bg-
|
|
141
|
+
class="fixed inset-0 z-[9998] bg-backdrop"
|
|
143
142
|
aria-hidden="true"
|
|
144
143
|
></div>
|
|
145
144
|
{/if}
|
|
146
145
|
<div
|
|
147
146
|
use:portal
|
|
148
147
|
bind:this={contentEl}
|
|
149
|
-
transition:scale={{ duration: 150, start: 0.95, easing: quintOut }}
|
|
150
148
|
class="
|
|
151
149
|
z-[9999] max-h-[80vh] overflow-y-auto
|
|
152
|
-
border border-outline bg-surface-overlay shadow-
|
|
150
|
+
border border-outline bg-surface-overlay shadow-lg
|
|
153
151
|
{asSheet
|
|
154
|
-
? 'fixed inset-x-0 bottom-0 max-h-[85vh] rounded-t-
|
|
155
|
-
: 'rounded-
|
|
152
|
+
? 'fixed inset-x-0 bottom-0 max-h-[85vh] rounded-t-[4px] border-x-0 border-b-0 p-5'
|
|
153
|
+
: 'rounded-[4px] p-4'}
|
|
156
154
|
"
|
|
157
155
|
>
|
|
158
156
|
{#if children}
|
|
@@ -45,19 +45,21 @@
|
|
|
45
45
|
{#if showLabel || label}
|
|
46
46
|
<div class="mb-1.5 flex items-center justify-between">
|
|
47
47
|
{#if label}
|
|
48
|
-
<span class="text-sm
|
|
48
|
+
<span class="font-mono text-sm text-on-surface-muted">{label}</span>
|
|
49
49
|
{/if}
|
|
50
50
|
{#if showLabel}
|
|
51
|
-
<span class="text-sm text-on-surface-muted"
|
|
51
|
+
<span class="font-mono text-sm text-on-surface-muted"
|
|
52
|
+
>{Math.round(percentage)}%</span
|
|
53
|
+
>
|
|
52
54
|
{/if}
|
|
53
55
|
</div>
|
|
54
56
|
{/if}
|
|
55
57
|
|
|
56
|
-
<div class="w-full {sizeClasses[size]} overflow-hidden rounded-full bg-
|
|
58
|
+
<div class="w-full {sizeClasses[size]} overflow-hidden rounded-full bg-surface-sunken">
|
|
57
59
|
<div
|
|
58
60
|
class="{sizeClasses[size]} {variantClasses[
|
|
59
61
|
variant
|
|
60
|
-
]} rounded-full transition-
|
|
62
|
+
]} rounded-full transition-[width] duration-200"
|
|
61
63
|
style="width: {percentage}%"
|
|
62
64
|
role="progressbar"
|
|
63
65
|
aria-valuenow={value}
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
prose-headings:text-on-surface
|
|
29
29
|
prose-p:text-on-surface-muted prose-a:text-primary prose-a:no-underline
|
|
30
30
|
hover:prose-a:underline
|
|
31
|
-
prose-blockquote:border-outline prose-blockquote:text-on-surface-muted prose-strong:text-on-surface prose-code:rounded prose-code:bg-surface-sunken
|
|
32
|
-
prose-code:px-1 prose-code:py-0.5 prose-code:text-on-surface
|
|
33
|
-
prose-pre:border prose-pre:border-outline
|
|
34
|
-
prose-pre:bg-surface-sunken
|
|
31
|
+
prose-blockquote:border-outline prose-blockquote:text-on-surface-muted prose-strong:text-on-surface prose-code:rounded-[3px] prose-code:bg-surface-sunken
|
|
32
|
+
prose-code:px-1 prose-code:py-0.5 prose-code:font-mono prose-code:text-on-surface
|
|
33
|
+
prose-pre:rounded-[4px] prose-pre:border prose-pre:border-outline
|
|
34
|
+
prose-pre:bg-surface-sunken prose-pre:font-mono
|
|
35
35
|
prose-li:text-on-surface-muted
|
|
36
36
|
prose-th:text-on-surface
|
|
37
37
|
prose-td:text-on-surface-muted
|
|
@@ -49,21 +49,20 @@
|
|
|
49
49
|
checked={isChecked}
|
|
50
50
|
onchange={() => (groupValue = value)}
|
|
51
51
|
class="
|
|
52
|
-
peer {sizeClasses[size].radio}
|
|
52
|
+
peer {sizeClasses[size].radio}
|
|
53
53
|
cursor-pointer appearance-none rounded-full
|
|
54
|
-
border
|
|
55
|
-
bg-surface-raised
|
|
56
|
-
|
|
57
|
-
hover:border-on-surface-faint
|
|
54
|
+
border border-outline
|
|
55
|
+
bg-surface-raised checked:border-primary checked:bg-primary
|
|
56
|
+
hover:border-outline-hover
|
|
58
57
|
checked:hover:border-primary-hover checked:hover:bg-primary-hover
|
|
59
|
-
focus:ring-2 focus:ring-ring
|
|
60
|
-
focus:
|
|
61
|
-
disabled:cursor-not-allowed disabled:hover:border-outline
|
|
58
|
+
focus:ring-2 focus:ring-ring focus:ring-offset-2
|
|
59
|
+
focus:outline-none
|
|
60
|
+
disabled:cursor-not-allowed disabled:hover:border-outline
|
|
62
61
|
disabled:checked:hover:bg-primary
|
|
63
62
|
"
|
|
64
63
|
/>
|
|
65
64
|
<div
|
|
66
|
-
class="
|
|
65
|
+
class="pointer-events-none absolute rounded-full bg-on-primary opacity-0 peer-checked:opacity-100 {sizeClasses[
|
|
67
66
|
size
|
|
68
67
|
].dot}"
|
|
69
68
|
></div>
|
|
@@ -72,7 +71,9 @@
|
|
|
72
71
|
{#if label || description}
|
|
73
72
|
<div class="flex flex-col gap-0.5">
|
|
74
73
|
{#if label}
|
|
75
|
-
<span class="{sizeClasses[size].text} font-medium text-on-surface"
|
|
74
|
+
<span class="{sizeClasses[size].text} font-mono font-medium text-on-surface"
|
|
75
|
+
>{label}</span
|
|
76
|
+
>
|
|
76
77
|
{/if}
|
|
77
78
|
{#if description}
|
|
78
79
|
<span class="text-sm text-on-surface-muted">{description}</span>
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
|
|
37
37
|
<fieldset class="space-y-3 {className}" role="radiogroup" aria-label={label}>
|
|
38
38
|
{#if label}
|
|
39
|
-
<legend class="text-
|
|
39
|
+
<legend class="font-mono text-xs font-medium text-on-surface-muted">{label}</legend>
|
|
40
40
|
{/if}
|
|
41
41
|
|
|
42
42
|
<div class={orientationClasses[orientation]}>
|
|
@@ -44,12 +44,10 @@
|
|
|
44
44
|
</div>
|
|
45
45
|
|
|
46
46
|
{#if error}
|
|
47
|
-
<p
|
|
48
|
-
class="animate-in slide-in-from-top-1 fade-in text-sm text-danger-soft-text duration-200"
|
|
49
|
-
>
|
|
47
|
+
<p class="font-sans text-xs text-danger-soft-text">
|
|
50
48
|
{error}
|
|
51
49
|
</p>
|
|
52
50
|
{:else if hint}
|
|
53
|
-
<p class="text-
|
|
51
|
+
<p class="font-sans text-xs text-on-surface-muted">{hint}</p>
|
|
54
52
|
{/if}
|
|
55
53
|
</fieldset>
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
<script lang="ts">
|
|
19
19
|
import { tick, onDestroy } from "svelte";
|
|
20
20
|
import { ChevronDown, Check, Search } from "@lucide/svelte";
|
|
21
|
-
import { fade } from "svelte/transition";
|
|
22
21
|
import { computePosition, autoUpdate, flip, shift, offset } from "@floating-ui/dom";
|
|
23
22
|
import { generateUlid } from "@runwisp/common";
|
|
24
23
|
|
|
@@ -54,7 +53,7 @@
|
|
|
54
53
|
id = `select-${generateUlid()}`,
|
|
55
54
|
name,
|
|
56
55
|
onchange,
|
|
57
|
-
onsearch,
|
|
56
|
+
onsearch,
|
|
58
57
|
}: Props & { onsearch?: (query: string) => void } = $props();
|
|
59
58
|
|
|
60
59
|
let isOpen = $state(false);
|
|
@@ -157,7 +156,7 @@
|
|
|
157
156
|
value = option.value;
|
|
158
157
|
onchange?.(value);
|
|
159
158
|
isOpen = false;
|
|
160
|
-
cleanupFloating?.();
|
|
159
|
+
cleanupFloating?.();
|
|
161
160
|
}
|
|
162
161
|
|
|
163
162
|
function handleKeydown(e: KeyboardEvent) {
|
|
@@ -231,18 +230,17 @@
|
|
|
231
230
|
};
|
|
232
231
|
|
|
233
232
|
const triggerBase = `
|
|
234
|
-
relative w-full text-left cursor-pointer
|
|
235
|
-
rounded-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
focus:outline-none focus:ring-4 focus:ring-ring/10 focus:border-ring
|
|
233
|
+
relative w-full text-left cursor-pointer font-mono
|
|
234
|
+
rounded-[3px] border bg-surface-raised
|
|
235
|
+
flex items-center justify-between
|
|
236
|
+
focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:border-ring
|
|
239
237
|
`;
|
|
240
238
|
|
|
241
239
|
const borderClass = $derived(
|
|
242
240
|
error
|
|
243
|
-
? "border-danger-
|
|
241
|
+
? "border-danger-surface"
|
|
244
242
|
: isOpen
|
|
245
|
-
? "border-ring ring-
|
|
243
|
+
? "border-ring ring-2 ring-ring ring-offset-2"
|
|
246
244
|
: "border-outline hover:border-outline-hover shadow-sm hover:shadow-md",
|
|
247
245
|
);
|
|
248
246
|
</script>
|
|
@@ -251,7 +249,7 @@
|
|
|
251
249
|
|
|
252
250
|
<div class="relative w-full {className}">
|
|
253
251
|
{#if label}
|
|
254
|
-
<label for={id} class="mb-1.5 block text-
|
|
252
|
+
<label for={id} class="mb-1.5 block font-mono text-xs font-medium text-on-surface-muted">
|
|
255
253
|
{label}
|
|
256
254
|
</label>
|
|
257
255
|
{/if}
|
|
@@ -292,30 +290,19 @@
|
|
|
292
290
|
<div
|
|
293
291
|
class="pointer-events-none absolute top-1/2 right-3 -translate-y-1/2 text-on-surface-faint"
|
|
294
292
|
>
|
|
295
|
-
<ChevronDown
|
|
296
|
-
size={16}
|
|
297
|
-
class="transition-transform duration-200 {isOpen ? 'rotate-180' : ''}"
|
|
298
|
-
/>
|
|
293
|
+
<ChevronDown size={16} class={isOpen ? "rotate-180" : ""} />
|
|
299
294
|
</div>
|
|
300
295
|
</button>
|
|
301
296
|
|
|
302
|
-
<!-- Hidden input for form submission if needed -->
|
|
303
297
|
{#if name}
|
|
304
298
|
<input type="hidden" {name} {value} />
|
|
305
299
|
{/if}
|
|
306
300
|
|
|
307
|
-
<!-- Dropdown Menu -->
|
|
308
301
|
{#if isOpen}
|
|
309
|
-
<div
|
|
310
|
-
use:portal
|
|
311
|
-
bind:this={menuEl}
|
|
312
|
-
transition:fade={{ duration: 100 }}
|
|
313
|
-
class="z-[9999] min-w-[200px]"
|
|
314
|
-
>
|
|
302
|
+
<div use:portal bind:this={menuEl} class="z-[9999] min-w-[200px]">
|
|
315
303
|
<div
|
|
316
304
|
class="
|
|
317
|
-
overflow-hidden rounded-
|
|
318
|
-
ring-1 shadow-on-surface/5 ring-black/5
|
|
305
|
+
overflow-hidden rounded-[4px] border border-outline bg-surface-overlay shadow-md
|
|
319
306
|
"
|
|
320
307
|
>
|
|
321
308
|
{#if searchable}
|
|
@@ -331,8 +318,8 @@
|
|
|
331
318
|
onkeydown={handleKeydown}
|
|
332
319
|
placeholder="Search..."
|
|
333
320
|
class="
|
|
334
|
-
w-full rounded-
|
|
335
|
-
text-on-surface placeholder:text-on-surface-faint focus:border-ring focus:ring-
|
|
321
|
+
w-full rounded-[3px] border border-outline bg-surface-raised py-1.5 pr-3 pl-8 font-mono text-xs
|
|
322
|
+
text-on-surface placeholder:text-on-surface-faint focus:border-ring focus:ring-2
|
|
336
323
|
focus:ring-ring focus:outline-none
|
|
337
324
|
"
|
|
338
325
|
/>
|
|
@@ -341,7 +328,7 @@
|
|
|
341
328
|
{/if}
|
|
342
329
|
|
|
343
330
|
<div
|
|
344
|
-
class="scrollbar-thin scrollbar-thumb-mist-200 scrollbar-track-transparent
|
|
331
|
+
class="max-h-60 scrollbar-thin scrollbar-thumb-mist-200 scrollbar-track-transparent overflow-x-hidden overflow-y-auto p-1"
|
|
345
332
|
>
|
|
346
333
|
{#if flattenedVisibleOptions.length === 0}
|
|
347
334
|
<div class="px-4 py-8 text-center text-sm text-on-surface-muted">
|
|
@@ -363,7 +350,7 @@
|
|
|
363
350
|
|
|
364
351
|
{#each Object.entries(groupedOptions.groups) as [groupName, groupOptions] (groupName)}
|
|
365
352
|
<div
|
|
366
|
-
class="sticky top-0 z-10 mt-1 bg-surface-sunken/50 px-2 py-1.5 text-xs font-semibold tracking-wider text-on-surface-faint uppercase backdrop-blur-sm first:mt-0"
|
|
353
|
+
class="sticky top-0 z-10 mt-1 bg-surface-sunken/50 px-2 py-1.5 font-mono text-xs font-semibold tracking-wider text-on-surface-faint uppercase backdrop-blur-sm first:mt-0"
|
|
367
354
|
>
|
|
368
355
|
{groupName}
|
|
369
356
|
</div>
|
|
@@ -385,17 +372,16 @@
|
|
|
385
372
|
{/if}
|
|
386
373
|
|
|
387
374
|
{#if error}
|
|
388
|
-
<p class="
|
|
375
|
+
<p class="mt-1.5 font-sans text-xs text-danger-soft-text">
|
|
389
376
|
{error}
|
|
390
377
|
</p>
|
|
391
378
|
{:else if hint}
|
|
392
|
-
<p class="mt-1.5 text-xs text-on-surface-muted">
|
|
379
|
+
<p class="mt-1.5 font-sans text-xs text-on-surface-muted">
|
|
393
380
|
{hint}
|
|
394
381
|
</p>
|
|
395
382
|
{/if}
|
|
396
383
|
</div>
|
|
397
384
|
|
|
398
|
-
<!-- Helper Component for items -->
|
|
399
385
|
{#snippet OptionItem({
|
|
400
386
|
option,
|
|
401
387
|
active,
|
|
@@ -416,8 +402,9 @@
|
|
|
416
402
|
{onclick}
|
|
417
403
|
onmouseenter={onsemiactive}
|
|
418
404
|
class="
|
|
419
|
-
flex w-full items-start gap-3 rounded-
|
|
420
|
-
|
|
405
|
+
flex w-full items-start gap-3 rounded-[3px] px-2.5 py-2 text-left {active
|
|
406
|
+
? 'bg-surface-sunken'
|
|
407
|
+
: 'hover:bg-surface-sunken/50'}
|
|
421
408
|
{selected ? 'bg-primary-soft/50 font-medium text-on-surface' : 'text-on-surface-muted'}
|
|
422
409
|
{option.disabled
|
|
423
410
|
? 'pointer-events-none cursor-not-allowed opacity-50'
|
|
@@ -433,14 +420,14 @@
|
|
|
433
420
|
|
|
434
421
|
<div class="min-w-0 flex-1">
|
|
435
422
|
<div class="flex items-center justify-between gap-2">
|
|
436
|
-
<span class="block truncate text-sm font-medium">{option.label}</span>
|
|
423
|
+
<span class="block truncate font-mono text-sm font-medium">{option.label}</span>
|
|
437
424
|
{#if selected}
|
|
438
425
|
<Check size={14} class="shrink-0 text-primary" />
|
|
439
426
|
{/if}
|
|
440
427
|
</div>
|
|
441
428
|
{#if option.description}
|
|
442
429
|
<div
|
|
443
|
-
class="mt-0.5 line-clamp-2 text-xs leading-normal text-wrap text-on-surface-muted"
|
|
430
|
+
class="mt-0.5 line-clamp-2 font-sans text-xs leading-normal text-wrap text-on-surface-muted"
|
|
444
431
|
>
|
|
445
432
|
{option.description}
|
|
446
433
|
</div>
|
|
@@ -22,7 +22,10 @@
|
|
|
22
22
|
{:else if label}
|
|
23
23
|
<div role="separator" class="flex items-center gap-3 {className}">
|
|
24
24
|
<div class="h-px flex-1 bg-outline"></div>
|
|
25
|
-
<span
|
|
25
|
+
<span
|
|
26
|
+
class="font-mono text-xs font-medium tracking-wider text-on-surface-faint uppercase select-none"
|
|
27
|
+
>{label}</span
|
|
28
|
+
>
|
|
26
29
|
<div class="h-px flex-1 bg-outline"></div>
|
|
27
30
|
</div>
|
|
28
31
|
{:else}
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
{#if shape === "circle"}
|
|
32
32
|
<div
|
|
33
|
-
class="animate-pulse rounded-full bg-
|
|
33
|
+
class="animate-pulse rounded-full bg-surface-sunken {className}"
|
|
34
34
|
style="width: {width ?? '2.5rem'}; height: {height ?? width ?? '2.5rem'}"
|
|
35
35
|
role="status"
|
|
36
36
|
aria-label="Loading"
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
</div>
|
|
40
40
|
{:else if shape === "rect"}
|
|
41
41
|
<div
|
|
42
|
-
class="animate-pulse rounded-
|
|
42
|
+
class="animate-pulse rounded-[4px] bg-surface-sunken {className}"
|
|
43
43
|
style="width: {width ?? '100%'}; height: {height ?? '2rem'}"
|
|
44
44
|
role="status"
|
|
45
45
|
aria-label="Loading"
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
<div class="animate-pulse space-y-6 p-6 {className}" role="status" aria-label="Loading content">
|
|
51
51
|
{#if header}
|
|
52
52
|
<div class="space-y-3">
|
|
53
|
-
<div class="h-7 w-48 rounded-
|
|
54
|
-
<div class="h-4 w-72 rounded bg-
|
|
53
|
+
<div class="h-7 w-48 rounded-[4px] bg-surface-sunken"></div>
|
|
54
|
+
<div class="h-4 w-72 rounded-[3px] bg-surface-sunken"></div>
|
|
55
55
|
</div>
|
|
56
56
|
{/if}
|
|
57
57
|
|
|
@@ -59,11 +59,11 @@
|
|
|
59
59
|
{#each Array.from({ length: rows }, (_, i) => i) as i (i)}
|
|
60
60
|
<div class="space-y-2">
|
|
61
61
|
<div
|
|
62
|
-
class="h-4 rounded bg-
|
|
62
|
+
class="h-4 rounded-[3px] bg-surface-sunken"
|
|
63
63
|
style="width: {70 + ((i * 17) % 30)}%"
|
|
64
64
|
></div>
|
|
65
65
|
<div
|
|
66
|
-
class="h-4 rounded bg-surface-sunken"
|
|
66
|
+
class="h-4 rounded-[3px] bg-surface-sunken"
|
|
67
67
|
style="width: {40 + ((i * 23) % 40)}%"
|
|
68
68
|
></div>
|
|
69
69
|
</div>
|