@react-fabric/core 1.0.0-beta.55 → 1.0.0-beta.58

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.
Files changed (93) hide show
  1. package/css/components/_card.css +8 -4
  2. package/css/components/_icon.css +3 -3
  3. package/css/components/_tabPanel.css +40 -0
  4. package/css/core/_aside.css +4 -6
  5. package/css/reset/_reset.css +14 -0
  6. package/dist/cjs/components/avatar/Avatar.js +9 -4
  7. package/dist/cjs/components/badge/Badge.js +2 -10
  8. package/dist/cjs/components/button/Button.js +7 -12
  9. package/dist/cjs/components/card/Card.js +18 -12
  10. package/dist/cjs/components/chip/Chip.js +9 -14
  11. package/dist/cjs/components/dropdown/Dropdown.js +1 -0
  12. package/dist/cjs/components/icon/Icon.js +37 -8
  13. package/dist/cjs/components/menu/MenuItem.js +5 -12
  14. package/dist/cjs/components/panel/Panel.js +4 -13
  15. package/dist/cjs/components/tabpanel/Tab.js +4 -13
  16. package/dist/cjs/components/tabpanel/TabPanel.js +2 -1
  17. package/dist/cjs/core/aside/Aside.js +2 -11
  18. package/dist/cjs/core/headfoot/HeadFoot.js +4 -2
  19. package/dist/cjs/core/page/Page.js +4 -13
  20. package/dist/cjs/index.js +1 -0
  21. package/dist/cjs/overlays/alert/Alert.js +3 -1
  22. package/dist/cjs/overlays/flyout/Flyout.js +6 -11
  23. package/dist/cjs/overlays/message/Message.js +2 -0
  24. package/dist/cjs/overlays/modal/Modal.js +6 -13
  25. package/dist/cjs/overlays/toast/Toast.js +3 -1
  26. package/dist/cjs/types/icons.js +2 -1
  27. package/dist/esm/components/avatar/Avatar.js +9 -4
  28. package/dist/esm/components/badge/Badge.js +3 -11
  29. package/dist/esm/components/button/Button.js +9 -14
  30. package/dist/esm/components/card/Card.js +18 -12
  31. package/dist/esm/components/chip/Chip.js +10 -15
  32. package/dist/esm/components/dropdown/Dropdown.js +1 -0
  33. package/dist/esm/components/icon/Icon.js +39 -11
  34. package/dist/esm/components/menu/MenuItem.js +6 -13
  35. package/dist/esm/components/panel/Panel.js +5 -14
  36. package/dist/esm/components/tabpanel/Tab.js +5 -14
  37. package/dist/esm/components/tabpanel/TabPanel.js +2 -1
  38. package/dist/esm/core/aside/Aside.js +3 -12
  39. package/dist/esm/core/headfoot/HeadFoot.js +4 -2
  40. package/dist/esm/core/page/Page.js +5 -14
  41. package/dist/esm/index.js +1 -1
  42. package/dist/esm/overlays/alert/Alert.js +3 -1
  43. package/dist/esm/overlays/flyout/Flyout.js +7 -12
  44. package/dist/esm/overlays/message/Message.js +2 -0
  45. package/dist/esm/overlays/modal/Modal.js +7 -14
  46. package/dist/esm/overlays/toast/Toast.js +3 -1
  47. package/dist/esm/types/icons.js +2 -1
  48. package/dist/types/components/avatar/Avatar.d.ts +5 -1
  49. package/dist/types/components/badge/Badge.d.ts +8 -3
  50. package/dist/types/components/button/Button.d.ts +12 -3
  51. package/dist/types/components/card/Card.d.ts +5 -3
  52. package/dist/types/components/chip/Chip.d.ts +12 -3
  53. package/dist/types/components/icon/Icon.d.ts +10 -4
  54. package/dist/types/components/index.d.ts +1 -1
  55. package/dist/types/components/menu/MenuItem.d.ts +1 -1
  56. package/dist/types/components/menu/types.d.ts +7 -2
  57. package/dist/types/components/panel/Panel.d.ts +8 -5
  58. package/dist/types/components/tabpanel/Tab.d.ts +8 -5
  59. package/dist/types/components/tabpanel/TabPanel.d.ts +5 -1
  60. package/dist/types/core/aside/Aside.d.ts +8 -5
  61. package/dist/types/core/page/Page.d.ts +8 -5
  62. package/dist/types/overlays/alert/Alert.d.ts +15 -3
  63. package/dist/types/overlays/flyout/Flyout.d.ts +9 -5
  64. package/dist/types/overlays/message/Message.d.ts +15 -3
  65. package/dist/types/overlays/modal/Modal.d.ts +6 -6
  66. package/dist/types/overlays/toast/Toast.d.ts +15 -3
  67. package/dist/types/types/icons.d.ts +2 -1
  68. package/dist/types/types/index.d.ts +0 -18
  69. package/package.json +14 -14
  70. package/src/components/avatar/Avatar.tsx +10 -2
  71. package/src/components/badge/Badge.tsx +7 -13
  72. package/src/components/button/Button.tsx +24 -19
  73. package/src/components/card/Card.tsx +29 -15
  74. package/src/components/chip/Chip.tsx +15 -13
  75. package/src/components/dropdown/Dropdown.tsx +1 -0
  76. package/src/components/icon/Icon.tsx +48 -7
  77. package/src/components/index.ts +1 -1
  78. package/src/components/menu/MenuItem.tsx +4 -9
  79. package/src/components/menu/types.ts +6 -6
  80. package/src/components/panel/Panel.tsx +7 -13
  81. package/src/components/tabpanel/Tab.tsx +8 -19
  82. package/src/components/tabpanel/TabPanel.tsx +6 -0
  83. package/src/core/aside/Aside.tsx +7 -13
  84. package/src/core/headfoot/HeadFoot.tsx +2 -2
  85. package/src/core/page/Page.tsx +8 -23
  86. package/src/overlays/alert/Alert.tsx +24 -5
  87. package/src/overlays/flyout/Flyout.tsx +11 -22
  88. package/src/overlays/message/Message.tsx +18 -3
  89. package/src/overlays/modal/Modal.tsx +8 -24
  90. package/src/overlays/toast/Toast.tsx +23 -4
  91. package/src/types/global.d.ts +8 -0
  92. package/src/types/icons.ts +3 -1
  93. package/src/types/index.ts +0 -19
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-fabric/core",
3
- "version": "1.0.0-beta.55",
3
+ "version": "1.0.0-beta.58",
4
4
  "description": "RUF: Core package",
