@scripso-homepad/ui 0.4.27 → 0.4.29

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.
@@ -63,6 +63,8 @@ type AppHeaderProps = {
63
63
  notificationsIcon?: ReactNode;
64
64
  searchIcon?: ReactNode;
65
65
  buildingChevronIcon?: ReactNode;
66
+ /** Rendered before the building select (e.g. month period control). */
67
+ actions?: ReactNode;
66
68
  buildingSelectDisabled?: boolean;
67
69
  searchDisabled?: boolean;
68
70
  notificationsDisabled?: boolean;
@@ -70,7 +72,7 @@ type AppHeaderProps = {
70
72
  onNotificationsClick?: () => void;
71
73
  onSearchChange?: (value: string) => void;
72
74
  };
73
- declare function AppHeader({ title, labels, hasBuildingSelect, showSearch, buildingOptions, selectedBuildingId, className, buildingSelectClassName, searchClassName, notificationsButtonClassName, searchValue, searchFieldStyle, buildingIcon, notificationsIcon, searchIcon, buildingChevronIcon, buildingSelectDisabled, searchDisabled, notificationsDisabled, onBuildingChange, onNotificationsClick, onSearchChange, }: AppHeaderProps): react.JSX.Element;
75
+ declare function AppHeader({ title, labels, hasBuildingSelect, showSearch, buildingOptions, selectedBuildingId, className, buildingSelectClassName, searchClassName, notificationsButtonClassName, searchValue, searchFieldStyle, buildingIcon, notificationsIcon, searchIcon, buildingChevronIcon, actions, buildingSelectDisabled, searchDisabled, notificationsDisabled, onBuildingChange, onNotificationsClick, onSearchChange, }: AppHeaderProps): react.JSX.Element;
74
76
 
75
77
  type BuildingSelectProps = {
76
78
  options: AdminBuildingOption[];
@@ -436,6 +438,8 @@ type ModalProps = {
436
438
  subtitle?: string;
437
439
  icon?: ReactNode;
438
440
  iconContainerClassName?: string;
441
+ titleClassName?: string;
442
+ subtitleClassName?: string;
439
443
  children: ReactNode;
440
444
  cancelText: string;
441
445
  confirmText: string;
@@ -451,7 +455,7 @@ type ModalProps = {
451
455
  contentClassName?: string;
452
456
  buttonClassName?: string;
453
457
  };
454
- declare function Modal({ open, title, subtitle, icon, iconContainerClassName, children, cancelText, confirmText, onCancel, onConfirm, footerAlign, footerLayout, cancelDisabled, confirmDisabled, closeOnBackdrop, closeOnEscape, containerClassName, contentClassName, buttonClassName, }: ModalProps): react.JSX.Element | null;
458
+ declare function Modal({ open, title, subtitle, icon, iconContainerClassName, titleClassName, subtitleClassName, children, cancelText, confirmText, onCancel, onConfirm, footerAlign, footerLayout, cancelDisabled, confirmDisabled, closeOnBackdrop, closeOnEscape, containerClassName, contentClassName, buttonClassName, }: ModalProps): react.JSX.Element | null;
455
459
 
456
460
  type DrawerProps = {
457
461
  open: boolean;
@@ -63,6 +63,8 @@ type AppHeaderProps = {
63
63
  notificationsIcon?: ReactNode;
64
64
  searchIcon?: ReactNode;
65
65
  buildingChevronIcon?: ReactNode;
66
+ /** Rendered before the building select (e.g. month period control). */
67
+ actions?: ReactNode;
66
68
  buildingSelectDisabled?: boolean;
67
69
  searchDisabled?: boolean;
68
70
  notificationsDisabled?: boolean;
@@ -70,7 +72,7 @@ type AppHeaderProps = {
70
72
  onNotificationsClick?: () => void;
71
73
  onSearchChange?: (value: string) => void;
72
74
  };
73
- declare function AppHeader({ title, labels, hasBuildingSelect, showSearch, buildingOptions, selectedBuildingId, className, buildingSelectClassName, searchClassName, notificationsButtonClassName, searchValue, searchFieldStyle, buildingIcon, notificationsIcon, searchIcon, buildingChevronIcon, buildingSelectDisabled, searchDisabled, notificationsDisabled, onBuildingChange, onNotificationsClick, onSearchChange, }: AppHeaderProps): react.JSX.Element;
75
+ declare function AppHeader({ title, labels, hasBuildingSelect, showSearch, buildingOptions, selectedBuildingId, className, buildingSelectClassName, searchClassName, notificationsButtonClassName, searchValue, searchFieldStyle, buildingIcon, notificationsIcon, searchIcon, buildingChevronIcon, actions, buildingSelectDisabled, searchDisabled, notificationsDisabled, onBuildingChange, onNotificationsClick, onSearchChange, }: AppHeaderProps): react.JSX.Element;
74
76
 
75
77
  type BuildingSelectProps = {
76
78
  options: AdminBuildingOption[];
@@ -436,6 +438,8 @@ type ModalProps = {
436
438
  subtitle?: string;
437
439
  icon?: ReactNode;
438
440
  iconContainerClassName?: string;
441
+ titleClassName?: string;
442
+ subtitleClassName?: string;
439
443
  children: ReactNode;
440
444
  cancelText: string;
441
445
  confirmText: string;
@@ -451,7 +455,7 @@ type ModalProps = {
451
455
  contentClassName?: string;
452
456
  buttonClassName?: string;
453
457
  };
454
- declare function Modal({ open, title, subtitle, icon, iconContainerClassName, children, cancelText, confirmText, onCancel, onConfirm, footerAlign, footerLayout, cancelDisabled, confirmDisabled, closeOnBackdrop, closeOnEscape, containerClassName, contentClassName, buttonClassName, }: ModalProps): react.JSX.Element | null;
458
+ declare function Modal({ open, title, subtitle, icon, iconContainerClassName, titleClassName, subtitleClassName, children, cancelText, confirmText, onCancel, onConfirm, footerAlign, footerLayout, cancelDisabled, confirmDisabled, closeOnBackdrop, closeOnEscape, containerClassName, contentClassName, buttonClassName, }: ModalProps): react.JSX.Element | null;
455
459
 
456
460
  type DrawerProps = {
457
461
  open: boolean;
package/dist/web/index.js CHANGED
@@ -28821,6 +28821,7 @@ function AppHeader({
28821
28821
  notificationsIcon,
28822
28822
  searchIcon,
28823
28823
  buildingChevronIcon,
28824
+ actions,
28824
28825
  buildingSelectDisabled = false,
28825
28826
  searchDisabled = false,
28826
28827
  notificationsDisabled = false,
@@ -28838,6 +28839,7 @@ function AppHeader({
28838
28839
  children: [
28839
28840
  /* @__PURE__ */ jsx("h1", { className: "truncate typography-title text-slate-blue", children: title }),
28840
28841
  /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-3", children: [
28842
+ actions,
28841
28843
  hasBuildingSelect ? /* @__PURE__ */ jsx(
28842
28844
  BuildingSelect,
28843
28845
  {
@@ -30322,6 +30324,8 @@ function Modal({
30322
30324
  subtitle,
30323
30325
  icon,
30324
30326
  iconContainerClassName,
30327
+ titleClassName,
30328
+ subtitleClassName,
30325
30329
  children,
30326
30330
  cancelText,
30327
30331
  confirmText,
@@ -30358,9 +30362,8 @@ function Modal({
30358
30362
  return null;
30359
30363
  }
30360
30364
  const sharedButtonClassName = cn(
30361
- "btn h-13 w-full justify-center!",
30362
- footerLayout === "split" && "min-w-0",
30363
- footerLayout !== "split" && buttonClassName
30365
+ "btn h-13 w-full! min-w-0! justify-center!",
30366
+ buttonClassName
30364
30367
  );
30365
30368
  const modal = /* @__PURE__ */ jsx(
30366
30369
  "div",
@@ -30403,7 +30406,7 @@ function Modal({
30403
30406
  "h2",
30404
30407
  {
30405
30408
  id: "homepad-modal-title",
30406
- className: "typography-title-sm tracking-normal text-black",
30409
+ className: cn("typography-title-sm tracking-normal text-black", titleClassName),
30407
30410
  children: title
30408
30411
  }
30409
30412
  ),
@@ -30411,7 +30414,10 @@ function Modal({
30411
30414
  "p",
30412
30415
  {
30413
30416
  id: "homepad-modal-subtitle",
30414
- className: "typography-caption tracking-normal text-storm-gray-400",
30417
+ className: cn(
30418
+ "typography-caption tracking-normal text-storm-gray-400",
30419
+ subtitleClassName
30420
+ ),
30415
30421
  children: subtitle
30416
30422
  }
30417
30423
  ) : null
@@ -30501,23 +30507,36 @@ function Drawer({
30501
30507
  }) {
30502
30508
  const [isPresent, setIsPresent] = useState(open);
30503
30509
  const [isAnimatedIn, setIsAnimatedIn] = useState(false);
30510
+ const [isTransformSettled, setIsTransformSettled] = useState(open);
30504
30511
  useEffect(() => {
30505
30512
  if (open) {
30506
30513
  setIsPresent(true);
30507
- const frame = window.requestAnimationFrame(() => {
30514
+ setIsTransformSettled(false);
30515
+ const frame2 = window.requestAnimationFrame(() => {
30508
30516
  window.requestAnimationFrame(() => {
30509
30517
  setIsAnimatedIn(true);
30510
30518
  });
30511
30519
  });
30520
+ const settleTimeout = window.setTimeout(() => {
30521
+ setIsTransformSettled(true);
30522
+ }, DRAWER_TRANSITION_MS);
30512
30523
  return () => {
30513
- window.cancelAnimationFrame(frame);
30524
+ window.cancelAnimationFrame(frame2);
30525
+ window.clearTimeout(settleTimeout);
30514
30526
  };
30515
30527
  }
30516
- setIsAnimatedIn(false);
30528
+ setIsTransformSettled(false);
30529
+ setIsAnimatedIn(true);
30530
+ const frame = window.requestAnimationFrame(() => {
30531
+ window.requestAnimationFrame(() => {
30532
+ setIsAnimatedIn(false);
30533
+ });
30534
+ });
30517
30535
  const timeout = window.setTimeout(() => {
30518
30536
  setIsPresent(false);
30519
30537
  }, DRAWER_TRANSITION_MS);
30520
30538
  return () => {
30539
+ window.cancelAnimationFrame(frame);
30521
30540
  window.clearTimeout(timeout);
30522
30541
  };
30523
30542
  }, [open]);
@@ -30566,8 +30585,10 @@ function Drawer({
30566
30585
  "aria-labelledby": "homepad-drawer-title",
30567
30586
  ...subtitle ? { "aria-describedby": "homepad-drawer-subtitle" } : {},
30568
30587
  className: cn(
30569
- "relative z-10 flex h-[calc(100dvh-16px)] min-h-0 flex-col overflow-hidden rounded-[16px] bg-white shadow-2xl transition-transform duration-300 ease-in-out will-change-transform max-md:h-dvh max-md:rounded-none",
30570
- isAnimatedIn ? "translate-x-0" : "translate-x-full",
30588
+ "relative z-10 flex h-[calc(100dvh-16px)] min-h-0 flex-col overflow-hidden rounded-[16px] bg-white shadow-2xl transition-transform duration-300 ease-in-out max-md:h-dvh max-md:rounded-none",
30589
+ // Keep GPU transform only while animating — settled translate-x-0 blurs text.
30590
+ !isTransformSettled && "will-change-transform",
30591
+ isAnimatedIn ? isTransformSettled ? "transform-none" : "translate-x-0" : "translate-x-full",
30571
30592
  widthClassName,
30572
30593
  className
30573
30594
  ),
@@ -30906,7 +30927,10 @@ function ConfirmModal({
30906
30927
  if (!open) {
30907
30928
  return null;
30908
30929
  }
30909
- const sharedButtonClassName = cn("btn h-10 min-w-0 flex-1 justify-center!", buttonClassName);
30930
+ const sharedButtonClassName = cn(
30931
+ "btn h-10! w-full! min-w-0! justify-center!",
30932
+ buttonClassName
30933
+ );
30910
30934
  return /* @__PURE__ */ jsx(
30911
30935
  "div",
30912
30936
  {
@@ -30921,7 +30945,7 @@ function ConfirmModal({
30921
30945
  "aria-labelledby": "homepad-confirm-modal-title",
30922
30946
  "aria-describedby": "homepad-confirm-modal-description",
30923
30947
  className: cn(
30924
- "flex w-full max-w-md flex-col gap-8 rounded-2xl bg-white p-4 opacity-100 md:p-6",
30948
+ "flex w-full max-w-md flex-col gap-8 rounded-3xl bg-white p-6 opacity-100 md:p-8",
30925
30949
  containerClassName
30926
30950
  ),
30927
30951
  onClick: (event) => {
@@ -30947,7 +30971,7 @@ function ConfirmModal({
30947
30971
  }
30948
30972
  )
30949
30973
  ] }),
30950
- /* @__PURE__ */ jsxs("footer", { className: "flex w-full gap-4", children: [
30974
+ /* @__PURE__ */ jsxs("footer", { className: "grid w-full grid-cols-2 gap-4", children: [
30951
30975
  /* @__PURE__ */ jsx(
30952
30976
  Button,
30953
30977
  {