@serhii.olishevskyi/docs 1.2.21 → 1.2.22

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.mts CHANGED
@@ -385,6 +385,48 @@ interface ExpandableNoteComponentProps extends Omit<TypographyProps, 'children'>
385
385
  label?: React__default.ReactNode;
386
386
  }
387
387
 
388
+ type TextTruncateMode = 'truncate' | 'clamp-2' | 'wrap';
389
+ interface HeaderActionItem {
390
+ id: string;
391
+ label: string;
392
+ icon?: React__default.ReactNode;
393
+ onClick: () => void;
394
+ color?: 'inherit' | 'primary' | 'secondary' | 'error' | 'warning' | 'info' | 'success';
395
+ disabled?: boolean;
396
+ divider?: boolean;
397
+ }
398
+ interface PrimaryActionProps {
399
+ label: string;
400
+ onClick: () => void;
401
+ icon?: React__default.ReactNode;
402
+ variant?: 'contained' | 'outlined' | 'text';
403
+ color?: 'primary' | 'secondary' | 'success' | 'error' | 'info' | 'warning';
404
+ disabled?: boolean;
405
+ }
406
+ interface RefreshActionProps {
407
+ onClick: () => void;
408
+ disabled?: boolean;
409
+ }
410
+ interface PageHeaderProps {
411
+ overrideNamespace?: string;
412
+ icon?: React__default.ReactNode;
413
+ title: string;
414
+ subtitle?: string;
415
+ tag?: React__default.ReactNode;
416
+ titleTruncateMode?: TextTruncateMode;
417
+ subtitleTruncateMode?: TextTruncateMode;
418
+ customFragment?: React__default.JSX.Element;
419
+ primaryAction?: PrimaryActionProps;
420
+ secondaryActions?: HeaderActionItem[];
421
+ refreshAction?: RefreshActionProps;
422
+ mobileBreakpoint?: 'xs' | 'sm' | 'md';
423
+ forceMobileView?: boolean;
424
+ sx?: SxProps<Theme>;
425
+ }
426
+ type PageComponentProps = {
427
+ header?: PageHeaderProps;
428
+ };
429
+
388
430
  interface PageLink {
389
431
  text: ReactNode;
390
432
  href?: string;
@@ -449,6 +491,9 @@ declare const UI: {
449
491
  MyAvatar: React$1.FC<MyAvatarComponentProps>;
450
492
  ExpandableNote: React$1.FC<ExpandableNoteComponentProps>;
451
493
  };
494
+ Layout: {
495
+ Page: React$1.FC<React$1.PropsWithChildren<PageComponentProps>>;
496
+ };
452
497
  Widgets: {
453
498
  Locales: {
454
499
  ProtectedLanguageSelector: React$1.FC<{}>;
@@ -814,4 +859,4 @@ declare const Utils: {
814
859
  };
815
860
  };
816
861
 
817
- export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ButtonComponentProps, type CheckboxComponentProps, type CollapsedWidgetContainerProps, type CompanyMember, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps, type DialogSeverity, type DisplayState, type EmailInputComponentProps, type ErrorAlertWidgetProps, type ExpandableNoteComponentProps, type FullCompanyMemberItem, Hooks, type Language, LocalizationProvider, type Membership, type MembershipRole, type MyAvatarComponentProps, type NumberInputComponentProps, type PageLink, type PageLinkWidgetProps, Providers, type RefreshButtonComponentProps, type SaveCompanyUserPayload, type SearchComponentProps, type SelectComponentProps, type SelectOption, Services, type SupabaseConfig, SupabaseProvider, type SupabaseProviderProps, type SwitchComponentProps, type TextFieldComponentProps, type ThemeColors, type ThemeConfig, type ThemeMode, ThemeProvider, ToastProvider, type ToastType, type TranslatableTooltipComponentProps, TranslateProvider, TranslateText, TranslationEditProvider, type TypographyConfig, UI, type UrlComponentProps as UrlProps, type UserAvatarComponentProps, type UserGroupedSessions, type UserPopoverComponentProps, type UserProfile, type UserRoleChipComponentProps, type UserSessionItem, type UserSettings, UserSettingsProvider, type UserStatusChipComponentProps, type UserStatusType, Utils, defaultUserSettings, initI18n, useAI, useAppSettings, useAppTheme, useAuth, useBreadcrumb, useConfirmation, useLocalization, useSupabase, useToast, useTranslationEdit, useTranslationNamespace, useUserSettings };
862
+ export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ButtonComponentProps, type CheckboxComponentProps, type CollapsedWidgetContainerProps, type CompanyMember, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps, type DialogSeverity, type DisplayState, type EmailInputComponentProps, type ErrorAlertWidgetProps, type ExpandableNoteComponentProps, type FullCompanyMemberItem, type HeaderActionItem, Hooks, type Language, LocalizationProvider, type Membership, type MembershipRole, type MyAvatarComponentProps, type NumberInputComponentProps, type PageComponentProps, type PageHeaderProps, type PageLink, type PageLinkWidgetProps, type PrimaryActionProps, Providers, type RefreshActionProps, type RefreshButtonComponentProps, type SaveCompanyUserPayload, type SearchComponentProps, type SelectComponentProps, type SelectOption, Services, type SupabaseConfig, SupabaseProvider, type SupabaseProviderProps, type SwitchComponentProps, type TextFieldComponentProps, type TextTruncateMode, type ThemeColors, type ThemeConfig, type ThemeMode, ThemeProvider, ToastProvider, type ToastType, type TranslatableTooltipComponentProps, TranslateProvider, TranslateText, TranslationEditProvider, type TypographyConfig, UI, type UrlComponentProps as UrlProps, type UserAvatarComponentProps, type UserGroupedSessions, type UserPopoverComponentProps, type UserProfile, type UserRoleChipComponentProps, type UserSessionItem, type UserSettings, UserSettingsProvider, type UserStatusChipComponentProps, type UserStatusType, Utils, defaultUserSettings, initI18n, useAI, useAppSettings, useAppTheme, useAuth, useBreadcrumb, useConfirmation, useLocalization, useSupabase, useToast, useTranslationEdit, useTranslationNamespace, useUserSettings };
package/dist/index.d.ts CHANGED
@@ -385,6 +385,48 @@ interface ExpandableNoteComponentProps extends Omit<TypographyProps, 'children'>
385
385
  label?: React__default.ReactNode;
