@rimelight/ui 0.0.57 → 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.
- package/package.json +3 -3
- package/src/components/avatar/avatar.theme.ts +58 -1
- package/src/components/avatar/avatar.ts +21 -1
- package/src/components/avatar-group/RLAAvatarGroup.astro +37 -161
- package/src/components/avatar-group/RLSAvatarGroup.tsx +37 -121
- package/src/components/breadcrumb/RLABreadcrumb.astro +59 -196
- package/src/components/breadcrumb/RLSBreadcrumb.tsx +57 -120
- package/src/components/card/RLSCard.tsx +1 -2
- package/src/components/card/RLVCard.vue +1 -2
- package/src/components/carousel/RLACarousel.astro +2 -1
- package/src/components/carousel/RLSCarousel.tsx +3 -11
- package/src/components/chart/RLAChart.astro +211 -219
- package/src/components/dashboard-navbar/RLADashboardNavbar.astro +1 -1
- package/src/components/dashboard-navbar/RLSDashboardNavbar.tsx +1 -15
- package/src/components/dashboard-panel/RLADashboardPanel.astro +1 -1
- package/src/components/dashboard-panel/RLSDashboardPanel.tsx +1 -6
- package/src/components/dashboard-search/RLADashboardSearch.astro +1 -1
- package/src/components/head/UIHead.astro +0 -11
- package/src/components/image/RLAImage.astro +15 -20
- package/src/components/image/RLSImage.tsx +5 -12
- package/src/components/image/image.theme.ts +4 -4
- package/src/components/input-rating/RLAInputRating.astro +19 -14
- package/src/components/input-rating/RLSInputRating.tsx +39 -32
- package/src/components/input-tags/RLAInputTags.astro +27 -137
- package/src/components/layout-grid/RLALayoutGrid.astro +4 -4
- package/src/components/logo/RLALogo.astro +0 -16
- package/src/components/logo/RLSLogo.tsx +1 -8
- package/src/components/marquee/RLAMarquee.astro +55 -62
- package/src/components/page-section/RLAPageSection.astro +2 -2
- package/src/components/progress/RLAProgress.astro +39 -38
- package/src/components/progress/RLSProgress.tsx +16 -5
- package/src/components/progress/progress.theme.ts +1 -1
- package/src/components/scroll-area/RLAScrollArea.astro +4 -5
- package/src/components/scroll-area/RLSScrollArea.tsx +5 -6
- package/src/components/splitter/RLASplitter.astro +217 -230
- package/src/components/splitter/RLSSplitter.tsx +2 -6
- package/src/components/steps/RLASteps.astro +110 -110
- package/src/components/sticky-surface/RLAStickySurface.astro +49 -67
- package/src/components/table/RLATable.astro +16 -46
- package/src/components/tabs/RLATabs.astro +352 -385
- package/src/components/textarea/RLATextarea.astro +1 -2
- package/src/components/theme-selector/RLAThemeSelector.astro +6 -6
- package/src/components/tooltip/RLATooltip.astro +7 -11
|
@@ -1,385 +1,352 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { TabsProps } from "./tabs"
|
|
3
|
-
import { tabsTheme } from "./tabs.theme"
|
|
4
|
-
import RLABadge from "../badge/RLABadge.astro"
|
|
5
|
-
import RLAIcon from "../icon/RLAIcon.astro"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const {
|
|
9
|
-
items = [],
|
|
10
|
-
value = "",
|
|
11
|
-
defaultValue = "",
|
|
12
|
-
variant = "pill",
|
|
13
|
-
orientation = "horizontal",
|
|
14
|
-
size = "md",
|
|
15
|
-
color = "primary",
|
|
16
|
-
content = true,
|
|
17
|
-
valueKey = "value",
|
|
18
|
-
labelKey = "label",
|
|
19
|
-
maxTabs,
|
|
20
|
-
estimatedTabWidth = 100,
|
|
21
|
-
...rest
|
|
22
|
-
} = Astro.props as TabsProps
|
|
23
|
-
|
|
24
|
-
// Normalize variant names
|
|
25
|
-
const normalizedVariant = (variant === "solid" || variant === "pills") ? "pill" : (variant === "link" ? "underline" : variant);
|
|
26
|
-
|
|
27
|
-
const classes = tabsTheme({
|
|
28
|
-
...Astro.props,
|
|
29
|
-
variant: normalizedVariant
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const initialValue = value || defaultValue || (items.length > 0 ? (items[0]?.[valueKey] ?? items[0]?.value ?? "0") : "")
|
|
33
|
-
|
|
34
|
-
// ───
|
|
35
|
-
const uid = Math.random().toString(36).substring(2, 9)
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
>
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
// Hide popover after selection
|
|
354
|
-
const popover = item.closest('[popover]') as HTMLElement | null;
|
|
355
|
-
if (popover && 'hidePopover' in popover) {
|
|
356
|
-
(popover as any).hidePopover();
|
|
357
|
-
}
|
|
358
|
-
};
|
|
359
|
-
item.addEventListener("click", onClick);
|
|
360
|
-
clickCleanups.push(() => item.removeEventListener("click", onClick));
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
this.tabsCleanup = () => {
|
|
364
|
-
clickCleanups.forEach(fn => fn());
|
|
365
|
-
beforeMatchCleanups.forEach(fn => fn());
|
|
366
|
-
if (this.resizeObserver) {
|
|
367
|
-
this.resizeObserver.disconnect();
|
|
368
|
-
this.resizeObserver = null;
|
|
369
|
-
}
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
disconnectedCallback() {
|
|
374
|
-
if (this.tabsCleanup) {
|
|
375
|
-
this.tabsCleanup();
|
|
376
|
-
this.tabsCleanup = null;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
if (!customElements.get('rla-tabs')) {
|
|
382
|
-
customElements.define('rla-tabs', RLATabs);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
</script>
|
|
1
|
+
---
|
|
2
|
+
import type { TabsProps } from "./tabs"
|
|
3
|
+
import { tabsTheme } from "./tabs.theme"
|
|
4
|
+
import RLABadge from "../badge/RLABadge.astro"
|
|
5
|
+
import RLAIcon from "../icon/RLAIcon.astro"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
items = [],
|
|
10
|
+
value = "",
|
|
11
|
+
defaultValue = "",
|
|
12
|
+
variant = "pill",
|
|
13
|
+
orientation = "horizontal",
|
|
14
|
+
size = "md",
|
|
15
|
+
color = "primary",
|
|
16
|
+
content = true,
|
|
17
|
+
valueKey = "value",
|
|
18
|
+
labelKey = "label",
|
|
19
|
+
maxTabs,
|
|
20
|
+
estimatedTabWidth = 100,
|
|
21
|
+
...rest
|
|
22
|
+
} = Astro.props as TabsProps
|
|
23
|
+
|
|
24
|
+
// Normalize variant names
|
|
25
|
+
const normalizedVariant = (variant === "solid" || variant === "pills") ? "pill" : (variant === "link" ? "underline" : variant);
|
|
26
|
+
|
|
27
|
+
const classes = tabsTheme({
|
|
28
|
+
...Astro.props,
|
|
29
|
+
variant: normalizedVariant
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const initialValue = value || defaultValue || (items.length > 0 ? (items[0]?.[valueKey] ?? items[0]?.value ?? "0") : "")
|
|
33
|
+
|
|
34
|
+
// ─── Native Popover Overflow ───────────────────
|
|
35
|
+
const uid = Math.random().toString(36).substring(2, 9)
|
|
36
|
+
const popoverId = `rla-tb-pop-${uid}`
|
|
37
|
+
|
|
38
|
+
const effectiveMaxTabs = maxTabs !== undefined ? Math.max(1, maxTabs) : items.length
|
|
39
|
+
const renderedListItems = items.slice(0, effectiveMaxTabs)
|
|
40
|
+
const overflowItems = items.slice(effectiveMaxTabs)
|
|
41
|
+
const baseHiddenCount = overflowItems.length
|
|
42
|
+
const needsOverflow = items.length > 1 && orientation === "horizontal" && baseHiddenCount > 0
|
|
43
|
+
---
|
|
44
|
+
<rla-tabs {...rest} data-orientation={orientation} data-variant={normalizedVariant}>
|
|
45
|
+
<div
|
|
46
|
+
class:list={[classes.root, orientation === "horizontal" && "rla-tb-host"]}
|
|
47
|
+
data-slot="root"
|
|
48
|
+
data-tabs-container
|
|
49
|
+
data-value={initialValue}
|
|
50
|
+
data-tb={uid}
|
|
51
|
+
>
|
|
52
|
+
<div class={classes.list} data-slot="list" role="tablist">
|
|
53
|
+
<div class:list={[classes.indicator, "hidden"]} data-slot="indicator"></div>
|
|
54
|
+
{renderedListItems.map((item, index) => {
|
|
55
|
+
const itemVal = item[valueKey] ?? item.value ?? String(index)
|
|
56
|
+
const itemLabel = item[labelKey] ?? item.label
|
|
57
|
+
const active = itemVal === initialValue
|
|
58
|
+
return (
|
|
59
|
+
<button
|
|
60
|
+
type="button"
|
|
61
|
+
class:list={[classes.trigger]}
|
|
62
|
+
data-slot="trigger"
|
|
63
|
+
role="tab"
|
|
64
|
+
data-value={itemVal}
|
|
65
|
+
data-state={active ? "active" : "inactive"}
|
|
66
|
+
disabled={item.disabled}
|
|
67
|
+
>
|
|
68
|
+
{item.icon && <span class={item.icon + " " + classes.leadingIcon} data-slot="leadingIcon" />}
|
|
69
|
+
{itemLabel && <span class={classes.label} data-slot="label">{itemLabel}</span>}
|
|
70
|
+
{item.badge !== undefined && item.badge !== null && (
|
|
71
|
+
<RLABadge
|
|
72
|
+
size="sm"
|
|
73
|
+
variant="subtle"
|
|
74
|
+
color="neutral"
|
|
75
|
+
class={classes.trailingBadge}
|
|
76
|
+
data-slot="trailingBadge"
|
|
77
|
+
>
|
|
78
|
+
{typeof item.badge === "object" ? item.badge.label : item.badge}
|
|
79
|
+
</RLABadge>
|
|
80
|
+
)}
|
|
81
|
+
</button>
|
|
82
|
+
)
|
|
83
|
+
})}
|
|
84
|
+
|
|
85
|
+
{needsOverflow && (
|
|
86
|
+
<div class="relative inline-flex items-center ml-auto">
|
|
87
|
+
<button
|
|
88
|
+
type="button"
|
|
89
|
+
class:list={[
|
|
90
|
+
classes.trigger,
|
|
91
|
+
"rla-tb-overflow-btn",
|
|
92
|
+
baseHiddenCount === 0 && "rla-tb-overflow-hidden"
|
|
93
|
+
]}
|
|
94
|
+
popovertarget={popoverId}
|
|
95
|
+
data-slot="overflow-trigger"
|
|
96
|
+
aria-label="More tabs"
|
|
97
|
+
>
|
|
98
|
+
<span class="rla-tb-label">
|
|
99
|
+
+{baseHiddenCount} more
|
|
100
|
+
</span>
|
|
101
|
+
<RLAIcon name="chevronDown" class="ml-1 size-3.5 opacity-70" />
|
|
102
|
+
</button>
|
|
103
|
+
|
|
104
|
+
<div
|
|
105
|
+
id={popoverId}
|
|
106
|
+
popover="auto"
|
|
107
|
+
class="rla-tb-popover rounded-lg border border-default bg-default p-1 shadow-lg backdrop-blur-sm"
|
|
108
|
+
>
|
|
109
|
+
<div class="flex flex-col gap-0.5 min-w-[10rem]">
|
|
110
|
+
{items.map((item, index) => {
|
|
111
|
+
const itemVal = item[valueKey] ?? item.value ?? String(index)
|
|
112
|
+
const itemLabel = item[labelKey] ?? item.label
|
|
113
|
+
const isExtra = index >= effectiveMaxTabs
|
|
114
|
+
return (
|
|
115
|
+
<button
|
|
116
|
+
type="button"
|
|
117
|
+
class:list={[
|
|
118
|
+
"w-full text-left px-3 py-1.5 text-sm rounded-md transition-colors flex items-center justify-between",
|
|
119
|
+
"hover:bg-muted focus-visible:outline-none cursor-pointer",
|
|
120
|
+
!isExtra && "rla-tb-pop-rendered"
|
|
121
|
+
]}
|
|
122
|
+
data-tab-overflow-value={itemVal}
|
|
123
|
+
data-popover-item
|
|
124
|
+
>
|
|
125
|
+
<span class="truncate">{itemLabel}</span>
|
|
126
|
+
<RLAIcon name="check" class="size-4 opacity-0 data-[active=true]:opacity-100" />
|
|
127
|
+
</button>
|
|
128
|
+
)
|
|
129
|
+
})}
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
)}
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
{content && (
|
|
137
|
+
<div class="flex-1">
|
|
138
|
+
<slot>
|
|
139
|
+
{items.map((item, index) => {
|
|
140
|
+
const itemVal = item[valueKey] ?? item.value ?? String(index)
|
|
141
|
+
const active = itemVal === initialValue
|
|
142
|
+
return (
|
|
143
|
+
<div
|
|
144
|
+
class={classes.content}
|
|
145
|
+
data-slot="content"
|
|
146
|
+
role="tabpanel"
|
|
147
|
+
data-value={itemVal}
|
|
148
|
+
hidden={active ? undefined : "until-found"}
|
|
149
|
+
>
|
|
150
|
+
{item.content}
|
|
151
|
+
</div>
|
|
152
|
+
)
|
|
153
|
+
})}
|
|
154
|
+
</slot>
|
|
155
|
+
</div>
|
|
156
|
+
)}
|
|
157
|
+
</div>
|
|
158
|
+
</rla-tabs>
|
|
159
|
+
|
|
160
|
+
<style>
|
|
161
|
+
.rla-tb-host {
|
|
162
|
+
width: 100%;
|
|
163
|
+
}
|
|
164
|
+
.rla-tb-popover {
|
|
165
|
+
margin: 0;
|
|
166
|
+
inset: auto;
|
|
167
|
+
position: absolute;
|
|
168
|
+
}
|
|
169
|
+
.rla-tb-popover:popover-open {
|
|
170
|
+
display: block;
|
|
171
|
+
}
|
|
172
|
+
.rla-tb-pop-rendered {
|
|
173
|
+
display: none;
|
|
174
|
+
}
|
|
175
|
+
@supports not (content-visibility: hidden) {
|
|
176
|
+
[hidden="until-found"] {
|
|
177
|
+
display: none !important;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
</style>
|
|
181
|
+
|
|
182
|
+
<script>
|
|
183
|
+
if (typeof HTMLElement !== 'undefined') {
|
|
184
|
+
class RLATabs extends HTMLElement {
|
|
185
|
+
private tabsCleanup: (() => void) | null = null;
|
|
186
|
+
private resizeObserver: ResizeObserver | null = null;
|
|
187
|
+
|
|
188
|
+
connectedCallback() {
|
|
189
|
+
this.style.display = 'contents';
|
|
190
|
+
const container = this.querySelector("[data-tabs-container]") as HTMLElement | null;
|
|
191
|
+
if (!container) return;
|
|
192
|
+
|
|
193
|
+
const list = container.querySelector("[data-slot=list]") as HTMLElement | null;
|
|
194
|
+
const indicator = container.querySelector("[data-slot=indicator]") as HTMLElement | null;
|
|
195
|
+
const orientation = this.dataset["orientation"] || "horizontal";
|
|
196
|
+
const isVertical = orientation === "vertical";
|
|
197
|
+
|
|
198
|
+
const updateIndicator = (activeTrigger: HTMLElement | null) => {
|
|
199
|
+
if (!indicator || !list || !activeTrigger) {
|
|
200
|
+
if (indicator) indicator.style.display = 'none';
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// If active trigger is hidden due to container queries, position near overflow button
|
|
205
|
+
if (getComputedStyle(activeTrigger).display === 'none') {
|
|
206
|
+
const overflowBtn = list.querySelector('.rla-tb-overflow-btn') as HTMLElement | null;
|
|
207
|
+
if (overflowBtn) activeTrigger = overflowBtn;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const listRect = list.getBoundingClientRect();
|
|
211
|
+
const triggerRect = activeTrigger.getBoundingClientRect();
|
|
212
|
+
|
|
213
|
+
if (triggerRect.width === 0 && triggerRect.height === 0) {
|
|
214
|
+
indicator.style.display = 'none';
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
indicator.style.display = 'block';
|
|
219
|
+
|
|
220
|
+
if (isVertical) {
|
|
221
|
+
const top = triggerRect.top - listRect.top + list.scrollTop;
|
|
222
|
+
const height = triggerRect.height;
|
|
223
|
+
indicator.style.transform = `translateY(${top}px)`;
|
|
224
|
+
indicator.style.height = `${height}px`;
|
|
225
|
+
} else {
|
|
226
|
+
const left = triggerRect.left - listRect.left + list.scrollLeft;
|
|
227
|
+
const width = triggerRect.width;
|
|
228
|
+
indicator.style.transform = `translateX(${left}px)`;
|
|
229
|
+
indicator.style.width = `${width}px`;
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const containerValue = container.dataset["value"];
|
|
234
|
+
const triggers = container.querySelectorAll("[role=tab]");
|
|
235
|
+
const panels = container.querySelectorAll("[role=tabpanel]");
|
|
236
|
+
const popoverItems = container.querySelectorAll("[data-popover-item]");
|
|
237
|
+
|
|
238
|
+
let activeTrigger: HTMLElement | null = null;
|
|
239
|
+
|
|
240
|
+
const syncState = (targetValue: string | undefined) => {
|
|
241
|
+
triggers.forEach(trigger => {
|
|
242
|
+
const el = trigger as HTMLElement;
|
|
243
|
+
const val = el.dataset["value"];
|
|
244
|
+
const isActive = val === targetValue;
|
|
245
|
+
el.setAttribute("data-state", isActive ? "active" : "inactive");
|
|
246
|
+
if (isActive) activeTrigger = el;
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
popoverItems.forEach(item => {
|
|
250
|
+
const el = item as HTMLElement;
|
|
251
|
+
const val = el.dataset["tabOverflowValue"];
|
|
252
|
+
if (val === targetValue) {
|
|
253
|
+
el.setAttribute("data-active", "true");
|
|
254
|
+
el.classList.add("bg-muted/80", "font-medium");
|
|
255
|
+
} else {
|
|
256
|
+
el.removeAttribute("data-active");
|
|
257
|
+
el.classList.remove("bg-muted/80", "font-medium");
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
panels.forEach(panel => {
|
|
262
|
+
const val = (panel as HTMLElement).dataset["value"];
|
|
263
|
+
if (val === targetValue) {
|
|
264
|
+
panel.removeAttribute("hidden");
|
|
265
|
+
} else {
|
|
266
|
+
panel.setAttribute("hidden", "until-found");
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
syncState(containerValue);
|
|
272
|
+
|
|
273
|
+
requestAnimationFrame(() => updateIndicator(activeTrigger));
|
|
274
|
+
|
|
275
|
+
if (window.ResizeObserver && list) {
|
|
276
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
277
|
+
const currentActive = list.querySelector("[role=tab][data-state=active]") as HTMLElement | null;
|
|
278
|
+
updateIndicator(currentActive);
|
|
279
|
+
});
|
|
280
|
+
this.resizeObserver.observe(list);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const clickCleanups: (() => void)[] = [];
|
|
284
|
+
const beforeMatchCleanups: (() => void)[] = [];
|
|
285
|
+
|
|
286
|
+
// Watch for browser Find-in-Page auto-expands
|
|
287
|
+
panels.forEach(panel => {
|
|
288
|
+
const onBeforeMatch = () => {
|
|
289
|
+
const targetValue = (panel as HTMLElement).dataset["value"];
|
|
290
|
+
const trigger = container.querySelector(`[role=tab][data-value="${targetValue}"]`) as HTMLButtonElement | null;
|
|
291
|
+
if (trigger) {
|
|
292
|
+
trigger.click();
|
|
293
|
+
} else {
|
|
294
|
+
syncState(targetValue);
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
panel.addEventListener("beforematch", onBeforeMatch);
|
|
298
|
+
beforeMatchCleanups.push(() => panel.removeEventListener("beforematch", onBeforeMatch));
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
triggers.forEach(triggerNode => {
|
|
302
|
+
const trigger = triggerNode as HTMLButtonElement;
|
|
303
|
+
const onClick = () => {
|
|
304
|
+
if (trigger.disabled) return;
|
|
305
|
+
const targetValue = trigger.dataset["value"];
|
|
306
|
+
syncState(targetValue);
|
|
307
|
+
updateIndicator(trigger);
|
|
308
|
+
};
|
|
309
|
+
trigger.addEventListener("click", onClick);
|
|
310
|
+
clickCleanups.push(() => trigger.removeEventListener("click", onClick));
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
popoverItems.forEach(itemNode => {
|
|
314
|
+
const item = itemNode as HTMLButtonElement;
|
|
315
|
+
const onClick = () => {
|
|
316
|
+
const targetValue = item.dataset["tabOverflowValue"];
|
|
317
|
+
syncState(targetValue);
|
|
318
|
+
const activeTrig = container.querySelector(`[role=tab][data-value="${targetValue}"]`) as HTMLElement | null;
|
|
319
|
+
updateIndicator(activeTrig);
|
|
320
|
+
// Hide popover after selection
|
|
321
|
+
const popover = item.closest('[popover]') as HTMLElement | null;
|
|
322
|
+
if (popover && 'hidePopover' in popover) {
|
|
323
|
+
(popover as any).hidePopover();
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
item.addEventListener("click", onClick);
|
|
327
|
+
clickCleanups.push(() => item.removeEventListener("click", onClick));
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
this.tabsCleanup = () => {
|
|
331
|
+
clickCleanups.forEach(fn => fn());
|
|
332
|
+
beforeMatchCleanups.forEach(fn => fn());
|
|
333
|
+
if (this.resizeObserver) {
|
|
334
|
+
this.resizeObserver.disconnect();
|
|
335
|
+
this.resizeObserver = null;
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
disconnectedCallback() {
|
|
341
|
+
if (this.tabsCleanup) {
|
|
342
|
+
this.tabsCleanup();
|
|
343
|
+
this.tabsCleanup = null;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (!customElements.get('rla-tabs')) {
|
|
349
|
+
customElements.define('rla-tabs', RLATabs);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
</script>
|