@react-fabric/core 1.0.0-beta.3 → 1.0.0-beta.30

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 (207) hide show
  1. package/css/index.js +14 -14
  2. package/css/reset/_reset.css +1 -1
  3. package/dist/cjs/components/actionLabel/ActionLabel.js +1 -0
  4. package/dist/cjs/components/animations/Animations.js +14 -7
  5. package/dist/cjs/components/avatar/Avatar.js +8 -10
  6. package/dist/cjs/components/avatar/AvatarGroup.js +1 -0
  7. package/dist/cjs/components/badge/Badge.js +5 -4
  8. package/dist/cjs/components/breadcrumbs/Breadcrumbs.js +5 -2
  9. package/dist/cjs/components/button/Button.js +5 -4
  10. package/dist/cjs/components/button/Button.module.css +1 -1
  11. package/dist/cjs/components/button/ButtonGroup.js +3 -1
  12. package/dist/cjs/components/button/ConfirmButton.js +7 -2
  13. package/dist/cjs/components/button/ToggleButtonGroup.js +2 -1
  14. package/dist/cjs/components/callout/Callout.js +7 -2
  15. package/dist/cjs/components/card/Card.js +5 -3
  16. package/dist/cjs/components/card/CardCover.js +1 -1
  17. package/dist/cjs/components/chip/Chip.js +9 -4
  18. package/dist/cjs/components/chip/Chip.module.css +1 -1
  19. package/dist/cjs/components/collapsable/Collapsable.js +3 -2
  20. package/dist/cjs/components/divider/Divider.js +4 -3
  21. package/dist/cjs/components/divider/Divider.module.css +1 -0
  22. package/dist/cjs/components/dropdown/Dropdown.js +4 -2
  23. package/dist/cjs/components/dropdown/DropdownTool.js +4 -3
  24. package/dist/cjs/components/icon/Icon.js +14 -12
  25. package/dist/cjs/components/icon/Icon.module.css +1 -1
  26. package/dist/cjs/components/menu/ContextMenu.js +30 -10
  27. package/dist/cjs/components/menu/Menu.js +39 -20
  28. package/dist/cjs/components/menu/MenuItem.js +29 -14
  29. package/dist/cjs/components/navigator/Navigator.js +16 -9
  30. package/dist/cjs/components/panel/Panel.js +3 -1
  31. package/dist/cjs/components/progress/ProgressBar.js +2 -1
  32. package/dist/cjs/components/progress/ProgressCircle.js +2 -1
  33. package/dist/cjs/components/tabpanel/Tab.js +55 -36
  34. package/dist/cjs/components/tabpanel/TabPanel.js +19 -14
  35. package/dist/cjs/components/tabpanel/TabPanel.module.css +1 -1
  36. package/dist/cjs/core/aside/Aside.js +6 -2
  37. package/dist/cjs/core/content/Content.js +8 -5
  38. package/dist/cjs/core/headfoot/HeadFoot.js +3 -2
  39. package/dist/cjs/core/headfoot/HeadFoot.module.css +1 -1
  40. package/dist/cjs/core/page/Page.js +1 -0
  41. package/dist/cjs/core/responsive/Responsive.js +1 -1
  42. package/dist/cjs/core/section/Section.module.css +1 -1
  43. package/dist/cjs/hooks/useNavigator.js +6 -4
  44. package/dist/cjs/index.js +7 -2
  45. package/dist/cjs/overlays/alert/Alert.js +42 -17
  46. package/dist/cjs/overlays/alert/Alert.module.css +1 -1
  47. package/dist/cjs/overlays/flyout/Flyout.js +40 -42
  48. package/dist/cjs/overlays/message/Message.js +1 -1
  49. package/dist/cjs/overlays/modal/Modal.js +4 -5
  50. package/dist/cjs/overlays/toast/Toast.js +1 -1
  51. package/dist/cjs/overlays/tooltip/Tooltip.js +3 -3
  52. package/dist/cjs/overlays/tooltip/Tooltip.module.css +1 -1
  53. package/dist/cjs/types/icons.js +3 -0
  54. package/dist/cjs/typography/Abbr.js +1 -1
  55. package/dist/cjs/typography/{Link.js → Anchor.js} +4 -3
  56. package/dist/cjs/typography/Mark.js +1 -1
  57. package/dist/cjs/typography/Text.js +2 -2
  58. package/dist/cjs/typography/Title.js +3 -2
  59. package/dist/cjs/typography/Typography.module.css +1 -1
  60. package/dist/cjs/utils/cloneElement.js +44 -0
  61. package/dist/esm/components/actionLabel/ActionLabel.js +1 -0
  62. package/dist/esm/components/animations/Animations.js +14 -7
  63. package/dist/esm/components/avatar/Avatar.js +9 -11
  64. package/dist/esm/components/avatar/AvatarGroup.js +1 -0
  65. package/dist/esm/components/badge/Badge.js +5 -4
  66. package/dist/esm/components/breadcrumbs/Breadcrumbs.js +5 -2
  67. package/dist/esm/components/button/Button.js +5 -4
  68. package/dist/esm/components/button/Button.module.css +1 -1
  69. package/dist/esm/components/button/ButtonGroup.js +4 -2
  70. package/dist/esm/components/button/ConfirmButton.js +7 -2
  71. package/dist/esm/components/button/ToggleButtonGroup.js +3 -2
  72. package/dist/esm/components/callout/Callout.js +7 -2
  73. package/dist/esm/components/card/Card.js +5 -3
  74. package/dist/esm/components/card/CardCover.js +1 -1
  75. package/dist/esm/components/chip/Chip.js +9 -4
  76. package/dist/esm/components/chip/Chip.module.css +1 -1
  77. package/dist/esm/components/collapsable/Collapsable.js +3 -2
  78. package/dist/esm/components/divider/Divider.js +4 -3
  79. package/dist/esm/components/divider/Divider.module.css +1 -0
  80. package/dist/esm/components/dropdown/Dropdown.js +4 -2
  81. package/dist/esm/components/dropdown/DropdownTool.js +4 -3
  82. package/dist/esm/components/icon/Icon.js +14 -12
  83. package/dist/esm/components/icon/Icon.module.css +1 -1
  84. package/dist/esm/components/menu/ContextMenu.js +32 -12
  85. package/dist/esm/components/menu/Menu.js +41 -22
  86. package/dist/esm/components/menu/MenuItem.js +23 -8
  87. package/dist/esm/components/navigator/Navigator.js +16 -9
  88. package/dist/esm/components/panel/Panel.js +3 -1
  89. package/dist/esm/components/progress/ProgressBar.js +2 -1
  90. package/dist/esm/components/progress/ProgressCircle.js +2 -1
  91. package/dist/esm/components/tabpanel/Tab.js +56 -37
  92. package/dist/esm/components/tabpanel/TabPanel.js +19 -14
  93. package/dist/esm/components/tabpanel/TabPanel.module.css +1 -1
  94. package/dist/esm/core/aside/Aside.js +6 -2
  95. package/dist/esm/core/content/Content.js +8 -5
  96. package/dist/esm/core/headfoot/HeadFoot.js +3 -2
  97. package/dist/esm/core/headfoot/HeadFoot.module.css +1 -1
  98. package/dist/esm/core/page/Page.js +1 -0
  99. package/dist/esm/core/responsive/Responsive.js +1 -1
  100. package/dist/esm/core/section/Section.module.css +1 -1
  101. package/dist/esm/hooks/useNavigator.js +7 -5
  102. package/dist/esm/index.js +4 -1
  103. package/dist/esm/overlays/alert/Alert.js +31 -6
  104. package/dist/esm/overlays/alert/Alert.module.css +1 -1
  105. package/dist/esm/overlays/flyout/Flyout.js +41 -43
  106. package/dist/esm/overlays/message/Message.js +1 -1
  107. package/dist/esm/overlays/modal/Modal.js +5 -6
  108. package/dist/esm/overlays/toast/Toast.js +1 -1
  109. package/dist/esm/overlays/tooltip/Tooltip.js +3 -3
  110. package/dist/esm/overlays/tooltip/Tooltip.module.css +1 -1
  111. package/dist/esm/types/icons.js +3 -0
  112. package/dist/esm/typography/Abbr.js +1 -1
  113. package/dist/esm/typography/{Link.js → Anchor.js} +4 -3
  114. package/dist/esm/typography/Mark.js +1 -1
  115. package/dist/esm/typography/Text.js +2 -2
  116. package/dist/esm/typography/Title.js +3 -2
  117. package/dist/esm/typography/Typography.module.css +1 -1
  118. package/dist/esm/utils/cloneElement.js +44 -0
  119. package/dist/types/components/actionLabel/ActionLabel.d.ts +2 -2
  120. package/dist/types/components/animations/Animations.d.ts +1 -1
  121. package/dist/types/components/badge/Badge.d.ts +5 -1
  122. package/dist/types/components/breadcrumbs/Breadcrumbs.d.ts +2 -2
  123. package/dist/types/components/button/Button.d.ts +5 -3
  124. package/dist/types/components/button/ConfirmButton.d.ts +6 -1
  125. package/dist/types/components/card/Card.d.ts +3 -3
  126. package/dist/types/components/chip/Chip.d.ts +1 -1
  127. package/dist/types/components/collapsable/Collapsable.d.ts +5 -1
  128. package/dist/types/components/dropdown/DropdownTool.d.ts +2 -1
  129. package/dist/types/components/media/Media.d.ts +2 -2
  130. package/dist/types/components/menu/ContextMenu.d.ts +2 -1
  131. package/dist/types/components/menu/MenuItem.d.ts +1 -1
  132. package/dist/types/components/navigator/Navigator.d.ts +3 -3
  133. package/dist/types/components/tabpanel/Tab.d.ts +4 -4
  134. package/dist/types/components/tabpanel/TabPanel.d.ts +10 -1
  135. package/dist/types/core/aside/Aside.d.ts +7 -3
  136. package/dist/types/core/content/Content.d.ts +3 -2
  137. package/dist/types/core/responsive/Responsive.d.ts +1 -1
  138. package/dist/types/core/theme/ThemeProvider.d.ts +1 -1
  139. package/dist/types/hooks/useOverlayService.d.ts +3 -3
  140. package/dist/types/index.d.ts +3 -0
  141. package/dist/types/overlays/alert/Alert.d.ts +9 -1
  142. package/dist/types/overlays/flyout/Flyout.d.ts +3 -2
  143. package/dist/types/overlays/modal/Modal.d.ts +4 -3
  144. package/dist/types/types/icons.d.ts +3 -0
  145. package/dist/types/types/index.d.ts +8 -1
  146. package/dist/types/typography/{Link.d.ts → Anchor.d.ts} +2 -2
  147. package/dist/types/typography/index.d.ts +1 -1
  148. package/dist/types/utils/cloneElement.d.ts +2 -0
  149. package/dist/types/utils/index.d.ts +1 -0
  150. package/package.json +5 -5
  151. package/src/components/actionLabel/ActionLabel.tsx +13 -3
  152. package/src/components/animations/Animations.tsx +9 -3
  153. package/src/components/avatar/Avatar.tsx +69 -81
  154. package/src/components/avatar/AvatarGroup.tsx +1 -0
  155. package/src/components/badge/Badge.tsx +9 -4
  156. package/src/components/breadcrumbs/Breadcrumbs.tsx +9 -4
  157. package/src/components/button/Button.module.css +8 -1
  158. package/src/components/button/Button.tsx +12 -9
  159. package/src/components/button/ButtonGroup.tsx +3 -2
  160. package/src/components/button/ConfirmButton.tsx +15 -5
  161. package/src/components/button/ToggleButtonGroup.tsx +3 -2
  162. package/src/components/callout/Callout.tsx +12 -3
  163. package/src/components/card/Card.tsx +4 -0
  164. package/src/components/chip/Chip.module.css +4 -1
  165. package/src/components/chip/Chip.tsx +9 -4
  166. package/src/components/collapsable/Collapsable.tsx +6 -0
  167. package/src/components/divider/Divider.module.css +32 -0
  168. package/src/components/divider/Divider.tsx +3 -2
  169. package/src/components/dropdown/Dropdown.tsx +3 -2
  170. package/src/components/dropdown/DropdownTool.tsx +4 -2
  171. package/src/components/icon/Icon.module.css +0 -1
  172. package/src/components/icon/Icon.tsx +48 -58
  173. package/src/components/media/Media.tsx +2 -2
  174. package/src/components/menu/ContextMenu.tsx +36 -11
  175. package/src/components/menu/Menu.tsx +51 -30
  176. package/src/components/menu/MenuItem.tsx +14 -3
  177. package/src/components/navigator/Navigator.tsx +17 -4
  178. package/src/components/panel/Panel.tsx +3 -1
  179. package/src/components/tabpanel/Tab.tsx +74 -59
  180. package/src/components/tabpanel/TabPanel.module.css +19 -30
  181. package/src/components/tabpanel/TabPanel.tsx +33 -10
  182. package/src/core/aside/Aside.tsx +17 -3
  183. package/src/core/content/Content.tsx +16 -10
  184. package/src/core/headfoot/HeadFoot.module.css +2 -0
  185. package/src/core/headfoot/HeadFoot.tsx +1 -1
  186. package/src/core/page/Page.tsx +1 -0
  187. package/src/core/responsive/Responsive.tsx +3 -2
  188. package/src/core/section/Section.module.css +1 -1
  189. package/src/core/theme/ThemeProvider.tsx +1 -1
  190. package/src/hooks/useNavigator.tsx +10 -5
  191. package/src/hooks/useOverlayService.tsx +12 -4
  192. package/src/index.ts +4 -0
  193. package/src/overlays/alert/Alert.module.css +1 -1
  194. package/src/overlays/alert/Alert.tsx +30 -4
  195. package/src/overlays/flyout/Flyout.tsx +63 -62
  196. package/src/overlays/modal/Modal.tsx +13 -8
  197. package/src/overlays/tooltip/Tooltip.module.css +7 -7
  198. package/src/overlays/tooltip/Tooltip.tsx +4 -4
  199. package/src/types/icons.ts +6 -0
  200. package/src/types/index.ts +10 -9
  201. package/src/typography/{Link.tsx → Anchor.tsx} +3 -3
  202. package/src/typography/Text.tsx +1 -1
  203. package/src/typography/Title.tsx +0 -1
  204. package/src/typography/Typography.module.css +4 -2
  205. package/src/typography/index.ts +1 -1
  206. package/src/utils/cloneElement.ts +44 -0
  207. package/src/utils/index.ts +1 -0