386
386
  }
387
387
 
388
+ type TextTruncateMode = 'truncate' | 'clamp-2' | 'wrap';
389
+ interface HeaderActionItem {
390
+ id: string;
391
+ label: string;
392
+ icon?: React__default.ReactNode;
393
+ onClick: () => void;
394
+ color?: 'inherit' | 'primary' | 'secondary' | 'error' | 'warning' | 'info' | 'success';
395
+ disabled?: boolean;
396
+ divider?: boolean;
397
+ }
398
+ interface PrimaryActionProps {
399
+ label: string;
400
+ onClick: () => void;
401
+ icon?: React__default.ReactNode;
402
+ variant?: 'contained' | 'outlined' | 'text';
403
+ color?: 'primary' | 'secondary' | 'success' | 'error' | 'info' | 'warning';
404
+ disabled?: boolean;
405
+ }
406
+ interface RefreshActionProps {
407
+ onClick: () => void;
408
+ disabled?: boolean;
409
+ }
410
+ interface PageHeaderProps {
411
+ overrideNamespace?: string;
412
+ icon?: React__default.ReactNode;
413
+ title: string;
414
+ subtitle?: string;
415
+ tag?: React__default.ReactNode;
416
+ titleTruncateMode?: TextTruncateMode;
417
+ subtitleTruncateMode?: TextTruncateMode;
418
+ customFragment?: React__default.JSX.Element;
419
+ primaryAction?: PrimaryActionProps;
420
+ secondaryActions?: HeaderActionItem[];
421
+ refreshAction?: RefreshActionProps;
422
+ mobileBreakpoint?: 'xs' | 'sm' | 'md';
423
+ forceMobileView?: boolean;
424
+ sx?: SxProps<Theme>;
425
+ }
426
+ type PageComponentProps = {
427
+ header?: PageHeaderProps;
428
+ };
429
+
388
430
  interface PageLink {
389
431
  text: ReactNode;
390
432
  href?: string;
@@ -449,6 +491,9 @@ declare const UI: {
449
491
  MyAvatar: React$1.FC<MyAvatarComponentProps>;
450
492
  ExpandableNote: React$1.FC<ExpandableNoteComponentProps>;
451
493
  };
494
+ Layout: {
495
+ Page: React$1.FC<React$1.PropsWithChildren<PageComponentProps>>;
496
+ };
452
497
  Widgets: {
453
498
  Locales: {
454
499
  ProtectedLanguageSelector: React$1.FC<{}>;
@@ -814,4 +859,4 @@ declare const Utils: {
814
859
  };
815
860
  };
816
861
 
817
- export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ButtonComponentProps, type CheckboxComponentProps, type CollapsedWidgetContainerProps, type CompanyMember, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps, type DialogSeverity, type DisplayState, type EmailInputComponentProps, type ErrorAlertWidgetProps, type ExpandableNoteComponentProps, type FullCompanyMemberItem, Hooks, type Language, LocalizationProvider, type Membership, type MembershipRole, type MyAvatarComponentProps, type NumberInputComponentProps, type PageLink, type PageLinkWidgetProps, Providers, type RefreshButtonComponentProps, type SaveCompanyUserPayload, type SearchComponentProps, type SelectComponentProps, type SelectOption, Services, type SupabaseConfig, SupabaseProvider, type SupabaseProviderProps, type SwitchComponentProps, type TextFieldComponentProps, type ThemeColors, type ThemeConfig, type ThemeMode, ThemeProvider, ToastProvider, type ToastType, type TranslatableTooltipComponentProps, TranslateProvider, TranslateText, TranslationEditProvider, type TypographyConfig, UI, type UrlComponentProps as UrlProps, type UserAvatarComponentProps, type UserGroupedSessions, type UserPopoverComponentProps, type UserProfile, type UserRoleChipComponentProps, type UserSessionItem, type UserSettings, UserSettingsProvider, type UserStatusChipComponentProps, type UserStatusType, Utils, defaultUserSettings, initI18n, useAI, useAppSettings, useAppTheme, useAuth, useBreadcrumb, useConfirmation, useLocalization, useSupabase, useToast, useTranslationEdit, useTranslationNamespace, useUserSettings };
862
+ export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ButtonComponentProps, type CheckboxComponentProps, type CollapsedWidgetContainerProps, type CompanyMember, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps, type DialogSeverity, type DisplayState, type EmailInputComponentProps, type ErrorAlertWidgetProps, type ExpandableNoteComponentProps, type FullCompanyMemberItem, type HeaderActionItem, Hooks, type Language, LocalizationProvider, type Membership, type MembershipRole, type MyAvatarComponentProps, type NumberInputComponentProps, type PageComponentProps, type PageHeaderProps, type PageLink, type PageLinkWidgetProps, type PrimaryActionProps, Providers, type RefreshActionProps, type RefreshButtonComponentProps, type SaveCompanyUserPayload, type SearchComponentProps, type SelectComponentProps, type SelectOption, Services, type SupabaseConfig, SupabaseProvider, type SupabaseProviderProps, type SwitchComponentProps, type TextFieldComponentProps, type TextTruncateMode, type ThemeColors, type ThemeConfig, type ThemeMode, ThemeProvider, ToastProvider, type ToastType, type TranslatableTooltipComponentProps, TranslateProvider, TranslateText, TranslationEditProvider, type TypographyConfig, UI, type UrlComponentProps as UrlProps, type UserAvatarComponentProps, type UserGroupedSessions, type UserPopoverComponentProps, type UserProfile, type UserRoleChipComponentProps, type UserSessionItem, type UserSettings, UserSettingsProvider, type UserStatusChipComponentProps, type UserStatusType, Utils, defaultUserSettings, initI18n, useAI, useAppSettings, useAppTheme, useAuth, useBreadcrumb, useConfirmation, useLocalization, useSupabase, useToast, useTranslationEdit, useTranslationNamespace, useUserSettings };
package/dist/index.js CHANGED
@@ -5131,6 +5131,318 @@ var ButtonComponent = (0, import_react31.forwardRef)(
5131
5131
  );
