@rimelight/ui 0.0.56 → 0.0.58

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 (43) hide show
  1. package/package.json +5 -5
  2. package/src/components/avatar/avatar.theme.ts +58 -1
  3. package/src/components/avatar/avatar.ts +21 -1
  4. package/src/components/avatar-group/RLAAvatarGroup.astro +37 -161
  5. package/src/components/avatar-group/RLSAvatarGroup.tsx +37 -121
  6. package/src/components/breadcrumb/RLABreadcrumb.astro +59 -196
  7. package/src/components/breadcrumb/RLSBreadcrumb.tsx +57 -120
  8. package/src/components/card/RLSCard.tsx +1 -2
  9. package/src/components/card/RLVCard.vue +1 -2
  10. package/src/components/carousel/RLACarousel.astro +2 -1
  11. package/src/components/carousel/RLSCarousel.tsx +3 -11
  12. package/src/components/chart/RLAChart.astro +211 -219
  13. package/src/components/dashboard-navbar/RLADashboardNavbar.astro +1 -1
  14. package/src/components/dashboard-navbar/RLSDashboardNavbar.tsx +1 -15
  15. package/src/components/dashboard-panel/RLADashboardPanel.astro +1 -1
  16. package/src/components/dashboard-panel/RLSDashboardPanel.tsx +1 -6
  17. package/src/components/dashboard-search/RLADashboardSearch.astro +1 -1
  18. package/src/components/head/UIHead.astro +0 -11
  19. package/src/components/image/RLAImage.astro +15 -20
  20. package/src/components/image/RLSImage.tsx +5 -12
  21. package/src/components/image/image.theme.ts +4 -4
  22. package/src/components/input-rating/RLAInputRating.astro +19 -14
  23. package/src/components/input-rating/RLSInputRating.tsx +39 -32
  24. package/src/components/input-tags/RLAInputTags.astro +27 -137
  25. package/src/components/layout-grid/RLALayoutGrid.astro +4 -4
  26. package/src/components/logo/RLALogo.astro +0 -16
  27. package/src/components/logo/RLSLogo.tsx +1 -8
  28. package/src/components/marquee/RLAMarquee.astro +55 -62
  29. package/src/components/page-section/RLAPageSection.astro +2 -2
  30. package/src/components/progress/RLAProgress.astro +39 -38
  31. package/src/components/progress/RLSProgress.tsx +16 -5
  32. package/src/components/progress/progress.theme.ts +1 -1
  33. package/src/components/scroll-area/RLAScrollArea.astro +4 -5
  34. package/src/components/scroll-area/RLSScrollArea.tsx +5 -6
  35. package/src/components/splitter/RLASplitter.astro +217 -230
  36. package/src/components/splitter/RLSSplitter.tsx +2 -6
  37. package/src/components/steps/RLASteps.astro +110 -110
  38. package/src/components/sticky-surface/RLAStickySurface.astro +49 -67
  39. package/src/components/table/RLATable.astro +16 -46
  40. package/src/components/tabs/RLATabs.astro +352 -385
  41. package/src/components/textarea/RLATextarea.astro +1 -2
  42. package/src/components/theme-selector/RLAThemeSelector.astro +6 -6
  43. package/src/components/tooltip/RLATooltip.astro +7 -11
@@ -45,9 +45,9 @@ const TitleTag = variant === "hero" ? "h1" : "h2";
45
45
  data-orientation={orientation}
46
46
  class:list={[
47
47
  classes.root,
48
- contentVisibility === "auto" && "[content-visibility:auto] [contain-intrinsic-size:var(--rla-contain-intrinsic-size,auto_500px)]"
48
+ contentVisibility === "auto" && "[content-visibility:auto]",
49
+ containIntrinsicSize ? `[contain-intrinsic-size:${containIntrinsicSize}]` : (contentVisibility === "auto" && "[contain-intrinsic-size:auto_500px]")
49
50
  ]}
