@lexibase/rdx-ui 3.2.1 → 3.3.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lexibase/rdx-ui",
3
- "version": "3.2.1",
3
+ "version": "3.3.0",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": "^22.18.0 || ^24.11.0"
@@ -37,7 +37,7 @@
37
37
  "tailwind-merge": "^3.7.0",
38
38
  "tailwindcss": "^4.3.3",
39
39
  "tw-animate-css": "^1.4.0",
40
- "@lexibase/rdx-types": "2.0.0"
40
+ "@lexibase/rdx-types": "2.1.0"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "next": "^16.4.2",
@@ -56,8 +56,8 @@
56
56
  "react-dom": "19.3.1",
57
57
  "tailwindcss": "^4.3.3",
58
58
  "typescript": "6.0.3",
59
- "@rdx/typescript-config": "1.0.0",
60
- "@rdx/eslint-config": "1.0.0"
59
+ "@rdx/eslint-config": "1.0.0",
60
+ "@rdx/typescript-config": "1.0.0"
61
61
  },
62
62
  "exports": {
63
63
  "./globals.css": {
@@ -0,0 +1,84 @@
1
+ 'use client'
2
+
3
+ import { ExternalLink, Languages } from 'lucide-react'
4
+ import Link from 'next/link'
5
+ import { Button } from './button'
6
+ import {
7
+ DropdownMenu,
8
+ DropdownMenuContent,
9
+ DropdownMenuGroup,
10
+ DropdownMenuLinkItem,
11
+ DropdownMenuSeparator,
12
+ DropdownMenuTrigger,
13
+ } from './dropdown-menu'
14
+ import { getMessages } from '../lib/i18n'
15
+
16
+ /** Locale navigation composes the shared shadcn/ui Base UI menu. */
17
+ export function LanguageDropdown({
18
+ options,
19
+ current,
20
+ lang,
21
+ contributionUrl,
22
+ }: {
23
+ options: { code: string; label: string; href: string }[]
24
+ current: string
25
+ lang?: string
26
+ contributionUrl?: string
27
+ }) {
28
+ const selected = options.find((option) => option.code === current)
29
+ if (!selected) return null
30
+ const messages = getMessages(lang)
31
+ return (
32
+ <DropdownMenu>
33
+ <DropdownMenuTrigger
34
+ render={
35
+ <Button
36
+ variant="outline"
37
+ size="sm"
38
+ aria-label={`${getMessages(lang).documentationLanguage}: ${selected.label}`}
39
+ data-rdx-language-trigger
40
+ />
41
+ }
42
+ >
43
+ <Languages className="size-4" aria-hidden="true" />
44
+ <span className="hidden sm:inline">{selected.label}</span>
45
+ <span className="sm:hidden">{selected.code}</span>
46
+ </DropdownMenuTrigger>
47
+ <DropdownMenuContent align="end" collisionPadding={8}>
48
+ <DropdownMenuGroup>
49
+ {options.map((option) => (
50
+ <DropdownMenuLinkItem
51
+ key={option.code}
52
+ className={option.code === current ? 'bg-accent/30' : undefined}
53
+ closeOnClick
54
+ render={<Link href={option.href} hrefLang={option.code} />}
55
+ aria-current={option.code === current ? 'true' : undefined}
56
+ >
57
+ {option.label}
58
+ </DropdownMenuLinkItem>
59
+ ))}
60
+ </DropdownMenuGroup>
61
+ {contributionUrl && (
62
+ <>
63
+ <DropdownMenuSeparator />
64
+ <DropdownMenuLinkItem
65
+ closeOnClick
66
+ render={
67
+ <a
68
+ href={contributionUrl}
69
+ target="_blank"
70
+ rel="noopener noreferrer"
71
+ />
72
+ }
73
+ data-rdx-help-translate
74
+ >
75
+ {messages.helpTranslate}
76
+ <ExternalLink className="ml-auto size-3.5" aria-hidden="true" />
77
+ <span className="sr-only"> ({messages.opensInNewTab})</span>
78
+ </DropdownMenuLinkItem>
79
+ </>
80
+ )}
81
+ </DropdownMenuContent>
82
+ </DropdownMenu>
83
+ )
84
+ }
@@ -0,0 +1,50 @@
1
+ 'use client'
2
+
3
+ import type { ComponentProps, ReactNode } from 'react'
4
+ import { useParams } from 'next/navigation'
5
+ import { Navbar } from './navbar'
6
+ import { NotFound } from './not-found'
7
+ import { LanguageDropdown } from './language-dropdown'
8
+
9
+ /** Error boundaries do not receive server route params; use Next's route context. */
10
+ export function LocalizedNotFound({
11
+ locales,
12
+ defaultLocale,
13
+ brand,
14
+ homepage,
15
+ }: {
16
+ locales: { code: string; path: string; label: string }[]
17
+ defaultLocale: string
18
+ brand: Pick<
19
+ ComponentProps<typeof Navbar>,
20
+ 'title' | 'siteTitle' | 'github' | 'showToggleMode'
21
+ > & { logo: ReactNode }
22
+ homepage: boolean
23
+ }) {
24
+ const params = useParams<{ locale?: string }>()
25
+ const selected =
26
+ locales.find((locale) => locale.path === params.locale) ??
27
+ locales.find((locale) => locale.code === defaultLocale)!
28
+ const docsHref = `/${selected.path}/docs`
29
+ return (
30
+ <>
31
+ <Navbar
32
+ {...brand}
33
+ lang={selected.code}
34
+ homeHref={homepage ? '/' : docsHref}
35
+ docsHref={docsHref}
36
+ languageMenu={
37
+ <LanguageDropdown
38
+ lang={selected.code}
39
+ current={selected.code}
40
+ options={locales.map((locale) => ({
41
+ ...locale,
42
+ href: `/${locale.path}/docs`,
43
+ }))}
44
+ />
45
+ }
46
+ />
47
+ <NotFound lang={selected.code} href={docsHref} />
48
+ </>
49
+ )
50
+ }
@@ -17,6 +17,7 @@ export function Navbar({
17
17
  docsHref = '/docs',
18
18
  docsLink,
19
19
  versionMenu,
20
+ languageMenu,
20
21
  search,
21
22
  github,
22
23
  showToggleMode = false,
@@ -29,6 +30,7 @@ export function Navbar({
29
30
  docsHref?: string
30
31
  docsLink?: ReactNode
31
32
  versionMenu?: ReactNode
33
+ languageMenu?: ReactNode
32
34
  search?: ReactNode
33
35
  github?: { visible: boolean; url: string }
34
36
  showToggleMode?: boolean
@@ -55,6 +57,7 @@ export function Navbar({
55
57
  <div className="flex items-center gap-x-1 md:gap-x-2 h-4">
56
58
  {search}
57
59
  {versionMenu}
60
+ {languageMenu}
58
61
  {docsLink ?? (
59
62
  <Button variant="link" size="sm" href={docsHref}>
60
63
  {messages.docs}
package/src/lib/i18n.ts CHANGED
@@ -1,5 +1,13 @@
1
1
  /** Shared labels only: document content and author-provided names stay untouched. */
2
2
  const en = {
3
+ documentationLanguage: 'Documentation language',
4
+ translationUnavailable: 'Translation unavailable',
5
+ translationFallback:
6
+ 'This page is not available in {requested}. You are reading the {original} version.',
7
+ viewOriginal: 'View the original page',
8
+ helpTranslate: 'Help translate',
9
+ translateThisPage: 'Translate this page',
10
+ opensInNewTab: 'opens in a new tab',
3
11
  keyboardJoiner: ' plus ',
4
12
  keyboardControl: 'Control',
5
13
  keyboardShift: 'Shift',
@@ -93,6 +101,14 @@ export type InterfaceMessages = { [Key in keyof typeof en]: string }
93
101
  export type InterfaceLocale = 'en' | 'pt-BR'
94
102
 
95
103
  const ptBR = {
104
+ documentationLanguage: 'Idioma da documentação',
105
+ translationUnavailable: 'Tradução indisponível',
106
+ translationFallback:
107
+ 'Esta página não está disponível em {requested}. Você está lendo a versão em {original}.',
108
+ viewOriginal: 'Ver a página original',
109
+ helpTranslate: 'Ajude a traduzir',
110
+ translateThisPage: 'Traduza esta página',
111
+ opensInNewTab: 'abre em uma nova aba',
96
112
  keyboardJoiner: ' mais ',
97
113
  keyboardControl: 'Control',
98
114
  keyboardShift: 'Shift',