@@ -24,8 +24,7 @@
24
24
  import { isSvgPath } from "@react-fabric/utilities";
25
25
  import BoringAvatar from "boring-avatars";
26
26
  import classNames from "classnames";
27
- import { useState } from "react";
28
- import { useMemoDebugger } from "../../hooks/useEffectDebugger";
27
+ import { useMemo, useState } from "react";
29
28
  import {
30
29
  type AriaProps,
31
30
  type ColorType,
@@ -109,89 +108,78 @@ export const Avatar = ({
109
108
  const [fallback, setFallback] = useState(true);
110
109
 
111
110
  /** ***************** style map *******************/
112
- const styles = useMemoDebugger(
113
- () => {
114
- const s: KeyValue = {};
115
- if (bg) {
116
- s.backgroundColor = getColor(bg);
117
- }
118
- if (color) {
119
- s.color = getColor(color);
120
- }
121
- if (size && !(size in SizeMap)) {
122
- s.fontSize = size;
123
- }
124
- if (size && size in SizeMap) {
125
- s.fontSize = SizeMap[size];
126
- }
127
- return s;
128
- },
129
- [bg, color, size],
130
- "Avatar styles",
131
- );
111
+ const styles = useMemo(() => {
112
+ const s: KeyValue = {};
113
+ if (bg) {
114
+ s.backgroundColor = getColor(bg);
115
+ }
116
+ if (color) {
117
+ s.color = getColor(color);
118
+ }
119
+ if (size && !(size in SizeMap)) {
120
+ s.fontSize = size;
121
+ }
122
+ if (size && size in SizeMap) {
123
+ s.fontSize = SizeMap[size];
124
+ }
125
+ return s;
126
+ }, [bg, color, size]);
132
127
 
133
128
  /** ***************** render icon *******************/
134
- const avatarImage = useMemoDebugger(
135
- () => {
136
- setFallback(!avatar);
129
+ const avatarImage = useMemo(() => {
130
+ setFallback(!avatar);
131
+ return (
132
+ avatar && (
133
+ <div className="contents">
134
+ <div
135
+ className={classNames(
136
+ classes.imgPlaceholder,
137
+ "absolute inset-0 bg-gray animate-pulse",
138
+ )}
139
+ />
140
+ <img
141
+ src={avatar}
142
+ alt={avatar}
143
+ className="align-baseline"
144
+ onError={() => setFallback(true)}
145
+ onLoad={(e) => e.currentTarget.previousElementSibling?.remove()}
146
+ />
147
+ </div>
148
+ )
149
+ );
150
+ }, [avatar]);
151
+
152
+ const fallbackAvatar = useMemo(() => {
153
+ if (fallbackIcon) {
154
+ return isSvgPath(fallbackIcon) ? (
155
+ <svg viewBox={viewBox}>
156
+ <path fill="currentColor" d={fallbackIcon.toString()} />
157
+ </svg>
158
+ ) : (
159
+ <i className={fallbackIcon} />
160
+ );
161
+ }
162
+ if (variant === "text") {
163
+ const [, first, second, group] = name.match(
164
+ /(?=(\w).* (\w).*)|(?=(\w\w).*)/,
165
+ ) as string[];
137
166
  return (
138
- avatar && (
139
- <div className="contents">
140
- <div
141
- className={classNames(
142
- classes.imgPlaceholder,
143
- "absolute inset-0 bg-gray animate-pulse",
144
- )}
145
- />
146
- <img
147
- src={avatar}
148
- alt={avatar}
149
- className="align-baseline"
150
- onError={() => setFallback(true)}
151
- onLoad={(e) => e.currentTarget.previousElementSibling?.remove()}
152
- />
153
- </div>
154
- )
167
+ <svg role="img">
168
+ <text
169
+ x="50%"
170
+ y="50%"
171
+ dy=".1em"
172
+ dominantBaseline="middle"
173
+ textAnchor="middle"
174
+ style={{ fontSize: ".5em", fontWeight: 500 }}
175
+ >
176
+ {group ?? `${first}${second}`}
177
+ </text>
178
+ </svg>
155
179
  );
156
- },
157
- [avatar],
158
- "Avatar icon",
159
- );
160
-
161
- const fallbackAvatar = useMemoDebugger(
162
- () => {
163
- if (fallbackIcon) {
164
- return isSvgPath(fallbackIcon) ? (
165
- <svg viewBox={viewBox}>
166
- <path fill="currentColor" d={fallbackIcon.toString()} />
167
- </svg>
168
- ) : (
169
- <i className={fallbackIcon} />
170
- );
171
- }
172
- if (variant === "text") {
173
- const [, first, second, group] =
174
- name.match(/(?=(\w).* (\w).*)|(?=(\w\w).*)/) ?? [];
175
- return (
176
- <svg role="img">
177
- <text
178
- x="50%"
179
- y="50%"
180
- dy=".1em"
181
- dominantBaseline="middle"
182
- textAnchor="middle"
183
- style={{ fontSize: ".5em", fontWeight: 500 }}
184
- >
185
- {group ?? `${first}${second}`}
186
- </text>
187
- </svg>
188
- );
189
- }
190
- return <BoringAvatar square size={64} variant={variant} name={name} />;
191
- },
192
- [name, variant, fallbackIcon],
193
- "Avatar fallback",
194
- );
180
+ }
181
+ return <BoringAvatar square size={64} variant={variant} name={name} />;
182
+ }, [name, variant, fallbackIcon]);
195
183
 
196
184
  return (
197
185
  <dfn
@@ -115,6 +115,7 @@ export const AvatarGroup = ({
115
115
  {avatars}
116
116
  {!!diff && (
117
117
  <dfn
118
+ data-ref="avatarCount"
118
119
  className={classNames(
119
120
  classes.avatar,
120
121
  "select-none relative overflow-hidden inline-block box-content leading-none not-italic text-center",
@@ -43,6 +43,10 @@ export interface BadgeProps
43
43
  * make wrapper a block element
44
44
  */
45
45
  block?: boolean;
46
+ /**
47
+ * inline badge
48
+ */
49
+ inline?: boolean;
46
50
  /**
47
51
  * badge value
48
52
  */
@@ -90,6 +94,7 @@ export const Badge = ({
90
94
  max,
91
95
  ping,
92
96
  block,
97
+ inline,
93
98
  placement = "top-end",
94
99
  children,
95
100
  // @ts-expect-error ignore
@@ -120,7 +125,7 @@ export const Badge = ({
120
125
  return (
121
126
  <div
122
127
  className={classNames(
123
- forButton ? "contents" : "relative",
128
+ forButton || inline ? "contents" : "relative",
124
129
  block ? "block" : "inline-block",
125
130
  )}
126
131
  >
@@ -129,7 +134,7 @@ export const Badge = ({
129
134
  ...rest,
130
135
  ref: innerRef,
131
136
  })}
132
- {(!!ping || label) && (
137
+ {(!!ping || (label ?? icon)) && (
133
138
  <div
134
139
  data-ref="badge"
135
140
  data-ping={ping}
@@ -137,8 +142,8 @@ export const Badge = ({
137
142
  className={classNames(
138
143
  classes.badge,
139
144
  className,
140
- "inline-block p-px min-w-2 min-h-2 text-center select-none rounded-full leading-none z-5 pointer-events-none",
141
- forButton && !placement ? "relative" : "absolute",
145
+ "inline-block p-px min-w-2 min-h-2 text-center select-none rounded-full leading-none z-2 pointer-events-none",
146
+ (forButton && !placement) || inline ? "relative" : "absolute",
142
147
  )}
143
148
  >
144
149
  {label && <span className="p-1">{label}</span>}
@@ -24,14 +24,14 @@
24
24
  import classNames from "classnames";
25
25
  import { Children, useMemo } from "react";
26
26
  import { type AriaProps, type ChildrenProp, type CssProp } from "../../types";
27
- import { Link } from "../../typography/Link";
27
+ import { Anchor } from "../../typography/Anchor";
28
28
  import { Dropdown } from "../dropdown/Dropdown";
29
29
  import classes from "./Breadcrumbs.module.css";
30
30
 
31
31
  export interface BreadcrumbProps
32
32
  extends CssProp,
33
33
  AriaProps,
34
- ChildrenProp<typeof Link> {
34
+ ChildrenProp<typeof Anchor> {
35
35
  /**
36
36
  * breadcrumb styling
37
37
  */
@@ -64,6 +64,7 @@ export const Breadcrumbs = ({
64
64
 
65
65
  return (
66
66
  <nav
67
+ data-ref="breadcrumbs"
67
68
  data-color={color}
68
69
  data-variant={variant}
69
70
  className={classNames(
@@ -84,8 +85,12 @@ export const Breadcrumbs = ({
84
85
  ))}
85
86
  {overflow && (
86
87
  <Dropdown closeOnClick showArrow>
87
- <li className={classes.breadcrumbLink} data-separator={separator}>
88
- <Link>...</Link>
88
+ <li
89
+ className={classes.breadcrumbLink}
90
+ data-separator={separator}
91
+ data-ref="breadcrumbOverflow"
92
+ >
93
+ <Anchor data->...</Anchor>
89
94
  </li>
90
95
  <div
91
96
  data-color={color}
@@ -166,6 +166,13 @@
166
166
  --outline: var(--color);
167
167
  }
168
168
 
169
+ &[data-variant="soft"] {
170
+ --bg: color-mix(in lab, var(--color) 25%, var(--fabric-bg));
171
+ --bg-hover: color-mix(in lab, var(--color) 35%, var(--fabric-bg));
172
+ --bg-click: color-mix(in lab, var(--color) 50%, theme(colors.tint.50));
173
+ --bg-active: color-mix(in lab, var(--color) 50%, theme(colors.tint.50));
174
+ }
175
+
169
176
  &[data-variant="solid"] {
170
177
  --outline: var(--color);
171
178
  --bg: color-mix(in lab, var(--color) 96%, var(--fabric-text));
@@ -245,7 +252,7 @@
245
252
  background-size: 1em 1em;
246
253
 
247
254
  & :global {
248
- animation: progress 750ms linear infinite;
255
+ animation: bgprogress 750ms linear infinite;
249
256
  }
250
257
  }
251
258
 
@@ -85,7 +85,7 @@ export interface BaseProps
85
85
  /**
86
86
  * button styling
87
87
  */
88
- variant?: "outline" | "solid" | "link";
88
+ variant?: "outline" | "soft" | "solid" | "link";
89
89
  /**
90
90
  * active state with click disabled
91
91
  */
@@ -147,10 +147,14 @@ export interface BaseProps
147
147
  onWheel?: WheelEventHandler;
148
148
  }
149
149
 
150
- export type ButtonProps =
150
+ type ButtonTypeProps =
151
151
  | { children: string | React.ReactElement; "aria-label"?: string }
152
152
  | { children?: never; "aria-label": string };
153
153
 
154
+ export type ButtonProps<Tag extends React.ElementType = "button"> = BaseProps &
155
+ ButtonTypeProps &
156
+ PolymorphicProps<Tag>;
157
+
154
158
  /**
155
159
  * Clickable action button
156
160
  */
@@ -186,7 +190,7 @@ export const Button = <Tag extends React.ElementType = "button">({
186
190
  // @ts-expect-error ignore
187
191
  "data-ref": dataRef,
188
192
  ...aria
189
- }: BaseProps & ButtonProps & PolymorphicProps<Tag>) => {
193
+ }: ButtonProps<Tag>) => {
190
194
  const refEl = useRef<AnyObject>(null);
191
195
  const [busy, setBusy] = useState(false);
192
196
  const [actionDone, setActionDone] = useState(false);
@@ -240,6 +244,10 @@ export const Button = <Tag extends React.ElementType = "button">({
240
244
  return getBadgeProps(badge);
241
245
  }, [badge]);
242
246
 
247
+ const hotKeyHandler = useRef(() => {
248
+ !disabled && refEl.current?.click();
249
+ });
250
+
243
251
  const E = as ?? "button";
244
252
  return (
245
253
  <div
@@ -254,12 +262,7 @@ export const Button = <Tag extends React.ElementType = "button">({
254
262
  data-loading={busy || loading}
255
263
  data-disabled={disabled}
256
264
  >
257
- {hotKey && (
258
- <HotKey
259
- keyCombo={hotKey}
260
- handler={() => !disabled && refEl.current?.click()}
261
- />
262
- )}
265
+ {hotKey && <HotKey keyCombo={hotKey} handler={hotKeyHandler.current} />}
263
266
  <TooltipWrapper {...tooltipProps}>
264
267
  <E
265
268
  ref={mergeRefs(ref, refEl)}
@@ -22,7 +22,7 @@
22
22
  */
23
23
 
24
24
  import classNames from "classnames";
25
- import { Children, cloneElement } from "react";
25
+ import { cloneElement } from "react";
26
26
  import {
27
27
  type AriaProps,
28
28
  type ChildrenProp,
@@ -32,6 +32,7 @@ import {
32
32
  type SizeType,
33
33
  type TestProps,
34
34
  } from "../../types";
35
+ import { cloneChildren } from "../../utils";
35
36
  import { type Button } from "./Button";
36
37
  import classes from "./Button.module.css";
37
38
 
@@ -96,7 +97,7 @@ export const ButtonGroup = ({
96
97
  )}
97
98
  {...aria}
98
99
  >
99
- {Children.map(children, (child: AnyObject) =>
100
+ {cloneChildren(children, (child: AnyObject) =>
100
101
  cloneElement(child, {
101
102
  color,
102
103
  size,
@@ -22,18 +22,19 @@
22
22
  */
23
23
 
24
24
  import {
25
- FloatingArrow,
26
- FloatingFocusManager,
27
- FloatingPortal,
28
25
  arrow,
29
26
  autoUpdate,
30
27
  flip,
28
+ FloatingArrow,
29
+ FloatingFocusManager,
30
+ FloatingPortal,
31
31
  offset,
32
32
  shift,
33
33
  useClick,
34
34
  useDismiss,
35
35
  useFloating,
36
36
  useInteractions,
37
+ type Placement,
37
38
  } from "@floating-ui/react";
38
39
  import { mergeRefs } from "@react-fabric/utilities";
39
40
  import classNames from "classnames";
@@ -66,6 +67,10 @@ interface ExtendedProps extends Omit<BaseProps, "onClick">, RefProp {
66
67
  * ok label
67
68
  */
68
69
  cancelLabel?: string;
70
+ /**
71
+ * dropdown placement
72
+ */
73
+ placement?: Placement;
69
74
  /**
70
75
  * click handler, return Promise to autoset loading state
71
76
  */
@@ -85,6 +90,7 @@ export const ConfirmButton = <Tag extends React.ElementType = "button">({
85
90
  cancelLabel,
86
91
  onClick,
87
92
  loading,
93
+ placement = "bottom",
88
94
  actionMessage,
89
95
  showActionDone,
90
96
  showActionDoneEvent = "click",
@@ -127,7 +133,7 @@ export const ConfirmButton = <Tag extends React.ElementType = "button">({
127
133
  }
128
134
  },
129
135
  strategy: "fixed",
130
- placement: "bottom",
136
+ placement,
131
137
  whileElementsMounted: autoUpdate,
132
138
  middleware: [
133
139
  shift({ padding: 8 }),
@@ -185,11 +191,14 @@ export const ConfirmButton = <Tag extends React.ElementType = "button">({
185
191
  {...getFloatingProps()}
186
192
  >
187
193
  <div className="font-medium ">
188
- <p className="py-2 px-4">{message}</p>
194
+ <p className="py-2 px-4" data-ref="confirmMessage">
195
+ {message}
196
+ </p>
189
197
  <div className="flex justify-end py-2 px-4 gap-2">
190
198
  <Button
191
199
  size="sm"
192
200
  variant="link"
201
+ data-ref="confirmCancel"
193
202
  color={color}
194
203
  onClick={() => [clickHandler(false), setIsOpen(false)]}
195
204
  >
@@ -200,6 +209,7 @@ export const ConfirmButton = <Tag extends React.ElementType = "button">({
200
209
  variant="solid"
201
210
  color={color}
202
211
  autoFocus
212
+ data-ref="confirmOk"
203
213
  onClick={() => [clickHandler(true), setIsOpen(false)]}
204
214
  >
205
215
  {okLabel ?? t("action.ok")}
@@ -23,7 +23,7 @@
23
23
 
24
24
  import { EMPTY_ARRAY, isArray } from "@react-fabric/utilities";
25
25
  import classNames from "classnames";
26
- import { Children, cloneElement, useCallback, useMemo } from "react";
26
+ import { cloneElement, useCallback, useMemo } from "react";
27
27
  import { useControlledValue } from "../../hooks/useControlledValue";
28
28
  import {
29
29
  type AriaProps,
@@ -32,6 +32,7 @@ import {
32
32
  type CssProp,
33
33
  type SizeType,
34
34
  } from "../../types";
35
+ import { cloneChildren } from "../../utils";
35
36
  import { type ButtonProps } from "./Button";
36
37
  import classes from "./Button.module.css";
37
38
 
@@ -140,7 +141,7 @@ export const ToggleButtonGroup = ({
140
141
  )}
141
142
  {...aria}
142
143
  >
143
- {Children.map(children, (child: AnyObject) =>
144
+ {cloneChildren(children, (child: AnyObject) =>
144
145
  cloneElement(child, {
145
146
  color,
146
147
  size,
@@ -90,17 +90,26 @@ export const Callout = ({
90
90
  )}
91
91
  {...aria}
92
92
  >
93
- {legend && <legend className="px-2 mx-4 font-medium">{legend}</legend>}
93
+ {legend && (
94
+ <legend className="px-2 mx-4 font-medium" data-ref="calloutLegend">
95
+ {legend}
96
+ </legend>
97
+ )}
94
98
  <div className={classNames("break-words whitespace-break-spaces p-2")}>
95
99
  <div className="flex flex-nowrap items-center text-xl pe-4 gap-2 mb-4 empty:mb-0">
96
- {icon && <Icon icon={icon} />}
97
- {title && <p className="flex-1">{title}</p>}
100
+ {icon && <Icon icon={icon} data-ref="calloutIcon" />}
101
+ {title && (
102
+ <p className="flex-1" data-ref="calloutTitle">
103
+ {title}
104
+ </p>
105
+ )}
98
106
  </div>
99
107
  <div className="pe-4">{children}</div>
100
108
  </div>
101
109
  {onClose && (
102
110
  <Icon
103
111
  size="md"
112
+ data-ref="calloutClose"
104
113
  className={classNames("absolute end-2", legend ? "top-0" : "top-2")}
105
114
  icon={CoreIcons.close}
106
115
  onClick={onClose}
@@ -39,6 +39,7 @@ import {
39
39
  type AriaProps,
40
40
  type ChildrenProp,
41
41
  type CssProp,
42
+ type RefProp,
42
43
  type TestProps,
43
44
  } from "../../types";
44
45
  import { nodeCheck } from "../../utils";
@@ -48,6 +49,7 @@ export interface CardProps
48
49
  extends CssProp,
49
50
  AriaProps,
50
51
  TestProps,
52
+ RefProp<HTMLDivElement>,
51
53
  ChildrenProp<React.ReactElement<HeadFootProps | ContentProps>> {
52
54
  /**
53
55
  * apply flex fill styling
@@ -94,6 +96,7 @@ export const Card = ({
94
96
  draggable,
95
97
  dragKey,
96
98
  dragData,
99
+ ref,
97
100
  ...aria
98
101
  }: CardProps) => {
99
102
  const [header, body, footer] = useMemo(() => {
@@ -136,6 +139,7 @@ export const Card = ({
136
139
  dragKey &&
137
140
  e.dataTransfer?.setData(dragKey, JSON.stringify(dragData))
138
141
  }
142
+ ref={ref}
139
143
  {...aria}
140
144
  >
141
145
  {header}
@@ -25,13 +25,16 @@
25
25
  .chip {
26
26
  --blank-gradient: linear-gradient(to bottom, #00000005 0%, #0000 10%);
27
27
 
28
+ font-size: 0.875rem;
28
29
  color: theme(colors.tint.500);
30
+
29
31
  background-image: var(--blank-gradient);
30
32
  outline: 1px solid color-mix(in lab, currentcolor 20%, var(--fabric-bg));
31
33
  outline-offset: -1px;
32
34
 
33
35
  & > .chipLabel {
34
- padding: 0.25em 0.5em;
36
+ padding: 0 0.5em;
37
+ line-height: 1.5;
35
38
  }
36
39
 
37
40
  & > .chipIcon {
@@ -49,7 +49,7 @@ export interface ChipProps
49
49
  /**
50
50
  * chip size
51
51
  */
52
- size?: SizeType;
52
+ size?: SizeType | number | string;
53
53
  /**
54
54
  * chip color (CSS color / tailwind color)
55
55
  */
@@ -152,11 +152,12 @@ export const Chip = <Tag extends React.ElementType = "div">({
152
152
  <E
153
153
  ref={ref}
154
154
  role="term"
155
+ data-ref="chip"
155
156
  className={classNames(
156
157
  classes.chip,
157
158
  className,
158
159
  color && getColorClass(color),
159
- "select-none inline-flex flex-nowrap items-center max-w-72 text-sm leading-none rounded",
160
+ "select-none inline-flex flex-nowrap items-center align-middle max-w-72 rounded",
160
161
  rounded && "rounded-full",
161
162
  !!onClick && classes.clickable,
162
163
  disabled && classes.disabled,
@@ -164,11 +165,12 @@ export const Chip = <Tag extends React.ElementType = "div">({
164
165
  style={styles}
165
166
  data-variant={variant}
166
167
  data-inner-clickable={!!onClick}
167
- {...{ onClick: clickHandler }}
168
+ {...{ onClick: disabled ? undefined : clickHandler }}
168
169
  {...aria}
169
170
  >
170
171
  {icon && (
171
172
  <Icon
173
+ data-ref="chipIcon"
172
174
  className={classNames(classes.chipIcon, "m-1")}
173
175
  icon={icon}
174
176
  bg={iconBg}
@@ -179,7 +181,8 @@ export const Chip = <Tag extends React.ElementType = "div">({
179
181
  )}
180
182
  {children && (
181
183
  <label
182
- className={classNames(classes.chipLabel, "leading-none truncate")}
184
+ data-ref="chipLabel"
185
+ className={classNames(classes.chipLabel, "truncate")}
183
186
  >
184
187
  {children}
185
188
  </label>
@@ -187,6 +190,8 @@ export const Chip = <Tag extends React.ElementType = "div">({
187
190
  {onRemove && (
188
191
  <span
189
192
  role="none"
193
+ data-ref="chipRemove"
194
+ data-inner-cliackable
190
195
  className={classNames(
191
196
  classes.chipRemove,
192
197
  "cursor-pointer pe-1 opacity-65 hover:opacity-90",
@@ -66,6 +66,10 @@ export interface CollapsableProps
66
66
  * header button className
67
67
  */
68
68
  headerClassName?: string;
69
+ /**
70
+ * Header position sticky
71
+ */
72
+ stickyHeader?: boolean;
69
73
  /**
70
74
  * open state icon
71
75
  */
@@ -100,6 +104,7 @@ export const Collapsable = ({
100
104
  headerClassName,
101
105
  children,
102
106
  iconAlign,
107
+ stickyHeader,
103
108
  iconClosed = CoreIcons.chevronRight,
104
109
  iconOpen = CoreIcons.chevronDown,
105
110
  open,
@@ -138,6 +143,7 @@ export const Collapsable = ({
138
143
  classes.collapsableHead,
139
144
  "flex gap-1 flex-nowrap py-2 font-medium cursor-pointer items-center select-none hover:opacity-70",
140
145
  headerClassName,
146
+ stickyHeader && "bg-base sticky top-0 px-2 py-1 z-10",
141
147
  iconAlign === "end" ? "flex-row-reverse" : "flex-row",
142
148
  )}
143
149
  onClick={() => !disabled && setOpenState(!openState)}
@@ -0,0 +1,32 @@
1
+ /*
2
+ * React Fabric
3
+ * @version: 1.0.0
4
+ *
5
+ *
6
+ * The MIT License (MIT)
7
+ * Copyright (c) 2024 Adarsh Pastakia
8
+ *
9
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
10
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
11
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
12
+ * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
13
+ * subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in all copies or substantial
16
+ * portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19
+ * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ */
23
+
24
+ @layer comp {
25
+ .vertical {
26
+ margin-inline: 0.25rem;
27
+ }
28
+
29
+ .horizontal {
30
+ margin-block: 0.25rem;
31
+ }
32
+ }