@particle-academy/react-fancy 3.4.3 → 4.0.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.
package/README.md CHANGED
@@ -57,7 +57,7 @@ Add the `@source` directive to your main CSS file so Tailwind v4 scans the compo
57
57
  Then import and use components:
58
58
 
59
59
  ```tsx
60
- import { Action, Input, Modal, Dropdown } from "@particle-academy/react-fancy";
60
+ import { Button, Input, Modal, Dropdown } from "@particle-academy/react-fancy";
61
61
  import "@particle-academy/react-fancy/styles.css";
62
62
  ```
63
63
 
@@ -82,7 +82,8 @@ npx vite build # Build demo app (verifies imports work)
82
82
 
83
83
  | Component | Description | Docs |
84
84
  |-----------|-------------|------|
85
- | Action | Button with colors, states, icons, emoji, avatar, badge, sort control | [docs](docs/Action.md) |
85
+ | Button | Button with colors, states, icons, emoji, avatar, badge, sort control | [docs](docs/Button.md) |
86
+ | ~~Action~~ | Deprecated alias of `Button` (kept for backward compatibility) | [docs](docs/Action.md) |
86
87
  | Carousel | Slide carousel with directional/wizard variants, autoplay, loop | [docs](docs/Carousel.md) |
87
88
  | ColorPicker | Native color input with swatch preview, hex display, presets | [docs](docs/ColorPicker.md) |
88
89
  | Emoji | Emoji renderer from slugs | [docs](docs/Emoji.md) |
@@ -240,7 +241,7 @@ src/
240
241
 
241
242
  - `Size` — `"xs" | "sm" | "md" | "lg" | "xl"`
242
243
  - `Color` — Full Tailwind color palette (17 colors)
243
- - `ActionColor` — Subset of 10 standalone colors used by Action and friends
244
+ - `ButtonColor` — Subset of 10 standalone colors used by `Button` and friends (legacy alias: `ActionColor`)
244
245
  - `Variant` — `"solid" | "outline" | "ghost" | "soft"`
245
246
  - `Placement` — `"top" | "bottom" | "left" | "right"` + start/end variants
246
247
 
package/dist/index.cjs CHANGED
@@ -2344,7 +2344,7 @@ function parseSortOrder(sort) {
2344
2344
  }
2345
2345
  return valid;
2346
2346
  }