50
- style={containIntrinsicSize ? `--rla-contain-intrinsic-size: ${containIntrinsicSize};` : undefined}
51
51
  {...rest}
52
52
  >
53
53
  {Astro.slots.has("background") && (
@@ -1,38 +1,39 @@
1
- ---
2
- import type { ProgressProps } from "./progress"
3
- import { progressTheme } from "./progress.theme"
4
-
5
-
6
- const {
7
- value = 0,
8
- max = 100,
9
- theme,
10
- ...rest
11
- } = Astro.props as ProgressProps
12
-
13
- const classes = progressTheme(Astro.props)
14
-
15
- const percentage = Math.min(100, Math.max(0, (value / max) * 100))
16
- const id = `progress-${Math.random().toString(36).substring(2, 9)}`
17
- ---
18
- <div
19
- class={classes.root}
20
- data-slot="progress-root"
21
- role="progressbar"
22
- aria-valuemin={0}
23
- aria-valuemax={max}
24
- aria-valuenow={value}
25
- data-theme={theme}
26
- {...rest}
27
- >
28
- <div
29
- class:list={[classes.indicator, id]}
30
- data-slot="indicator"
31
- />
32
- </div>
33
-
34
- <style is:inline set:html={`
35
- .${id} {
36
- transform: translateX(-${100 - percentage}%) !important;
37
- }
38
- `} />
1
+ ---
2
+ import type { ProgressProps } from "./progress"
3
+ import { progressTheme } from "./progress.theme"
4
+
5
+
6
+ const {
7
+ value = 0,
8
+ max = 100,
9
+ theme,
10
+ ...rest
11
+ } = Astro.props as ProgressProps
12
+
13
+ const classes = progressTheme(Astro.props)
14
+
15
+ const percentage = Math.min(100, Math.max(0, Math.round((value / max) * 100)))
16
+
17
+ const widthClass =
18
+ percentage === 100 ? "w-full" :
19
+ percentage === 75 ? "w-3/4" :
20
+ percentage === 50 ? "w-1/2" :
21
+ percentage === 25 ? "w-1/4" :
22
+ percentage === 0 ? "w-0" :
23
+ `w-[${percentage}%]`
24
+ ---
25
+ <div
26
+ class={classes.root}
27
+ data-slot="progress-root"
28
+ role="progressbar"
29
+ aria-valuemin={0}
30
+ aria-valuemax={max}
31
+ aria-valuenow={value}
32
+ data-theme={theme}
33
+ {...rest}
34
+ >
35
+ <div
36
+ class:list={[classes.indicator, widthClass]}
37
+ data-slot="indicator"
38
+ />
39
+ </div>
@@ -29,6 +29,21 @@ const RLSProgress: Component<RLSProgressProps> = (allProps) => {
29
29
  })
30
30
  )
31
31
 
