diff --git a/src/uix/soma/components/words/engine/document.ts b/src/uix/soma/components/words/engine/document.ts index 83a6babf1..924281030 100644 --- a/src/uix/soma/components/words/engine/document.ts +++ b/src/uix/soma/components/words/engine/document.ts @@ -120,16 +120,13 @@ export const WORDS_TEXT_ALIGNS = [ 'right', 'justify' ] as const satisfies readonly WordsTextAlign[]; -export const WORDS_TABLE_CELL_VERTICAL_ALIGNS = [ - 'top', - 'middle', - 'bottom' -] as const satisfies readonly WordsTableCellVerticalAlign[]; -export const WORDS_TABLE_CELL_TONES = [ - 'default', - 'muted', - 'accent' -] as const satisfies readonly WordsTableCellTone[]; +// Table cell value-set constants live in the table extension since +// F2.3b. Re-exported here for backward compat with consumers that +// import them from `engine/document`. +export { + WORDS_TABLE_CELL_VERTICAL_ALIGNS, + WORDS_TABLE_CELL_TONES +} from '../extensions/table/factories'; export function createEmptyWordsDocument(): WordsDocument { return { @@ -192,39 +189,9 @@ export function createListItem( }; } -export function createTable( - children: readonly WordsTableRow[] = [createTableRow()], - options: WordsTableOptions = {} -): WordsTableBlock { - return { - type: 'table', - ...(options.striped ? { striped: true } : {}), - ...(options.compact ? { compact: true } : {}), - children - }; -} - -export function createTableRow( - children: readonly WordsTableCell[] = [createTableCell()] -): WordsTableRow { - return { type: 'table-row', children }; -} - -export function createTableCell( - children: readonly WordsInline[] = [createText('')], - options: WordsTableCellOptions = {} -): WordsTableCell { - return { - type: 'table-cell', - ...(options.header ? { header: true } : {}), - ...(options.textAlign && options.textAlign !== 'left' ? { textAlign: options.textAlign } : {}), - ...(options.verticalAlign && options.verticalAlign !== 'top' - ? { verticalAlign: options.verticalAlign } - : {}), - ...(options.tone && options.tone !== 'default' ? { tone: options.tone } : {}), - children - }; -} +// Table factory functions live in the table extension since F2.3b. +// Re-exported here for backward compat — see `extensions/table/factories.ts`. +export { createTable, createTableRow, createTableCell } from '../extensions/table/factories'; export function createText(text: string, marks: readonly WordsMark[] = []): WordsText { const normalizedMarks = normalizeMarks(marks); @@ -280,18 +247,12 @@ export function isWordsTextAlign(value: unknown): value is WordsTextAlign { return typeof value === 'string' && (WORDS_TEXT_ALIGNS as readonly string[]).includes(value); } -export function isWordsTableCellVerticalAlign( - value: unknown -): value is WordsTableCellVerticalAlign { - return ( - typeof value === 'string' && - (WORDS_TABLE_CELL_VERTICAL_ALIGNS as readonly string[]).includes(value) - ); -} - -export function isWordsTableCellTone(value: unknown): value is WordsTableCellTone { - return typeof value === 'string' && (WORDS_TABLE_CELL_TONES as readonly string[]).includes(value); -} +// Table predicates live in the table extension since F2.3b. +// Re-exported here for backward compat. +export { + isWordsTableCellVerticalAlign, + isWordsTableCellTone +} from '../extensions/table/factories'; export function normalizeWordsCodeLanguage(value: unknown): string | undefined { if (typeof value !== 'string') return undefined; diff --git a/src/uix/soma/components/words/extensions/table/factories.ts b/src/uix/soma/components/words/extensions/table/factories.ts new file mode 100644 index 000000000..f8436dfef --- /dev/null +++ b/src/uix/soma/components/words/extensions/table/factories.ts @@ -0,0 +1,85 @@ +/** + * Table factories + value-set predicates. + * + * Owned by the table extension. The engine's `document.ts` re-exports + * these for backward compatibility. New code should import from the + * `extensions/table` barrel. + * + * Factories canonicalize the shape of every table node — they apply + * defaults (single empty row, single empty cell, text "left" align + * stripped when default, etc.) so the engine never has to think about + * "is this a valid table?". Predicates validate user-supplied values + * for cell tone and vertical align, used by the operations layer + * before applying commands. + */ + +import { createText } from '../../engine/document'; +import type { WordsInline } from '../../engine/document'; +import type { + WordsTableBlock, + WordsTableCell, + WordsTableCellOptions, + WordsTableCellTone, + WordsTableCellVerticalAlign, + WordsTableOptions, + WordsTableRow +} from './types'; + +export const WORDS_TABLE_CELL_VERTICAL_ALIGNS = [ + 'top', + 'middle', + 'bottom' +] as const satisfies readonly WordsTableCellVerticalAlign[]; + +export const WORDS_TABLE_CELL_TONES = [ + 'default', + 'muted', + 'accent' +] as const satisfies readonly WordsTableCellTone[]; + +export function createTable( + children: readonly WordsTableRow[] = [createTableRow()], + options: WordsTableOptions = {} +): WordsTableBlock { + return { + type: 'table', + ...(options.striped ? { striped: true } : {}), + ...(options.compact ? { compact: true } : {}), + children + }; +} + +export function createTableRow( + children: readonly WordsTableCell[] = [createTableCell()] +): WordsTableRow { + return { type: 'table-row', children }; +} + +export function createTableCell( + children: readonly WordsInline[] = [createText('')], + options: WordsTableCellOptions = {} +): WordsTableCell { + return { + type: 'table-cell', + ...(options.header ? { header: true } : {}), + ...(options.textAlign && options.textAlign !== 'left' ? { textAlign: options.textAlign } : {}), + ...(options.verticalAlign && options.verticalAlign !== 'top' + ? { verticalAlign: options.verticalAlign } + : {}), + ...(options.tone && options.tone !== 'default' ? { tone: options.tone } : {}), + children + }; +} + +export function isWordsTableCellVerticalAlign( + value: unknown +): value is WordsTableCellVerticalAlign { + return ( + typeof value === 'string' && + (WORDS_TABLE_CELL_VERTICAL_ALIGNS as readonly string[]).includes(value) + ); +} + +export function isWordsTableCellTone(value: unknown): value is WordsTableCellTone { + return typeof value === 'string' && (WORDS_TABLE_CELL_TONES as readonly string[]).includes(value); +} diff --git a/src/uix/soma/components/words/extensions/table/index.ts b/src/uix/soma/components/words/extensions/table/index.ts new file mode 100644 index 000000000..b1e2a6667 --- /dev/null +++ b/src/uix/soma/components/words/extensions/table/index.ts @@ -0,0 +1,39 @@ +/** + * Table extension — public barrel. + * + * Migration in progress (F2.3). This barrel exposes the pieces already + * moved to the extension so consumers can start importing from here + * instead of `engine/document.ts`. + * + * Pieces moved so far: + * - Types (F2.3a) + * - Factories + value-set predicates (F2.3b) + * + * Pending: + * - Serializers (HTML + Markdown) (F2.3c, F2.3d) + * - Render (F2.3e) + * - Path / navigation (F2.3f) + * - Normalize (F2.3g) + * - Operations (F2.3h) + * - Registry wire-up + WordsExtension export (F2.3i) + */ + +export type { + WordsTableBlock, + WordsTableCell, + WordsTableCellOptions, + WordsTableCellTone, + WordsTableCellVerticalAlign, + WordsTableOptions, + WordsTableRow +} from './types'; + +export { + createTable, + createTableCell, + createTableRow, + isWordsTableCellTone, + isWordsTableCellVerticalAlign, + WORDS_TABLE_CELL_TONES, + WORDS_TABLE_CELL_VERTICAL_ALIGNS +} from './factories';