refactor: rewrite radix dialog and sheet templates with jsx (#4671)

- dropped radix sheet meta
- added reusable button styles
- added radix dialog and sheet templates
This commit is contained in:
Bogdan Chadkin authored and GitHub committed 2024-12-29 17:20:36 +07:00
1 parent 6c5711cf2a
commit ef6e71ac6d
10 files changed
+489 -410

No files matched your search

@@ -0,0 +1,151 @@
import { LargeXIcon } from "@webstudio-is/icons/svg";
import {
type TemplateMeta,
$,
css,
PlaceholderValue,
} from "@webstudio-is/template";
import { radix } from "./shared/proxy";
import {
blur,
borderRadius,
borderWidth,
boxShadow,
colors,
fontSize,
fontSizeLineHeight,
height,
letterSpacing,
lineHeight,
maxWidth,
opacity,
spacing,
width,
zIndex,
} from "./shared/theme";
import { getButtonStyle } from "./shared/styles";
export const meta: TemplateMeta = {
category: "radix",
description:
"Displays content with an overlay that covers the window, triggered by a button. Clicking the overlay will close the dialog.",
order: 4,
template: (
<radix.Dialog>
<radix.DialogTrigger>
<$.Button ws:style={getButtonStyle("outline")}>
{new PlaceholderValue("Button")}
</$.Button>
</radix.DialogTrigger>
<radix.DialogOverlay
/**
* fixed inset-0 z-50 bg-background/80 backdrop-blur-sm
* flex
**/
ws:style={css`
position: fixed;
inset: 0;
z-index: ${zIndex[50]};
background-color: rgb(255 255 255 / 0.8);
backdrop-filter: ${blur.sm};
/* To allow positioning Content */
display: flex;
overflow: auto;
`}
>
<radix.DialogContent
/**
* fixed w-full z-50
* grid gap-4 max-w-lg
* m-auto
* border bg-background p-6 shadow-lg
**/
ws:style={css`
width: ${width.full};
z-index: ${zIndex[50]};
display: flex;
flex-direction: column;
gap: ${spacing[4]};
margin: auto;
max-width: ${maxWidth.lg};
border: ${borderWidth.DEFAULT} solid ${colors.border};
background-color: ${colors.background};
padding: ${spacing[6]};
box-shadow: ${boxShadow.lg};
position: relative;
`}
>
<$.Box
ws:label="Dialog Header"
ws:style={css`
display: flex;
flex-direction: column;
gap: ${spacing[2]};
`}
>
<radix.DialogTitle
/**
* text-lg leading-none tracking-tight
**/
ws:style={css`
font-size: ${fontSize.lg};
line-height: ${lineHeight.none};
letter-spacing: ${letterSpacing.tight};
margin: 0;
`}
>
{new PlaceholderValue("Dialog Title you can edit")}
</radix.DialogTitle>
<radix.DialogDescription
/**
* text-sm text-muted-foreground
**/
ws:style={css`
font-size: ${fontSize.sm};
line-height: ${fontSizeLineHeight.sm};
color: ${colors.mutedForeground};
margin: 0;
`}
>
{new PlaceholderValue("Dialog description text you can edit")}
</radix.DialogDescription>
</$.Box>
<$.Text>{new PlaceholderValue("The text you can edit")}</$.Text>
<radix.DialogClose
ws:label="Close Button"
/**
* absolute right-4 top-4
* rounded-sm opacity-70
* ring-offset-background
* hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2
* flex items-center justify-center h-4 w-4
**/
ws:style={css`
position: absolute;
right: ${spacing[4]};
top: ${spacing[4]};
border-radius: ${borderRadius.sm};
opacity: ${opacity[70]};
display: flex;
align-items: center;
justify-content: center;
height: ${height[4]};
width: ${height[4]};
border: 0;
background-color: transparent;
outline: none;
&:hover {
opacity: ${opacity[100]};
}
&:focus-visible {
box-shadow: ${boxShadow.ring};
}
`}
>
<$.HtmlEmbed ws:label="Close Icon" code={LargeXIcon} />
</radix.DialogClose>
</radix.DialogContent>
</radix.DialogOverlay>
</radix.Dialog>
),
};
@@ -6,7 +6,6 @@ import {
HeadingIcon,
TextIcon,
ButtonElementIcon,
LargeXIcon,
} from "@webstudio-is/icons/svg";
import {
defaultStates,
@@ -15,7 +14,6 @@ import {
type WsComponentPropsMeta,
} from "@webstudio-is/react-sdk";
import { div, button, h2, p } from "@webstudio-is/sdk/normalize.css";
import * as tc from "./theme/tailwind-classes";
import {
propsDialog,
propsDialogContent,
@@ -25,7 +23,7 @@ import {
propsDialogTitle,
propsDialogDescription,
} from "./__generated__/dialog.props";
import { buttonReset, getButtonStyles } from "./theme/styles";
import { buttonReset } from "./theme/styles";
const presetStyle = {
div,
@@ -41,7 +39,6 @@ const descriptionPresetStyle = {
// @todo add [data-state] to button and link
export const metaDialogTrigger: WsComponentMeta = {
category: "hidden",
type: "container",
icon: TriggerIcon,
stylable: false,
@@ -52,7 +49,6 @@ export const metaDialogTrigger: WsComponentMeta = {
};
export const metaDialogOverlay: WsComponentMeta = {
category: "hidden",
type: "container",
presetStyle,
icon: OverlayIcon,
@@ -69,7 +65,6 @@ export const metaDialogOverlay: WsComponentMeta = {
};
export const metaDialogContent: WsComponentMeta = {
category: "hidden",
type: "container",
presetStyle,
icon: ContentIcon,
@@ -98,7 +93,6 @@ export const metaDialogContent: WsComponentMeta = {
};
export const metaDialogTitle: WsComponentMeta = {
category: "hidden",
type: "container",
presetStyle: titlePresetStyle,
icon: HeadingIcon,
@@ -109,7 +103,6 @@ export const metaDialogTitle: WsComponentMeta = {
};
export const metaDialogDescription: WsComponentMeta = {
category: "hidden",
type: "container",
presetStyle: descriptionPresetStyle,
icon: TextIcon,
@@ -120,7 +113,6 @@ export const metaDialogDescription: WsComponentMeta = {
};
export const metaDialogClose: WsComponentMeta = {
category: "hidden",
type: "container",
presetStyle: {
button: [buttonReset, button].flat(),
@@ -143,8 +135,6 @@ export const metaDialogClose: WsComponentMeta = {
* Copyright (c) 2023 shadcn
**/
export const metaDialog: WsComponentMeta = {
category: "radix",
order: 4,
type: "container",
constraints: [
{
@@ -158,177 +148,6 @@ export const metaDialog: WsComponentMeta = {
],
icon: DialogIcon,
stylable: false,
description:
"Displays content with an overlay that covers the window, triggered by a button. Clicking the overlay will close the dialog.",
template: [
{
type: "instance",
component: "Dialog",
children: [
{
type: "instance",
component: "DialogTrigger",
children: [
{
type: "instance",
component: "Button",
styles: getButtonStyles("outline"),
children: [{ type: "text", value: "Button", placeholder: true }],
},
],
},
{
type: "instance",
component: "DialogOverlay",
/**
* fixed inset-0 z-50 bg-background/80 backdrop-blur-sm
* flex
**/
styles: [
tc.fixed(),
tc.inset(0),
tc.z(50),
tc.bg("background", 80),
tc.backdropBlur("sm"),
// To allow positioning Content
tc.flex(),
tc.overflow("auto"),
].flat(),
children: [
{
type: "instance",
component: "DialogContent",
/**
* fixed w-full z-50
* grid gap-4 max-w-lg
* m-auto
* border bg-background p-6 shadow-lg
**/
styles: [
tc.w("full"),
tc.z(50),
tc.flex(),
tc.flex("col"),
tc.gap(4),
tc.m("auto"),
tc.maxW("lg"),
tc.border(),
tc.bg("background"),
tc.p(6),
tc.shadow("lg"),
tc.relative(),
].flat(),
children: [
{
type: "instance",
component: "Box",
label: "Dialog Header",
styles: [tc.flex(), tc.flex("col"), tc.gap(1)].flat(),
children: [
{
type: "instance",
component: "DialogTitle",
/**
* text-lg leading-none tracking-tight
**/
styles: [
tc.my(0),
tc.leading("none"),
tc.text("lg"),
tc.tracking("tight"),
].flat(),
children: [
{
type: "text",
value: "Dialog Title you can edit",
placeholder: true,
},
],
},
{
type: "instance",
component: "DialogDescription",
/**
* text-sm text-muted-foreground
**/
styles: [
tc.my(0),
tc.text("sm"),
tc.text("mutedForeground"),
].flat(),
children: [
{
type: "text",
value: "Dialog description text you can edit",
placeholder: true,
},
],
},
],
},
{
type: "instance",
component: "Text",
children: [
{
type: "text",
value: "The text you can edit",
placeholder: true,
},
],
},
{
type: "instance",
component: "DialogClose",
/**
* absolute right-4 top-4
* rounded-sm opacity-70
* ring-offset-background
* hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2
* flex items-center justify-center h-4 w-4
**/
styles: [
tc.absolute(),
tc.right(4),
tc.top(4),
tc.rounded("sm"),
tc.opacity(70),
tc.flex(),
tc.items("center"),
tc.justify("center"),
tc.h(4),
tc.w(4),
tc.border(0),
tc.bg("transparent"),
tc.outline("none"),
tc.hover(tc.opacity(100)),
tc.focus(tc.ring("ring", 2, "background", 2)),
].flat(),
children: [
{
type: "instance",
component: "HtmlEmbed",
label: "Close Icon",
props: [
{
type: "string",
name: "code",
value: LargeXIcon,
},
],
children: [],
},
],
},
],
},
],
},
],
},
],
};
export const propsMetaDialog: WsComponentPropsMeta = {
@@ -6,6 +6,14 @@ import {
import { radix } from "./shared/proxy";
import { fontSize, lineHeight, weights } from "./shared/theme";
/**
* Styles source without animations:
* https://github.com/shadcn-ui/ui/blob/main/apps/www/registry/default/ui/label.tsx
*
* Attributions
* MIT License
* Copyright (c) 2023 shadcn
**/
export const meta: TemplateMeta = {
category: "radix",
description:
@@ -12,7 +12,6 @@ export {
metaDialogTitle as DialogTitle,
metaDialogDescription as DialogDescription,
} from "./dialog.ws";
export { meta as Sheet } from "./sheet.ws";
export {
metaPopover as Popover,
metaPopoverTrigger as PopoverTrigger,
@@ -0,0 +1,93 @@
import { css, type TemplateStyleDecl } from "@webstudio-is/template";
import {
borderRadius,
borderWidth,
boxShadow,
colors,
fontSize,
fontSizeLineHeight,
height,
opacity,
spacing,
weights,
} from "./theme";
// ghost icon button
// 'inline-flex items-center justify-center rounded-md text-sm font-medium
// ring-offset-background transition-colors
// focus-visible:outline-none focus-visible:ring-2
// focus-visible:ring-ring focus-visible:ring-offset-2
// disabled:pointer-events-none disabled:opacity-50'
const buttonStyle = css`
display: inline-flex;
align-items: center;
justify-content: center;
background-color: transparent;
border: 0 solid ${colors.border};
border-radius: ${borderRadius.md};
font-size: ${fontSize.sm};
line-height: ${fontSizeLineHeight.sm};
font-weight: ${weights.medium};
&:focus-visible {
outline: 2px solid transparent;
outline-offset: 2px;
box-shadow: ${boxShadow.ring};
}
&:disabled {
pointer-events: none;
opacity: ${opacity[50]};
}
`;
// hover:bg-accent hover:text-accent-foreground
const ghostButtonStyle = css`
&:hover {
background-color: ${colors.accent};
color: ${colors.accentForeground};
}
`;
// border border-input bg-background hover:bg-accent hover:text-accent-foreground
const outlineButtonStyle = css`
border: ${borderWidth.DEFAULT} solid ${colors.input};
background-color: ${colors.background};
&:hover {
background-color: ${colors.accent};
color: ${colors.accentForeground};
}
`;
// h-10 px-4 py-2
const defaultButtonStyle = css`
height: ${height[10]};
padding: ${spacing[2]} ${spacing[4]};
`;
// Set explicit paddings for IOS Safari to prevent the icon from collapsing
// h-10 w-10
const iconButtonStyle = css`
height: ${spacing[10]};
width: ${spacing[10]};
padding: ${spacing[0]} ${spacing[1.5]};
`;
export const getButtonStyle = (
variant: "outline" | "ghost",
size: "default" | /*"sm" |*/ "icon" = "default"
) => {
const style: TemplateStyleDecl[] = [...buttonStyle];
if (variant === "ghost") {
style.push(...ghostButtonStyle);
}
if (variant === "outline") {
style.push(...outlineButtonStyle);
}
if (size === "default") {
style.push(...defaultButtonStyle);
}
if (size === "icon") {
style.push(...iconButtonStyle);
}
return style;
};
@@ -59,6 +59,15 @@ export const weights = {
black: "900",
} as const;
export const letterSpacing = {
tighter: "-0.05em",
tight: "-0.025em",
normal: "0em",
wide: "0.025em",
wider: "0.05em",
widest: "0.1em",
} as const;
export const spacing = {
"0": "0px",
"1": "0.25rem",
@@ -97,6 +106,11 @@ export const spacing = {
"3.5": "0.875rem",
} as const;
export const width = {
...spacing,
full: "100%",
} as const;
export const height = {
...spacing,
auto: "auto",
@@ -122,6 +136,34 @@ export const height = {
fit: "fit-content",
} as const;
export const maxWidth = {
"0": "0rem",
xs: "20rem",
sm: "24rem",
md: "28rem",
lg: "32rem",
xl: "36rem",
"2xl": "42rem",
"3xl": "48rem",
"4xl": "56rem",
"5xl": "64rem",
"6xl": "72rem",
"7xl": "80rem",
full: "100%",
min: "min-content",
max: "max-content",
fit: "fit-content",
prose: "65ch",
} as const;
export const borderWidth = {
"0": "0px",
"2": "2px",
"4": "4px",
"8": "8px",
DEFAULT: "1px",
};
export const borderRadius = {
none: "0px",
sm: "0.125rem",
@@ -212,3 +254,24 @@ export const boxShadow = {
`0 0 0 ${ringOffsetWidth[2]} ${colors.background}, ` +
`0 0 0 calc(${ringWidth[2]} + ${ringOffsetWidth[2]}) ${colors.ring}`,
} as const;
export const zIndex = {
"0": "0",
"10": "10",
"20": "20",
"30": "30",
"40": "40",
"50": "50",
} as const;
export const blur = {
sm: "blur(0 1px 2px 0 rgb(0 0 0 / 0.05))",
DEFAULT:
"blur(0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1))",
md: "blur(0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1))",
lg: "blur(0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1))",
xl: "blur(0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1))",
"2xl": "blur(0 25px 50px -12px rgb(0 0 0 / 0.25))",
inner: "blur(inset 0 2px 4px 0 rgb(0 0 0 / 0.05))",
none: "blur(none)",
};
@@ -0,0 +1,169 @@
import { LargeXIcon, MenuIcon } from "@webstudio-is/icons/svg";
import {
type TemplateMeta,
$,
css,
PlaceholderValue,
} from "@webstudio-is/template";
import { radix } from "./shared/proxy";
import {
blur,
borderRadius,
borderWidth,
boxShadow,
colors,
fontSize,
fontSizeLineHeight,
height,
letterSpacing,
lineHeight,
maxWidth,
opacity,
spacing,
width,
zIndex,
} from "./shared/theme";
import { getButtonStyle } from "./shared/styles";
/**
* Styles source without animations:
* https://github.com/shadcn-ui/ui/blob/main/apps/www/registry/default/ui/sheet.tsx
*
* Attributions
* MIT License
* Copyright (c) 2023 shadcn
**/
export const meta: TemplateMeta = {
category: "radix",
icon: MenuIcon,
description:
"Displays content in a menu that slides out from the side of the screen, triggered by a button. Use this component for a typical mobile hamburger menu.",
order: 1,
template: (
<radix.Dialog ws:label="Sheet">
<radix.DialogTrigger ws:label="Sheet Trigger">
<$.Button ws:style={getButtonStyle("ghost", "icon")}>
<$.HtmlEmbed ws:label="Hamburger Menu Svg" code={MenuIcon} />
</$.Button>
</radix.DialogTrigger>
<radix.DialogOverlay
ws:label="Sheet Overlay"
/**
* fixed inset-0 z-50 bg-background/80 backdrop-blur-sm
* flex
**/
ws:style={css`
position: fixed;
inset: 0;
z-index: ${zIndex[50]};
background-color: rgb(255 255 255 / 0.8);
backdrop-filter: ${blur.sm};
/* To allow positioning Content */
display: flex;
flex-direction: column;
overflow: auto;
`}
>
<radix.DialogContent
ws:label="Sheet Content"
/**
* fixed w-full z-50
* grid gap-4 max-w-lg
* m-auto
* border bg-background p-6 shadow-lg
**/
ws:style={css`
width: ${width.full};
z-index: ${zIndex[50]};
display: flex;
flex-direction: column;
gap: ${spacing[4]};
border: ${borderWidth.DEFAULT} solid ${colors.border};
background-color: ${colors.background};
padding: ${spacing[6]};
box-shadow: ${boxShadow.lg};
position: relative;
/* side=left */
margin-right: auto;
max-width: ${maxWidth.sm};
flex-grow: 1;
`}
>
<$.Box ws:label="Navigation" tag="nav" role="navigation">
<$.Box
ws:label="Sheet Header"
ws:style={css`
display: flex;
flex-direction: column;
gap: ${spacing[2]};
`}
>
<radix.DialogTitle
ws:label="Sheet Title"
/**
* text-lg leading-none tracking-tight
**/
ws:style={css`
font-size: ${fontSize.lg};
line-height: ${lineHeight.none};
letter-spacing: ${letterSpacing.tight};
margin: 0;
`}
>
{new PlaceholderValue("Sheet Title")}
</radix.DialogTitle>
<radix.DialogDescription
ws:label="Sheet Description"
/**
* text-sm text-muted-foreground
**/
ws:style={css`
font-size: ${fontSize.sm};
line-height: ${fontSizeLineHeight.sm};
color: ${colors.mutedForeground};
margin: 0;
`}
>
{new PlaceholderValue("Sheet description text you can edit")}
</radix.DialogDescription>
</$.Box>
<$.Text>{new PlaceholderValue("The text you can edit")}</$.Text>
</$.Box>
<radix.DialogClose
ws:label="Close Button"
/**
* absolute right-4 top-4
* rounded-sm opacity-70
* ring-offset-background
* hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2
* flex items-center justify-center h-4 w-4
**/
ws:style={css`
position: absolute;
right: ${spacing[4]};
top: ${spacing[4]};
border-radius: ${borderRadius.sm};
opacity: ${opacity[70]};
display: flex;
align-items: center;
justify-content: center;
height: ${height[4]};
width: ${height[4]};
border: 0;
background-color: transparent;
outline: none;
&:hover {
opacity: ${opacity[100]};
}
&:focus-visible {
box-shadow: ${boxShadow.ring};
}
`}
>
<$.HtmlEmbed ws:label="Close Icon" code={LargeXIcon} />
</radix.DialogClose>
</radix.DialogContent>
</radix.DialogOverlay>
</radix.Dialog>
),
};
@@ -1,226 +0,0 @@
import { MenuIcon, LargeXIcon } from "@webstudio-is/icons/svg";
import type { WsComponentMeta } from "@webstudio-is/react-sdk";
import * as tc from "./theme/tailwind-classes";
import { getButtonStyles } from "./theme/styles";
/**
* Styles source without animations:
* https://github.com/shadcn-ui/ui/blob/main/apps/www/registry/default/ui/sheet.tsx
*
* Attributions
* MIT License
* Copyright (c) 2023 shadcn
**/
export const meta: WsComponentMeta = {
category: "radix",
order: 1,
type: "container",
icon: MenuIcon,
stylable: false,
description:
"Displays content in a menu that slides out from the side of the screen, triggered by a button. Use this component for a typical mobile hamburger menu.",
template: [
{
type: "instance",
component: "Dialog",
label: "Sheet",
props: [],
children: [
{
type: "instance",
component: "DialogTrigger",
label: "Sheet Trigger",
children: [
{
type: "instance",
component: "Button",
styles: getButtonStyles("ghost", "icon"),
children: [
{
type: "instance",
component: "HtmlEmbed",
label: "Hamburger Menu Svg",
props: [
{
type: "string",
name: "code",
value: MenuIcon,
},
],
children: [],
},
],
},
],
},
{
type: "instance",
component: "DialogOverlay",
label: "Sheet Overlay",
/**
* fixed inset-0 z-50 bg-background/80 backdrop-blur-sm
* flex
**/
styles: [
tc.fixed(),
tc.inset(0),
tc.z(50),
tc.bg("background", 80),
tc.backdropBlur("sm"),
// To allow positioning Content
tc.flex(),
tc.flex("col"),
tc.overflow("auto"),
].flat(),
children: [
{
type: "instance",
component: "DialogContent",
label: "Sheet Content",
/**
* fixed w-full z-50
* grid gap-4 max-w-lg
* m-auto
* border bg-background p-6 shadow-lg
**/
styles: [
tc.w("full"),
tc.z(50),
tc.flex(),
tc.flex("col"),
tc.gap(4),
tc.border(),
tc.bg("background"),
tc.p(6),
tc.shadow("lg"),
tc.relative(),
// side=left
tc.mr("auto"),
tc.maxW("sm"),
tc.grow(),
].flat(),
children: [
{
type: "instance",
component: "Box",
label: "Navigation",
props: [
{ name: "tag", type: "string", value: "nav" },
{ name: "role", type: "string", value: "navigation" },
],
children: [
{
type: "instance",
component: "Box",
label: "Sheet Header",
styles: [tc.flex(), tc.flex("col"), tc.gap(1)].flat(),
children: [
{
type: "instance",
component: "DialogTitle",
label: "Sheet Title",
/**
* text-lg leading-none tracking-tight
**/
styles: [
tc.my(0),
tc.leading("none"),
tc.text("lg"),
tc.tracking("tight"),
].flat(),
children: [
{
type: "text",
value: "Sheet Title",
placeholder: true,
},
],
},
{
type: "instance",
component: "DialogDescription",
label: "Sheet Description",
/**
* text-sm text-muted-foreground
**/
styles: [
tc.my(0),
tc.text("sm"),
tc.text("mutedForeground"),
].flat(),
children: [
{
type: "text",
value: "Sheet description text you can edit",
placeholder: true,
},
],
},
],
},
{
type: "instance",
component: "Text",
children: [
{
type: "text",
value: "The text you can edit",
placeholder: true,
},
],
},
],
},
{
type: "instance",
component: "DialogClose",
label: "Close Button",
/**
* absolute right-4 top-4
* rounded-sm opacity-70
* ring-offset-background
* hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2
* flex items-center justify-center h-4 w-4
**/
styles: [
tc.absolute(),
tc.right(4),
tc.top(4),
tc.rounded("sm"),
tc.opacity(70),
tc.flex(),
tc.items("center"),
tc.justify("center"),
tc.h(4),
tc.w(4),
tc.border(0),
tc.bg("transparent"),
tc.outline("none"),
tc.hover(tc.opacity(100)),
tc.focus(tc.ring("ring", 2, "background", 2)),
].flat(),
children: [
{
type: "instance",
component: "HtmlEmbed",
label: "Close Icon",
props: [
{
type: "string",
name: "code",
value: LargeXIcon,
},
],
children: [],
},
],
},
],
},
],
},
],
},
],
};
@@ -43,7 +43,8 @@ const tabsTriggerStyle = css`
font-weight: ${weights.medium};
transition: ${transition.all};
&:focus-visible {
outline: none;
outline: 2px solid transparent;
outline-offset: 2px;
box-shadow: ${boxShadow.ring};
}
&:disabled {
@@ -1,2 +1,4 @@
export { meta as Label } from "./label.template";
export { meta as Tabs } from "./tabs.template";
export { meta as Sheet } from "./sheet.template";
export { meta as Dialog } from "./dialog.template";