2347
- var Action = react.forwardRef(
2347
+ var Button = react.forwardRef(
2348
2348
  ({
2349
2349
  children,
2350
2350
  className,
@@ -2507,12 +2507,13 @@ var Action = react.forwardRef(
2507
2507
  trailingElements
2508
2508
  ] });
2509
2509
  const safeHref = sanitizeHref(href);
2510
- const buttonEl = safeHref && !disabled ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: safeHref, className: classes, "data-react-fancy-action": "", children: content }) : /* @__PURE__ */ jsxRuntime.jsx(
2510
+ const buttonEl = safeHref && !disabled ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: safeHref, className: classes, "data-react-fancy-button": "", "data-react-fancy-action": "", children: content }) : /* @__PURE__ */ jsxRuntime.jsx(
2511
2511
  "button",
2512
2512
  {
2513
2513
  ref,
2514
2514
  className: classes,
2515
2515
  disabled: disabled || loading,
2516
+ "data-react-fancy-button": "",
2516
2517
  "data-react-fancy-action": "",
2517
2518
  ...props,
2518
2519
  children: content
@@ -2576,7 +2577,8 @@ var Action = react.forwardRef(
2576
2577
  return buttonEl;
2577
2578
  }
2578
2579
  );
2579
- Action.displayName = "Action";
2580
+ Button.displayName = "Button";
2581
+ var Action = Button;
2580
2582
  function useControllableState(controlledValue, defaultValue, onChange) {
2581
2583
  const [uncontrolledValue, setUncontrolledValue] = react.useState(defaultValue);
2582
2584
  const isControlled = controlledValue !== void 0;
@@ -6413,6 +6415,98 @@ var Callout = react.forwardRef(
6413
6415
  }
6414
6416
  );
6415
6417
  Callout.displayName = "Callout";
6418
+ var DOT_COLORS = ["bg-rose-300", "bg-amber-300", "bg-green-300"];
6419
+ var FauxClient = react.forwardRef(
6420
+ ({
6421
+ variant = "browser",
6422
+ url,
6423
+ meta,
6424
+ dots = true,
6425
+ width,
6426
+ scale = "fit",
6427
+ className,
6428
+ barClassName,
6429
+ bodyClassName,
6430
+ children,
6431
+ ...rest
6432
+ }, ref) => {
6433
+ const scaled = typeof width === "number";
6434
+ const viewportRef = react.useRef(null);
6435
+ const stageRef = react.useRef(null);
6436
+ const [s, setS] = react.useState(typeof scale === "number" ? scale : 1);
6437
+ const [contentHeight, setContentHeight] = react.useState(void 0);
6438
+ react.useLayoutEffect(() => {
6439
+ if (!scaled) return;
6440
+ const viewport = viewportRef.current;
6441
+ const stage = stageRef.current;
6442
+ if (!viewport || !stage) return;
6443
+ if (typeof ResizeObserver === "undefined") return;
6444
+ const measure = () => {
6445
+ const avail = viewport.clientWidth;
6446
+ const next = scale === "fit" ? width && width > 0 ? avail / width : 1 : scale;
6447
+ const naturalHeight = stage.offsetHeight;
6448
+ setS(next);
6449
+ setContentHeight(naturalHeight * next);
6450
+ };
6451
+ measure();
6452
+ const ro = new ResizeObserver(measure);
6453
+ ro.observe(viewport);
6454
+ ro.observe(stage);
6455
+ return () => ro.disconnect();
6456
+ }, [scaled, scale, width]);
6457
+ const isBrowser = variant === "browser";
6458
+ const isDevice = variant === "device";
6459
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6460
+ "div",
6461
+ {
6462
+ ref,
6463
+ "data-react-fancy-faux-client": "",
6464
+ className: cn(
6465
+ "overflow-hidden bg-white dark:bg-zinc-900",
6466
+ isBrowser && "rounded-2xl border border-zinc-200 shadow-xl dark:border-zinc-800",
6467
+ isDevice && "rounded-[2rem] border-[10px] border-zinc-800 shadow-2xl dark:border-zinc-700",
6468
+ variant === "bare" && "rounded-lg border border-zinc-200 dark:border-zinc-800",
6469
+ className
6470
+ ),
6471
+ ...rest,
6472
+ children: [
6473
+ isBrowser && /* @__PURE__ */ jsxRuntime.jsxs(
6474
+ "div",
6475
+ {
6476
+ className: cn(
6477
+ "flex items-center gap-2 border-b border-zinc-200 bg-zinc-50 px-3.5 py-2.5 font-mono text-[11.5px] text-zinc-500 dark:border-zinc-800 dark:bg-zinc-950 dark:text-zinc-400",
6478
+ barClassName
6479
+ ),
6480
+ children: [
6481
+ dots && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mr-1.5 flex gap-[5px]", children: DOT_COLORS.map((color, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("h-[9px] w-[9px] rounded-full", color) }, i)) }),
6482
+ url != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: url }),
6483
+ meta != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-zinc-400 dark:text-zinc-500", children: meta })
6484
+ ]
6485
+ }
6486
+ ),
6487
+ /* @__PURE__ */ jsxRuntime.jsx(
6488
+ "div",
6489
+ {
6490
+ ref: viewportRef,
6491
+ className: cn("relative overflow-hidden", bodyClassName),
6492
+ style: scaled ? { height: contentHeight } : void 0,
6493
+ children: scaled ? /* @__PURE__ */ jsxRuntime.jsx(
6494
+ "div",
6495
+ {
6496
+ ref: stageRef,
6497
+ className: "absolute left-0 top-0 origin-top-left",
6498
+ style: { width, transform: `scale(${s})` },
6499
+ children
6500
+ }
6501
+ ) : children
6502
+ }
6503
+ )
6504
+ ]
6505
+ }
6506
+ );
6507
+ }
6508
+ );
6509
+ FauxClient.displayName = "FauxClient";
6416
6510
  var colorClasses5 = {
6417
6511
  yellow: "bg-amber-100 text-amber-950 dark:bg-amber-200 dark:text-amber-950",
6418
6512
  blue: "bg-sky-100 text-sky-950 dark:bg-sky-200 dark:text-sky-950",
@@ -12168,7 +12262,7 @@ function ReasonTag({
12168
12262
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] uppercase tracking-wider text-zinc-400", children: "sources" }),
12169
12263
  /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mt-0.5 space-y-0.5 text-[12px]", children: sources.map((s, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: s.href ? /* @__PURE__ */ jsxRuntime.jsx("a", { className: "text-violet-600 hover:underline", href: s.href, children: s.label }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-600 dark:text-zinc-300", children: s.label }) }, i)) })
