@window-splitter/svelte 0.8.4

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.
Files changed (42) hide show
  1. package/.storybook/main.ts +33 -0
  2. package/.storybook/preview.ts +14 -0
  3. package/.tshy/build.json +8 -0
  4. package/.tshy/commonjs.json +19 -0
  5. package/.tshy/esm.json +18 -0
  6. package/.turbo/turbo-build.log +6 -0
  7. package/CHANGELOG.md +20 -0
  8. package/README.md +58 -0
  9. package/dist/Panel.svelte +178 -0
  10. package/dist/Panel.svelte.d.ts +19 -0
  11. package/dist/Panel.svelte.d.ts.map +1 -0
  12. package/dist/PanelGroup.svelte +159 -0
  13. package/dist/PanelGroup.svelte.d.ts +18 -0
  14. package/dist/PanelGroup.svelte.d.ts.map +1 -0
  15. package/dist/PanelResizer.svelte +171 -0
  16. package/dist/PanelResizer.svelte.d.ts +8 -0
  17. package/dist/PanelResizer.svelte.d.ts.map +1 -0
  18. package/dist/index.d.ts +4 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +3 -0
  21. package/eslint.config.js +24 -0
  22. package/package.json +92 -0
  23. package/src/SvelteWindowSplitter.test.svelte.ts +283 -0
  24. package/src/__snapshots__/SvelteWindowSplitter.test.svelte.ts.snap +56 -0
  25. package/src/__snapshots__/SvelteWindowSplitter.test.ts.snap +54 -0
  26. package/src/lib/Panel.svelte +178 -0
  27. package/src/lib/PanelGroup.svelte +159 -0
  28. package/src/lib/PanelResizer.svelte +171 -0
  29. package/src/lib/index.ts +3 -0
  30. package/src/stories/Autosave.svelte +52 -0
  31. package/src/stories/AutosaveCollapsible.svelte +65 -0
  32. package/src/stories/AutosaveCookie.svelte +63 -0
  33. package/src/stories/Collapsible.svelte +112 -0
  34. package/src/stories/Conditional.svelte +70 -0
  35. package/src/stories/DynamicConstraints.svelte +73 -0
  36. package/src/stories/Simple.svelte +48 -0
  37. package/src/stories/SvelteWindowSplitter.stories.svelte +468 -0
  38. package/src/stories/VerticalLayout.svelte +58 -0
  39. package/svelte.config.js +7 -0
  40. package/tsconfig.json +6 -0
  41. package/vite.config.js +7 -0
  42. package/vitest.config.js +19 -0
