@rimelight/ui 0.0.24 → 0.0.26

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 (65) hide show
  1. package/package.json +7 -3
  2. package/src/components/Head.astro +199 -156
  3. package/src/components/ThemeToggle.astro +2 -2
  4. package/src/components/astro/RLAAccordion.astro +22 -0
  5. package/src/components/astro/RLAButton.astro +104 -118
  6. package/src/components/astro/RLAFooter.astro +17 -43
  7. package/src/components/astro/RLAHeader.astro +21 -80
  8. package/src/components/astro/RLAIcon.astro +14 -39
  9. package/src/components/astro/RLALogo.astro +14 -48
  10. package/src/components/astro/RLAPlaceholder.astro +11 -35
  11. package/src/components/astro/RLAQuote.astro +15 -0
  12. package/src/components/astro/RLAScrollToTop.astro +171 -221
  13. package/src/components/astro/RLASection.astro +210 -0
  14. package/src/components/vue/RLVButton.vue +166 -139
  15. package/src/components/vue/RLVFooter.vue +17 -54
  16. package/src/components/vue/RLVHeader.vue +22 -105
  17. package/src/components/vue/RLVIcon.vue +14 -45
  18. package/src/components/vue/RLVLogo.vue +11 -58
  19. package/src/components/vue/RLVPlaceholder.vue +14 -35
  20. package/src/components/vue/RLVScrollToTop.vue +18 -89
  21. package/src/components/vue/RLVSection.vue +166 -0
  22. package/src/composables/index.ts +0 -1
  23. package/src/env.d.ts +5 -0
  24. package/src/integrations/ui.ts +2 -6
  25. package/src/plugins/index.ts +5 -2
  26. package/src/plugins/starlightAddons/index.ts +3 -64
  27. package/src/plugins/starlightDocsApi/components/ApiEmits.astro +46 -0
  28. package/src/plugins/starlightDocsApi/components/ApiProps.astro +47 -0
  29. package/src/plugins/starlightDocsApi/components/ApiSlots.astro +50 -0
  30. package/src/plugins/starlightDocsApi/components/ApiTheme.astro +27 -0
  31. package/src/plugins/starlightDocsApi/extract-vue.ts +286 -0
  32. package/src/plugins/starlightDocsApi/index.ts +265 -0
  33. package/src/plugins/starlightDocsApi/types.ts +40 -0
  34. package/src/plugins/starlightDocsApi/utils.ts +45 -0
  35. package/src/themes/button.theme.ts +29 -14
  36. package/src/themes/footer.theme.ts +4 -6
  37. package/src/themes/header.theme.ts +4 -28
  38. package/src/themes/icon.theme.ts +4 -2
  39. package/src/themes/index.ts +15 -20
  40. package/src/themes/logo.theme.ts +4 -2
  41. package/src/themes/placeholder.theme.ts +4 -6
  42. package/src/themes/scroll-to-top.theme.ts +4 -6
  43. package/src/themes/section.theme.ts +187 -0
  44. package/src/types/componentVariant.ts +14 -0
  45. package/src/types/index.ts +1 -0
  46. package/src/utils/defineTheme.ts +11 -0
  47. package/src/utils/index.ts +3 -0
  48. package/src/utils/resolveClasses.ts +21 -0
  49. package/src/utils/useUi.ts +19 -0
  50. package/src/composables/useUi.ts +0 -27
  51. package/src/plugins/starlightAddons/Sidebar.astro +0 -89
  52. package/src/plugins/starlightAddons/data.ts +0 -39
  53. package/src/plugins/starlightAddons/libs/config.ts +0 -107
  54. package/src/plugins/starlightAddons/libs/content.ts +0 -20
  55. package/src/plugins/starlightAddons/libs/i18n.ts +0 -51
  56. package/src/plugins/starlightAddons/libs/locals.ts +0 -12
  57. package/src/plugins/starlightAddons/libs/pathname.ts +0 -22
  58. package/src/plugins/starlightAddons/libs/plugin.ts +0 -9
  59. package/src/plugins/starlightAddons/libs/sidebar.ts +0 -183
  60. package/src/plugins/starlightAddons/libs/vite.ts +0 -46
  61. package/src/plugins/starlightAddons/locals.d.ts +0 -14
  62. package/src/plugins/starlightAddons/middleware.ts +0 -132
  63. package/src/plugins/starlightAddons/overrides/Sidebar.astro +0 -8
  64. package/src/plugins/starlightAddons/schema.ts +0 -13
  65. package/src/plugins/starlightAddons/virtual.d.ts +0 -13