12170
12264
  ] }),
12171
- onFollowUp && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end pt-1", children: /* @__PURE__ */ jsxRuntime.jsx(Action, { size: "sm", variant: "ghost", onClick: onFollowUp, children: "ask follow-up" }) })
12265
+ onFollowUp && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end pt-1", children: /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", variant: "ghost", onClick: onFollowUp, children: "ask follow-up" }) })
12172
12266
  ] }) })
12173
12267
  ] });
12174
12268
  }
@@ -12608,7 +12702,7 @@ function PromptInput({
12608
12702
  ] }),
12609
12703
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 border-t border-zinc-200 bg-zinc-50/60 px-3 py-2 dark:border-zinc-800 dark:bg-zinc-900/40", children: [
12610
12704
  /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: "Drop files here, or click", children: /* @__PURE__ */ jsxRuntime.jsx(
12611
- Action,
12705
+ Button,
12612
12706
  {
12613
12707
  variant: "ghost",
12614
12708
  size: "sm",
@@ -12641,7 +12735,7 @@ function PromptInput({
12641
12735
  " ",
12642
12736
  "to send"
12643
12737
  ] }),
12644
- /* @__PURE__ */ jsxRuntime.jsx(Action, { color: "violet", size: "sm", onClick: submit, children: "send \u2192" })
12738
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { color: "violet", size: "sm", onClick: submit, children: "send \u2192" })
12645
12739
  ] })
12646
12740
  ] })
12647
12741
  ]
@@ -13259,7 +13353,7 @@ function Wand({
13259
13353
  ] })
13260
13354
  ] }),
13261
13355
  actions.map((a) => /* @__PURE__ */ jsxRuntime.jsxs(
13262
- Action,
13356
+ Button,
13263
13357
  {
13264
13358
  size: "sm",
13265
13359
  variant: "ghost",
@@ -13346,6 +13440,7 @@ exports.Avatar = Avatar;
13346
13440
  exports.Badge = Badge;
13347
13441
  exports.Brand = Brand;
13348
13442
  exports.Breadcrumbs = Breadcrumbs;
13443
+ exports.Button = Button;
13349
13444
  exports.Calendar = Calendar;
13350
13445
  exports.Callout = Callout;
13351
13446
  exports.Card = Card;
@@ -13367,6 +13462,7 @@ exports.EMOJI_ENTRIES = EMOJI_ENTRIES;
13367
13462
  exports.Editor = Editor;
13368
13463
  exports.Emoji = Emoji;
13369
13464
  exports.EmojiSelect = EmojiSelect;
13465
+ exports.FauxClient = FauxClient;
13370
13466
  exports.Field = Field;
13371
13467
  exports.FileUpload = FileUpload;
13372
13468
  exports.Heading = Heading;