5132
5132
  ButtonComponent.displayName = "ButtonComponent";
5133
5133
 
5134
+ // src/UI/components/layout/PageComponent.tsx
5135
+ var import_react32 = __toESM(require("react"));
5136
+ var import_material28 = require("@mui/material");
5137
+ var import_MoreVert = __toESM(require("@mui/icons-material/MoreVert"));
5138
+ var import_KeyboardArrowDown = __toESM(require("@mui/icons-material/KeyboardArrowDown"));
5139
+ var import_icons_material5 = require("@mui/icons-material");
5140
+ init_context();
5141
+ init_TranslatableTooltipComponent();
5142
+ var import_jsx_runtime38 = require("react/jsx-runtime");
5143
+ var getTruncateStyles = (mode = "truncate") => {
5144
+ switch (mode) {
5145
+ case "truncate":
5146
+ return { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", display: "block" };
5147
+ case "clamp-2":
5148
+ return { display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "normal" };
5149
+ case "wrap":
5150
+ default:
5151
+ return { whiteSpace: "normal", wordBreak: "break-word" };
5152
+ }
5153
+ };
5154
+ var PageHeader = ({
5155
+ overrideNamespace,
5156
+ icon,
5157
+ title,
5158
+ subtitle,
5159
+ tag,
5160
+ titleTruncateMode = "truncate",
5161
+ subtitleTruncateMode = "truncate",
5162
+ customFragment,
5163
+ primaryAction,
5164
+ secondaryActions = [],
5165
+ refreshAction,
5166
+ mobileBreakpoint = "sm",
5167
+ forceMobileView,
5168
+ sx = []
5169
+ }) => {
5170
+ const theme = (0, import_material28.useTheme)();
5171
+ const mediaIsMobile = (0, import_material28.useMediaQuery)(theme.breakpoints.down(mobileBreakpoint));
5172
+ const isMobile = forceMobileView ?? mediaIsMobile;
5173
+ const [anchorEl, setAnchorEl] = (0, import_react32.useState)(null);
5174
+ const isMenuOpen = Boolean(anchorEl);
5175
+ const handleOpenMenu = (e) => setAnchorEl(e.currentTarget);
5176
+ const handleCloseMenu = () => setAnchorEl(null);
5177
+ const handleMenuAction = (cb) => {
5178
+ handleCloseMenu();
5179
+ cb();
5180
+ };
5181
+ const hasSecondaryActions = secondaryActions.length > 0;
5182
+ const hasActions = Boolean(primaryAction || hasSecondaryActions || refreshAction);
5183
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
5184
+ import_material28.Box,
5185
+ {
5186
+ sx: [
5187
+ {
5188
+ display: "flex",
5189
+ alignItems: "center",
5190
+ justifyContent: "space-between",
5191
+ width: "100%",
5192
+ gap: { xs: 1.5, sm: 2.5 },
5193
+ py: 1.5,
5194
+ px: { xs: 1.5, sm: 2 },
5195
+ borderRadius: 2,
5196
+ backgroundColor: "background.paper",
5197
+ boxShadow: "0 1px 3px rgba(0,0,0,0.05)"
5198
+ },
5199
+ ...Array.isArray(sx) ? sx : [sx]
5200
+ ],
5201
+ children: [
5202
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_material28.Box, { sx: { display: "flex", alignItems: "center", gap: { xs: 1.5, sm: 2 }, minWidth: 0, flex: 1 }, children: [
5203
+ icon && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
5204
+ import_material28.Box,
5205
+ {
5206
+ sx: {
5207
+ display: "flex",
5208
+ alignItems: "center",
5209
+ justifyContent: "center",
5210
+ width: { xs: 40, sm: 48 },
5211
+ height: { xs: 40, sm: 48 },
5212
+ borderRadius: 2.5,
5213
+ backgroundColor: "primary.50",
5214
+ color: "primary.main",
5215
+ flexShrink: 0,
5216
+ border: "1px solid",
5217
+ borderColor: "primary.100",
5218
+ "& svg": { fontSize: { xs: 22, sm: 26 } }
5219
+ },
5220
+ children: icon
5221
+ }
5222
+ ),
5223
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_material28.Box, { sx: { minWidth: 0, flex: 1 }, children: [
5224
+ tag && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.Box, { sx: { mb: 0.5, display: "flex", alignItems: "center" }, children: tag }),
5225
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.Tooltip, { title: titleTruncateMode === "truncate" ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(TranslateText, { children: title }) : void 0, arrow: true, placement: "top", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
5226
+ import_material28.Typography,
5227
+ {
5228
+ variant: "h5",
5229
+ component: "h1",
5230
+ sx: {
5231
+ fontWeight: 700,
5232
+ color: "text.primary",
5233
+ fontSize: { xs: "1.125rem", sm: "1.35rem" },
5234
+ lineHeight: 1.3,
5235
+ ...getTruncateStyles(titleTruncateMode)
5236
+ },
5237
+ children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(TranslateText, { children: title })
5238
+ }
5239
+ ) }),
5240
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.Tooltip, { title: subtitleTruncateMode === "truncate" ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(TranslateText, { children: subtitle }) : void 0, arrow: true, placement: "top", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
5241
+ import_material28.Typography,
5242
+ {
5243
+ variant: "body2",
5244
+ sx: {
5245
+ color: "text.secondary",
5246
+ mt: 0.25,
5247
+ fontSize: { xs: "0.8125rem", sm: "0.875rem" },
5248
+ lineHeight: 1.4,
5249
+ ...getTruncateStyles(subtitleTruncateMode)
5250
+ },
5251
+ children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(TranslateText, { children: subtitle })
5252
+ }
5253
+ ) })
5254
+ ] })
5255
+ ] }),
5256
+ hasActions && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.Box, { sx: { flexShrink: 0, display: "flex", alignItems: "center", gap: 1 }, children: isMobile ? (
5257
+ /* MOBILE: IconButton with MoreVertIcon showing ALL actions inside Menu */
5258
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
5259
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(TranslatableTooltipComponent, { title: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Actions" }), children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
5260
+ import_material28.IconButton,
5261
+ {
5262
+ onClick: handleOpenMenu,
5263
+ sx: { border: "1px solid", borderColor: "divider", borderRadius: 2, p: 1 },
5264
+ children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_MoreVert.default, {})
5265
+ }
5266
+ ) }),
5267
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
5268
+ import_material28.Menu,
5269
+ {
5270
+ anchorEl,
5271
+ open: isMenuOpen,
5272
+ onClose: handleCloseMenu,
5273
+ transformOrigin: { horizontal: "right", vertical: "top" },
5274
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
5275
+ slotProps: { paper: { elevation: 4, sx: { minWidth: 200, borderRadius: 2, mt: 1, p: 0.5 } } },
5276
+ children: [
5277
+ primaryAction && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
5278
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
5279
+ import_material28.MenuItem,
5280
+ {
5281
+ onClick: () => handleMenuAction(primaryAction.onClick),
5282
+ disabled: primaryAction.disabled,
5283
+ sx: {
5284
+ borderRadius: 1.5,
5285
+ fontWeight: 700,
5286
+ backgroundColor: "primary.50",
5287
+ color: primaryAction.color ? `${primaryAction.color}.main` : "primary.main",
5288
+ py: 1.2,
5289
+ px: 1.5
5290
+ },
5291
+ children: [
5292
+ primaryAction.icon && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.ListItemIcon, { sx: { color: "inherit", minWidth: 32 }, children: primaryAction.icon }),
5293
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.ListItemText, { primary: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(TranslateText, { children: primaryAction.label }), slotProps: { primary: { sx: { fontWeight: 700, fontSize: "0.9rem" } } } })
5294
+ ]
5295
+ }
5296
+ ),
5297
+ hasSecondaryActions && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.Divider, { sx: { my: 0.75 } })
5298
+ ] }),
5299
+ secondaryActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_react32.default.Fragment, { children: [
5300
+ action.divider && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.Divider, { sx: { my: 0.5 } }),
5301
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
5302
+ import_material28.MenuItem,
5303
+ {
5304
+ onClick: () => handleMenuAction(action.onClick),
5305
+ disabled: action.disabled,
5306
+ sx: { borderRadius: 1, py: 1, px: 1.5, color: action.color ? `${action.color}.main` : "text.primary" },
5307
+ children: [
5308
+ action.icon && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.ListItemIcon, { sx: { color: action.color ? `${action.color}.main` : "text.secondary", minWidth: 32 }, children: action.icon }),
5309
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.ListItemText, { primary: action.label, slotProps: { primary: { sx: { fontSize: "0.875rem" } } } })
5310
+ ]
5311
+ }
5312
+ )
5313
+ ] }, action.id)),
5314
+ refreshAction && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
5315
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.Divider, { sx: { my: 0.5 } }),
5316
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
5317
+ import_material28.MenuItem,
5318
+ {
5319
+ onClick: () => handleMenuAction(refreshAction.onClick),
5320
+ disabled: refreshAction.disabled,
5321
+ sx: {
5322
+ borderRadius: 1.5,
5323
+ fontWeight: 700,
5324
+ backgroundColor: "primary.50",
5325
+ py: 1.2,
5326
+ px: 1.5
5327
+ },
5328
+ children: [
5329
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.ListItemIcon, { sx: { color: "inherit", minWidth: 32 }, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_icons_material5.Refresh, {}) }),
5330
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.ListItemText, { primary: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Refresh" }), slotProps: { primary: { sx: { fontWeight: 700, fontSize: "0.9rem" } } } })
5331
+ ]
5332
+ }
5333
+ )
5334
+ ] })
5335
+ ]
5336
+ }
5337
+ )
5338
+ ] })
5339
+ ) : (
5340
+ /* DESKTOP: Primary Action Button + Secondary Actions Dropdown Button */
5341
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_material28.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
5342
+ (primaryAction || refreshAction) && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_material28.Stack, { direction: "row", spacing: 2, children: [
5343
+ primaryAction && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
5344
+ import_material28.Button,
5345
+ {
5346
+ variant: primaryAction.variant || "contained",
5347
+ color: primaryAction.color || "primary",
5348
+ onClick: primaryAction.onClick,
5349
+ disabled: primaryAction.disabled,
5350
+ startIcon: primaryAction.icon,
5351
+ sx: { borderRadius: 2, textTransform: "none", fontWeight: 600, px: 2, py: 0.85 },
5352
+ children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(TranslateText, { children: primaryAction.label })
5353
+ }
5354
+ ),
5355
+ refreshAction && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(TranslatableTooltipComponent, { title: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Refresh" }), children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
5356
+ import_material28.Fab,
5357
+ {
5358
+ color: "default",
5359
+ onClick: refreshAction.onClick,
5360
+ disabled: refreshAction.disabled,
5361
+ "aria-label": "refresh",
5362
+ size: "small",
5363
+ children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_icons_material5.Refresh, {})
5364
+ }
5365
+ ) })
5366
+ ] }),
5367
+ hasSecondaryActions && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
5368
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
5369
+ import_material28.IconButton,
5370
+ {
5371
+ onClick: handleOpenMenu,
5372
+ sx: { border: "1px solid", borderColor: "divider", borderRadius: 2, p: 1 },
5373
+ children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_KeyboardArrowDown.default, {})
5374
+ }
5375
+ ),
5376
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
5377
+ import_material28.Menu,
5378
+ {
5379
+ anchorEl,
5380
+ open: isMenuOpen,
5381
+ onClose: handleCloseMenu,
5382
+ transformOrigin: { horizontal: "right", vertical: "top" },
5383
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
5384
+ slotProps: { paper: { elevation: 4, sx: { minWidth: 180, borderRadius: 2, mt: 1, p: 0.5 } } },
5385
+ children: secondaryActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_react32.default.Fragment, { children: [
5386
+ action.divider && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.Divider, { sx: { my: 0.5 } }),
5387
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
5388
+ import_material28.MenuItem,
5389
+ {
5390
+ onClick: () => handleMenuAction(action.onClick),
5391
+ disabled: action.disabled,
5392
+ sx: { borderRadius: 1, py: 0.85, color: action.color ? `${action.color}.main` : "text.primary" },
5393
+ children: [
5394
+ action.icon && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.ListItemIcon, { sx: { color: action.color ? `${action.color}.main` : "text.secondary", minWidth: 32 }, children: action.icon }),
5395
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material28.ListItemText, { primary: action.label, slotProps: { primary: { sx: { fontSize: "0.875rem" } } } })
5396
+ ]
5397
+ }
5398
+ )
5399
+ ] }, action.id))
5400
+ }
5401
+ )
5402
+ ] })
5403
+ ] })
5404
+ ) }),
5405
+ customFragment && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_jsx_runtime38.Fragment, { children: customFragment })
5406
+ ]
5407
+ }
5408
+ );
5409
+ };
5410
+ var PageContainer = ({ children }) => {
5411
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
5412
+ import_material28.Box,
5413
+ {
5414
+ sx: {
5415
+ width: "100%",
5416
+ boxSizing: "border-box",
5417
+ p: { xs: 1.5, sm: 3 },
5418
+ backgroundColor: "background.paper"
5419
+ },
5420
+ children
5421
+ }
5422
+ );
5423
+ };
5424
+ var PageComponent = ({
5425
+ header,
5426
+ children
5427
+ }) => {
5428
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
5429
+ import_material28.Box,
5430
+ {
5431
+ sx: {
5432
+ //pt: 2,
5433
+ flexGrow: 1,
5434
+ minHeight: 0,
5435
+ overflowY: "auto",
5436
+ boxSizing: "border-box"
5437
+ },
5438
+ children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(PageContainer, { children: [
5439
+ header && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PageHeader, { ...header }),
5440
+ children
5441
+ ] })
5442
+ }
5443
+ );
5444
+ };
5445
+
5134
5446
  // src/UI/index.ts