@@ -0,0 +1,54 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Autosave > localStorage 1`] = `
4
+ [
5
+ {
6
+ "collapseIsControlled": false,
7
+ "collapsedSize": {
8
+ "type": "pixel",
9
+ "value": "0",
10
+ },
11
+ "currentValue": {
12
+ "type": "percent",
13
+ "value": "0.70081967213114754098",
14
+ },
15
+ "id": "1",
16
+ "max": "1fr",
17
+ "min": {
18
+ "type": "pixel",
19
+ "value": "0",
20
+ },
21
+ "onCollapseChange": {},
22
+ "onResize": {},
23
+ "type": "panel",
24
+ },
25
+ {
26
+ "id": "resizer",
27
+ "size": {
28
+ "type": "pixel",
29
+ "value": "10",
30
+ },
31
+ "type": "handle",
32
+ },
33
+ {
34
+ "collapseIsControlled": false,
35
+ "collapsedSize": {
36
+ "type": "pixel",
37
+ "value": "0",
38
+ },
39
+ "currentValue": {
40
+ "type": "percent",
41
+ "value": "0.29918032786885245902",
42
+ },
43
+ "id": "2",
44
+ "max": "1fr",
45
+ "min": {
46
+ "type": "pixel",
47
+ "value": "0",
48
+ },
49
+ "onCollapseChange": {},
50
+ "onResize": {},
51
+ "type": "panel",
52
+ },
53
+ ]
54
+ `;
@@ -0,0 +1,178 @@
1
+ <script lang="ts">
2
+ import type { SharedPanelProps } from "@window-splitter/interface";
3
+ import { getContext } from "svelte";
4
+ import {
5
+ initializePanel,
6
+ isPanelData,
7
+ haveConstraintsChangedForPanel,
8
+ getPanelPercentageSize,
9
+ getPanelPixelSize,
10
+ } from "@window-splitter/state";
11
+ import type {
12
+ PanelData,
13
+ GroupMachineContextValue,
14
+ SendFn,
15
+ Unit,
16
+ } from "@window-splitter/state";
17
+ import { getPanelDomAttributes } from "@window-splitter/interface";
18
+ import type { HTMLAttributes } from "svelte/elements";
19
+
20
+ export { PanelHandle } from "@window-splitter/interface";
21
+
22
+ interface Props
23
+ extends SharedPanelProps<boolean>,
24
+ HTMLAttributes<HTMLDivElement> {}
25
+
26
+ let {
27
+ children,
28
+ min,
29
+ max,
30
+ id: _id,
31
+ collapsible,
32
+ collapsed,
33
+ collapsedSize,
34
+ onCollapseChange,
35
+ collapseAnimation,
36
+ onResize,
37
+ defaultCollapsed,
38
+ default: defaultSize,
39
+ isStaticAtRest,
40
+ ...attrs
41
+ }: Props = $props();
42
+
43
+ const defaultId = $props.id();
44
+ const id = _id || defaultId;
45
+ const send = getContext<SendFn>("send");
46
+ const state = getContext<GroupMachineContextValue>("state");
47
+
48
+ const initPanel = (): PanelData =>
49
+ initializePanel({
50
+ id,
51
+ min,
52
+ max,
53
+ collapsible,
54
+ collapsed,
55
+ collapsedSize,
56
+ onCollapseChange: { current: onCollapseChange },
57
+ collapseAnimation,
58
+ onResize: { current: onResize },
59
+ defaultCollapsed,
60
+ default: defaultSize,
61
+ isStaticAtRest,
62
+ });
63
+
64
+ const isPrerender = getContext<{ current: boolean }>("isPrerender");
65
+ const panelData = () => {
66
+ const item = state?.items.find((i) => i.id === id);
67
+ if (!item || !isPanelData(item)) return undefined;
68
+ return item;
69
+ };
70
+
71
+ let dynamicPanelIsMounting = false;
72
+
73
+ if (panelData()) {
74
+ send({
75
+ type: "rebindPanelCallbacks",
76
+ data: {
77
+ id,
78
+ onCollapseChange: { current: onCollapseChange },
79
+ onResize: { current: onResize },
80
+ },
81
+ });
82
+ } else {
83
+ if (isPrerender.current) {
84
+ send({ type: "registerPanel", data: initPanel() });
85
+ } else {
86
+ dynamicPanelIsMounting = true;
87
+ }
88
+ }
89
+
90
+ const contraintChanged = $derived(
91
+ !dynamicPanelIsMounting &&
92
+ haveConstraintsChangedForPanel(initPanel(), panelData())
93
+ );
94
+
95
+ $effect(() => {
96
+ if (!contraintChanged) return;
97
+ send({ type: "updateConstraints", data: initPanel() });
98
+ });
99
+
100
+ const dynamicPanelData = initPanel();
101
+
102
+ $effect(() => {
103
+ if (!dynamicPanelIsMounting) return;
104
+
105
+ const groupElement = document.getElementById(state.groupId);
106
+ if (!groupElement) return;
107
+
108
+ const panelElement = document.getElementById(id);
109
+ if (!panelElement) return;
110
+
111
+ const order = Array.from(groupElement.children).indexOf(panelElement);
112
+ if (typeof order !== "number") return;
113
+
114
+ send({
115
+ type: "registerDynamicPanel",
116
+ data: { ...dynamicPanelData, order },
117
+ });
118
+ dynamicPanelIsMounting = false;
119
+ });
120
+
121
+ $effect(() => () => {
122
+ requestAnimationFrame(() => {
123
+ send({ type: "unregisterPanel", id });
124
+ });
125
+ });
126
+
127
+ const isControlledCollapse = $derived(panelData()?.collapseIsControlled);
128
+
129
+ $effect(() => {
130
+ if (!isControlledCollapse) return;
131
+
132
+ if (collapsed) {
133
+ send?.({ type: "collapsePanel", panelId: id, controlled: true });
134
+ } else {
135
+ send?.({ type: "expandPanel", panelId: id, controlled: true });
136
+ }
137
+ });
138
+
139
+ const domAttributes = () => {
140
+ const currentPanel = panelData();
141
+
142
+ return getPanelDomAttributes({
143
+ groupId: state.groupId,
144
+ id,
145
+ collapsible: currentPanel?.collapsible,
146
+ collapsed: currentPanel?.collapsed,
147
+ });
148
+ };
149
+
150
+ export const getId = () => id;
151
+ export const collapse = () => {
152
+ if (!panelData()?.collapsible) return;
153
+ send({ type: "collapsePanel", panelId: id, controlled: true });
154
+ };
155
+ export const isCollapsed = () =>
156
+ Boolean(panelData()?.collapsible && panelData()?.collapsed);
157
+ export const expand = () => {
158
+ if (!panelData()?.collapsible) return;
159
+ send({ type: "expandPanel", panelId: id, controlled: true });
160
+ };
161
+ export const isExpanded = () =>
162
+ Boolean(panelData()?.collapsible && !panelData()?.collapsed);
163
+ export const getPixelSize = () => getPanelPixelSize(state, id);
164
+ export const setSize = (size: Unit) => {
165
+ send({ type: "setPanelPixelSize", panelId: id, size });
166
+ };
167
+ export const getPercentageSize = () => getPanelPercentageSize(state, id);
168
+ </script>
169
+
170
+ <div
171
+ {...attrs}
172
+ {...domAttributes()}
173
+ style:min-width={0}
174
+ style:min-height={0}
175
+ style:overflow="hidden"
176
+ >
177
+ {@render children?.()}
178
+ </div>
@@ -0,0 +1,159 @@
1
+ <script lang="ts">
2
+ import type { SharedPanelGroupProps } from "@window-splitter/interface";
3
+ import { measureGroupChildren } from "@window-splitter/interface";
4
+ import {
5
+ buildTemplate,
6
+ groupMachine,
7
+ prepareSnapshot,
8
+ prepareItems,
9
+ getPanelGroupPixelSizes,
10
+ getPanelGroupPercentageSizes,
11
+ isPanelData,
12
+ } from "@window-splitter/state";
13
+ import type { GroupMachineContextValue, Unit } from "@window-splitter/state";
14
+ import { setContext } from "svelte";
15
+ import type { HTMLAttributes } from "svelte/elements";
16
+
17
+ export { PanelGroupHandle } from "@window-splitter/interface";
18
+
19
+ interface Props
20
+ extends SharedPanelGroupProps,
21
+ HTMLAttributes<HTMLDivElement> {
22
+ id: string;
23
+ }
24
+
25
+ let {
26
+ children,
27
+ orientation = "horizontal",
28
+ autosaveStrategy = "localStorage",
29
+ autosaveId,
30
+ snapshot,
31
+ ...attrs
32
+ }: Props = $props();
33
+
34
+ if (
35
+ !snapshot &&
36
+ typeof window !== "undefined" &&
37
+ autosaveId &&
38
+ autosaveStrategy === "localStorage"
39
+ ) {
40
+ const localSnapshot = localStorage.getItem(autosaveId);
41
+
42
+ if (localSnapshot) {
43
+ snapshot = JSON.parse(localSnapshot) as GroupMachineContextValue;
44
+ }
45
+ }
46
+
47
+ const defaultId = $props.id();
48
+ const id = autosaveId || defaultId;
49
+
50
+ const [initialState, send, machineState] = groupMachine(
51
+ {
52
+ orientation,
53
+ groupId: id,
54
+ autosaveStrategy,
55
+ ...(snapshot ? prepareSnapshot(snapshot) : undefined),
56
+ },
57
+ (s) => {
58
+ if (!context) return;
59
+ updateContext(s);
60
+ }
61
+ );
62
+
63
+ const context = $state<GroupMachineContextValue>(initialState);
64
+ function updateContext(s: GroupMachineContextValue) {
65
+ for (const key in s) {
66
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
+ (context as any)[key] = (s as any)[key];
68
+ }
69
+ }
70
+
71
+ setContext("send", send);
72
+ setContext("state", context);
73
+ setContext("id", machineState);
74
+
75
+ const isPrerender = $state({ current: true });
76
+ setContext("isPrerender", isPrerender);
77
+ $effect(() => {
78
+ isPrerender.current = false;
79
+ });
80
+
81
+ let elementRef = $state<HTMLDivElement>();
82
+
83
+ $effect(() => {
84
+ const observer = new ResizeObserver(([entry]) => {
85
+ if (!entry) return;
86
+ if (entry.contentRect.width > 0 && entry.contentRect.height > 0) {
87
+ send({ type: "setSize", size: entry.contentRect });
88
+ }
89
+ });
90
+
91
+ if (elementRef) {
92
+ observer.observe(elementRef);
93
+ }
94
+
95
+ return () => observer.disconnect();
96
+ });
97
+
98
+ let childIds = $derived(context.items.map((i) => i.id).join(","));
99
+
100
+ $effect(() => {
101
+ // re-render when the childIds change
102
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
103
+ childIds;
104
+ measureGroupChildren(id, (childrenSizes) => {
105
+ send({ type: "setActualItemsSize", childrenSizes });
106
+ });
107
+ });
108
+
109
+ let template = $derived(buildTemplate(context));
110
+
111
+ $effect(() => {
112
+ send({ type: "unlockGroup" });
113
+ return () => send({ type: "lockGroup" });
114
+ });
115
+
116
+ export const getId = () => id;
117
+ export const getPixelSizes = () => getPanelGroupPixelSizes(context);
118
+ export const getPercentageSizes = () => getPanelGroupPercentageSizes(context);
119
+ export const getTemplate = () =>
120
+ buildTemplate({ ...context, items: prepareItems(context) });
121
+ export const getState = () =>
122
+ machineState.current === "idle" ? "idle" : "dragging";
123
+ export const setSizes = (updates: Array<Unit>) => {
124
+ for (let index = 0; index < updates.length; index++) {
125
+ const item = context.items[index];
126
+ const update = updates[index];
127
+
128
+ if (item && isPanelData(item) && update) {
129
+ send({
130
+ type: "setPanelPixelSize",
131
+ panelId: item.id,
132
+ size: update,
133
+ });
134
+ }
135
+ }
136
+ };
137
+ </script>
138
+
139
+ <div
140
+ {...attrs}
141
+ data-panel-group-wrapper
142
+ bind:this={elementRef}
143
+ style:display="grid"
144
+ style:grid-template-columns={context.orientation === "horizontal"
145
+ ? template
146
+ : undefined}
147
+ style:grid-template-rows={context.orientation === "vertical"
148
+ ? template
149
+ : undefined}
150
+ {id}
151
+ >
152
+ {@render children?.()}
153
+ </div>
154
+
155
+ <style>
156
+ :where([data-panel-group-wrapper]) {
157
+ height: 100%;
158
+ }
159
+ </style>
@@ -0,0 +1,171 @@
1
+ <script lang="ts">
2
+ import { getContext } from "svelte";
3
+ import {
4
+ getCursor,
5
+ getGroupSize,
6
+ initializePanelHandleData,
7
+ isPanelData,
8
+ isPanelHandle,
9
+ getCollapsiblePanelForHandleId,
10
+ haveConstraintsChangedForPanelHandle,
11
+ } from "@window-splitter/state";
12
+ import type {
13
+ SendFn,
14
+ GroupMachineContextValue,
15
+ } from "@window-splitter/state";
16
+ import type { SharedPanelResizerProps } from "@window-splitter/interface";
17
+ import {
18
+ getPanelResizerDomAttributes,
19
+ move,
20
+ } from "@window-splitter/interface";
21
+ import type { HTMLAttributes } from "svelte/elements";
22
+
23
+ interface Props
24
+ extends SharedPanelResizerProps,
25
+ HTMLAttributes<HTMLDivElement> {}
26
+
27
+ let {
28
+ size = "0px",
29
+ id: _id,
30
+ onDragStart,
31
+ onDrag,
32
+ onDragEnd,
33
+ disabled,
34
+ ...attrs
35
+ }: Props = $props();
36
+
37
+ const defaultId = $props.id();
38
+ const id = _id || defaultId;
39
+ const send = getContext<SendFn>("send");
40
+ const state = getContext<GroupMachineContextValue>("state");
41
+ const isPrerender = getContext<{ current: boolean }>("isPrerender");
42
+ const initHandle = () => initializePanelHandleData({ size, id });
43
+ const handleData = () => {
44
+ const item = state?.items.find((i) => i.id === id);
45
+ if (!item || !isPanelHandle(item)) return undefined;
46
+ return item;
47
+ };
48
+
49
+ let dynamicPanelHandleIsMounting = false;
50
+
51
+ if (!handleData()) {
52
+ if (isPrerender.current) {
53
+ send({ type: "registerPanelHandle", data: initHandle() });
54
+ } else {
55
+ dynamicPanelHandleIsMounting = true;
56
+ }
57
+ }
58
+
59
+ $effect(() => {
60
+ if (!dynamicPanelHandleIsMounting) return;
61
+
62
+ const groupElement = document.getElementById(state.groupId);
63
+ if (!groupElement) return;
64
+
65
+ const handleEl = document.getElementById(id);
66
+ if (!handleEl) return;
67
+
68
+ const order = Array.from(groupElement.children).indexOf(handleEl);
69
+ if (typeof order !== "number") return;
70
+
71
+ send({
72
+ type: "registerPanelHandle",
73
+ data: { ...initHandle(), order },
74
+ });
75
+ dynamicPanelHandleIsMounting = false;
76
+ });
77
+
78
+ const contraintChanged = $derived(
79
+ !dynamicPanelHandleIsMounting &&
80
+ haveConstraintsChangedForPanelHandle(initHandle(), handleData())
81
+ );
82
+
83
+ const dynamicPanelHandleData = initHandle();
84
+ $effect(() => {
85
+ if (!contraintChanged) return;
86
+ send({ type: "updateConstraints", data: dynamicPanelHandleData });
87
+ });
88
+
89
+ $effect(() => () => {
90
+ requestAnimationFrame(() => {
91
+ send({ type: "unregisterPanelHandle", id });
92
+ });
93
+ });
94
+
95
+ const { moveProps } = move({
96
+ onMoveStart: () => {
97
+ send({ type: "dragHandleStart", handleId: id });
98
+ onDragStart?.();
99
+ document.body.style.cursor = getCursor(state) || "auto";
100
+ },
101
+ onMove: (e) => {
102
+ send({ type: "dragHandle", handleId: id, value: e });
103
+ onDrag?.();
104
+ },
105
+ onMoveEnd: () => {
106
+ send({ type: "dragHandleEnd", handleId: id });
107
+ onDragEnd?.();
108
+ document.body.style.cursor = "auto";
109
+ },
110
+ });
111
+
112
+ const itemIndex = 1;
113
+ const panelAttributes = () => {
114
+ const panelBeforeHandle = state?.items[itemIndex - 1];
115
+
116
+ if (!panelBeforeHandle || !isPanelData(panelBeforeHandle)) return { id };
117
+
118
+ return getPanelResizerDomAttributes({
119
+ groupId: state.groupId,
120
+ id,
121
+ orientation: state.orientation,
122
+ isDragging: state.activeDragHandleId === id,
123
+ activeDragHandleId: state.activeDragHandleId,
124
+ disabled: disabled,
125
+ controlsId: panelBeforeHandle.id,
126
+ min: panelBeforeHandle.min,
127
+ max: panelBeforeHandle.max,
128
+ currentValue: panelBeforeHandle.currentValue,
129
+ groupSize: getGroupSize(state),
130
+ });
131
+ };
132
+ const getDimensions = () => {
133
+ const handle = state.items.find((item) => item.id === id);
134
+ if (!handle || !isPanelHandle(handle)) return {};
135
+ return state.orientation === "horizontal"
136
+ ? { width: `${handle.size.value.toNumber()}px`, height: "100%" }
137
+ : { height: `${handle.size.value.toNumber()}px`, width: "100%" };
138
+ };
139
+ const onKeyDown = (e: KeyboardEvent) => {
140
+ try {
141
+ const collapsiblePanel = getCollapsiblePanelForHandleId(state, id);
142
+
143
+ if (e.key === "Enter" && collapsiblePanel) {
144
+ if (collapsiblePanel.collapsed) {
145
+ send({ type: "expandPanel", panelId: collapsiblePanel.id });
146
+ } else {
147
+ send({ type: "collapsePanel", panelId: collapsiblePanel.id });
148
+ }
149
+ }
150
+ } catch {
151
+ //
152
+ }
153
+ };
154
+ </script>
155
+
156
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
157
+ <div
158
+ {...attrs}
159
+ {...panelAttributes()}
160
+ onpointerdown={disabled ? undefined : moveProps.onPointerDown}
161
+ onkeydown={disabled
162
+ ? undefined
163
+ : (e) => {
164
+ moveProps.onKeyDown(e);
165
+ onKeyDown(e);
166
+ }}
167
+ tabindex={disabled ? -1 : 0}
168
+ style:cursor={getCursor(state)}
169
+ style:width={getDimensions().width}
170
+ style:height={getDimensions().height}
171
+ ></div>
@@ -0,0 +1,3 @@
1
+ export * from "./Panel.svelte";
2
+ export * from "./PanelGroup.svelte";
3
+ export * from "./PanelResizer.svelte";
@@ -0,0 +1,52 @@
1
+ <script module>
2
+ import PanelGroup from "../lib/PanelGroup.svelte";
3
+ import Panel from "../lib/Panel.svelte";
4
+ import PanelResizer from "../lib/PanelResizer.svelte";
5
+
6
+ let panelGroup;
7
+
8
+ /** @type {import("@window-splitter/interface").PanelGroupHandle} */
9
+ export const handle = {
10
+ getId: () => "panel-group",
11
+ getTemplate: () => panelGroup.getTemplate(),
12
+ getState: () => panelGroup.getState(),
13
+ getPixelSizes: () => panelGroup.getPixelSizes(),
14
+ getPercentageSizes: () => panelGroup.getPercentageSizes(),
15
+ setSizes: (sizes) => panelGroup.setSizes(sizes),
16
+ };
17
+ </script>
18
+
19
+ <PanelGroup
20
+ bind:this={panelGroup}
21
+ class="panel-group"
22
+ autosaveId="autosave-example-svelte"
23
+ >
24
+ <Panel id="1" class="panel">1</Panel>
25
+ <PanelResizer id="resizer" class="panel-resizer" size="10px" />
26
+ <Panel id="2" class="panel">2</Panel>
27
+ </PanelGroup>
28
+
29
+ <style>
30
+ :global(.panel-group) {
31
+ border: 1px solid rgba(0, 0, 0, 0.3);
32
+ background: rgba(0, 0, 0, 0.1);
33
+ border-radius: 12px;
34
+ box-sizing: border-box;
35
+ width: 500px;
36
+ }
37
+
38
+ :global(.panel) {
39
+ height: 100%;
40
+ width: 100%;
41
+ padding: 20px;
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ overflow: hidden;
46
+ box-sizing: border-box;
47
+ }
48
+
49
+ :global(.panel-resizer) {
50
+ background: red;
51
+ }
52
+ </style>
@@ -0,0 +1,65 @@
1
+ <script>
2
+ import PanelGroup from "../lib/PanelGroup.svelte";
3
+ import Panel from "../lib/Panel.svelte";
4
+ import PanelResizer from "../lib/PanelResizer.svelte";
5
+
6
+ const { onCollapseChange, handle: handleProp } = $props();
7
+
8
+ let panelGroup;
9
+
10
+ if (handleProp) {
11
+ /** @type {import("@window-splitter/interface").PanelGroupHandle} */
12
+ handleProp.current = {
13
+ getId: () => "panel-group",
14
+ getTemplate: () => panelGroup.getTemplate(),
15
+ getState: () => panelGroup.getState(),
16
+ getPixelSizes: () => panelGroup.getPixelSizes(),
17
+ getPercentageSizes: () => panelGroup.getPercentageSizes(),
18
+ setSizes: (sizes) => panelGroup.setSizes(sizes),
19
+ };
20
+ }
21
+ </script>
22
+
23
+ <PanelGroup
24
+ bind:this={panelGroup}
25
+ class="panel-group"
26
+ autosaveId="autosave-collapsible-svelte"
27
+ >
28
+ <Panel
29
+ id="1"
30
+ collapsible
31
+ collapsedSize="100px"
32
+ {onCollapseChange}
33
+ min="140px"
34
+ class="panel"
35
+ >
36
+ Collapsible
37
+ </Panel>
38
+ <PanelResizer id="resizer" class="panel-resizer" size="10px" />
39
+ <Panel id="2" class="panel">Panel 2</Panel>
40
+ </PanelGroup>
41
+
42
+ <style>
43
+ :global(.panel-group) {
44
+ border: 1px solid rgba(0, 0, 0, 0.3);
45
+ background: rgba(0, 0, 0, 0.1);
46
+ border-radius: 12px;
47
+ box-sizing: border-box;
48
+ width: 500px;
49
+ }
50
+
51
+ :global(.panel) {
52
+ height: 100%;
53
+ width: 100%;
54
+ padding: 20px;
55
+ display: flex;
56
+ align-items: center;
57
+ justify-content: center;
58
+ overflow: hidden;
59
+ box-sizing: border-box;
60
+ }
61
+
62
+ :global(.panel-resizer) {
63
+ background: red;
64
+ }
65
+ </style>