diff --git a/.changeset/eighty-peaches-reply.md b/.changeset/eighty-peaches-reply.md new file mode 100644 index 000000000..92330d748 --- /dev/null +++ b/.changeset/eighty-peaches-reply.md @@ -0,0 +1,62 @@ +--- +"@wpmudev/sui-navigation-wpmudev": major +"@wpmudev/sui-segmented-control": major +"@wpmudev/sui-dashboard-widget": major +"@wpmudev/sui-rich-text-editor": major +"@wpmudev/sui-advanced-banner": major +"@wpmudev/sui-editor-toolbar": major +"@wpmudev/sui-setting-block": major +"@wpmudev/sui-upsell-notice": major +"@wpmudev/sui-alert-banner": major +"@wpmudev/sui-code-snippet": major +"@wpmudev/sui-color-picker": major +"@wpmudev/sui-config-table": major +"@wpmudev/sui-notification": major +"@wpmudev/sui-progress-bar": major +"@wpmudev/sui-setup-banner": major +"@wpmudev/sui-code-editor": major +"@wpmudev/sui-date-picker": major +"@wpmudev/sui-empty-state": major +"@wpmudev/sui-integration": major +"@wpmudev/sui-page-header": major +"@wpmudev/sui-summary-box": major +"@wpmudev/sui-field-list": major +"@wpmudev/sui-form-field": major +"@wpmudev/sui-navigation": major +"@wpmudev/sui-pagination": major +"@wpmudev/sui-accordion": major +"@wpmudev/sui-basic-box": major +"@wpmudev/sui-recipient": major +"@wpmudev/sui-tree-view": major +"@wpmudev/sui-checkbox": major +"@wpmudev/sui-dropdown": major +"@wpmudev/sui-selector": major +"@wpmudev/sui-skeleton": major +"@wpmudev/sui-uploader": major +"@wpmudev/sui-css": major +"@wpmudev/sui-builder": major +"@wpmudev/sui-popover": major +"@wpmudev/sui-sidebar": major +"@wpmudev/sui-spinner": major +"@wpmudev/sui-tooltip": major +"@wpmudev/sui-avatar": major +"@wpmudev/sui-drawer": major +"@wpmudev/sui-footer": major +"@wpmudev/sui-search": major +"@wpmudev/sui-select": major +"@wpmudev/sui-toggle": major +"@wpmudev/sui-upsell": major +"@wpmudev/sui-input": major +"@wpmudev/sui-modal": major +"@wpmudev/sui-radio": major +"@wpmudev/sui-score": major +"@wpmudev/sui-table": major +"@wpmudev/sui-grid": major +"@wpmudev/sui-icon": major +"@wpmudev/sui-link": major +"@wpmudev/sui-tabs": major +"@wpmudev/sui-box": major +"@wpmudev/sui-tag": major +--- + +Added missing ids to components diff --git a/packages/assets/css/src/scss/_utils/_tokens.scss b/packages/assets/css/src/scss/_utils/_tokens.scss index a7da68e17..091cd85c6 100644 --- a/packages/assets/css/src/scss/_utils/_tokens.scss +++ b/packages/assets/css/src/scss/_utils/_tokens.scss @@ -1,6 +1,6 @@ // Do not edit directly -// Generated on Mon, 03 Nov 2025 10:48:23 GMT +// Generated on Tue, 16 Dec 2025 09:32:11 GMT $accordion-border-radius-sm: 10px; $advanced-banner-background: linear-gradient(90deg, #222 0%, #383323 48.96%, #514524 100%); diff --git a/packages/ui/accordion/src/accordion-item.tsx b/packages/ui/accordion/src/accordion-item.tsx index 0870c0b1b..e579b0e06 100644 --- a/packages/ui/accordion/src/accordion-item.tsx +++ b/packages/ui/accordion/src/accordion-item.tsx @@ -17,6 +17,7 @@ import { AccordionItemProps } from "./accordion.types" // The AccordionItem component is defined as a functional component using React.FC. const AccordionItem: React.FC = ({ + id, title = "{title}", description, children, @@ -40,7 +41,8 @@ const AccordionItem: React.FC = ({ const [isPressed, setIsPressed] = useState(false) // Custom hook to generate a unique ID for the accordion item. - const uniqueId = useId() + const generatedId = useId() + const uniqueId = id || `sui_accordion_${generatedId}` // Get the "toggle" method and "isCurrentlyExpanded" state from the current AccordionItem const { toggle, isCurrentlyExpanded } = useAccordion({ @@ -50,8 +52,8 @@ const AccordionItem: React.FC = ({ const { spacing } = useContext(AccordionContext) // IDs for the accordion and its panel to manage accessibility. - const accordionId = `sui-accordion-${uniqueId}` - const accordionPanelId = `sui-accordion-panel-${uniqueId}` + const accordionId = uniqueId + const accordionPanelId = `${uniqueId}_panel` const onMouseDownCapture = () => { setIsPressed(true) @@ -100,6 +102,7 @@ const AccordionItem: React.FC = ({ // Render the AccordionItem component with proper accessibility attributes. return (
= ({ )} {/* Content of the accordion item's header */} -
+
{(!!hasCheckbox || !!icon) && ( -
+
{hasCheckbox && ( = ({ {!!icon && icon}
)} -
+

{title}

{!isEmpty(description ?? "") &&

{description}

}
{/* Icon component to display a chevron icon */} -
+
@@ -188,7 +203,12 @@ const AccordionItem: React.FC = ({ })} data-testid="accordion-item-panel" > -
{children}
+
+ {children} +
) diff --git a/packages/ui/accordion/src/accordion.tsx b/packages/ui/accordion/src/accordion.tsx index 21d876b10..3a834c119 100644 --- a/packages/ui/accordion/src/accordion.tsx +++ b/packages/ui/accordion/src/accordion.tsx @@ -1,5 +1,5 @@ // Import necessary modules and types -import React, { useState } from "react" +import React, { useState, useId } from "react" import { _renderHTMLPropsSafely, generateCN, isEmpty } from "@wpmudev/sui-utils" import { AccordionProps } from "./accordion.types" @@ -8,6 +8,7 @@ import { useDefaultChildren, useStyles } from "@wpmudev/sui-hooks" // Define the Accordion component as a functional component (React.FC) const Accordion: React.FC = ({ + id, className, state = "default", noBorderRadius = false, @@ -19,6 +20,8 @@ const Accordion: React.FC = ({ _htmlProps = {}, _style = {}, }) => { + const generatedId = useId() + const accordionId = id || `sui_accordion_${generatedId}` const [expandState, setExpandState] = useState>({}) // Default children content @@ -48,7 +51,11 @@ const Accordion: React.FC = ({ isFlushed, }} > -
+
{children}
diff --git a/packages/ui/accordion/src/accordion.types.ts b/packages/ui/accordion/src/accordion.types.ts index 6508eac27..71e7d211a 100644 --- a/packages/ui/accordion/src/accordion.types.ts +++ b/packages/ui/accordion/src/accordion.types.ts @@ -8,6 +8,7 @@ import { SuiHTMLAttributes, SuiStyleType } from "@wpmudev/sui-utils" interface AccordionProps extends SuiHTMLAttributes>, SuiStyleType { + id?: string // Optional custom ID for the accordion item. /** Additional CSS class name for styling the accordion component. */ className?: string /** Remove border-radius when true */ @@ -36,6 +37,7 @@ type AccordionCheckboxProps = interface AccordionItemBaseProps extends SuiHTMLAttributes>, SuiStyleType { + id?: string // Optional custom ID for the accordion item. title?: string // The title of the accordion item. description?: string // The description of the accordion item. children?: React.ReactNode // The content of the accordion item, which can be any valid React node. diff --git a/packages/ui/advanced-banner/src/advanced-banner.tsx b/packages/ui/advanced-banner/src/advanced-banner.tsx index 980bbcc3b..5f042f25f 100644 --- a/packages/ui/advanced-banner/src/advanced-banner.tsx +++ b/packages/ui/advanced-banner/src/advanced-banner.tsx @@ -1,4 +1,4 @@ -import React from "react" +import React, { useId } from "react" import { _renderHTMLPropsSafely, generateCN, isEmpty } from "@wpmudev/sui-utils" import { Button, ButtonProps } from "@wpmudev/sui-button" @@ -7,6 +7,7 @@ import { useStyles } from "@wpmudev/sui-hooks" // Build "advanced-banner" component const AdvancedBanner: React.FC = ({ + id, variation = "plugin", imageUrl = "https://placehold.co/100", title = "Banner Title", @@ -23,6 +24,8 @@ const AdvancedBanner: React.FC = ({ _htmlProps = {}, _style = {}, }) => { + const generatedId = useId() + const advancedBannerId = id || `sui_advanced_banner_${generatedId}` const { suiInlineClassname } = useStyles(_style, className) // Define class name @@ -43,6 +46,7 @@ const AdvancedBanner: React.FC = ({ return (
>, SuiStyleType { + /** + * Unique identifier for the advanced banner. + */ + id?: string /** * Sets the headline text */ diff --git a/packages/ui/alert-banner/src/alert-banner.tsx b/packages/ui/alert-banner/src/alert-banner.tsx index 6b821bf29..347605717 100644 --- a/packages/ui/alert-banner/src/alert-banner.tsx +++ b/packages/ui/alert-banner/src/alert-banner.tsx @@ -1,4 +1,4 @@ -import React, { useState, useCallback } from "react" +import React, { useId, useState, useCallback } from "react" import { _renderHTMLPropsSafely, generateCN, isEmpty } from "@wpmudev/sui-utils" import { Button, ButtonProps } from "@wpmudev/sui-button" import Icons from "@wpmudev/sui-icons" @@ -7,6 +7,7 @@ import { useDefaultChildren, useStyles } from "@wpmudev/sui-hooks" import { AlertBannerProps } from "./alert-banner.types" const AlertBanner: React.FC = ({ + id, children, variation = "informative", actions, @@ -18,6 +19,8 @@ const AlertBanner: React.FC = ({ _style = {}, _htmlProps, }) => { + const generatedId = useId() + const alertBannerId = id || `sui_alert_banner_${generatedId}` // State to control the visibility of the alert banner const [isVisible, setIsVisible] = useState(true) @@ -85,6 +88,7 @@ const AlertBanner: React.FC = ({ return (
> { + /** + * Unique identifier for the alert banner. + */ + id?: string /** * Alert Banner content */ diff --git a/packages/ui/avatar/src/avatar.tsx b/packages/ui/avatar/src/avatar.tsx index 834d96400..d082ad90e 100644 --- a/packages/ui/avatar/src/avatar.tsx +++ b/packages/ui/avatar/src/avatar.tsx @@ -1,4 +1,4 @@ -import React from "react" +import React, { useId } from "react" import { _renderHTMLPropsSafely, generateCN, @@ -16,6 +16,7 @@ import { useStyles } from "@wpmudev/sui-hooks" // Build "avatar" component const Avatar: React.FC = ({ + id, image, status = "none", isSmall = false, @@ -25,6 +26,9 @@ const Avatar: React.FC = ({ _style = {}, onClick, }) => { + const generatedId = useId() + const avatarId = id || `sui_avatar_${generatedId}` + // Define image object const imageObj = Object.assign( { @@ -51,6 +55,7 @@ const Avatar: React.FC = ({ ) const attributes = { + id: avatarId, className: classNames, ..._renderHTMLPropsSafely(_htmlProps), "data-testid": "avatar", @@ -59,9 +64,17 @@ const Avatar: React.FC = ({ return ( - {hasImage && } - {!hasImage && } - {hasStatus && status !== "none" && } + {hasImage && ( + + )} + {!hasImage && } + {hasStatus && status !== "none" && ( + + )} ) } diff --git a/packages/ui/avatar/src/avatar.types.ts b/packages/ui/avatar/src/avatar.types.ts index 35ebba1aa..22b057fe7 100644 --- a/packages/ui/avatar/src/avatar.types.ts +++ b/packages/ui/avatar/src/avatar.types.ts @@ -9,6 +9,10 @@ import { IconsNamesType } from "@wpmudev/sui-icons" interface AvatarProps extends SuiHTMLAttributes>, SuiStyleType { + /** + * Unique identifier for the avatar. + */ + id?: string /** * The image source for the avatar. */ diff --git a/packages/ui/avatar/src/elements/icon-avatar.tsx b/packages/ui/avatar/src/elements/icon-avatar.tsx index 755c23bf2..32fe98fc0 100644 --- a/packages/ui/avatar/src/elements/icon-avatar.tsx +++ b/packages/ui/avatar/src/elements/icon-avatar.tsx @@ -1,10 +1,10 @@ import React, { Fragment } from "react" import Icons, { IconsNamesType, User, UserAlt } from "@wpmudev/sui-icons" // Build "icon avatar" element -const Icon = ({ iconName }: { iconName: IconsNamesType }) => { +const Icon = ({ id, iconName }: { id?: string; iconName: IconsNamesType }) => { const IconTag = Icons?.[iconName as IconsNamesType] return ( -