diff --git a/apps/builder/app/builder/features/sidebar-left/panels/components/components.tsx b/apps/builder/app/builder/features/sidebar-left/panels/components/components.tsx index 56e2a0b23b..cbc0c192e5 100644 --- a/apps/builder/app/builder/features/sidebar-left/panels/components/components.tsx +++ b/apps/builder/app/builder/features/sidebar-left/panels/components/components.tsx @@ -1,4 +1,4 @@ -import { useMemo, useState, type FormEvent } from "react"; +import { useMemo, useState } from "react"; import { useStore } from "@nanostores/react"; import { type WsComponentMeta, @@ -13,42 +13,217 @@ import { ListItem, SearchField, Separator, + useSearchFieldKeys, + findNextListItemIndex, + Text, + Box, + Kbd, } from "@webstudio-is/design-system"; import { PlusIcon } from "@webstudio-is/icons"; import { CollapsibleSection } from "~/builder/shared/collapsible-section"; import type { TabContentProps } from "../../types"; import { Header, CloseButton, Root } from "../../shared/panel"; -import { - dragItemAttribute, - elementToComponentName, - useDraggable, -} from "./use-draggable"; +import { dragItemAttribute, useDraggable } from "./use-draggable"; import { MetaIcon } from "~/builder/shared/meta-icon"; import { $registeredComponentMetas, $selectedPage } from "~/shared/nano-states"; -import { getMetaMaps } from "./get-meta-maps"; +import { + getMetaMaps, + type MetaByCategory, + type ComponentNamesByMeta, +} from "./get-meta-maps"; import { getInstanceLabel } from "~/shared/instance-utils"; import { isFeatureEnabled } from "@webstudio-is/feature-flags"; import { insert } from "./insert"; import { matchSorter } from "match-sorter"; +import { parseComponentName } from "@webstudio-is/sdk"; + +const matchComponents = ( + metas: Array, + componentNamesByMeta: ComponentNamesByMeta, + search: string +) => { + const getKey = (meta: WsComponentMeta) => { + if (meta.label) { + return meta.label.toLowerCase(); + } + const component = componentNamesByMeta.get(meta); + if (component) { + const [_namespace, name] = parseComponentName(component); + return name.toLowerCase(); + } + return ""; + }; + + return matchSorter(metas, search, { + keys: [getKey], + }); +}; + +type Groups = Array<{ + category: Exclude | "found"; + metas: Array; +}>; + +const filterAndGroupComponents = ({ + documentType = "html", + metaByCategory, + componentNamesByMeta, + search, +}: { + documentType?: "html" | "xml"; + metaByCategory: MetaByCategory; + componentNamesByMeta: ComponentNamesByMeta; + search: string; +}): Groups => { + const categories = componentCategories.filter((category) => { + if (category === "hidden") { + return false; + } + + // Only xml category is allowed for xml document type + if (documentType === "xml") { + return category === "xml" || category === "data"; + } + // Hide xml category for non-xml document types + if (category === "xml") { + return false; + } + + if ( + isFeatureEnabled("internalComponents") === false && + category === "internal" + ) { + return false; + } + + return true; + }); + + let groups: Groups = categories.map((category) => { + const metas = (metaByCategory.get(category) ?? []).filter((meta) => { + const component = componentNamesByMeta.get(meta); + + if (component === undefined) { + return false; + } + + if (documentType === "xml" && meta.category === "data") { + return component === "ws:collection"; + } + + if (component === "RemixForm" && isFeatureEnabled("filters") === false) { + return false; + } + + if (component === "ContentEmbed" && isFeatureEnabled("cms") === false) { + return false; + } + + return true; + }); + + return { category, metas }; + }); + + if (search.length !== 0) { + let metas = groups.map((group) => group.metas).flat(); + metas = matchComponents(metas, componentNamesByMeta, search); + groups = [{ category: "found", metas }]; + } + + groups = groups.filter((group) => group.metas.length > 0); + + return groups; +}; + +const findComponentIndex = ( + groups: Groups, + componentNamesByMeta: ComponentNamesByMeta, + selectedComponent?: string +) => { + if (selectedComponent === undefined) { + return { index: -1, metas: groups[0].metas }; + } + + for (const { metas } of groups) { + const index = metas.findIndex((meta) => { + return componentNamesByMeta.get(meta) === selectedComponent; + }); + if (index === -1) { + continue; + } + return { index, metas }; + } + + return { index: -1, metas: [] }; +}; export const TabContent = ({ publish, onSetActiveTab }: TabContentProps) => { const metaByComponentName = useStore($registeredComponentMetas); const selectedPage = useStore($selectedPage); - const [searchText, setSearchText] = useState(""); - const documentType = selectedPage?.meta.documentType ?? "html"; + const [selectedComponent, setSelectedComponent] = useState(); + + const handleInsert = (component: string) => { + onSetActiveTab("none"); + insert(component); + }; + + const resetSelectedComponent = () => { + setSelectedComponent(undefined); + }; + + const getSelectedComponent = () => { + // When user didn't select a component but they have search input, + // we want to always have the first component selected, so that user can just hit enter. + if (selectedComponent === undefined && searchFieldProps.value) { + return componentNamesByMeta.get(groups[0].metas[0]); + } + return selectedComponent; + }; + + const searchFieldProps = useSearchFieldKeys({ + onChange: resetSelectedComponent, + onCancel: resetSelectedComponent, + onMove({ direction }) { + if (direction === "current") { + const component = getSelectedComponent(); + if (component !== undefined) { + handleInsert(component); + } + return; + } + + const { index, metas } = findComponentIndex( + groups, + componentNamesByMeta, + selectedComponent + ); + + const nextIndex = findNextListItemIndex(index, metas.length, direction); + const nextComponent = componentNamesByMeta.get(metas[nextIndex]); + + if (nextComponent) { + setSelectedComponent(nextComponent); + } + }, + }); const { metaByCategory, componentNamesByMeta } = useMemo( () => getMetaMaps(metaByComponentName), [metaByComponentName] ); + const { dragCard, draggableContainerRef } = useDraggable({ publish, metaByComponentName, }); - const handleSearch = (e: FormEvent) => { - setSearchText((e.target as HTMLInputElement).value); - }; + const groups = filterAndGroupComponents({ + documentType: selectedPage?.meta.documentType, + metaByCategory, + componentNamesByMeta, + search: searchFieldProps.value, + }); return ( @@ -56,128 +231,72 @@ export const TabContent = ({ publish, onSetActiveTab }: TabContentProps) => { title="Components" suffix={ onSetActiveTab("none")} />} /> - - setSearchText("")} - css={{ - mx: theme.spacing[9], - mt: theme.spacing[9], - mb: theme.spacing[9], - }} - /> + + + - {componentCategories - .filter((category) => { - if (category === "hidden") { - return false; - } + {groups.map((group) => ( + + + + {group.metas.map((meta: WsComponentMeta, index) => { + const component = componentNamesByMeta.get(meta); - // Only xml category is allowed for xml document type - if (documentType === "xml") { - return category === "xml" || category === "data"; - } - // Hide xml category for non-xml document types - if (category === "xml") { - return false; - } + if (component === undefined) { + return; + } - if ( - isFeatureEnabled("internalComponents") === false && - category === "internal" - ) { - return false; - } - - return true; - }) - .map((category) => { - const meta = (metaByCategory.get(category) ?? []).filter( - (meta: WsComponentMeta) => { - if (documentType === "xml" && meta.category === "data") { - return componentNamesByMeta.get(meta) === "ws:collection"; - } - return true; - } - ); - const matchedMeta = matchSorter(meta, searchText, { - keys: [(item) => componentNamesByMeta.get(item) || ""], - }); - - return { - category, - meta: matchedMeta, - }; - }) - .filter((category) => { - return category.meta.length > 0; - }) - .map((categoryGroup) => ( - - - - {categoryGroup.meta.map((meta: WsComponentMeta, index) => { - const component = componentNamesByMeta.get(meta); - if (component === undefined) { - return; - } - if ( - isFeatureEnabled("filters") === false && - component === "RemixForm" - ) { - return; - } - if ( - isFeatureEnabled("cms") === false && - component === "ContentEmbed" - ) { - return; - } - return ( - { - const component = elementToComponentName( - event.target as HTMLElement, - metaByComponentName - ); - if (component) { - onSetActiveTab("none"); - insert(component); - } - }} - > - } - /> - - ); - })} - {dragCard} - - - - ))} + return ( + { + handleInsert(component); + }} + onFocus={() => { + setSelectedComponent(component); + }} + > + } + /> + + ); + })} + {dragCard} + {group.metas.length === 0 && ( + + No matching component + + )} + + + + ))} ); @@ -185,4 +304,9 @@ export const TabContent = ({ publish, onSetActiveTab }: TabContentProps) => { export const Icon = PlusIcon; -export const label = "Components"; +export const label = ( + + Components + + +); diff --git a/apps/builder/app/builder/features/sidebar-left/panels/components/get-meta-maps.ts b/apps/builder/app/builder/features/sidebar-left/panels/components/get-meta-maps.ts index 124f017adf..5127b33373 100644 --- a/apps/builder/app/builder/features/sidebar-left/panels/components/get-meta-maps.ts +++ b/apps/builder/app/builder/features/sidebar-left/panels/components/get-meta-maps.ts @@ -1,13 +1,17 @@ import { type WsComponentMeta } from "@webstudio-is/react-sdk"; +export type MetaByCategory = Map< + WsComponentMeta["category"], + Array +>; + +export type ComponentNamesByMeta = Map; + export const getMetaMaps = ( metaByComponentName: Map ) => { - const metaByCategory: Map< - WsComponentMeta["category"], - Array - > = new Map(); - const componentNamesByMeta: Map = new Map(); + const metaByCategory: MetaByCategory = new Map(); + const componentNamesByMeta: ComponentNamesByMeta = new Map(); for (const [name, meta] of metaByComponentName) { if (meta.category === undefined || meta.category === "hidden") { diff --git a/apps/builder/app/builder/features/sidebar-left/panels/components/use-draggable.tsx b/apps/builder/app/builder/features/sidebar-left/panels/components/use-draggable.tsx index b630bb3d9b..c6fdbfc1b4 100644 --- a/apps/builder/app/builder/features/sidebar-left/panels/components/use-draggable.tsx +++ b/apps/builder/app/builder/features/sidebar-left/panels/components/use-draggable.tsx @@ -68,7 +68,7 @@ const toCanvasCoordinates = ( }; }; -export const elementToComponentName = ( +const elementToComponentName = ( element: Element, metaByComponentName: Map ) => { diff --git a/apps/builder/app/builder/features/sidebar-left/panels/index.ts b/apps/builder/app/builder/features/sidebar-left/panels/index.ts index 298beb2642..ad708ecb34 100644 --- a/apps/builder/app/builder/features/sidebar-left/panels/index.ts +++ b/apps/builder/app/builder/features/sidebar-left/panels/index.ts @@ -10,7 +10,7 @@ import type { IconComponent } from "@webstudio-is/icons"; type PanelExports = { TabContent: (props: TabContentProps) => ReactNode; Icon: IconComponent; - label: string; + label: ReactNode; }; export const panels = new Map([ diff --git a/apps/builder/app/builder/features/sidebar-left/sidebar-left.tsx b/apps/builder/app/builder/features/sidebar-left/sidebar-left.tsx index 6e9e5ad031..19c47faa00 100644 --- a/apps/builder/app/builder/features/sidebar-left/sidebar-left.tsx +++ b/apps/builder/app/builder/features/sidebar-left/sidebar-left.tsx @@ -162,7 +162,7 @@ export const SidebarLeft = ({ publish }: SidebarLeftProps) => { ([tabName, { Icon, label }]) => { return ( { diff --git a/apps/builder/app/builder/features/sidebar-left/sidebar-tabs.tsx b/apps/builder/app/builder/features/sidebar-left/sidebar-tabs.tsx index b4c7724635..39071c9ecb 100644 --- a/apps/builder/app/builder/features/sidebar-left/sidebar-tabs.tsx +++ b/apps/builder/app/builder/features/sidebar-left/sidebar-tabs.tsx @@ -9,7 +9,7 @@ import { styled, theme, } from "@webstudio-is/design-system"; -import { forwardRef, type ComponentProps } from "react"; +import { forwardRef, type ComponentProps, type ReactNode } from "react"; export const SidebarTabs = styled(Tabs, { display: "flex", @@ -77,7 +77,7 @@ export const SidebarButton = forwardRef< export const SidebarTabsTrigger = forwardRef< HTMLButtonElement, - ComponentProps & { label: string } + ComponentProps & { label: ReactNode | string } >(({ label, children, ...props }, ref) => { return ( @@ -85,7 +85,7 @@ export const SidebarTabsTrigger = forwardRef< {children} diff --git a/apps/builder/app/builder/shared/assets/index.ts b/apps/builder/app/builder/shared/assets/index.ts index dc3e837c4d..ef15394620 100644 --- a/apps/builder/app/builder/shared/assets/index.ts +++ b/apps/builder/app/builder/shared/assets/index.ts @@ -1,5 +1,4 @@ export * from "./use-assets"; export * from "./types"; export * from "./separator"; -export * from "./use-search"; export * from "./assets-shell"; diff --git a/apps/builder/app/builder/shared/assets/use-search.tsx b/apps/builder/app/builder/shared/assets/use-search.tsx deleted file mode 100644 index 7fee5d84bd..0000000000 --- a/apps/builder/app/builder/shared/assets/use-search.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { - type ChangeEventHandler, - type KeyboardEventHandler, - useState, -} from "react"; - -type UseSearch = { - onSelect: (direction: "next" | "previous" | "current") => void; -}; - -export const useSearch = ({ onSelect }: UseSearch) => { - const [search, setSearch] = useState(""); - const handleKeyDown: KeyboardEventHandler = ({ code }) => { - const keyMap = { - ArrowUp: "previous", - ArrowDown: "next", - Enter: "current", - } as const; - const direction = keyMap[code as keyof typeof keyMap]; - if (direction !== undefined) { - onSelect(direction); - } - }; - - const handleChange: ChangeEventHandler = (event) => { - const { value } = event.currentTarget; - setSearch(value); - }; - - const handleCancel = () => { - setSearch(""); - }; - - return { - value: search, - onCancel: handleCancel, - onChange: handleChange, - onKeyDown: handleKeyDown, - }; -}; diff --git a/apps/builder/app/builder/shared/commands.ts b/apps/builder/app/builder/shared/commands.ts index 7d88c74082..9e4b550229 100644 --- a/apps/builder/app/builder/shared/commands.ts +++ b/apps/builder/app/builder/shared/commands.ts @@ -126,6 +126,14 @@ export const { emitCommand, subscribeCommands } = createCommandsEmitter({ $breakpointsMenuView.set("initial"); }, }, + { + name: "openComponentsPanel", + defaultHotkeys: ["a"], + handler: () => { + $activeSidebarPanel.set("components"); + }, + disableHotkeyOnFormTags: true, + }, makeBreakpointCommand("selectBreakpoint1", 1), makeBreakpointCommand("selectBreakpoint2", 2), makeBreakpointCommand("selectBreakpoint3", 3), diff --git a/apps/builder/app/builder/shared/fonts-manager/fonts-manager.tsx b/apps/builder/app/builder/shared/fonts-manager/fonts-manager.tsx index 8433055170..290da87206 100644 --- a/apps/builder/app/builder/shared/fonts-manager/fonts-manager.tsx +++ b/apps/builder/app/builder/shared/fonts-manager/fonts-manager.tsx @@ -2,15 +2,15 @@ import { DeprecatedList, DeprecatedListItem, useDeprecatedList, - deprecatedFindNextListIndex, theme, + useSearchFieldKeys, + findNextListItemIndex, } from "@webstudio-is/design-system"; import { AssetsShell, deleteAssets, Separator, useAssets, - useSearch, } from "~/builder/shared/assets"; import { useEffect, useMemo, useState } from "react"; import { useMenu } from "./item-menu"; @@ -34,13 +34,13 @@ const useLogic = ({ const [selectedIndex, setSelectedIndex] = useState(-1); const fontItems = useMemo(() => toItems(assetContainers), [assetContainers]); - const searchProps = useSearch({ - onSelect(direction) { + const searchProps = useSearchFieldKeys({ + onMove({ direction }) { if (direction === "current") { handleChangeCurrent(selectedIndex); return; } - const nextIndex = deprecatedFindNextListIndex( + const nextIndex = findNextListItemIndex( selectedIndex, groupedItems.length, direction diff --git a/apps/builder/app/builder/shared/image-manager/image-manager.tsx b/apps/builder/app/builder/shared/image-manager/image-manager.tsx index fcbf1fd8b7..eead6ccbc6 100644 --- a/apps/builder/app/builder/shared/image-manager/image-manager.tsx +++ b/apps/builder/app/builder/shared/image-manager/image-manager.tsx @@ -1,9 +1,10 @@ import { useState, useMemo } from "react"; import { matchSorter } from "match-sorter"; import { - deprecatedFindNextListIndex, Grid, + findNextListItemIndex, theme, + useSearchFieldKeys, } from "@webstudio-is/design-system"; import type { ImageAsset } from "@webstudio-is/sdk"; import { @@ -14,7 +15,6 @@ import { AssetsShell, type AssetContainer, useAssets, - useSearch, deleteAssets, } from "../assets"; import { ImageThumbnail } from "./image-thumbnail"; @@ -30,8 +30,8 @@ const useLogic = ({ const [selectedIndex, setSelectedIndex] = useState(-1); - const searchProps = useSearch({ - onSelect(direction) { + const searchProps = useSearchFieldKeys({ + onMove({ direction }) { if (direction === "current") { setSelectedIndex(selectedIndex); const assetContainer = filteredItems[selectedIndex]; @@ -43,7 +43,7 @@ const useLogic = ({ } return; } - const nextIndex = deprecatedFindNextListIndex( + const nextIndex = findNextListItemIndex( selectedIndex, filteredItems.length, direction diff --git a/packages/design-system/src/components/__DEPRECATED__/list.tsx b/packages/design-system/src/components/__DEPRECATED__/list.tsx index d74954e30e..790b00ab35 100644 --- a/packages/design-system/src/components/__DEPRECATED__/list.tsx +++ b/packages/design-system/src/components/__DEPRECATED__/list.tsx @@ -7,6 +7,7 @@ import { import { Text } from "../text"; import { Flex } from "../flex"; import { styled, theme } from "../../stitches.config"; +import { findNextListItemIndex } from "../primitives/list"; const ListBase = styled("ul", { display: "flex", @@ -92,27 +93,6 @@ export const DeprecatedListItem = forwardRef< }); DeprecatedListItem.displayName = "DeprecatedListItem"; -export const deprecatedFindNextListIndex = ( - currentIndex: number, - total: number, - direction: "next" | "previous" -) => { - const nextIndex = - direction === "next" - ? currentIndex + 1 - : direction === "previous" - ? currentIndex - 1 - : currentIndex; - - if (nextIndex < 0) { - return total - 1; - } - if (nextIndex >= total) { - return 0; - } - return nextIndex; -}; - type UseList = { items: Array; selectedIndex: number; @@ -155,7 +135,7 @@ export const useDeprecatedList = ({ switch (event.code) { case "ArrowUp": case "ArrowDown": { - const nextIndex = deprecatedFindNextListIndex( + const nextIndex = findNextListItemIndex( selectedIndex, items.length, event.code === "ArrowUp" ? "previous" : "next" diff --git a/packages/design-system/src/components/component-card.stories.tsx b/packages/design-system/src/components/component-card.stories.tsx index b56916cb6b..be184eacd1 100644 --- a/packages/design-system/src/components/component-card.stories.tsx +++ b/packages/design-system/src/components/component-card.stories.tsx @@ -22,7 +22,7 @@ export const Demo = () => { } label="Box" - state="focus" + state="selected" tabIndex={1} /> ; export const ComponentCard = forwardRef( diff --git a/packages/design-system/src/components/primitives/list.tsx b/packages/design-system/src/components/primitives/list.tsx index 509377f505..f0d965bb51 100644 --- a/packages/design-system/src/components/primitives/list.tsx +++ b/packages/design-system/src/components/primitives/list.tsx @@ -63,3 +63,24 @@ export const ListItem = ({ }; ListItem.displayName = "ListItem"; + +export const findNextListItemIndex = ( + currentIndex: number, + total: number, + direction: "next" | "previous" +) => { + const nextIndex = + direction === "next" + ? currentIndex + 1 + : direction === "previous" + ? currentIndex - 1 + : currentIndex; + + if (nextIndex < 0) { + return total - 1; + } + if (nextIndex >= total) { + return 0; + } + return nextIndex; +}; diff --git a/packages/design-system/src/components/search-field.tsx b/packages/design-system/src/components/search-field.tsx index 0cf71672b8..8b4d61fcec 100644 --- a/packages/design-system/src/components/search-field.tsx +++ b/packages/design-system/src/components/search-field.tsx @@ -5,6 +5,8 @@ import { useRef, useState, useEffect, + type ChangeEventHandler, + type KeyboardEventHandler, } from "react"; import { CrossCircledFilledIcon, @@ -13,7 +15,8 @@ import { import { styled } from "../stitches.config"; import { theme } from "../stitches.config"; import { InputField } from "./input-field"; -import { IconButton } from "./icon-button"; +import { SmallIconButton } from "./small-icon-button"; +import { Flex } from "./flex"; const SearchIcon = styled(MagnifyingGlassIcon, { // need to center icon vertically @@ -22,8 +25,7 @@ const SearchIcon = styled(MagnifyingGlassIcon, { padding: theme.spacing[3], }); -const AbortButton = styled(IconButton, { - marginRight: theme.spacing[3], +const AbortButton = styled(SmallIconButton, { variants: { hidden: { false: { visibility: "hidden" }, @@ -48,6 +50,10 @@ const SearchFieldBase: ForwardRefRenderFunction< useEffect(() => { setValue(String(propsValue)); }, [propsValue]); + const handleCancel = () => { + setValue(""); + onCancel?.(); + }; return ( } suffix={ - + + } onChange={(event) => { setValue(event.target.value); onChange?.(event); }} onKeyDown={(event) => { - // Make sure we clear the search on esc and preserve the default browser behavior if (event.key === "Escape" && value.length !== 0) { - event.stopPropagation(); - return; + handleCancel(); } onKeyDown?.(event); }} @@ -90,3 +92,46 @@ const SearchFieldBase: ForwardRefRenderFunction< }; export const SearchField = forwardRef(SearchFieldBase); + +type UseSearchFieldKeys = { + onMove: (event: { direction: "next" | "previous" | "current" }) => void; + onChange?: ComponentProps["onChange"]; + onCancel?: ComponentProps["onCancel"]; +}; + +export const useSearchFieldKeys = ({ + onMove, + onChange, + onCancel, +}: UseSearchFieldKeys) => { + const [search, setSearch] = useState(""); + const handleKeyDown: KeyboardEventHandler = ({ code }) => { + const keyMap = { + ArrowUp: "previous", + ArrowDown: "next", + Enter: "current", + } as const; + const direction = keyMap[code as keyof typeof keyMap]; + if (direction !== undefined) { + onMove({ direction }); + } + }; + + const handleChange: ChangeEventHandler = (event) => { + const { value } = event.currentTarget; + setSearch(value.trim()); + onChange?.(event); + }; + + const handleCancel = () => { + setSearch(""); + onCancel?.(); + }; + + return { + value: search, + onCancel: handleCancel, + onChange: handleChange, + onKeyDown: handleKeyDown, + }; +}; diff --git a/packages/design-system/src/index.ts b/packages/design-system/src/index.ts index 1708941403..32abdb9918 100644 --- a/packages/design-system/src/index.ts +++ b/packages/design-system/src/index.ts @@ -53,7 +53,7 @@ export { AccessibleIcon } from "@radix-ui/react-accessible-icon"; export * from "./components/toggle-group"; export * from "./components/progress-radial"; export * from "./components/progress"; -export { SearchField } from "./components/search-field"; +export { SearchField, useSearchFieldKeys } from "./components/search-field"; export { Tabs, TabsContent, TabsList, TabsTrigger } from "@radix-ui/react-tabs"; export { Card } from "./components/card"; export * from "./components/tooltip"; diff --git a/packages/sdk-components-react/src/blockquote.ws.ts b/packages/sdk-components-react/src/blockquote.ws.ts index f229febee9..75f344528e 100644 --- a/packages/sdk-components-react/src/blockquote.ws.ts +++ b/packages/sdk-components-react/src/blockquote.ws.ts @@ -62,7 +62,6 @@ const presetStyle = { export const meta: WsComponentMeta = { category: "text", type: "container", - label: "Blockquote", description: "Use to style a quote from an external source like an article or book.", icon: BlockquoteIcon, diff --git a/packages/sdk-components-react/src/body.ws.ts b/packages/sdk-components-react/src/body.ws.ts index 0e706cc8bc..a1e0b324f6 100644 --- a/packages/sdk-components-react/src/body.ws.ts +++ b/packages/sdk-components-react/src/body.ws.ts @@ -25,7 +25,6 @@ const presetStyle = { export const meta: WsComponentMeta = { type: "container", - label: "Body", icon: BodyIcon, states: defaultStates, presetStyle, diff --git a/packages/sdk-components-react/src/box.ws.ts b/packages/sdk-components-react/src/box.ws.ts index e3c9981136..967ab17bca 100644 --- a/packages/sdk-components-react/src/box.ws.ts +++ b/packages/sdk-components-react/src/box.ws.ts @@ -39,7 +39,6 @@ const presetStyle = { export const meta: WsComponentMeta = { category: "general", type: "container", - label: "Box", description: "A container for content. By default this is a Div, but the tag can be changed in settings.", icon: BoxIcon, diff --git a/packages/sdk-components-react/src/button.ws.ts b/packages/sdk-components-react/src/button.ws.ts index 1f6d2ca8f8..5a5dddc66a 100644 --- a/packages/sdk-components-react/src/button.ws.ts +++ b/packages/sdk-components-react/src/button.ws.ts @@ -17,7 +17,6 @@ export const meta: WsComponentMeta = { category: "forms", type: "container", invalidAncestors: ["Button", "Link"], - label: "Button", description: "Use a button to submit forms or trigger actions within a page. Do not use a button to navigate users to another resource or another page - that’s what a link is used for.", icon: ButtonElementIcon, diff --git a/packages/sdk-components-react/src/checkbox.ws.ts b/packages/sdk-components-react/src/checkbox.ws.ts index 77a43c58f7..5b83b9b13f 100644 --- a/packages/sdk-components-react/src/checkbox.ws.ts +++ b/packages/sdk-components-react/src/checkbox.ws.ts @@ -23,7 +23,6 @@ export const meta: WsComponentMeta = { category: "forms", invalidAncestors: ["Button", "Link"], type: "control", - label: "Checkbox", description: "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.", icon: CheckboxCheckedIcon, diff --git a/packages/sdk-components-react/src/code-text.ws.ts b/packages/sdk-components-react/src/code-text.ws.ts index 61002d110e..1d4adfec4f 100644 --- a/packages/sdk-components-react/src/code-text.ws.ts +++ b/packages/sdk-components-react/src/code-text.ws.ts @@ -42,7 +42,6 @@ const presetStyle = { export const meta: WsComponentMeta = { category: "general", type: "embed", - label: "Code Text", description: "Use this component when you want to display code as text on the page.", icon: CodeTextIcon, diff --git a/packages/sdk-components-react/src/content-embed.ws.ts b/packages/sdk-components-react/src/content-embed.ws.ts index f0b6f4b35b..5f6e2a4e62 100644 --- a/packages/sdk-components-react/src/content-embed.ws.ts +++ b/packages/sdk-components-react/src/content-embed.ws.ts @@ -47,7 +47,6 @@ const descendant = (label: string, tag: string): WsEmbedTemplate[number] => { export const meta: WsComponentMeta = { category: "data", type: "control", - label: "Content Embed", description: "Content Embed allows styling of HTML, which can be provided via the Code property statically or loaded dynamically from any Resource, for example, from a CMS.", icon: ContentEmbedIcon, diff --git a/packages/sdk-components-react/src/form.ws.ts b/packages/sdk-components-react/src/form.ws.ts index f4649a10af..61ff28ec8a 100644 --- a/packages/sdk-components-react/src/form.ws.ts +++ b/packages/sdk-components-react/src/form.ws.ts @@ -20,7 +20,6 @@ export const meta: WsComponentMeta = { category: "forms", type: "container", invalidAncestors: ["Form", "Button", "Link"], - label: "Form", description: "Create filters, surveys, searches and more.", icon: FormIcon, states: defaultStates, diff --git a/packages/sdk-components-react/src/fragment.ws.ts b/packages/sdk-components-react/src/fragment.ws.ts index 1f2d49f299..0ad61e8011 100644 --- a/packages/sdk-components-react/src/fragment.ws.ts +++ b/packages/sdk-components-react/src/fragment.ws.ts @@ -5,7 +5,6 @@ import type { export const meta: WsComponentMeta = { type: "container", - label: "Fragment", icon: "", stylable: false, }; diff --git a/packages/sdk-components-react/src/heading.ws.ts b/packages/sdk-components-react/src/heading.ws.ts index c6b2bd6e1a..be114a70ec 100644 --- a/packages/sdk-components-react/src/heading.ws.ts +++ b/packages/sdk-components-react/src/heading.ws.ts @@ -24,7 +24,6 @@ const presetStyle = { export const meta: WsComponentMeta = { category: "text", type: "container", - label: "Heading", description: "Use HTML headings to structure and organize content. Use the Tag property in settings to change the heading level (h1-h6).", icon: HeadingIcon, diff --git a/packages/sdk-components-react/src/image.ws.ts b/packages/sdk-components-react/src/image.ws.ts index 343397bcde..8d287e9e2f 100644 --- a/packages/sdk-components-react/src/image.ws.ts +++ b/packages/sdk-components-react/src/image.ws.ts @@ -37,7 +37,6 @@ const presetStyle = { export const meta: WsComponentMeta = { category: "media", type: "embed", - label: "Image", description: "Add an image asset to the page. Webstudio automatically converts images to WebP or AVIF format and makes them responsive for best performance.", icon: ImageIcon, diff --git a/packages/sdk-components-react/src/link.ws.ts b/packages/sdk-components-react/src/link.ws.ts index 98bf68dbc3..2185afe216 100644 --- a/packages/sdk-components-react/src/link.ws.ts +++ b/packages/sdk-components-react/src/link.ws.ts @@ -26,7 +26,6 @@ const presetStyle = { export const meta: WsComponentMeta = { category: "general", type: "container", - label: "Link", description: "Use a link to send your users to another page, section, or resource. Configure links in the Settings panel.", icon: LinkIcon, diff --git a/packages/sdk-components-react/src/list-item.ws.ts b/packages/sdk-components-react/src/list-item.ws.ts index 797e511bfc..cee9b4fed9 100644 --- a/packages/sdk-components-react/src/list-item.ws.ts +++ b/packages/sdk-components-react/src/list-item.ws.ts @@ -17,7 +17,6 @@ export const meta: WsComponentMeta = { category: "general", type: "container", requiredAncestors: ["List"], - label: "List Item", description: "Adds a new item to an existing list.", icon: ListItemIcon, states: defaultStates, diff --git a/packages/sdk-components-react/src/list.ws.ts b/packages/sdk-components-react/src/list.ws.ts index 7fa1859f9d..a22057e4d8 100644 --- a/packages/sdk-components-react/src/list.ws.ts +++ b/packages/sdk-components-react/src/list.ws.ts @@ -45,7 +45,6 @@ const presetStyle = { export const meta: WsComponentMeta = { category: "general", type: "container", - label: "List", description: "Groups content, like links in a menu or steps in a recipe.", icon: ListIcon, states: defaultStates, diff --git a/packages/sdk-components-react/src/markdown-embed.ws.ts b/packages/sdk-components-react/src/markdown-embed.ws.ts index 0eeb4c7ac2..41e50455b2 100644 --- a/packages/sdk-components-react/src/markdown-embed.ws.ts +++ b/packages/sdk-components-react/src/markdown-embed.ws.ts @@ -59,7 +59,6 @@ const descendant = (label: string, tag: string): WsEmbedTemplate[number] => { export const meta: WsComponentMeta = { category: "data", type: "embed", - label: "Markdown Embed", description: "Used to add markdown code to the page", icon: MarkdownEmbedIcon, presetStyle: { diff --git a/packages/sdk-components-react/src/option.ws.ts b/packages/sdk-components-react/src/option.ws.ts index 67fec3268e..76530607b9 100644 --- a/packages/sdk-components-react/src/option.ws.ts +++ b/packages/sdk-components-react/src/option.ws.ts @@ -29,7 +29,6 @@ export const meta: WsComponentMeta = { // @todo: requiredAncestors should be ["Select", "Optgroup", "Datalist"] but that gives unreadable error when adding Select onto Canvas requiredAncestors: ["Select"], type: "control", - label: "Option", description: "An item within a drop-down menu that users can select as their chosen value.", icon: ItemIcon, diff --git a/packages/sdk-components-react/src/paragraph.ws.ts b/packages/sdk-components-react/src/paragraph.ws.ts index 7a46992431..ced5424e66 100644 --- a/packages/sdk-components-react/src/paragraph.ws.ts +++ b/packages/sdk-components-react/src/paragraph.ws.ts @@ -16,7 +16,6 @@ const presetStyle = { export const meta: WsComponentMeta = { category: "text", type: "container", - label: "Paragraph", description: "A container for multi-line text.", icon: TextAlignLeftIcon, invalidAncestors: ["Paragraph"], diff --git a/packages/sdk-components-react/src/select.ws.ts b/packages/sdk-components-react/src/select.ws.ts index 3dde3e3ba7..d5e1b59db2 100644 --- a/packages/sdk-components-react/src/select.ws.ts +++ b/packages/sdk-components-react/src/select.ws.ts @@ -23,7 +23,6 @@ export const meta: WsComponentMeta = { category: "forms", invalidAncestors: ["Button", "Link"], type: "container", - label: "Select", description: "A drop-down menu for users to select a single option from a predefined list.", icon: SelectIcon, diff --git a/packages/sdk-components-react/src/separator.ws.ts b/packages/sdk-components-react/src/separator.ws.ts index c4cace23a4..49c152c94b 100644 --- a/packages/sdk-components-react/src/separator.ws.ts +++ b/packages/sdk-components-react/src/separator.ws.ts @@ -43,7 +43,6 @@ const presetStyle = { export const meta: WsComponentMeta = { category: "general", type: "embed", - label: "Separator", description: "Used to visually divide sections of content, helping to improve readability and organization within a webpage.", icon: DashIcon, diff --git a/packages/sdk-components-react/src/slot.ws.ts b/packages/sdk-components-react/src/slot.ws.ts index c2e83e4f4b..6f7e89e05d 100644 --- a/packages/sdk-components-react/src/slot.ws.ts +++ b/packages/sdk-components-react/src/slot.ws.ts @@ -7,7 +7,6 @@ import type { export const meta: WsComponentMeta = { category: "general", type: "container", - label: "Slot", description: "Slot is a container for content that you want to reference across the project. Changes made to a Slot's children will be reflected in all other instances of that Slot.", icon: SlotComponentIcon, diff --git a/packages/sdk-components-react/src/text.ws.ts b/packages/sdk-components-react/src/text.ws.ts index 0bf2b18bc5..3e14538f60 100644 --- a/packages/sdk-components-react/src/text.ws.ts +++ b/packages/sdk-components-react/src/text.ws.ts @@ -22,7 +22,6 @@ const presetStyle = { export const meta: WsComponentMeta = { category: "text", type: "container", - label: "Text", description: "A generic container for any text content that is not a heading or a link.", icon: TextIcon, diff --git a/packages/sdk-components-react/src/vimeo.ws.ts b/packages/sdk-components-react/src/vimeo.ws.ts index fe5f88c2b7..bf7e4011f8 100644 --- a/packages/sdk-components-react/src/vimeo.ws.ts +++ b/packages/sdk-components-react/src/vimeo.ws.ts @@ -17,7 +17,6 @@ const presetStyle = { export const meta: WsComponentMeta = { category: "media", type: "container", - label: "Vimeo", description: "Add a video to your page that is hosted on Vimeo. Paste a Vimeo URL and configure the video in the Settings tab.", order: 1, diff --git a/packages/sdk-components-react/src/xml-node.ws.ts b/packages/sdk-components-react/src/xml-node.ws.ts index 34114115ad..299ff13c09 100644 --- a/packages/sdk-components-react/src/xml-node.ws.ts +++ b/packages/sdk-components-react/src/xml-node.ws.ts @@ -13,7 +13,7 @@ export const meta: WsComponentMeta = { type: "container", icon: XmlIcon, stylable: false, - description: "Xml Node", + description: "XML Node", }; export const propsMeta: WsComponentPropsMeta = {