5135
5447
  var UI = {
5136
5448
  Inputs: {
@@ -5157,9 +5469,9 @@ var UI = {
5157
5469
  MyAvatar: MyAvatarComponent,
5158
5470
  ExpandableNote: ExpandableNoteComponent
5159
5471
  },
5160
- /*Layout: {
5161
- Row: FormRow,
5162
- },*/
5472
+ Layout: {
5473
+ Page: PageComponent
5474
+ },
5163
5475
  Widgets: {
5164
5476
  Locales: {
5165
5477
  ProtectedLanguageSelector: LanguageSelector,
@@ -5198,16 +5510,16 @@ var Services = {
5198
5510
  };
5199
5511
 
5200
5512
  // src/hooks/useUserStatus.ts
5201
- var import_react32 = require("react");
5513
+ var import_react33 = require("react");
5202
5514
  init_deviceId();
5203
5515
  init_context();
5204
5516
  var ONLINE_THRESHOLD_MINUTES = 2;
5205
5517
  var AWAY_THRESHOLD_MINUTES = 15;
5206
5518
  var useUserStatus2 = (userId, initialLastSeenAt, currentAuthUserId) => {
5207
5519
  const supabase = useSupabase();
5208
- const [status, setStatus] = (0, import_react32.useState)("offline");
5209
- const [lastSeen, setLastSeen] = (0, import_react32.useState)(initialLastSeenAt ?? null);
5210
- const lastSeenRef = (0, import_react32.useRef)(initialLastSeenAt ?? null);
5520
+ const [status, setStatus] = (0, import_react33.useState)("offline");
5521
+ const [lastSeen, setLastSeen] = (0, import_react33.useState)(initialLastSeenAt ?? null);
5522
+ const lastSeenRef = (0, import_react33.useRef)(initialLastSeenAt ?? null);
5211
5523
  lastSeenRef.current = lastSeen;
5212
5524
  const calculateStatus = (isOnline, lastSeenIso) => {
5213
5525
  if (isOnline) return "online";
@@ -5223,7 +5535,7 @@ var useUserStatus2 = (userId, initialLastSeenAt, currentAuthUserId) => {
5223
5535
  }
5224
5536
  return "offline";
5225
5537
  };
5226
- (0, import_react32.useEffect)(() => {
5538
+ (0, import_react33.useEffect)(() => {
5227
5539
  if (!userId) return;
5228
5540
  let isMounted = true;
5229
5541
  const isSelf = currentAuthUserId && userId === currentAuthUserId;
package/dist/index.mjs CHANGED
@@ -2215,6 +2215,331 @@ var ButtonComponent = forwardRef(
2215
2215
  );
2216
2216
  ButtonComponent.displayName = "ButtonComponent";
2217
2217
 
2218
+ // src/UI/components/layout/PageComponent.tsx
2219
+ import React12, { useState as useState13 } from "react";
2220
+ import {
2221
+ Box as Box10,
2222
+ Typography as Typography9,
2223
+ Button as Button6,
2224
+ IconButton as IconButton8,
2225
+ Menu as Menu2,
2226
+ MenuItem as MenuItem3,
2227
+ ListItemIcon as ListItemIcon2,
2228
+ ListItemText as ListItemText3,
2229
+ Divider as Divider3,
2230
+ Tooltip as Tooltip8,
2231
+ useTheme as useTheme2,
2232
+ useMediaQuery,
2233
+ Stack,
2234
+ Fab as Fab2
2235
+ } from "@mui/material";
2236
+ import MoreVertIcon from "@mui/icons-material/MoreVert";
2237
+ import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
2238
+ import { Refresh as RefreshIcon } from "@mui/icons-material";
2239
+ import { Fragment as Fragment10, jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
2240
+ var getTruncateStyles = (mode = "truncate") => {
2241
+ switch (mode) {
2242
+ case "truncate":
2243
+ return { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", display: "block" };
2244
+ case "clamp-2":
2245
+ return { display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "normal" };
2246
+ case "wrap":
2247
+ default:
2248
+ return { whiteSpace: "normal", wordBreak: "break-word" };
2249
+ }
2250
+ };
2251
+ var PageHeader = ({
2252
+ overrideNamespace,
2253
+ icon,
2254
+ title,
2255
+ subtitle,
2256
+ tag,
2257
+ titleTruncateMode = "truncate",
2258
+ subtitleTruncateMode = "truncate",
2259
+ customFragment,
2260
+ primaryAction,
2261
+ secondaryActions = [],
2262
+ refreshAction,
2263
+ mobileBreakpoint = "sm",
2264
+ forceMobileView,
2265
+ sx = []
2266
+ }) => {
2267
+ const theme = useTheme2();
2268
+ const mediaIsMobile = useMediaQuery(theme.breakpoints.down(mobileBreakpoint));
2269
+ const isMobile = forceMobileView ?? mediaIsMobile;
2270
+ const [anchorEl, setAnchorEl] = useState13(null);
2271
+ const isMenuOpen = Boolean(anchorEl);
2272
+ const handleOpenMenu = (e) => setAnchorEl(e.currentTarget);
2273
+ const handleCloseMenu = () => setAnchorEl(null);
2274
+ const handleMenuAction = (cb) => {
2275
+ handleCloseMenu();
2276
+ cb();
2277
+ };
2278
+ const hasSecondaryActions = secondaryActions.length > 0;
2279
+ const hasActions = Boolean(primaryAction || hasSecondaryActions || refreshAction);
2280
+ return /* @__PURE__ */ jsxs13(
2281
+ Box10,
2282
+ {
2283
+ sx: [
2284
+ {
2285
+ display: "flex",
2286
+ alignItems: "center",
2287
+ justifyContent: "space-between",
2288
+ width: "100%",
2289
+ gap: { xs: 1.5, sm: 2.5 },
2290
+ py: 1.5,
2291
+ px: { xs: 1.5, sm: 2 },
2292
+ borderRadius: 2,
2293
+ backgroundColor: "background.paper",
2294
+ boxShadow: "0 1px 3px rgba(0,0,0,0.05)"
2295
+ },
2296
+ ...Array.isArray(sx) ? sx : [sx]
2297
+ ],
2298
+ children: [
2299
+ /* @__PURE__ */ jsxs13(Box10, { sx: { display: "flex", alignItems: "center", gap: { xs: 1.5, sm: 2 }, minWidth: 0, flex: 1 }, children: [
2300
+ icon && /* @__PURE__ */ jsx18(
2301
+ Box10,
2302
+ {
2303
+ sx: {
2304
+ display: "flex",
2305
+ alignItems: "center",
2306
+ justifyContent: "center",
2307
+ width: { xs: 40, sm: 48 },
2308
+ height: { xs: 40, sm: 48 },
2309
+ borderRadius: 2.5,
2310
+ backgroundColor: "primary.50",
2311
+ color: "primary.main",
2312
+ flexShrink: 0,
2313
+ border: "1px solid",
2314
+ borderColor: "primary.100",
2315
+ "& svg": { fontSize: { xs: 22, sm: 26 } }
2316
+ },
2317
+ children: icon
2318
+ }
2319
+ ),
2320
+ /* @__PURE__ */ jsxs13(Box10, { sx: { minWidth: 0, flex: 1 }, children: [
2321
+ tag && /* @__PURE__ */ jsx18(Box10, { sx: { mb: 0.5, display: "flex", alignItems: "center" }, children: tag }),
2322
+ /* @__PURE__ */ jsx18(Tooltip8, { title: titleTruncateMode === "truncate" ? /* @__PURE__ */ jsx18(TranslateText, { children: title }) : void 0, arrow: true, placement: "top", children: /* @__PURE__ */ jsx18(
2323
+ Typography9,
2324
+ {
2325
+ variant: "h5",
2326
+ component: "h1",
2327
+ sx: {
2328
+ fontWeight: 700,
2329
+ color: "text.primary",
2330
+ fontSize: { xs: "1.125rem", sm: "1.35rem" },
2331
+ lineHeight: 1.3,
2332
+ ...getTruncateStyles(titleTruncateMode)
2333
+ },
2334
+ children: /* @__PURE__ */ jsx18(TranslateText, { children: title })
2335
+ }
2336
+ ) }),
2337
+ subtitle && /* @__PURE__ */ jsx18(Tooltip8, { title: subtitleTruncateMode === "truncate" ? /* @__PURE__ */ jsx18(TranslateText, { children: subtitle }) : void 0, arrow: true, placement: "top", children: /* @__PURE__ */ jsx18(
2338
+ Typography9,
2339
+ {
2340
+ variant: "body2",
2341
+ sx: {
2342
+ color: "text.secondary",
2343
+ mt: 0.25,
2344
+ fontSize: { xs: "0.8125rem", sm: "0.875rem" },
2345
+ lineHeight: 1.4,
2346
+ ...getTruncateStyles(subtitleTruncateMode)
2347
+ },
2348
+ children: /* @__PURE__ */ jsx18(TranslateText, { children: subtitle })
2349
+ }
2350
+ ) })
2351
+ ] })
2352
+ ] }),
2353
+ hasActions && /* @__PURE__ */ jsx18(Box10, { sx: { flexShrink: 0, display: "flex", alignItems: "center", gap: 1 }, children: isMobile ? (
2354
+ /* MOBILE: IconButton with MoreVertIcon showing ALL actions inside Menu */
2355
+ /* @__PURE__ */ jsxs13(Fragment10, { children: [
2356
+ /* @__PURE__ */ jsx18(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Actions" }), children: /* @__PURE__ */ jsx18(
2357
+ IconButton8,
2358
+ {
2359
+ onClick: handleOpenMenu,
2360
+ sx: { border: "1px solid", borderColor: "divider", borderRadius: 2, p: 1 },
2361
+ children: /* @__PURE__ */ jsx18(MoreVertIcon, {})
2362
+ }
2363
+ ) }),
2364
+ /* @__PURE__ */ jsxs13(
2365
+ Menu2,
2366
+ {
2367
+ anchorEl,
2368
+ open: isMenuOpen,
2369
+ onClose: handleCloseMenu,
2370
+ transformOrigin: { horizontal: "right", vertical: "top" },
2371
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
2372
+ slotProps: { paper: { elevation: 4, sx: { minWidth: 200, borderRadius: 2, mt: 1, p: 0.5 } } },
2373
+ children: [
2374
+ primaryAction && /* @__PURE__ */ jsxs13(Fragment10, { children: [
2375
+ /* @__PURE__ */ jsxs13(
2376
+ MenuItem3,
2377
+ {
2378
+ onClick: () => handleMenuAction(primaryAction.onClick),
2379
+ disabled: primaryAction.disabled,
2380
+ sx: {
2381
+ borderRadius: 1.5,
2382
+ fontWeight: 700,
2383
+ backgroundColor: "primary.50",
2384
+ color: primaryAction.color ? `${primaryAction.color}.main` : "primary.main",
2385
+ py: 1.2,
2386
+ px: 1.5
2387
+ },
2388
+ children: [
2389
+ primaryAction.icon && /* @__PURE__ */ jsx18(ListItemIcon2, { sx: { color: "inherit", minWidth: 32 }, children: primaryAction.icon }),
2390
+ /* @__PURE__ */ jsx18(ListItemText3, { primary: /* @__PURE__ */ jsx18(TranslateText, { children: primaryAction.label }), slotProps: { primary: { sx: { fontWeight: 700, fontSize: "0.9rem" } } } })
2391
+ ]
2392
+ }
2393
+ ),
2394
+ hasSecondaryActions && /* @__PURE__ */ jsx18(Divider3, { sx: { my: 0.75 } })
2395
+ ] }),
2396
+ secondaryActions.map((action) => /* @__PURE__ */ jsxs13(React12.Fragment, { children: [
2397
+ action.divider && /* @__PURE__ */ jsx18(Divider3, { sx: { my: 0.5 } }),
2398
+ /* @__PURE__ */ jsxs13(
2399
+ MenuItem3,
2400
+ {
2401
+ onClick: () => handleMenuAction(action.onClick),
2402
+ disabled: action.disabled,
2403
+ sx: { borderRadius: 1, py: 1, px: 1.5, color: action.color ? `${action.color}.main` : "text.primary" },
2404
+ children: [
2405
+ action.icon && /* @__PURE__ */ jsx18(ListItemIcon2, { sx: { color: action.color ? `${action.color}.main` : "text.secondary", minWidth: 32 }, children: action.icon }),
2406
+ /* @__PURE__ */ jsx18(ListItemText3, { primary: action.label, slotProps: { primary: { sx: { fontSize: "0.875rem" } } } })
2407
+ ]
2408
+ }
2409
+ )
2410
+ ] }, action.id)),
2411
+ refreshAction && /* @__PURE__ */ jsxs13(Fragment10, { children: [
2412
+ /* @__PURE__ */ jsx18(Divider3, { sx: { my: 0.5 } }),
2413
+ /* @__PURE__ */ jsxs13(
2414
+ MenuItem3,
2415
+ {
2416
+ onClick: () => handleMenuAction(refreshAction.onClick),
2417
+ disabled: refreshAction.disabled,
2418
+ sx: {
2419
+ borderRadius: 1.5,
2420
+ fontWeight: 700,
2421
+ backgroundColor: "primary.50",
2422
+ py: 1.2,
2423
+ px: 1.5
2424
+ },
2425
+ children: [
2426
+ /* @__PURE__ */ jsx18(ListItemIcon2, { sx: { color: "inherit", minWidth: 32 }, children: /* @__PURE__ */ jsx18(RefreshIcon, {}) }),
2427
+ /* @__PURE__ */ jsx18(ListItemText3, { primary: /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Refresh" }), slotProps: { primary: { sx: { fontWeight: 700, fontSize: "0.9rem" } } } })
2428
+ ]
2429
+ }
2430
+ )
2431
+ ] })
2432
+ ]
2433
+ }
2434
+ )
2435
+ ] })
2436
+ ) : (
2437
+ /* DESKTOP: Primary Action Button + Secondary Actions Dropdown Button */
2438
+ /* @__PURE__ */ jsxs13(Box10, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
2439
+ (primaryAction || refreshAction) && /* @__PURE__ */ jsxs13(Stack, { direction: "row", spacing: 2, children: [
2440
+ primaryAction && /* @__PURE__ */ jsx18(
2441
+ Button6,
2442
+ {
2443
+ variant: primaryAction.variant || "contained",
2444
+ color: primaryAction.color || "primary",
2445
+ onClick: primaryAction.onClick,
2446
+ disabled: primaryAction.disabled,
2447
+ startIcon: primaryAction.icon,
2448
+ sx: { borderRadius: 2, textTransform: "none", fontWeight: 600, px: 2, py: 0.85 },
2449
+ children: /* @__PURE__ */ jsx18(TranslateText, { children: primaryAction.label })
2450
+ }
2451
+ ),
2452
+ refreshAction && /* @__PURE__ */ jsx18(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Refresh" }), children: /* @__PURE__ */ jsx18(
2453
+ Fab2,
2454
+ {
2455
+ color: "default",
2456
+ onClick: refreshAction.onClick,
2457
+ disabled: refreshAction.disabled,
2458
+ "aria-label": "refresh",
2459
+ size: "small",
2460
+ children: /* @__PURE__ */ jsx18(RefreshIcon, {})
2461
+ }
2462
+ ) })
2463
+ ] }),
2464
+ hasSecondaryActions && /* @__PURE__ */ jsxs13(Fragment10, { children: [
2465
+ /* @__PURE__ */ jsx18(
2466
+ IconButton8,
2467
+ {
2468
+ onClick: handleOpenMenu,
2469
+ sx: { border: "1px solid", borderColor: "divider", borderRadius: 2, p: 1 },
2470
+ children: /* @__PURE__ */ jsx18(KeyboardArrowDownIcon, {})
2471
+ }
2472
+ ),
2473
+ /* @__PURE__ */ jsx18(
2474
+ Menu2,
2475
+ {
2476
+ anchorEl,
2477
+ open: isMenuOpen,
2478
+ onClose: handleCloseMenu,
2479
+ transformOrigin: { horizontal: "right", vertical: "top" },
2480
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
2481
+ slotProps: { paper: { elevation: 4, sx: { minWidth: 180, borderRadius: 2, mt: 1, p: 0.5 } } },
2482
+ children: secondaryActions.map((action) => /* @__PURE__ */ jsxs13(React12.Fragment, { children: [
2483
+ action.divider && /* @__PURE__ */ jsx18(Divider3, { sx: { my: 0.5 } }),
2484
+ /* @__PURE__ */ jsxs13(
2485
+ MenuItem3,
2486
+ {
2487
+ onClick: () => handleMenuAction(action.onClick),
2488
+ disabled: action.disabled,
2489
+ sx: { borderRadius: 1, py: 0.85, color: action.color ? `${action.color}.main` : "text.primary" },
2490
+ children: [
2491
+ action.icon && /* @__PURE__ */ jsx18(ListItemIcon2, { sx: { color: action.color ? `${action.color}.main` : "text.secondary", minWidth: 32 }, children: action.icon }),
2492
+ /* @__PURE__ */ jsx18(ListItemText3, { primary: action.label, slotProps: { primary: { sx: { fontSize: "0.875rem" } } } })
2493
+ ]
2494
+ }
2495
+ )
2496
+ ] }, action.id))
2497
+ }
2498
+ )
2499
+ ] })
2500
+ ] })
2501
+ ) }),
2502
+ customFragment && /* @__PURE__ */ jsx18(Fragment10, { children: customFragment })
2503
+ ]
2504
+ }
2505
+ );
2506
+ };
2507
+ var PageContainer = ({ children }) => {
2508
+ return /* @__PURE__ */ jsx18(
2509
+ Box10,
2510
+ {
2511
+ sx: {
2512
+ width: "100%",
2513
+ boxSizing: "border-box",
2514
+ p: { xs: 1.5, sm: 3 },
2515
+ backgroundColor: "background.paper"
2516
+ },
2517
+ children
2518
+ }
2519
+ );
2520
+ };
2521
+ var PageComponent = ({
2522
+ header,
2523
+ children
2524
+ }) => {
2525
+ return /* @__PURE__ */ jsx18(
2526
+ Box10,
2527
+ {
2528
+ sx: {
2529
+ //pt: 2,
2530
+ flexGrow: 1,
2531
+ minHeight: 0,
2532
+ overflowY: "auto",
2533
+ boxSizing: "border-box"
2534
+ },
2535
+ children: /* @__PURE__ */ jsxs13(PageContainer, { children: [
2536
+ header && /* @__PURE__ */ jsx18(PageHeader, { ...header }),
2537
+ children
2538
+ ] })
2539
+ }
2540
+ );
2541
+ };
2542
+
2218
2543
  // src/UI/index.ts
2219
2544
  var UI = {
2220
2545
  Inputs: {
@@ -2241,9 +2566,9 @@ var UI = {
2241
2566
  MyAvatar: MyAvatarComponent,
2242
2567
  ExpandableNote: ExpandableNoteComponent
2243
2568
  },
2244
- /*Layout: {
2245
- Row: FormRow,
2246
- },*/
2569
+ Layout: {
2570
+ Page: PageComponent
2571
+ },
2247
2572
  Widgets: {
2248
2573
  Locales: {
2249
2574
  ProtectedLanguageSelector: LanguageSelector,
@@ -2274,13 +2599,13 @@ var Services = {
2274
2599
  };
2275
2600
 
2276
2601
  // src/hooks/useUserStatus.ts
2277
- import { useEffect as useEffect6, useRef, useState as useState13 } from "react";
2602
+ import { useEffect as useEffect6, useRef, useState as useState14 } from "react";
2278
2603
  var ONLINE_THRESHOLD_MINUTES = 2;
2279
2604
  var AWAY_THRESHOLD_MINUTES = 15;
2280
2605
  var useUserStatus = (userId, initialLastSeenAt, currentAuthUserId) => {
2281
2606
  const supabase = useSupabase();
2282
- const [status, setStatus] = useState13("offline");
2283
- const [lastSeen, setLastSeen] = useState13(initialLastSeenAt ?? null);
2607
+ const [status, setStatus] = useState14("offline");
2608
+ const [lastSeen, setLastSeen] = useState14(initialLastSeenAt ?? null);
2284
2609
  const lastSeenRef = useRef(initialLastSeenAt ?? null);
2285
2610
  lastSeenRef.current = lastSeen;
2286
2611
  const calculateStatus = (isOnline, lastSeenIso) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serhii.olishevskyi/docs",
3
- "version": "1.2.21",
3
+ "version": "1.2.22",
4
4
  "description": "DOCS.UA react packages",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",