@geomak/ui 6.29.2 → 6.30.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.d.cts CHANGED
@@ -1381,6 +1381,8 @@ interface ChatProps {
1381
1381
  disabled?: boolean;
1382
1382
  /** Hide the composer entirely (read-only transcript). */
1383
1383
  hideComposer?: boolean;
1384
+ /** Shows a transcript skeleton (use while loading history, before messages arrive). */
1385
+ loading?: boolean;
1384
1386
  /** Shown when there are no messages. */
1385
1387
  emptyState?: React__default.ReactNode;
1386
1388
  /** Overall height — the message list scrolls within it. Default `480`. */
@@ -1406,7 +1408,7 @@ interface ChatProps {
1406
1408
  * onSend={(text) => send(text)}
1407
1409
  * />
1408
1410
  */
1409
- declare function Chat({ messages, currentUserId, onSend, typingNames, title, subtitle, avatar, headerActions, placeholder, disabled, hideComposer, emptyState, height, className, style, }: ChatProps): react_jsx_runtime.JSX.Element;
1411
+ declare function Chat({ messages, currentUserId, onSend, typingNames, title, subtitle, avatar, headerActions, placeholder, disabled, hideComposer, loading, emptyState, height, className, style, }: ChatProps): react_jsx_runtime.JSX.Element;
1410
1412
 
1411
1413
  type StatisticSize = 'sm' | 'md' | 'lg';
1412
1414
  type DeltaDirection = 'up' | 'down' | 'neutral';
package/dist/index.d.ts CHANGED
@@ -1381,6 +1381,8 @@ interface ChatProps {
1381
1381
  disabled?: boolean;
1382
1382
  /** Hide the composer entirely (read-only transcript). */
1383
1383
  hideComposer?: boolean;
1384
+ /** Shows a transcript skeleton (use while loading history, before messages arrive). */
1385
+ loading?: boolean;
1384
1386
  /** Shown when there are no messages. */
1385
1387
  emptyState?: React__default.ReactNode;
1386
1388
  /** Overall height — the message list scrolls within it. Default `480`. */
@@ -1406,7 +1408,7 @@ interface ChatProps {
1406
1408
  * onSend={(text) => send(text)}
1407
1409
  * />
1408
1410
  */
1409
- declare function Chat({ messages, currentUserId, onSend, typingNames, title, subtitle, avatar, headerActions, placeholder, disabled, hideComposer, emptyState, height, className, style, }: ChatProps): react_jsx_runtime.JSX.Element;
1411
+ declare function Chat({ messages, currentUserId, onSend, typingNames, title, subtitle, avatar, headerActions, placeholder, disabled, hideComposer, loading, emptyState, height, className, style, }: ChatProps): react_jsx_runtime.JSX.Element;
1410
1412
 
1411
1413
  type StatisticSize = 'sm' | 'md' | 'lg';
1412
1414
  type DeltaDirection = 'up' | 'down' | 'neutral';
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { colors_default } from './chunk-I2P4JJDB.js';
2
2
  export { colors_default as COLORS, PALETTE as palette, semanticTokens, vars } from './chunk-I2P4JJDB.js';
3
3
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
- import React28, { createContext, useState, useEffect, useMemo, useId, useCallback, useRef, useLayoutEffect, useContext, useSyncExternalStore } from 'react';
4
+ import React28, { createContext, useState, useEffect, useMemo, useId, useCallback, useRef, useContext, useSyncExternalStore, useLayoutEffect } from 'react';
5
5
  import { createPortal } from 'react-dom';
6
6
  import * as AvatarPrimitive from '@radix-ui/react-avatar';
7
7
  import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
@@ -2267,6 +2267,19 @@ var ArrowDown = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "
2267
2267
  function TypingDots() {
2268
2268
  return /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-1", "aria-hidden": "true", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx("span", { className: "h-1.5 w-1.5 animate-bounce rounded-full bg-foreground-muted", style: { animationDelay: `${i * 0.15}s` } }, i)) });
2269
2269
  }
2270
+ var SKELETON_ROWS = [
2271
+ { own: false, w: 150 },
2272
+ { own: false, w: 110 },
2273
+ { own: true, w: 180 },
2274
+ { own: false, w: 130 },
2275
+ { own: true, w: 90 }
2276
+ ];
2277
+ function ChatSkeleton() {
2278
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", "aria-hidden": "true", children: SKELETON_ROWS.map((r, i) => /* @__PURE__ */ jsxs("div", { className: ["flex items-end gap-2", r.own ? "flex-row-reverse" : ""].filter(Boolean).join(" "), children: [
2279
+ !r.own && /* @__PURE__ */ jsx("span", { className: "h-6 w-6 flex-shrink-0 animate-pulse rounded-full bg-surface" }),
2280
+ /* @__PURE__ */ jsx("span", { className: "h-8 animate-pulse rounded-2xl bg-surface", style: { width: r.w } })
2281
+ ] }, i)) });
2282
+ }
2270
2283
  function Chat({
2271
2284
  messages,
2272
2285
  currentUserId,
@@ -2279,6 +2292,7 @@ function Chat({
2279
2292
  placeholder = "Write a message\u2026",
2280
2293
  disabled = false,
2281
2294
  hideComposer = false,
2295
+ loading = false,
2282
2296
  emptyState,
2283
2297
  height = 480,
2284
2298
  className = "",
@@ -2288,7 +2302,6 @@ function Chat({
2288
2302
  const atBottomRef = useRef(true);
2289
2303
  const [showJump, setShowJump] = useState(false);
2290
2304
  const [draft, setDraft] = useState("");
2291
- const taRef = useRef(null);
2292
2305
  const hasHeader = title != null || subtitle != null || avatar != null || headerActions != null;
2293
2306
  const isTyping = typingNames.length > 0;
2294
2307
  const scrollToBottom = useCallback((smooth = true) => {
@@ -2310,12 +2323,6 @@ function Chat({
2310
2323
  useEffect(() => {
2311
2324
  scrollToBottom(false);
2312
2325
  }, [scrollToBottom]);
2313
- useLayoutEffect(() => {
2314
- const ta = taRef.current;
2315
- if (!ta) return;
2316
- ta.style.height = "auto";
2317
- ta.style.height = `${Math.min(ta.scrollHeight, 120)}px`;
2318
- }, [draft]);
2319
2326
  const send = () => {
2320
2327
  const text = draft.trim();
2321
2328
  if (!text || disabled) return;
@@ -2344,7 +2351,7 @@ function Chat({
2344
2351
  ] }),
2345
2352
  /* @__PURE__ */ jsxs("div", { className: "relative flex-1 overflow-hidden", children: [
2346
2353
  /* @__PURE__ */ jsxs("div", { ref: listRef, onScroll, className: "flex h-full flex-col gap-1 overflow-y-auto bg-background px-4 py-3", children: [
2347
- messages.length === 0 && !isTyping ? /* @__PURE__ */ 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) => {
2354
+ loading && messages.length === 0 ? /* @__PURE__ */ jsx(ChatSkeleton, {}) : messages.length === 0 && !isTyping ? /* @__PURE__ */ 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) => {
2348
2355
  const own = m.authorId === currentUserId;
2349
2356
  const prev = messages[i - 1];
2350
2357
  const next = messages[i + 1];
@@ -2399,15 +2406,14 @@ function Chat({
2399
2406
  /* @__PURE__ */ jsx(
2400
2407
  "textarea",
2401
2408
  {
2402
- ref: taRef,
2403
- rows: 1,
2409
+ rows: 2,
2404
2410
  value: draft,
2405
2411
  disabled,
2406
2412
  placeholder,
2407
2413
  onChange: (e) => setDraft(e.target.value),
2408
2414
  onKeyDown,
2409
2415
  "aria-label": "Message",
2410
- className: `${fieldShell({ size: "md", hasError: false, disabled, sized: false })} max-h-[120px] flex-1 resize-none px-3 py-2 leading-snug`
2416
+ className: `${fieldShell({ size: "md", hasError: false, disabled, sized: false })} h-[4.5rem] flex-1 resize-none px-3 py-2 leading-snug`
2411
2417
  }
2412
2418
  ),
2413
2419
  /* @__PURE__ */ jsx(