cortena-ui 1.0.0 → 1.1.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/dist/index.d.ts +39 -8
- package/dist/index.js +38 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/button-link.tsx +49 -0
- package/src/components/markdown.tsx +12 -2
- package/src/index.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cortena-ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Cortena UI — the shared React component library for cortenaweb and every Cortena extension. shadcn over Base UI, styled entirely from cortena-design tokens.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type * as React from "react";
|
|
4
|
+
import { cn } from "@/lib/cn";
|
|
5
|
+
import { buttonVariants, type ButtonProps } from "@/components/button";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* An anchor that looks like a Button and keeps link semantics.
|
|
9
|
+
*
|
|
10
|
+
* `Button render={<a />}` makes Base UI treat the anchor as a button (role,
|
|
11
|
+
* tabindex, its `nativeButton` warning), which demotes real navigation for
|
|
12
|
+
* assistive technology and breaks `getByRole("link")`. Navigation should stay
|
|
13
|
+
* an anchor. This is the migration target for every Radix-era
|
|
14
|
+
* `<Button asChild><Link /></Button>`.
|
|
15
|
+
*
|
|
16
|
+
* Framework routers: pass `render` with the router's link so the styling and
|
|
17
|
+
* `href` land on it, e.g. `render={<NextLink href="/x" />}`; otherwise it
|
|
18
|
+
* renders a plain `<a>`.
|
|
19
|
+
*/
|
|
20
|
+
export interface ButtonLinkProps
|
|
21
|
+
extends Omit<React.ComponentProps<"a">, "children">,
|
|
22
|
+
Pick<ButtonProps, "variant" | "size"> {
|
|
23
|
+
children?: React.ReactNode;
|
|
24
|
+
/** Replace the rendered `<a>` with a router link; props are merged onto it. */
|
|
25
|
+
render?: React.ReactElement<Record<string, unknown>>;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function ButtonLink({ className, variant, size, render, disabled, children, ...props }: ButtonLinkProps) {
|
|
30
|
+
const classes = cn(buttonVariants({ variant, size }), disabled && "pointer-events-none opacity-50", className);
|
|
31
|
+
const merged = {
|
|
32
|
+
...props,
|
|
33
|
+
"data-slot": "button-link",
|
|
34
|
+
className: classes,
|
|
35
|
+
"aria-disabled": disabled || undefined,
|
|
36
|
+
tabIndex: disabled ? -1 : props.tabIndex,
|
|
37
|
+
};
|
|
38
|
+
if (render) {
|
|
39
|
+
const Element = render.type as React.ElementType;
|
|
40
|
+
return (
|
|
41
|
+
<Element {...(render.props as Record<string, unknown>)} {...merged}>
|
|
42
|
+
{children ?? (render.props as { children?: React.ReactNode }).children}
|
|
43
|
+
</Element>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return <a {...merged}>{children}</a>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { ButtonLink };
|
|
@@ -327,6 +327,15 @@ export interface MarkdownProps extends Omit<React.ComponentProps<"div">, "childr
|
|
|
327
327
|
remarkPlugins?: NonNullable<Options["remarkPlugins"]>;
|
|
328
328
|
/** Extra rehype plugins, appended after sanitize. */
|
|
329
329
|
rehypePlugins?: NonNullable<Options["rehypePlugins"]>;
|
|
330
|
+
/**
|
|
331
|
+
* Rehype plugins that must run BEFORE sanitize. The one legitimate use is
|
|
332
|
+
* `rehype-raw` in a host that embeds trusted custom tags in markdown (the
|
|
333
|
+
* webchat's `<cortena-*>` blocks): raw HTML has to become nodes before the
|
|
334
|
+
* sanitizer sees it, and the sanitize schema then decides what survives.
|
|
335
|
+
* Anything placed here widens what reaches the sanitizer, so keep the
|
|
336
|
+
* schema strict when you use it.
|
|
337
|
+
*/
|
|
338
|
+
rehypePluginsBeforeSanitize?: NonNullable<Options["rehypePlugins"]>;
|
|
330
339
|
/** Replace the sanitize schema; defaults to `markdownSanitizeSchema`. */
|
|
331
340
|
sanitizeSchema?: SanitizeSchema;
|
|
332
341
|
/** Rewrite URLs; defaults to react-markdown's, which drops non-http(s)/mailto/tel schemes. */
|
|
@@ -340,6 +349,7 @@ function Markdown({
|
|
|
340
349
|
components,
|
|
341
350
|
remarkPlugins,
|
|
342
351
|
rehypePlugins,
|
|
352
|
+
rehypePluginsBeforeSanitize,
|
|
343
353
|
sanitizeSchema = markdownSanitizeSchema,
|
|
344
354
|
urlTransform,
|
|
345
355
|
className,
|
|
@@ -351,8 +361,8 @@ function Markdown({
|
|
|
351
361
|
);
|
|
352
362
|
const remark = React.useMemo(() => [remarkGfm, ...(remarkPlugins ?? [])], [remarkPlugins]);
|
|
353
363
|
const rehype = React.useMemo(
|
|
354
|
-
() => [[rehypeSanitize, sanitizeSchema] as const, ...(rehypePlugins ?? [])],
|
|
355
|
-
[rehypePlugins, sanitizeSchema],
|
|
364
|
+
() => [...(rehypePluginsBeforeSanitize ?? []), [rehypeSanitize, sanitizeSchema] as const, ...(rehypePlugins ?? [])],
|
|
365
|
+
[rehypePluginsBeforeSanitize, rehypePlugins, sanitizeSchema],
|
|
356
366
|
);
|
|
357
367
|
return (
|
|
358
368
|
<div
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,8 @@ export type { AlertProps } from "@/components/alert";
|
|
|
9
9
|
export { Avatar, AvatarFallback, AvatarImage } from "@/components/avatar";
|
|
10
10
|
export { Badge, badgeVariants } from "@/components/badge";
|
|
11
11
|
export type { BadgeProps } from "@/components/badge";
|
|
12
|
+
export { ButtonLink } from "@/components/button-link";
|
|
13
|
+
export type { ButtonLinkProps } from "@/components/button-link";
|
|
12
14
|
export { Button, buttonVariants } from "@/components/button";
|
|
13
15
|
export type { ButtonProps } from "@/components/button";
|
|
14
16
|
export { Calendar, CalendarDayButton } from "@/components/calendar";
|