bento-grid-builder 0.2.0 → 0.2.1
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.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -446,11 +446,12 @@ function useGridStyles() {
|
|
|
446
446
|
grid-template-rows: var(--bento-row-heights, repeat(var(--bento-rows, 2), minmax(0, 1fr)));
|
|
447
447
|
column-gap: var(--bento-column-gap, var(--bento-gap, 16px));
|
|
448
448
|
row-gap: var(--bento-row-gap, var(--bento-gap, 16px));
|
|
449
|
-
height: var(--bento-height, auto);
|
|
450
449
|
}
|
|
451
450
|
.bento-cell {
|
|
452
451
|
grid-column: var(--bento-col, 1) / span var(--bento-col-span, 1);
|
|
453
452
|
grid-row: var(--bento-row, 1) / span var(--bento-row-span, 1);
|
|
453
|
+
min-height: 0;
|
|
454
|
+
overflow: hidden;
|
|
454
455
|
}
|
|
455
456
|
`;
|
|
456
457
|
document.head.appendChild(style);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/BentoGrid.tsx","../src/presets.ts","../src/BentoCard.tsx","../src/utils.ts","../src/hooks.ts"],"sourcesContent":["// Core components\nexport { BentoGrid, UnifiedBentoGrid } from \"./BentoGrid.js\";\nexport { BentoCard } from \"./BentoCard.js\";\n\n// Hooks\nexport {\n useCardDefinitions,\n useDataMapping,\n useLayout,\n useResponsiveLayout,\n useWindowWidth,\n isResponsiveConfig,\n} from \"./hooks.js\";\n\n// Utilities\nexport { createSimpleLayout, layoutBuilder, validateLayout } from \"./utils.js\";\n\n// Presets\nexport {\n PRESET_LAYOUTS,\n presetToLayout,\n isPresetName,\n getPresetSlotNames,\n} from \"./presets.js\";\n\n// Types\nexport type {\n BentoGridProps,\n UnifiedBentoGridProps,\n BentoCardProps,\n BentoCardDefinition,\n UnifiedCardDefinition,\n BentoLayoutConfig,\n ResponsiveLayoutConfig,\n BreakpointConfig,\n CardPlacement,\n CardDataMapping,\n CardWrapperProps,\n PresetLayoutName,\n PresetLayout,\n PresetSlotMapping,\n} from \"./types.js\";\n","import React, { useMemo, useEffect } from \"react\";\nimport type {\n BentoGridProps,\n BentoLayoutConfig,\n BentoCardDefinition,\n CardDataMapping,\n CardWrapperProps,\n UnifiedBentoGridProps,\n UnifiedCardDefinition,\n} from \"./types.js\";\nimport { isPresetName, presetToLayout } from \"./presets.js\";\nimport { BentoCard } from \"./BentoCard.js\";\nimport { validateLayout } from \"./utils.js\";\nimport { useResponsiveLayout } from \"./hooks.js\";\n\n/**\n * Default card wrapper - just uses BentoCard\n */\nconst DefaultCardWrapper: React.FC<CardWrapperProps> = ({\n children,\n className,\n style,\n}) => (\n <BentoCard className={className} style={style}>\n {children}\n </BentoCard>\n);\n\n/**\n * Default loading component - simple pulse animation\n */\nconst DefaultLoadingComponent: React.FC = () => (\n <div\n className=\"bento-card-loading\"\n style={{\n width: \"100%\",\n height: \"100%\",\n minHeight: 100,\n backgroundColor: \"var(--bento-loading-bg, rgba(128, 128, 128, 0.1))\",\n borderRadius: \"var(--bento-card-radius, 12px)\",\n animation: \"bento-pulse 1.5s ease-in-out infinite\",\n }}\n aria-label=\"Loading\"\n role=\"status\"\n />\n);\n\n/**\n * Inject base grid styles into the document\n * Uses CSS custom properties so Tailwind classes can override\n */\nfunction useGridStyles() {\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n\n const styleId = \"bento-grid-styles\";\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement(\"style\");\n style.id = styleId;\n style.textContent = `\n .bento-grid {\n display: grid;\n grid-template-columns: repeat(var(--bento-columns, 3), 1fr);\n grid-template-rows: var(--bento-row-heights, repeat(var(--bento-rows, 2), minmax(0, 1fr)));\n column-gap: var(--bento-column-gap, var(--bento-gap, 16px));\n row-gap: var(--bento-row-gap, var(--bento-gap, 16px));\n height: var(--bento-height, auto);\n }\n .bento-cell {\n grid-column: var(--bento-col, 1) / span var(--bento-col-span, 1);\n grid-row: var(--bento-row, 1) / span var(--bento-row-span, 1);\n }\n `;\n document.head.appendChild(style);\n }, []);\n}\n\n/**\n * Inject animation keyframes into the document\n */\nfunction useAnimationStyles() {\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n\n const styleId = \"bento-grid-animations\";\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement(\"style\");\n style.id = styleId;\n style.textContent = `\n @keyframes bento-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n @keyframes bento-fade-in {\n from { opacity: 0; transform: scale(0.95); }\n to { opacity: 1; transform: scale(1); }\n }\n .bento-cell-animated {\n animation: bento-fade-in var(--bento-animation-duration, 300ms) ease-out;\n }\n `;\n document.head.appendChild(style);\n }, []);\n}\n\n/**\n * Error boundary for individual cards\n * Resets when cardId or children change\n */\nclass CardErrorBoundary extends React.Component<\n {\n cardId: string;\n onError?: (cardId: string, error: Error) => void;\n children: React.ReactNode;\n resetKey?: string | number;\n },\n { hasError: boolean; errorKey: string }\n> {\n constructor(props: {\n cardId: string;\n onError?: (cardId: string, error: Error) => void;\n children: React.ReactNode;\n resetKey?: string | number;\n }) {\n super(props);\n this.state = {\n hasError: false,\n errorKey: `${props.cardId}-${props.resetKey ?? \"\"}`,\n };\n }\n\n static getDerivedStateFromError() {\n return { hasError: true };\n }\n\n static getDerivedStateFromProps(\n props: { cardId: string; resetKey?: string | number },\n state: { errorKey: string },\n ) {\n const newKey = `${props.cardId}-${props.resetKey ?? \"\"}`;\n // Reset error state when key changes\n if (newKey !== state.errorKey) {\n return { hasError: false, errorKey: newKey };\n }\n return null;\n }\n\n componentDidCatch(error: Error) {\n this.props.onError?.(this.props.cardId, error);\n }\n\n render() {\n if (this.state.hasError) {\n return (\n <div\n className=\"bento-card-error\"\n role=\"alert\"\n style={{ color: \"#ef4444\", padding: 16 }}\n >\n Failed to render card\n </div>\n );\n }\n return this.props.children;\n }\n}\n\n/**\n * BentoGrid - A flexible, configurable bento grid layout system\n *\n * @example\n * ```tsx\n * <BentoGrid\n * layout=\"3x3\"\n * cards={[\n * { id: 'stats', component: StatsCard },\n * { id: 'chart', component: ChartCard },\n * ]}\n * data={myData}\n * dataMapping={[\n * { cardId: 'stats', propsSelector: (d) => ({ count: d.total }) },\n * { cardId: 'chart', propsSelector: (d) => ({ points: d.chartData }) },\n * ]}\n * />\n * ```\n */\nexport function BentoGrid<TData>({\n layout,\n cards,\n data,\n dataMapping,\n className = \"\",\n style,\n cardWrapper,\n onCardError,\n ariaLabel,\n ariaLabelledBy,\n animated = false,\n animationDuration = 300,\n cellClassName,\n}: BentoGridProps<TData>): React.ReactElement {\n // Inject styles\n useGridStyles();\n useAnimationStyles();\n\n // Handle responsive layouts\n const responsiveLayout = useResponsiveLayout(layout);\n\n // Choose card wrapper\n const CardWrapper = cardWrapper ?? DefaultCardWrapper;\n\n // Resolve layout config from preset or use directly\n const resolvedLayout = useMemo((): BentoLayoutConfig => {\n if (isPresetName(responsiveLayout)) {\n const cardIds = dataMapping.map((m) => m.cardId);\n return presetToLayout(responsiveLayout, cardIds);\n }\n return responsiveLayout as BentoLayoutConfig;\n }, [responsiveLayout, dataMapping]);\n\n // Create lookup maps for cards and data mappings\n const cardMap = useMemo(() => {\n const map = new Map<string, BentoCardDefinition>();\n cards.forEach((card) => map.set(card.id, card));\n return map;\n }, [cards]);\n\n const dataMappingMap = useMemo(() => {\n const map = new Map<string, CardDataMapping<TData>>();\n dataMapping.forEach((mapping) => map.set(mapping.cardId, mapping));\n return map;\n }, [dataMapping]);\n\n // Validate layout in development\n useMemo(() => {\n if (process.env.NODE_ENV !== \"production\") {\n const errors = validateLayout(resolvedLayout);\n if (errors.length > 0) {\n console.warn(\"BentoGrid layout validation errors:\", errors);\n }\n\n // Check for missing card definitions\n for (const placement of resolvedLayout.placements) {\n if (!cards.some((c) => c.id === placement.cardId)) {\n console.warn(\n `BentoGrid: Card \"${placement.cardId}\" in layout but not in cards array`,\n );\n }\n }\n\n // Check for missing data mappings\n for (const placement of resolvedLayout.placements) {\n if (!dataMapping.some((m) => m.cardId === placement.cardId)) {\n console.warn(\n `BentoGrid: Card \"${placement.cardId}\" has no data mapping`,\n );\n }\n }\n }\n }, [resolvedLayout, cards, dataMapping]);\n\n // Calculate grid dimensions\n const {\n columns,\n rows,\n gap = 16,\n columnGap,\n rowGap,\n rowHeights,\n placements,\n } = resolvedLayout;\n const calculatedRows =\n rows ?? Math.max(...placements.map((p) => p.row + (p.rowSpan ?? 1) - 1), 1);\n\n // Compute row template: use custom rowHeights if provided, otherwise equal 1fr rows\n const rowTemplate = rowHeights\n ? rowHeights.join(\" \")\n : `repeat(${calculatedRows}, minmax(0, 1fr))`;\n\n // Grid uses CSS custom properties - Tailwind classes can override the CSS rules\n const gridStyle: React.CSSProperties = {\n \"--bento-columns\": columns,\n \"--bento-rows\": calculatedRows,\n \"--bento-row-heights\": rowTemplate,\n \"--bento-gap\": `${gap}px`,\n \"--bento-column-gap\": `${columnGap ?? gap}px`,\n \"--bento-row-gap\": `${rowGap ?? gap}px`,\n ...(animated && { \"--bento-animation-duration\": `${animationDuration}ms` }),\n ...style,\n } as React.CSSProperties;\n\n // Helper to get cell class name\n const getCellClassName = (cardId: string) => {\n const baseClass = `bento-cell ${animated ? \"bento-cell-animated\" : \"\"}`;\n if (!cellClassName) return baseClass;\n if (typeof cellClassName === \"function\")\n return `${baseClass} ${cellClassName(cardId)}`;\n return `${baseClass} ${cellClassName}`;\n };\n\n return (\n <div\n className={`bento-grid ${className}`}\n style={gridStyle}\n role=\"region\"\n aria-label={ariaLabel ?? (ariaLabelledBy ? undefined : \"Dashboard grid\")}\n aria-labelledby={ariaLabelledBy}\n >\n {placements.map((placement) => {\n const card = cardMap.get(placement.cardId);\n const mapping = dataMappingMap.get(placement.cardId);\n\n if (!card) {\n console.warn(`BentoGrid: Card \"${placement.cardId}\" not found`);\n return null;\n }\n\n // Get props from data mapping or empty object\n const cardProps = mapping ? mapping.propsSelector(data) : {};\n\n // Create a reset key for error boundary - changes when data changes\n const resetKey = JSON.stringify(cardProps);\n\n // Calculate span (placement overrides card defaults)\n const colSpan = placement.colSpan ?? card.colSpan ?? 1;\n const rowSpan = placement.rowSpan ?? card.rowSpan ?? 1;\n\n // Cell uses CSS custom properties for positioning\n const cellStyle: React.CSSProperties = {\n \"--bento-col\": placement.col,\n \"--bento-row\": placement.row,\n \"--bento-col-span\": colSpan,\n \"--bento-row-span\": rowSpan,\n } as React.CSSProperties;\n\n const CardComponent = card.component;\n\n return (\n <div\n key={`${placement.cardId}-${placement.col}-${placement.row}`}\n className={getCellClassName(placement.cardId)}\n style={cellStyle}\n data-card-id={placement.cardId}\n >\n <CardErrorBoundary\n cardId={placement.cardId}\n onError={onCardError}\n resetKey={resetKey}\n >\n <CardWrapper cardId={placement.cardId}>\n <CardComponent {...cardProps} />\n </CardWrapper>\n </CardErrorBoundary>\n </div>\n );\n })}\n </div>\n );\n}\n\n/**\n * Check if a card should be visible based on its visibility config\n */\nfunction isCardVisible<TData>(\n card: UnifiedCardDefinition<TData>,\n data: TData,\n): boolean {\n if (card.visible === undefined) return true;\n if (typeof card.visible === \"function\") return card.visible(data);\n return card.visible;\n}\n\n/**\n * Check if a card is in loading state\n */\nfunction isCardLoading<TData>(\n card: UnifiedCardDefinition<TData>,\n data: TData,\n): boolean {\n if (card.loading === undefined) return false;\n if (typeof card.loading === \"function\") return card.loading(data);\n return card.loading;\n}\n\n/**\n * UnifiedBentoGrid - Cleaner API that combines cards and data mapping\n *\n * This is the preferred way to use BentoGrid. Instead of separate `cards` and\n * `dataMapping` arrays, you define everything in one place.\n *\n * @example\n * ```tsx\n * <UnifiedBentoGrid\n * layout=\"3x2\"\n * cards={[\n * {\n * id: 'stats',\n * component: StatsCard,\n * propsSelector: (d) => ({ count: d.total, label: 'Users' }),\n * colSpan: 2,\n * },\n * {\n * id: 'chart',\n * component: ChartCard,\n * propsSelector: (d) => ({ data: d.chartData }),\n * visible: (d) => d.chartData.length > 0,\n * loading: (d) => d.isLoading,\n * },\n * ]}\n * data={myData}\n * animated\n * />\n * ```\n */\nexport function UnifiedBentoGrid<TData>({\n layout,\n cards,\n data,\n className = \"\",\n style,\n cardWrapper,\n onCardError,\n ariaLabel,\n ariaLabelledBy,\n animated = false,\n animationDuration = 300,\n loadingComponent: GlobalLoadingComponent = DefaultLoadingComponent,\n cellClassName,\n}: UnifiedBentoGridProps<TData>): React.ReactElement {\n // Inject styles\n useGridStyles();\n useAnimationStyles();\n\n // Handle responsive layouts\n const responsiveLayout = useResponsiveLayout(layout);\n\n // Choose card wrapper\n const CardWrapper = cardWrapper ?? DefaultCardWrapper;\n\n // Filter visible cards\n const visibleCards = useMemo(() => {\n return cards.filter((card) => isCardVisible(card, data));\n }, [cards, data]);\n\n // Resolve layout config from preset or use directly\n const resolvedLayout = useMemo((): BentoLayoutConfig => {\n if (isPresetName(responsiveLayout)) {\n const cardIds = visibleCards.map((c) => c.id);\n return presetToLayout(responsiveLayout, cardIds);\n }\n return responsiveLayout as BentoLayoutConfig;\n }, [responsiveLayout, visibleCards]);\n\n // Create lookup map for cards\n const cardMap = useMemo(() => {\n const map = new Map<string, UnifiedCardDefinition<TData>>();\n visibleCards.forEach((card) => map.set(card.id, card));\n return map;\n }, [visibleCards]);\n\n // Validate layout in development\n useMemo(() => {\n if (process.env.NODE_ENV !== \"production\") {\n const errors = validateLayout(resolvedLayout);\n if (errors.length > 0) {\n console.warn(\"UnifiedBentoGrid layout validation errors:\", errors);\n }\n\n // Check for missing card definitions\n for (const placement of resolvedLayout.placements) {\n if (!visibleCards.some((c) => c.id === placement.cardId)) {\n console.warn(\n `UnifiedBentoGrid: Card \"${placement.cardId}\" in layout but not in cards array`,\n );\n }\n }\n }\n }, [resolvedLayout, visibleCards]);\n\n // Calculate grid dimensions\n const {\n columns,\n rows,\n gap = 16,\n columnGap,\n rowGap,\n rowHeights,\n placements,\n } = resolvedLayout;\n const calculatedRows =\n rows ?? Math.max(...placements.map((p) => p.row + (p.rowSpan ?? 1) - 1), 1);\n\n // Compute row template: use custom rowHeights if provided, otherwise equal 1fr rows\n const rowTemplate = rowHeights\n ? rowHeights.join(\" \")\n : `repeat(${calculatedRows}, minmax(0, 1fr))`;\n\n // Grid uses CSS custom properties - Tailwind classes can override the CSS rules\n const gridStyle: React.CSSProperties = {\n \"--bento-columns\": columns,\n \"--bento-rows\": calculatedRows,\n \"--bento-row-heights\": rowTemplate,\n \"--bento-gap\": `${gap}px`,\n \"--bento-column-gap\": `${columnGap ?? gap}px`,\n \"--bento-row-gap\": `${rowGap ?? gap}px`,\n ...(animated && { \"--bento-animation-duration\": `${animationDuration}ms` }),\n ...style,\n } as React.CSSProperties;\n\n // Helper to get cell class name\n const getCellClassName = (cardId: string) => {\n const baseClass = `bento-cell ${animated ? \"bento-cell-animated\" : \"\"}`;\n if (!cellClassName) return baseClass;\n if (typeof cellClassName === \"function\")\n return `${baseClass} ${cellClassName(cardId)}`;\n return `${baseClass} ${cellClassName}`;\n };\n\n return (\n <div\n className={`bento-grid ${className}`}\n style={gridStyle}\n role=\"region\"\n aria-label={ariaLabel ?? (ariaLabelledBy ? undefined : \"Dashboard grid\")}\n aria-labelledby={ariaLabelledBy}\n >\n {placements.map((placement) => {\n const card = cardMap.get(placement.cardId);\n\n if (!card) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `UnifiedBentoGrid: Card \"${placement.cardId}\" not found`,\n );\n }\n return null;\n }\n\n // Check loading state\n const loading = isCardLoading(card, data);\n\n // Get props from card's propsSelector\n const cardProps = card.propsSelector(data);\n\n // Create a reset key for error boundary\n const resetKey = JSON.stringify(cardProps);\n\n // Calculate span (placement overrides card defaults)\n const colSpan = placement.colSpan ?? card.colSpan ?? 1;\n const rowSpan = placement.rowSpan ?? card.rowSpan ?? 1;\n\n // Cell uses CSS custom properties for positioning\n const cellStyle: React.CSSProperties = {\n \"--bento-col\": placement.col,\n \"--bento-row\": placement.row,\n \"--bento-col-span\": colSpan,\n \"--bento-row-span\": rowSpan,\n } as React.CSSProperties;\n\n const CardComponent = card.component;\n const LoadingComponent =\n card.loadingComponent ?? GlobalLoadingComponent;\n\n return (\n <div\n key={`${placement.cardId}-${placement.col}-${placement.row}`}\n className={getCellClassName(placement.cardId)}\n style={cellStyle}\n data-card-id={placement.cardId}\n >\n <CardErrorBoundary\n cardId={placement.cardId}\n onError={onCardError}\n resetKey={resetKey}\n >\n <CardWrapper cardId={placement.cardId}>\n {loading ? (\n <LoadingComponent />\n ) : (\n <CardComponent {...cardProps} />\n )}\n </CardWrapper>\n </CardErrorBoundary>\n </div>\n );\n })}\n </div>\n );\n}\n","import type {\n PresetLayout,\n PresetLayoutName,\n BentoLayoutConfig,\n PresetSlotMapping,\n} from \"./types.js\";\n\n/**\n * Preset layout definitions\n * Users can use these by name instead of defining custom layouts\n */\nexport const PRESET_LAYOUTS: Record<PresetLayoutName, PresetLayout> = {\n \"2x2\": {\n name: \"2x2\",\n columns: 2,\n rows: 2,\n slots: [\n { name: \"top-left\", col: 1, row: 1 },\n { name: \"top-right\", col: 2, row: 1 },\n { name: \"bottom-left\", col: 1, row: 2 },\n { name: \"bottom-right\", col: 2, row: 2 },\n ],\n },\n \"3x2\": {\n name: \"3x2\",\n columns: 3,\n rows: 2,\n slots: [\n { name: \"top-1\", col: 1, row: 1 },\n { name: \"top-2\", col: 2, row: 1 },\n { name: \"top-3\", col: 3, row: 1 },\n { name: \"bottom-1\", col: 1, row: 2 },\n { name: \"bottom-2\", col: 2, row: 2 },\n { name: \"bottom-3\", col: 3, row: 2 },\n ],\n },\n \"3x3\": {\n name: \"3x3\",\n columns: 3,\n rows: 3,\n slots: [\n { name: \"r1-c1\", col: 1, row: 1 },\n { name: \"r1-c2\", col: 2, row: 1 },\n { name: \"r1-c3\", col: 3, row: 1 },\n { name: \"r2-c1\", col: 1, row: 2 },\n { name: \"r2-c2\", col: 2, row: 2 },\n { name: \"r2-c3\", col: 3, row: 2 },\n { name: \"r3-c1\", col: 1, row: 3 },\n { name: \"r3-c2\", col: 2, row: 3 },\n { name: \"r3-c3\", col: 3, row: 3 },\n ],\n },\n \"4x2\": {\n name: \"4x2\",\n columns: 4,\n rows: 2,\n slots: [\n { name: \"top-1\", col: 1, row: 1 },\n { name: \"top-2\", col: 2, row: 1 },\n { name: \"top-3\", col: 3, row: 1 },\n { name: \"top-4\", col: 4, row: 1 },\n { name: \"bottom-1\", col: 1, row: 2 },\n { name: \"bottom-2\", col: 2, row: 2 },\n { name: \"bottom-3\", col: 3, row: 2 },\n { name: \"bottom-4\", col: 4, row: 2 },\n ],\n },\n \"2x1-hero-left\": {\n name: \"2x1-hero-left\",\n columns: 3,\n rows: 2,\n slots: [\n { name: \"hero\", col: 1, row: 1, colSpan: 2, rowSpan: 2 },\n { name: \"side-top\", col: 3, row: 1 },\n { name: \"side-bottom\", col: 3, row: 2 },\n ],\n },\n \"2x1-hero-right\": {\n name: \"2x1-hero-right\",\n columns: 3,\n rows: 2,\n slots: [\n { name: \"side-top\", col: 1, row: 1 },\n { name: \"side-bottom\", col: 1, row: 2 },\n { name: \"hero\", col: 2, row: 1, colSpan: 2, rowSpan: 2 },\n ],\n },\n \"dashboard-9\": {\n name: \"dashboard-9\",\n columns: 3,\n rows: 4,\n slots: [\n { name: \"header-wide\", col: 1, row: 1, colSpan: 2 },\n { name: \"header-right\", col: 3, row: 1 },\n { name: \"hero\", col: 1, row: 2, rowSpan: 2 },\n { name: \"mid-center\", col: 2, row: 2 },\n { name: \"mid-right\", col: 3, row: 2 },\n { name: \"lower-center\", col: 2, row: 3 },\n { name: \"lower-right\", col: 3, row: 3 },\n { name: \"footer-left\", col: 1, row: 4 },\n { name: \"footer-wide\", col: 2, row: 4, colSpan: 2 },\n ],\n },\n};\n\n/**\n * Convert a preset name to a full layout config with card IDs\n * Supports both legacy array-based assignment and explicit slot mapping\n */\nexport function presetToLayout(\n presetName: PresetLayoutName,\n cardIdsOrMapping: string[] | PresetSlotMapping[],\n): BentoLayoutConfig {\n const preset = PRESET_LAYOUTS[presetName];\n if (!preset) {\n throw new Error(`Unknown preset layout: ${presetName}`);\n }\n\n let placements;\n\n // Check if it's explicit slot mapping or legacy array\n if (\n cardIdsOrMapping.length > 0 &&\n typeof cardIdsOrMapping[0] === \"object\" &&\n \"slot\" in cardIdsOrMapping[0]\n ) {\n // Explicit slot mapping\n const slotMapping = cardIdsOrMapping as PresetSlotMapping[];\n placements = slotMapping\n .map((mapping) => {\n const slotIndex =\n typeof mapping.slot === \"number\"\n ? mapping.slot\n : preset.slots.findIndex((s) => s.name === mapping.slot);\n\n if (slotIndex === -1 || slotIndex >= preset.slots.length) {\n console.warn(\n `Preset \"${presetName}\": slot \"${mapping.slot}\" not found`,\n );\n return null;\n }\n\n const slot = preset.slots[slotIndex];\n return {\n cardId: mapping.cardId,\n col: slot.col,\n row: slot.row,\n colSpan: slot.colSpan,\n rowSpan: slot.rowSpan,\n };\n })\n .filter((p): p is NonNullable<typeof p> => p !== null);\n } else {\n // Legacy array-based assignment\n const cardIds = cardIdsOrMapping as string[];\n placements = preset.slots.map((slot, index) => ({\n cardId: cardIds[index] ?? `card-${index}`,\n col: slot.col,\n row: slot.row,\n colSpan: slot.colSpan,\n rowSpan: slot.rowSpan,\n }));\n }\n\n return {\n columns: preset.columns,\n rows: preset.rows,\n placements,\n };\n}\n\n/**\n * Get available slot names for a preset layout\n * Useful for discovering what slots are available\n */\nexport function getPresetSlotNames(presetName: PresetLayoutName): string[] {\n const preset = PRESET_LAYOUTS[presetName];\n if (!preset) {\n throw new Error(`Unknown preset layout: ${presetName}`);\n }\n return preset.slots.map((s, i) => s.name ?? `slot-${i}`);\n}\n\n/**\n * Check if a value is a preset layout name\n */\nexport function isPresetName(value: unknown): value is PresetLayoutName {\n return typeof value === \"string\" && value in PRESET_LAYOUTS;\n}\n","import React from \"react\";\nimport type { BentoCardProps } from \"./types.js\";\n\n/**\n * Default card wrapper component\n * Provides basic styling - users can override with their own wrapper\n * Uses CSS custom properties for easy theming\n */\nexport const BentoCard: React.FC<BentoCardProps> = ({\n children,\n className = \"\",\n style,\n}) => (\n <div\n className={`bento-card ${className}`}\n style={{\n backgroundColor: \"var(--bento-card-bg, transparent)\",\n borderRadius: \"var(--bento-card-radius, 12px)\",\n padding: \"var(--bento-card-padding, 16px)\",\n border: \"var(--bento-card-border, 1px solid rgba(128, 128, 128, 0.2))\",\n height: \"100%\",\n boxSizing: \"border-box\",\n ...style,\n }}\n >\n {children}\n </div>\n);\n","import type { BentoLayoutConfig, CardPlacement } from \"./types.js\";\n\n/**\n * Create a simple grid layout where cards are placed sequentially\n * Useful for quick prototyping\n *\n * @example\n * ```ts\n * const layout = createSimpleLayout(3, [\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"]);\n * // Creates a 3-column grid with cards placed left-to-right, top-to-bottom\n * ```\n */\nexport function createSimpleLayout(\n columns: number,\n cardIds: string[],\n gap?: number,\n): BentoLayoutConfig {\n const placements: CardPlacement[] = cardIds.map((cardId, index) => ({\n cardId,\n col: (index % columns) + 1,\n row: Math.floor(index / columns) + 1,\n }));\n\n return {\n columns,\n gap,\n placements,\n };\n}\n\n/**\n * Layout builder for fluent API\n *\n * @example\n * ```ts\n * const layout = layoutBuilder(3)\n * .gap(16)\n * .columnGap(20)\n * .rowGap(12)\n * .place(\"hero\", 1, 1, { colSpan: 2, rowSpan: 2 })\n * .place(\"stats\", 3, 1)\n * .place(\"chart\", 3, 2)\n * .build();\n * ```\n */\nexport function layoutBuilder(columns: number) {\n const config: BentoLayoutConfig = {\n columns,\n placements: [],\n };\n\n const builder = {\n gap(value: number) {\n config.gap = value;\n return builder;\n },\n columnGap(value: number) {\n config.columnGap = value;\n return builder;\n },\n rowGap(value: number) {\n config.rowGap = value;\n return builder;\n },\n rows(value: number) {\n config.rows = value;\n return builder;\n },\n rowHeights(heights: string[]) {\n config.rowHeights = heights;\n return builder;\n },\n place(\n cardId: string,\n col: number,\n row: number,\n options?: { colSpan?: number; rowSpan?: number },\n ) {\n config.placements.push({\n cardId,\n col,\n row,\n ...options,\n });\n return builder;\n },\n build(): BentoLayoutConfig {\n return config;\n },\n };\n\n return builder;\n}\n\n/**\n * Validate a layout configuration\n * Returns array of validation errors (empty if valid)\n */\nexport function validateLayout(layout: BentoLayoutConfig): string[] {\n const errors: string[] = [];\n\n if (layout.columns < 1) {\n errors.push(\"columns must be at least 1\");\n }\n\n if (layout.rows !== undefined && layout.rows < 1) {\n errors.push(\"rows must be at least 1\");\n }\n\n if (layout.gap !== undefined && layout.gap < 0) {\n errors.push(\"gap cannot be negative\");\n }\n\n const occupied = new Set<string>();\n\n for (const placement of layout.placements) {\n const colSpan = placement.colSpan ?? 1;\n const rowSpan = placement.rowSpan ?? 1;\n\n // Check bounds\n if (placement.col < 1 || placement.col + colSpan - 1 > layout.columns) {\n errors.push(\n `Card \"${placement.cardId}\" exceeds column bounds (col: ${placement.col}, span: ${colSpan})`,\n );\n }\n\n if (placement.row < 1) {\n errors.push(\n `Card \"${placement.cardId}\" has invalid row: ${placement.row}`,\n );\n }\n\n // Check overlaps\n for (let c = placement.col; c < placement.col + colSpan; c++) {\n for (let r = placement.row; r < placement.row + rowSpan; r++) {\n const key = `${c},${r}`;\n if (occupied.has(key)) {\n errors.push(\n `Card \"${placement.cardId}\" overlaps at position (${c}, ${r})`,\n );\n }\n occupied.add(key);\n }\n }\n }\n\n return errors;\n}\n","import { useMemo, useRef, useState, useEffect, useCallback } from \"react\";\nimport type {\n BentoCardDefinition,\n CardDataMapping,\n BentoLayoutConfig,\n PresetLayoutName,\n ResponsiveLayoutConfig,\n BreakpointConfig,\n} from \"./types.js\";\nimport { isPresetName, presetToLayout } from \"./presets.js\";\n\n/**\n * Deep comparison for stable memoization of object inputs\n */\nfunction useStableValue<T>(value: T): T {\n const ref = useRef<T>(value);\n const prevJson = useRef<string>(\"\");\n\n // Compare by serializing - works for our use case of simple config objects\n // For components, we compare by reference using a custom replacer\n const json = JSON.stringify(value, (key, val) => {\n if (typeof val === \"function\") {\n return val.toString();\n }\n return val;\n });\n\n if (json !== prevJson.current) {\n ref.current = value;\n prevJson.current = json;\n }\n\n return ref.current;\n}\n\n/**\n * Check if a layout config is a responsive config\n */\nexport function isResponsiveConfig(\n layout: BentoLayoutConfig | PresetLayoutName | ResponsiveLayoutConfig,\n): layout is ResponsiveLayoutConfig {\n return (\n typeof layout === \"object\" && \"default\" in layout && \"breakpoints\" in layout\n );\n}\n\n/**\n * Hook to handle responsive layouts based on viewport width\n * Returns the appropriate layout for the current viewport\n *\n * @example\n * ```tsx\n * const layout = useResponsiveLayout({\n * default: \"2x2\",\n * breakpoints: [\n * { minWidth: 768, layout: \"3x2\" },\n * { minWidth: 1024, layout: \"4x2\" },\n * ],\n * });\n * ```\n */\nexport function useResponsiveLayout(\n config: BentoLayoutConfig | PresetLayoutName | ResponsiveLayoutConfig,\n): BentoLayoutConfig | PresetLayoutName {\n const [width, setWidth] = useState(() =>\n typeof window !== \"undefined\" ? window.innerWidth : 0,\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const handleResize = () => setWidth(window.innerWidth);\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n return useMemo(() => {\n if (!isResponsiveConfig(config)) {\n return config;\n }\n\n // Sort breakpoints by minWidth descending to find the largest matching one\n const sortedBreakpoints = [...config.breakpoints].sort(\n (a, b) => b.minWidth - a.minWidth,\n );\n\n for (const bp of sortedBreakpoints) {\n if (width >= bp.minWidth) {\n return bp.layout;\n }\n }\n\n return config.default;\n }, [config, width]);\n}\n\n/**\n * Hook to track window width with debouncing\n */\nexport function useWindowWidth(debounceMs = 100): number {\n const [width, setWidth] = useState(() =>\n typeof window !== \"undefined\" ? window.innerWidth : 0,\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n let timeoutId: ReturnType<typeof setTimeout>;\n const handleResize = () => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => setWidth(window.innerWidth), debounceMs);\n };\n\n window.addEventListener(\"resize\", handleResize);\n return () => {\n clearTimeout(timeoutId);\n window.removeEventListener(\"resize\", handleResize);\n };\n }, [debounceMs]);\n\n return width;\n}\n\n/**\n * Hook to create card definitions from an object map\n * Provides a cleaner API for defining cards\n *\n * @example\n * ```tsx\n * const cards = useCardDefinitions({\n * stats: { component: StatsCard, colSpan: 2 },\n * chart: { component: ChartCard },\n * list: { component: ListCard, rowSpan: 2 },\n * });\n * ```\n */\nexport function useCardDefinitions<\n T extends Record<string, Omit<BentoCardDefinition<any>, \"id\">>,\n>(definitions: T): BentoCardDefinition<any>[] {\n const stableDefinitions = useStableValue(definitions);\n\n return useMemo(() => {\n return Object.entries(stableDefinitions).map(([id, def]) => ({\n id,\n ...def,\n }));\n }, [stableDefinitions]);\n}\n\n/**\n * Hook to create data mappings from an object map\n * Provides a cleaner API for mapping data to cards\n *\n * @example\n * ```tsx\n * const dataMapping = useDataMapping<MyDataType>({\n * stats: (data) => ({ count: data.total, label: 'Items' }),\n * chart: (data) => ({ points: data.chartData }),\n * });\n * ```\n */\nexport function useDataMapping<TData>(\n mappings: Record<string, (data: TData) => Record<string, unknown>>,\n): CardDataMapping<TData>[] {\n const stableMappings = useStableValue(mappings);\n\n return useMemo(() => {\n return Object.entries(stableMappings).map(([cardId, propsSelector]) => ({\n cardId,\n propsSelector,\n }));\n }, [stableMappings]);\n}\n\n/**\n * Hook to create a layout configuration\n * Handles both preset names and custom configs\n *\n * @example\n * ```tsx\n * // Using preset\n * const layout = useLayout(\"3x3\", [\"stats\", \"chart\", \"list\", ...]);\n *\n * // Using custom config\n * const layout = useLayout({\n * columns: 3,\n * placements: [\n * { cardId: \"stats\", col: 1, row: 1, colSpan: 2 },\n * { cardId: \"chart\", col: 3, row: 1 },\n * ]\n * });\n * ```\n */\nexport function useLayout(\n config: PresetLayoutName | BentoLayoutConfig,\n cardIds?: string[],\n): BentoLayoutConfig {\n return useMemo(() => {\n if (isPresetName(config)) {\n if (!cardIds) {\n throw new Error(\"cardIds required when using preset layout name\");\n }\n return presetToLayout(config, cardIds);\n }\n return config;\n }, [config, cardIds]);\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime","React"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/BentoGrid.tsx","../src/presets.ts","../src/BentoCard.tsx","../src/utils.ts","../src/hooks.ts"],"sourcesContent":["// Core components\nexport { BentoGrid, UnifiedBentoGrid } from \"./BentoGrid.js\";\nexport { BentoCard } from \"./BentoCard.js\";\n\n// Hooks\nexport {\n useCardDefinitions,\n useDataMapping,\n useLayout,\n useResponsiveLayout,\n useWindowWidth,\n isResponsiveConfig,\n} from \"./hooks.js\";\n\n// Utilities\nexport { createSimpleLayout, layoutBuilder, validateLayout } from \"./utils.js\";\n\n// Presets\nexport {\n PRESET_LAYOUTS,\n presetToLayout,\n isPresetName,\n getPresetSlotNames,\n} from \"./presets.js\";\n\n// Types\nexport type {\n BentoGridProps,\n UnifiedBentoGridProps,\n BentoCardProps,\n BentoCardDefinition,\n UnifiedCardDefinition,\n BentoLayoutConfig,\n ResponsiveLayoutConfig,\n BreakpointConfig,\n CardPlacement,\n CardDataMapping,\n CardWrapperProps,\n PresetLayoutName,\n PresetLayout,\n PresetSlotMapping,\n} from \"./types.js\";\n","import React, { useMemo, useEffect } from \"react\";\nimport type {\n BentoGridProps,\n BentoLayoutConfig,\n BentoCardDefinition,\n CardDataMapping,\n CardWrapperProps,\n UnifiedBentoGridProps,\n UnifiedCardDefinition,\n} from \"./types.js\";\nimport { isPresetName, presetToLayout } from \"./presets.js\";\nimport { BentoCard } from \"./BentoCard.js\";\nimport { validateLayout } from \"./utils.js\";\nimport { useResponsiveLayout } from \"./hooks.js\";\n\n/**\n * Default card wrapper - just uses BentoCard\n */\nconst DefaultCardWrapper: React.FC<CardWrapperProps> = ({\n children,\n className,\n style,\n}) => (\n <BentoCard className={className} style={style}>\n {children}\n </BentoCard>\n);\n\n/**\n * Default loading component - simple pulse animation\n */\nconst DefaultLoadingComponent: React.FC = () => (\n <div\n className=\"bento-card-loading\"\n style={{\n width: \"100%\",\n height: \"100%\",\n minHeight: 100,\n backgroundColor: \"var(--bento-loading-bg, rgba(128, 128, 128, 0.1))\",\n borderRadius: \"var(--bento-card-radius, 12px)\",\n animation: \"bento-pulse 1.5s ease-in-out infinite\",\n }}\n aria-label=\"Loading\"\n role=\"status\"\n />\n);\n\n/**\n * Inject base grid styles into the document\n * Uses CSS custom properties so Tailwind classes can override\n */\nfunction useGridStyles() {\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n\n const styleId = \"bento-grid-styles\";\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement(\"style\");\n style.id = styleId;\n style.textContent = `\n .bento-grid {\n display: grid;\n grid-template-columns: repeat(var(--bento-columns, 3), 1fr);\n grid-template-rows: var(--bento-row-heights, repeat(var(--bento-rows, 2), minmax(0, 1fr)));\n column-gap: var(--bento-column-gap, var(--bento-gap, 16px));\n row-gap: var(--bento-row-gap, var(--bento-gap, 16px));\n }\n .bento-cell {\n grid-column: var(--bento-col, 1) / span var(--bento-col-span, 1);\n grid-row: var(--bento-row, 1) / span var(--bento-row-span, 1);\n min-height: 0;\n overflow: hidden;\n }\n `;\n document.head.appendChild(style);\n }, []);\n}\n\n/**\n * Inject animation keyframes into the document\n */\nfunction useAnimationStyles() {\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n\n const styleId = \"bento-grid-animations\";\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement(\"style\");\n style.id = styleId;\n style.textContent = `\n @keyframes bento-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n @keyframes bento-fade-in {\n from { opacity: 0; transform: scale(0.95); }\n to { opacity: 1; transform: scale(1); }\n }\n .bento-cell-animated {\n animation: bento-fade-in var(--bento-animation-duration, 300ms) ease-out;\n }\n `;\n document.head.appendChild(style);\n }, []);\n}\n\n/**\n * Error boundary for individual cards\n * Resets when cardId or children change\n */\nclass CardErrorBoundary extends React.Component<\n {\n cardId: string;\n onError?: (cardId: string, error: Error) => void;\n children: React.ReactNode;\n resetKey?: string | number;\n },\n { hasError: boolean; errorKey: string }\n> {\n constructor(props: {\n cardId: string;\n onError?: (cardId: string, error: Error) => void;\n children: React.ReactNode;\n resetKey?: string | number;\n }) {\n super(props);\n this.state = {\n hasError: false,\n errorKey: `${props.cardId}-${props.resetKey ?? \"\"}`,\n };\n }\n\n static getDerivedStateFromError() {\n return { hasError: true };\n }\n\n static getDerivedStateFromProps(\n props: { cardId: string; resetKey?: string | number },\n state: { errorKey: string },\n ) {\n const newKey = `${props.cardId}-${props.resetKey ?? \"\"}`;\n // Reset error state when key changes\n if (newKey !== state.errorKey) {\n return { hasError: false, errorKey: newKey };\n }\n return null;\n }\n\n componentDidCatch(error: Error) {\n this.props.onError?.(this.props.cardId, error);\n }\n\n render() {\n if (this.state.hasError) {\n return (\n <div\n className=\"bento-card-error\"\n role=\"alert\"\n style={{ color: \"#ef4444\", padding: 16 }}\n >\n Failed to render card\n </div>\n );\n }\n return this.props.children;\n }\n}\n\n/**\n * BentoGrid - A flexible, configurable bento grid layout system\n *\n * @example\n * ```tsx\n * <BentoGrid\n * layout=\"3x3\"\n * cards={[\n * { id: 'stats', component: StatsCard },\n * { id: 'chart', component: ChartCard },\n * ]}\n * data={myData}\n * dataMapping={[\n * { cardId: 'stats', propsSelector: (d) => ({ count: d.total }) },\n * { cardId: 'chart', propsSelector: (d) => ({ points: d.chartData }) },\n * ]}\n * />\n * ```\n */\nexport function BentoGrid<TData>({\n layout,\n cards,\n data,\n dataMapping,\n className = \"\",\n style,\n cardWrapper,\n onCardError,\n ariaLabel,\n ariaLabelledBy,\n animated = false,\n animationDuration = 300,\n cellClassName,\n}: BentoGridProps<TData>): React.ReactElement {\n // Inject styles\n useGridStyles();\n useAnimationStyles();\n\n // Handle responsive layouts\n const responsiveLayout = useResponsiveLayout(layout);\n\n // Choose card wrapper\n const CardWrapper = cardWrapper ?? DefaultCardWrapper;\n\n // Resolve layout config from preset or use directly\n const resolvedLayout = useMemo((): BentoLayoutConfig => {\n if (isPresetName(responsiveLayout)) {\n const cardIds = dataMapping.map((m) => m.cardId);\n return presetToLayout(responsiveLayout, cardIds);\n }\n return responsiveLayout as BentoLayoutConfig;\n }, [responsiveLayout, dataMapping]);\n\n // Create lookup maps for cards and data mappings\n const cardMap = useMemo(() => {\n const map = new Map<string, BentoCardDefinition>();\n cards.forEach((card) => map.set(card.id, card));\n return map;\n }, [cards]);\n\n const dataMappingMap = useMemo(() => {\n const map = new Map<string, CardDataMapping<TData>>();\n dataMapping.forEach((mapping) => map.set(mapping.cardId, mapping));\n return map;\n }, [dataMapping]);\n\n // Validate layout in development\n useMemo(() => {\n if (process.env.NODE_ENV !== \"production\") {\n const errors = validateLayout(resolvedLayout);\n if (errors.length > 0) {\n console.warn(\"BentoGrid layout validation errors:\", errors);\n }\n\n // Check for missing card definitions\n for (const placement of resolvedLayout.placements) {\n if (!cards.some((c) => c.id === placement.cardId)) {\n console.warn(\n `BentoGrid: Card \"${placement.cardId}\" in layout but not in cards array`,\n );\n }\n }\n\n // Check for missing data mappings\n for (const placement of resolvedLayout.placements) {\n if (!dataMapping.some((m) => m.cardId === placement.cardId)) {\n console.warn(\n `BentoGrid: Card \"${placement.cardId}\" has no data mapping`,\n );\n }\n }\n }\n }, [resolvedLayout, cards, dataMapping]);\n\n // Calculate grid dimensions\n const {\n columns,\n rows,\n gap = 16,\n columnGap,\n rowGap,\n rowHeights,\n placements,\n } = resolvedLayout;\n const calculatedRows =\n rows ?? Math.max(...placements.map((p) => p.row + (p.rowSpan ?? 1) - 1), 1);\n\n // Compute row template: use custom rowHeights if provided, otherwise equal 1fr rows\n const rowTemplate = rowHeights\n ? rowHeights.join(\" \")\n : `repeat(${calculatedRows}, minmax(0, 1fr))`;\n\n // Grid uses CSS custom properties - Tailwind classes can override the CSS rules\n const gridStyle: React.CSSProperties = {\n \"--bento-columns\": columns,\n \"--bento-rows\": calculatedRows,\n \"--bento-row-heights\": rowTemplate,\n \"--bento-gap\": `${gap}px`,\n \"--bento-column-gap\": `${columnGap ?? gap}px`,\n \"--bento-row-gap\": `${rowGap ?? gap}px`,\n ...(animated && { \"--bento-animation-duration\": `${animationDuration}ms` }),\n ...style,\n } as React.CSSProperties;\n\n // Helper to get cell class name\n const getCellClassName = (cardId: string) => {\n const baseClass = `bento-cell ${animated ? \"bento-cell-animated\" : \"\"}`;\n if (!cellClassName) return baseClass;\n if (typeof cellClassName === \"function\")\n return `${baseClass} ${cellClassName(cardId)}`;\n return `${baseClass} ${cellClassName}`;\n };\n\n return (\n <div\n className={`bento-grid ${className}`}\n style={gridStyle}\n role=\"region\"\n aria-label={ariaLabel ?? (ariaLabelledBy ? undefined : \"Dashboard grid\")}\n aria-labelledby={ariaLabelledBy}\n >\n {placements.map((placement) => {\n const card = cardMap.get(placement.cardId);\n const mapping = dataMappingMap.get(placement.cardId);\n\n if (!card) {\n console.warn(`BentoGrid: Card \"${placement.cardId}\" not found`);\n return null;\n }\n\n // Get props from data mapping or empty object\n const cardProps = mapping ? mapping.propsSelector(data) : {};\n\n // Create a reset key for error boundary - changes when data changes\n const resetKey = JSON.stringify(cardProps);\n\n // Calculate span (placement overrides card defaults)\n const colSpan = placement.colSpan ?? card.colSpan ?? 1;\n const rowSpan = placement.rowSpan ?? card.rowSpan ?? 1;\n\n // Cell uses CSS custom properties for positioning\n const cellStyle: React.CSSProperties = {\n \"--bento-col\": placement.col,\n \"--bento-row\": placement.row,\n \"--bento-col-span\": colSpan,\n \"--bento-row-span\": rowSpan,\n } as React.CSSProperties;\n\n const CardComponent = card.component;\n\n return (\n <div\n key={`${placement.cardId}-${placement.col}-${placement.row}`}\n className={getCellClassName(placement.cardId)}\n style={cellStyle}\n data-card-id={placement.cardId}\n >\n <CardErrorBoundary\n cardId={placement.cardId}\n onError={onCardError}\n resetKey={resetKey}\n >\n <CardWrapper cardId={placement.cardId}>\n <CardComponent {...cardProps} />\n </CardWrapper>\n </CardErrorBoundary>\n </div>\n );\n })}\n </div>\n );\n}\n\n/**\n * Check if a card should be visible based on its visibility config\n */\nfunction isCardVisible<TData>(\n card: UnifiedCardDefinition<TData>,\n data: TData,\n): boolean {\n if (card.visible === undefined) return true;\n if (typeof card.visible === \"function\") return card.visible(data);\n return card.visible;\n}\n\n/**\n * Check if a card is in loading state\n */\nfunction isCardLoading<TData>(\n card: UnifiedCardDefinition<TData>,\n data: TData,\n): boolean {\n if (card.loading === undefined) return false;\n if (typeof card.loading === \"function\") return card.loading(data);\n return card.loading;\n}\n\n/**\n * UnifiedBentoGrid - Cleaner API that combines cards and data mapping\n *\n * This is the preferred way to use BentoGrid. Instead of separate `cards` and\n * `dataMapping` arrays, you define everything in one place.\n *\n * @example\n * ```tsx\n * <UnifiedBentoGrid\n * layout=\"3x2\"\n * cards={[\n * {\n * id: 'stats',\n * component: StatsCard,\n * propsSelector: (d) => ({ count: d.total, label: 'Users' }),\n * colSpan: 2,\n * },\n * {\n * id: 'chart',\n * component: ChartCard,\n * propsSelector: (d) => ({ data: d.chartData }),\n * visible: (d) => d.chartData.length > 0,\n * loading: (d) => d.isLoading,\n * },\n * ]}\n * data={myData}\n * animated\n * />\n * ```\n */\nexport function UnifiedBentoGrid<TData>({\n layout,\n cards,\n data,\n className = \"\",\n style,\n cardWrapper,\n onCardError,\n ariaLabel,\n ariaLabelledBy,\n animated = false,\n animationDuration = 300,\n loadingComponent: GlobalLoadingComponent = DefaultLoadingComponent,\n cellClassName,\n}: UnifiedBentoGridProps<TData>): React.ReactElement {\n // Inject styles\n useGridStyles();\n useAnimationStyles();\n\n // Handle responsive layouts\n const responsiveLayout = useResponsiveLayout(layout);\n\n // Choose card wrapper\n const CardWrapper = cardWrapper ?? DefaultCardWrapper;\n\n // Filter visible cards\n const visibleCards = useMemo(() => {\n return cards.filter((card) => isCardVisible(card, data));\n }, [cards, data]);\n\n // Resolve layout config from preset or use directly\n const resolvedLayout = useMemo((): BentoLayoutConfig => {\n if (isPresetName(responsiveLayout)) {\n const cardIds = visibleCards.map((c) => c.id);\n return presetToLayout(responsiveLayout, cardIds);\n }\n return responsiveLayout as BentoLayoutConfig;\n }, [responsiveLayout, visibleCards]);\n\n // Create lookup map for cards\n const cardMap = useMemo(() => {\n const map = new Map<string, UnifiedCardDefinition<TData>>();\n visibleCards.forEach((card) => map.set(card.id, card));\n return map;\n }, [visibleCards]);\n\n // Validate layout in development\n useMemo(() => {\n if (process.env.NODE_ENV !== \"production\") {\n const errors = validateLayout(resolvedLayout);\n if (errors.length > 0) {\n console.warn(\"UnifiedBentoGrid layout validation errors:\", errors);\n }\n\n // Check for missing card definitions\n for (const placement of resolvedLayout.placements) {\n if (!visibleCards.some((c) => c.id === placement.cardId)) {\n console.warn(\n `UnifiedBentoGrid: Card \"${placement.cardId}\" in layout but not in cards array`,\n );\n }\n }\n }\n }, [resolvedLayout, visibleCards]);\n\n // Calculate grid dimensions\n const {\n columns,\n rows,\n gap = 16,\n columnGap,\n rowGap,\n rowHeights,\n placements,\n } = resolvedLayout;\n const calculatedRows =\n rows ?? Math.max(...placements.map((p) => p.row + (p.rowSpan ?? 1) - 1), 1);\n\n // Compute row template: use custom rowHeights if provided, otherwise equal 1fr rows\n const rowTemplate = rowHeights\n ? rowHeights.join(\" \")\n : `repeat(${calculatedRows}, minmax(0, 1fr))`;\n\n // Grid uses CSS custom properties - Tailwind classes can override the CSS rules\n const gridStyle: React.CSSProperties = {\n \"--bento-columns\": columns,\n \"--bento-rows\": calculatedRows,\n \"--bento-row-heights\": rowTemplate,\n \"--bento-gap\": `${gap}px`,\n \"--bento-column-gap\": `${columnGap ?? gap}px`,\n \"--bento-row-gap\": `${rowGap ?? gap}px`,\n ...(animated && { \"--bento-animation-duration\": `${animationDuration}ms` }),\n ...style,\n } as React.CSSProperties;\n\n // Helper to get cell class name\n const getCellClassName = (cardId: string) => {\n const baseClass = `bento-cell ${animated ? \"bento-cell-animated\" : \"\"}`;\n if (!cellClassName) return baseClass;\n if (typeof cellClassName === \"function\")\n return `${baseClass} ${cellClassName(cardId)}`;\n return `${baseClass} ${cellClassName}`;\n };\n\n return (\n <div\n className={`bento-grid ${className}`}\n style={gridStyle}\n role=\"region\"\n aria-label={ariaLabel ?? (ariaLabelledBy ? undefined : \"Dashboard grid\")}\n aria-labelledby={ariaLabelledBy}\n >\n {placements.map((placement) => {\n const card = cardMap.get(placement.cardId);\n\n if (!card) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `UnifiedBentoGrid: Card \"${placement.cardId}\" not found`,\n );\n }\n return null;\n }\n\n // Check loading state\n const loading = isCardLoading(card, data);\n\n // Get props from card's propsSelector\n const cardProps = card.propsSelector(data);\n\n // Create a reset key for error boundary\n const resetKey = JSON.stringify(cardProps);\n\n // Calculate span (placement overrides card defaults)\n const colSpan = placement.colSpan ?? card.colSpan ?? 1;\n const rowSpan = placement.rowSpan ?? card.rowSpan ?? 1;\n\n // Cell uses CSS custom properties for positioning\n const cellStyle: React.CSSProperties = {\n \"--bento-col\": placement.col,\n \"--bento-row\": placement.row,\n \"--bento-col-span\": colSpan,\n \"--bento-row-span\": rowSpan,\n } as React.CSSProperties;\n\n const CardComponent = card.component;\n const LoadingComponent =\n card.loadingComponent ?? GlobalLoadingComponent;\n\n return (\n <div\n key={`${placement.cardId}-${placement.col}-${placement.row}`}\n className={getCellClassName(placement.cardId)}\n style={cellStyle}\n data-card-id={placement.cardId}\n >\n <CardErrorBoundary\n cardId={placement.cardId}\n onError={onCardError}\n resetKey={resetKey}\n >\n <CardWrapper cardId={placement.cardId}>\n {loading ? (\n <LoadingComponent />\n ) : (\n <CardComponent {...cardProps} />\n )}\n </CardWrapper>\n </CardErrorBoundary>\n </div>\n );\n })}\n </div>\n );\n}\n","import type {\n PresetLayout,\n PresetLayoutName,\n BentoLayoutConfig,\n PresetSlotMapping,\n} from \"./types.js\";\n\n/**\n * Preset layout definitions\n * Users can use these by name instead of defining custom layouts\n */\nexport const PRESET_LAYOUTS: Record<PresetLayoutName, PresetLayout> = {\n \"2x2\": {\n name: \"2x2\",\n columns: 2,\n rows: 2,\n slots: [\n { name: \"top-left\", col: 1, row: 1 },\n { name: \"top-right\", col: 2, row: 1 },\n { name: \"bottom-left\", col: 1, row: 2 },\n { name: \"bottom-right\", col: 2, row: 2 },\n ],\n },\n \"3x2\": {\n name: \"3x2\",\n columns: 3,\n rows: 2,\n slots: [\n { name: \"top-1\", col: 1, row: 1 },\n { name: \"top-2\", col: 2, row: 1 },\n { name: \"top-3\", col: 3, row: 1 },\n { name: \"bottom-1\", col: 1, row: 2 },\n { name: \"bottom-2\", col: 2, row: 2 },\n { name: \"bottom-3\", col: 3, row: 2 },\n ],\n },\n \"3x3\": {\n name: \"3x3\",\n columns: 3,\n rows: 3,\n slots: [\n { name: \"r1-c1\", col: 1, row: 1 },\n { name: \"r1-c2\", col: 2, row: 1 },\n { name: \"r1-c3\", col: 3, row: 1 },\n { name: \"r2-c1\", col: 1, row: 2 },\n { name: \"r2-c2\", col: 2, row: 2 },\n { name: \"r2-c3\", col: 3, row: 2 },\n { name: \"r3-c1\", col: 1, row: 3 },\n { name: \"r3-c2\", col: 2, row: 3 },\n { name: \"r3-c3\", col: 3, row: 3 },\n ],\n },\n \"4x2\": {\n name: \"4x2\",\n columns: 4,\n rows: 2,\n slots: [\n { name: \"top-1\", col: 1, row: 1 },\n { name: \"top-2\", col: 2, row: 1 },\n { name: \"top-3\", col: 3, row: 1 },\n { name: \"top-4\", col: 4, row: 1 },\n { name: \"bottom-1\", col: 1, row: 2 },\n { name: \"bottom-2\", col: 2, row: 2 },\n { name: \"bottom-3\", col: 3, row: 2 },\n { name: \"bottom-4\", col: 4, row: 2 },\n ],\n },\n \"2x1-hero-left\": {\n name: \"2x1-hero-left\",\n columns: 3,\n rows: 2,\n slots: [\n { name: \"hero\", col: 1, row: 1, colSpan: 2, rowSpan: 2 },\n { name: \"side-top\", col: 3, row: 1 },\n { name: \"side-bottom\", col: 3, row: 2 },\n ],\n },\n \"2x1-hero-right\": {\n name: \"2x1-hero-right\",\n columns: 3,\n rows: 2,\n slots: [\n { name: \"side-top\", col: 1, row: 1 },\n { name: \"side-bottom\", col: 1, row: 2 },\n { name: \"hero\", col: 2, row: 1, colSpan: 2, rowSpan: 2 },\n ],\n },\n \"dashboard-9\": {\n name: \"dashboard-9\",\n columns: 3,\n rows: 4,\n slots: [\n { name: \"header-wide\", col: 1, row: 1, colSpan: 2 },\n { name: \"header-right\", col: 3, row: 1 },\n { name: \"hero\", col: 1, row: 2, rowSpan: 2 },\n { name: \"mid-center\", col: 2, row: 2 },\n { name: \"mid-right\", col: 3, row: 2 },\n { name: \"lower-center\", col: 2, row: 3 },\n { name: \"lower-right\", col: 3, row: 3 },\n { name: \"footer-left\", col: 1, row: 4 },\n { name: \"footer-wide\", col: 2, row: 4, colSpan: 2 },\n ],\n },\n};\n\n/**\n * Convert a preset name to a full layout config with card IDs\n * Supports both legacy array-based assignment and explicit slot mapping\n */\nexport function presetToLayout(\n presetName: PresetLayoutName,\n cardIdsOrMapping: string[] | PresetSlotMapping[],\n): BentoLayoutConfig {\n const preset = PRESET_LAYOUTS[presetName];\n if (!preset) {\n throw new Error(`Unknown preset layout: ${presetName}`);\n }\n\n let placements;\n\n // Check if it's explicit slot mapping or legacy array\n if (\n cardIdsOrMapping.length > 0 &&\n typeof cardIdsOrMapping[0] === \"object\" &&\n \"slot\" in cardIdsOrMapping[0]\n ) {\n // Explicit slot mapping\n const slotMapping = cardIdsOrMapping as PresetSlotMapping[];\n placements = slotMapping\n .map((mapping) => {\n const slotIndex =\n typeof mapping.slot === \"number\"\n ? mapping.slot\n : preset.slots.findIndex((s) => s.name === mapping.slot);\n\n if (slotIndex === -1 || slotIndex >= preset.slots.length) {\n console.warn(\n `Preset \"${presetName}\": slot \"${mapping.slot}\" not found`,\n );\n return null;\n }\n\n const slot = preset.slots[slotIndex];\n return {\n cardId: mapping.cardId,\n col: slot.col,\n row: slot.row,\n colSpan: slot.colSpan,\n rowSpan: slot.rowSpan,\n };\n })\n .filter((p): p is NonNullable<typeof p> => p !== null);\n } else {\n // Legacy array-based assignment\n const cardIds = cardIdsOrMapping as string[];\n placements = preset.slots.map((slot, index) => ({\n cardId: cardIds[index] ?? `card-${index}`,\n col: slot.col,\n row: slot.row,\n colSpan: slot.colSpan,\n rowSpan: slot.rowSpan,\n }));\n }\n\n return {\n columns: preset.columns,\n rows: preset.rows,\n placements,\n };\n}\n\n/**\n * Get available slot names for a preset layout\n * Useful for discovering what slots are available\n */\nexport function getPresetSlotNames(presetName: PresetLayoutName): string[] {\n const preset = PRESET_LAYOUTS[presetName];\n if (!preset) {\n throw new Error(`Unknown preset layout: ${presetName}`);\n }\n return preset.slots.map((s, i) => s.name ?? `slot-${i}`);\n}\n\n/**\n * Check if a value is a preset layout name\n */\nexport function isPresetName(value: unknown): value is PresetLayoutName {\n return typeof value === \"string\" && value in PRESET_LAYOUTS;\n}\n","import React from \"react\";\nimport type { BentoCardProps } from \"./types.js\";\n\n/**\n * Default card wrapper component\n * Provides basic styling - users can override with their own wrapper\n * Uses CSS custom properties for easy theming\n */\nexport const BentoCard: React.FC<BentoCardProps> = ({\n children,\n className = \"\",\n style,\n}) => (\n <div\n className={`bento-card ${className}`}\n style={{\n backgroundColor: \"var(--bento-card-bg, transparent)\",\n borderRadius: \"var(--bento-card-radius, 12px)\",\n padding: \"var(--bento-card-padding, 16px)\",\n border: \"var(--bento-card-border, 1px solid rgba(128, 128, 128, 0.2))\",\n height: \"100%\",\n boxSizing: \"border-box\",\n ...style,\n }}\n >\n {children}\n </div>\n);\n","import type { BentoLayoutConfig, CardPlacement } from \"./types.js\";\n\n/**\n * Create a simple grid layout where cards are placed sequentially\n * Useful for quick prototyping\n *\n * @example\n * ```ts\n * const layout = createSimpleLayout(3, [\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"]);\n * // Creates a 3-column grid with cards placed left-to-right, top-to-bottom\n * ```\n */\nexport function createSimpleLayout(\n columns: number,\n cardIds: string[],\n gap?: number,\n): BentoLayoutConfig {\n const placements: CardPlacement[] = cardIds.map((cardId, index) => ({\n cardId,\n col: (index % columns) + 1,\n row: Math.floor(index / columns) + 1,\n }));\n\n return {\n columns,\n gap,\n placements,\n };\n}\n\n/**\n * Layout builder for fluent API\n *\n * @example\n * ```ts\n * const layout = layoutBuilder(3)\n * .gap(16)\n * .columnGap(20)\n * .rowGap(12)\n * .place(\"hero\", 1, 1, { colSpan: 2, rowSpan: 2 })\n * .place(\"stats\", 3, 1)\n * .place(\"chart\", 3, 2)\n * .build();\n * ```\n */\nexport function layoutBuilder(columns: number) {\n const config: BentoLayoutConfig = {\n columns,\n placements: [],\n };\n\n const builder = {\n gap(value: number) {\n config.gap = value;\n return builder;\n },\n columnGap(value: number) {\n config.columnGap = value;\n return builder;\n },\n rowGap(value: number) {\n config.rowGap = value;\n return builder;\n },\n rows(value: number) {\n config.rows = value;\n return builder;\n },\n rowHeights(heights: string[]) {\n config.rowHeights = heights;\n return builder;\n },\n place(\n cardId: string,\n col: number,\n row: number,\n options?: { colSpan?: number; rowSpan?: number },\n ) {\n config.placements.push({\n cardId,\n col,\n row,\n ...options,\n });\n return builder;\n },\n build(): BentoLayoutConfig {\n return config;\n },\n };\n\n return builder;\n}\n\n/**\n * Validate a layout configuration\n * Returns array of validation errors (empty if valid)\n */\nexport function validateLayout(layout: BentoLayoutConfig): string[] {\n const errors: string[] = [];\n\n if (layout.columns < 1) {\n errors.push(\"columns must be at least 1\");\n }\n\n if (layout.rows !== undefined && layout.rows < 1) {\n errors.push(\"rows must be at least 1\");\n }\n\n if (layout.gap !== undefined && layout.gap < 0) {\n errors.push(\"gap cannot be negative\");\n }\n\n const occupied = new Set<string>();\n\n for (const placement of layout.placements) {\n const colSpan = placement.colSpan ?? 1;\n const rowSpan = placement.rowSpan ?? 1;\n\n // Check bounds\n if (placement.col < 1 || placement.col + colSpan - 1 > layout.columns) {\n errors.push(\n `Card \"${placement.cardId}\" exceeds column bounds (col: ${placement.col}, span: ${colSpan})`,\n );\n }\n\n if (placement.row < 1) {\n errors.push(\n `Card \"${placement.cardId}\" has invalid row: ${placement.row}`,\n );\n }\n\n // Check overlaps\n for (let c = placement.col; c < placement.col + colSpan; c++) {\n for (let r = placement.row; r < placement.row + rowSpan; r++) {\n const key = `${c},${r}`;\n if (occupied.has(key)) {\n errors.push(\n `Card \"${placement.cardId}\" overlaps at position (${c}, ${r})`,\n );\n }\n occupied.add(key);\n }\n }\n }\n\n return errors;\n}\n","import { useMemo, useRef, useState, useEffect, useCallback } from \"react\";\nimport type {\n BentoCardDefinition,\n CardDataMapping,\n BentoLayoutConfig,\n PresetLayoutName,\n ResponsiveLayoutConfig,\n BreakpointConfig,\n} from \"./types.js\";\nimport { isPresetName, presetToLayout } from \"./presets.js\";\n\n/**\n * Deep comparison for stable memoization of object inputs\n */\nfunction useStableValue<T>(value: T): T {\n const ref = useRef<T>(value);\n const prevJson = useRef<string>(\"\");\n\n // Compare by serializing - works for our use case of simple config objects\n // For components, we compare by reference using a custom replacer\n const json = JSON.stringify(value, (key, val) => {\n if (typeof val === \"function\") {\n return val.toString();\n }\n return val;\n });\n\n if (json !== prevJson.current) {\n ref.current = value;\n prevJson.current = json;\n }\n\n return ref.current;\n}\n\n/**\n * Check if a layout config is a responsive config\n */\nexport function isResponsiveConfig(\n layout: BentoLayoutConfig | PresetLayoutName | ResponsiveLayoutConfig,\n): layout is ResponsiveLayoutConfig {\n return (\n typeof layout === \"object\" && \"default\" in layout && \"breakpoints\" in layout\n );\n}\n\n/**\n * Hook to handle responsive layouts based on viewport width\n * Returns the appropriate layout for the current viewport\n *\n * @example\n * ```tsx\n * const layout = useResponsiveLayout({\n * default: \"2x2\",\n * breakpoints: [\n * { minWidth: 768, layout: \"3x2\" },\n * { minWidth: 1024, layout: \"4x2\" },\n * ],\n * });\n * ```\n */\nexport function useResponsiveLayout(\n config: BentoLayoutConfig | PresetLayoutName | ResponsiveLayoutConfig,\n): BentoLayoutConfig | PresetLayoutName {\n const [width, setWidth] = useState(() =>\n typeof window !== \"undefined\" ? window.innerWidth : 0,\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const handleResize = () => setWidth(window.innerWidth);\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n return useMemo(() => {\n if (!isResponsiveConfig(config)) {\n return config;\n }\n\n // Sort breakpoints by minWidth descending to find the largest matching one\n const sortedBreakpoints = [...config.breakpoints].sort(\n (a, b) => b.minWidth - a.minWidth,\n );\n\n for (const bp of sortedBreakpoints) {\n if (width >= bp.minWidth) {\n return bp.layout;\n }\n }\n\n return config.default;\n }, [config, width]);\n}\n\n/**\n * Hook to track window width with debouncing\n */\nexport function useWindowWidth(debounceMs = 100): number {\n const [width, setWidth] = useState(() =>\n typeof window !== \"undefined\" ? window.innerWidth : 0,\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n let timeoutId: ReturnType<typeof setTimeout>;\n const handleResize = () => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => setWidth(window.innerWidth), debounceMs);\n };\n\n window.addEventListener(\"resize\", handleResize);\n return () => {\n clearTimeout(timeoutId);\n window.removeEventListener(\"resize\", handleResize);\n };\n }, [debounceMs]);\n\n return width;\n}\n\n/**\n * Hook to create card definitions from an object map\n * Provides a cleaner API for defining cards\n *\n * @example\n * ```tsx\n * const cards = useCardDefinitions({\n * stats: { component: StatsCard, colSpan: 2 },\n * chart: { component: ChartCard },\n * list: { component: ListCard, rowSpan: 2 },\n * });\n * ```\n */\nexport function useCardDefinitions<\n T extends Record<string, Omit<BentoCardDefinition<any>, \"id\">>,\n>(definitions: T): BentoCardDefinition<any>[] {\n const stableDefinitions = useStableValue(definitions);\n\n return useMemo(() => {\n return Object.entries(stableDefinitions).map(([id, def]) => ({\n id,\n ...def,\n }));\n }, [stableDefinitions]);\n}\n\n/**\n * Hook to create data mappings from an object map\n * Provides a cleaner API for mapping data to cards\n *\n * @example\n * ```tsx\n * const dataMapping = useDataMapping<MyDataType>({\n * stats: (data) => ({ count: data.total, label: 'Items' }),\n * chart: (data) => ({ points: data.chartData }),\n * });\n * ```\n */\nexport function useDataMapping<TData>(\n mappings: Record<string, (data: TData) => Record<string, unknown>>,\n): CardDataMapping<TData>[] {\n const stableMappings = useStableValue(mappings);\n\n return useMemo(() => {\n return Object.entries(stableMappings).map(([cardId, propsSelector]) => ({\n cardId,\n propsSelector,\n }));\n }, [stableMappings]);\n}\n\n/**\n * Hook to create a layout configuration\n * Handles both preset names and custom configs\n *\n * @example\n * ```tsx\n * // Using preset\n * const layout = useLayout(\"3x3\", [\"stats\", \"chart\", \"list\", ...]);\n *\n * // Using custom config\n * const layout = useLayout({\n * columns: 3,\n * placements: [\n * { cardId: \"stats\", col: 1, row: 1, colSpan: 2 },\n * { cardId: \"chart\", col: 3, row: 1 },\n * ]\n * });\n * ```\n */\nexport function useLayout(\n config: PresetLayoutName | BentoLayoutConfig,\n cardIds?: string[],\n): BentoLayoutConfig {\n return useMemo(() => {\n if (isPresetName(config)) {\n if (!cardIds) {\n throw new Error(\"cardIds required when using preset layout name\");\n }\n return presetToLayout(config, cardIds);\n }\n return config;\n }, [config, cardIds]);\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime","React"]}
|
package/dist/index.mjs
CHANGED
|
@@ -395,11 +395,12 @@ function useGridStyles() {
|
|
|
395
395
|
grid-template-rows: var(--bento-row-heights, repeat(var(--bento-rows, 2), minmax(0, 1fr)));
|
|
396
396
|
column-gap: var(--bento-column-gap, var(--bento-gap, 16px));
|
|
397
397
|
row-gap: var(--bento-row-gap, var(--bento-gap, 16px));
|
|
398
|
-
height: var(--bento-height, auto);
|
|
399
398
|
}
|
|
400
399
|
.bento-cell {
|
|
401
400
|
grid-column: var(--bento-col, 1) / span var(--bento-col-span, 1);
|
|
402
401
|
grid-row: var(--bento-row, 1) / span var(--bento-row-span, 1);
|
|
402
|
+
min-height: 0;
|
|
403
|
+
overflow: hidden;
|
|
403
404
|
}
|
|
404
405
|
`;
|
|
405
406
|
document.head.appendChild(style);
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/BentoGrid.tsx","../src/presets.ts","../src/BentoCard.tsx","../src/utils.ts","../src/hooks.ts"],"sourcesContent":["import React, { useMemo, useEffect } from \"react\";\nimport type {\n BentoGridProps,\n BentoLayoutConfig,\n BentoCardDefinition,\n CardDataMapping,\n CardWrapperProps,\n UnifiedBentoGridProps,\n UnifiedCardDefinition,\n} from \"./types.js\";\nimport { isPresetName, presetToLayout } from \"./presets.js\";\nimport { BentoCard } from \"./BentoCard.js\";\nimport { validateLayout } from \"./utils.js\";\nimport { useResponsiveLayout } from \"./hooks.js\";\n\n/**\n * Default card wrapper - just uses BentoCard\n */\nconst DefaultCardWrapper: React.FC<CardWrapperProps> = ({\n children,\n className,\n style,\n}) => (\n <BentoCard className={className} style={style}>\n {children}\n </BentoCard>\n);\n\n/**\n * Default loading component - simple pulse animation\n */\nconst DefaultLoadingComponent: React.FC = () => (\n <div\n className=\"bento-card-loading\"\n style={{\n width: \"100%\",\n height: \"100%\",\n minHeight: 100,\n backgroundColor: \"var(--bento-loading-bg, rgba(128, 128, 128, 0.1))\",\n borderRadius: \"var(--bento-card-radius, 12px)\",\n animation: \"bento-pulse 1.5s ease-in-out infinite\",\n }}\n aria-label=\"Loading\"\n role=\"status\"\n />\n);\n\n/**\n * Inject base grid styles into the document\n * Uses CSS custom properties so Tailwind classes can override\n */\nfunction useGridStyles() {\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n\n const styleId = \"bento-grid-styles\";\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement(\"style\");\n style.id = styleId;\n style.textContent = `\n .bento-grid {\n display: grid;\n grid-template-columns: repeat(var(--bento-columns, 3), 1fr);\n grid-template-rows: var(--bento-row-heights, repeat(var(--bento-rows, 2), minmax(0, 1fr)));\n column-gap: var(--bento-column-gap, var(--bento-gap, 16px));\n row-gap: var(--bento-row-gap, var(--bento-gap, 16px));\n height: var(--bento-height, auto);\n }\n .bento-cell {\n grid-column: var(--bento-col, 1) / span var(--bento-col-span, 1);\n grid-row: var(--bento-row, 1) / span var(--bento-row-span, 1);\n }\n `;\n document.head.appendChild(style);\n }, []);\n}\n\n/**\n * Inject animation keyframes into the document\n */\nfunction useAnimationStyles() {\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n\n const styleId = \"bento-grid-animations\";\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement(\"style\");\n style.id = styleId;\n style.textContent = `\n @keyframes bento-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n @keyframes bento-fade-in {\n from { opacity: 0; transform: scale(0.95); }\n to { opacity: 1; transform: scale(1); }\n }\n .bento-cell-animated {\n animation: bento-fade-in var(--bento-animation-duration, 300ms) ease-out;\n }\n `;\n document.head.appendChild(style);\n }, []);\n}\n\n/**\n * Error boundary for individual cards\n * Resets when cardId or children change\n */\nclass CardErrorBoundary extends React.Component<\n {\n cardId: string;\n onError?: (cardId: string, error: Error) => void;\n children: React.ReactNode;\n resetKey?: string | number;\n },\n { hasError: boolean; errorKey: string }\n> {\n constructor(props: {\n cardId: string;\n onError?: (cardId: string, error: Error) => void;\n children: React.ReactNode;\n resetKey?: string | number;\n }) {\n super(props);\n this.state = {\n hasError: false,\n errorKey: `${props.cardId}-${props.resetKey ?? \"\"}`,\n };\n }\n\n static getDerivedStateFromError() {\n return { hasError: true };\n }\n\n static getDerivedStateFromProps(\n props: { cardId: string; resetKey?: string | number },\n state: { errorKey: string },\n ) {\n const newKey = `${props.cardId}-${props.resetKey ?? \"\"}`;\n // Reset error state when key changes\n if (newKey !== state.errorKey) {\n return { hasError: false, errorKey: newKey };\n }\n return null;\n }\n\n componentDidCatch(error: Error) {\n this.props.onError?.(this.props.cardId, error);\n }\n\n render() {\n if (this.state.hasError) {\n return (\n <div\n className=\"bento-card-error\"\n role=\"alert\"\n style={{ color: \"#ef4444\", padding: 16 }}\n >\n Failed to render card\n </div>\n );\n }\n return this.props.children;\n }\n}\n\n/**\n * BentoGrid - A flexible, configurable bento grid layout system\n *\n * @example\n * ```tsx\n * <BentoGrid\n * layout=\"3x3\"\n * cards={[\n * { id: 'stats', component: StatsCard },\n * { id: 'chart', component: ChartCard },\n * ]}\n * data={myData}\n * dataMapping={[\n * { cardId: 'stats', propsSelector: (d) => ({ count: d.total }) },\n * { cardId: 'chart', propsSelector: (d) => ({ points: d.chartData }) },\n * ]}\n * />\n * ```\n */\nexport function BentoGrid<TData>({\n layout,\n cards,\n data,\n dataMapping,\n className = \"\",\n style,\n cardWrapper,\n onCardError,\n ariaLabel,\n ariaLabelledBy,\n animated = false,\n animationDuration = 300,\n cellClassName,\n}: BentoGridProps<TData>): React.ReactElement {\n // Inject styles\n useGridStyles();\n useAnimationStyles();\n\n // Handle responsive layouts\n const responsiveLayout = useResponsiveLayout(layout);\n\n // Choose card wrapper\n const CardWrapper = cardWrapper ?? DefaultCardWrapper;\n\n // Resolve layout config from preset or use directly\n const resolvedLayout = useMemo((): BentoLayoutConfig => {\n if (isPresetName(responsiveLayout)) {\n const cardIds = dataMapping.map((m) => m.cardId);\n return presetToLayout(responsiveLayout, cardIds);\n }\n return responsiveLayout as BentoLayoutConfig;\n }, [responsiveLayout, dataMapping]);\n\n // Create lookup maps for cards and data mappings\n const cardMap = useMemo(() => {\n const map = new Map<string, BentoCardDefinition>();\n cards.forEach((card) => map.set(card.id, card));\n return map;\n }, [cards]);\n\n const dataMappingMap = useMemo(() => {\n const map = new Map<string, CardDataMapping<TData>>();\n dataMapping.forEach((mapping) => map.set(mapping.cardId, mapping));\n return map;\n }, [dataMapping]);\n\n // Validate layout in development\n useMemo(() => {\n if (process.env.NODE_ENV !== \"production\") {\n const errors = validateLayout(resolvedLayout);\n if (errors.length > 0) {\n console.warn(\"BentoGrid layout validation errors:\", errors);\n }\n\n // Check for missing card definitions\n for (const placement of resolvedLayout.placements) {\n if (!cards.some((c) => c.id === placement.cardId)) {\n console.warn(\n `BentoGrid: Card \"${placement.cardId}\" in layout but not in cards array`,\n );\n }\n }\n\n // Check for missing data mappings\n for (const placement of resolvedLayout.placements) {\n if (!dataMapping.some((m) => m.cardId === placement.cardId)) {\n console.warn(\n `BentoGrid: Card \"${placement.cardId}\" has no data mapping`,\n );\n }\n }\n }\n }, [resolvedLayout, cards, dataMapping]);\n\n // Calculate grid dimensions\n const {\n columns,\n rows,\n gap = 16,\n columnGap,\n rowGap,\n rowHeights,\n placements,\n } = resolvedLayout;\n const calculatedRows =\n rows ?? Math.max(...placements.map((p) => p.row + (p.rowSpan ?? 1) - 1), 1);\n\n // Compute row template: use custom rowHeights if provided, otherwise equal 1fr rows\n const rowTemplate = rowHeights\n ? rowHeights.join(\" \")\n : `repeat(${calculatedRows}, minmax(0, 1fr))`;\n\n // Grid uses CSS custom properties - Tailwind classes can override the CSS rules\n const gridStyle: React.CSSProperties = {\n \"--bento-columns\": columns,\n \"--bento-rows\": calculatedRows,\n \"--bento-row-heights\": rowTemplate,\n \"--bento-gap\": `${gap}px`,\n \"--bento-column-gap\": `${columnGap ?? gap}px`,\n \"--bento-row-gap\": `${rowGap ?? gap}px`,\n ...(animated && { \"--bento-animation-duration\": `${animationDuration}ms` }),\n ...style,\n } as React.CSSProperties;\n\n // Helper to get cell class name\n const getCellClassName = (cardId: string) => {\n const baseClass = `bento-cell ${animated ? \"bento-cell-animated\" : \"\"}`;\n if (!cellClassName) return baseClass;\n if (typeof cellClassName === \"function\")\n return `${baseClass} ${cellClassName(cardId)}`;\n return `${baseClass} ${cellClassName}`;\n };\n\n return (\n <div\n className={`bento-grid ${className}`}\n style={gridStyle}\n role=\"region\"\n aria-label={ariaLabel ?? (ariaLabelledBy ? undefined : \"Dashboard grid\")}\n aria-labelledby={ariaLabelledBy}\n >\n {placements.map((placement) => {\n const card = cardMap.get(placement.cardId);\n const mapping = dataMappingMap.get(placement.cardId);\n\n if (!card) {\n console.warn(`BentoGrid: Card \"${placement.cardId}\" not found`);\n return null;\n }\n\n // Get props from data mapping or empty object\n const cardProps = mapping ? mapping.propsSelector(data) : {};\n\n // Create a reset key for error boundary - changes when data changes\n const resetKey = JSON.stringify(cardProps);\n\n // Calculate span (placement overrides card defaults)\n const colSpan = placement.colSpan ?? card.colSpan ?? 1;\n const rowSpan = placement.rowSpan ?? card.rowSpan ?? 1;\n\n // Cell uses CSS custom properties for positioning\n const cellStyle: React.CSSProperties = {\n \"--bento-col\": placement.col,\n \"--bento-row\": placement.row,\n \"--bento-col-span\": colSpan,\n \"--bento-row-span\": rowSpan,\n } as React.CSSProperties;\n\n const CardComponent = card.component;\n\n return (\n <div\n key={`${placement.cardId}-${placement.col}-${placement.row}`}\n className={getCellClassName(placement.cardId)}\n style={cellStyle}\n data-card-id={placement.cardId}\n >\n <CardErrorBoundary\n cardId={placement.cardId}\n onError={onCardError}\n resetKey={resetKey}\n >\n <CardWrapper cardId={placement.cardId}>\n <CardComponent {...cardProps} />\n </CardWrapper>\n </CardErrorBoundary>\n </div>\n );\n })}\n </div>\n );\n}\n\n/**\n * Check if a card should be visible based on its visibility config\n */\nfunction isCardVisible<TData>(\n card: UnifiedCardDefinition<TData>,\n data: TData,\n): boolean {\n if (card.visible === undefined) return true;\n if (typeof card.visible === \"function\") return card.visible(data);\n return card.visible;\n}\n\n/**\n * Check if a card is in loading state\n */\nfunction isCardLoading<TData>(\n card: UnifiedCardDefinition<TData>,\n data: TData,\n): boolean {\n if (card.loading === undefined) return false;\n if (typeof card.loading === \"function\") return card.loading(data);\n return card.loading;\n}\n\n/**\n * UnifiedBentoGrid - Cleaner API that combines cards and data mapping\n *\n * This is the preferred way to use BentoGrid. Instead of separate `cards` and\n * `dataMapping` arrays, you define everything in one place.\n *\n * @example\n * ```tsx\n * <UnifiedBentoGrid\n * layout=\"3x2\"\n * cards={[\n * {\n * id: 'stats',\n * component: StatsCard,\n * propsSelector: (d) => ({ count: d.total, label: 'Users' }),\n * colSpan: 2,\n * },\n * {\n * id: 'chart',\n * component: ChartCard,\n * propsSelector: (d) => ({ data: d.chartData }),\n * visible: (d) => d.chartData.length > 0,\n * loading: (d) => d.isLoading,\n * },\n * ]}\n * data={myData}\n * animated\n * />\n * ```\n */\nexport function UnifiedBentoGrid<TData>({\n layout,\n cards,\n data,\n className = \"\",\n style,\n cardWrapper,\n onCardError,\n ariaLabel,\n ariaLabelledBy,\n animated = false,\n animationDuration = 300,\n loadingComponent: GlobalLoadingComponent = DefaultLoadingComponent,\n cellClassName,\n}: UnifiedBentoGridProps<TData>): React.ReactElement {\n // Inject styles\n useGridStyles();\n useAnimationStyles();\n\n // Handle responsive layouts\n const responsiveLayout = useResponsiveLayout(layout);\n\n // Choose card wrapper\n const CardWrapper = cardWrapper ?? DefaultCardWrapper;\n\n // Filter visible cards\n const visibleCards = useMemo(() => {\n return cards.filter((card) => isCardVisible(card, data));\n }, [cards, data]);\n\n // Resolve layout config from preset or use directly\n const resolvedLayout = useMemo((): BentoLayoutConfig => {\n if (isPresetName(responsiveLayout)) {\n const cardIds = visibleCards.map((c) => c.id);\n return presetToLayout(responsiveLayout, cardIds);\n }\n return responsiveLayout as BentoLayoutConfig;\n }, [responsiveLayout, visibleCards]);\n\n // Create lookup map for cards\n const cardMap = useMemo(() => {\n const map = new Map<string, UnifiedCardDefinition<TData>>();\n visibleCards.forEach((card) => map.set(card.id, card));\n return map;\n }, [visibleCards]);\n\n // Validate layout in development\n useMemo(() => {\n if (process.env.NODE_ENV !== \"production\") {\n const errors = validateLayout(resolvedLayout);\n if (errors.length > 0) {\n console.warn(\"UnifiedBentoGrid layout validation errors:\", errors);\n }\n\n // Check for missing card definitions\n for (const placement of resolvedLayout.placements) {\n if (!visibleCards.some((c) => c.id === placement.cardId)) {\n console.warn(\n `UnifiedBentoGrid: Card \"${placement.cardId}\" in layout but not in cards array`,\n );\n }\n }\n }\n }, [resolvedLayout, visibleCards]);\n\n // Calculate grid dimensions\n const {\n columns,\n rows,\n gap = 16,\n columnGap,\n rowGap,\n rowHeights,\n placements,\n } = resolvedLayout;\n const calculatedRows =\n rows ?? Math.max(...placements.map((p) => p.row + (p.rowSpan ?? 1) - 1), 1);\n\n // Compute row template: use custom rowHeights if provided, otherwise equal 1fr rows\n const rowTemplate = rowHeights\n ? rowHeights.join(\" \")\n : `repeat(${calculatedRows}, minmax(0, 1fr))`;\n\n // Grid uses CSS custom properties - Tailwind classes can override the CSS rules\n const gridStyle: React.CSSProperties = {\n \"--bento-columns\": columns,\n \"--bento-rows\": calculatedRows,\n \"--bento-row-heights\": rowTemplate,\n \"--bento-gap\": `${gap}px`,\n \"--bento-column-gap\": `${columnGap ?? gap}px`,\n \"--bento-row-gap\": `${rowGap ?? gap}px`,\n ...(animated && { \"--bento-animation-duration\": `${animationDuration}ms` }),\n ...style,\n } as React.CSSProperties;\n\n // Helper to get cell class name\n const getCellClassName = (cardId: string) => {\n const baseClass = `bento-cell ${animated ? \"bento-cell-animated\" : \"\"}`;\n if (!cellClassName) return baseClass;\n if (typeof cellClassName === \"function\")\n return `${baseClass} ${cellClassName(cardId)}`;\n return `${baseClass} ${cellClassName}`;\n };\n\n return (\n <div\n className={`bento-grid ${className}`}\n style={gridStyle}\n role=\"region\"\n aria-label={ariaLabel ?? (ariaLabelledBy ? undefined : \"Dashboard grid\")}\n aria-labelledby={ariaLabelledBy}\n >\n {placements.map((placement) => {\n const card = cardMap.get(placement.cardId);\n\n if (!card) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `UnifiedBentoGrid: Card \"${placement.cardId}\" not found`,\n );\n }\n return null;\n }\n\n // Check loading state\n const loading = isCardLoading(card, data);\n\n // Get props from card's propsSelector\n const cardProps = card.propsSelector(data);\n\n // Create a reset key for error boundary\n const resetKey = JSON.stringify(cardProps);\n\n // Calculate span (placement overrides card defaults)\n const colSpan = placement.colSpan ?? card.colSpan ?? 1;\n const rowSpan = placement.rowSpan ?? card.rowSpan ?? 1;\n\n // Cell uses CSS custom properties for positioning\n const cellStyle: React.CSSProperties = {\n \"--bento-col\": placement.col,\n \"--bento-row\": placement.row,\n \"--bento-col-span\": colSpan,\n \"--bento-row-span\": rowSpan,\n } as React.CSSProperties;\n\n const CardComponent = card.component;\n const LoadingComponent =\n card.loadingComponent ?? GlobalLoadingComponent;\n\n return (\n <div\n key={`${placement.cardId}-${placement.col}-${placement.row}`}\n className={getCellClassName(placement.cardId)}\n style={cellStyle}\n data-card-id={placement.cardId}\n >\n <CardErrorBoundary\n cardId={placement.cardId}\n onError={onCardError}\n resetKey={resetKey}\n >\n <CardWrapper cardId={placement.cardId}>\n {loading ? (\n <LoadingComponent />\n ) : (\n <CardComponent {...cardProps} />\n )}\n </CardWrapper>\n </CardErrorBoundary>\n </div>\n );\n })}\n </div>\n );\n}\n","import type {\n PresetLayout,\n PresetLayoutName,\n BentoLayoutConfig,\n PresetSlotMapping,\n} from \"./types.js\";\n\n/**\n * Preset layout definitions\n * Users can use these by name instead of defining custom layouts\n */\nexport const PRESET_LAYOUTS: Record<PresetLayoutName, PresetLayout> = {\n \"2x2\": {\n name: \"2x2\",\n columns: 2,\n rows: 2,\n slots: [\n { name: \"top-left\", col: 1, row: 1 },\n { name: \"top-right\", col: 2, row: 1 },\n { name: \"bottom-left\", col: 1, row: 2 },\n { name: \"bottom-right\", col: 2, row: 2 },\n ],\n },\n \"3x2\": {\n name: \"3x2\",\n columns: 3,\n rows: 2,\n slots: [\n { name: \"top-1\", col: 1, row: 1 },\n { name: \"top-2\", col: 2, row: 1 },\n { name: \"top-3\", col: 3, row: 1 },\n { name: \"bottom-1\", col: 1, row: 2 },\n { name: \"bottom-2\", col: 2, row: 2 },\n { name: \"bottom-3\", col: 3, row: 2 },\n ],\n },\n \"3x3\": {\n name: \"3x3\",\n columns: 3,\n rows: 3,\n slots: [\n { name: \"r1-c1\", col: 1, row: 1 },\n { name: \"r1-c2\", col: 2, row: 1 },\n { name: \"r1-c3\", col: 3, row: 1 },\n { name: \"r2-c1\", col: 1, row: 2 },\n { name: \"r2-c2\", col: 2, row: 2 },\n { name: \"r2-c3\", col: 3, row: 2 },\n { name: \"r3-c1\", col: 1, row: 3 },\n { name: \"r3-c2\", col: 2, row: 3 },\n { name: \"r3-c3\", col: 3, row: 3 },\n ],\n },\n \"4x2\": {\n name: \"4x2\",\n columns: 4,\n rows: 2,\n slots: [\n { name: \"top-1\", col: 1, row: 1 },\n { name: \"top-2\", col: 2, row: 1 },\n { name: \"top-3\", col: 3, row: 1 },\n { name: \"top-4\", col: 4, row: 1 },\n { name: \"bottom-1\", col: 1, row: 2 },\n { name: \"bottom-2\", col: 2, row: 2 },\n { name: \"bottom-3\", col: 3, row: 2 },\n { name: \"bottom-4\", col: 4, row: 2 },\n ],\n },\n \"2x1-hero-left\": {\n name: \"2x1-hero-left\",\n columns: 3,\n rows: 2,\n slots: [\n { name: \"hero\", col: 1, row: 1, colSpan: 2, rowSpan: 2 },\n { name: \"side-top\", col: 3, row: 1 },\n { name: \"side-bottom\", col: 3, row: 2 },\n ],\n },\n \"2x1-hero-right\": {\n name: \"2x1-hero-right\",\n columns: 3,\n rows: 2,\n slots: [\n { name: \"side-top\", col: 1, row: 1 },\n { name: \"side-bottom\", col: 1, row: 2 },\n { name: \"hero\", col: 2, row: 1, colSpan: 2, rowSpan: 2 },\n ],\n },\n \"dashboard-9\": {\n name: \"dashboard-9\",\n columns: 3,\n rows: 4,\n slots: [\n { name: \"header-wide\", col: 1, row: 1, colSpan: 2 },\n { name: \"header-right\", col: 3, row: 1 },\n { name: \"hero\", col: 1, row: 2, rowSpan: 2 },\n { name: \"mid-center\", col: 2, row: 2 },\n { name: \"mid-right\", col: 3, row: 2 },\n { name: \"lower-center\", col: 2, row: 3 },\n { name: \"lower-right\", col: 3, row: 3 },\n { name: \"footer-left\", col: 1, row: 4 },\n { name: \"footer-wide\", col: 2, row: 4, colSpan: 2 },\n ],\n },\n};\n\n/**\n * Convert a preset name to a full layout config with card IDs\n * Supports both legacy array-based assignment and explicit slot mapping\n */\nexport function presetToLayout(\n presetName: PresetLayoutName,\n cardIdsOrMapping: string[] | PresetSlotMapping[],\n): BentoLayoutConfig {\n const preset = PRESET_LAYOUTS[presetName];\n if (!preset) {\n throw new Error(`Unknown preset layout: ${presetName}`);\n }\n\n let placements;\n\n // Check if it's explicit slot mapping or legacy array\n if (\n cardIdsOrMapping.length > 0 &&\n typeof cardIdsOrMapping[0] === \"object\" &&\n \"slot\" in cardIdsOrMapping[0]\n ) {\n // Explicit slot mapping\n const slotMapping = cardIdsOrMapping as PresetSlotMapping[];\n placements = slotMapping\n .map((mapping) => {\n const slotIndex =\n typeof mapping.slot === \"number\"\n ? mapping.slot\n : preset.slots.findIndex((s) => s.name === mapping.slot);\n\n if (slotIndex === -1 || slotIndex >= preset.slots.length) {\n console.warn(\n `Preset \"${presetName}\": slot \"${mapping.slot}\" not found`,\n );\n return null;\n }\n\n const slot = preset.slots[slotIndex];\n return {\n cardId: mapping.cardId,\n col: slot.col,\n row: slot.row,\n colSpan: slot.colSpan,\n rowSpan: slot.rowSpan,\n };\n })\n .filter((p): p is NonNullable<typeof p> => p !== null);\n } else {\n // Legacy array-based assignment\n const cardIds = cardIdsOrMapping as string[];\n placements = preset.slots.map((slot, index) => ({\n cardId: cardIds[index] ?? `card-${index}`,\n col: slot.col,\n row: slot.row,\n colSpan: slot.colSpan,\n rowSpan: slot.rowSpan,\n }));\n }\n\n return {\n columns: preset.columns,\n rows: preset.rows,\n placements,\n };\n}\n\n/**\n * Get available slot names for a preset layout\n * Useful for discovering what slots are available\n */\nexport function getPresetSlotNames(presetName: PresetLayoutName): string[] {\n const preset = PRESET_LAYOUTS[presetName];\n if (!preset) {\n throw new Error(`Unknown preset layout: ${presetName}`);\n }\n return preset.slots.map((s, i) => s.name ?? `slot-${i}`);\n}\n\n/**\n * Check if a value is a preset layout name\n */\nexport function isPresetName(value: unknown): value is PresetLayoutName {\n return typeof value === \"string\" && value in PRESET_LAYOUTS;\n}\n","import React from \"react\";\nimport type { BentoCardProps } from \"./types.js\";\n\n/**\n * Default card wrapper component\n * Provides basic styling - users can override with their own wrapper\n * Uses CSS custom properties for easy theming\n */\nexport const BentoCard: React.FC<BentoCardProps> = ({\n children,\n className = \"\",\n style,\n}) => (\n <div\n className={`bento-card ${className}`}\n style={{\n backgroundColor: \"var(--bento-card-bg, transparent)\",\n borderRadius: \"var(--bento-card-radius, 12px)\",\n padding: \"var(--bento-card-padding, 16px)\",\n border: \"var(--bento-card-border, 1px solid rgba(128, 128, 128, 0.2))\",\n height: \"100%\",\n boxSizing: \"border-box\",\n ...style,\n }}\n >\n {children}\n </div>\n);\n","import type { BentoLayoutConfig, CardPlacement } from \"./types.js\";\n\n/**\n * Create a simple grid layout where cards are placed sequentially\n * Useful for quick prototyping\n *\n * @example\n * ```ts\n * const layout = createSimpleLayout(3, [\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"]);\n * // Creates a 3-column grid with cards placed left-to-right, top-to-bottom\n * ```\n */\nexport function createSimpleLayout(\n columns: number,\n cardIds: string[],\n gap?: number,\n): BentoLayoutConfig {\n const placements: CardPlacement[] = cardIds.map((cardId, index) => ({\n cardId,\n col: (index % columns) + 1,\n row: Math.floor(index / columns) + 1,\n }));\n\n return {\n columns,\n gap,\n placements,\n };\n}\n\n/**\n * Layout builder for fluent API\n *\n * @example\n * ```ts\n * const layout = layoutBuilder(3)\n * .gap(16)\n * .columnGap(20)\n * .rowGap(12)\n * .place(\"hero\", 1, 1, { colSpan: 2, rowSpan: 2 })\n * .place(\"stats\", 3, 1)\n * .place(\"chart\", 3, 2)\n * .build();\n * ```\n */\nexport function layoutBuilder(columns: number) {\n const config: BentoLayoutConfig = {\n columns,\n placements: [],\n };\n\n const builder = {\n gap(value: number) {\n config.gap = value;\n return builder;\n },\n columnGap(value: number) {\n config.columnGap = value;\n return builder;\n },\n rowGap(value: number) {\n config.rowGap = value;\n return builder;\n },\n rows(value: number) {\n config.rows = value;\n return builder;\n },\n rowHeights(heights: string[]) {\n config.rowHeights = heights;\n return builder;\n },\n place(\n cardId: string,\n col: number,\n row: number,\n options?: { colSpan?: number; rowSpan?: number },\n ) {\n config.placements.push({\n cardId,\n col,\n row,\n ...options,\n });\n return builder;\n },\n build(): BentoLayoutConfig {\n return config;\n },\n };\n\n return builder;\n}\n\n/**\n * Validate a layout configuration\n * Returns array of validation errors (empty if valid)\n */\nexport function validateLayout(layout: BentoLayoutConfig): string[] {\n const errors: string[] = [];\n\n if (layout.columns < 1) {\n errors.push(\"columns must be at least 1\");\n }\n\n if (layout.rows !== undefined && layout.rows < 1) {\n errors.push(\"rows must be at least 1\");\n }\n\n if (layout.gap !== undefined && layout.gap < 0) {\n errors.push(\"gap cannot be negative\");\n }\n\n const occupied = new Set<string>();\n\n for (const placement of layout.placements) {\n const colSpan = placement.colSpan ?? 1;\n const rowSpan = placement.rowSpan ?? 1;\n\n // Check bounds\n if (placement.col < 1 || placement.col + colSpan - 1 > layout.columns) {\n errors.push(\n `Card \"${placement.cardId}\" exceeds column bounds (col: ${placement.col}, span: ${colSpan})`,\n );\n }\n\n if (placement.row < 1) {\n errors.push(\n `Card \"${placement.cardId}\" has invalid row: ${placement.row}`,\n );\n }\n\n // Check overlaps\n for (let c = placement.col; c < placement.col + colSpan; c++) {\n for (let r = placement.row; r < placement.row + rowSpan; r++) {\n const key = `${c},${r}`;\n if (occupied.has(key)) {\n errors.push(\n `Card \"${placement.cardId}\" overlaps at position (${c}, ${r})`,\n );\n }\n occupied.add(key);\n }\n }\n }\n\n return errors;\n}\n","import { useMemo, useRef, useState, useEffect, useCallback } from \"react\";\nimport type {\n BentoCardDefinition,\n CardDataMapping,\n BentoLayoutConfig,\n PresetLayoutName,\n ResponsiveLayoutConfig,\n BreakpointConfig,\n} from \"./types.js\";\nimport { isPresetName, presetToLayout } from \"./presets.js\";\n\n/**\n * Deep comparison for stable memoization of object inputs\n */\nfunction useStableValue<T>(value: T): T {\n const ref = useRef<T>(value);\n const prevJson = useRef<string>(\"\");\n\n // Compare by serializing - works for our use case of simple config objects\n // For components, we compare by reference using a custom replacer\n const json = JSON.stringify(value, (key, val) => {\n if (typeof val === \"function\") {\n return val.toString();\n }\n return val;\n });\n\n if (json !== prevJson.current) {\n ref.current = value;\n prevJson.current = json;\n }\n\n return ref.current;\n}\n\n/**\n * Check if a layout config is a responsive config\n */\nexport function isResponsiveConfig(\n layout: BentoLayoutConfig | PresetLayoutName | ResponsiveLayoutConfig,\n): layout is ResponsiveLayoutConfig {\n return (\n typeof layout === \"object\" && \"default\" in layout && \"breakpoints\" in layout\n );\n}\n\n/**\n * Hook to handle responsive layouts based on viewport width\n * Returns the appropriate layout for the current viewport\n *\n * @example\n * ```tsx\n * const layout = useResponsiveLayout({\n * default: \"2x2\",\n * breakpoints: [\n * { minWidth: 768, layout: \"3x2\" },\n * { minWidth: 1024, layout: \"4x2\" },\n * ],\n * });\n * ```\n */\nexport function useResponsiveLayout(\n config: BentoLayoutConfig | PresetLayoutName | ResponsiveLayoutConfig,\n): BentoLayoutConfig | PresetLayoutName {\n const [width, setWidth] = useState(() =>\n typeof window !== \"undefined\" ? window.innerWidth : 0,\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const handleResize = () => setWidth(window.innerWidth);\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n return useMemo(() => {\n if (!isResponsiveConfig(config)) {\n return config;\n }\n\n // Sort breakpoints by minWidth descending to find the largest matching one\n const sortedBreakpoints = [...config.breakpoints].sort(\n (a, b) => b.minWidth - a.minWidth,\n );\n\n for (const bp of sortedBreakpoints) {\n if (width >= bp.minWidth) {\n return bp.layout;\n }\n }\n\n return config.default;\n }, [config, width]);\n}\n\n/**\n * Hook to track window width with debouncing\n */\nexport function useWindowWidth(debounceMs = 100): number {\n const [width, setWidth] = useState(() =>\n typeof window !== \"undefined\" ? window.innerWidth : 0,\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n let timeoutId: ReturnType<typeof setTimeout>;\n const handleResize = () => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => setWidth(window.innerWidth), debounceMs);\n };\n\n window.addEventListener(\"resize\", handleResize);\n return () => {\n clearTimeout(timeoutId);\n window.removeEventListener(\"resize\", handleResize);\n };\n }, [debounceMs]);\n\n return width;\n}\n\n/**\n * Hook to create card definitions from an object map\n * Provides a cleaner API for defining cards\n *\n * @example\n * ```tsx\n * const cards = useCardDefinitions({\n * stats: { component: StatsCard, colSpan: 2 },\n * chart: { component: ChartCard },\n * list: { component: ListCard, rowSpan: 2 },\n * });\n * ```\n */\nexport function useCardDefinitions<\n T extends Record<string, Omit<BentoCardDefinition<any>, \"id\">>,\n>(definitions: T): BentoCardDefinition<any>[] {\n const stableDefinitions = useStableValue(definitions);\n\n return useMemo(() => {\n return Object.entries(stableDefinitions).map(([id, def]) => ({\n id,\n ...def,\n }));\n }, [stableDefinitions]);\n}\n\n/**\n * Hook to create data mappings from an object map\n * Provides a cleaner API for mapping data to cards\n *\n * @example\n * ```tsx\n * const dataMapping = useDataMapping<MyDataType>({\n * stats: (data) => ({ count: data.total, label: 'Items' }),\n * chart: (data) => ({ points: data.chartData }),\n * });\n * ```\n */\nexport function useDataMapping<TData>(\n mappings: Record<string, (data: TData) => Record<string, unknown>>,\n): CardDataMapping<TData>[] {\n const stableMappings = useStableValue(mappings);\n\n return useMemo(() => {\n return Object.entries(stableMappings).map(([cardId, propsSelector]) => ({\n cardId,\n propsSelector,\n }));\n }, [stableMappings]);\n}\n\n/**\n * Hook to create a layout configuration\n * Handles both preset names and custom configs\n *\n * @example\n * ```tsx\n * // Using preset\n * const layout = useLayout(\"3x3\", [\"stats\", \"chart\", \"list\", ...]);\n *\n * // Using custom config\n * const layout = useLayout({\n * columns: 3,\n * placements: [\n * { cardId: \"stats\", col: 1, row: 1, colSpan: 2 },\n * { cardId: \"chart\", col: 3, row: 1 },\n * ]\n * });\n * ```\n */\nexport function useLayout(\n config: PresetLayoutName | BentoLayoutConfig,\n cardIds?: string[],\n): BentoLayoutConfig {\n return useMemo(() => {\n if (isPresetName(config)) {\n if (!cardIds) {\n throw new Error(\"cardIds required when using preset layout name\");\n }\n return presetToLayout(config, cardIds);\n }\n return config;\n }, [config, cardIds]);\n}\n"],"mappings":"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","names":["useMemo","useEffect","jsx","useEffect","useMemo"]}
|
|
1
|
+
{"version":3,"sources":["../src/BentoGrid.tsx","../src/presets.ts","../src/BentoCard.tsx","../src/utils.ts","../src/hooks.ts"],"sourcesContent":["import React, { useMemo, useEffect } from \"react\";\nimport type {\n BentoGridProps,\n BentoLayoutConfig,\n BentoCardDefinition,\n CardDataMapping,\n CardWrapperProps,\n UnifiedBentoGridProps,\n UnifiedCardDefinition,\n} from \"./types.js\";\nimport { isPresetName, presetToLayout } from \"./presets.js\";\nimport { BentoCard } from \"./BentoCard.js\";\nimport { validateLayout } from \"./utils.js\";\nimport { useResponsiveLayout } from \"./hooks.js\";\n\n/**\n * Default card wrapper - just uses BentoCard\n */\nconst DefaultCardWrapper: React.FC<CardWrapperProps> = ({\n children,\n className,\n style,\n}) => (\n <BentoCard className={className} style={style}>\n {children}\n </BentoCard>\n);\n\n/**\n * Default loading component - simple pulse animation\n */\nconst DefaultLoadingComponent: React.FC = () => (\n <div\n className=\"bento-card-loading\"\n style={{\n width: \"100%\",\n height: \"100%\",\n minHeight: 100,\n backgroundColor: \"var(--bento-loading-bg, rgba(128, 128, 128, 0.1))\",\n borderRadius: \"var(--bento-card-radius, 12px)\",\n animation: \"bento-pulse 1.5s ease-in-out infinite\",\n }}\n aria-label=\"Loading\"\n role=\"status\"\n />\n);\n\n/**\n * Inject base grid styles into the document\n * Uses CSS custom properties so Tailwind classes can override\n */\nfunction useGridStyles() {\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n\n const styleId = \"bento-grid-styles\";\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement(\"style\");\n style.id = styleId;\n style.textContent = `\n .bento-grid {\n display: grid;\n grid-template-columns: repeat(var(--bento-columns, 3), 1fr);\n grid-template-rows: var(--bento-row-heights, repeat(var(--bento-rows, 2), minmax(0, 1fr)));\n column-gap: var(--bento-column-gap, var(--bento-gap, 16px));\n row-gap: var(--bento-row-gap, var(--bento-gap, 16px));\n }\n .bento-cell {\n grid-column: var(--bento-col, 1) / span var(--bento-col-span, 1);\n grid-row: var(--bento-row, 1) / span var(--bento-row-span, 1);\n min-height: 0;\n overflow: hidden;\n }\n `;\n document.head.appendChild(style);\n }, []);\n}\n\n/**\n * Inject animation keyframes into the document\n */\nfunction useAnimationStyles() {\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n\n const styleId = \"bento-grid-animations\";\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement(\"style\");\n style.id = styleId;\n style.textContent = `\n @keyframes bento-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n @keyframes bento-fade-in {\n from { opacity: 0; transform: scale(0.95); }\n to { opacity: 1; transform: scale(1); }\n }\n .bento-cell-animated {\n animation: bento-fade-in var(--bento-animation-duration, 300ms) ease-out;\n }\n `;\n document.head.appendChild(style);\n }, []);\n}\n\n/**\n * Error boundary for individual cards\n * Resets when cardId or children change\n */\nclass CardErrorBoundary extends React.Component<\n {\n cardId: string;\n onError?: (cardId: string, error: Error) => void;\n children: React.ReactNode;\n resetKey?: string | number;\n },\n { hasError: boolean; errorKey: string }\n> {\n constructor(props: {\n cardId: string;\n onError?: (cardId: string, error: Error) => void;\n children: React.ReactNode;\n resetKey?: string | number;\n }) {\n super(props);\n this.state = {\n hasError: false,\n errorKey: `${props.cardId}-${props.resetKey ?? \"\"}`,\n };\n }\n\n static getDerivedStateFromError() {\n return { hasError: true };\n }\n\n static getDerivedStateFromProps(\n props: { cardId: string; resetKey?: string | number },\n state: { errorKey: string },\n ) {\n const newKey = `${props.cardId}-${props.resetKey ?? \"\"}`;\n // Reset error state when key changes\n if (newKey !== state.errorKey) {\n return { hasError: false, errorKey: newKey };\n }\n return null;\n }\n\n componentDidCatch(error: Error) {\n this.props.onError?.(this.props.cardId, error);\n }\n\n render() {\n if (this.state.hasError) {\n return (\n <div\n className=\"bento-card-error\"\n role=\"alert\"\n style={{ color: \"#ef4444\", padding: 16 }}\n >\n Failed to render card\n </div>\n );\n }\n return this.props.children;\n }\n}\n\n/**\n * BentoGrid - A flexible, configurable bento grid layout system\n *\n * @example\n * ```tsx\n * <BentoGrid\n * layout=\"3x3\"\n * cards={[\n * { id: 'stats', component: StatsCard },\n * { id: 'chart', component: ChartCard },\n * ]}\n * data={myData}\n * dataMapping={[\n * { cardId: 'stats', propsSelector: (d) => ({ count: d.total }) },\n * { cardId: 'chart', propsSelector: (d) => ({ points: d.chartData }) },\n * ]}\n * />\n * ```\n */\nexport function BentoGrid<TData>({\n layout,\n cards,\n data,\n dataMapping,\n className = \"\",\n style,\n cardWrapper,\n onCardError,\n ariaLabel,\n ariaLabelledBy,\n animated = false,\n animationDuration = 300,\n cellClassName,\n}: BentoGridProps<TData>): React.ReactElement {\n // Inject styles\n useGridStyles();\n useAnimationStyles();\n\n // Handle responsive layouts\n const responsiveLayout = useResponsiveLayout(layout);\n\n // Choose card wrapper\n const CardWrapper = cardWrapper ?? DefaultCardWrapper;\n\n // Resolve layout config from preset or use directly\n const resolvedLayout = useMemo((): BentoLayoutConfig => {\n if (isPresetName(responsiveLayout)) {\n const cardIds = dataMapping.map((m) => m.cardId);\n return presetToLayout(responsiveLayout, cardIds);\n }\n return responsiveLayout as BentoLayoutConfig;\n }, [responsiveLayout, dataMapping]);\n\n // Create lookup maps for cards and data mappings\n const cardMap = useMemo(() => {\n const map = new Map<string, BentoCardDefinition>();\n cards.forEach((card) => map.set(card.id, card));\n return map;\n }, [cards]);\n\n const dataMappingMap = useMemo(() => {\n const map = new Map<string, CardDataMapping<TData>>();\n dataMapping.forEach((mapping) => map.set(mapping.cardId, mapping));\n return map;\n }, [dataMapping]);\n\n // Validate layout in development\n useMemo(() => {\n if (process.env.NODE_ENV !== \"production\") {\n const errors = validateLayout(resolvedLayout);\n if (errors.length > 0) {\n console.warn(\"BentoGrid layout validation errors:\", errors);\n }\n\n // Check for missing card definitions\n for (const placement of resolvedLayout.placements) {\n if (!cards.some((c) => c.id === placement.cardId)) {\n console.warn(\n `BentoGrid: Card \"${placement.cardId}\" in layout but not in cards array`,\n );\n }\n }\n\n // Check for missing data mappings\n for (const placement of resolvedLayout.placements) {\n if (!dataMapping.some((m) => m.cardId === placement.cardId)) {\n console.warn(\n `BentoGrid: Card \"${placement.cardId}\" has no data mapping`,\n );\n }\n }\n }\n }, [resolvedLayout, cards, dataMapping]);\n\n // Calculate grid dimensions\n const {\n columns,\n rows,\n gap = 16,\n columnGap,\n rowGap,\n rowHeights,\n placements,\n } = resolvedLayout;\n const calculatedRows =\n rows ?? Math.max(...placements.map((p) => p.row + (p.rowSpan ?? 1) - 1), 1);\n\n // Compute row template: use custom rowHeights if provided, otherwise equal 1fr rows\n const rowTemplate = rowHeights\n ? rowHeights.join(\" \")\n : `repeat(${calculatedRows}, minmax(0, 1fr))`;\n\n // Grid uses CSS custom properties - Tailwind classes can override the CSS rules\n const gridStyle: React.CSSProperties = {\n \"--bento-columns\": columns,\n \"--bento-rows\": calculatedRows,\n \"--bento-row-heights\": rowTemplate,\n \"--bento-gap\": `${gap}px`,\n \"--bento-column-gap\": `${columnGap ?? gap}px`,\n \"--bento-row-gap\": `${rowGap ?? gap}px`,\n ...(animated && { \"--bento-animation-duration\": `${animationDuration}ms` }),\n ...style,\n } as React.CSSProperties;\n\n // Helper to get cell class name\n const getCellClassName = (cardId: string) => {\n const baseClass = `bento-cell ${animated ? \"bento-cell-animated\" : \"\"}`;\n if (!cellClassName) return baseClass;\n if (typeof cellClassName === \"function\")\n return `${baseClass} ${cellClassName(cardId)}`;\n return `${baseClass} ${cellClassName}`;\n };\n\n return (\n <div\n className={`bento-grid ${className}`}\n style={gridStyle}\n role=\"region\"\n aria-label={ariaLabel ?? (ariaLabelledBy ? undefined : \"Dashboard grid\")}\n aria-labelledby={ariaLabelledBy}\n >\n {placements.map((placement) => {\n const card = cardMap.get(placement.cardId);\n const mapping = dataMappingMap.get(placement.cardId);\n\n if (!card) {\n console.warn(`BentoGrid: Card \"${placement.cardId}\" not found`);\n return null;\n }\n\n // Get props from data mapping or empty object\n const cardProps = mapping ? mapping.propsSelector(data) : {};\n\n // Create a reset key for error boundary - changes when data changes\n const resetKey = JSON.stringify(cardProps);\n\n // Calculate span (placement overrides card defaults)\n const colSpan = placement.colSpan ?? card.colSpan ?? 1;\n const rowSpan = placement.rowSpan ?? card.rowSpan ?? 1;\n\n // Cell uses CSS custom properties for positioning\n const cellStyle: React.CSSProperties = {\n \"--bento-col\": placement.col,\n \"--bento-row\": placement.row,\n \"--bento-col-span\": colSpan,\n \"--bento-row-span\": rowSpan,\n } as React.CSSProperties;\n\n const CardComponent = card.component;\n\n return (\n <div\n key={`${placement.cardId}-${placement.col}-${placement.row}`}\n className={getCellClassName(placement.cardId)}\n style={cellStyle}\n data-card-id={placement.cardId}\n >\n <CardErrorBoundary\n cardId={placement.cardId}\n onError={onCardError}\n resetKey={resetKey}\n >\n <CardWrapper cardId={placement.cardId}>\n <CardComponent {...cardProps} />\n </CardWrapper>\n </CardErrorBoundary>\n </div>\n );\n })}\n </div>\n );\n}\n\n/**\n * Check if a card should be visible based on its visibility config\n */\nfunction isCardVisible<TData>(\n card: UnifiedCardDefinition<TData>,\n data: TData,\n): boolean {\n if (card.visible === undefined) return true;\n if (typeof card.visible === \"function\") return card.visible(data);\n return card.visible;\n}\n\n/**\n * Check if a card is in loading state\n */\nfunction isCardLoading<TData>(\n card: UnifiedCardDefinition<TData>,\n data: TData,\n): boolean {\n if (card.loading === undefined) return false;\n if (typeof card.loading === \"function\") return card.loading(data);\n return card.loading;\n}\n\n/**\n * UnifiedBentoGrid - Cleaner API that combines cards and data mapping\n *\n * This is the preferred way to use BentoGrid. Instead of separate `cards` and\n * `dataMapping` arrays, you define everything in one place.\n *\n * @example\n * ```tsx\n * <UnifiedBentoGrid\n * layout=\"3x2\"\n * cards={[\n * {\n * id: 'stats',\n * component: StatsCard,\n * propsSelector: (d) => ({ count: d.total, label: 'Users' }),\n * colSpan: 2,\n * },\n * {\n * id: 'chart',\n * component: ChartCard,\n * propsSelector: (d) => ({ data: d.chartData }),\n * visible: (d) => d.chartData.length > 0,\n * loading: (d) => d.isLoading,\n * },\n * ]}\n * data={myData}\n * animated\n * />\n * ```\n */\nexport function UnifiedBentoGrid<TData>({\n layout,\n cards,\n data,\n className = \"\",\n style,\n cardWrapper,\n onCardError,\n ariaLabel,\n ariaLabelledBy,\n animated = false,\n animationDuration = 300,\n loadingComponent: GlobalLoadingComponent = DefaultLoadingComponent,\n cellClassName,\n}: UnifiedBentoGridProps<TData>): React.ReactElement {\n // Inject styles\n useGridStyles();\n useAnimationStyles();\n\n // Handle responsive layouts\n const responsiveLayout = useResponsiveLayout(layout);\n\n // Choose card wrapper\n const CardWrapper = cardWrapper ?? DefaultCardWrapper;\n\n // Filter visible cards\n const visibleCards = useMemo(() => {\n return cards.filter((card) => isCardVisible(card, data));\n }, [cards, data]);\n\n // Resolve layout config from preset or use directly\n const resolvedLayout = useMemo((): BentoLayoutConfig => {\n if (isPresetName(responsiveLayout)) {\n const cardIds = visibleCards.map((c) => c.id);\n return presetToLayout(responsiveLayout, cardIds);\n }\n return responsiveLayout as BentoLayoutConfig;\n }, [responsiveLayout, visibleCards]);\n\n // Create lookup map for cards\n const cardMap = useMemo(() => {\n const map = new Map<string, UnifiedCardDefinition<TData>>();\n visibleCards.forEach((card) => map.set(card.id, card));\n return map;\n }, [visibleCards]);\n\n // Validate layout in development\n useMemo(() => {\n if (process.env.NODE_ENV !== \"production\") {\n const errors = validateLayout(resolvedLayout);\n if (errors.length > 0) {\n console.warn(\"UnifiedBentoGrid layout validation errors:\", errors);\n }\n\n // Check for missing card definitions\n for (const placement of resolvedLayout.placements) {\n if (!visibleCards.some((c) => c.id === placement.cardId)) {\n console.warn(\n `UnifiedBentoGrid: Card \"${placement.cardId}\" in layout but not in cards array`,\n );\n }\n }\n }\n }, [resolvedLayout, visibleCards]);\n\n // Calculate grid dimensions\n const {\n columns,\n rows,\n gap = 16,\n columnGap,\n rowGap,\n rowHeights,\n placements,\n } = resolvedLayout;\n const calculatedRows =\n rows ?? Math.max(...placements.map((p) => p.row + (p.rowSpan ?? 1) - 1), 1);\n\n // Compute row template: use custom rowHeights if provided, otherwise equal 1fr rows\n const rowTemplate = rowHeights\n ? rowHeights.join(\" \")\n : `repeat(${calculatedRows}, minmax(0, 1fr))`;\n\n // Grid uses CSS custom properties - Tailwind classes can override the CSS rules\n const gridStyle: React.CSSProperties = {\n \"--bento-columns\": columns,\n \"--bento-rows\": calculatedRows,\n \"--bento-row-heights\": rowTemplate,\n \"--bento-gap\": `${gap}px`,\n \"--bento-column-gap\": `${columnGap ?? gap}px`,\n \"--bento-row-gap\": `${rowGap ?? gap}px`,\n ...(animated && { \"--bento-animation-duration\": `${animationDuration}ms` }),\n ...style,\n } as React.CSSProperties;\n\n // Helper to get cell class name\n const getCellClassName = (cardId: string) => {\n const baseClass = `bento-cell ${animated ? \"bento-cell-animated\" : \"\"}`;\n if (!cellClassName) return baseClass;\n if (typeof cellClassName === \"function\")\n return `${baseClass} ${cellClassName(cardId)}`;\n return `${baseClass} ${cellClassName}`;\n };\n\n return (\n <div\n className={`bento-grid ${className}`}\n style={gridStyle}\n role=\"region\"\n aria-label={ariaLabel ?? (ariaLabelledBy ? undefined : \"Dashboard grid\")}\n aria-labelledby={ariaLabelledBy}\n >\n {placements.map((placement) => {\n const card = cardMap.get(placement.cardId);\n\n if (!card) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `UnifiedBentoGrid: Card \"${placement.cardId}\" not found`,\n );\n }\n return null;\n }\n\n // Check loading state\n const loading = isCardLoading(card, data);\n\n // Get props from card's propsSelector\n const cardProps = card.propsSelector(data);\n\n // Create a reset key for error boundary\n const resetKey = JSON.stringify(cardProps);\n\n // Calculate span (placement overrides card defaults)\n const colSpan = placement.colSpan ?? card.colSpan ?? 1;\n const rowSpan = placement.rowSpan ?? card.rowSpan ?? 1;\n\n // Cell uses CSS custom properties for positioning\n const cellStyle: React.CSSProperties = {\n \"--bento-col\": placement.col,\n \"--bento-row\": placement.row,\n \"--bento-col-span\": colSpan,\n \"--bento-row-span\": rowSpan,\n } as React.CSSProperties;\n\n const CardComponent = card.component;\n const LoadingComponent =\n card.loadingComponent ?? GlobalLoadingComponent;\n\n return (\n <div\n key={`${placement.cardId}-${placement.col}-${placement.row}`}\n className={getCellClassName(placement.cardId)}\n style={cellStyle}\n data-card-id={placement.cardId}\n >\n <CardErrorBoundary\n cardId={placement.cardId}\n onError={onCardError}\n resetKey={resetKey}\n >\n <CardWrapper cardId={placement.cardId}>\n {loading ? (\n <LoadingComponent />\n ) : (\n <CardComponent {...cardProps} />\n )}\n </CardWrapper>\n </CardErrorBoundary>\n </div>\n );\n })}\n </div>\n );\n}\n","import type {\n PresetLayout,\n PresetLayoutName,\n BentoLayoutConfig,\n PresetSlotMapping,\n} from \"./types.js\";\n\n/**\n * Preset layout definitions\n * Users can use these by name instead of defining custom layouts\n */\nexport const PRESET_LAYOUTS: Record<PresetLayoutName, PresetLayout> = {\n \"2x2\": {\n name: \"2x2\",\n columns: 2,\n rows: 2,\n slots: [\n { name: \"top-left\", col: 1, row: 1 },\n { name: \"top-right\", col: 2, row: 1 },\n { name: \"bottom-left\", col: 1, row: 2 },\n { name: \"bottom-right\", col: 2, row: 2 },\n ],\n },\n \"3x2\": {\n name: \"3x2\",\n columns: 3,\n rows: 2,\n slots: [\n { name: \"top-1\", col: 1, row: 1 },\n { name: \"top-2\", col: 2, row: 1 },\n { name: \"top-3\", col: 3, row: 1 },\n { name: \"bottom-1\", col: 1, row: 2 },\n { name: \"bottom-2\", col: 2, row: 2 },\n { name: \"bottom-3\", col: 3, row: 2 },\n ],\n },\n \"3x3\": {\n name: \"3x3\",\n columns: 3,\n rows: 3,\n slots: [\n { name: \"r1-c1\", col: 1, row: 1 },\n { name: \"r1-c2\", col: 2, row: 1 },\n { name: \"r1-c3\", col: 3, row: 1 },\n { name: \"r2-c1\", col: 1, row: 2 },\n { name: \"r2-c2\", col: 2, row: 2 },\n { name: \"r2-c3\", col: 3, row: 2 },\n { name: \"r3-c1\", col: 1, row: 3 },\n { name: \"r3-c2\", col: 2, row: 3 },\n { name: \"r3-c3\", col: 3, row: 3 },\n ],\n },\n \"4x2\": {\n name: \"4x2\",\n columns: 4,\n rows: 2,\n slots: [\n { name: \"top-1\", col: 1, row: 1 },\n { name: \"top-2\", col: 2, row: 1 },\n { name: \"top-3\", col: 3, row: 1 },\n { name: \"top-4\", col: 4, row: 1 },\n { name: \"bottom-1\", col: 1, row: 2 },\n { name: \"bottom-2\", col: 2, row: 2 },\n { name: \"bottom-3\", col: 3, row: 2 },\n { name: \"bottom-4\", col: 4, row: 2 },\n ],\n },\n \"2x1-hero-left\": {\n name: \"2x1-hero-left\",\n columns: 3,\n rows: 2,\n slots: [\n { name: \"hero\", col: 1, row: 1, colSpan: 2, rowSpan: 2 },\n { name: \"side-top\", col: 3, row: 1 },\n { name: \"side-bottom\", col: 3, row: 2 },\n ],\n },\n \"2x1-hero-right\": {\n name: \"2x1-hero-right\",\n columns: 3,\n rows: 2,\n slots: [\n { name: \"side-top\", col: 1, row: 1 },\n { name: \"side-bottom\", col: 1, row: 2 },\n { name: \"hero\", col: 2, row: 1, colSpan: 2, rowSpan: 2 },\n ],\n },\n \"dashboard-9\": {\n name: \"dashboard-9\",\n columns: 3,\n rows: 4,\n slots: [\n { name: \"header-wide\", col: 1, row: 1, colSpan: 2 },\n { name: \"header-right\", col: 3, row: 1 },\n { name: \"hero\", col: 1, row: 2, rowSpan: 2 },\n { name: \"mid-center\", col: 2, row: 2 },\n { name: \"mid-right\", col: 3, row: 2 },\n { name: \"lower-center\", col: 2, row: 3 },\n { name: \"lower-right\", col: 3, row: 3 },\n { name: \"footer-left\", col: 1, row: 4 },\n { name: \"footer-wide\", col: 2, row: 4, colSpan: 2 },\n ],\n },\n};\n\n/**\n * Convert a preset name to a full layout config with card IDs\n * Supports both legacy array-based assignment and explicit slot mapping\n */\nexport function presetToLayout(\n presetName: PresetLayoutName,\n cardIdsOrMapping: string[] | PresetSlotMapping[],\n): BentoLayoutConfig {\n const preset = PRESET_LAYOUTS[presetName];\n if (!preset) {\n throw new Error(`Unknown preset layout: ${presetName}`);\n }\n\n let placements;\n\n // Check if it's explicit slot mapping or legacy array\n if (\n cardIdsOrMapping.length > 0 &&\n typeof cardIdsOrMapping[0] === \"object\" &&\n \"slot\" in cardIdsOrMapping[0]\n ) {\n // Explicit slot mapping\n const slotMapping = cardIdsOrMapping as PresetSlotMapping[];\n placements = slotMapping\n .map((mapping) => {\n const slotIndex =\n typeof mapping.slot === \"number\"\n ? mapping.slot\n : preset.slots.findIndex((s) => s.name === mapping.slot);\n\n if (slotIndex === -1 || slotIndex >= preset.slots.length) {\n console.warn(\n `Preset \"${presetName}\": slot \"${mapping.slot}\" not found`,\n );\n return null;\n }\n\n const slot = preset.slots[slotIndex];\n return {\n cardId: mapping.cardId,\n col: slot.col,\n row: slot.row,\n colSpan: slot.colSpan,\n rowSpan: slot.rowSpan,\n };\n })\n .filter((p): p is NonNullable<typeof p> => p !== null);\n } else {\n // Legacy array-based assignment\n const cardIds = cardIdsOrMapping as string[];\n placements = preset.slots.map((slot, index) => ({\n cardId: cardIds[index] ?? `card-${index}`,\n col: slot.col,\n row: slot.row,\n colSpan: slot.colSpan,\n rowSpan: slot.rowSpan,\n }));\n }\n\n return {\n columns: preset.columns,\n rows: preset.rows,\n placements,\n };\n}\n\n/**\n * Get available slot names for a preset layout\n * Useful for discovering what slots are available\n */\nexport function getPresetSlotNames(presetName: PresetLayoutName): string[] {\n const preset = PRESET_LAYOUTS[presetName];\n if (!preset) {\n throw new Error(`Unknown preset layout: ${presetName}`);\n }\n return preset.slots.map((s, i) => s.name ?? `slot-${i}`);\n}\n\n/**\n * Check if a value is a preset layout name\n */\nexport function isPresetName(value: unknown): value is PresetLayoutName {\n return typeof value === \"string\" && value in PRESET_LAYOUTS;\n}\n","import React from \"react\";\nimport type { BentoCardProps } from \"./types.js\";\n\n/**\n * Default card wrapper component\n * Provides basic styling - users can override with their own wrapper\n * Uses CSS custom properties for easy theming\n */\nexport const BentoCard: React.FC<BentoCardProps> = ({\n children,\n className = \"\",\n style,\n}) => (\n <div\n className={`bento-card ${className}`}\n style={{\n backgroundColor: \"var(--bento-card-bg, transparent)\",\n borderRadius: \"var(--bento-card-radius, 12px)\",\n padding: \"var(--bento-card-padding, 16px)\",\n border: \"var(--bento-card-border, 1px solid rgba(128, 128, 128, 0.2))\",\n height: \"100%\",\n boxSizing: \"border-box\",\n ...style,\n }}\n >\n {children}\n </div>\n);\n","import type { BentoLayoutConfig, CardPlacement } from \"./types.js\";\n\n/**\n * Create a simple grid layout where cards are placed sequentially\n * Useful for quick prototyping\n *\n * @example\n * ```ts\n * const layout = createSimpleLayout(3, [\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"]);\n * // Creates a 3-column grid with cards placed left-to-right, top-to-bottom\n * ```\n */\nexport function createSimpleLayout(\n columns: number,\n cardIds: string[],\n gap?: number,\n): BentoLayoutConfig {\n const placements: CardPlacement[] = cardIds.map((cardId, index) => ({\n cardId,\n col: (index % columns) + 1,\n row: Math.floor(index / columns) + 1,\n }));\n\n return {\n columns,\n gap,\n placements,\n };\n}\n\n/**\n * Layout builder for fluent API\n *\n * @example\n * ```ts\n * const layout = layoutBuilder(3)\n * .gap(16)\n * .columnGap(20)\n * .rowGap(12)\n * .place(\"hero\", 1, 1, { colSpan: 2, rowSpan: 2 })\n * .place(\"stats\", 3, 1)\n * .place(\"chart\", 3, 2)\n * .build();\n * ```\n */\nexport function layoutBuilder(columns: number) {\n const config: BentoLayoutConfig = {\n columns,\n placements: [],\n };\n\n const builder = {\n gap(value: number) {\n config.gap = value;\n return builder;\n },\n columnGap(value: number) {\n config.columnGap = value;\n return builder;\n },\n rowGap(value: number) {\n config.rowGap = value;\n return builder;\n },\n rows(value: number) {\n config.rows = value;\n return builder;\n },\n rowHeights(heights: string[]) {\n config.rowHeights = heights;\n return builder;\n },\n place(\n cardId: string,\n col: number,\n row: number,\n options?: { colSpan?: number; rowSpan?: number },\n ) {\n config.placements.push({\n cardId,\n col,\n row,\n ...options,\n });\n return builder;\n },\n build(): BentoLayoutConfig {\n return config;\n },\n };\n\n return builder;\n}\n\n/**\n * Validate a layout configuration\n * Returns array of validation errors (empty if valid)\n */\nexport function validateLayout(layout: BentoLayoutConfig): string[] {\n const errors: string[] = [];\n\n if (layout.columns < 1) {\n errors.push(\"columns must be at least 1\");\n }\n\n if (layout.rows !== undefined && layout.rows < 1) {\n errors.push(\"rows must be at least 1\");\n }\n\n if (layout.gap !== undefined && layout.gap < 0) {\n errors.push(\"gap cannot be negative\");\n }\n\n const occupied = new Set<string>();\n\n for (const placement of layout.placements) {\n const colSpan = placement.colSpan ?? 1;\n const rowSpan = placement.rowSpan ?? 1;\n\n // Check bounds\n if (placement.col < 1 || placement.col + colSpan - 1 > layout.columns) {\n errors.push(\n `Card \"${placement.cardId}\" exceeds column bounds (col: ${placement.col}, span: ${colSpan})`,\n );\n }\n\n if (placement.row < 1) {\n errors.push(\n `Card \"${placement.cardId}\" has invalid row: ${placement.row}`,\n );\n }\n\n // Check overlaps\n for (let c = placement.col; c < placement.col + colSpan; c++) {\n for (let r = placement.row; r < placement.row + rowSpan; r++) {\n const key = `${c},${r}`;\n if (occupied.has(key)) {\n errors.push(\n `Card \"${placement.cardId}\" overlaps at position (${c}, ${r})`,\n );\n }\n occupied.add(key);\n }\n }\n }\n\n return errors;\n}\n","import { useMemo, useRef, useState, useEffect, useCallback } from \"react\";\nimport type {\n BentoCardDefinition,\n CardDataMapping,\n BentoLayoutConfig,\n PresetLayoutName,\n ResponsiveLayoutConfig,\n BreakpointConfig,\n} from \"./types.js\";\nimport { isPresetName, presetToLayout } from \"./presets.js\";\n\n/**\n * Deep comparison for stable memoization of object inputs\n */\nfunction useStableValue<T>(value: T): T {\n const ref = useRef<T>(value);\n const prevJson = useRef<string>(\"\");\n\n // Compare by serializing - works for our use case of simple config objects\n // For components, we compare by reference using a custom replacer\n const json = JSON.stringify(value, (key, val) => {\n if (typeof val === \"function\") {\n return val.toString();\n }\n return val;\n });\n\n if (json !== prevJson.current) {\n ref.current = value;\n prevJson.current = json;\n }\n\n return ref.current;\n}\n\n/**\n * Check if a layout config is a responsive config\n */\nexport function isResponsiveConfig(\n layout: BentoLayoutConfig | PresetLayoutName | ResponsiveLayoutConfig,\n): layout is ResponsiveLayoutConfig {\n return (\n typeof layout === \"object\" && \"default\" in layout && \"breakpoints\" in layout\n );\n}\n\n/**\n * Hook to handle responsive layouts based on viewport width\n * Returns the appropriate layout for the current viewport\n *\n * @example\n * ```tsx\n * const layout = useResponsiveLayout({\n * default: \"2x2\",\n * breakpoints: [\n * { minWidth: 768, layout: \"3x2\" },\n * { minWidth: 1024, layout: \"4x2\" },\n * ],\n * });\n * ```\n */\nexport function useResponsiveLayout(\n config: BentoLayoutConfig | PresetLayoutName | ResponsiveLayoutConfig,\n): BentoLayoutConfig | PresetLayoutName {\n const [width, setWidth] = useState(() =>\n typeof window !== \"undefined\" ? window.innerWidth : 0,\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const handleResize = () => setWidth(window.innerWidth);\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n return useMemo(() => {\n if (!isResponsiveConfig(config)) {\n return config;\n }\n\n // Sort breakpoints by minWidth descending to find the largest matching one\n const sortedBreakpoints = [...config.breakpoints].sort(\n (a, b) => b.minWidth - a.minWidth,\n );\n\n for (const bp of sortedBreakpoints) {\n if (width >= bp.minWidth) {\n return bp.layout;\n }\n }\n\n return config.default;\n }, [config, width]);\n}\n\n/**\n * Hook to track window width with debouncing\n */\nexport function useWindowWidth(debounceMs = 100): number {\n const [width, setWidth] = useState(() =>\n typeof window !== \"undefined\" ? window.innerWidth : 0,\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n let timeoutId: ReturnType<typeof setTimeout>;\n const handleResize = () => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => setWidth(window.innerWidth), debounceMs);\n };\n\n window.addEventListener(\"resize\", handleResize);\n return () => {\n clearTimeout(timeoutId);\n window.removeEventListener(\"resize\", handleResize);\n };\n }, [debounceMs]);\n\n return width;\n}\n\n/**\n * Hook to create card definitions from an object map\n * Provides a cleaner API for defining cards\n *\n * @example\n * ```tsx\n * const cards = useCardDefinitions({\n * stats: { component: StatsCard, colSpan: 2 },\n * chart: { component: ChartCard },\n * list: { component: ListCard, rowSpan: 2 },\n * });\n * ```\n */\nexport function useCardDefinitions<\n T extends Record<string, Omit<BentoCardDefinition<any>, \"id\">>,\n>(definitions: T): BentoCardDefinition<any>[] {\n const stableDefinitions = useStableValue(definitions);\n\n return useMemo(() => {\n return Object.entries(stableDefinitions).map(([id, def]) => ({\n id,\n ...def,\n }));\n }, [stableDefinitions]);\n}\n\n/**\n * Hook to create data mappings from an object map\n * Provides a cleaner API for mapping data to cards\n *\n * @example\n * ```tsx\n * const dataMapping = useDataMapping<MyDataType>({\n * stats: (data) => ({ count: data.total, label: 'Items' }),\n * chart: (data) => ({ points: data.chartData }),\n * });\n * ```\n */\nexport function useDataMapping<TData>(\n mappings: Record<string, (data: TData) => Record<string, unknown>>,\n): CardDataMapping<TData>[] {\n const stableMappings = useStableValue(mappings);\n\n return useMemo(() => {\n return Object.entries(stableMappings).map(([cardId, propsSelector]) => ({\n cardId,\n propsSelector,\n }));\n }, [stableMappings]);\n}\n\n/**\n * Hook to create a layout configuration\n * Handles both preset names and custom configs\n *\n * @example\n * ```tsx\n * // Using preset\n * const layout = useLayout(\"3x3\", [\"stats\", \"chart\", \"list\", ...]);\n *\n * // Using custom config\n * const layout = useLayout({\n * columns: 3,\n * placements: [\n * { cardId: \"stats\", col: 1, row: 1, colSpan: 2 },\n * { cardId: \"chart\", col: 3, row: 1 },\n * ]\n * });\n * ```\n */\nexport function useLayout(\n config: PresetLayoutName | BentoLayoutConfig,\n cardIds?: string[],\n): BentoLayoutConfig {\n return useMemo(() => {\n if (isPresetName(config)) {\n if (!cardIds) {\n throw new Error(\"cardIds required when using preset layout name\");\n }\n return presetToLayout(config, cardIds);\n }\n return config;\n }, [config, cardIds]);\n}\n"],"mappings":"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","names":["useMemo","useEffect","jsx","useEffect","useMemo"]}
|