@alfakit/core 0.2.0 → 0.2.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"table-layout.js","names":[],"sources":["../src/table-layout.ts"],"sourcesContent":["import { inertiaReload, requestJson } from './http'\nimport type { Alignment } from './schema/common'\nimport type {\n AnyPaginationSchema,\n BaseColumnSchema,\n Breakpoint,\n ColumnGroupSchema,\n ColumnLayoutNode,\n ColumnSchema,\n SplitLayoutSchema,\n StackLayoutSchema,\n TableSchema,\n} from './schema/table'\nimport type { TableQuery } from './table'\n\n/**\n * One cell of the column-group header row: a group spanning `span` adjacent visible\n * columns, or (without `group`) an ungrouped column whose header spans both rows.\n */\nexport interface ColumnGroupHeaderCell {\n key: string\n span: number\n group?: ColumnGroupSchema\n column?: ColumnSchema\n}\n\n/**\n * The extra header row for `ColumnGroup`s. Adjacent visible columns of the same group\n * share one header; a group split by a reordered column gets one header per run.\n * Returns null when the table has no groups.\n */\nexport function columnGroupHeaderRow(\n columns: ColumnSchema[],\n groups: ColumnGroupSchema[] | undefined,\n): ColumnGroupHeaderCell[] | null {\n if (!groups || groups.length === 0) {\n return null\n }\n\n const groupOf = new Map<string, ColumnGroupSchema>()\n\n for (const group of groups) {\n for (const name of group.columns) {\n groupOf.set(name, group)\n }\n }\n\n const cells: ColumnGroupHeaderCell[] = []\n\n for (const column of columns) {\n const group = groupOf.get(column.name)\n const previous = cells[cells.length - 1]\n\n if (group && previous?.group === group) {\n previous.span += 1\n } else if (group) {\n cells.push({ key: `group:${group.label}:${column.name}`, span: 1, group })\n } else {\n cells.push({ key: `column:${column.name}`, span: 1, column })\n }\n }\n\n return cells\n}\n\n/** Whether a column sits under a group header (so its own header is in the second row). */\nexport function isGroupedColumn(name: string, groups: ColumnGroupSchema[] | undefined): boolean {\n return Boolean(groups?.some((group) => group.columns.includes(name)))\n}\n\n/** Column names referenced anywhere in a content layout, in order. */\nexport function layoutColumnNames(nodes: ColumnLayoutNode[] | undefined): string[] {\n const names: string[] = []\n\n for (const node of nodes ?? []) {\n if (node.type === 'Column') {\n names.push(node.name)\n } else {\n names.push(...layoutColumnNames(node.schema))\n }\n }\n\n return names\n}\n\nconst SPLIT_FROM: Record<Breakpoint | 'default', string> = {\n default: 'flex-row items-center',\n sm: 'flex-col sm:flex-row sm:items-center',\n md: 'flex-col md:flex-row md:items-center',\n lg: 'flex-col lg:flex-row lg:items-center',\n xl: 'flex-col xl:flex-row xl:items-center',\n '2xl': 'flex-col 2xl:flex-row 2xl:items-center',\n}\n\n/** Classes of a `Split`: side by side from its breakpoint, stacked below it. */\nexport function splitClasses(layout: Pick<SplitLayoutSchema, 'from'>): string {\n return `flex gap-3 ${SPLIT_FROM[layout.from ?? 'default']}`\n}\n\nconst VISIBLE_FROM: Record<Breakpoint, string> = {\n sm: 'hidden sm:flex',\n md: 'hidden md:flex',\n lg: 'hidden lg:flex',\n xl: 'hidden xl:flex',\n '2xl': 'hidden 2xl:flex',\n}\n\nconst HIDDEN_FROM: Record<Breakpoint, string> = {\n sm: 'sm:hidden',\n md: 'md:hidden',\n lg: 'lg:hidden',\n xl: 'xl:hidden',\n '2xl': '2xl:hidden',\n}\n\n/** Responsive visibility classes for `visibleFrom()` / `hiddenFrom()`. */\nexport function layoutVisibilityClasses(layout: {\n visibleFrom?: Breakpoint\n hiddenFrom?: Breakpoint\n}): string {\n return [\n layout.visibleFrom ? VISIBLE_FROM[layout.visibleFrom] : '',\n layout.hiddenFrom ? HIDDEN_FROM[layout.hiddenFrom] : '',\n ]\n .filter(Boolean)\n .join(' ')\n}\n\nconst VISIBLE_FROM_CELL: Record<Breakpoint, string> = {\n sm: 'hidden sm:table-cell',\n md: 'hidden md:table-cell',\n lg: 'hidden lg:table-cell',\n xl: 'hidden xl:table-cell',\n '2xl': 'hidden 2xl:table-cell',\n}\n\nconst VISIBLE_FROM_BLOCK: Record<Breakpoint, string> = {\n sm: 'hidden sm:block',\n md: 'hidden md:block',\n lg: 'hidden lg:block',\n xl: 'hidden xl:block',\n '2xl': 'hidden 2xl:block',\n}\n\n/**\n * Responsive visibility classes for a column's `visibleFrom()` / `hiddenFrom()`: for its\n * header and cells in a table (`table-cell`), or its block in a content layout.\n */\nexport function columnVisibilityClasses(\n column: Pick<BaseColumnSchema, 'visibleFrom' | 'hiddenFrom'>,\n display: 'table-cell' | 'block' = 'table-cell',\n): string {\n const visible = display === 'block' ? VISIBLE_FROM_BLOCK : VISIBLE_FROM_CELL\n\n return [\n column.visibleFrom ? visible[column.visibleFrom] : '',\n column.hiddenFrom ? HIDDEN_FROM[column.hiddenFrom] : '',\n ]\n .filter(Boolean)\n .join(' ')\n}\n\nconst STACK_SPACE: Record<number, string> = { 1: 'gap-1', 2: 'gap-2', 3: 'gap-3' }\n\nconst STACK_ALIGN: Partial<Record<Alignment, string>> = {\n start: 'items-start text-start',\n center: 'items-center text-center',\n end: 'items-end text-end',\n}\n\n/** Classes of a `Stack`: a vertical flex column with its gap and alignment. */\nexport function stackClasses(layout: Pick<StackLayoutSchema, 'space' | 'alignment'>): string {\n return [\n 'flex flex-col',\n STACK_SPACE[layout.space ?? 0] ?? 'gap-0.5',\n layout.alignment ? STACK_ALIGN[layout.alignment] : '',\n ]\n .filter(Boolean)\n .join(' ')\n}\n\n/** Inside a `Split`, whether a node takes the remaining width. */\nexport function layoutNodeGrows(node: ColumnLayoutNode, columns: ColumnSchema[]): boolean {\n if (node.type === 'Column') {\n return columns.find((column) => column.name === node.name)?.grow !== false\n }\n\n return node.grow !== false\n}\n\n/** Record actions placed at the start of the row (before or after the checkbox). */\nexport function recordActionsAtStart(position: TableSchema['recordActionsPosition']): boolean {\n return position === 'before-cells' || position === 'before-columns'\n}\n\n/** The total record count, when the pagination mode knows it. */\nexport function paginationTotal(pagination: AnyPaginationSchema | null | undefined): number | null {\n if (!pagination || ('mode' in pagination && pagination.mode && pagination.mode !== 'default')) {\n return null\n }\n\n return 'total' in pagination ? pagination.total : null\n}\n\n/** Load more and infinite scroll keep earlier pages and append the next one. */\nexport function isAppendingPagination(\n pagination: AnyPaginationSchema | null | undefined,\n): pagination is Extract<AnyPaginationSchema, { mode: 'load-more' | 'infinite' }> {\n return pagination?.mode === 'load-more' || pagination?.mode === 'infinite'\n}\n\n/**\n * The table query for the next page of a simple, cursor or appending paginator, or null\n * on the last page.\n */\nexport function nextPageQuery(\n pagination: AnyPaginationSchema | null | undefined,\n): TableQuery | null {\n if (!pagination) return null\n\n switch (pagination.mode) {\n case 'cursor':\n return pagination.hasMorePages && pagination.nextCursor\n ? { cursor: pagination.nextCursor }\n : null\n case 'simple':\n case 'load-more':\n case 'infinite':\n return pagination.hasMorePages ? { page: pagination.currentPage + 1 } : null\n default:\n return pagination.currentPage < pagination.lastPage\n ? { page: pagination.currentPage + 1 }\n : null\n }\n}\n\n/** The table query for the previous page, or null on the first page. */\nexport function previousPageQuery(\n pagination: AnyPaginationSchema | null | undefined,\n): TableQuery | null {\n if (!pagination || isAppendingPagination(pagination)) return null\n\n if (pagination.mode === 'cursor') {\n return pagination.previousCursor ? { cursor: pagination.previousCursor } : null\n }\n\n return pagination.currentPage > 1 ? { page: pagination.currentPage - 1 } : null\n}\n\n/** Move a column one step in the user's column order. */\nexport function moveColumn(names: readonly string[], name: string, offset: -1 | 1): string[] {\n const from = names.indexOf(name)\n const to = from + offset\n\n if (from < 0 || to < 0 || to >= names.length) {\n return [...names]\n }\n\n const next = [...names]\n const [moved] = next.splice(from, 1)\n\n if (moved !== undefined) next.splice(to, 0, moved)\n\n return next\n}\n\n/** Drop a dragged column onto another: it takes the target's position in the order. */\nexport function moveColumnTo(names: readonly string[], name: string, target: string): string[] {\n const from = names.indexOf(name)\n const to = names.indexOf(target)\n\n if (from < 0 || to < 0 || from === to) {\n return [...names]\n }\n\n const next = [...names]\n const [moved] = next.splice(from, 1)\n\n if (moved !== undefined) next.splice(to, 0, moved)\n\n return next\n}\n\n/**\n * Where a column sits in the column manager, for screen readers: inside a column group\n * it counts among the group's columns (`group` is its label); otherwise among the\n * top-level items, where a column group counts as one item.\n */\nexport interface ColumnManagerPosition {\n position: number\n count: number\n group?: string\n}\n\n/** The column group (of `columnGroups`) a column belongs to. */\nfunction columnGroupOf(\n name: string,\n groups: readonly ColumnGroupSchema[] | undefined,\n): ColumnGroupSchema | undefined {\n return groups?.find((group) => group.columns.includes(name))\n}\n\n/**\n * The top-level items of a column order: an ungrouped column, or the contiguous columns\n * of one column group.\n */\nfunction columnManagerItems(\n order: readonly string[],\n groups: readonly ColumnGroupSchema[] | undefined,\n): string[][] {\n const items: string[][] = []\n let current: ColumnGroupSchema | undefined\n\n for (const name of order) {\n const group = columnGroupOf(name, groups)\n const last = items[items.length - 1]\n\n if (group && group === current && last) {\n last.push(name)\n } else {\n items.push([name])\n }\n\n current = group\n }\n\n return items\n}\n\nexport function columnManagerPosition(\n order: readonly string[],\n name: string,\n groups?: readonly ColumnGroupSchema[],\n): ColumnManagerPosition {\n const group = columnGroupOf(name, groups)\n\n if (group) {\n const siblings = order.filter((column) => group.columns.includes(column))\n\n return { position: siblings.indexOf(name) + 1, count: siblings.length, group: group.label }\n }\n\n const items = columnManagerItems(order, groups)\n\n return {\n position: items.findIndex((item) => item.includes(name)) + 1,\n count: items.length,\n }\n}\n\n/**\n * Move a column one step in the column manager: a grouped column swaps with its\n * neighbour in the same group; an ungrouped column moves past the neighbouring item\n * (a whole column group), so groups stay together. Returns the order unchanged at an edge.\n */\nexport function moveColumnInManager(\n order: readonly string[],\n name: string,\n offset: -1 | 1,\n groups?: readonly ColumnGroupSchema[],\n): string[] {\n const group = columnGroupOf(name, groups)\n\n if (group) {\n const siblings = order.filter((column) => group.columns.includes(column))\n const neighbour = siblings[siblings.indexOf(name) + offset]\n\n if (neighbour === undefined) return [...order]\n\n const next = [...order]\n next[order.indexOf(name)] = neighbour\n next[order.indexOf(neighbour)] = name\n\n return next\n }\n\n const items = columnManagerItems(order, groups)\n const index = items.findIndex((item) => item.includes(name))\n const target = index + offset\n\n if (index < 0 || target < 0 || target >= items.length) return [...order]\n\n const next = [...items]\n const [moved] = next.splice(index, 1)\n\n if (moved !== undefined) next.splice(target, 0, moved)\n\n return next.flat()\n}\n\n/** The columns in a (draft) column order; columns missing from it keep their place at the end. */\nexport function orderColumnsBy<T extends { name: string }>(\n columns: readonly T[],\n order: readonly string[] | null | undefined,\n): T[] {\n if (!order) return [...columns]\n\n const rank = (name: string) => {\n const index = order.indexOf(name)\n\n return index < 0 ? order.length : index\n }\n\n return [...columns].sort((a, b) => rank(a.name) - rank(b.name))\n}\n\n/** Whether a draft column order differs from the applied one. */\nexport function columnOrderChanged(applied: readonly string[], draft: readonly string[]): boolean {\n return applied.length !== draft.length || applied.some((name, index) => draft[index] !== name)\n}\n\n/**\n * Keep keyboard focus on a column manager move button after a move: once the list has\n * re-rendered, refocus it, or the other move button when it became disabled at an edge.\n */\nexport function keepMoveButtonFocus(button: HTMLElement | null | undefined): void {\n if (!button || typeof document === 'undefined' || document.activeElement !== button) return\n\n const controls = button.parentElement\n const schedule =\n typeof requestAnimationFrame === 'function'\n ? requestAnimationFrame\n : (callback: () => void) => setTimeout(callback, 0)\n\n schedule(() => {\n const active = document.activeElement\n\n if (active !== button && active !== document.body && active !== null) return\n\n if (button.isConnected && !(button as HTMLButtonElement).disabled) {\n button.focus()\n\n return\n }\n\n controls?.querySelector<HTMLElement>('button:not(:disabled)')?.focus()\n })\n}\n\n/**\n * Store the user's column order on the server (per user, in the session), then reload the\n * table so it renders in the new order. `reload: false` when a table visit follows (Reset,\n * Apply with visibility changes): that visit renders the new order, and a reload of the\n * current URL running alongside it could finish last and bring the old columns back.\n */\nexport async function saveColumnOrder(\n endpoint: string,\n token: string,\n component: string,\n columns: string[],\n options: { reload?: boolean } = {},\n): Promise<string[]> {\n const response = await requestJson<{ columns: string[] }>(endpoint, {\n method: 'POST',\n body: { token, component, columns },\n })\n\n if (options.reload ?? true) inertiaReload({ only: ['page'] })\n\n return response.columns\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"table-layout.js","names":[],"sources":["../src/table-layout.ts"],"sourcesContent":["import { inertiaReload, requestJson } from './http'\nimport type { Alignment } from './schema/common'\nimport type {\n AnyPaginationSchema,\n BaseColumnSchema,\n Breakpoint,\n ColumnGroupSchema,\n ColumnLayoutNode,\n ColumnSchema,\n SplitLayoutSchema,\n StackLayoutSchema,\n TableSchema,\n} from './schema/table'\nimport type { TableQuery } from './table'\n\n/**\n * One cell of the column-group header row: a group spanning `span` adjacent visible\n * columns, or (without `group`) an ungrouped column whose header spans both rows.\n */\nexport interface ColumnGroupHeaderCell {\n key: string\n span: number\n group?: ColumnGroupSchema\n column?: ColumnSchema\n}\n\n/**\n * The extra header row for `ColumnGroup`s. Adjacent visible columns of the same group\n * share one header; a group split by a reordered column gets one header per run.\n * Returns null when the table has no groups.\n */\nexport function columnGroupHeaderRow(\n columns: ColumnSchema[],\n groups: ColumnGroupSchema[] | undefined,\n): ColumnGroupHeaderCell[] | null {\n if (!groups || groups.length === 0) {\n return null\n }\n\n const groupOf = new Map<string, ColumnGroupSchema>()\n\n for (const group of groups) {\n for (const name of group.columns) {\n groupOf.set(name, group)\n }\n }\n\n const cells: ColumnGroupHeaderCell[] = []\n\n for (const column of columns) {\n const group = groupOf.get(column.name)\n const previous = cells[cells.length - 1]\n\n if (group && previous?.group === group) {\n previous.span += 1\n } else if (group) {\n cells.push({ key: `group:${group.label}:${column.name}`, span: 1, group })\n } else {\n cells.push({ key: `column:${column.name}`, span: 1, column })\n }\n }\n\n return cells\n}\n\n/** Whether a column sits under a group header (so its own header is in the second row). */\nexport function isGroupedColumn(name: string, groups: ColumnGroupSchema[] | undefined): boolean {\n return Boolean(groups?.some((group) => group.columns.includes(name)))\n}\n\n/** Column names referenced anywhere in a content layout, in order. */\nexport function layoutColumnNames(nodes: ColumnLayoutNode[] | undefined): string[] {\n const names: string[] = []\n\n for (const node of nodes ?? []) {\n if (node.type === 'Column') {\n names.push(node.name)\n } else {\n names.push(...layoutColumnNames(node.schema))\n }\n }\n\n return names\n}\n\n/**\n * `Split::from()` follows the width of the record (its `@container`), not the viewport, at\n * the sizes of `RECORD_CONTAINER_FROM`: in a narrow card a badge goes under the text\n * instead of squeezing it.\n */\nconst SPLIT_FROM: Record<Breakpoint | 'default', string> = {\n default: 'flex-row items-center',\n sm: 'flex-col @3xs:flex-row @3xs:items-center',\n md: 'flex-col @xs:flex-row @xs:items-center',\n lg: 'flex-col @md:flex-row @md:items-center',\n xl: 'flex-col @xl:flex-row @xl:items-center',\n '2xl': 'flex-col @3xl:flex-row @3xl:items-center',\n}\n\n/**\n * Classes of a `Split`: side by side once the record is wide enough for its `from`\n * breakpoint, stacked below it. Needs the record's `@container` (`data-slot=\"table-record\"`).\n */\nexport function splitClasses(layout: Pick<SplitLayoutSchema, 'from'>): string {\n return `flex gap-3 ${SPLIT_FROM[layout.from ?? 'default']}`\n}\n\nconst VISIBLE_FROM: Record<Breakpoint, string> = {\n sm: 'hidden sm:flex',\n md: 'hidden md:flex',\n lg: 'hidden lg:flex',\n xl: 'hidden xl:flex',\n '2xl': 'hidden 2xl:flex',\n}\n\nconst HIDDEN_FROM: Record<Breakpoint, string> = {\n sm: 'sm:hidden',\n md: 'md:hidden',\n lg: 'lg:hidden',\n xl: 'xl:hidden',\n '2xl': '2xl:hidden',\n}\n\n/** Responsive visibility classes for `visibleFrom()` / `hiddenFrom()`. */\nexport function layoutVisibilityClasses(layout: {\n visibleFrom?: Breakpoint\n hiddenFrom?: Breakpoint\n}): string {\n return [\n layout.visibleFrom ? VISIBLE_FROM[layout.visibleFrom] : '',\n layout.hiddenFrom ? HIDDEN_FROM[layout.hiddenFrom] : '',\n ]\n .filter(Boolean)\n .join(' ')\n}\n\nconst VISIBLE_FROM_CELL: Record<Breakpoint, string> = {\n sm: 'hidden sm:table-cell',\n md: 'hidden md:table-cell',\n lg: 'hidden lg:table-cell',\n xl: 'hidden xl:table-cell',\n '2xl': 'hidden 2xl:table-cell',\n}\n\nconst VISIBLE_FROM_BLOCK: Record<Breakpoint, string> = {\n sm: 'hidden sm:block',\n md: 'hidden md:block',\n lg: 'hidden lg:block',\n xl: 'hidden xl:block',\n '2xl': 'hidden 2xl:block',\n}\n\n/**\n * Responsive visibility classes for a column's `visibleFrom()` / `hiddenFrom()`: for its\n * header and cells in a table (`table-cell`), or its block in a content layout.\n */\nexport function columnVisibilityClasses(\n column: Pick<BaseColumnSchema, 'visibleFrom' | 'hiddenFrom'>,\n display: 'table-cell' | 'block' = 'table-cell',\n): string {\n const visible = display === 'block' ? VISIBLE_FROM_BLOCK : VISIBLE_FROM_CELL\n\n return [\n column.visibleFrom ? visible[column.visibleFrom] : '',\n column.hiddenFrom ? HIDDEN_FROM[column.hiddenFrom] : '',\n ]\n .filter(Boolean)\n .join(' ')\n}\n\nconst STACK_SPACE: Record<number, string> = { 1: 'gap-1', 2: 'gap-2', 3: 'gap-3' }\n\nconst STACK_ALIGN: Partial<Record<Alignment, string>> = {\n start: 'items-start text-start',\n center: 'items-center text-center',\n end: 'items-end text-end',\n}\n\n/** Classes of a `Stack`: a vertical flex column with its gap and alignment. */\nexport function stackClasses(layout: Pick<StackLayoutSchema, 'space' | 'alignment'>): string {\n return [\n 'flex flex-col',\n STACK_SPACE[layout.space ?? 0] ?? 'gap-0.5',\n layout.alignment ? STACK_ALIGN[layout.alignment] : '',\n ]\n .filter(Boolean)\n .join(' ')\n}\n\n/** Inside a `Split`, whether a node takes the remaining width. */\nexport function layoutNodeGrows(node: ColumnLayoutNode, columns: ColumnSchema[]): boolean {\n if (node.type === 'Column') {\n return columns.find((column) => column.name === node.name)?.grow !== false\n }\n\n return node.grow !== false\n}\n\n/** Record actions placed at the start of the row (before or after the checkbox). */\nexport function recordActionsAtStart(position: TableSchema['recordActionsPosition']): boolean {\n return position === 'before-cells' || position === 'before-columns'\n}\n\n/** The total record count, when the pagination mode knows it. */\nexport function paginationTotal(pagination: AnyPaginationSchema | null | undefined): number | null {\n if (!pagination || ('mode' in pagination && pagination.mode && pagination.mode !== 'default')) {\n return null\n }\n\n return 'total' in pagination ? pagination.total : null\n}\n\n/** Load more and infinite scroll keep earlier pages and append the next one. */\nexport function isAppendingPagination(\n pagination: AnyPaginationSchema | null | undefined,\n): pagination is Extract<AnyPaginationSchema, { mode: 'load-more' | 'infinite' }> {\n return pagination?.mode === 'load-more' || pagination?.mode === 'infinite'\n}\n\n/**\n * The table query for the next page of a simple, cursor or appending paginator, or null\n * on the last page.\n */\nexport function nextPageQuery(\n pagination: AnyPaginationSchema | null | undefined,\n): TableQuery | null {\n if (!pagination) return null\n\n switch (pagination.mode) {\n case 'cursor':\n return pagination.hasMorePages && pagination.nextCursor\n ? { cursor: pagination.nextCursor }\n : null\n case 'simple':\n case 'load-more':\n case 'infinite':\n return pagination.hasMorePages ? { page: pagination.currentPage + 1 } : null\n default:\n return pagination.currentPage < pagination.lastPage\n ? { page: pagination.currentPage + 1 }\n : null\n }\n}\n\n/** The table query for the previous page, or null on the first page. */\nexport function previousPageQuery(\n pagination: AnyPaginationSchema | null | undefined,\n): TableQuery | null {\n if (!pagination || isAppendingPagination(pagination)) return null\n\n if (pagination.mode === 'cursor') {\n return pagination.previousCursor ? { cursor: pagination.previousCursor } : null\n }\n\n return pagination.currentPage > 1 ? { page: pagination.currentPage - 1 } : null\n}\n\n/** Move a column one step in the user's column order. */\nexport function moveColumn(names: readonly string[], name: string, offset: -1 | 1): string[] {\n const from = names.indexOf(name)\n const to = from + offset\n\n if (from < 0 || to < 0 || to >= names.length) {\n return [...names]\n }\n\n const next = [...names]\n const [moved] = next.splice(from, 1)\n\n if (moved !== undefined) next.splice(to, 0, moved)\n\n return next\n}\n\n/** Drop a dragged column onto another: it takes the target's position in the order. */\nexport function moveColumnTo(names: readonly string[], name: string, target: string): string[] {\n const from = names.indexOf(name)\n const to = names.indexOf(target)\n\n if (from < 0 || to < 0 || from === to) {\n return [...names]\n }\n\n const next = [...names]\n const [moved] = next.splice(from, 1)\n\n if (moved !== undefined) next.splice(to, 0, moved)\n\n return next\n}\n\n/**\n * Where a column sits in the column manager, for screen readers: inside a column group\n * it counts among the group's columns (`group` is its label); otherwise among the\n * top-level items, where a column group counts as one item.\n */\nexport interface ColumnManagerPosition {\n position: number\n count: number\n group?: string\n}\n\n/** The column group (of `columnGroups`) a column belongs to. */\nfunction columnGroupOf(\n name: string,\n groups: readonly ColumnGroupSchema[] | undefined,\n): ColumnGroupSchema | undefined {\n return groups?.find((group) => group.columns.includes(name))\n}\n\n/**\n * The top-level items of a column order: an ungrouped column, or the contiguous columns\n * of one column group.\n */\nfunction columnManagerItems(\n order: readonly string[],\n groups: readonly ColumnGroupSchema[] | undefined,\n): string[][] {\n const items: string[][] = []\n let current: ColumnGroupSchema | undefined\n\n for (const name of order) {\n const group = columnGroupOf(name, groups)\n const last = items[items.length - 1]\n\n if (group && group === current && last) {\n last.push(name)\n } else {\n items.push([name])\n }\n\n current = group\n }\n\n return items\n}\n\nexport function columnManagerPosition(\n order: readonly string[],\n name: string,\n groups?: readonly ColumnGroupSchema[],\n): ColumnManagerPosition {\n const group = columnGroupOf(name, groups)\n\n if (group) {\n const siblings = order.filter((column) => group.columns.includes(column))\n\n return { position: siblings.indexOf(name) + 1, count: siblings.length, group: group.label }\n }\n\n const items = columnManagerItems(order, groups)\n\n return {\n position: items.findIndex((item) => item.includes(name)) + 1,\n count: items.length,\n }\n}\n\n/**\n * Move a column one step in the column manager: a grouped column swaps with its\n * neighbour in the same group; an ungrouped column moves past the neighbouring item\n * (a whole column group), so groups stay together. Returns the order unchanged at an edge.\n */\nexport function moveColumnInManager(\n order: readonly string[],\n name: string,\n offset: -1 | 1,\n groups?: readonly ColumnGroupSchema[],\n): string[] {\n const group = columnGroupOf(name, groups)\n\n if (group) {\n const siblings = order.filter((column) => group.columns.includes(column))\n const neighbour = siblings[siblings.indexOf(name) + offset]\n\n if (neighbour === undefined) return [...order]\n\n const next = [...order]\n next[order.indexOf(name)] = neighbour\n next[order.indexOf(neighbour)] = name\n\n return next\n }\n\n const items = columnManagerItems(order, groups)\n const index = items.findIndex((item) => item.includes(name))\n const target = index + offset\n\n if (index < 0 || target < 0 || target >= items.length) return [...order]\n\n const next = [...items]\n const [moved] = next.splice(index, 1)\n\n if (moved !== undefined) next.splice(target, 0, moved)\n\n return next.flat()\n}\n\n/** The columns in a (draft) column order; columns missing from it keep their place at the end. */\nexport function orderColumnsBy<T extends { name: string }>(\n columns: readonly T[],\n order: readonly string[] | null | undefined,\n): T[] {\n if (!order) return [...columns]\n\n const rank = (name: string) => {\n const index = order.indexOf(name)\n\n return index < 0 ? order.length : index\n }\n\n return [...columns].sort((a, b) => rank(a.name) - rank(b.name))\n}\n\n/** Whether a draft column order differs from the applied one. */\nexport function columnOrderChanged(applied: readonly string[], draft: readonly string[]): boolean {\n return applied.length !== draft.length || applied.some((name, index) => draft[index] !== name)\n}\n\n/**\n * Keep keyboard focus on a column manager move button after a move: once the list has\n * re-rendered, refocus it, or the other move button when it became disabled at an edge.\n */\nexport function keepMoveButtonFocus(button: HTMLElement | null | undefined): void {\n if (!button || typeof document === 'undefined' || document.activeElement !== button) return\n\n const controls = button.parentElement\n const schedule =\n typeof requestAnimationFrame === 'function'\n ? requestAnimationFrame\n : (callback: () => void) => setTimeout(callback, 0)\n\n schedule(() => {\n const active = document.activeElement\n\n if (active !== button && active !== document.body && active !== null) return\n\n if (button.isConnected && !(button as HTMLButtonElement).disabled) {\n button.focus()\n\n return\n }\n\n controls?.querySelector<HTMLElement>('button:not(:disabled)')?.focus()\n })\n}\n\n/**\n * Store the user's column order on the server (per user, in the session), then reload the\n * table so it renders in the new order. `reload: false` when a table visit follows (Reset,\n * Apply with visibility changes): that visit renders the new order, and a reload of the\n * current URL running alongside it could finish last and bring the old columns back.\n */\nexport async function saveColumnOrder(\n endpoint: string,\n token: string,\n component: string,\n columns: string[],\n options: { reload?: boolean } = {},\n): Promise<string[]> {\n const response = await requestJson<{ columns: string[] }>(endpoint, {\n method: 'POST',\n body: { token, component, columns },\n })\n\n if (options.reload ?? true) inertiaReload({ only: ['page'] })\n\n return response.columns\n}\n"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ //#region src/topbar.d.ts
2
+ /**
3
+ * Classes for the `topbar.end` slot box in every renderer's top bar (sidebar, top
4
+ * navigation and fullscreen layouts). Items apps add there get a box of their own that
5
+ * shrinks, and clips, before the bar's buttons do, so they can't push the bar wider than
6
+ * the screen. The negative margin with matching padding keeps their focus rings visible.
7
+ */
8
+ export declare const TOPBAR_END_SLOT_CLASS = "-m-1 flex min-w-0 items-center gap-1 overflow-hidden p-1";
9
+ //#endregion
10
+ //# sourceMappingURL=topbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topbar.d.ts","names":[],"sources":["../src/topbar.ts"],"mappings":";;;;;;;qBAMa"}
package/dist/topbar.js ADDED
@@ -0,0 +1,12 @@
1
+ //#region src/topbar.ts
2
+ /**
3
+ * Classes for the `topbar.end` slot box in every renderer's top bar (sidebar, top
4
+ * navigation and fullscreen layouts). Items apps add there get a box of their own that
5
+ * shrinks, and clips, before the bar's buttons do, so they can't push the bar wider than
6
+ * the screen. The negative margin with matching padding keeps their focus rings visible.
7
+ */
8
+ const TOPBAR_END_SLOT_CLASS = "-m-1 flex min-w-0 items-center gap-1 overflow-hidden p-1";
9
+ //#endregion
10
+ export { TOPBAR_END_SLOT_CLASS };
11
+
12
+ //# sourceMappingURL=topbar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topbar.js","names":[],"sources":["../src/topbar.ts"],"sourcesContent":["/**\n * Classes for the `topbar.end` slot box in every renderer's top bar (sidebar, top\n * navigation and fullscreen layouts). Items apps add there get a box of their own that\n * shrinks, and clips, before the bar's buttons do, so they can't push the bar wider than\n * the screen. The negative margin with matching padding keeps their focus rings visible.\n */\nexport const TOPBAR_END_SLOT_CLASS = '-m-1 flex min-w-0 items-center gap-1 overflow-hidden p-1'\n"],"mappings":";;;;;;;AAMA,MAAa,wBAAwB"}
@@ -12,6 +12,30 @@ export declare function hasContainerBreakpoints(map: Breakpoints<unknown> | unde
12
12
  export declare function containerGridColumnsClasses(columns: Breakpoints | undefined): string;
13
13
  /** `@md:col-span-2`-style classes for the container keys of a `columnSpan` map. */
14
14
  export declare function containerColumnSpanClasses(span: Breakpoints<ColumnSpanValue> | undefined): string;
15
+ /**
16
+ * Classes for a table's `contentGrid()`: one column, then `@…:grid-cols-N` container-query
17
+ * classes relative to the `@container` around the card grid. A column count applies from
18
+ * the wider of its key's size (`CONTENT_GRID_FROM`) and the size that fits that many cards
19
+ * (`CONTENT_GRID_MIN`), so cards get fewer columns instead of getting narrow. Container
20
+ * keys (`'@lg' => 2`) are used as given; when two keys land on the same size, the later
21
+ * (wider) key wins.
22
+ */
23
+ export declare function contentGridClasses(grid: Breakpoints | undefined | null): string;
24
+ /**
25
+ * Layout breakpoints inside a table record (`Split::from()`, a `Grid`'s `columns` and the
26
+ * `columnSpan()` / `columnStart()` of its children) are read against the width of the
27
+ * record (its `@container`) rather than the viewport: a card in a `contentGrid()` can be
28
+ * 15rem wide on a wide screen. Each viewport key maps to a card-sized width, so
29
+ * `Split::from('md')` puts its parts side by side once the record has 20rem (320px).
30
+ */
31
+ export declare const RECORD_CONTAINER_FROM: Readonly<Record<string, ContainerBreakpoint>>;
32
+ /** A `Grid` layout's `columns` inside a table record (sizes of `RECORD_CONTAINER_FROM`). */
33
+ export declare function recordGridColumnsClasses(columns: Breakpoints | undefined | null): string;
34
+ /**
35
+ * `columnSpan()` / `columnStart()` of a node inside a table record's `Grid` (sizes of
36
+ * `RECORD_CONTAINER_FROM`).
37
+ */
38
+ export declare function recordColumnSpanClasses(span: Breakpoints<ColumnSpanValue> | undefined | null, start?: Breakpoints<number | string | null> | undefined | null): string;
15
39
  /**
16
40
  * Classes for a `Flex` schema component: stacked, then a row (and the vertical alignment)
17
41
  * from its `from` breakpoint. Force-generated with `@source inline(...)` in each renderer.
@@ -1 +1 @@
1
- {"version":3,"file":"container-breakpoints.d.ts","names":[],"sources":["../../src/utils/container-breakpoints.ts"],"mappings":";;;;;;;qBAOa,gCAAgC;;wBAkC7B,wBAAwB,KAAK;;wBAK7B,4BAA4B,SAAS;;wBAarC,2BAA2B,MAAM,YAAY;;;;;wBA6D7C,kBAAkB;EAChC;EACA;EACA;;;wBAYc,gBAAgB;EAAa"}
1
+ {"version":3,"file":"container-breakpoints.d.ts","names":[],"sources":["../../src/utils/container-breakpoints.ts"],"mappings":";;;;;;;qBAOa,gCAAgC;;wBAkC7B,wBAAwB,KAAK;;wBAK7B,4BAA4B,SAAS;;wBAarC,2BAA2B,MAAM,YAAY;;;;;;;;;wBA2D7C,mBAAmB,MAAM;;;;;;;;qBAsC5B,uBAAuB,SAAS,eAAe;;wBAoD5C,yBAAyB,SAAS;;;;;wBAUlC,wBACd,MAAM,YAAY,qCAClB,QAAQ;;;;;wBAyDM,kBAAkB;EAChC;EACA;EACA;;;wBAYc,gBAAgB;EAAa"}
@@ -58,6 +58,127 @@ function containerColumnSpanClasses(span) {
58
58
  return value ? CONTAINER_COL_SPAN[breakpoint]?.[String(value)] : void 0;
59
59
  }).filter(Boolean).join(" ");
60
60
  }
61
+ /**
62
+ * `contentGrid()` breakpoints, read against the width of the table rather than the
63
+ * viewport: the table sits beside the panel sidebar (and a cluster's sub-navigation), so a
64
+ * viewport breakpoint says little about the room the cards have. Each viewport key maps to
65
+ * the largest container size at or below that viewport minus 24rem (a 16rem sidebar plus
66
+ * the page's gutters): `md` 48rem → `@sm` 24rem, `xl` 80rem → `@4xl` 56rem.
67
+ */
68
+ const CONTENT_GRID_FROM = {
69
+ default: null,
70
+ sm: "@3xs",
71
+ md: "@sm",
72
+ lg: "@xl",
73
+ xl: "@4xl",
74
+ "2xl": "@6xl"
75
+ };
76
+ /**
77
+ * The smallest container size that keeps `n` cards at least 15rem wide, with the grid's
78
+ * `p-4` and `gap-4`: 16rem per column plus 1rem. Five or more columns need `@7xl` (80rem).
79
+ */
80
+ const CONTENT_GRID_MIN = {
81
+ 1: null,
82
+ 2: "@xl",
83
+ 3: "@4xl",
84
+ 4: "@6xl"
85
+ };
86
+ const CONTENT_GRID_KEYS = [
87
+ "default",
88
+ "sm",
89
+ "md",
90
+ "lg",
91
+ "xl",
92
+ "2xl"
93
+ ];
94
+ function widerBreakpoint(a, b) {
95
+ if (!a) return b;
96
+ if (!b) return a;
97
+ return CONTAINER_BREAKPOINTS.indexOf(a) >= CONTAINER_BREAKPOINTS.indexOf(b) ? a : b;
98
+ }
99
+ /**
100
+ * Classes for a table's `contentGrid()`: one column, then `@…:grid-cols-N` container-query
101
+ * classes relative to the `@container` around the card grid. A column count applies from
102
+ * the wider of its key's size (`CONTENT_GRID_FROM`) and the size that fits that many cards
103
+ * (`CONTENT_GRID_MIN`), so cards get fewer columns instead of getting narrow. Container
104
+ * keys (`'@lg' => 2`) are used as given; when two keys land on the same size, the later
105
+ * (wider) key wins.
106
+ */
107
+ function contentGridClasses(grid) {
108
+ const classes = /* @__PURE__ */ new Map();
109
+ for (const key of CONTENT_GRID_KEYS) {
110
+ const value = grid?.[key];
111
+ if (!value) continue;
112
+ const count = Math.min(Math.max(Math.trunc(value), 1), 12);
113
+ const at = widerBreakpoint(CONTENT_GRID_FROM[key] ?? null, CONTENT_GRID_MIN[count] ?? "@7xl");
114
+ const cls = at ? CONTAINER_GRID_COLS[at]?.[String(count)] : void 0;
115
+ if (at && cls) classes.set(at, cls);
116
+ }
117
+ for (const breakpoint of CONTAINER_BREAKPOINTS) {
118
+ const cls = CONTAINER_GRID_COLS[breakpoint]?.[String(grid?.[breakpoint] ?? "")];
119
+ if (cls) classes.set(breakpoint, cls);
120
+ }
121
+ return ["grid-cols-1", ...CONTAINER_BREAKPOINTS.map((breakpoint) => classes.get(breakpoint)).filter(Boolean)].join(" ");
122
+ }
123
+ const CONTAINER_COL_START = Object.fromEntries(CONTAINER_BREAKPOINTS.map((breakpoint) => [breakpoint, table(`${breakpoint}:col-start-`, SPANS)]));
124
+ /**
125
+ * Layout breakpoints inside a table record (`Split::from()`, a `Grid`'s `columns` and the
126
+ * `columnSpan()` / `columnStart()` of its children) are read against the width of the
127
+ * record (its `@container`) rather than the viewport: a card in a `contentGrid()` can be
128
+ * 15rem wide on a wide screen. Each viewport key maps to a card-sized width, so
129
+ * `Split::from('md')` puts its parts side by side once the record has 20rem (320px).
130
+ */
131
+ const RECORD_CONTAINER_FROM = {
132
+ sm: "@3xs",
133
+ md: "@xs",
134
+ lg: "@md",
135
+ xl: "@xl",
136
+ "2xl": "@3xl"
137
+ };
138
+ const RECORD_KEYS = [
139
+ "sm",
140
+ "md",
141
+ "lg",
142
+ "xl",
143
+ "2xl"
144
+ ];
145
+ /**
146
+ * Classes for a responsive map inside a table record: `default` as is, viewport keys at
147
+ * their `RECORD_CONTAINER_FROM` size and container keys (`'@md' => 2`) as given; when two
148
+ * keys land on the same size, the container key wins.
149
+ */
150
+ function recordClasses(map, base, containers) {
151
+ if (!map) return [];
152
+ const classes = /* @__PURE__ */ new Map();
153
+ for (const key of RECORD_KEYS) {
154
+ const value = map[key];
155
+ const at = RECORD_CONTAINER_FROM[key];
156
+ const cls = value && at ? containers[at]?.[String(value)] : void 0;
157
+ if (at && cls) classes.set(at, cls);
158
+ }
159
+ for (const breakpoint of CONTAINER_BREAKPOINTS) {
160
+ const value = map[breakpoint];
161
+ const cls = value ? containers[breakpoint]?.[String(value)] : void 0;
162
+ if (cls) classes.set(breakpoint, cls);
163
+ }
164
+ const value = map.default;
165
+ return [value ? base[String(value)] : void 0, ...CONTAINER_BREAKPOINTS.map((breakpoint) => classes.get(breakpoint))].filter((cls) => Boolean(cls));
166
+ }
167
+ const GRID_COLS = table("grid-cols-", SPANS);
168
+ const COL_SPAN = table("col-span-", [...SPANS, "full"]);
169
+ const COL_START = table("col-start-", SPANS);
170
+ /** A `Grid` layout's `columns` inside a table record (sizes of `RECORD_CONTAINER_FROM`). */
171
+ function recordGridColumnsClasses(columns) {
172
+ const classes = recordClasses(columns, GRID_COLS, CONTAINER_GRID_COLS);
173
+ return (columns?.default ? classes : ["grid-cols-1", ...classes]).join(" ");
174
+ }
175
+ /**
176
+ * `columnSpan()` / `columnStart()` of a node inside a table record's `Grid` (sizes of
177
+ * `RECORD_CONTAINER_FROM`).
178
+ */
179
+ function recordColumnSpanClasses(span, start) {
180
+ return [...recordClasses(span, COL_SPAN, CONTAINER_COL_SPAN), ...recordClasses(start, COL_START, CONTAINER_COL_START)].join(" ");
181
+ }
61
182
  const FLEX_ROW = {
62
183
  default: "flex-row",
63
184
  sm: "sm:flex-row",
@@ -120,6 +241,6 @@ function flexItemClasses(component) {
120
241
  return component.grow === false ? "min-w-0 shrink-0" : "min-w-0 flex-1";
121
242
  }
122
243
  //#endregion
123
- export { CONTAINER_BREAKPOINTS, containerColumnSpanClasses, containerGridColumnsClasses, flexItemClasses, flexLayoutClasses, hasContainerBreakpoints };
244
+ export { CONTAINER_BREAKPOINTS, RECORD_CONTAINER_FROM, containerColumnSpanClasses, containerGridColumnsClasses, contentGridClasses, flexItemClasses, flexLayoutClasses, hasContainerBreakpoints, recordColumnSpanClasses, recordGridColumnsClasses };
124
245
 
125
246
  //# sourceMappingURL=container-breakpoints.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"container-breakpoints.js","names":[],"sources":["../../src/utils/container-breakpoints.ts"],"sourcesContent":["import type { Breakpoints, ColumnSpanValue, ContainerBreakpoint } from '../schema/common'\n\n/**\n * Container-query variants of the grid classes: a `columns` map with `@md`-style keys\n * follows the width of the surrounding `@container` instead of the viewport. Classes are\n * spelled out in full so Tailwind's scanner (and `@source inline`) can see them.\n */\nexport const CONTAINER_BREAKPOINTS: readonly ContainerBreakpoint[] = [\n '@3xs',\n '@2xs',\n '@xs',\n '@sm',\n '@md',\n '@lg',\n '@xl',\n '@2xl',\n '@3xl',\n '@4xl',\n '@5xl',\n '@6xl',\n '@7xl',\n]\n\nconst SPANS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] as const\n\nfunction table(prefix: string, values: readonly (number | string)[]): Record<string, string> {\n return Object.fromEntries(values.map((value) => [String(value), `${prefix}${value}`]))\n}\n\nconst CONTAINER_GRID_COLS: Record<string, Record<string, string>> = Object.fromEntries(\n CONTAINER_BREAKPOINTS.map((breakpoint) => [breakpoint, table(`${breakpoint}:grid-cols-`, SPANS)]),\n)\n\nconst CONTAINER_COL_SPAN: Record<string, Record<string, string>> = Object.fromEntries(\n CONTAINER_BREAKPOINTS.map((breakpoint) => [\n breakpoint,\n table(`${breakpoint}:col-span-`, [...SPANS, 'full']),\n ]),\n)\n\n/** Whether a responsive map uses container sizes (`@md`) and so needs an `@container` parent. */\nexport function hasContainerBreakpoints(map: Breakpoints<unknown> | undefined | null): boolean {\n return !!map && Object.keys(map).some((key) => key.startsWith('@'))\n}\n\n/** `@md:grid-cols-3`-style classes for the container keys of a `columns` map. */\nexport function containerGridColumnsClasses(columns: Breakpoints | undefined): string {\n if (!columns) return ''\n\n return CONTAINER_BREAKPOINTS.map((breakpoint) => {\n const value = columns[breakpoint]\n\n return value ? CONTAINER_GRID_COLS[breakpoint]?.[String(value)] : undefined\n })\n .filter(Boolean)\n .join(' ')\n}\n\n/** `@md:col-span-2`-style classes for the container keys of a `columnSpan` map. */\nexport function containerColumnSpanClasses(span: Breakpoints<ColumnSpanValue> | undefined): string {\n if (!span) return ''\n\n return CONTAINER_BREAKPOINTS.map((breakpoint) => {\n const value = span[breakpoint]\n\n return value ? CONTAINER_COL_SPAN[breakpoint]?.[String(value)] : undefined\n })\n .filter(Boolean)\n .join(' ')\n}\n\nconst FLEX_ROW: Record<string, string> = {\n default: 'flex-row',\n sm: 'sm:flex-row',\n md: 'md:flex-row',\n lg: 'lg:flex-row',\n xl: 'xl:flex-row',\n '2xl': '2xl:flex-row',\n}\n\n/** `Flex::alignment()`: main-axis alignment (logical, so `start` follows the direction). */\nconst FLEX_JUSTIFY: Record<string, string> = {\n start: 'justify-start',\n center: 'justify-center',\n end: 'justify-end',\n between: 'justify-between',\n justify: 'justify-between',\n}\n\nconst FLEX_ALIGN: Record<string, Record<string, string>> = {\n start: {\n default: 'items-start',\n sm: 'sm:items-start',\n md: 'md:items-start',\n lg: 'lg:items-start',\n xl: 'xl:items-start',\n '2xl': '2xl:items-start',\n },\n center: {\n default: 'items-center',\n sm: 'sm:items-center',\n md: 'md:items-center',\n lg: 'lg:items-center',\n xl: 'xl:items-center',\n '2xl': '2xl:items-center',\n },\n end: {\n default: 'items-end',\n sm: 'sm:items-end',\n md: 'md:items-end',\n lg: 'lg:items-end',\n xl: 'xl:items-end',\n '2xl': '2xl:items-end',\n },\n}\n\n/**\n * Classes for a `Flex` schema component: stacked, then a row (and the vertical alignment)\n * from its `from` breakpoint. Force-generated with `@source inline(...)` in each renderer.\n */\nexport function flexLayoutClasses(flex: {\n from?: string | null\n verticalAlignment?: string | null\n alignment?: string | null\n}): string {\n const from = flex.from ?? 'default'\n const align = flex.verticalAlignment ? FLEX_ALIGN[flex.verticalAlignment]?.[from] : undefined\n const justify = flex.alignment ? FLEX_JUSTIFY[flex.alignment] : undefined\n\n return ['flex flex-col gap-6', FLEX_ROW[from] ?? 'flex-row', align, justify]\n .filter(Boolean)\n .join(' ')\n}\n\n/** Width behaviour of a child inside a `Flex`: share the row, or keep its natural width. */\nexport function flexItemClasses(component: { grow?: boolean }): string {\n return component.grow === false ? 'min-w-0 shrink-0' : 'min-w-0 flex-1'\n}\n"],"mappings":";;;;;;AAOA,MAAa,wBAAwD;CACnE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,QAAQ;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAI;CAAI;AAAE;AAEpD,SAAS,MAAM,QAAgB,QAA8D;CAC3F,OAAO,OAAO,YAAY,OAAO,KAAK,UAAU,CAAC,OAAO,KAAK,GAAG,GAAG,SAAS,OAAO,CAAC,CAAC;AACvF;AAEA,MAAM,sBAA8D,OAAO,YACzE,sBAAsB,KAAK,eAAe,CAAC,YAAY,MAAM,GAAG,WAAW,cAAc,KAAK,CAAC,CAAC,CAClG;AAEA,MAAM,qBAA6D,OAAO,YACxE,sBAAsB,KAAK,eAAe,CACxC,YACA,MAAM,GAAG,WAAW,aAAa,CAAC,GAAG,OAAO,MAAM,CAAC,CACrD,CAAC,CACH;;AAGA,SAAgB,wBAAwB,KAAuD;CAC7F,OAAO,CAAC,CAAC,OAAO,OAAO,KAAK,GAAG,CAAC,CAAC,MAAM,QAAQ,IAAI,WAAW,GAAG,CAAC;AACpE;;AAGA,SAAgB,4BAA4B,SAA0C;CACpF,IAAI,CAAC,SAAS,OAAO;CAErB,OAAO,sBAAsB,KAAK,eAAe;EAC/C,MAAM,QAAQ,QAAQ;EAEtB,OAAO,QAAQ,oBAAoB,WAAW,GAAG,OAAO,KAAK,KAAK,KAAA;CACpE,CAAC,CAAC,CACC,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;AACb;;AAGA,SAAgB,2BAA2B,MAAwD;CACjG,IAAI,CAAC,MAAM,OAAO;CAElB,OAAO,sBAAsB,KAAK,eAAe;EAC/C,MAAM,QAAQ,KAAK;EAEnB,OAAO,QAAQ,mBAAmB,WAAW,GAAG,OAAO,KAAK,KAAK,KAAA;CACnE,CAAC,CAAC,CACC,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;AACb;AAEA,MAAM,WAAmC;CACvC,SAAS;CACT,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,OAAO;AACT;;AAGA,MAAM,eAAuC;CAC3C,OAAO;CACP,QAAQ;CACR,KAAK;CACL,SAAS;CACT,SAAS;AACX;AAEA,MAAM,aAAqD;CACzD,OAAO;EACL,SAAS;EACT,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,OAAO;CACT;CACA,QAAQ;EACN,SAAS;EACT,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,OAAO;CACT;CACA,KAAK;EACH,SAAS;EACT,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,OAAO;CACT;AACF;;;;;AAMA,SAAgB,kBAAkB,MAIvB;CACT,MAAM,OAAO,KAAK,QAAQ;CAC1B,MAAM,QAAQ,KAAK,oBAAoB,WAAW,KAAK,kBAAkB,GAAG,QAAQ,KAAA;CACpF,MAAM,UAAU,KAAK,YAAY,aAAa,KAAK,aAAa,KAAA;CAEhE,OAAO;EAAC;EAAuB,SAAS,SAAS;EAAY;EAAO;CAAO,CAAC,CACzE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;AACb;;AAGA,SAAgB,gBAAgB,WAAuC;CACrE,OAAO,UAAU,SAAS,QAAQ,qBAAqB;AACzD"}
1
+ {"version":3,"file":"container-breakpoints.js","names":[],"sources":["../../src/utils/container-breakpoints.ts"],"sourcesContent":["import type { Breakpoints, ColumnSpanValue, ContainerBreakpoint } from '../schema/common'\n\n/**\n * Container-query variants of the grid classes: a `columns` map with `@md`-style keys\n * follows the width of the surrounding `@container` instead of the viewport. Classes are\n * spelled out in full so Tailwind's scanner (and `@source inline`) can see them.\n */\nexport const CONTAINER_BREAKPOINTS: readonly ContainerBreakpoint[] = [\n '@3xs',\n '@2xs',\n '@xs',\n '@sm',\n '@md',\n '@lg',\n '@xl',\n '@2xl',\n '@3xl',\n '@4xl',\n '@5xl',\n '@6xl',\n '@7xl',\n]\n\nconst SPANS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] as const\n\nfunction table(prefix: string, values: readonly (number | string)[]): Record<string, string> {\n return Object.fromEntries(values.map((value) => [String(value), `${prefix}${value}`]))\n}\n\nconst CONTAINER_GRID_COLS: Record<string, Record<string, string>> = Object.fromEntries(\n CONTAINER_BREAKPOINTS.map((breakpoint) => [breakpoint, table(`${breakpoint}:grid-cols-`, SPANS)]),\n)\n\nconst CONTAINER_COL_SPAN: Record<string, Record<string, string>> = Object.fromEntries(\n CONTAINER_BREAKPOINTS.map((breakpoint) => [\n breakpoint,\n table(`${breakpoint}:col-span-`, [...SPANS, 'full']),\n ]),\n)\n\n/** Whether a responsive map uses container sizes (`@md`) and so needs an `@container` parent. */\nexport function hasContainerBreakpoints(map: Breakpoints<unknown> | undefined | null): boolean {\n return !!map && Object.keys(map).some((key) => key.startsWith('@'))\n}\n\n/** `@md:grid-cols-3`-style classes for the container keys of a `columns` map. */\nexport function containerGridColumnsClasses(columns: Breakpoints | undefined): string {\n if (!columns) return ''\n\n return CONTAINER_BREAKPOINTS.map((breakpoint) => {\n const value = columns[breakpoint]\n\n return value ? CONTAINER_GRID_COLS[breakpoint]?.[String(value)] : undefined\n })\n .filter(Boolean)\n .join(' ')\n}\n\n/** `@md:col-span-2`-style classes for the container keys of a `columnSpan` map. */\nexport function containerColumnSpanClasses(span: Breakpoints<ColumnSpanValue> | undefined): string {\n if (!span) return ''\n\n return CONTAINER_BREAKPOINTS.map((breakpoint) => {\n const value = span[breakpoint]\n\n return value ? CONTAINER_COL_SPAN[breakpoint]?.[String(value)] : undefined\n })\n .filter(Boolean)\n .join(' ')\n}\n\n/**\n * `contentGrid()` breakpoints, read against the width of the table rather than the\n * viewport: the table sits beside the panel sidebar (and a cluster's sub-navigation), so a\n * viewport breakpoint says little about the room the cards have. Each viewport key maps to\n * the largest container size at or below that viewport minus 24rem (a 16rem sidebar plus\n * the page's gutters): `md` 48rem → `@sm` 24rem, `xl` 80rem → `@4xl` 56rem.\n */\nconst CONTENT_GRID_FROM: Record<string, ContainerBreakpoint | null> = {\n default: null,\n sm: '@3xs',\n md: '@sm',\n lg: '@xl',\n xl: '@4xl',\n '2xl': '@6xl',\n}\n\n/**\n * The smallest container size that keeps `n` cards at least 15rem wide, with the grid's\n * `p-4` and `gap-4`: 16rem per column plus 1rem. Five or more columns need `@7xl` (80rem).\n */\nconst CONTENT_GRID_MIN: Record<number, ContainerBreakpoint | null> = {\n 1: null,\n 2: '@xl', // 33rem → 36rem\n 3: '@4xl', // 49rem → 56rem\n 4: '@6xl', // 65rem → 72rem\n}\n\nconst CONTENT_GRID_KEYS = ['default', 'sm', 'md', 'lg', 'xl', '2xl'] as const\n\nfunction widerBreakpoint(\n a: ContainerBreakpoint | null,\n b: ContainerBreakpoint | null,\n): ContainerBreakpoint | null {\n if (!a) return b\n if (!b) return a\n\n return CONTAINER_BREAKPOINTS.indexOf(a) >= CONTAINER_BREAKPOINTS.indexOf(b) ? a : b\n}\n\n/**\n * Classes for a table's `contentGrid()`: one column, then `@…:grid-cols-N` container-query\n * classes relative to the `@container` around the card grid. A column count applies from\n * the wider of its key's size (`CONTENT_GRID_FROM`) and the size that fits that many cards\n * (`CONTENT_GRID_MIN`), so cards get fewer columns instead of getting narrow. Container\n * keys (`'@lg' => 2`) are used as given; when two keys land on the same size, the later\n * (wider) key wins.\n */\nexport function contentGridClasses(grid: Breakpoints | undefined | null): string {\n const classes = new Map<ContainerBreakpoint, string>()\n\n for (const key of CONTENT_GRID_KEYS) {\n const value = grid?.[key]\n\n if (!value) continue\n\n const count = Math.min(Math.max(Math.trunc(value), 1), 12)\n const at = widerBreakpoint(CONTENT_GRID_FROM[key] ?? null, CONTENT_GRID_MIN[count] ?? '@7xl')\n const cls = at ? CONTAINER_GRID_COLS[at]?.[String(count)] : undefined\n\n if (at && cls) classes.set(at, cls)\n }\n\n for (const breakpoint of CONTAINER_BREAKPOINTS) {\n const cls = CONTAINER_GRID_COLS[breakpoint]?.[String(grid?.[breakpoint] ?? '')]\n\n if (cls) classes.set(breakpoint, cls)\n }\n\n return [\n 'grid-cols-1',\n ...CONTAINER_BREAKPOINTS.map((breakpoint) => classes.get(breakpoint)).filter(Boolean),\n ].join(' ')\n}\n\nconst CONTAINER_COL_START: Record<string, Record<string, string>> = Object.fromEntries(\n CONTAINER_BREAKPOINTS.map((breakpoint) => [breakpoint, table(`${breakpoint}:col-start-`, SPANS)]),\n)\n\n/**\n * Layout breakpoints inside a table record (`Split::from()`, a `Grid`'s `columns` and the\n * `columnSpan()` / `columnStart()` of its children) are read against the width of the\n * record (its `@container`) rather than the viewport: a card in a `contentGrid()` can be\n * 15rem wide on a wide screen. Each viewport key maps to a card-sized width, so\n * `Split::from('md')` puts its parts side by side once the record has 20rem (320px).\n */\nexport const RECORD_CONTAINER_FROM: Readonly<Record<string, ContainerBreakpoint>> = {\n sm: '@3xs', // 16rem\n md: '@xs', // 20rem\n lg: '@md', // 28rem\n xl: '@xl', // 36rem\n '2xl': '@3xl', // 48rem\n}\n\nconst RECORD_KEYS = ['sm', 'md', 'lg', 'xl', '2xl'] as const\n\n/**\n * Classes for a responsive map inside a table record: `default` as is, viewport keys at\n * their `RECORD_CONTAINER_FROM` size and container keys (`'@md' => 2`) as given; when two\n * keys land on the same size, the container key wins.\n */\nfunction recordClasses(\n map: Breakpoints<number | string | null> | undefined | null,\n base: Record<string, string>,\n containers: Record<string, Record<string, string>>,\n): string[] {\n if (!map) return []\n\n const classes = new Map<ContainerBreakpoint, string>()\n\n for (const key of RECORD_KEYS) {\n const value = map[key]\n const at = RECORD_CONTAINER_FROM[key]\n const cls = value && at ? containers[at]?.[String(value)] : undefined\n\n if (at && cls) classes.set(at, cls)\n }\n\n for (const breakpoint of CONTAINER_BREAKPOINTS) {\n const value = map[breakpoint]\n const cls = value ? containers[breakpoint]?.[String(value)] : undefined\n\n if (cls) classes.set(breakpoint, cls)\n }\n\n const value = map.default\n\n return [\n value ? base[String(value)] : undefined,\n ...CONTAINER_BREAKPOINTS.map((breakpoint) => classes.get(breakpoint)),\n ].filter((cls): cls is string => Boolean(cls))\n}\n\nconst GRID_COLS = table('grid-cols-', SPANS)\nconst COL_SPAN = table('col-span-', [...SPANS, 'full'])\nconst COL_START = table('col-start-', SPANS)\n\n/** A `Grid` layout's `columns` inside a table record (sizes of `RECORD_CONTAINER_FROM`). */\nexport function recordGridColumnsClasses(columns: Breakpoints | undefined | null): string {\n const classes = recordClasses(columns, GRID_COLS, CONTAINER_GRID_COLS)\n\n return (columns?.default ? classes : ['grid-cols-1', ...classes]).join(' ')\n}\n\n/**\n * `columnSpan()` / `columnStart()` of a node inside a table record's `Grid` (sizes of\n * `RECORD_CONTAINER_FROM`).\n */\nexport function recordColumnSpanClasses(\n span: Breakpoints<ColumnSpanValue> | undefined | null,\n start?: Breakpoints<number | string | null> | undefined | null,\n): string {\n return [\n ...recordClasses(span, COL_SPAN, CONTAINER_COL_SPAN),\n ...recordClasses(start, COL_START, CONTAINER_COL_START),\n ].join(' ')\n}\n\nconst FLEX_ROW: Record<string, string> = {\n default: 'flex-row',\n sm: 'sm:flex-row',\n md: 'md:flex-row',\n lg: 'lg:flex-row',\n xl: 'xl:flex-row',\n '2xl': '2xl:flex-row',\n}\n\n/** `Flex::alignment()`: main-axis alignment (logical, so `start` follows the direction). */\nconst FLEX_JUSTIFY: Record<string, string> = {\n start: 'justify-start',\n center: 'justify-center',\n end: 'justify-end',\n between: 'justify-between',\n justify: 'justify-between',\n}\n\nconst FLEX_ALIGN: Record<string, Record<string, string>> = {\n start: {\n default: 'items-start',\n sm: 'sm:items-start',\n md: 'md:items-start',\n lg: 'lg:items-start',\n xl: 'xl:items-start',\n '2xl': '2xl:items-start',\n },\n center: {\n default: 'items-center',\n sm: 'sm:items-center',\n md: 'md:items-center',\n lg: 'lg:items-center',\n xl: 'xl:items-center',\n '2xl': '2xl:items-center',\n },\n end: {\n default: 'items-end',\n sm: 'sm:items-end',\n md: 'md:items-end',\n lg: 'lg:items-end',\n xl: 'xl:items-end',\n '2xl': '2xl:items-end',\n },\n}\n\n/**\n * Classes for a `Flex` schema component: stacked, then a row (and the vertical alignment)\n * from its `from` breakpoint. Force-generated with `@source inline(...)` in each renderer.\n */\nexport function flexLayoutClasses(flex: {\n from?: string | null\n verticalAlignment?: string | null\n alignment?: string | null\n}): string {\n const from = flex.from ?? 'default'\n const align = flex.verticalAlignment ? FLEX_ALIGN[flex.verticalAlignment]?.[from] : undefined\n const justify = flex.alignment ? FLEX_JUSTIFY[flex.alignment] : undefined\n\n return ['flex flex-col gap-6', FLEX_ROW[from] ?? 'flex-row', align, justify]\n .filter(Boolean)\n .join(' ')\n}\n\n/** Width behaviour of a child inside a `Flex`: share the row, or keep its natural width. */\nexport function flexItemClasses(component: { grow?: boolean }): string {\n return component.grow === false ? 'min-w-0 shrink-0' : 'min-w-0 flex-1'\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfakit/core",
3
- "version": "0.2.0",
3
+ "version": "0.2.3",
4
4
  "description": "Framework-agnostic schema types and state management for Alfakit, the Laravel admin panel builder by Alfa Six.",
5
5
  "license": "MIT",
6
6
  "author": "Alfa Six (https://alfasixbh.com)",