diff --git a/apps/builder/app/builder/features/style-panel/style-source-section.tsx b/apps/builder/app/builder/features/style-panel/style-source-section.tsx index 28b4ef735a95..2fb316ab389f 100644 --- a/apps/builder/app/builder/features/style-panel/style-source-section.tsx +++ b/apps/builder/app/builder/features/style-panel/style-source-section.tsx @@ -2,6 +2,7 @@ import { useState } from "react"; import { useStore } from "@nanostores/react"; import { nanoid } from "nanoid"; import { computed, type WritableAtom } from "nanostores"; +import { pseudoClassesByTag } from "@webstudio-is/html-data"; import { type Instance, type StyleSource, @@ -41,6 +42,8 @@ import { removeByMutable } from "~/shared/array-utils"; import { cloneStyles } from "~/shared/tree-utils"; import { serverSyncStore } from "~/shared/sync"; import { $selectedInstance } from "~/shared/awareness"; +import { $instanceTags } from "./shared/model"; +import { humanizeString } from "~/shared/string-utils"; const selectStyleSource = ( styleSourceId: StyleSource["id"], @@ -325,12 +328,26 @@ const clearStyles = (styleSourceId: StyleSource["id"]) => { }; const $componentStates = computed( - [$selectedInstance, $registeredComponentMetas], - (selectedInstance, registeredComponentMetas) => { + [$selectedInstance, $registeredComponentMetas, $instanceTags], + (selectedInstance, registeredComponentMetas, instanceTags) => { if (selectedInstance === undefined) { return; } - return registeredComponentMetas.get(selectedInstance.component)?.states; + const tag = instanceTags.get(selectedInstance.id); + const tagStates = [ + ...pseudoClassesByTag["*"], + ...(pseudoClassesByTag[tag ?? ""] ?? []), + ].map((state) => ({ + category: "states" as const, + label: humanizeString(state), + selector: state, + })); + const meta = registeredComponentMetas.get(selectedInstance.component); + const componentStates = (meta?.states ?? []).map((item) => ({ + category: "component-states" as const, + ...item, + })); + return [...tagStates, ...componentStates]; } ); diff --git a/apps/builder/app/builder/features/style-panel/style-source/style-source-control.tsx b/apps/builder/app/builder/features/style-panel/style-source/style-source-control.tsx index 9b7a39fbb32c..0ffe08314d14 100644 --- a/apps/builder/app/builder/features/style-panel/style-source/style-source-control.tsx +++ b/apps/builder/app/builder/features/style-panel/style-source/style-source-control.tsx @@ -98,7 +98,7 @@ const Menu = (props: MenuProps) => { event.preventDefault()} - css={{ maxWidth: theme.spacing[24] }} + css={{ maxWidth: theme.spacing[26] }} > {props.children} diff --git a/apps/builder/app/builder/features/style-panel/style-source/style-source-input.tsx b/apps/builder/app/builder/features/style-panel/style-source/style-source-input.tsx index 20134d9ff242..7aaca676d4cb 100644 --- a/apps/builder/app/builder/features/style-panel/style-source/style-source-input.tsx +++ b/apps/builder/app/builder/features/style-panel/style-source/style-source-input.tsx @@ -50,7 +50,6 @@ import { useCallback, } from "react"; import { mergeRefs } from "@react-aria/utils"; -import { type ComponentState, stateCategories } from "@webstudio-is/sdk"; import { type ItemSource, type StyleSourceError, @@ -268,6 +267,17 @@ const TextFieldBase: ForwardRefRenderFunction< const TextField = forwardRef(TextFieldBase); TextField.displayName = "TextField"; +type ComponentState = { + category: "states" | "component-states"; + selector: string; + label: string; +}; + +const categories = [ + "states", + "component-states", +] satisfies ComponentState["category"][]; + type StyleSourceInputProps = { $styleSourceInputElement: WritableAtom; error?: StyleSourceError; @@ -417,9 +427,9 @@ const renderMenuItems = (props: { )} - {stateCategories.map((currentCategory) => { + {categories.map((currentCategory) => { const categoryStates = props.states.filter( - ({ category }) => (category ?? "states") === currentCategory + ({ category }) => category === currentCategory ); // prevent rendering empty category if (categoryStates.length === 0) { diff --git a/packages/html-data/src/index.ts b/packages/html-data/src/index.ts index 04e2535ca47c..abd0c7bb3832 100644 --- a/packages/html-data/src/index.ts +++ b/packages/html-data/src/index.ts @@ -1,3 +1,4 @@ export * from "./__generated__/elements"; export * from "./__generated__/attributes"; export * from "./__generated__/aria"; +export * from "./pseudo-classes"; diff --git a/packages/html-data/src/pseudo-classes.ts b/packages/html-data/src/pseudo-classes.ts new file mode 100644 index 000000000000..d1f1d3d48629 --- /dev/null +++ b/packages/html-data/src/pseudo-classes.ts @@ -0,0 +1,70 @@ +// https://drafts.csswg.org/selectors + +const location = [ + // ':link', + ":visited", + // ':any-link', + // ':local-link', + // ':target', + // ':target-within', +]; + +const userAction = [":hover", ":focus-visible", ":focus-within", ":active"]; + +const ability = [ + // ":enabled", + ":disabled", +]; + +const validity = [ + // ":valid", + ":invalid", + // ":user-valid", + ":user-invalid", +]; + +const required = [ + ":required", + // ":optional" +]; + +export const pseudoClassesByTag: Record = { + "*": userAction, + a: [...location], + area: [...location], + button: [...ability], + label: [], + input: [ + ":placeholder-shown", + // @todo temporary until proper pseudo elements support is added + "::placeholder", + ...ability, + ...validity, + ...required, + ":checked", + // ":indeterminate", + // :in-range + // :out-of-range + // ":open", + ], + textarea: [ + ":placeholder-shown", + // @todo temporary until proper pseudo elements support is added + "::placeholder", + ...ability, + ...validity, + ...required, + ], + select: [ + ...ability, + ...validity, + ...required, + // ":open" + ], + optgroup: [...ability], + option: [...ability, ":checked"], + fieldset: [...ability, ...validity], + progress: [":indeterminate"], + details: [":open"], + dialog: [":open"], +}; diff --git a/packages/sdk-components-react-radix/src/accordion.ws.ts b/packages/sdk-components-react-radix/src/accordion.ws.ts index 9699bb47cb94..2795935ac1f9 100644 --- a/packages/sdk-components-react-radix/src/accordion.ws.ts +++ b/packages/sdk-components-react-radix/src/accordion.ws.ts @@ -5,7 +5,7 @@ import { TriggerIcon, ContentIcon, } from "@webstudio-is/icons/svg"; -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { div, h3, button } from "@webstudio-is/sdk/normalize.css"; import { radix } from "./shared/meta"; import { buttonReset } from "./shared/preset-styles"; @@ -74,14 +74,7 @@ export const metaAccordionTrigger: WsComponentMeta = { category: "none", children: ["instance", "rich-text"], }, - states: [ - ...defaultStates, - { - category: "component-states", - label: "Open", - selector: "[data-state=open]", - }, - ], + states: [{ label: "Open", selector: "[data-state=open]" }], presetStyle: { button: [button, buttonReset].flat(), }, diff --git a/packages/sdk-components-react-radix/src/checkbox.ws.ts b/packages/sdk-components-react-radix/src/checkbox.ws.ts index 73d1a34c62e9..2b6da74027f5 100644 --- a/packages/sdk-components-react-radix/src/checkbox.ws.ts +++ b/packages/sdk-components-react-radix/src/checkbox.ws.ts @@ -1,5 +1,5 @@ import { CheckboxCheckedIcon, TriggerIcon } from "@webstudio-is/icons/svg"; -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { button, span } from "@webstudio-is/sdk/normalize.css"; import { radix } from "./shared/meta"; import { buttonReset } from "./shared/preset-styles"; @@ -16,17 +16,8 @@ export const metaCheckbox: WsComponentMeta = { descendants: [radix.CheckboxIndicator], }, states: [ - ...defaultStates, - { - label: "Checked", - selector: "[data-state=checked]", - category: "component-states", - }, - { - label: "Unchecked", - selector: "[data-state=unchecked]", - category: "component-states", - }, + { label: "Checked", selector: "[data-state=checked]" }, + { label: "Unchecked", selector: "[data-state=unchecked]" }, ], presetStyle: { button: [button, buttonReset].flat(), @@ -41,7 +32,6 @@ export const metaCheckboxIndicator: WsComponentMeta = { category: "none", children: ["instance", "rich-text"], }, - states: defaultStates, presetStyle: { span, }, diff --git a/packages/sdk-components-react-radix/src/dialog.ws.ts b/packages/sdk-components-react-radix/src/dialog.ws.ts index 45579ea22d3d..ed71518c1f35 100644 --- a/packages/sdk-components-react-radix/src/dialog.ws.ts +++ b/packages/sdk-components-react-radix/src/dialog.ws.ts @@ -7,7 +7,7 @@ import { TextIcon, ButtonElementIcon, } from "@webstudio-is/icons/svg"; -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { div, button, h2, p } from "@webstudio-is/sdk/normalize.css"; import { radix } from "./shared/meta"; import { @@ -84,7 +84,6 @@ export const metaDialogClose: WsComponentMeta = { category: "none", children: ["instance", "rich-text"], }, - states: defaultStates, presetStyle: { button: [buttonReset, button].flat(), }, diff --git a/packages/sdk-components-react-radix/src/label.ws.ts b/packages/sdk-components-react-radix/src/label.ws.ts index f16a81f81ca6..e2b60af24616 100644 --- a/packages/sdk-components-react-radix/src/label.ws.ts +++ b/packages/sdk-components-react-radix/src/label.ws.ts @@ -1,14 +1,11 @@ import { LabelIcon } from "@webstudio-is/icons/svg"; -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { label } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/label.props"; export const meta: WsComponentMeta = { icon: LabelIcon, - states: defaultStates, - presetStyle: { - label, - }, + presetStyle: { label }, initialProps: ["id", "class", "for"], props, }; diff --git a/packages/sdk-components-react-radix/src/popover.ws.ts b/packages/sdk-components-react-radix/src/popover.ws.ts index a76dfd12c87e..69c490ae7bab 100644 --- a/packages/sdk-components-react-radix/src/popover.ws.ts +++ b/packages/sdk-components-react-radix/src/popover.ws.ts @@ -4,7 +4,7 @@ import { ContentIcon, ButtonElementIcon, } from "@webstudio-is/icons/svg"; -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { button, div } from "@webstudio-is/sdk/normalize.css"; import { radix } from "./shared/meta"; import { @@ -57,7 +57,6 @@ export const metaPopoverClose: WsComponentMeta = { category: "none", children: ["instance", "rich-text"], }, - states: defaultStates, presetStyle: { button: [buttonReset, button].flat(), }, 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 7182bedc0c9e..ca81dd45802e 100644 --- a/packages/sdk-components-react-radix/src/radio-group.ws.ts +++ b/packages/sdk-components-react-radix/src/radio-group.ws.ts @@ -1,5 +1,5 @@ import { ItemIcon, RadioGroupIcon, TriggerIcon } from "@webstudio-is/icons/svg"; -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { button, div, span } from "@webstudio-is/sdk/normalize.css"; import { radix } from "./shared/meta"; import { buttonReset } from "./shared/preset-styles"; @@ -17,17 +17,8 @@ export const metaRadioGroup: WsComponentMeta = { descendants: [radix.RadioGroupItem], }, states: [ - ...defaultStates, - { - label: "Checked", - selector: "[data-state=checked]", - category: "component-states", - }, - { - label: "Unchecked", - selector: "[data-state=unchecked]", - category: "component-states", - }, + { label: "Checked", selector: "[data-state=checked]" }, + { label: "Unchecked", selector: "[data-state=unchecked]" }, ], presetStyle: { div, @@ -43,7 +34,6 @@ export const metaRadioGroupItem: WsComponentMeta = { children: ["instance"], descendants: [radix.RadioGroupIndicator], }, - states: defaultStates, presetStyle: { button: [button, buttonReset].flat(), }, @@ -57,7 +47,6 @@ export const metaRadioGroupIndicator: WsComponentMeta = { category: "none", children: ["instance"], }, - states: defaultStates, presetStyle: { span, }, diff --git a/packages/sdk-components-react-radix/src/switch.ws.ts b/packages/sdk-components-react-radix/src/switch.ws.ts index 615736ed8afc..da4cc43e5dee 100644 --- a/packages/sdk-components-react-radix/src/switch.ws.ts +++ b/packages/sdk-components-react-radix/src/switch.ws.ts @@ -1,5 +1,5 @@ import { SwitchIcon, TriggerIcon } from "@webstudio-is/icons/svg"; -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { button, span } from "@webstudio-is/sdk/normalize.css"; import { radix } from "./shared/meta"; import { buttonReset } from "./shared/preset-styles"; @@ -13,17 +13,8 @@ export const metaSwitch: WsComponentMeta = { descendants: [radix.SwitchThumb], }, states: [ - ...defaultStates, - { - label: "Checked", - selector: "[data-state=checked]", - category: "component-states", - }, - { - label: "Unchecked", - selector: "[data-state=unchecked]", - category: "component-states", - }, + { label: "Checked", selector: "[data-state=checked]" }, + { label: "Unchecked", selector: "[data-state=unchecked]" }, ], presetStyle: { button: [button, buttonReset].flat(), @@ -39,17 +30,8 @@ export const metaSwitchThumb: WsComponentMeta = { children: ["instance"], }, states: [ - ...defaultStates, - { - label: "Checked", - selector: "[data-state=checked]", - category: "component-states", - }, - { - label: "Unchecked", - selector: "[data-state=unchecked]", - category: "component-states", - }, + { label: "Checked", selector: "[data-state=checked]" }, + { label: "Unchecked", selector: "[data-state=unchecked]" }, ], presetStyle: { span, diff --git a/packages/sdk-components-react-radix/src/tabs.ws.ts b/packages/sdk-components-react-radix/src/tabs.ws.ts index 0c211d441fd2..a35962114145 100644 --- a/packages/sdk-components-react-radix/src/tabs.ws.ts +++ b/packages/sdk-components-react-radix/src/tabs.ws.ts @@ -4,7 +4,7 @@ import { TabsIcon, TriggerIcon, } from "@webstudio-is/icons/svg"; -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { button, div } from "@webstudio-is/sdk/normalize.css"; import { radix } from "./shared/meta"; import { buttonReset } from "./shared/preset-styles"; @@ -45,14 +45,7 @@ export const metaTabsTrigger: WsComponentMeta = { category: "none", children: ["instance", "rich-text"], }, - states: [ - ...defaultStates, - { - category: "component-states", - label: "Active", - selector: "[data-state=active]", - }, - ], + states: [{ label: "Active", selector: "[data-state=active]" }], presetStyle: { button: [button, buttonReset].flat(), }, diff --git a/packages/sdk-components-react/src/blockquote.ws.ts b/packages/sdk-components-react/src/blockquote.ws.ts index ae83691bef06..9b5f4939cf28 100644 --- a/packages/sdk-components-react/src/blockquote.ws.ts +++ b/packages/sdk-components-react/src/blockquote.ws.ts @@ -1,8 +1,4 @@ -import { - defaultStates, - type PresetStyle, - type WsComponentMeta, -} from "@webstudio-is/sdk"; +import type { PresetStyle, WsComponentMeta } from "@webstudio-is/sdk"; import type { defaultTag } from "./blockquote"; import { props } from "./__generated__/blockquote.props"; @@ -58,7 +54,6 @@ const presetStyle = { } satisfies PresetStyle; export const meta: WsComponentMeta = { - states: defaultStates, presetStyle, initialProps: ["id", "class", "cite"], props, diff --git a/packages/sdk-components-react/src/body.ws.ts b/packages/sdk-components-react/src/body.ws.ts index c8b16b20e5d2..f1117c651edd 100644 --- a/packages/sdk-components-react/src/body.ws.ts +++ b/packages/sdk-components-react/src/body.ws.ts @@ -1,29 +1,9 @@ -import { - defaultStates, - type PresetStyle, - type WsComponentMeta, -} from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { body } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/body.props"; -import type { defaultTag } from "./body"; - -const presetStyle = { - body: [ - ...body, - { - property: "-webkit-font-smoothing", - value: { type: "keyword", value: "antialiased" }, - }, - { - property: "-moz-osx-font-smoothing", - value: { type: "keyword", value: "grayscale" }, - }, - ], -} satisfies PresetStyle; export const meta: WsComponentMeta = { - states: defaultStates, - presetStyle, + presetStyle: { body }, initialProps: ["id", "class"], props, }; diff --git a/packages/sdk-components-react/src/bold.ws.ts b/packages/sdk-components-react/src/bold.ws.ts index 0fb6717162f9..f6717e748bdf 100644 --- a/packages/sdk-components-react/src/bold.ws.ts +++ b/packages/sdk-components-react/src/bold.ws.ts @@ -1,10 +1,9 @@ -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { b } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/bold.props"; export const meta: WsComponentMeta = { label: "Bold Text", - states: defaultStates, presetStyle: { b }, initialProps: ["id", "class"], props, diff --git a/packages/sdk-components-react/src/box.ws.ts b/packages/sdk-components-react/src/box.ws.ts index 918cd406de3e..e5c98e639151 100644 --- a/packages/sdk-components-react/src/box.ws.ts +++ b/packages/sdk-components-react/src/box.ws.ts @@ -1,4 +1,4 @@ -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { div, address, @@ -17,7 +17,6 @@ export const meta: WsComponentMeta = { category: "general", description: "A container for content. By default this is a Div, but the tag can be changed in settings.", - states: defaultStates, presetStyle: { div, address, diff --git a/packages/sdk-components-react/src/button.ws.ts b/packages/sdk-components-react/src/button.ws.ts index 8b44d3d5e83a..66f94f96f445 100644 --- a/packages/sdk-components-react/src/button.ws.ts +++ b/packages/sdk-components-react/src/button.ws.ts @@ -1,23 +1,9 @@ -import { - defaultStates, - type PresetStyle, - type WsComponentMeta, -} from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { button } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/button.props"; -import type { defaultTag } from "./button"; - -const presetStyle = { - button, -} satisfies PresetStyle; export const meta: WsComponentMeta = { - presetStyle, - states: [ - ...defaultStates, - { selector: ":disabled", label: "Disabled" }, - { selector: ":enabled", label: "Enabled" }, - ], + presetStyle: { button }, initialProps: ["id", "class", "type", "aria-label"], props, }; diff --git a/packages/sdk-components-react/src/checkbox.ws.ts b/packages/sdk-components-react/src/checkbox.ws.ts index 32dbdf3d0149..8287a50ba61c 100644 --- a/packages/sdk-components-react/src/checkbox.ws.ts +++ b/packages/sdk-components-react/src/checkbox.ws.ts @@ -1,9 +1,5 @@ import { CheckboxCheckedIcon } from "@webstudio-is/icons/svg"; -import { - type WsComponentMeta, - type PresetStyle, - defaultStates, -} from "@webstudio-is/sdk"; +import type { WsComponentMeta, PresetStyle } from "@webstudio-is/sdk"; import { checkbox } from "@webstudio-is/sdk/normalize.css"; import type { defaultTag } from "./checkbox"; import { props } from "./__generated__/checkbox.props"; @@ -21,16 +17,6 @@ const presetStyle = { export const meta: WsComponentMeta = { icon: CheckboxCheckedIcon, presetStyle, - states: [ - ...defaultStates, - { selector: ":checked", label: "Checked" }, - { selector: ":required", label: "Required" }, - { selector: ":optional", label: "Optional" }, - { selector: ":disabled", label: "Disabled" }, - { selector: ":enabled", label: "Enabled" }, - { selector: ":read-only", label: "Read Only" }, - { selector: ":read-write", label: "Read Write" }, - ], initialProps: ["id", "class", "name", "value", "required", "checked"], props, }; diff --git a/packages/sdk-components-react/src/code-text.ws.ts b/packages/sdk-components-react/src/code-text.ws.ts index 9221be12e72d..b492f6d05123 100644 --- a/packages/sdk-components-react/src/code-text.ws.ts +++ b/packages/sdk-components-react/src/code-text.ws.ts @@ -1,9 +1,5 @@ import { BracesIcon } from "@webstudio-is/icons/svg"; -import { - defaultStates, - type PresetStyle, - type WsComponentMeta, -} from "@webstudio-is/sdk"; +import type { PresetStyle, WsComponentMeta } from "@webstudio-is/sdk"; import { code } from "@webstudio-is/sdk/normalize.css"; import type { defaultTag } from "./code-text"; import { props } from "./__generated__/code-text.props"; @@ -44,7 +40,6 @@ export const meta: WsComponentMeta = { category: "instance", children: [], }, - states: defaultStates, presetStyle, initialProps: ["id", "class", "lang", "code"], props: { diff --git a/packages/sdk-components-react/src/form.ws.ts b/packages/sdk-components-react/src/form.ws.ts index 0b78c2d982a4..d156e2ebf628 100644 --- a/packages/sdk-components-react/src/form.ws.ts +++ b/packages/sdk-components-react/src/form.ws.ts @@ -1,8 +1,4 @@ -import { - defaultStates, - type PresetStyle, - type WsComponentMeta, -} from "@webstudio-is/sdk"; +import type { PresetStyle, WsComponentMeta } from "@webstudio-is/sdk"; import { form } from "@webstudio-is/sdk/normalize.css"; import type { defaultTag } from "./form"; import { props } from "./__generated__/form.props"; @@ -18,7 +14,6 @@ export const meta: WsComponentMeta = { category: "forms", label: "Form", description: "Create filters, surveys, searches and more.", - states: defaultStates, presetStyle, order: 0, initialProps: ["id", "class", "action"], diff --git a/packages/sdk-components-react/src/heading.ws.ts b/packages/sdk-components-react/src/heading.ws.ts index 7f5ea714d35a..d7c52e5eaf93 100644 --- a/packages/sdk-components-react/src/heading.ws.ts +++ b/packages/sdk-components-react/src/heading.ws.ts @@ -1,9 +1,8 @@ -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { h1, h2, h3, h4, h5, h6 } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/heading.props"; export const meta: WsComponentMeta = { - states: defaultStates, presetStyle: { h1, h2, diff --git a/packages/sdk-components-react/src/image.ws.ts b/packages/sdk-components-react/src/image.ws.ts index 9a1d3665a0a1..4da1c2164f9c 100644 --- a/packages/sdk-components-react/src/image.ws.ts +++ b/packages/sdk-components-react/src/image.ws.ts @@ -1,8 +1,4 @@ -import { - defaultStates, - type PresetStyle, - type WsComponentMeta, -} from "@webstudio-is/sdk"; +import type { PresetStyle, WsComponentMeta } from "@webstudio-is/sdk"; import { img } from "@webstudio-is/sdk/normalize.css"; import type { defaultTag } from "./image"; import { props } from "./__generated__/image.props"; @@ -36,7 +32,6 @@ export const meta: WsComponentMeta = { category: "media", description: "Add an image asset to the page. Webstudio automatically converts images to WebP or AVIF format and makes them responsive for best performance.", - states: defaultStates, presetStyle, order: 0, initialProps: [ diff --git a/packages/sdk-components-react/src/input.ws.ts b/packages/sdk-components-react/src/input.ws.ts index d71fb9d01204..3581a03f8833 100644 --- a/packages/sdk-components-react/src/input.ws.ts +++ b/packages/sdk-components-react/src/input.ws.ts @@ -1,8 +1,4 @@ -import { - defaultStates, - type PresetStyle, - type WsComponentMeta, -} from "@webstudio-is/sdk"; +import type { PresetStyle, WsComponentMeta } from "@webstudio-is/sdk"; import { input } from "@webstudio-is/sdk/normalize.css"; import type { defaultTag } from "./input"; import { props } from "./__generated__/input.props"; @@ -24,19 +20,6 @@ export const meta: WsComponentMeta = { "A single-line text input for collecting string data from your users.", presetStyle, order: 3, - states: [ - ...defaultStates, - { selector: "::placeholder", label: "Placeholder" }, - { selector: ":valid", label: "Valid" }, - { selector: ":invalid", label: "Invalid" }, - { selector: ":required", label: "Required" }, - { selector: ":optional", label: "Optional" }, - // Additional states will go into submenu - //{ selector: ":disabled", label: "Disabled" }, - //{ selector: ":enabled", label: "Enabled" }, - //{ selector: ":read-only", label: "Read Only" }, - //{ selector: ":read-write", label: "Read Write" }, - ], initialProps: [ "id", "class", diff --git a/packages/sdk-components-react/src/italic.ws.ts b/packages/sdk-components-react/src/italic.ws.ts index b9074c286685..9da086ef39ab 100644 --- a/packages/sdk-components-react/src/italic.ws.ts +++ b/packages/sdk-components-react/src/italic.ws.ts @@ -1,26 +1,10 @@ -import type { defaultTag } from "./italic"; -import { - defaultStates, - type PresetStyle, - type WsComponentMeta, -} from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { i } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/italic.props"; -const presetStyle = { - i: [ - ...i, - { - property: "font-style", - value: { type: "keyword", value: "italic" }, - }, - ], -} satisfies PresetStyle; - export const meta: WsComponentMeta = { label: "Italic Text", - states: defaultStates, - presetStyle, + presetStyle: { i }, initialProps: ["id", "class"], props, }; diff --git a/packages/sdk-components-react/src/label.ws.ts b/packages/sdk-components-react/src/label.ws.ts index cba9e5577517..a9e1f4c25456 100644 --- a/packages/sdk-components-react/src/label.ws.ts +++ b/packages/sdk-components-react/src/label.ws.ts @@ -1,8 +1,4 @@ -import { - type WsComponentMeta, - type PresetStyle, - defaultStates, -} from "@webstudio-is/sdk"; +import type { WsComponentMeta, PresetStyle } from "@webstudio-is/sdk"; import { label } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/label.props"; import type { defaultTag } from "./label"; @@ -16,7 +12,6 @@ const presetStyle = { export const meta: WsComponentMeta = { label: "Input Label", - states: defaultStates, presetStyle, initialProps: ["id", "class", "for"], props, diff --git a/packages/sdk-components-react/src/link.ws.ts b/packages/sdk-components-react/src/link.ws.ts index 20b2a1b3d563..0de9f2b5ab0d 100644 --- a/packages/sdk-components-react/src/link.ws.ts +++ b/packages/sdk-components-react/src/link.ws.ts @@ -1,8 +1,4 @@ -import { - defaultStates, - type PresetStyle, - type WsComponentMeta, -} from "@webstudio-is/sdk"; +import type { PresetStyle, WsComponentMeta } from "@webstudio-is/sdk"; import { a } from "@webstudio-is/sdk/normalize.css"; import type { defaultTag } from "./link"; import { props } from "./__generated__/link.props"; @@ -19,18 +15,7 @@ const presetStyle = { export const meta: WsComponentMeta = { presetStyle, - states: [ - ...defaultStates, - { - selector: ":visited", - label: "Visited", - }, - { - category: "component-states", - selector: "[aria-current=page]", - label: "Current page", - }, - ], + states: [{ label: "Current page", selector: "[aria-current=page]" }], initialProps: ["id", "class", "href", "target", "prefetch", "download"], props: { ...props, diff --git a/packages/sdk-components-react/src/list-item.ws.ts b/packages/sdk-components-react/src/list-item.ws.ts index 198e8727cfde..6c7248a6aef2 100644 --- a/packages/sdk-components-react/src/list-item.ws.ts +++ b/packages/sdk-components-react/src/list-item.ws.ts @@ -1,9 +1,8 @@ -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { li } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/list-item.props"; export const meta: WsComponentMeta = { - states: defaultStates, presetStyle: { li }, initialProps: ["id", "class"], props, diff --git a/packages/sdk-components-react/src/list.ws.ts b/packages/sdk-components-react/src/list.ws.ts index 53388a9fe1f9..6a685d94397b 100644 --- a/packages/sdk-components-react/src/list.ws.ts +++ b/packages/sdk-components-react/src/list.ws.ts @@ -1,8 +1,4 @@ -import { - defaultStates, - type PresetStyle, - type WsComponentMeta, -} from "@webstudio-is/sdk"; +import type { PresetStyle, WsComponentMeta } from "@webstudio-is/sdk"; import { ol, ul } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/list.props"; import type { ListTag } from "./list"; @@ -41,7 +37,6 @@ const presetStyle = { } satisfies PresetStyle; export const meta: WsComponentMeta = { - states: defaultStates, presetStyle, initialProps: ["id", "class", "ordered", "start", "reversed"], props, diff --git a/packages/sdk-components-react/src/paragraph.ws.ts b/packages/sdk-components-react/src/paragraph.ws.ts index ef8514aa3b20..0aa2c38e5ad1 100644 --- a/packages/sdk-components-react/src/paragraph.ws.ts +++ b/packages/sdk-components-react/src/paragraph.ws.ts @@ -1,9 +1,8 @@ -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { p } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/paragraph.props"; export const meta: WsComponentMeta = { - states: defaultStates, presetStyle: { p }, initialProps: ["id", "class"], props, diff --git a/packages/sdk-components-react/src/radio-button.ws.ts b/packages/sdk-components-react/src/radio-button.ws.ts index a026b36b2584..8ae3c8483ced 100644 --- a/packages/sdk-components-react/src/radio-button.ws.ts +++ b/packages/sdk-components-react/src/radio-button.ws.ts @@ -1,9 +1,5 @@ import { RadioCheckedIcon } from "@webstudio-is/icons/svg"; -import { - type WsComponentMeta, - type PresetStyle, - defaultStates, -} from "@webstudio-is/sdk"; +import type { WsComponentMeta, PresetStyle } from "@webstudio-is/sdk"; import type { defaultTag } from "./radio-button"; import { radio } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/radio-button.props"; @@ -22,17 +18,6 @@ export const meta: WsComponentMeta = { label: "Radio", icon: RadioCheckedIcon, presetStyle, - states: [ - ...defaultStates, - { selector: ":checked", label: "Checked" }, - { selector: ":required", label: "Required" }, - { selector: ":optional", label: "Optional" }, - // Additional states will go into submenu - //{ selector: ":disabled", label: "Disabled" }, - //{ selector: ":enabled", label: "Enabled" }, - //{ selector: ":read-only", label: "Read Only" }, - //{ selector: ":read-write", label: "Read Write" }, - ], initialProps: ["id", "class", "name", "value", "required", "checked"], props, }; diff --git a/packages/sdk-components-react/src/select.ws.ts b/packages/sdk-components-react/src/select.ws.ts index b5ebf1312071..76e1ab177e43 100644 --- a/packages/sdk-components-react/src/select.ws.ts +++ b/packages/sdk-components-react/src/select.ws.ts @@ -1,8 +1,4 @@ -import { - defaultStates, - type PresetStyle, - type WsComponentMeta, -} from "@webstudio-is/sdk"; +import type { PresetStyle, WsComponentMeta } from "@webstudio-is/sdk"; import { select } from "@webstudio-is/sdk/normalize.css"; import type { defaultTag } from "./select"; import { props } from "./__generated__/select.props"; @@ -19,14 +15,6 @@ const presetStyle = { export const meta: WsComponentMeta = { presetStyle, - states: [ - ...defaultStates, - { selector: "::placeholder", label: "Placeholder" }, - { selector: ":valid", label: "Valid" }, - { selector: ":invalid", label: "Invalid" }, - { selector: ":required", label: "Required" }, - { selector: ":optional", label: "Optional" }, - ], initialProps: [ "id", "class", diff --git a/packages/sdk-components-react/src/separator.ws.ts b/packages/sdk-components-react/src/separator.ws.ts index 6e7d8aeccab7..008ef8d70f19 100644 --- a/packages/sdk-components-react/src/separator.ws.ts +++ b/packages/sdk-components-react/src/separator.ws.ts @@ -1,8 +1,4 @@ -import { - defaultStates, - type PresetStyle, - type WsComponentMeta, -} from "@webstudio-is/sdk"; +import type { PresetStyle, WsComponentMeta } from "@webstudio-is/sdk"; import { hr } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/separator.props"; import type { defaultTag } from "./separator"; @@ -38,7 +34,6 @@ const presetStyle = { } satisfies PresetStyle; export const meta: WsComponentMeta = { - states: defaultStates, presetStyle, initialProps: ["id", "class"], props, diff --git a/packages/sdk-components-react/src/span.ws.ts b/packages/sdk-components-react/src/span.ws.ts index fbdd0ad2584c..c435dcb0da02 100644 --- a/packages/sdk-components-react/src/span.ws.ts +++ b/packages/sdk-components-react/src/span.ws.ts @@ -1,12 +1,11 @@ import { PaintBrushIcon } from "@webstudio-is/icons/svg"; -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { span } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/span.props"; export const meta: WsComponentMeta = { label: "Text", icon: PaintBrushIcon, - states: defaultStates, presetStyle: { span }, initialProps: ["id", "class"], props, diff --git a/packages/sdk-components-react/src/subscript.ws.ts b/packages/sdk-components-react/src/subscript.ws.ts index 72bae98fa767..b6eae30941f4 100644 --- a/packages/sdk-components-react/src/subscript.ws.ts +++ b/packages/sdk-components-react/src/subscript.ws.ts @@ -1,10 +1,9 @@ -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { sub } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/subscript.props"; export const meta: WsComponentMeta = { label: "Subscript Text", - states: defaultStates, presetStyle: { sub }, initialProps: ["id", "class"], props, diff --git a/packages/sdk-components-react/src/superscript.ws.ts b/packages/sdk-components-react/src/superscript.ws.ts index 4bcee0a23541..c62538989373 100644 --- a/packages/sdk-components-react/src/superscript.ws.ts +++ b/packages/sdk-components-react/src/superscript.ws.ts @@ -1,10 +1,9 @@ -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { sup } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/superscript.props"; export const meta: WsComponentMeta = { label: "Superscript Text", - states: defaultStates, presetStyle: { sup }, initialProps: ["id", "class"], props, diff --git a/packages/sdk-components-react/src/text.ws.ts b/packages/sdk-components-react/src/text.ws.ts index 1e5427781886..342bc0454bdc 100644 --- a/packages/sdk-components-react/src/text.ws.ts +++ b/packages/sdk-components-react/src/text.ws.ts @@ -1,11 +1,10 @@ import { TextIcon } from "@webstudio-is/icons/svg"; -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { div } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/text.props"; export const meta: WsComponentMeta = { icon: TextIcon, - states: defaultStates, presetStyle: { div: [ ...div, diff --git a/packages/sdk-components-react/src/textarea.ws.ts b/packages/sdk-components-react/src/textarea.ws.ts index 19ce31de8351..7dd4d4cac0b4 100644 --- a/packages/sdk-components-react/src/textarea.ws.ts +++ b/packages/sdk-components-react/src/textarea.ws.ts @@ -1,8 +1,4 @@ -import { - type WsComponentMeta, - type PresetStyle, - defaultStates, -} from "@webstudio-is/sdk"; +import type { WsComponentMeta, PresetStyle } from "@webstudio-is/sdk"; import { textarea } from "@webstudio-is/sdk/normalize.css"; import type { defaultTag } from "./textarea"; import { props } from "./__generated__/textarea.props"; @@ -30,19 +26,6 @@ export const meta: WsComponentMeta = { category: "instance", children: [], }, - states: [ - ...defaultStates, - { selector: "::placeholder", label: "Placeholder" }, - { selector: ":valid", label: "Valid" }, - { selector: ":invalid", label: "Invalid" }, - { selector: ":required", label: "Required" }, - { selector: ":optional", label: "Optional" }, - // Additional states will go into submenu - //{ selector: ":disabled", label: "Disabled" }, - //{ selector: ":enabled", label: "Enabled" }, - //{ selector: ":read-only", label: "Read Only" }, - //{ selector: ":read-write", label: "Read Write" }, - ], initialProps: [ "id", "class", diff --git a/packages/sdk-components-react/src/time.ws.ts b/packages/sdk-components-react/src/time.ws.ts index 3a7ca160ab11..081b6ad514a0 100644 --- a/packages/sdk-components-react/src/time.ws.ts +++ b/packages/sdk-components-react/src/time.ws.ts @@ -1,4 +1,4 @@ -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { time } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/time.props"; @@ -10,7 +10,6 @@ export const meta: WsComponentMeta = { category: "instance", children: [], }, - states: defaultStates, presetStyle: { time, }, diff --git a/packages/sdk-components-react/src/vimeo-play-button.ws.ts b/packages/sdk-components-react/src/vimeo-play-button.ws.ts index 0647f58cd9c1..093b5dc59ca1 100644 --- a/packages/sdk-components-react/src/vimeo-play-button.ws.ts +++ b/packages/sdk-components-react/src/vimeo-play-button.ws.ts @@ -1,4 +1,4 @@ -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { ButtonElementIcon } from "@webstudio-is/icons/svg"; import { button } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/vimeo-play-button.props"; @@ -7,7 +7,6 @@ export const meta: WsComponentMeta = { category: "hidden", label: "Play Button", icon: ButtonElementIcon, - states: defaultStates, contentModel: { category: "none", children: ["instance"], diff --git a/packages/sdk-components-react/src/vimeo-spinner.ws.ts b/packages/sdk-components-react/src/vimeo-spinner.ws.ts index f91d67b93cc9..340969725e4d 100644 --- a/packages/sdk-components-react/src/vimeo-spinner.ws.ts +++ b/packages/sdk-components-react/src/vimeo-spinner.ws.ts @@ -1,11 +1,10 @@ -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { div } from "@webstudio-is/sdk/normalize.css"; import { BoxIcon } from "@webstudio-is/icons/svg"; import { props } from "./__generated__/vimeo-spinner.props"; export const meta: WsComponentMeta = { icon: BoxIcon, - states: defaultStates, category: "hidden", label: "Spinner", contentModel: { diff --git a/packages/sdk-components-react/src/vimeo.ws.ts b/packages/sdk-components-react/src/vimeo.ws.ts index 8bc257a8e976..ff304fc7bd28 100644 --- a/packages/sdk-components-react/src/vimeo.ws.ts +++ b/packages/sdk-components-react/src/vimeo.ws.ts @@ -1,6 +1,6 @@ import type { ComponentProps } from "react"; import { VimeoIcon } from "@webstudio-is/icons/svg"; -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { div } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/vimeo.props"; import type { Vimeo } from "./vimeo"; @@ -27,7 +27,6 @@ const initialProps: Array> = [ export const meta: WsComponentMeta = { icon: VimeoIcon, - states: defaultStates, contentModel: { category: "instance", children: ["instance"], diff --git a/packages/sdk-components-react/src/youtube.ws.ts b/packages/sdk-components-react/src/youtube.ws.ts index 3eb03b2c25a6..ece717201b4b 100644 --- a/packages/sdk-components-react/src/youtube.ws.ts +++ b/packages/sdk-components-react/src/youtube.ws.ts @@ -1,6 +1,6 @@ import type { ComponentProps } from "react"; import { YoutubeIcon } from "@webstudio-is/icons/svg"; -import { defaultStates, type WsComponentMeta } from "@webstudio-is/sdk"; +import type { WsComponentMeta } from "@webstudio-is/sdk"; import { div } from "@webstudio-is/sdk/normalize.css"; import { props } from "./__generated__/youtube.props"; import type { YouTube } from "./youtube"; @@ -37,7 +37,6 @@ const initialProps: Array> = [ export const meta: WsComponentMeta = { icon: YoutubeIcon, - states: defaultStates, contentModel: { category: "instance", children: ["instance"], diff --git a/packages/sdk/src/__generated__/normalize.css.ts b/packages/sdk/src/__generated__/normalize.css.ts index eef4c853a3d8..9a354d1a28c0 100644 --- a/packages/sdk/src/__generated__/normalize.css.ts +++ b/packages/sdk/src/__generated__/normalize.css.ts @@ -128,6 +128,14 @@ export const body: StyleDecl[] = [ property: "border-left-width", value: { type: "unit", unit: "px", value: 1 }, }, + { + property: "-webkit-font-smoothing", + value: { type: "keyword", value: "antialiased" }, + }, + { + property: "-moz-osx-font-smoothing", + value: { type: "keyword", value: "grayscale" }, + }, ]; export const hr: StyleDecl[] = [ diff --git a/packages/sdk/src/normalize.css b/packages/sdk/src/normalize.css index 3311d7f4a3fd..96185b8198dd 100644 --- a/packages/sdk/src/normalize.css +++ b/packages/sdk/src/normalize.css @@ -92,6 +92,8 @@ body { /* webstudio custom opinionated presets */ box-sizing: border-box; border-width: 1px; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } /** diff --git a/packages/sdk/src/schema/component-meta.ts b/packages/sdk/src/schema/component-meta.ts index f249f7a49bc0..411d1dcd037b 100644 --- a/packages/sdk/src/schema/component-meta.ts +++ b/packages/sdk/src/schema/component-meta.ts @@ -35,24 +35,13 @@ export const componentCategories = [ "internal", ] as const; -export const stateCategories = ["states", "component-states"] as const; - export const ComponentState = z.object({ - category: z.enum(stateCategories).optional(), selector: z.string(), label: z.string(), }); export type ComponentState = z.infer; -export const defaultStates: ComponentState[] = [ - { selector: ":hover", label: "Hover" }, - { selector: ":active", label: "Active" }, - { selector: ":focus", label: "Focus" }, - { selector: ":focus-visible", label: "Focus Visible" }, - { selector: ":focus-within", label: "Focus Within" }, -]; - /** * rich-text - can be edited as rich text * instance - other instances accepted