@streamscloud/kit 0.46.0 → 0.48.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/dist/styles/_semantic.scss +9 -3
- package/dist/ui/button/cmp.button.svelte +7 -2
- package/dist/ui/chip-group/cmp.chip-group.svelte +5 -2
- package/dist/ui/date-picker/cmp.date-picker.svelte +5 -1
- package/dist/ui/document-tabs/cmp.document-tabs.svelte +245 -0
- package/dist/ui/document-tabs/cmp.document-tabs.svelte.d.ts +80 -0
- package/dist/ui/document-tabs/document-tab.svelte +212 -0
- package/dist/ui/document-tabs/document-tab.svelte.d.ts +34 -0
- package/dist/ui/document-tabs/document-tabs-localization.d.ts +6 -0
- package/dist/ui/document-tabs/document-tabs-localization.js +33 -0
- package/dist/ui/document-tabs/index.d.ts +3 -0
- package/dist/ui/document-tabs/index.js +2 -0
- package/dist/ui/document-tabs/types.d.ts +20 -0
- package/dist/ui/document-tabs/types.js +1 -0
- package/dist/ui/emoji-picker/cmp.emoji-panel.svelte +1 -1
- package/dist/ui/grid-card/fields/cmp.grid-card-select-field.svelte +1 -0
- package/dist/ui/handle-input/cmp.handle-input.svelte +0 -1
- package/dist/ui/icon/cmp.icon.svelte +2 -2
- package/dist/ui/icon/cmp.icon.svelte.d.ts +3 -3
- package/dist/ui/icon-picker/cmp.icon-picker.svelte +1 -1
- package/dist/ui/icon-text/cmp.icon-text.svelte +4 -0
- package/dist/ui/icon-text/cmp.icon-text.svelte.d.ts +2 -2
- package/dist/ui/input/cmp.input.svelte +5 -1
- package/dist/ui/numeral-input/cmp.numeral-input.svelte +5 -1
- package/dist/ui/option-pill/cmp.option-pill.svelte +1 -1
- package/dist/ui/page-layout/cmp.page-panel-sidebars.svelte +29 -3
- package/dist/ui/page-layout/cmp.page-panel-sidebars.svelte.d.ts +8 -0
- package/dist/ui/page-layout/cmp.page-panel.svelte +66 -42
- package/dist/ui/page-toolbar/cmp.toolbar-icon-button.svelte +1 -1
- package/dist/ui/page-toolbar/cmp.toolbar-option.svelte +4 -1
- package/dist/ui/page-toolbar/cmp.toolbar-sort-select.svelte.d.ts +1 -1
- package/dist/ui/page-toolbar/cmp.toolbar-value-stepper.svelte +4 -0
- package/dist/ui/page-toolbar/cmp.toolbar-view-controls.svelte.d.ts +1 -1
- package/dist/ui/segmented-control/cmp.segmented-control.svelte +5 -2
- package/dist/ui/select/_select-trigger.scss +5 -1
- package/dist/ui/select/cmp.input-suggest.svelte +5 -1
- package/dist/ui/select/cmp.singleselect-async.svelte +5 -1
- package/dist/ui/select/multiselect-base.svelte +5 -1
- package/dist/ui/slider/cmp.slider.svelte +1 -0
- package/dist/ui/tabs/cmp.tabs.svelte +6 -14
- package/dist/ui/tabs/cmp.tabs.svelte.d.ts +5 -11
- package/dist/ui/tabs/tab.svelte +18 -76
- package/dist/ui/tabs/tab.svelte.d.ts +0 -1
- package/dist/ui/tabs/types.d.ts +1 -1
- package/dist/ui/url-input/cmp.url-input.svelte +0 -1
- package/dist/ui/website-input/cmp.website-input.svelte +0 -1
- package/package.json +5 -1
- package/dist/ui/tabs/tabs-localization.d.ts +0 -3
- package/dist/ui/tabs/tabs-localization.js +0 -12
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
// FIELD SIZING — cross-cutting for input-shaped controls
|
|
120
120
|
// (Input, Textarea, NumeralInput, DatePicker, Select triggers)
|
|
121
121
|
// ============================================================
|
|
122
|
-
--sc-kit--field--height--sm: 1.
|
|
122
|
+
--sc-kit--field--height--sm: 1.8125rem; // 29px
|
|
123
123
|
--sc-kit--field--height--md: 2rem; // 32px
|
|
124
124
|
--sc-kit--field--height--lg: 2.5rem; // 40px
|
|
125
125
|
|
|
@@ -127,8 +127,8 @@
|
|
|
127
127
|
--sc-kit--field--padding-inline--md: 0.625rem; // 10px
|
|
128
128
|
--sc-kit--field--padding-inline--lg: 0.75rem; // 12px
|
|
129
129
|
|
|
130
|
-
--sc-kit--field--icon--size--xs: 0.
|
|
131
|
-
--sc-kit--field--icon--size--sm: 0.
|
|
130
|
+
--sc-kit--field--icon--size--xs: 0.875rem; // 14px
|
|
131
|
+
--sc-kit--field--icon--size--sm: 0.9375rem; // 15px
|
|
132
132
|
--sc-kit--field--icon--size--md: 1rem; // 16px
|
|
133
133
|
--sc-kit--field--icon--size--lg: 1.125rem; // 18px
|
|
134
134
|
--sc-kit--field--icon--size--xl: 1.25rem; // 20px
|
|
@@ -168,6 +168,12 @@
|
|
|
168
168
|
--sc-kit--line-height--3xl: 40px;
|
|
169
169
|
--sc-kit--line-height--4xl: 48px;
|
|
170
170
|
|
|
171
|
+
// Each value keeps (control height − this) even, or the label's line box starts on a half pixel and the engines break that tie in opposite directions.
|
|
172
|
+
--sc-kit--line-height--control--xs: 14px;
|
|
173
|
+
--sc-kit--line-height--control--sm: 15px;
|
|
174
|
+
--sc-kit--line-height--control--md: 18px;
|
|
175
|
+
--sc-kit--line-height--control--lg: 22px;
|
|
176
|
+
|
|
171
177
|
--sc-kit--font-weight--regular: 400;
|
|
172
178
|
--sc-kit--font-weight--medium: 500;
|
|
173
179
|
--sc-kit--font-weight--semibold: 600;
|
|
@@ -130,6 +130,7 @@ Pass `type="anchor"` to render as `<a>` with `href`, or `type="presentational"`
|
|
|
130
130
|
--_btn--height: var(--sc-kit--button--height, var(--_btn--size-height));
|
|
131
131
|
--_btn--padding-inline: var(--sc-kit--button--padding-inline, var(--_btn--size-padding-inline));
|
|
132
132
|
--_btn--font-size: var(--sc-kit--button--font-size, var(--_btn--size-font-size));
|
|
133
|
+
--_btn--line-height: var(--_btn--size-line-height);
|
|
133
134
|
--_btn--gap: var(--sc-kit--button--gap, var(--_btn--size-gap));
|
|
134
135
|
--_btn--icon-size: var(--_btn--size-icon-size);
|
|
135
136
|
--_btn--width: var(--sc-kit--button--width, fit-content);
|
|
@@ -152,7 +153,7 @@ Pass `type="anchor"` to render as `<a>` with `href`, or `type="presentational"`
|
|
|
152
153
|
font-family: inherit;
|
|
153
154
|
font-size: var(--_btn--font-size);
|
|
154
155
|
font-weight: var(--_btn--font-weight);
|
|
155
|
-
line-height: var(--
|
|
156
|
+
line-height: var(--_btn--line-height);
|
|
156
157
|
color: var(--_btn--color);
|
|
157
158
|
background: var(--_btn--background);
|
|
158
159
|
border: var(--_btn--border);
|
|
@@ -207,14 +208,16 @@ Pass `type="anchor"` to render as `<a>` with `href`, or `type="presentational"`
|
|
|
207
208
|
--_btn--size-height: 1.5rem;
|
|
208
209
|
--_btn--size-padding-inline: var(--sc-kit--space--2);
|
|
209
210
|
--_btn--size-font-size: var(--sc-kit--font-size--xs);
|
|
211
|
+
--_btn--size-line-height: var(--sc-kit--line-height--control--xs);
|
|
210
212
|
--_btn--size-gap: var(--sc-kit--space--1);
|
|
211
213
|
--_btn--size-icon-size: var(--sc-kit--field--icon--size--xs);
|
|
212
214
|
--_btn--size-border-radius: var(--sc-kit--field--border-radius--sm);
|
|
213
215
|
}
|
|
214
216
|
.btn--sm {
|
|
215
|
-
--_btn--size-height: 1.
|
|
217
|
+
--_btn--size-height: 1.8125rem;
|
|
216
218
|
--_btn--size-padding-inline: var(--sc-kit--space--3);
|
|
217
219
|
--_btn--size-font-size: var(--sc-kit--font-size--sm);
|
|
220
|
+
--_btn--size-line-height: var(--sc-kit--line-height--control--sm);
|
|
218
221
|
--_btn--size-gap: var(--sc-kit--space--1);
|
|
219
222
|
--_btn--size-icon-size: var(--sc-kit--field--icon--size--sm);
|
|
220
223
|
--_btn--size-border-radius: var(--sc-kit--field--border-radius--sm);
|
|
@@ -223,6 +226,7 @@ Pass `type="anchor"` to render as `<a>` with `href`, or `type="presentational"`
|
|
|
223
226
|
--_btn--size-height: 2rem;
|
|
224
227
|
--_btn--size-padding-inline: var(--sc-kit--space--4);
|
|
225
228
|
--_btn--size-font-size: var(--sc-kit--font-size--md);
|
|
229
|
+
--_btn--size-line-height: var(--sc-kit--line-height--control--md);
|
|
226
230
|
--_btn--size-gap: var(--sc-kit--space--2);
|
|
227
231
|
--_btn--size-icon-size: var(--sc-kit--field--icon--size--md);
|
|
228
232
|
--_btn--size-border-radius: var(--sc-kit--field--border-radius--md);
|
|
@@ -231,6 +235,7 @@ Pass `type="anchor"` to render as `<a>` with `href`, or `type="presentational"`
|
|
|
231
235
|
--_btn--size-height: 2.5rem;
|
|
232
236
|
--_btn--size-padding-inline: var(--sc-kit--space--6);
|
|
233
237
|
--_btn--size-font-size: var(--sc-kit--font-size--lg);
|
|
238
|
+
--_btn--size-line-height: var(--sc-kit--line-height--control--lg);
|
|
234
239
|
--_btn--size-gap: var(--sc-kit--space--2);
|
|
235
240
|
--_btn--size-icon-size: var(--sc-kit--field--icon--size--lg);
|
|
236
241
|
--_btn--size-border-radius: var(--sc-kit--field--border-radius--md);
|
|
@@ -74,6 +74,7 @@ checkmark on selected chips.
|
|
|
74
74
|
--_cg--height: var(--sc-kit--chip-group--height, 2rem);
|
|
75
75
|
--_cg--padding-inline: var(--sc-kit--chip-group--padding-inline, 0.875rem);
|
|
76
76
|
--_cg--font-size: var(--sc-kit--chip-group--font-size, var(--sc-kit--font-size--md));
|
|
77
|
+
--_cg--line-height: var(--_cg--size-line-height, var(--sc-kit--line-height--control--md));
|
|
77
78
|
--_cg--font-weight: var(--sc-kit--chip-group--font-weight, var(--sc-kit--font-weight--medium));
|
|
78
79
|
--_cg--background: var(--sc-kit--chip-group--background, var(--sc-kit--color--bg--field));
|
|
79
80
|
--_cg--background-hover: var(--sc-kit--chip-group--background--hover, var(--sc-kit--color--bg--hover));
|
|
@@ -92,14 +93,16 @@ checkmark on selected chips.
|
|
|
92
93
|
max-width: 100%;
|
|
93
94
|
}
|
|
94
95
|
.chip-group--sm {
|
|
95
|
-
--sc-kit--chip-group--height: 1.
|
|
96
|
+
--sc-kit--chip-group--height: 1.8125rem;
|
|
96
97
|
--sc-kit--chip-group--padding-inline: 0.75rem;
|
|
97
98
|
--sc-kit--chip-group--font-size: var(--sc-kit--font-size--sm);
|
|
99
|
+
--_cg--size-line-height: var(--sc-kit--line-height--control--sm);
|
|
98
100
|
}
|
|
99
101
|
.chip-group--md {
|
|
100
102
|
--sc-kit--chip-group--height: 2rem;
|
|
101
103
|
--sc-kit--chip-group--padding-inline: 0.875rem;
|
|
102
104
|
--sc-kit--chip-group--font-size: var(--sc-kit--font-size--md);
|
|
105
|
+
--_cg--size-line-height: var(--sc-kit--line-height--control--md);
|
|
103
106
|
}
|
|
104
107
|
.chip-group--soft {
|
|
105
108
|
--sc-kit--chip-group--background--selected: var(--sc-kit--color--accent--soft);
|
|
@@ -132,7 +135,7 @@ checkmark on selected chips.
|
|
|
132
135
|
font-family: inherit;
|
|
133
136
|
font-size: var(--_cg--font-size);
|
|
134
137
|
font-weight: var(--_cg--font-weight);
|
|
135
|
-
line-height: var(--
|
|
138
|
+
line-height: var(--_cg--line-height);
|
|
136
139
|
white-space: nowrap;
|
|
137
140
|
cursor: pointer;
|
|
138
141
|
transition: background-color var(--sc-kit--duration--base) var(--sc-kit--ease--default), border-color var(--sc-kit--duration--base) var(--sc-kit--ease--default), color var(--sc-kit--duration--base) var(--sc-kit--ease--default);
|
|
@@ -212,6 +212,7 @@ DatePicker — single-day calendar picker built on Floating UI for positioning.
|
|
|
212
212
|
--_dp--border-radius: var(--sc-kit--date-picker--border-radius, var(--_dp--size-border-radius, var(--sc-kit--field--border-radius--md)));
|
|
213
213
|
--_dp--underline-color: var(--sc-kit--date-picker--underline-color, transparent);
|
|
214
214
|
--_dp--font-size: var(--sc-kit--date-picker--font-size, var(--_dp--size-font-size, var(--sc-kit--font-size--md)));
|
|
215
|
+
--_dp--line-height: var(--_dp--size-line-height, var(--sc-kit--line-height--control--md));
|
|
215
216
|
--_dp--color: var(--sc-kit--date-picker--color, var(--sc-kit--color--text--primary));
|
|
216
217
|
--_dp--placeholder-color: var(--sc-kit--date-picker--placeholder--color, var(--sc-kit--color--text--placeholder));
|
|
217
218
|
--_dp--icon-color: var(--sc-kit--date-picker--icon--color, var(--sc-kit--color--text--muted));
|
|
@@ -237,6 +238,7 @@ DatePicker — single-day calendar picker built on Floating UI for positioning.
|
|
|
237
238
|
--_dp--size-height: var(--sc-kit--field--height--sm);
|
|
238
239
|
--_dp--size-padding-inline: var(--sc-kit--field--padding-inline--sm);
|
|
239
240
|
--_dp--size-font-size: var(--sc-kit--font-size--sm);
|
|
241
|
+
--_dp--size-line-height: var(--sc-kit--line-height--control--sm);
|
|
240
242
|
--_dp--size-icon-size: var(--sc-kit--field--icon--size--sm);
|
|
241
243
|
--_dp--size-border-radius: var(--sc-kit--field--border-radius--sm);
|
|
242
244
|
}
|
|
@@ -244,6 +246,7 @@ DatePicker — single-day calendar picker built on Floating UI for positioning.
|
|
|
244
246
|
--_dp--size-height: var(--sc-kit--field--height--md);
|
|
245
247
|
--_dp--size-padding-inline: var(--sc-kit--field--padding-inline--md);
|
|
246
248
|
--_dp--size-font-size: var(--sc-kit--font-size--md);
|
|
249
|
+
--_dp--size-line-height: var(--sc-kit--line-height--control--md);
|
|
247
250
|
--_dp--size-icon-size: var(--sc-kit--field--icon--size--md);
|
|
248
251
|
--_dp--size-border-radius: var(--sc-kit--field--border-radius--md);
|
|
249
252
|
}
|
|
@@ -251,6 +254,7 @@ DatePicker — single-day calendar picker built on Floating UI for positioning.
|
|
|
251
254
|
--_dp--size-height: var(--sc-kit--field--height--lg);
|
|
252
255
|
--_dp--size-padding-inline: var(--sc-kit--field--padding-inline--lg);
|
|
253
256
|
--_dp--size-font-size: var(--sc-kit--font-size--lg);
|
|
257
|
+
--_dp--size-line-height: var(--sc-kit--line-height--control--lg);
|
|
254
258
|
--_dp--size-icon-size: var(--sc-kit--field--icon--size--lg);
|
|
255
259
|
--_dp--size-border-radius: var(--sc-kit--field--border-radius--md);
|
|
256
260
|
}
|
|
@@ -297,7 +301,7 @@ DatePicker — single-day calendar picker built on Floating UI for positioning.
|
|
|
297
301
|
color: var(--_dp--color);
|
|
298
302
|
font-family: inherit;
|
|
299
303
|
font-size: var(--_dp--font-size);
|
|
300
|
-
line-height: var(--
|
|
304
|
+
line-height: var(--_dp--line-height);
|
|
301
305
|
box-shadow: inset 0 calc(-1 * max(2px, 0.125em)) var(--_dp--underline-color);
|
|
302
306
|
cursor: pointer;
|
|
303
307
|
transition: background-color var(--sc-kit--duration--base) var(--sc-kit--ease--default), border-color var(--sc-kit--duration--base) var(--sc-kit--ease--default), color var(--sc-kit--duration--base) var(--sc-kit--ease--default), box-shadow var(--sc-kit--duration--base) var(--sc-kit--ease--default);
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
<script lang="ts" generics="T">import { horizontalWheelScroll } from '../../core/actions';
|
|
2
|
+
import { Icon } from '../icon';
|
|
3
|
+
import DocumentTabItem from './document-tab.svelte';
|
|
4
|
+
import { DocumentTabsLocalization } from './document-tabs-localization';
|
|
5
|
+
import IconChevronLeft from '@fluentui/svg-icons/icons/chevron_left_20_regular.svg?raw';
|
|
6
|
+
import IconChevronRight from '@fluentui/svg-icons/icons/chevron_right_20_regular.svg?raw';
|
|
7
|
+
const { value, tabs, overflow = 'visible', compare, on } = $props();
|
|
8
|
+
const localization = new DocumentTabsLocalization();
|
|
9
|
+
const SCROLL_STEP = 160;
|
|
10
|
+
let trackNode = $state(null);
|
|
11
|
+
let canScrollBack = $state(false);
|
|
12
|
+
let canScrollForward = $state(false);
|
|
13
|
+
let scrollSyncArmed = false;
|
|
14
|
+
const isActive = (tab) => (compare ? compare(value, tab.value) : value === tab.value);
|
|
15
|
+
const isClosable = (tab) => !!on?.close && tab.closable !== false && !tab.disabled;
|
|
16
|
+
const activeIndex = $derived(tabs.findIndex((tab) => isActive(tab)));
|
|
17
|
+
const tabButtons = () => Array.from(trackNode?.querySelectorAll('[role="tab"]') ?? []);
|
|
18
|
+
const updateScrollState = (node) => {
|
|
19
|
+
if (overflow !== 'scroll') {
|
|
20
|
+
canScrollBack = false;
|
|
21
|
+
canScrollForward = false;
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const { scrollLeft, scrollWidth, clientWidth } = node;
|
|
25
|
+
canScrollBack = scrollLeft > 0;
|
|
26
|
+
canScrollForward = scrollLeft < scrollWidth - clientWidth - 1;
|
|
27
|
+
};
|
|
28
|
+
const trackMounted = (node) => {
|
|
29
|
+
trackNode = node;
|
|
30
|
+
const observer = new ResizeObserver(() => updateScrollState(node));
|
|
31
|
+
observer.observe(node);
|
|
32
|
+
updateScrollState(node);
|
|
33
|
+
return {
|
|
34
|
+
destroy: () => observer.disconnect()
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
const scrollBack = () => {
|
|
38
|
+
trackNode?.scrollBy({ left: -SCROLL_STEP, behavior: 'smooth' });
|
|
39
|
+
};
|
|
40
|
+
const scrollForward = () => {
|
|
41
|
+
trackNode?.scrollBy({ left: SCROLL_STEP, behavior: 'smooth' });
|
|
42
|
+
};
|
|
43
|
+
const stepFocus = (buttons, from, step) => {
|
|
44
|
+
const count = buttons.length;
|
|
45
|
+
for (let offset = 1; offset <= count; offset++) {
|
|
46
|
+
const candidate = buttons[(((from + step * offset) % count) + count) % count];
|
|
47
|
+
if (!candidate.disabled) {
|
|
48
|
+
return candidate;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
};
|
|
53
|
+
const handleKeydown = (event) => {
|
|
54
|
+
const buttons = tabButtons();
|
|
55
|
+
const current = buttons.indexOf(document.activeElement);
|
|
56
|
+
if (current === -1) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (event.key === 'Delete' || event.key === 'Backspace') {
|
|
60
|
+
const tab = tabs[current];
|
|
61
|
+
if (tab && isClosable(tab)) {
|
|
62
|
+
event.preventDefault();
|
|
63
|
+
on?.close?.(tab.value);
|
|
64
|
+
}
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
let target;
|
|
68
|
+
switch (event.key) {
|
|
69
|
+
case 'ArrowRight':
|
|
70
|
+
target = stepFocus(buttons, current, 1);
|
|
71
|
+
break;
|
|
72
|
+
case 'ArrowLeft':
|
|
73
|
+
target = stepFocus(buttons, current, -1);
|
|
74
|
+
break;
|
|
75
|
+
case 'Home':
|
|
76
|
+
target = stepFocus(buttons, -1, 1);
|
|
77
|
+
break;
|
|
78
|
+
case 'End':
|
|
79
|
+
target = stepFocus(buttons, buttons.length, -1);
|
|
80
|
+
break;
|
|
81
|
+
default:
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (!target) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
event.preventDefault();
|
|
88
|
+
target.focus();
|
|
89
|
+
target.click();
|
|
90
|
+
};
|
|
91
|
+
$effect(() => {
|
|
92
|
+
const index = activeIndex;
|
|
93
|
+
if (!trackNode || index < 0) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (!scrollSyncArmed) {
|
|
97
|
+
scrollSyncArmed = true;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
tabButtons()[index]?.scrollIntoView({ block: 'nearest', inline: 'nearest', behavior: 'smooth' });
|
|
101
|
+
});
|
|
102
|
+
</script>
|
|
103
|
+
|
|
104
|
+
<div class="document-tabs">
|
|
105
|
+
{#if canScrollBack}
|
|
106
|
+
<button type="button" class="document-tabs__scroll-btn document-tabs__scroll-btn--back" onclick={scrollBack} aria-label={localization.scrollBack}>
|
|
107
|
+
<Icon src={IconChevronLeft} size="sm" />
|
|
108
|
+
</button>
|
|
109
|
+
{/if}
|
|
110
|
+
<div
|
|
111
|
+
class="document-tabs__track"
|
|
112
|
+
class:document-tabs__track--scrollable={overflow === 'scroll'}
|
|
113
|
+
class:document-tabs__track--mask-back={canScrollBack && !canScrollForward}
|
|
114
|
+
class:document-tabs__track--mask-forward={canScrollForward && !canScrollBack}
|
|
115
|
+
class:document-tabs__track--mask-both={canScrollBack && canScrollForward}
|
|
116
|
+
role="tablist"
|
|
117
|
+
use:trackMounted
|
|
118
|
+
use:horizontalWheelScroll={{ isolateScroll: overflow === 'scroll' }}
|
|
119
|
+
onscroll={(event) => updateScrollState(event.currentTarget)}>
|
|
120
|
+
{#each tabs as tab (tab.value)}
|
|
121
|
+
<DocumentTabItem tab={tab} active={isActive(tab)} closable={isClosable(tab)} on={{ select: on?.change, close: on?.close, keydown: handleKeydown }} />
|
|
122
|
+
{/each}
|
|
123
|
+
</div>
|
|
124
|
+
{#if canScrollForward}
|
|
125
|
+
<button type="button" class="document-tabs__scroll-btn document-tabs__scroll-btn--forward" onclick={scrollForward} aria-label={localization.scrollForward}>
|
|
126
|
+
<Icon src={IconChevronRight} size="sm" />
|
|
127
|
+
</button>
|
|
128
|
+
{/if}
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<!--
|
|
132
|
+
@component
|
|
133
|
+
DocumentTabs — browser-style tabs for an editor: the active tab is taller than its neighbours and
|
|
134
|
+
sits flush on the container's bottom rule, so it reads as continuous with the panel below while the
|
|
135
|
+
inactive ones stay behind that line. Each tab carries an optional icon, an unsaved-changes dot, a
|
|
136
|
+
`tone` for a tab of a different kind (a live preview), and its own `closable` opt-out. A closable or
|
|
137
|
+
dirty tab reserves the trailing slot permanently: the dot sits there at rest, the close button takes
|
|
138
|
+
its place on hover, and a tab's width never depends on which of them is showing. Arrow keys / Home /
|
|
139
|
+
End move between tabs (roving tabindex), Delete closes the focused one.
|
|
140
|
+
|
|
141
|
+
`overflow="scroll"` gives the strip its own scroll container with edge fades, chevrons and
|
|
142
|
+
wheel-to-scroll. Leave it `'visible'` where the container already scrolls the strip — two nested
|
|
143
|
+
scrollers fight each other.
|
|
144
|
+
|
|
145
|
+
The active tab dips `--sc-kit--document-tabs--baseline-overlap` below the strip to cover the bottom
|
|
146
|
+
rule of the bar it sits in. A container that clips (any `overflow` other than `visible`) has to
|
|
147
|
+
leave that last pixel inside its own clip region, or the overlap is cut off.
|
|
148
|
+
|
|
149
|
+
### CSS Custom Properties
|
|
150
|
+
| Property | Description | Default |
|
|
151
|
+
|---|---|---|
|
|
152
|
+
| `--sc-kit--document-tabs--height` | Inactive tab height | `29px` |
|
|
153
|
+
| `--sc-kit--document-tabs--height--active` | Active tab height | `32px` |
|
|
154
|
+
| `--sc-kit--document-tabs--padding-inline` | Tab horizontal padding — the same in both states, so activating a tab shifts nothing sideways | `10px` |
|
|
155
|
+
| `--sc-kit--document-tabs--min-width` | Minimum tab width | `112px` |
|
|
156
|
+
| `--sc-kit--document-tabs--max-width` | Maximum tab width — the label ellipsizes past it | `200px` |
|
|
157
|
+
| `--sc-kit--document-tabs--gap` | Gap between tabs | `1px` |
|
|
158
|
+
| `--sc-kit--document-tabs--tab--gap` | Gap between a tab's icon, label and trailing slot | `8px` |
|
|
159
|
+
| `--sc-kit--document-tabs--radius` | Top corner radius | `--sc-kit--radius--sm` |
|
|
160
|
+
| `--sc-kit--document-tabs--border-width` | Tab border width | `1px` |
|
|
161
|
+
| `--sc-kit--document-tabs--border-color` | Tab border color | `--sc-kit--color--border` |
|
|
162
|
+
| `--sc-kit--document-tabs--baseline-overlap` | How far the active tab dips below the strip to cover its container's bottom rule | `1px` |
|
|
163
|
+
| `--sc-kit--document-tabs--background` | Inactive tab background | `--sc-kit--color--bg--app` |
|
|
164
|
+
| `--sc-kit--document-tabs--background--active` | Active tab background — matches the pane below | `--sc-kit--color--bg--panel` |
|
|
165
|
+
| `--sc-kit--document-tabs--background--hover` | Inactive tab hover background | `--sc-kit--color--bg--hover` |
|
|
166
|
+
| `--sc-kit--document-tabs--color` | Inactive tab label color | `--sc-kit--color--text--secondary` |
|
|
167
|
+
| `--sc-kit--document-tabs--color--active` | Active tab label color | `--sc-kit--color--text--primary` |
|
|
168
|
+
| `--sc-kit--document-tabs--color--hover` | Inactive tab hover label color | `--sc-kit--color--text--primary` |
|
|
169
|
+
| `--sc-kit--document-tabs--color--disabled` | Disabled tab label color | `--sc-kit--color--text--muted` |
|
|
170
|
+
| `--sc-kit--document-tabs--font-size` | Label font size | `--sc-kit--font-size--sm` |
|
|
171
|
+
| `--sc-kit--document-tabs--font-weight` | Label font weight | `--sc-kit--font-weight--regular` |
|
|
172
|
+
| `--sc-kit--document-tabs--scroll-btn--background` | Fade behind the overflow chevrons | `--sc-kit--color--bg--panel` |
|
|
173
|
+
-->
|
|
174
|
+
|
|
175
|
+
<style>.document-tabs {
|
|
176
|
+
--_document-tabs--gap: var(--sc-kit--document-tabs--gap, 1px);
|
|
177
|
+
--_document-tabs--baseline-overlap: var(--sc-kit--document-tabs--baseline-overlap, 1px);
|
|
178
|
+
--_document-tabs--scroll-btn-background: var(--sc-kit--document-tabs--scroll-btn--background, var(--sc-kit--color--bg--panel));
|
|
179
|
+
position: relative;
|
|
180
|
+
display: flex;
|
|
181
|
+
align-self: stretch;
|
|
182
|
+
align-items: flex-end;
|
|
183
|
+
min-inline-size: 0;
|
|
184
|
+
margin-block-end: calc(-1 * var(--_document-tabs--baseline-overlap));
|
|
185
|
+
}
|
|
186
|
+
.document-tabs:hover {
|
|
187
|
+
--_scroll-btn-opacity: 1;
|
|
188
|
+
}
|
|
189
|
+
.document-tabs__track {
|
|
190
|
+
--_mask-size: 1.5rem;
|
|
191
|
+
display: flex;
|
|
192
|
+
align-items: flex-end;
|
|
193
|
+
gap: var(--_document-tabs--gap);
|
|
194
|
+
min-inline-size: 0;
|
|
195
|
+
}
|
|
196
|
+
.document-tabs__track--scrollable {
|
|
197
|
+
overflow-x: auto;
|
|
198
|
+
scrollbar-width: none;
|
|
199
|
+
}
|
|
200
|
+
.document-tabs__track--scrollable::-webkit-scrollbar {
|
|
201
|
+
display: none;
|
|
202
|
+
}
|
|
203
|
+
.document-tabs__track--mask-back {
|
|
204
|
+
mask-image: linear-gradient(to right, transparent 0%, black var(--_mask-size), black 100%);
|
|
205
|
+
}
|
|
206
|
+
.document-tabs__track--mask-forward {
|
|
207
|
+
mask-image: linear-gradient(to right, black 0%, black calc(100% - var(--_mask-size)), transparent 100%);
|
|
208
|
+
}
|
|
209
|
+
.document-tabs__track--mask-both {
|
|
210
|
+
mask-image: linear-gradient(to right, transparent 0%, black var(--_mask-size), black calc(100% - var(--_mask-size)), transparent 100%);
|
|
211
|
+
}
|
|
212
|
+
.document-tabs__scroll-btn {
|
|
213
|
+
position: absolute;
|
|
214
|
+
inset-block: 0;
|
|
215
|
+
z-index: 1;
|
|
216
|
+
display: flex;
|
|
217
|
+
align-items: center;
|
|
218
|
+
justify-content: center;
|
|
219
|
+
padding-inline: 0.25rem;
|
|
220
|
+
background: transparent;
|
|
221
|
+
backdrop-filter: blur(2px);
|
|
222
|
+
border: none;
|
|
223
|
+
cursor: pointer;
|
|
224
|
+
color: var(--sc-kit--color--text--secondary);
|
|
225
|
+
opacity: var(--_scroll-btn-opacity, 0);
|
|
226
|
+
transition: opacity var(--sc-kit--duration--base) var(--sc-kit--ease--default);
|
|
227
|
+
}
|
|
228
|
+
.document-tabs__scroll-btn:hover {
|
|
229
|
+
color: var(--sc-kit--color--text--primary);
|
|
230
|
+
}
|
|
231
|
+
.document-tabs__scroll-btn:focus-visible {
|
|
232
|
+
outline: 2px solid var(--sc-kit--color--border--focus);
|
|
233
|
+
outline-offset: -2px;
|
|
234
|
+
opacity: 1;
|
|
235
|
+
}
|
|
236
|
+
.document-tabs__scroll-btn--back {
|
|
237
|
+
inset-inline-start: 0;
|
|
238
|
+
padding-inline-end: 0.625rem;
|
|
239
|
+
background: linear-gradient(to right, var(--_document-tabs--scroll-btn-background) 60%, transparent);
|
|
240
|
+
}
|
|
241
|
+
.document-tabs__scroll-btn--forward {
|
|
242
|
+
inset-inline-end: 0;
|
|
243
|
+
padding-inline-start: 0.625rem;
|
|
244
|
+
background: linear-gradient(to left, var(--_document-tabs--scroll-btn-background) 60%, transparent);
|
|
245
|
+
}</style>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { DocumentTab, DocumentTabsOverflow } from './types';
|
|
2
|
+
declare function $$render<T>(): {
|
|
3
|
+
props: {
|
|
4
|
+
value: T;
|
|
5
|
+
/** `NoInfer<T>` ensures `T` narrows from `value` only; inline tab literals type-check against the value's T without widening — no `as const` needed at callsites. */
|
|
6
|
+
tabs: DocumentTab<NoInfer<T>>[];
|
|
7
|
+
/** `'scroll'` makes the strip its own scroll container with edge fades and chevrons. Leave it `'visible'` when the container already scrolls the strip. @default 'visible' */
|
|
8
|
+
overflow?: DocumentTabsOverflow;
|
|
9
|
+
/** Equality for object T values. @default reference equality (`===`) */
|
|
10
|
+
compare?: (a: T, b: T) => boolean;
|
|
11
|
+
on?: {
|
|
12
|
+
change?: (value: T) => void;
|
|
13
|
+
/** Providing this renders a close button on every tab that doesn't opt out with `closable: false`. */
|
|
14
|
+
close?: (value: T) => void;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
exports: {};
|
|
18
|
+
bindings: "";
|
|
19
|
+
slots: {};
|
|
20
|
+
events: {};
|
|
21
|
+
};
|
|
22
|
+
declare class __sveltets_Render<T> {
|
|
23
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
24
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
25
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
26
|
+
bindings(): "";
|
|
27
|
+
exports(): {};
|
|
28
|
+
}
|
|
29
|
+
interface $$IsomorphicComponent {
|
|
30
|
+
new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
31
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
32
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
33
|
+
<T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
34
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* DocumentTabs — browser-style tabs for an editor: the active tab is taller than its neighbours and
|
|
38
|
+
* sits flush on the container's bottom rule, so it reads as continuous with the panel below while the
|
|
39
|
+
* inactive ones stay behind that line. Each tab carries an optional icon, an unsaved-changes dot, a
|
|
40
|
+
* `tone` for a tab of a different kind (a live preview), and its own `closable` opt-out. A closable or
|
|
41
|
+
* dirty tab reserves the trailing slot permanently: the dot sits there at rest, the close button takes
|
|
42
|
+
* its place on hover, and a tab's width never depends on which of them is showing. Arrow keys / Home /
|
|
43
|
+
* End move between tabs (roving tabindex), Delete closes the focused one.
|
|
44
|
+
*
|
|
45
|
+
* `overflow="scroll"` gives the strip its own scroll container with edge fades, chevrons and
|
|
46
|
+
* wheel-to-scroll. Leave it `'visible'` where the container already scrolls the strip — two nested
|
|
47
|
+
* scrollers fight each other.
|
|
48
|
+
*
|
|
49
|
+
* The active tab dips `--sc-kit--document-tabs--baseline-overlap` below the strip to cover the bottom
|
|
50
|
+
* rule of the bar it sits in. A container that clips (any `overflow` other than `visible`) has to
|
|
51
|
+
* leave that last pixel inside its own clip region, or the overlap is cut off.
|
|
52
|
+
*
|
|
53
|
+
* ### CSS Custom Properties
|
|
54
|
+
* | Property | Description | Default |
|
|
55
|
+
* |---|---|---|
|
|
56
|
+
* | `--sc-kit--document-tabs--height` | Inactive tab height | `29px` |
|
|
57
|
+
* | `--sc-kit--document-tabs--height--active` | Active tab height | `32px` |
|
|
58
|
+
* | `--sc-kit--document-tabs--padding-inline` | Tab horizontal padding — the same in both states, so activating a tab shifts nothing sideways | `10px` |
|
|
59
|
+
* | `--sc-kit--document-tabs--min-width` | Minimum tab width | `112px` |
|
|
60
|
+
* | `--sc-kit--document-tabs--max-width` | Maximum tab width — the label ellipsizes past it | `200px` |
|
|
61
|
+
* | `--sc-kit--document-tabs--gap` | Gap between tabs | `1px` |
|
|
62
|
+
* | `--sc-kit--document-tabs--tab--gap` | Gap between a tab's icon, label and trailing slot | `8px` |
|
|
63
|
+
* | `--sc-kit--document-tabs--radius` | Top corner radius | `--sc-kit--radius--sm` |
|
|
64
|
+
* | `--sc-kit--document-tabs--border-width` | Tab border width | `1px` |
|
|
65
|
+
* | `--sc-kit--document-tabs--border-color` | Tab border color | `--sc-kit--color--border` |
|
|
66
|
+
* | `--sc-kit--document-tabs--baseline-overlap` | How far the active tab dips below the strip to cover its container's bottom rule | `1px` |
|
|
67
|
+
* | `--sc-kit--document-tabs--background` | Inactive tab background | `--sc-kit--color--bg--app` |
|
|
68
|
+
* | `--sc-kit--document-tabs--background--active` | Active tab background — matches the pane below | `--sc-kit--color--bg--panel` |
|
|
69
|
+
* | `--sc-kit--document-tabs--background--hover` | Inactive tab hover background | `--sc-kit--color--bg--hover` |
|
|
70
|
+
* | `--sc-kit--document-tabs--color` | Inactive tab label color | `--sc-kit--color--text--secondary` |
|
|
71
|
+
* | `--sc-kit--document-tabs--color--active` | Active tab label color | `--sc-kit--color--text--primary` |
|
|
72
|
+
* | `--sc-kit--document-tabs--color--hover` | Inactive tab hover label color | `--sc-kit--color--text--primary` |
|
|
73
|
+
* | `--sc-kit--document-tabs--color--disabled` | Disabled tab label color | `--sc-kit--color--text--muted` |
|
|
74
|
+
* | `--sc-kit--document-tabs--font-size` | Label font size | `--sc-kit--font-size--sm` |
|
|
75
|
+
* | `--sc-kit--document-tabs--font-weight` | Label font weight | `--sc-kit--font-weight--regular` |
|
|
76
|
+
* | `--sc-kit--document-tabs--scroll-btn--background` | Fade behind the overflow chevrons | `--sc-kit--color--bg--panel` |
|
|
77
|
+
*/
|
|
78
|
+
declare const Cmp: $$IsomorphicComponent;
|
|
79
|
+
type Cmp<T> = InstanceType<typeof Cmp<T>>;
|
|
80
|
+
export default Cmp;
|