@@ -1,65 +1,22 @@
1
1
  <script setup lang="ts">
2
2
  import { computed, onMounted, onUnmounted, ref } from "vue"
3
- import { scv, cx } from "css-variants"
4
- import { twMerge } from "tailwind-merge"
5
- import { useUi } from "../../composables"
6
- import { headerTheme } from "../../themes/header.theme.ts"
7
- import { getHeaderStack } from "../../utils/headerStack.ts"
8
-
9
- // ── Style engine ─────────────────────────────────────────────────────────────
10
-
11
- const header = scv({
12
- slots: [...headerTheme.slots],
13
- base: headerTheme.base,
14
- variants: headerTheme.variants,
15
- defaultVariants: headerTheme.defaultVariants,
16
- classNameResolver: (...args) => twMerge(cx(...args))
17
- })
3
+ import { scv } from "css-variants"
4
+ import { useUi, resolveClasses } from "../../utils"
5
+ import type { ComponentVariants, ComponentSlots } from "../../types"
6
+ import headerTheme from "../../themes/header.theme"
7
+ import { getHeaderStack } from "../../utils/headerStack"
18
8
 
19
- // ── Props ─────────────────────────────────────────────────────────────────────
9
+ const header = scv(headerTheme)
10
+ type HeaderVariants = ComponentVariants<typeof headerTheme>
20
11
 
21
12
  export interface RLVHeaderProps {
22
- /**
23
- * Whether to contain the header content in a max-width container.
24
- *
25
- * @default true
26
- */
27
- contain?: boolean
28
- /**
29
- * Sticky positioning when `fixed` is false.
30
- *
31
- * @default true
32
- */
33
- sticky?: boolean
34
- /**
35
- * Switches to `position: fixed; left: 0; right: 0` (layer mode). When true, `top` and
36
- * `stackIndex` control the exact position.
37
- *
38
- * @default false
39
- */
40
- fixed?: boolean
41
- /**
42
- * Controls z-index when `fixed` is true: `z-index = 100 - stackIndex`. Lower index = higher in
43
- * the visual stack.
44
- *
45
- * @default 0
46
- */
13
+ contain?: HeaderVariants["contain"]
14
+ sticky?: HeaderVariants["sticky"]
15
+ fixed?: HeaderVariants["fixed"]
47
16
  stackIndex?: number
48
- /**
49
- * When true, hides the header on scroll-down and shows it on scroll-up. Uses a passive `scroll`
50
- * event listener — no external dependencies. Only meaningful when `fixed` is true.
51
- *
52
- * @default false
53
- */
54
17
  hideOnScroll?: boolean
55
- /**
56
- * UI overrides for individual slots, derived from the header theme.
57
- */
58
- ui?: Partial<Record<keyof typeof headerTheme.base, string>>
59
- /**
60
- * External class — applied to the root element.
61
- */
62
- class?: string
18
+ ui?: ComponentSlots<typeof headerTheme>
19
+ class?: any
63
20
  }
64
21
 