5
5
  "author": "Adarsh Pastakia <adarshpastakia@outlook.com>",
6
6
  "license": "MIT",
@@ -35,24 +35,24 @@
35
35
  "watch": "npm-run-all -p watch:rollup watch:dts"
36
36
  },
37
37
  "dependencies": {
38
- "@floating-ui/react": "^0.27.12",
39
- "@react-fabric/utilities": "^1.0.0-beta.52",
40
- "@tailwindcss/postcss": "~4.1.8",
41
- "boring-avatars": "^1.11.2",
42
- "classnames": "^2.5.1",
43
- "color": "^4.2.3",
44
- "resize-observer-polyfill": "^1.5.1",
45
- "tailwindcss": "^4.1.8"
38
+ "@floating-ui/react": "~0.27.16",
39
+ "@react-fabric/utilities": "^1.0.0-beta.58",
40
+ "@tailwindcss/postcss": "~4.1.16",
41
+ "boring-avatars": "~1.11.2",
42
+ "classnames": "~2.5.1",
43
+ "color": "~5.0.2",
44
+ "resize-observer-polyfill": "~1.5.1",
45
+ "tailwindcss": "~4.1.16"
46
46
  },
47
47
  "peerDependencies": {
48
- "i18next": "^25.2.1",
49
- "react": "^19.0.0",
50
- "react-dom": "^19.0.0",
51
- "react-i18next": "^15.5.2"
48
+ "i18next": "~25.6.0",
49
+ "react": "~19.2.0",
50
+ "react-dom": "~19.2.0",
51
+ "react-i18next": "~16.2.1"
52
52
  },
