@rlx-ui/mcp 0.0.6 → 0.0.8
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/dist/data/registry.json +62 -1
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/data/registry.json
CHANGED
|
@@ -1264,6 +1264,20 @@
|
|
|
1264
1264
|
}
|
|
1265
1265
|
]
|
|
1266
1266
|
},
|
|
1267
|
+
{
|
|
1268
|
+
"name": "Code Block",
|
|
1269
|
+
"exportName": "CodeBlock",
|
|
1270
|
+
"packageName": "@rlx-components/code-block",
|
|
1271
|
+
"slug": "code-block",
|
|
1272
|
+
"category": "component",
|
|
1273
|
+
"sourceCode": "import { cn } from \"@rlx-widgets/base\";\nimport { ReactNode } from \"react\";\n\nexport const CodeBlock = ({ className, code, children }: CodeBlockProps) => {\n return (\n <pre\n className={cn(\n \"bg-muted rounded p-3 overflow-x-auto text-sm\",\n className,\n \"dark-scroll\"\n )}\n >\n <code>{code ?? children}</code>\n </pre>\n );\n};\ntype CodeBlockProps =\n | { code: string; children?: never; className?: string }\n | { children: ReactNode; code?: never; className?: string };\n\nexport default CodeBlock;\n",
|
|
1274
|
+
"demos": [
|
|
1275
|
+
{
|
|
1276
|
+
"name": "default",
|
|
1277
|
+
"code": "\"use client\";\n\nimport { CodeBlock } from \"@rlx-components/code-block\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full\">\n <CodeBlock>{`console.log('Hello, world!');`}</CodeBlock>\n </div>\n );\n};\n"
|
|
1278
|
+
}
|
|
1279
|
+
]
|
|
1280
|
+
},
|
|
1267
1281
|
{
|
|
1268
1282
|
"name": "Code Preview Tabs",
|
|
1269
1283
|
"exportName": "CodePreviewTabs",
|
|
@@ -1289,6 +1303,34 @@
|
|
|
1289
1303
|
"types/TabType.t.ts": "import { TabTypeEnum } from \"../enums\";\n\nexport type TabType = `${TabTypeEnum}`;\n"
|
|
1290
1304
|
}
|
|
1291
1305
|
},
|
|
1306
|
+
{
|
|
1307
|
+
"name": "Code Tabs",
|
|
1308
|
+
"exportName": "CodeTabs",
|
|
1309
|
+
"packageName": "@rlx-components/code-tabs",
|
|
1310
|
+
"slug": "code-tabs",
|
|
1311
|
+
"category": "component",
|
|
1312
|
+
"sourceCode": "\"use client\";\n\nimport { BundledLanguage, BundledTheme } from \"shiki/bundle/web\";\nimport { ReactNode, useCallback, useEffect, useState } from \"react\";\nimport { ShikiCodeBlock } from \"@rlx-components/shiki-code-block\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"@rlx-widgets/tabs\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { getThemeBackgroundHex } from \"../../utils\";\n\nexport const CodeTabs = ({\n tabs,\n theme = \"ayu-dark\",\n startAdornment,\n}: {\n tabs: Array<{\n id: string;\n label: ReactNode;\n code: string;\n lang: BundledLanguage;\n codeBlockClassName?: string;\n }>;\n theme?: BundledTheme;\n startAdornment?: ReactNode;\n}) => {\n const [backgroundColor, setBackgroundColor] = useState<string | undefined>(\n undefined\n );\n const [value, setValue] = useState<string>(tabs[0]?.id ?? \"\");\n\n const handleValueChange = useCallback((newValue: string) => {\n setValue(newValue);\n }, []);\n\n useEffect(() => {\n void getThemeBackgroundHex(theme)\n .then((bgHex) => {\n if (bgHex) {\n setBackgroundColor(bgHex);\n }\n })\n .catch(() => {\n // Silently handle errors - fallback to default bg-muted/30\n });\n }, [theme]);\n\n if (!tabs.length || !value) {\n return null;\n }\n\n return (\n <div className=\"relative w-full\">\n <Tabs\n value={value}\n onValueChange={handleValueChange}\n className=\"w-full gap-0\"\n >\n <div\n className={cn(\n \"border-b pb-0 rounded-lg rounded-b-none\",\n backgroundColor ? \"\" : \"bg-muted/30\"\n )}\n style={backgroundColor ? { backgroundColor } : undefined}\n >\n <TabsList className=\"bg-transparent h-auto p-0\">\n {startAdornment}\n {tabs.map((tab) => (\n <TabsTrigger\n key={tab.id}\n value={tab.id}\n className=\"px-4 py-2.5 border-b-0\"\n >\n {tab.label}\n </TabsTrigger>\n ))}\n </TabsList>\n </div>\n\n <div className=\"p-0\">\n {tabs.map((tab) => (\n <TabsContent key={tab.id} value={tab.id}>\n <ShikiCodeBlock\n code={tab.code}\n lang={tab.lang}\n className={cn(\n \"h-fit rounded-lg rounded-t-none border-0\",\n tab.codeBlockClassName\n )}\n />\n </TabsContent>\n ))}\n </div>\n </Tabs>\n </div>\n );\n};\n",
|
|
1313
|
+
"demos": [
|
|
1314
|
+
{
|
|
1315
|
+
"name": "default",
|
|
1316
|
+
"code": "\"use client\";\n\nimport { CodeTabs } from \"@rlx-components/code-tabs\";\nimport { TerminalIcon } from \"lucide-react\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full\">\n <CodeTabs\n tabs={[\n {\n id: \"pnpm\",\n label: \"pnpm\",\n code: \"pnpm add @rlx-components/code-tabs\",\n lang: \"bash\",\n },\n {\n id: \"npm\",\n label: \"npm\",\n code: \"npm install @rlx-components/code-tabs\",\n lang: \"bash\",\n },\n {\n id: \"yarn\",\n label: \"yarn\",\n code: \"yarn add @rlx-components/code-tabs\",\n lang: \"bash\",\n },\n ]}\n startAdornment={\n <div className=\"px-4\">\n <TerminalIcon className=\"w-4 h-4\" />\n </div>\n }\n />\n </div>\n );\n};\n"
|
|
1317
|
+
}
|
|
1318
|
+
]
|
|
1319
|
+
},
|
|
1320
|
+
{
|
|
1321
|
+
"name": "Inline Code",
|
|
1322
|
+
"exportName": "InlineCode",
|
|
1323
|
+
"packageName": "@rlx-components/inline-code",
|
|
1324
|
+
"slug": "inline-code",
|
|
1325
|
+
"category": "component",
|
|
1326
|
+
"sourceCode": "import { cn } from \"@rlx-widgets/base\";\nimport { ReactNode } from \"react\";\n\nexport const InlineCode = ({ className, code, children }: InlineCodeProps) => {\n return (\n <span\n className={cn(\n \"bg-muted rounded px-1 py-0.5 overflow-x-auto text-sm\",\n className\n )}\n >\n <code>{code ?? children}</code>\n </span>\n );\n};\ntype InlineCodeProps =\n | { code: string; children?: never; className?: string }\n | { children: ReactNode; code?: never; className?: string };\n\nexport default InlineCode;\n",
|
|
1327
|
+
"demos": [
|
|
1328
|
+
{
|
|
1329
|
+
"name": "default",
|
|
1330
|
+
"code": "\"use client\";\n\nimport { InlineCode } from \"@rlx-components/inline-code\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full text-center\">\n In order to solve <InlineCode>x</InlineCode> in{\" \"}\n <InlineCode>x + 4 = 5</InlineCode>, we need to isolate{\" \"}\n <InlineCode>x</InlineCode> by subtracting 4 from both sides\n </div>\n );\n};\n"
|
|
1331
|
+
}
|
|
1332
|
+
]
|
|
1333
|
+
},
|
|
1292
1334
|
{
|
|
1293
1335
|
"name": "Shiki Code Block",
|
|
1294
1336
|
"exportName": "ShikiCodeBlock",
|
|
@@ -1327,6 +1369,25 @@
|
|
|
1327
1369
|
"StackedCard.tsx": "import { cn } from \"@rlx-widgets/base\";\nimport { Card } from \"@rlx-widgets/card\";\nimport { forwardRef, MouseEventHandler } from \"react\";\n\nconst boxShadow =\n\t\"[box-shadow:0px_5px_10px_0px_#22215140,1px_1px_1px_1px_#75757526]\";\n\ntype StackedCardProps = {\n\tchildren: React.ReactNode;\n\tclassName?: string;\n\tstyle?: React.CSSProperties;\n\tonMouseEnter?: () => void;\n\tonMouseLeave?: () => void;\n\tonClick?: MouseEventHandler<HTMLDivElement> | undefined;\n};\n\nexport const StackedCard = forwardRef<HTMLDivElement, StackedCardProps>(\n\t({ children, className, style, ...props }, ref) => {\n\t\treturn (\n\t\t\t<Card\n\t\t\t\tref={ref}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"transition-transform duration-200 ease-in-out\",\n\t\t\t\t\t\"h-[175px] w-[260px]\",\n\t\t\t\t\t\"inline-flex gap-4\",\n\t\t\t\t\tboxShadow,\n\t\t\t\t\t\"border-0\",\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t\tstyle={style}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Card>\n\t\t);\n\t}\n);\n\nStackedCard.displayName = \"StackedCard\";\n\nexport default StackedCard;\n"
|
|
1328
1370
|
}
|
|
1329
1371
|
},
|
|
1372
|
+
{
|
|
1373
|
+
"name": "Streaming Text",
|
|
1374
|
+
"exportName": "StreamingText",
|
|
1375
|
+
"packageName": "@rlx-components/streaming-text",
|
|
1376
|
+
"slug": "streaming-text",
|
|
1377
|
+
"category": "component",
|
|
1378
|
+
"sourceCode": "\"use client\";\n\nimport { cn } from \"@rlx-widgets/base\";\nimport {\n ComponentProps,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\nimport {\n type StreamingState,\n type StreamingTextControls,\n type StreamingTextProps,\n} from \"./types\";\n\nexport const StreamingText = forwardRef<\n StreamingTextControls,\n StreamingTextProps\n>(\n (\n {\n text,\n className,\n delay = 10,\n indicator,\n autoStart = false,\n onStateChange,\n },\n ref\n ) => {\n const intervalRef = useRef<NodeJS.Timeout | null>(null);\n const [displayedText, setDisplayedText] = useState(\"\");\n const streamingStateRef = useRef<StreamingState>(\"idle\");\n const charIndexRef = useRef(0);\n\n // Helper to clear interval\n const clearIntervalSafe = useCallback(() => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n }, []);\n\n // Update state and notify callback\n const updateState = useCallback(\n (newState: StreamingState) => {\n streamingStateRef.current = newState;\n onStateChange?.(newState);\n },\n [onStateChange]\n );\n\n // Helper to reset internal state\n const resetInternalState = useCallback(() => {\n charIndexRef.current = 0;\n setDisplayedText(\"\");\n }, []);\n\n const handleStreaming = useCallback(() => {\n // Don't stream if paused or completed\n if (streamingStateRef.current !== \"streaming\") {\n return;\n }\n\n if (charIndexRef.current >= text.length) {\n clearIntervalSafe();\n updateState(\"completed\");\n return;\n }\n const streamedText = text.slice(0, charIndexRef.current + 1);\n setDisplayedText(streamedText);\n ++charIndexRef.current;\n }, [text, clearIntervalSafe, updateState]);\n\n // Helper to start interval\n const startInterval = useCallback(\n (callback: () => void, delayMs: number) => {\n clearIntervalSafe();\n intervalRef.current = setInterval(callback, delayMs);\n },\n [clearIntervalSafe]\n );\n\n // Control methods\n const start = useCallback(() => {\n const currentState = streamingStateRef.current;\n const isCompleted =\n currentState === \"completed\" || charIndexRef.current >= text.length;\n\n if (isCompleted) {\n resetInternalState();\n updateState(\"idle\");\n }\n\n const newState = streamingStateRef.current;\n if (newState === \"idle\" || newState === \"paused\") {\n const validDelay = Math.max(0, delay);\n updateState(\"streaming\");\n\n // Start immediately and then set interval\n handleStreaming();\n startInterval(handleStreaming, validDelay);\n }\n }, [text, delay, handleStreaming, updateState, resetInternalState, startInterval]);\n\n const pause = useCallback(() => {\n if (streamingStateRef.current === \"streaming\") {\n clearIntervalSafe();\n updateState(\"paused\");\n }\n }, [clearIntervalSafe, updateState]);\n\n const reset = useCallback(() => {\n clearIntervalSafe();\n resetInternalState();\n updateState(\"idle\");\n }, [clearIntervalSafe, resetInternalState, updateState]);\n\n // Expose control methods via ref\n useImperativeHandle(\n ref,\n () => ({\n start,\n pause,\n reset,\n getState: () => streamingStateRef.current,\n }),\n [start, pause, reset]\n );\n\n // Reset when text or delay changes\n useEffect(() => {\n clearIntervalSafe();\n resetInternalState();\n updateState(\"idle\");\n\n // Handle empty text\n if (!text) {\n return;\n }\n\n // Start streaming if autoStart is enabled\n if (autoStart) {\n const validDelay = Math.max(0, delay);\n updateState(\"streaming\");\n\n // Start immediately and then set interval\n const initialText = text.slice(0, 1);\n setDisplayedText(initialText);\n charIndexRef.current = 1;\n\n startInterval(handleStreaming, validDelay);\n }\n }, [\n text,\n delay,\n autoStart,\n handleStreaming,\n updateState,\n clearIntervalSafe,\n resetInternalState,\n startInterval,\n ]);\n\n // Cleanup on unmount\n useEffect(() => {\n return clearIntervalSafe;\n }, [clearIntervalSafe]);\n\n return (\n <div className={cn(\"whitespace-pre-wrap\", className)}>\n {displayedText}\n {indicator}\n </div>\n );\n }\n);\n\nStreamingText.displayName = \"StreamingText\";\n\nexport type StreamingTextIndicatorProps = ComponentProps<\"span\">;\n\nexport const StreamingTextIndicator = ({\n className,\n children,\n ...props\n}: StreamingTextIndicatorProps) => {\n return (\n <span\n className={cn(\"inline-block animate-pulse\", className)}\n aria-hidden=\"true\"\n {...props}\n >\n {children ?? \" ▋\"}\n </span>\n );\n};\n",
|
|
1379
|
+
"demos": [
|
|
1380
|
+
{
|
|
1381
|
+
"name": "default",
|
|
1382
|
+
"code": "\"use client\";\n\nimport {\n StreamingText,\n StreamingTextIndicator,\n} from \"@rlx-components/streaming-text\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { useRef } from \"react\";\nimport type { StreamingTextControls } from \"@rlx-components/streaming-text\";\n\nexport const Preview = () => {\n const controlsRef = useRef<StreamingTextControls>(null);\n\n return (\n <div className=\"w-full space-y-4\">\n <div className=\"flex items-center justify-center min-h-[100px]\">\n <StreamingText\n ref={controlsRef}\n text=\"Hello, world! This is a streaming text component that displays text character by character.\"\n autoStart={true}\n indicator={<StreamingTextIndicator />}\n />\n </div>\n <div className=\"flex gap-2 justify-center\">\n <Button onClick={() => controlsRef.current?.start()}>Start</Button>\n <Button onClick={() => controlsRef.current?.pause()}>Pause</Button>\n <Button onClick={() => controlsRef.current?.reset()}>Reset</Button>\n </div>\n </div>\n );\n};\n\n"
|
|
1383
|
+
}
|
|
1384
|
+
],
|
|
1385
|
+
"sourceFiles": {
|
|
1386
|
+
"types/StreamingState.t.ts": "export type StreamingState = \"idle\" | \"streaming\" | \"paused\" | \"completed\";\n",
|
|
1387
|
+
"types/StreamingTextControls.t.ts": "import { StreamingState } from \"./StreamingState.t\";\n\nexport type StreamingTextControls = {\n /**\n * Start or resume streaming.\n */\n start: () => void;\n /**\n * Pause streaming (can be resumed later).\n */\n pause: () => void;\n /**\n * Reset streaming to the beginning (idle state).\n */\n reset: () => void;\n /**\n * Get the current streaming state.\n */\n getState: () => StreamingState;\n};\n",
|
|
1388
|
+
"types/StreamingTextProps.t.ts": "import { ReactNode } from \"react\";\nimport { StreamingState } from \"./StreamingState.t\";\n\nexport type StreamingTextProps = {\n text: string;\n className?: string;\n /**\n * The delay in milliseconds between each character.\n * @default 10\n */\n delay?: number;\n /**\n * Optional indicator to show while streaming (e.g., a blinking cursor).\n * Only displayed when streaming is in progress.\n */\n indicator?: ReactNode;\n /**\n * Whether to automatically start streaming on mount.\n * @default false\n */\n autoStart?: boolean;\n /**\n * Callback fired when streaming state changes.\n * Use this to handle state transitions (idle -> streaming -> paused -> completed).\n */\n onStateChange?: (state: StreamingState) => void;\n};\n"
|
|
1389
|
+
}
|
|
1390
|
+
},
|
|
1330
1391
|
{
|
|
1331
1392
|
"name": "Theme Toggle",
|
|
1332
1393
|
"exportName": "ThemeToggle",
|
|
@@ -1439,5 +1500,5 @@
|
|
|
1439
1500
|
"sourceCode": "export const isValidDate = (date: Date) => {\n return !Number.isNaN(date.getTime());\n};\n\nexport default isValidDate;\n"
|
|
1440
1501
|
}
|
|
1441
1502
|
],
|
|
1442
|
-
"extractedAt": "2025-11-
|
|
1503
|
+
"extractedAt": "2025-11-30T07:11:01.111Z"
|
|
1443
1504
|
}
|
package/dist/package.json
CHANGED