65
22
  const {
@@ -68,46 +25,19 @@ const {
68
25
  fixed = false,
69
26
  stackIndex = 0,
70
27
  hideOnScroll = false,
71
- class: className,
72
- ui: uiProp
28
+ ui: uiProp,
29
+ class: className
73
30
  } = defineProps<RLVHeaderProps>()
74
31
 
75
- // ── Slots ─────────────────────────────────────────────────────────────────────
76
-
77
32
  defineSlots<{
78
- /**
79
- * Content to display on the left side of the header (e.g., Logo).
80
- */
81
33
  left(props: {}): any
82
- /**
83
- * Content to display in the center of the header (e.g., Navigation Links).
84
- */
85
34
  center(props: {}): any
86
- /**
87
- * Content to display on the right side of the header (e.g., User Menu, Theme Toggle).
88
- */
89
35
  right(props: {}): any
90
36
  }>()
91
37
 
92
- // ── UI merge ──────────────────────────────────────────────────────────────────
93
-
94
- const mergedUI = useUi("header", uiProp as Record<string, unknown> | undefined)
95
-
96
- // ── Resolved classes ──────────────────────────────────────────────────────────
97
-
98
- const resolvedClasses = computed(() => {
99
- const classes = header({ contain, sticky, fixed })
100
- return {
101
- root: twMerge(classes.root, mergedUI.value.root as string | undefined),
102
- content: twMerge(classes.content, mergedUI.value.content as string | undefined),
103
- container: twMerge(classes.container, mergedUI.value.container as string | undefined),
104
- left: twMerge(classes.left, mergedUI.value.left as string | undefined),
105
- center: twMerge(classes.center, mergedUI.value.center as string | undefined),
106
- right: twMerge(classes.right, mergedUI.value.right as string | undefined)
107
- }
108
- })
109
-
110
- // ── Fixed-mode state ──────────────────────────────────────────────────────────
38
+ const resolvedClasses = computed(() =>
39
+ resolveClasses(header, { contain, sticky, fixed }, useUi("header", uiProp), className)
40
+ )
111
41
 
112
42
  const id = `rlv-header-${Math.random().toString(36).slice(2, 8)}`
113
43
  const rootRef = ref<HTMLElement | null>(null)
@@ -115,9 +45,6 @@ const contentRef = ref<HTMLElement | null>(null)
115
45
  const naturalHeight = ref(0)
116
46
  const isVisible = ref(true)
117
47
 
118
- /**
119
- * Inline style applied to the root element in fixed mode.
120
- */
121
48
  const fixedStyle = computed(() => {
122
49
  if (!fixed) return {}
123
50
  return {
@@ -125,8 +52,6 @@ const fixedStyle = computed(() => {
125
52
  }
126
53
  })
127
54
 
128
- // ── Lifecycle: height measurement + scroll listener ───────────────────────────
129
-
130
55
  let resizeObserver: ResizeObserver | null = null
131
56
  let scrollHandler: (() => void) | null = null
132
57
 
@@ -139,7 +64,6 @@ onMounted(() => {
139
64
  stack.register(id, stackIndex, naturalHeight.value, isVisible.value, rootRef.value)
140
65
  }
141
66
 
142
- // Measure natural height via ResizeObserver
143
67
  if (contentRef.value) {
144
68
  naturalHeight.value = contentRef.value.getBoundingClientRect().height
145
69
  resizeObserver = new ResizeObserver((entries) => {
@@ -152,14 +76,12 @@ onMounted(() => {
152
76
  resizeObserver.observe(contentRef.value)
153
77
  }
154
78
 
155
- // Raw scroll listener for hideOnScroll
156
79
  if (hideOnScroll) {
157
80
  let localLastScrollY = window.scrollY
158
81
  scrollHandler = () => {
159
82
  const current = window.scrollY
160
83
  const diff = current - localLastScrollY
161
84
 
162
- // Ignore tiny jitter
163
85
  if (Math.abs(diff) < 10) return
164
86
 
165
87
  const newVisible = current <= 50 ? true : diff <= 0
@@ -188,25 +110,20 @@ onUnmounted(() => {
188
110
  <header
189
111
  ref="rootRef"
190
112
  :id="id"
191
- :class="[resolvedClasses.root, className]"
113
+ :class="[resolvedClasses.root]"
192
114
  :style="fixedStyle"
193
- data-slot="rlv-header"
115
+ data-slot="root"
194
116
  v-bind="$attrs"
195
117
  >
196
- <!--
197
- content wrapper: always rendered, but only meaningful in fixed mode.
198
- The ResizeObserver targets this element so the `<header>` root's padding/border
199
- don't interfere with the height measurement.
200
- -->
201
118
  <div ref="contentRef" :class="resolvedClasses.content">
202
119
  <div :class="resolvedClasses.container">
203
- <div :class="resolvedClasses.left" data-slot="header-left">
120
+ <div :class="resolvedClasses.left" data-slot="left">
204
121
  <slot name="left" />
205
122
  </div>
206
- <div :class="resolvedClasses.center" data-slot="header-center">
123
+ <div :class="resolvedClasses.center" data-slot="center">
207
124
  <slot name="center" />
208
125
  </div>
209
- <div :class="resolvedClasses.right" data-slot="header-right">
126
+ <div :class="resolvedClasses.right" data-slot="right">
210
127
  <slot name="right" />
211
128
  </div>
212
129
  </div>
@@ -1,51 +1,25 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from "vue"
3
- import { scv, cx } from "css-variants"
4
- import { twMerge } from "tailwind-merge"
5
- import { useUi } from "../../composables"
6
- import { iconTheme } from "../../themes/icon.theme"
3
+ import { scv } from "css-variants"
4
+ import { useUi, resolveClasses } from "../../utils"
5
+ import type { ComponentVariants, ComponentSlots } from "../../types"
6
+ import iconTheme from "../../themes/icon.theme"
7
7
 
8
- const icon = scv({
9
- slots: [...iconTheme.slots],
10
- base: iconTheme.base,
11
- variants: iconTheme.variants,
12
- defaultVariants: iconTheme.defaultVariants,
13
- classNameResolver: (...args) => twMerge(cx(...args))
14
- })
8
+ const icon = scv(iconTheme)
9
+ type IconVariants = ComponentVariants<typeof iconTheme>
15
10
 
16
11
  export interface RLVIconProps {
17
- /**
18
- * Icon name following the UnoCSS icons format. Can be a string like "i-lucide-home" or a Vue
19
- * component.
20
- *
21
- * @example
22
- * "i-lucide-home"
23
- */
24
12
  name: string
25
- /**
26
- * Size variant for the icon.
27
- */
28
- size?: keyof typeof iconTheme.variants.size
29
- /**
30
- * External class applied to the root element.
31
- */
32
- class?: string
33
- /**
34
- * UI overrides for individual slots.
35
- */
36
- ui?: Partial<Record<keyof typeof iconTheme.base, string>>
13
+ size?: IconVariants["size"]
14
+ ui?: ComponentSlots<typeof iconTheme>
15
+ class?: any
37
16
  }
38
17
 
39
- const { name, size = "md", class: className, ui: uiProp } = defineProps<RLVIconProps>()
18
+ const { name, size = "md", ui: uiProp, class: className } = defineProps<RLVIconProps>()
40
19
 
41
- const mergedUI = useUi("icon", uiProp as Record<string, unknown> | undefined)
42
-
43
- const resolvedClasses = computed(() => {
44
- const { root } = icon({ size })
45
- return {
46
- root: twMerge(root, mergedUI.value.root, className)
47
- }
48
- })
20
+ const resolvedClasses = computed(() =>
21
+ resolveClasses(icon, { size }, useUi("icon", uiProp), className)
22
+ )
49
23
 
50
24
  defineSlots<{
51
25
  default(props: {}): any
@@ -53,12 +27,7 @@ defineSlots<{
53
27
  </script>
54
28
 
55
29
  <template>
56
- <span
57
- v-bind="$attrs"
58
- :class="[resolvedClasses.root, name]"
59
- data-slot="rlv-icon"
60
- aria-hidden="true"
61
- >
30
+ <span v-bind="$attrs" :class="[resolvedClasses.root, name]" data-slot="root" aria-hidden="true">
62
31
  <slot />
63
32
  </span>
64
33
  </template>
@@ -1,51 +1,20 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from "vue"
3
- import { scv, cx } from "css-variants"
4
- import { twMerge } from "tailwind-merge"
5
- import defu from "defu"
6
- import { logoTheme } from "../../themes/logo.theme.ts"
3
+ import { scv } from "css-variants"
4
+ import { useUi, resolveClasses } from "../../utils"
5
+ import type { ComponentSlots } from "../../types"
6
+ import logoTheme from "../../themes/logo.theme"
7
7
  import { getUIConfig } from "virtual:rimelight-ui"
8
8
 
9
- const logo = scv({
10
- slots: [...logoTheme.slots],
11
- base: logoTheme.base,
12
- variants: logoTheme.variants,
13
- defaultVariants: logoTheme.defaultVariants,
14
- classNameResolver: (...args) => twMerge(cx(...args))
15
- })
9
+ const logo = scv(logoTheme)
16
10
 
17
11
  export interface RLVLogoProps {
18
- /**
19
- * The variant of the logo to display.
20
- *
21
- * @default "logomark"
22
- */
23
12
  variant?: string
24
- /**
25
- * Override the color mode.
26
- */
27
13
  mode?: "color" | "white" | "black"
28
- /**
29
- * The URL to link to.
30
- *
31
- * @default "/"
32
- */
33
14
  href?: string
34
- /**
35
- * UI overrides for individual slots, derived from the logo theme.
36
- */
37
- ui?: Partial<Record<keyof typeof logoTheme.base, string>>
38
- /**
39
- * External class — applied to the root element.
40
- */
41
- class?: string
42
- /**
43
- * The alt text for the logo image.
44
- */
45
15
  alt?: string
46
- /**
47
- * Standard HTML attributes for <a>
48
- */
16
+ ui?: ComponentSlots<typeof logoTheme>
17
+ class?: any
49
18
  [key: string]: unknown
50
19
  }
51
20
 
@@ -55,30 +24,15 @@ const props = withDefaults(defineProps<RLVLogoProps>(), {
55
24
  })
56
25
 
57
26
  defineSlots<{
58
- /**
59
- * The default slot for the logo content (e.g., text, custom elements).
60
- */
61
27
  default(props: {}): any
62
28
  }>()
63
29
 
64
- const globalConfig = getUIConfig()
65
-
66
- const mergedUI = computed(
67
- () =>
68
- defu(props.ui ?? {}, (globalConfig.logo as Record<string, unknown>) ?? {}) as Record<
69
- keyof typeof logoTheme.base,
70
- string | undefined
71
- >
30
+ const resolvedClasses = computed(() =>
31
+ resolveClasses(logo, {}, useUi("logo", props.ui), props.class)
72
32
  )
73
33
 
74
- const resolvedClasses = computed(() => {
75
- const { root } = logo()
76
- return {
77
- root: twMerge(root, mergedUI.value.root, props.class)
78
- }
79
- })
80
-
81
34
  const logoSrc = computed<string | null>(() => {
35
+ const globalConfig = getUIConfig()
82
36
  const rcLogos = globalConfig.logos as Record<string, any>
83
37
  let src: any = null
84
38
 
@@ -111,10 +65,9 @@ const Tag = computed(() => (props.href ? "a" : "div"))
111
65
  :href="Tag === 'a' ? href : undefined"
112
66
  :aria-label="alt || variant"
113
67
  :class="resolvedClasses.root"
114
- data-slot="rlv-logo"
68
+ data-slot="root"
115
69
  >
116
70
  <template v-if="logoSrc">
117
- <!-- Using mode='svg' pattern is not strictly needed for UnoCSS icons -->
118
71
  <span v-if="isIcon" :class="[logoSrc, 'size-full block shrink-0']" aria-hidden="true" />
119
72
  <img v-else :src="logoSrc" :alt="alt || ''" class="size-full block object-contain shrink-0" />
120
73
  </template>
@@ -1,35 +1,19 @@
1
1
  <script setup lang="ts">
2
- import { scv, cx } from "css-variants"
3
- import { twMerge } from "tailwind-merge"
4
- import defu from "defu"
5
- import { placeholderTheme } from "../../themes/placeholder.theme.ts"
6
- import { getUIConfig } from "virtual:rimelight-ui"
2
+ import { computed } from "vue"
3
+ import { scv } from "css-variants"
4
+ import { useUi, resolveClasses } from "../../utils"
5
+ import type { ComponentSlots } from "../../types"
6
+ import placeholderTheme from "../../themes/placeholder.theme"
7
7
 
8
- const placeholder = scv({
9
- slots: [...placeholderTheme.slots],
10
- base: placeholderTheme.base,
11
- variants: placeholderTheme.variants,
12
- compoundVariants: [...placeholderTheme.compoundVariants],
13
- defaultVariants: placeholderTheme.defaultVariants,
14
- classNameResolver: (...args) => twMerge(cx(...args))
15
- })
8
+ const placeholder = scv(placeholderTheme)
16
9
 
17
10
  export interface RLVPlaceholderProps {
18
- /**
19
- * UI overrides for individual slots, derived from the placeholder theme.
20
- */
21
- ui?: Partial<Record<keyof typeof placeholderTheme.base, string>>
22
- /**
23
- * External class — applied to the root element.
24
- */
25
- class?: string
26
- /**
27
- * Standard HTML attributes.
28
- */
11
+ ui?: ComponentSlots<typeof placeholderTheme>
12
+ class?: any
29
13
  [key: string]: unknown
30
14
  }
31
15
 
32
- const { class: className, ui: uiProp } = defineProps<RLVPlaceholderProps>()
16
+ const { ui: uiProp, class: className } = defineProps<RLVPlaceholderProps>()
33
17
 
34
18
  defineSlots<{
35
19
  /**
@@ -38,19 +22,14 @@ defineSlots<{
38
22
  default(props: {}): any
39
23
  }>()
40
24
 
41
- const globalConfig = getUIConfig()
42
-
43
- const mergedUI = defu(
44
- uiProp ?? {},
45
- (globalConfig.placeholder as Record<string, unknown>) ?? {}
46
- ) as Record<keyof typeof placeholderTheme.base, string | undefined>
47
-
48
- const { base, svg } = placeholder()
25
+ const resolvedClasses = computed(() =>
26
+ resolveClasses(placeholder, {}, useUi("placeholder", uiProp), className)
27
+ )
49
28
  </script>
50
29
 
51
30
  <template>
52
- <div :class="twMerge(base, mergedUI.base, className)" v-bind="$attrs">
53
- <svg :class="twMerge(svg, mergedUI.svg)">
31
+ <div :class="resolvedClasses.base" v-bind="$attrs">
32
+ <svg :class="resolvedClasses.svg">
54
33
  <defs>
55
34
  <pattern
56
35
  id="pattern-5c1e4f0e-62d5-498b-8ff0-cf77bb448c8e"
@@ -1,66 +1,24 @@
1
1
  <script setup lang="ts">
2
- import { scv, cx } from "css-variants"
3
- import { twMerge } from "tailwind-merge"
4
- import defu from "defu"
5
- import { scrollToTopTheme } from "../../themes/scroll-to-top.theme.ts"
2
+ import { scv } from "css-variants"
3
+ import { useUi, resolveClasses } from "../../utils"
4
+ import type { ComponentVariants, ComponentSlots } from "../../types"
5
+ import scrollToTopTheme from "../../themes/scroll-to-top.theme"
6
6
  import { useScrollToTop } from "../../composables/useScrollToTop"
7
7
  import { computed } from "vue"
8
- import { getUIConfig } from "virtual:rimelight-ui"
8
+
9
+ const scrollToTop = scv(scrollToTopTheme)
10
+ type ScrollToTopVariants = ComponentVariants<typeof scrollToTopTheme>
9
11
 
10
12
  export interface RLVScrollToTopProps {
11
- /**
12
- * Button color.
13
- *
14
- * @default "primary"
15
- */
16
- color?: keyof typeof scrollToTopTheme.variants.color
17
- /**
18
- * Transition duration for the progress circle (in seconds).
19
- *
20
- * @default 0.1
21
- */
13
+ color?: ScrollToTopVariants["color"]
14
+ progressWidth?: number
22
15
  duration?: number
23
- /**
24
- * Scroll threshold (in pixels) before the button becomes visible.
25
- *
26
- * @default 200
27
- */
28
16
  threshold?: number
29
- /**
30
- * Whether to show the scroll progress indicator.
31
- *
32
- * @default false
33
- */
34
17
  showProgress?: boolean
35
- /**
36
- * Stroke width of the progress circle.
37
- *
38
- * @default 6
39
- */
40
- progressWidth?: number
41
- /**
42
- * UI overrides for individual slots, derived from the scroll-to-top theme.
43
- */
44
- ui?: Partial<Record<keyof typeof scrollToTopTheme.base, string>>
45
- /**
46
- * External class — applied to the root element.
47
- */
48
- class?: string
49
- /**
50
- * Standard HTML attributes.
51
- */
52
- [key: string]: unknown
18
+ ui?: ComponentSlots<typeof scrollToTopTheme>
19
+ class?: any
53
20
  }
54
21
 
55
- const scrollToTop = scv({
56
- slots: [...scrollToTopTheme.slots],
57
- base: scrollToTopTheme.base,
58
- variants: scrollToTopTheme.variants,
59
- compoundVariants: [...scrollToTopTheme.compoundVariants],
60
- defaultVariants: scrollToTopTheme.defaultVariants,
61
- classNameResolver: (...args) => twMerge(cx(...args))
62
- })
63
-
64
22
  const {
65
23
  color = "primary",
66
24
  progressWidth = 6,
@@ -71,23 +29,7 @@ const {
71
29
  class: className
72
30
  } = defineProps<RLVScrollToTopProps>()
73
31
 
74
- const globalConfig = getUIConfig()
75
-
76
- const mergedUI = defu(
77
- uiProp ?? {},
78
- (globalConfig["scroll-to-top"] as Record<string, unknown>) ?? {}
79
- ) as Record<keyof typeof scrollToTopTheme.base, string | undefined>
80
-
81
- const {
82
- root,
83
- button,
84
- progressBase,
85
- svg: svgClass,
86
- iconContainer,
87
- icon
88
- } = scrollToTop({
89
- color
90
- })
32
+ const classes = resolveClasses(scrollToTop, { color }, useUi("scrollToTop", uiProp), className)
91
33
 
92
34
  const {
93
35
  isVisible,
@@ -107,25 +49,12 @@ const durationInSeconds = computed(() => `${duration}s`)
107
49
 
108
50
  <template>
109
51
  <div
110
- :class="[
111
- 'rla-scroll-to-top fixed bottom-6 right-6 z-50',
112
- { visible: isVisible },
113
- twMerge(root, mergedUI.root, className)
114
- ]"
52
+ :class="['rla-scroll-to-top fixed bottom-6 right-6 z-50', { visible: isVisible }, classes.root]"
115
53
  v-bind="$attrs"
116
54
  >
117
- <button
118
- type="button"
119
- :class="twMerge(button, mergedUI.button)"
120
- aria-label="Scroll to top"
121
- @click="scrollToTopFn"
122
- >
123
- <div :class="twMerge(progressBase, mergedUI.progressBase)">
124
- <svg
125
- :class="twMerge(svgClass, mergedUI.svg)"
126
- viewBox="0 0 100 100"
127
- shape-rendering="geometricPrecision"
128
- >
55
+ <button type="button" :class="classes.button" aria-label="Scroll to top" @click="scrollToTopFn">
56
+ <div :class="classes.progressBase">
57
+ <svg :class="classes.svg" viewBox="0 0 100 100" shape-rendering="geometricPrecision">
129
58
  <circle
130
59
  cx="50"
131
60
  cy="50"
@@ -153,7 +82,7 @@ const durationInSeconds = computed(() => `${duration}s`)
153
82
  }"
154
83
  />
155
84
  </svg>
156
- <div :class="twMerge(iconContainer, mergedUI.iconContainer)">
85
+ <div :class="classes.iconContainer">
157
86
  <svg
158
87
  xmlns="http://www.w3.org/2000/svg"
159
88
  width="24"
@@ -164,7 +93,7 @@ const durationInSeconds = computed(() => `${duration}s`)
164
93
  stroke-width="2"
165
94
  stroke-linecap="round"
166
95
  stroke-linejoin="round"
167
- :class="twMerge(icon, mergedUI.icon)"
96
+ :class="classes.icon"
168
97
  >
169
98
  <path d="m5 12 7-7 7 7" />
170
99
  <path d="M12 19V5" />