@mirror-physics/fractal-ui 0.2.0-next.75 → 0.2.0-next.76
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.
- package/README.md +8 -0
- package/dist/index.cjs +41 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +140 -73
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +26 -9
- package/dist/index.d.ts +26 -9
- package/dist/index.js +41 -34
- package/dist/index.js.map +1 -1
- package/dist/tokens.css +71 -6
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -43,3 +43,11 @@ import { Button, Card, CardContent } from '@mirror-physics/fractal-ui'
|
|
|
43
43
|
npm run typecheck
|
|
44
44
|
npm run build
|
|
45
45
|
```
|
|
46
|
+
|
|
47
|
+
### Shared control sizes
|
|
48
|
+
|
|
49
|
+
Use `controlSize="xs" | "sm" | "md" | "lg" | "xl"` on Button, Dropdown, Input, NumberInput, TableSearch, PasswordInput, and Label. The default is `md`. Matching sizes share typography and padding; their block size derives from the line box, padding, and borders. Existing `Button.buttonSize` and `Dropdown.size` remain aliases; `controlSize` wins if both are supplied. Native numeric `Input.size` retains its HTML meaning.
|
|
50
|
+
|
|
51
|
+
Compose a persistent label and control in `className="fractal-field"` to use the shared label gap. For dropdowns, connect `Label.htmlFor` to `Dropdown.triggerId` and provide a meaningful `triggerLabel`. Use matching sizes across a row. Icons add a shared leading slot; centered action labels remain centered.
|
|
52
|
+
|
|
53
|
+
This changes the rendered geometry of existing size presets, including default controls. Remove product CSS that hardcodes the previous heights. Compact sizes suit pointer interfaces; choose an appropriately large target for touch. Custom multiline dropdown content may grow beyond the single-line minimum.
|
package/dist/index.cjs
CHANGED
|
@@ -161,31 +161,19 @@ var colorPalette = {
|
|
|
161
161
|
700: "var(--green-700)"
|
|
162
162
|
}
|
|
163
163
|
};
|
|
164
|
-
|
|
165
|
-
xs: { height: "28px", padding: "4px 8px", iconOnly: "28px", fontSize: "0.75rem" },
|
|
166
|
-
sm: { height: "32px", padding: "6px 12px", iconOnly: "32px", fontSize: "0.75rem" },
|
|
167
|
-
md: { height: "40px", padding: "8px 16px", iconOnly: "40px", fontSize: "0.875rem" },
|
|
168
|
-
lg: { height: "44px", padding: "10px 20px", iconOnly: "44px", fontSize: "1rem" },
|
|
169
|
-
xl: { height: "56px", padding: "14px 28px", iconOnly: "56px", fontSize: "1rem" }
|
|
170
|
-
};
|
|
171
|
-
function getButtonStyles(buttonType, isHovered, isActive, buttonSize, disabled, color, hasIconOnly) {
|
|
164
|
+
function getButtonStyles(buttonType, isHovered, isActive, disabled, color, hasIconOnly) {
|
|
172
165
|
const palette = colorPalette[color];
|
|
173
|
-
const size = sizeConfig[buttonSize];
|
|
174
166
|
const base = {
|
|
175
|
-
height: size.height,
|
|
176
|
-
padding: hasIconOnly ? "0" : size.padding,
|
|
177
167
|
borderRadius: hasIconOnly ? "var(--radius-lg, 8px)" : "var(--radius-full, 9999px)",
|
|
178
168
|
cursor: disabled ? "not-allowed" : "pointer",
|
|
179
|
-
fontSize: size.fontSize,
|
|
180
169
|
transition: "background-color 0.15s ease, border-color 0.15s ease, opacity 0.15s ease"
|
|
181
170
|
};
|
|
182
171
|
if (hasIconOnly) {
|
|
183
|
-
base.width = size.iconOnly;
|
|
184
172
|
base.justifyContent = "center";
|
|
185
173
|
}
|
|
186
174
|
if (disabled) {
|
|
187
175
|
if (buttonType === "ghost") {
|
|
188
|
-
return { ...base, backgroundColor: "transparent", border: "
|
|
176
|
+
return { ...base, backgroundColor: "transparent", border: "1px solid transparent", color: "var(--fg-disabled)" };
|
|
189
177
|
}
|
|
190
178
|
return { ...base, backgroundColor: "transparent", border: "1px solid var(--fg-disabled)", color: "var(--fg-disabled)" };
|
|
191
179
|
}
|
|
@@ -196,7 +184,7 @@ function getButtonStyles(buttonType, isHovered, isActive, buttonSize, disabled,
|
|
|
196
184
|
return {
|
|
197
185
|
...base,
|
|
198
186
|
backgroundColor: isActive ? palette[700] : isHovered ? palette[500] : palette[600],
|
|
199
|
-
border: "
|
|
187
|
+
border: "1px solid transparent",
|
|
200
188
|
color: "var(--fg-inverse)"
|
|
201
189
|
};
|
|
202
190
|
}
|
|
@@ -220,7 +208,7 @@ function getButtonStyles(buttonType, isHovered, isActive, buttonSize, disabled,
|
|
|
220
208
|
return {
|
|
221
209
|
...base,
|
|
222
210
|
backgroundColor: isHovered || isActive ? "var(--bg-surface-1)" : "transparent",
|
|
223
|
-
border: "
|
|
211
|
+
border: "1px solid transparent",
|
|
224
212
|
color: "var(--fg-primary)"
|
|
225
213
|
};
|
|
226
214
|
// Danger: low-intensity destructive action. Text stays steady; hover deepens the light red surface.
|
|
@@ -228,7 +216,7 @@ function getButtonStyles(buttonType, isHovered, isActive, buttonSize, disabled,
|
|
|
228
216
|
return {
|
|
229
217
|
...base,
|
|
230
218
|
backgroundColor: isHovered || isActive ? "var(--danger-button-surface-hover)" : "var(--danger-button-surface)",
|
|
231
|
-
border: "
|
|
219
|
+
border: "1px solid transparent",
|
|
232
220
|
color: "var(--danger-button-fg)"
|
|
233
221
|
};
|
|
234
222
|
default:
|
|
@@ -236,10 +224,10 @@ function getButtonStyles(buttonType, isHovered, isActive, buttonSize, disabled,
|
|
|
236
224
|
}
|
|
237
225
|
}
|
|
238
226
|
var Button = React.forwardRef(
|
|
239
|
-
({ className, buttonType = "primary", buttonSize = "md", color = "blue", icon, hasIconOnly, iconPosition = "left", style, disabled, children, ...props }, ref) => {
|
|
227
|
+
({ className, buttonType = "primary", buttonSize = "md", controlSize, color = "blue", icon, hasIconOnly, iconPosition = "left", style, disabled, children, ...props }, ref) => {
|
|
240
228
|
const [isHovered, setIsHovered] = React.useState(false);
|
|
241
229
|
const [isActive, setIsActive] = React.useState(false);
|
|
242
|
-
const typeStyles = getButtonStyles(buttonType, isHovered, isActive,
|
|
230
|
+
const typeStyles = getButtonStyles(buttonType, isHovered, isActive, !!disabled, color, hasIconOnly);
|
|
243
231
|
const hasIconAndText = icon && children && !hasIconOnly;
|
|
244
232
|
const finalStyles = hasIconAndText ? { ...typeStyles, gap: "var(--space-2, 8px)", ...style } : { ...typeStyles, ...style };
|
|
245
233
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
@@ -247,7 +235,9 @@ var Button = React.forwardRef(
|
|
|
247
235
|
{
|
|
248
236
|
ref,
|
|
249
237
|
type: "button",
|
|
250
|
-
|
|
238
|
+
"data-control-size": controlSize ?? buttonSize,
|
|
239
|
+
"data-icon-only": hasIconOnly || void 0,
|
|
240
|
+
className: cn("fractal-control", "fractal-button", `fractal-button--${buttonType}`, className),
|
|
251
241
|
style: finalStyles,
|
|
252
242
|
disabled,
|
|
253
243
|
onMouseEnter: (e) => {
|
|
@@ -649,7 +639,7 @@ var React2 = __toESM(require("react"), 1);
|
|
|
649
639
|
var import_fractal_icons3 = require("@mirror-physics/fractal-icons");
|
|
650
640
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
651
641
|
var Card = React2.forwardRef(
|
|
652
|
-
({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, className: cn("fractal-card", className), ...props })
|
|
642
|
+
({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, "data-fractal-border-surface": "surface-1", className: cn("fractal-card", className), ...props })
|
|
653
643
|
);
|
|
654
644
|
Card.displayName = "Card";
|
|
655
645
|
var CardHeader = React2.forwardRef(
|
|
@@ -779,12 +769,13 @@ PromptGrid.displayName = "PromptGrid";
|
|
|
779
769
|
var React4 = __toESM(require("react"), 1);
|
|
780
770
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
781
771
|
var Input = React4.forwardRef(
|
|
782
|
-
({ className, type, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
772
|
+
({ className, type, controlSize = "md", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
783
773
|
"input",
|
|
784
774
|
{
|
|
785
775
|
type,
|
|
786
776
|
ref,
|
|
787
|
-
|
|
777
|
+
"data-control-size": controlSize,
|
|
778
|
+
className: cn("fractal-control", "fractal-input", className),
|
|
788
779
|
...props
|
|
789
780
|
}
|
|
790
781
|
)
|
|
@@ -798,6 +789,7 @@ var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
|
798
789
|
var TableSearch = React5.forwardRef(
|
|
799
790
|
({
|
|
800
791
|
searchType = "text",
|
|
792
|
+
controlSize = "md",
|
|
801
793
|
className,
|
|
802
794
|
inputClassName,
|
|
803
795
|
placeholder,
|
|
@@ -811,12 +803,14 @@ var TableSearch = React5.forwardRef(
|
|
|
811
803
|
{
|
|
812
804
|
className: cn("fractal-table-search", className),
|
|
813
805
|
"data-search-type": searchType,
|
|
806
|
+
"data-control-size": controlSize,
|
|
814
807
|
children: [
|
|
815
808
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SearchIcon, { className: "fractal-table-search__icon", size: 17, "aria-hidden": "true" }),
|
|
816
809
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
817
810
|
Input,
|
|
818
811
|
{
|
|
819
812
|
...props,
|
|
813
|
+
controlSize,
|
|
820
814
|
ref,
|
|
821
815
|
type: "search",
|
|
822
816
|
className: cn("fractal-table-search__input", inputClassName),
|
|
@@ -837,6 +831,7 @@ var import_fractal_icons5 = require("@mirror-physics/fractal-icons");
|
|
|
837
831
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
838
832
|
function NumberInput({
|
|
839
833
|
unit,
|
|
834
|
+
controlSize = "md",
|
|
840
835
|
className,
|
|
841
836
|
value,
|
|
842
837
|
defaultValue,
|
|
@@ -860,11 +855,12 @@ function NumberInput({
|
|
|
860
855
|
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
861
856
|
input.focus();
|
|
862
857
|
};
|
|
863
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: cn("fractal-number-input", unit && "fractal-number-input--with-unit", className), children: [
|
|
858
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { "data-control-size": controlSize, className: cn("fractal-number-input", unit && "fractal-number-input--with-unit", className), children: [
|
|
864
859
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
865
860
|
Input,
|
|
866
861
|
{
|
|
867
862
|
ref: inputRef,
|
|
863
|
+
controlSize,
|
|
868
864
|
type: "number",
|
|
869
865
|
value,
|
|
870
866
|
defaultValue,
|
|
@@ -879,7 +875,7 @@ function NumberInput({
|
|
|
879
875
|
"span",
|
|
880
876
|
{
|
|
881
877
|
className: "fractal-number-input-unit",
|
|
882
|
-
style: { left: `calc(var(--
|
|
878
|
+
style: { left: `calc(var(--control-padding-inline) + ${characterCount}ch)` },
|
|
883
879
|
"aria-hidden": "true",
|
|
884
880
|
children: unit
|
|
885
881
|
}
|
|
@@ -1044,6 +1040,7 @@ var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
|
1044
1040
|
var PasswordInput = React7.forwardRef(
|
|
1045
1041
|
({
|
|
1046
1042
|
className,
|
|
1043
|
+
controlSize = "md",
|
|
1047
1044
|
disabled,
|
|
1048
1045
|
showPasswordLabel = "Show password",
|
|
1049
1046
|
hidePasswordLabel = "Hide password",
|
|
@@ -1055,12 +1052,14 @@ var PasswordInput = React7.forwardRef(
|
|
|
1055
1052
|
"div",
|
|
1056
1053
|
{
|
|
1057
1054
|
className: cn("fractal-password-input", className),
|
|
1055
|
+
"data-control-size": controlSize,
|
|
1058
1056
|
"data-password-visible": passwordVisible ? "" : void 0,
|
|
1059
1057
|
children: [
|
|
1060
1058
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1061
1059
|
Input,
|
|
1062
1060
|
{
|
|
1063
1061
|
...props,
|
|
1062
|
+
controlSize,
|
|
1064
1063
|
ref,
|
|
1065
1064
|
className: "fractal-password-input-field",
|
|
1066
1065
|
disabled,
|
|
@@ -1091,10 +1090,11 @@ PasswordInput.displayName = "PasswordInput";
|
|
|
1091
1090
|
var React8 = __toESM(require("react"), 1);
|
|
1092
1091
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1093
1092
|
var Label = React8.forwardRef(
|
|
1094
|
-
({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1093
|
+
({ className, controlSize = "md", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1095
1094
|
"label",
|
|
1096
1095
|
{
|
|
1097
1096
|
ref,
|
|
1097
|
+
"data-control-size": controlSize,
|
|
1098
1098
|
className: cn("fractal-label", className),
|
|
1099
1099
|
...props
|
|
1100
1100
|
}
|
|
@@ -1449,7 +1449,9 @@ function Dropdown({
|
|
|
1449
1449
|
label,
|
|
1450
1450
|
iconOnly = false,
|
|
1451
1451
|
noChevron = false,
|
|
1452
|
-
size = "md",
|
|
1452
|
+
size: sizeAlias = "md",
|
|
1453
|
+
controlSize,
|
|
1454
|
+
triggerId,
|
|
1453
1455
|
triggerVariant = "outline",
|
|
1454
1456
|
className,
|
|
1455
1457
|
triggerClassName,
|
|
@@ -1457,6 +1459,7 @@ function Dropdown({
|
|
|
1457
1459
|
closeOnSelect = true,
|
|
1458
1460
|
disabled = false
|
|
1459
1461
|
}) {
|
|
1462
|
+
const size = controlSize ?? sizeAlias;
|
|
1460
1463
|
const [open, setOpen] = React12.useState(false);
|
|
1461
1464
|
const triggerRef = React12.useRef(null);
|
|
1462
1465
|
const panelRef = React12.useRef(null);
|
|
@@ -1531,11 +1534,13 @@ function Dropdown({
|
|
|
1531
1534
|
document.addEventListener("mousedown", handleClickOutside);
|
|
1532
1535
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1533
1536
|
}, [open]);
|
|
1534
|
-
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: cn("fractal-dropdown", className), children: [
|
|
1537
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { "data-control-size": size, className: cn("fractal-dropdown", className), children: [
|
|
1535
1538
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
1536
1539
|
"button",
|
|
1537
1540
|
{
|
|
1538
1541
|
ref: triggerRef,
|
|
1542
|
+
id: triggerId,
|
|
1543
|
+
"data-control-size": size,
|
|
1539
1544
|
type: "button",
|
|
1540
1545
|
disabled,
|
|
1541
1546
|
"aria-haspopup": "listbox",
|
|
@@ -1543,6 +1548,7 @@ function Dropdown({
|
|
|
1543
1548
|
"aria-label": triggerLabel,
|
|
1544
1549
|
onClick: () => setOpen((o) => !o),
|
|
1545
1550
|
className: cn(
|
|
1551
|
+
"fractal-control",
|
|
1546
1552
|
"fractal-dropdown-trigger",
|
|
1547
1553
|
`fractal-dropdown-trigger--${size}`,
|
|
1548
1554
|
`fractal-dropdown-trigger--${triggerVariant}`,
|
|
@@ -1632,6 +1638,7 @@ var Chip = React14.forwardRef(
|
|
|
1632
1638
|
"span",
|
|
1633
1639
|
{
|
|
1634
1640
|
ref,
|
|
1641
|
+
"data-fractal-border-surface": tone === "neutral" ? "surface-2" : void 0,
|
|
1635
1642
|
className: cn("fractal-chip", `fractal-chip--${tone}`, className),
|
|
1636
1643
|
...props
|
|
1637
1644
|
}
|
|
@@ -2311,8 +2318,8 @@ function Ghost({ className, width, height, radius, style, ...props }) {
|
|
|
2311
2318
|
function GhostLine({ className, size = "md", width = "100%", ...props }) {
|
|
2312
2319
|
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Ghost, { className: cn("fractal-ghost-line", `fractal-ghost-line--${size}`, className), width, ...props });
|
|
2313
2320
|
}
|
|
2314
|
-
function ButtonGhost({ className, size = "md", iconOnly = false, width, ...props }) {
|
|
2315
|
-
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Ghost, { className: cn("fractal-ghost-button", `fractal-ghost-button--${size}`, iconOnly && "fractal-ghost-button--icon-only", className), width, ...props });
|
|
2321
|
+
function ButtonGhost({ className, size = "md", controlSize, iconOnly = false, width, ...props }) {
|
|
2322
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Ghost, { "data-control-size": controlSize ?? size, className: cn("fractal-ghost-button", `fractal-ghost-button--${size}`, iconOnly && "fractal-ghost-button--icon-only", className), width, ...props });
|
|
2316
2323
|
}
|
|
2317
2324
|
function CardGhost({ className, lines = 3, showHeader = true, ...props }) {
|
|
2318
2325
|
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-card", className), ...props, children: [
|
|
@@ -2345,8 +2352,8 @@ function TextareaGhost({ className, labelWidth = "26%", ...props }) {
|
|
|
2345
2352
|
function LabelGhost({ className, width = "26%", ...props }) {
|
|
2346
2353
|
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(GhostLine, { className: cn("fractal-ghost-label", className), size: "sm", width, ...props });
|
|
2347
2354
|
}
|
|
2348
|
-
function FormFieldGhost({ className, labelWidth = "26%", multiline = false, ...props }) {
|
|
2349
|
-
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-field", className), ...props, children: [
|
|
2355
|
+
function FormFieldGhost({ className, labelWidth = "26%", multiline = false, controlSize = "md", ...props }) {
|
|
2356
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { "aria-hidden": "true", "data-control-size": controlSize, className: cn("fractal-ghost-field", className), ...props, children: [
|
|
2350
2357
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(LabelGhost, { width: labelWidth }),
|
|
2351
2358
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Ghost, { className: cn("fractal-ghost-field__control", multiline && "fractal-ghost-field__control--multiline") })
|
|
2352
2359
|
] });
|
|
@@ -2371,8 +2378,8 @@ function LinkGhost({ className, width = 96, ...props }) {
|
|
|
2371
2378
|
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(GhostLine, { className: cn("fractal-ghost-link", className), size: "sm", width, ...props });
|
|
2372
2379
|
}
|
|
2373
2380
|
var TextButtonGhost = LinkGhost;
|
|
2374
|
-
function DropdownGhost({ className, ...props }) {
|
|
2375
|
-
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { "aria-hidden": "true", className: cn("fractal-ghost-dropdown", className), ...props, children: [
|
|
2381
|
+
function DropdownGhost({ className, controlSize = "md", ...props }) {
|
|
2382
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { "aria-hidden": "true", "data-control-size": controlSize, className: cn("fractal-ghost-dropdown", className), ...props, children: [
|
|
2376
2383
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(GhostLine, { width: "38%" }),
|
|
2377
2384
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Ghost, { className: "fractal-ghost-dropdown__chevron" })
|
|
2378
2385
|
] });
|