@epicbagel/saas-kit 1.28.0 → 1.29.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.
@@ -924,7 +924,7 @@ function MobileReplySuggestions({
924
924
  _chunk2BHI5ZWJcjs.DrawerContent,
925
925
  {
926
926
  "aria-describedby": void 0,
927
- className: "max-h-[min(85dvh,40rem)] overflow-hidden pb-[env(safe-area-inset-bottom)]",
927
+ className: "max-h-[min(85dvh,40rem)] overflow-hidden pb-[env(safe-area-inset-bottom)] md:mx-auto md:w-full md:max-w-xl",
928
928
  onOpenAutoFocus: (event) => {
929
929
  event.preventDefault();
930
930
  _optionalChain([closeRef, 'access', _11 => _11.current, 'optionalAccess', _12 => _12.focus, 'call', _13 => _13({ preventScroll: true })]);
@@ -999,6 +999,19 @@ function ExamplePromptsLoading({ label, className }) {
999
999
  function ChatError({ children, className }) {
1000
1000
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { "data-slot": "chat-error", role: "alert", className: _chunkKWLSBTB2cjs.cn.call(void 0, "mt-2 text-xs text-destructive", className), children });
1001
1001
  }
1002
+ var SHORT_VIEWPORT_HEIGHT = 900;
1003
+ function useIsShortViewport() {
1004
+ const [short, setShort] = _react.useState.call(void 0, false);
1005
+ _react.useEffect.call(void 0, () => {
1006
+ if (typeof window === "undefined") return;
1007
+ const mql = window.matchMedia(`(max-height: ${SHORT_VIEWPORT_HEIGHT - 1}px)`);
1008
+ const onChange = () => setShort(window.innerHeight < SHORT_VIEWPORT_HEIGHT);
1009
+ mql.addEventListener("change", onChange);
1010
+ onChange();
1011
+ return () => mql.removeEventListener("change", onChange);
1012
+ }, []);
1013
+ return short;
1014
+ }
1002
1015
  var Chat = _react.forwardRef.call(void 0, function Chat2({
1003
1016
  messages,
1004
1017
  onSend,
@@ -1127,7 +1140,8 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
1127
1140
  );
1128
1141
  const application = layout === "application";
1129
1142
  const workspace = layout === "workspace";
1130
- const compactSuggestions = mobileCompactSuggestions && isMobile;
1143
+ const shortViewport = useIsShortViewport();
1144
+ const compactSuggestions = mobileCompactSuggestions && (isMobile || shortViewport);
1131
1145
  const showEmptyFileDropzone = emptyFileDropzone && Boolean(onFilesSelected) && attachments.length === 0;
1132
1146
  const liveVoiceActive = voiceSession && voiceSession.state !== "disconnected" && voiceSession.state !== "error";
1133
1147
  const showEmptyPending = !conversationStarted && pending && Boolean(emptyPendingContent) && !liveVoiceActive;
@@ -402,7 +402,10 @@ interface ChatProps {
402
402
  replySuggestions?: ReadonlyArray<string>;
403
403
  /** The reply suggestions' accessible name. Defaults to "Suggested replies". */
404
404
  replySuggestionsLabel?: string;
405
- /** Below 768px, show replies inside the composer as the first reply and a bottom-sheet picker. Desktop chips are unchanged. */
405
+ /**
406
+ * Below 768px wide, or 900px tall, show replies inside the composer as the
407
+ * first reply and a bottom-sheet picker. Taller desktop windows keep chips.
408
+ */
406
409
  mobileCompactSuggestions?: boolean;
407
410
  /** The mobile picker's opener, given the number of additional replies. Defaults to `+N more`. */
408
411
  replySuggestionsMoreLabel?: (count: number) => string;
@@ -402,7 +402,10 @@ interface ChatProps {
402
402
  replySuggestions?: ReadonlyArray<string>;
403
403
  /** The reply suggestions' accessible name. Defaults to "Suggested replies". */
404
404
  replySuggestionsLabel?: string;
405
- /** Below 768px, show replies inside the composer as the first reply and a bottom-sheet picker. Desktop chips are unchanged. */
405
+ /**
406
+ * Below 768px wide, or 900px tall, show replies inside the composer as the
407
+ * first reply and a bottom-sheet picker. Taller desktop windows keep chips.
408
+ */
406
409
  mobileCompactSuggestions?: boolean;
407
410
  /** The mobile picker's opener, given the number of additional replies. Defaults to `+N more`. */
408
411
  replySuggestionsMoreLabel?: (count: number) => string;
@@ -924,7 +924,7 @@ function MobileReplySuggestions({
924
924
  DrawerContent,
925
925
  {
926
926
  "aria-describedby": void 0,
927
- className: "max-h-[min(85dvh,40rem)] overflow-hidden pb-[env(safe-area-inset-bottom)]",
927
+ className: "max-h-[min(85dvh,40rem)] overflow-hidden pb-[env(safe-area-inset-bottom)] md:mx-auto md:w-full md:max-w-xl",
928
928
  onOpenAutoFocus: (event) => {
929
929
  event.preventDefault();
930
930
  closeRef.current?.focus({ preventScroll: true });
@@ -999,6 +999,19 @@ function ExamplePromptsLoading({ label, className }) {
999
999
  function ChatError({ children, className }) {
1000
1000
  return /* @__PURE__ */ jsx("p", { "data-slot": "chat-error", role: "alert", className: cn("mt-2 text-xs text-destructive", className), children });
1001
1001
  }
1002
+ var SHORT_VIEWPORT_HEIGHT = 900;
1003
+ function useIsShortViewport() {
1004
+ const [short, setShort] = useState(false);
1005
+ useEffect(() => {
1006
+ if (typeof window === "undefined") return;
1007
+ const mql = window.matchMedia(`(max-height: ${SHORT_VIEWPORT_HEIGHT - 1}px)`);
1008
+ const onChange = () => setShort(window.innerHeight < SHORT_VIEWPORT_HEIGHT);
1009
+ mql.addEventListener("change", onChange);
1010
+ onChange();
1011
+ return () => mql.removeEventListener("change", onChange);
1012
+ }, []);
1013
+ return short;
1014
+ }
1002
1015
  var Chat = forwardRef(function Chat2({
1003
1016
  messages,
1004
1017
  onSend,
@@ -1127,7 +1140,8 @@ var Chat = forwardRef(function Chat2({
1127
1140
  );
1128
1141
  const application = layout === "application";
1129
1142
  const workspace = layout === "workspace";
1130
- const compactSuggestions = mobileCompactSuggestions && isMobile;
1143
+ const shortViewport = useIsShortViewport();
1144
+ const compactSuggestions = mobileCompactSuggestions && (isMobile || shortViewport);
1131
1145
  const showEmptyFileDropzone = emptyFileDropzone && Boolean(onFilesSelected) && attachments.length === 0;
1132
1146
  const liveVoiceActive = voiceSession && voiceSession.state !== "disconnected" && voiceSession.state !== "error";
1133
1147
  const showEmptyPending = !conversationStarted && pending && Boolean(emptyPendingContent) && !liveVoiceActive;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epicbagel/saas-kit",
3
- "version": "1.28.0",
3
+ "version": "1.29.0",
4
4
  "description": "Accessible React primitives, layout components and design tokens for SaaS apps, built on Radix UI and Tailwind CSS v4.",
5
5
  "license": "MIT",
6
6
  "keywords": [