@geomak/ui 6.29.2 → 6.31.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/dist/index.cjs CHANGED
@@ -507,8 +507,8 @@ function Avatar({
507
507
  if (fallback) return fallback;
508
508
  if (alt) {
509
509
  const parts = alt.trim().split(/\s+/).slice(0, 2);
510
- const initials2 = parts.map((p) => p[0]?.toUpperCase() ?? "").join("");
511
- if (initials2) return initials2;
510
+ const initials3 = parts.map((p) => p[0]?.toUpperCase() ?? "").join("");
511
+ if (initials3) return initials3;
512
512
  }
513
513
  return /* @__PURE__ */ jsxRuntime.jsx(PersonSilhouette, {});
514
514
  })();
@@ -2304,6 +2304,19 @@ var ArrowDown = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 2
2304
2304
  function TypingDots() {
2305
2305
  return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center gap-1", "aria-hidden": "true", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-1.5 w-1.5 animate-bounce rounded-full bg-foreground-muted", style: { animationDelay: `${i * 0.15}s` } }, i)) });
2306
2306
  }
2307
+ var SKELETON_ROWS = [
2308
+ { own: false, w: 150 },
2309
+ { own: false, w: 110 },
2310
+ { own: true, w: 180 },
2311
+ { own: false, w: 130 },
2312
+ { own: true, w: 90 }
2313
+ ];
2314
+ function ChatSkeleton() {
2315
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", "aria-hidden": "true", children: SKELETON_ROWS.map((r, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ["flex items-end gap-2", r.own ? "flex-row-reverse" : ""].filter(Boolean).join(" "), children: [
2316
+ !r.own && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-6 w-6 flex-shrink-0 animate-pulse rounded-full bg-surface" }),
2317
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-8 animate-pulse rounded-2xl bg-surface", style: { width: r.w } })
2318
+ ] }, i)) });
2319
+ }
2307
2320
  function Chat({
2308
2321
  messages,
2309
2322
  currentUserId,
@@ -2316,6 +2329,7 @@ function Chat({
2316
2329
  placeholder = "Write a message\u2026",
2317
2330
  disabled = false,
2318
2331
  hideComposer = false,
2332
+ loading = false,
2319
2333
  emptyState,
2320
2334
  height = 480,
2321
2335
  className = "",
@@ -2325,7 +2339,6 @@ function Chat({
2325
2339
  const atBottomRef = React28.useRef(true);
2326
2340
  const [showJump, setShowJump] = React28.useState(false);
2327
2341
  const [draft, setDraft] = React28.useState("");
2328
- const taRef = React28.useRef(null);
2329
2342
  const hasHeader = title != null || subtitle != null || avatar != null || headerActions != null;
2330
2343
  const isTyping = typingNames.length > 0;
2331
2344
  const scrollToBottom = React28.useCallback((smooth = true) => {
@@ -2347,12 +2360,6 @@ function Chat({
2347
2360
  React28.useEffect(() => {
2348
2361
  scrollToBottom(false);
2349
2362
  }, [scrollToBottom]);
2350
- React28.useLayoutEffect(() => {
2351
- const ta = taRef.current;
2352
- if (!ta) return;
2353
- ta.style.height = "auto";
2354
- ta.style.height = `${Math.min(ta.scrollHeight, 120)}px`;
2355
- }, [draft]);
2356
2363
  const send = () => {
2357
2364
  const text = draft.trim();
2358
2365
  if (!text || disabled) return;
@@ -2381,7 +2388,7 @@ function Chat({
2381
2388
  ] }),
2382
2389
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1 overflow-hidden", children: [
2383
2390
  /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: listRef, onScroll, className: "flex h-full flex-col gap-1 overflow-y-auto bg-background px-4 py-3", children: [
2384
- messages.length === 0 && !isTyping ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-center text-center text-sm text-foreground-muted", children: emptyState ?? "No messages yet. Say hello \u{1F44B}" }) : messages.map((m, i) => {
2391
+ loading && messages.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ChatSkeleton, {}) : messages.length === 0 && !isTyping ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-center text-center text-sm text-foreground-muted", children: emptyState ?? "No messages yet. Say hello \u{1F44B}" }) : messages.map((m, i) => {
2385
2392
  const own = m.authorId === currentUserId;
2386
2393
  const prev = messages[i - 1];
2387
2394
  const next = messages[i + 1];
@@ -2436,15 +2443,14 @@ function Chat({
2436
2443
  /* @__PURE__ */ jsxRuntime.jsx(
2437
2444
  "textarea",
2438
2445
  {
2439
- ref: taRef,
2440
- rows: 1,
2446
+ rows: 2,
2441
2447
  value: draft,
2442
2448
  disabled,
2443
2449
  placeholder,
2444
2450
  onChange: (e) => setDraft(e.target.value),
2445
2451
  onKeyDown,
2446
2452
  "aria-label": "Message",
2447
- className: `${fieldShell({ size: "md", hasError: false, disabled, sized: false })} max-h-[120px] flex-1 resize-none px-3 py-2 leading-snug`
2453
+ className: `${fieldShell({ size: "md", hasError: false, disabled, sized: false })} h-[4.5rem] flex-1 resize-none px-3 py-2 leading-snug`
2448
2454
  }
2449
2455
  ),
2450
2456
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -9320,6 +9326,154 @@ function useJwt(token) {
9320
9326
  const isValid = decoded.payload != null && !isExpired;
9321
9327
  return { payload: decoded.payload, header: decoded.header, expiresAt, isExpired, isValid, raw: token ?? null };
9322
9328
  }
9329
+ var GRADIENT = "radial-gradient(ellipse 80% 60% at 50% 0%, color-mix(in oklab, var(--color-accent) 12%, transparent), transparent 70%)";
9330
+ function Jumbotron({
9331
+ eyebrow,
9332
+ title,
9333
+ description,
9334
+ actions,
9335
+ media,
9336
+ layout = "centered",
9337
+ background = "none",
9338
+ className = "",
9339
+ style
9340
+ }) {
9341
+ const split = layout === "split" && media != null;
9342
+ const bgClass = background === "surface" ? "bg-surface" : "";
9343
+ const copy = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ["flex flex-col gap-5", split ? "items-start text-left" : "items-center text-center"].join(" "), children: [
9344
+ eyebrow != null && /* @__PURE__ */ jsxRuntime.jsx("div", { children: eyebrow }),
9345
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: ["text-4xl font-bold leading-tight tracking-tight text-foreground sm:text-5xl", split ? "" : "max-w-3xl"].join(" "), children: title }),
9346
+ description != null && /* @__PURE__ */ jsxRuntime.jsx("p", { className: ["text-lg leading-relaxed text-foreground-secondary", split ? "max-w-xl" : "max-w-2xl"].join(" "), children: description }),
9347
+ actions != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: ["mt-2 flex flex-wrap gap-3", split ? "justify-start" : "justify-center"].join(" "), children: actions })
9348
+ ] });
9349
+ return /* @__PURE__ */ jsxRuntime.jsx(
9350
+ "section",
9351
+ {
9352
+ className: ["relative overflow-hidden rounded-2xl px-6 py-16 sm:px-10 sm:py-24", bgClass, className].filter(Boolean).join(" "),
9353
+ style: { ...background === "gradient" ? { backgroundImage: GRADIENT } : null, ...style },
9354
+ children: split ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto grid max-w-6xl items-center gap-10 lg:grid-cols-2", children: [
9355
+ copy,
9356
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-xl", children: media })
9357
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto flex max-w-4xl flex-col items-center", children: [
9358
+ copy,
9359
+ media != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-12 w-full overflow-hidden rounded-xl", children: media })
9360
+ ] })
9361
+ }
9362
+ );
9363
+ }
9364
+ var COLS = {
9365
+ 2: "sm:grid-cols-2",
9366
+ 3: "sm:grid-cols-2 lg:grid-cols-3",
9367
+ 4: "sm:grid-cols-2 lg:grid-cols-4"
9368
+ };
9369
+ function FeatureGrid({
9370
+ features,
9371
+ eyebrow,
9372
+ title,
9373
+ description,
9374
+ columns = 3,
9375
+ centeredHeader = true,
9376
+ className = "",
9377
+ style
9378
+ }) {
9379
+ const hasHeader = eyebrow != null || title != null || description != null;
9380
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: ["px-2", className].filter(Boolean).join(" "), style, children: [
9381
+ hasHeader && /* @__PURE__ */ jsxRuntime.jsxs("header", { className: ["mb-10 flex flex-col gap-3", centeredHeader ? "items-center text-center" : "items-start text-left"].join(" "), children: [
9382
+ eyebrow != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-semibold uppercase tracking-wide text-accent", children: eyebrow }),
9383
+ title != null && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-3xl font-bold tracking-tight text-foreground", children: title }),
9384
+ description != null && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-2xl text-base leading-relaxed text-foreground-secondary", children: description })
9385
+ ] }),
9386
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: ["grid grid-cols-1 gap-6", COLS[columns]].join(" "), children: features.map((f, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 rounded-xl border border-border bg-surface p-5", children: [
9387
+ f.icon != null && /* @__PURE__ */ jsxRuntime.jsx(
9388
+ "span",
9389
+ {
9390
+ className: "flex h-10 w-10 items-center justify-center rounded-lg text-accent",
9391
+ style: { backgroundColor: "color-mix(in oklab, var(--color-accent) 12%, var(--color-surface))" },
9392
+ children: f.icon
9393
+ }
9394
+ ),
9395
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-base font-semibold text-foreground", children: f.title }),
9396
+ f.description != null && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm leading-relaxed text-foreground-secondary", children: f.description })
9397
+ ] }, f.key ?? i)) })
9398
+ ] });
9399
+ }
9400
+ var Check3 = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, "aria-hidden": "true", className: "mt-0.5 h-4 w-4 flex-shrink-0 text-accent", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M20 6 9 17l-5-5" }) });
9401
+ function PricingPlans({ plans, eyebrow, title, description, className = "", style }) {
9402
+ const hasHeader = eyebrow != null || title != null || description != null;
9403
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: ["px-2", className].filter(Boolean).join(" "), style, children: [
9404
+ hasHeader && /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "mb-10 flex flex-col items-center gap-3 text-center", children: [
9405
+ eyebrow != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-semibold uppercase tracking-wide text-accent", children: eyebrow }),
9406
+ title != null && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-3xl font-bold tracking-tight text-foreground", children: title }),
9407
+ description != null && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-2xl text-base leading-relaxed text-foreground-secondary", children: description })
9408
+ ] }),
9409
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 items-stretch gap-6 md:grid-cols-2 lg:grid-cols-3", children: plans.map((p, i) => /* @__PURE__ */ jsxRuntime.jsxs(
9410
+ "div",
9411
+ {
9412
+ className: [
9413
+ "relative flex flex-col rounded-2xl border bg-surface p-6",
9414
+ p.highlighted ? "border-accent shadow-lg lg:-my-2 lg:py-8" : "border-border"
9415
+ ].join(" "),
9416
+ children: [
9417
+ p.highlighted && p.badge != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-3 left-1/2 -translate-x-1/2 rounded-full bg-accent px-3 py-0.5 text-xs font-semibold text-accent-fg shadow-sm", children: p.badge }),
9418
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold uppercase tracking-wide text-foreground-muted", children: p.name }),
9419
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex items-baseline gap-1", children: [
9420
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-4xl font-bold tracking-tight text-foreground", children: p.price }),
9421
+ p.period != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-foreground-muted", children: p.period })
9422
+ ] }),
9423
+ p.description != null && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm leading-relaxed text-foreground-secondary", children: p.description }),
9424
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mt-6 flex flex-1 flex-col gap-2.5", children: p.features.map((f, fi) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex gap-2 text-sm text-foreground-secondary", children: [
9425
+ /* @__PURE__ */ jsxRuntime.jsx(Check3, {}),
9426
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: f })
9427
+ ] }, fi)) }),
9428
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-6", children: /* @__PURE__ */ jsxRuntime.jsx(
9429
+ Button_default,
9430
+ {
9431
+ content: p.cta.label,
9432
+ variant: p.highlighted ? "primary" : "outline",
9433
+ onClick: p.cta.onClick,
9434
+ style: { width: "100%" }
9435
+ }
9436
+ ) })
9437
+ ]
9438
+ },
9439
+ p.key ?? i
9440
+ )) })
9441
+ ] });
9442
+ }
9443
+ var COLS2 = {
9444
+ 1: "mx-auto max-w-2xl",
9445
+ 2: "sm:grid-cols-2",
9446
+ 3: "sm:grid-cols-2 lg:grid-cols-3"
9447
+ };
9448
+ var initials2 = (name) => typeof name === "string" ? name.trim().split(/\s+/).slice(0, 2).map((w) => w[0]?.toUpperCase() ?? "").join("") || void 0 : void 0;
9449
+ function Stars({ value }) {
9450
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-0.5", "aria-label": `${value} out of 5`, children: Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", className: `h-4 w-4 ${i < value ? "text-status-warning" : "text-border-strong"}`, fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2l2.9 6.3 6.9.7-5.1 4.6 1.4 6.8L12 17.8 5.9 20.4l1.4-6.8L2.2 9l6.9-.7L12 2z" }) }, i)) });
9451
+ }
9452
+ function Testimonials({ testimonials, eyebrow, title, description, columns = 3, className = "", style }) {
9453
+ const hasHeader = eyebrow != null || title != null || description != null;
9454
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: ["px-2", className].filter(Boolean).join(" "), style, children: [
9455
+ hasHeader && /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "mb-10 flex flex-col items-center gap-3 text-center", children: [
9456
+ eyebrow != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-semibold uppercase tracking-wide text-accent", children: eyebrow }),
9457
+ title != null && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-3xl font-bold tracking-tight text-foreground", children: title }),
9458
+ description != null && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-2xl text-base leading-relaxed text-foreground-secondary", children: description })
9459
+ ] }),
9460
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: ["grid grid-cols-1 gap-6", COLS2[columns]].join(" "), children: testimonials.map((tm, i) => /* @__PURE__ */ jsxRuntime.jsxs("figure", { className: "flex flex-col gap-4 rounded-xl border border-border bg-surface p-6", children: [
9461
+ tm.rating != null && /* @__PURE__ */ jsxRuntime.jsx(Stars, { value: tm.rating }),
9462
+ /* @__PURE__ */ jsxRuntime.jsxs("blockquote", { className: "flex-1 text-sm leading-relaxed text-foreground", children: [
9463
+ "\u201C",
9464
+ tm.quote,
9465
+ "\u201D"
9466
+ ] }),
9467
+ /* @__PURE__ */ jsxRuntime.jsxs("figcaption", { className: "flex items-center gap-3", children: [
9468
+ /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: tm.avatar, alt: typeof tm.author === "string" ? tm.author : "Reviewer", fallback: initials2(tm.author), size: "sm" }),
9469
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
9470
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-sm font-semibold text-foreground", children: tm.author }),
9471
+ tm.role != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-xs text-foreground-muted", children: tm.role })
9472
+ ] })
9473
+ ] })
9474
+ ] }, tm.key ?? i)) })
9475
+ ] });
9476
+ }
9323
9477
 
