@rimelight/ui 0.0.47 → 0.0.48

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 (197) hide show
  1. package/dist/index.d.mts +4 -5
  2. package/dist/preset.mjs +73 -1
  3. package/dist/resolver.d.mts +3 -4
  4. package/dist/resolver.mjs +2 -4
  5. package/dist/shortcuts.d.mts +10 -11
  6. package/dist/stores.d.mts +3 -4
  7. package/package.json +8 -6
  8. package/src/components/3d-hover/RLS3dHover.tsx +21 -0
  9. package/src/components/accordion/RLSAccordion.tsx +112 -0
  10. package/src/components/app/RLSApp.tsx +21 -0
  11. package/src/components/aspect-ratio/RLSAspectRatio.tsx +30 -0
  12. package/src/components/audio/RLSAudio.tsx +27 -0
  13. package/src/components/avatar/RLSAvatar.tsx +142 -0
  14. package/src/components/avatar/avatar.ts +22 -21
  15. package/src/components/avatar-group/RLSAvatarGroup.tsx +163 -0
  16. package/src/components/badge/RLSBadge.tsx +1 -1
  17. package/src/components/badge/RLVBadge.vue +5 -3
  18. package/src/components/banner/RLSBanner.tsx +151 -0
  19. package/src/components/breadcrumb/RLSBreadcrumb.tsx +194 -0
  20. package/src/components/browser-mockup/RLSBrowserMockup.tsx +21 -0
  21. package/src/components/button/RLSButton.tsx +49 -40
  22. package/src/components/button/RLVButton.vue +44 -32
  23. package/src/components/calendar/RLSCalendar.tsx +26 -0
  24. package/src/components/callout/RLSCallout.tsx +151 -0
  25. package/src/components/card/RLSCard.tsx +4 -0
  26. package/src/components/card/RLVCard.vue +4 -0
  27. package/src/components/card/card.ts +10 -0
  28. package/src/components/carousel/RLACarousel.astro +14 -1
  29. package/src/components/carousel/RLSCarousel.tsx +260 -0
  30. package/src/components/chart/RLSChart.tsx +299 -0
  31. package/src/components/chat/RLSChat.tsx +27 -0
  32. package/src/components/chat-message/RLSChatMessage.tsx +27 -0
  33. package/src/components/chat-messages/RLSChatMessages.tsx +27 -0
  34. package/src/components/chat-palette/RLSChatPalette.tsx +27 -0
  35. package/src/components/chat-prompt/RLSChatPrompt.tsx +27 -0
  36. package/src/components/chat-prompt-submit/RLSChatPromptSubmit.tsx +27 -0
  37. package/src/components/chat-reasoning/RLSChatReasoning.tsx +27 -0
  38. package/src/components/chat-shimmer/RLSChatShimmer.tsx +27 -0
  39. package/src/components/chat-tool/RLSChatTool.tsx +27 -0
  40. package/src/components/checkbox/RLACheckbox.astro +1 -0
  41. package/src/components/checkbox/RLSCheckbox.tsx +1 -1
  42. package/src/components/checkbox/checkbox.theme.ts +2 -2
  43. package/src/components/chip/RLSChip.tsx +65 -0
  44. package/src/components/collapsible/RLSCollapsible.tsx +89 -0
  45. package/src/components/color-area/RLSColorArea.tsx +554 -0
  46. package/src/components/color-field/RLSColorField.tsx +236 -0
  47. package/src/components/color-picker/RLSColorPicker.tsx +26 -0
  48. package/src/components/color-slider/RLSColorSlider.tsx +373 -0
  49. package/src/components/command-palette/RLSCommandPalette.tsx +26 -0
  50. package/src/components/compare/RLSCompare.tsx +26 -0
  51. package/src/components/confirm/RLSConfirm.tsx +173 -0
  52. package/src/components/container/RLSContainer.tsx +24 -0
  53. package/src/components/context-menu/RLSContextMenu.tsx +26 -0
  54. package/src/components/copy-markdown/RLSCopyMarkdown.tsx +57 -0
  55. package/src/components/dashboard-group/RLSDashboardGroup.tsx +29 -0
  56. package/src/components/dashboard-navbar/RLSDashboardNavbar.tsx +116 -0
  57. package/src/components/dashboard-panel/RLSDashboardPanel.tsx +84 -0
  58. package/src/components/dashboard-resize-handle/RLSDashboardResizeHandle.tsx +35 -0
  59. package/src/components/dashboard-search/RLADashboardSearch.astro +1 -1
  60. package/src/components/dashboard-search/RLSDashboardSearch.tsx +125 -0
  61. package/src/components/dashboard-search-button/RLSDashboardSearchButton.tsx +82 -0
  62. package/src/components/dashboard-sidebar/RLSDashboardSidebar.tsx +184 -0
  63. package/src/components/dashboard-sidebar-collapse/RLSDashboardSidebarCollapse.tsx +46 -0
  64. package/src/components/dashboard-sidebar-toggle/RLSDashboardSidebarToggle.tsx +35 -0
  65. package/src/components/dashboard-toolbar/RLSDashboardToolbar.tsx +49 -0
  66. package/src/components/date/RLSDate.tsx +34 -0
  67. package/src/components/dock/RLSDock.tsx +26 -0
  68. package/src/components/drawer/RLSDrawer.tsx +177 -0
  69. package/src/components/dropdown-menu/RLADropdownMenu.astro +250 -241
  70. package/src/components/dropdown-menu/RLSDropdownMenu.tsx +183 -86
  71. package/src/components/editor/RLSEditor.tsx +26 -0
  72. package/src/components/empty/RLSEmpty.tsx +132 -0
  73. package/src/components/error/RLSError.tsx +26 -0
  74. package/src/components/field-group/RLSFieldGroup.tsx +46 -0
  75. package/src/components/fieldset/RLSFieldset.tsx +26 -0
  76. package/src/components/file-upload/RLSFileUpload.tsx +163 -0
  77. package/src/components/floating-action/RLSFloatingAction.tsx +26 -0
  78. package/src/components/footer/RLSFooter.tsx +56 -0
  79. package/src/components/form/RLSForm.tsx +34 -0
  80. package/src/components/gallery/RLSGallery.tsx +21 -0
  81. package/src/components/gamepad/RLSGamepad.tsx +269 -0
  82. package/src/components/grid/RLSGrid.tsx +29 -0
  83. package/src/components/head/RLAHead.astro +9 -0
  84. package/src/components/head/RLSHead.tsx +42 -0
  85. package/src/components/head/UIHead.astro +3 -0
  86. package/src/components/header/RLSHeader.tsx +87 -0
  87. package/src/components/hover-card/RLSHoverCard.tsx +72 -0
  88. package/src/components/icon/RLSIcon.tsx +3 -1
  89. package/src/components/image/RLAImage.astro +447 -138
  90. package/src/components/image/RLSImage.tsx +545 -0
  91. package/src/components/image/image.theme.ts +19 -3
  92. package/src/components/image/image.ts +31 -1
  93. package/src/components/input/RLAInput.astro +62 -51
  94. package/src/components/input/RLSInput.tsx +1 -1
  95. package/src/components/input-date/RLSInputDate.tsx +92 -0
  96. package/src/components/input-menu/RLSInputMenu.tsx +199 -0
  97. package/src/components/input-number/RLSInputNumber.tsx +184 -0
  98. package/src/components/input-pin/RLSInputPin.tsx +185 -0
  99. package/src/components/input-rating/RLSInputRating.tsx +198 -0
  100. package/src/components/input-rating/input-rating.ts +4 -0
  101. package/src/components/input-tags/RLSInputTags.tsx +94 -0
  102. package/src/components/input-time/RLSInputTime.tsx +92 -0
  103. package/src/components/kbd/RLSKbd.tsx +37 -0
  104. package/src/components/keyboard/RLSKeyboard.tsx +476 -0
  105. package/src/components/knob/RLSKnob.tsx +27 -0
  106. package/src/components/label/RLSLabel.tsx +27 -0
  107. package/src/components/layout-grid/RLSLayoutGrid.tsx +402 -0
  108. package/src/components/layout-grid/layout-grid.ts +25 -1
  109. package/src/components/link/RLSLink.tsx +2 -1
  110. package/src/components/link/link.ts +21 -12
  111. package/src/components/link-group/RLSLinkGroup.tsx +76 -0
  112. package/src/components/listbox/RLSListbox.tsx +27 -0
  113. package/src/components/locale-selector/RLALocaleSelector.astro +2 -1
  114. package/src/components/locale-selector/RLSLocaleSelector.tsx +178 -0
  115. package/src/components/logo/RLALogo.astro +69 -4
  116. package/src/components/logo/RLSLogo.tsx +129 -0
  117. package/src/components/main/RLSMain.tsx +40 -0
  118. package/src/components/marquee/RLSMarquee.tsx +80 -0
  119. package/src/components/meter/RLSMeter.tsx +27 -0
  120. package/src/components/modal/RLAModal.astro +1 -1
  121. package/src/components/modal/RLSModal.tsx +109 -72
  122. package/src/components/navigation-menu/RLSNavigationMenu.tsx +228 -0
  123. package/src/components/navigation-menu/navigation-menu.ts +2 -2
  124. package/src/components/package-managers/RLSPackageManagers.tsx +204 -0
  125. package/src/components/page/RLSPage.tsx +21 -0
  126. package/src/components/page-aside/RLSPageAside.tsx +21 -0
  127. package/src/components/page-body/RLSPageBody.tsx +21 -0
  128. package/src/components/page-header/RLSPageHeader.tsx +21 -0
  129. package/src/components/page-section/RLSPageSection.tsx +201 -0
  130. package/src/components/pagination/RLSPagination.tsx +114 -0
  131. package/src/components/password/RLSPassword.tsx +27 -0
  132. package/src/components/phone-mockup/RLSPhoneMockup.tsx +27 -0
  133. package/src/components/placeholder/RLSPlaceholder.tsx +47 -0
  134. package/src/components/popover/RLSPopover.tsx +124 -0
  135. package/src/components/post/RLSPost.tsx +134 -0
  136. package/src/components/pricing-plan/RLSPricingPlan.tsx +26 -0
  137. package/src/components/pricing-table/RLSPricingTable.tsx +26 -0
  138. package/src/components/progress/RLSProgress.tsx +53 -0
  139. package/src/components/prose/RLSProse.tsx +26 -0
  140. package/src/components/qr-code/RLSQrCode.tsx +26 -0
  141. package/src/components/quote/RLAQuote.astro +10 -6
  142. package/src/components/quote/RLSQuote.tsx +37 -0
  143. package/src/components/quote/quote.theme.ts +5 -2
  144. package/src/components/radio-group/RLSRadioGroup.tsx +37 -0
  145. package/src/components/rating/RLSRating.tsx +27 -0
  146. package/src/components/scroll-area/RLSScrollArea.tsx +210 -0
  147. package/src/components/scroll-to-top/RLAScrollToTop.astro +1 -0
  148. package/src/components/scroll-to-top/RLSScrollToTop.tsx +145 -0
  149. package/src/components/search/RLSSearch.tsx +237 -0
  150. package/src/components/select/RLASelect.astro +67 -4
  151. package/src/components/select/RLSSelect.tsx +107 -39
  152. package/src/components/select/RLVSelect.vue +50 -1
  153. package/src/components/select/select.theme.ts +30 -10
  154. package/src/components/select/select.ts +20 -1
  155. package/src/components/separator/RLSSeparator.tsx +92 -0
  156. package/src/components/share/RLSShare.tsx +66 -0
  157. package/src/components/shortcuts/RLSShortcuts.tsx +393 -0
  158. package/src/components/sidebar/RLSSidebar.tsx +271 -0
  159. package/src/components/skeleton/RLSSkeleton.tsx +21 -0
  160. package/src/components/slideover/RLASlideover.astro +1 -1
  161. package/src/components/slideover/RLSSlideover.tsx +159 -0
  162. package/src/components/slider/RLSSlider.tsx +112 -0
  163. package/src/components/speed-dial/RLSSpeedDial.tsx +27 -0
  164. package/src/components/spinner/RLSSpinner.tsx +22 -0
  165. package/src/components/splitter/RLSSplitter.tsx +178 -0
  166. package/src/components/spoiler/RLSSpoiler.tsx +26 -0
  167. package/src/components/stepper/RLSStepper.tsx +205 -0
  168. package/src/components/steps/RLSSteps.tsx +108 -0
  169. package/src/components/sticky-surface/RLSStickySurface.tsx +63 -0
  170. package/src/components/surround/RLSSurround.tsx +57 -0
  171. package/src/components/switch/RLSSwitch.tsx +56 -0
  172. package/src/components/table/RLATable.astro +1044 -579
  173. package/src/components/table/RLSTable.tsx +893 -0
  174. package/src/components/table/table.theme.ts +47 -16
  175. package/src/components/table/table.ts +104 -66
  176. package/src/components/table-of-contents/RLSTableOfContents.tsx +196 -0
  177. package/src/components/tabs/RLSTabs.tsx +298 -0
  178. package/src/components/textarea/RLATextarea.astro +1 -0
  179. package/src/components/textarea/RLSTextarea.tsx +3 -1
  180. package/src/components/theme-selector/RLAThemeSelector.astro +85 -56
  181. package/src/components/theme-selector/RLSThemeSelector.tsx +131 -0
  182. package/src/components/theme-selector/theme-selector.theme.ts +5 -7
  183. package/src/components/theme-selector/theme-selector.ts +11 -1
  184. package/src/components/timeline/RLSTimeline.tsx +171 -0
  185. package/src/components/toast/RLSToast.tsx +179 -0
  186. package/src/components/toaster/RLSToaster.tsx +82 -0
  187. package/src/components/tooltip/RLSTooltip.tsx +48 -0
  188. package/src/components/tour/RLSTour.tsx +26 -0
  189. package/src/components/tree/RLSTree.tsx +26 -0
  190. package/src/components/user/RLSUser.tsx +26 -0
  191. package/src/components/video/RLAVideo.astro +4 -1
  192. package/src/components/video/RLSVideo.tsx +158 -0
  193. package/src/components/watermark/RLSWatermark.tsx +27 -0
  194. package/src/components/window-mockup/RLSWindowMockup.tsx +27 -0
  195. package/src/preset.ts +73 -1
  196. package/src/resolver.ts +6 -1
  197. package/src/virtual.d.ts +6 -0
