@carbon-labs/react-ui-shell 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Copyright IBM Corp. 2024
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import PropTypes from 'prop-types';
9
+
10
+ const iconPropTypes = {
11
+ size: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
12
+ };
13
+
14
+ export { iconPropTypes as i };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Copyright IBM Corp. 2025
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import React, { ReactNode } from 'react';
8
+ export interface HeaderPanelProps {
9
+ /**
10
+ * Specify whether focus and blur listeners are added. They are by default.
11
+ */
12
+ addFocusListeners?: boolean;
13
+ /**
14
+ * The content that will render inside of the `HeaderPanel`
15
+ */
16
+ children?: ReactNode;
17
+ /**
18
+ * Optionally provide a custom class to apply to the underlying `<li>` node
19
+ */
20
+ className?: string;
21
+ /**
22
+ * Specify whether the panel is expanded
23
+ */
24
+ expanded?: boolean;
25
+ /**
26
+ * Provide the `href` to the id of the element on your package that could
27
+ * be target.
28
+ */
29
+ href?: string;
30
+ /**
31
+ * An optional listener that is called a callback to collapse the HeaderPanel
32
+ */
33
+ onHeaderPanelFocus?: () => void;
34
+ }
35
+ export declare const HeaderPanel: React.FC<HeaderPanelProps>;
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Copyright IBM Corp. 2024
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ var _rollupPluginBabelHelpers = require('../_virtual/_rollupPluginBabelHelpers.js');
11
+ var index = require('../_virtual/index.js');
12
+ var PropTypes = require('prop-types');
13
+ var React = require('react');
14
+ var usePrefix = require('@carbon/react/lib/internal/usePrefix');
15
+ var keys = require('@carbon/react/lib/internal/keyboard/keys');
16
+ var match = require('@carbon/react/lib/internal/keyboard/match');
17
+ var useEvent = require('@carbon/react/lib/internal/useEvent');
18
+ var useMergedRefs = require('@carbon/react/lib/internal/useMergedRefs');
19
+
20
+ const noopFn = () => {};
21
+ const HeaderPanel = /*#__PURE__*/React.forwardRef(function HeaderPanel(_ref, ref) {
22
+ let {
23
+ children,
24
+ className: customClassName,
25
+ expanded,
26
+ addFocusListeners = true,
27
+ onHeaderPanelFocus = noopFn,
28
+ href,
29
+ ...rest
30
+ } = _ref;
31
+ const prefix = usePrefix.usePrefix();
32
+ const headerPanelReference = React.useRef(null);
33
+ const headerPanelRef = useMergedRefs.useMergedRefs([headerPanelReference, ref]);
34
+ const controlled = React.useRef(expanded !== undefined).current;
35
+ const [expandedState, setExpandedState] = React.useState(expanded);
36
+ const expandedProp = controlled ? expanded : expandedState;
37
+ const [lastClickedElement, setLastClickedElement] = React.useState(null);
38
+ const className = index.default(`${prefix}--header-panel`, {
39
+ [`${prefix}--header-panel--expanded`]: expandedProp,
40
+ [customClassName]: !!customClassName
41
+ });
42
+ const eventHandlers = {};
43
+ if (addFocusListeners) {
44
+ eventHandlers.onBlur = event => {
45
+ if (!event.currentTarget.contains(event.relatedTarget) && !lastClickedElement?.classList?.contains(`${prefix}--switcher__item-link`)) {
46
+ setExpandedState(false);
47
+ setLastClickedElement(null);
48
+ if (expanded) {
49
+ onHeaderPanelFocus();
50
+ }
51
+ }
52
+ };
53
+ eventHandlers.onKeyDown = event => {
54
+ if (match.match(event, keys.keys.Escape)) {
55
+ setExpandedState(false);
56
+ onHeaderPanelFocus();
57
+ if (href) {
58
+ window.location.href = href;
59
+ }
60
+ }
61
+ };
62
+ }
63
+ useEvent.useWindowEvent('click', () => {
64
+ const focusedElement = document.activeElement;
65
+ setLastClickedElement(focusedElement);
66
+ const childJsxElement = children;
67
+ if (childJsxElement?.type?.displayName === 'Switcher' && !focusedElement?.closest(`.${prefix}--header-panel--expanded`) && !focusedElement?.closest(`.${prefix}--header__action`) && !headerPanelReference?.current?.classList.contains(`${prefix}--switcher`) && expanded) {
68
+ setExpandedState(false);
69
+ onHeaderPanelFocus();
70
+ }
71
+ });
72
+ return /*#__PURE__*/React.createElement("div", _rollupPluginBabelHelpers.extends({}, rest, {
73
+ className: className,
74
+ ref: headerPanelRef
75
+ }, eventHandlers), children);
76
+ });
77
+ HeaderPanel.propTypes = {
78
+ /**
79
+ * Specify whether focus and blur listeners are added. They are by default.
80
+ */
81
+ addFocusListeners: PropTypes.bool,
82
+ /**
83
+ * The content that will render inside of the `HeaderPanel`
84
+ */
85
+ children: PropTypes.any,
86
+ /**
87
+ * Optionally provide a custom class to apply to the underlying `<li>` node
88
+ */
89
+ className: PropTypes.string,
90
+ /**
91
+ * Specify whether the panel is expanded
92
+ */
93
+ expanded: PropTypes.bool,
94
+ /**
95
+ * Provide the `href` to the id of the element on your package that could
96
+ * be target.
97
+ */
98
+ href: PropTypes.string,
99
+ /**
100
+ * An optional listener that is called a callback to collapse the HeaderPanel
101
+ */
102
+ onHeaderPanelFocus: PropTypes.func
103
+ };
104
+ HeaderPanel.displayName = 'HeaderPanel';
105
+
106
+ exports.HeaderPanel = HeaderPanel;
@@ -5,26 +5,39 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React, { type ComponentProps, type FocusEvent, type KeyboardEvent, type MouseEventHandler } from 'react';
8
- export interface SideNavProps extends ComponentProps<'nav'> {
9
- expanded?: boolean | undefined;
10
- defaultExpanded?: boolean | undefined;
11
- isChildOfHeader?: boolean | undefined;
12
- onToggle?: (event: FocusEvent<HTMLElement> | KeyboardEvent<HTMLElement> | boolean, value: boolean) => void | undefined;
13
- href?: string | undefined;
14
- isFixedNav?: boolean | undefined;
15
- isRail?: boolean | undefined;
16
- isPersistent?: boolean | undefined;
17
- addFocusListeners?: boolean | undefined;
18
- addMouseListeners?: boolean | undefined;
19
- onOverlayClick?: MouseEventHandler<HTMLDivElement> | undefined;
20
- onSideNavBlur?: () => void | undefined;
8
+ import { TranslateWithId } from '@carbon/react/lib/types/common';
9
+ export declare enum SIDE_NAV_TYPE {
10
+ DEFAULT = "default",
11
+ RAIL = "rail",
12
+ PANEL = "panel"
13
+ }
14
+ export type TranslationKey = keyof typeof translationIds;
15
+ export declare const translationIds: {
16
+ readonly 'collapse.sidenav': "collapse.sidenav";
17
+ readonly 'expand.sidenav': "expand.sidenav";
18
+ };
19
+ export interface SideNavProps extends ComponentProps<'nav'>, TranslateWithId<TranslationKey> {
20
+ expanded?: boolean;
21
+ defaultExpanded?: boolean;
22
+ isChildOfHeader?: boolean;
23
+ onToggle?: (event: FocusEvent<HTMLElement> | KeyboardEvent<HTMLElement> | boolean, value: boolean) => void;
24
+ href?: string;
25
+ isFixedNav?: boolean;
26
+ isRail?: boolean;
27
+ isPersistent?: boolean;
28
+ addFocusListeners?: boolean;
29
+ addMouseListeners?: boolean;
30
+ onOverlayClick?: MouseEventHandler<HTMLDivElement>;
31
+ onSideNavBlur?: () => void;
21
32
  enterDelayMs?: number;
22
33
  inert?: boolean;
23
- isCollapsible: boolean | undefined;
24
- hideOverlay: boolean | undefined;
34
+ isCollapsible: boolean;
35
+ hideOverlay: boolean;
36
+ navType: SIDE_NAV_TYPE;
25
37
  }
26
38
  interface SideNavContextData {
27
- isRail?: boolean | undefined;
39
+ isRail?: boolean;
40
+ navType?: SIDE_NAV_TYPE;
28
41
  }
29
42
  export declare const SideNavContext: React.Context<SideNavContextData>;
30
43
  export declare const SideNav: React.ForwardRefExoticComponent<Omit<SideNavProps, "ref"> & React.RefAttributes<HTMLElement>>;
@@ -21,10 +21,43 @@ var useEvent = require('@carbon/react/lib/internal/useEvent');
21
21
  var useDelayedState = require('@carbon/react/lib/internal/useDelayedState');
22
22
  var index$1 = require('../node_modules/@carbon/layout/es/index.js');
23
23
  var useMatchMedia = require('@carbon/react/lib/internal/useMatchMedia');
24
+ var SideNavToggle = require('./SideNavToggle.js');
25
+ var bucket15 = require('../node_modules/@carbon/icons-react/es/generated/bucket-15.js');
24
26
 
25
- // TO-DO: comment back in when footer is added for rails
26
- // import SideNavFooter from './SideNavFooter';
27
+ function _interopNamespaceDefault(e) {
28
+ var n = Object.create(null);
29
+ if (e) {
30
+ Object.keys(e).forEach(function (k) {
31
+ if (k !== 'default') {
32
+ var d = Object.getOwnPropertyDescriptor(e, k);
33
+ Object.defineProperty(n, k, d.get ? d : {
34
+ enumerable: true,
35
+ get: function () { return e[k]; }
36
+ });
37
+ }
38
+ });
39
+ }
40
+ n.default = e;
41
+ return Object.freeze(n);
42
+ }
43
+
44
+ var keys__namespace = /*#__PURE__*/_interopNamespaceDefault(keys);
27
45
 
46
+ let SIDE_NAV_TYPE = /*#__PURE__*/function (SIDE_NAV_TYPE) {
47
+ SIDE_NAV_TYPE["DEFAULT"] = "default";
48
+ SIDE_NAV_TYPE["RAIL"] = "rail";
49
+ SIDE_NAV_TYPE["PANEL"] = "panel";
50
+ return SIDE_NAV_TYPE;
51
+ }({});
52
+ const translationIds = {
53
+ 'collapse.sidenav': 'collapse.sidenav',
54
+ 'expand.sidenav': 'expand.sidenav'
55
+ };
56
+ const defaultTranslations = {
57
+ [translationIds['collapse.sidenav']]: 'Collapse',
58
+ [translationIds['expand.sidenav']]: 'Expand'
59
+ };
60
+ const defaultTranslateWithId = id => defaultTranslations[id];
28
61
  const SideNavContext = /*#__PURE__*/React.createContext({});
29
62
  function SideNavRenderFunction(_ref, ref) {
30
63
  let {
@@ -40,6 +73,7 @@ function SideNavRenderFunction(_ref, ref) {
40
73
  isFixedNav = false,
41
74
  isRail,
42
75
  isPersistent = true,
76
+ navType = SIDE_NAV_TYPE.DEFAULT,
43
77
  addFocusListeners = true,
44
78
  addMouseListeners = true,
45
79
  onOverlayClick,
@@ -47,6 +81,7 @@ function SideNavRenderFunction(_ref, ref) {
47
81
  enterDelayMs = 100,
48
82
  isCollapsible = false,
49
83
  hideOverlay = false,
84
+ translateWithId: t = defaultTranslateWithId,
50
85
  ...other
51
86
  } = _ref;
52
87
  const prefix = usePrefix.usePrefix();
@@ -58,6 +93,7 @@ function SideNavRenderFunction(_ref, ref) {
58
93
  const expanded = controlled ? expandedProp : expandedState;
59
94
  const sideNavRef = React.useRef(null);
60
95
  const navRef = useMergedRefs.useMergedRefs([sideNavRef, ref]);
96
+ const sideNavToggleText = expandedState ? t('collapse.sidenav') : t('expand.sidenav');
61
97
  const handleToggle = function (event) {
62
98
  let value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : !expanded;
63
99
  if (!controlled) {
@@ -79,6 +115,7 @@ function SideNavRenderFunction(_ref, ref) {
79
115
  [`${prefix}--side-nav--expanded`]: expanded || expandedViaHoverState,
80
116
  [`${prefix}--side-nav--collapsed`]: !expanded && isFixedNav,
81
117
  [`${prefix}--side-nav--rail`]: isRail,
118
+ [`${prefix}--side-nav--panel`]: navType === SIDE_NAV_TYPE.PANEL,
82
119
  [`${prefix}--side-nav--ux`]: isChildOfHeader,
83
120
  [`${prefix}--side-nav--hidden`]: !isPersistent,
84
121
  [`${prefix}--side-nav--collapsible`]: isCollapsible
@@ -112,6 +149,9 @@ function SideNavRenderFunction(_ref, ref) {
112
149
  }
113
150
  };
114
151
  eventHandlers.onBlur = event => {
152
+ if (navType === SIDE_NAV_TYPE.PANEL) {
153
+ return;
154
+ }
115
155
  if (!event.currentTarget.contains(event.relatedTarget)) {
116
156
  handleToggle(event, false);
117
157
  }
@@ -122,7 +162,7 @@ function SideNavRenderFunction(_ref, ref) {
122
162
  }
123
163
  };
124
164
  eventHandlers.onKeyDown = event => {
125
- if (match.match(event, keys.keys.Escape)) {
165
+ if (match.match(event, keys__namespace.Escape)) {
126
166
  handleToggle(event, false);
127
167
  if (href) {
128
168
  window.location.href = href;
@@ -148,7 +188,7 @@ function SideNavRenderFunction(_ref, ref) {
148
188
  }
149
189
  useEvent.useWindowEvent('keydown', event => {
150
190
  const focusedElement = document.activeElement;
151
- if (match.match(event, keys.keys.Tab) && expanded && !isFixedNav && sideNavRef.current && focusedElement?.classList.contains(`${prefix}--header__menu-toggle`) && !focusedElement.closest('nav')) {
191
+ if (match.match(event, keys__namespace.Tab) && expanded && !isFixedNav && sideNavRef.current && focusedElement?.classList.contains(`${prefix}--header__menu-toggle`) && !focusedElement.closest('nav')) {
152
192
  sideNavRef.current.focus();
153
193
  }
154
194
  });
@@ -169,7 +209,10 @@ function SideNavRenderFunction(_ref, ref) {
169
209
  ref: navRef,
170
210
  className: `${prefix}--side-nav__navigation ${className}`,
171
211
  inert: !isRail ? expanded || isLg ? undefined : -1 : undefined
172
- }, accessibilityLabel, eventHandlers, other), childrenToRender));
212
+ }, accessibilityLabel, eventHandlers, other), childrenToRender, navType === SIDE_NAV_TYPE.PANEL && /*#__PURE__*/React.createElement(SideNavToggle.SideNavToggle, {
213
+ renderIcon: expandedState ? bucket15.SidePanelClose : bucket15.SidePanelOpen,
214
+ onClick: () => setExpandedState(!expandedState)
215
+ }, sideNavToggleText)));
173
216
  }
174
217
  const SideNav = /*#__PURE__*/React.forwardRef(SideNavRenderFunction);
175
218
  SideNav.displayName = 'SideNav';
@@ -261,5 +304,7 @@ SideNav.propTypes = {
261
304
  // translateById: PropTypes.func,
262
305
  };
263
306
 
307
+ exports.SIDE_NAV_TYPE = SIDE_NAV_TYPE;
264
308
  exports.SideNav = SideNav;
265
309
  exports.SideNavContext = SideNavContext;
310
+ exports.translationIds = translationIds;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Copyright IBM Corp. 2025
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import React, { ReactNode } from 'react';
8
+ interface SideNavToggleProps {
9
+ /**
10
+ * Specify the text content for the link
11
+ */
12
+ children: ReactNode;
13
+ /**
14
+ * Provide an optional function to be called when the item is clicked.
15
+ */
16
+ onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
17
+ /**
18
+ * A custom icon to render next to the SideNavToggle title. This can be a function returning JSX or JSX itself.
19
+ */
20
+ renderIcon?: React.ComponentType;
21
+ /**
22
+ * The tabIndex for the button element.
23
+ * If not specified, the default validation will be applied.
24
+ */
25
+ tabIndex?: number;
26
+ }
27
+ export declare const SideNavToggle: React.ForwardRefExoticComponent<SideNavToggleProps & React.RefAttributes<HTMLElement>>;
28
+ export default SideNavToggle;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Copyright IBM Corp. 2024
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ Object.defineProperty(exports, '__esModule', { value: true });
11
+
12
+ var _rollupPluginBabelHelpers = require('../_virtual/_rollupPluginBabelHelpers.js');
13
+ var PropTypes = require('prop-types');
14
+ var React = require('react');
15
+ var react = require('@carbon/react');
16
+ var usePrefix = require('@carbon/react/lib/internal/usePrefix');
17
+
18
+ const SideNavToggle = /*#__PURE__*/React.forwardRef(function SideNavToggle(_ref, ref) {
19
+ let {
20
+ renderIcon: IconElement,
21
+ tabIndex,
22
+ children,
23
+ ...rest
24
+ } = _ref;
25
+ const prefix = usePrefix.usePrefix();
26
+ return /*#__PURE__*/React.createElement("button", _rollupPluginBabelHelpers.extends({
27
+ className: `${prefix}--side-nav__toggle`,
28
+ ref: ref,
29
+ type: "button",
30
+ tabIndex: tabIndex ?? 0
31
+ }, rest), IconElement && /*#__PURE__*/React.createElement(react.SideNavIcon, null, /*#__PURE__*/React.createElement(IconElement, null)), /*#__PURE__*/React.createElement("span", {
32
+ className: `${prefix}--side-nav__toggle-text`
33
+ }, children));
34
+ });
35
+ SideNavToggle.displayName = 'SideNavToggle';
36
+ SideNavToggle.propTypes = {
37
+ /**
38
+ * Specify the text content for the toggle
39
+ */
40
+ children: PropTypes.element,
41
+ /**
42
+ * Provide an optional function to be called when clicked
43
+ */
44
+ onClick: PropTypes.func,
45
+ /**
46
+ * Pass in a custom icon to render next to the `SideNavToggle` title
47
+ */
48
+ // @ts-expect-error - PropTypes are unable to cover this case.
49
+ renderIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
50
+ /**
51
+ * Optional prop to specify the tabIndex of the button. If undefined, it will be applied default validation
52
+ */
53
+ tabIndex: PropTypes.number
54
+ };
55
+
56
+ exports.SideNavToggle = SideNavToggle;
57
+ exports.default = SideNavToggle;
package/lib/index.d.ts CHANGED
@@ -7,3 +7,4 @@
7
7
  * LICENSE file in the root directory of this source tree.
8
8
  */
9
9
  export { SideNav } from './components/SideNav.js';
10
+ export { HeaderPanel } from './components/HeaderPanel';
package/lib/index.js CHANGED
@@ -8,7 +8,9 @@
8
8
  'use strict';
9
9
 
10
10
  var SideNav = require('./components/SideNav.js');
11
+ var HeaderPanel = require('./components/HeaderPanel.js');
11
12
 
12
13
 
13
14
 
14
15
  exports.SideNav = SideNav.SideNav;
16
+ exports.HeaderPanel = HeaderPanel.HeaderPanel;
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Copyright IBM Corp. 2024
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ function _defineProperty(e, r, t) {
11
+ return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
12
+ value: t,
13
+ enumerable: !0,
14
+ configurable: !0,
15
+ writable: !0
16
+ }) : e[r] = t, e;
17
+ }
18
+ function ownKeys(e, r) {
19
+ var t = Object.keys(e);
20
+ if (Object.getOwnPropertySymbols) {
21
+ var o = Object.getOwnPropertySymbols(e);
22
+ r && (o = o.filter(function (r) {
23
+ return Object.getOwnPropertyDescriptor(e, r).enumerable;
24
+ })), t.push.apply(t, o);
25
+ }
26
+ return t;
27
+ }
28
+ function _objectSpread2(e) {
29
+ for (var r = 1; r < arguments.length; r++) {
30
+ var t = null != arguments[r] ? arguments[r] : {};
31
+ r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
32
+ _defineProperty(e, r, t[r]);
33
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
34
+ Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
35
+ });
36
+ }
37
+ return e;
38
+ }
39
+ function _objectWithoutProperties(e, t) {
40
+ if (null == e) return {};
41
+ var o,
42
+ r,
43
+ i = _objectWithoutPropertiesLoose(e, t);
44
+ if (Object.getOwnPropertySymbols) {
45
+ var s = Object.getOwnPropertySymbols(e);
46
+ for (r = 0; r < s.length; r++) o = s[r], t.includes(o) || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);
47
+ }
48
+ return i;
49
+ }
50
+ function _objectWithoutPropertiesLoose(r, e) {
51
+ if (null == r) return {};
52
+ var t = {};
53
+ for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
54
+ if (e.includes(n)) continue;
55
+ t[n] = r[n];
56
+ }
57
+ return t;
58
+ }
59
+ function _toPrimitive(t, r) {
60
+ if ("object" != typeof t || !t) return t;
61
+ var e = t[Symbol.toPrimitive];
62
+ if (void 0 !== e) {
63
+ var i = e.call(t, r || "default");
64
+ if ("object" != typeof i) return i;
65
+ throw new TypeError("@@toPrimitive must return a primitive value.");
66
+ }
67
+ return ("string" === r ? String : Number)(t);
68
+ }
69
+ function _toPropertyKey(t) {
70
+ var i = _toPrimitive(t, "string");
71
+ return "symbol" == typeof i ? i : i + "";
72
+ }
73
+ var _excluded = ["width", "height", "viewBox"],
74
+ _excluded2 = ["tabindex"];
75
+ /**
76
+ * Copyright IBM Corp. 2018, 2024
77
+ *
78
+ * This source code is licensed under the Apache-2.0 license found in the
79
+ * LICENSE file in the root directory of this source tree.
80
+ */
81
+
82
+ var defaultAttributes = {
83
+ // Reference:
84
+ // https://github.com/IBM/carbon-components-react/issues/1392
85
+ // https://github.com/PolymerElements/iron-iconset-svg/pull/47
86
+ // `focusable` is a string attribute which is why we do not use a boolean here
87
+ focusable: 'false',
88
+ preserveAspectRatio: 'xMidYMid meet'
89
+ };
90
+
91
+ /**
92
+ * Get supplementary HTML attributes for a given <svg> element based on existing
93
+ * attributes.
94
+ */
95
+ function getAttributes() {
96
+ var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
97
+ width = _ref.width,
98
+ height = _ref.height,
99
+ _ref$viewBox = _ref.viewBox,
100
+ viewBox = _ref$viewBox === void 0 ? "0 0 ".concat(width, " ").concat(height) : _ref$viewBox,
101
+ attributes = _objectWithoutProperties(_ref, _excluded);
102
+ var tabindex = attributes.tabindex,
103
+ rest = _objectWithoutProperties(attributes, _excluded2);
104
+ var iconAttributes = _objectSpread2(_objectSpread2(_objectSpread2({}, defaultAttributes), rest), {}, {
105
+ width: width,
106
+ height: height,
107
+ viewBox: viewBox
108
+ });
109
+
110
+ // TODO: attributes.title assumes that the consumer will implement <title> and
111
+ // correctly set `aria-labelledby`.
112
+ if (iconAttributes['aria-label'] || iconAttributes['aria-labelledby'] || iconAttributes.title) {
113
+ iconAttributes.role = 'img';
114
+
115
+ // Reference:
116
+ // https://allyjs.io/tutorials/focusing-in-svg.html
117
+ if (tabindex !== undefined && tabindex !== null) {
118
+ iconAttributes.focusable = 'true';
119
+ iconAttributes.tabindex = tabindex;
120
+ }
121
+ } else {
122
+ iconAttributes['aria-hidden'] = true;
123
+ }
124
+ return iconAttributes;
125
+ }
126
+
127
+ exports.defaultAttributes = defaultAttributes;
128
+ exports.getAttributes = getAttributes;
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Copyright IBM Corp. 2024
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ Object.defineProperty(exports, '__esModule', { value: true });
11
+
12
+ var index = require('../../icon-helpers/es/index.js');
13
+ var PropTypes = require('prop-types');
14
+ var React = require('react');
15
+
16
+ /**
17
+ * Copyright IBM Corp. 2019, 2023
18
+ *
19
+ * This source code is licensed under the Apache-2.0 license found in the
20
+ * LICENSE file in the root directory of this source tree.
21
+ */
22
+ const Icon = /*#__PURE__*/React.forwardRef(function Icon(_ref, ref) {
23
+ let {
24
+ className,
25
+ children,
26
+ tabIndex,
27
+ xmlns = 'http://www.w3.org/2000/svg',
28
+ preserveAspectRatio = 'xMidYMid meet',
29
+ ...rest
30
+ } = _ref;
31
+ const {
32
+ tabindex,
33
+ ...attrs
34
+ } = index.getAttributes({
35
+ ...rest,
36
+ tabindex: tabIndex
37
+ });
38
+ const props = attrs;
39
+ if (className) {
40
+ props.className = className;
41
+ }
42
+ if (tabindex !== undefined && tabindex !== null) {
43
+ if (typeof tabindex === 'number') {
44
+ props.tabIndex = tabindex;
45
+ } else {
46
+ props.tabIndex = Number(tabIndex);
47
+ }
48
+ }
49
+ if (ref) {
50
+ props.ref = ref;
51
+ }
52
+ if (xmlns) {
53
+ props.xmlns = xmlns;
54
+ }
55
+ if (preserveAspectRatio) {
56
+ props.preserveAspectRatio = preserveAspectRatio;
57
+ }
58
+ return /*#__PURE__*/React.createElement('svg', props, children);
59
+ });
60
+ Icon.displayName = 'Icon';
61
+ Icon.propTypes = {
62
+ 'aria-hidden': PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['true', 'false'])]),
63
+ 'aria-label': PropTypes.string,
64
+ 'aria-labelledby': PropTypes.string,
65
+ children: PropTypes.node,
66
+ className: PropTypes.string,
67
+ height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
68
+ preserveAspectRatio: PropTypes.string,
69
+ tabIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
70
+ viewBox: PropTypes.string,
71
+ width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
72
+ xmlns: PropTypes.string
73
+ };
74
+
75
+ exports.default = Icon;