From b9e20844e5978cbf7e25bdcdce8800d36453dd48 Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Thu, 2 Jan 2025 22:04:33 +0700 Subject: [PATCH] refactor: rewrite radio group and select templates with jsx (#4697) - got rid of variables and expressions in template, both use defaultValue - returned back radix label in checkbox template --- .../src/checkbox.template.tsx | 4 +- .../src/radio-group.template.tsx | 85 +++++++ .../src/radio-group.ws.ts | 112 +--------- .../src/select.template.tsx | 156 +++++++++++++ .../src/select.ws.ts | 209 ------------------ .../src/templates.ts | 2 + 6 files changed, 246 insertions(+), 322 deletions(-) create mode 100644 packages/sdk-components-react-radix/src/radio-group.template.tsx create mode 100644 packages/sdk-components-react-radix/src/select.template.tsx diff --git a/packages/sdk-components-react-radix/src/checkbox.template.tsx b/packages/sdk-components-react-radix/src/checkbox.template.tsx index 39ab5701c84a..32461fd80cf3 100644 --- a/packages/sdk-components-react-radix/src/checkbox.template.tsx +++ b/packages/sdk-components-react-radix/src/checkbox.template.tsx @@ -23,7 +23,7 @@ export const meta: TemplateMeta = { "Use within a form to allow your users to toggle between checked and not checked. Group checkboxes by matching their “Name” properties. Unlike radios, any number of checkboxes in a group can be checked.", order: 101, template: ( - <$.Label + {new PlaceholderValue("Checkbox")} - + ), }; diff --git a/packages/sdk-components-react-radix/src/radio-group.template.tsx b/packages/sdk-components-react-radix/src/radio-group.template.tsx new file mode 100644 index 000000000000..0b80a57713b3 --- /dev/null +++ b/packages/sdk-components-react-radix/src/radio-group.template.tsx @@ -0,0 +1,85 @@ +import { + $, + css, + PlaceholderValue, + type TemplateMeta, +} from "@webstudio-is/template"; +import { DotIcon } from "@webstudio-is/icons/svg"; +import { radix } from "./shared/proxy"; +import { + borderRadius, + borderWidth, + boxShadow, + colors, + height, + opacity, + spacing, + width, +} from "./shared/theme"; + +const createRadioGroupItem = ({ + value, + label, +}: { + value: string; + label: string; +}) => ( + + + + <$.HtmlEmbed ws:label="Indicator Icon" code={DotIcon} /> + + + <$.Text>{new PlaceholderValue(label)} + +); + +export const meta: TemplateMeta = { + category: "radix", + order: 100, + description: + "A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time.", + template: ( + + {createRadioGroupItem({ value: "default", label: "Default" })} + {createRadioGroupItem({ value: "comfortable", label: "Comfortable" })} + {createRadioGroupItem({ value: "compact", label: "Compact" })} + + ), +}; diff --git a/packages/sdk-components-react-radix/src/radio-group.ws.ts b/packages/sdk-components-react-radix/src/radio-group.ws.ts index 576018222f5e..cb56c4ccd867 100644 --- a/packages/sdk-components-react-radix/src/radio-group.ws.ts +++ b/packages/sdk-components-react-radix/src/radio-group.ws.ts @@ -1,17 +1,10 @@ -import { - ItemIcon, - RadioGroupIcon, - DotIcon, - TriggerIcon, -} from "@webstudio-is/icons/svg"; +import { ItemIcon, RadioGroupIcon, TriggerIcon } from "@webstudio-is/icons/svg"; import { defaultStates, - WsEmbedTemplate, type WsComponentMeta, type WsComponentPropsMeta, } from "@webstudio-is/react-sdk"; import { button, div, span } from "@webstudio-is/sdk/normalize.css"; -import * as tc from "./theme/tailwind-classes"; import { buttonReset } from "./theme/styles"; import { propsRadioGroup, @@ -19,79 +12,12 @@ import { propsRadioGroupItem, } from "./__generated__/radio-group.props"; -const createRadioGroupItem = ({ - value, - label, -}: { - value: string; - label: string; -}): WsEmbedTemplate[number] => ({ - type: "instance", - component: "Label", - // flex items-center space-x-2 - styles: [tc.flex(), tc.items("center"), tc.gap(2)].flat(), - children: [ - { - type: "instance", - component: "RadioGroupItem", - props: [{ name: "value", type: "string", value }], - // aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background - // focus:outline-none - // focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 - // disabled:cursor-not-allowed disabled:opacity-50 - styles: [ - tc.aspect("square"), - tc.h(4), - tc.w(4), - tc.rounded("full"), - tc.border(), - tc.border("primary"), - tc.text("primary"), - tc.focusVisible( - [tc.outline("none"), tc.ring("ring", 2, "background", 2)].flat() - ), - tc.disabled([tc.cursor("not-allowed"), tc.opacity(50)].flat()), - ].flat(), - children: [ - { - type: "instance", - component: "RadioGroupIndicator", - children: [ - { - type: "instance", - component: "HtmlEmbed", - label: "Indicator Icon", - props: [ - { - type: "string", - name: "code", - value: DotIcon, - }, - ], - children: [], - }, - ], - }, - ], - }, - { - type: "instance", - component: "Text", - children: [{ type: "text", value: label, placeholder: true }], - }, - ], -}); - export const metaRadioGroup: WsComponentMeta = { - category: "radix", - order: 100, type: "container", constraints: { relation: "descendant", component: { $eq: "RadioGroupItem" }, }, - description: - "A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time.", icon: RadioGroupIcon, states: [ ...defaultStates, @@ -109,44 +35,9 @@ export const metaRadioGroup: WsComponentMeta = { presetStyle: { div, }, - template: [ - { - type: "instance", - component: "RadioGroup", - variables: { - radioGroupValue: { initialValue: "" }, - }, - // grid gap-2 - styles: [tc.flex(), tc.flex("col"), tc.gap(2)].flat(), - props: [ - { - type: "expression", - name: "value", - code: "radioGroupValue", - }, - { - name: "onValueChange", - type: "action", - value: [ - { - type: "execute", - args: ["value"], - code: `radioGroupValue = value`, - }, - ], - }, - ], - children: [ - createRadioGroupItem({ value: "default", label: "Default" }), - createRadioGroupItem({ value: "comfortable", label: "Comfortable" }), - createRadioGroupItem({ value: "compact", label: "Compact" }), - ], - }, - ], }; export const metaRadioGroupItem: WsComponentMeta = { - category: "hidden", type: "container", constraints: [ { @@ -166,7 +57,6 @@ export const metaRadioGroupItem: WsComponentMeta = { }; export const metaRadioGroupIndicator: WsComponentMeta = { - category: "hidden", type: "container", icon: TriggerIcon, constraints: { diff --git a/packages/sdk-components-react-radix/src/select.template.tsx b/packages/sdk-components-react-radix/src/select.template.tsx new file mode 100644 index 000000000000..f80a52458ce9 --- /dev/null +++ b/packages/sdk-components-react-radix/src/select.template.tsx @@ -0,0 +1,156 @@ +import { + $, + css, + PlaceholderValue, + type TemplateMeta, +} from "@webstudio-is/template"; +import { radix } from "./shared/proxy"; +import { + borderRadius, + borderWidth, + boxShadow, + colors, + fontSize, + fontSizeLineHeight, + height, + opacity, + spacing, + width, + zIndex, +} from "./shared/theme"; +import { CheckMarkIcon } from "@webstudio-is/icons/svg"; + +const createSelectItem = (value: string, label: string) => { + return ( + + + <$.HtmlEmbed ws:label="Indicator Icon" code={CheckMarkIcon} /> + + {new PlaceholderValue(label)} + + ); +}; + +export const meta: TemplateMeta = { + category: "radix", + description: + "Use within a form to give your users a list of options to choose from.", + order: 10, + template: ( + + + + + + + {createSelectItem("light", "Light")} + {createSelectItem("dark", "Dark")} + {createSelectItem("system", "System")} + + + + ), +}; diff --git a/packages/sdk-components-react-radix/src/select.ws.ts b/packages/sdk-components-react-radix/src/select.ws.ts index 1dda0bdc381a..1d9323f145ed 100644 --- a/packages/sdk-components-react-radix/src/select.ws.ts +++ b/packages/sdk-components-react-radix/src/select.ws.ts @@ -9,14 +9,11 @@ import { CheckMarkIcon, } from "@webstudio-is/icons/svg"; import type { - EmbedTemplateInstance, PresetStyle, WsComponentMeta, WsComponentPropsMeta, - WsEmbedTemplate, } from "@webstudio-is/react-sdk"; import { button, div, span } from "@webstudio-is/sdk/normalize.css"; -import * as tc from "./theme/tailwind-classes"; import { propsSelect, propsSelectContent, @@ -32,79 +29,7 @@ const presetStyle = { div, } satisfies PresetStyle<"div">; -const createSelectItem = ({ - props, - children, -}: { - props?: EmbedTemplateInstance["props"]; - children: WsEmbedTemplate; -}): EmbedTemplateInstance => ({ - type: "instance", - component: "SelectItem", - props, - // relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none - // focus:bg-accent focus:text-accent-foreground - // data-[disabled]:pointer-events-none data-[disabled]:opacity-50 - styles: [ - tc.relative(), - tc.flex(), - tc.w("full"), - tc.cursor("default"), - tc.select("none"), - tc.items("center"), - tc.rounded("md"), - tc.py(1.5), - tc.pl(8), - tc.pr(2), - tc.text("sm"), - tc.outline("none"), - tc.focus([tc.bg("accent"), tc.text("accentForeground")].flat()), - tc.state( - [tc.pointerEvents("none"), tc.opacity(50)].flat(), - "[data-disabled]" - ), - ].flat(), - children: [ - { - type: "instance", - component: "SelectItemIndicator", - // absolute left-2 flex h-3.5 w-3.5 items-center justify-center - styles: [ - tc.absolute(), - tc.left(2), - tc.flex(), - tc.h(3.5), - tc.w(3.5), - tc.items("center"), - tc.justify("center"), - ].flat(), - children: [ - { - type: "instance", - component: "HtmlEmbed", - label: "Indicator Icon", - props: [ - { - type: "string", - name: "code", - value: CheckMarkIcon, - }, - ], - children: [], - }, - ], - }, - { - type: "instance", - component: "SelectItemText", - children, - }, - ], -}); - export const metaSelect: WsComponentMeta = { - category: "radix", - order: 10, type: "container", constraints: [ { @@ -118,137 +43,9 @@ export const metaSelect: WsComponentMeta = { ], icon: SelectIcon, stylable: false, - description: - "Use within a form to give your users a list of options to choose from.", - template: [ - { - type: "instance", - component: "Select", - variables: { - selectValue: { initialValue: "" }, - }, - props: [ - { - name: "value", - type: "expression", - code: "selectValue", - }, - { - name: "onValueChange", - type: "action", - value: [ - { type: "execute", args: ["value"], code: `selectValue = value` }, - ], - }, - ], - children: [ - { - type: "instance", - component: "SelectTrigger", - // flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background - // placeholder:text-muted-foreground - // focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 - // disabled:cursor-not-allowed disabled:opacity-50 - styles: [ - tc.flex(), - tc.h(10), - tc.w("full"), - tc.items("center"), - tc.justify("between"), - tc.rounded("md"), - tc.border(), - tc.border("input"), - tc.bg("background"), - tc.px(3), - tc.py(2), - tc.text("sm"), - tc.state([tc.text("mutedForeground")].flat(), "::placeholder"), - tc.focus( - [tc.outline("none"), tc.ring("ring", 2, "background", 2)].flat() - ), - tc.disabled([tc.cursor("not-allowed"), tc.opacity(50)].flat()), - ].flat(), - children: [ - { - type: "instance", - component: "SelectValue", - props: [{ name: "placeholder", type: "string", value: "Theme" }], - children: [], - }, - ], - }, - { - type: "instance", - component: "SelectContent", - // relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md - // data-[state=open]:animate-in - // data-[state=closed]:animate-out data-[state=closed]:fade-out-0 - // data-[state=open]:fade-in-0 - // data-[state=closed]:zoom-out-95 - // data-[state=open]:zoom-in-95 - // data-[side=bottom]:slide-in-from-top-2 - // data-[side=left]:slide-in-from-right-2 - // data-[side=right]:slide-in-from-left-2 - // data-[side=top]:slide-in-from-bottom-2 - // position=popper - // data-[side=bottom]:translate-y-1 - // data-[side=left]:-translate-x-1 - // data-[side=right]:translate-x-1 - // data-[side=top]:-translate-y-1 - styles: [ - tc.relative(), - tc.z(50), - tc.property("minWidth", "8rem"), - tc.overflow("hidden"), - tc.rounded("md"), - tc.border(), - tc.bg("popover"), - tc.text("popoverForeground"), - tc.shadow("md"), - ].flat(), - children: [ - { - type: "instance", - component: "SelectViewport", - // p-1 - // position=popper - // h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] - styles: [ - tc.p(1), - tc.property("height", "--radix-select-trigger-height"), - tc.w("full"), - tc.property("minWidth", "--radix-select-trigger-width"), - ].flat(), - children: [ - createSelectItem({ - props: [{ name: "value", type: "string", value: "light" }], - children: [ - { type: "text", value: "Light", placeholder: true }, - ], - }), - createSelectItem({ - props: [{ name: "value", type: "string", value: "dark" }], - children: [ - { type: "text", value: "Dark", placeholder: true }, - ], - }), - createSelectItem({ - props: [{ name: "value", type: "string", value: "system" }], - children: [ - { type: "text", value: "System", placeholder: true }, - ], - }), - ], - }, - ], - }, - ], - }, - ], }; export const metaSelectTrigger: WsComponentMeta = { - category: "hidden", type: "container", icon: TriggerIcon, presetStyle: { @@ -267,7 +64,6 @@ export const metaSelectTrigger: WsComponentMeta = { }; export const metaSelectValue: WsComponentMeta = { - category: "hidden", type: "container", label: "Value", icon: FormTextFieldIcon, @@ -281,7 +77,6 @@ export const metaSelectValue: WsComponentMeta = { }; export const metaSelectContent: WsComponentMeta = { - category: "hidden", type: "container", icon: ContentIcon, presetStyle, @@ -298,7 +93,6 @@ export const metaSelectContent: WsComponentMeta = { }; export const metaSelectViewport: WsComponentMeta = { - category: "hidden", type: "container", icon: ViewportIcon, presetStyle, @@ -315,7 +109,6 @@ export const metaSelectViewport: WsComponentMeta = { }; export const metaSelectItem: WsComponentMeta = { - category: "hidden", type: "container", icon: ItemIcon, constraints: [ @@ -336,7 +129,6 @@ export const metaSelectItem: WsComponentMeta = { }; export const metaSelectItemIndicator: WsComponentMeta = { - category: "hidden", type: "container", label: "Indicator", icon: CheckMarkIcon, @@ -350,7 +142,6 @@ export const metaSelectItemIndicator: WsComponentMeta = { }; export const metaSelectItemText: WsComponentMeta = { - category: "hidden", type: "container", label: "Item Text", icon: TextIcon, diff --git a/packages/sdk-components-react-radix/src/templates.ts b/packages/sdk-components-react-radix/src/templates.ts index 1a04131e3801..2500e1380f0a 100644 --- a/packages/sdk-components-react-radix/src/templates.ts +++ b/packages/sdk-components-react-radix/src/templates.ts @@ -8,3 +8,5 @@ export { meta as Collapsible } from "./collapsible.template"; export { meta as Accordion } from "./accordion.template"; export { meta as Tooltip } from "./tooltip.template"; export { meta as Popover } from "./popover.template"; +export { meta as RadioGroup } from "./radio-group.template"; +export { meta as Select } from "./select.template";