diff --git a/packages/sdk-components-react-radix/src/accordion.template.tsx b/packages/sdk-components-react-radix/src/accordion.template.tsx
new file mode 100644
index 000000000000..e6adca8187b7
--- /dev/null
+++ b/packages/sdk-components-react-radix/src/accordion.template.tsx
@@ -0,0 +1,116 @@
+import {
+ $,
+ css,
+ PlaceholderValue,
+ type TemplateMeta,
+} from "@webstudio-is/template";
+import { radix } from "./shared/proxy";
+import {
+ borderWidth,
+ colors,
+ fontSize,
+ fontSizeLineHeight,
+ height,
+ spacing,
+ transition,
+ weights,
+ width,
+} from "./shared/theme";
+import { ChevronDownIcon } from "@webstudio-is/icons/svg";
+
+const createAccordionItem = (triggerText: string, contentText: string) => {
+ return (
+
+
+ svg]:rotate-180
+ ws:style={css`
+ display: flex;
+ flex: 1 1 0;
+ align-items: center;
+ justify-content: between;
+ padding: ${spacing[4]} 0;
+ font-weight: ${weights.medium};
+ --accordion-trigger-icon-transform: 0deg;
+ &:hover {
+ text-decoration-line: underline;
+ }
+ &[data-state="open"] {
+ --accordion-trigger-icon-transform: 180deg;
+ }
+ `}
+ >
+ {new PlaceholderValue(triggerText)}
+
+ <$.Box
+ ws:label="Icon Container"
+ // h-4 w-4 shrink-0 transition-transform duration-200
+ ws:style={css`
+ rotate: --accordion-trigger-icon-transform;
+ height: ${height[4]};
+ width: ${width[4]};
+ flex-shrink: 0;
+ transition: ${transition.all};
+ transition-duration: 200ms;
+ `}
+ >
+ <$.HtmlEmbed ws:label="Chevron Icon" code={ChevronDownIcon} />
+ $.Box>
+
+
+ {new PlaceholderValue(contentText)}
+
+
+ );
+};
+
+/**
+ * Styles source without animations:
+ * https://github.com/shadcn-ui/ui/blob/main/apps/www/registry/default/ui/accordion.tsx
+ *
+ * Attributions
+ * MIT License
+ * Copyright (c) 2023 shadcn
+ **/
+export const meta: TemplateMeta = {
+ category: "radix",
+ description:
+ "A vertically stacked set of interactive headings that each reveal an associated section of content. Clicking on the heading will open the item and close other items.",
+ order: 3,
+ template: (
+
+ {createAccordionItem(
+ "Is it accessible?",
+ "Yes. It adheres to the WAI-ARIA design pattern."
+ )}
+ {createAccordionItem(
+ "Is it styled?",
+ "Yes. It comes with default styles that matches the other components' aesthetic."
+ )}
+ {createAccordionItem(
+ "Is it animated?",
+ "Yes. It's animated by default, but you can disable it if you prefer."
+ )}
+
+ ),
+};
diff --git a/packages/sdk-components-react-radix/src/accordion.ws.ts b/packages/sdk-components-react-radix/src/accordion.ws.ts
index 0c5658651c97..fece7c41d7f2 100644
--- a/packages/sdk-components-react-radix/src/accordion.ws.ts
+++ b/packages/sdk-components-react-radix/src/accordion.ws.ts
@@ -4,15 +4,12 @@ import {
HeaderIcon,
TriggerIcon,
ContentIcon,
- ChevronDownIcon,
} from "@webstudio-is/icons/svg";
import {
defaultStates,
- type EmbedTemplateStyleDecl,
type PresetStyle,
type WsComponentMeta,
type WsComponentPropsMeta,
- type WsEmbedTemplate,
} from "@webstudio-is/react-sdk";
import { div, h3, button } from "@webstudio-is/sdk/normalize.css";
import * as tc from "./theme/tailwind-classes";
@@ -29,202 +26,19 @@ const presetStyle = {
div,
} satisfies PresetStyle<"div">;
-/**
- * Styles source without animations:
- * https://github.com/shadcn-ui/ui/blob/main/apps/www/registry/default/ui/accordion.tsx
- *
- * Attributions
- * MIT License
- * Copyright (c) 2023 shadcn
- **/
-
-// border-b
-const accordionItemStyles: EmbedTemplateStyleDecl[] = [tc.borderB()].flat();
-
-const createAccordionTrigger = ({
- children,
-}: {
- children: WsEmbedTemplate;
-}): WsEmbedTemplate[number] => ({
- type: "instance",
- component: "AccordionHeader",
- // flex
- styles: [tc.flex()].flat(),
- children: [
- {
- type: "instance",
- component: "AccordionTrigger",
- // flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180
- styles: [
- tc.flex(),
- tc.flex(1),
- tc.items("center"),
- tc.justify("between"),
- tc.py(4),
- tc.font("medium"),
- tc.hover([tc.underline()].flat()),
- tc.property("--accordion-trigger-icon-transform", "0deg"),
- tc.state(
- [tc.property("--accordion-trigger-icon-transform", "180deg")],
- "[data-state=open]"
- ),
- ].flat(),
- children: [
- {
- type: "instance",
- component: "Text",
- children,
- },
- {
- type: "instance",
- component: "Box",
- label: "Icon Container",
- // h-4 w-4 shrink-0 transition-transform duration-200
- styles: [
- tc.property("rotate", "--accordion-trigger-icon-transform"),
- tc.h(4),
- tc.w(4),
- tc.shrink(0),
- tc.transition("all"),
- tc.duration(200),
- ].flat(),
- children: [
- {
- type: "instance",
- component: "HtmlEmbed",
- label: "Chevron Icon",
- props: [
- {
- type: "string",
- name: "code",
- value: ChevronDownIcon,
- },
- ],
- children: [],
- },
- ],
- },
- ],
- },
- ],
-});
-
-// overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down
-// pb-4 pt-0
-const accordionContentStyles: EmbedTemplateStyleDecl[] = [
- tc.overflow("hidden"),
- tc.text("sm"),
- // transition does not work with display: none
- // tc.transition("all"),
- tc.pb(4),
-].flat();
-
export const metaAccordion: WsComponentMeta = {
- category: "radix",
- order: 3,
type: "container",
icon: AccordionIcon,
presetStyle,
- description:
- "A vertically stacked set of interactive headings that each reveal an associated section of content. Clicking on the heading will open the item and close other items.",
constraints: [
{
relation: "descendant",
component: { $eq: "AccordionItem" },
},
],
- template: [
- {
- type: "instance",
- component: "Accordion",
- props: [
- { type: "boolean", name: "collapsible", value: true },
- { type: "string", name: "defaultValue", value: "0" },
- ],
- children: [
- {
- type: "instance",
- component: "AccordionItem",
- styles: accordionItemStyles,
- children: [
- createAccordionTrigger({
- children: [
- { type: "text", value: "Is it accessible?", placeholder: true },
- ],
- }),
- {
- type: "instance",
- component: "AccordionContent",
- styles: accordionContentStyles,
- children: [
- {
- type: "text",
- value: "Yes. It adheres to the WAI-ARIA design pattern.",
- placeholder: true,
- },
- ],
- },
- ],
- },
-
- {
- type: "instance",
- component: "AccordionItem",
- styles: accordionItemStyles,
- children: [
- createAccordionTrigger({
- children: [
- { type: "text", value: "Is it styled?", placeholder: true },
- ],
- }),
- {
- type: "instance",
- component: "AccordionContent",
- styles: accordionContentStyles,
- children: [
- {
- type: "text",
- value:
- "Yes. It comes with default styles that matches the other components' aesthetic.",
- placeholder: true,
- },
- ],
- },
- ],
- },
-
- {
- type: "instance",
- component: "AccordionItem",
- styles: accordionItemStyles,
- children: [
- createAccordionTrigger({
- children: [
- { type: "text", value: "Is it animated?", placeholder: true },
- ],
- }),
- {
- type: "instance",
- component: "AccordionContent",
- styles: accordionContentStyles,
- children: [
- {
- type: "text",
- value:
- "Yes. It's animated by default, but you can disable it if you prefer.",
- placeholder: true,
- },
- ],
- },
- ],
- },
- ],
- },
- ],
};
export const metaAccordionItem: WsComponentMeta = {
- category: "hidden",
type: "container",
label: "Item",
icon: ItemIcon,
@@ -247,7 +61,6 @@ export const metaAccordionItem: WsComponentMeta = {
};
export const metaAccordionHeader: WsComponentMeta = {
- category: "hidden",
type: "container",
label: "Item Header",
icon: HeaderIcon,
@@ -267,7 +80,6 @@ export const metaAccordionHeader: WsComponentMeta = {
};
export const metaAccordionTrigger: WsComponentMeta = {
- category: "hidden",
type: "container",
label: "Item Trigger",
icon: TriggerIcon,
@@ -289,7 +101,6 @@ export const metaAccordionTrigger: WsComponentMeta = {
};
export const metaAccordionContent: WsComponentMeta = {
- category: "hidden",
type: "container",
label: "Item Content",
icon: ContentIcon,
diff --git a/packages/sdk-components-react-radix/src/collapsible.template.tsx b/packages/sdk-components-react-radix/src/collapsible.template.tsx
new file mode 100644
index 000000000000..1606c1d5502c
--- /dev/null
+++ b/packages/sdk-components-react-radix/src/collapsible.template.tsx
@@ -0,0 +1,22 @@
+import { $, PlaceholderValue, type TemplateMeta } from "@webstudio-is/template";
+import { radix } from "./shared/proxy";
+import { getButtonStyle } from "./shared/styles";
+
+export const meta: TemplateMeta = {
+ category: "radix",
+ description:
+ "An interactive component which expands and collapses some content, triggered by a button.",
+ order: 5,
+ template: (
+
+
+ <$.Button ws:style={getButtonStyle("outline")}>
+ {new PlaceholderValue("Click to toggle content")}
+ $.Button>
+
+
+ <$.Text>{new PlaceholderValue("Collapsible Content")}$.Text>
+
+
+ ),
+};
diff --git a/packages/sdk-components-react-radix/src/collapsible.ws.ts b/packages/sdk-components-react-radix/src/collapsible.ws.ts
index 598045c15daa..c774a9438384 100644
--- a/packages/sdk-components-react-radix/src/collapsible.ws.ts
+++ b/packages/sdk-components-react-radix/src/collapsible.ws.ts
@@ -14,15 +14,12 @@ import {
propsCollapsibleContent,
propsCollapsibleTrigger,
} from "./__generated__/collapsible.props";
-import { getButtonStyles } from "./theme/styles";
const presetStyle = {
div,
} satisfies PresetStyle<"div">;
export const metaCollapsible: WsComponentMeta = {
- category: "radix",
- order: 5,
type: "container",
constraints: [
{
@@ -36,56 +33,9 @@ export const metaCollapsible: WsComponentMeta = {
],
presetStyle,
icon: CollapsibleIcon,
- description:
- "An interactive component which expands and collapses some content, triggered by a button.",
- template: [
- {
- type: "instance",
- component: "Collapsible",
- props: [],
- children: [
- {
- type: "instance",
- component: "CollapsibleTrigger",
- children: [
- {
- type: "instance",
- component: "Button",
- styles: getButtonStyles("outline"),
- children: [
- {
- type: "text",
- value: "Click to toggle content",
- placeholder: true,
- },
- ],
- },
- ],
- },
- {
- type: "instance",
- component: "CollapsibleContent",
- children: [
- {
- type: "instance",
- component: "Text",
- children: [
- {
- type: "text",
- value: "Collapsible Content",
- placeholder: true,
- },
- ],
- },
- ],
- },
- ],
- },
- ],
};
export const metaCollapsibleTrigger: WsComponentMeta = {
- category: "hidden",
type: "container",
icon: TriggerIcon,
stylable: false,
@@ -96,7 +46,6 @@ export const metaCollapsibleTrigger: WsComponentMeta = {
};
export const metaCollapsibleContent: WsComponentMeta = {
- category: "hidden",
type: "container",
presetStyle,
icon: ContentIcon,
diff --git a/packages/sdk-components-react-radix/src/templates.ts b/packages/sdk-components-react-radix/src/templates.ts
index bc6fa481d8c6..787a28b60ecb 100644
--- a/packages/sdk-components-react-radix/src/templates.ts
+++ b/packages/sdk-components-react-radix/src/templates.ts
@@ -4,3 +4,5 @@ export { meta as Sheet } from "./sheet.template";
export { meta as Dialog } from "./dialog.template";
export { meta as Switch } from "./switch.template";
export { meta as Checkbox } from "./checkbox.template";
+export { meta as Collapsible } from "./collapsible.template";
+export { meta as Accordion } from "./accordion.template";