53
53
  "engines": {
54
54
  "node": ">=18.12.0",
55
55
  "npm": ">=8.19.0"
56
56
  },
57
- "gitHead": "c8454798fb7546174ee8c7ea10e491c5e903e789"
57
+ "gitHead": "7e66f8c498e37a40e410ecafff2ea6b31505dc1a"
58
58
  }
@@ -73,6 +73,10 @@ export interface AvatarProps extends CssProp, AriaProps, TestProps, RefProp {
73
73
  * rounded icon
74
74
  */
75
75
  rounded?: boolean;
76
+ /**
77
+ * prevent click default, useful when component is within a `a` link
78
+ */
79
+ preventDefault?: boolean;
76
80
  /**
77
81
  * click handler
78
82
  */
@@ -127,6 +131,7 @@ export const Avatar = ({
127
131
  variant = "beam",
128
132
  className,
129
133
  viewBox = "0 0 24 24",
134
+ preventDefault,
130
135
  onClick,
131
136
  ...aria
132
137
  }: AvatarProps) => {
@@ -180,7 +185,7 @@ export const Avatar = ({
180
185
  const fallbackAvatar = useMemo(() => {
181
186
  if (fallbackIcon) {
182
187
  return isSvgPath(fallbackIcon) ? (
183
- <svg viewBox={viewBox}>
188
+ <svg viewBox={viewBox} className="p-[0.125em]">
184
189
  <path fill="currentColor" d={fallbackIcon.toString()} />
185
190
  </svg>
186
191
  ) : (
@@ -220,7 +225,10 @@ export const Avatar = ({
220
225
  !rounded && "rounded",
221
226
  rounded && "rounded-full",
222
227
  )}
223
- onClick={onClick}
228
+ onClick={(e) => {
229
+ preventDefault && e.preventDefault();
230
+ onClick?.(e);
231
+ }}
224
232
  style={styles}
225
233
  data-clickable={!!onClick}
226
234
  ref={ref}
@@ -28,16 +28,11 @@ import {
28
28
  type BadgeType,
29
29
  type ChildProp,
30
30
  type CssProp,
31
- type IconProps,
32
31
  type RefProp,
33
32
  } from "../../types";
34
- import { Icon } from "../icon/Icon";
33
+ import { getIconProps, Icon, IconProps } from "../icon/Icon";
35
34
 
36
- export interface BadgeProps
37
- extends CssProp,
38
- RefProp,
39
- IconProps,
40
- Partial<ChildProp> {
35
+ export interface BadgeProps extends CssProp, RefProp, Partial<ChildProp> {
41
36
  /**
42
37
  * make wrapper a block element
43
38
  */
@@ -50,6 +45,10 @@ export interface BadgeProps
50
45
  * badge value
51
46
  */
52
47
  value?: number | string;
48
+ /**
49
+ * icon path or props
50
+ */
51
+ icon?: IconProps;
53
52
  /**
54
53
  * max value for number display
55
54
  */
@@ -124,9 +123,6 @@ export const Badge = ({
124
123
  // @ts-expect-error ignore
125
124
  forButton = false,
126
125
  icon,
127
- iconBg,
128
- iconColor,
129
- rtlFlip,
130
126
  ...rest
131
127
  }: BadgeProps) => {
132
128
  const label = useMemo(() => {
@@ -176,9 +172,7 @@ export const Badge = ({
176
172
  )}
177
173
  >
178
174
  {label && <span className="p-1">{label}</span>}
179
- {icon && (
180
- <Icon icon={icon} bg={iconBg} color={iconColor} rtlFlip={rtlFlip} />
181
- )}
175
+ {icon && <Icon {...getIconProps(icon)} />}
182
176
  </div>
183
177
  )}
184
178
  </div>
@@ -21,7 +21,7 @@
21
21
  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  */
23
23
 
24
- import { isNil, isString, mergeRefs } from "@react-fabric/utilities";
24
+ import { isNil, isObject, isString, mergeRefs } from "@react-fabric/utilities";
25
25
  import classNames from "classnames";
26
26
  import {
27
27
  Fragment,
@@ -39,12 +39,11 @@ import { HotKey } from "../../hotkeys/HotKey";
39
39
  import { HotKeyLabel } from "../../hotkeys/HotKeyLabel";
40
40
  import { Tooltip } from "../../overlays/tooltip/Tooltip";
41
41
  import {
42
- type ColorState,
43
42
  type AriaProps,
44
43
  type BadgeType,
45
44
  type CallbackReturn,
45
+ type ColorState,
46
46
  type CssProp,
47
- type IconProps,
48
47
  type PolymorphicProps,
49
48
  type RefProp,
50
49
  type SizeType,
@@ -54,14 +53,9 @@ import {
54
53
  import { getColor } from "../../utils";
55
54
  import { AnimationIndicator } from "../animations/Animations";
56
55
  import { Badge, getBadgeProps } from "../badge/Badge";
57
- import { Icon } from "../icon/Icon";
56
+ import { getIconProps, Icon, IconProps } from "../icon/Icon";
58
57
 
59
- export interface BaseProps
60
- extends CssProp,
61
- AriaProps,
62
- IconProps,
63
- RefProp,
64
- TestProps {
58
+ export interface BaseProps extends CssProp, AriaProps, RefProp, TestProps {
65
59
  /**
66
60
  * primary icon alignment
67
61
  */
@@ -78,6 +72,10 @@ export interface BaseProps
78
72
  * button color
79
73
  */
80
74
  color?: ColorState;
75
+ /**
76
+ * icon path or props
77
+ */
78
+ icon?: IconProps;
81
79
  /**
82
80
  * button type
83
81
  */
@@ -136,6 +134,10 @@ export interface BaseProps
136
134
  */
137
135
  hotKey?: string;
138
136
 
137
+ /**
138
+ * prevent click default, useful when button is within a `a` link
139
+ */
140
+ preventDefault?: boolean;
139
141
  stopPropagation?: boolean;
140
142
 
141
143
  onMouseOut?: MouseEventHandler;
@@ -187,11 +189,8 @@ export const Button = <Tag extends React.ElementType = "button">({
187
189
  active,
188
190
  color = "primary",
189
191
  icon,
190
- iconBg,
191
- iconColor,
192
192
  iconAlign = "start",
193
193
  altIcon,
194
- rtlFlip,
195
194
  rounded,
196
195
  size,
197
196
  disabled,
@@ -202,6 +201,7 @@ export const Button = <Tag extends React.ElementType = "button">({
202
201
  spinOnHover,
203
202
  onClick,
204
203
  actionMessage,
204
+ preventDefault,
205
205
  stopPropagation,
206
206
  type = "button",
207
207
  hotKey,
@@ -220,6 +220,7 @@ export const Button = <Tag extends React.ElementType = "button">({
220
220
  const clickHandler = useCallback(
221
221
  (e: React.MouseEvent) => {
222
222
  setBusy(true);
223
+ preventDefault && e.preventDefault();
223
224
  stopPropagation && e.stopPropagation();
224
225
  const ret = onClick?.(e);
225
226
  void Promise.resolve(ret).then((b) => {
@@ -229,7 +230,14 @@ export const Button = <Tag extends React.ElementType = "button">({
229
230
  }
230
231
  });
231
232
  },
232
- [onClick, disabled, actionMessage, showActionDoneEvent, stopPropagation],
233
+ [
234
+ onClick,
235
+ disabled,
236
+ preventDefault,
237
+ actionMessage,
238
+ showActionDoneEvent,
239
+ stopPropagation,
240
+ ],
233
241
  );
234
242
 
235
243
  /** ***************** reset done state on timeout *******************/
@@ -310,11 +318,8 @@ export const Button = <Tag extends React.ElementType = "button">({
310
318
  {icon && (
311
319
  <Icon
312
320
  className={"fabric-buttonIcon"}
313
- icon={icon}
314
- bg={iconBg}
315
- color={iconColor}
316
- rtlFlip={rtlFlip}
317
321
  data-align={iconAlign}
322
+ {...getIconProps(icon)}
318
323
  />
319
324
  )}
320
325
  {isValidElement(children) && (
@@ -323,7 +328,7 @@ export const Button = <Tag extends React.ElementType = "button">({
323
328
  {isString(children) && (
324
329
  <label
325
330
  className={classNames("fabric-buttonLabel", "truncate")}
326
- data-colored-icon={!!iconBg}
331
+ data-colored-icon={isObject(icon) && "bg" in icon}
327
332
  >
328
333
  {children}
329
334
  </label>
@@ -24,10 +24,10 @@
24
24
  import classNames from "classnames";
25
25
  import {
26
26
  Children,
27
- type DragEvent,
28
- type MouseEventHandler,
29
27
  useCallback,
30
28
  useMemo,
29
+ type DragEvent,
30
+ type MouseEventHandler,
31
31
  } from "react";
32
32
  import { ErrorBoundary } from "../../core/boundary/ErrorBoundary";
33
33
  import { type ContentProps } from "../../core/content/Content";
@@ -37,6 +37,7 @@ import {
37
37
  type HeadFootProps,
38
38
  } from "../../core/headfoot/HeadFoot";
39
39
  import {
40
+ PolymorphicProps,
40
41
  type AriaProps,
41
42
  type ChildrenProp,
42
43
  type CssProp,
@@ -45,7 +46,7 @@ import {
45
46
  } from "../../types";
46
47
  import { nodeCheck } from "../../utils";
47
48
 
48
- export interface CardProps
49
+ interface BaseProps
49
50
  extends CssProp,
50
51
  AriaProps,
51
52
  TestProps,
@@ -93,6 +94,9 @@ export interface CardProps
93
94
  dragData?: KeyValue;
94
95
  }
95
96
 
97
+ export type CardProps<Tag extends React.ElementType = "div"> = BaseProps &
98
+ PolymorphicProps<Tag>;
99
+
96
100
  /**
97
101
  * A component that displays a card with a header, body, and footer. It can be used to display content in a structured format.
98
102
  * It supports various features such as click handling, drag-and-drop functionality, and customizable styles.
@@ -127,7 +131,7 @@ export interface CardProps
127
131
  *
128
132
  * @see {@link https://adarshpastakia.github.io/react-fabric/?path=/docs/core-components-card--docs} for more details.
129
133
  */
130
- export const Card = ({
134
+ export const Card = <Tag extends React.ElementType = "div">({
131
135
  children,
132
136
  className,
133
137
  bodyClassName,
@@ -140,8 +144,9 @@ export const Card = ({
140
144
  dragKey,
141
145
  dragData,
142
146
  ref,
147
+ as,
143
148
  ...aria
144
- }: CardProps) => {
149
+ }: CardProps<Tag>) => {
145
150
  const [header, body, footer] = useMemo(() => {
146
151
  return Children.toArray(children as AnyObject).reduce<AnyObject[]>(
147
152
  (ret, node) => {
@@ -164,6 +169,7 @@ export const Card = ({
164
169
  [onDragStart, dragKey, dragData],
165
170
  );
166
171
 
172
+ const E = as ?? "div";
167
173
  return (
168
174
  <div
169
175
  className={classNames(
@@ -171,7 +177,7 @@ export const Card = ({
171
177
  "rounded-capped relative grid",
172
178
  flex && "flex-1",
173
179
  selected && selectedRibbon && "selected",
174
- selected && "outline-2 outline-accent-500 outline-offset-2",
180
+ selected && "outline-1 outline-accent-500 outline-offset-2",
175
181
  )}
176
182
  >
177
183
  <ErrorBoundary>
@@ -179,22 +185,30 @@ export const Card = ({
179
185
  className={classNames(
180
186
  "fabric-card",
181
187
  className,
182
- "rounded-capped flex flex-col flex-nowrap overflow-hidden",
188
+ "rounded-capped relative flex flex-col flex-nowrap overflow-hidden",
189
+ "href" in aria && "clickable",
190
+ "to" in aria && "clickable",
183
191
  onClick && "clickable",
184
192
  )}
185
193
  draggable={draggable}
186
194
  onDragStart={!draggable ? undefined : handleDragStart}
187
195
  ref={ref}
188
- {...aria}
189
196
  >
190
197
  {header}
191
- <div
192
- role="none"
193
- className={classNames("fabric-cardBody", bodyClassName, "flex-1")}
194
- onClick={onClick}
195
- >
196
- {body}
197
- </div>
198
+ <E role="none" onClick={onClick} {...aria} className="contents">
199
+ {body && (
200
+ <object
201
+ type="none"
202
+ className={classNames(
203
+ "fabric-cardBody",
204
+ bodyClassName,
205
+ "flex-1",
206
+ )}
207
+ >
208
+ {body}
209
+ </object>
210
+ )}
211
+ </E>
198
212
  {footer}
199
213
  </div>
200
214
  </ErrorBoundary>
@@ -29,7 +29,6 @@ import {
29
29
  type ChildProp,
30
30
  type ColorType,
31
31
  type CssProp,
32
- type IconProps,
33
32
  type PaletteType,
34
33
  type PolymorphicProps,
35
34
  type RefProp,
@@ -37,12 +36,11 @@ import {
37
36
  type TestProps,
38
37
  } from "../../types";
39
38
  import { getColor } from "../../utils";
40
- import { Icon } from "../icon/Icon";
39
+ import { getIconProps, Icon, IconProps } from "../icon/Icon";
41
40
 
42
41
  export interface ChipProps
43
42
  extends CssProp,
44
43
  AriaProps,
45
- IconProps,
46
44
  TestProps,
47
45
  ChildProp<string | ReactElement>,
48
46
  RefProp<HTMLDivElement> {
@@ -62,10 +60,18 @@ export interface ChipProps
62
60
  * full rounded edges
63
61
  */
64
62
  rounded?: boolean;
63
+ /**
64
+ * icon path or props
65
+ */
66
+ icon?: IconProps;
65
67
  /**
66
68
  * disabled state
67
69
  */
68
70
  disabled?: boolean;
71
+ /**
72
+ * prevent click default, useful when component is within a `a` link
73
+ */
74
+ preventDefault?: boolean;
69
75
  /**
70
76
  * prevent click propagation
71
77
  */
@@ -120,14 +126,12 @@ export const Chip = <Tag extends React.ElementType = "div">({
120
126
  color,
121
127
  variant,
122
128
  icon,
123
- iconBg,
124
- iconColor,
125
- rtlFlip,
126
129
  disabled,
127
130
  onClick,
128
131
  onIconClick,
129
132
  onRemove,
130
133
  rounded,
134
+ preventDefault,
131
135
  stopPropagation,
132
136
  as,
133
137
  ...aria
@@ -153,10 +157,11 @@ export const Chip = <Tag extends React.ElementType = "div">({
153
157
 
154
158
  const clickHandler = useCallback(
155
159
  (e: React.MouseEvent) => {
156
- if (stopPropagation) e.stopPropagation();
160
+ preventDefault && e.preventDefault();
161
+ stopPropagation && e.stopPropagation();
157
162
  onClick?.(e);
158
163
  },
159
- [onClick, stopPropagation],
164
+ [onClick, preventDefault, stopPropagation],
160
165
  );
161
166
 
162
167
  const removeHandler = useCallback(
@@ -191,17 +196,14 @@ export const Chip = <Tag extends React.ElementType = "div">({
191
196
  <Icon
192
197
  data-ref="chipIcon"
193
198
  className={classNames("fabric-chipIcon", "m-1 flex-content")}
194
- icon={icon}
195
- bg={iconBg}
196
199
  onClick={onIconClick}
197
- color={iconColor}
198
- rtlFlip={rtlFlip}
200
+ {...getIconProps(icon)}
199
201
  />
200
202
  )}
201
203
  {children && (
202
204
  <label
203
205
  data-ref="chipLabel"
204
- className={classNames("fabric-chipLabel", "truncate")}
206
+ className={classNames("fabric-chipLabel", "truncate flex-1")}
205
207
  >
206
208
  {children}
207
209
  </label>
@@ -221,6 +221,7 @@ const DropdownElement = ({
221
221
  onClick: (e) => {
222
222
  anchor.props.onClick?.(e);
223
223
  e.stopPropagation();
224
+ e.preventDefault();
224
225
  },
225
226
  }),
226
227
  "data-inner-clickable": "true",
@@ -23,23 +23,27 @@
23
23
 
24
24
  import { isString, isSvgPath } from "@react-fabric/utilities";
25
25
  import classNames from "classnames";
26
- import { useMemo } from "react";
26
+ import { isValidElement, useEffect, useMemo, useState } from "react";
27
27
  import {
28
- type PaletteType,
29
28
  type AriaProps,
30
29
  type ColorType,
31
30
  type CssProp,
31
+ type PaletteType,
32
32
  type RefProp,
33
33
  type SizeType,
34
34
  type TestProps,
35
35
  } from "../../types";
36
36
  import { getColor } from "../../utils";
37
37
 
38
- export interface IconProps extends CssProp, AriaProps, RefProp, TestProps {
38
+ export interface Props extends CssProp, AriaProps, RefProp, TestProps {
39
39
  /**
40
40
  * svg path / webfont className / 1-4 letter text
41
41
  */
42
- icon: string;
42
+ icon: string | JSX.Element;
43
+ /**
44
+ * icon image source URL, if failed to load then shows icon
45
+ */
46
+ iconSrc?: string;
43
47
  /**
44
48
  * background color (CSS color / tailwind color)
45
49
  */
@@ -75,6 +79,28 @@ export interface IconProps extends CssProp, AriaProps, RefProp, TestProps {
75
79
  onClick?: React.MouseEventHandler;
76
80
  }
77
81
 
82
+ export type IconProps =
83
+ | string
84
+ | Pick<
85
+ Props,
86
+ | "icon"
87
+ | "iconSrc"
88
+ | "bg"
89
+ | "color"
90
+ | "size"
91
+ | "rtlFlip"
92
+ | "viewBox"
93
+ | "rounded"
94
+ | "animate"
95
+ >;
96
+
97
+ export const getIconProps = (props: IconProps): Props => {
98
+ if (typeof props === "string") {
99
+ return { icon: props };
100
+ }
101
+ return props;
102
+ };
103
+
78
104
  const SvgTextSize = ["", ".875em", ".525em", ".35em", ".25em"];
79
105
  const SizeMap: KeyValue<string> = {
80
106
  xs: "0.625rem",
@@ -116,6 +142,7 @@ const SizeMap: KeyValue<string> = {
116
142
  export const Icon = ({
117
143
  ref,
118
144
  icon,
145
+ iconSrc,
119
146
  bg,
120
147
  color,
121
148
  size = "",
@@ -127,7 +154,13 @@ export const Icon = ({
127
154
  className,
128
155
  onClick,
129
156
  ...rest
130
- }: IconProps) => {
157
+ }: Props) => {
158
+ const [imageFailed, setImageFailed] = useState(false);
159
+
160
+ useEffect(() => {
161
+ setImageFailed(false);
162
+ }, [iconSrc]);
163
+
131
164
  /** ***************** style map *******************/
132
165
  const styles = useMemo(() => {
133
166
  const s: KeyValue = {};
@@ -153,6 +186,7 @@ export const Icon = ({
153
186
 
154
187
  /** ***************** render icon *******************/
155
188
  const iconEl = useMemo(() => {
189
+ if (isValidElement(icon)) return icon;
156
190
  if (!isString(icon)) {
157
191
  throw Error("Invalid icon expected string");
158
192
  }
@@ -193,13 +227,20 @@ export const Icon = ({
193
227
  !!onClick && disabled && "opacity-30 pointer-events-none",
194
228
  className,
195
229
  )}
196
- onClick={onClick}
230
+ onClick={(e) => {
231
+ onClick && e.stopPropagation();
232
+ onClick && e.preventDefault();
233
+ onClick?.(e);
234
+ }}
197
235
  data-flip={rtlFlip}
198
236
  style={styles}
199
237
  data-clickable={!!onClick}
200
238
  data-inner-clickable={!!onClick}
201
239
  >
202
- {iconEl}
240
+ {iconSrc && !imageFailed && (
241
+ <img src={iconSrc} onError={() => setImageFailed(true)} />
242
+ )}
243
+ {(!iconSrc || imageFailed) && iconEl}
203
244
  </dfn>
204
245
  );
205
246
  };
@@ -47,7 +47,7 @@ export { Divider } from "./divider/Divider";
47
47
  export { Dropdown, DropdownDismiss } from "./dropdown/Dropdown";
48
48
  export { DropdownTool } from "./dropdown/DropdownTool";
49
49
  export { EmptyContent } from "./empty/EmptyContent";
50
- export { Icon } from "./icon/Icon";
50
+ export { Icon, getIconProps } from "./icon/Icon";
51
51
  export { Image, Video } from "./media/Media";
52
52
  export { ContextMenu } from "./menu/ContextMenu";
53
53
  export { Menu } from "./menu/Menu";
@@ -30,8 +30,9 @@ import { HotKeyLabel } from "../../hotkeys/HotKeyLabel";
30
30
  import { Tooltip } from "../../overlays";
31
31
  import { type PolymorphicProps } from "../../types";
32
32
  import { Badge, getBadgeProps } from "../badge/Badge";
33
- import { Icon } from "../icon/Icon";
33
+ import { getIconProps, Icon } from "../icon/Icon";
34
34
  import { type MenuItemProps } from "./types";
35
+ import { get } from "http";
35
36
 
36
37
  /**
37
38
  * A menu item component that can be used in a dropdown or menu.
@@ -60,10 +61,7 @@ export const MenuItem = <Tag extends React.ElementType = "button">({
60
61
  color = "primary",
61
62
  className,
62
63
  icon,
63
- iconBg,
64
- iconColor,
65
64
  appendLabel,
66
- rtlFlip,
67
65
  altIcon,
68
66
  id,
69
67
  active,
@@ -98,13 +96,10 @@ export const MenuItem = <Tag extends React.ElementType = "button">({
98
96
  return (
99
97
  <Icon
100
98
  className={classNames("fabric-menuIcon", minimal && "minimal")}
101
- icon={path ?? ""}
102
- bg={iconBg}
103
- color={iconColor}
104
- rtlFlip={rtlFlip}
99
+ {...getIconProps(path ?? "")}
105
100
  />
106
101
  );
107
- }, [icon, iconBg, iconColor, rtlFlip, minimal, label]);
102
+ }, [icon, minimal, label]);
108
103
 
109
104
  const Wrapper = useCallback(
110
105
  ({ children, ...rest }: AnyObject) => {
@@ -29,15 +29,11 @@ import {
29
29
  type ChildrenProp,
30
30
  type ColorState,
31
31
  type CssProp,
32
- type IconProps,
33
32
  type TestProps,
34
33
  } from "../../types";
34
+ import { IconProps } from "../icon/Icon";
35
35
 
36
- export interface MenuItemProps
37
- extends CssProp,
38
- AriaProps,
39
- TestProps,
40
- IconProps {
36
+ export interface MenuItemProps extends CssProp, AriaProps, TestProps {
41
37
  /**
42
38
  * menu id passed via menu.onClick
43
39
  */
@@ -54,6 +50,10 @@ export interface MenuItemProps
54
50
  * menu color
55
51
  */
56
52
  color?: ColorState;
53
+ /**
54
+ * icon path or props
55
+ */
56
+ icon?: IconProps;
57
57
  /**
58
58
  * item active
59
59
  */