@@ -0,0 +1,163 @@
1
+ import { createMemo, splitProps, For, type Component, type JSX } from "solid-js"
2
+ import type { AvatarGroupProps } from "./avatar-group"
3
+ import { avatarGroupTheme } from "./avatar-group.theme"
4
+ import RLSAvatar from "../avatar/RLSAvatar"
5
+
6
+ export interface RLSAvatarGroupProps extends AvatarGroupProps {
7
+ children?: JSX.Element
8
+ }
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
+ const sizeCls: Record<string, string> = {
23
+ "3xs": "size-4 text-[7px]",
24
+ "2xs": "size-5 text-[8px]",
25
+ "xs": "size-6 text-[9px]",
26
+ "sm": "size-7 text-[10px]",
27
+ "md": "size-8 text-[11px]",
28
+ "lg": "size-9 text-xs",
29
+ "xl": "size-10 text-xs",
30
+ "2xl": "size-11 text-sm",
31
+ "3xl": "size-12 text-sm"
32
+ }
33
+
34
+ const RLSAvatarGroup: Component<RLSAvatarGroupProps> = (allProps) => {
35
+ const [props, rest] = splitProps(allProps, [
36
+ "items",
37
+ "displayLimit",
38
+ "size",
39
+ "ui",
40
+ "class",
41
+ "children"
42
+ ])
43
+
44
+ const normalizedItems = props.items ?? []
45
+ const displayLimit = props.displayLimit ?? 5
46
+ const size = props.size ?? "md"
47
+
48
+ const resolvedClasses = createMemo(() => avatarGroupTheme({ ui: props.ui, class: props.class }))
49
+
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
70
+
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" />
117
+ </span>
118
+ )}
119
+ </div>
120
+ </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>
160
+ )
161
+ }
162
+
163
+ export default RLSAvatarGroup
@@ -32,7 +32,7 @@ const RLSBadge: Component<RLSBadgeProps> = (allProps) => {
32
32
  )