32
+ const widthClass = () => {
33
+ const pct = Math.round(percentage())
34
+ return pct === 100
35
+ ? "w-full"
36
+ : pct === 75
37
+ ? "w-3/4"
38
+ : pct === 50
39
+ ? "w-1/2"
40
+ : pct === 25
41
+ ? "w-1/4"
42
+ : pct === 0
43
+ ? "w-0"
44
+ : `w-[${pct}%]`
45
+ }
46
+
32
47
  return (
33
48
  <div
34
49
  class={resolvedClasses().root}
@@ -40,11 +55,7 @@ const RLSProgress: Component<RLSProgressProps> = (allProps) => {
40
55
  data-theme={props.theme}
41
56
  {...rest}
42
57
  >
43
- <div
44
- class={resolvedClasses().indicator}
45
- data-slot="indicator"
46
- style={{ transform: `translateX(-${100 - percentage()}%)` }}
47
- />
58
+ <div class={`${resolvedClasses().indicator} ${widthClass()}`} data-slot="indicator" />
48
59
  {props.children}
49
60
  </div>
50
61
  )
@@ -4,7 +4,7 @@ export const progressTheme = defineTheme("progress", {
4
4
  slots: ["root", "indicator"],
5
5
  base: {
6
6
  root: "relative w-full overflow-hidden rounded-full bg-muted shadow-inner",
7
- indicator: "h-full w-full flex-1 transition-all duration-300 ease-in-out bg-[var(--rl-bg)]"
7
+ indicator: "h-full rounded-full transition-all duration-300 ease-in-out bg-[var(--rl-bg)]"
8
8
  },
9
9
  variants: {
10
10
  color: "auto",
@@ -13,18 +13,17 @@ const {
13
13
 
14
14
  const classes = scrollAreaTheme(Astro.props)
15
15
 
16
- const heightStyle = height
17
- ? `height:${typeof height === "number" ? `${height}px` : height}`
18
- : undefined
16
+ const heightClass = height
17
+ ? (typeof height === "number" ? `h-[${height}px]` : `h-[${height}]`)
18
+ : ""
19
19
  ---
20
20
 
21
21
  <div
22
- class={classes.root}
22
+ class:list={[classes.root, heightClass]}
23
23
  data-slot="root"
24
24
  data-scroll-area
25
25
  data-orientation={orientation}
26
26
  data-hide-delay={scrollHideDelay}
27
- style={heightStyle}
28
27
  {...rest}
29
28
  >
30
29
  {/* Scrollable viewport */}
@@ -141,21 +141,20 @@ const RLSScrollArea: Component<RLSScrollAreaProps> = (allProps) => {
141
141
  })
142
142
  )
143
143
 
144
- const heightStyle = () =>
144
+ const heightClass = () =>
145
145
  props.height
146
146
  ? typeof props.height === "number"
147
- ? `${props.height}px`
148
- : props.height
149
- : undefined
147
+ ? `h-[${props.height}px]`
148
+ : `h-[${props.height}]`
149
+ : ""
150
150
 
151
151
  return (
152
152
  <div
153
- class={resolvedClasses().root}
153
+ class={`${resolvedClasses().root} ${heightClass()}`}
154
154
  data-slot="root"
155
155
  data-scroll-area
156
156
  data-orientation={orientation()}
157
157
  data-hide-delay={hideDelay()}
158
- style={{ height: heightStyle() }}
159
158
  {...rest}
160
159
  >
161
160
  <div
@@ -1,230 +1,217 @@
1
- ---
2
- import type { SplitterProps } from "./splitter"
3
- import { splitterTheme } from "./splitter.theme"
4
-
5
- import RLAIcon from "../icon/RLAIcon.astro"
6
-
7
-
8
- const {
9
- direction = "horizontal",
10
- defaultSizes = [50, 50],
11
- ...rest
12
- } = Astro.props as SplitterProps
13
-
14
- const classes = splitterTheme(Astro.props)
15
-
16
- // Normalise sizes so they sum to 100
17
- const total = defaultSizes.reduce((s, v) => s + v, 0)
18
- const sizes = defaultSizes.map(s => (s / (total || 100)) * 100)
19
-
20
- const panelCount = sizes.length
21
- const id = `splitter-${Math.random().toString(36).substring(2, 9)}`
22
-
23
- const panelContents: string[] = []
24
- await Promise.all(
25
- sizes.map(async (_, i) => {
26
- if (Astro.slots.has(`panel-${i}`)) {
27
- panelContents[i] = await Astro.slots.render(`panel-${i}`)
28
- }
29
- })
30
- )
31
- ---
32
-
33
- <rla-splitter {...rest}>
34
- <div
35
- class:list={[classes.root, id]}
36
- data-slot="root"
37
- data-resizable
38
- data-direction={direction}
39
- >
40
- {sizes.map((_size, i) => (
41
- <>
42
- <div
43
- class={classes.panel}
44
- data-slot="panel"
45
- data-resizable-panel={i}
46
- >
47
- {Astro.slots.has(`panel-${i}`) ? (
48
- <Fragment set:html={panelContents[i]} />
49
- ) : (
50
- i === 0
51
- ? <slot />
52
- : <slot name="panel" />
53
- )}
54
- </div>
55
-
56
- {/* Render a handle between panels, not after the last one */}
57
- {i < panelCount - 1 && (
58
- <div
59
- class={classes.handle}
60
- data-slot="handle"
61
- data-resizable-handle={i}
62
- role="separator"
63
- aria-orientation={direction === "horizontal" ? "vertical" : "horizontal"}
64
- tabindex={0}
65
- aria-label="Resize panels"
66
- >
67
- <RLAIcon
68
- name={direction === "horizontal" ? "gripVertical" : "gripHorizontal"}
69
- class="size-3.5 text-muted/50"
70
- aria-hidden="true"
71
- />
72
- </div>
73
- )}
74
- </>
75
- ))}
76
- </div>
77
- </rla-splitter>
78
-
79
- <script>
80
- class RLASplitter extends HTMLElement {
81
- private splitterCleanup: (() => void) | null = null;
82
-
83
- connectedCallback() {
84
- this.style.display = 'contents';
85
- const container = this.querySelector("[data-resizable]") as HTMLElement | null;
86
- if (!container) return;
87
-
88
- const direction = container.dataset["direction"] ?? "horizontal";
89
- const isHorizontal = direction === "horizontal";
90
-
91
- const panels = Array.from(
92
- container.querySelectorAll("[data-resizable-panel]")
93
- ) as HTMLElement[];
94
-
95
- const handles = Array.from(
96
- container.querySelectorAll("[data-resizable-handle]")
97
- ) as HTMLElement[];
98
-
99
- const cleanupFns: (() => void)[] = [];
100
-
101
- handles.forEach((handle, idx) => {
102
- const panelA = panels[idx];
103
- const panelB = panels[idx + 1];
104
- if (!panelA || !panelB) return;
105
-
106
- const containerSize = () =>
107
- isHorizontal
108
- ? container.clientWidth
109
- : container.clientHeight;
110
-
111
- let isDragging = false;
112
- let startPos = 0;
113
- let startASize = 0;
114
- let startBSize = 0;
115
-
116
- const getSize = (el: HTMLElement) =>
117
- isHorizontal ? el.offsetWidth : el.offsetHeight;
118
-
119
- const setSize = (el: HTMLElement, px: number) => {
120
- const pct = (px / containerSize()) * 100;
121
- if (isHorizontal) {
122
- el.style.width = `${pct}%`;
123
- } else {
124
- el.style.height = `${pct}%`;
125
- }
126
- };
127
-
128
- const onMouseMove = (e: MouseEvent) => {
129
- if (!isDragging) return;
130
- const delta = isHorizontal
131
- ? e.clientX - startPos
132
- : e.clientY - startPos;
133
-
134
- const newASize = Math.max(48, startASize + delta);
135
- const newBSize = Math.max(48, startBSize - delta);
136
-
137
- // Only resize if both panels have enough space
138
- if (startASize + startBSize - newASize < 48) return;
139
-
140
- setSize(panelA, newASize);
141
- setSize(panelB, newBSize);
142
- };
143
-
144
- const onMouseUp = () => {
145
- isDragging = false;
146
- document.body.style.cursor = "";
147
- document.body.style.userSelect = "";
148
- handle.classList.remove("bg-primary/30");
149
- panels.forEach(p => p.style.transition = "");
150
- document.removeEventListener("mousemove", onMouseMove);
151
- document.removeEventListener("mouseup", onMouseUp);
152
- };
153
-
154
- const onMouseDown = (e: MouseEvent) => {
155
- e.preventDefault();
156
- isDragging = true;
157
- startPos = isHorizontal ? e.clientX : e.clientY;
158
- startASize = getSize(panelA);
159
- startBSize = getSize(panelB);
160
- document.body.style.cursor = isHorizontal ? "col-resize" : "row-resize";
161
- document.body.style.userSelect = "none";
162
- handle.classList.add("bg-primary/30");
163
- panels.forEach(p => p.style.transition = "none");
164
- document.addEventListener("mousemove", onMouseMove);
165
- document.addEventListener("mouseup", onMouseUp);
166
- };
167
-
168
- handle.addEventListener("mousedown", onMouseDown);
169
- cleanupFns.push(() => {
170
- handle.removeEventListener("mousedown", onMouseDown);
171
- document.removeEventListener("mousemove", onMouseMove);
172
- document.removeEventListener("mouseup", onMouseUp);
173
- });
174
-
175
- // Keyboard resize: arrow keys shift by 2%
176
- const onKeyDown = (e: KeyboardEvent) => {
177
- const step = containerSize() * 0.02;
178
- const forward = isHorizontal
179
- ? e.key === "ArrowRight"
180
- : e.key === "ArrowDown";
181
- const backward = isHorizontal
182
- ? e.key === "ArrowLeft"
183
- : e.key === "ArrowUp";
184
-
185
- if (!forward && !backward) return;
186
- e.preventDefault();
187
-
188
- const aSize = getSize(panelA);
189
- const bSize = getSize(panelB);
190
- const delta = forward ? step : -step;
191
-
192
- setSize(panelA, Math.max(48, aSize + delta));
193
- setSize(panelB, Math.max(48, bSize - delta));
194
- };
195
-
196
- handle.addEventListener("keydown", onKeyDown);
197
- cleanupFns.push(() => {
198
- handle.removeEventListener("keydown", onKeyDown);
199
- });
200
- });
201
-
202
- this.splitterCleanup = () => {
203
- cleanupFns.forEach(fn => fn());
204
- };
205
- }
206
-
207
- disconnectedCallback() {
208
- if (this.splitterCleanup) {
209
- this.splitterCleanup();
210
- this.splitterCleanup = null;
211
- }
212
- }
213
- }
214
-
215
- if (!customElements.get('rla-splitter')) {
216
- customElements.define('rla-splitter', RLASplitter);
217
- }
218
- </script>
219
-
220
- <style is:inline set:html={`
221
- .${id}[data-direction="horizontal"] > [data-resizable-panel="0"] { width: ${sizes[0] ?? 50}%; }
222
- .${id}[data-direction="horizontal"] > [data-resizable-panel="1"] { width: ${sizes[1] ?? 50}%; }
223
- .${id}[data-direction="horizontal"] > [data-resizable-panel="2"] { width: ${sizes[2] ?? 0}%; }
224
- .${id}[data-direction="horizontal"] > [data-resizable-panel="3"] { width: ${sizes[3] ?? 0}%; }
225
-
226
- .${id}[data-direction="vertical"] > [data-resizable-panel="0"] { height: ${sizes[0] ?? 50}%; }
227
- .${id}[data-direction="vertical"] > [data-resizable-panel="1"] { height: ${sizes[1] ?? 50}%; }
228
- .${id}[data-direction="vertical"] > [data-resizable-panel="2"] { height: ${sizes[2] ?? 0}%; }
229
- .${id}[data-direction="vertical"] > [data-resizable-panel="3"] { height: ${sizes[3] ?? 0}%; }
230
- `} />
1
+ ---
2
+ import type { SplitterProps } from "./splitter"
3
+ import { splitterTheme } from "./splitter.theme"
4
+
5
+ import RLAIcon from "../icon/RLAIcon.astro"
6
+
7
+
8
+ const {
9
+ direction = "horizontal",
10
+ defaultSizes = [50, 50],
11
+ ...rest
12
+ } = Astro.props as SplitterProps
13
+
14
+ const classes = splitterTheme(Astro.props)
15
+
16
+ // Normalise sizes so they sum to 100
17
+ const total = defaultSizes.reduce((s, v) => s + v, 0)
18
+ const sizes = defaultSizes.map(s => (s / (total || 100)) * 100)
19
+
20
+ const panelCount = sizes.length
21
+
22
+ const panelContents: string[] = []
23
+ await Promise.all(
24
+ sizes.map(async (_, i) => {
25
+ if (Astro.slots.has(`panel-${i}`)) {
26
+ panelContents[i] = await Astro.slots.render(`panel-${i}`)
27
+ }
28
+ })
29
+ )
30
+ ---
31
+
32
+ <rla-splitter {...rest}>
33
+ <div
34
+ class:list={[classes.root]}
35
+ data-slot="root"
36
+ data-resizable
37
+ data-direction={direction}
38
+ >
39
+ {sizes.map((_size, i) => (
40
+ <>
41
+ <div
42
+ class:list={[classes.panel, direction === "horizontal" ? `w-[${sizes[i]}%]` : `h-[${sizes[i]}%]`]}
43
+ data-slot="panel"
44
+ data-resizable-panel={i}
45
+ >
46
+ {Astro.slots.has(`panel-${i}`) ? (
47
+ <Fragment set:html={panelContents[i]} />
48
+ ) : (
49
+ i === 0
50
+ ? <slot />
51
+ : <slot name="panel" />
52
+ )}
53
+ </div>
54
+
55
+ {/* Render a handle between panels, not after the last one */}
56
+ {i < panelCount - 1 && (
57
+ <div
58
+ class={classes.handle}
59
+ data-slot="handle"
60
+ data-resizable-handle={i}
61
+ role="separator"
62
+ aria-orientation={direction === "horizontal" ? "vertical" : "horizontal"}
63
+ tabindex={0}
64
+ aria-label="Resize panels"
65
+ >
66
+ <RLAIcon
67
+ name={direction === "horizontal" ? "gripVertical" : "gripHorizontal"}
68
+ class="size-3.5 text-muted/50"
69
+ aria-hidden="true"
70
+ />
71
+ </div>
72
+ )}
73
+ </>
74
+ ))}
75
+ </div>
76
+ </rla-splitter>
77
+
78
+ <script>
79
+ class RLASplitter extends HTMLElement {
80
+ private splitterCleanup: (() => void) | null = null;
81
+
82
+ connectedCallback() {
83
+ this.style.display = 'contents';
84
+ const container = this.querySelector("[data-resizable]") as HTMLElement | null;
85
+ if (!container) return;
86
+
87
+ const direction = container.dataset["direction"] ?? "horizontal";
88
+ const isHorizontal = direction === "horizontal";
89
+
90
+ const panels = Array.from(
91
+ container.querySelectorAll("[data-resizable-panel]")
92
+ ) as HTMLElement[];
93
+
94
+ const handles = Array.from(
95
+ container.querySelectorAll("[data-resizable-handle]")
96
+ ) as HTMLElement[];
97
+
98
+ const cleanupFns: (() => void)[] = [];
99
+
100
+ handles.forEach((handle, idx) => {
101
+ const panelA = panels[idx];
102
+ const panelB = panels[idx + 1];
103
+ if (!panelA || !panelB) return;
104
+
105
+ const containerSize = () =>
106
+ isHorizontal
107
+ ? container.clientWidth
108
+ : container.clientHeight;
109
+
110
+ let isDragging = false;
111
+ let startPos = 0;
112
+ let startASize = 0;
113
+ let startBSize = 0;
114
+
115
+ const getSize = (el: HTMLElement) =>
116
+ isHorizontal ? el.offsetWidth : el.offsetHeight;
117
+
118
+ const setSize = (el: HTMLElement, px: number) => {
119
+ const pct = (px / containerSize()) * 100;
120
+ if (isHorizontal) {
121
+ el.style.width = `${pct}%`;
122
+ } else {
123
+ el.style.height = `${pct}%`;
124
+ }
125
+ };
126
+
127
+ const onMouseMove = (e: MouseEvent) => {
128
+ if (!isDragging) return;
129
+ const delta = isHorizontal
130
+ ? e.clientX - startPos
131
+ : e.clientY - startPos;
132
+
133
+ const newASize = Math.max(48, startASize + delta);
134
+ const newBSize = Math.max(48, startBSize - delta);
135
+
136
+ // Only resize if both panels have enough space
137
+ if (startASize + startBSize - newASize < 48) return;
138
+
139
+ setSize(panelA, newASize);
140
+ setSize(panelB, newBSize);
141
+ };
142
+
143
+ const onMouseUp = () => {
144
+ isDragging = false;
145
+ document.body.style.cursor = "";
146
+ document.body.style.userSelect = "";
147
+ handle.classList.remove("bg-primary/30");
148
+ panels.forEach(p => p.style.transition = "");
149
+ document.removeEventListener("mousemove", onMouseMove);
150
+ document.removeEventListener("mouseup", onMouseUp);
151
+ };
152
+
153
+ const onMouseDown = (e: MouseEvent) => {
154
+ e.preventDefault();
155
+ isDragging = true;
156
+ startPos = isHorizontal ? e.clientX : e.clientY;
157
+ startASize = getSize(panelA);
158
+ startBSize = getSize(panelB);
159
+ document.body.style.cursor = isHorizontal ? "col-resize" : "row-resize";
160
+ document.body.style.userSelect = "none";
161
+ handle.classList.add("bg-primary/30");
162
+ panels.forEach(p => p.style.transition = "none");
163
+ document.addEventListener("mousemove", onMouseMove);
164
+ document.addEventListener("mouseup", onMouseUp);
165
+ };
166
+
167
+ handle.addEventListener("mousedown", onMouseDown);
168
+ cleanupFns.push(() => {
169
+ handle.removeEventListener("mousedown", onMouseDown);
170
+ document.removeEventListener("mousemove", onMouseMove);
171
+ document.removeEventListener("mouseup", onMouseUp);
172
+ });
173
+
174
+ // Keyboard resize: arrow keys shift by 2%
175
+ const onKeyDown = (e: KeyboardEvent) => {
176
+ const step = containerSize() * 0.02;
177
+ const forward = isHorizontal
178
+ ? e.key === "ArrowRight"
179
+ : e.key === "ArrowDown";
180
+ const backward = isHorizontal
181
+ ? e.key === "ArrowLeft"
182
+ : e.key === "ArrowUp";
183
+
184
+ if (!forward && !backward) return;
185
+ e.preventDefault();
186
+
187
+ const aSize = getSize(panelA);
188
+ const bSize = getSize(panelB);
189
+ const delta = forward ? step : -step;
190
+
191
+ setSize(panelA, Math.max(48, aSize + delta));
192
+ setSize(panelB, Math.max(48, bSize - delta));
193
+ };
194
+
195
+ handle.addEventListener("keydown", onKeyDown);
196
+ cleanupFns.push(() => {
197
+ handle.removeEventListener("keydown", onKeyDown);
198
+ });
199
+ });
200
+
201
+ this.splitterCleanup = () => {
202
+ cleanupFns.forEach(fn => fn());
203
+ };
204
+ }
205
+
206
+ disconnectedCallback() {
207
+ if (this.splitterCleanup) {
208
+ this.splitterCleanup();
209
+ this.splitterCleanup = null;
210
+ }
211
+ }
212
+ }
213
+
214
+ if (!customElements.get('rla-splitter')) {
215
+ customElements.define('rla-splitter', RLASplitter);
216
+ }
217
+ </script>