From c1f10dbfa1490cd49873b09b29101f0f830bf501 Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Wed, 16 Aug 2023 21:06:19 +0400 Subject: [PATCH] Add chevron icon to accordion (#2126) Here added chevron to accordion trigger by using css custom properties for cascade. We still do not support css custom properties in style panel though here used only for transform which does not have ui too. --- packages/icons/icons/chevron-down.svg | 5 + packages/icons/icons/chevron-left.svg | 5 + packages/icons/icons/chevron-right.svg | 5 + packages/icons/icons/chevron-up.svg | 5 + packages/icons/package.json | 2 +- .../icons/src/__generated__/chevron-down.tsx | 15 +++ .../icons/src/__generated__/chevron-left.tsx | 15 +++ .../icons/src/__generated__/chevron-right.tsx | 15 +++ .../icons/src/__generated__/chevron-up.tsx | 15 +++ packages/icons/src/__generated__/index.ts | 4 + .../src/__generated__/svg/chevron-down.ts | 1 + .../src/__generated__/svg/chevron-left.ts | 1 + .../src/__generated__/svg/chevron-right.ts | 1 + .../icons/src/__generated__/svg/chevron-up.ts | 1 + packages/icons/src/__generated__/svg/index.ts | 4 + packages/icons/src/chevron-down.tsx | 25 ---- packages/icons/src/chevron-left.tsx | 27 ---- packages/icons/src/chevron-right.tsx | 27 ---- packages/icons/src/chevron-up.tsx | 27 ---- packages/icons/src/index.ts | 4 - .../src/accordion.ws.ts | 126 ++++++++++-------- .../src/theme/tailwind-classes.ts | 47 ++++++- 22 files changed, 206 insertions(+), 171 deletions(-) create mode 100644 packages/icons/icons/chevron-down.svg create mode 100644 packages/icons/icons/chevron-left.svg create mode 100644 packages/icons/icons/chevron-right.svg create mode 100644 packages/icons/icons/chevron-up.svg create mode 100644 packages/icons/src/__generated__/chevron-down.tsx create mode 100644 packages/icons/src/__generated__/chevron-left.tsx create mode 100644 packages/icons/src/__generated__/chevron-right.tsx create mode 100644 packages/icons/src/__generated__/chevron-up.tsx create mode 100644 packages/icons/src/__generated__/svg/chevron-down.ts create mode 100644 packages/icons/src/__generated__/svg/chevron-left.ts create mode 100644 packages/icons/src/__generated__/svg/chevron-right.ts create mode 100644 packages/icons/src/__generated__/svg/chevron-up.ts delete mode 100644 packages/icons/src/chevron-down.tsx delete mode 100644 packages/icons/src/chevron-left.tsx delete mode 100644 packages/icons/src/chevron-right.tsx delete mode 100644 packages/icons/src/chevron-up.tsx diff --git a/packages/icons/icons/chevron-down.svg b/packages/icons/icons/chevron-down.svg new file mode 100644 index 0000000000..0863c3a77c --- /dev/null +++ b/packages/icons/icons/chevron-down.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/icons/icons/chevron-left.svg b/packages/icons/icons/chevron-left.svg new file mode 100644 index 0000000000..ed786c595a --- /dev/null +++ b/packages/icons/icons/chevron-left.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/icons/icons/chevron-right.svg b/packages/icons/icons/chevron-right.svg new file mode 100644 index 0000000000..3ec167769b --- /dev/null +++ b/packages/icons/icons/chevron-right.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/icons/icons/chevron-up.svg b/packages/icons/icons/chevron-up.svg new file mode 100644 index 0000000000..afa1d3b57e --- /dev/null +++ b/packages/icons/icons/chevron-up.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/icons/package.json b/packages/icons/package.json index 7b14826f15..052dec24c1 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -9,7 +9,7 @@ "dev": "build-package --watch", "build": "build-package", "dts": "tsc --declarationDir lib/types", - "generate": "rm -fr src/__generated__ && NODE_OPTIONS='--loader=tsx' svgo-jsx svgo-jsx.config.ts && tsx svg-string.ts && prettier --write ./", + "generate": "rm -fr src/__generated__ && NODE_OPTIONS='--loader=tsx' svgo-jsx svgo-jsx.config.ts && tsx svg-string.ts && prettier --write src/__generated__", "typecheck": "tsc", "checks": "pnpm typecheck", "storybook:dev": "storybook dev -p 6006", diff --git a/packages/icons/src/__generated__/chevron-down.tsx b/packages/icons/src/__generated__/chevron-down.tsx new file mode 100644 index 0000000000..3cf7490604 --- /dev/null +++ b/packages/icons/src/__generated__/chevron-down.tsx @@ -0,0 +1,15 @@ +// Generated from icons/chevron-down.svg + +import { forwardRef } from "react"; +import type { IconProps } from "../types"; + +// prettier-ignore +export const ChevronDownIcon = forwardRef( + ({ color = "currentColor", size = 16, ...props }, forwardedRef) => { + return ( + + ); + } +); + +ChevronDownIcon.displayName = "ChevronDownIcon"; diff --git a/packages/icons/src/__generated__/chevron-left.tsx b/packages/icons/src/__generated__/chevron-left.tsx new file mode 100644 index 0000000000..8763512267 --- /dev/null +++ b/packages/icons/src/__generated__/chevron-left.tsx @@ -0,0 +1,15 @@ +// Generated from icons/chevron-left.svg + +import { forwardRef } from "react"; +import type { IconProps } from "../types"; + +// prettier-ignore +export const ChevronLeftIcon = forwardRef( + ({ color = "currentColor", size = 16, ...props }, forwardedRef) => { + return ( + + ); + } +); + +ChevronLeftIcon.displayName = "ChevronLeftIcon"; diff --git a/packages/icons/src/__generated__/chevron-right.tsx b/packages/icons/src/__generated__/chevron-right.tsx new file mode 100644 index 0000000000..9bd040fc28 --- /dev/null +++ b/packages/icons/src/__generated__/chevron-right.tsx @@ -0,0 +1,15 @@ +// Generated from icons/chevron-right.svg + +import { forwardRef } from "react"; +import type { IconProps } from "../types"; + +// prettier-ignore +export const ChevronRightIcon = forwardRef( + ({ color = "currentColor", size = 16, ...props }, forwardedRef) => { + return ( + + ); + } +); + +ChevronRightIcon.displayName = "ChevronRightIcon"; diff --git a/packages/icons/src/__generated__/chevron-up.tsx b/packages/icons/src/__generated__/chevron-up.tsx new file mode 100644 index 0000000000..636bcce542 --- /dev/null +++ b/packages/icons/src/__generated__/chevron-up.tsx @@ -0,0 +1,15 @@ +// Generated from icons/chevron-up.svg + +import { forwardRef } from "react"; +import type { IconProps } from "../types"; + +// prettier-ignore +export const ChevronUpIcon = forwardRef( + ({ color = "currentColor", size = 16, ...props }, forwardedRef) => { + return ( + + ); + } +); + +ChevronUpIcon.displayName = "ChevronUpIcon"; diff --git a/packages/icons/src/__generated__/index.ts b/packages/icons/src/__generated__/index.ts index cb00c45321..13c6448f41 100644 --- a/packages/icons/src/__generated__/index.ts +++ b/packages/icons/src/__generated__/index.ts @@ -50,10 +50,14 @@ export * from "./chevron-big-down"; export * from "./chevron-big-left"; export * from "./chevron-big-right"; export * from "./chevron-big-up"; +export * from "./chevron-down"; export * from "./chevron-filled-down"; export * from "./chevron-filled-left"; export * from "./chevron-filled-right"; export * from "./chevron-filled-up"; +export * from "./chevron-left"; +export * from "./chevron-right"; +export * from "./chevron-up"; export * from "./code-text"; export * from "./collapsible"; export * from "./commit"; diff --git a/packages/icons/src/__generated__/svg/chevron-down.ts b/packages/icons/src/__generated__/svg/chevron-down.ts new file mode 100644 index 0000000000..5d67649729 --- /dev/null +++ b/packages/icons/src/__generated__/svg/chevron-down.ts @@ -0,0 +1 @@ +export const ChevronDownIcon = ``; diff --git a/packages/icons/src/__generated__/svg/chevron-left.ts b/packages/icons/src/__generated__/svg/chevron-left.ts new file mode 100644 index 0000000000..c20d4fd3f9 --- /dev/null +++ b/packages/icons/src/__generated__/svg/chevron-left.ts @@ -0,0 +1 @@ +export const ChevronLeftIcon = ``; diff --git a/packages/icons/src/__generated__/svg/chevron-right.ts b/packages/icons/src/__generated__/svg/chevron-right.ts new file mode 100644 index 0000000000..17848f0ec3 --- /dev/null +++ b/packages/icons/src/__generated__/svg/chevron-right.ts @@ -0,0 +1 @@ +export const ChevronRightIcon = ``; diff --git a/packages/icons/src/__generated__/svg/chevron-up.ts b/packages/icons/src/__generated__/svg/chevron-up.ts new file mode 100644 index 0000000000..984f96b5ba --- /dev/null +++ b/packages/icons/src/__generated__/svg/chevron-up.ts @@ -0,0 +1 @@ +export const ChevronUpIcon = ``; diff --git a/packages/icons/src/__generated__/svg/index.ts b/packages/icons/src/__generated__/svg/index.ts index 7eaf3d16c2..9f0c5324a6 100644 --- a/packages/icons/src/__generated__/svg/index.ts +++ b/packages/icons/src/__generated__/svg/index.ts @@ -50,10 +50,14 @@ export { ChevronBigDownIcon } from "./chevron-big-down"; export { ChevronBigLeftIcon } from "./chevron-big-left"; export { ChevronBigRightIcon } from "./chevron-big-right"; export { ChevronBigUpIcon } from "./chevron-big-up"; +export { ChevronDownIcon } from "./chevron-down"; export { ChevronFilledDownIcon } from "./chevron-filled-down"; export { ChevronFilledLeftIcon } from "./chevron-filled-left"; export { ChevronFilledRightIcon } from "./chevron-filled-right"; export { ChevronFilledUpIcon } from "./chevron-filled-up"; +export { ChevronLeftIcon } from "./chevron-left"; +export { ChevronRightIcon } from "./chevron-right"; +export { ChevronUpIcon } from "./chevron-up"; export { CodeTextIcon } from "./code-text"; export { CollapsibleIcon } from "./collapsible"; export { CommitIcon } from "./commit"; diff --git a/packages/icons/src/chevron-down.tsx b/packages/icons/src/chevron-down.tsx deleted file mode 100644 index f69bfcc3df..0000000000 --- a/packages/icons/src/chevron-down.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import * as React from "react"; -import type { IconProps } from "./types"; - -export const ChevronDownIcon = React.forwardRef( - ({ color = "currentColor", ...props }, forwardedRef) => { - return ( - - - - ); - } -); - -ChevronDownIcon.displayName = "ChevronDownIcon"; diff --git a/packages/icons/src/chevron-left.tsx b/packages/icons/src/chevron-left.tsx deleted file mode 100644 index 5c82c0ed9f..0000000000 --- a/packages/icons/src/chevron-left.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import * as React from "react"; -import type { IconProps } from "./types"; - -export const ChevronLeftIcon = React.forwardRef( - ({ color = "currentColor", ...props }, forwardedRef) => { - return ( - - - - ); - } -); - -ChevronLeftIcon.displayName = "ChevronLeftIcon"; diff --git a/packages/icons/src/chevron-right.tsx b/packages/icons/src/chevron-right.tsx deleted file mode 100644 index 5e8cb37d76..0000000000 --- a/packages/icons/src/chevron-right.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import * as React from "react"; -import type { IconProps } from "./types"; - -export const ChevronRightIcon = React.forwardRef( - ({ color = "currentColor", ...props }, forwardedRef) => { - return ( - - - - ); - } -); - -ChevronRightIcon.displayName = "ChevronRightIcon"; diff --git a/packages/icons/src/chevron-up.tsx b/packages/icons/src/chevron-up.tsx deleted file mode 100644 index 800090a5bc..0000000000 --- a/packages/icons/src/chevron-up.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import * as React from "react"; -import type { IconProps } from "./types"; - -export const ChevronUpIcon = React.forwardRef( - ({ color = "currentColor", ...props }, forwardedRef) => { - return ( - - - - ); - } -); - -ChevronUpIcon.displayName = "ChevronUpIcon"; diff --git a/packages/icons/src/index.ts b/packages/icons/src/index.ts index a683c3d0c4..2ec1632236 100644 --- a/packages/icons/src/index.ts +++ b/packages/icons/src/index.ts @@ -21,10 +21,6 @@ export * from "./chevron-double-up"; export * from "./chevron-double-down"; export * from "./chevron-double-left"; export * from "./chevron-double-right"; -export * from "./chevron-up"; -export * from "./chevron-down"; -export * from "./chevron-left"; -export * from "./chevron-right"; export * from "./cross-circled-filled"; export * from "./cross"; export * from "./magnifying-glass"; diff --git a/packages/sdk-components-react-radix/src/accordion.ws.ts b/packages/sdk-components-react-radix/src/accordion.ws.ts index f5657b96ef..cd64ea7303 100644 --- a/packages/sdk-components-react-radix/src/accordion.ws.ts +++ b/packages/sdk-components-react-radix/src/accordion.ws.ts @@ -4,12 +4,14 @@ import { HeaderIcon, TriggerIcon, ContentIcon, + ChevronDownIcon, } from "@webstudio-is/icons/svg"; import type { EmbedTemplateStyleDecl, PresetStyle, WsComponentMeta, WsComponentPropsMeta, + WsEmbedTemplate, } from "@webstudio-is/react-sdk"; import { div, h3, button } from "@webstudio-is/react-sdk/css-normalize"; import * as tc from "./theme/tailwind-classes"; @@ -37,20 +39,68 @@ const presetStyle = { // border-b const accordionItemStyles: EmbedTemplateStyleDecl[] = [tc.borderB()].flat(); -// flex -const accordionHeaderStyles: EmbedTemplateStyleDecl[] = [tc.flex()].flat(); - -// flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180 -const accordionTriggerStyles: EmbedTemplateStyleDecl[] = [ - tc.flex(), - tc.flex(1), - tc.items("center"), - tc.justify("between"), - tc.py(4), - tc.font("medium"), - tc.transition("all"), - tc.hover([tc.underline()].flat()), -].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: [ + ...children, + { + type: "instance", + component: "Box", + // 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 @@ -95,19 +145,9 @@ export const metaAccordion: WsComponentMeta = { component: "AccordionItem", styles: accordionItemStyles, children: [ - { - type: "instance", - component: "AccordionHeader", - styles: accordionHeaderStyles, - children: [ - { - type: "instance", - component: "AccordionTrigger", - styles: accordionTriggerStyles, - children: [{ type: "text", value: "Is it accessible?" }], - }, - ], - }, + createAccordionTrigger({ + children: [{ type: "text", value: "Is it accessible?" }], + }), { type: "instance", component: "AccordionContent", @@ -127,19 +167,9 @@ export const metaAccordion: WsComponentMeta = { component: "AccordionItem", styles: accordionItemStyles, children: [ - { - type: "instance", - component: "AccordionHeader", - styles: accordionHeaderStyles, - children: [ - { - type: "instance", - component: "AccordionTrigger", - styles: accordionTriggerStyles, - children: [{ type: "text", value: "Is it styled?" }], - }, - ], - }, + createAccordionTrigger({ + children: [{ type: "text", value: "Is it styled?" }], + }), { type: "instance", component: "AccordionContent", @@ -160,19 +190,9 @@ export const metaAccordion: WsComponentMeta = { component: "AccordionItem", styles: accordionItemStyles, children: [ - { - type: "instance", - component: "AccordionHeader", - styles: accordionHeaderStyles, - children: [ - { - type: "instance", - component: "AccordionTrigger", - styles: accordionTriggerStyles, - children: [{ type: "text", value: "Is it animated?" }], - }, - ], - }, + createAccordionTrigger({ + children: [{ type: "text", value: "Is it animated?" }], + }), { type: "instance", component: "AccordionContent", diff --git a/packages/sdk-components-react-radix/src/theme/tailwind-classes.ts b/packages/sdk-components-react-radix/src/theme/tailwind-classes.ts index 081f9c99bc..be717a1bf5 100644 --- a/packages/sdk-components-react-radix/src/theme/tailwind-classes.ts +++ b/packages/sdk-components-react-radix/src/theme/tailwind-classes.ts @@ -7,9 +7,26 @@ import { parseCssValue, parseBoxShadow, StyleValue, + type StyleProperty, } from "@webstudio-is/css-data"; import type { EvaluatedDefaultTheme } from "./radix-common-types"; +export const property = ( + property: StyleProperty, + value: string +): EmbedTemplateStyleDecl => { + if (value.startsWith("--")) { + return { + property, + value: { type: "var", value: value.slice(2), fallbacks: [] }, + }; + } + return { + property, + value: { type: "unparsed", value }, + }; +}; + // https://github.com/tailwindlabs/tailwindcss/blob/master/src/css/preflight.css const preflight = (): EmbedTemplateStyleDecl[] => { const borderColorValue = parseCssValue("color", theme("colors")["border"]); @@ -585,11 +602,16 @@ export const grow = (): EmbedTemplateStyleDecl[] => { return [ { property: "flexGrow", - value: { - type: "unit", - value: 1, - unit: "number", - }, + value: { type: "unit", value: 1, unit: "number" }, + }, + ]; +}; + +export const shrink = (value: number): EmbedTemplateStyleDecl[] => { + return [ + { + property: "flexGrow", + value: { type: "unit", value, unit: "number" }, }, ]; }; @@ -818,7 +840,9 @@ export const pointerEvents = ( return [{ property: "pointerEvents", value: { type: "keyword", value } }]; }; -export const transition = (value: "none" | "all"): EmbedTemplateStyleDecl[] => { +export const transition = ( + value: "none" | "all" | "transform" +): EmbedTemplateStyleDecl[] => { if (value === "none") { return [ { @@ -830,7 +854,7 @@ export const transition = (value: "none" | "all"): EmbedTemplateStyleDecl[] => { return [ { property: "transitionProperty", - value: { type: "keyword", value: "all" }, + value: { type: "keyword", value }, }, { property: "transitionTimingFunction", @@ -843,6 +867,15 @@ export const transition = (value: "none" | "all"): EmbedTemplateStyleDecl[] => { ]; }; +export const duration = (ms: number): EmbedTemplateStyleDecl[] => { + return [ + { + property: "transitionDuration", + value: { type: "unit", value: ms, unit: "ms" }, + }, + ]; +}; + export const hover = ( value: EmbedTemplateStyleDecl[] ): EmbedTemplateStyleDecl[] => {