@rcarls/rc-splitter 0.2.0 → 0.3.1

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,473 @@
1
+ import { css as v, LitElement as _, html as c, nothing as f } from "lit";
2
+ import { property as o, state as h, query as b, queryAssignedElements as u } from "lit/decorators.js";
3
+ import { keyNavigation as m, keyInteraction as y, mouseMove as g } from "@rcarls/rc-common";
4
+ const x = v`
5
+ *,
6
+ *::before,
7
+ *::after {
8
+ box-sizing: border-box;
9
+ }
10
+
11
+ :host {
12
+ --rc-splitter-separator-size: 6px;
13
+
14
+ position: relative;
15
+ display: flex;
16
+ flex-direction: row;
17
+ align-items: stretch;
18
+ }
19
+
20
+ :host([orientation='vertical']) {
21
+ flex-direction: column;
22
+ }
23
+
24
+ :host([hidden]) {
25
+ display: none;
26
+ }
27
+
28
+ /* because :has(:focus-visible) doesn't work across slot boundary */
29
+ :host([data-interaction-mode='keyboard']):focus-within {
30
+ outline: auto;
31
+ }
32
+
33
+ ::slotted(*) {
34
+ width: 100%;
35
+ height: 100%;
36
+ }
37
+
38
+ #separator {
39
+ grid-column: separator;
40
+ flex: 0 0 var(--rc-splitter-separator-size, 6px);
41
+ display: flex;
42
+ flex-direction: column;
43
+ justify-content: center;
44
+ background-color: var(--rc-splitter-separator-color, color-mix(in srgb, ButtonBorder 35%, Canvas 65%));
45
+ border-left: var(--rc-splitter-separator-border-inline-start, var(--rc-splitter-keyline, 1px solid ButtonBorder));
46
+ border-right: var(--rc-splitter-separator-border-inline-end, var(--rc-splitter-keyline, 1px solid ButtonBorder));
47
+ /* z-index: 1 as a flex item stacks separator above pane siblings so the
48
+ ::after touch-target circle (which extends past the strip) is hittable */
49
+ z-index: 1;
50
+ /* Required for collapse-button absolute positioning */
51
+ position: relative;
52
+
53
+ :host([orientation='vertical']) & {
54
+ flex-direction: row;
55
+ border-left: unset;
56
+ border-right: unset;
57
+ border-top: var(--rc-splitter-separator-border-block-start, var(--rc-splitter-keyline, 1px solid ButtonBorder));
58
+ border-bottom: var(--rc-splitter-separator-border-block-end, var(--rc-splitter-keyline, 1px solid ButtonBorder));
59
+ }
60
+ }
61
+
62
+ #collapse-button {
63
+ /* Positioned at the start of the separator strip, centered on the cross
64
+ axis. The button intentionally protrudes into the primary pane so it
65
+ is visible and hittable at a reasonable size even on narrow strips. */
66
+ position: absolute;
67
+ top: var(--rc-splitter-collapse-button-offset, 8px);
68
+ left: 50%;
69
+ transform: translateX(-50%);
70
+ width: var(--rc-splitter-collapse-button-size, 20px);
71
+ height: var(--rc-splitter-collapse-button-size, 20px);
72
+ display: flex;
73
+ align-items: center;
74
+ justify-content: center;
75
+ padding: 0;
76
+ border: 1px solid var(--rc-splitter-collapse-button-border, ButtonBorder);
77
+ border-radius: 50%;
78
+ background: var(--rc-splitter-collapse-button-bg, Canvas);
79
+ color: var(--rc-splitter-collapse-button-color, ButtonText);
80
+ cursor: pointer;
81
+ line-height: 1;
82
+
83
+ &:hover {
84
+ background: var(--rc-splitter-collapse-button-hover-bg, ButtonFace);
85
+ }
86
+
87
+ &:focus-visible {
88
+ outline: 2px solid Highlight;
89
+ outline-offset: 2px;
90
+ }
91
+
92
+ :host([orientation='vertical']) & {
93
+ top: 50%;
94
+ left: var(--rc-splitter-collapse-button-offset, 8px);
95
+ transform: translateY(-50%);
96
+ }
97
+ }
98
+
99
+ #separator-handle {
100
+ width: 100%;
101
+ height: var(--rc-splitter-separator-handle-size, 100%);
102
+ cursor: col-resize;
103
+ display: flex;
104
+ align-items: center;
105
+ justify-content: center;
106
+ /* Required so ::after is positioned relative to this element */
107
+ position: relative;
108
+
109
+ /* ── Visual drag indicator ─────────────────────────────────────────────
110
+ Default: 3-dot vertical grip (horizontal splitter / vertical bar).
111
+ Themes override via --rc-splitter-handle-pattern (background-image) and
112
+ --rc-splitter-handle-fill (background-color). */
113
+ &::before {
114
+ content: '';
115
+ display: block;
116
+ width: var(--rc-splitter-handle-thickness, 4px);
117
+ height: 100%;
118
+ background-color: var(--rc-splitter-handle-fill, transparent);
119
+ background-image: var(
120
+ --rc-splitter-handle-pattern,
121
+ radial-gradient(circle 1px at 50% calc(50% - 5px), var(--rc-splitter-handle-color, ButtonBorder) 100%, transparent 100%),
122
+ radial-gradient(circle 1px at 50% 50%, var(--rc-splitter-handle-color, ButtonBorder) 100%, transparent 100%),
123
+ radial-gradient(circle 1px at 50% calc(50% + 5px), var(--rc-splitter-handle-color, ButtonBorder) 100%, transparent 100%)
124
+ );
125
+ border-radius: var(--rc-splitter-handle-border-radius, 0);
126
+ pointer-events: none;
127
+ transition: background-color var(--rc-splitter-handle-transition, 0ms);
128
+ }
129
+
130
+ /* Hover highlight stays on the visual indicator only, never the full strip */
131
+ &:hover::before {
132
+ background-color: var(--rc-splitter-handle-hover-fill, transparent);
133
+ }
134
+
135
+ /* ── Touch target circle ───────────────────────────────────────────────
136
+ 24 px diameter transparent circle, centered on the handle. Invisible
137
+ and non-interactive for mouse/keyboard. On coarse-pointer (touch)
138
+ devices the circle becomes hittable, giving a WCAG-compliant touch
139
+ target without widening the visual separator. */
140
+ &::after {
141
+ content: '';
142
+ position: absolute;
143
+ width: 24px;
144
+ height: 24px;
145
+ border-radius: 50%;
146
+ top: 50%;
147
+ left: 50%;
148
+ transform: translate(-50%, -50%);
149
+ pointer-events: none;
150
+ }
151
+
152
+ :host([orientation='vertical']) & {
153
+ width: var(--rc-splitter-separator-handle-size, 100%);
154
+ height: 100%;
155
+ cursor: row-resize;
156
+
157
+ /* Horizontal 3-dot grip (vertical splitter / horizontal bar) */
158
+ &::before {
159
+ width: 100%;
160
+ height: var(--rc-splitter-handle-thickness, 4px);
161
+ background-image: var(
162
+ --rc-splitter-handle-pattern,
163
+ radial-gradient(circle 1px at calc(50% - 5px) 50%, var(--rc-splitter-handle-color, ButtonBorder) 100%, transparent 100%),
164
+ radial-gradient(circle 1px at 50% 50%, var(--rc-splitter-handle-color, ButtonBorder) 100%, transparent 100%),
165
+ radial-gradient(circle 1px at calc(50% + 5px) 50%, var(--rc-splitter-handle-color, ButtonBorder) 100%, transparent 100%)
166
+ );
167
+ }
168
+ }
169
+
170
+ :host([fixed]) & {
171
+ pointer-events: none;
172
+ }
173
+ }
174
+
175
+ /* Activate the touch target circle only on coarse-pointer (touch) devices */
176
+ @media (any-pointer: coarse) {
177
+ #separator-handle::after {
178
+ pointer-events: auto;
179
+ }
180
+ }
181
+
182
+ #primary,
183
+ #secondary {
184
+ overflow: hidden;
185
+ }
186
+
187
+ #primary {
188
+ grid-column: primary;
189
+ flex: 0 0 auto;
190
+ }
191
+
192
+ #secondary {
193
+ grid-column: secondary;
194
+ flex: 1;
195
+ }
196
+ `;
197
+ var V = Object.defineProperty, k = Object.getOwnPropertyDescriptor, r = (d, e, t, s) => {
198
+ for (var a = s > 1 ? void 0 : s ? k(e, t) : e, n = d.length - 1, l; n >= 0; n--)
199
+ (l = d[n]) && (a = (s ? l(e, t, a) : l(a)) || a);
200
+ return s && a && V(e, t, a), a;
201
+ };
202
+ const p = class p extends _ {
203
+ constructor() {
204
+ super(...arguments), this.label = "Splitter", this.orientation = "horizontal", this.mode = "length", this.step = 1, this.min = 0, this.max = void 0, this._valueInitialized = !1, this._value = 0, this.fixed = !1, this.collapsible = !1, this._minValue = 0, this._maxValue = 0, this._lastValue = 0, this._initialMax = 0, this._resizeObserver = new ResizeObserver(() => this._onResize());
205
+ }
206
+ set value(e) {
207
+ const t = this._hostValue;
208
+ this._hostValue = e, this._initialMax && this._setValue(e, !1), this.requestUpdate("value", t);
209
+ }
210
+ /** The current splitter value, corresponding to the separator position, in either pixels or percentage points depending on `mode`. */
211
+ get value() {
212
+ return this._value;
213
+ }
214
+ set defaultValue(e) {
215
+ const t = this._defaultValue;
216
+ this._defaultValue = e, !this._initialMax && this._hostValue === void 0 && e !== void 0 && this._setValue(e, !1), this.requestUpdate("defaultValue", t);
217
+ }
218
+ /** Initial uncontrolled splitter value. */
219
+ get defaultValue() {
220
+ return this._defaultValue;
221
+ }
222
+ get _effectiveMin() {
223
+ return Math.max(this._minValue, this.min);
224
+ }
225
+ get _effectiveMax() {
226
+ return Math.min(this._maxValue, this.max ?? this._maxValue);
227
+ }
228
+ /** True once initialized and the primary pane is at its effective minimum. */
229
+ get _isCollapsed() {
230
+ return this._initialMax > 0 && this.value <= this._effectiveMin;
231
+ }
232
+ _toggleCollapse() {
233
+ this._setUserValue(
234
+ this._isCollapsed ? this._lastValue : this._effectiveMin
235
+ );
236
+ }
237
+ _onCollapseButtonClick() {
238
+ this._toggleCollapse();
239
+ }
240
+ _onCollapseKeydown(e) {
241
+ if (!this.collapsible || this.fixed || !e.ctrlKey && !e.metaKey) return;
242
+ (this.orientation === "horizontal" ? e.key === "ArrowLeft" || e.key === "ArrowRight" : e.key === "ArrowUp" || e.key === "ArrowDown") && (e.preventDefault(), e.stopImmediatePropagation(), this._toggleCollapse());
243
+ }
244
+ get _collapseButtonIcon() {
245
+ const t = this.orientation === "horizontal" ? this._isCollapsed ? "M 3 1 L 7 5 L 3 9" : "M 7 1 L 3 5 L 7 9" : this._isCollapsed ? "M 1 3 L 5 7 L 9 3" : "M 1 7 L 5 3 L 9 7";
246
+ return c`<svg
247
+ aria-hidden="true"
248
+ viewBox="0 0 10 10"
249
+ width="10"
250
+ height="10"
251
+ fill="none"
252
+ stroke="currentColor"
253
+ stroke-width="1.5"
254
+ stroke-linecap="round"
255
+ stroke-linejoin="round"
256
+ >
257
+ <path d=${t} />
258
+ </svg>`;
259
+ }
260
+ _setValue(e, t) {
261
+ const s = this._value;
262
+ this._value = Math.min(
263
+ Math.max(Math.round(e / this.step) * this.step, this._effectiveMin),
264
+ this._effectiveMax
265
+ ), t && this._value !== s && this.dispatchEvent(
266
+ new CustomEvent("rc-splitter-change", {
267
+ bubbles: !0,
268
+ composed: !0,
269
+ detail: { value: this._value, valueText: this.valueText }
270
+ })
271
+ );
272
+ }
273
+ _setUserValue(e) {
274
+ this._valueInitialized = !0, this._hostValue = void 0, this._value > this._effectiveMin && (this._lastValue = this._value), this._setValue(e, !0);
275
+ }
276
+ /** A human-readable string representation of the value. */
277
+ get valueText() {
278
+ return `${this.value}${this.mode === "length" ? "px" : "%"}`;
279
+ }
280
+ _onKeyboardResize(e) {
281
+ if (!this.fixed)
282
+ switch (e) {
283
+ case "next":
284
+ this._setUserValue(this.value + this.step);
285
+ break;
286
+ case "prev":
287
+ this._setUserValue(this.value - this.step);
288
+ break;
289
+ case "next-large":
290
+ this._setUserValue(this.value + this.step * 10);
291
+ break;
292
+ case "prev-large":
293
+ this._setUserValue(this.value - this.step * 10);
294
+ break;
295
+ case "start":
296
+ this._setUserValue(this._effectiveMin);
297
+ break;
298
+ case "end":
299
+ this._setUserValue(this._effectiveMax);
300
+ break;
301
+ case "toggle":
302
+ this._setUserValue(
303
+ this.value === this._effectiveMin ? this._lastValue : this._effectiveMin
304
+ );
305
+ break;
306
+ }
307
+ }
308
+ _onPointerResize(e) {
309
+ if (this.fixed)
310
+ return;
311
+ const t = this.getBoundingClientRect();
312
+ this.orientation === "vertical" ? this._setUserValue(
313
+ (e.clientY - t.top) / t.height * this._maxValue
314
+ ) : this._setUserValue(
315
+ (e.clientX - t.left) / t.width * this._maxValue
316
+ );
317
+ }
318
+ _onPrimaryChange(e) {
319
+ queueMicrotask(() => {
320
+ this._$primaryElements.length < 2 || this._$primaryElements.slice(1).forEach((t) => t.setAttribute("slot", "secondary"));
321
+ });
322
+ }
323
+ _onSecondaryChange(e) {
324
+ queueMicrotask(() => {
325
+ !this._$secondaryElements.length || this._$primaryElements.length || this._$secondaryElements.at(0)?.removeAttribute("slot");
326
+ });
327
+ }
328
+ _measureHostSize(e) {
329
+ const t = this.getBoundingClientRect(), s = e === "inline" ? t.width : t.height;
330
+ if (s > 0)
331
+ return Math.ceil(s);
332
+ const a = getComputedStyle(this), n = e === "inline" ? a.width : a.height, l = Number.parseFloat(n);
333
+ return Number.isFinite(l) ? Math.ceil(l) : 0;
334
+ }
335
+ _onResize() {
336
+ const e = this._$primaryElements.at(0), t = this._$primary.style.getPropertyValue("display");
337
+ globalThis.requestAnimationFrame(() => {
338
+ this._$primary.style.setProperty("display", "contents");
339
+ const s = e?.getBoundingClientRect() ?? this.getBoundingClientRect();
340
+ if (this.mode === "length") {
341
+ const a = this.orientation === "horizontal" ? (
342
+ // For horizontal splitters, just take the host width...
343
+ this._measureHostSize("inline")
344
+ ) : (
345
+ // ...otherwise try to use the first lightDOM element's auto height, and cache it
346
+ this._initialMax || Math.ceil(s.height) || this._measureHostSize("block")
347
+ );
348
+ (a > 0 || !this._initialMax) && (this._maxValue = a);
349
+ } else
350
+ this._maxValue = 100;
351
+ this._initialMax ? this._hostValue !== void 0 ? this._setValue(this._hostValue, !1) : this._setValue(this.value, !1) : (this._initialMax = this._maxValue, this._setValue(
352
+ this._valueInitialized ? this._value : this._hostValue ?? this.defaultValue ?? this._maxValue / 2,
353
+ !1
354
+ )), t ? this._$primary.style.setProperty("display", t) : this._$primary.style.removeProperty("display");
355
+ });
356
+ }
357
+ connectedCallback() {
358
+ super.connectedCallback(), this._resizeObserver.observe(this);
359
+ }
360
+ disconnectedCallback() {
361
+ this._resizeObserver.disconnect(), super.disconnectedCallback();
362
+ }
363
+ firstUpdated() {
364
+ this._onResize();
365
+ }
366
+ render() {
367
+ return c`
368
+ <div
369
+ id="primary"
370
+ part="primary"
371
+ aria-label=${this.label}
372
+ style=${this.orientation === "horizontal" ? `width: ${this.valueText}` : `height: ${this.valueText}`}
373
+ ?hidden=${this.value === this._minValue}
374
+ >
375
+ <slot @slotchange=${this._onPrimaryChange}></slot>
376
+ </div>
377
+
378
+ <div id="separator" part="separator">
379
+ ${this.collapsible && this._$secondaryElements.length && !this.fixed ? c`<button
380
+ id="collapse-button"
381
+ part="collapse-button"
382
+ aria-label=${this._isCollapsed ? `Expand ${this.label}` : `Collapse ${this.label}`}
383
+ aria-expanded=${String(!this._isCollapsed)}
384
+ aria-controls="primary"
385
+ @click=${this._onCollapseButtonClick}
386
+ >${this._collapseButtonIcon}</button>` : f}
387
+ <div
388
+ id="separator-handle"
389
+ role="separator"
390
+ tabindex="0"
391
+ part="separator-handle"
392
+ aria-labelledby="primary"
393
+ aria-controls="primary"
394
+ aria-orientation=${this.orientation === "horizontal" ? "vertical" : "horizontal"}
395
+ aria-valuenow=${this.value}
396
+ aria-valuetext=${this.valueText}
397
+ aria-valuemin=${this._effectiveMin}
398
+ aria-valuemax=${this._effectiveMax}
399
+ @keydown=${this._onCollapseKeydown}
400
+ ${m(this._onKeyboardResize)}
401
+ ${y()}
402
+ ${g(this._onPointerResize)}
403
+ ?hidden=${!this._$secondaryElements.length}
404
+ ></div>
405
+ </div>
406
+
407
+ <aside
408
+ id="secondary"
409
+ part="secondary"
410
+ ?hidden=${!this._$secondaryElements.length || this.value === this._maxValue}
411
+ >
412
+ <slot name="secondary" @slotchange=${this._onSecondaryChange}></slot>
413
+ </aside>
414
+ `;
415
+ }
416
+ };
417
+ p.styles = [x];
418
+ let i = p;
419
+ r([
420
+ o({ type: String })
421
+ ], i.prototype, "label", 2);
422
+ r([
423
+ o({ type: String, reflect: !0 })
424
+ ], i.prototype, "orientation", 2);
425
+ r([
426
+ o({ type: String })
427
+ ], i.prototype, "mode", 2);
428
+ r([
429
+ o({ type: Number })
430
+ ], i.prototype, "step", 2);
431
+ r([
432
+ o({ type: Number })
433
+ ], i.prototype, "min", 2);
434
+ r([
435
+ o({ type: Number })
436
+ ], i.prototype, "max", 2);
437
+ r([
438
+ o({ type: Number })
439
+ ], i.prototype, "value", 1);
440
+ r([
441
+ o({ type: Number, attribute: "default-value" })
442
+ ], i.prototype, "defaultValue", 1);
443
+ r([
444
+ h()
445
+ ], i.prototype, "_value", 2);
446
+ r([
447
+ o({ type: Boolean })
448
+ ], i.prototype, "fixed", 2);
449
+ r([
450
+ o({ type: Boolean })
451
+ ], i.prototype, "collapsible", 2);
452
+ r([
453
+ h()
454
+ ], i.prototype, "_minValue", 2);
455
+ r([
456
+ h()
457
+ ], i.prototype, "_maxValue", 2);
458
+ r([
459
+ h()
460
+ ], i.prototype, "_lastValue", 2);
461
+ r([
462
+ b("#primary", !0)
463
+ ], i.prototype, "_$primary", 2);
464
+ r([
465
+ u()
466
+ ], i.prototype, "_$primaryElements", 2);
467
+ r([
468
+ u({ slot: "secondary" })
469
+ ], i.prototype, "_$secondaryElements", 2);
470
+ export {
471
+ i as R
472
+ };
473
+ //# sourceMappingURL=rc-splitter-BZgnDbmR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-splitter-BZgnDbmR.js","sources":["../src/rc-splitter.styles.ts","../src/rc-splitter.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const splitterStyles = css`\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n }\n\n :host {\n --rc-splitter-separator-size: 6px;\n\n position: relative;\n display: flex;\n flex-direction: row;\n align-items: stretch;\n }\n\n :host([orientation='vertical']) {\n flex-direction: column;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n /* because :has(:focus-visible) doesn't work across slot boundary */\n :host([data-interaction-mode='keyboard']):focus-within {\n outline: auto;\n }\n\n ::slotted(*) {\n width: 100%;\n height: 100%;\n }\n\n #separator {\n grid-column: separator;\n flex: 0 0 var(--rc-splitter-separator-size, 6px);\n display: flex;\n flex-direction: column;\n justify-content: center;\n background-color: var(--rc-splitter-separator-color, color-mix(in srgb, ButtonBorder 35%, Canvas 65%));\n border-left: var(--rc-splitter-separator-border-inline-start, var(--rc-splitter-keyline, 1px solid ButtonBorder));\n border-right: var(--rc-splitter-separator-border-inline-end, var(--rc-splitter-keyline, 1px solid ButtonBorder));\n /* z-index: 1 as a flex item stacks separator above pane siblings so the\n ::after touch-target circle (which extends past the strip) is hittable */\n z-index: 1;\n /* Required for collapse-button absolute positioning */\n position: relative;\n\n :host([orientation='vertical']) & {\n flex-direction: row;\n border-left: unset;\n border-right: unset;\n border-top: var(--rc-splitter-separator-border-block-start, var(--rc-splitter-keyline, 1px solid ButtonBorder));\n border-bottom: var(--rc-splitter-separator-border-block-end, var(--rc-splitter-keyline, 1px solid ButtonBorder));\n }\n }\n\n #collapse-button {\n /* Positioned at the start of the separator strip, centered on the cross\n axis. The button intentionally protrudes into the primary pane so it\n is visible and hittable at a reasonable size even on narrow strips. */\n position: absolute;\n top: var(--rc-splitter-collapse-button-offset, 8px);\n left: 50%;\n transform: translateX(-50%);\n width: var(--rc-splitter-collapse-button-size, 20px);\n height: var(--rc-splitter-collapse-button-size, 20px);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 1px solid var(--rc-splitter-collapse-button-border, ButtonBorder);\n border-radius: 50%;\n background: var(--rc-splitter-collapse-button-bg, Canvas);\n color: var(--rc-splitter-collapse-button-color, ButtonText);\n cursor: pointer;\n line-height: 1;\n\n &:hover {\n background: var(--rc-splitter-collapse-button-hover-bg, ButtonFace);\n }\n\n &:focus-visible {\n outline: 2px solid Highlight;\n outline-offset: 2px;\n }\n\n :host([orientation='vertical']) & {\n top: 50%;\n left: var(--rc-splitter-collapse-button-offset, 8px);\n transform: translateY(-50%);\n }\n }\n\n #separator-handle {\n width: 100%;\n height: var(--rc-splitter-separator-handle-size, 100%);\n cursor: col-resize;\n display: flex;\n align-items: center;\n justify-content: center;\n /* Required so ::after is positioned relative to this element */\n position: relative;\n\n /* ── Visual drag indicator ─────────────────────────────────────────────\n Default: 3-dot vertical grip (horizontal splitter / vertical bar).\n Themes override via --rc-splitter-handle-pattern (background-image) and\n --rc-splitter-handle-fill (background-color). */\n &::before {\n content: '';\n display: block;\n width: var(--rc-splitter-handle-thickness, 4px);\n height: 100%;\n background-color: var(--rc-splitter-handle-fill, transparent);\n background-image: var(\n --rc-splitter-handle-pattern,\n radial-gradient(circle 1px at 50% calc(50% - 5px), var(--rc-splitter-handle-color, ButtonBorder) 100%, transparent 100%),\n radial-gradient(circle 1px at 50% 50%, var(--rc-splitter-handle-color, ButtonBorder) 100%, transparent 100%),\n radial-gradient(circle 1px at 50% calc(50% + 5px), var(--rc-splitter-handle-color, ButtonBorder) 100%, transparent 100%)\n );\n border-radius: var(--rc-splitter-handle-border-radius, 0);\n pointer-events: none;\n transition: background-color var(--rc-splitter-handle-transition, 0ms);\n }\n\n /* Hover highlight stays on the visual indicator only, never the full strip */\n &:hover::before {\n background-color: var(--rc-splitter-handle-hover-fill, transparent);\n }\n\n /* ── Touch target circle ───────────────────────────────────────────────\n 24 px diameter transparent circle, centered on the handle. Invisible\n and non-interactive for mouse/keyboard. On coarse-pointer (touch)\n devices the circle becomes hittable, giving a WCAG-compliant touch\n target without widening the visual separator. */\n &::after {\n content: '';\n position: absolute;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n pointer-events: none;\n }\n\n :host([orientation='vertical']) & {\n width: var(--rc-splitter-separator-handle-size, 100%);\n height: 100%;\n cursor: row-resize;\n\n /* Horizontal 3-dot grip (vertical splitter / horizontal bar) */\n &::before {\n width: 100%;\n height: var(--rc-splitter-handle-thickness, 4px);\n background-image: var(\n --rc-splitter-handle-pattern,\n radial-gradient(circle 1px at calc(50% - 5px) 50%, var(--rc-splitter-handle-color, ButtonBorder) 100%, transparent 100%),\n radial-gradient(circle 1px at 50% 50%, var(--rc-splitter-handle-color, ButtonBorder) 100%, transparent 100%),\n radial-gradient(circle 1px at calc(50% + 5px) 50%, var(--rc-splitter-handle-color, ButtonBorder) 100%, transparent 100%)\n );\n }\n }\n\n :host([fixed]) & {\n pointer-events: none;\n }\n }\n\n /* Activate the touch target circle only on coarse-pointer (touch) devices */\n @media (any-pointer: coarse) {\n #separator-handle::after {\n pointer-events: auto;\n }\n }\n\n #primary,\n #secondary {\n overflow: hidden;\n }\n\n #primary {\n grid-column: primary;\n flex: 0 0 auto;\n }\n\n #secondary {\n grid-column: secondary;\n flex: 1;\n }\n`;\n\nexport default splitterStyles;\n","import { LitElement, html, nothing } from \"lit\";\nimport {\n property,\n state,\n query,\n queryAssignedElements,\n} from \"lit/decorators.js\";\n\nimport {\n keyInteraction,\n keyNavigation,\n type KeyboardNavigationAction,\n mouseMove,\n} from \"@rcarls/rc-common\";\n\nimport splitterStyles from \"./rc-splitter.styles\";\n\ntype SplitterOrientation = \"horizontal\" | \"vertical\";\n\ntype SplitterMode = \"length\" | \"percent\";\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"rc-splitter\": RCSplitter;\n }\n}\n\n/**\n * Resizable pane splitter with pointer, keyboard, and collapse/restore controls, following\n * the WAI-ARIA Window Splitter pattern.\n *\n * Set `orientation=\"vertical\"` for a vertical splitter\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-splitter rc-splitter docs}\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/ WAI-ARIA Window Splitter pattern}\n *\n * @slot - Primary pane contents\n * @slot secondary - Secondary pane contents (optional)\n *\n * @cssprop [--rc-splitter-separator-size=6px] - Thickness of the separator bar\n * @cssprop [--rc-splitter-separator-handle-size=100%] - Length of the drag handle area within the separator (also the length of the visible indicator)\n * @cssprop [--rc-splitter-separator-color=color-mix(in srgb, ButtonBorder 35%, Canvas 65%)] - Separator background color\n * @cssprop [--rc-splitter-keyline=1px solid ButtonBorder] - Shared separator keyline border\n * @cssprop [--rc-splitter-handle-color=ButtonBorder] - Color of the dot grip indicators (default visual)\n * @cssprop [--rc-splitter-handle-thickness=4px] - Cross-axis size of the visual indicator (dot column width or pill/line thickness)\n * @cssprop [--rc-splitter-handle-border-radius=0] - Border-radius of the visual indicator; set to a large value (e.g. 999px) for a pill shape\n * @cssprop [--rc-splitter-handle-pattern=<3-dot radial-gradient>] - background-image for the visual indicator; set to `none` to use a solid fill via --rc-splitter-handle-fill instead\n * @cssprop [--rc-splitter-handle-fill=transparent] - background-color of the visual indicator; effective when --rc-splitter-handle-pattern is none (e.g. for a solid pill)\n * @cssprop [--rc-splitter-handle-hover-fill=transparent] - background-color of the visual indicator on hover; scoped to the indicator element only, not the full separator strip\n * @cssprop [--rc-splitter-handle-transition=0ms] - CSS transition duration/easing for the visual indicator's background-color changes\n * @cssprop [--rc-splitter-collapse-button-size=20px] - Diameter of the collapse/expand toggle button\n * @cssprop [--rc-splitter-collapse-button-offset=8px] - Distance from the start edge of the separator to the collapse button center\n * @cssprop [--rc-splitter-collapse-button-bg=Canvas] - Collapse button background color\n * @cssprop [--rc-splitter-collapse-button-hover-bg=ButtonFace] - Collapse button background color on hover\n * @cssprop [--rc-splitter-collapse-button-border=ButtonBorder] - Collapse button border color\n * @cssprop [--rc-splitter-collapse-button-color=ButtonText] - Collapse button icon color\n * @cssprop [--rc-splitter-separator-border-inline-start=1px solid ButtonBorder] - Inline-start border\n * @cssprop [--rc-splitter-separator-border-inline-end=1px solid ButtonBorder] - Inline-end border\n * @cssprop [--rc-splitter-separator-border-block-start=1px solid ButtonBorder] - Block-start border (vertical orientation)\n * @cssprop [--rc-splitter-separator-border-block-end=1px solid ButtonBorder] - Block-end border (vertical orientation)\n * @csspart primary - Primary pane container\n * @csspart secondary - Secondary pane container\n * @csspart separator - The separator bar\n * @csspart separator-handle - The focusable drag handle\n * @csspart collapse-button - The collapse/expand toggle button (only rendered when `collapsible` is set)\n */\nexport class RCSplitter extends LitElement {\n static styles = [splitterStyles];\n\n /** Accessible label for this splitter. Default label is 'Splitter'. */\n @property({ type: String })\n label = \"Splitter\";\n\n /** Splitter orientation, for keyboard navigation and initial sizing. */\n @property({ type: String, reflect: true })\n orientation: SplitterOrientation = \"horizontal\";\n\n /** Determines length units for min, max and step attributes, one of either `length` (default) or `percent` */\n @property({ type: String })\n mode: SplitterMode = \"length\";\n\n /** The step size for resizing, in either pixels or percentage points depending on `mode`. */\n @property({ type: Number })\n step: number = 1;\n\n /** Minimum size of the primary pane in current mode units. Defaults to 0. */\n @property({ type: Number })\n min: number = 0;\n\n /** Maximum size of the primary pane in current mode units. Defaults to the full container size. */\n @property({ type: Number })\n max: number | undefined = undefined;\n\n private _defaultValue: number | undefined;\n private _hostValue: number | undefined;\n private _valueInitialized = false;\n\n /** The current splitter value. Host writes update silently. */\n @property({ type: Number })\n set value(val: number) {\n const oldValue = this._hostValue;\n\n this._hostValue = val;\n\n if (this._initialMax) {\n this._setValue(val, false);\n }\n\n this.requestUpdate(\"value\", oldValue);\n }\n\n /** The current splitter value, corresponding to the separator position, in either pixels or percentage points depending on `mode`. */\n get value() {\n return this._value;\n }\n\n /** Initial uncontrolled splitter value. */\n @property({ type: Number, attribute: \"default-value\" })\n set defaultValue(val: number | undefined) {\n const oldValue = this._defaultValue;\n\n this._defaultValue = val;\n\n if (!this._initialMax && this._hostValue === undefined && val !== undefined) {\n this._setValue(val, false);\n }\n\n this.requestUpdate(\"defaultValue\", oldValue);\n }\n\n /** Initial uncontrolled splitter value. */\n get defaultValue() {\n return this._defaultValue;\n }\n\n protected get _effectiveMin(): number {\n return Math.max(this._minValue, this.min);\n }\n\n protected get _effectiveMax(): number {\n return Math.min(this._maxValue, this.max ?? this._maxValue);\n }\n\n /** True once initialized and the primary pane is at its effective minimum. */\n protected get _isCollapsed(): boolean {\n return this._initialMax > 0 && this.value <= this._effectiveMin;\n }\n\n protected _toggleCollapse(): void {\n this._setUserValue(\n this._isCollapsed ? this._lastValue : this._effectiveMin,\n );\n }\n\n protected _onCollapseButtonClick(): void {\n this._toggleCollapse();\n }\n\n protected _onCollapseKeydown(e: KeyboardEvent): void {\n if (!this.collapsible || this.fixed) return;\n if (!e.ctrlKey && !e.metaKey) return;\n\n const isRelevantKey =\n this.orientation === \"horizontal\"\n ? e.key === \"ArrowLeft\" || e.key === \"ArrowRight\"\n : e.key === \"ArrowUp\" || e.key === \"ArrowDown\";\n\n if (isRelevantKey) {\n e.preventDefault();\n e.stopImmediatePropagation();\n this._toggleCollapse();\n }\n }\n\n private get _collapseButtonIcon() {\n const isHorizontal = this.orientation === \"horizontal\";\n // Chevron points LEFT/UP to collapse (separator moves toward primary),\n // RIGHT/DOWN to expand (separator moves away from primary).\n const d = isHorizontal\n ? this._isCollapsed\n ? \"M 3 1 L 7 5 L 3 9\"\n : \"M 7 1 L 3 5 L 7 9\"\n : this._isCollapsed\n ? \"M 1 3 L 5 7 L 9 3\"\n : \"M 1 7 L 5 3 L 9 7\";\n\n return html`<svg\n aria-hidden=\"true\"\n viewBox=\"0 0 10 10\"\n width=\"10\"\n height=\"10\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=${d} />\n </svg>`;\n }\n\n private _setValue(val: number, dispatch: boolean): void {\n const oldValue = this._value;\n\n this._value = Math.min(\n Math.max(Math.round(val / this.step) * this.step, this._effectiveMin),\n this._effectiveMax,\n );\n\n if (dispatch && this._value !== oldValue) {\n this.dispatchEvent(\n new CustomEvent(\"rc-splitter-change\", {\n bubbles: true,\n composed: true,\n detail: { value: this._value, valueText: this.valueText },\n }),\n );\n }\n }\n\n private _setUserValue(val: number): void {\n this._valueInitialized = true;\n this._hostValue = undefined;\n // Capture the last position above the effective minimum before a user-driven\n // change so toggle-collapse can restore it. Internal resize callbacks use\n // _setValue directly and must not overwrite this.\n if (this._value > this._effectiveMin) {\n this._lastValue = this._value;\n }\n this._setValue(val, true);\n }\n\n @state()\n private _value: number = 0;\n\n /** Toggles resizing ability */\n @property({ type: Boolean })\n fixed: boolean = false;\n\n /** Renders a collapse/expand toggle button on the separator. */\n @property({ type: Boolean })\n collapsible: boolean = false;\n\n /** A human-readable string representation of the value. */\n get valueText() {\n return `${this.value}${this.mode === \"length\" ? \"px\" : \"%\"}`;\n }\n\n @state()\n protected _minValue: number = 0;\n\n @state()\n protected _maxValue: number = 0;\n\n /** Last valid value, for collapse functionality. */\n @state()\n protected _lastValue: number = 0;\n\n @query(\"#primary\", true)\n protected _$primary!: HTMLDivElement;\n\n @queryAssignedElements()\n protected _$primaryElements!: Array<HTMLElement>;\n\n @queryAssignedElements({ slot: \"secondary\" })\n protected _$secondaryElements!: Array<HTMLElement>;\n\n protected _initialMax: number = 0;\n\n protected _resizeObserver = new ResizeObserver(() => this._onResize());\n\n protected _onKeyboardResize(action: KeyboardNavigationAction) {\n if (this.fixed) {\n return;\n }\n\n switch (action) {\n case \"next\":\n this._setUserValue(this.value + this.step);\n break;\n case \"prev\":\n this._setUserValue(this.value - this.step);\n break;\n case \"next-large\":\n this._setUserValue(this.value + this.step * 10);\n break;\n case \"prev-large\":\n this._setUserValue(this.value - this.step * 10);\n break;\n case \"start\":\n this._setUserValue(this._effectiveMin);\n break;\n case \"end\":\n this._setUserValue(this._effectiveMax);\n break;\n case \"toggle\":\n this._setUserValue(\n this.value === this._effectiveMin ? this._lastValue : this._effectiveMin,\n );\n break;\n }\n }\n\n protected _onPointerResize(e: MouseEvent) {\n if (this.fixed) {\n return;\n }\n\n const clientRect = this.getBoundingClientRect();\n\n if (this.orientation === \"vertical\") {\n this._setUserValue(\n ((e.clientY - clientRect.top) / clientRect.height) * this._maxValue,\n );\n } else {\n this._setUserValue(\n ((e.clientX - clientRect.left) / clientRect.width) * this._maxValue,\n );\n }\n }\n\n protected _onPrimaryChange(_e: Event) {\n queueMicrotask(() => {\n if (this._$primaryElements.length < 2) return;\n\n this._$primaryElements\n .slice(1)\n .forEach((el) => el.setAttribute(\"slot\", \"secondary\"));\n });\n }\n\n protected _onSecondaryChange(_e: Event) {\n queueMicrotask(() => {\n if (!this._$secondaryElements.length || this._$primaryElements.length) {\n return;\n }\n\n this._$secondaryElements.at(0)?.removeAttribute(\"slot\");\n });\n }\n\n private _measureHostSize(axis: \"inline\" | \"block\"): number {\n const clientRect = this.getBoundingClientRect();\n const measuredSize = axis === \"inline\" ? clientRect.width : clientRect.height;\n\n if (measuredSize > 0) {\n return Math.ceil(measuredSize);\n }\n\n const computedStyle = getComputedStyle(this);\n const fallbackSize =\n axis === \"inline\" ? computedStyle.width : computedStyle.height;\n const parsedFallbackSize = Number.parseFloat(fallbackSize);\n\n return Number.isFinite(parsedFallbackSize)\n ? Math.ceil(parsedFallbackSize)\n : 0;\n }\n\n protected _onResize() {\n const el = this._$primaryElements.at(0);\n const prevStyle = this._$primary.style.getPropertyValue(\"display\");\n\n // Request animation frame to prevent layout paint jank.\n globalThis.requestAnimationFrame(() => {\n // Temporarily display the first light DOM element as a direct child for measurement.\n this._$primary.style.setProperty(\"display\", \"contents\");\n\n const clientRect =\n el?.getBoundingClientRect() ?? this.getBoundingClientRect();\n\n if (this.mode === \"length\") {\n const measured =\n this.orientation === \"horizontal\"\n ? // For horizontal splitters, just take the host width...\n this._measureHostSize(\"inline\")\n : // ...otherwise try to use the first lightDOM element's auto height, and cache it\n this._initialMax ||\n Math.ceil(clientRect.height) ||\n this._measureHostSize(\"block\");\n\n // After initialization, ignore spurious zero measurements (e.g. during\n // Chromium's layout recalculation triggered by a secondary ResizeObserver\n // callback). A temporarily-zero result would clamp _value to 0 incorrectly.\n if (measured > 0 || !this._initialMax) {\n this._maxValue = measured;\n }\n } else {\n // Percentage max is always just 100%\n this._maxValue = 100.0;\n }\n\n if (!this._initialMax) {\n this._initialMax = this._maxValue;\n this._setValue(\n this._valueInitialized\n ? this._value\n : (this._hostValue ?? this.defaultValue ?? this._maxValue / 2),\n false,\n );\n } else if (this._hostValue !== undefined) {\n this._setValue(this._hostValue, false);\n } else {\n this._setValue(this.value, false);\n }\n\n // Restore previous display mode\n prevStyle\n ? this._$primary.style.setProperty(\"display\", prevStyle)\n : this._$primary.style.removeProperty(\"display\");\n });\n }\n\n connectedCallback() {\n super.connectedCallback();\n this._resizeObserver.observe(this);\n }\n\n disconnectedCallback(): void {\n this._resizeObserver.disconnect();\n super.disconnectedCallback();\n }\n\n firstUpdated() {\n this._onResize();\n }\n\n render() {\n return html`\n <div\n id=\"primary\"\n part=\"primary\"\n aria-label=${this.label}\n style=${this.orientation === \"horizontal\"\n ? `width: ${this.valueText}`\n : `height: ${this.valueText}`}\n ?hidden=${this.value === this._minValue}\n >\n <slot @slotchange=${this._onPrimaryChange}></slot>\n </div>\n\n <div id=\"separator\" part=\"separator\">\n ${this.collapsible && this._$secondaryElements.length && !this.fixed\n ? html`<button\n id=\"collapse-button\"\n part=\"collapse-button\"\n aria-label=${this._isCollapsed\n ? `Expand ${this.label}`\n : `Collapse ${this.label}`}\n aria-expanded=${String(!this._isCollapsed)}\n aria-controls=\"primary\"\n @click=${this._onCollapseButtonClick}\n >${this._collapseButtonIcon}</button>`\n : nothing}\n <div\n id=\"separator-handle\"\n role=\"separator\"\n tabindex=\"0\"\n part=\"separator-handle\"\n aria-labelledby=\"primary\"\n aria-controls=\"primary\"\n aria-orientation=${this.orientation === 'horizontal' ? 'vertical' : 'horizontal'}\n aria-valuenow=${this.value}\n aria-valuetext=${this.valueText}\n aria-valuemin=${this._effectiveMin}\n aria-valuemax=${this._effectiveMax}\n @keydown=${this._onCollapseKeydown}\n ${keyNavigation(this._onKeyboardResize)}\n ${keyInteraction()}\n ${mouseMove(this._onPointerResize)}\n ?hidden=${!this._$secondaryElements.length}\n ></div>\n </div>\n\n <aside\n id=\"secondary\"\n part=\"secondary\"\n ?hidden=${!this._$secondaryElements.length ||\n this.value === this._maxValue}\n >\n <slot name=\"secondary\" @slotchange=${this._onSecondaryChange}></slot>\n </aside>\n `;\n }\n}\n\nexport default RCSplitter;\n"],"names":["splitterStyles","css","_RCSplitter","LitElement","val","oldValue","d","html","dispatch","action","clientRect","_e","el","axis","measuredSize","computedStyle","fallbackSize","parsedFallbackSize","prevStyle","measured","nothing","keyNavigation","keyInteraction","mouseMove","RCSplitter","__decorateClass","property","state","query","queryAssignedElements"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { R as t } from "./rc-splitter-CkpiDBPA.js";
1
+ import { R as t } from "./rc-splitter-BZgnDbmR.js";
2
2
  customElements.get("rc-splitter") || customElements.define("rc-splitter", t);
