@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.
Files changed (43) hide show
  1. package/package.json +3 -3
  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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rimelight/ui",
3
- "version": "0.0.57",
3
+ "version": "0.0.58",
4
4
  "private": false,
5
5
  "description": "Rimelight Entertainment's UI Package",
6
6
  "homepage": "https://rimelight.com/docs",
@@ -63,7 +63,7 @@
63
63
  "@astrojs/solid-js": "7.0.2",
64
64
  "@astrojs/ts-plugin": "1.10.12",
65
65
  "@astrojs/vue": "7.0.3",
66
- "@rimelight/config": "0.0.15",
66
+ "@rimelight/config": "0.0.18",
67
67
  "@vitejs/plugin-vue": "6.0.9",
68
68
  "astro": "7.3.3",
69
69
  "solid-js": "1.9.15",
@@ -93,7 +93,7 @@
93
93
  }
94
94
  },
95
95
  "engines": {
96
- "node": ">=26.8.2"
96
+ "node": ">=26.9.0"
97
97
  },
98
98
  "scripts": {
99
99
  "build": "vp pack",
@@ -47,7 +47,64 @@ export const avatarTheme = defineTheme("avatar", {
47
47
  "3xl": {
48
48
  root: "size-12 text-2xl",
49
49
  badge: "size-4"
50
- }
50
+ },
51
+ "4xl": {
52
+ root: "size-14 text-3xl",
53
+ badge: "size-4.5"
54
+ },
55
+ "5xl": {
56
+ root: "size-16 text-3xl",
57
+ badge: "size-5"
58
+ },
59
+ "6xl": {
60
+ root: "size-20 text-4xl",
61
+ badge: "size-6"
62
+ },
63
+ "7xl": {
64
+ root: "size-24 text-5xl",
65
+ badge: "size-7"
66
+ },
67
+ "8xl": {
68
+ root: "size-28 text-6xl",
69
+ badge: "size-8"
70
+ },
71
+ "9xl": {
72
+ root: "size-32 text-7xl",
73
+ badge: "size-9"
74
+ },
75
+ "10xl": {
76
+ root: "size-36 text-7xl",
77
+ badge: "size-10"
78
+ },
79
+ "11xl": {
80
+ root: "size-40 text-8xl",
81
+ badge: "size-10"
82
+ },
83
+ "12xl": {
84
+ root: "size-48 text-9xl",
85
+ badge: "size-12"
86
+ },
87
+ "4": { root: "size-4 text-[8px]", badge: "size-1.5" },
88
+ "5": { root: "size-5 text-[10px]", badge: "size-2" },
89
+ "6": { root: "size-6 text-xs", badge: "size-2" },
90
+ "7": { root: "size-7 text-sm", badge: "size-2.5" },
91
+ "8": { root: "size-8 text-base", badge: "size-3" },
92
+ "9": { root: "size-9 text-lg", badge: "size-3" },
93
+ "10": { root: "size-10 text-xl", badge: "size-3.5" },
94
+ "11": { root: "size-11 text-[22px]", badge: "size-4" },
95
+ "12": { root: "size-12 text-2xl", badge: "size-4" },
96
+ "14": { root: "size-14 text-3xl", badge: "size-4.5" },
97
+ "16": { root: "size-16 text-3xl", badge: "size-5" },
98
+ "20": { root: "size-20 text-4xl", badge: "size-6" },
99
+ "24": { root: "size-24 text-5xl", badge: "size-7" },
100
+ "28": { root: "size-28 text-6xl", badge: "size-8" },
101
+ "32": { root: "size-32 text-7xl", badge: "size-9" },
102
+ "36": { root: "size-36 text-7xl", badge: "size-10" },
103
+ "40": { root: "size-40 text-8xl", badge: "size-10" },
104
+ "48": { root: "size-48 text-9xl", badge: "size-12" },
105
+ "56": { root: "size-56 text-9xl", badge: "size-14" },
106
+ "64": { root: "size-64 text-9xl", badge: "size-16" },
107
+ "128": { root: "size-32 text-7xl", badge: "size-9" }
51
108
  },
52
109
  badgePosition: {
53
110
  "top-right": { badge: "top-0 right-0" },
@@ -16,7 +16,27 @@ export interface AvatarProps {
16
16
  /**
17
17
  * @default "md"
18
18
  */
19
- size?: "3xs" | "2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | undefined
19
+ size?:
20
+ | "3xs"
21
+ | "2xs"
22
+ | "xs"
23
+ | "sm"
24
+ | "md"
25
+ | "lg"
26
+ | "xl"
27
+ | "2xl"
28
+ | "3xl"
29
+ | "4xl"
30
+ | "5xl"
31
+ | "6xl"
32
+ | "7xl"
33
+ | "8xl"
34
+ | "9xl"
35
+ | "10xl"
36
+ | "11xl"
37
+ | "12xl"
38
+ | (string & {})
39
+ | undefined
20
40
  /**
21
41
  * @default "neutral"
22
42
  */
@@ -3,8 +3,6 @@ import type { AvatarGroupProps } from "./avatar-group"
3
3
  import { avatarGroupTheme } from "./avatar-group.theme"
4
4
  import RLAAvatar from "../avatar/RLAAvatar.astro"
5
5
 
6
-
7
-
8
6
  const {
9
7
  items,
10
8
  displayLimit = 5,
@@ -14,175 +12,53 @@ const {
14
12
 
15
13
  const classes = avatarGroupTheme(Astro.props)
16
14
 
17
- // ─── Responsive CSS Item Counter ────────────────────────────────────────────
18
- //
19
- // Technique: CSS Container Queries + Custom Properties + CSS Counters.
20
- //
21
- // 1. Server-side: compute baseHiddenCount = max(0, total - displayLimit).
22
- // Set --base-hidden on the list element.
23
- // 2. Per-instance container queries: as the container shrinks, each breakpoint
24
- // hides one more avatar (nth-child) and bumps --hidden-items.
25
- // 3. CSS counter: "+N more" = counter-reset: calc(--base-hidden + --hidden-items).
26
- // Entirely CSS arithmetic — zero JS resize observers.
27
- //
28
- // ─────────────────────────────────────────────────────────────────────────────
29
-
30
- const uid = Math.random().toString(36).substring(2, 9)
31
- const cName = `rla-ag-${uid}` // unique CSS container-name
32
-
33
- // Avatar pixel sizes (matching avatar.theme.ts size variants)
34
- const sizePx: Record<string, number> = {
35
- "3xs": 16, "2xs": 20, "xs": 24, "sm": 28,
36
- "md": 32, "lg": 36, "xl": 40, "2xl": 44, "3xl": 48
37
- }
38
- // UnoCSS utility classes for the "+more" bubble sized to match the avatar
39
15
  const sizeCls: Record<string, string> = {
40
- "3xs": "size-4 text-[7px]", "2xs": "size-5 text-[8px]",
41
- "xs": "size-6 text-[9px]", "sm": "size-7 text-[10px]",
42
- "md": "size-8 text-[11px]", "lg": "size-9 text-xs",
43
- "xl": "size-10 text-xs", "2xl": "size-11 text-sm", "3xl": "size-12 text-sm"
16
+ "3xs": "size-4 text-[7px]",
17
+ "2xs": "size-5 text-[8px]",
18
+ "xs": "size-6 text-[9px]",
19
+ "sm": "size-7 text-[10px]",
20
+ "md": "size-8 text-[11px]",
21
+ "lg": "size-9 text-xs",
22
+ "xl": "size-10 text-xs",
23
+ "2xl": "size-11 text-sm",
24
+ "3xl": "size-12 text-sm"
44
25
  }
45
26
 
46
- const avatarPx = sizePx[size] ?? 32
47
- const overlapPx = 12 // -space-x-3 = -0.75rem = 12px
48
- const effectivePx = avatarPx - overlapPx // width each extra avatar adds
49
- const morePx = avatarPx + 4 // "+more" bubble ~= avatar with tiny padding
50
-
51
27
  const normalizedItems = items ?? []
52
- const renderedItems = normalizedItems.slice(0, displayLimit)
53
- const baseHiddenCount = Math.max(0, normalizedItems.length - displayLimit)
54
-
55
- // We need an overflow indicator when total ≥ displayLimit so that even when
56
- // base-hidden is 0, CSS breakpoints can still surface the "+N more" bubble.
57
- const needsOverflow = normalizedItems.length >= displayLimit
58
-
59
- // ── Generate per-instance container-query CSS ────────────────────────────────
60
- // Each breakpoint hides exactly ONE new nth-child (CSS cascade accumulates them).
61
- //
62
- // Breakpoint i (0-indexed):
63
- // hiddenItems = i + 1 → value set on --hidden-items
64
- // visibleCount = rendered - hiddenItems → avatars still showing
65
- // maxWidth = width of visibleCount avatars + more bubble
66
- // hideNthChild = rendered - i → the avatar position to newly hide
67
- //
68
- // At container width W:
69
- // every breakpoint with maxWidth ≥ W matches.
70
- // Each matching rule adds one hidden nth-child and raises --hidden-items.
71
- // The LAST matching rule's --hidden-items wins (correct, since smaller
72
- // containers match more rules and the last has the highest count).
73
- // ─────────────────────────────────────────────────────────────────────────────
74
- let instanceCss = ""
75
- if (needsOverflow && renderedItems.length > 1) {
76
- const maxBreaks = renderedItems.length - 1 // keep at least 1 avatar always
77
- for (let i = 0; i < maxBreaks; i++) {
78
- const hiddenItems = i + 1
79
- const visibleCount = renderedItems.length - hiddenItems
80
- // Min container width for this many avatars + the more bubble
81
- const maxWidth = avatarPx + Math.max(0, visibleCount - 1) * effectivePx + morePx + 4
82
- const hideNthChild = renderedItems.length - i // count from end
83
-
84
- instanceCss += `\n@container ${cName} (max-width: ${maxWidth}px) {`
85
- instanceCss += `\n [data-ag="${uid}"] { --hidden-items: ${hiddenItems}; }`
86
- instanceCss += `\n [data-ag="${uid}"] > .rla-ag-item.hidable:nth-child(${hideNthChild}) { display: none; }`
87
- // When base-hidden is 0, the bubble starts hidden; show it once a breakpoint fires
88
- if (baseHiddenCount === 0) {
89
- instanceCss += `\n [data-ag="${uid}"] > .rla-ag-more-hidden { display: inline-flex; }`
90
- }
91
- instanceCss += `\n}`
92
- }
93
- }
28
+ const renderedItems = normalizedItems.slice(0, displayLimit)
29
+ const hiddenCount = normalizedItems.length - displayLimit
94
30
  ---
95
31
 
96
32
  {normalizedItems.length > 0 ? (
97
- <div
98
- class="rla-ag-host"
99
- style={`container-type: inline-size; container-name: ${cName};`}
100
- {...rest}
101
- >
102
- <div
103
- class:list={[classes.root, "rla-ag-list"]}
104
- data-slot="avatar-group"
105
- data-ag={uid}
106
- style={`--base-hidden: ${baseHiddenCount}; --hidden-items: 0;`}
107
- >
108
- {renderedItems.map((item, idx) => (
109
- <span class:list={["rla-ag-item", needsOverflow && idx > 0 && "hidable"]}>
110
- <RLAAvatar
111
- src={item.src}
112
- alt={item.alt ?? ""}
113
- fallback={item.fallback}
114
- initials={item.initials}
115
- size={size}
116
- color={(item.color ?? "neutral") as any}
117
- />
118
- </span>
119
- ))}
120
-
121
- {needsOverflow && (
122
- <span
123
- class:list={[
124
- classes.more,
125
- sizeCls[size] ?? sizeCls["md"],
126
- "rla-ag-more",
127
- baseHiddenCount === 0 && "rla-ag-more-hidden"
128
- ]}
129
- aria-hidden="true"
130
- data-slot="more"
131
- >
132
- +<span class="rla-ag-count" />
133
- </span>
134
- )}
135
- </div>
33
+ <div class:list={[classes.root]} data-slot="avatar-group" {...rest}>
34
+ {renderedItems.map((item) => (
35
+ <span class="inline-flex shrink-0">
36
+ <RLAAvatar
37
+ src={item.src}
38
+ alt={item.alt ?? ""}
39
+ fallback={item.fallback}
40
+ initials={item.initials}
41
+ size={size}
42
+ color={(item.color ?? "neutral") as any}
43
+ />
44
+ </span>
45
+ ))}
46
+
47
+ {hiddenCount > 0 && (
48
+ <span
49
+ class:list={[
50
+ classes.more,
51
+ sizeCls[size] ?? sizeCls["md"]
52
+ ]}
53
+ aria-hidden="true"
54
+ data-slot="more"
55
+ >
56
+ +{hiddenCount}
57
+ </span>
58
+ )}
136
59
  </div>
137
60
  ) : (
138
61
  <div class={classes.root} data-slot="avatar-group" {...rest}>
139
62
  <slot />
140
63
  </div>
141
64
  )}
142
-
143
- <!-- Per-instance container-query CSS (scoped via unique data-ag attribute) -->
144
- <style is:inline set:html={instanceCss} />
145
-
146
- <style>
147
- .rla-ag-host {
148
- /* Inline so the group doesn't stretch to full column width */
149
- display: inline-block;
150
- }
151
-
152
- .rla-ag-item {
153
- display: inline-flex;
154
- flex-shrink: 0;
155
- }
156
-
157
- /* "+more" bubble — base styles; size/color come from theme + sizeCls above */
158
- .rla-ag-more {
159
- display: inline-flex;
160
- align-items: center;
161
- justify-content: center;
162
- flex-shrink: 0;
163
- white-space: nowrap;
164
- font-feature-settings: "tnum";
165
- }
166
-
167
- /* Hidden by default when base-hidden is 0 (no pre-truncation).
168
- Container queries restore display when responsive hiding fires. */
169
- .rla-ag-more-hidden {
170
- display: none;
171
- }
172
-
173
- /*
174
- * CSS Counter — the entire "+N" calculation happens here.
175
- *
176
- * counter-reset creates a named counter with an initial value equal to
177
- * the sum of:
178
- * --base-hidden (set at render time: total - displayLimit)
179
- * --hidden-items (set by container queries: how many are responsively hidden)
180
- *
181
- * The `content` property reads it back as a string.
182
- * Zero JS arithmetic. Automatic — no resize observers.
183
- */
184
- .rla-ag-count::after {
185
- counter-reset: rla-ag-cnt calc(var(--base-hidden, 0) + var(--hidden-items, 0));
186
- content: counter(rla-ag-cnt);
187
- }
188
- </style>
@@ -7,18 +7,6 @@ export interface RLSAvatarGroupProps extends AvatarGroupProps {
7
7
  children?: JSX.Element
8
8
  }
9
9
 
10
- const sizePx: Record<string, number> = {
11
- "3xs": 16,
12
- "2xs": 20,
13
- "xs": 24,
14
- "sm": 28,
15
- "md": 32,
16
- "lg": 36,
17
- "xl": 40,
18
- "2xl": 44,
19
- "3xl": 48
20
- }
21
-
22
10
  const sizeCls: Record<string, string> = {
23
11
  "3xs": "size-4 text-[7px]",
24
12
  "2xs": "size-5 text-[8px]",
@@ -41,122 +29,50 @@ const RLSAvatarGroup: Component<RLSAvatarGroupProps> = (allProps) => {
41
29
  "children"
42
30
  ])
43
31
 
44
- const normalizedItems = props.items ?? []
45
- const displayLimit = props.displayLimit ?? 5
46
- const size = props.size ?? "md"
32
+ const normalizedItems = () => props.items ?? []
33
+ const displayLimit = () => props.displayLimit ?? 5
34
+ const size = () => props.size ?? "md"
47
35
 
48
36
  const resolvedClasses = createMemo(() => avatarGroupTheme({ ui: props.ui, class: props.class }))
49
37
 
50
- const uid = Math.random().toString(36).substring(2, 9)
51
- const cName = `rla-ag-${uid}`
52
-
53
- const avatarPx = sizePx[size] ?? 32
54
- const overlapPx = 12
55
- const effectivePx = avatarPx - overlapPx
56
- const morePx = avatarPx + 4
57
-
58
- const renderedItems = normalizedItems.slice(0, displayLimit)
59
- const baseHiddenCount = Math.max(0, normalizedItems.length - displayLimit)
60
- const needsOverflow = normalizedItems.length >= displayLimit
61
-
62
- let instanceCss = ""
63
- if (needsOverflow && renderedItems.length > 1) {
64
- const maxBreaks = renderedItems.length - 1
65
- for (let i = 0; i < maxBreaks; i++) {
66
- const hiddenItems = i + 1
67
- const visibleCount = renderedItems.length - hiddenItems
68
- const maxWidth = avatarPx + Math.max(0, visibleCount - 1) * effectivePx + morePx + 4
69
- const hideNthChild = renderedItems.length - i
38
+ const renderedItems = () => normalizedItems().slice(0, displayLimit())
39
+ const hiddenCount = () => normalizedItems().length - displayLimit()
70
40
 
71
- instanceCss += `\n@container ${cName} (max-width: ${maxWidth}px) {`
72
- instanceCss += `\n [data-ag="${uid}"] { --hidden-items: ${hiddenItems}; }`
73
- instanceCss += `\n [data-ag="${uid}"] > .rla-ag-item.hidable:nth-child(${hideNthChild}) { display: none; }`
74
- if (baseHiddenCount === 0) {
75
- instanceCss += `\n [data-ag="${uid}"] > .rla-ag-more-hidden { display: inline-flex; }`
76
- }
77
- instanceCss += `\n}`
78
- }
79
- }
80
-
81
- if (normalizedItems.length > 0) {
82
- return (
83
- <>
84
- <div
85
- class="rla-ag-host"
86
- style={`container-type: inline-size; container-name: ${cName};`}
87
- {...rest}
88
- >
89
- <div
90
- class={`${resolvedClasses().root} rla-ag-list`}
91
- data-slot="avatar-group"
92
- data-ag={uid}
93
- style={`--base-hidden: ${baseHiddenCount}; --hidden-items: 0;`}
94
- >
95
- <For each={renderedItems}>
96
- {(item, idx) => (
97
- <span class={needsOverflow && idx() > 0 ? "rla-ag-item hidable" : "rla-ag-item"}>
98
- <RLSAvatar
99
- src={item.src}
100
- alt={item.alt ?? ""}
101
- fallback={item.fallback}
102
- initials={item.initials}
103
- size={size}
104
- color={(item.color ?? "neutral") as any}
105
- />
106
- </span>
107
- )}
108
- </For>
109
-
110
- {needsOverflow && (
111
- <span
112
- class={`${resolvedClasses().more} ${sizeCls[size] ?? sizeCls["md"]} rla-ag-more${baseHiddenCount === 0 ? " rla-ag-more-hidden" : ""}`}
113
- aria-hidden="true"
114
- data-slot="more"
115
- >
116
- +<span class="rla-ag-count" />
41
+ return (
42
+ <>
43
+ {normalizedItems().length > 0 ? (
44
+ <div class={resolvedClasses().root} data-slot="avatar-group" {...rest}>
45
+ <For each={renderedItems()}>
46
+ {(item) => (
47
+ <span class="inline-flex shrink-0">
48
+ <RLSAvatar
49
+ src={item.src}
50
+ alt={item.alt ?? ""}
51
+ fallback={item.fallback}
52
+ initials={item.initials}
53
+ size={size()}
54
+ color={(item.color ?? "neutral") as any}
55
+ />
117
56
  </span>
118
57
  )}
119
- </div>
58
+ </For>
59
+
60
+ {hiddenCount() > 0 && (
61
+ <span
62
+ class={`${resolvedClasses().more} ${sizeCls[size()] ?? sizeCls["md"]}`}
63
+ aria-hidden="true"
64
+ data-slot="more"
65
+ >
66
+ +{hiddenCount()}
67
+ </span>
68
+ )}
120
69
  </div>
121
-
122
- <style>{instanceCss}</style>
123
-
124
- <style>{`
125
- .rla-ag-host {
126
- display: inline-block;
127
- }
128
-
129
- .rla-ag-item {
130
- display: inline-flex;
131
- flex-shrink: 0;
132
- }
133
-
134
- .rla-ag-more {
135
- display: inline-flex;
136
- align-items: center;
137
- justify-content: center;
138
- flex-shrink: 0;
139
- white-space: nowrap;
140
- font-feature-settings: "tnum";
141
- }
142
-
143
- .rla-ag-more-hidden {
144
- display: none;
145
- }
146
-
147
- .rla-ag-count::after {
148
- counter-reset: rla-ag-cnt calc(var(--base-hidden, 0) + var(--hidden-items, 0));
149
- content: counter(rla-ag-cnt);
150
- }
151
- `}</style>
152
- </>
153
- )
154
- }
155
-
156
- return (
157
- <div class={resolvedClasses().root} data-slot="avatar-group" {...rest}>
158
- {props.children}
159
- </div>
70
+ ) : (
71
+ <div class={resolvedClasses().root} data-slot="avatar-group" {...rest}>
72
+ {props.children}
73
+ </div>
74
+ )}
75
+ </>
160
76
  )
161
77
  }
162
78