@dorsk/tsumikit 0.35.0 → 0.36.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.
@@ -0,0 +1,254 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import { capFromPointer, capKeyStep, capTone, clampCap, snapCap } from '../../cap-bar';
4
+
5
+ let {
6
+ value = 0,
7
+ cap = $bindable(100),
8
+ min = 0,
9
+ max = 100,
10
+ step = 5,
11
+ warnAt = 75,
12
+ size = 'md',
13
+ label,
14
+ labelWidth = '96px',
15
+ readout,
16
+ readoutWidth = '76px',
17
+ hint,
18
+ caption,
19
+ tooltip,
20
+ readonly = false,
21
+ oninput,
22
+ onchange,
23
+ class: klass = '',
24
+ style: styleProp = ''
25
+ }: {
26
+ /** Consumption, in percent of `max`. */
27
+ value?: number;
28
+ /** Cap position; bindable, moved by drag/keyboard. */
29
+ cap?: number;
30
+ min?: number;
31
+ max?: number;
32
+ /** Snap increment for drag and keyboard. */
33
+ step?: number;
34
+ /** Consumption at which the fill turns `--warn`. */
35
+ warnAt?: number;
36
+ size?: 'md' | 'lg';
37
+ label?: string | Snippet;
38
+ labelWidth?: string;
39
+ /** Overrides the default `{value}% · {hint}` readout. */
40
+ readout?: string | Snippet;
41
+ readoutWidth?: string;
42
+ hint?: string;
43
+ caption?: Snippet;
44
+ /** Track tooltip; defaults to "cap N% — drag the bar". */
45
+ tooltip?: string;
46
+ readonly?: boolean;
47
+ /** Fires live while dragging or stepping. */
48
+ oninput?: (cap: number) => void;
49
+ /** Fires once the cap is committed (pointer release / key-up). */
50
+ onchange?: (cap: number) => void;
51
+ class?: string;
52
+ style?: string;
53
+ } = $props();
54
+
55
+ const range = $derived(max - min || 1);
56
+ const pct = $derived(clampCap(((value - min) / range) * 100, 0, 100));
57
+ const capPct = $derived(clampCap(((cap - min) / range) * 100, 0, 100));
58
+ const tone = $derived(capTone(value, cap, warnAt));
59
+ const readoutText = $derived(hint ? `${value}% · ${hint}` : `${value}%`);
60
+ const tip = $derived(tooltip ?? `cap ${cap}% — drag the bar`);
61
+ const ariaLabel = $derived(typeof label === 'string' ? `${label} cap` : 'cap');
62
+
63
+ let trackEl = $state<HTMLDivElement | null>(null);
64
+ let dragging = $state(false);
65
+ let committed = cap;
66
+
67
+ function setCap(next: number) {
68
+ if (next === cap) return;
69
+ cap = next;
70
+ oninput?.(cap);
71
+ }
72
+ function commit() {
73
+ if (cap === committed) return;
74
+ committed = cap;
75
+ onchange?.(cap);
76
+ }
77
+
78
+ function pointerDown(e: PointerEvent) {
79
+ if (readonly || !trackEl || e.button !== 0) return;
80
+ e.preventDefault();
81
+ dragging = true;
82
+ trackEl.setPointerCapture(e.pointerId);
83
+ setCap(capFromPointer(e.clientX, trackEl.getBoundingClientRect(), step, min, max));
84
+ trackEl.querySelector<HTMLElement>('.handle')?.focus();
85
+ }
86
+ function pointerMove(e: PointerEvent) {
87
+ if (!dragging || !trackEl) return;
88
+ setCap(capFromPointer(e.clientX, trackEl.getBoundingClientRect(), step, min, max));
89
+ }
90
+ function pointerUp() {
91
+ if (!dragging) return;
92
+ dragging = false;
93
+ commit();
94
+ }
95
+ function keyDown(e: KeyboardEvent) {
96
+ if (readonly) return;
97
+ const next = capKeyStep(e.key, e.shiftKey, snapCap(cap, step, min, max), step, min, max);
98
+ if (next === null) return;
99
+ e.preventDefault();
100
+ setCap(next);
101
+ }
102
+ function keyUp(e: KeyboardEvent) {
103
+ if (readonly || capKeyStep(e.key, e.shiftKey, cap, step, min, max) === null) return;
104
+ commit();
105
+ }
106
+ </script>
107
+
108
+ <div
109
+ data-tsu="CapBar"
110
+ class="cap-bar size-{size} tone-{tone} {klass}"
111
+ class:readonly
112
+ class:dragging
113
+ style="--label-w: {labelWidth}; --readout-w: {readoutWidth}; --pct: {pct}%; --cap: {capPct}%; {styleProp}"
114
+ >
115
+ {#if label}
116
+ <div class="label">
117
+ {#if typeof label === 'string'}{label}{:else}{@render label()}{/if}
118
+ </div>
119
+ {/if}
120
+ <div
121
+ class="track"
122
+ role="presentation"
123
+ bind:this={trackEl}
124
+ title={tip}
125
+ onpointerdown={pointerDown}
126
+ onpointermove={pointerMove}
127
+ onpointerup={pointerUp}
128
+ onpointercancel={pointerUp}
129
+ >
130
+ <div class="fill"></div>
131
+ <div
132
+ class="handle"
133
+ role="slider"
134
+ tabindex={readonly ? -1 : 0}
135
+ aria-label={ariaLabel}
136
+ aria-valuemin={min}
137
+ aria-valuemax={max}
138
+ aria-valuenow={cap}
139
+ aria-valuetext="cap {cap}%"
140
+ aria-disabled={readonly ? 'true' : undefined}
141
+ onkeydown={keyDown}
142
+ onkeyup={keyUp}
143
+ ></div>
144
+ </div>
145
+ <div class="readout">
146
+ {#if readout === undefined}{readoutText}{:else if typeof readout === 'string'}{readout}{:else}{@render readout()}{/if}
147
+ </div>
148
+ {#if caption}
149
+ <div class="caption">{@render caption()}</div>
150
+ {/if}
151
+ </div>
152
+
153
+ <style>
154
+ .cap-bar {
155
+ display: grid;
156
+ grid-template-columns: var(--label-w) 1fr var(--readout-w);
157
+ align-items: center;
158
+ column-gap: var(--sp-3);
159
+ row-gap: var(--sp-1);
160
+ width: 100%;
161
+ font-size: var(--fs-sm);
162
+ --track-h: 6px;
163
+ --fill: var(--ok);
164
+ }
165
+ .cap-bar.size-lg {
166
+ --track-h: 10px;
167
+ }
168
+ .tone-warn {
169
+ --fill: var(--warn);
170
+ }
171
+ .tone-danger {
172
+ --fill: var(--danger);
173
+ }
174
+ .label {
175
+ color: var(--text-muted);
176
+ overflow: hidden;
177
+ text-overflow: ellipsis;
178
+ white-space: nowrap;
179
+ }
180
+ .cap-bar:not(:has(.label)) .track {
181
+ grid-column: 1 / 3;
182
+ }
183
+ .track {
184
+ position: relative;
185
+ height: var(--track-h);
186
+ border-radius: var(--r-pill);
187
+ background: color-mix(in oklab, var(--accent) 26%, var(--bg));
188
+ cursor: ew-resize;
189
+ touch-action: none;
190
+ user-select: none;
191
+ }
192
+ .track::after {
193
+ content: '';
194
+ position: absolute;
195
+ inset: 0 0 0 var(--cap);
196
+ border-radius: 0 var(--r-pill) var(--r-pill) 0;
197
+ background: var(--bg);
198
+ box-shadow: inset 0 0 0 1px var(--border);
199
+ pointer-events: none;
200
+ }
201
+ .fill {
202
+ position: absolute;
203
+ inset: 0 auto 0 0;
204
+ width: var(--pct);
205
+ border-radius: var(--r-pill);
206
+ background: var(--fill);
207
+ transition: width 0.2s var(--ease);
208
+ z-index: 1;
209
+ }
210
+ .handle {
211
+ position: absolute;
212
+ top: 50%;
213
+ left: var(--cap);
214
+ width: 3px;
215
+ height: 16px;
216
+ transform: translate(-50%, -50%);
217
+ border-radius: 2px;
218
+ background: var(--text);
219
+ box-shadow: 0 0 0 2px var(--surface);
220
+ cursor: ew-resize;
221
+ z-index: 2;
222
+ }
223
+ .handle:focus-visible {
224
+ outline: 2px solid var(--accent);
225
+ outline-offset: 2px;
226
+ }
227
+ .readonly .track,
228
+ .readonly .handle {
229
+ cursor: default;
230
+ pointer-events: none;
231
+ }
232
+ .readonly .handle {
233
+ opacity: 0.6;
234
+ }
235
+ .readout {
236
+ text-align: right;
237
+ font-variant-numeric: tabular-nums;
238
+ color: var(--text-muted);
239
+ white-space: nowrap;
240
+ }
241
+ .caption {
242
+ grid-column: 2 / 3;
243
+ font-size: var(--fs-xs);
244
+ color: var(--text-faint);
245
+ }
246
+ .cap-bar:not(:has(.label)) .caption {
247
+ grid-column: 1 / 3;
248
+ }
249
+ @media (prefers-reduced-motion: reduce) {
250
+ .fill {
251
+ transition: none;
252
+ }
253
+ }
254
+ </style>
@@ -0,0 +1,33 @@
1
+ import type { Snippet } from 'svelte';
2
+ type $$ComponentProps = {
3
+ /** Consumption, in percent of `max`. */
4
+ value?: number;
5
+ /** Cap position; bindable, moved by drag/keyboard. */
6
+ cap?: number;
7
+ min?: number;
8
+ max?: number;
9
+ /** Snap increment for drag and keyboard. */
10
+ step?: number;
11
+ /** Consumption at which the fill turns `--warn`. */
12
+ warnAt?: number;
13
+ size?: 'md' | 'lg';
14
+ label?: string | Snippet;
15
+ labelWidth?: string;
16
+ /** Overrides the default `{value}% · {hint}` readout. */
17
+ readout?: string | Snippet;
18
+ readoutWidth?: string;
19
+ hint?: string;
20
+ caption?: Snippet;
21
+ /** Track tooltip; defaults to "cap N% — drag the bar". */
22
+ tooltip?: string;
23
+ readonly?: boolean;
24
+ /** Fires live while dragging or stepping. */
25
+ oninput?: (cap: number) => void;
26
+ /** Fires once the cap is committed (pointer release / key-up). */
27
+ onchange?: (cap: number) => void;
28
+ class?: string;
29
+ style?: string;
30
+ };
31
+ declare const CapBar: import("svelte").Component<$$ComponentProps, {}, "cap">;
32
+ type CapBar = ReturnType<typeof CapBar>;
33
+ export default CapBar;
@@ -0,0 +1,183 @@
1
+ <script lang="ts">
2
+ // Bordered zone whose legend rides the top border. Real <fieldset>/<legend>
3
+ // for semantics. `droppable` turns it into an HTML5 drop target: a hovering
4
+ // drag that passes `accepts` highlights the zone and shows `dropHint`;
5
+ // `ondrop` receives the payload read from `dataTransfer` under `mime`.
6
+ // Keyboard users cannot drag — the consumer must offer a non-drag path
7
+ // (a move menu, a select) to the same action. Pointer-based DnD can drive
8
+ // the highlight through the bindable `over` prop.
9
+ import type { Snippet } from 'svelte';
10
+
11
+ type Tone = 'accent' | 'neutral' | 'strong';
12
+
13
+ let {
14
+ legend,
15
+ tone = 'accent',
16
+ dashed = true,
17
+ padding = 'md',
18
+ droppable = false,
19
+ mime = 'text/plain',
20
+ accepts,
21
+ ondrop,
22
+ dropHint,
23
+ over = $bindable(false),
24
+ disabled = false,
25
+ class: klass = '',
26
+ style = '',
27
+ children,
28
+ ...rest
29
+ }: {
30
+ legend?: string | Snippet;
31
+ tone?: Tone;
32
+ dashed?: boolean;
33
+ padding?: 'sm' | 'md' | 'lg';
34
+ droppable?: boolean;
35
+ mime?: string;
36
+ accepts?: (data: string, e: DragEvent) => boolean;
37
+ ondrop?: (data: string, e: DragEvent) => void;
38
+ dropHint?: string | Snippet;
39
+ over?: boolean;
40
+ disabled?: boolean;
41
+ class?: string;
42
+ style?: string;
43
+ children?: Snippet;
44
+ [key: string]: unknown;
45
+ } = $props();
46
+
47
+ let depth = 0;
48
+
49
+ function payload(e: DragEvent): string {
50
+ return e.dataTransfer?.getData(mime) ?? '';
51
+ }
52
+ function valid(e: DragEvent): boolean {
53
+ if (!droppable || disabled) return false;
54
+ if (!Array.from(e.dataTransfer?.types ?? []).includes(mime)) return false;
55
+ return accepts ? accepts(payload(e), e) : true;
56
+ }
57
+
58
+ function onDragEnter(e: DragEvent) {
59
+ if (!valid(e)) return;
60
+ e.preventDefault();
61
+ depth++;
62
+ if (depth === 1) over = true;
63
+ }
64
+ function onDragLeave(e: DragEvent) {
65
+ if (!droppable || disabled) return;
66
+ depth = Math.max(0, depth - 1);
67
+ if (depth === 0) over = false;
68
+ }
69
+ function onDragOver(e: DragEvent) {
70
+ if (!valid(e)) return;
71
+ e.preventDefault();
72
+ if (e.dataTransfer) e.dataTransfer.dropEffect = 'move';
73
+ }
74
+ function onDrop(e: DragEvent) {
75
+ depth = 0;
76
+ over = false;
77
+ if (!valid(e)) return;
78
+ e.preventDefault();
79
+ ondrop?.(payload(e), e);
80
+ }
81
+ </script>
82
+
83
+ <fieldset
84
+ class="fieldset fieldset-{tone} pad-{padding} {klass}"
85
+ class:dashed
86
+ class:droppable
87
+ class:over
88
+ class:disabled
89
+ data-tsu="Fieldset"
90
+ {style}
91
+ ondragenter={onDragEnter}
92
+ ondragleave={onDragLeave}
93
+ ondragover={onDragOver}
94
+ ondrop={onDrop}
95
+ {...rest}
96
+ >
97
+ {#if legend}
98
+ <legend class="fieldset-legend">
99
+ {#if typeof legend === 'string'}{legend}{:else}{@render legend()}{/if}
100
+ </legend>
101
+ {/if}
102
+ {@render children?.()}
103
+ {#if droppable && over && dropHint}
104
+ <div class="fieldset-hint" aria-live="polite">
105
+ {#if typeof dropHint === 'string'}{dropHint}{:else}{@render dropHint()}{/if}
106
+ </div>
107
+ {/if}
108
+ </fieldset>
109
+
110
+ <style>
111
+ .fieldset {
112
+ --fieldset-border: var(--accent-dim);
113
+ --fieldset-pad: var(--sp-4);
114
+ position: relative;
115
+ min-width: 0;
116
+ margin: 0;
117
+ padding: calc(var(--fieldset-pad) + var(--sp-1)) var(--fieldset-pad) var(--fieldset-pad);
118
+ border: 2px solid var(--fieldset-border);
119
+ border-radius: var(--r-lg);
120
+ background: var(--bg);
121
+ transition:
122
+ border-color 0.12s var(--ease),
123
+ background 0.12s var(--ease);
124
+ }
125
+ .fieldset.dashed {
126
+ border-style: dashed;
127
+ }
128
+ .fieldset-neutral {
129
+ --fieldset-border: var(--border);
130
+ }
131
+ .fieldset-strong {
132
+ --fieldset-border: var(--border-strong);
133
+ }
134
+ .pad-sm {
135
+ --fieldset-pad: var(--sp-3);
136
+ }
137
+ .pad-lg {
138
+ --fieldset-pad: var(--sp-6);
139
+ }
140
+
141
+ .fieldset-legend {
142
+ position: absolute;
143
+ top: -13px;
144
+ left: 16px;
145
+ display: inline-flex;
146
+ align-items: center;
147
+ gap: var(--sp-2);
148
+ max-width: calc(100% - 32px);
149
+ padding: 0 8px;
150
+ background: var(--bg);
151
+ font-size: var(--fs-sm);
152
+ font-weight: var(--fw-semibold);
153
+ line-height: 1.5;
154
+ color: var(--text);
155
+ }
156
+
157
+ .fieldset.over {
158
+ --fieldset-border: var(--accent);
159
+ background: color-mix(in srgb, var(--accent) 6%, var(--bg));
160
+ }
161
+ .fieldset.over .fieldset-legend {
162
+ background: color-mix(in srgb, var(--accent) 6%, var(--bg));
163
+ }
164
+ .fieldset-hint {
165
+ margin-top: var(--sp-3);
166
+ padding: var(--sp-2) var(--sp-3);
167
+ border: 1px dashed var(--accent);
168
+ border-radius: var(--r-md);
169
+ font-size: var(--fs-sm);
170
+ color: var(--accent);
171
+ text-align: center;
172
+ pointer-events: none;
173
+ }
174
+ .fieldset.disabled {
175
+ opacity: 0.6;
176
+ }
177
+
178
+ @media (prefers-reduced-motion: reduce) {
179
+ .fieldset {
180
+ transition: none;
181
+ }
182
+ }
183
+ </style>
@@ -0,0 +1,22 @@
1
+ import type { Snippet } from 'svelte';
2
+ type Tone = 'accent' | 'neutral' | 'strong';
3
+ type $$ComponentProps = {
4
+ legend?: string | Snippet;
5
+ tone?: Tone;
6
+ dashed?: boolean;
7
+ padding?: 'sm' | 'md' | 'lg';
8
+ droppable?: boolean;
9
+ mime?: string;
10
+ accepts?: (data: string, e: DragEvent) => boolean;
11
+ ondrop?: (data: string, e: DragEvent) => void;
12
+ dropHint?: string | Snippet;
13
+ over?: boolean;
14
+ disabled?: boolean;
15
+ class?: string;
16
+ style?: string;
17
+ children?: Snippet;
18
+ [key: string]: unknown;
19
+ };
20
+ declare const Fieldset: import("svelte").Component<$$ComponentProps, {}, "over">;
21
+ type Fieldset = ReturnType<typeof Fieldset>;
22
+ export default Fieldset;
@@ -0,0 +1,174 @@
1
+ <script lang="ts" module>
2
+ import type { Tone } from '../../tone';
3
+
4
+ export type PrState = 'open' | 'merged' | 'closed' | 'draft';
5
+
6
+ export type PullRequest = {
7
+ url: string;
8
+ owner?: string;
9
+ repo?: string;
10
+ number: number;
11
+ state?: PrState;
12
+ };
13
+
14
+ export type DiffStats = { additions: number; deletions: number };
15
+
16
+ export const PR_TONE: Record<PrState, Tone> = {
17
+ open: 'ok',
18
+ merged: 'accent',
19
+ closed: 'danger',
20
+ draft: 'neutral',
21
+ };
22
+
23
+ const TONE_COLOR: Record<Tone, string> = {
24
+ neutral: 'var(--text-muted)',
25
+ ok: 'var(--ok)',
26
+ success: 'var(--ok)',
27
+ warn: 'var(--warn)',
28
+ danger: 'var(--danger)',
29
+ info: 'var(--info)',
30
+ accent: 'var(--accent)',
31
+ };
32
+
33
+ export function prLabel(pr: PullRequest): string {
34
+ return pr.owner && pr.repo ? `${pr.owner}/${pr.repo}#${pr.number}` : `#${pr.number}`;
35
+ }
36
+ </script>
37
+
38
+ <script lang="ts">
39
+ import Icon from '../atoms/Icon.svelte';
40
+
41
+ let {
42
+ branch,
43
+ pr,
44
+ diff,
45
+ maxWidth = '14rem',
46
+ collapse = 'auto',
47
+ class: klass = '',
48
+ ...rest
49
+ }: {
50
+ branch?: string;
51
+ pr?: PullRequest;
52
+ diff?: DiffStats;
53
+ /** Cap on the branch chip; the name truncates with an ellipsis past it. */
54
+ maxWidth?: string;
55
+ /** `auto` drops chip text below 18rem of the nearest `.cq` container,
56
+ * `glyph` always shows icon-only; the full text stays in the tooltip. */
57
+ collapse?: 'auto' | 'never' | 'glyph';
58
+ class?: string;
59
+ [key: string]: unknown;
60
+ } = $props();
61
+
62
+ const prTone = $derived(pr ? TONE_COLOR[PR_TONE[pr.state ?? 'open']] : undefined);
63
+ const label = $derived(pr ? prLabel(pr) : '');
64
+ const prTitle = $derived(pr ? (pr.state ? `${label} · ${pr.state}` : label) : '');
65
+ </script>
66
+
67
+ {#snippet pullRequestGlyph()}
68
+ <circle cx="5" cy="6" r="3" />
69
+ <path d="M5 9v12" />
70
+ <circle cx="19" cy="18" r="3" />
71
+ <path d="m15 9-3-3 3-3" />
72
+ <path d="M12 6h5a2 2 0 0 1 2 2v7" />
73
+ {/snippet}
74
+
75
+ {#if branch || pr || diff}
76
+ <span
77
+ data-tsu="GitRef"
78
+ class="git-ref collapse-{collapse} {klass}"
79
+ style:--git-ref-max-width={maxWidth}
80
+ {...rest}
81
+ >
82
+ {#if branch}
83
+ <span class="chip branch" title={branch}>
84
+ <Icon name="fork" label="Branch" />
85
+ <span class="text">{branch}</span>
86
+ </span>
87
+ {/if}
88
+ {#if pr}
89
+ <a
90
+ class="chip pr"
91
+ href={pr.url}
92
+ target="_blank"
93
+ rel="noopener noreferrer"
94
+ title={prTitle}
95
+ style:--git-ref-tone={prTone}
96
+ >
97
+ <Icon label="Pull request">{@render pullRequestGlyph()}</Icon>
98
+ <span class="text">{label}</span>
99
+ </a>
100
+ {/if}
101
+ {#if diff}
102
+ <span class="diff" title="+{diff.additions} −{diff.deletions}">
103
+ <span class="add">+{diff.additions}</span>
104
+ <span class="del">−{diff.deletions}</span>
105
+ </span>
106
+ {/if}
107
+ </span>
108
+ {/if}
109
+
110
+ <style>
111
+ .git-ref {
112
+ display: inline-flex;
113
+ align-items: center;
114
+ gap: var(--sp-1);
115
+ min-width: 0;
116
+ font-family: var(--font-mono);
117
+ font-size: var(--fs-xs);
118
+ line-height: 1.4;
119
+ white-space: nowrap;
120
+ }
121
+ .chip {
122
+ display: inline-flex;
123
+ align-items: center;
124
+ gap: 0.25em;
125
+ min-width: 0;
126
+ padding: 0.15rem var(--sp-2);
127
+ border-radius: var(--r-pill);
128
+ background: var(--bg-elevated-2);
129
+ color: var(--text-muted);
130
+ border: 1px solid var(--border);
131
+ text-decoration: none;
132
+ }
133
+ .branch {
134
+ max-width: var(--git-ref-max-width, 14rem);
135
+ }
136
+ .pr {
137
+ color: var(--git-ref-tone);
138
+ border-color: color-mix(in srgb, var(--git-ref-tone) 40%, transparent);
139
+ background: color-mix(in srgb, var(--git-ref-tone) 12%, transparent);
140
+ transition: border-color 0.12s var(--ease);
141
+ }
142
+ .pr:hover {
143
+ border-color: var(--git-ref-tone);
144
+ }
145
+ .pr:focus-visible {
146
+ outline: 2px solid var(--git-ref-tone);
147
+ outline-offset: 2px;
148
+ }
149
+ .text {
150
+ min-width: 0;
151
+ overflow: hidden;
152
+ text-overflow: ellipsis;
153
+ white-space: nowrap;
154
+ }
155
+ .diff {
156
+ display: inline-flex;
157
+ gap: 0.35em;
158
+ font-variant-numeric: tabular-nums;
159
+ }
160
+ .add {
161
+ color: var(--ok);
162
+ }
163
+ .del {
164
+ color: var(--danger);
165
+ }
166
+ .collapse-glyph .text {
167
+ display: none;
168
+ }
169
+ @container (max-width: 18rem) {
170
+ .collapse-auto .text {
171
+ display: none;
172
+ }
173
+ }
174
+ </style>
@@ -0,0 +1,30 @@
1
+ import type { Tone } from '../../tone';
2
+ export type PrState = 'open' | 'merged' | 'closed' | 'draft';
3
+ export type PullRequest = {
4
+ url: string;
5
+ owner?: string;
6
+ repo?: string;
7
+ number: number;
8
+ state?: PrState;
9
+ };
10
+ export type DiffStats = {
11
+ additions: number;
12
+ deletions: number;
13
+ };
14
+ export declare const PR_TONE: Record<PrState, Tone>;
15
+ export declare function prLabel(pr: PullRequest): string;
16
+ type $$ComponentProps = {
17
+ branch?: string;
18
+ pr?: PullRequest;
19
+ diff?: DiffStats;
20
+ /** Cap on the branch chip; the name truncates with an ellipsis past it. */
21
+ maxWidth?: string;
22
+ /** `auto` drops chip text below 18rem of the nearest `.cq` container,
23
+ * `glyph` always shows icon-only; the full text stays in the tooltip. */
24
+ collapse?: 'auto' | 'never' | 'glyph';
25
+ class?: string;
26
+ [key: string]: unknown;
27
+ };
28
+ declare const GitRef: import("svelte").Component<$$ComponentProps, {}, "">;
29
+ type GitRef = ReturnType<typeof GitRef>;
30
+ export default GitRef;