3
3
  export {
4
4
  t as RCSplitter
@@ -1,4 +1,4 @@
1
- import { R as e } from "./rc-splitter-CkpiDBPA.js";
1
+ import { R as e } from "./rc-splitter-BZgnDbmR.js";
2
2
  export {
3
3
  e as RCSplitter
4
4
  };
@@ -8,19 +8,34 @@ declare global {
8
8
  }
9
9
  }
10
10
  /**
11
- * An accessible splitter layout component.
11
+ * Resizable pane splitter with pointer, keyboard, and collapse/restore controls, following
12
+ * the WAI-ARIA Window Splitter pattern.
12
13
  *
13
14
  * Set `orientation="vertical"` for a vertical splitter
14
15
  *
16
+ * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-splitter rc-splitter docs}
17
+ * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/ WAI-ARIA Window Splitter pattern}
18
+ *
15
19
  * @slot - Primary pane contents
16
20
  * @slot secondary - Secondary pane contents (optional)
17
21
  *
18
- * @see https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/
19
22
  * @cssprop [--rc-splitter-separator-size=6px] - Thickness of the separator bar
20
- * @cssprop [--rc-splitter-separator-handle-size=100%] - Length of the drag handle within the separator
23
+ * @cssprop [--rc-splitter-separator-handle-size=100%] - Length of the drag handle area within the separator (also the length of the visible indicator)
21
24
  * @cssprop [--rc-splitter-separator-color=color-mix(in srgb, ButtonBorder 35%, Canvas 65%)] - Separator background color
22
25
  * @cssprop [--rc-splitter-keyline=1px solid ButtonBorder] - Shared separator keyline border
23
- * @cssprop [--rc-splitter-handle-color=ButtonBorder] - Visible handle line color
26
+ * @cssprop [--rc-splitter-handle-color=ButtonBorder] - Color of the dot grip indicators (default visual)
27
+ * @cssprop [--rc-splitter-handle-thickness=4px] - Cross-axis size of the visual indicator (dot column width or pill/line thickness)
28
+ * @cssprop [--rc-splitter-handle-border-radius=0] - Border-radius of the visual indicator; set to a large value (e.g. 999px) for a pill shape
29
+ * @cssprop [--rc-splitter-handle-pattern=<3-dot radial-gradient>] - background-image for the visual indicator; set to `none` to use a solid fill via --rc-splitter-handle-fill instead
30
+ * @cssprop [--rc-splitter-handle-fill=transparent] - background-color of the visual indicator; effective when --rc-splitter-handle-pattern is none (e.g. for a solid pill)
31
+ * @cssprop [--rc-splitter-handle-hover-fill=transparent] - background-color of the visual indicator on hover; scoped to the indicator element only, not the full separator strip
32
+ * @cssprop [--rc-splitter-handle-transition=0ms] - CSS transition duration/easing for the visual indicator's background-color changes
33
+ * @cssprop [--rc-splitter-collapse-button-size=20px] - Diameter of the collapse/expand toggle button
34
+ * @cssprop [--rc-splitter-collapse-button-offset=8px] - Distance from the start edge of the separator to the collapse button center
35
+ * @cssprop [--rc-splitter-collapse-button-bg=Canvas] - Collapse button background color
36
+ * @cssprop [--rc-splitter-collapse-button-hover-bg=ButtonFace] - Collapse button background color on hover
37
+ * @cssprop [--rc-splitter-collapse-button-border=ButtonBorder] - Collapse button border color
38
+ * @cssprop [--rc-splitter-collapse-button-color=ButtonText] - Collapse button icon color
24
39
  * @cssprop [--rc-splitter-separator-border-inline-start=1px solid ButtonBorder] - Inline-start border
25
40
  * @cssprop [--rc-splitter-separator-border-inline-end=1px solid ButtonBorder] - Inline-end border
26
41
  * @cssprop [--rc-splitter-separator-border-block-start=1px solid ButtonBorder] - Block-start border (vertical orientation)
@@ -29,6 +44,7 @@ declare global {
29
44
  * @csspart secondary - Secondary pane container
30
45
  * @csspart separator - The separator bar
31
46
  * @csspart separator-handle - The focusable drag handle
47
+ * @csspart collapse-button - The collapse/expand toggle button (only rendered when `collapsible` is set)
32
48
  */
