@rcarls/rc-splitter 0.1.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/README.md +159 -0
- package/dist/custom-elements.json +499 -0
- package/dist/demo.css +85 -0
- package/dist/demo.js +40 -0
- package/dist/rc-splitter-CkpiDBPA.js +314 -0
- package/dist/rc-splitter-CkpiDBPA.js.map +1 -0
- package/dist/rc-splitter-define.js +6 -0
- package/dist/rc-splitter-define.js.map +1 -0
- package/dist/rc-splitter.js +5 -0
- package/dist/rc-splitter.js.map +1 -0
- package/dist/types/packages/rc-splitter/src/define.d.ts +1 -0
- package/dist/types/packages/rc-splitter/src/index.d.ts +1 -0
- package/dist/types/packages/rc-splitter/src/rc-splitter.d.ts +80 -0
- package/dist/types/packages/rc-splitter/src/rc-splitter.styles.d.ts +2 -0
- package/dist/types/packages/rc-splitter/src/rc-splitter.test.d.ts +0 -0
- package/package.json +68 -0
package/README.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# `@rcarls/rc-splitter`
|
|
2
|
+
|
|
3
|
+
A WAI-ARIA compliant resizable pane splitter implementing the [Window Splitter pattern](https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/). Supports horizontal and vertical orientations, pixel and percentage modes, collapse/restore via keyboard, and full pointer and keyboard control. Built with [Lit 3](https://lit.dev).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @rcarls/rc-splitter
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Import
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
import '@rcarls/rc-splitter'; // side-effect: registers <rc-splitter>
|
|
17
|
+
import { RCSplitter } from '@rcarls/rc-splitter'; // named class export
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Basic usage
|
|
23
|
+
|
|
24
|
+
Place the primary pane in the default slot and the secondary pane in the `secondary` slot. The splitter takes up the full available space of its container.
|
|
25
|
+
|
|
26
|
+
```html
|
|
27
|
+
<rc-splitter style="width: 100%; height: 400px;">
|
|
28
|
+
<div>Primary pane — resizes when you drag the separator</div>
|
|
29
|
+
<div slot="secondary">Secondary pane — fills remaining space</div>
|
|
30
|
+
</rc-splitter>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Vertical orientation:
|
|
34
|
+
|
|
35
|
+
```html
|
|
36
|
+
<rc-splitter orientation="vertical" style="width: 100%; height: 600px;">
|
|
37
|
+
<div>Top pane</div>
|
|
38
|
+
<div slot="secondary">Bottom pane</div>
|
|
39
|
+
</rc-splitter>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## API
|
|
45
|
+
|
|
46
|
+
### Properties / attributes
|
|
47
|
+
|
|
48
|
+
| Property | Attribute | Type | Default | Description |
|
|
49
|
+
|---|---|---|---|---|
|
|
50
|
+
| `label` | `label` | `string` | `'Splitter'` | Accessible label applied to the primary pane and used by the separator handle via `aria-labelledby`. |
|
|
51
|
+
| `orientation` | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Layout direction. `horizontal` = left/right panes; `vertical` = top/bottom panes. Reflects to attribute. |
|
|
52
|
+
| `mode` | `mode` | `'length' \| 'percent'` | `'length'` | Unit for `value`. `length` = pixels of the primary pane; `percent` = percentage of total container size. |
|
|
53
|
+
| `step` | `step` | `number` | `1` | Keyboard step size in the current unit (px or %). Shift multiplies by 10×. |
|
|
54
|
+
| `value` | — | `number \| null` | `null` | Initial primary pane size. When `null`, the pane uses its natural size until first interaction. Setting via property updates the separator position. |
|
|
55
|
+
| `fixed` | `fixed` | `boolean` | `false` | Disable resizing. The separator is rendered but non-interactive. |
|
|
56
|
+
|
|
57
|
+
### CSS custom properties
|
|
58
|
+
|
|
59
|
+
| Property | Default | Description |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| `--rc-splitter-separator-size` | `6px` | Thickness of the separator bar |
|
|
62
|
+
| `--rc-splitter-separator-handle-size` | `100%` | Length of the drag handle within the separator (set to a smaller value to create a centred grab handle) |
|
|
63
|
+
| `--rc-splitter-separator-color` | `ButtonFace` | Background color of the separator bar |
|
|
64
|
+
| `--rc-splitter-separator-border-inline-start` | `1px solid ButtonBorder` | Inline-start (left in LTR) border of the separator |
|
|
65
|
+
| `--rc-splitter-separator-border-inline-end` | `1px solid ButtonBorder` | Inline-end (right in LTR) border of the separator |
|
|
66
|
+
| `--rc-splitter-separator-border-block-start` | `1px solid ButtonBorder` | Block-start (top) border when `orientation="vertical"` |
|
|
67
|
+
| `--rc-splitter-separator-border-block-end` | `1px solid ButtonBorder` | Block-end (bottom) border when `orientation="vertical"` |
|
|
68
|
+
|
|
69
|
+
All color defaults use CSS system color keywords so they adapt automatically to the user's color scheme and forced-color modes.
|
|
70
|
+
|
|
71
|
+
### CSS parts
|
|
72
|
+
|
|
73
|
+
| Part | Element | Description |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| `primary` | `div#primary` | Primary pane container |
|
|
76
|
+
| `secondary` | `aside#secondary` | Secondary pane container |
|
|
77
|
+
| `separator` | `div#separator` | The separator bar |
|
|
78
|
+
| `separator-handle` | `div[role="separator"]` inside separator | The focusable drag handle (narrower than the bar if `--rc-splitter-separator-handle-size` is set) |
|
|
79
|
+
|
|
80
|
+
### Slots
|
|
81
|
+
|
|
82
|
+
| Slot | Description |
|
|
83
|
+
|---|---|
|
|
84
|
+
| *(default)* | Primary pane. Its inline-size (or block-size when vertical) is set by the splitter. |
|
|
85
|
+
| `secondary` | Secondary pane. Fills remaining space via `flex: 1`. |
|
|
86
|
+
|
|
87
|
+
### Events
|
|
88
|
+
|
|
89
|
+
| Event | Bubbles | Cancelable | Detail | When |
|
|
90
|
+
|---|---|---|---|---|
|
|
91
|
+
| `rc-splitter-change` | Yes (composed) | No | `{ value: number, valueText: string }` | Separator position changes (on every pointer move or key press) |
|
|
92
|
+
|
|
93
|
+
### Read-only getters
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
value: number | null // Current primary pane size in the current mode unit
|
|
97
|
+
valueText: string // Human-readable value string (e.g. "240px" or "40%")
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Keyboard behaviour
|
|
103
|
+
|
|
104
|
+
Focus the separator handle (click or Tab), then:
|
|
105
|
+
|
|
106
|
+
| Key | Action |
|
|
107
|
+
|---|---|
|
|
108
|
+
| `ArrowRight` / `ArrowDown` | Increase primary pane by `step` (horizontal: right; vertical: down) |
|
|
109
|
+
| `ArrowLeft` / `ArrowUp` | Decrease primary pane by `step` |
|
|
110
|
+
| `Shift` + Arrow | Multiply step by 10× |
|
|
111
|
+
| `Home` | Collapse primary pane to zero |
|
|
112
|
+
| `End` | Expand primary pane to fill all available space |
|
|
113
|
+
| `Enter` | Restore last non-collapsed size (if currently collapsed) |
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## ARIA
|
|
118
|
+
|
|
119
|
+
The separator handle implements the WAI-ARIA slider role pattern:
|
|
120
|
+
|
|
121
|
+
| Attribute | Where | Value |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| `role="separator"` | Separator handle `div` | — |
|
|
124
|
+
| `aria-label` | Primary pane | Value of `label` property |
|
|
125
|
+
| `aria-orientation` | Separator handle | `"horizontal"` or `"vertical"` |
|
|
126
|
+
| `aria-valuenow` | Separator handle | Current numeric value |
|
|
127
|
+
| `aria-valuemin` | Separator handle | `0` |
|
|
128
|
+
| `aria-valuemax` | Separator handle | Container width or height in current mode units |
|
|
129
|
+
| `aria-valuetext` | Separator handle | Human-readable string (e.g. `"240px"`) |
|
|
130
|
+
| `aria-controls` | Separator handle | `"primary"` — ID of the primary pane |
|
|
131
|
+
| `aria-labelledby` | Separator handle | `"primary"` — uses the primary pane as label context |
|
|
132
|
+
| `tabindex="0"` | Separator handle | Always focusable |
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Example: percentage mode with a styled separator
|
|
137
|
+
|
|
138
|
+
```html
|
|
139
|
+
<rc-splitter
|
|
140
|
+
mode="percent"
|
|
141
|
+
style="
|
|
142
|
+
width: 100%;
|
|
143
|
+
height: 500px;
|
|
144
|
+
--rc-splitter-separator-size: 4px;
|
|
145
|
+
--rc-splitter-separator-color: ButtonFace;
|
|
146
|
+
--rc-splitter-separator-border-inline-start: none;
|
|
147
|
+
--rc-splitter-separator-border-inline-end: none;
|
|
148
|
+
"
|
|
149
|
+
>
|
|
150
|
+
<nav>Sidebar</nav>
|
|
151
|
+
<div slot="secondary">Main content</div>
|
|
152
|
+
</rc-splitter>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Browser support
|
|
158
|
+
|
|
159
|
+
All modern browsers. Requires Web Components support (Chrome 67+, Firefox 63+, Safari 12.1+) and ResizeObserver (Chrome 64+, Firefox 69+, Safari 13.1+).
|
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0.0",
|
|
3
|
+
"readme": "",
|
|
4
|
+
"modules": [
|
|
5
|
+
{
|
|
6
|
+
"kind": "javascript-module",
|
|
7
|
+
"path": "src/define.ts",
|
|
8
|
+
"declarations": [],
|
|
9
|
+
"exports": [
|
|
10
|
+
{
|
|
11
|
+
"kind": "custom-element-definition",
|
|
12
|
+
"name": "rc-splitter",
|
|
13
|
+
"declaration": {
|
|
14
|
+
"name": "RCSplitter",
|
|
15
|
+
"module": "/src/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"kind": "js",
|
|
20
|
+
"name": "*",
|
|
21
|
+
"declaration": {
|
|
22
|
+
"name": "*",
|
|
23
|
+
"module": "src/index.js"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"kind": "javascript-module",
|
|
30
|
+
"path": "src/index.ts",
|
|
31
|
+
"declarations": [],
|
|
32
|
+
"exports": [
|
|
33
|
+
{
|
|
34
|
+
"kind": "js",
|
|
35
|
+
"name": "*",
|
|
36
|
+
"declaration": {
|
|
37
|
+
"name": "*",
|
|
38
|
+
"module": "src/rc-splitter"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"kind": "javascript-module",
|
|
45
|
+
"path": "src/rc-splitter.ts",
|
|
46
|
+
"declarations": [
|
|
47
|
+
{
|
|
48
|
+
"kind": "class",
|
|
49
|
+
"description": "An accessible splitter layout component.\n\nSet `orientation=\"vertical\"` for a vertical splitter",
|
|
50
|
+
"name": "RCSplitter",
|
|
51
|
+
"cssProperties": [
|
|
52
|
+
{
|
|
53
|
+
"description": "Thickness of the separator bar",
|
|
54
|
+
"name": "--rc-splitter-separator-size",
|
|
55
|
+
"default": "6px"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"description": "Length of the drag handle within the separator",
|
|
59
|
+
"name": "--rc-splitter-separator-handle-size",
|
|
60
|
+
"default": "100%"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"description": "Separator background color",
|
|
64
|
+
"name": "--rc-splitter-separator-color",
|
|
65
|
+
"default": "color-mix(in srgb, ButtonBorder 35%, Canvas 65%)"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"description": "Shared separator keyline border",
|
|
69
|
+
"name": "--rc-splitter-keyline",
|
|
70
|
+
"default": "1px solid ButtonBorder"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"description": "Visible handle line color",
|
|
74
|
+
"name": "--rc-splitter-handle-color",
|
|
75
|
+
"default": "ButtonBorder"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"description": "Inline-start border",
|
|
79
|
+
"name": "--rc-splitter-separator-border-inline-start",
|
|
80
|
+
"default": "1px solid ButtonBorder"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"description": "Inline-end border",
|
|
84
|
+
"name": "--rc-splitter-separator-border-inline-end",
|
|
85
|
+
"default": "1px solid ButtonBorder"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"description": "Block-start border (vertical orientation)",
|
|
89
|
+
"name": "--rc-splitter-separator-border-block-start",
|
|
90
|
+
"default": "1px solid ButtonBorder"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"description": "Block-end border (vertical orientation)",
|
|
94
|
+
"name": "--rc-splitter-separator-border-block-end",
|
|
95
|
+
"default": "1px solid ButtonBorder"
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
"cssParts": [
|
|
99
|
+
{
|
|
100
|
+
"description": "Primary pane container",
|
|
101
|
+
"name": "primary"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"description": "Secondary pane container",
|
|
105
|
+
"name": "secondary"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"description": "The separator bar",
|
|
109
|
+
"name": "separator"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"description": "The focusable drag handle",
|
|
113
|
+
"name": "separator-handle"
|
|
114
|
+
}
|
|
115
|
+
],
|
|
116
|
+
"slots": [
|
|
117
|
+
{
|
|
118
|
+
"description": "Primary pane contents",
|
|
119
|
+
"name": ""
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"description": "Secondary pane contents (optional)",
|
|
123
|
+
"name": "secondary"
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
"members": [
|
|
127
|
+
{
|
|
128
|
+
"kind": "field",
|
|
129
|
+
"name": "label",
|
|
130
|
+
"type": {
|
|
131
|
+
"text": "string"
|
|
132
|
+
},
|
|
133
|
+
"default": "\"Splitter\"",
|
|
134
|
+
"description": "Accessible label for this splitter. Default label is 'Splitter'.",
|
|
135
|
+
"attribute": "label"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"kind": "field",
|
|
139
|
+
"name": "orientation",
|
|
140
|
+
"type": {
|
|
141
|
+
"text": "SplitterOrientation"
|
|
142
|
+
},
|
|
143
|
+
"default": "\"horizontal\"",
|
|
144
|
+
"description": "Splitter orientation, for keyboard navigation and initial sizing.",
|
|
145
|
+
"attribute": "orientation",
|
|
146
|
+
"reflects": true
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"kind": "field",
|
|
150
|
+
"name": "mode",
|
|
151
|
+
"type": {
|
|
152
|
+
"text": "SplitterMode"
|
|
153
|
+
},
|
|
154
|
+
"default": "\"length\"",
|
|
155
|
+
"description": "Determines length units for min, max and step attributes, one of either `length` (default) or `percent`",
|
|
156
|
+
"attribute": "mode"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"kind": "field",
|
|
160
|
+
"name": "step",
|
|
161
|
+
"type": {
|
|
162
|
+
"text": "number"
|
|
163
|
+
},
|
|
164
|
+
"default": "1",
|
|
165
|
+
"description": "The step size for resizing, in either pixels or percentage points depending on `mode`.",
|
|
166
|
+
"attribute": "step"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"kind": "field",
|
|
170
|
+
"name": "_defaultValue",
|
|
171
|
+
"type": {
|
|
172
|
+
"text": "number | undefined"
|
|
173
|
+
},
|
|
174
|
+
"privacy": "private"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"kind": "field",
|
|
178
|
+
"name": "_hostValue",
|
|
179
|
+
"type": {
|
|
180
|
+
"text": "number | undefined"
|
|
181
|
+
},
|
|
182
|
+
"privacy": "private"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"kind": "field",
|
|
186
|
+
"name": "value",
|
|
187
|
+
"description": "The current splitter value, corresponding to the separator position, in either pixels or percentage points depending on `mode`.",
|
|
188
|
+
"attribute": "value"
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"kind": "field",
|
|
192
|
+
"name": "defaultValue",
|
|
193
|
+
"description": "Initial uncontrolled splitter value.",
|
|
194
|
+
"attribute": "default-value"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"kind": "method",
|
|
198
|
+
"name": "_setValue",
|
|
199
|
+
"privacy": "private",
|
|
200
|
+
"return": {
|
|
201
|
+
"type": {
|
|
202
|
+
"text": "void"
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
"parameters": [
|
|
206
|
+
{
|
|
207
|
+
"name": "val",
|
|
208
|
+
"type": {
|
|
209
|
+
"text": "number"
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
"name": "dispatch",
|
|
214
|
+
"type": {
|
|
215
|
+
"text": "boolean"
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"kind": "method",
|
|
222
|
+
"name": "_setUserValue",
|
|
223
|
+
"privacy": "private",
|
|
224
|
+
"return": {
|
|
225
|
+
"type": {
|
|
226
|
+
"text": "void"
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
"parameters": [
|
|
230
|
+
{
|
|
231
|
+
"name": "val",
|
|
232
|
+
"type": {
|
|
233
|
+
"text": "number"
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
]
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"kind": "field",
|
|
240
|
+
"name": "_value",
|
|
241
|
+
"type": {
|
|
242
|
+
"text": "number"
|
|
243
|
+
},
|
|
244
|
+
"privacy": "private",
|
|
245
|
+
"default": "0"
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"kind": "field",
|
|
249
|
+
"name": "fixed",
|
|
250
|
+
"type": {
|
|
251
|
+
"text": "boolean"
|
|
252
|
+
},
|
|
253
|
+
"default": "false",
|
|
254
|
+
"description": "Toggles resizing ability",
|
|
255
|
+
"attribute": "fixed"
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"kind": "field",
|
|
259
|
+
"name": "valueText",
|
|
260
|
+
"description": "A human-readable string representation of the value.",
|
|
261
|
+
"readonly": true
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"kind": "field",
|
|
265
|
+
"name": "_minValue",
|
|
266
|
+
"type": {
|
|
267
|
+
"text": "number"
|
|
268
|
+
},
|
|
269
|
+
"privacy": "protected",
|
|
270
|
+
"default": "0"
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
"kind": "field",
|
|
274
|
+
"name": "_maxValue",
|
|
275
|
+
"type": {
|
|
276
|
+
"text": "number"
|
|
277
|
+
},
|
|
278
|
+
"privacy": "protected",
|
|
279
|
+
"default": "0"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"kind": "field",
|
|
283
|
+
"name": "_lastValue",
|
|
284
|
+
"type": {
|
|
285
|
+
"text": "number"
|
|
286
|
+
},
|
|
287
|
+
"privacy": "protected",
|
|
288
|
+
"default": "0",
|
|
289
|
+
"description": "Last valid value, for collapse functionality."
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
"kind": "field",
|
|
293
|
+
"name": "_$primary",
|
|
294
|
+
"type": {
|
|
295
|
+
"text": "HTMLDivElement"
|
|
296
|
+
},
|
|
297
|
+
"privacy": "protected"
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
"kind": "field",
|
|
301
|
+
"name": "_$primaryElements",
|
|
302
|
+
"type": {
|
|
303
|
+
"text": "Array<HTMLElement>"
|
|
304
|
+
},
|
|
305
|
+
"privacy": "protected"
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
"kind": "field",
|
|
309
|
+
"name": "_$secondaryElements",
|
|
310
|
+
"type": {
|
|
311
|
+
"text": "Array<HTMLElement>"
|
|
312
|
+
},
|
|
313
|
+
"privacy": "protected"
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"kind": "field",
|
|
317
|
+
"name": "_initialMax",
|
|
318
|
+
"type": {
|
|
319
|
+
"text": "number"
|
|
320
|
+
},
|
|
321
|
+
"privacy": "protected",
|
|
322
|
+
"default": "0"
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
"kind": "field",
|
|
326
|
+
"name": "_resizeObserver",
|
|
327
|
+
"privacy": "protected",
|
|
328
|
+
"default": "new ResizeObserver(() => this._onResize())"
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
"kind": "method",
|
|
332
|
+
"name": "_onKeyboardResize",
|
|
333
|
+
"privacy": "protected",
|
|
334
|
+
"parameters": [
|
|
335
|
+
{
|
|
336
|
+
"name": "action",
|
|
337
|
+
"type": {
|
|
338
|
+
"text": "KeyboardNavigationAction"
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
]
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
"kind": "method",
|
|
345
|
+
"name": "_onPointerResize",
|
|
346
|
+
"privacy": "protected",
|
|
347
|
+
"parameters": [
|
|
348
|
+
{
|
|
349
|
+
"name": "e",
|
|
350
|
+
"type": {
|
|
351
|
+
"text": "MouseEvent"
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
]
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
"kind": "method",
|
|
358
|
+
"name": "_onPrimaryChange",
|
|
359
|
+
"privacy": "protected",
|
|
360
|
+
"parameters": [
|
|
361
|
+
{
|
|
362
|
+
"name": "_e",
|
|
363
|
+
"type": {
|
|
364
|
+
"text": "Event"
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
]
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
"kind": "method",
|
|
371
|
+
"name": "_onSecondaryChange",
|
|
372
|
+
"privacy": "protected",
|
|
373
|
+
"parameters": [
|
|
374
|
+
{
|
|
375
|
+
"name": "_e",
|
|
376
|
+
"type": {
|
|
377
|
+
"text": "Event"
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
]
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"kind": "method",
|
|
384
|
+
"name": "_measureHostSize",
|
|
385
|
+
"privacy": "private",
|
|
386
|
+
"return": {
|
|
387
|
+
"type": {
|
|
388
|
+
"text": "number"
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
"parameters": [
|
|
392
|
+
{
|
|
393
|
+
"name": "axis",
|
|
394
|
+
"type": {
|
|
395
|
+
"text": "\"inline\" | \"block\""
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
]
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
"kind": "method",
|
|
402
|
+
"name": "_onResize",
|
|
403
|
+
"privacy": "protected"
|
|
404
|
+
}
|
|
405
|
+
],
|
|
406
|
+
"events": [
|
|
407
|
+
{
|
|
408
|
+
"name": "rc-splitter-change",
|
|
409
|
+
"type": {
|
|
410
|
+
"text": "CustomEvent"
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
],
|
|
414
|
+
"attributes": [
|
|
415
|
+
{
|
|
416
|
+
"name": "label",
|
|
417
|
+
"type": {
|
|
418
|
+
"text": "string"
|
|
419
|
+
},
|
|
420
|
+
"default": "\"Splitter\"",
|
|
421
|
+
"description": "Accessible label for this splitter. Default label is 'Splitter'.",
|
|
422
|
+
"fieldName": "label"
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
"name": "orientation",
|
|
426
|
+
"type": {
|
|
427
|
+
"text": "SplitterOrientation"
|
|
428
|
+
},
|
|
429
|
+
"default": "\"horizontal\"",
|
|
430
|
+
"description": "Splitter orientation, for keyboard navigation and initial sizing.",
|
|
431
|
+
"fieldName": "orientation"
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
"name": "mode",
|
|
435
|
+
"type": {
|
|
436
|
+
"text": "SplitterMode"
|
|
437
|
+
},
|
|
438
|
+
"default": "\"length\"",
|
|
439
|
+
"description": "Determines length units for min, max and step attributes, one of either `length` (default) or `percent`",
|
|
440
|
+
"fieldName": "mode"
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
"name": "step",
|
|
444
|
+
"type": {
|
|
445
|
+
"text": "number"
|
|
446
|
+
},
|
|
447
|
+
"default": "1",
|
|
448
|
+
"description": "The step size for resizing, in either pixels or percentage points depending on `mode`.",
|
|
449
|
+
"fieldName": "step"
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
"name": "value",
|
|
453
|
+
"description": "The current splitter value, corresponding to the separator position, in either pixels or percentage points depending on `mode`.",
|
|
454
|
+
"fieldName": "value"
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
"name": "default-value",
|
|
458
|
+
"description": "Initial uncontrolled splitter value.",
|
|
459
|
+
"fieldName": "defaultValue"
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
"name": "fixed",
|
|
463
|
+
"type": {
|
|
464
|
+
"text": "boolean"
|
|
465
|
+
},
|
|
466
|
+
"default": "false",
|
|
467
|
+
"description": "Toggles resizing ability",
|
|
468
|
+
"fieldName": "fixed"
|
|
469
|
+
}
|
|
470
|
+
],
|
|
471
|
+
"superclass": {
|
|
472
|
+
"name": "LitElement",
|
|
473
|
+
"package": "lit"
|
|
474
|
+
},
|
|
475
|
+
"tagName": "rc-splitter",
|
|
476
|
+
"customElement": true
|
|
477
|
+
}
|
|
478
|
+
],
|
|
479
|
+
"exports": [
|
|
480
|
+
{
|
|
481
|
+
"kind": "js",
|
|
482
|
+
"name": "RCSplitter",
|
|
483
|
+
"declaration": {
|
|
484
|
+
"name": "RCSplitter",
|
|
485
|
+
"module": "src/rc-splitter.ts"
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
"kind": "js",
|
|
490
|
+
"name": "default",
|
|
491
|
+
"declaration": {
|
|
492
|
+
"name": "RCSplitter",
|
|
493
|
+
"module": "src/rc-splitter.ts"
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
]
|
|
497
|
+
}
|
|
498
|
+
]
|
|
499
|
+
}
|
package/dist/demo.css
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
*, *::before, *::after {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
:root {
|
|
6
|
+
color-scheme: light dark;
|
|
7
|
+
--rc-accent: Highlight; /* Chrome doesn't support AccentColor on the open web */
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@supports (color: AccentColor) {
|
|
11
|
+
:root {
|
|
12
|
+
--rc-accent: AccentColor;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
[data-theme="light"] { color-scheme: light; }
|
|
17
|
+
[data-theme="dark"] { color-scheme: dark; }
|
|
18
|
+
|
|
19
|
+
[data-theme="solarized-light"] {
|
|
20
|
+
color-scheme: light;
|
|
21
|
+
--rc-surface: #fdf6e3;
|
|
22
|
+
--rc-text: #657b83;
|
|
23
|
+
--rc-border: 1px solid #93a1a1;
|
|
24
|
+
--rc-shadow: 0 2px 8px rgba(0, 0, 0, .12);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
[data-theme="solarized-dark"] {
|
|
28
|
+
color-scheme: dark;
|
|
29
|
+
--rc-surface: #002b36;
|
|
30
|
+
--rc-text: #839496;
|
|
31
|
+
--rc-border: 1px solid #586e75;
|
|
32
|
+
--rc-shadow: 0 2px 8px rgba(0, 0, 0, .3);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
body {
|
|
36
|
+
font-family: system-ui, sans-serif;
|
|
37
|
+
margin: 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.demo-page {
|
|
41
|
+
max-width: 60rem;
|
|
42
|
+
margin: 0 auto;
|
|
43
|
+
padding: 2rem 1.5rem;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.demo-controls {
|
|
47
|
+
display: flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
gap: 1rem;
|
|
50
|
+
margin-bottom: 2rem;
|
|
51
|
+
padding-bottom: 1rem;
|
|
52
|
+
border-bottom: 1px solid ButtonBorder;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.demo-controls .demo-title {
|
|
56
|
+
flex: 1;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.demo-controls h1 {
|
|
60
|
+
margin: 0 0 0.15rem;
|
|
61
|
+
font-size: 1.5rem;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.demo-controls a {
|
|
65
|
+
font-size: 0.8rem;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.demo-section {
|
|
69
|
+
margin-bottom: 2rem;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.demo-section h2 {
|
|
73
|
+
margin: 0 0 0.5rem;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.theme-picker {
|
|
77
|
+
padding: 0.35em 0.75em;
|
|
78
|
+
font-family: inherit;
|
|
79
|
+
font-size: 0.8rem;
|
|
80
|
+
cursor: pointer;
|
|
81
|
+
border: 1px solid ButtonBorder;
|
|
82
|
+
border-radius: 4px;
|
|
83
|
+
background: Canvas;
|
|
84
|
+
color: CanvasText;
|
|
85
|
+
}
|
package/dist/demo.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const THEMES = ['', 'light', 'dark', 'solarized-light', 'solarized-dark'];
|
|
2
|
+
const LABELS = ['Auto', 'Light', 'Dark', 'Solarized ☀', 'Solarized ☾'];
|
|
3
|
+
|
|
4
|
+
const stored = localStorage.getItem('rc-demo-theme') ?? '';
|
|
5
|
+
applyTheme(stored);
|
|
6
|
+
|
|
7
|
+
function applyTheme(theme) {
|
|
8
|
+
if (theme) {
|
|
9
|
+
document.documentElement.dataset.theme = theme;
|
|
10
|
+
} else {
|
|
11
|
+
delete document.documentElement.dataset.theme;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function currentIndex() {
|
|
16
|
+
const current = document.documentElement.dataset.theme ?? '';
|
|
17
|
+
const idx = THEMES.indexOf(current);
|
|
18
|
+
return idx === -1 ? 0 : idx;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function updateButtons() {
|
|
22
|
+
const label = LABELS[currentIndex()];
|
|
23
|
+
document.querySelectorAll('.theme-picker').forEach((btn) => {
|
|
24
|
+
btn.textContent = label;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
window.cycleTheme = function () {
|
|
29
|
+
const next = THEMES[(currentIndex() + 1) % THEMES.length];
|
|
30
|
+
applyTheme(next);
|
|
31
|
+
localStorage.setItem('rc-demo-theme', next);
|
|
32
|
+
updateButtons();
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
36
|
+
updateButtons();
|
|
37
|
+
document.querySelectorAll('.theme-picker').forEach((btn) => {
|
|
38
|
+
btn.addEventListener('click', window.cycleTheme);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { css as c, LitElement as _, html as m } from "lit";
|
|
2
|
+
import { property as l, state as h, query as y, queryAssignedElements as d } from "lit/decorators.js";
|
|
3
|
+
import { keyNavigation as v, mouseMove as b } from "@rcarls/rc-common";
|
|
4
|
+
const f = c`
|
|
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) doens'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
|
+
|
|
48
|
+
:host([orientation='vertical']) & {
|
|
49
|
+
flex-direction: row;
|
|
50
|
+
border-left: unset;
|
|
51
|
+
border-right: unset;
|
|
52
|
+
border-top: var(--rc-splitter-separator-border-block-start, var(--rc-splitter-keyline, 1px solid ButtonBorder));
|
|
53
|
+
border-bottom: var(--rc-splitter-separator-border-block-end, var(--rc-splitter-keyline, 1px solid ButtonBorder));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
#separator-handle {
|
|
58
|
+
width: 100%;
|
|
59
|
+
height: var(--rc-splitter-separator-handle-size, 100%);
|
|
60
|
+
background:
|
|
61
|
+
linear-gradient(
|
|
62
|
+
to bottom,
|
|
63
|
+
transparent,
|
|
64
|
+
transparent calc(50% - 1px),
|
|
65
|
+
var(--rc-splitter-handle-color, ButtonBorder) calc(50% - 1px),
|
|
66
|
+
var(--rc-splitter-handle-color, ButtonBorder) calc(50% + 1px),
|
|
67
|
+
transparent calc(50% + 1px),
|
|
68
|
+
transparent
|
|
69
|
+
);
|
|
70
|
+
cursor: col-resize;
|
|
71
|
+
|
|
72
|
+
:host([orientation='vertical']) & {
|
|
73
|
+
width: var(--rc-splitter-separator-handle-size, 100%);
|
|
74
|
+
height: 100%;
|
|
75
|
+
background:
|
|
76
|
+
linear-gradient(
|
|
77
|
+
to right,
|
|
78
|
+
transparent,
|
|
79
|
+
transparent calc(50% - 1px),
|
|
80
|
+
var(--rc-splitter-handle-color, ButtonBorder) calc(50% - 1px),
|
|
81
|
+
var(--rc-splitter-handle-color, ButtonBorder) calc(50% + 1px),
|
|
82
|
+
transparent calc(50% + 1px),
|
|
83
|
+
transparent
|
|
84
|
+
);
|
|
85
|
+
cursor: row-resize;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
:host([fixed]) {
|
|
89
|
+
pointer-events: none;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
#primary,
|
|
94
|
+
#secondary {
|
|
95
|
+
overflow: hidden;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
#primary {
|
|
99
|
+
grid-column: primary;
|
|
100
|
+
flex: 0 0 auto;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
#secondary {
|
|
104
|
+
grid-column: secondary;
|
|
105
|
+
flex: 1;
|
|
106
|
+
}
|
|
107
|
+
`;
|
|
108
|
+
var x = Object.defineProperty, g = Object.getOwnPropertyDescriptor, i = (p, e, t, a) => {
|
|
109
|
+
for (var s = a > 1 ? void 0 : a ? g(e, t) : e, n = p.length - 1, o; n >= 0; n--)
|
|
110
|
+
(o = p[n]) && (s = (a ? o(e, t, s) : o(s)) || s);
|
|
111
|
+
return a && s && x(e, t, s), s;
|
|
112
|
+
};
|
|
113
|
+
const u = class u extends _ {
|
|
114
|
+
constructor() {
|
|
115
|
+
super(...arguments), this.label = "Splitter", this.orientation = "horizontal", this.mode = "length", this.step = 1, this._value = 0, this.fixed = !1, this._minValue = 0, this._maxValue = 0, this._lastValue = 0, this._initialMax = 0, this._resizeObserver = new ResizeObserver(() => this._onResize());
|
|
116
|
+
}
|
|
117
|
+
set value(e) {
|
|
118
|
+
const t = this._hostValue;
|
|
119
|
+
this._hostValue = e, this._initialMax && this._setValue(e, !1), this.requestUpdate("value", t);
|
|
120
|
+
}
|
|
121
|
+
/** The current splitter value, corresponding to the separator position, in either pixels or percentage points depending on `mode`. */
|
|
122
|
+
get value() {
|
|
123
|
+
return this._value;
|
|
124
|
+
}
|
|
125
|
+
set defaultValue(e) {
|
|
126
|
+
const t = this._defaultValue;
|
|
127
|
+
this._defaultValue = e, !this._initialMax && this._hostValue === void 0 && e !== void 0 && this._setValue(e, !1), this.requestUpdate("defaultValue", t);
|
|
128
|
+
}
|
|
129
|
+
/** Initial uncontrolled splitter value. */
|
|
130
|
+
get defaultValue() {
|
|
131
|
+
return this._defaultValue;
|
|
132
|
+
}
|
|
133
|
+
_setValue(e, t) {
|
|
134
|
+
const a = this._value;
|
|
135
|
+
this._lastValue = a, this._value = Math.min(
|
|
136
|
+
Math.max(Math.round(e / this.step) * this.step, this._minValue),
|
|
137
|
+
this._maxValue
|
|
138
|
+
), t && this._value !== a && this.dispatchEvent(
|
|
139
|
+
new CustomEvent("rc-splitter-change", {
|
|
140
|
+
bubbles: !0,
|
|
141
|
+
composed: !0,
|
|
142
|
+
detail: { value: this._value, valueText: this.valueText }
|
|
143
|
+
})
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
_setUserValue(e) {
|
|
147
|
+
this._hostValue = void 0, this._setValue(e, !0);
|
|
148
|
+
}
|
|
149
|
+
/** A human-readable string representation of the value. */
|
|
150
|
+
get valueText() {
|
|
151
|
+
return `${this.value}${this.mode === "length" ? "px" : "%"}`;
|
|
152
|
+
}
|
|
153
|
+
_onKeyboardResize(e) {
|
|
154
|
+
if (!this.fixed)
|
|
155
|
+
switch (e) {
|
|
156
|
+
case "next":
|
|
157
|
+
this._setUserValue(this.value + this.step);
|
|
158
|
+
break;
|
|
159
|
+
case "prev":
|
|
160
|
+
this._setUserValue(this.value - this.step);
|
|
161
|
+
break;
|
|
162
|
+
case "start":
|
|
163
|
+
this._setUserValue(0);
|
|
164
|
+
break;
|
|
165
|
+
case "end":
|
|
166
|
+
this._setUserValue(this._maxValue);
|
|
167
|
+
break;
|
|
168
|
+
case "toggle":
|
|
169
|
+
this._setUserValue(this.value === 0 ? this._lastValue : 0);
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
_onPointerResize(e) {
|
|
174
|
+
if (this.fixed)
|
|
175
|
+
return;
|
|
176
|
+
const t = this.getBoundingClientRect();
|
|
177
|
+
this.orientation === "vertical" ? this._setUserValue(
|
|
178
|
+
(e.clientY - t.top) / t.height * this._maxValue
|
|
179
|
+
) : this._setUserValue(
|
|
180
|
+
(e.clientX - t.left) / t.width * this._maxValue
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
_onPrimaryChange(e) {
|
|
184
|
+
queueMicrotask(() => {
|
|
185
|
+
this._$primaryElements.length < 2 || this._$primaryElements.slice(1).forEach((t) => t.setAttribute("slot", "secondary"));
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
_onSecondaryChange(e) {
|
|
189
|
+
queueMicrotask(() => {
|
|
190
|
+
!this._$secondaryElements.length || this._$primaryElements.length || this._$secondaryElements.at(0)?.removeAttribute("slot");
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
_measureHostSize(e) {
|
|
194
|
+
const t = this.getBoundingClientRect(), a = e === "inline" ? t.width : t.height;
|
|
195
|
+
if (a > 0)
|
|
196
|
+
return Math.ceil(a);
|
|
197
|
+
const s = getComputedStyle(this), n = e === "inline" ? s.width : s.height, o = Number.parseFloat(n);
|
|
198
|
+
return Number.isFinite(o) ? Math.ceil(o) : 0;
|
|
199
|
+
}
|
|
200
|
+
_onResize() {
|
|
201
|
+
const e = this._$primaryElements.at(0), t = this._$primary.style.getPropertyValue("display");
|
|
202
|
+
globalThis.requestAnimationFrame(() => {
|
|
203
|
+
this._$primary.style.setProperty("display", "contents");
|
|
204
|
+
const a = e?.getBoundingClientRect() ?? this.getBoundingClientRect();
|
|
205
|
+
this.mode === "length" ? this._maxValue = this.orientation === "horizontal" ? (
|
|
206
|
+
// For horizontal splitters, just take the host width...
|
|
207
|
+
this._measureHostSize("inline")
|
|
208
|
+
) : (
|
|
209
|
+
// ...otherwise try to use the first lightDOM element's auto height, and cache it
|
|
210
|
+
this._initialMax || Math.ceil(a.height) || this._measureHostSize("block")
|
|
211
|
+
) : this._maxValue = 100, this._initialMax ? this._hostValue !== void 0 ? this._setValue(this._hostValue, !1) : this._setValue(this.value, !1) : (this._initialMax = this._maxValue, this._setValue(
|
|
212
|
+
this._hostValue ?? this.defaultValue ?? this._maxValue / 2,
|
|
213
|
+
!1
|
|
214
|
+
)), t ? this._$primary.style.setProperty("display", t) : this._$primary.style.removeProperty("display");
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
connectedCallback() {
|
|
218
|
+
super.connectedCallback(), this._resizeObserver.observe(this);
|
|
219
|
+
}
|
|
220
|
+
disconnectedCallback() {
|
|
221
|
+
this._resizeObserver.disconnect(), super.disconnectedCallback();
|
|
222
|
+
}
|
|
223
|
+
firstUpdated() {
|
|
224
|
+
this._onResize();
|
|
225
|
+
}
|
|
226
|
+
render() {
|
|
227
|
+
return m`
|
|
228
|
+
<div
|
|
229
|
+
id="primary"
|
|
230
|
+
part="primary"
|
|
231
|
+
aria-label=${this.label}
|
|
232
|
+
style=${this.orientation === "horizontal" ? `width: ${this.valueText}` : `height: ${this.valueText}`}
|
|
233
|
+
?hidden=${this.value === this._minValue}
|
|
234
|
+
>
|
|
235
|
+
<slot @slotchange=${this._onPrimaryChange}></slot>
|
|
236
|
+
</div>
|
|
237
|
+
|
|
238
|
+
<div id="separator" part="separator">
|
|
239
|
+
<div
|
|
240
|
+
id="separator-handle"
|
|
241
|
+
role="separator"
|
|
242
|
+
tabindex="0"
|
|
243
|
+
part="separator-handle"
|
|
244
|
+
aria-labelledby="primary"
|
|
245
|
+
aria-controls="primary"
|
|
246
|
+
aria-orientation=${this.orientation}
|
|
247
|
+
aria-valuenow=${this.value}
|
|
248
|
+
aria-valuetext=${this.valueText}
|
|
249
|
+
aria-valuemin=${this._minValue}
|
|
250
|
+
aria-valuemax=${this._maxValue}
|
|
251
|
+
${v(this._onKeyboardResize)}
|
|
252
|
+
${b(this._onPointerResize)}
|
|
253
|
+
?hidden=${!this._$secondaryElements.length}
|
|
254
|
+
></div>
|
|
255
|
+
</div>
|
|
256
|
+
|
|
257
|
+
<aside
|
|
258
|
+
id="secondary"
|
|
259
|
+
part="secondary"
|
|
260
|
+
?hidden=${!this._$secondaryElements.length || this.value === this._maxValue}
|
|
261
|
+
>
|
|
262
|
+
<slot name="secondary" @slotchange=${this._onSecondaryChange}></slot>
|
|
263
|
+
</aside>
|
|
264
|
+
`;
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
u.styles = [f];
|
|
268
|
+
let r = u;
|
|
269
|
+
i([
|
|
270
|
+
l({ type: String })
|
|
271
|
+
], r.prototype, "label", 2);
|
|
272
|
+
i([
|
|
273
|
+
l({ type: String, reflect: !0 })
|
|
274
|
+
], r.prototype, "orientation", 2);
|
|
275
|
+
i([
|
|
276
|
+
l({ type: String })
|
|
277
|
+
], r.prototype, "mode", 2);
|
|
278
|
+
i([
|
|
279
|
+
l({ type: Number })
|
|
280
|
+
], r.prototype, "step", 2);
|
|
281
|
+
i([
|
|
282
|
+
l({ type: Number })
|
|
283
|
+
], r.prototype, "value", 1);
|
|
284
|
+
i([
|
|
285
|
+
l({ type: Number, attribute: "default-value" })
|
|
286
|
+
], r.prototype, "defaultValue", 1);
|
|
287
|
+
i([
|
|
288
|
+
h()
|
|
289
|
+
], r.prototype, "_value", 2);
|
|
290
|
+
i([
|
|
291
|
+
l({ type: Boolean })
|
|
292
|
+
], r.prototype, "fixed", 2);
|
|
293
|
+
i([
|
|
294
|
+
h()
|
|
295
|
+
], r.prototype, "_minValue", 2);
|
|
296
|
+
i([
|
|
297
|
+
h()
|
|
298
|
+
], r.prototype, "_maxValue", 2);
|
|
299
|
+
i([
|
|
300
|
+
h()
|
|
301
|
+
], r.prototype, "_lastValue", 2);
|
|
302
|
+
i([
|
|
303
|
+
y("#primary", !0)
|
|
304
|
+
], r.prototype, "_$primary", 2);
|
|
305
|
+
i([
|
|
306
|
+
d()
|
|
307
|
+
], r.prototype, "_$primaryElements", 2);
|
|
308
|
+
i([
|
|
309
|
+
d({ slot: "secondary" })
|
|
310
|
+
], r.prototype, "_$secondaryElements", 2);
|
|
311
|
+
export {
|
|
312
|
+
r as R
|
|
313
|
+
};
|
|
314
|
+
//# sourceMappingURL=rc-splitter-CkpiDBPA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-splitter-CkpiDBPA.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) doens'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\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 #separator-handle {\n width: 100%;\n height: var(--rc-splitter-separator-handle-size, 100%);\n background:\n linear-gradient(\n to bottom,\n transparent,\n transparent calc(50% - 1px),\n var(--rc-splitter-handle-color, ButtonBorder) calc(50% - 1px),\n var(--rc-splitter-handle-color, ButtonBorder) calc(50% + 1px),\n transparent calc(50% + 1px),\n transparent\n );\n cursor: col-resize;\n\n :host([orientation='vertical']) & {\n width: var(--rc-splitter-separator-handle-size, 100%);\n height: 100%;\n background:\n linear-gradient(\n to right,\n transparent,\n transparent calc(50% - 1px),\n var(--rc-splitter-handle-color, ButtonBorder) calc(50% - 1px),\n var(--rc-splitter-handle-color, ButtonBorder) calc(50% + 1px),\n transparent calc(50% + 1px),\n transparent\n );\n cursor: row-resize;\n }\n\n :host([fixed]) {\n pointer-events: none;\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 } from \"lit\";\nimport {\n property,\n state,\n query,\n queryAssignedElements,\n} from \"lit/decorators.js\";\n\nimport {\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 * An accessible splitter layout component.\n *\n * Set `orientation=\"vertical\"` for a vertical splitter\n *\n * @slot - Primary pane contents\n * @slot secondary - Secondary pane contents (optional)\n *\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/\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 within the separator\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] - Visible handle line 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 */\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 private _defaultValue: number | undefined;\n private _hostValue: number | undefined;\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 private _setValue(val: number, dispatch: boolean): void {\n const oldValue = this._value;\n this._lastValue = oldValue;\n\n this._value = Math.min(\n Math.max(Math.round(val / this.step) * this.step, this._minValue),\n this._maxValue,\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._hostValue = undefined;\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 /** 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 \"start\":\n this._setUserValue(0);\n break;\n case \"end\":\n this._setUserValue(this._maxValue);\n break;\n case \"toggle\":\n this._setUserValue(this.value === 0 ? this._lastValue : 0);\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 this._maxValue =\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 } 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._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 <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}\n aria-valuenow=${this.value}\n aria-valuetext=${this.valueText}\n aria-valuemin=${this._minValue}\n aria-valuemax=${this._maxValue}\n ${keyNavigation(this._onKeyboardResize)}\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","dispatch","action","clientRect","_e","el","axis","measuredSize","computedStyle","fallbackSize","parsedFallbackSize","prevStyle","html","keyNavigation","mouseMove","RCSplitter","__decorateClass","property","state","query","queryAssignedElements"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-splitter-define.js","sources":["../src/define.ts"],"sourcesContent":["import { RCSplitter } from './index.js';\n\ncustomElements.get('rc-splitter') || customElements.define('rc-splitter', RCSplitter);\n\nexport * from './index.js';\n"],"names":["RCSplitter"],"mappings":";AAEA,eAAe,IAAI,aAAa,KAAK,eAAe,OAAO,eAAeA,CAAU;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-splitter.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './rc-splitter';
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
import { KeyboardNavigationAction } from '@rcarls/rc-common';
|
|
3
|
+
type SplitterOrientation = "horizontal" | "vertical";
|
|
4
|
+
type SplitterMode = "length" | "percent";
|
|
5
|
+
declare global {
|
|
6
|
+
interface HTMLElementTagNameMap {
|
|
7
|
+
"rc-splitter": RCSplitter;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* An accessible splitter layout component.
|
|
12
|
+
*
|
|
13
|
+
* Set `orientation="vertical"` for a vertical splitter
|
|
14
|
+
*
|
|
15
|
+
* @slot - Primary pane contents
|
|
16
|
+
* @slot secondary - Secondary pane contents (optional)
|
|
17
|
+
*
|
|
18
|
+
* @see https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/
|
|
19
|
+
* @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
|
|
21
|
+
* @cssprop [--rc-splitter-separator-color=color-mix(in srgb, ButtonBorder 35%, Canvas 65%)] - Separator background color
|
|
22
|
+
* @cssprop [--rc-splitter-keyline=1px solid ButtonBorder] - Shared separator keyline border
|
|
23
|
+
* @cssprop [--rc-splitter-handle-color=ButtonBorder] - Visible handle line color
|
|
24
|
+
* @cssprop [--rc-splitter-separator-border-inline-start=1px solid ButtonBorder] - Inline-start border
|
|
25
|
+
* @cssprop [--rc-splitter-separator-border-inline-end=1px solid ButtonBorder] - Inline-end border
|
|
26
|
+
* @cssprop [--rc-splitter-separator-border-block-start=1px solid ButtonBorder] - Block-start border (vertical orientation)
|
|
27
|
+
* @cssprop [--rc-splitter-separator-border-block-end=1px solid ButtonBorder] - Block-end border (vertical orientation)
|
|
28
|
+
* @csspart primary - Primary pane container
|
|
29
|
+
* @csspart secondary - Secondary pane container
|
|
30
|
+
* @csspart separator - The separator bar
|
|
31
|
+
* @csspart separator-handle - The focusable drag handle
|
|
32
|
+
*/
|
|
33
|
+
export declare class RCSplitter extends LitElement {
|
|
34
|
+
static styles: import('lit').CSSResult[];
|
|
35
|
+
/** Accessible label for this splitter. Default label is 'Splitter'. */
|
|
36
|
+
label: string;
|
|
37
|
+
/** Splitter orientation, for keyboard navigation and initial sizing. */
|
|
38
|
+
orientation: SplitterOrientation;
|
|
39
|
+
/** Determines length units for min, max and step attributes, one of either `length` (default) or `percent` */
|
|
40
|
+
mode: SplitterMode;
|
|
41
|
+
/** The step size for resizing, in either pixels or percentage points depending on `mode`. */
|
|
42
|
+
step: number;
|
|
43
|
+
private _defaultValue;
|
|
44
|
+
private _hostValue;
|
|
45
|
+
/** The current splitter value. Host writes update silently. */
|
|
46
|
+
set value(val: number);
|
|
47
|
+
/** The current splitter value, corresponding to the separator position, in either pixels or percentage points depending on `mode`. */
|
|
48
|
+
get value(): number;
|
|
49
|
+
/** Initial uncontrolled splitter value. */
|
|
50
|
+
set defaultValue(val: number | undefined);
|
|
51
|
+
/** Initial uncontrolled splitter value. */
|
|
52
|
+
get defaultValue(): number | undefined;
|
|
53
|
+
private _setValue;
|
|
54
|
+
private _setUserValue;
|
|
55
|
+
private _value;
|
|
56
|
+
/** Toggles resizing ability */
|
|
57
|
+
fixed: boolean;
|
|
58
|
+
/** A human-readable string representation of the value. */
|
|
59
|
+
get valueText(): string;
|
|
60
|
+
protected _minValue: number;
|
|
61
|
+
protected _maxValue: number;
|
|
62
|
+
/** Last valid value, for collapse functionality. */
|
|
63
|
+
protected _lastValue: number;
|
|
64
|
+
protected _$primary: HTMLDivElement;
|
|
65
|
+
protected _$primaryElements: Array<HTMLElement>;
|
|
66
|
+
protected _$secondaryElements: Array<HTMLElement>;
|
|
67
|
+
protected _initialMax: number;
|
|
68
|
+
protected _resizeObserver: ResizeObserver;
|
|
69
|
+
protected _onKeyboardResize(action: KeyboardNavigationAction): void;
|
|
70
|
+
protected _onPointerResize(e: MouseEvent): void;
|
|
71
|
+
protected _onPrimaryChange(_e: Event): void;
|
|
72
|
+
protected _onSecondaryChange(_e: Event): void;
|
|
73
|
+
private _measureHostSize;
|
|
74
|
+
protected _onResize(): void;
|
|
75
|
+
connectedCallback(): void;
|
|
76
|
+
disconnectedCallback(): void;
|
|
77
|
+
firstUpdated(): void;
|
|
78
|
+
render(): import('lit').TemplateResult<1>;
|
|
79
|
+
}
|
|
80
|
+
export default RCSplitter;
|
|
File without changes
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rcarls/rc-splitter",
|
|
3
|
+
"publishConfig": {
|
|
4
|
+
"access": "public"
|
|
5
|
+
},
|
|
6
|
+
"version": "0.1.0",
|
|
7
|
+
"description": "Headless resizable pane splitter web component built with Lit",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/richardcarls/rc-webcomponents.git",
|
|
11
|
+
"directory": "packages/rc-splitter"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/richardcarls/rc-webcomponents#readme",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"module": "./dist/rc-splitter.js",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"import": {
|
|
23
|
+
"types": "./dist/types/packages/rc-splitter/src/index.d.ts",
|
|
24
|
+
"default": "./dist/rc-splitter.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"./define": {
|
|
28
|
+
"import": {
|
|
29
|
+
"types": "./dist/types/packages/rc-splitter/src/define.d.ts",
|
|
30
|
+
"default": "./dist/rc-splitter-define.js"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"types": "./dist/types/packages/rc-splitter/src/index.d.ts",
|
|
35
|
+
"sideEffects": [
|
|
36
|
+
"./dist/rc-splitter-define.js"
|
|
37
|
+
],
|
|
38
|
+
"customElements": "dist/custom-elements.json",
|
|
39
|
+
"scripts": {
|
|
40
|
+
"dev": "vite",
|
|
41
|
+
"build": "tsc && vite build && cem analyze",
|
|
42
|
+
"cem:analyze": "cem analyze",
|
|
43
|
+
"preview": "vite preview",
|
|
44
|
+
"test:browser": "vitest",
|
|
45
|
+
"test:browser:chrome": "vitest --project=chromium",
|
|
46
|
+
"test:browser:firefox": "vitest --project=firefox",
|
|
47
|
+
"yalc:publish": "yalc publish --push"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@rcarls/rc-common": "workspace:^"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@custom-elements-manifest/analyzer": "0.11.0",
|
|
54
|
+
"@guanghechen/rollup-plugin-copy": "^6.0.9",
|
|
55
|
+
"@vitest/browser-playwright": "4.1.5",
|
|
56
|
+
"lit": "^3.0.0",
|
|
57
|
+
"playwright": "^1.56.0",
|
|
58
|
+
"rollup": "^4.60.2",
|
|
59
|
+
"typescript": "~5.9.3",
|
|
60
|
+
"vite": "^7.1.7",
|
|
61
|
+
"vite-plugin-dts": "^4.5.4",
|
|
62
|
+
"vitest": "^4.0.6",
|
|
63
|
+
"vitest-browser-lit": "^1.0.1"
|
|
64
|
+
},
|
|
65
|
+
"peerDependencies": {
|
|
66
|
+
"lit": "^3.0.0"
|
|
67
|
+
}
|
|
68
|
+
}
|