@@ -35,16 +35,32 @@ export type IconDefinitionWithSvgPathData = Required<Pick<IconDefinition, 'svgPa
3535 */
3636export type IconDefinitionWithSvgPath = Required < Pick < IconDefinition , 'svgPath' > > & IconDefinition ;
3737
38- /** When passing `icon` or `rhUiIcon` keys (nested form), `icon` is required at runtime. */
39- export interface CreateIconProps {
38+ /**
39+ * Props for {@link createIconBase} — nested icon definition(s). Used by generated icons and callers
40+ * that already structure data as `{ icon, rhUiIcon? }`.
41+ */
42+ export interface CreateIconBaseProps {
4043 name ?: string ;
41- icon ? : IconDefinition ;
44+ icon : IconDefinition ;
4245 rhUiIcon ?: IconDefinition | null ;
4346}
4447
4548/**
46- * @deprecated The previous `createIcon` accepted a flat {@link IconDefinition} with top-level
47- * `svgPath`. Pass {@link CreateIconProps} with a nested `icon` field instead.
49+ * @deprecated Use {@link CreateIconBaseProps} instead.
50+ */
51+ export type CreateIconProps = CreateIconBaseProps ;
52+
53+ /**
54+ * Props for {@link createIcon} — flat {@link IconDefinition} fields at the top level, optionally with
55+ * `rhUiIcon`, matching the pre–nested-config API.
56+ */
57+ export type CreateIconLegacyProps = IconDefinition & {
58+ rhUiIcon ?: IconDefinition | null ;
59+ } ;
60+
61+ /**
62+ * @deprecated The previous `createIcon` accepted only a flat {@link IconDefinition}. Use {@link createIcon}
63+ * for that shape, or {@link createIconBase} with nested `icon` / `rhUiIcon`.
4864 */
4965export type LegacyFlatIconDefinition = IconDefinition ;
5066
@@ -83,44 +99,6 @@ function normalizeIconDefinition(icon: IconDefinition): IconDefinitionWithSvgPat
8399 } ;
84100}
85101
86- /** True when the argument uses the nested `CreateIconProps` shape (`icon` and/or `rhUiIcon` keys). */
87- function isNestedCreateIconProps ( arg : object ) : arg is CreateIconProps {
88- return 'icon' in arg || 'rhUiIcon' in arg ;
89- }
90-
91- /** Props after resolving legacy `svgPath` and flat `createIcon` arguments. */
92- interface NormalizedCreateIconProps {
93- name ?: string ;
94- icon ?: IconDefinitionWithSvgPathData ;
95- rhUiIcon : IconDefinitionWithSvgPathData | null ;
96- }
97-
98- /**
99- * Coerces legacy flat or nested props into normalized {@link NormalizedCreateIconProps}.
100- * Nested input must include a non-null `icon` or throws.
101- */
102- function normalizeCreateIconArg ( arg : CreateIconProps | LegacyFlatIconDefinition ) : NormalizedCreateIconProps {
103- if ( isNestedCreateIconProps ( arg ) ) {
104- const p = arg as CreateIconProps ;
105- if ( p . icon == null ) {
106- const label = p . name != null ? ` (name: ${ String ( p . name ) } )` : '' ;
107- throw new Error (
108- `@patternfly/react-icons: createIcon requires an \`icon\` definition when using nested CreateIconProps${ label } .`
109- ) ;
110- }
111- return {
112- name : p . name ,
113- icon : normalizeIconDefinition ( p . icon ) ,
114- rhUiIcon : p . rhUiIcon != null ? normalizeIconDefinition ( p . rhUiIcon ) : null
115- } ;
116- }
117- return {
118- name : ( arg as LegacyFlatIconDefinition ) . name ,
119- icon : normalizeIconDefinition ( arg as IconDefinition ) ,
120- rhUiIcon : null
121- } ;
122- }
123-
124102/** Renders an inner `<svg>` with viewBox and path(s) for the dual-SVG (CSS swap) layout. */
125103const createSvg = ( icon : IconDefinitionWithSvgPathData , iconClassName : string ) => {
126104 const { xOffset, yOffset, width, height, svgPathData, svgClassName } = icon ?? { } ;
@@ -154,35 +132,26 @@ const createSvg = (icon: IconDefinitionWithSvgPathData, iconClassName: string) =
154132} ;
155133
156134/**
157- * Builds a React **class** component that renders a PatternFly SVG icon (`role="img"`, optional `<title>` for a11y).
158- *
159- * **Argument shape — pick one:**
160- *
161- * 1. **`CreateIconProps` (preferred)** — `{ name?, icon?, rhUiIcon? }`. Dimensions and path data sit on `icon`
162- * (and optionally on `rhUiIcon` for Red Hat UI–mapped icons). If the object **has an `icon` or `rhUiIcon` key**
163- * (including `rhUiIcon: null`), this shape is assumed.
164- *
165- * 2. **Legacy flat `IconDefinition`** — the same fields as `icon`, but at the **top level** (no nested `icon`).
166- * Still accepted so existing callers are not broken. Prefer migrating to `CreateIconProps`.
135+ * Preferred factory for **nested** icon config (`icon` and optional `rhUiIcon`). Package-generated icons use this.
167136 *
168- * **Path data on each `IconDefinition`:** use `svgPathData` (string or {@link SVGPathObject}[]). The old name
169- * `svgPath` is deprecated but still read; `svgPathData` wins if both are present.
170- *
171- * **Default vs RH UI rendering:** If `rhUiIcon` is set and the consumer does **not** pass `set` on the component,
172- * the output is an outer `<svg.pf-v6-svg>` containing **two** inner `<svg>`s (default + rh-ui) so CSS can swap
173- * which variant is visible. If `set` is `"default"` or `"rh-ui"`, a **single** flat `<svg>` is rendered for that
174- * variant. Requesting `set="rh-ui"` when there is no `rhUiIcon` falls back to the default glyph and logs a
175- * `console.warn` (see implementation).
176- *
177- * @param arg Icon configuration: either {@link CreateIconProps} (nested `icon` / `rhUiIcon`) or a legacy flat
178- * {@link LegacyFlatIconDefinition}. Runtime detection follows the rules in **Argument shape** above.
179- * @returns A `ComponentClass<SVGIconProps>` — render it as `<YourIcon />` or with `title`, `className`, `set`, etc.
137+ * @param name Optional display name for the component; falls back to `icon.name` when not set.
138+ * @see {@link createIcon } for the legacy **flat** argument shape.
180139 */
181- export function createIcon ( arg : CreateIconProps | LegacyFlatIconDefinition ) : React . ComponentClass < SVGIconProps > {
182- const { name, icon, rhUiIcon = null } = normalizeCreateIconArg ( arg ) ;
140+ export function createIconBase ( {
141+ name,
142+ icon,
143+ rhUiIcon = null
144+ } : CreateIconBaseProps ) : React . ComponentClass < SVGIconProps > {
145+ if ( icon == null ) {
146+ const label = name != null ? ` (name: ${ String ( name ) } )` : '' ;
147+ throw new Error ( `@patternfly/react-icons: createIconBase requires an \`icon\` definition${ label } .` ) ;
148+ }
149+ const normalizedIcon = normalizeIconDefinition ( icon ) ;
150+ const normalizedRhUiIcon = rhUiIcon != null ? normalizeIconDefinition ( rhUiIcon ) : null ;
151+ const displayName = name ?? icon . name ;
183152
184153 return class SVGIcon extends Component < SVGIconProps > {
185- static displayName = name ;
154+ static displayName = displayName ;
186155
187156 id = `icon-title-${ currentId ++ } ` ;
188157
@@ -201,16 +170,16 @@ export function createIcon(arg: CreateIconProps | LegacyFlatIconDefinition): Rea
201170 classNames . push ( propsClassName ) ;
202171 }
203172
204- if ( set === 'rh-ui' && rhUiIcon === null ) {
173+ if ( set === 'rh-ui' && normalizedRhUiIcon === null ) {
205174 // eslint-disable-next-line no-console
206175 console . warn (
207- `Set "rh-ui" was provided for ${ name } , but no rh-ui icon data exists for this icon. The default icon will be rendered.`
176+ `Set "rh-ui" was provided for ${ displayName } , but no rh-ui icon data exists for this icon. The default icon will be rendered.`
208177 ) ;
209178 }
210179
211- if ( ( set === undefined && rhUiIcon === null ) || set !== undefined ) {
180+ if ( ( set === undefined && normalizedRhUiIcon === null ) || set !== undefined ) {
212181 const iconData : IconDefinitionWithSvgPathData | undefined =
213- set !== undefined && set === 'rh-ui' && rhUiIcon !== null ? rhUiIcon : icon ;
182+ set !== undefined && set === 'rh-ui' && normalizedRhUiIcon !== null ? normalizedRhUiIcon : normalizedIcon ;
214183 const { xOffset, yOffset, width, height, svgPathData, svgClassName } =
215184 iconData ?? ( { } as Partial < IconDefinitionWithSvgPathData > ) ;
216185 const _xOffset = xOffset ?? 0 ;
@@ -259,11 +228,24 @@ export function createIcon(arg: CreateIconProps | LegacyFlatIconDefinition): Rea
259228 { ...( props as Omit < React . SVGProps < SVGElement > , 'ref' > ) } // Lie.
260229 >
261230 { hasTitle && < title id = { this . id } > { title } </ title > }
262- { icon && createSvg ( icon , 'pf-v6-icon-default' ) }
263- { rhUiIcon && createSvg ( rhUiIcon , 'pf-v6-icon-rh-ui' ) }
231+ { normalizedIcon && createSvg ( normalizedIcon , 'pf-v6-icon-default' ) }
232+ { normalizedRhUiIcon && createSvg ( normalizedRhUiIcon , 'pf-v6-icon-rh-ui' ) }
264233 </ svg >
265234 ) ;
266235 }
267236 }
268237 } ;
269238}
239+
240+ /**
241+ * Legacy-friendly factory: **flat** {@link IconDefinition} fields (plus optional `rhUiIcon`) and delegates to
242+ * {@link createIconBase}. For nested configs, use {@link createIconBase} directly.
243+ */
244+ export function createIcon ( props : CreateIconLegacyProps ) : React . ComponentClass < SVGIconProps > {
245+ const { rhUiIcon, ...icon } = props ;
246+ return createIconBase ( {
247+ name : icon . name ,
248+ icon,
249+ rhUiIcon : rhUiIcon ?? null
250+ } ) ;
251+ }
0 commit comments