Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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"],
Expand Down Expand Up @@ -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];
}
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const Menu = (props: MenuProps) => {
</DropdownMenuTrigger>
<DropdownMenuContent
onCloseAutoFocus={(event) => event.preventDefault()}
css={{ maxWidth: theme.spacing[24] }}
css={{ maxWidth: theme.spacing[26] }}
>
{props.children}
</DropdownMenuContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<Item extends IntermediateItem> = {
$styleSourceInputElement: WritableAtom<HTMLInputElement | undefined>;
error?: StyleSourceError;
Expand Down Expand Up @@ -417,9 +427,9 @@ const renderMenuItems = (props: {
</DropdownMenuItem>
)}

{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) {
Expand Down
1 change: 1 addition & 0 deletions packages/html-data/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./__generated__/elements";
export * from "./__generated__/attributes";
export * from "./__generated__/aria";
export * from "./pseudo-classes";
70 changes: 70 additions & 0 deletions packages/html-data/src/pseudo-classes.ts
Original file line number Diff line number Diff line change
@@ -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<string, string[]> = {
"*": 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"],
};
11 changes: 2 additions & 9 deletions packages/sdk-components-react-radix/src/accordion.ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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(),
},
Expand Down
16 changes: 3 additions & 13 deletions packages/sdk-components-react-radix/src/checkbox.ws.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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(),
Expand All @@ -41,7 +32,6 @@ export const metaCheckboxIndicator: WsComponentMeta = {
category: "none",
children: ["instance", "rich-text"],
},
states: defaultStates,
presetStyle: {
span,
},
Expand Down
3 changes: 1 addition & 2 deletions packages/sdk-components-react-radix/src/dialog.ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -84,7 +84,6 @@ export const metaDialogClose: WsComponentMeta = {
category: "none",
children: ["instance", "rich-text"],
},
states: defaultStates,
presetStyle: {
button: [buttonReset, button].flat(),
},
Expand Down
7 changes: 2 additions & 5 deletions packages/sdk-components-react-radix/src/label.ws.ts
Original file line number Diff line number Diff line change
@@ -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,
};
3 changes: 1 addition & 2 deletions packages/sdk-components-react-radix/src/popover.ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -57,7 +57,6 @@ export const metaPopoverClose: WsComponentMeta = {
category: "none",
children: ["instance", "rich-text"],
},
states: defaultStates,
presetStyle: {
button: [buttonReset, button].flat(),
},
Expand Down
17 changes: 3 additions & 14 deletions packages/sdk-components-react-radix/src/radio-group.ws.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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,
Expand All @@ -43,7 +34,6 @@ export const metaRadioGroupItem: WsComponentMeta = {
children: ["instance"],
descendants: [radix.RadioGroupIndicator],
},
states: defaultStates,
presetStyle: {
button: [button, buttonReset].flat(),
},
Expand All @@ -57,7 +47,6 @@ export const metaRadioGroupIndicator: WsComponentMeta = {
category: "none",
children: ["instance"],
},
states: defaultStates,
presetStyle: {
span,
},
Expand Down
28 changes: 5 additions & 23 deletions packages/sdk-components-react-radix/src/switch.ws.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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(),
Expand All @@ -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,
Expand Down
11 changes: 2 additions & 9 deletions packages/sdk-components-react-radix/src/tabs.ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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(),
},
Expand Down
Loading