33
33
 
34
34
  return (
35
- <span class={resolvedClasses().root} data-slot="root" {...rest}>
35
+ <span class={resolvedClasses().root} data-slot="root" data-theme={props.theme} {...rest}>
36
36
  {props.children !== undefined && props.children !== null ? props.children : props.label}
37
37
  </span>
38
38
  )
@@ -11,7 +11,7 @@ const props = withDefaults(defineProps<BadgeProps>(), {
11
11
  variant: "solid",
12
12
  color: "primary",
13
13
  size: "md",
14
- shape: "rounded"
14
+ shape: "pill"
15
15
  })
16
16
 
17
17
  const resolvedClasses = computed(() =>
@@ -20,13 +20,15 @@ const resolvedClasses = computed(() =>
20
20
  color: props.color,
21
21
  size: props.size,
22
22
  shape: props.shape,
23
+ theme: props.theme,
24
+ ui: props.ui,
23
25
  class: props.class
24
26
  })
25
27
  )
26
28
  </script>
27
29
 
28
30
  <template>
29
- <span v-bind="attrs" :class="resolvedClasses.root" data-slot="root">
30
- <slot />
31
+ <span v-bind="attrs" :class="resolvedClasses.root" data-slot="root" :data-theme="theme">
32
+ <slot>{{ label }}</slot>
31
33
  </span>
