Skip to content

Commit e1af1a1

Browse files
committed
Refactor min/max size to use unit prop
1 parent 28c51cb commit e1af1a1

File tree

1 file changed

+77
-36
lines changed

1 file changed

+77
-36
lines changed

src/SplitPanel.vue

Lines changed: 77 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,17 @@ export interface SplitPanelProps {
1818
/** Disable the manual resizing of the panels */
1919
disabled?: boolean;
2020
21-
/** The minimum allowed size of the primary panel. Accepts CSS like `"15px"` or `"5em"` */
22-
minSize?: string;
21+
/** The minimum allowed size of the primary panel */
22+
minSize?: number;
2323
24-
/** The maximum allowed size of the primary panel. Accepts CSS like `"15px"` or `"5em"` */
25-
maxSize?: string;
24+
/** The maximum allowed size of the primary panel */
25+
maxSize?: number;
2626
2727
/** Whether to allow the primary panel to be collapsed on enter key on divider or when the collapse threshold is met */
2828
collapsible?: boolean;
29+
30+
/** How far to drag beyond the minSize to collapse/expand the primary panel */
31+
collapseThreshold?: number;
2932
}
3033
</script>
3134

@@ -40,8 +43,8 @@ const props = withDefaults(defineProps<SplitPanelProps>(), {
4043
orientation: 'horizontal',
4144
disabled: false,
4245
snapThreshold: 12,
43-
minSize: '0px',
44-
maxSize: '100%',
46+
minSize: 0,
47+
maxSize: 100,
4548
dividerHitArea: '12px',
4649
sizeUnit: '%',
4750
direction: 'ltr',
@@ -57,62 +60,90 @@ const componentSize = computed(() => props.orientation === 'horizontal' ? compon
5760
const { width: dividerWidth, height: dividerHeight } = useElementSize(dividerEl);
5861
const dividerSize = computed(() => props.orientation === 'horizontal' ? dividerWidth.value : dividerHeight.value);
5962
60-
const { x: dividerX, y: dividerY } = useDraggable(dividerEl, { containerElement: panelEl });
61-
62-
/** Whether the primary column is collapsed or not */
63-
const collapsed = defineModel<boolean>('collapsed', { default: false });
64-
6563
/** Size of the primary panel in either percentages or pixels as defined by the sizeUnit property */
66-
const primaryPanelSize = defineModel<number>('size', { default: 50 });
64+
const size = defineModel<number>('size', { default: 50 });
6765
68-
const primaryPanelSizePercentage = computed({
66+
const sizePercentage = computed({
6967
get() {
70-
if (props.sizeUnit === '%') return primaryPanelSize.value;
71-
return pixelsToPercentage(componentSize.value, primaryPanelSize.value);
68+
if (props.sizeUnit === '%') return size.value;
69+
return pixelsToPercentage(componentSize.value, size.value);
7270
},
7371
set(newValue: number) {
7472
if (props.sizeUnit === '%') {
75-
primaryPanelSize.value = newValue;
73+
size.value = newValue;
7674
}
7775
else {
78-
primaryPanelSize.value = percentageToPixels(componentSize.value, newValue);
76+
size.value = percentageToPixels(componentSize.value, newValue);
7977
}
8078
},
8179
});
8280
83-
const primaryPanelSizePixels = computed({
81+
const sizePixels = computed({
8482
get() {
85-
if (props.sizeUnit === 'px') return primaryPanelSize.value;
86-
return percentageToPixels(componentSize.value, primaryPanelSize.value);
83+
if (props.sizeUnit === 'px') return size.value;
84+
return percentageToPixels(componentSize.value, size.value);
8785
},
8886
set(newValue: number) {
8987
if (props.sizeUnit === 'px') {
90-
primaryPanelSize.value = newValue;
88+
size.value = newValue;
9189
}
9290
else {
93-
primaryPanelSize.value = pixelsToPercentage(componentSize.value, newValue);
91+
size.value = pixelsToPercentage(componentSize.value, newValue);
9492
}
9593
},
9694
});
9795
98-
let expandedPrimaryPanelSizePercentage = 0;
96+
const minSizePercentage = computed(() => {
97+
if (props.minSize === undefined) return;
98+
99+
if (props.sizeUnit === '%') return props.minSize;
100+
return pixelsToPercentage(componentSize.value, props.minSize);
101+
});
102+
103+
const minSizePixels = computed(() => {
104+
if (props.minSize === undefined) return;
105+
106+
if (props.sizeUnit === 'px') return props.minSize;
107+
return percentageToPixels(componentSize.value, props.minSize);
108+
});
109+
110+
const maxSizePercentage = computed(() => {
111+
if (props.maxSize === undefined) return;
112+
113+
if (props.sizeUnit === '%') return props.maxSize;
114+
return pixelsToPercentage(componentSize.value, props.maxSize);
115+
});
116+
117+
const maxSizePixels = computed(() => {
118+
if (props.maxSize === undefined) return;
119+
120+
if (props.sizeUnit === 'px') return props.maxSize;
121+
return percentageToPixels(componentSize.value, props.maxSize);
122+
});
123+
124+
let expandedSizePercentage = 0;
125+
126+
/** Whether the primary column is collapsed or not */
127+
const collapsed = defineModel<boolean>('collapsed', { default: false });
99128
100129
watch(collapsed, (newCollapsed) => {
101130
if (newCollapsed === true) {
102-
expandedPrimaryPanelSizePercentage = primaryPanelSizePercentage.value;
103-
primaryPanelSizePercentage.value = 0;
131+
expandedSizePercentage = sizePercentage.value;
132+
sizePercentage.value = 0;
104133
}
105134
else {
106-
primaryPanelSizePercentage.value = expandedPrimaryPanelSizePercentage;
135+
sizePercentage.value = expandedSizePercentage;
107136
}
108137
});
109138
110-
let cachedPrimaryPanelSizePixels = 0;
139+
let cachedSizePixels = 0;
111140
112141
onMounted(() => {
113-
cachedPrimaryPanelSizePixels = primaryPanelSizePixels.value;
142+
cachedSizePixels = sizePixels.value;
114143
});
115144
145+
const { x: dividerX, y: dividerY } = useDraggable(dividerEl, { containerElement: panelEl });
146+
116147
watch([dividerX, dividerY], ([newX, newY]) => {
117148
if (props.disabled) return;
118149
@@ -122,12 +153,22 @@ watch([dividerX, dividerY], ([newX, newY]) => {
122153
newPositionInPixels = componentSize.value - newPositionInPixels;
123154
}
124155
125-
primaryPanelSizePercentage.value = clamp(pixelsToPercentage(componentSize.value, newPositionInPixels), 0, 100);
156+
// if (props.collapsible && props.minSize !== undefined && props.collapseThreshold !== undefined) {
157+
// const threshold = props.minSize - (props.collapseThreshold ?? 0);
158+
159+
// console.log(threshold, newPositionInPixels);
160+
161+
// if (newPositionInPixels < threshold) {
162+
// collapsed.value = true;
163+
// }
164+
// }
165+
166+
sizePercentage.value = clamp(pixelsToPercentage(componentSize.value, newPositionInPixels), 0, 100);
126167
});
127168
128-
watch(primaryPanelSizePixels, (newPixels, oldPixels) => {
169+
watch(sizePixels, (newPixels, oldPixels) => {
129170
if (newPixels === oldPixels) return;
130-
cachedPrimaryPanelSizePixels = newPixels;
171+
cachedSizePixels = newPixels;
131172
});
132173
133174
useResizeObserver(panelEl, (entries) => {
@@ -136,15 +177,15 @@ useResizeObserver(panelEl, (entries) => {
136177
const size = props.orientation === 'horizontal' ? width : height;
137178
138179
if (props.primary) {
139-
primaryPanelSizePercentage.value = pixelsToPercentage(size, cachedPrimaryPanelSizePixels);
180+
sizePercentage.value = pixelsToPercentage(size, cachedSizePixels);
140181
}
141182
});
142183
143184
const handleKeydown = (event: KeyboardEvent) => {
144185
if (props.disabled) return;
145186
146187
if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End', 'Enter'].includes(event.key)) {
147-
let newPosition = primaryPanelSizePercentage.value;
188+
let newPosition = sizePercentage.value;
148189
149190
const increment = (event.shiftKey ? 10 : 1) * (props.primary === 'end' ? -1 : 1);
150191
@@ -170,12 +211,12 @@ const handleKeydown = (event: KeyboardEvent) => {
170211
newPosition = props.primary === 'end' ? 0 : 100;
171212
}
172213
173-
primaryPanelSizePercentage.value = clamp(newPosition, 0, 100);
214+
sizePercentage.value = clamp(newPosition, 0, 100);
174215
}
175216
};
176217
177218
const gridTemplate = computed(() => {
178-
const primary = `clamp(0%, clamp(${props.minSize}, ${primaryPanelSizePercentage.value}%, ${props.maxSize}), calc(100% - ${dividerSize.value}px))`;
219+
const primary = `clamp(0%, clamp(${minSizePercentage.value}%, ${sizePercentage.value}%, ${maxSizePercentage.value}%), calc(100% - ${dividerSize.value}px))`;
179220
const secondary = 'auto';
180221
181222
if (!props.primary || props.primary === 'start') {
@@ -214,7 +255,7 @@ defineExpose({ collapse, expand, toggle });
214255
:class="[{ disabled }, orientation]"
215256
:tabindex="disabled ? undefined : 0"
216257
role="separator"
217-
:aria-valuenow="primaryPanelSizePercentage"
258+
:aria-valuenow="sizePercentage"
218259
aria-valuemin="0"
219260
aria-valuemax="100"
220261
aria-label="Resize"

0 commit comments

Comments
 (0)