33
49
  export declare class RCSplitter extends LitElement {
34
50
  static styles: import('lit').CSSResult[];
@@ -40,8 +56,13 @@ export declare class RCSplitter extends LitElement {
40
56
  mode: SplitterMode;
41
57
  /** The step size for resizing, in either pixels or percentage points depending on `mode`. */
42
58
  step: number;
59
+ /** Minimum size of the primary pane in current mode units. Defaults to 0. */
60
+ min: number;
61
+ /** Maximum size of the primary pane in current mode units. Defaults to the full container size. */
62
+ max: number | undefined;
43
63
  private _defaultValue;
44
64
  private _hostValue;
65
+ private _valueInitialized;
45
66
  /** The current splitter value. Host writes update silently. */
46
67
  set value(val: number);
47
68
  /** The current splitter value, corresponding to the separator position, in either pixels or percentage points depending on `mode`. */
@@ -50,11 +71,21 @@ export declare class RCSplitter extends LitElement {
50
71
  set defaultValue(val: number | undefined);
51
72
  /** Initial uncontrolled splitter value. */
52
73
  get defaultValue(): number | undefined;
74
+ protected get _effectiveMin(): number;
75
+ protected get _effectiveMax(): number;
76
+ /** True once initialized and the primary pane is at its effective minimum. */
77
+ protected get _isCollapsed(): boolean;
78
+ protected _toggleCollapse(): void;
79
+ protected _onCollapseButtonClick(): void;
80
+ protected _onCollapseKeydown(e: KeyboardEvent): void;
81
+ private get _collapseButtonIcon();
53
82
  private _setValue;
54
83
  private _setUserValue;
55
84
  private _value;
56
85
  /** Toggles resizing ability */
57
86
  fixed: boolean;
87
+ /** Renders a collapse/expand toggle button on the separator. */
88
+ collapsible: boolean;
58
89
  /** A human-readable string representation of the value. */
59
90
  get valueText(): string;
60
91
  protected _minValue: number;