expose sidebars sizing, v0.1.4
Some checks failed
continuous-integration/drone/push Build encountered an error
Some checks failed
continuous-integration/drone/push Build encountered an error
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@panic/web-core",
|
"name": "@panic/web-core",
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"description": "Core auth and utilities for panic.haus web applications",
|
"description": "Core auth and utilities for panic.haus web applications",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -18,6 +18,13 @@ const SIDEBAR_MIN_WIDTH = 220;
|
|||||||
const SIDEBAR_MAX_WIDTH = 420;
|
const SIDEBAR_MAX_WIDTH = 420;
|
||||||
const SIDEBAR_COLLAPSED_WIDTH = 56;
|
const SIDEBAR_COLLAPSED_WIDTH = 56;
|
||||||
|
|
||||||
|
export type LeftMenuSizing = {
|
||||||
|
defaultWidth?: number;
|
||||||
|
minWidth?: number;
|
||||||
|
maxWidth?: number;
|
||||||
|
collapsedWidth?: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type LeftMenuRenderState = {
|
export type LeftMenuRenderState = {
|
||||||
collapsed: boolean;
|
collapsed: boolean;
|
||||||
mobileOpen: boolean;
|
mobileOpen: boolean;
|
||||||
@@ -53,10 +60,40 @@ type LeftMenuProviderProps = {
|
|||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
defaultContent: LeftMenuContent;
|
defaultContent: LeftMenuContent;
|
||||||
closeOnPathname?: string;
|
closeOnPathname?: string;
|
||||||
|
sizing?: LeftMenuSizing;
|
||||||
};
|
};
|
||||||
|
|
||||||
const LeftMenuContext = createContext<LeftMenuContextValue | undefined>(undefined);
|
const LeftMenuContext = createContext<LeftMenuContextValue | undefined>(undefined);
|
||||||
|
|
||||||
|
function readSizingValue(value: number | undefined, fallback: number): number {
|
||||||
|
if (!Number.isFinite(value) || value == null || value <= 0) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveLeftMenuSizing(sizing: LeftMenuSizing | undefined) {
|
||||||
|
const requestedMinWidth = readSizingValue(sizing?.minWidth, SIDEBAR_MIN_WIDTH);
|
||||||
|
const requestedMaxWidth = readSizingValue(sizing?.maxWidth, SIDEBAR_MAX_WIDTH);
|
||||||
|
const minWidth = Math.min(requestedMinWidth, requestedMaxWidth);
|
||||||
|
const maxWidth = Math.max(requestedMinWidth, requestedMaxWidth);
|
||||||
|
const requestedDefaultWidth = readSizingValue(sizing?.defaultWidth, SIDEBAR_DEFAULT_WIDTH);
|
||||||
|
const defaultWidth = Math.min(maxWidth, Math.max(minWidth, requestedDefaultWidth));
|
||||||
|
const requestedCollapsedWidth = readSizingValue(
|
||||||
|
sizing?.collapsedWidth,
|
||||||
|
SIDEBAR_COLLAPSED_WIDTH,
|
||||||
|
);
|
||||||
|
const collapsedWidth = Math.min(minWidth, requestedCollapsedWidth);
|
||||||
|
|
||||||
|
return {
|
||||||
|
defaultWidth,
|
||||||
|
minWidth,
|
||||||
|
maxWidth,
|
||||||
|
collapsedWidth,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function readStoredCollapsed(): boolean {
|
function readStoredCollapsed(): boolean {
|
||||||
if (!globalThis.window) {
|
if (!globalThis.window) {
|
||||||
return false;
|
return false;
|
||||||
@@ -69,7 +106,9 @@ export function LeftMenuProvider({
|
|||||||
children,
|
children,
|
||||||
defaultContent,
|
defaultContent,
|
||||||
closeOnPathname,
|
closeOnPathname,
|
||||||
|
sizing,
|
||||||
}: Readonly<LeftMenuProviderProps>) {
|
}: Readonly<LeftMenuProviderProps>) {
|
||||||
|
const { defaultWidth, minWidth, maxWidth, collapsedWidth } = resolveLeftMenuSizing(sizing);
|
||||||
const [collapsed, setCollapsed] = useState<boolean>(() => readStoredCollapsed());
|
const [collapsed, setCollapsed] = useState<boolean>(() => readStoredCollapsed());
|
||||||
const [mobileOpen, setMobileOpen] = useState(false);
|
const [mobileOpen, setMobileOpen] = useState(false);
|
||||||
const [content, setContent] = useState<LeftMenuContent>(defaultContent);
|
const [content, setContent] = useState<LeftMenuContent>(defaultContent);
|
||||||
@@ -162,9 +201,9 @@ export function LeftMenuProvider({
|
|||||||
|
|
||||||
const { width, startResize } = useSidePanelMachine({
|
const { width, startResize } = useSidePanelMachine({
|
||||||
storageKey: SIDEBAR_WIDTH_KEY,
|
storageKey: SIDEBAR_WIDTH_KEY,
|
||||||
defaultWidth: SIDEBAR_DEFAULT_WIDTH,
|
defaultWidth,
|
||||||
minWidth: SIDEBAR_MIN_WIDTH,
|
minWidth,
|
||||||
maxWidth: SIDEBAR_MAX_WIDTH,
|
maxWidth,
|
||||||
resizeAxis: 'from-left',
|
resizeAxis: 'from-left',
|
||||||
resizingBodyClass: 'auth-sidebar-resizing',
|
resizingBodyClass: 'auth-sidebar-resizing',
|
||||||
isOpen: mobileOpen,
|
isOpen: mobileOpen,
|
||||||
@@ -177,9 +216,9 @@ export function LeftMenuProvider({
|
|||||||
|
|
||||||
const desktopMenuStyle = useMemo<LeftMenuStyle>(
|
const desktopMenuStyle = useMemo<LeftMenuStyle>(
|
||||||
() => ({
|
() => ({
|
||||||
'--auth-sidebar-width': `${collapsed ? SIDEBAR_COLLAPSED_WIDTH : width}px`,
|
'--auth-sidebar-width': `${collapsed ? collapsedWidth : width}px`,
|
||||||
}),
|
}),
|
||||||
[collapsed, width],
|
[collapsed, collapsedWidth, width],
|
||||||
);
|
);
|
||||||
|
|
||||||
const value = useMemo<LeftMenuContextValue>(
|
const value = useMemo<LeftMenuContextValue>(
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ const RIGHT_SIDEBAR_DEFAULT_WIDTH = 320;
|
|||||||
const RIGHT_SIDEBAR_MIN_WIDTH = 260;
|
const RIGHT_SIDEBAR_MIN_WIDTH = 260;
|
||||||
const RIGHT_SIDEBAR_MAX_WIDTH = 480;
|
const RIGHT_SIDEBAR_MAX_WIDTH = 480;
|
||||||
|
|
||||||
|
export type RightSidebarSizing = {
|
||||||
|
defaultWidth?: number;
|
||||||
|
minWidth?: number;
|
||||||
|
maxWidth?: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type RightSidebarContent = {
|
export type RightSidebarContent = {
|
||||||
title: string;
|
title: string;
|
||||||
content: ReactNode;
|
content: ReactNode;
|
||||||
@@ -39,15 +45,44 @@ type RightSidebarProviderProps = {
|
|||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
closeOnPathname?: string;
|
closeOnPathname?: string;
|
||||||
onMobileOpenRequest?: () => void;
|
onMobileOpenRequest?: () => void;
|
||||||
|
sizing?: RightSidebarSizing;
|
||||||
};
|
};
|
||||||
|
|
||||||
const RightSidebarContext = createContext<RightSidebarContextValue | undefined>(undefined);
|
const RightSidebarContext = createContext<RightSidebarContextValue | undefined>(undefined);
|
||||||
|
|
||||||
|
function readSizingValue(value: number | undefined, fallback: number): number {
|
||||||
|
if (!Number.isFinite(value) || value == null || value <= 0) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveRightSidebarSizing(sizing: RightSidebarSizing | undefined) {
|
||||||
|
const requestedMinWidth = readSizingValue(sizing?.minWidth, RIGHT_SIDEBAR_MIN_WIDTH);
|
||||||
|
const requestedMaxWidth = readSizingValue(sizing?.maxWidth, RIGHT_SIDEBAR_MAX_WIDTH);
|
||||||
|
const minWidth = Math.min(requestedMinWidth, requestedMaxWidth);
|
||||||
|
const maxWidth = Math.max(requestedMinWidth, requestedMaxWidth);
|
||||||
|
const requestedDefaultWidth = readSizingValue(
|
||||||
|
sizing?.defaultWidth,
|
||||||
|
RIGHT_SIDEBAR_DEFAULT_WIDTH,
|
||||||
|
);
|
||||||
|
const defaultWidth = Math.min(maxWidth, Math.max(minWidth, requestedDefaultWidth));
|
||||||
|
|
||||||
|
return {
|
||||||
|
defaultWidth,
|
||||||
|
minWidth,
|
||||||
|
maxWidth,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function RightSidebarProvider({
|
export function RightSidebarProvider({
|
||||||
children,
|
children,
|
||||||
closeOnPathname,
|
closeOnPathname,
|
||||||
onMobileOpenRequest,
|
onMobileOpenRequest,
|
||||||
|
sizing,
|
||||||
}: Readonly<RightSidebarProviderProps>) {
|
}: Readonly<RightSidebarProviderProps>) {
|
||||||
|
const { defaultWidth, minWidth, maxWidth } = resolveRightSidebarSizing(sizing);
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [content, setContent] = useState<RightSidebarContent | null>(null);
|
const [content, setContent] = useState<RightSidebarContent | null>(null);
|
||||||
|
|
||||||
@@ -92,9 +127,9 @@ export function RightSidebarProvider({
|
|||||||
|
|
||||||
const { width, startResize } = useSidePanelMachine({
|
const { width, startResize } = useSidePanelMachine({
|
||||||
storageKey: RIGHT_SIDEBAR_WIDTH_KEY,
|
storageKey: RIGHT_SIDEBAR_WIDTH_KEY,
|
||||||
defaultWidth: RIGHT_SIDEBAR_DEFAULT_WIDTH,
|
defaultWidth,
|
||||||
minWidth: RIGHT_SIDEBAR_MIN_WIDTH,
|
minWidth,
|
||||||
maxWidth: RIGHT_SIDEBAR_MAX_WIDTH,
|
maxWidth,
|
||||||
resizeAxis: 'from-right',
|
resizeAxis: 'from-right',
|
||||||
resizingBodyClass: 'auth-right-sidebar-resizing',
|
resizingBodyClass: 'auth-right-sidebar-resizing',
|
||||||
isOpen,
|
isOpen,
|
||||||
|
|||||||
@@ -35,10 +35,15 @@ export { LeftMenuProvider, useLeftMenu } from './contexts/LeftMenuContext';
|
|||||||
export type {
|
export type {
|
||||||
LeftMenuContent,
|
LeftMenuContent,
|
||||||
LeftMenuRenderState,
|
LeftMenuRenderState,
|
||||||
|
LeftMenuSizing,
|
||||||
LeftMenuStyle,
|
LeftMenuStyle,
|
||||||
} from './contexts/LeftMenuContext';
|
} from './contexts/LeftMenuContext';
|
||||||
export { RightSidebarProvider, useRightSidebar } from './contexts/RightSidebarContext';
|
export { RightSidebarProvider, useRightSidebar } from './contexts/RightSidebarContext';
|
||||||
export type { RightSidebarContent, RightSidebarStyle } from './contexts/RightSidebarContext';
|
export type {
|
||||||
|
RightSidebarContent,
|
||||||
|
RightSidebarSizing,
|
||||||
|
RightSidebarStyle,
|
||||||
|
} from './contexts/RightSidebarContext';
|
||||||
|
|
||||||
export { formatDate, capitalize, splitAndCapitalize } from './utils/formatting';
|
export { formatDate, capitalize, splitAndCapitalize } from './utils/formatting';
|
||||||
export type { SplitMode } from './utils/formatting';
|
export type { SplitMode } from './utils/formatting';
|
||||||
|
|||||||
Reference in New Issue
Block a user