32
34
  </template>
@@ -0,0 +1,151 @@
1
+ import { createMemo, createSignal, splitProps, For, Show, type Component, type JSX } from "solid-js"
2
+ import type { BannerAction, BannerProps } from "./banner"
3
+ import { bannerTheme } from "./banner.theme"
4
+ import RLSButton from "../button/RLSButton"
5
+
6
+ export interface RLSBannerProps extends BannerProps {
7
+ children?: JSX.Element
8
+ left?: JSX.Element
9
+ center?: JSX.Element
10
+ right?: JSX.Element
11
+ actions?: BannerAction[]
12
+ }
13
+
14
+ const RLSBanner: Component<RLSBannerProps> = (allProps) => {
15
+ const [props, rest] = splitProps(allProps, [
16
+ "contain",
17
+ "sticky",
18
+ "fixed",
19
+ "stackIndex",
20
+ "hideOnScroll",
21
+ "dismissable",
22
+ "dismissId",
23
+ "actions",
24
+ "ui",
25
+ "class",
26
+ "children",
27
+ "left",
28
+ "center",
29
+ "right"
30
+ ])
31
+
32
+ const classes = createMemo(() =>
33
+ bannerTheme({
34
+ contain: props.contain ?? true,
35
+ sticky: (props.fixed ?? true) ? false : (props.sticky ?? false),
36
+ fixed: props.fixed ?? true,
37
+ ui: props.ui,
38
+ class: props.class
39
+ })
40
+ )
41
+
42
+ const bannerId = (rest["id"] as string) || `rla-banner-${Math.random().toString(36).slice(2, 8)}`
43
+ const storageKey = props.dismissId || bannerId
44
+ const dismissKey = `rl-banner-dismiss-${storageKey}`
45
+ const actions = props.actions ?? []
46
+
47
+ const readDismissed = () => {
48
+ if (typeof window === "undefined") return false
49
+ try {
50
+ return window.localStorage.getItem(dismissKey) !== null
51
+ } catch {
52
+ return false
53
+ }
54
+ }
55
+
56
+ const [dismissed, setDismissed] = createSignal<boolean>(readDismissed())
57
+
58
+ const handleDismiss = () => {
59
+ try {
60
+ window.localStorage.setItem(dismissKey, "1")
61
+ } catch {}
62
+ setDismissed(true)
63
+ }
64
+
65
+ return (
66
+ <Show when={!dismissed()}>
67
+ <div
68
+ id={bannerId}
69
+ data-slot="root"
70
+ class={classes()["root"]}
71
+ data-contain={(props.contain ?? true) ? "true" : "false"}
72
+ data-rla-banner="true"
73
+ data-stack-index={props.stackIndex ?? 0}
74
+ data-hide-on-scroll={String(props.hideOnScroll ?? true)}
75
+ data-header-layer-id={bannerId}
76
+ data-layer-type="banner"
77
+ data-dismiss-key={dismissKey}
78
+ {...rest}
79
+ >
80
+ <div class={classes()["content"]} data-header-content>
81
+ <div class={classes()["container"]} data-slot="container">
82
+ <Show when={actions.length > 0}>
83
+ <input type="checkbox" id={`${bannerId}-act`} class="peer sr-only shrink-0" />
84
+ </Show>
85
+
86
+ <div class={`${classes()["left"]} peer-checked:hidden`} data-slot="left">
87
+ {props.left}
88
+ </div>
89
+ <div class={`${classes()["center"]} peer-checked:hidden`} data-slot="center">
90
+ {props.center !== undefined
91
+ ? props.center
92
+ : props.children !== undefined
93
+ ? props.children
94
+ : null}
95
+ </div>
96
+
97
+ <div class="flex-1"></div>
98
+
99
+ <div class={classes()["side"]}>{props.right}</div>
100
+
101
+ <Show when={actions.length > 0}>
102
+ <label
103
+ for={`${bannerId}-act`}
104
+ class="flex-none flex items-center justify-center size-7 rounded-md hover:bg-black/10 dark:hover:bg-white/10 cursor-pointer md:hidden text-sm leading-none peer-checked:order-first"
105
+ aria-label="Show actions"
106
+ >
107
+ ···
108
+ </label>
109
+
110
+ <div
111
+ class={`${classes()["actions"]} hidden peer-checked:flex md:flex flex-row items-center justify-center gap-2 peer-checked:order-first`}
112
+ >
113
+ <For each={actions}>
114
+ {(action) => (
115
+ <a
116
+ href={action.href || "#"}
117
+ class={`inline-flex items-center justify-center gap-1 px-3 py-1 rounded-md text-xs font-semibold transition-colors no-underline cursor-pointer shrink-0 ${
118
+ action.variant === "solid" || !action.variant
119
+ ? "bg-neutral-950 text-neutral-50 hover:opacity-90"
120
+ : "bg-white/20 text-white hover:bg-white/30"
121
+ } ${action.class ?? ""}`}
122
+ data-banner-action
123
+ >
124
+ {action.label}
125
+ </a>
126
+ )}
127
+ </For>
128
+ </div>
129
+ </Show>
130
+
131
+ <Show when={props.dismissable}>
132
+ <RLSButton
133
+ type="button"
134
+ variant="ghost"
135
+ color="neutral"
136
+ square
137
+ leadingIcon="close"
138
+ ariaLabel="Close banner"
139
+ class={classes()["dismiss"]}
140
+ data-banner-close
141
+ onClick={handleDismiss}
142
+ />
143
+ </Show>
144
+ </div>
145
+ </div>
146
+ </div>
147
+ </Show>
148
+ )
149
+ }
150
+
151
+ export default RLSBanner
@@ -0,0 +1,194 @@
1
+ import { createMemo, splitProps, type Component, type JSX } from "solid-js"
2
+ import type { BreadcrumbItem, BreadcrumbProps } from "./breadcrumb"
3
+ import { breadcrumbTheme } from "./breadcrumb.theme"
4
+ import RLSIcon from "../icon/RLSIcon"
5
+
6
+ export interface RLSBreadcrumbProps extends BreadcrumbProps {
7
+ children?: JSX.Element
8
+ separator?: JSX.Element
9
+ }
10
+
11
+ const RLSBreadcrumb: Component<RLSBreadcrumbProps> = (allProps) => {
12
+ const [props, rest] = splitProps(allProps, [
13
+ "items",
14
+ "maxVisible",
15
+ "estimatedItemWidth",
16
+ "separatorIcon",
17
+ "separator",
18
+ "children",
19
+ "ui",
20
+ "class"
21
+ ])
22
+
23
+ const classes = createMemo(() =>
24
+ breadcrumbTheme({
25
+ ui: props.ui,
26
+ class: props.class
27
+ })
28
+ )
29
+
30
+ const allItems = props.items ?? []
31
+ const firstItem = allItems[0]
32
+ const lastItem = allItems.length > 1 ? allItems[allItems.length - 1] : null
33
+ const allMidItems = allItems.length > 2 ? allItems.slice(1, allItems.length - 1) : []
34
+
35
+ const effectiveMaxMid =
36
+ props.maxVisible !== undefined ? Math.max(0, props.maxVisible - 2) : allMidItems.length
37
+
38
+ const renderedMidItems = allMidItems.slice(allMidItems.length - effectiveMaxMid)
39
+ const baseHiddenCount = Math.max(0, allMidItems.length - effectiveMaxMid)
40
+
41
+ const hasMidItems = renderedMidItems.length > 0
42
+ const needsOverflow = allItems.length > 2
43
+
44
+ const uid = Math.random().toString(36).substring(2, 9)
45
+ const cName = `rla-bc-${uid}`
46
+
47
+ let instanceCss = ""
48
+ if (needsOverflow && hasMidItems) {
49
+ for (let i = 0; i < renderedMidItems.length; i++) {
50
+ const hiddenItems = i + 1
51
+ const visibleMids = renderedMidItems.length - hiddenItems
52
+ const visibleTotal = 2 + visibleMids
53
+ const maxWidth = visibleTotal * (props.estimatedItemWidth ?? 120) + 60
54
+ const hideNthChild = 3 + i
55
+
56
+ instanceCss += `\n@container ${cName} (max-width: ${maxWidth}px) {`
57
+ instanceCss += `\n [data-bc="${uid}"] { --hidden-items: ${hiddenItems}; }`
58
+ instanceCss += `\n [data-bc="${uid}"] > li.hidable:nth-child(${hideNthChild}) { display: none; }`
59
+ instanceCss += `\n [data-bc="${uid}"] > .rla-bc-overflow { display: flex; }`
60
+ instanceCss += `\n}`
61
+ }
62
+ }
63
+
64
+ const separatorEl = () => (
65
+ <span class={classes()["separator"]} data-slot="separator" aria-hidden="true">
66
+ {props.separator !== undefined ? (
67
+ props.separator
68
+ ) : (
69
+ <RLSIcon name={props.separatorIcon ?? "chevronRight"} />
70
+ )}
71
+ </span>
72
+ )
73
+
74
+ const itemMarker = (item: BreadcrumbItem) =>
75
+ item.href ? (
76
+ <a href={item.href} class={classes()["link"]} data-slot="link">
77
+ {item.label}
78
+ </a>
79
+ ) : (
80
+ <span class={classes()["page"]} data-slot="page">
81
+ {item.label}
82
+ </span>
83
+ )
84
+
85
+ const ldJson = JSON.stringify({
86
+ "@context": "https://schema.org",
87
+ "@type": "BreadcrumbList",
88
+ "itemListElement": allItems.map((item, idx) => ({
89
+ "@type": "ListItem",
90
+ "position": idx + 1,
91
+ "name": item.label,
92
+ "item": item.href ? new URL(item.href, "https://starter.rimelight.com").toString() : undefined
93
+ }))
94
+ })
95
+
96
+ const staticCss = `
97
+ .rla-bc-host {
98
+ display: block;
99
+ width: 100%;
100
+ }
101
+
102
+ .rla-bc-overflow {
103
+ display: flex;
104
+ align-items: center;
105
+ gap: 0.25rem;
106
+ list-style: none;
107
+ flex-shrink: 0;
108
+ }
109
+
110
+ .rla-bc-overflow-hidden {
111
+ display: none;
112
+ }
113
+
114
+ .rla-bc-ellipsis {
115
+ color: var(--rl-neutral-600);
116
+ letter-spacing: 0.05em;
117
+ font-weight: 500;
118
+ }
119
+
120
+ .rla-bc-more-count::after {
121
+ counter-reset: rla-bc-cnt calc(var(--base-hidden, 0) + var(--hidden-items, 0));
122
+ content: "+" counter(rla-bc-cnt);
123
+ color: var(--rl-neutral-600);
124
+ font-size: 0.6875rem;
125
+ font-weight: 600;
126
+ vertical-align: super;
127
+ line-height: 1;
128
+ }`
129
+
130
+ return (
131
+ <>
132
+ <nav aria-label="breadcrumb" class={classes()["root"]} data-slot="breadcrumb-root" {...rest}>
133
+ {props.items ? (
134
+ <div class="rla-bc-host" style={`container-type: inline-size; container-name: ${cName};`}>
135
+ <ol
136
+ class={classes()["list"]}
137
+ data-slot="list"
138
+ data-bc={uid}
139
+ style={`--base-hidden: ${baseHiddenCount}; --hidden-items: 0;`}
140
+ >
141
+ {firstItem && (
142
+ <li class={classes()["item"]} data-slot="item">
143
+ {itemMarker(firstItem)}
144
+ {(hasMidItems || lastItem) && separatorEl()}
145
+ </li>
146
+ )}
147
+
148
+ {needsOverflow && (
149
+ <li
150
+ class={
151
+ baseHiddenCount === 0
152
+ ? "rla-bc-overflow rla-bc-overflow-hidden"
153
+ : "rla-bc-overflow"
154
+ }
155
+ aria-hidden="true"
156
+ data-slot="overflow"
157
+ >
158
+ <span class="rla-bc-ellipsis">…</span>
159
+ <span class="rla-bc-more-count" />
160
+ {separatorEl()}
161
+ </li>
162
+ )}
163
+
164
+ {renderedMidItems.map((item) => (
165
+ <li class={`${classes()["item"]} hidable`} data-slot="item">
166
+ {itemMarker(item)}
167
+ {separatorEl()}
168
+ </li>
169
+ ))}
170
+
171
+ {lastItem && (
172
+ <li class={classes()["item"]} data-slot="item">
173
+ <span class={classes()["page"]} data-slot="page" aria-current="page">
174
+ {lastItem.label}
175
+ </span>
176
+ </li>
177
+ )}
178
+ </ol>
179
+ </div>
180
+ ) : (
181
+ <ol class={classes()["list"]} data-slot="list">
182
+ {props.children}
183
+ </ol>
184
+ )}
185
+ </nav>
186
+
187
+ <style>{staticCss + instanceCss}</style>
188
+
189
+ {props.items && <script type="application/ld+json" innerHTML={ldJson} />}
190
+ </>
191
+ )
192
+ }
193
+
194
+ export default RLSBreadcrumb
@@ -0,0 +1,21 @@
1
+ import { createMemo, splitProps, type Component, type JSX } from "solid-js"
2
+ import type { BrowserMockupProps } from "./browser-mockup"
3
+ import { browserMockupTheme } from "./browser-mockup.theme"
4
+
5
+ export interface RLSBrowserMockupProps extends BrowserMockupProps {
6
+ children?: JSX.Element
7
+ }
8
+
9
+ const RLSBrowserMockup: Component<RLSBrowserMockupProps> = (allProps) => {
10
+ const [props, rest] = splitProps(allProps, ["ui", "class", "children"])
11
+
12
+ const resolvedClasses = createMemo(() => browserMockupTheme({ ui: props.ui, class: props.class }))
13
+
14
+ return (
15
+ <div class={resolvedClasses().root} data-slot="root" {...rest}>
16
+ {props.children}
17
+ </div>
18
+ )
19
+ }
20
+
21
+ export default RLSBrowserMockup