From 5c779ce2243f04c3bf54a8bc6a4b393d4b1cd539 Mon Sep 17 00:00:00 2001 From: Seydi Charyyev Date: Thu, 5 Mar 2026 10:21:33 +0500 Subject: [PATCH 1/2] fix: ensure unique control id attributes across multiple Controls blocks on docs page --- code/addons/docs/src/blocks/blocks/Controls.tsx | 2 ++ .../src/blocks/components/ArgsTable/ArgControl.tsx | 13 +++++++++++-- .../docs/src/blocks/components/ArgsTable/ArgRow.tsx | 1 + .../src/blocks/components/ArgsTable/ArgsTable.tsx | 4 +++- code/addons/docs/src/blocks/controls/Boolean.tsx | 5 +++-- code/addons/docs/src/blocks/controls/Color.tsx | 3 ++- code/addons/docs/src/blocks/controls/Date.tsx | 12 ++++++++++-- code/addons/docs/src/blocks/controls/Files.tsx | 3 ++- code/addons/docs/src/blocks/controls/Number.tsx | 5 +++-- code/addons/docs/src/blocks/controls/Object.tsx | 6 +++--- code/addons/docs/src/blocks/controls/Range.tsx | 3 ++- code/addons/docs/src/blocks/controls/Text.tsx | 5 +++-- .../addons/docs/src/blocks/controls/helpers.test.ts | 8 ++++++++ code/addons/docs/src/blocks/controls/helpers.ts | 10 ++++++++-- .../docs/src/blocks/controls/options/Checkbox.tsx | 3 ++- .../docs/src/blocks/controls/options/Radio.tsx | 3 ++- .../docs/src/blocks/controls/options/Select.tsx | 8 ++++---- code/addons/docs/src/blocks/controls/types.ts | 1 + 18 files changed, 70 insertions(+), 25 deletions(-) diff --git a/code/addons/docs/src/blocks/blocks/Controls.tsx b/code/addons/docs/src/blocks/blocks/Controls.tsx index 5f7e9eee69fa..2e614f9f881c 100644 --- a/code/addons/docs/src/blocks/blocks/Controls.tsx +++ b/code/addons/docs/src/blocks/blocks/Controls.tsx @@ -69,6 +69,7 @@ export const Controls: FC = (props) => { } return ( = (props) => { globals={globals} updateArgs={updateArgs} resetArgs={resetArgs} + storyId={story.id} /> ); }; diff --git a/code/addons/docs/src/blocks/components/ArgsTable/ArgControl.tsx b/code/addons/docs/src/blocks/components/ArgsTable/ArgControl.tsx index dd6f7a997544..97d3013b4bd8 100644 --- a/code/addons/docs/src/blocks/components/ArgsTable/ArgControl.tsx +++ b/code/addons/docs/src/blocks/components/ArgsTable/ArgControl.tsx @@ -21,6 +21,7 @@ export interface ArgControlProps { arg: any; updateArgs: (args: Args) => void; isHovered: boolean; + storyId?: string; } const Controls: Record> = { @@ -43,7 +44,7 @@ const Controls: Record> = { const NoControl = () => <>-; -export const ArgControl: FC = ({ row, arg, updateArgs, isHovered }) => { +export const ArgControl: FC = ({ row, arg, updateArgs, isHovered, storyId }) => { const { key, control } = row; const [isFocused, setFocused] = useState(false); @@ -84,7 +85,15 @@ export const ArgControl: FC = ({ row, arg, updateArgs, isHovere } // row.name is a display name and not a suitable DOM input id or name - i might contain whitespace etc. // row.key is a hash key and therefore a much safer choice - const props = { name: key, argType: row, value: boxedValue.value, onChange, onBlur, onFocus }; + const props = { + name: key, + storyId, + argType: row, + value: boxedValue.value, + onChange, + onBlur, + onFocus, + }; const Control = Controls[control.type] || NoControl; return ; }; diff --git a/code/addons/docs/src/blocks/components/ArgsTable/ArgRow.tsx b/code/addons/docs/src/blocks/components/ArgsTable/ArgRow.tsx index c6ccb0099ae2..83ad20c476ac 100644 --- a/code/addons/docs/src/blocks/components/ArgsTable/ArgRow.tsx +++ b/code/addons/docs/src/blocks/components/ArgsTable/ArgRow.tsx @@ -21,6 +21,7 @@ interface ArgRowProps { compact?: boolean; expandable?: boolean; initialExpandedArgs?: boolean; + storyId?: string; } const Name = styled.span({ fontWeight: 'bold' }); diff --git a/code/addons/docs/src/blocks/components/ArgsTable/ArgsTable.tsx b/code/addons/docs/src/blocks/components/ArgsTable/ArgsTable.tsx index 874edbc2ccc2..1f1dfc4394a5 100644 --- a/code/addons/docs/src/blocks/components/ArgsTable/ArgsTable.tsx +++ b/code/addons/docs/src/blocks/components/ArgsTable/ArgsTable.tsx @@ -204,6 +204,7 @@ export interface ArgsTableOptionProps { initialExpandedArgs?: boolean; isLoading?: boolean; sort?: SortType; + storyId?: string; } interface ArgsTableDataProps { rows: ArgTypes; @@ -327,6 +328,7 @@ export const ArgsTable: FC = (props) => { initialExpandedArgs, sort = 'none', isLoading, + storyId, } = props; if ('error' in props) { @@ -380,7 +382,7 @@ export const ArgsTable: FC = (props) => { } const expandable = Object.keys(groups.sections).length > 0; - const common = { updateArgs, compact, inAddonPanel, initialExpandedArgs }; + const common = { updateArgs, compact, inAddonPanel, initialExpandedArgs, storyId }; return ( diff --git a/code/addons/docs/src/blocks/controls/Boolean.tsx b/code/addons/docs/src/blocks/controls/Boolean.tsx index 584ed2a6d0e0..b94b9fe500ee 100644 --- a/code/addons/docs/src/blocks/controls/Boolean.tsx +++ b/code/addons/docs/src/blocks/controls/Boolean.tsx @@ -116,6 +116,7 @@ export type BooleanProps = ControlProps & BooleanConfig; */ export const BooleanControl: FC = ({ name, + storyId, value, onChange, onBlur, @@ -130,7 +131,7 @@ export const BooleanControl: FC = ({ ariaLabel={false} variant="outline" size="medium" - id={getControlSetterButtonId(name)} + id={getControlSetterButtonId(name, storyId)} onClick={onSetFalse} disabled={readonly} > @@ -138,7 +139,7 @@ export const BooleanControl: FC = ({ ); } - const controlId = getControlId(name); + const controlId = getControlId(name, storyId); const parsedValue = typeof value === 'string' ? parse(value) : value; diff --git a/code/addons/docs/src/blocks/controls/Color.tsx b/code/addons/docs/src/blocks/controls/Color.tsx index 0758f7b8611c..2f923c0aeda3 100644 --- a/code/addons/docs/src/blocks/controls/Color.tsx +++ b/code/addons/docs/src/blocks/controls/Color.tsx @@ -360,6 +360,7 @@ const usePresets = ( export type ColorControlProps = ControlProps & ColorConfig; export const ColorControl: FC = ({ name, + storyId, value: initialValue, onChange, onFocus, @@ -377,7 +378,7 @@ export const ColorControl: FC = ({ const Picker = ColorPicker[colorSpace]; const readOnly = !!argType?.table?.readonly; - const controlId = getControlId(name); + const controlId = getControlId(name, storyId); return ( diff --git a/code/addons/docs/src/blocks/controls/Date.tsx b/code/addons/docs/src/blocks/controls/Date.tsx index 3568cf940f5c..55fe0063bb71 100644 --- a/code/addons/docs/src/blocks/controls/Date.tsx +++ b/code/addons/docs/src/blocks/controls/Date.tsx @@ -66,7 +66,15 @@ const FlexSpaced = styled.fieldset({ }); export type DateProps = ControlProps & DateConfig; -export const DateControl: FC = ({ name, value, onChange, onFocus, onBlur, argType }) => { +export const DateControl: FC = ({ + name, + storyId, + value, + onChange, + onFocus, + onBlur, + argType, +}) => { const [valid, setValid] = useState(true); const dateRef = useRef(); const timeRef = useRef(); @@ -114,7 +122,7 @@ export const DateControl: FC = ({ name, value, onChange, onFocus, onB setValid(!!time); }; - const controlId = getControlId(name); + const controlId = getControlId(name, storyId); return ( diff --git a/code/addons/docs/src/blocks/controls/Files.tsx b/code/addons/docs/src/blocks/controls/Files.tsx index 1569790641da..85f2d839701a 100644 --- a/code/addons/docs/src/blocks/controls/Files.tsx +++ b/code/addons/docs/src/blocks/controls/Files.tsx @@ -40,6 +40,7 @@ function revokeOldUrls(urls: string[]) { export const FilesControl: FC = ({ onChange, name, + storyId, accept = 'image/*', value, argType, @@ -63,7 +64,7 @@ export const FilesControl: FC = ({ } }, [value, name]); - const controlId = getControlId(name); + const controlId = getControlId(name, storyId); return ( <> diff --git a/code/addons/docs/src/blocks/controls/Number.tsx b/code/addons/docs/src/blocks/controls/Number.tsx index 947a9f7afca7..a3f33db74de7 100644 --- a/code/addons/docs/src/blocks/controls/Number.tsx +++ b/code/addons/docs/src/blocks/controls/Number.tsx @@ -27,6 +27,7 @@ const FormInput = styled(Form.Input)(({ theme }) => ({ export const NumberControl: FC = ({ name, + storyId, value, onChange, min, @@ -102,7 +103,7 @@ export const NumberControl: FC = ({ ariaLabel={false} variant="outline" size="medium" - id={getControlSetterButtonId(name)} + id={getControlSetterButtonId(name, storyId)} onClick={onForceVisible} disabled={readonly} > @@ -115,7 +116,7 @@ export const NumberControl: FC = ({ ) => { export type ObjectProps = ControlProps & ObjectConfig; -export const ObjectControl: FC = ({ name, value, onChange, argType }) => { +export const ObjectControl: FC = ({ name, storyId, value, onChange, argType }) => { const theme = useTheme(); const data = useMemo(() => value && cloneDeep(value), [value]); const hasData = data !== null && data !== undefined; @@ -208,7 +208,7 @@ export const ObjectControl: FC = ({ name, value, onChange, argType