9324
9478
  Object.defineProperty(exports, "COLORS", {
9325
9479
  enumerable: true,
@@ -9366,6 +9520,7 @@ exports.Dropdown = Dropdown;
9366
9520
  exports.EmptyCart = EmptyCart;
9367
9521
  exports.FAB = FAB;
9368
9522
  exports.FadingBase = FadingBase;
9523
+ exports.FeatureGrid = FeatureGrid;
9369
9524
  exports.Field = Field;
9370
9525
  exports.FieldHelpIcon = FieldHelpIcon;
9371
9526
  exports.FieldLabel = FieldLabel;
@@ -9379,6 +9534,7 @@ exports.Grid = Grid2;
9379
9534
  exports.GridCard = GridCard;
9380
9535
  exports.Icon = icons_default;
9381
9536
  exports.IconButton = IconButton;
9537
+ exports.Jumbotron = Jumbotron;
9382
9538
  exports.Kbd = Kbd;
9383
9539
  exports.List = List2;
9384
9540
  exports.LoadingSpinner = LoadingSpinner;
@@ -9393,6 +9549,7 @@ exports.OtpInput = OtpInput;
9393
9549
  exports.Password = Password;
9394
9550
  exports.PopConfirm = PopConfirm;
9395
9551
  exports.Portal = Portal;
9552
+ exports.PricingPlans = PricingPlans;
9396
9553
  exports.RadioGroup = RadioGroup;
9397
9554
  exports.Rating = Rating;
9398
9555
  exports.ScalableContainer = ScalableContainer;
@@ -9413,6 +9570,7 @@ exports.Table = Table;
9413
9570
  exports.Tabs = Tabs_default;
9414
9571
  exports.TagsInput = TagsInput;
9415
9572
  exports.Temporal = DatePicker;
9573
+ exports.Testimonials = Testimonials;
9416
9574
  exports.TextArea = TextArea;
9417
9575
  exports.TextInput = TextInput;
9418
9576
  exports.ThemeProvider = ThemeProvider;