@fieldia/viewer 0.9.0 → 0.9.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../tools/script-entry.ts", "../../../../libs/core/src/lib/format/names.ts", "../../../../libs/core/src/lib/format/columns.ts", "../../../../libs/core/src/lib/format/version.ts", "../../../../libs/core/src/lib/expression/evaluator.ts", "../../../../libs/core/src/lib/expression/tokenizer.ts", "../../../../libs/core/src/lib/expression/parser.ts", "../../../../libs/core/src/lib/expression/modifier.ts", "../../../../libs/core/src/lib/format/references.ts", "../../../../libs/core/src/lib/format/check-page.ts", "../../../../libs/core/src/lib/format/translate.ts", "../../../../libs/core/src/lib/expression/evaluateModifier.ts", "../../../../libs/core/src/lib/record/values.ts", "../../../../libs/core/src/lib/record/messages.ts", "../../../../libs/core/src/lib/record/check.ts", "../../../../libs/core/src/lib/record/data-source.ts", "../../../../libs/core/src/lib/record/filter.ts", "../../../../libs/core/src/lib/record/search.ts", "../../../../libs/core/src/lib/record/scheduler.ts", "../../../../libs/core/src/lib/record/memory-data-source.ts", "../../../../libs/core/src/lib/record/form.ts", "../../../../libs/widgets/src/lib/numbers.ts", "../../../../libs/widgets/src/lib/labels.ts", "../../../../libs/widgets/src/lib/relations.ts", "../../../../libs/widgets/src/lib/display.ts", "../../../../libs/widgets/src/lib/lines.ts", "../../../../libs/widgets/src/lib/files.ts", "../../../../libs/widgets/src/lib/progress.ts", "../../../../libs/widgets/src/lib/label.ts", "../../../../libs/widgets/src/lib/statusbar.ts", "../../../../libs/widgets/src/lib/calendar.ts", "../../../../libs/widgets/src/lib/properties.ts", "../../../../libs/widgets/src/lib/extras.ts", "../../../../libs/widgets/src/lib/widgets.ts", "../../../../libs/widgets/src/lib/styles.ts", "../../../../libs/widgets/src/lib/preferences.ts", "../../../../libs/widgets/src/lib/icons.ts", "../../../../libs/viewer/src/lib/dialog.ts", "../../../../libs/viewer/src/lib/related.ts", "../../../../libs/viewer/src/lib/favourites.ts", "../../../../libs/viewer/src/lib/list-groups.ts", "../../../../libs/viewer/src/lib/list-styles.ts", "../../../../libs/viewer/src/lib/custom-filter.ts", "../../../../libs/viewer/src/lib/search-bar.ts", "../../../../libs/viewer/src/lib/list.ts", "../../../../libs/viewer/src/lib/labels.ts", "../../../../libs/viewer/src/lib/viewer.ts"],
4
- "sourcesContent": ["/**\n * What the `<script>` bundle puts on `window.Fieldia`: everything a page with\n * no build step needs to show a form and handle what people enter.\n */\n// The runtime alone: the format's schemas and validation library stay out of a page with no build step.\nexport * from '../libs/core/src/runtime';\nexport * from '@fieldia/widgets';\nexport * from '@fieldia/viewer';\n\ndeclare const __FIELDIA_VERSION__: string;\n/** The version of @fieldia/viewer this bundle was built from. */\nexport const VERSION: string = __FIELDIA_VERSION__;\n", "/** Field names and kinds, apart from the schemas so code that runs a form never carries the validation library. */\n\n/** A field name: what expressions and layout nodes use to refer to a field. */\nexport const FIELD_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nexport const FIELD_TYPES = [\n 'char',\n 'text',\n 'html',\n 'integer',\n 'float',\n 'monetary',\n 'boolean',\n 'date',\n 'datetime',\n 'selection',\n 'binary',\n 'image',\n 'many2one',\n 'many2many',\n 'one2many',\n 'reference',\n 'properties',\n 'json',\n] as const;\n\nexport type FieldType = (typeof FIELD_TYPES)[number];\n", "import type { ColumnCount, ColumnsByWidth } from './layout';\n\n/** A section's columns at full width, whichever way they are written. */\nexport function wideColumns(columns: ColumnCount | ColumnsByWidth | undefined): ColumnCount {\n return typeof columns === 'object' ? columns.wide : columns ?? 1;\n}\n", "/** The page format version this build reads and writes. */\nexport const FORMAT_VERSION = '0.1' as const;\n", "/**\n * AST evaluator for modifiers, ported from the React form engine.\n *\n * Python semantics where the React version used JavaScript's: an empty list\n * or string is false, and an empty value is never smaller or larger than\n * anything \u2014 modifiers come from backends that think in Python.\n */\n\nimport type { ASTNode, BinaryOpNode, UnaryOpNode } from './parser';\n\n/**\n * Evaluate an AST node against a context object\n *\n * @param ast - The AST node to evaluate\n * @param context - Object containing field values\n * @returns The result of evaluation\n *\n * @example\n * const ast = { type: 'BinaryOp', operator: '==', left: {...}, right: {...} };\n * const context = { state: 'draft', amount: 100 };\n * evaluate(ast, context); // Returns boolean result\n */\nexport function evaluate(ast: ASTNode, context: Record<string, unknown>): unknown {\n switch (ast.type) {\n case 'BinaryOp':\n return evaluateBinaryOp(ast, context);\n\n case 'UnaryOp':\n return evaluateUnaryOp(ast, context);\n\n case 'Literal':\n return ast.value;\n\n case 'Identifier':\n return getNestedValue(context, ast.name);\n\n default:\n throw new Error(`Unknown AST node type: ${(ast as { type: string }).type}`);\n }\n}\n\n/**\n * Evaluate binary operations\n */\nfunction evaluateBinaryOp(node: BinaryOpNode, context: Record<string, unknown>): unknown {\n const left = normalize(evaluate(node.left, context));\n const right = normalize(evaluate(node.right, context));\n const operator = node.operator.toLowerCase();\n const ordered = left !== null && right !== null;\n\n switch (operator) {\n // Comparison operators\n case '==':\n return left === right;\n\n case '!=':\n case '<>':\n return left !== right;\n\n case '<':\n return ordered && (left as Comparable) < (right as Comparable);\n\n case '>':\n return ordered && (left as Comparable) > (right as Comparable);\n\n case '<=':\n return ordered && (left as Comparable) <= (right as Comparable);\n\n case '>=':\n return ordered && (left as Comparable) >= (right as Comparable);\n\n // In operators\n case 'in':\n return Array.isArray(right) && right.includes(left);\n\n case 'not in':\n return Array.isArray(right) && !right.includes(left);\n\n // Logical operators (use truthiness)\n case 'and':\n return truthy(left) && truthy(right);\n\n case 'or':\n return truthy(left) || truthy(right);\n\n default:\n throw new Error(`Unknown binary operator: ${node.operator}`);\n }\n}\n\n/**\n * Evaluate unary operations\n */\nfunction evaluateUnaryOp(node: UnaryOpNode, context: Record<string, unknown>): unknown {\n const operand = evaluate(node.operand, context);\n const operator = node.operator.toLowerCase();\n\n switch (operator) {\n case 'not':\n return !truthy(operand);\n\n default:\n throw new Error(`Unknown unary operator: ${node.operator}`);\n }\n}\n\n/** What `<` and `>` order: numbers with numbers, strings with strings. */\ntype Comparable = number | string;\n\n/** A missing value compares like None. */\nfunction normalize(value: unknown): unknown {\n return value === undefined ? null : value;\n}\n\n/** Python's truth test: empty lists, strings and objects, 0 and None are false. */\nexport function truthy(value: unknown): boolean {\n if (Array.isArray(value)) return value.length > 0;\n if (value !== null && typeof value === 'object') return Object.keys(value).length > 0;\n return Boolean(value);\n}\n\n/**\n * Get a nested value from an object using dot notation\n *\n * @param obj - The object to traverse\n * @param path - Dot-separated path (e.g., 'partner_id.country_id.name')\n * @returns The value at the path, or undefined if not found\n *\n * @example\n * getNestedValue({ a: { b: { c: 5 } } }, 'a.b.c') // Returns 5\n * getNestedValue({ a: null }, 'a.b.c') // Returns undefined\n */\nfunction getNestedValue(obj: unknown, path: string): unknown {\n const parts = path.split('.');\n let current: unknown = obj;\n\n for (const part of parts) {\n if (current === null || current === undefined) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n}\n", "/**\n * Tokenizer for modifier expressions.\n *\n * Ported from the React form engine, with one change in behaviour: a\n * character the language does not know is an error, not something to skip.\n * The React version dropped it silently, so `amount > -5` read as\n * `amount > 5` and `a && b` read as `a b`.\n */\n\nexport type TokenType =\n | 'IDENTIFIER' // Field names, including dotted notation (e.g., partner_id.country_id)\n | 'NUMBER' // Integer or float (e.g., 42, 3.14)\n | 'STRING' // Single or double quoted string (e.g., 'draft', \"draft\")\n | 'LIST' // List literal (e.g., ['draft', 'sent'])\n | 'OPERATOR' // Comparison operators (==, !=, <>, <, >, <=, >=, in, not in)\n | 'LOGICAL' // Logical operators (and, or, not)\n | 'CONSTANT' // True, False, None (and true, false, null)\n | 'PAREN'; // Parentheses ( )\n\nexport interface Token {\n type: TokenType;\n value: string;\n position: number;\n}\n\n/**\n * Tokenizes a Flectra modifier expression.\n *\n * @param expr - The expression string to tokenize\n * @returns Array of tokens\n *\n * @example\n * tokenize(\"state == 'draft'\")\n * // Returns: [\n * // { type: 'IDENTIFIER', value: 'state', position: 0 },\n * // { type: 'OPERATOR', value: '==', position: 1 },\n * // { type: 'STRING', value: \"'draft'\", position: 2 }\n * // ]\n */\n/** The words that are values, not field names. */\nexport const CONSTANTS: ReadonlyMap<string, boolean | null> = new Map<string, boolean | null>([\n ['True', true],\n ['False', false],\n ['None', null],\n ['true', true],\n ['false', false],\n ['null', null],\n]);\n\nexport function tokenize(expr: string): Token[] {\n const tokens: Token[] = [];\n if (!expr) return tokens;\n\n // Alternatives in priority order: \"not in\" before \"not\", operators of two\n // characters before one, a signed number before anything else that could\n // start with a digit. Sticky (`y`), so a position nothing matches is an\n // error instead of a gap.\n const token =\n /(\\(|\\)|==|!=|<=|>=|<>|<|>|not\\s+in\\b|in\\b|and\\b|or\\b|not\\b|\\[[^\\]]*\\]|'[^']*'|\"[^\"]*\"|-?\\d+\\.?\\d*|\\w+(?:\\.\\w+)*)/iy;\n const space = /\\s*/y;\n let at = 0;\n\n for (;;) {\n space.lastIndex = at;\n space.exec(expr);\n at = space.lastIndex;\n if (at >= expr.length) return tokens;\n\n token.lastIndex = at;\n const match = token.exec(expr);\n if (!match) {\n throw new Error(`Unexpected \"${expr[at]}\" at character ${at + 1} of: ${expr}`);\n }\n tokens.push({ type: getTokenType(match[0]), value: match[0], position: tokens.length });\n at = token.lastIndex;\n }\n}\n\n/**\n * Determines the type of a token based on its text value.\n */\nfunction getTokenType(text: string): TokenType {\n const lowerText = text.toLowerCase().trim();\n\n // Python's constants, and their JSON spellings\n if (CONSTANTS.has(text)) {\n return 'CONSTANT';\n }\n\n // Logical operators (case-insensitive)\n if (lowerText === 'and' || lowerText === 'or' || lowerText === 'not') {\n return 'LOGICAL';\n }\n\n // Comparison operators (case-insensitive for word operators)\n if (\n ['==', '!=', '<>', '<', '>', '<=', '>='].includes(text) ||\n lowerText === 'in' ||\n lowerText === 'not in'\n ) {\n return 'OPERATOR';\n }\n\n // Parentheses\n if (text === '(' || text === ')') {\n return 'PAREN';\n }\n\n // Lists (start with '[')\n if (text.startsWith('[')) {\n return 'LIST';\n }\n\n // Strings (start with ' or \")\n if (text.startsWith(\"'\") || text.startsWith('\"')) {\n return 'STRING';\n }\n\n // Numbers (matches integer or float, either sign)\n if (/^-?\\d+\\.?\\d*$/.test(text)) {\n return 'NUMBER';\n }\n\n // Default to identifier\n return 'IDENTIFIER';\n}\n", "/**\n * Expression parser for modifiers, ported from the React form engine.\n *\n * Recursive descent parser that converts tokens into an Abstract Syntax Tree (AST).\n * Implements Python-like operator precedence:\n * 1. OR (lowest precedence)\n * 2. AND\n * 3. NOT\n * 4. Comparison operators (==, !=, <, >, <=, >=, in, not in)\n * 5. Values/Identifiers (highest precedence)\n */\n\nimport { CONSTANTS, type Token } from './tokenizer';\n\n/**\n * AST Node Types\n */\nexport type ASTNode = BinaryOpNode | UnaryOpNode | LiteralNode | IdentifierNode;\n\nexport interface BinaryOpNode {\n type: 'BinaryOp';\n operator: string;\n left: ASTNode;\n right: ASTNode;\n}\n\nexport interface UnaryOpNode {\n type: 'UnaryOp';\n operator: string;\n operand: ASTNode;\n}\n\nexport interface LiteralNode {\n type: 'Literal';\n value: unknown;\n}\n\nexport interface IdentifierNode {\n type: 'Identifier';\n name: string;\n}\n\n/**\n * Recursive Descent Expression Parser\n */\nexport class ExpressionParser {\n private tokens: Token[];\n private position: number = 0;\n\n constructor(tokens: Token[]) {\n this.tokens = tokens;\n }\n\n /**\n * Parse tokens into an AST\n */\n parse(): ASTNode {\n if (this.tokens.length === 0) {\n throw new Error('Cannot parse empty expression');\n }\n\n const ast = this.parseOr();\n\n // Ensure all tokens were consumed\n if (!this.isAtEnd()) {\n throw new Error(`Unexpected token at position ${this.position}: ${this.peek()?.value}`);\n }\n\n return ast;\n }\n\n /**\n * Parse OR expressions (lowest precedence)\n * or_expr: and_expr ('or' and_expr)*\n */\n private parseOr(): ASTNode {\n let left = this.parseAnd();\n\n while (this.matchLogical('or')) {\n const operator = this.previous().value;\n const right = this.parseAnd();\n left = {\n type: 'BinaryOp',\n operator: operator.toLowerCase(),\n left,\n right,\n };\n }\n\n return left;\n }\n\n /**\n * Parse AND expressions\n * and_expr: not_expr ('and' not_expr)*\n */\n private parseAnd(): ASTNode {\n let left = this.parseNot();\n\n while (this.matchLogical('and')) {\n const operator = this.previous().value;\n const right = this.parseNot();\n left = {\n type: 'BinaryOp',\n operator: operator.toLowerCase(),\n left,\n right,\n };\n }\n\n return left;\n }\n\n /**\n * Parse NOT expressions\n * not_expr: 'not' comparison | comparison\n */\n private parseNot(): ASTNode {\n if (this.matchLogical('not')) {\n const operator = this.previous().value;\n const operand = this.parseComparison();\n return {\n type: 'UnaryOp',\n operator: operator.toLowerCase(),\n operand,\n };\n }\n\n return this.parseComparison();\n }\n\n /**\n * Parse comparison expressions\n * comparison: value (comp_op value)?\n * comp_op: '==' | '!=' | '<>' | '<' | '>' | '<=' | '>=' | 'in' | 'not in'\n */\n private parseComparison(): ASTNode {\n const left = this.parseValue();\n\n const compOperators = ['==', '!=', '<>', '<', '>', '<=', '>=', 'in', 'not in'];\n if (this.matchOperator(...compOperators)) {\n const operator = this.previous().value;\n const right = this.parseValue();\n return {\n type: 'BinaryOp',\n operator: operator.toLowerCase(),\n left,\n right,\n };\n }\n\n // If no comparison operator, return value as-is (truthiness check)\n return left;\n }\n\n /**\n * Parse value expressions (highest precedence)\n * value: '(' or_expr ')' | literal | identifier\n */\n private parseValue(): ASTNode {\n // Parenthesized expression\n if (this.match('PAREN', '(')) {\n const expr = this.parseOr();\n this.consume('PAREN', ')', 'Expected closing parenthesis');\n return expr;\n }\n\n // String literal\n if (this.check('STRING')) {\n const token = this.advance();\n // Remove quotes\n const value = token.value.slice(1, -1);\n return { type: 'Literal', value };\n }\n\n // True, False, None\n if (this.check('CONSTANT')) {\n const token = this.advance();\n return { type: 'Literal', value: CONSTANTS.get(token.value) ?? null };\n }\n\n // Number literal\n if (this.check('NUMBER')) {\n const token = this.advance();\n return { type: 'Literal', value: Number(token.value) };\n }\n\n // List literal\n if (this.check('LIST')) {\n const token = this.advance();\n const value = parseListLiteral(token.value);\n return { type: 'Literal', value };\n }\n\n // Identifier\n if (this.check('IDENTIFIER')) {\n const token = this.advance();\n return { type: 'Identifier', name: token.value };\n }\n\n throw new Error(`Unexpected token: ${this.peek()?.value || 'EOF'}`);\n }\n\n // ========== Helper Methods ==========\n\n /**\n * Check if current token matches any of the given types/values\n */\n private match(type: string, ...values: string[]): boolean {\n if (this.check(type)) {\n if (values.length === 0) {\n this.advance();\n return true;\n }\n const token = this.peek();\n if (token && values.includes(token.value)) {\n this.advance();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Match logical operators (case-insensitive)\n */\n private matchLogical(...operators: string[]): boolean {\n const token = this.peek();\n if (token && token.type === 'LOGICAL') {\n const lowerValue = token.value.toLowerCase();\n if (operators.map(op => op.toLowerCase()).includes(lowerValue)) {\n this.advance();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Match comparison operators (case-insensitive)\n */\n private matchOperator(...operators: string[]): boolean {\n const token = this.peek();\n if (token && token.type === 'OPERATOR') {\n const lowerValue = token.value.toLowerCase();\n if (operators.map(op => op.toLowerCase()).includes(lowerValue)) {\n this.advance();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Check if current token has given type\n */\n private check(type: string): boolean {\n const token = this.peek();\n return token?.type === type;\n }\n\n /**\n * Consume current token and advance\n */\n private advance(): Token {\n if (!this.isAtEnd()) {\n this.position++;\n }\n return this.previous();\n }\n\n /**\n * Get current token without advancing\n */\n private peek(): Token | null {\n if (this.isAtEnd()) {\n return null;\n }\n return this.tokens[this.position];\n }\n\n /**\n * Get previous token\n */\n private previous(): Token {\n return this.tokens[this.position - 1];\n }\n\n /**\n * Check if we've consumed all tokens\n */\n private isAtEnd(): boolean {\n return this.position >= this.tokens.length;\n }\n\n /**\n * Consume a token of specific type/value or throw error\n */\n private consume(type: string, value: string, message: string): Token {\n if (this.check(type)) {\n const token = this.peek();\n if (token && token.value === value) {\n return this.advance();\n }\n }\n throw new Error(message);\n }\n}\n\n/**\n * Parse a list literal string into an array\n * Example: \"['draft', 'sent']\" -> ['draft', 'sent']\n */\nfunction parseListLiteral(listStr: string): unknown[] {\n try {\n // Remove brackets\n const content = listStr.slice(1, -1).trim();\n if (!content) {\n return [];\n }\n\n // Split by comma and parse each element\n const elements: unknown[] = [];\n let current = '';\n let inString = false;\n let stringChar = '';\n\n for (let i = 0; i < content.length; i++) {\n const char = content[i];\n\n if ((char === \"'\" || char === '\"') && (i === 0 || content[i - 1] !== '\\\\')) {\n if (!inString) {\n inString = true;\n stringChar = char;\n } else if (char === stringChar) {\n inString = false;\n stringChar = '';\n }\n }\n\n if (char === ',' && !inString) {\n elements.push(parseElement(current.trim()));\n current = '';\n } else {\n current += char;\n }\n }\n\n if (current.trim()) {\n elements.push(parseElement(current.trim()));\n }\n\n return elements;\n } catch (error) {\n // A list that cannot be read is a syntax error, not an empty list.\n throw new Error(`Cannot read the list ${listStr}`, { cause: error });\n }\n}\n\n/**\n * Parse a single element from a list\n */\nfunction parseElement(element: string): unknown {\n // String\n if ((element.startsWith(\"'\") && element.endsWith(\"'\")) ||\n (element.startsWith('\"') && element.endsWith('\"'))) {\n return element.slice(1, -1);\n }\n\n // Number\n if (!isNaN(Number(element))) {\n return Number(element);\n }\n\n // Boolean\n if (element.toLowerCase() === 'true') return true;\n if (element.toLowerCase() === 'false') return false;\n\n // Default to string\n return element;\n}\n", "import type { Modifier } from '../format/layout';\nimport { evaluate, truthy } from './evaluator';\nimport { ExpressionParser, type ASTNode } from './parser';\nimport { tokenize } from './tokenizer';\n\n/** A modifier read once, ready to evaluate against a record's values. */\nexport interface CompiledModifier {\n readonly source: Modifier | undefined;\n /** The fields it reads, by their first name, in order of appearance. */\n readonly fields: readonly string[];\n evaluate(values: Readonly<Record<string, unknown>>): boolean;\n}\n\n/**\n * Read a modifier. `true`, `false` and a missing modifier become constants;\n * an expression is parsed now, so a mistake surfaces here and not on the\n * first keystroke. Throws when the expression cannot be read.\n */\nexport function compileModifier(modifier: Modifier | undefined): CompiledModifier {\n if (typeof modifier !== 'string') {\n const value = modifier === true;\n return { source: modifier, fields: [], evaluate: () => value };\n }\n const ast = new ExpressionParser(tokenize(modifier)).parse();\n return {\n source: modifier,\n fields: fieldsRead(ast),\n evaluate(values) {\n try {\n return truthy(evaluate(ast, values));\n } catch {\n return false;\n }\n },\n };\n}\n\nfunction fieldsRead(ast: ASTNode): string[] {\n const names: string[] = [];\n const visit = (node: ASTNode): void => {\n switch (node.type) {\n case 'Identifier': {\n const root = node.name.split('.')[0];\n if (!names.includes(root)) names.push(root);\n return;\n }\n case 'BinaryOp':\n visit(node.left);\n visit(node.right);\n return;\n case 'UnaryOp':\n visit(node.operand);\n return;\n default:\n return;\n }\n };\n visit(ast);\n return names;\n}\n", "import type { Field, Fields, FilterItem, LineField, LineKinds } from './field';\nimport type { FieldNode, LayoutNode, ListNode, RootLayout, SheetNode, TabsNode } from './layout';\nimport type { Page } from './page';\nimport { compileModifier } from '../expression/modifier';\n\nexport interface PageIssue {\n /** Where the problem is, as a path into the page: `layout.children[0].field`. */\n path: string;\n message: string;\n}\n\nexport type PageValidation = { ok: true; page: Page } | { ok: false; issues: PageIssue[] };\n\nconst has = (record: object, key: string) => Object.prototype.hasOwnProperty.call(record, key);\n\n/** The second pass of every check: ids unique, every name defined, every condition readable. */\nexport class ReferenceCheck {\n private readonly issues: PageIssue[] = [];\n private readonly ids = new Map<string, string>();\n\n constructor(private readonly page: Page) {}\n\n run(): PageIssue[] {\n this.checkFields(this.page.fields, 'fields');\n this.walkRoot(this.page.layout, 'layout');\n return this.issues;\n }\n\n private report(path: string, message: string) {\n this.issues.push({ path, message });\n }\n\n private claim(id: string, path: string) {\n const first = this.ids.get(id);\n if (first !== undefined) this.report(path, `duplicate id \"${id}\", also used at ${first}`);\n else this.ids.set(id, path);\n }\n\n /** The field a reference names, or a reported issue and undefined. */\n private need(name: string, path: string, scope: Record<string, Field | LineField> = this.page.fields) {\n if (has(scope, name)) return scope[name];\n this.report(path, `no field \"${name}\"`);\n return undefined;\n }\n\n /** Every modifier on `owner` must read, and read only fields of this page. */\n private checkModifiers(owner: object, path: string, keys: readonly string[] = ['invisible']) {\n for (const key of keys) {\n const value = (owner as Record<string, unknown>)[key];\n if (typeof value !== 'string') continue;\n let fields: readonly string[];\n try {\n fields = compileModifier(value).fields;\n } catch (error) {\n this.report(`${path}.${key}`, `cannot read \"${value}\": ${(error as Error).message}`);\n continue;\n }\n for (const name of fields) {\n if (!has(this.page.fields, name)) {\n this.report(`${path}.${key}`, `\"${value}\" reads \"${name}\", which is not a field of this page`);\n }\n }\n }\n }\n\n private checkFields(fields: Fields | Record<string, LineField>, base: string) {\n for (const [name, def] of Object.entries(fields)) {\n const path = `${base}.${name}`;\n if (def.type === 'monetary' && def.currencyField !== undefined) {\n const currency = this.need(def.currencyField, `${path}.currencyField`, fields);\n if (currency && !['many2one', 'selection', 'char'].includes(currency.type)) {\n this.report(\n `${path}.currencyField`,\n `\"${def.currencyField}\" is a ${currency.type}; a currency field must be a many2one, selection or char`\n );\n }\n }\n if ((def.type === 'many2one' || def.type === 'many2many') && def.filter) {\n // Groups nest: each valueFrom inside them must name a field too.\n const walk = (item: FilterItem, at: string): void => {\n if ('any' in item) return item.any.forEach((inner, i) => walk(inner, `${at}.any[${i}]`));\n if ('all' in item) return item.all.forEach((inner, i) => walk(inner, `${at}.all[${i}]`));\n if (item.valueFrom !== undefined) this.need(item.valueFrom, `${at}.valueFrom`, fields);\n };\n def.filter.forEach((item, i) => {\n walk(item, `${path}.filter[${i}]`);\n });\n }\n if (def.type === 'properties' && def.definitions) {\n const seen = new Set<string>();\n def.definitions.forEach((property, i) => {\n if (property.type === 'selection' && !property.options) {\n this.report(`${path}.definitions[${i}].options`, 'a choice property needs its choices');\n }\n if (seen.has(property.name)) this.report(`${path}.definitions[${i}].name`, `\"${property.name}\" is named twice`);\n seen.add(property.name);\n });\n }\n if (def.type === 'one2many') {\n this.checkFields(def.fields, `${path}.fields`);\n if (def.lineKinds) this.checkLineKinds(name, def.lineKinds, def.fields, `${path}.lineKinds`);\n if (def.sequenceField !== undefined) {\n const sequence = def.fields[def.sequenceField];\n if (!sequence) this.report(`${path}.sequenceField`, `\"${def.sequenceField}\" is not a field of the lines of \"${name}\"`);\n else if (sequence.type !== 'integer') {\n this.report(`${path}.sequenceField`, `\"${def.sequenceField}\" is a ${sequence.type}; the field that keeps the order of lines must be an integer`);\n }\n }\n }\n }\n }\n\n private checkLineKinds(field: string, kinds: LineKinds, lineFields: Record<string, LineField>, path: string) {\n const kindField = lineFields[kinds.field];\n if (!kindField) this.report(`${path}.field`, `\"${kinds.field}\" is not a field of the lines of \"${field}\"`);\n else if (kindField.type !== 'selection' && kindField.type !== 'char') {\n this.report(`${path}.field`, `\"${kinds.field}\" is a ${kindField.type}; the field that says what a line is must be a selection or char`);\n } else if (kindField.type === 'selection') {\n for (const which of ['section', 'note'] as const) {\n const value = kinds[which] ?? which;\n if (!kindField.options.some((o) => o.value === value)) this.report(`${path}.${which}`, `\"${kinds.field}\" has no option \"${value}\"`);\n }\n }\n const text = lineFields[kinds.text];\n if (!text) this.report(`${path}.text`, `\"${kinds.text}\" is not a field of the lines of \"${field}\"`);\n else if (text.type !== 'char' && text.type !== 'text') {\n this.report(`${path}.text`, `\"${kinds.text}\" is a ${text.type}; a section's or note's text must be a char or text field`);\n }\n }\n\n private walkRoot(root: RootLayout, path: string) {\n if (root.type === 'tabs') return this.walkNode(root, path);\n this.claim(root.id, path);\n if (root.type === 'sheet') return this.walkSheet(root, path);\n if (root.type === 'sections') return this.walkChildren(root.children, path);\n if (root.type === 'list') return this.walkList(root, path);\n root.children.forEach((step, i) => {\n const stepPath = `${path}.children[${i}]`;\n this.claim(step.id, stepPath);\n this.checkModifiers(step, stepPath);\n this.walkChildren(step.children, stepPath);\n });\n }\n\n private walkList(list: ListNode, path: string) {\n if (this.page.data.kind !== 'record') this.report('data', 'a list shows records: its data needs kind \"record\" and a model');\n list.columns.forEach((name, i) => this.need(name, `${path}.columns[${i}]`));\n list.sort?.forEach((order, i) => this.need(order.field, `${path}.sort[${i}].field`));\n list.searchFields?.forEach((name, i) => this.need(name, `${path}.searchFields[${i}]`));\n list.groupBy?.forEach((name, i) => this.need(name, `${path}.groupBy[${i}]`));\n // A list's filters are about its own records: their fields are the page's, and there is no record to take a value from.\n const walk = (item: FilterItem, at: string): void => {\n if ('any' in item) return item.any.forEach((inner, i) => walk(inner, `${at}.any[${i}]`));\n if ('all' in item) return item.all.forEach((inner, i) => walk(inner, `${at}.all[${i}]`));\n this.need(item.field, `${at}.field`);\n if (item.valueFrom !== undefined) this.report(`${at}.valueFrom`, \"a list's filter compares with values, not with another field\");\n };\n const named = new Set<string>();\n list.filters?.forEach((filter, i) => {\n this.claim(filter.id, `${path}.filters[${i}]`);\n named.add(filter.id);\n filter.filter.forEach((item, j) => walk(item, `${path}.filters[${i}].filter[${j}]`));\n });\n list.defaultFilters?.forEach((id, i) => {\n if (!named.has(id)) this.report(`${path}.defaultFilters[${i}]`, `no filter \"${id}\" in this list`);\n });\n list.actions?.forEach((button, i) => this.claim(button.id, `${path}.actions[${i}]`));\n }\n\n private walkChildren(children: LayoutNode[], path: string) {\n children.forEach((child, i) => this.walkNode(child, `${path}.children[${i}]`));\n }\n\n private walkNode(node: LayoutNode, path: string) {\n this.claim(node.id, path);\n this.checkModifiers(node, path, node.type === 'field' ? ['invisible', 'readonly', 'required'] : node.type === 'section' ? ['invisible', 'readonly'] : ['invisible']);\n switch (node.type) {\n case 'field':\n return this.checkFieldNode(node, path);\n case 'section':\n if (node.collapsible && !node.title) this.report(path, 'a collapsible section needs a title to fold it by');\n if (node.collapsed && !node.collapsible) this.report(path, 'collapsed needs collapsible: true');\n return this.walkChildren(node.children, path);\n case 'tabs':\n return this.walkTabs(node, path);\n default:\n return;\n }\n }\n\n private walkTabs(node: TabsNode, path: string) {\n node.children.forEach((tab, i) => {\n const tabPath = `${path}.children[${i}]`;\n this.claim(tab.id, tabPath);\n this.checkModifiers(tab, tabPath);\n this.walkChildren(tab.children, tabPath);\n });\n }\n\n private walkSheet(sheet: SheetNode, path: string) {\n if (sheet.title) {\n this.need(sheet.title.field, `${path}.title.field`);\n if (sheet.title.subtitleField !== undefined) this.need(sheet.title.subtitleField, `${path}.title.subtitleField`);\n if (sheet.title.avatarField !== undefined) this.need(sheet.title.avatarField, `${path}.title.avatarField`);\n }\n if (sheet.statusbar) {\n const { field, visibleStates } = sheet.statusbar;\n const def = this.need(field, `${path}.statusbar.field`);\n if (def && def.type !== 'selection' && def.type !== 'many2one') {\n this.report(`${path}.statusbar.field`, `\"${field}\" is a ${def.type}; a statusbar needs a selection or many2one`);\n }\n if (def?.type === 'selection' && visibleStates) {\n const values = new Set(def.options.map((o) => o.value));\n visibleStates.forEach((state, i) => {\n if (!values.has(state)) {\n this.report(`${path}.statusbar.visibleStates[${i}]`, `\"${state}\" is not an option of \"${field}\"`);\n }\n });\n }\n }\n sheet.buttons?.forEach((button, i) => {\n this.claim(button.id, `${path}.buttons[${i}]`);\n this.checkModifiers(button, `${path}.buttons[${i}]`);\n });\n sheet.statButtons?.forEach((stat, i) => {\n this.claim(stat.id, `${path}.statButtons[${i}]`);\n this.checkModifiers(stat, `${path}.statButtons[${i}]`);\n if (stat.field !== undefined) this.need(stat.field, `${path}.statButtons[${i}].field`);\n });\n if (sheet.ribbon) {\n this.claim(sheet.ribbon.id, `${path}.ribbon`);\n this.checkModifiers(sheet.ribbon, `${path}.ribbon`);\n }\n sheet.badges?.forEach((badge, i) => {\n this.claim(badge.id, `${path}.badges[${i}]`);\n this.checkModifiers(badge, `${path}.badges[${i}]`);\n });\n for (const place of ['above', 'below'] as const) {\n sheet.title?.[place]?.forEach((node, i) => this.walkNode(node, `${path}.title.${place}[${i}]`));\n }\n sheet.alerts?.forEach((alert, i) => {\n this.claim(alert.id, `${path}.alerts[${i}]`);\n this.checkModifiers(alert, `${path}.alerts[${i}]`);\n });\n this.walkChildren(sheet.children, path);\n if (sheet.sidePanel) {\n this.claim(sheet.sidePanel.id, `${path}.sidePanel`);\n this.checkModifiers(sheet.sidePanel, `${path}.sidePanel`);\n }\n }\n\n private checkFieldNode(node: FieldNode, path: string) {\n const def = this.need(node.field, `${path}.field`);\n if (def && node.totals) {\n if (def.type !== 'one2many') {\n this.report(`${path}.totals`, `totals only apply to one2many fields; \"${node.field}\" is a ${def.type}`);\n } else {\n node.totals.forEach((column, i) => {\n const sub = has(def.fields, column) ? def.fields[column] : undefined;\n if (!sub) this.report(`${path}.totals[${i}]`, `\"${column}\" is not a field of the lines of \"${node.field}\"`);\n else if (!['integer', 'float', 'monetary'].includes(sub.type)) {\n this.report(`${path}.totals[${i}]`, `\"${column}\" is a ${sub.type}; only integer, float and monetary columns add up`);\n }\n });\n }\n }\n // Options that point at another field: by convention their names end in \"Field\".\n for (const [key, value] of Object.entries(node.options ?? {})) {\n if (key.endsWith('Field') && typeof value === 'string') this.need(value, `${path}.options.${key}`);\n }\n if (def && node.editMode && def.type !== 'one2many') {\n this.report(`${path}.editMode`, `editMode only applies to one2many fields; \"${node.field}\" is a ${def.type}`);\n }\n if (def && node.optionalColumns) {\n if (def.type !== 'one2many') {\n this.report(`${path}.optionalColumns`, `optional columns only apply to one2many fields; \"${node.field}\" is a ${def.type}`);\n } else {\n // The columns the table shows: those named, or every line field but the structural ones.\n const shown = node.columns ?? Object.keys(def.fields).filter((c) => c !== def.lineKinds?.field && c !== def.sequenceField);\n for (const column of Object.keys(node.optionalColumns)) {\n if (!shown.includes(column)) this.report(`${path}.optionalColumns.${column}`, `\"${column}\" is not a column of \"${node.field}\"`);\n }\n }\n }\n if (!def || !node.columns) return;\n if (def.type === 'one2many') {\n node.columns.forEach((column, i) => {\n if (!has(def.fields, column)) {\n this.report(`${path}.columns[${i}]`, `\"${column}\" is not a field of the lines of \"${node.field}\"`);\n }\n });\n } else if (def.type !== 'many2many') {\n this.report(`${path}.columns`, `columns only apply to one2many and many2many fields; \"${node.field}\" is a ${def.type}`);\n }\n }\n}\n", "import { FIELD_TYPES } from './names';\nimport type { Page } from './page';\nimport { ReferenceCheck, type PageIssue, type PageValidation } from './references';\nimport { FORMAT_VERSION } from './version';\n\nconst isObject = (value: unknown): value is Record<string, unknown> => value !== null && typeof value === 'object' && !Array.isArray(value);\nconst LAYOUTS = ['sheet', 'sections', 'tabs', 'wizard'];\n\n/**\n * The check a page gets as it is shown: its outline, then every name and\n * condition in it, the same as `validatePage` finds them. It leaves out the\n * key-by-key check of the format, and so the validation library, which an app\n * showing forms need not carry; run `validatePage` where pages are made or\n * tested. A page that passes is handed back as it is.\n */\nexport function checkPage(input: unknown): PageValidation {\n if (!isObject(input)) return { ok: false, issues: [{ path: '(page)', message: 'a page is a JSON object' }] };\n const issues: PageIssue[] = [];\n const say = (path: string, message: string) => issues.push({ path, message });\n if (input['fieldia'] !== FORMAT_VERSION) say('fieldia', `this build reads format ${FORMAT_VERSION}`);\n if (typeof input['id'] !== 'string' || !input['id']) say('id', 'a page needs an id');\n const data = input['data'];\n if (!isObject(data) || !(data['kind'] === 'responses' || (data['kind'] === 'record' && typeof data['model'] === 'string' && data['model']))) {\n say('data', 'data is { \"kind\": \"record\", \"model\": \u2026 } or { \"kind\": \"responses\" }');\n }\n const fields = input['fields'];\n if (!isObject(fields)) say('fields', 'fields is an object of field definitions, by name');\n else {\n for (const [name, def] of Object.entries(fields)) {\n if (!isObject(def) || !(FIELD_TYPES as readonly unknown[]).includes(def['type']) || typeof def['label'] !== 'string') {\n say(`fields.${name}`, 'a field needs a type Fieldia knows and a label');\n }\n }\n }\n const layout = input['layout'];\n const isList = isObject(layout) && layout['type'] === 'list';\n if (!isObject(layout) || (isList ? !Array.isArray(layout['columns']) : !LAYOUTS.includes(layout['type'] as string) || !Array.isArray(layout['children']))) {\n say('layout', 'the layout is a sheet, sections, tabs or wizard, with children, or a list with columns');\n }\n if (issues.length) return { ok: false, issues };\n const page = input as unknown as Page;\n try {\n const found = new ReferenceCheck(page).run();\n return found.length ? { ok: false, issues: found } : { ok: true, page };\n } catch (error) {\n return { ok: false, issues: [{ path: '(page)', message: `a part of this page cannot be read: ${(error as Error).message}` }] };\n }\n}\n", "import type { Page } from './page';\n\n/** Keys whose text a person reads: titles, labels, help, prompts, messages and a wizard's buttons. */\nconst TEXT_KEYS = new Set(['title', 'description', 'label', 'help', 'placeholder', 'message', 'text', 'confirm', 'nextLabel', 'backLabel', 'finishLabel']);\n\n/**\n * Parts that hold names or data, never words to translate: which line fields\n * mark sections and notes, a link's filter, a default value, a widget's options,\n * and what the page's data is.\n */\nconst NOT_TEXT = new Set(['lineKinds', 'filter', 'default', 'data']);\n\n/**\n * The page with every word a person reads passed through the app's own\n * translator, for apps that keep their translations by text or by key. Ids,\n * field names, choice values, conditions and data stay as they are; the page\n * given is left alone.\n */\nexport function translatePage(page: Page, translate: (text: string) => string): Page {\n const walk = (value: unknown, key: string | null): unknown => {\n if (typeof value === 'string') return key !== null && TEXT_KEYS.has(key) ? translate(value) : value;\n if (Array.isArray(value)) return value.map((item) => walk(item, null));\n if (value === null || typeof value !== 'object') return value;\n const out: Record<string, unknown> = {};\n for (const [name, inner] of Object.entries(value)) {\n // A field node's `options` are its widget's settings, not a list of choices.\n const widgetOptions = name === 'options' && !Array.isArray(inner);\n out[name] = NOT_TEXT.has(name) || widgetOptions ? inner : walk(inner, name);\n }\n return out;\n };\n return walk(page, null) as Page;\n}\n", "/**\n * evaluateModifier - Evaluate modifier expressions with form context\n *\n * Phase 2 implementation with full expression parser.\n * Supports Python-like expressions used in Flectra modifiers.\n *\n * Structura Reference:\n * - DynBehaviorManager.evaluateCondition() method\n * - Supports Python-like expressions: \"state == 'draft' and amount > 100\"\n *\n * Supported features:\n * - Comparison operators: ==, !=, <>, <, >, <=, >=\n * - In operators: in, not in\n * - Logical operators: and, or, not\n * - Parentheses for precedence\n * - Nested field access: partner_id.country_id.name\n * - Truthiness checks: partner_id (true if partner_id has value)\n *\n * @param expression - The modifier expression to evaluate\n * @param context - Current form values\n * @returns Boolean result of evaluation\n *\n * @example\n * ```typescript\n * // Simple boolean\n * evaluateModifier(true, {}) // => true\n *\n * // String boolean\n * evaluateModifier('1', {}) // => true\n * evaluateModifier('True', {}) // => true\n *\n * // Field truthiness\n * evaluateModifier('is_company', { is_company: true }) // => true\n * evaluateModifier('partner_id', { partner_id: null }) // => false\n *\n * // Comparison expressions\n * evaluateModifier(\"state == 'done'\", { state: 'done' }) // => true\n * evaluateModifier(\"amount > 100\", { amount: 150 }) // => true\n *\n * // Logical expressions\n * evaluateModifier(\"state == 'draft' and amount > 100\", { state: 'draft', amount: 150 }) // => true\n * evaluateModifier(\"state in ['draft', 'sent']\", { state: 'draft' }) // => true\n *\n * // Nested field access\n * evaluateModifier(\"partner_id.country_id == 5\", { partner_id: { country_id: 5 } }) // => true\n * ```\n */\n\nimport { tokenize } from './tokenizer';\nimport { ExpressionParser } from './parser';\nimport { evaluate, truthy } from './evaluator';\n\nexport function evaluateModifier(\n expression: string | boolean | undefined,\n context: Record<string, unknown>\n): boolean {\n // Undefined modifier = false (field is not affected)\n if (expression === undefined) {\n return false;\n }\n\n // Direct boolean value\n if (typeof expression === 'boolean') {\n return expression;\n }\n\n // String representation of boolean\n if (expression === '1' || expression === 'True' || expression === 'true') {\n return true;\n }\n\n if (expression === '0' || expression === 'False' || expression === 'false') {\n return false;\n }\n\n // Empty string = false\n if (expression === '') {\n return false;\n }\n\n // Parse and evaluate complex expression\n try {\n const tokens = tokenize(expression);\n\n // Empty token list\n if (tokens.length === 0) {\n return false;\n }\n\n const parser = new ExpressionParser(tokens);\n const ast = parser.parse();\n const result = evaluate(ast, context);\n\n // Convert result to boolean\n return truthy(result);\n } catch {\n // A page is validated before it runs (validatePage reads every\n // expression), so this only guards pages that skipped validation.\n // Fail safely - return false so field is not hidden/disabled by broken modifier\n return false;\n }\n}\n\n/**\n * Check if a modifier expression is valid and can be parsed\n *\n * @param expression - The modifier expression to check\n * @returns true if expression is valid, false otherwise\n */\nexport function isModifierValid(expression: string | boolean | undefined): boolean {\n if (expression === undefined || typeof expression === 'boolean') {\n return true;\n }\n\n if (expression === '') {\n return true;\n }\n\n try {\n const tokens = tokenize(expression);\n if (tokens.length === 0) {\n return true;\n }\n const parser = new ExpressionParser(tokens);\n parser.parse();\n return true;\n } catch {\n return false;\n }\n}\n", "import type { Field, LineField } from '../format/field';\nimport type { JsonValue } from '../format/json';\n\n/**\n * The values a form holds while someone edits it. Plain JSON, so a draft can\n * be stored and a record handed to any data source.\n */\n\nexport type RecordId = number | string;\n\n/** A related record, as a many2one or many2many holds it: enough to show it. */\nexport interface RelatedRecord {\n id: RecordId;\n label: string;\n}\n\n/** A reference points at a record of one of several models. */\nexport interface ReferenceValue {\n model: string;\n id: RecordId;\n label: string;\n}\n\n/** An uploaded or stored file. `data` is base64; `url` is where a stored one lives. */\nexport interface FileValue {\n name: string;\n type: string;\n size: number;\n data?: string;\n url?: string;\n}\n\n/**\n * One line of a one2many. `key` is stable for the life of the form, so a line\n * keeps its identity while it is edited; `id` is the saved record's id, absent\n * until the line is saved.\n */\nexport interface Line {\n key: string;\n id?: RecordId;\n values: Values;\n}\n\nexport type Value =\n | JsonValue\n | RelatedRecord\n | RelatedRecord[]\n | ReferenceValue\n | FileValue\n | Line[];\n\nexport type Values = Record<string, Value>;\n\ntype AnyField = Field | LineField;\n\n/** What a field holds before anyone types in it. */\nexport function emptyValue(field: AnyField): Value {\n switch (field.type) {\n case 'boolean':\n return false;\n case 'many2many':\n case 'one2many':\n return [];\n case 'selection':\n return field.multiple ? [] : null;\n default:\n return null;\n }\n}\n\n/** A fresh record: each field's default, or its empty value. */\nexport function initialValues(fields: Record<string, AnyField>): Values {\n const values: Values = {};\n for (const [name, field] of Object.entries(fields)) {\n values[name] = field.default !== undefined ? structuredCopy(field.default) : emptyValue(field);\n }\n return values;\n}\n\n/** Nothing worth keeping: no value, blank text, or an empty list. Numbers and booleans never are. */\nexport function isEmpty(_field: AnyField, value: Value | undefined): boolean {\n if (value === null || value === undefined) return true;\n if (typeof value === 'string') return value.trim() === '';\n if (Array.isArray(value)) return value.length === 0;\n return false;\n}\n\n/**\n * The values as modifiers read them, matching what backends write in their\n * expressions: a many2one is its id, a many2many its ids, a reference\n * \"model,id\", a file its name, and lines a list (so `not child_ids` works).\n */\nexport function expressionContext(values: Values, fields: Record<string, AnyField>): Record<string, unknown> {\n const context: Record<string, unknown> = {};\n for (const [name, value] of Object.entries(values)) {\n const field = fields[name];\n context[name] = field ? forExpressions(field, value) : value;\n }\n return context;\n}\n\nfunction forExpressions(field: AnyField, value: Value): unknown {\n if (value === null || value === undefined) return null;\n switch (field.type) {\n case 'many2one':\n return (value as RelatedRecord).id;\n case 'many2many':\n return (value as RelatedRecord[]).map((record) => record.id);\n case 'one2many':\n return (value as Line[]).map((line) => line.key);\n case 'reference': {\n const ref = value as ReferenceValue;\n return `${ref.model},${ref.id}`;\n }\n case 'binary':\n case 'image':\n return (value as FileValue).name;\n default:\n return value;\n }\n}\n\n/**\n * What a line of a one2many is: a section heading, a note, or (null) an item.\n * Lines only have kinds when the field declares `lineKinds`.\n */\nexport function lineKind(field: Extract<Field, { type: 'one2many' }>, values: Values): 'section' | 'note' | null {\n const kinds = field.lineKinds;\n if (!kinds) return null;\n const value = values[kinds.field];\n if (value === (kinds.section ?? 'section')) return 'section';\n if (value === (kinds.note ?? 'note')) return 'note';\n return null;\n}\n\n/** A deep copy of plain JSON. */\nexport function structuredCopy<T>(value: T): T {\n return value === undefined ? value : (JSON.parse(JSON.stringify(value)) as T);\n}\n", "/**\n * Validation messages, by language. `{label}` is the field's label; the other\n * placeholders are named in each English message. English keeps the React\n * engine's wording; Arabic, German and French build on its translations.\n */\nexport interface Messages {\n required: string;\n maxLength: string;\n pattern: string;\n text: string;\n number: string;\n integer: string;\n min: string;\n max: string;\n decimals: string;\n boolean: string;\n dateFormat: string;\n dateInvalid: string;\n datetimeFormat: string;\n datetimeInvalid: string;\n choice: string;\n choices: string;\n record: string;\n records: string;\n reference: string;\n file: string;\n fileSize: string;\n fileType: string;\n /** Joins the last two items of a list: \"PDF or image\". */\n or: string;\n}\n\nexport type Locale = 'en' | 'ar' | 'de' | 'fr';\n\nexport const MESSAGES: Record<Locale, Messages> = {\n en: {\n required: '{label} is required',\n maxLength: 'Maximum {max} characters allowed',\n pattern: '{label} is not in the expected format',\n text: '{label} must be text',\n number: '{label} must be a number',\n integer: '{label} must be a whole number',\n min: '{label} must be at least {min}',\n max: '{label} must be at most {max}',\n decimals: 'Maximum {digits} decimal places allowed',\n boolean: '{label} must be yes or no',\n dateFormat: 'Invalid date format (expected YYYY-MM-DD)',\n dateInvalid: 'Invalid date (check month/day values)',\n datetimeFormat: 'Invalid date and time format (expected YYYY-MM-DDTHH:MM:SS)',\n datetimeInvalid: 'Invalid date and time (check the values)',\n choice: 'Must be one of: {options}',\n choices: '{label} must be a list of choices',\n record: '{label} must be a record',\n records: '{label} must be a list of records',\n reference: '{label} must point to {aModels}',\n file: '{label} must be a file',\n fileSize: '{label} is larger than {size}',\n fileType: '{label} must be {aTypes} file',\n or: 'or',\n },\n ar: {\n required: '{label} \u0645\u0637\u0644\u0648\u0628',\n maxLength: '\u0627\u0644\u062D\u062F \u0627\u0644\u0623\u0642\u0635\u0649 {max} \u062D\u0631\u0641\u064B\u0627',\n pattern: '\u0635\u064A\u063A\u0629 {label} \u063A\u064A\u0631 \u0635\u062D\u064A\u062D\u0629',\n text: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0646\u0635\u064B\u0627',\n number: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0631\u0642\u0645\u064B\u0627',\n integer: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0631\u0642\u0645\u064B\u0627 \u0635\u062D\u064A\u062D\u064B\u0627',\n min: '\u064A\u062C\u0628 \u0623\u0644\u0627 \u064A\u0642\u0644 {label} \u0639\u0646 {min}',\n max: '\u064A\u062C\u0628 \u0623\u0644\u0627 \u064A\u0632\u064A\u062F {label} \u0639\u0646 {max}',\n decimals: '\u0627\u0644\u062D\u062F \u0627\u0644\u0623\u0642\u0635\u0649 {digits} \u0645\u0646\u0627\u0632\u0644 \u0639\u0634\u0631\u064A\u0629',\n boolean: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0646\u0639\u0645 \u0623\u0648 \u0644\u0627',\n dateFormat: '\u0635\u064A\u063A\u0629 \u0627\u0644\u062A\u0627\u0631\u064A\u062E \u063A\u064A\u0631 \u0635\u062D\u064A\u062D\u0629 (\u0627\u0644\u0645\u062A\u0648\u0642\u0639 YYYY-MM-DD)',\n dateInvalid: '\u0627\u0644\u062A\u0627\u0631\u064A\u062E \u063A\u064A\u0631 \u0635\u062D\u064A\u062D (\u062A\u062D\u0642\u0642 \u0645\u0646 \u0627\u0644\u0634\u0647\u0631 \u0648\u0627\u0644\u064A\u0648\u0645)',\n datetimeFormat: '\u0635\u064A\u063A\u0629 \u0627\u0644\u062A\u0627\u0631\u064A\u062E \u0648\u0627\u0644\u0648\u0642\u062A \u063A\u064A\u0631 \u0635\u062D\u064A\u062D\u0629 (\u0627\u0644\u0645\u062A\u0648\u0642\u0639 YYYY-MM-DDTHH:MM:SS)',\n datetimeInvalid: '\u0627\u0644\u062A\u0627\u0631\u064A\u062E \u0648\u0627\u0644\u0648\u0642\u062A \u063A\u064A\u0631 \u0635\u062D\u064A\u062D\u064A\u0646',\n choice: '\u064A\u062C\u0628 \u0623\u0646 \u062A\u0643\u0648\u0646 \u0627\u0644\u0642\u064A\u0645\u0629 \u0648\u0627\u062D\u062F\u0629 \u0645\u0646: {options}',\n choices: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0642\u0627\u0626\u0645\u0629 \u0627\u062E\u062A\u064A\u0627\u0631\u0627\u062A',\n record: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0633\u062C\u0644\u064B\u0627',\n records: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0642\u0627\u0626\u0645\u0629 \u0633\u062C\u0644\u0627\u062A',\n reference: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0634\u064A\u0631 {label} \u0625\u0644\u0649 {models}',\n file: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0645\u0644\u0641\u064B\u0627',\n fileSize: '\u062D\u062C\u0645 {label} \u0623\u0643\u0628\u0631 \u0645\u0646 {size}',\n fileType: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0645\u0644\u0641 {types}',\n or: '\u0623\u0648',\n },\n de: {\n required: '{label} ist erforderlich',\n maxLength: 'Maximal {max} Zeichen erlaubt',\n pattern: '{label} hat nicht das erwartete Format',\n text: '{label} muss Text sein',\n number: '{label} muss eine Zahl sein',\n integer: '{label} muss eine ganze Zahl sein',\n min: '{label} muss mindestens {min} sein',\n max: '{label} darf h\u00F6chstens {max} sein',\n decimals: 'Maximal {digits} Nachkommastellen erlaubt',\n boolean: '{label} muss ja oder nein sein',\n dateFormat: 'Ung\u00FCltiges Datumsformat (erwartet JJJJ-MM-TT)',\n dateInvalid: 'Ung\u00FCltiges Datum (Monat und Tag pr\u00FCfen)',\n datetimeFormat: 'Ung\u00FCltiges Datums- und Zeitformat (erwartet JJJJ-MM-TTTHH:MM:SS)',\n datetimeInvalid: 'Ung\u00FCltiges Datum oder ung\u00FCltige Uhrzeit',\n choice: 'Muss eines davon sein: {options}',\n choices: '{label} muss eine Liste von Optionen sein',\n record: '{label} muss ein Datensatz sein',\n records: '{label} muss eine Liste von Datens\u00E4tzen sein',\n reference: '{label} muss auf {models} verweisen',\n file: '{label} muss eine Datei sein',\n fileSize: '{label} ist gr\u00F6\u00DFer als {size}',\n fileType: '{label} muss eine {types}-Datei sein',\n or: 'oder',\n },\n fr: {\n required: '{label} est obligatoire',\n maxLength: '{max} caract\u00E8res au maximum',\n pattern: \"{label} n'a pas le format attendu\",\n text: '{label} doit \u00EAtre du texte',\n number: '{label} doit \u00EAtre un nombre',\n integer: '{label} doit \u00EAtre un nombre entier',\n min: '{label} doit \u00EAtre au moins {min}',\n max: '{label} doit \u00EAtre au plus {max}',\n decimals: '{digits} d\u00E9cimales au maximum',\n boolean: '{label} doit \u00EAtre oui ou non',\n dateFormat: 'Format de date invalide (attendu AAAA-MM-JJ)',\n dateInvalid: 'Date invalide (v\u00E9rifiez le mois et le jour)',\n datetimeFormat: 'Format de date et heure invalide (attendu AAAA-MM-JJTHH:MM:SS)',\n datetimeInvalid: 'Date ou heure invalide',\n choice: 'Doit \u00EAtre parmi : {options}',\n choices: '{label} doit \u00EAtre une liste de choix',\n record: '{label} doit \u00EAtre un enregistrement',\n records: \"{label} doit \u00EAtre une liste d'enregistrements\",\n reference: '{label} doit pointer vers {models}',\n file: '{label} doit \u00EAtre un fichier',\n fileSize: '{label} d\u00E9passe {size}',\n fileType: '{label} doit \u00EAtre un fichier {types}',\n or: 'ou',\n },\n};\n\n/** Fill `{name}` placeholders. */\nexport function fill(template: string, values: Record<string, string | number>): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) => (name in values ? String(values[name]) : match));\n}\n", "import type { Field, LineField } from '../format/field';\nimport { fill, MESSAGES, type Messages } from './messages';\nimport { isEmpty, type FileValue, type ReferenceValue, type RelatedRecord, type Value } from './values';\n\n/**\n * Check one value against its field. Returns the message to show, or\n * undefined when the value is fine. The wording follows the React engine's\n * (\"Name is required\", \"Maximum 120 characters allowed\").\n *\n * An empty optional value passes everything: a pattern or a minimum applies\n * to what someone typed, not to a field they left alone.\n */\nexport function checkValue(\n field: Field | LineField,\n value: Value | undefined,\n required: boolean,\n messages: Messages = MESSAGES.en\n): string | undefined {\n const label = field.label || 'This field';\n const say = (key: keyof Messages, values: Record<string, string | number> = {}) => fill(messages[key], { label, ...values });\n if (isEmpty(field, value)) return required ? say('required') : undefined;\n\n switch (field.type) {\n case 'char':\n case 'text':\n case 'html': {\n if (typeof value !== 'string') return say('text');\n if ((field.type === 'char' || field.type === 'text') && field.size !== undefined && value.length > field.size) {\n return say('maxLength', { max: field.size });\n }\n if (field.type === 'char' && field.pattern !== undefined && !new RegExp(field.pattern).test(value)) {\n return say('pattern');\n }\n return undefined;\n }\n case 'integer':\n case 'float':\n case 'monetary': {\n if (typeof value !== 'number' || !Number.isFinite(value)) return say('number');\n if (field.type === 'integer' && !Number.isInteger(value)) return say('integer');\n if (field.min !== undefined && value < field.min) return say('min', { min: field.min });\n if (field.max !== undefined && value > field.max) return say('max', { max: field.max });\n if (field.type !== 'integer' && field.digits && decimals(value) > field.digits[1]) {\n return say('decimals', { digits: field.digits[1] });\n }\n return undefined;\n }\n case 'boolean':\n return typeof value === 'boolean' ? undefined : say('boolean');\n case 'date':\n return checkDate(value, say);\n case 'datetime':\n return checkDateTime(value, say);\n case 'selection': {\n const allowed = new Set(field.options.map((o) => o.value));\n const listing = say('choice', { options: field.options.map((o) => o.label).join(', ') });\n if (field.multiple) {\n if (!Array.isArray(value)) return say('choices');\n return value.every((v) => allowed.has(v as string | number)) ? undefined : listing;\n }\n return allowed.has(value as string | number) ? undefined : listing;\n }\n case 'many2one':\n return isRecord(value) ? undefined : say('record');\n case 'many2many':\n return Array.isArray(value) && value.every(isRecord) ? undefined : say('records');\n case 'reference': {\n const ref = value as ReferenceValue;\n if (!isRecord(value) || typeof ref.model !== 'string') return say('record');\n if (!field.models.some((m) => m.value === ref.model)) {\n const models = listOr(field.models.map((m) => m.label), messages.or);\n return say('reference', { models, aModels: article(models) });\n }\n return undefined;\n }\n case 'binary':\n case 'image':\n return checkFile(field, value, say, messages);\n default:\n return undefined;\n }\n}\n\nfunction decimals(value: number): number {\n const text = String(value);\n if (text.includes('e-')) return Number(text.split('e-')[1]);\n const dot = text.indexOf('.');\n return dot === -1 ? 0 : text.length - dot - 1;\n}\n\nfunction isRecord(value: unknown): value is RelatedRecord {\n return (\n value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n (typeof (value as RelatedRecord).id === 'number' || typeof (value as RelatedRecord).id === 'string') &&\n typeof (value as RelatedRecord).label === 'string'\n );\n}\n\ntype Say = (key: keyof Messages, values?: Record<string, string | number>) => string;\n\nfunction checkDate(value: Value | undefined, say: Say): string | undefined {\n if (typeof value !== 'string' || !/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return say('dateFormat');\n const [y, m, d] = value.split('-').map(Number);\n return realDay(y, m, d) ? undefined : say('dateInvalid');\n}\n\nconst ISO_DATETIME = /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d{1,9})?)?(?:Z|[+-]\\d{2}:\\d{2})?$/;\n\nfunction checkDateTime(value: Value | undefined, say: Say): string | undefined {\n const match = typeof value === 'string' ? ISO_DATETIME.exec(value) : null;\n if (!match) return say('datetimeFormat');\n const [y, mo, d, h, mi, s] = match.slice(1).map((part) => Number(part ?? 0));\n return realDay(y, mo, d) && h < 24 && mi < 60 && s < 60 ? undefined : say('datetimeInvalid');\n}\n\nfunction realDay(year: number, month: number, day: number): boolean {\n if (month < 1 || month > 12 || day < 1) return false;\n const lengths = [31, year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n return day <= lengths[month - 1];\n}\n\nfunction checkFile(field: Field | LineField, value: Value | undefined, say: Say, messages: Messages): string | undefined {\n const file = value as FileValue;\n if (!isFile(value)) return say('file');\n if ('maxSize' in field && field.maxSize !== undefined && file.size > field.maxSize) {\n return say('fileSize', { size: formatBytes(field.maxSize) });\n }\n if (field.type === 'binary' && field.accept && !field.accept.some((pattern) => matchesType(pattern, file.type))) {\n const types = listOr(field.accept.map(describeType), messages.or);\n return say('fileType', { types, aTypes: article(types) });\n }\n return undefined;\n}\n\nfunction isFile(value: unknown): value is FileValue {\n const file = value as FileValue;\n return value !== null && typeof value === 'object' && typeof file.name === 'string' && typeof file.size === 'number';\n}\n\nfunction matchesType(pattern: string, type: string): boolean {\n return pattern.endsWith('/*') ? type.startsWith(pattern.slice(0, -1)) : pattern === type;\n}\n\nfunction describeType(pattern: string): string {\n if (pattern.endsWith('/*')) return pattern.slice(0, -2);\n if (pattern === 'application/pdf') return 'PDF';\n return (pattern.split('/')[1] ?? pattern).toUpperCase();\n}\n\nfunction listOr(items: string[], or: string): string {\n if (items.length <= 1) return items.join('');\n return `${items.slice(0, -1).join(', ')} ${or} ${items[items.length - 1]}`;\n}\n\nfunction article(phrase: string): string {\n return /^[aeiou]/i.test(phrase) ? `an ${phrase}` : `a ${phrase}`;\n}\n\n/** 1048576 -> \"1 MB\". */\nexport function formatBytes(bytes: number): string {\n const units = ['bytes', 'KB', 'MB', 'GB'];\n let size = bytes;\n let unit = 0;\n while (size >= 1024 && unit < units.length - 1) {\n size /= 1024;\n unit++;\n }\n return `${Number(size.toFixed(1))} ${units[unit]}`;\n}\n", "import type { FilterCondition, Fields } from '../format/field';\nimport type { JsonValue } from '../format/json';\nimport type { RecordId, RelatedRecord, Values } from './values';\n\n/**\n * How Fieldia reaches data. Fieldia knows no backend: an app implements this\n * interface for its own (a Flectra adapter, a REST client, a survey store),\n * and every method is optional so a page uses only what it needs.\n */\nexport interface DataSource {\n /** Read a record. Needed to edit an existing record. */\n load?(request: LoadRequest): Promise<Values>;\n /** Create (`id: null`) or update a record. Needed to save a record page. */\n save?(request: SaveRequest): Promise<SaveResult>;\n /** Recalculate after a value changes, the way a backend's onchange does. */\n onchange?(request: OnchangeRequest): Promise<OnchangeResult>;\n /** Find records a many2one, many2many or reference may point to. */\n search?(request: SearchRequest): Promise<RelatedRecord[]>;\n /** Make a record from just its name, for \"Create 'xyz'\" in a link field (a backend's name_create). */\n create?(request: CreateRequest): Promise<RelatedRecord>;\n /** Store one response to a `responses` page, such as a survey. */\n submit?(request: SubmitRequest): Promise<SubmitResult>;\n /** Records for a list: filtered, sorted and one page of them, with how many there are in all. */\n list?(request: ListRequest): Promise<ListResult>;\n /** How many records fall under each value of a field, for a list's Group By. */\n groups?(request: GroupRequest): Promise<Group[]>;\n}\n\nexport interface CreateRequest {\n model: string;\n /** What the person typed: the new record's name. */\n name: string;\n}\n\nexport interface LoadRequest {\n model: string;\n id: RecordId;\n /** The page's fields, so the source reads exactly what the page shows. */\n fields: Fields;\n}\n\nexport interface SaveRequest {\n model: string;\n id: RecordId | null;\n /** The page's fields, so the source knows each relation's model. */\n fields: Fields;\n /** Only what changed since the record was loaded or last saved. */\n changes: RecordChanges;\n /** Every value, for sources that save whole records. */\n values: Values;\n}\n\nexport interface SaveResult {\n id: RecordId;\n /** The record as stored, when the source recalculated anything. */\n values?: Values;\n}\n\nexport interface OnchangeRequest {\n model: string;\n id: RecordId | null;\n /** The field that changed. */\n changed: string;\n values: Values;\n}\n\nexport interface OnchangeResult {\n /** New values for other fields. */\n values?: Values;\n /** Something to tell the person editing, without blocking them. */\n warning?: string;\n}\n\nexport interface SearchRequest {\n /** The related model, from the field's `relation`. */\n model: string;\n query: string;\n /** The field's filter, with every `valueFrom` already replaced by its value. */\n filter?: ResolvedFilter[];\n limit?: number;\n}\n\nexport type ResolvedFilterCondition = Omit<FilterCondition, 'valueFrom' | 'value'> & { value: JsonValue };\n\nexport interface SortOrder {\n field: string;\n desc?: boolean;\n}\n\nexport interface ListRequest {\n model: string;\n /** The fields the list shows. */\n fields: string[];\n /** What the search bar and the open groups ask for; an `any` group is an OR. */\n filter: ResolvedFilter[];\n /** By the first, then the next: a link by its label, empty values last. */\n sort: SortOrder[];\n offset: number;\n limit: number;\n}\n\nexport interface ListResult {\n records: { id: RecordId; values: Values }[];\n /** How many records match in all, for the pager. */\n total: number;\n}\n\nexport interface GroupRequest {\n model: string;\n field: string;\n filter: ResolvedFilter[];\n}\n\n/** The records under one value of a field: a link's by its id, and those with none as a group of their own (value null). */\nexport interface Group {\n value: JsonValue;\n label: string;\n count: number;\n}\n\n/**\n * A filter as a search receives it: each `valueFrom` already replaced by its\n * value. An adapter must keep the groups: `any` is an OR, `all` an AND.\n */\nexport type ResolvedFilter = ResolvedFilterCondition | { any: ResolvedFilter[] } | { all: ResolvedFilter[] };\n\nexport interface SubmitRequest {\n pageId: string;\n /** The answers to the questions that were shown. Skipped steps are left out. */\n values: Values;\n}\n\nexport interface SubmitResult {\n id?: RecordId;\n}\n\n/**\n * What changed, using the operation names Odoo gives its x2many commands, so\n * an adapter maps them one to one.\n */\nexport interface RecordChanges {\n /** Changed values of every field that is not one2many or many2many. */\n values: Values;\n /** one2many changes, per field. */\n lines: Record<string, LineOp[]>;\n /** many2many changes, per field. */\n links: Record<string, LinkOp[]>;\n}\n\nexport type LineOp =\n | { op: 'create'; key: string; values: Values }\n | { op: 'update'; id: RecordId; values: Values }\n | { op: 'delete'; id: RecordId };\n\nexport type LinkOp =\n | { op: 'link'; id: RecordId }\n | { op: 'unlink'; id: RecordId }\n | { op: 'set'; ids: RecordId[] }\n | { op: 'clear' };\n\n/**\n * Why a save was refused, so each kind is shown where it belongs: `fields`\n * under those fields, a `rule` (a backend's business rule) in a dialog,\n * `network` in a banner with Retry, and `other` beside Save with Retry.\n */\nexport interface SaveProblem {\n kind: 'fields' | 'rule' | 'network' | 'other';\n message: string;\n /** For `fields`: a message for each field, by name. */\n fields?: Record<string, string>;\n}\n\n/** An error for a data source's save to throw when the backend refuses it. */\nexport function saveRefused(problem: SaveProblem): Error & { problem: SaveProblem } {\n return Object.assign(new Error(problem.message), { problem });\n}\n\n/** What a failed save tells: its own problem, a failed fetch as the network, anything else as it is. */\nexport function saveProblemOf(error: unknown): SaveProblem {\n const carried = (error as { problem?: SaveProblem } | null)?.problem;\n if (carried && typeof carried.kind === 'string') return carried;\n const message = error instanceof Error ? error.message : String(error);\n if (error instanceof TypeError && /fetch|network|load failed/i.test(message)) return { kind: 'network', message };\n return { kind: 'other', message };\n}\n", "import type { JsonValue } from '../format/json';\nimport type { ResolvedFilter, ResolvedFilterCondition } from './data-source';\nimport type { RelatedRecord, Values } from './values';\n\n/**\n * Whether a record passes a filter, the way a search should judge it: every\n * item of the list holds, an `any` group when one of its items holds, an `all`\n * group when each does. The memory data source searches with it; an app may too.\n */\nexport function matchesFilter(values: Values, filter: readonly ResolvedFilter[]): boolean {\n return filter.every((item) => holds(values, item));\n}\n\nfunction holds(values: Values, item: ResolvedFilter): boolean {\n if ('any' in item) return item.any.some((inner) => holds(values, inner));\n if ('all' in item) return item.all.every((inner) => holds(values, inner));\n return meets(values, item);\n}\n\n/** Empty is not set: no value, empty text, an empty list. */\nfunction isSet(value: unknown): boolean {\n return value !== null && value !== undefined && value !== '' && value !== false && !(Array.isArray(value) && !value.length);\n}\n\nfunction meets(values: Values, condition: ResolvedFilterCondition): boolean {\n const raw = values[condition.field];\n // A link compares by its id.\n const actual = raw !== null && typeof raw === 'object' && !Array.isArray(raw) && 'id' in raw ? (raw as RelatedRecord).id : (raw as JsonValue | undefined);\n const expected = condition.value;\n // Text is looked for in a link's name, as a search by name does.\n const text = raw !== null && typeof raw === 'object' && !Array.isArray(raw) && 'label' in raw ? String((raw as RelatedRecord).label) : String(actual ?? '');\n switch (condition.op) {\n case '=':\n return actual === expected;\n case '!=':\n return actual !== expected;\n case '<':\n return isSet(actual) && (actual as number) < (expected as number);\n case '>':\n return isSet(actual) && (actual as number) > (expected as number);\n case '<=':\n return isSet(actual) && (actual as number) <= (expected as number);\n case '>=':\n return isSet(actual) && (actual as number) >= (expected as number);\n case 'in':\n return Array.isArray(expected) && expected.includes(actual as JsonValue);\n case 'not in':\n return Array.isArray(expected) && !expected.includes(actual as JsonValue);\n case 'like':\n return text.includes(String(expected));\n case 'ilike':\n return text.toLowerCase().includes(String(expected).toLowerCase());\n case 'startswith':\n return text.toLowerCase().startsWith(String(expected).toLowerCase());\n case 'endswith':\n return text.toLowerCase().endsWith(String(expected).toLowerCase());\n case 'set':\n return isSet(raw);\n case 'notset':\n return !isSet(raw);\n case 'between': {\n if (!isSet(actual) || !Array.isArray(expected)) return false;\n const [low, high] = expected as (number | string)[];\n return (actual as number | string) >= low && (actual as number | string) <= high;\n }\n }\n}\n", "import type { JsonValue } from '../format/json';\nimport type { ListNode } from '../format/layout';\nimport type { Page } from '../format/page';\nimport type { ResolvedFilter, ResolvedFilterCondition } from './data-source';\nimport { fill } from './messages';\n\n/**\n * What a list's search bar holds, each shown as a chip: values searched in\n * one field (any of them), named filters (any of them), a custom filter, or\n * the fields the list is grouped by. The facets all apply together.\n */\nexport type Facet =\n | { kind: 'field'; field: string; label: string; values: { op: ResolvedFilterCondition['op']; value: JsonValue; label: string }[] }\n | { kind: 'filters'; ids: string[]; labels: string[] }\n | { kind: 'custom'; label: string; filter: ResolvedFilter[] }\n | { kind: 'groupBy'; fields: string[]; labels: string[] };\n\n/** One way to search what was typed: a field, how to compare, and the words that say so. */\nexport interface Suggestion {\n field: string;\n fieldLabel: string;\n op: ResolvedFilterCondition['op'];\n value: JsonValue;\n valueLabel: string;\n label: string;\n}\n\nconst TEXT = new Set(['char', 'text', 'html']);\nconst NUMBER = new Set(['integer', 'float', 'monetary']);\nconst LINK = new Set(['many2one', 'many2many']);\n\n/**\n * The searches the typed text can be: text looked for in each text field, a\n * choice whose label it matches, a number where it is one, a link by its\n * record's name. Only the list's search fields, the columns unless it says.\n */\nexport function suggestions(typed: string, page: Page, list: ListNode, words: { searchFor: string } = { searchFor: 'Search {field} for: {text}' }): Suggestion[] {\n const text = typed.trim();\n if (!text) return [];\n const found: Suggestion[] = [];\n for (const field of list.searchFields ?? list.columns) {\n const def = page.fields[field];\n if (!def) continue;\n const say = (op: Suggestion['op'], value: JsonValue, valueLabel: string, label?: string) =>\n found.push({ field, fieldLabel: def.label, op, value, valueLabel, label: label ?? fill(words.searchFor, { field: def.label, text }) });\n if (TEXT.has(def.type) || LINK.has(def.type)) say('ilike', text, text);\n else if (def.type === 'selection') {\n const lower = text.toLowerCase();\n for (const option of def.options) if (option.label.toLowerCase().includes(lower)) say('=', option.value, option.label, `${def.label}: ${option.label}`);\n } else if (NUMBER.has(def.type)) {\n const number = Number(text.replace(/[\\s,]/g, ''));\n if (text && Number.isFinite(number)) say('=', number, text);\n }\n }\n // Text fields first, then the choices, then the links: the order a person looks in.\n const rank = (s: Suggestion) => {\n const type = page.fields[s.field]?.type ?? '';\n return TEXT.has(type) ? 0 : type === 'selection' ? 1 : NUMBER.has(type) ? 2 : 3;\n };\n return found.map((s, i) => ({ s, i })).sort((a, b) => rank(a.s) - rank(b.s) || a.i - b.i).map(({ s }) => s);\n}\n\n/** The filter a list's facets make: the values of one field any of them, named filters any of them, the facets all together. */\nexport function facetsToFilter(facets: readonly Facet[], list: ListNode): ResolvedFilter[] {\n const filter: ResolvedFilter[] = [];\n for (const facet of facets) {\n if (facet.kind === 'field') {\n const conditions = facet.values.map((v) => ({ field: facet.field, op: v.op, value: v.value }));\n filter.push(conditions.length === 1 ? conditions[0] : { any: conditions });\n } else if (facet.kind === 'filters') {\n // A list's own filters have no valueFrom: their conditions are already values.\n const chosen = facet.ids.map((id) => (list.filters?.find((f) => f.id === id)?.filter ?? []) as ResolvedFilter[]).filter((items) => items.length);\n if (chosen.length === 1) filter.push(...chosen[0]);\n else if (chosen.length > 1) filter.push({ any: chosen.map((items) => (items.length === 1 ? items[0] : { all: items })) });\n } else if (facet.kind === 'custom') {\n filter.push(...facet.filter);\n }\n }\n return filter;\n}\n\n/** The fields a list is grouped by, in order, from its Group By facet. */\nexport function groupByFields(facets: readonly Facet[]): string[] {\n return facets.find((f): f is Extract<Facet, { kind: 'groupBy' }> => f.kind === 'groupBy')?.fields ?? [];\n}\n", "/**\n * Timers, injected. Core compiles without the DOM or Node's types, and tests\n * drive time by hand instead of waiting for it.\n */\nexport interface Scheduler {\n setTimeout(callback: () => void, ms: number): unknown;\n clearTimeout(handle: unknown): void;\n}\n\ninterface HostTimers {\n setTimeout(callback: () => void, ms: number): unknown;\n clearTimeout(handle: unknown): void;\n}\n\n/** The host's own timers: the browser's or Node's, whichever is running. */\nexport const hostScheduler: Scheduler = {\n setTimeout: (callback, ms) => (globalThis as unknown as HostTimers).setTimeout(callback, ms),\n clearTimeout: (handle) => (globalThis as unknown as HostTimers).clearTimeout(handle),\n};\n\n/** Resolve after `ms`, on the given scheduler. */\nexport function wait(ms: number, scheduler: Scheduler = hostScheduler): Promise<void> {\n return new Promise((resolve) => {\n scheduler.setTimeout(resolve, ms);\n });\n}\n", "import type { Field, Fields } from '../format/field';\nimport type { JsonValue } from '../format/json';\nimport type {\n DataSource,\n Group,\n GroupRequest,\n ListRequest,\n ListResult,\n LineOp,\n LinkOp,\n LoadRequest,\n OnchangeRequest,\n OnchangeResult,\n SaveRequest,\n SaveResult,\n SearchRequest,\n CreateRequest,\n SubmitRequest,\n SubmitResult,\n} from './data-source';\nimport { matchesFilter } from './filter';\nimport { wait, type Scheduler } from './scheduler';\nimport { structuredCopy, type Line, type RecordId, type RelatedRecord, type Value, type Values } from './values';\n\nexport interface MemoryDataSourceOptions {\n /** Records by model, then by id. */\n records?: Record<string, Record<string, Values>>;\n /** Recalculation rules by model, then by the field that changed. */\n onchange?: Record<string, Record<string, (values: Values) => Values>>;\n /** Warnings by model, then by the field that changed: a message, or null for none. */\n warnings?: Record<string, Record<string, (values: Values) => string | null>>;\n /** Which value names a record in search results, per model. Defaults to `name`. */\n labelField?: Record<string, string>;\n /** Answer after this long, so a demo shows its loading states. */\n delayMs?: number;\n scheduler?: Scheduler;\n}\n\nexport interface MemoryDataSource extends Required<DataSource> {\n readonly records: Record<string, Record<string, Values>>;\n readonly responses: SubmitRequest[];\n readonly calls: { method: keyof DataSource; request: unknown }[];\n}\n\n/**\n * A data source that keeps everything in memory. It implements the whole\n * interface, the way a backend would, so tests and demos exercise the same\n * paths a real adapter takes.\n */\nexport function createMemoryDataSource(options: MemoryDataSourceOptions = {}): MemoryDataSource {\n const records = structuredCopy(options.records ?? {});\n const responses: SubmitRequest[] = [];\n const calls: MemoryDataSource['calls'] = [];\n let lineIds = 1000;\n\n const pause = () => (options.delayMs ? wait(options.delayMs, options.scheduler) : Promise.resolve());\n const table = (model: string) => (records[model] ??= {});\n const labelOf = (model: string, id: RecordId) => {\n const value = table(model)[String(id)]?.[options.labelField?.[model] ?? 'name'];\n return typeof value === 'string' ? value : String(id);\n };\n const nextId = (model: string) => Math.max(0, ...Object.keys(table(model)).map(Number).filter(Number.isFinite)) + 1;\n const asId = (key: string): RecordId => (Number.isFinite(Number(key)) ? Number(key) : key);\n\n function applyLines(current: Line[], ops: LineOp[]): Line[] {\n let lines = [...current];\n for (const op of ops) {\n if (op.op === 'create') lines.push({ key: op.key, id: ++lineIds, values: structuredCopy(op.values) });\n else if (op.op === 'update') lines = lines.map((l) => (l.id === op.id ? { ...l, values: { ...l.values, ...structuredCopy(op.values) } } : l));\n else lines = lines.filter((l) => l.id !== op.id);\n }\n return lines;\n }\n\n function applyLinks(current: RelatedRecord[], ops: LinkOp[], model: string): RelatedRecord[] {\n let links = [...current];\n const related = (id: RecordId): RelatedRecord => ({ id, label: labelOf(model, id) });\n for (const op of ops) {\n if (op.op === 'link' && !links.some((r) => r.id === op.id)) links.push(related(op.id));\n else if (op.op === 'unlink') links = links.filter((r) => r.id !== op.id);\n else if (op.op === 'set') links = op.ids.map(related);\n else if (op.op === 'clear') links = [];\n }\n return links;\n }\n\n function relationOf(fields: Fields, name: string): string {\n const field: Field | undefined = fields[name];\n return field && 'relation' in field ? field.relation : name;\n }\n\n return {\n records,\n responses,\n calls,\n\n async load(request: LoadRequest): Promise<Values> {\n calls.push({ method: 'load', request });\n await pause();\n const stored = table(request.model)[String(request.id)];\n if (!stored) throw new Error(`No ${request.model} record with id ${request.id}`);\n return structuredCopy(stored);\n },\n\n async save(request: SaveRequest): Promise<SaveResult> {\n calls.push({ method: 'save', request });\n await pause();\n const id = request.id ?? nextId(request.model);\n const stored: Values = { ...(table(request.model)[String(id)] ?? {}), ...structuredCopy(request.changes.values) };\n for (const [name, ops] of Object.entries(request.changes.lines)) {\n stored[name] = applyLines((stored[name] as Line[] | undefined) ?? [], ops);\n }\n for (const [name, ops] of Object.entries(request.changes.links)) {\n stored[name] = applyLinks((stored[name] as RelatedRecord[] | undefined) ?? [], ops, relationOf(request.fields, name));\n }\n table(request.model)[String(id)] = stored;\n return { id, values: structuredCopy(stored) };\n },\n\n async onchange(request: OnchangeRequest): Promise<OnchangeResult> {\n calls.push({ method: 'onchange', request });\n await pause();\n const rule = options.onchange?.[request.model]?.[request.changed];\n const warn = options.warnings?.[request.model]?.[request.changed];\n const result: OnchangeResult = rule ? { values: rule(structuredCopy(request.values)) } : {};\n const warning = warn?.(structuredCopy(request.values));\n return warning ? { ...result, warning } : result;\n },\n\n async search(request: SearchRequest): Promise<RelatedRecord[]> {\n calls.push({ method: 'search', request });\n await pause();\n const query = request.query.trim().toLowerCase();\n return Object.entries(table(request.model))\n .filter(([, values]) => matchesFilter(values, request.filter ?? []))\n .map(([key]) => ({ id: asId(key), label: labelOf(request.model, asId(key)) }))\n .filter((record) => record.label.toLowerCase().includes(query))\n .slice(0, request.limit ?? 8);\n },\n\n async list(request: ListRequest): Promise<ListResult> {\n calls.push({ method: 'list', request });\n await pause();\n const matching = Object.entries(table(request.model))\n .filter(([, values]) => matchesFilter(values, request.filter))\n .map(([key, values]) => ({ id: asId(key), values }));\n matching.sort((a, b) => {\n for (const order of request.sort) {\n const compared = compareValues(a.values[order.field], b.values[order.field]);\n // Empty last, whichever way the rest goes.\n if (compared.empty) return compared.result;\n if (compared.result) return order.desc ? -compared.result : compared.result;\n }\n return 0;\n });\n return {\n total: matching.length,\n records: matching.slice(request.offset, request.offset + request.limit).map(({ id, values }) => ({\n id,\n values: Object.fromEntries(request.fields.map((field) => [field, structuredCopy(values[field] ?? null) as Value])),\n })),\n };\n },\n\n async groups(request: GroupRequest): Promise<Group[]> {\n calls.push({ method: 'groups', request });\n await pause();\n const counted = new Map<string, Group>();\n for (const values of Object.values(table(request.model))) {\n if (!matchesFilter(values, request.filter)) continue;\n const raw = values[request.field] ?? null;\n const link = raw !== null && typeof raw === 'object' && !Array.isArray(raw) && 'id' in raw ? (raw as RelatedRecord) : null;\n const value = (link ? link.id : raw) as JsonValue;\n const key = JSON.stringify(value);\n const group = counted.get(key) ?? { value, label: link ? link.label : raw === null || raw === '' ? '' : String(raw), count: 0 };\n group.count++;\n counted.set(key, group);\n }\n return [...counted.values()].sort((a, b) => (a.value === null) === (b.value === null) ? a.label.localeCompare(b.label) : a.value === null ? 1 : -1);\n },\n\n async create(request: CreateRequest): Promise<RelatedRecord> {\n calls.push({ method: 'create', request });\n await pause();\n const rows = table(request.model);\n const id = Object.keys(rows).reduce((top, key) => Math.max(top, Number(key) || 0), 0) + 1;\n rows[String(id)] = { name: request.name };\n return { id, label: request.name };\n },\n\n async submit(request: SubmitRequest): Promise<SubmitResult> {\n calls.push({ method: 'submit', request });\n await pause();\n responses.push(structuredCopy(request));\n return { id: responses.length };\n },\n };\n}\n\n/** Two values in order: a link by its label, text by the reader's rules, numbers by size; `empty` says one of them had nothing. */\nfunction compareValues(a: unknown, b: unknown): { result: number; empty: boolean } {\n const blank = (v: unknown) => v === null || v === undefined || v === '';\n if (blank(a) || blank(b)) return { result: blank(a) === blank(b) ? 0 : blank(a) ? 1 : -1, empty: blank(a) !== blank(b) };\n const label = (v: unknown) => (typeof v === 'object' && v !== null && 'label' in v ? (v as RelatedRecord).label : v);\n const [x, y] = [label(a), label(b)];\n if (typeof x === 'number' && typeof y === 'number') return { result: x - y, empty: false };\n return { result: String(x).localeCompare(String(y)), empty: false };\n}\n", "import type { Field, FilterItem, LineField } from '../format/field';\nimport type { JsonValue } from '../format/json';\nimport type { ButtonNode, LayoutNode, Modifier, RootLayout, StatButton, StepNode } from '../format/layout';\nimport type { Page } from '../format/page';\nimport { compileModifier, type CompiledModifier } from '../expression/modifier';\nimport { checkValue } from './check';\nimport { MESSAGES, type Messages } from './messages';\nimport { saveProblemOf, type DataSource, type LineOp, type LinkOp, type RecordChanges, type ResolvedFilter, type SaveProblem } from './data-source';\nimport { hostScheduler, type Scheduler } from './scheduler';\nimport {\n emptyValue,\n expressionContext,\n initialValues,\n isEmpty,\n lineKind,\n structuredCopy,\n type Line,\n type RecordId,\n type RelatedRecord,\n type Value,\n type Values,\n} from './values';\n\nexport type FormStatus = 'idle' | 'loading' | 'ready' | 'saving' | 'saved' | 'error';\n\nexport interface FormState {\n readonly status: FormStatus;\n readonly recordId: RecordId | null;\n readonly values: Readonly<Values>;\n /** Messages by field name; a line's field is `field.lineKey.subfield`. */\n readonly errors: Readonly<Record<string, string>>;\n /** Fields that differ from the record as loaded or last saved. */\n readonly dirty: readonly string[];\n /** A warning from the data source's onchange, shown without blocking. */\n readonly warning: string | null;\n /** The field whose change brought the warning, so it can be shown beside it. */\n readonly warningField: string | null;\n /** Why loading or saving failed. */\n readonly error: string | null;\n /** A saved draft that can be restored. */\n readonly draft: { savedAt: string } | null;\n /** The wizard step on screen, for a wizard page. */\n readonly step: string | null;\n /** Optional steps passed over with Skip: their answers are left out, and not asked for. */\n readonly skipped: readonly string[];\n /** Why the last save was refused, until the next one starts or the form is reset. */\n readonly saveProblem: SaveProblem | null;\n}\n\n/** What a layout element looks like right now. */\nexport interface NodeState {\n invisible: boolean;\n readonly: boolean;\n required: boolean;\n}\n\n/** localStorage fits this, and so does anything else with the same three methods. */\nexport interface DraftStore {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\nexport interface ActionRequest {\n /** The button or stat button pressed. */\n id: string;\n action: string;\n params?: { [key: string]: JsonValue };\n recordId: RecordId | null;\n values: Values;\n /** The records chosen in a list, when the button belongs to one. */\n recordIds?: RecordId[];\n}\n\nexport interface FormOptions {\n page: Page;\n dataSource?: DataSource;\n /** The record to edit. Leave out for a new record or a survey. */\n recordId?: RecordId | null;\n /** Values to start with, on top of each field's default. */\n values?: Values;\n /** What a button does. Fieldia hands the press over; the app decides. */\n onAction?: (request: ActionRequest) => void | Promise<void>;\n drafts?: { store: DraftStore; restore?: 'auto' | 'ask'; delayMs?: number };\n autosave?: { delayMs: number };\n scheduler?: Scheduler;\n /** Validation messages in the page's language. English by default. */\n messages?: Messages;\n}\n\nexport interface Form {\n readonly page: Page;\n getState(): FormState;\n subscribe(listener: (state: FormState) => void): () => void;\n load(): Promise<void>;\n setValue(name: string, value: Value): void;\n node(id: string): NodeState;\n fieldReadonly(name: string): boolean;\n /** What a field would be told if the form were checked now, or null when it passes. Nothing is shown. */\n problem(field: string): string | null;\n validate(): boolean;\n save(): Promise<boolean>;\n reset(): void;\n changes(): RecordChanges;\n addLine(field: string, values?: Values): string;\n updateLine(field: string, key: string, name: string, value: Value): void;\n removeLine(field: string, key: string): void;\n /** Move a line to another place among its lines, numbering its sequence field again. */\n moveLine(field: string, key: string, to: number): void;\n /**\n * What a line would become with these values once the data source's onchange\n * has run, as a line edited in a dialog shows its subtotal follow. Nothing is\n * written: the record, its changes and its autosave stay as they are.\n */\n previewLine(field: string, key: string, values: Values): Promise<Values>;\n /** Records a many2one, many2many or reference may point to. A reference needs `options.model`. */\n search(field: string, query: string, limit?: number, options?: { model?: string }): Promise<RelatedRecord[]>;\n /** The same, for a relation inside a one2many line, filtered by that line's values. */\n searchLine(field: string, key: string, subfield: string, query: string, limit?: number): Promise<RelatedRecord[]>;\n /** Whether a link field can make a record from a typed name: the data source must be able to. */\n canCreate(field: string): boolean;\n /** Make a record from a typed name, for the link field to point to. */\n quickCreate(field: string, name: string): Promise<RelatedRecord>;\n /** The same, for a link inside a one2many's lines. */\n canCreateLine(field: string, subfield: string): boolean;\n quickCreateLine(field: string, subfield: string, name: string): Promise<RelatedRecord>;\n steps(): string[];\n next(): boolean;\n back(): boolean;\n /** Pass over the step on screen, when it is optional and not the last one. */\n skip(): boolean;\n /**\n * Go to a step that applies. Back, at once; forward, only past steps that are\n * complete: it stops at the first one with a problem and shows it, and skips\n * an optional one instead.\n */\n goTo(step: string): boolean;\n /** Run a button; a list's button passes the records chosen in it. */\n runAction(id: string, chosen?: { recordIds: RecordId[] }): Promise<void>;\n restoreDraft(): void;\n discardDraft(): void;\n /** Resolves once every onchange, save and autosave started so far has finished. */\n settled(): Promise<void>;\n dispose(): void;\n}\n\ninterface IndexedNode {\n id: string;\n parent: string | null;\n kind: 'field' | 'button' | 'stat' | 'other' | 'step';\n field?: string;\n invisible: CompiledModifier;\n readonly: CompiledModifier;\n required: CompiledModifier;\n source: LayoutNode | StepNode | ButtonNode | StatButton | RootLayout | { id: string; invisible?: Modifier };\n}\n\n/**\n * The record state behind a page: values, what changed, what is visible and\n * required, errors, loading and saving. No DOM and no framework \u2014 every\n * binding renders from `getState()` and calls these methods.\n */\nexport function createForm(options: FormOptions): Form {\n const { page } = options;\n const scheduler = options.scheduler ?? hostScheduler;\n const messages = options.messages ?? MESSAGES.en;\n const index = indexLayout(page.layout);\n const steps = page.layout.type === 'wizard' ? page.layout.children.map((step) => step.id) : [];\n const draftKey = () => `fieldia:draft:${page.id}:${state.recordId ?? 'new'}`;\n\n let baseline: Values = { ...initialValues(page.fields), ...structuredCopy(options.values ?? {}) };\n let state: FormState = {\n status: options.recordId != null ? 'idle' : 'ready',\n recordId: options.recordId ?? null,\n values: structuredCopy(baseline),\n errors: {},\n dirty: [],\n warning: null,\n warningField: null,\n error: null,\n draft: null,\n step: steps[0] ?? null,\n skipped: [],\n saveProblem: null,\n };\n /** Field errors a refused save brought, each kept until its field changes from the value it was refused with. */\n let serverErrors: Record<string, { message: string; value: string }> = {};\n let lineKeys = 0;\n let onchangeSeq = 0;\n let draftTimer: unknown = null;\n let autosaveTimer: unknown = null;\n const pending = new Set<Promise<unknown>>();\n const listeners = new Set<(state: FormState) => void>();\n let contextCache: { values: Values; context: Record<string, unknown> } | null = null;\n\n function set(patch: Partial<FormState>) {\n state = { ...state, ...patch };\n for (const listener of [...listeners]) listener(state);\n }\n\n function track<T>(promise: Promise<T>): Promise<T> {\n pending.add(promise);\n const done = () => pending.delete(promise);\n promise.then(done, done);\n return promise;\n }\n\n function context(): Record<string, unknown> {\n if (contextCache?.values !== state.values) {\n contextCache = { values: state.values as Values, context: expressionContext(state.values as Values, page.fields) };\n }\n return contextCache.context;\n }\n\n function fieldDef(name: string): Field {\n const def = page.fields[name];\n if (!def) throw new Error(`The page has no field \"${name}\"`);\n return def;\n }\n\n function dirtyFields(values: Values): string[] {\n return Object.keys(page.fields).filter((name) => JSON.stringify(values[name] ?? null) !== JSON.stringify(baseline[name] ?? null));\n }\n\n function nodeState(id: string): NodeState {\n const node = index.get(id);\n if (!node) throw new Error(`The page has no element \"${id}\"`);\n const ctx = context();\n let invisible = node.invisible.evaluate(ctx);\n for (let parent = node.parent; !invisible && parent; parent = index.get(parent)?.parent ?? null) {\n invisible = index.get(parent)?.invisible.evaluate(ctx) ?? false;\n }\n // A section read-only right now makes everything inside it read-only too.\n let readonly = node.readonly.evaluate(ctx);\n for (let parent = node.parent; !readonly && parent; parent = index.get(parent)?.parent ?? null) {\n readonly = index.get(parent)?.readonly.evaluate(ctx) ?? false;\n }\n const def = node.field ? page.fields[node.field] : undefined;\n return {\n invisible,\n readonly: readonly || def?.readonly === true,\n required: node.required.evaluate(ctx) || def?.required === true,\n };\n }\n\n /** Field nodes inside `root` (or the whole page), visible right now. */\n function visibleFieldNodes(root?: string): IndexedNode[] {\n const inside = (node: IndexedNode) => {\n if (!root) return true;\n for (let at: string | null = node.id; at; at = index.get(at)?.parent ?? null) if (at === root) return true;\n return false;\n };\n // The whole page leaves out the steps passed over with Skip.\n const skipped = (node: IndexedNode) => {\n if (root || !state.skipped.length) return false;\n for (let at: string | null = node.id; at; at = index.get(at)?.parent ?? null) if (state.skipped.includes(at)) return true;\n return false;\n };\n return [...index.values()].filter((node) => node.kind === 'field' && inside(node) && !skipped(node) && !nodeState(node.id).invisible);\n }\n\n /** Errors for the visible fields under `root`, without publishing them. */\n function collectErrors(root?: string): Record<string, string> {\n const errors: Record<string, string> = {};\n for (const node of visibleFieldNodes(root)) {\n const name = node.field as string;\n if (errors[name]) continue;\n const def = page.fields[name];\n const message = checkValue(def, state.values[name], nodeState(node.id).required, messages);\n if (message) errors[name] = message;\n if (def.type === 'one2many') {\n for (const line of (state.values[name] as Line[] | null) ?? []) {\n // A section or note answers only for its text, never for what an item needs.\n const kind = lineKind(def, line.values);\n for (const [sub, subDef] of Object.entries(def.fields)) {\n if (kind && sub !== def.lineKinds?.text) continue;\n const lineMessage = checkValue(subDef, line.values[sub], subDef.required === true, messages);\n if (lineMessage) errors[`${name}.${line.key}.${sub}`] = lineMessage;\n }\n }\n }\n }\n return errors;\n }\n\n function writeValues(values: Values, extra: Partial<FormState> = {}) {\n const errors = Object.keys(state.errors).length ? revalidateShown(values) : state.errors;\n set({ values, dirty: dirtyFields(values), errors, ...extra });\n }\n\n /** Once errors are on screen, keep them current as the person fixes things. */\n function revalidateShown(values: Values): Record<string, string> {\n const previous = state;\n state = { ...state, values };\n const fresh = collectErrors(state.step ?? undefined);\n state = previous;\n const kept: Record<string, string> = {};\n for (const key of Object.keys(state.errors)) if (fresh[key]) kept[key] = fresh[key];\n for (const [name, refused] of Object.entries(serverErrors)) {\n if (JSON.stringify(values[name] ?? null) === refused.value) kept[name] ??= refused.message;\n else delete serverErrors[name];\n }\n return kept;\n }\n\n function scheduleDraft() {\n const drafts = options.drafts;\n if (!drafts) return;\n if (draftTimer !== null) scheduler.clearTimeout(draftTimer);\n draftTimer = scheduler.setTimeout(() => {\n draftTimer = null;\n drafts.store.setItem(draftKey(), JSON.stringify({ savedAt: new Date().toISOString(), values: state.values }));\n }, drafts.delayMs ?? 400);\n }\n\n function forgetDraft() {\n if (draftTimer !== null) scheduler.clearTimeout(draftTimer);\n draftTimer = null;\n options.drafts?.store.removeItem(draftKey());\n }\n\n function offerDraft() {\n const drafts = options.drafts;\n if (!drafts) return;\n const raw = drafts.store.getItem(draftKey());\n if (!raw) return;\n let draft: { savedAt: string; values: Values };\n try {\n draft = JSON.parse(raw);\n } catch {\n drafts.store.removeItem(draftKey());\n return;\n }\n if (drafts.restore === 'auto') writeValues({ ...state.values, ...draft.values }, { draft: null });\n else set({ draft: { savedAt: draft.savedAt } });\n }\n\n function scheduleAutosave() {\n const autosave = options.autosave;\n if (!autosave || page.data.kind !== 'record') return;\n if (autosaveTimer !== null) scheduler.clearTimeout(autosaveTimer);\n autosaveTimer = scheduler.setTimeout(() => {\n autosaveTimer = null;\n if (state.dirty.length && Object.keys(collectErrors()).length === 0) void track(save());\n }, autosave.delayMs);\n }\n\n function runOnchange(changed: string) {\n const source = options.dataSource;\n if (!source?.onchange || page.data.kind !== 'record') return;\n const seq = ++onchangeSeq;\n const request = { model: page.data.model, id: state.recordId, changed, values: structuredCopy(state.values as Values) };\n void track(\n source.onchange(request).then(\n (result) => {\n if (seq !== onchangeSeq) return;\n const values = { ...(state.values as Values), ...(result.values ?? {}) };\n writeValues(values, { warning: result.warning ?? null, warningField: result.warning ? changed : null });\n },\n () => undefined\n )\n );\n }\n\n function afterEdit(changed: string) {\n scheduleDraft();\n scheduleAutosave();\n runOnchange(changed);\n }\n\n function changes(): RecordChanges {\n const result: RecordChanges = { values: {}, lines: {}, links: {} };\n // A new record sends every value it holds, those it started with and defaults\n // included; a stored one sends only what changed since it was loaded.\n const creating = state.recordId === null || state.recordId === undefined;\n const names = creating\n ? Object.keys(page.fields).filter((name) => state.dirty.includes(name) || !isEmpty(page.fields[name], state.values[name]))\n : state.dirty;\n for (const name of names) {\n const def = page.fields[name];\n const now = state.values[name];\n const before = creating ? emptyValue(def) : baseline[name];\n if (def.type === 'one2many') result.lines[name] = lineOps((before as Line[] | null) ?? [], (now as Line[] | null) ?? []);\n else if (def.type === 'many2many') result.links[name] = linkOps((before as RelatedRecord[] | null) ?? [], (now as RelatedRecord[] | null) ?? []);\n else result.values[name] = structuredCopy(now) as Value;\n }\n return result;\n }\n\n /** The values to submit: only fields a visible question shows. */\n function shownValues(): Values {\n const shown: Values = {};\n for (const node of visibleFieldNodes()) {\n const name = node.field as string;\n shown[name] = structuredCopy(state.values[name]) as Value;\n }\n return shown;\n }\n\n async function save(): Promise<boolean> {\n const errors = collectErrors();\n if (Object.keys(errors).length) {\n set({ errors });\n return false;\n }\n const source = options.dataSource;\n serverErrors = {};\n set({ status: 'saving', errors: {}, error: null, saveProblem: null });\n try {\n if (page.data.kind === 'responses') {\n if (!source?.submit) throw new Error('This page has no data source to send its answers to');\n await source.submit({ pageId: page.id, values: shownValues() });\n forgetDraft();\n set({ status: 'saved' });\n return true;\n }\n if (!source?.save) throw new Error('This page has no data source to save to');\n const result = await source.save({\n model: page.data.model,\n id: state.recordId,\n fields: page.fields,\n changes: changes(),\n values: structuredCopy(state.values as Values),\n });\n forgetDraft();\n const values = result.values ? { ...(state.values as Values), ...result.values } : (state.values as Values);\n baseline = structuredCopy(values);\n set({ status: 'saved', recordId: result.id, values, dirty: [] });\n return true;\n } catch (error) {\n const problem = saveProblemOf(error);\n const fields = problem.kind === 'fields' ? problem.fields ?? {} : {};\n serverErrors = Object.fromEntries(Object.entries(fields).map(([name, message]) => [name, { message, value: JSON.stringify(state.values[name] ?? null) }]));\n set({ status: 'error', error: problem.message, saveProblem: problem, errors: { ...fields } });\n return false;\n }\n }\n\n /** The model a link field's new record belongs to, or null when it cannot make one. */\n function creatable(def: Field | LineField | undefined): string | null {\n if (!options.dataSource?.create || !def || def.readonly) return null;\n return def.type === 'many2one' || def.type === 'many2many' ? def.relation : null;\n }\n\n async function runCreate(def: Field | LineField | undefined, name: string, typed: string): Promise<RelatedRecord> {\n const model = creatable(def);\n const source = options.dataSource;\n if (!model || !source?.create) throw new Error(`\"${name}\" cannot make records: its data source has no create, or it is not a link`);\n return track(source.create({ model, name: typed.trim() }));\n }\n\n async function runSearch(\n def: Field | LineField,\n name: string,\n ctx: Record<string, unknown>,\n query: string,\n limit: number,\n model?: string\n ): Promise<RelatedRecord[]> {\n if (def.type !== 'many2one' && def.type !== 'many2many' && def.type !== 'reference') {\n throw new Error(`\"${name}\" is not a many2one, many2many or reference`);\n }\n if (def.type === 'reference' && !model) throw new Error(`Searching \"${name}\" needs a model`);\n const source = options.dataSource;\n if (!source?.search) return [];\n // Every valueFrom, in groups too, becomes the value it names before the search goes out.\n const resolve = (item: FilterItem): ResolvedFilter =>\n 'any' in item\n ? { any: item.any.map(resolve) }\n : 'all' in item\n ? { all: item.all.map(resolve) }\n : { field: item.field, op: item.op, value: (item.valueFrom !== undefined ? ctx[item.valueFrom] ?? null : item.value ?? null) as JsonValue };\n const filter: ResolvedFilter[] | undefined = def.type === 'reference' ? undefined : def.filter?.map(resolve);\n const relation = def.type === 'reference' ? (model as string) : def.relation;\n return track(source.search({ model: relation, query, ...(filter ? { filter } : {}), limit }));\n }\n\n function lineField(field: string) {\n const def = fieldDef(field);\n if (def.type !== 'one2many') throw new Error(`\"${field}\" is a ${def.type}, not a one2many`);\n return def;\n }\n\n function stepIndex(): number {\n return state.step ? steps.indexOf(state.step) : -1;\n }\n\n /** Whether a step can be passed over with Skip. */\n function optionalStep(id: string): boolean {\n return (index.get(id)?.source as { optional?: boolean } | undefined)?.optional === true;\n }\n\n async function load(): Promise<void> {\n const source = options.dataSource;\n if (state.recordId == null || page.data.kind !== 'record') return;\n if (!source?.load) {\n set({ status: 'error', error: 'This page has no data source to load from' });\n return;\n }\n set({ status: 'loading', error: null });\n try {\n const loaded = await source.load({ model: page.data.model, id: state.recordId, fields: page.fields });\n baseline = { ...initialValues(page.fields), ...loaded };\n set({ status: 'ready', values: structuredCopy(baseline), dirty: [], errors: {} });\n offerDraft();\n } catch (error) {\n set({ status: 'error', error: (error as Error).message });\n }\n }\n\n const form: Form = {\n page,\n getState: () => state,\n\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n\n load: () => track(load()),\n\n setValue(name, value) {\n fieldDef(name);\n writeValues({ ...(state.values as Values), [name]: structuredCopy(value) });\n afterEdit(name);\n },\n\n node: nodeState,\n\n fieldReadonly: (name) => fieldDef(name).readonly === true,\n\n problem(name) {\n const def = fieldDef(name);\n // Only a field someone can see is asked anything, and required wherever it is shown so.\n const shown = visibleFieldNodes().filter((node) => node.field === name);\n if (!shown.length) return null;\n return checkValue(def, state.values[name], shown.some((node) => nodeState(node.id).required), messages) ?? null;\n },\n\n validate() {\n const errors = collectErrors();\n set({ errors });\n return Object.keys(errors).length === 0;\n },\n\n save: () => track(save()),\n\n reset() {\n forgetDraft();\n serverErrors = {};\n set({ values: structuredCopy(baseline), dirty: [], errors: {}, warning: null, warningField: null, draft: null, step: steps[0] ?? null, skipped: [], saveProblem: null });\n },\n\n changes,\n\n addLine(field, values = {}) {\n const def = lineField(field);\n const key = `new-${++lineKeys}`;\n const current = (state.values[field] as Line[] | null) ?? [];\n const line: Line = { key, values: { ...initialValues(def.fields as Record<string, LineField>), ...structuredCopy(values) } };\n // A new line comes last, so it is numbered after the last.\n if (def.sequenceField && line.values[def.sequenceField] == null) {\n const numbers = current.map((l) => l.values[def.sequenceField as string]).filter((n): n is number => typeof n === 'number');\n line.values[def.sequenceField] = numbers.length ? Math.max(...numbers) + 1 : 1;\n }\n const lines = [...current, line];\n writeValues({ ...(state.values as Values), [field]: lines });\n afterEdit(field);\n return key;\n },\n\n updateLine(field, key, name, value) {\n const def = lineField(field);\n if (!def.fields[name]) throw new Error(`The lines of \"${field}\" have no field \"${name}\"`);\n const lines = ((state.values[field] as Line[] | null) ?? []).map((line) =>\n line.key === key ? { ...line, values: { ...line.values, [name]: structuredCopy(value) } } : line\n );\n writeValues({ ...(state.values as Values), [field]: lines });\n afterEdit(field);\n },\n\n moveLine(field, key, to) {\n const def = lineField(field);\n const sequence = def.sequenceField;\n if (!sequence) throw new Error(`The lines of \"${field}\" keep no order: give the field a sequenceField`);\n const lines = [...((state.values[field] as Line[] | null) ?? [])];\n const from = lines.findIndex((line) => line.key === key);\n if (from < 0) throw new Error(`\"${field}\" has no line \"${key}\"`);\n const target = Math.max(0, Math.min(to, lines.length - 1));\n if (target === from) return;\n // The numbers can be reused only if they rise with the lines as shown.\n const before = lines.map((line) => line.values[sequence]);\n const trusted = before.every((n, i) => typeof n === 'number' && (i === 0 || n > (before[i - 1] as number)));\n lines.splice(target, 0, ...lines.splice(from, 1));\n // The lines that moved take the numbers they held between them, in their\n // new order, and the rest keep theirs; otherwise every line is numbered\n // afresh, 1, 2, 3\u2026, so the order saved is the order shown.\n const low = Math.min(from, target);\n const high = Math.max(from, target);\n const pool = trusted ? (before.slice(low, high + 1) as number[]) : [];\n const renumbered = lines.map((line, i) => {\n const value = trusted ? (i >= low && i <= high ? pool[i - low] : line.values[sequence]) : i + 1;\n return value === line.values[sequence] ? line : { ...line, values: { ...line.values, [sequence]: value } };\n });\n writeValues({ ...(state.values as Values), [field]: renumbered });\n afterEdit(field);\n },\n\n removeLine(field, key) {\n lineField(field);\n const lines = ((state.values[field] as Line[] | null) ?? []).filter((line) => line.key !== key);\n writeValues({ ...(state.values as Values), [field]: lines });\n afterEdit(field);\n },\n\n async search(field, query, limit = 8, options = {}) {\n return runSearch(fieldDef(field), field, context(), query, limit, options.model);\n },\n\n async previewLine(field, key, values) {\n lineField(field);\n const lines = (state.values[field] as Line[] | null) ?? [];\n const line = lines.find((l) => l.key === key);\n if (!line) throw new Error(`\"${field}\" has no line \"${key}\"`);\n const merged = { ...line.values, ...values };\n const source = options.dataSource;\n if (!source?.onchange || page.data.kind !== 'record') return merged;\n const changed = lines.map((l) => (l.key === key ? { ...l, values: merged } : l));\n const result = await source.onchange({ model: page.data.model, id: state.recordId, changed: field, values: structuredCopy({ ...(state.values as Values), [field]: changed }) });\n const after = ((result.values?.[field] as Line[] | undefined) ?? []).find((l) => l.key === key);\n return after ? { ...merged, ...after.values } : merged;\n },\n\n async searchLine(field, key, subfield, query, limit = 8) {\n const def = lineField(field);\n const sub = def.fields[subfield];\n if (!sub) throw new Error(`The lines of \"${field}\" have no field \"${subfield}\"`);\n const line = ((state.values[field] as Line[] | null) ?? []).find((l) => l.key === key);\n if (!line) throw new Error(`\"${field}\" has no line \"${key}\"`);\n return runSearch(sub, subfield, expressionContext(line.values, def.fields as Record<string, LineField>), query, limit);\n },\n\n canCreate: (field) => creatable(page.fields[field]) !== null,\n quickCreate: (field, typed) => runCreate(page.fields[field], field, typed),\n canCreateLine: (field, subfield) => creatable(lineField(field).fields[subfield]) !== null,\n quickCreateLine: (field, subfield, typed) => runCreate(lineField(field).fields[subfield], subfield, typed),\n\n steps: () => steps.filter((id) => !nodeState(id).invisible),\n\n next() {\n if (!state.step) return false;\n // A step skipped before and gone back to is answered now, and checked like any other.\n if (state.skipped.includes(state.step)) set({ skipped: state.skipped.filter((id) => id !== state.step) });\n const errors = collectErrors(state.step);\n if (Object.keys(errors).length) {\n set({ errors });\n return false;\n }\n const visible = form.steps();\n const following = steps.slice(stepIndex() + 1).find((id) => visible.includes(id));\n if (!following) return false;\n set({ step: following, errors: {} });\n return true;\n },\n\n back() {\n if (!state.step) return false;\n const visible = form.steps();\n const previous = steps.slice(0, stepIndex()).reverse().find((id) => visible.includes(id));\n if (!previous) return false;\n set({ step: previous, errors: {} });\n return true;\n },\n\n skip() {\n const current = state.step;\n if (!current || !optionalStep(current)) return false;\n const visible = form.steps();\n const following = visible[visible.indexOf(current) + 1];\n if (!following) return false;\n set({ step: following, errors: {}, skipped: [...state.skipped.filter((id) => id !== current), current] });\n return true;\n },\n\n goTo(target) {\n const visible = form.steps();\n const to = visible.indexOf(target);\n const at = state.step ? visible.indexOf(state.step) : -1;\n if (to === -1 || at === -1) return false;\n if (to <= at) {\n set({ step: target, errors: {} });\n return true;\n }\n const skipped = [...state.skipped];\n for (const id of visible.slice(at, to)) {\n if (skipped.includes(id)) continue;\n const errors = collectErrors(id);\n if (!Object.keys(errors).length) continue;\n if (optionalStep(id)) {\n skipped.push(id);\n continue;\n }\n set({ step: id, errors, skipped });\n return false;\n }\n set({ step: target, errors: {}, skipped });\n return true;\n },\n\n async runAction(id, chosen) {\n const node = index.get(id);\n if (!node || (node.kind !== 'button' && node.kind !== 'stat')) throw new Error(`The page has no button \"${id}\"`);\n if (nodeState(id).invisible) return;\n const source = node.source as ButtonNode | StatButton;\n await track(\n Promise.resolve(\n options.onAction?.({\n id,\n action: source.action,\n ...('params' in source && source.params ? { params: source.params } : {}),\n recordId: state.recordId,\n values: structuredCopy(state.values as Values),\n ...(chosen ? { recordIds: [...chosen.recordIds] } : {}),\n })\n )\n );\n },\n\n restoreDraft() {\n const raw = options.drafts?.store.getItem(draftKey());\n if (!raw) return;\n const draft = JSON.parse(raw) as { values: Values };\n writeValues({ ...(state.values as Values), ...draft.values }, { draft: null });\n },\n\n discardDraft() {\n forgetDraft();\n set({ draft: null });\n },\n\n async settled() {\n while (pending.size) await Promise.allSettled([...pending]);\n },\n\n dispose() {\n if (draftTimer !== null) scheduler.clearTimeout(draftTimer);\n if (autosaveTimer !== null) scheduler.clearTimeout(autosaveTimer);\n listeners.clear();\n },\n };\n\n if (state.recordId == null) offerDraft();\n return form;\n}\n\nfunction lineOps(before: Line[], now: Line[]): LineOp[] {\n const ops: LineOp[] = [];\n const old = new Map(before.filter((line) => line.id !== undefined).map((line) => [line.key, line]));\n for (const line of now) {\n const previous = old.get(line.key);\n if (line.id === undefined || !previous) {\n ops.push({ op: 'create', key: line.key, values: structuredCopy(line.values) });\n continue;\n }\n const changed: Values = {};\n for (const [name, value] of Object.entries(line.values)) {\n if (JSON.stringify(value) !== JSON.stringify(previous.values[name])) changed[name] = structuredCopy(value) as Value;\n }\n if (Object.keys(changed).length) ops.push({ op: 'update', id: line.id, values: changed });\n }\n const kept = new Set(now.map((line) => line.key));\n for (const line of before) if (line.id !== undefined && !kept.has(line.key)) ops.push({ op: 'delete', id: line.id });\n return ops;\n}\n\nfunction linkOps(before: RelatedRecord[], now: RelatedRecord[]): LinkOp[] {\n const had = new Set(before.map((r) => r.id));\n const has = new Set(now.map((r) => r.id));\n return [\n ...now.filter((r) => !had.has(r.id)).map((r): LinkOp => ({ op: 'link', id: r.id })),\n ...before.filter((r) => !has.has(r.id)).map((r): LinkOp => ({ op: 'unlink', id: r.id })),\n ];\n}\n\nfunction indexLayout(root: RootLayout): Map<string, IndexedNode> {\n const index = new Map<string, IndexedNode>();\n const add = (\n source: IndexedNode['source'],\n parent: string | null,\n kind: IndexedNode['kind'],\n modifiers: { invisible?: Modifier; readonly?: Modifier; required?: Modifier; field?: string }\n ) => {\n index.set(source.id, {\n id: source.id,\n parent,\n kind,\n field: modifiers.field,\n invisible: compileModifier(modifiers.invisible),\n readonly: compileModifier(modifiers.readonly),\n required: compileModifier(modifiers.required),\n source,\n });\n };\n const walk = (nodes: LayoutNode[], parent: string) => {\n for (const node of nodes) {\n if (node.type === 'field') {\n add(node, parent, 'field', { invisible: node.invisible, readonly: node.readonly, required: node.required, field: node.field });\n } else if (node.type === 'button') {\n add(node, parent, 'button', { invisible: node.invisible });\n } else if (node.type === 'tabs') {\n add(node, parent, 'other', { invisible: node.invisible });\n for (const tab of node.children) {\n add(tab, node.id, 'other', { invisible: tab.invisible });\n walk(tab.children, tab.id);\n }\n } else if (node.type === 'section') {\n add(node, parent, 'other', { invisible: node.invisible, readonly: node.readonly });\n walk(node.children, node.id);\n } else {\n add(node, parent, 'other', { invisible: node.invisible });\n }\n }\n };\n\n if (root.type === 'tabs') {\n walk([root], '');\n index.get(root.id)!.parent = null;\n return index;\n }\n add(root, null, 'other', {});\n if (root.type === 'wizard') {\n for (const step of root.children) {\n add(step, root.id, 'step', { invisible: step.invisible });\n walk(step.children, step.id);\n }\n } else if (root.type === 'sections') {\n walk(root.children, root.id);\n } else if (root.type === 'list') {\n // A list holds no fields of its own record: only the buttons for what is selected.\n for (const button of root.actions ?? []) add(button, root.id, 'button', { invisible: button.invisible });\n } else {\n // The title and statusbar show fields too, so they are validated like\n // any field node. Their ids start with \"#\", which no page id can.\n const shown = (id: string, field: string | undefined) => {\n if (field) add({ id }, root.id, 'field', { field });\n };\n shown('#title', root.title?.field);\n shown('#subtitle', root.title?.subtitleField);\n shown('#avatar', root.title?.avatarField);\n shown('#statusbar', root.statusbar?.field);\n for (const button of root.buttons ?? []) add(button, root.id, 'button', { invisible: button.invisible });\n for (const stat of root.statButtons ?? []) add(stat, root.id, 'stat', { invisible: stat.invisible });\n if (root.ribbon) add(root.ribbon, root.id, 'other', { invisible: root.ribbon.invisible });\n for (const alert of root.alerts ?? []) add(alert, root.id, 'other', { invisible: alert.invisible });\n for (const badge of root.badges ?? []) add(badge, root.id, 'other', { invisible: badge.invisible });\n // Fields over and under the title are field nodes like any other.\n walk([...(root.title?.above ?? []), ...(root.title?.below ?? [])], root.id);\n walk(root.children, root.id);\n if (root.sidePanel) add(root.sidePanel, root.id, 'other', { invisible: root.sidePanel.invisible });\n }\n return index;\n}\n", "import type { Locale } from '@fieldia/core';\n\n/**\n * Numbers as a reader of the page's language writes them: grouped, with a\n * field's decimals, in Latin digits (as business software in Arabic shows\n * them), and read back the same way. Shared by the number widget, the lines\n * grid and totals.\n */\n\nconst formats = new Map<string, Intl.NumberFormat>();\nfunction format(locale: Locale, decimals: number): Intl.NumberFormat {\n const key = `${locale}:${decimals}`;\n let found = formats.get(key);\n if (!found) {\n found = new Intl.NumberFormat(locale, { numberingSystem: 'latn', minimumFractionDigits: decimals, maximumFractionDigits: decimals });\n formats.set(key, found);\n }\n return found;\n}\n\n/** The language's grouping and decimal marks. */\nfunction marks(locale: Locale): { group: string; decimal: string } {\n const parts = format(locale, 1).formatToParts(12345.6);\n return { group: parts.find((p) => p.type === 'group')?.value ?? ',', decimal: parts.find((p) => p.type === 'decimal')?.value ?? '.' };\n}\n\n/** A number at rest: \"1,850,000.50\", \"1.850.000,50\". */\nexport function formatNumber(value: number, decimals: number, locale: Locale = 'en'): string {\n return format(locale, decimals).format(value);\n}\n\n/**\n * Typed text as a number in JavaScript's own spelling (\"1234.5\"), or the text\n * unchanged when it is not one. Arabic-Indic digits are read as digits.\n */\nexport function normalizeNumber(text: string, locale: Locale = 'en'): string {\n const { group, decimal } = marks(locale);\n let out = text\n .replace(/[\u0660-\u0669]/g, (d) => String(d.charCodeAt(0) - 0x0660))\n .replace(/[\u06F0-\u06F9]/g, (d) => String(d.charCodeAt(0) - 0x06f0))\n .replace(/\u066B/g, decimal)\n .replace(/\u066C/g, group);\n // Spaces of any width group digits too (French uses a narrow no-break space).\n out = out.replace(/[\\s\\u00a0\\u202f]/g, '');\n if (group.trim()) out = out.split(group).join('');\n return decimal === '.' ? out : out.split(decimal).join('.');\n}\n", "import type { Locale } from '@fieldia/core';\n\n/** Every word a widget shows on its own. `{label}` and `{name}` are filled in. */\nexport interface WidgetLabels {\n search: string;\n noResults: string;\n remove: string;\n clear: string;\n addLine: string;\n addSection: string;\n addNote: string;\n deleteLine: string;\n /** Heads the row that adds up a table's number columns. */\n total: string;\n /** A problem on one line of a table, under the table. `{n}` counts from 1. */\n lineProblem: string;\n /** Problems beyond the first few. */\n moreProblems: string;\n /** The choice that makes a new record from what was typed. `{name}` is filled in. */\n createNamed: string;\n /** Choices at the end of a link's list, and the button that opens the linked record (`{name}`). */\n createAndEdit: string;\n searchMore: string;\n openNamed: string;\n /** The button that opens a line of a table in a dialog. */\n openLine: string;\n /** The button that lets a person hide or show a table's optional columns. */\n chooseColumns: string;\n /** The button beside a date that opens its calendar. */\n chooseDate: string;\n previousMonth: string;\n nextMonth: string;\n /** Heads the column of week numbers: short, and in full. */\n weekShort: string;\n week: string;\n /** The formatted-text toolbar and its buttons. */\n formatting: string;\n bold: string;\n italic: string;\n underline: string;\n textStyle: string;\n paragraph: string;\n heading: string;\n subheading: string;\n bulletList: string;\n numberList: string;\n alignLeft: string;\n alignCenter: string;\n alignRight: string;\n link: string;\n linkAddress: string;\n applyLink: string;\n removeLink: string;\n upload: string;\n uploadImage: string;\n replace: string;\n removeFile: string;\n dropHere: string;\n invalidJson: string;\n}\n\nexport const WIDGET_LABELS: Record<Locale, WidgetLabels> = {\n en: {\n search: 'Search\u2026',\n noResults: 'No results',\n remove: 'Remove {name}',\n clear: 'Clear {label}',\n addLine: 'Add a line',\n addSection: 'Add a section',\n addNote: 'Add a note',\n deleteLine: 'Delete line',\n total: 'Total',\n lineProblem: 'Line {n}: {message}',\n moreProblems: 'and {n} more',\n chooseColumns: 'Choose columns',\n createNamed: 'Create \u201C{name}\u201D',\n createAndEdit: 'Create and edit\u2026',\n searchMore: 'Search more\u2026',\n openNamed: 'Open {name}',\n openLine: 'Open line',\n chooseDate: 'Choose a date',\n previousMonth: 'Previous month',\n nextMonth: 'Next month',\n weekShort: 'Wk',\n week: 'Week',\n formatting: 'Formatting',\n bold: 'Bold',\n italic: 'Italic',\n underline: 'Underline',\n textStyle: 'Text style',\n paragraph: 'Paragraph',\n heading: 'Heading',\n subheading: 'Subheading',\n bulletList: 'Bulleted list',\n numberList: 'Numbered list',\n alignLeft: 'Align left',\n alignCenter: 'Align centre',\n alignRight: 'Align right',\n link: 'Link',\n linkAddress: 'Link address',\n applyLink: 'Apply',\n removeLink: 'Remove link',\n upload: 'Upload a file',\n uploadImage: 'Add a photo',\n replace: 'Replace',\n removeFile: 'Remove',\n dropHere: 'or drop it here',\n invalidJson: 'Not valid JSON',\n },\n ar: {\n search: '\u0628\u062D\u062B\u2026',\n noResults: '\u0644\u0627 \u062A\u0648\u062C\u062F \u0646\u062A\u0627\u0626\u062C',\n remove: '\u0625\u0632\u0627\u0644\u0629 {name}',\n clear: '\u0645\u0633\u062D {label}',\n addLine: '\u0625\u0636\u0627\u0641\u0629 \u0633\u0637\u0631',\n addSection: '\u0625\u0636\u0627\u0641\u0629 \u0642\u0633\u0645',\n addNote: '\u0625\u0636\u0627\u0641\u0629 \u0645\u0644\u0627\u062D\u0638\u0629',\n deleteLine: '\u062D\u0630\u0641 \u0627\u0644\u0633\u0637\u0631',\n total: '\u0627\u0644\u0625\u062C\u0645\u0627\u0644\u064A',\n lineProblem: '\u0627\u0644\u0633\u0637\u0631 {n}: {message}',\n moreProblems: '\u0648{n} \u0623\u062E\u0631\u0649',\n chooseColumns: '\u0627\u062E\u062A\u064A\u0627\u0631 \u0627\u0644\u0623\u0639\u0645\u062F\u0629',\n createNamed: '\u0625\u0646\u0634\u0627\u0621 \u00AB{name}\u00BB',\n createAndEdit: '\u0625\u0646\u0634\u0627\u0621 \u0648\u062A\u0639\u062F\u064A\u0644\u2026',\n searchMore: '\u0628\u062D\u062B \u0645\u0648\u0633\u0651\u0639\u2026',\n openNamed: '\u0641\u062A\u062D {name}',\n openLine: '\u0641\u062A\u062D \u0627\u0644\u0633\u0637\u0631',\n chooseDate: '\u0627\u062E\u062A\u064A\u0627\u0631 \u062A\u0627\u0631\u064A\u062E',\n previousMonth: '\u0627\u0644\u0634\u0647\u0631 \u0627\u0644\u0633\u0627\u0628\u0642',\n nextMonth: '\u0627\u0644\u0634\u0647\u0631 \u0627\u0644\u062A\u0627\u0644\u064A',\n weekShort: '\u0623\u0633\u0628\u0648\u0639',\n week: '\u0627\u0644\u0623\u0633\u0628\u0648\u0639',\n formatting: '\u0627\u0644\u062A\u0646\u0633\u064A\u0642',\n bold: '\u063A\u0627\u0645\u0642',\n italic: '\u0645\u0627\u0626\u0644',\n underline: '\u062A\u0633\u0637\u064A\u0631',\n textStyle: '\u0646\u0645\u0637 \u0627\u0644\u0646\u0635',\n paragraph: '\u0641\u0642\u0631\u0629',\n heading: '\u0639\u0646\u0648\u0627\u0646',\n subheading: '\u0639\u0646\u0648\u0627\u0646 \u0641\u0631\u0639\u064A',\n bulletList: '\u0642\u0627\u0626\u0645\u0629 \u0646\u0642\u0637\u064A\u0629',\n numberList: '\u0642\u0627\u0626\u0645\u0629 \u0645\u0631\u0642\u0645\u0629',\n alignLeft: '\u0645\u062D\u0627\u0630\u0627\u0629 \u0644\u0644\u064A\u0633\u0627\u0631',\n alignCenter: '\u062A\u0648\u0633\u064A\u0637',\n alignRight: '\u0645\u062D\u0627\u0630\u0627\u0629 \u0644\u0644\u064A\u0645\u064A\u0646',\n link: '\u0631\u0627\u0628\u0637',\n linkAddress: '\u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0631\u0627\u0628\u0637',\n applyLink: '\u062A\u0637\u0628\u064A\u0642',\n removeLink: '\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0631\u0627\u0628\u0637',\n upload: '\u0631\u0641\u0639 \u0645\u0644\u0641',\n uploadImage: '\u0625\u0636\u0627\u0641\u0629 \u0635\u0648\u0631\u0629',\n replace: '\u0627\u0633\u062A\u0628\u062F\u0627\u0644',\n removeFile: '\u0625\u0632\u0627\u0644\u0629',\n dropHere: '\u0623\u0648 \u0623\u0641\u0644\u062A\u0647 \u0647\u0646\u0627',\n invalidJson: '\u0644\u064A\u0633 JSON \u0635\u0627\u0644\u062D\u064B\u0627',\n },\n de: {\n search: 'Suchen\u2026',\n noResults: 'Keine Ergebnisse',\n remove: '{name} entfernen',\n clear: '{label} leeren',\n addLine: 'Zeile hinzuf\u00FCgen',\n addSection: 'Abschnitt hinzuf\u00FCgen',\n addNote: 'Notiz hinzuf\u00FCgen',\n deleteLine: 'Zeile l\u00F6schen',\n total: 'Summe',\n lineProblem: 'Zeile {n}: {message}',\n moreProblems: 'und {n} weitere',\n chooseColumns: 'Spalten ausw\u00E4hlen',\n createNamed: '\u201E{name}\u201C anlegen',\n createAndEdit: 'Anlegen und bearbeiten\u2026',\n searchMore: 'Weitere suchen\u2026',\n openNamed: '{name} \u00F6ffnen',\n openLine: 'Zeile \u00F6ffnen',\n chooseDate: 'Datum ausw\u00E4hlen',\n previousMonth: 'Vorheriger Monat',\n nextMonth: 'N\u00E4chster Monat',\n weekShort: 'KW',\n week: 'Kalenderwoche',\n formatting: 'Formatierung',\n bold: 'Fett',\n italic: 'Kursiv',\n underline: 'Unterstrichen',\n textStyle: 'Textstil',\n paragraph: 'Absatz',\n heading: '\u00DCberschrift',\n subheading: 'Unter\u00FCberschrift',\n bulletList: 'Aufz\u00E4hlung',\n numberList: 'Nummerierte Liste',\n alignLeft: 'Linksb\u00FCndig',\n alignCenter: 'Zentriert',\n alignRight: 'Rechtsb\u00FCndig',\n link: 'Link',\n linkAddress: 'Linkadresse',\n applyLink: '\u00DCbernehmen',\n removeLink: 'Link entfernen',\n upload: 'Datei hochladen',\n uploadImage: 'Foto hinzuf\u00FCgen',\n replace: 'Ersetzen',\n removeFile: 'Entfernen',\n dropHere: 'oder hier ablegen',\n invalidJson: 'Kein g\u00FCltiges JSON',\n },\n fr: {\n search: 'Rechercher\u2026',\n noResults: 'Aucun r\u00E9sultat',\n remove: 'Retirer {name}',\n clear: 'Effacer {label}',\n addLine: 'Ajouter une ligne',\n addSection: 'Ajouter une section',\n addNote: 'Ajouter une note',\n deleteLine: 'Supprimer la ligne',\n total: 'Total',\n lineProblem: 'Ligne {n} : {message}',\n moreProblems: 'et {n} de plus',\n chooseColumns: 'Choisir les colonnes',\n createNamed: 'Cr\u00E9er \u00AB {name} \u00BB',\n createAndEdit: 'Cr\u00E9er et modifier\u2026',\n searchMore: 'Rechercher plus\u2026',\n openNamed: 'Ouvrir {name}',\n openLine: 'Ouvrir la ligne',\n chooseDate: 'Choisir une date',\n previousMonth: 'Mois pr\u00E9c\u00E9dent',\n nextMonth: 'Mois suivant',\n weekShort: 'Sem.',\n week: 'Semaine',\n formatting: 'Mise en forme',\n bold: 'Gras',\n italic: 'Italique',\n underline: 'Soulign\u00E9',\n textStyle: 'Style du texte',\n paragraph: 'Paragraphe',\n heading: 'Titre',\n subheading: 'Sous-titre',\n bulletList: 'Liste \u00E0 puces',\n numberList: 'Liste num\u00E9rot\u00E9e',\n alignLeft: 'Aligner \u00E0 gauche',\n alignCenter: 'Centrer',\n alignRight: 'Aligner \u00E0 droite',\n link: 'Lien',\n linkAddress: 'Adresse du lien',\n applyLink: 'Appliquer',\n removeLink: 'Supprimer le lien',\n upload: 'T\u00E9l\u00E9verser un fichier',\n uploadImage: 'Ajouter une photo',\n replace: 'Remplacer',\n removeFile: 'Retirer',\n dropHere: 'ou d\u00E9posez-le ici',\n invalidJson: 'JSON invalide',\n },\n};\n", "import type { FieldNode, Form, ReferenceValue, RelatedRecord } from '@fieldia/core';\nimport { WIDGET_LABELS, type WidgetLabels } from './labels';\nimport type { Widget, WidgetContext, WidgetFactory } from './widgets';\n\n/**\n * Pickers for related records: a search-as-you-type combobox (the ARIA 1.2\n * combobox pattern), tags for a many2many, and a reference picker. Results\n * come from the data source through the form, so a field's filter applies.\n */\n\nconst DEBOUNCE_MS = 180;\n/** How many matches a link's list shows, as the data source's search would. */\nconst SHOWN = 8;\n\nfunction fill(template: string, values: Record<string, string>) {\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) => values[name] ?? match);\n}\n\ninterface Combobox {\n element: HTMLElement;\n input: HTMLInputElement;\n /** Show this text when nobody is typing. */\n setText(text: string): void;\n setReadonly(readonly: boolean): void;\n close(): void;\n}\n\n/**\n * A text box with a list of matches under it. `search` finds records,\n * `pick` takes the chosen one, `exclude` hides records already chosen.\n */\nfunction combobox(options: {\n document: Document;\n id: string;\n labels: WidgetLabels;\n search: (query: string) => Promise<RelatedRecord[]>;\n pick: (record: RelatedRecord) => void;\n exclude?: () => Set<RelatedRecord['id']>;\n onEmptyBackspace?: () => void;\n onCommitEmpty?: () => void;\n /** Make a record from what was typed, offered when nothing found has that name. */\n create?: (text: string) => Promise<RelatedRecord>;\n /** How many found records the list shows; a search may find one more, to tell there are others. */\n shown?: number;\n /** Further choices at the end of the list: each acts on the typed text and may hand back a record to pick. */\n more?: (typed: string, overflow: boolean) => { label: string; act: (typed: string) => Promise<RelatedRecord | null> }[];\n}): Combobox {\n const { document: doc, id, labels } = options;\n const listId = `${id}-list`;\n const input = doc.createElement('input');\n Object.assign(input, { id, className: 'fd-input fd-combo-input', autocomplete: 'off' });\n input.setAttribute('role', 'combobox');\n input.setAttribute('aria-autocomplete', 'list');\n input.setAttribute('aria-expanded', 'false');\n input.setAttribute('aria-controls', listId);\n input.placeholder = labels.search;\n const list = doc.createElement('ul');\n list.id = listId;\n list.className = 'fd-listbox';\n list.setAttribute('role', 'listbox');\n list.hidden = true;\n const element = doc.createElement('div');\n element.className = 'fd-combo';\n element.append(input, list);\n\n let shown = '';\n /** The \"Create \u2026\" choice in the list, and the text it would make a record from. */\n let creating: RelatedRecord | null = null;\n let creatingText = '';\n /** The further choices at the end of the list, by the entry that stands for each. */\n let extras = new Map<RelatedRecord, (typed: string) => Promise<RelatedRecord | null>>();\n /** True while the person's own typing is in the box. */\n let editing = false;\n let results: RelatedRecord[] = [];\n let active = -1;\n let seq = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let readonly = false;\n\n function render() {\n list.replaceChildren();\n results.forEach((record, i) => {\n const option = doc.createElement('li');\n option.id = `${listId}-${i}`;\n option.setAttribute('role', 'option');\n option.setAttribute('aria-selected', String(i === active));\n option.className = `fd-option${i === active ? ' fd-active' : ''}${record === creating || extras.has(record) ? ' fd-option-create' : ''}`;\n option.textContent = record.label;\n option.addEventListener('mousedown', (event) => event.preventDefault()); // keep focus in the box\n option.addEventListener('click', () => choose(i));\n list.append(option);\n });\n if (!results.length) {\n const empty = doc.createElement('li');\n empty.className = 'fd-empty';\n empty.textContent = labels.noResults;\n list.append(empty);\n }\n if (active >= 0) input.setAttribute('aria-activedescendant', `${listId}-${active}`);\n else input.removeAttribute('aria-activedescendant');\n }\n\n function open() {\n list.hidden = false;\n input.setAttribute('aria-expanded', 'true');\n }\n\n function close() {\n // A search still on its way must not open the list again.\n clearTimeout(timer);\n seq++;\n list.hidden = true;\n input.setAttribute('aria-expanded', 'false');\n input.removeAttribute('aria-activedescendant');\n active = -1;\n }\n\n function choose(index: number) {\n const record = results[index];\n if (!record) return;\n const typed = creatingText;\n close();\n editing = false;\n if (record === creating && options.create) {\n void options.create(typed).then(options.pick, () => undefined);\n return;\n }\n const act = extras.get(record);\n if (act) {\n void act(typed).then((picked) => picked && options.pick(picked), () => undefined);\n return;\n }\n options.pick(record);\n }\n\n function lookUp(query: string) {\n clearTimeout(timer);\n const mine = ++seq;\n timer = setTimeout(async () => {\n const found = await options.search(query).catch(() => [] as RelatedRecord[]);\n if (mine !== seq || doc.activeElement !== input) return; // a newer search, or the person left\n // A record the arrow keys reached stays reached if the answer still lists it.\n const reached = results[active];\n const held = reached && reached !== creating && !extras.has(reached) ? reached.id : undefined;\n const hidden = options.exclude?.() ?? new Set();\n const kept = found.filter((record) => !hidden.has(record.id));\n const overflow = options.shown !== undefined && kept.length > options.shown;\n results = overflow ? kept.slice(0, options.shown) : kept;\n // Nothing found by that name: offer to make it.\n const typed = query.trim();\n creating = null;\n if (options.create && typed && !found.some((record) => record.label.trim().toLowerCase() === typed.toLowerCase())) {\n creatingText = typed;\n creating = { id: '__create__', label: fill(labels.createNamed, { name: typed }) };\n results = [...results, creating];\n }\n creatingText = typed;\n extras = new Map((options.more?.(typed, overflow) ?? []).map((extra, i) => [{ id: `__more_${i}__`, label: extra.label }, extra.act]));\n results = [...results, ...extras.keys()];\n active = held === undefined ? -1 : results.findIndex((record) => record.id === held);\n render();\n open();\n }, DEBOUNCE_MS);\n }\n\n input.addEventListener('input', () => {\n editing = true;\n if (!readonly) lookUp(input.value);\n });\n input.addEventListener('focus', () => {\n if (!readonly) lookUp('');\n });\n input.addEventListener('keydown', (event) => {\n if (readonly) return;\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowUp': {\n event.preventDefault();\n if (list.hidden) return lookUp(input.value);\n if (!results.length) return;\n active = (active + (event.key === 'ArrowDown' ? 1 : -1) + results.length) % results.length;\n render();\n list.children[active]?.scrollIntoView?.({ block: 'nearest' });\n return;\n }\n case 'Enter':\n if (!list.hidden && active >= 0) {\n event.preventDefault();\n choose(active);\n }\n return;\n case 'Escape':\n if (!list.hidden) event.preventDefault();\n close();\n editing = false;\n input.value = shown;\n return;\n case 'Backspace':\n if (input.value === '') options.onEmptyBackspace?.();\n return;\n }\n });\n input.addEventListener('blur', () => {\n seq++;\n clearTimeout(timer);\n close();\n const emptied = editing && input.value.trim() === '' && shown !== '';\n editing = false;\n if (emptied) options.onCommitEmpty?.();\n else input.value = shown;\n });\n\n return {\n element,\n input,\n setText(text) {\n shown = text;\n if (!editing) input.value = text;\n },\n setReadonly(next) {\n readonly = next;\n input.readOnly = next;\n if (next) close();\n },\n close,\n };\n}\n\n/** Making a record from a typed name, unless the page turns it off or the data source cannot. */\nfunction creator(form: Form, name: string, node: FieldNode): ((text: string) => Promise<RelatedRecord>) | undefined {\n return node.options?.['create'] !== false && form.canCreate(name) ? (text) => form.quickCreate(name, text) : undefined;\n}\n\nexport const many2oneWidget: WidgetFactory = ({ form, name, field, node, id, document, labels = WIDGET_LABELS.en, dialogs }) => {\n const relation = field.type === 'many2one' ? field.relation : '';\n const canOpen = !!dialogs && dialogs.canOpen(relation);\n let readonly = false;\n const box = combobox({\n document,\n id,\n labels,\n // One past what the list shows, to know whether Search more\u2026 has more to find.\n search: (query) => form.search(name, query, SHOWN + 1),\n shown: SHOWN,\n pick: (record) => form.setValue(name, record),\n onCommitEmpty: () => form.setValue(name, null),\n create: creator(form, name, node),\n // With dialogs: make a record in its own page, or pick from a full list when the short one has no room.\n more: (typed, overflow) => {\n if (!dialogs || readonly) return [];\n const choices: { label: string; act: (text: string) => Promise<RelatedRecord | null> }[] = [];\n if (typed && canOpen && node.options?.['create'] !== false) {\n choices.push({ label: labels.createAndEdit, act: (text) => dialogs.openRecord(relation, { name: text, title: field.label }) });\n }\n if (overflow) choices.push({ label: labels.searchMore, act: () => dialogs.searchMore({ title: field.label, search: (query, limit) => form.search(name, query, limit) }) });\n return choices;\n },\n });\n // The linked record, opened in a dialog where the app can show it; a new name it is saved with follows here.\n const open = canOpen ? document.createElement('button') : null;\n if (open) {\n open.type = 'button';\n open.className = 'fd-combo-open';\n open.textContent = '\u2197';\n open.hidden = true;\n open.addEventListener('click', async () => {\n const current = form.getState().values[name] as RelatedRecord | null;\n if (!current || !dialogs) return;\n const saved = await dialogs.openRecord(relation, { recordId: current.id, title: current.label });\n if (saved && saved.label !== current.label) form.setValue(name, saved);\n });\n }\n const clear = document.createElement('button');\n clear.type = 'button';\n clear.className = 'fd-combo-clear';\n clear.textContent = '\u00D7';\n clear.setAttribute('aria-label', fill(labels.clear, { label: field.label }));\n clear.addEventListener('click', () => {\n form.setValue(name, null);\n box.input.focus();\n });\n box.element.append(clear, ...(open ? [open] : []));\n return {\n element: box.element,\n focus: () => box.input.focus(),\n update(state) {\n const record = state.value as RelatedRecord | null | undefined;\n readonly = state.readonly;\n box.setText(record?.label ?? '');\n box.setReadonly(state.readonly);\n clear.hidden = !record || state.readonly;\n if (open) {\n open.hidden = !record;\n if (record) open.setAttribute('aria-label', fill(labels.openNamed, { name: record.label }));\n }\n box.input.setAttribute('aria-invalid', String(state.invalid));\n box.input.setAttribute('aria-required', String(state.required));\n if (state.describedBy) box.input.setAttribute('aria-describedby', state.describedBy);\n },\n } satisfies Widget;\n};\n\nexport const tagsWidget: WidgetFactory = ({ form, name, node, id, document, labels = WIDGET_LABELS.en }) => {\n const current = () => (form.getState().values[name] as RelatedRecord[] | null) ?? [];\n const element = document.createElement('div');\n element.className = 'fd-tags';\n element.setAttribute('role', 'group');\n const chips = document.createElement('ul');\n chips.className = 'fd-chips';\n const box = combobox({\n document,\n id,\n labels,\n search: (query) => form.search(name, query),\n pick: (record) => {\n form.setValue(name, [...current(), record]);\n box.input.value = '';\n },\n exclude: () => new Set(current().map((record) => record.id)),\n onEmptyBackspace: () => {\n const records = current();\n if (records.length) form.setValue(name, records.slice(0, -1));\n },\n create: creator(form, name, node),\n });\n element.append(chips, box.element);\n let readonly = false;\n let drawn = '';\n return {\n element,\n focus: () => box.input.focus(),\n update(state) {\n const records = (state.value as RelatedRecord[] | null) ?? [];\n // Rebuild the chips only when they change, not on every keystroke elsewhere.\n const key = JSON.stringify([state.readonly, records]);\n readonly = state.readonly;\n box.setReadonly(readonly);\n box.element.hidden = readonly;\n box.input.setAttribute('aria-invalid', String(state.invalid));\n if (state.describedBy) box.input.setAttribute('aria-describedby', state.describedBy);\n if (key === drawn) return;\n drawn = key;\n drawChips(chips, records, readonly, labels, (record) => form.setValue(name, current().filter((r) => r.id !== record.id)));\n box.setText('');\n },\n };\n};\n\n/** Chips for tags, each with a remove button unless read-only. */\nfunction drawChips(chips: HTMLElement, records: RelatedRecord[], readonly: boolean, labels: WidgetLabels, remove: (record: RelatedRecord) => void) {\n const doc = chips.ownerDocument;\n chips.replaceChildren(\n ...records.map((record) => {\n const chip = doc.createElement('li');\n chip.className = 'fd-chip';\n const text = doc.createElement('span');\n text.className = 'fd-chip-label';\n text.textContent = record.label;\n chip.append(text);\n if (!readonly) {\n const button = doc.createElement('button');\n button.type = 'button';\n button.className = 'fd-chip-remove';\n button.textContent = '\u00D7';\n button.setAttribute('aria-label', fill(labels.remove, { name: record.label }));\n button.addEventListener('click', () => remove(record));\n chip.append(button);\n }\n return chip;\n })\n );\n}\n\n/**\n * Free-text tags on a text field, kept as \"oak, glass\": Enter or a comma adds\n * what was typed, Backspace in an empty box takes the last one away, and the\n * node's `options.suggestions` are offered as you type. `options.separator`\n * is \",\" unless set.\n */\nexport const charTagsWidget: WidgetFactory = ({ form, name, node, id, document, labels = WIDGET_LABELS.en }) => {\n const options = node.options ?? {};\n const separator = typeof options['separator'] === 'string' && options['separator'] ? options['separator'] : ',';\n const suggestions = Array.isArray(options['suggestions']) ? options['suggestions'].filter((s): s is string => typeof s === 'string') : [];\n const split = (text: unknown) =>\n typeof text === 'string' ? text.split(separator).map((t) => t.trim()).filter((t) => t !== '') : [];\n const current = () => split(form.getState().values[name]);\n const write = (tags: string[]) => form.setValue(name, tags.length ? tags.join(`${separator} `) : null);\n const add = (raw: string) => {\n const tag = raw.trim();\n const tags = current();\n if (tag && !tags.some((t) => t.toLowerCase() === tag.toLowerCase())) write([...tags, tag]);\n };\n\n const element = document.createElement('div');\n element.className = 'fd-tags';\n element.setAttribute('role', 'group');\n const chips = document.createElement('ul');\n chips.className = 'fd-chips';\n const box = combobox({\n document,\n id,\n labels,\n search: async (query) => {\n const taken = new Set(current().map((t) => t.toLowerCase()));\n const wanted = query.trim().toLowerCase();\n return suggestions\n .filter((s) => !taken.has(s.toLowerCase()) && s.toLowerCase().includes(wanted))\n .map((s) => ({ id: s, label: s }));\n },\n pick: (record) => {\n add(record.label);\n box.input.value = '';\n },\n onEmptyBackspace: () => {\n const tags = current();\n if (tags.length) write(tags.slice(0, -1));\n },\n });\n // Enter with nothing chosen from the list adds what was typed.\n box.input.addEventListener('keydown', (event) => {\n if (event.key !== 'Enter' || event.defaultPrevented || box.input.value.trim() === '') return;\n event.preventDefault();\n add(box.input.value);\n box.input.value = '';\n box.close();\n });\n // A separator typed ends a tag.\n box.input.addEventListener('input', () => {\n const parts = box.input.value.split(separator);\n if (parts.length < 2) return;\n for (const part of parts.slice(0, -1)) add(part);\n box.input.value = parts[parts.length - 1].trimStart();\n });\n // Typed and left without Enter: kept. (change comes before blur clears the box.)\n box.input.addEventListener('change', () => {\n if (box.input.value.trim()) add(box.input.value);\n });\n element.append(chips, box.element);\n let drawn = '';\n return {\n element,\n focus: () => box.input.focus(),\n update(state) {\n const tags = split(state.value);\n box.setReadonly(state.readonly);\n box.element.hidden = state.readonly;\n box.input.setAttribute('aria-invalid', String(state.invalid));\n if (state.describedBy) box.input.setAttribute('aria-describedby', state.describedBy);\n const key = JSON.stringify([state.readonly, tags]);\n if (key === drawn) return;\n drawn = key;\n drawChips(chips, tags.map((t) => ({ id: t, label: t })), state.readonly, labels, (record) => write(current().filter((t) => t !== record.label)));\n box.setText('');\n },\n };\n};\n\n/** Every record as a checkbox. For short lists: it loads up to 50. */\nexport const linkCheckboxesWidget: WidgetFactory = ({ form, name, id, document }) => {\n const element = document.createElement('div');\n element.id = id;\n element.className = 'fd-choices fd-choices-checkbox';\n element.setAttribute('role', 'group');\n let boxes: { record: RelatedRecord; box: HTMLInputElement }[] = [];\n let latest = { readonly: false, value: [] as RelatedRecord[] };\n // Built once, when the records arrive; updates only tick boxes, so focus stays put.\n const sync = () => {\n const chosen = new Set(latest.value.map((r) => r.id));\n for (const { record, box } of boxes) {\n box.checked = chosen.has(record.id);\n box.disabled = latest.readonly;\n }\n };\n void form.search(name, '', 50).then((records) => {\n boxes = records.map((record, i) => {\n const box = document.createElement('input');\n box.type = 'checkbox';\n box.id = `${id}-${i}`;\n box.addEventListener('change', () => {\n const now = (form.getState().values[name] as RelatedRecord[] | null) ?? [];\n form.setValue(name, box.checked ? [...now, record] : now.filter((r) => r.id !== record.id));\n });\n const label = document.createElement('label');\n label.className = 'fd-choice';\n label.htmlFor = box.id;\n const text = document.createElement('span');\n text.textContent = record.label;\n label.append(box, text);\n element.append(label);\n return { record, box };\n });\n sync();\n });\n return {\n element,\n focus: () => element.querySelector('input')?.focus(),\n update(state) {\n latest = { readonly: state.readonly, value: (state.value as RelatedRecord[] | null) ?? [] };\n sync();\n },\n };\n};\n\nexport const referenceWidget: WidgetFactory = (context: WidgetContext) => {\n const { form, name, field, id, document, labels = WIDGET_LABELS.en } = context;\n const models = field.type === 'reference' ? field.models : [];\n const element = document.createElement('div');\n element.className = 'fd-reference';\n const select = document.createElement('select');\n select.className = 'fd-input fd-select';\n select.setAttribute('aria-label', field.label);\n select.append(document.createElement('option'));\n for (const model of models) {\n const option = document.createElement('option');\n option.value = String(model.value);\n option.textContent = model.label;\n select.append(option);\n }\n let model = '';\n select.addEventListener('change', () => {\n model = select.value;\n form.setValue(name, null);\n });\n const box = combobox({\n document,\n id,\n labels,\n search: (query) => (model ? form.search(name, query, 8, { model }) : Promise.resolve([])),\n pick: (record) => form.setValue(name, { model, id: record.id, label: record.label }),\n onCommitEmpty: () => form.setValue(name, null),\n });\n element.append(select, box.element);\n return {\n element,\n focus: () => (model ? box.input.focus() : select.focus()),\n update(state) {\n const value = state.value as ReferenceValue | null | undefined;\n if (value) model = value.model;\n select.value = model;\n select.disabled = state.readonly;\n box.setText(value?.label ?? '');\n box.setReadonly(state.readonly || !model);\n },\n };\n};\n", "import type { LineField, Locale, Value } from '@fieldia/core';\nimport { formatNumber } from './numbers';\n\n\nfunction localDate(text: string): Date | null {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})(?:[T ](\\d{2}):(\\d{2}))?/.exec(text);\n if (!match) return null;\n const [, y, m, d, hh, mm] = match;\n return new Date(Number(y), Number(m) - 1, Number(d), Number(hh ?? 0), Number(mm ?? 0));\n}\n\n/**\n * A value as a person reads it where it is not being edited: a cell of the\n * lines grid, a totals row. Shared by the plain lines table and @fieldia/grid.\n */\nexport function displayValue(def: LineField, value: Value | undefined, values: Record<string, Value> = {}, locale: Locale = 'en'): string {\n const number = (n: number, digits: number) => formatNumber(n, digits, locale);\n if (value === null || value === undefined || value === '') return '';\n switch (def.type) {\n case 'many2one':\n case 'reference':\n return (value as { label?: string }).label ?? '';\n case 'many2many':\n return ((value as { label: string }[]) ?? []).map((r) => r.label).join(', ');\n case 'selection': {\n const label = (v: unknown) => def.options.find((o) => o.value === v)?.label ?? String(v);\n return Array.isArray(value) ? value.map(label).join(', ') : label(value);\n }\n case 'integer':\n return number(Number(value), 0);\n case 'float':\n return number(Number(value), def.digits?.[1] ?? 2);\n case 'monetary': {\n const currency = def.currency ?? (def.currencyField ? (values[def.currencyField] as { label?: string } | null)?.label : undefined);\n const amount = number(Number(value), def.digits?.[1] ?? 2);\n return currency ? `${currency} ${amount}` : amount;\n }\n case 'date': {\n const date = localDate(String(value));\n return date ? new Intl.DateTimeFormat(locale === 'en' ? 'en-GB' : locale, { day: 'numeric', month: 'short', year: 'numeric', numberingSystem: 'latn' }).format(date) : String(value);\n }\n case 'datetime': {\n const date = localDate(String(value));\n return date\n ? new Intl.DateTimeFormat(locale === 'en' ? 'en-GB' : locale, { day: 'numeric', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', numberingSystem: 'latn' }).format(date)\n : String(value);\n }\n case 'html':\n return String(value).replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim();\n case 'binary':\n case 'image':\n return (value as { name?: string }).name ?? '';\n case 'boolean':\n return value ? '\u2713' : '';\n default:\n return String(value);\n }\n}\n", "import { lineKind, type Field, type FieldNode, type Form, type FormState, type Line, type LineField, type Value } from '@fieldia/core';\nimport { displayValue } from './display';\nimport { WIDGET_LABELS } from './labels';\nimport { createWidget, type Widget, type WidgetFactory } from './widgets';\n\n/**\n * A one2many as an editable table. Each cell is an ordinary widget; a small\n * adapter routes its edits to `updateLine` and its searches to `searchLine`,\n * so a many2one inside a line searches with that line's own values. Rows are\n * matched by line key, so adding or removing a line never rebuilds the others.\n * When the field declares `lineKinds`, a section or a note is one wide row of\n * its text.\n */\n\ninterface Row {\n element: HTMLTableRowElement;\n kind: 'section' | 'note' | null;\n cells: { name: string; def: LineField; widget: Widget; error: HTMLElement }[];\n remove: HTMLButtonElement;\n}\n\n/** The field a section or note is typed into: one line for a heading, a growing box for a note. */\nexport function kindTextField(def: LineField, kind: 'section' | 'note'): LineField {\n return kind === 'section' ? ({ ...def, type: 'char' } as LineField) : ({ ...def, type: 'text' } as LineField);\n}\n\n/** The form a cell sees: the line's values, written back into the line. Shared with @fieldia/grid. */\nexport function lineForm(form: Form, field: string, key: string): Form {\n const values = () => (((form.getState().values[field] as Line[] | null) ?? []).find((l) => l.key === key)?.values ?? {});\n return {\n ...form,\n getState: (): FormState => ({ ...form.getState(), values: values() }),\n setValue: (name: string, value: Value) => form.updateLine(field, key, name, value),\n search: (name: string, query: string, limit?: number) => form.searchLine(field, key, name, query, limit),\n canCreate: (name: string) => form.canCreateLine(field, name),\n quickCreate: (name: string, text: string) => form.quickCreateLine(field, name, text),\n };\n}\n\nexport const linesWidget: WidgetFactory = ({ form, name, field, node, id, document, labels = WIDGET_LABELS.en, locale, dialogs }) => {\n const def = field as Extract<Field, { type: 'one2many' }>;\n const kinds = def.lineKinds;\n // The fields that say what a line is and keep the lines' order never show as columns.\n // Optional columns the page starts hidden stay out of the plain table.\n const columns = (node.columns ?? Object.keys(def.fields)).filter(\n (column) => def.fields[column] && column !== kinds?.field && column !== def.sequenceField && node.optionalColumns?.[column] !== 'hide'\n );\n const element = document.createElement('div');\n element.className = 'fd-lines';\n element.id = id;\n element.setAttribute('role', 'group');\n const scroller = document.createElement('div');\n scroller.className = 'fd-lines-scroll';\n const table = document.createElement('table');\n table.className = 'fd-lines-table';\n const head = document.createElement('thead');\n const headRow = document.createElement('tr');\n for (const column of columns) {\n const th = document.createElement('th');\n th.scope = 'col';\n th.textContent = def.fields[column].label;\n headRow.append(th);\n }\n const lastTh = document.createElement('th');\n lastTh.className = 'fd-lines-tools';\n headRow.append(lastTh);\n head.append(headRow);\n const body = document.createElement('tbody');\n table.append(head, body);\n // Number columns the page asks to add up, in a row under the lines.\n const totals = (node.totals ?? []).filter((column) => columns.includes(column));\n const sums = new Map<string, HTMLTableCellElement>();\n if (totals.length) {\n const foot = document.createElement('tfoot');\n const row = document.createElement('tr');\n row.className = 'fd-lines-totals';\n columns.forEach((column, i) => {\n const td = document.createElement('td');\n if (totals.includes(column)) sums.set(column, td);\n else if (i === 0) td.textContent = labels.total;\n row.append(td);\n });\n row.append(document.createElement('td'));\n foot.append(row);\n table.append(foot);\n }\n scroller.append(table);\n const adds = document.createElement('div');\n adds.className = 'fd-lines-adds';\n const addButton = (text: string, values: Record<string, Value>, kind: string) => {\n const button = document.createElement('button');\n button.type = 'button';\n button.className = 'fd-button fd-button-link fd-lines-add';\n button.dataset['add'] = kind;\n button.textContent = `+ ${text}`;\n button.addEventListener('click', () => {\n focusNew = form.addLine(name, values);\n const row = rows.get(focusNew);\n if (row) {\n row.cells[0]?.widget.focus();\n focusNew = null;\n }\n });\n adds.append(button);\n };\n addButton(labels.addLine, {}, 'line');\n if (kinds) {\n addButton(labels.addSection, { [kinds.field]: kinds.section ?? 'section' }, 'section');\n addButton(labels.addNote, { [kinds.field]: kinds.note ?? 'note' }, 'note');\n }\n element.append(scroller, adds);\n\n const rows = new Map<string, Row>();\n let focusNew: string | null = null;\n let readonly = false;\n\n function makeCell(tr: HTMLTableRowElement, line: Line, column: string, sub: LineField, span = 1) {\n const cellId = `${id}-${line.key}-${column}`;\n const subNode: FieldNode = { type: 'field', id: `${node.id}.${line.key}.${column}`, field: column };\n const widget = createWidget({ form: lineForm(form, name, line.key), name: column, field: sub as Field, node: subNode, id: cellId, document, labels, locale, dialogs });\n const td = document.createElement('td');\n td.colSpan = span;\n const label = document.createElement('label');\n label.className = 'fd-sr-only';\n label.htmlFor = cellId;\n label.textContent = sub.label;\n const error = document.createElement('div');\n error.className = 'fd-cell-error';\n error.hidden = true;\n td.append(label, widget.element, error);\n tr.append(td);\n return { name: column, def: sub, widget, error };\n }\n\n function makeRow(line: Line): Row {\n const tr = document.createElement('tr');\n tr.dataset['line'] = line.key;\n const kind = lineKind(def, line.values);\n if (kind) tr.className = `fd-line-${kind}`;\n const cells =\n kind && kinds\n ? [makeCell(tr, line, kinds.text, kindTextField(def.fields[kinds.text], kind), columns.length)]\n : columns.map((column) => makeCell(tr, line, column, def.fields[column]));\n const tools = document.createElement('td');\n tools.className = 'fd-lines-tools';\n const remove = document.createElement('button');\n remove.type = 'button';\n remove.className = 'fd-line-delete';\n remove.textContent = '\u00D7';\n remove.setAttribute('aria-label', labels.deleteLine);\n remove.addEventListener('click', () => form.removeLine(name, line.key));\n tools.append(remove);\n tr.append(tools);\n return { element: tr, kind, cells, remove };\n }\n\n return {\n element,\n focus: () => (body.querySelector<HTMLElement>('input, select, textarea') ?? adds.querySelector('button'))?.focus(),\n update(state) {\n readonly = state.readonly;\n adds.hidden = readonly;\n const current = (state.value as Line[] | null) ?? [];\n const errors = form.getState().errors;\n const keep = new Set(current.map((line) => line.key));\n for (const [key, row] of rows) {\n if (!keep.has(key)) {\n row.element.remove();\n rows.delete(key);\n }\n }\n current.forEach((line, index) => {\n let row = rows.get(line.key);\n // A line that changed kind is drawn afresh.\n if (row && row.kind !== lineKind(def, line.values)) {\n row.element.remove();\n row = undefined;\n }\n if (!row) {\n row = makeRow(line);\n rows.set(line.key, row);\n }\n if (body.children[index] !== row.element) body.insertBefore(row.element, body.children[index] ?? null);\n row.remove.hidden = readonly;\n if (readonly) row.remove.remove();\n else if (!row.remove.isConnected) row.element.lastElementChild?.append(row.remove);\n for (const cell of row.cells) {\n const message = errors[`${name}.${line.key}.${cell.name}`];\n cell.error.hidden = !message;\n cell.error.textContent = message ?? '';\n cell.widget.update({\n value: line.values[cell.name],\n values: line.values,\n readonly: readonly || cell.def.readonly === true,\n required: cell.def.required === true,\n invalid: !!message,\n });\n }\n });\n for (const [column, td] of sums) {\n const sum = current.filter((line) => !lineKind(def, line.values)).reduce((total, line) => total + Number(line.values[column] ?? 0), 0);\n td.textContent = displayValue(def.fields[column], sum, current[0]?.values ?? {}, locale);\n }\n if (focusNew && rows.has(focusNew)) {\n rows.get(focusNew)?.cells[0]?.widget.focus();\n focusNew = null;\n }\n },\n };\n};\n", "import { formatBytes, type FileValue } from '@fieldia/core';\nimport { WIDGET_LABELS } from './labels';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * File and image fields. A chosen or dropped file is read into the value as\n * base64, the way a backend's binary fields carry it; a stored one may carry\n * a `url` instead. Size and type limits are checked by the field's validation.\n */\n\nfunction read(file: File): Promise<FileValue> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const url = String(reader.result ?? '');\n resolve({ name: file.name, type: file.type, size: file.size, data: url.slice(url.indexOf(',') + 1) });\n };\n reader.onerror = () => reject(reader.error);\n reader.readAsDataURL(file);\n });\n}\n\nfunction fileWidget(kind: 'binary' | 'image'): WidgetFactory {\n return ({ form, name, field, id, document, labels = WIDGET_LABELS.en }) => {\n const element = document.createElement('div');\n element.className = `fd-file fd-file-${kind}`;\n const input = document.createElement('input');\n input.type = 'file';\n input.id = id;\n input.className = 'fd-sr-only';\n const accept = field.type === 'binary' ? field.accept : kind === 'image' ? ['image/*'] : undefined;\n if (accept) input.accept = accept.join(',');\n\n const preview = document.createElement('img');\n preview.className = 'fd-image-preview';\n preview.alt = field.label;\n preview.hidden = true;\n\n const pick = document.createElement('label');\n pick.className = kind === 'image' ? 'fd-file-pick fd-image-pick' : 'fd-file-pick';\n pick.htmlFor = id;\n const pickText = document.createElement('span');\n pickText.className = 'fd-button';\n pickText.textContent = kind === 'image' ? labels.uploadImage : labels.upload;\n const hint = document.createElement('span');\n hint.className = 'fd-help';\n hint.textContent = labels.dropHere;\n pick.append(pickText, hint);\n\n const chosen = document.createElement('div');\n chosen.className = 'fd-file-chosen';\n const fileName = document.createElement('span');\n fileName.className = 'fd-file-name';\n const replace = document.createElement('button');\n replace.type = 'button';\n replace.className = 'fd-button fd-button-link';\n replace.textContent = labels.replace;\n replace.addEventListener('click', () => input.click());\n const remove = document.createElement('button');\n remove.type = 'button';\n remove.className = 'fd-button fd-button-link';\n remove.textContent = labels.removeFile;\n remove.addEventListener('click', () => form.setValue(name, null));\n chosen.append(fileName, replace, remove);\n\n element.append(input, ...(kind === 'image' ? [preview] : []), pick, chosen);\n\n let readonly = false;\n const take = async (file: File | undefined) => {\n if (!file || readonly) return;\n form.setValue(name, await read(file));\n };\n input.addEventListener('change', () => {\n void take(input.files?.[0]);\n input.value = '';\n });\n element.addEventListener('dragover', (event) => {\n if (readonly) return;\n event.preventDefault();\n element.classList.add('fd-dragging');\n });\n element.addEventListener('dragleave', () => element.classList.remove('fd-dragging'));\n element.addEventListener('drop', (event) => {\n event.preventDefault();\n element.classList.remove('fd-dragging');\n void take((event as DragEvent).dataTransfer?.files?.[0]);\n });\n\n return {\n element,\n focus: () => (pick.hidden ? replace : input).focus(),\n update(state) {\n readonly = state.readonly;\n const file = state.value as FileValue | null | undefined;\n pick.hidden = !!file || readonly;\n chosen.hidden = !file;\n replace.hidden = remove.hidden = readonly;\n input.disabled = readonly;\n input.setAttribute('aria-invalid', String(state.invalid));\n if (state.describedBy) input.setAttribute('aria-describedby', state.describedBy);\n fileName.textContent = file ? `${file.name} \u00B7 ${formatBytes(file.size)}` : '';\n if (kind === 'image') {\n const src = file ? (file.data ? `data:${file.type};base64,${file.data}` : file.url ?? '') : '';\n preview.hidden = !src;\n if (preview.getAttribute('src') !== src) {\n if (src) preview.src = src;\n else preview.removeAttribute('src');\n }\n }\n },\n };\n };\n}\n\nexport const binaryWidget = fileWidget('binary');\nexport const imageWidget = fileWidget('image');\n", "import type { Locale } from '@fieldia/core';\nimport { createWidget, type Widget, type WidgetFactory } from './widgets';\n\n/**\n * A number shown as a bar that fills towards a maximum, coloured by how far\n * it has come: red under 30 %, yellow under 70 %, green from there. Options:\n *\n * max the maximum, 100 by default (min 0)\n * maxField a number field that holds the maximum instead\n * color \"auto\", or always \"success\", \"warning\", \"danger\" or \"info\"\n * showPercent false to leave the percentage off the bar\n * editable true for a box beside the bar to type the value in\n */\n\nconst percents = new Map<Locale, Intl.NumberFormat>();\nfunction percent(value: number, locale: Locale) {\n let format = percents.get(locale);\n if (!format) {\n format = new Intl.NumberFormat(locale, { style: 'percent', maximumFractionDigits: 0, numberingSystem: 'latn' });\n percents.set(locale, format);\n }\n return format.format(value / 100);\n}\n\nexport const progressbarWidget: WidgetFactory = (context) => {\n const { node, id, document, locale = 'en' } = context;\n const options = node.options ?? {};\n const min = typeof options['min'] === 'number' ? options['min'] : 0;\n const fixedMax = typeof options['max'] === 'number' ? options['max'] : 100;\n const maxField = typeof options['maxField'] === 'string' ? options['maxField'] : null;\n const color = typeof options['color'] === 'string' ? options['color'] : 'auto';\n const showPercent = options['showPercent'] !== false;\n\n const bar = document.createElement('div');\n bar.className = 'fd-progressbar';\n bar.setAttribute('role', 'progressbar');\n const fill = document.createElement('div');\n fill.className = 'fd-progressbar-fill';\n const text = document.createElement('span');\n text.className = 'fd-progressbar-text';\n bar.append(fill, text);\n\n // Editable: the field's own number box takes the value; the bar beside it only shows it.\n let box: Widget | null = null;\n let element: HTMLElement = bar;\n if (options['editable'] === true) {\n box = createWidget({ ...context, node: { ...node, widget: undefined } });\n bar.setAttribute('aria-hidden', 'true');\n element = document.createElement('div');\n element.className = 'fd-progressbar-edit';\n element.append(bar, box.element);\n } else {\n bar.id = id;\n }\n\n return {\n element,\n focus: () => box?.focus(),\n update(state) {\n const value = typeof state.value === 'number' ? state.value : 0;\n const max = maxField ? Number(state.values[maxField] ?? 0) : fixedMax;\n const share = max > min ? Math.min(100, Math.max(0, ((value - min) / (max - min)) * 100)) : 0;\n const rounded = Math.round(share * 10) / 10;\n fill.style.width = `${rounded}%`;\n bar.setAttribute('aria-valuenow', String(value));\n bar.setAttribute('aria-valuemin', String(min));\n bar.setAttribute('aria-valuemax', String(max));\n bar.setAttribute('aria-valuetext', percent(share, locale));\n text.textContent = showPercent ? percent(share, locale) : '';\n bar.dataset['tone'] = color !== 'auto' ? color : share < 30 ? 'danger' : share < 70 ? 'warning' : 'success';\n box?.update(state);\n },\n };\n};\n", "import type { Locale, RelatedRecord, Value } from '@fieldia/core';\nimport { formatNumber } from './numbers';\nimport { summary, type WidgetFactory } from './widgets';\n\n/**\n * A value shown as text between a prefix and a suffix: \"24 months\",\n * \"240.0 m\". Never edited. Options:\n *\n * prefix, suffix words around the value\n * prefixField, suffixField a field whose value is the prefix or suffix instead\n */\n\n/** Another field's value as words: a link's label, or the value itself. */\nfunction words(value: Value | undefined): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'object' && 'label' in (value as object)) return (value as RelatedRecord).label;\n return String(value);\n}\n\nexport const labelWidget: WidgetFactory = ({ field, node, id, document, locale = 'en' as Locale }) => {\n const options = node.options ?? {};\n const text = (key: 'prefix' | 'suffix') => (typeof options[key] === 'string' ? (options[key] as string) : '');\n const from = (key: 'prefixField' | 'suffixField') => (typeof options[key] === 'string' ? (options[key] as string) : null);\n const decimals =\n field.type === 'integer' ? 0 : field.type === 'float' || field.type === 'monetary' ? (field.digits?.[1] ?? 2) : null;\n\n const output = document.createElement('output');\n output.id = id;\n output.className = 'fd-value-text';\n return {\n element: output,\n focus: () => undefined,\n update({ value, values }) {\n if (value === null || value === undefined || value === '') {\n output.textContent = '';\n return;\n }\n const shown = decimals !== null && typeof value === 'number' ? formatNumber(value, decimals, locale) : summary(value, field);\n const prefixField = from('prefixField');\n const suffixField = from('suffixField');\n const prefix = prefixField ? words(values[prefixField]) : text('prefix');\n const suffix = suffixField ? words(values[suffixField]) : text('suffix');\n output.textContent = [prefix, shown, suffix].filter((part) => part !== '').join(' ');\n },\n };\n};\n", "import type { RelatedRecord } from '@fieldia/core';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * Where a record stands, as a row of steps with the current one marked: a\n * selection's states, or the records a link may point to (stages). Used in a\n * sheet's header, and anywhere in a form with `\"widget\": \"statusbar\"`. Options:\n *\n * clickable true to let a click move the record to another step\n * visibleStates the values to show; the current one always shows\n */\n\ninterface Step {\n key: string;\n label: string;\n value: unknown;\n}\n\nexport const statusbarWidget: WidgetFactory = ({ form, name, field, node, id, document }) => {\n const options = node.options ?? {};\n const clickable = options['clickable'] === true;\n const visible = Array.isArray(options['visibleStates']) ? options['visibleStates'] : null;\n const list = document.createElement('ol');\n list.className = 'fd-statusbar';\n list.id = id;\n list.setAttribute('aria-label', field.label);\n\n const keyOf = (value: unknown) =>\n value && typeof value === 'object' && 'id' in value ? `id:${String((value as RelatedRecord).id)}` : `v:${String(value)}`;\n // A selection knows its steps; a link's are looked up once.\n let steps: Step[] =\n field.type === 'selection' ? field.options.map((o) => ({ key: keyOf(o.value), label: o.label, value: o.value })) : [];\n let lookedUp = field.type === 'selection';\n let last: { value: unknown; readonly: boolean } = { value: undefined, readonly: false };\n\n function draw() {\n const { value, readonly } = last;\n const currentKey = value === null || value === undefined ? null : keyOf(value);\n let shown = steps.filter((s) => !visible || visible.some((v) => keyOf(v) === s.key) || s.key === currentKey);\n if (currentKey && !shown.some((s) => s.key === currentKey) && value && typeof value === 'object') {\n shown = [...shown, { key: currentKey, label: (value as RelatedRecord).label, value }];\n }\n list.replaceChildren(\n ...shown.map((step) => {\n const label = document.createElement('span');\n label.textContent = step.label;\n const inner = document.createElement(clickable ? 'button' : 'span');\n if (inner instanceof HTMLButtonElement) {\n inner.type = 'button';\n inner.disabled = readonly;\n inner.addEventListener('click', () => form.setValue(name, step.value as never));\n }\n inner.append(label);\n if (step.key === currentKey) inner.setAttribute('aria-current', 'step');\n const item = document.createElement('li');\n item.append(inner);\n return item;\n })\n );\n }\n\n return {\n element: list,\n focus: () => list.querySelector<HTMLElement>('button:not([disabled])')?.focus(),\n update(state) {\n last = { value: state.value, readonly: state.readonly };\n draw();\n if (!lookedUp) {\n lookedUp = true;\n void form\n .search(name, '', 20)\n .then((records) => {\n steps = records.map((r) => ({ key: keyOf(r), label: r.label, value: r }));\n draw();\n })\n .catch(() => undefined);\n }\n },\n };\n};\n", "import type { Locale, Value } from '@fieldia/core';\nimport { WIDGET_LABELS, type WidgetLabels } from './labels';\nimport type { Widget, WidgetContext } from './widgets';\n\n/**\n * A calendar beside a date, for when the person needs the week numbers\n * (`options.weekNumbers` on a date or date-and-time node). The ARIA\n * date-picker dialog: a grid of days, Monday first, an ISO 8601 week number at\n * the start of each row, arrow keys by day and week, PageUp and PageDown by\n * month, Enter to pick, Escape to close.\n */\n\n/** The ISO 8601 week a day falls in: weeks start on Monday, week 1 holds the year's first Thursday. */\nexport function isoWeek(day: Date): number {\n const t = new Date(Date.UTC(day.getFullYear(), day.getMonth(), day.getDate()));\n t.setUTCDate(t.getUTCDate() + 4 - (t.getUTCDay() || 7));\n const yearStart = Date.UTC(t.getUTCFullYear(), 0, 1);\n return Math.ceil(((t.getTime() - yearStart) / 86400000 + 1) / 7);\n}\n\nconst pad = (n: number) => String(n).padStart(2, '0');\nconst sameDay = (a: Date, b: Date) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\nconst addDays = (d: Date, n: number) => new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);\n/** The same day of another month, or that month's last day when it is shorter. */\nfunction addMonths(d: Date, n: number) {\n const last = new Date(d.getFullYear(), d.getMonth() + n + 1, 0).getDate();\n return new Date(d.getFullYear(), d.getMonth() + n, Math.min(d.getDate(), last));\n}\n\n/** The day a date field holds (\"2026-10-11\"), or a date and time (an ISO instant), in local time. */\nfunction dayOf(kind: 'date' | 'datetime', value: Value | undefined): Date | null {\n if (typeof value !== 'string' || !value) return null;\n if (kind === 'date') {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})/.exec(value);\n return m ? new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3])) : null;\n }\n const d = new Date(value);\n return Number.isNaN(d.getTime()) ? null : d;\n}\n\nexport function withCalendar(inner: Widget, context: WidgetContext, kind: 'date' | 'datetime'): Widget {\n const { form, name, id, document: doc, locale = 'en' as Locale } = context;\n const labels: WidgetLabels = context.labels ?? WIDGET_LABELS.en;\n const lang = locale === 'en' ? 'en-GB' : locale;\n const monthName = new Intl.DateTimeFormat(lang, { month: 'long', year: 'numeric', numberingSystem: 'latn' });\n const dayName = new Intl.DateTimeFormat(lang, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric', numberingSystem: 'latn' });\n const weekdayShort = new Intl.DateTimeFormat(lang, { weekday: 'short' });\n const weekdayLong = new Intl.DateTimeFormat(lang, { weekday: 'long' });\n\n const button = doc.createElement('button');\n button.type = 'button';\n button.className = 'fd-calendar-button';\n // A drawn calendar: an emoji would look different on every system.\n const svg = 'http://www.w3.org/2000/svg';\n const icon = doc.createElementNS(svg, 'svg');\n icon.setAttribute('viewBox', '0 0 16 16');\n icon.setAttribute('aria-hidden', 'true');\n for (const [tag, attrs] of [\n ['rect', { x: '2', y: '3', width: '12', height: '11', rx: '1.5' }],\n ['path', { d: 'M2 6.5h12M5 1.5v3M11 1.5v3' }],\n ] as const) {\n const shape = doc.createElementNS(svg, tag);\n for (const [k, v] of Object.entries(attrs)) shape.setAttribute(k, v);\n icon.append(shape);\n }\n button.append(icon);\n button.setAttribute('aria-label', labels.chooseDate);\n button.setAttribute('aria-haspopup', 'dialog');\n button.setAttribute('aria-expanded', 'false');\n button.setAttribute('aria-controls', `${id}-calendar`);\n\n const dialog = doc.createElement('div');\n dialog.className = 'fd-calendar';\n dialog.id = `${id}-calendar`;\n dialog.setAttribute('role', 'dialog');\n dialog.hidden = true;\n const head = doc.createElement('div');\n head.className = 'fd-calendar-head';\n const prev = doc.createElement('button');\n prev.type = 'button';\n prev.textContent = '\u2039';\n prev.setAttribute('aria-label', labels.previousMonth);\n const title = doc.createElement('span');\n title.className = 'fd-calendar-title';\n title.setAttribute('aria-live', 'polite');\n const next = doc.createElement('button');\n next.type = 'button';\n next.textContent = '\u203A';\n next.setAttribute('aria-label', labels.nextMonth);\n head.append(prev, title, next);\n const grid = doc.createElement('table');\n grid.className = 'fd-calendar-grid';\n grid.setAttribute('role', 'grid');\n dialog.append(head, grid);\n\n const element = doc.createElement('span');\n element.className = 'fd-date-pick';\n element.append(inner.element, button, dialog);\n\n let focused = new Date();\n let readonly = false;\n\n function pick(day: Date) {\n if (kind === 'date') {\n form.setValue(name, `${day.getFullYear()}-${pad(day.getMonth() + 1)}-${pad(day.getDate())}`);\n } else {\n const was = dayOf('datetime', form.getState().values[name]);\n const at = new Date(day.getFullYear(), day.getMonth(), day.getDate(), was?.getHours() ?? 0, was?.getMinutes() ?? 0);\n form.setValue(name, at.toISOString());\n }\n close();\n }\n\n function draw(focus: boolean) {\n const chosen = dayOf(kind, form.getState().values[name]);\n const today = new Date();\n const label = monthName.format(focused);\n title.textContent = label;\n dialog.setAttribute('aria-label', label);\n const first = new Date(focused.getFullYear(), focused.getMonth(), 1);\n const start = addDays(first, -((first.getDay() + 6) % 7)); // back to Monday\n const headRow = doc.createElement('tr');\n const weekHead = doc.createElement('th');\n weekHead.scope = 'col';\n weekHead.textContent = labels.weekShort;\n weekHead.setAttribute('abbr', labels.week);\n headRow.append(weekHead);\n for (let i = 0; i < 7; i++) {\n const d = addDays(start, i);\n const th = doc.createElement('th');\n th.scope = 'col';\n th.textContent = weekdayShort.format(d).replace(/\\.$/, '');\n th.setAttribute('abbr', weekdayLong.format(d));\n headRow.append(th);\n }\n const thead = doc.createElement('thead');\n thead.append(headRow);\n const tbody = doc.createElement('tbody');\n for (let row = start; row <= new Date(focused.getFullYear(), focused.getMonth() + 1, 0); row = addDays(row, 7)) {\n const tr = doc.createElement('tr');\n const week = doc.createElement('th');\n week.scope = 'row';\n week.className = 'fd-week';\n week.textContent = String(isoWeek(row));\n tr.append(week);\n for (let i = 0; i < 7; i++) {\n const d = addDays(row, i);\n const cell = doc.createElement('td');\n const day = doc.createElement('button');\n day.type = 'button';\n day.textContent = String(d.getDate());\n day.setAttribute('aria-label', dayName.format(d));\n day.tabIndex = sameDay(d, focused) ? 0 : -1;\n if (d.getMonth() !== focused.getMonth()) day.classList.add('fd-outside');\n if (chosen && sameDay(d, chosen)) day.setAttribute('aria-selected', 'true');\n if (sameDay(d, today)) day.setAttribute('aria-current', 'date');\n day.disabled = readonly;\n day.addEventListener('click', () => pick(d));\n day.addEventListener('keydown', (event) => onKey(event, d));\n cell.append(day);\n tr.append(cell);\n }\n tbody.append(tr);\n }\n grid.replaceChildren(thead, tbody);\n if (focus) grid.querySelector<HTMLButtonElement>('button[tabindex=\"0\"]')?.focus();\n }\n\n function move(to: Date) {\n focused = to;\n draw(true);\n }\n\n function onKey(event: KeyboardEvent, day: Date) {\n const moves: Record<string, () => Date> = {\n ArrowLeft: () => addDays(day, -1),\n ArrowRight: () => addDays(day, 1),\n ArrowUp: () => addDays(day, -7),\n ArrowDown: () => addDays(day, 7),\n PageUp: () => addMonths(day, -1),\n PageDown: () => addMonths(day, 1),\n Home: () => addDays(day, -((day.getDay() + 6) % 7)),\n End: () => addDays(day, 6 - ((day.getDay() + 6) % 7)),\n };\n if (moves[event.key]) {\n event.preventDefault();\n move(moves[event.key]());\n } else if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n pick(day);\n }\n }\n\n function open() {\n focused = dayOf(kind, form.getState().values[name]) ?? new Date();\n dialog.hidden = false;\n button.setAttribute('aria-expanded', 'true');\n draw(true);\n }\n\n function close() {\n if (dialog.hidden) return;\n dialog.hidden = true;\n button.setAttribute('aria-expanded', 'false');\n button.focus();\n }\n\n button.addEventListener('click', () => (dialog.hidden ? open() : close()));\n prev.addEventListener('click', () => {\n focused = addMonths(focused, -1);\n draw(false);\n });\n next.addEventListener('click', () => {\n focused = addMonths(focused, 1);\n draw(false);\n });\n dialog.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n event.stopPropagation();\n close();\n }\n });\n const outside = (event: Event) => {\n if (!dialog.hidden && !element.contains(event.target as Node)) {\n dialog.hidden = true;\n button.setAttribute('aria-expanded', 'false');\n }\n };\n doc.addEventListener('mousedown', outside);\n\n return {\n element,\n focus: () => inner.focus(),\n update(state) {\n readonly = state.readonly;\n button.hidden = state.readonly;\n if (state.readonly) dialog.hidden = true;\n inner.update(state);\n },\n destroy() {\n doc.removeEventListener('mousedown', outside);\n inner.destroy?.();\n },\n };\n}\n", "import type { Field, FieldNode, Form, FormState, JsonValue, PropertyDefinition, Value } from '@fieldia/core';\nimport { createWidget, type Widget, type WidgetFactory } from './widgets';\n\n/**\n * A properties field, one row per property, each edited with the widget for\n * its type: text, numbers, yes/no, a choice, a date. The field's `definitions`\n * say which properties there are; without them, each property is worked out\n * from its value. The properties stay one value: an object by property name.\n */\n\n/** \"lift_access\" \u2192 \"Lift access\". */\nconst humanize = (name: string) => {\n const words = name.replace(/_/g, ' ').trim();\n return words.charAt(0).toUpperCase() + words.slice(1);\n};\n\n/** A property's type, from what it holds. */\nfunction guess(name: string, value: Value | undefined): PropertyDefinition {\n const label = humanize(name);\n if (typeof value === 'boolean') return { name, label, type: 'boolean' };\n if (typeof value === 'number') return { name, label, type: Number.isInteger(value) ? 'integer' : 'float' };\n if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return { name, label, type: 'date' };\n return { name, label, type: 'char' };\n}\n\nexport const propertiesWidget: WidgetFactory = (context) => {\n const { form, name, field, node, id, document } = context;\n const declared = field.type === 'properties' ? field.definitions : undefined;\n const current = () => {\n const value = form.getState().values[name];\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, Value>) : {};\n };\n // Each property's widget sees the properties as its record, and writes into them.\n const properties: Form = {\n ...form,\n getState: (): FormState => ({ ...form.getState(), values: current() }),\n // Property values are plain JSON: text, numbers, yes/no, a choice, a date.\n setValue: (property: string, value: Value) => form.setValue(name, { ...current(), [property]: value } as JsonValue),\n };\n\n const element = document.createElement('div');\n element.className = 'fd-properties';\n element.setAttribute('role', 'group');\n let rows: { definition: PropertyDefinition; widget: Widget }[] = [];\n let drawn = '';\n\n function draw(definitions: PropertyDefinition[]) {\n for (const row of rows) row.widget.destroy?.();\n rows = definitions.map((definition) => {\n const rowId = `${id}-${definition.name}`;\n const propertyField = { type: definition.type, label: definition.label, ...(definition.options ? { options: definition.options } : {}) } as Field;\n const propertyNode: FieldNode = { type: 'field', id: `${node.id}.${definition.name}`, field: definition.name };\n const widget = createWidget({ ...context, form: properties, name: definition.name, field: propertyField, node: propertyNode, id: rowId });\n return { definition, widget };\n });\n element.replaceChildren(\n ...rows.map(({ definition, widget }) => {\n const row = document.createElement('div');\n row.className = 'fd-property';\n row.dataset['type'] = definition.type;\n const label = document.createElement('label');\n label.htmlFor = `${id}-${definition.name}`;\n label.textContent = definition.label;\n row.append(label, widget.element);\n return row;\n })\n );\n }\n\n return {\n element,\n focus: () => rows[0]?.widget.focus(),\n destroy: () => rows.forEach((row) => row.widget.destroy?.()),\n update(state) {\n const values = current();\n const definitions = declared ?? Object.keys(values).map((key) => guess(key, values[key]));\n const key = JSON.stringify(definitions);\n if (key !== drawn) {\n drawn = key;\n draw(definitions);\n }\n for (const { definition, widget } of rows) {\n widget.update({ value: values[definition.name] ?? null, values, readonly: state.readonly, required: false, invalid: false });\n }\n },\n };\n};\n", "import { WIDGET_LABELS, type WidgetLabels } from './labels';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * Formatted text and JSON. Formatted text is edited in place, with a toolbar\n * (bold, italic, underline, headings, lists, alignment, links) that drives the\n * browser's own editing, so no editor library is loaded. Every value \u2014 typed,\n * pasted or loaded \u2014 passes through `sanitizeHtml`, so stored markup can never\n * run script in the page.\n */\n\nconst ALLOWED = new Set([\n 'P', 'BR', 'B', 'STRONG', 'I', 'EM', 'U', 'S', 'UL', 'OL', 'LI', 'A', 'H1', 'H2', 'H3', 'H4',\n 'BLOCKQUOTE', 'CODE', 'PRE', 'SPAN', 'DIV',\n]);\nconst DROPPED_WITH_CONTENT = new Set(['SCRIPT', 'STYLE', 'IFRAME', 'OBJECT', 'EMBED', 'TEMPLATE', 'NOSCRIPT', 'SVG', 'MATH']);\n/** Blocks that may keep their alignment, the one style the toolbar sets. */\nconst ALIGNABLE = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'LI', 'BLOCKQUOTE', 'PRE']);\nconst ALIGNMENTS = new Set(['left', 'center', 'right', 'justify', 'start', 'end']);\n\n/** Keep text structure, block alignment and http(s)/mailto links; drop every other element and attribute. */\nexport function sanitizeHtml(html: string, document: Document = globalThis.document): string {\n const box = document.createElement('template');\n box.innerHTML = html;\n const clean = (parent: ParentNode) => {\n for (const node of [...parent.childNodes]) {\n if (node.nodeType === Node.TEXT_NODE) continue;\n if (node.nodeType !== Node.ELEMENT_NODE) {\n node.remove();\n continue;\n }\n const element = node as Element;\n if (DROPPED_WITH_CONTENT.has(element.tagName)) {\n element.remove();\n continue;\n }\n clean(element);\n if (!ALLOWED.has(element.tagName)) {\n element.replaceWith(...element.childNodes);\n continue;\n }\n const href = element.tagName === 'A' ? element.getAttribute('href') : null;\n const align = ALIGNABLE.has(element.tagName) ? (element as HTMLElement).style?.textAlign?.trim().toLowerCase() : '';\n for (const attribute of [...element.attributes]) element.removeAttribute(attribute.name);\n if (href && /^(https?:|mailto:)/i.test(href.trim())) element.setAttribute('href', href.trim());\n if (align && ALIGNMENTS.has(align)) element.setAttribute('style', `text-align: ${align};`);\n }\n };\n clean(box.content);\n const out = document.createElement('div');\n out.append(box.content);\n return out.innerHTML;\n}\n\n/** A typed address as a link target: web and mail addresses only, \"https://\" added to a bare domain. */\nexport function linkAddress(typed: string): string | null {\n const text = typed.trim();\n if (/^(https?:\\/\\/|mailto:)\\S+$/i.test(text)) return text;\n if (/^[^\\s@:/]+@[^\\s@:/]+\\.[^\\s@:/]+$/.test(text)) return `mailto:${text}`;\n if (/^[\\w-]+(\\.[\\w-]+)+([/?#]\\S*)?$/.test(text)) return `https://${text}`;\n return null;\n}\n\n/** The toolbar's buttons: [label key, editing command, drawn icon]. */\nconst TOOLS: [keyof WidgetLabels, string, string][] = [\n ['bold', 'bold', '<b>B</b>'],\n ['italic', 'italic', '<i>I</i>'],\n ['underline', 'underline', '<u>U</u>'],\n ['bulletList', 'insertUnorderedList', '<svg viewBox=\"0 0 16 16\"><circle cx=\"3\" cy=\"4\" r=\"1.2\"/><circle cx=\"3\" cy=\"8\" r=\"1.2\"/><circle cx=\"3\" cy=\"12\" r=\"1.2\"/><path d=\"M6 4h8M6 8h8M6 12h8\"/></svg>'],\n ['numberList', 'insertOrderedList', '<svg viewBox=\"0 0 16 16\"><path d=\"M2.5 3h1v3M2 10.5c.5-.8 2-.8 2 .2 0 .8-2 1.3-2 2.3h2M6 4h8M6 8h8M6 12h8\"/></svg>'],\n ['alignLeft', 'justifyLeft', '<svg viewBox=\"0 0 16 16\"><path d=\"M2 3.5h12M2 6.5h8M2 9.5h12M2 12.5h8\"/></svg>'],\n ['alignCenter', 'justifyCenter', '<svg viewBox=\"0 0 16 16\"><path d=\"M2 3.5h12M4 6.5h8M2 9.5h12M4 12.5h8\"/></svg>'],\n ['alignRight', 'justifyRight', '<svg viewBox=\"0 0 16 16\"><path d=\"M2 3.5h12M6 6.5h8M2 9.5h12M6 12.5h8\"/></svg>'],\n ['link', 'createLink', '<svg viewBox=\"0 0 16 16\"><path d=\"M7 9a3 3 0 0 0 4.2 0l2.3-2.3a3 3 0 0 0-4.2-4.2L8.2 3.6M9 7a3 3 0 0 0-4.2 0L2.5 9.3a3 3 0 0 0 4.2 4.2l1.1-1.1\"/></svg>'],\n];\n\nexport const htmlWidget: WidgetFactory = ({ form, name, node, id, document, labels = WIDGET_LABELS.en }) => {\n const area = document.createElement('div');\n area.id = id;\n area.className = 'fd-input fd-richtext';\n area.setAttribute('role', 'textbox');\n area.setAttribute('aria-multiline', 'true');\n area.setAttribute('contenteditable', 'true');\n const withToolbar = node.options?.['toolbar'] !== false;\n let last = '';\n area.addEventListener('input', () => {\n const clean = sanitizeHtml(area.innerHTML, document);\n last = clean;\n form.setValue(name, clean.trim() === '' ? null : clean);\n });\n area.addEventListener('blur', () => {\n // Show what was stored: anything unsafe that was typed or pasted is gone.\n if (area.innerHTML !== last) area.innerHTML = last;\n });\n const toolbar = withToolbar ? formattingToolbar(area, document, labels) : null;\n let element: HTMLElement = area;\n if (toolbar) {\n // The box is labelled by the field's label; the text inside it says so too.\n element = document.createElement('div');\n element.className = 'fd-richtext-box';\n element.setAttribute('role', 'group');\n area.setAttribute('aria-labelledby', `${id}-label`);\n element.append(toolbar.bar, toolbar.linkRow, area);\n }\n return {\n element,\n focus: () => area.focus(),\n destroy: () => toolbar?.destroy(),\n update(state) {\n if (toolbar) {\n toolbar.bar.hidden = state.readonly;\n if (state.readonly) toolbar.linkRow.hidden = true;\n }\n const clean = sanitizeHtml(typeof state.value === 'string' ? state.value : '', document);\n if (clean !== last || document.activeElement !== area) {\n if (area.innerHTML !== clean) area.innerHTML = clean;\n last = clean;\n }\n area.setAttribute('contenteditable', String(!state.readonly));\n area.setAttribute('aria-readonly', String(state.readonly));\n area.setAttribute('aria-invalid', String(state.invalid));\n if (state.describedBy) area.setAttribute('aria-describedby', state.describedBy);\n },\n };\n};\n\n/**\n * The toolbar of a formatted text: buttons that keep the text's selection\n * (they act on mousedown's behalf), a text-style choice, and a row for a link's\n * address. One button takes Tab; the arrow keys move along the bar.\n */\nfunction formattingToolbar(area: HTMLElement, doc: Document, labels: WidgetLabels) {\n const bar = doc.createElement('div');\n bar.className = 'fd-richtext-bar';\n bar.setAttribute('role', 'toolbar');\n bar.setAttribute('aria-label', labels.formatting);\n // The last selection made in the text: the style box and the address box take\n // the focus, and a command must act where the person had selected.\n let lastRange: Range | null = null;\n const restore = () => {\n area.focus();\n const selection = doc.getSelection();\n if (lastRange && selection) {\n selection.removeAllRanges();\n selection.addRange(lastRange);\n }\n };\n const run = (command: string, value?: string) => {\n restore();\n doc.execCommand?.(command, false, value);\n };\n\n const style = doc.createElement('select');\n style.className = 'fd-richtext-style';\n style.setAttribute('aria-label', labels.textStyle);\n for (const [value, key] of [['p', 'paragraph'], ['h2', 'heading'], ['h3', 'subheading']] as const) {\n const option = doc.createElement('option');\n option.value = value;\n option.textContent = labels[key];\n style.append(option);\n }\n style.addEventListener('change', () => run('formatBlock', `<${style.value}>`));\n\n const linkRow = doc.createElement('div');\n linkRow.className = 'fd-link-row';\n linkRow.hidden = true;\n const address = doc.createElement('input');\n address.className = 'fd-input';\n address.type = 'url';\n address.placeholder = 'https://';\n address.setAttribute('aria-label', labels.linkAddress);\n const apply = doc.createElement('button');\n apply.type = 'button';\n apply.className = 'fd-button fd-link-apply';\n apply.textContent = labels.applyLink;\n const unlink = doc.createElement('button');\n unlink.type = 'button';\n unlink.className = 'fd-button fd-button-link fd-link-remove';\n unlink.textContent = labels.removeLink;\n linkRow.append(address, apply, unlink);\n apply.addEventListener('click', () => {\n const url = linkAddress(address.value);\n if (!url) {\n address.setAttribute('aria-invalid', 'true');\n return;\n }\n address.setAttribute('aria-invalid', 'false');\n restore();\n doc.execCommand?.('createLink', false, url);\n linkRow.hidden = true;\n });\n unlink.addEventListener('click', () => {\n restore();\n doc.execCommand?.('unlink', false);\n linkRow.hidden = true;\n });\n address.addEventListener('keydown', (event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n apply.click();\n } else if (event.key === 'Escape') {\n event.preventDefault();\n linkRow.hidden = true;\n restore();\n }\n });\n\n const buttons = TOOLS.map(([key, command, icon]) => {\n const button = doc.createElement('button');\n button.type = 'button';\n button.className = 'fd-richtext-tool';\n button.setAttribute('aria-label', labels[key]);\n button.title = labels[key];\n button.innerHTML = icon;\n button.querySelector('svg')?.setAttribute('aria-hidden', 'true');\n if (['bold', 'italic', 'underline'].includes(command)) button.setAttribute('aria-pressed', 'false');\n // Keep the text's selection when the button is pressed.\n button.addEventListener('mousedown', (event) => event.preventDefault());\n button.addEventListener('click', () => {\n if (command !== 'createLink') return run(command);\n linkRow.hidden = false;\n address.value = '';\n address.focus();\n });\n return button;\n });\n bar.append(style, ...buttons);\n\n // One stop on Tab; the arrow keys move along the bar.\n const stops = [style, ...buttons];\n stops.forEach((stop, i) => (stop.tabIndex = i === 0 ? 0 : -1));\n bar.addEventListener('keydown', (event) => {\n if (event.key !== 'ArrowRight' && event.key !== 'ArrowLeft') return;\n const at = stops.indexOf(doc.activeElement as HTMLButtonElement);\n if (at < 0) return;\n const rtl = getComputedStyle(bar).direction === 'rtl';\n const step = (event.key === 'ArrowRight') !== rtl ? 1 : -1;\n const next = stops[(at + step + stops.length) % stops.length];\n event.preventDefault();\n stops.forEach((stop) => (stop.tabIndex = stop === next ? 0 : -1));\n next.focus();\n });\n\n // Show which formats the selection already has.\n const reflect = () => {\n const selection = doc.getSelection();\n if (!selection || !selection.rangeCount || !area.contains(selection.anchorNode)) return;\n lastRange = selection.getRangeAt(0).cloneRange();\n for (const button of buttons) {\n const command = TOOLS[buttons.indexOf(button)][1];\n if (button.hasAttribute('aria-pressed')) button.setAttribute('aria-pressed', String(doc.queryCommandState?.(command) ?? false));\n }\n const block = String(doc.queryCommandValue?.('formatBlock') ?? '').toLowerCase().replace(/[<>]/g, '');\n style.value = block === 'h2' || block === 'h3' ? block : 'p';\n };\n doc.addEventListener('selectionchange', reflect);\n return { bar, linkRow, destroy: () => doc.removeEventListener('selectionchange', reflect) };\n}\n\nexport const jsonWidget: WidgetFactory = ({ form, name, id, document, labels = WIDGET_LABELS.en }) => {\n const element = document.createElement('div');\n element.className = 'fd-json';\n const area = document.createElement('textarea');\n area.id = id;\n area.className = 'fd-input fd-textarea fd-code';\n area.spellcheck = false;\n const error = document.createElement('div');\n error.className = 'fd-cell-error';\n error.hidden = true;\n element.append(area, error);\n area.addEventListener('input', () => {\n if (area.value.trim() === '') {\n error.hidden = true;\n form.setValue(name, null);\n return;\n }\n try {\n const parsed = JSON.parse(area.value);\n error.hidden = true;\n form.setValue(name, parsed);\n } catch {\n error.hidden = false;\n error.textContent = labels.invalidJson;\n }\n });\n return {\n element,\n focus: () => area.focus(),\n update(state) {\n if (document.activeElement !== area) {\n const text = state.value === null || state.value === undefined ? '' : JSON.stringify(state.value, null, 2);\n if (area.value !== text) area.value = text;\n }\n area.readOnly = state.readonly;\n area.setAttribute('aria-invalid', String(state.invalid || !error.hidden));\n },\n };\n};\n", "import type {\n Field,\n FieldNode,\n FileValue,\n Form,\n Line,\n Locale,\n RecordId,\n ReferenceValue,\n RelatedRecord,\n Value,\n Values,\n} from '@fieldia/core';\nimport type { PreferenceStore } from './preferences';\nimport { formatNumber, normalizeNumber } from './numbers';\nimport type { WidgetLabels } from './labels';\nimport { charTagsWidget, linkCheckboxesWidget, many2oneWidget, referenceWidget, tagsWidget } from './relations';\nimport { linesWidget } from './lines';\nimport { binaryWidget, imageWidget } from './files';\nimport { progressbarWidget } from './progress';\nimport { labelWidget } from './label';\nimport { statusbarWidget } from './statusbar';\nimport { withCalendar } from './calendar';\nimport { propertiesWidget } from './properties';\nimport { htmlWidget, jsonWidget } from './extras';\n\n/**\n * Field inputs in plain DOM. Each widget builds its element once and then only\n * patches it from state, so typing never loses focus or the caret, and the\n * same widget serves every framework binding.\n */\n\nexport interface WidgetContext {\n form: Form;\n /** The field's name in the page. */\n name: string;\n field: Field;\n node: FieldNode;\n /** The id the field's label points at. */\n id: string;\n document: Document;\n /** Words the widget shows itself, in the page's language. English when left out. */\n labels?: WidgetLabels;\n /** Where to keep a person's choices about how the widget looks, such as a table's columns. */\n preferences?: PreferenceStore;\n /** The page's language: numbers and dates are written as its readers write them. English when left out. */\n locale?: Locale;\n /** Dialogs the page can open: a related record, a searchable list, values to edit. Left out, widgets offer none. */\n dialogs?: WidgetDialogs;\n}\n\n/** What a widget may ask of the page around it in a dialog. The viewer provides these. */\nexport interface WidgetDialogs {\n /** Whether a record of this model can be shown in a dialog: the app gave a page for it. */\n canOpen(model: string): boolean;\n /**\n * A record in a dialog: an existing one (`recordId`) or a new one, whose name\n * starts as `name`. Resolves with the record once saved, or null.\n */\n openRecord(model: string, request: { recordId?: RecordId; name?: string; title: string }): Promise<RelatedRecord | null>;\n /** Pick a record from a searchable list. */\n searchMore(request: { title: string; search(query: string, limit: number): Promise<RelatedRecord[]> }): Promise<RelatedRecord | null>;\n /**\n * Values edited in a form made of these fields. Resolves with the new values,\n * or null. `recompute` recalculates them as they change, as a line's onchange.\n */\n editValues(request: { title: string; fields: Record<string, Field>; values: Values; readonly?: boolean; recompute?: (values: Values) => Promise<Values> }): Promise<Values | null>;\n}\n\nexport interface WidgetState {\n value: Value | undefined;\n /** Every value of the record, for widgets that show one field beside another. */\n values: Readonly<Values>;\n readonly: boolean;\n required: boolean;\n invalid: boolean;\n /** Ids of the help and error text, for assistive technology. */\n describedBy?: string;\n}\n\nexport interface Widget {\n element: HTMLElement;\n update(state: WidgetState): void;\n focus(): void;\n destroy?(): void;\n}\n\nexport type WidgetFactory = (context: WidgetContext) => Widget;\n\n/**\n * Pick the widget for a field: the app's or the built-in one for\n * `type.widget` (such as `selection.radio`), then for the type alone. A type\n * with no editor yet shows its value read-only.\n */\nexport function createWidget(context: WidgetContext, registry: Record<string, WidgetFactory> = {}): Widget {\n const { field, node } = context;\n const keys = [\n node.widget ? `${field.type}.${node.widget}` : null,\n field.type === 'selection' && field.multiple ? 'selection.checkboxes' : null,\n field.type,\n ].filter((key): key is string => key !== null);\n for (const key of keys) {\n const factory = registry[key] ?? builtInWidgets[key];\n if (factory) return factory(context);\n }\n return pendingWidget(context);\n}\n\n// ---------------------------------------------------------------------------\n\nfunction make<K extends keyof HTMLElementTagNameMap>(\n doc: Document,\n tag: K,\n props: Partial<Record<string, string>> = {},\n ...children: (Node | string)[]\n): HTMLElementTagNameMap[K] {\n const element = doc.createElement(tag);\n for (const [name, value] of Object.entries(props)) if (value !== undefined) element.setAttribute(name, value);\n element.append(...children);\n return element;\n}\n\nfunction describe(element: HTMLElement, state: WidgetState) {\n element.setAttribute('aria-invalid', String(state.invalid));\n element.setAttribute('aria-required', String(state.required));\n if (state.describedBy) element.setAttribute('aria-describedby', state.describedBy);\n else element.removeAttribute('aria-describedby');\n}\n\nconst textOf = (value: Value | undefined) => (value === null || value === undefined ? '' : String(value));\n\nfunction textWidget(inputType: string): WidgetFactory {\n return ({ form, name, field, node, id, document }) => {\n const input = make(document, 'input', { id, type: inputType, class: 'fd-input', autocomplete: 'off' });\n if (field.type === 'char' && field.size !== undefined) input.maxLength = field.size;\n if (node.placeholder) input.placeholder = node.placeholder;\n input.addEventListener('input', () => form.setValue(name, input.value === '' ? null : input.value));\n return {\n element: input,\n focus: () => input.focus(),\n update(state) {\n const text = textOf(state.value);\n if (input.value !== text) input.value = text;\n input.readOnly = state.readonly;\n describe(input, state);\n },\n };\n };\n}\n\nconst textareaWidget: WidgetFactory = ({ form, name, field, node, id, document }) => {\n const area = make(document, 'textarea', { id, class: 'fd-input fd-textarea', rows: '3' });\n if (field.type === 'text' && field.size !== undefined) area.maxLength = field.size;\n if (node.placeholder) area.placeholder = node.placeholder;\n area.addEventListener('input', () => form.setValue(name, area.value === '' ? null : area.value));\n return {\n element: area,\n focus: () => area.focus(),\n update(state) {\n const text = textOf(state.value);\n if (area.value !== text) area.value = text;\n area.readOnly = state.readonly;\n describe(area, state);\n },\n };\n};\n\nconst NUMBER = /^-?(\\d+\\.?\\d*|\\.\\d+)$/;\nconst UNFINISHED = /^-?\\.?$/;\n\n/**\n * Numbers are written as readers of the page's language write them, grouped,\n * with the field's decimals, and read back the same way. What is typed stays\n * as typed while focused: \"1.\" means 1 now and 1.5 a keystroke later. The box\n * keeps its spelling when entered, so a selection made on the way in holds.\n */\nconst numberWidget: WidgetFactory = (context) => {\n const { form, name, field, node, id, document, locale = 'en' } = context;\n const integer = field.type === 'integer';\n const decimals = integer ? 0 : (field.type === 'float' || field.type === 'monetary' ? field.digits?.[1] : undefined) ?? 2;\n const shown = (value: Value | undefined) => (typeof value === 'number' ? formatNumber(value, decimals, locale) : textOf(value));\n const input = make(document, 'input', { id, type: 'text', class: 'fd-input fd-number-input', autocomplete: 'off' });\n input.inputMode = integer ? 'numeric' : 'decimal';\n if (node.placeholder) input.placeholder = node.placeholder;\n\n const parse = (raw: string): Value | undefined => {\n const text = normalizeNumber(raw.trim(), locale);\n if (text === '') return null;\n if (NUMBER.test(text)) return Number(text);\n if (UNFINISHED.test(text)) return undefined; // \"-\" or \".\": keep typing\n return text; // not a number: validation names it\n };\n input.addEventListener('input', () => {\n const value = parse(input.value);\n if (value !== undefined) form.setValue(name, value);\n });\n input.addEventListener('blur', () => {\n input.value = shown(form.getState().values[name]);\n });\n\n // Money shows its currency beside the amount (options.symbol \"after\" puts it\n // after), or with options.pickCurrency the currency field's own widget, to change it.\n const options = node.options ?? {};\n const currencyField = field.type === 'monetary' ? field.currencyField : undefined;\n const currencyDef = currencyField ? form.page.fields[currencyField] : undefined;\n const picker =\n currencyField && currencyDef && options['pickCurrency'] === true\n ? createWidget({ ...context, name: currencyField, field: currencyDef, node: { type: 'field', id: `${node.id}.currency`, field: currencyField }, id: `${id}-currency` })\n : null;\n if (picker && currencyDef) picker.element.querySelector('input, select')?.setAttribute('aria-label', currencyDef.label);\n if (picker?.element.matches('input, select') && currencyDef) picker.element.setAttribute('aria-label', currencyDef.label);\n const currency = field.type === 'monetary' && !picker ? make(document, 'span', { class: 'fd-currency', 'aria-hidden': 'true' }) : null;\n const side = picker?.element ?? currency;\n const after = options['symbol'] === 'after';\n const element = side\n ? make(document, 'span', { class: `fd-number${after ? ' fd-currency-after' : ''}${picker ? ' fd-currency-picked' : ''}` }, ...(after ? [input, side] : [side, input]))\n : input;\n\n return {\n element,\n focus: () => input.focus(),\n update(state) {\n const typing = document.activeElement === input;\n const parsed = parse(input.value);\n const showsSame = parsed === undefined || parsed === state.value;\n if (!(typing && showsSame)) {\n const text = shown(state.value);\n if (input.value !== text) input.value = text;\n }\n input.readOnly = state.readonly;\n describe(input, state);\n if (picker && currencyField) {\n picker.update({ value: state.values[currencyField], values: state.values, readonly: state.readonly, required: false, invalid: false });\n }\n if (currency && field.type === 'monetary') {\n const holder = field.currencyField ? state.values[field.currencyField] : null;\n currency.textContent =\n holder && typeof holder === 'object' && 'label' in holder ? (holder as RelatedRecord).label : (typeof holder === 'string' ? holder : field.currency ?? '');\n }\n },\n };\n};\n\nfunction checkboxWidget(role?: 'switch'): WidgetFactory {\n return ({ form, name, id, document }) => {\n const box = make(document, 'input', { id, type: 'checkbox', class: role ? 'fd-switch' : 'fd-checkbox', role });\n box.addEventListener('change', () => form.setValue(name, box.checked));\n return {\n element: box,\n focus: () => box.focus(),\n update(state) {\n box.checked = state.value === true;\n box.disabled = state.readonly;\n describe(box, state);\n },\n };\n };\n}\n\nfunction options(field: Field) {\n return field.type === 'selection' ? field.options : [];\n}\n\nconst selectWidget: WidgetFactory = ({ form, name, field, id, document }) => {\n const choices = options(field);\n const select = make(document, 'select', { id, class: 'fd-input fd-select' }, make(document, 'option', { value: '' }));\n choices.forEach((option, i) => select.append(make(document, 'option', { value: String(i) }, option.label)));\n select.addEventListener('change', () => form.setValue(name, select.value === '' ? null : choices[Number(select.value)].value));\n return {\n element: select,\n focus: () => select.focus(),\n update(state) {\n const index = choices.findIndex((option) => option.value === state.value);\n select.value = index === -1 ? '' : String(index);\n select.disabled = state.readonly;\n describe(select, state);\n },\n };\n};\n\nfunction choiceGroup(kind: 'radio' | 'checkbox'): WidgetFactory {\n return ({ form, name, field, id, document }) => {\n const choices = options(field);\n const group = make(document, 'div', { id, class: `fd-choices fd-choices-${kind}`, role: kind === 'radio' ? 'radiogroup' : 'group' });\n const inputs = choices.map((option, i) => {\n const input = make(document, 'input', { type: kind, name: id, value: String(i), id: `${id}-${i}` });\n group.append(make(document, 'label', { class: 'fd-choice', for: `${id}-${i}` }, input, make(document, 'span', {}, option.label)));\n return input;\n });\n group.addEventListener('change', () => {\n if (kind === 'radio') {\n const chosen = inputs.findIndex((input) => input.checked);\n form.setValue(name, chosen === -1 ? null : choices[chosen].value);\n } else {\n form.setValue(name, choices.filter((_, i) => inputs[i].checked).map((option) => option.value));\n }\n });\n return {\n element: group,\n focus: () => (inputs.find((input) => input.checked) ?? inputs[0])?.focus(),\n update(state) {\n const chosen = Array.isArray(state.value) ? state.value : [state.value];\n inputs.forEach((input, i) => {\n input.checked = chosen.includes(choices[i].value as never);\n input.disabled = state.readonly;\n });\n describe(group, state);\n },\n };\n };\n}\n\n/** Stars or numbers to pick from, as a radio group with arrow-key support. */\nfunction pointsWidget(style: 'rating' | 'scale'): WidgetFactory {\n return ({ form, name, field, id, document }) => {\n const min = 'min' in field && field.min !== undefined ? field.min : style === 'rating' ? 1 : 0;\n const max = 'max' in field && field.max !== undefined ? field.max : style === 'rating' ? 5 : 10;\n const group = make(document, 'div', { id, class: `fd-points fd-${style}`, role: 'radiogroup' });\n const points: HTMLButtonElement[] = [];\n for (let n = min; n <= max; n++) {\n const point = make(document, 'button', { type: 'button', role: 'radio', 'aria-label': `${n} of ${max}`, 'data-value': String(n) }, style === 'rating' ? '\u2605' : String(n));\n if (style === 'scale') point.removeAttribute('aria-label');\n point.addEventListener('click', () => form.setValue(name, n));\n points.push(point);\n group.append(point);\n }\n group.addEventListener('keydown', (event) => {\n const current = form.getState().values[name];\n const value = typeof current === 'number' ? current : min - 1;\n const step = event.key === 'ArrowRight' || event.key === 'ArrowUp' ? 1 : event.key === 'ArrowLeft' || event.key === 'ArrowDown' ? -1 : 0;\n if (!step) return;\n event.preventDefault();\n const next = Math.min(max, Math.max(min, value + step));\n form.setValue(name, next);\n points[next - min]?.focus();\n });\n return {\n element: group,\n focus: () => (points.find((p) => p.getAttribute('aria-checked') === 'true') ?? points[0])?.focus(),\n update(state) {\n const value = typeof state.value === 'number' ? state.value : null;\n points.forEach((point, i) => {\n const n = min + i;\n point.setAttribute('aria-checked', String(n === value));\n point.classList.toggle('fd-on', style === 'rating' ? value !== null && n <= value : n === value);\n point.tabIndex = n === value || (value === null && i === 0) ? 0 : -1;\n point.disabled = state.readonly;\n });\n describe(group, state);\n },\n };\n };\n}\n\nconst dateWidget: WidgetFactory = (context) => {\n const { form, name, id, document, node } = context;\n const input = make(document, 'input', { id, type: 'date', class: 'fd-input fd-date' });\n input.addEventListener('input', () => form.setValue(name, input.value || null));\n const widget: Widget = {\n element: input,\n focus: () => input.focus(),\n update(state) {\n const text = textOf(state.value);\n if (input.value !== text) input.value = text;\n input.readOnly = state.readonly;\n describe(input, state);\n },\n };\n return node.options?.['weekNumbers'] === true ? withCalendar(widget, context, 'date') : widget;\n};\n\nconst pad = (n: number) => String(n).padStart(2, '0');\n\n/** Shown in local time, stored as an ISO instant in UTC. */\nconst dateTimeWidget: WidgetFactory = (context) => {\n const { form, name, id, document, node } = context;\n const input = make(document, 'input', { id, type: 'datetime-local', class: 'fd-input fd-datetime' });\n const local = (iso: Value | undefined) => {\n if (typeof iso !== 'string' || !iso) return '';\n const d = new Date(iso);\n return Number.isNaN(d.getTime()) ? '' : `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;\n };\n input.addEventListener('input', () => {\n if (!input.value) return form.setValue(name, null);\n const d = new Date(input.value);\n if (!Number.isNaN(d.getTime())) form.setValue(name, d.toISOString());\n });\n const widget: Widget = {\n element: input,\n focus: () => input.focus(),\n update(state) {\n const text = local(state.value);\n if (input.value !== text) input.value = text;\n input.readOnly = state.readonly;\n describe(input, state);\n },\n };\n return node.options?.['weekNumbers'] === true ? withCalendar(widget, context, 'datetime') : widget;\n};\n\n/** Until a type has its own editor (Phase 5), show what it holds. */\nfunction pendingWidget({ field, id, document }: WidgetContext): Widget {\n const span = make(document, 'span', { id, class: 'fd-pending', 'data-fd-pending': field.type });\n return {\n element: span,\n focus: () => undefined,\n update(state) {\n span.textContent = summary(state.value, field);\n },\n };\n}\n\nexport function summary(value: Value | undefined, field: Field): string {\n if (value === null || value === undefined) return '';\n switch (field.type) {\n case 'many2one':\n case 'reference':\n return (value as RelatedRecord | ReferenceValue).label;\n case 'many2many':\n return (value as RelatedRecord[]).map((record) => record.label).join(', ');\n case 'one2many': {\n const count = (value as Line[]).length;\n return `${count} ${count === 1 ? 'line' : 'lines'}`;\n }\n case 'binary':\n case 'image':\n return (value as FileValue).name;\n case 'html':\n return String(value).replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim();\n default:\n return typeof value === 'object' ? JSON.stringify(value) : String(value);\n }\n}\n\nexport const builtInWidgets: Record<string, WidgetFactory> = {\n char: textWidget('text'),\n 'char.email': textWidget('email'),\n 'char.phone': textWidget('tel'),\n 'char.url': textWidget('url'),\n 'char.password': textWidget('password'),\n 'char.tags': charTagsWidget,\n text: textareaWidget,\n integer: numberWidget,\n float: numberWidget,\n monetary: numberWidget,\n 'integer.rating': pointsWidget('rating'),\n 'integer.scale': pointsWidget('scale'),\n 'integer.progressbar': progressbarWidget,\n 'integer.label': labelWidget,\n 'float.label': labelWidget,\n 'monetary.label': labelWidget,\n 'float.progressbar': progressbarWidget,\n 'monetary.progressbar': progressbarWidget,\n boolean: checkboxWidget(),\n 'boolean.toggle': checkboxWidget('switch'),\n selection: selectWidget,\n 'selection.radio': choiceGroup('radio'),\n 'selection.checkboxes': choiceGroup('checkbox'),\n 'selection.statusbar': statusbarWidget,\n date: dateWidget,\n datetime: dateTimeWidget,\n many2one: many2oneWidget,\n 'many2one.statusbar': statusbarWidget,\n many2many: tagsWidget,\n 'many2many.tags': tagsWidget,\n 'many2many.checkboxes': linkCheckboxesWidget,\n reference: referenceWidget,\n one2many: linesWidget,\n binary: binaryWidget,\n image: imageWidget,\n html: htmlWidget,\n json: jsonWidget,\n properties: propertiesWidget,\n};\n", "/**\n * Fieldia's stylesheet: two skins and the layout chrome, all scoped to the\n * form's own root (`.fd-form[data-fd-skin=\u2026]`), so two forms on one page can\n * wear different skins and the host page's own controls are never touched.\n *\n * underline \u2014 the Flectra and Odoo style: flat inputs on a single line, labels\n * beside the field, navy accents.\n * outlined \u2014 the Ant Design style: boxed inputs with rounded corners, labels\n * above the field, a blue focus glow.\n *\n * Written with logical properties (inline/block, start/end), so a right-to-left\n * form mirrors without a second stylesheet.\n */\nexport const FIELDIA_CSS = /* css */ `.fd-form,.fd-theme{--fd-font: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Noto Sans\", \"Noto Sans Arabic\", sans-serif;--fd-text: #212529;--fd-muted: #6b7280;--fd-page: #f2f3f5;--fd-surface: #ffffff;--fd-border: #cfd4da;--fd-border-strong: #9aa3ad;--fd-accent: #002855;--fd-accent-text: #ffffff;--fd-accent-soft: #e6ebf2;--fd-focus: #002855;--fd-focus-ring: none;--fd-error: #c62828;--fd-error-soft: #fdecea;--fd-success: #2e7d32;--fd-success-soft: #e8f5e9;--fd-warning: #8a5300;--fd-warning-soft: #fff4e0;--fd-info: #0b5cad;--fd-info-soft: #e7f0fb;--fd-radius: 0px;--fd-control-radius: 0px;--fd-pad-y: 3px;--fd-pad-x: 4px;--fd-input-border: 0 0 1px 0;--fd-label-weight: 600;--fd-gap-x: 32px;--fd-gap-y: 14px;container-type:inline-size;font-family:var(--fd-font);font-size:14px;line-height:1.45;color:var(--fd-text);-webkit-text-size-adjust:100%}.fd-form[data-fd-skin=outlined],.fd-theme[data-fd-skin=outlined]{--fd-text: rgba(0, 0, 0, .88);--fd-muted: rgba(0, 0, 0, .55);--fd-page: #f5f5f5;--fd-border: #d9d9d9;--fd-border-strong: #bfbfbf;--fd-accent: #1677ff;--fd-accent-soft: #e6f4ff;--fd-focus: #1677ff;--fd-focus-ring: 0 0 0 2px rgba(5, 145, 255, .12);--fd-error: #ff4d4f;--fd-error-soft: #fff2f0;--fd-radius: 8px;--fd-control-radius: 6px;--fd-pad-y: 4px;--fd-pad-x: 11px;--fd-input-border: 1px;--fd-label-weight: 400;--fd-gap-x: 24px;--fd-gap-y: 18px}.fd-form *,.fd-form *:before,.fd-form *:after{box-sizing:border-box}.fd-form [hidden]{display:none!important}.fd-page-head{display:grid;gap:4px;margin-block-end:20px}.fd-page-title{font-size:22px;font-weight:650;margin:0;line-height:1.25}.fd-page-description{color:var(--fd-muted);margin:0}.fd-form[data-max-width=narrow]{--fd-page-max: 640px}.fd-form[data-max-width=medium]{--fd-page-max: 900px}.fd-form[data-max-width=wide]{--fd-page-max: 1180px}.fd-form[data-max-width=full]{--fd-page-max: none}.fd-form[data-max-width]>.fd-content:not(:has(>.fd-sheet-page)){max-width:var(--fd-page-max);margin-inline:auto}.fd-actions.fd-actions-top{margin-block-start:0;padding-block-end:14px;margin-block-end:18px;border-block-end:1px solid var(--fd-border)}.fd-icon{width:1.15em;height:1.15em;flex:none;vertical-align:-.2em}.fd-section-title .fd-icon,.fd-tab .fd-icon,.fd-button .fd-icon,.fd-step-title .fd-icon{margin-inline-end:.4em}.fd-section-title .fd-icon{color:var(--fd-muted)}.fd-grid{display:grid;grid-template-columns:repeat(var(--fd-columns, 1),minmax(0,1fr));gap:var(--fd-gap-y) var(--fd-gap-x);align-items:start}.fd-field{display:grid;gap:4px;min-width:0;grid-column:span min(var(--fd-span, 1),var(--fd-columns, 1))}.fd-label{font-weight:var(--fd-label-weight);color:var(--fd-text)}.fd-valid-mark{color:var(--fd-success);width:1em;height:1em;margin-inline-start:6px;vertical-align:-.15em;stroke-width:2.4}.fd-field.fd-required>.fd-label:after{content:\" *\";color:var(--fd-error)}.fd-form[data-fd-skin=outlined] .fd-field.fd-required>.fd-label:after{content:\"\"}.fd-form[data-fd-skin=outlined] .fd-field.fd-required>.fd-label:before{content:\"* \";color:var(--fd-error)}.fd-help{color:var(--fd-muted);font-size:12.5px}.fd-error{color:var(--fd-error);font-size:12.5px}.fd-warning{color:var(--fd-warning);background:var(--fd-warning-soft);font-size:12.5px;padding:3px 8px;border-radius:var(--fd-control-radius);justify-self:start}.fd-form[data-fd-skin=underline] .fd-field{grid-template-columns:var(--fd-label-width, 11em) minmax(0,1fr);column-gap:12px;align-items:baseline}.fd-form[data-fd-skin=underline] .fd-field>.fd-label{grid-column:1}.fd-form[data-fd-skin=underline] .fd-field[data-type=one2many]{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-field[data-type=one2many]>*{grid-column:1!important}.fd-form[data-fd-skin=underline] .fd-field>:not(.fd-label){grid-column:2}@container (max-width: 760px){.fd-form[data-fd-skin=underline] .fd-grid{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-field{grid-column:auto}.fd-form .fd-grid[data-columns-medium]{grid-template-columns:repeat(var(--fd-columns-medium),minmax(0,1fr))}.fd-form .fd-grid[data-columns-medium]>.fd-field{grid-column:span min(var(--fd-span, 1),var(--fd-columns-medium))}.fd-form[data-fd-skin=underline] .fd-grid[data-columns-medium]:not([data-columns-medium=\"1\"]) .fd-field{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-grid[data-columns-medium]:not([data-columns-medium=\"1\"]) .fd-field>*{grid-column:1!important}}@container (max-width: 520px){.fd-grid{grid-template-columns:minmax(0,1fr)}.fd-field{grid-column:auto}.fd-form[data-fd-skin=underline] .fd-field{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-field>*{grid-column:1!important}.fd-form .fd-grid[data-columns-medium],.fd-form .fd-grid[data-columns-narrow]{grid-template-columns:repeat(var(--fd-columns-narrow, 1),minmax(0,1fr))}.fd-form .fd-grid[data-columns-medium]>.fd-field,.fd-form .fd-grid[data-columns-narrow]>.fd-field{grid-column:span min(var(--fd-span, 1),var(--fd-columns-narrow, 1))}}.fd-input{width:100%;min-width:0;font:inherit;color:inherit;background:var(--fd-surface);border:solid var(--fd-border);border-width:var(--fd-input-border);border-radius:var(--fd-control-radius);padding:var(--fd-pad-y) var(--fd-pad-x);min-height:30px;transition:border-color .15s ease,box-shadow .15s ease}.fd-input::placeholder{color:var(--fd-muted);opacity:.8}.fd-input:hover{border-color:var(--fd-border-strong)}.fd-input:focus{outline:none;border-color:var(--fd-focus);box-shadow:var(--fd-focus-ring)}.fd-form[data-fd-skin=underline] .fd-input{background:transparent}.fd-form[data-fd-skin=underline] .fd-input:focus{box-shadow:0 1px 0 0 var(--fd-focus)}.fd-form[data-fd-skin=underline] .fd-field.fd-required .fd-input{border-color:var(--fd-accent)}.fd-input[readonly]{background:transparent;border-color:transparent;padding-inline:0}.fd-form[data-fd-skin=outlined] .fd-input[readonly]{background:#0000000a;border-color:var(--fd-border);padding-inline:var(--fd-pad-x);color:var(--fd-muted)}.fd-form[data-readonly] .fd-input[readonly]{background:transparent;border-color:transparent;padding-inline:0;color:var(--fd-text)}.fd-form[data-readonly] .fd-input::placeholder{color:transparent}.fd-form[data-readonly] select.fd-input:disabled{appearance:none;background:transparent;border-color:transparent;padding-inline:0;color:var(--fd-text);opacity:1}.fd-input[aria-invalid=true]{border-color:var(--fd-error)}.fd-form[data-fd-skin=outlined] .fd-input[aria-invalid=true]:focus{box-shadow:0 0 0 2px #ff26050f}.fd-textarea{resize:vertical;min-height:64px}.fd-select{appearance:auto}.fd-number{display:flex;align-items:baseline;gap:6px}.fd-number-input{font-variant-numeric:tabular-nums}.fd-currency{color:var(--fd-muted);font-size:12.5px;font-weight:600}.fd-currency-after>.fd-number-input{text-align:end}.fd-currency-picked{align-items:center}.fd-currency-picked>:not(.fd-number-input){flex:0 0 104px;min-width:0}.fd-currency-picked>.fd-number-input{flex:1 1 auto;min-width:0}.fd-pending{color:var(--fd-muted);font-style:italic}.fd-pending:empty:before{content:\"\u2014\"}.fd-checkbox,.fd-choice input{width:16px;height:16px;accent-color:var(--fd-accent);margin:0}.fd-switch{appearance:none;width:34px;height:20px;margin:0;border-radius:999px;position:relative;background:var(--fd-border-strong);cursor:pointer;transition:background .2s ease}.fd-switch:after{content:\"\";position:absolute;inset-block-start:2px;inset-inline-start:2px;width:16px;height:16px;border-radius:50%;background:#fff;transition:transform .2s ease;box-shadow:0 1px 2px #00000040}.fd-switch:checked{background:var(--fd-accent)}.fd-switch:checked:after{transform:translate(14px)}[dir=rtl] .fd-switch:checked:after{transform:translate(-14px)}.fd-choices{display:flex;flex-wrap:wrap;gap:6px 18px}.fd-choice{display:inline-flex;align-items:center;gap:8px;cursor:pointer}.fd-points{display:flex;flex-wrap:wrap;gap:6px}.fd-points button{font:inherit;cursor:pointer;border:1px solid var(--fd-border);background:var(--fd-surface);color:var(--fd-text);border-radius:var(--fd-control-radius);min-width:34px;height:34px;padding:0 8px}.fd-points button.fd-on{background:var(--fd-accent);color:var(--fd-accent-text);border-color:var(--fd-accent)}.fd-rating button{border:none;background:none;font-size:24px;color:var(--fd-border-strong);padding:0 2px;min-width:0}.fd-rating button.fd-on{background:none;color:#f5a623}.fd-points button:disabled,.fd-choice input:disabled{cursor:default}.fd-form :focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px}.fd-form .fd-input:focus-visible{outline:none}.fd-combo{position:relative;display:flex;align-items:center;min-width:0}.fd-combo-input{padding-inline-end:28px}.fd-combo-clear{position:absolute;inset-inline-end:4px;border:none;background:none;cursor:pointer;color:var(--fd-muted);font-size:16px;line-height:1;padding:2px 6px;border-radius:4px}.fd-combo-clear:hover{color:var(--fd-text);background:var(--fd-page)}.fd-combo:has(>.fd-combo-open:not([hidden])) .fd-combo-input{padding-inline-end:52px}.fd-combo-open{position:absolute;inset-inline-end:28px;border:none;background:none;cursor:pointer;color:var(--fd-accent);font-size:14px;line-height:1;padding:2px 6px;border-radius:4px}.fd-combo-open:hover{background:var(--fd-page)}.fd-listbox{position:absolute;inset-inline:0;inset-block-start:calc(100% + 2px);z-index:20;margin:0;padding:4px 0;list-style:none;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:max(var(--fd-control-radius),4px);box-shadow:0 8px 24px #0f14191f;max-height:240px;overflow-y:auto}.fd-option{padding:6px 12px;cursor:pointer}.fd-option:hover,.fd-option.fd-active{background:var(--fd-accent-soft)}.fd-option-create{color:var(--fd-accent);border-block-start:1px solid var(--fd-border)}.fd-empty{padding:6px 12px;color:var(--fd-muted);font-style:italic}.fd-tags{display:flex;flex-wrap:wrap;gap:6px;align-items:center;min-width:0}.fd-chips{display:contents;list-style:none;margin:0;padding:0}.fd-chip{display:inline-flex;align-items:center;gap:4px;padding:1px 4px 1px 10px;border-radius:999px;background:var(--fd-accent-soft);color:var(--fd-text);font-size:13px;line-height:22px}.fd-chip-remove{border:none;background:none;cursor:pointer;color:var(--fd-muted);font-size:15px;line-height:1;padding:0 4px;border-radius:999px}.fd-chip-remove:hover{color:var(--fd-error)}.fd-tags .fd-combo{flex:1 1 140px}.fd-reference{display:grid;grid-template-columns:minmax(7em,34%) minmax(0,1fr);gap:8px}.fd-lines{display:grid;grid-template-columns:minmax(0,1fr);gap:6px;min-width:0}.fd-lines-scroll{overflow-x:auto;min-width:0;position:relative}.fd-lines-table{width:100%;border-collapse:collapse;font-size:13.5px}.fd-lines-table th{text-align:start;font-weight:600;color:var(--fd-muted);font-size:12.5px;padding:6px 8px;border-block-end:1px solid var(--fd-border);white-space:nowrap}.fd-lines-table td{padding:4px 8px;border-block-end:1px solid var(--fd-border);vertical-align:top;min-width:7em}.fd-lines-table td.fd-lines-tools,.fd-lines-table th.fd-lines-tools{width:32px;min-width:32px;padding-inline:0;text-align:center}.fd-lines-table .fd-input{min-height:28px}.fd-lines-table td>.fd-checkbox,.fd-lines-table td>.fd-switch{margin-block-start:6px}.fd-line-delete{border:none;background:none;cursor:pointer;color:var(--fd-muted);font-size:16px;line-height:1;padding:4px 6px;border-radius:4px}.fd-line-delete:hover{color:var(--fd-error);background:var(--fd-error-soft)}.fd-lines-totals td{padding:8px;font-weight:600;border-block-start:1px solid var(--fd-border);font-variant-numeric:tabular-nums}.fd-lines-adds{display:flex;flex-wrap:wrap;gap:4px 16px;justify-self:start}.fd-line-section td{background:var(--fd-page)}.fd-line-section .fd-input{font-weight:600}.fd-line-note .fd-input{font-style:italic}.fd-cell-error{color:var(--fd-error);font-size:12px}.fd-sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-file{display:grid;gap:8px;justify-items:start;padding:6px 0;border-radius:var(--fd-control-radius)}.fd-file.fd-dragging{outline:2px dashed var(--fd-accent);outline-offset:4px}.fd-file-pick{display:inline-flex;flex-wrap:wrap;gap:8px;align-items:center;cursor:pointer}.fd-file-chosen{display:inline-flex;flex-wrap:wrap;gap:4px 10px;align-items:center}.fd-file-name{font-variant-numeric:tabular-nums}.fd-image-pick{width:120px;height:120px;border:1px dashed var(--fd-border-strong);border-radius:var(--fd-control-radius);display:grid;place-content:center;justify-items:center;text-align:center;padding:8px;background:var(--fd-page)}.fd-avatar .fd-image-pick{width:88px;height:88px}.fd-image-preview{max-width:160px;max-height:160px;border-radius:var(--fd-control-radius);border:1px solid var(--fd-border);object-fit:cover;background:var(--fd-page)}.fd-richtext{min-height:96px;line-height:1.5;overflow-wrap:anywhere}.fd-richtext-box{display:grid;gap:0;min-width:0}.fd-richtext-box>.fd-richtext{border-start-start-radius:0;border-start-end-radius:0}.fd-richtext-bar{display:flex;flex-wrap:wrap;align-items:center;gap:2px;padding:4px;min-width:0;border:1px solid var(--fd-border);border-block-end:none;border-start-start-radius:var(--fd-control-radius);border-start-end-radius:var(--fd-control-radius);background:var(--fd-page)}.fd-richtext-style{font:inherit;font-size:12.5px;padding:3px 6px;margin-inline-end:4px;border:1px solid var(--fd-border);border-radius:4px;background:var(--fd-surface);color:var(--fd-text)}.fd-richtext-tool{display:grid;place-items:center;width:28px;height:28px;padding:0;border:none;border-radius:4px;background:none;cursor:pointer;color:var(--fd-text);font:inherit;font-size:14px}.fd-richtext-tool:hover{background:var(--fd-surface)}.fd-richtext-tool[aria-pressed=true]{background:var(--fd-accent-soft);color:var(--fd-accent)}.fd-richtext-tool svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.3;stroke-linecap:round}.fd-richtext-tool svg circle{fill:currentColor;stroke:none}.fd-link-row{display:flex;flex-wrap:wrap;gap:6px;align-items:center;padding:6px;border:1px solid var(--fd-border);border-block-end:none;background:var(--fd-surface)}.fd-link-row>.fd-input{flex:1 1 200px;min-width:0}.fd-richtext[contenteditable=false]{background:transparent;border-color:transparent;padding-inline:0;min-height:0}.fd-richtext p{margin:0 0 6px}.fd-code{font-family:ui-monospace,SF Mono,Menlo,Consolas,monospace;font-size:12.5px;min-height:96px}.fd-sections{display:grid;gap:24px}.fd-section{border:0;margin:0;padding:0;min-width:0;display:grid;gap:14px}.fd-section-title{font-size:15px;font-weight:650;padding:0;margin:0;float:inline-start;width:100%}.fd-section-title+*{clear:both}.fd-form[data-fd-skin=underline] .fd-section-title{text-transform:uppercase;letter-spacing:.05em;font-size:12.5px;color:var(--fd-muted);border-block-end:1px solid var(--fd-border);padding-block-end:6px;width:100%}.fd-section-description{color:var(--fd-muted);margin:0}.fd-section-toggle{font:inherit;color:inherit;background:none;border:0;padding:0;margin:0;cursor:pointer;display:inline-flex;align-items:center;gap:8px;text-align:start}.fd-section-toggle:focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px;border-radius:2px}.fd-section-chevron{width:.5em;height:.5em;border:solid currentColor;border-width:0 2px 2px 0;transform:rotate(45deg);margin-block-start:-.2em;transition:transform .15s ease;flex:none}.fd-section-folded .fd-section-chevron{transform:rotate(-45deg);margin-block-start:0}[dir=rtl] .fd-section-folded .fd-section-chevron{transform:rotate(135deg)}.fd-form[data-fd-skin=outlined] .fd-sections>.fd-section{background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius);padding:20px 24px}.fd-tablist{display:flex;gap:2px;border-block-end:1px solid var(--fd-border);overflow-x:auto}.fd-tab{font:inherit;background:none;border:none;cursor:pointer;padding:8px 14px;color:var(--fd-muted);border-block-end:2px solid transparent;margin-block-end:-1px;white-space:nowrap}.fd-tab[aria-selected=true]{color:var(--fd-accent);border-block-end-color:var(--fd-accent);font-weight:600}.fd-tabpanel{padding-block:16px;display:grid;gap:16px}.fd-button{font:inherit;cursor:pointer;display:inline-flex;align-items:center;gap:6px;justify-content:center;min-height:32px;padding:4px 14px;border-radius:var(--fd-control-radius);border:1px solid var(--fd-border);background:var(--fd-surface);color:var(--fd-text)}.fd-button:hover{border-color:var(--fd-accent);color:var(--fd-accent)}.fd-button-primary{background:var(--fd-accent);border-color:var(--fd-accent);color:var(--fd-accent-text)}.fd-button-primary:hover{color:var(--fd-accent-text);filter:brightness(1.12)}.fd-button-danger{color:var(--fd-error);border-color:var(--fd-error)}.fd-button-danger:hover{background:var(--fd-error);color:#fff}.fd-button-link{border-color:transparent;background:none;color:var(--fd-accent);padding-inline:4px}.fd-form[data-fd-skin=underline] .fd-button{border-radius:3px}.fd-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.fd-actions-end{justify-content:flex-end;margin-block-start:24px}.fd-sheet-page{background:var(--fd-page);padding:0 0 32px;min-width:0}.fd-header{display:flex;flex-wrap:wrap;gap:10px 16px;align-items:center;justify-content:space-between;background:var(--fd-surface);border-block-end:1px solid var(--fd-border);padding:8px 16px}.fd-statusbar{display:flex;list-style:none;margin:0;padding:0;overflow-x:auto}.fd-statusbar li{display:flex}.fd-statusbar button,.fd-statusbar span{font:inherit;font-size:13px;border:none;background:var(--fd-page);color:var(--fd-muted);padding:5px 18px 5px 22px;margin-inline-start:-6px;white-space:nowrap;clip-path:polygon(0 0,calc(100% - 10px) 0,100% 50%,calc(100% - 10px) 100%,0 100%,10px 50%)}.fd-statusbar li:first-child button,.fd-statusbar li:first-child span{margin-inline-start:0;padding-inline-start:14px;clip-path:polygon(0 0,calc(100% - 10px) 0,100% 50%,calc(100% - 10px) 100%,0 100%)}.fd-statusbar button{cursor:pointer}.fd-statusbar [aria-current=step]{background:var(--fd-accent);color:var(--fd-accent-text);font-weight:600}[dir=rtl] .fd-statusbar button,[dir=rtl] .fd-statusbar span{transform:scaleX(-1)}[dir=rtl] .fd-statusbar button>*,[dir=rtl] .fd-statusbar span>*{display:inline-block;transform:scaleX(-1)}.fd-sheet-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:16px;max-width:var(--fd-page-max, 1180px);margin:16px auto 0;padding-inline:16px}.fd-sheet-layout{align-items:start}.fd-sheet-foot{margin:4px -28px -28px;padding:12px 28px;border-block-start:1px solid var(--fd-border);border-end-start-radius:inherit;border-end-end-radius:inherit}.fd-sheet-layout.fd-has-side{grid-template-columns:minmax(0,1fr) minmax(260px,360px)}@container (max-width: 860px){.fd-sheet-layout.fd-has-side{grid-template-columns:minmax(0,1fr)}}.fd-card{position:relative;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius);padding:24px 28px 28px;display:grid;gap:18px;min-width:0}.fd-ribbon-frame{position:absolute;inset:0;overflow:hidden;border-radius:inherit;pointer-events:none}.fd-ribbon{position:absolute;inset-block-start:18px;inset-inline-end:-42px;transform:rotate(45deg);width:160px;text-align:center;font-size:12px;font-weight:700;padding:4px 0;color:#fff;background:var(--fd-muted);text-transform:uppercase;letter-spacing:.06em;pointer-events:none}[dir=rtl] .fd-ribbon{transform:rotate(-45deg)}.fd-ribbon.fd-tone-danger{background:var(--fd-error)}.fd-ribbon.fd-tone-success{background:var(--fd-success)}.fd-ribbon.fd-tone-warning{background:#d97706}.fd-ribbon.fd-tone-info{background:var(--fd-info)}.fd-alert{padding:10px 14px;border-radius:var(--fd-control-radius);border:1px solid;font-size:13.5px;display:flex;align-items:flex-start;gap:10px}.fd-alert-message{flex:1 1 auto;min-width:0}.fd-alert-close{border:none;background:none;color:inherit;cursor:pointer;font:inherit;font-size:18px;line-height:1;padding:0 4px;border-radius:4px;opacity:.75}.fd-alert-close:hover{opacity:1}.fd-alert-close:focus-visible{outline:2px solid var(--fd-focus);opacity:1}.fd-alert.fd-tone-warning{background:var(--fd-warning-soft);border-color:#f0c47a;color:var(--fd-warning)}.fd-alert.fd-tone-danger{background:var(--fd-error-soft);border-color:#f1a7a7;color:var(--fd-error)}.fd-alert.fd-tone-success{background:var(--fd-success-soft);border-color:#a7d7ab;color:var(--fd-success)}.fd-alert.fd-tone-info,.fd-alert:not([class*=fd-tone-]){background:var(--fd-info-soft);border-color:#a9c8ef;color:var(--fd-info)}.fd-stats{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:0;margin:-24px -28px 0;border-block-end:1px solid var(--fd-border)}.fd-stats:empty{display:none}.fd-card:has(>.fd-ribbon-frame>.fd-ribbon:not([hidden])) .fd-stats{padding-inline-end:104px}.fd-stat{font:inherit;background:none;border:none;border-inline-start:1px solid var(--fd-border);cursor:pointer;padding:8px 18px;display:grid;justify-items:start;line-height:1.2;color:var(--fd-text);min-width:120px}.fd-stat:hover{background:var(--fd-page)}.fd-stat:has(>.fd-icon){grid-template-columns:auto minmax(0,1fr);align-items:center;column-gap:10px}.fd-stat>.fd-icon{width:22px;height:22px;color:var(--fd-muted)}.fd-stat-words{display:grid;justify-items:start}.fd-stat-value{font-weight:700;font-size:15px;color:var(--fd-accent);font-variant-numeric:tabular-nums}.fd-stat-label{font-size:12.5px;color:var(--fd-muted)}.fd-title-row{display:flex;gap:16px;align-items:flex-start;justify-content:space-between}.fd-title{display:grid;gap:4px;flex:1 1 auto;min-width:0}.fd-avatar{flex:none}.fd-avatar>.fd-label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-form[data-fd-skin=underline] .fd-avatar{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-avatar>*{grid-column:1!important}.fd-avatar .fd-image-pick{width:120px;height:120px;border:1px dashed var(--fd-border-strong);border-radius:var(--fd-control-radius);display:grid;place-content:center;justify-items:center;text-align:center;padding:8px;background:var(--fd-page)}.fd-image-pick .fd-button{border:none;background:none;color:var(--fd-accent);padding:0;min-height:0}.fd-image-pick:hover{border-color:var(--fd-accent)}.fd-avatar .fd-image-pick,.fd-image-preview{width:88px;height:88px}.fd-avatar .fd-file-pick .fd-help,.fd-avatar .fd-file-name{display:none}.fd-avatar .fd-file{justify-items:center;gap:2px;padding:0}.fd-avatar .fd-file-chosen{gap:2px 8px;justify-content:center;font-size:12.5px}.fd-title>.fd-field .fd-input{font-size:24px;font-weight:600;min-height:40px}.fd-form[data-fd-skin=underline] .fd-title>.fd-field{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-title>.fd-field>*{grid-column:1}.fd-title>.fd-field>.fd-label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-title-above,.fd-title-below{display:flex;flex-wrap:wrap;align-items:center;gap:6px 24px}.fd-title-above{margin-block-end:4px}.fd-title-below{margin-block-start:6px}.fd-form .fd-title-above>.fd-field,.fd-form .fd-title-below>.fd-field{display:flex;align-items:center;gap:8px;grid-template-columns:none}.fd-form .fd-title-above>.fd-field>*,.fd-form .fd-title-below>.fd-field>*{grid-column:auto!important}.fd-title-above .fd-label:empty,.fd-title-below .fd-label:empty{display:none}.fd-title-above>.fd-field>.fd-label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-title-statusbar{display:flex}.fd-badges{display:flex;flex-wrap:wrap;gap:6px}.fd-badge{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:600;line-height:1;padding:5px 10px;border-radius:999px;border:1px solid var(--fd-border);background:var(--fd-page);color:var(--fd-muted)}.fd-badge .fd-icon{width:13px;height:13px}.fd-badge.fd-tone-info{background:var(--fd-info-soft);border-color:#a9c8ef;color:var(--fd-info)}.fd-badge.fd-tone-success{background:var(--fd-success-soft);border-color:#a7d7ab;color:var(--fd-success)}.fd-badge.fd-tone-warning{background:var(--fd-warning-soft);border-color:#f0c47a;color:var(--fd-warning)}.fd-badge.fd-tone-danger{background:var(--fd-error-soft);border-color:#f1a7a7;color:var(--fd-error)}.fd-side{display:grid;gap:12px;align-content:start;min-width:0}.fd-wizard{display:grid;gap:20px}.fd-progress{display:grid;gap:8px}.fd-progress-text{color:var(--fd-muted);font-size:13px}.fd-value-text{display:block;padding-block:6px;font-variant-numeric:tabular-nums}.fd-date-pick{position:relative;display:flex;align-items:center;gap:6px;min-width:0}.fd-date-pick>.fd-input{flex:1 1 auto;min-width:0}.fd-calendar-button{flex:0 0 auto;display:grid;place-items:center;width:32px;height:32px;padding:0;cursor:pointer;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);background:var(--fd-surface);color:var(--fd-muted)}.fd-calendar-button:hover,.fd-calendar-button[aria-expanded=true]{color:var(--fd-text);background:var(--fd-page)}.fd-calendar-button svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.4;stroke-linecap:round}.fd-calendar{position:absolute;inset-block-start:calc(100% + 4px);inset-inline-end:0;z-index:30;padding:8px;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:max(var(--fd-control-radius),6px);box-shadow:0 8px 24px #0f141924}.fd-calendar-head{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:2px 4px 6px}.fd-calendar-head button{border:none;background:none;cursor:pointer;font-size:18px;line-height:1;padding:4px 8px;border-radius:4px;color:var(--fd-text)}.fd-calendar-head button:hover{background:var(--fd-page)}.fd-calendar-title{font-weight:600}.fd-calendar-grid{border-collapse:collapse;font-variant-numeric:tabular-nums}.fd-calendar-grid th{font-size:11.5px;font-weight:600;color:var(--fd-muted);padding:4px 0;width:34px;text-align:center}.fd-calendar-grid .fd-week{color:var(--fd-accent);font-weight:600;border-inline-end:1px solid var(--fd-border)}.fd-calendar-grid td{padding:1px}.fd-calendar-grid td button{width:32px;height:30px;border:none;border-radius:4px;background:none;cursor:pointer;color:var(--fd-text);font:inherit;font-size:13px}.fd-calendar-grid td button:hover{background:var(--fd-accent-soft)}.fd-calendar-grid td button.fd-outside{color:var(--fd-muted);opacity:.6}.fd-calendar-grid td button[aria-current=date]{box-shadow:inset 0 0 0 1px var(--fd-accent)}.fd-calendar-grid td button[aria-selected=true]{background:var(--fd-accent);color:var(--fd-accent-text);font-weight:600}.fd-calendar-grid td button:focus-visible{outline:2px solid var(--fd-focus);outline-offset:1px}.fd-properties{display:grid;gap:8px;min-width:0}.fd-property{display:grid;grid-template-columns:minmax(120px,30%) minmax(0,1fr);align-items:center;gap:12px;min-width:0}.fd-property>label{color:var(--fd-muted);font-size:13px}.fd-property[data-type=boolean]>:last-child{justify-self:start}@container (max-width: 520px){.fd-property{grid-template-columns:minmax(0,1fr);gap:4px}}.fd-progressbar{position:relative;height:22px;min-width:120px;border-radius:999px;overflow:hidden;background:var(--fd-page);border:1px solid var(--fd-border);font-variant-numeric:tabular-nums}.fd-progressbar-fill{height:100%;background:var(--fd-success);transition:width .2s ease}.fd-progressbar[data-tone=warning] .fd-progressbar-fill{background:#d97706}.fd-progressbar[data-tone=danger] .fd-progressbar-fill{background:var(--fd-error)}.fd-progressbar[data-tone=info] .fd-progressbar-fill{background:var(--fd-info)}.fd-progressbar-text{position:absolute;inset:0;display:grid;place-items:center;font-size:12px;font-weight:600;color:var(--fd-text)}.fd-progressbar-edit{display:flex;align-items:center;gap:12px;min-width:0}.fd-progressbar-edit>.fd-progressbar{flex:1 1 auto}.fd-progressbar-edit>.fd-input{flex:0 0 96px}.fd-progress-bar{height:4px;background:var(--fd-border);border-radius:999px;overflow:hidden}.fd-progress-bar>span{display:block;height:100%;background:var(--fd-accent);transition:width .25s ease}.fd-step{display:grid;gap:18px}.fd-step-title{font-size:18px;font-weight:650;margin:0}.fd-wizard-nav{display:flex;gap:8px;justify-content:space-between}.fd-steps-list{display:flex;flex-wrap:wrap;gap:8px;list-style:none;margin:0;padding:0;counter-reset:fd-step}.fd-steps-list>li{counter-increment:fd-step}.fd-step-link{font:inherit;font-size:13.5px;display:inline-flex;align-items:center;gap:6px;cursor:pointer;border:1px solid var(--fd-border);background:var(--fd-surface);color:var(--fd-muted);border-radius:999px;padding:4px 12px 4px 6px}.fd-step-link:before{content:counter(fd-step);display:inline-grid;place-items:center;width:20px;height:20px;border-radius:50%;background:var(--fd-page);color:var(--fd-muted);font-size:12px;font-weight:600;font-variant-numeric:tabular-nums}.fd-step-link:hover{border-color:var(--fd-accent);color:var(--fd-text)}.fd-step-link:focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px}.fd-step-link.fd-step-done{color:var(--fd-text)}.fd-step-link.fd-step-done:before{content:\"\u2713\";background:var(--fd-accent-soft);color:var(--fd-accent)}.fd-step-link.fd-step-skipped{border-style:dashed;color:var(--fd-muted)}.fd-step-link.fd-step-skipped:before{content:\"\u2013\";background:var(--fd-page);color:var(--fd-muted)}.fd-step-link[aria-current=step]{border-color:var(--fd-accent);color:var(--fd-accent);font-weight:600}.fd-step-link[aria-current=step]:before{content:counter(fd-step);background:var(--fd-accent);color:var(--fd-accent-text)}.fd-wizard-nav .fd-spacer{flex:1}.fd-text-heading{font-size:16px;font-weight:650;margin:0}.fd-text-paragraph{margin:0}.fd-text-note{margin:0;color:var(--fd-muted);font-size:13px}.fd-status{min-height:1.4em;color:var(--fd-muted);font-size:13px}.fd-status-box{display:inline-flex;align-items:center;gap:6px;min-width:0}.fd-status-box .fd-retry{font-size:13px}.fd-announce{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-banner{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;padding:10px 14px;margin-block-end:16px;border:1px solid #f0c47a;border-radius:var(--fd-control-radius);background:var(--fd-warning-soft);color:var(--fd-warning);font-size:13.5px}.fd-banner-text{flex:1 1 16em;min-width:0}.fd-content>.fd-banner:has(+.fd-draft+.fd-sheet-page),.fd-content>.fd-banner:has(+.fd-sheet-page){margin:12px 16px 0}.fd-status-box.fd-toast{position:fixed;inset-block-end:max(20px,env(safe-area-inset-bottom,0px));inset-inline-end:20px;z-index:900;padding:10px 16px;border-radius:8px;background:var(--fd-text);box-shadow:0 8px 24px #0f141940}.fd-toast .fd-status,.fd-toast .fd-status.fd-status-saved,.fd-toast .fd-status.fd-status-error{color:var(--fd-surface);font-size:13.5px;min-height:0}.fd-toast .fd-retry{color:var(--fd-surface);text-decoration:underline}.fd-toast:has(.fd-status-error){background:var(--fd-error)}.fd-status-box.fd-status-bar{display:flex;justify-content:center;min-height:32px;padding:6px 16px;background:var(--fd-surface);border-block-end:1px solid var(--fd-border)}.fd-status-bar .fd-status-error,.fd-status.fd-status-error{color:var(--fd-error)}.fd-status.fd-status-saved{color:var(--fd-success)}.fd-draft{display:flex;flex-wrap:wrap;gap:8px 12px;align-items:center;padding:10px 14px;margin-block-end:16px;background:var(--fd-info-soft);border:1px solid #a9c8ef;border-radius:var(--fd-control-radius)}.fd-done{padding:40px 0;text-align:center;display:grid;gap:12px;justify-items:center}.fd-done-title{font-size:20px;font-weight:650;margin:0}.fd-dialog-backdrop{position:fixed;inset:0;background:#0f141973;display:grid;place-items:center;z-index:1000;padding:16px}.fd-dialog{background:var(--fd-surface);color:var(--fd-text);border-radius:max(var(--fd-radius),6px);max-width:420px;width:100%;padding:20px 22px;display:grid;gap:16px;box-shadow:0 10px 30px #0003;font-family:var(--fd-font)}.fd-dialog p{margin:0}.fd-form-dialog{display:flex;flex-direction:column;width:100%;max-height:min(90vh,100%);min-height:0;background:var(--fd-page);color:var(--fd-text);border-radius:max(var(--fd-radius),8px);box-shadow:0 24px 64px #0f14194d;overflow:hidden}.fd-form-dialog:focus{outline:none}.fd-form-dialog.fd-size-small{max-width:440px}.fd-form-dialog.fd-size-medium{max-width:760px}.fd-form-dialog.fd-size-large{max-width:1080px}.fd-form-dialog-backdrop:has(>.fd-size-full){padding:0}.fd-form-dialog.fd-size-full{max-width:none;max-height:none;height:100%;border-radius:0}.fd-form-dialog-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;border-block-end:1px solid var(--fd-border);background:var(--fd-surface)}.fd-form-dialog-title{margin:0;font-size:16px;font-weight:600}.fd-dialog-close{border:none;background:none;cursor:pointer;font-size:22px;line-height:1;padding:2px 8px;border-radius:4px;color:var(--fd-muted)}.fd-dialog-close:hover{background:var(--fd-page);color:var(--fd-text)}.fd-form-dialog-body{flex:1 1 auto;min-height:0;overflow:auto;container-type:inline-size}.fd-form-dialog-body .fd-sheet-layout{margin-block-start:12px}.fd-form-dialog-body .fd-page-title{display:none}.fd-form-dialog-body .fd-page-head:not(:has(.fd-page-description)){display:none}.fd-form-dialog-body .fd-sheet-layout.fd-has-side{grid-template-columns:minmax(0,1fr)}.fd-form-dialog-body .fd-side{display:none}.fd-search-body{display:grid;gap:12px;align-content:start}.fd-search-list{list-style:none;margin:0;padding:0;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);overflow:auto;max-height:min(60vh,520px)}.fd-search-list .fd-option{padding:8px 12px}.fd-search-list .fd-option+.fd-option{border-block-start:1px solid var(--fd-border)}.fd-search-list .fd-empty{padding:10px 12px;color:var(--fd-muted)}.fd-form-dialog-body:not(:has(.fd-sheet-layout)){background:var(--fd-surface);padding:16px 20px 20px}.fd-form-dialog-foot{padding:12px 16px;border-block-start:1px solid var(--fd-border);background:var(--fd-surface);margin:0}@media(prefers-reduced-motion:reduce){.fd-form *,.fd-form *:before,.fd-form *:after{transition:none!important}}`;\n\nconst STYLE_ID = 'fieldia-styles';\n\n/** Add Fieldia's stylesheet to a document, once. */\nexport function installStyles(document: Document): void {\n if (document.getElementById(STYLE_ID)) return;\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = FIELDIA_CSS;\n (document.head ?? document.documentElement).append(style);\n}\n", "import type { JsonValue } from '@fieldia/core';\n\n/**\n * Where a person's choices about how a page looks are kept between visits:\n * a table's column widths, their order, which columns show. Never data, and\n * never anything a page needs to work: a store that forgets is fine.\n */\nexport interface PreferenceStore {\n get(key: string): JsonValue | null;\n set(key: string, value: JsonValue): void;\n}\n\n/** Preferences in the browser's local storage, under `fieldia:`. A browser that refuses storage just forgets. */\nexport function browserPreferences(storage?: Storage): PreferenceStore {\n const area = () => {\n try {\n return storage ?? globalThis.localStorage ?? null;\n } catch {\n return null; // reading localStorage itself throws where site data is blocked\n }\n };\n return {\n get(key) {\n try {\n const text = area()?.getItem(`fieldia:${key}`);\n return text == null ? null : (JSON.parse(text) as JsonValue);\n } catch {\n return null;\n }\n },\n set(key, value) {\n try {\n area()?.setItem(`fieldia:${key}`, JSON.stringify(value));\n } catch {\n // Full, private or blocked: the choice lasts until the page closes.\n }\n },\n };\n}\n\n/** Preferences that last as long as the page: for tests, and apps that keep nothing. */\nexport function memoryPreferences(): PreferenceStore {\n const values = new Map<string, JsonValue>();\n return {\n get: (key) => (values.has(key) ? structuredCloneSafe(values.get(key) as JsonValue) : null),\n set: (key, value) => void values.set(key, structuredCloneSafe(value)),\n };\n}\n\nconst structuredCloneSafe = (value: JsonValue): JsonValue => JSON.parse(JSON.stringify(value)) as JsonValue;\n", "/**\n * Icons by name, for sections, tabs, buttons, stat buttons, badges and steps.\n * Each is the inside of a 24\u00D724 SVG drawn with lines in the text colour, so it\n * takes the colour and size of the words beside it. An app adds its own, or\n * replaces one of these, with the viewer's `icons` option, in the same form.\n */\nexport type IconSet = Readonly<Record<string, string>>;\n\nconst SVG = 'http://www.w3.org/2000/svg';\n\nexport const ICONS: IconSet = {\n user: '<circle cx=\"12\" cy=\"8\" r=\"4\"/><path d=\"M4 21c0-4 3.6-6 8-6s8 2 8 6\"/>',\n users: '<circle cx=\"9\" cy=\"8\" r=\"3.5\"/><path d=\"M2 20c0-3.5 3-5.5 7-5.5s7 2 7 5.5\"/><circle cx=\"17\" cy=\"9\" r=\"2.5\"/><path d=\"M16.5 14.5c3 0 5.5 1.6 5.5 4.5\"/>',\n building: '<rect x=\"4\" y=\"3\" width=\"16\" height=\"18\" rx=\"1\"/><path d=\"M9 21v-4h6v4M8 7h2M14 7h2M8 11h2M14 11h2\"/>',\n home: '<path d=\"M3 11l9-7 9 7\"/><path d=\"M5 10v10h14V10\"/><path d=\"M10 20v-6h4v6\"/>',\n phone: '<rect x=\"7\" y=\"2\" width=\"10\" height=\"20\" rx=\"2\"/><path d=\"M11 18h2\"/>',\n mail: '<rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\"/><path d=\"M3 7l9 6 9-6\"/>',\n pin: '<path d=\"M12 21s-7-6.5-7-12a7 7 0 0 1 14 0c0 5.5-7 12-7 12z\"/><circle cx=\"12\" cy=\"9\" r=\"2.5\"/>',\n globe: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M3 12h18M12 3c3 3.2 3 14.8 0 18M12 3c-3 3.2-3 14.8 0 18\"/>',\n calendar: '<rect x=\"3\" y=\"5\" width=\"18\" height=\"16\" rx=\"2\"/><path d=\"M3 10h18M8 3v4M16 3v4\"/>',\n clock: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M12 7v5l3 3\"/>',\n money: '<rect x=\"2\" y=\"6\" width=\"20\" height=\"12\" rx=\"2\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M6 9.5v0M18 14.5v0\"/>',\n cart: '<path d=\"M3 4h2l2.5 11h11L21 7H6.4\"/><circle cx=\"9\" cy=\"19.5\" r=\"1.5\"/><circle cx=\"17\" cy=\"19.5\" r=\"1.5\"/>',\n box: '<path d=\"M12 3l8 4.5v9L12 21l-8-4.5v-9z\"/><path d=\"M4 7.5l8 4.5 8-4.5M12 12v9\"/>',\n truck: '<path d=\"M2 6h12v10H2zM14 9h4l3 3.5V16h-7\"/><circle cx=\"6.5\" cy=\"17.5\" r=\"1.8\"/><circle cx=\"17\" cy=\"17.5\" r=\"1.8\"/>',\n receipt: '<path d=\"M6 3h12v18l-3-2-3 2-3-2-3 2z\"/><path d=\"M9 8h6M9 12h6\"/>',\n file: '<path d=\"M6 3h8l4 4v14H6z\"/><path d=\"M14 3v4h4M9 12h6M9 16h6\"/>',\n edit: '<path d=\"M4 20h4L19 9l-4-4L4 16z\"/><path d=\"M13.5 6.5l4 4\"/>',\n tag: '<path d=\"M3 12V4h8l10 10-8 8z\"/><circle cx=\"7.5\" cy=\"8\" r=\"1.5\"/>',\n star: '<path d=\"M12 3l2.8 6 6.2.6-4.7 4.2 1.4 6.2L12 16.8 6.3 20l1.4-6.2L3 9.6 9.2 9z\"/>',\n lock: '<rect x=\"5\" y=\"11\" width=\"14\" height=\"10\" rx=\"2\"/><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"/>',\n check: '<path d=\"M5 12.5l4.5 4.5L19 7.5\"/>',\n info: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M12 11v6M12 7.5v0\"/>',\n warning: '<path d=\"M12 3l10 18H2z\"/><path d=\"M12 10v5M12 18v0\"/>',\n settings: '<path d=\"M4 6h9M17 6h3M4 12h3M11 12h9M4 18h11M19 18h1\"/><circle cx=\"15\" cy=\"6\" r=\"2\"/><circle cx=\"9\" cy=\"12\" r=\"2\"/><circle cx=\"17\" cy=\"18\" r=\"2\"/>',\n chart: '<path d=\"M3 20h18M6 20v-8M11 20V5M16 20v-6\"/>',\n link: '<path d=\"M10 14a4 4 0 0 0 5.6 0l3-3a4 4 0 0 0-5.6-5.6l-1 1\"/><path d=\"M14 10a4 4 0 0 0-5.6 0l-3 3a4 4 0 0 0 5.6 5.6l1-1\"/>',\n list: '<path d=\"M8 6h12M8 12h12M8 18h12M4 6v0M4 12v0M4 18v0\"/>',\n chat: '<path d=\"M4 5h16v11H9l-5 4z\"/>',\n search: '<circle cx=\"11\" cy=\"11\" r=\"6.5\"/><path d=\"M16 16l5 5\"/>',\n filter: '<path d=\"M3 5h18l-7 8.5V20l-4-2v-4.5z\"/>',\n layers: '<path d=\"M12 3l9 5-9 5-9-5z\"/><path d=\"M3 13l9 5 9-5\"/>',\n};\n\n/** An icon by name, the app's own first and then Fieldia's; null for a name neither has. */\nexport function drawIcon(doc: Document, name: string | undefined, own?: IconSet): SVGSVGElement | null {\n const inside = name ? own?.[name] ?? ICONS[name] : undefined;\n if (inside === undefined) return null;\n const svg = doc.createElementNS(SVG, 'svg');\n for (const [key, value] of Object.entries({\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n 'stroke-width': '1.8',\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round',\n 'aria-hidden': 'true',\n focusable: 'false',\n class: 'fd-icon',\n 'data-icon': name as string,\n })) {\n svg.setAttribute(key, value);\n }\n svg.innerHTML = inside;\n return svg;\n}\n", "import type { Locale, RecordId, RelatedRecord, Values } from '@fieldia/core';\nimport { WIDGET_LABELS } from '@fieldia/widgets';\nimport { mountViewer, VIEWER_LABELS, type Skin, type ViewerHandle, type ViewerOptions } from './viewer';\n\n/**\n * A page in a dialog: a new related record, a line to edit, a quick task. The\n * dialog saves (Save & Close) or closes without saving (Discard, \u00D7, Escape);\n * the page's own Save and Discard stay hidden. The focus moves into the dialog,\n * Tab stays inside it, and the focus goes back where it was when it closes.\n */\n\nexport interface FormDialogOptions extends ViewerOptions {\n title: string;\n size?: 'small' | 'medium' | 'large' | 'full';\n /**\n * \"save\" (the default) saves the record through the data source. \"values\"\n * only checks the form and hands its values back, for something saved with\n * a bigger record, such as a line.\n */\n mode?: 'save' | 'values';\n /**\n * Recalculates the values as they change, for a dialog with no data source of\n * its own: a line's subtotal following its quantity. What comes back is shown.\n */\n recompute?: (values: Values) => Promise<Values>;\n /** Where the dialog goes: the document's body by default. */\n container?: HTMLElement;\n}\n\nexport interface FormDialogResult {\n /** True when Save & Close was pressed and the form accepted. */\n saved: boolean;\n recordId: RecordId | null;\n values: Values;\n}\n\nlet dialogs = 0;\n\nconst FOCUSABLE = 'button, [href], input, select, textarea, [contenteditable=\"true\"], [tabindex]:not([tabindex=\"-1\"])';\n\nexport function openFormDialog(options: FormDialogOptions): Promise<FormDialogResult> {\n const doc = options.container?.ownerDocument ?? document;\n const container = options.container ?? doc.body;\n const opener = doc.activeElement instanceof doc.defaultView!.HTMLElement ? (doc.activeElement as HTMLElement) : null;\n const labels = { ...VIEWER_LABELS[options.locale ?? 'en'], ...options.labels };\n const id = `fd-dialog-${++dialogs}`;\n const make = <K extends keyof HTMLElementTagNameMap>(tag: K, attrs: Record<string, string> = {}, text?: string) => {\n const element = doc.createElement(tag);\n for (const [name, value] of Object.entries(attrs)) element.setAttribute(name, value);\n if (text !== undefined) element.textContent = text;\n return element;\n };\n\n const title = make('h2', { id: `${id}-title`, class: 'fd-form-dialog-title' }, options.title);\n const closeButton = make('button', { type: 'button', class: 'fd-dialog-close', 'aria-label': labels.close }, '\u00D7');\n const body = make('div', { class: 'fd-form-dialog-body' });\n const discard = make('button', { type: 'button', class: 'fd-button' }, labels.discard);\n const saveClose = make('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.saveClose);\n const box = make('div', {\n // Its own tokens and skin: the dialog sits outside the page that opened it.\n class: `fd-theme fd-form-dialog fd-size-${options.size ?? 'medium'}`,\n 'data-fd-skin': options.skin ?? 'underline',\n role: 'dialog',\n 'aria-modal': 'true',\n 'aria-labelledby': title.id,\n tabindex: '-1',\n });\n if (options.dir) box.setAttribute('dir', options.dir);\n box.append(make('div', { class: 'fd-form-dialog-head' }), body, make('div', { class: 'fd-actions fd-actions-end fd-form-dialog-foot' }));\n box.firstElementChild?.append(title, closeButton);\n box.lastElementChild?.append(discard, saveClose);\n const backdrop = make('div', { class: 'fd-dialog-backdrop fd-form-dialog-backdrop' });\n backdrop.append(box);\n container.append(backdrop);\n\n const handle = mountViewer(body, { ...options, showActions: false });\n let done = false;\n if (options.recompute) recalculate(handle.form, options.page.fields, options.recompute, () => done);\n\n const focusables = () =>\n [...box.querySelectorAll<HTMLElement>(FOCUSABLE)].filter(\n (element) => !element.closest('[hidden], [inert]') && !(element as HTMLButtonElement).disabled\n );\n // Into the dialog: its first field, once the record is in, or the dialog itself meanwhile.\n const firstField = () => body.querySelector<HTMLElement>('input:not([type=\"hidden\"]), select, textarea, [contenteditable=\"true\"]');\n (firstField() ?? box).focus();\n void handle.form.settled().then(() => {\n if (doc.activeElement === box || !box.contains(doc.activeElement)) firstField()?.focus();\n });\n\n return new Promise((resolve) => {\n const close = (saved: boolean) => {\n if (done) return;\n done = true;\n const state = handle.form.getState();\n // The form never changes its values in place, so these are safe to hand back.\n const result: FormDialogResult = { saved, recordId: state.recordId ?? null, values: state.values as Values };\n handle.destroy();\n backdrop.remove();\n opener?.focus();\n resolve(result);\n };\n saveClose.addEventListener('click', async () => {\n saveClose.disabled = true;\n const accepted = options.mode === 'values' ? handle.check() : await handle.save();\n saveClose.disabled = false;\n if (accepted) close(true);\n });\n discard.addEventListener('click', () => close(false));\n closeButton.addEventListener('click', () => close(false));\n box.addEventListener('keydown', (event) => {\n // Ctrl+Enter is Save & Close from wherever the cursor is, even after a field used the Enter\n // (a tag box adding its tag), taking what is still being typed. The grid keeps its own keys.\n if (event.key === 'Enter' && (event.ctrlKey || event.metaKey) && !event.isComposing) {\n if ((event.target as Element).closest('.ag-root-wrapper')) return;\n event.preventDefault();\n doc.activeElement?.dispatchEvent(new Event('change', { bubbles: true }));\n saveClose.click();\n return;\n }\n // A key a field used itself (Escape closing a list) is not the dialog's.\n if (event.defaultPrevented) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n close(false);\n } else if (event.key === 'Tab') {\n const all = focusables();\n if (!all.length) return;\n const first = all[0];\n const last = all[all.length - 1];\n if (event.shiftKey && doc.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && doc.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n }\n });\n });\n}\n\n/** Each change of the values asks for them recalculated, and shows the answer unless they changed again meanwhile. */\nfunction recalculate(form: ViewerHandle['form'], fields: Record<string, unknown>, recompute: (values: Values) => Promise<Values>, closed: () => boolean) {\n let seen = JSON.stringify(form.getState().values);\n let writing = false;\n form.subscribe(() => {\n const values = form.getState().values as Values;\n const now = JSON.stringify(values);\n if (writing || now === seen) return;\n seen = now;\n recompute(values).then(\n (next) => {\n if (closed() || JSON.stringify(form.getState().values) !== now) return; // a newer answer is on its way\n writing = true;\n for (const [name, value] of Object.entries(next)) {\n if (name in fields && JSON.stringify(values[name] ?? null) !== JSON.stringify(value ?? null)) form.setValue(name, value);\n }\n writing = false;\n seen = JSON.stringify(form.getState().values);\n },\n () => undefined\n );\n });\n}\n\nexport interface SearchDialogOptions {\n title: string;\n /** Finds records for what is typed: the field's own search, filter and all. */\n search(query: string, limit: number): Promise<RelatedRecord[]>;\n locale?: Locale;\n skin?: Skin;\n dir?: 'ltr' | 'rtl';\n /** Where the dialog goes: the document's body by default. */\n container?: HTMLElement;\n}\n\n/**\n * A searchable list in a dialog, for \"Search more\u2026\": every record the field may\n * point to, narrowed as the person types, picked with a click or the keyboard.\n * Resolves with the record picked, or null when closed.\n */\nexport function openSearchDialog(options: SearchDialogOptions): Promise<RelatedRecord | null> {\n const doc = options.container?.ownerDocument ?? document;\n const container = options.container ?? doc.body;\n const opener = doc.activeElement instanceof doc.defaultView!.HTMLElement ? (doc.activeElement as HTMLElement) : null;\n const labels = VIEWER_LABELS[options.locale ?? 'en'];\n const words = WIDGET_LABELS[options.locale ?? 'en'];\n const id = `fd-dialog-${++dialogs}`;\n const make = <K extends keyof HTMLElementTagNameMap>(tag: K, attrs: Record<string, string> = {}, text?: string) => {\n const element = doc.createElement(tag);\n for (const [name, value] of Object.entries(attrs)) element.setAttribute(name, value);\n if (text !== undefined) element.textContent = text;\n return element;\n };\n const title = make('h2', { id: `${id}-title`, class: 'fd-form-dialog-title' }, options.title);\n const closeButton = make('button', { type: 'button', class: 'fd-dialog-close', 'aria-label': labels.close }, '\u00D7');\n const query = make('input', { type: 'search', class: 'fd-input', 'aria-label': words.search, placeholder: words.search, 'aria-controls': `${id}-list`, autocomplete: 'off' });\n const list = make('ul', { id: `${id}-list`, class: 'fd-search-list', role: 'listbox', 'aria-labelledby': title.id });\n const cancel = make('button', { type: 'button', class: 'fd-button' }, labels.cancel);\n const box = make('div', {\n class: `fd-theme fd-form-dialog fd-search-dialog fd-size-small`,\n 'data-fd-skin': options.skin ?? 'underline',\n role: 'dialog',\n 'aria-modal': 'true',\n 'aria-labelledby': title.id,\n });\n if (options.dir) box.setAttribute('dir', options.dir);\n const head = make('div', { class: 'fd-form-dialog-head' });\n head.append(title, closeButton);\n const body = make('div', { class: 'fd-form-dialog-body fd-search-body' });\n body.append(query, list);\n const foot = make('div', { class: 'fd-actions fd-actions-end fd-form-dialog-foot' });\n foot.append(cancel);\n box.append(head, body, foot);\n const backdrop = make('div', { class: 'fd-dialog-backdrop fd-form-dialog-backdrop' });\n backdrop.append(box);\n container.append(backdrop);\n query.focus();\n\n return new Promise((resolve) => {\n let found: RelatedRecord[] = [];\n let active = -1;\n let asked = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const close = (picked: RelatedRecord | null) => {\n clearTimeout(timer);\n asked++;\n backdrop.remove();\n opener?.focus();\n resolve(picked);\n };\n const draw = () => {\n list.replaceChildren(\n ...found.map((record, i) => {\n const option = make('li', { id: `${id}-option-${i}`, role: 'option', class: `fd-option${i === active ? ' fd-active' : ''}`, 'aria-selected': String(i === active) }, record.label);\n option.addEventListener('click', () => close(record));\n return option;\n })\n );\n if (!found.length) list.append(make('li', { class: 'fd-empty' }, words.noResults));\n if (active >= 0) query.setAttribute('aria-activedescendant', `${id}-option-${active}`);\n else query.removeAttribute('aria-activedescendant');\n };\n const look = () => {\n clearTimeout(timer);\n const mine = ++asked;\n timer = setTimeout(async () => {\n const records = await options.search(query.value, 80).catch(() => [] as RelatedRecord[]);\n if (mine !== asked) return; // a newer search, or the dialog closed\n found = records;\n active = -1;\n draw();\n }, 180);\n };\n query.addEventListener('input', look);\n query.addEventListener('keydown', (event) => {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n if (!found.length) return;\n active = (active + (event.key === 'ArrowDown' ? 1 : -1) + found.length) % found.length;\n draw();\n list.children[active]?.scrollIntoView?.({ block: 'nearest' });\n } else if (event.key === 'Enter' && active >= 0) {\n event.preventDefault();\n close(found[active]);\n }\n });\n cancel.addEventListener('click', () => close(null));\n closeButton.addEventListener('click', () => close(null));\n box.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n close(null);\n }\n });\n look();\n });\n}\n", "import type { CreateRequest, DataSource, Field, Page, SearchRequest } from '@fieldia/core';\nimport type { WidgetDialogs } from '@fieldia/widgets';\nimport { openFormDialog, openSearchDialog } from './dialog';\nimport type { ViewerOptions } from './viewer';\n\n/** The field a page's records are named by: its title, or \"name\", or its first line of text. */\nexport function nameFieldOf(page: Page): string | null {\n if (page.layout.type === 'sheet' && page.layout.title?.field) return page.layout.title.field;\n if (page.fields['name']) return 'name';\n return Object.entries(page.fields).find(([, def]) => def.type === 'char')?.[0] ?? null;\n}\n\n\n\n/** A form made of fields, for values edited in a dialog (a line, for one). */\nfunction valuesPage(fields: Record<string, Field>, title: string, readonly: boolean): Page {\n const shown = Object.fromEntries(Object.entries(fields).map(([name, def]) => [name, readonly ? { ...def, readonly: true } : def])) as Page['fields'];\n return {\n fieldia: '0.1',\n id: 'values',\n title,\n data: { kind: 'record', model: 'values' },\n fields: shown,\n layout: {\n type: 'sections',\n id: 'values',\n children: [{ type: 'section', id: 'values-section', columns: 2, children: Object.keys(shown).map((name) => ({ type: 'field' as const, id: `values-${name}`, field: name })) }],\n },\n };\n}\n\n/** Only finding and making linked records: values edited in a dialog are no record of the source's to load, save or recalculate. */\nfunction lookupsOf(source: DataSource | undefined): DataSource | undefined {\n if (!source) return undefined;\n return {\n ...(source.search ? { search: (request: SearchRequest) => source.search!(request) } : {}),\n ...(source.create ? { create: (request: CreateRequest) => source.create!(request) } : {}),\n };\n}\n\n/** The dialogs a page's widgets may open, made from the viewer's own options. */\nexport function pageDialogs(options: ViewerOptions): WidgetDialogs {\n const pageFor = (model: string) =>\n (typeof options.relatedPages === 'function' ? options.relatedPages(model) : options.relatedPages?.[model]) ?? null;\n // A dialog's page looks and reads like the page that opened it, and can open dialogs of its own.\n const shared = {\n locale: options.locale,\n skin: options.skin,\n dir: options.dir,\n widgets: options.widgets,\n preferences: options.preferences,\n relatedPages: options.relatedPages,\n translate: options.translate,\n };\n return {\n canOpen: (model) => pageFor(model) !== null,\n async openRecord(model, request) {\n const related = pageFor(model);\n if (!related) return null;\n const nameField = nameFieldOf(related);\n const result = await openFormDialog({\n ...shared,\n page: related,\n dataSource: options.dataSource,\n recordId: request.recordId ?? null,\n values: request.name && nameField ? { [nameField]: request.name } : undefined,\n title: request.title,\n size: 'large',\n });\n if (!result.saved || result.recordId === null) return null;\n const name = nameField ? result.values[nameField] : null;\n return { id: result.recordId, label: typeof name === 'string' && name ? name : request.name ?? request.title };\n },\n searchMore: (request) => openSearchDialog({ title: request.title, search: request.search, locale: options.locale, skin: options.skin, dir: options.dir }),\n async editValues(request) {\n const result = await openFormDialog({\n ...shared,\n page: valuesPage(request.fields, request.title, request.readonly === true),\n dataSource: lookupsOf(options.dataSource),\n values: request.values,\n title: request.title,\n mode: 'values',\n ...(request.recompute ? { recompute: request.recompute } : {}),\n });\n return result.saved ? result.values : null;\n },\n };\n}\n", "import type { Facet, JsonValue, ListNode, Page } from '@fieldia/core';\nimport type { PreferenceStore } from '@fieldia/widgets';\nimport type { El } from './dom';\nimport type { ViewerLabels } from './labels';\n\n/** A search a person kept, by its name; the one used by default opens the list. */\nexport interface Favourite {\n name: string;\n facets: Facet[];\n isDefault?: boolean;\n}\n\nconst key = (page: Page) => `favourites:${page.id}`;\n\nexport function readFavourites(preferences: PreferenceStore, page: Page): Favourite[] {\n const kept = preferences.get(key(page));\n return Array.isArray(kept) ? (kept as unknown as Favourite[]) : [];\n}\n\n/** What a list starts with: the favourite used by default, or else the list's own default filters. */\nexport function startingFacets(node: ListNode, preferences: PreferenceStore, page: Page): Facet[] {\n const chosen = readFavourites(preferences, page).find((favourite) => favourite.isDefault);\n if (chosen) return chosen.facets;\n if (!node.defaultFilters?.length) return [];\n return [{ kind: 'filters', ids: [...node.defaultFilters], labels: node.defaultFilters.map((id) => node.filters?.find((f) => f.id === id)?.label ?? id) }];\n}\n\n/**\n * The Favourites of the search menu: searches kept by name, each one put back\n * with a click or deleted, and the search on screen kept as a new one, used by\n * default if the person says so. Kept where the page keeps its preferences.\n */\nexport function favouritesPart(context: { page: Page; el: El; labels: ViewerLabels; fill: (template: string, values: Record<string, string>) => string; preferences: PreferenceStore; current: () => Facet[]; apply: (facets: Facet[]) => void }) {\n const { page, el, labels, fill, preferences } = context;\n const list = el('ul', { class: 'fd-favourite-list' });\n const none = el('p', { class: 'fd-favourites-none' }, labels.noFavourites);\n const name = el('input', { class: 'fd-input', 'aria-label': labels.searchName, placeholder: labels.searchName });\n const byDefault = el('input', { type: 'checkbox' });\n const save = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.save);\n const form = el('div', { class: 'fd-favourite-form', hidden: '' }, name, el('label', { class: 'fd-favourite-default' }, byDefault, labels.useByDefault), save);\n const open = el('button', { type: 'button', class: 'fd-search-option fd-search-add', 'aria-expanded': 'false' }, labels.saveSearch);\n\n const write = (favourites: Favourite[]) => preferences.set(key(page), favourites as unknown as JsonValue);\n\n function draw() {\n const favourites = readFavourites(preferences, page);\n none.hidden = favourites.length > 0;\n list.replaceChildren(\n ...favourites.map((favourite) => {\n const use = el('button', { type: 'button', class: 'fd-search-option', 'data-default': favourite.isDefault ? 'true' : undefined }, favourite.name);\n use.addEventListener('click', () => context.apply(favourite.facets));\n const remove = el('button', { type: 'button', class: 'fd-favourite-remove', 'aria-label': fill(labels.deleteFavourite, { name: favourite.name }) }, '\u00D7');\n remove.addEventListener('click', () => {\n write(readFavourites(preferences, page).filter((f) => f.name !== favourite.name));\n draw();\n });\n return el('li', { class: 'fd-favourite' }, use, remove);\n })\n );\n }\n\n open.addEventListener('click', () => {\n form.hidden = !form.hidden;\n open.setAttribute('aria-expanded', String(!form.hidden));\n if (!form.hidden) name.focus();\n });\n save.addEventListener('click', () => {\n const named = name.value.trim();\n if (!named) return name.focus();\n const kept: Favourite = { name: named, facets: context.current(), ...(byDefault.checked ? { isDefault: true } : {}) };\n // A name kept again replaces the old search; one default at a time.\n const others = readFavourites(preferences, page)\n .filter((f) => f.name !== named)\n .map((f) => (byDefault.checked ? { name: f.name, facets: f.facets } : f));\n write([...others, kept]);\n name.value = '';\n byDefault.checked = false;\n form.hidden = true;\n open.setAttribute('aria-expanded', 'false');\n draw();\n });\n\n draw();\n return { list, none, open, form };\n}\n", "import type { DataSource, Group, Page, RecordId, ResolvedFilter, SortOrder, Value } from '@fieldia/core';\nimport type { El } from './dom';\nimport type { ViewerLabels } from './labels';\n\nexport type Row = { id: RecordId; values: Record<string, Value> };\n\nexport interface GroupContext {\n page: Page;\n el: El;\n labels: ViewerLabels;\n fill: (template: string, values: Record<string, string | number>) => string;\n dataSource: DataSource;\n model: string;\n fields: string[];\n columns: number;\n pageSize: number;\n sort: () => SortOrder[];\n /** A record's row, at a depth under its groups. */\n recordRow: (record: Row, level: number) => HTMLTableRowElement;\n /** Rows came or went. */\n changed: () => void;\n}\n\n/** A group's name as a person reads it: the choice's label, yes or no, the linked record's name, or None. */\nfunction groupName(context: GroupContext, field: string, group: Group): string {\n const def = context.page.fields[field];\n if (group.value === null) return context.labels.none;\n if (def.type === 'selection') return def.options.find((o) => o.value === group.value)?.label ?? group.label;\n if (def.type === 'boolean') return group.value ? context.labels.yes : context.labels.no;\n return group.label || String(group.value);\n}\n\n/** Take away every row under a group: its records, its groups and theirs. */\nfunction closeUnder(tr: HTMLElement) {\n const level = Number(tr.dataset['level']);\n let next = tr.nextElementSibling as HTMLElement | null;\n while (next && Number(next.dataset['level'] ?? 0) > level) {\n const after = next.nextElementSibling as HTMLElement | null;\n next.remove();\n next = after;\n }\n}\n\n/**\n * A group's row: its name and how many records it holds. Opened, it shows\n * the next field's groups under it, or at the last field its records, a page\n * at a time; closed, everything under it goes.\n */\nexport function groupRow(context: GroupContext, group: Group, level: number, within: ResolvedFilter[], grouping: string[]): HTMLTableRowElement {\n const { el, labels } = context;\n const field = grouping[level];\n const filter: ResolvedFilter[] = [...within, group.value === null ? { field, op: 'notset', value: null } : { field, op: '=', value: group.value }];\n const toggle = el(\n 'button',\n { type: 'button', class: 'fd-group-toggle', 'aria-expanded': 'false' },\n el('span', { class: 'fd-group-label' }, groupName(context, field, group)),\n ' ',\n el('span', { class: 'fd-group-count' }, `(${group.count})`)\n );\n const tr = el('tr', { class: 'fd-list-group', 'data-level': String(level), 'aria-level': String(level + 1) }, el('td', { colspan: String(context.columns) }, toggle));\n tr.style.setProperty('--fd-level', String(level));\n let opening = false;\n\n async function open() {\n opening = true;\n try {\n const rows =\n level + 1 < grouping.length\n ? (await context.dataSource.groups?.({ model: context.model, field: grouping[level + 1], filter }))?.map((inner) => groupRow(context, inner, level + 1, filter, grouping)) ?? []\n : await recordsFrom(0);\n // Closed, or the list drawn again, while the answer was on its way.\n if (!tr.isConnected || toggle.getAttribute('aria-expanded') !== 'true') return;\n tr.after(...rows);\n context.changed();\n } finally {\n opening = false;\n }\n }\n\n /** A page of the group's records, from `offset`, and a row for the rest when there are more. */\n async function recordsFrom(offset: number): Promise<HTMLTableRowElement[]> {\n const answer = await context.dataSource.list!({ model: context.model, fields: context.fields, filter, sort: context.sort(), offset, limit: context.pageSize });\n const rows = answer.records.map((record) => context.recordRow(record, level + 1));\n const left = answer.total - offset - answer.records.length;\n if (left <= 0) return rows;\n const more = el('button', { type: 'button', class: 'fd-button fd-button-link' }, context.fill(labels.loadMore, { n: left }));\n const moreRow = el('tr', { class: 'fd-list-more', 'data-level': String(level + 1) }, el('td', { colspan: String(context.columns) }, more));\n moreRow.style.setProperty('--fd-level', String(level));\n more.addEventListener('click', async () => {\n more.disabled = true;\n const next = await recordsFrom(offset + answer.records.length);\n if (!moreRow.isConnected) return;\n moreRow.replaceWith(...next);\n context.changed();\n });\n return [...rows, moreRow];\n }\n\n toggle.addEventListener('click', () => {\n const opened = toggle.getAttribute('aria-expanded') === 'true';\n toggle.setAttribute('aria-expanded', String(!opened));\n if (opened) {\n closeUnder(tr);\n context.changed();\n } else if (!opening) void open();\n });\n return tr;\n}\n", "/** The list's look, on the same tokens as the forms it opens. */\nexport const LIST_STYLES = `.fd-list{display:grid;gap:10px;min-width:0}.fd-list [hidden]{display:none!important}.fd-list-bar{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;min-height:34px}.fd-search{position:relative;flex:1 1 360px;max-width:680px;min-width:0;container:fd-search / inline-size}.fd-search-field{display:flex;flex-wrap:wrap;align-items:center;gap:4px;min-height:34px;box-sizing:border-box;padding:2px 2px 2px 8px;padding-inline:8px 2px;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);background:var(--fd-surface)}.fd-search-field:focus-within{border-color:var(--fd-focus);box-shadow:var(--fd-focus-ring)}.fd-search-field>.fd-icon,.fd-search-field>svg{width:16px;height:16px;color:var(--fd-muted);flex:none}.fd-facets{display:contents}.fd-facet{display:inline-flex;align-items:center;gap:4px;max-width:100%;min-width:0;padding-block:2px;padding-inline:6px 2px;border-radius:3px;background:var(--fd-accent-soft);color:var(--fd-accent);font-size:13px;line-height:18px}.fd-facet svg{width:13px;height:13px;flex:none}.fd-facet[data-kind=groupBy]{background:var(--fd-success-soft);color:var(--fd-success)}.fd-facet-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fd-facet-remove{all:unset;cursor:pointer;display:grid;place-items:center;width:18px;height:18px;border-radius:2px;font-size:15px;line-height:1;opacity:.7}.fd-facet-remove:hover,.fd-facet-remove:focus-visible{opacity:1;background:var(--fd-surface)}.fd-search-input{flex:1 1 140px;min-width:100px;border:none;outline:none;background:none;font:inherit;font-size:14px;color:var(--fd-text);padding:5px 4px}.fd-form .fd-search-input:focus-visible{outline:none}.fd-search-toggle{all:unset;cursor:pointer;display:grid;place-items:center;width:30px;height:28px;border-radius:3px;color:var(--fd-muted)}.fd-search-toggle:before{content:\"\";width:7px;height:7px;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:translateY(-2px) rotate(45deg)}.fd-search-toggle[aria-expanded=true]:before{transform:translateY(2px) rotate(-135deg)}.fd-search-toggle:hover,.fd-search-toggle[aria-expanded=true]{background:var(--fd-page);color:var(--fd-text)}.fd-search-toggle:focus-visible{outline:2px solid var(--fd-focus)}.fd-search-suggestions,.fd-search-panel{position:absolute;z-index:30;inset-inline:0;top:calc(100% + 4px);box-sizing:border-box;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius);box-shadow:0 10px 28px #0f172a24}.fd-search-suggestions{list-style:none;margin:0;padding:4px 0}.fd-search-suggestions [role=option]{padding:7px 12px;cursor:pointer;font-size:14px}.fd-search-suggestions [role=option][aria-selected=true]{background:var(--fd-accent-soft)}.fd-search-panel{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);padding-block:6px}.fd-search-group{display:flex;flex-direction:column;align-items:stretch;gap:1px;padding:4px 10px 8px;min-width:0}.fd-search-group+.fd-search-group{border-inline-start:1px solid var(--fd-border)}@container fd-search (max-width: 540px){.fd-search-panel{grid-auto-flow:row}.fd-search-group+.fd-search-group{border-inline-start:none;border-block-start:1px solid var(--fd-border);padding-block-start:8px}}.fd-search-heading{display:flex;align-items:center;gap:6px;font-weight:600;font-size:13.5px;padding:4px 6px 6px}.fd-search-heading svg{width:15px;height:15px}.fd-search-group[data-group-kind=filters] .fd-search-heading svg{color:var(--fd-accent)}.fd-search-group[data-group-kind=groupBy] .fd-search-heading svg{color:var(--fd-success)}.fd-search-group[data-group-kind=favourites] .fd-search-heading svg{color:var(--fd-warning)}.fd-search-option{all:unset;box-sizing:border-box;cursor:pointer;display:flex;align-items:center;gap:6px;padding:5px 6px;border-radius:4px;font-size:14px;color:var(--fd-text)}.fd-search-option:before{content:\"\";width:14px;flex:none;text-align:center;color:var(--fd-accent);font-weight:700}.fd-search-option[aria-pressed=true]:before{content:\"\u2713\"}.fd-search-option:hover,.fd-search-option:focus-visible{background:var(--fd-page)}.fd-search-add{color:var(--fd-muted);margin-block-start:4px}.fd-search-add:before{content:\"+\";color:var(--fd-muted);font-weight:400}.fd-custom-filter,.fd-favourite-form{display:grid;gap:6px;padding:6px}.fd-custom-filter .fd-input,.fd-favourite-form .fd-input{width:100%;box-sizing:border-box;min-height:30px;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);padding:3px 6px;font:inherit;font-size:13.5px;background:var(--fd-surface);color:var(--fd-text)}.fd-favourite-default{display:flex;align-items:center;gap:6px;font-size:13.5px}.fd-favourite-list{list-style:none;margin:0;padding:0}.fd-favourite{display:flex;align-items:center}.fd-favourite .fd-search-option{flex:1;min-width:0}.fd-favourite .fd-search-option[data-default=true]:before{content:\"\u2605\";color:var(--fd-warning)}.fd-favourite-remove{all:unset;cursor:pointer;width:24px;height:24px;display:grid;place-items:center;border-radius:4px;color:var(--fd-muted)}.fd-favourite-remove:hover{background:var(--fd-page);color:var(--fd-error)}.fd-favourites-none{margin:0;padding:4px 6px;color:var(--fd-muted);font-size:13px}.fd-list-selection{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:3px 4px 3px 10px;border-radius:var(--fd-control-radius);background:var(--fd-accent-soft)}.fd-list-count{font-weight:600;font-size:13.5px;color:var(--fd-accent);font-variant-numeric:tabular-nums}.fd-pager{display:flex;align-items:center;gap:4px;margin-inline-start:auto}.fd-pager-text{color:var(--fd-muted);font-size:13.5px;font-variant-numeric:tabular-nums;margin-inline-end:6px;white-space:nowrap}.fd-pager-button{min-width:32px;padding-inline:0;font-size:18px;line-height:1}.fd-list-scroll{overflow-x:auto;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius)}.fd-list-table{width:100%;border-collapse:collapse;font-size:14px}.fd-list-table th{text-align:start;font-weight:600;font-size:13px;color:var(--fd-text);padding:8px 10px;border-block-end:1px solid var(--fd-border-strong);white-space:nowrap;background:var(--fd-surface)}.fd-list-table td{padding:7px 10px;border-block-end:1px solid var(--fd-border);max-width:28em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fd-list-table tbody tr:last-child td{border-block-end:none}.fd-list-table .fd-num{text-align:end;font-variant-numeric:tabular-nums}.fd-list-table th.fd-list-check,.fd-list-table td.fd-list-check{width:36px;padding-inline:10px 0}.fd-list-checkbox{width:16px;height:16px;margin:0;vertical-align:middle;accent-color:var(--fd-accent);cursor:pointer}.fd-list-sort{all:unset;box-sizing:border-box;width:100%;cursor:pointer;display:flex;align-items:center;gap:4px;font:inherit;color:inherit}.fd-list-sort:after{content:\"\";width:0;height:0;border-inline:4px solid transparent;opacity:0}.fd-list-sort:hover:after{opacity:.35;border-block-start:5px solid currentColor}.fd-list-table th[aria-sort=ascending] .fd-list-sort:after{opacity:1;border-block-start:none;border-block-end:5px solid currentColor}.fd-list-table th[aria-sort=descending] .fd-list-sort:after{opacity:1;border-block-end:none;border-block-start:5px solid currentColor}.fd-list-table th.fd-num .fd-list-sort{justify-content:flex-end}.fd-list-table th.fd-num .fd-list-sort:after{order:-1}.fd-list-sort:focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px}.fd-list-row:hover td{background:var(--fd-page)}.fd-list-openable{cursor:pointer}.fd-list-row[aria-selected=true] td{background:var(--fd-accent-soft)}.fd-list-row:focus-visible{outline:2px solid var(--fd-focus);outline-offset:-2px}.fd-list-table[aria-busy=true] tbody{opacity:.6;transition:opacity .2s .15s}.fd-list-group td{padding:0;background:var(--fd-page)}.fd-group-toggle{all:unset;box-sizing:border-box;cursor:pointer;display:flex;align-items:center;gap:8px;width:100%;padding:8px 10px;padding-inline-start:calc(12px + var(--fd-level, 0) * 22px);font-weight:600;font-size:13.5px;color:var(--fd-text)}.fd-group-toggle:before{content:\"\";flex:none;width:6px;height:6px;border-top:1.5px solid currentColor;border-right:1.5px solid currentColor;transform:rotate(45deg);transition:transform .12s}.fd-group-toggle:dir(rtl):before{transform:rotate(-135deg)}.fd-group-toggle[aria-expanded=true]:before{transform:rotate(135deg)}.fd-group-toggle:hover{background:var(--fd-accent-soft)}.fd-group-toggle:focus-visible{outline:2px solid var(--fd-focus);outline-offset:-2px}.fd-group-count{color:var(--fd-muted);font-weight:400;font-variant-numeric:tabular-nums}.fd-list-more td{padding:4px 10px;padding-inline-start:calc(46px + var(--fd-level, 0) * 22px)}.fd-list-empty,.fd-list-failed{margin:0;padding:28px 12px;text-align:center;color:var(--fd-muted)}.fd-list-failed{color:var(--fd-error)}`;\n\n/** Puts the list's look in the document once. */\nexport function installListStyles(doc: Document): void {\n if (doc.getElementById('fd-list-styles')) return;\n const style = doc.createElement('style');\n style.id = 'fd-list-styles';\n style.textContent = LIST_STYLES;\n doc.head.append(style);\n}\n", "import type { Facet, Field, JsonValue, Page, ResolvedFilterCondition } from '@fieldia/core';\nimport type { El } from './dom';\nimport type { ViewerLabels } from './labels';\n\ntype Op = ResolvedFilterCondition['op'];\ntype Words = Pick<ViewerLabels, 'opIs' | 'opIsNot' | 'opContains' | 'opGreater' | 'opLess' | 'opSet' | 'opNotSet'>;\n\nconst TEXT: [Op, keyof Words][] = [['ilike', 'opContains'], ['=', 'opIs'], ['!=', 'opIsNot'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst LINK: [Op, keyof Words][] = [['ilike', 'opContains'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst CHOICE: [Op, keyof Words][] = [['=', 'opIs'], ['!=', 'opIsNot'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst NUMBER: [Op, keyof Words][] = [['=', 'opIs'], ['!=', 'opIsNot'], ['>', 'opGreater'], ['<', 'opLess'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst DATE: [Op, keyof Words][] = [['=', 'opIs'], ['>', 'opGreater'], ['<', 'opLess'], ['set', 'opSet'], ['notset', 'opNotSet']];\n\n/** The conditions that suit a field, or none for a field a custom filter cannot look at. */\nfunction conditionsFor(def: Field): [Op, keyof Words][] {\n switch (def.type) {\n case 'char':\n case 'text':\n case 'html':\n return TEXT;\n case 'many2one':\n case 'many2many':\n return LINK;\n case 'selection':\n return CHOICE;\n case 'integer':\n case 'float':\n case 'monetary':\n return NUMBER;\n case 'date':\n case 'datetime':\n return DATE;\n case 'boolean':\n return [['=', 'opIs']];\n default:\n return [];\n }\n}\n\n/**\n * A filter of a person's own, under the list's filters: a field, a condition\n * that suits it, and a value of its kind. Applied, it becomes a chip.\n */\nexport function customFilterPart(context: { page: Page; el: El; labels: ViewerLabels; add: (facet: Facet) => void }) {\n const { page, el, labels } = context;\n const fields = Object.entries(page.fields).filter(([, def]) => conditionsFor(def).length);\n const field = el('select', { class: 'fd-input', 'aria-label': labels.field }, ...fields.map(([name, def]) => el('option', { value: name }, def.label)));\n const condition = el('select', { class: 'fd-input', 'aria-label': labels.condition });\n const valueBox = el('span', { class: 'fd-custom-filter-value' });\n const apply = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.apply);\n const form = el('div', { class: 'fd-custom-filter', hidden: '' }, field, condition, valueBox, apply);\n const button = el('button', { type: 'button', class: 'fd-search-option fd-search-add', 'aria-expanded': 'false' }, labels.addCustomFilter);\n let value: HTMLInputElement | HTMLSelectElement = el('input', { class: 'fd-input', 'aria-label': labels.value });\n\n const def = () => page.fields[field.value];\n\n function drawConditions() {\n condition.replaceChildren(...conditionsFor(def()).map(([op, word]) => el('option', { value: op }, labels[word])));\n drawValue();\n }\n\n /** A box of the field's kind: its choices, yes or no, a number, a day, or text. */\n function drawValue() {\n const current = def();\n if (current.type === 'selection') value = el('select', { class: 'fd-input', 'aria-label': labels.value }, ...current.options.map((o) => el('option', { value: String(o.value) }, o.label)));\n else if (current.type === 'boolean') value = el('select', { class: 'fd-input', 'aria-label': labels.value }, el('option', { value: 'true' }, labels.yes), el('option', { value: 'false' }, labels.no));\n else {\n const type = ['integer', 'float', 'monetary'].includes(current.type) ? 'number' : current.type === 'date' ? 'date' : current.type === 'datetime' ? 'datetime-local' : 'text';\n value = el('input', { class: 'fd-input', type, 'aria-label': labels.value });\n }\n valueBox.replaceChildren(value);\n valueBox.hidden = condition.value === 'set' || condition.value === 'notset';\n }\n\n field.addEventListener('change', drawConditions);\n condition.addEventListener('change', () => (valueBox.hidden = condition.value === 'set' || condition.value === 'notset'));\n button.addEventListener('click', () => {\n form.hidden = !form.hidden;\n button.setAttribute('aria-expanded', String(!form.hidden));\n if (!form.hidden) field.focus();\n });\n\n apply.addEventListener('click', () => {\n const current = def();\n const op = condition.value as Op;\n const word = labels[conditionsFor(current).find(([o]) => o === op)?.[1] ?? 'opIs'];\n let wanted: JsonValue = null;\n let shown = '';\n if (!valueBox.hidden) {\n const text = value.value.trim();\n if (!text) return value.focus();\n if (current.type === 'selection') {\n const option = current.options.find((o) => String(o.value) === text);\n wanted = option?.value ?? text;\n shown = option?.label ?? text;\n } else if (current.type === 'boolean') {\n wanted = text === 'true';\n shown = wanted ? labels.yes : labels.no;\n } else if (['integer', 'float', 'monetary'].includes(current.type)) {\n wanted = Number(text);\n if (!Number.isFinite(wanted)) return value.focus();\n shown = text;\n } else {\n wanted = text;\n shown = text;\n }\n }\n context.add({ kind: 'custom', label: [current.label, word, shown].filter(Boolean).join(' '), filter: [{ field: field.value, op, value: wanted }] });\n form.hidden = true;\n button.setAttribute('aria-expanded', 'false');\n });\n\n drawConditions();\n return { button, form };\n}\n", "import { suggestions, type Facet, type ListNode, type Page, type Suggestion } from '@fieldia/core';\nimport { drawIcon, type IconSet, type PreferenceStore } from '@fieldia/widgets';\nimport { customFilterPart } from './custom-filter';\nimport type { El } from './dom';\nimport { favouritesPart } from './favourites';\nimport type { ViewerLabels } from './labels';\n\ntype FieldFacet = Extract<Facet, { kind: 'field' }>;\n\nexport interface SearchContext {\n page: Page;\n node: ListNode;\n doc: Document;\n el: El;\n labels: ViewerLabels;\n fill: (template: string, values: Record<string, string | number>) => string;\n uid: (id: string) => string;\n icons?: IconSet;\n preferences: PreferenceStore;\n /** What the list starts with. */\n facets: Facet[];\n onChange: (facets: Facet[]) => void;\n}\n\n/** A chip's words: a field and the values looked for in it, filters any of which apply, or the fields grouped by. */\nexport function facetText(facet: Facet, labels: Pick<ViewerLabels, 'or'>): string {\n const or = ` ${labels.or} `;\n switch (facet.kind) {\n case 'field':\n return `${facet.label}: ${facet.values.map((v) => v.label).join(or)}`;\n case 'filters':\n return facet.labels.join(or);\n case 'groupBy':\n return facet.labels.join(' > ');\n case 'custom':\n return facet.label;\n }\n}\n\n/**\n * A list's search bar: what is typed becomes a search in one of the list's\n * fields, chosen from suggestions; the menu turns the list's filters on and\n * off, groups by its fields, builds a filter, and keeps searches as\n * favourites. Everything chosen shows as a chip, and all of it applies.\n */\nexport function searchBar(context: SearchContext) {\n const { page, node, doc, el, labels, fill, uid } = context;\n let facets = context.facets;\n const icon = (name: string) => {\n const drawn = drawIcon(doc, name, context.icons);\n drawn?.setAttribute('aria-hidden', 'true');\n return drawn ? [drawn] : [];\n };\n\n function change(next: Facet[]) {\n facets = next;\n drawChips();\n drawPanel();\n context.onChange(facets);\n }\n\n // ---- the box, its chips and its suggestions -----------------------------------------\n\n const listId = uid(`${node.id}-suggestions`);\n const panelId = uid(`${node.id}-search-panel`);\n const input = el('input', {\n class: 'fd-search-input',\n role: 'combobox',\n autocomplete: 'off',\n placeholder: labels.search,\n 'aria-label': labels.searchLabel,\n 'aria-autocomplete': 'list',\n 'aria-expanded': 'false',\n 'aria-controls': listId,\n });\n const chips = el('div', { class: 'fd-facets' });\n const offeredList = el('ul', { class: 'fd-search-suggestions', role: 'listbox', id: listId, 'aria-label': labels.searchLabel, hidden: '' });\n const toggle = el('button', { type: 'button', class: 'fd-search-toggle', 'aria-label': labels.searchOptions, 'aria-expanded': 'false', 'aria-controls': panelId });\n let offered: Suggestion[] = [];\n let active = 0;\n\n function drawChips() {\n chips.replaceChildren(\n ...facets.map((facet, index) => {\n const text = facetText(facet, labels);\n const remove = el('button', { type: 'button', class: 'fd-facet-remove', 'aria-label': fill(labels.removeFacet, { label: text }) }, '\u00D7');\n remove.addEventListener('click', () => {\n change(facets.filter((_, i) => i !== index));\n input.focus();\n });\n const kind = facet.kind === 'groupBy' ? 'layers' : facet.kind === 'field' ? '' : 'filter';\n return el('span', { class: 'fd-facet', 'data-kind': facet.kind }, ...(kind ? icon(kind) : []), el('span', { class: 'fd-facet-text' }, text), remove);\n })\n );\n }\n\n function drawOffered() {\n offeredList.replaceChildren(\n ...offered.map((suggestion, index) => {\n const option = el('li', { role: 'option', id: `${listId}-${index}`, 'aria-selected': String(index === active) }, suggestion.label);\n // The box keeps the focus while a suggestion is clicked.\n option.addEventListener('mousedown', (event) => event.preventDefault());\n option.addEventListener('click', () => pick(suggestion));\n return option;\n })\n );\n offeredList.hidden = offered.length === 0;\n input.setAttribute('aria-expanded', String(!offeredList.hidden));\n if (offeredList.hidden) input.removeAttribute('aria-activedescendant');\n else input.setAttribute('aria-activedescendant', `${listId}-${active}`);\n }\n\n function closeOffered() {\n offered = [];\n drawOffered();\n }\n\n /** A search in a field joins the field's chip, any of its values; the same value twice is once. */\n function pick(suggestion: Suggestion) {\n const value = { op: suggestion.op, value: suggestion.value, label: suggestion.valueLabel };\n const at = facets.findIndex((f) => f.kind === 'field' && f.field === suggestion.field);\n const next = [...facets];\n if (at < 0) next.push({ kind: 'field', field: suggestion.field, label: suggestion.fieldLabel, values: [value] });\n else {\n const facet = next[at] as FieldFacet;\n const known = facet.values.some((v) => v.op === value.op && JSON.stringify(v.value) === JSON.stringify(value.value));\n if (!known) next[at] = { ...facet, values: [...facet.values, value] };\n }\n input.value = '';\n closeOffered();\n change(next);\n }\n\n input.addEventListener('input', () => {\n offered = suggestions(input.value, page, node, { searchFor: labels.searchFor });\n active = 0;\n drawOffered();\n });\n input.addEventListener('blur', closeOffered);\n input.addEventListener('keydown', (event) => {\n if (event.isComposing) return;\n if ((event.key === 'ArrowDown' || event.key === 'ArrowUp') && offered.length) {\n event.preventDefault();\n active = (active + (event.key === 'ArrowDown' ? 1 : offered.length - 1)) % offered.length;\n drawOffered();\n } else if (event.key === 'Enter') {\n // Never the form's Enter: a list has nothing to send.\n event.preventDefault();\n if (offered.length) pick(offered[active]);\n } else if (event.key === 'Backspace' && !input.value && facets.length) {\n change(facets.slice(0, -1));\n } else if (event.key === 'Escape' && !offeredList.hidden) {\n event.preventDefault();\n closeOffered();\n }\n });\n\n // ---- the menu: filters, group by, favourites ---------------------------------------\n\n const heading = (iconName: string, text: string, id: string) => el('div', { class: 'fd-search-heading', id }, ...icon(iconName), text);\n const toggleIn = (kind: 'filters' | 'groupBy', key: string) => {\n const at = facets.findIndex((f) => f.kind === kind);\n const now = at < 0 ? [] : kind === 'filters' ? (facets[at] as Extract<Facet, { kind: 'filters' }>).ids : (facets[at] as Extract<Facet, { kind: 'groupBy' }>).fields;\n const keys = now.includes(key) ? now.filter((k) => k !== key) : [...now, key];\n const facet: Facet =\n kind === 'filters'\n ? { kind, ids: keys, labels: keys.map((id) => node.filters?.find((f) => f.id === id)?.label ?? id) }\n : { kind, fields: keys, labels: keys.map((field) => page.fields[field]?.label ?? field) };\n const next = [...facets];\n if (at < 0) next.push(facet);\n else if (keys.length) next[at] = facet;\n else next.splice(at, 1);\n change(next);\n };\n\n const filterButtons = (node.filters ?? []).map((filter) => {\n const button = el('button', { type: 'button', class: 'fd-search-option', 'aria-pressed': 'false', 'data-filter': filter.id }, filter.label);\n button.addEventListener('click', () => toggleIn('filters', filter.id));\n return button;\n });\n const groupButtons = (node.groupBy ?? []).map((field) => {\n const button = el('button', { type: 'button', class: 'fd-search-option', 'aria-pressed': 'false', 'data-group': field }, page.fields[field].label);\n button.addEventListener('click', () => toggleIn('groupBy', field));\n return button;\n });\n const custom = customFilterPart({ page, el, labels, add: (facet) => change([...facets, facet]) });\n const favourites = favouritesPart({ page, el, labels, fill, preferences: context.preferences, current: () => facets, apply: change });\n\n const group = (kind: string, iconName: string, title: string, ...parts: HTMLElement[]) =>\n el('div', { class: 'fd-search-group', 'data-group-kind': kind, role: 'group', 'aria-labelledby': `${panelId}-${kind}` }, heading(iconName, title, `${panelId}-${kind}`), ...parts);\n const panel = el(\n 'div',\n { class: 'fd-search-panel', id: panelId, hidden: '' },\n group('filters', 'filter', labels.filters, ...filterButtons, custom.button, custom.form),\n ...(groupButtons.length ? [group('groupBy', 'layers', labels.groupBy, ...groupButtons)] : []),\n group('favourites', 'star', labels.favourites, favourites.list, favourites.none, favourites.open, favourites.form)\n );\n\n function drawPanel() {\n const ids = (facets.find((f) => f.kind === 'filters') as Extract<Facet, { kind: 'filters' }> | undefined)?.ids ?? [];\n const fields = (facets.find((f) => f.kind === 'groupBy') as Extract<Facet, { kind: 'groupBy' }> | undefined)?.fields ?? [];\n for (const button of filterButtons) button.setAttribute('aria-pressed', String(ids.includes(button.dataset['filter'] ?? '')));\n for (const button of groupButtons) button.setAttribute('aria-pressed', String(fields.includes(button.dataset['group'] ?? '')));\n }\n\n function showPanel(open: boolean) {\n panel.hidden = !open;\n toggle.setAttribute('aria-expanded', String(open));\n if (open) closeOffered();\n }\n toggle.addEventListener('click', () => showPanel(panel.hidden));\n panel.addEventListener('keydown', (event) => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n showPanel(false);\n toggle.focus();\n });\n const element = el('div', { class: 'fd-search' }, el('div', { class: 'fd-search-field' }, ...icon('search'), chips, input, toggle), offeredList, panel);\n // A press anywhere else closes the menu.\n const outside = (event: Event) => {\n if (!panel.hidden && !element.contains(event.target as Node)) showPanel(false);\n };\n doc.addEventListener('pointerdown', outside);\n\n drawChips();\n drawPanel();\n return {\n element,\n destroy: () => doc.removeEventListener('pointerdown', outside),\n };\n}\n", "import {\n facetsToFilter,\n groupByFields,\n type ButtonNode,\n type DataSource,\n type Facet,\n type Form,\n type LineField,\n type ListNode,\n type Locale,\n type Page,\n type RecordId,\n type SortOrder,\n type Value,\n} from '@fieldia/core';\nimport { displayValue, type IconSet, type PreferenceStore } from '@fieldia/widgets';\nimport type { El } from './dom';\nimport { startingFacets } from './favourites';\nimport type { ViewerLabels } from './labels';\nimport { groupRow, type GroupContext, type Row } from './list-groups';\nimport { installListStyles } from './list-styles';\nimport { searchBar } from './search-bar';\n\nexport interface ListContext {\n page: Page;\n node: ListNode;\n form: Form;\n dataSource: DataSource | undefined;\n doc: Document;\n el: El;\n labels: ViewerLabels;\n locale: Locale;\n fill: (template: string, values: Record<string, string | number>) => string;\n confirm: (message: string) => Promise<boolean>;\n withIcon: (icon: string | undefined, text: string) => (Node | string)[];\n uid: (id: string) => string;\n icons?: IconSet;\n /** Where the list's favourite searches are kept. */\n preferences: PreferenceStore;\n onOpenRecord?: (id: RecordId) => void;\n}\n\nexport interface ListView {\n element: HTMLElement;\n /** Ask for the records again, keeping the page, the order and what is chosen where it still applies. */\n reload(): Promise<void>;\n destroy(): void;\n}\n\n/** Numbers line up on the end of their column. */\nconst NUMBERS = new Set(['integer', 'float', 'monetary']);\n/** Fields no list can put in order. */\nconst UNSORTABLE = new Set(['one2many', 'many2many', 'binary', 'image', 'html', 'json', 'properties']);\n\n/**\n * Records as a table: one page at a time, in the order a header asks for, each\n * row opening its record. Chosen rows get the list's buttons, which hand the\n * app their ids. A plain table, so it reads the same in every binding.\n */\nexport function listView(context: ListContext): ListView {\n const { page, node, form, el, labels, fill, locale, doc } = context;\n installListStyles(doc);\n const pageSize = node.pageSize ?? 40;\n const defaultSort = node.sort ?? [];\n let sort: SortOrder[] = defaultSort;\n let offset = 0;\n let total = 0;\n /** The page of records, when the list is not grouped. */\n let rows: Row[] = [];\n /** Each record's row, for the records on show however they are grouped. */\n const recordOf = new WeakMap<Element, Row>();\n const visible = () => [...body.querySelectorAll('.fd-list-row')].map((tr) => recordOf.get(tr) as Row);\n // Only a page of records gets this far: the page check refuses a list of anything else.\n const model = page.data.kind === 'record' ? page.data.model : '';\n let facets: Facet[] = startingFacets(node, context.preferences, page);\n /** In the order they were chosen, which is the order the app gets them. */\n const chosen = new Set<RecordId>();\n let asking = 0;\n let destroyed = false;\n\n // The columns, and what an amount needs to be read: its currency, from the record.\n const fields = [...new Set(node.columns.flatMap((name) => {\n const def = page.fields[name];\n return def.type === 'monetary' && def.currencyField ? [name, def.currencyField] : [name];\n }))];\n const show = (name: string, values: Record<string, Value>) => displayValue(page.fields[name] as LineField, values[name], values, locale);\n\n // ---- the table ---------------------------------------------------------------\n\n const chooseAll = el('input', { type: 'checkbox', class: 'fd-list-checkbox', 'aria-label': labels.selectAll });\n const headers = node.columns.map((name) => {\n const def = page.fields[name];\n const th = el('th', { scope: 'col', 'data-field': name, class: NUMBERS.has(def.type) ? 'fd-num' : undefined });\n if (UNSORTABLE.has(def.type)) th.append(def.label);\n else {\n const button = el('button', { type: 'button', class: 'fd-list-sort' }, def.label);\n button.addEventListener('click', () => {\n // The header's field leads; the list's own order breaks the ties.\n const desc = sort[0]?.field === name ? !sort[0].desc : false;\n sort = [{ field: name, ...(desc ? { desc } : {}) }, ...defaultSort.filter((order) => order.field !== name)];\n offset = 0;\n void load();\n });\n th.append(button);\n }\n return th;\n });\n const body = el('tbody');\n const table = el(\n 'table',\n { class: 'fd-list-table', 'aria-label': page.title },\n el('thead', {}, el('tr', {}, el('th', { class: 'fd-list-check', scope: 'col' }, chooseAll), ...headers)),\n body\n );\n const empty = el('p', { class: 'fd-list-empty', hidden: '' }, labels.noRecords);\n const retry = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.retry);\n const failed = el('p', { class: 'fd-list-failed', role: 'alert', hidden: '' }, labels.loadFailed, ' ', retry);\n retry.addEventListener('click', () => void load());\n\n function row(record: Row, level = 0): HTMLTableRowElement {\n const name = show(node.columns[0], record.values) || String(record.id);\n const box = el('input', { type: 'checkbox', class: 'fd-list-checkbox', 'aria-label': fill(labels.selectRecord, { name }) });\n box.checked = chosen.has(record.id);\n box.addEventListener('change', () => {\n if (box.checked) chosen.add(record.id);\n else chosen.delete(record.id);\n drawChoice();\n });\n const tr = el(\n 'tr',\n { class: context.onOpenRecord ? 'fd-list-row fd-list-openable' : 'fd-list-row', tabindex: '0', 'data-id': String(record.id), 'data-level': level ? String(level) : undefined },\n el('td', { class: 'fd-list-check' }, box),\n // Each value in its own direction: a phone number or an amount reads left to right on a right-to-left page.\n ...node.columns.map((name) => el('td', { class: NUMBERS.has(page.fields[name].type) ? 'fd-num' : undefined }, el('bdi', {}, show(name, record.values))))\n );\n tr.addEventListener('click', (event) => {\n const cell = (event.target as Element).closest('td');\n // The box's own cell is a bigger target for the box.\n if (cell?.classList.contains('fd-list-check')) {\n if (event.target === cell) box.click();\n return;\n }\n context.onOpenRecord?.(record.id);\n });\n tr.addEventListener('keydown', (event) => {\n if (event.target !== tr) return;\n if (event.key === 'Enter') {\n event.preventDefault();\n context.onOpenRecord?.(record.id);\n } else if (event.key === ' ') {\n event.preventDefault();\n box.click();\n } else if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n const next = event.key === 'ArrowDown' ? tr.nextElementSibling : tr.previousElementSibling;\n (next as HTMLElement | null)?.focus();\n }\n });\n recordOf.set(tr, record);\n return tr;\n }\n\n // ---- what is chosen, and the buttons for it --------------------------------------\n\n const count = el('span', { class: 'fd-list-count', role: 'status' });\n const clear = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.clearSelection);\n const buttons = (node.actions ?? []).map((action: ButtonNode) => {\n const button = el('button', { type: 'button', class: `fd-button fd-button-${action.style ?? 'secondary'}`, 'data-node': action.id }, ...context.withIcon(action.icon, action.label));\n button.addEventListener('click', async () => {\n if (action.confirm && !(await context.confirm(action.confirm))) return;\n await form.runAction(action.id, { recordIds: [...chosen] });\n await load();\n });\n return button;\n });\n const selection = el('div', { class: 'fd-list-selection', hidden: '' }, count, ...buttons, clear);\n clear.addEventListener('click', () => {\n chosen.clear();\n for (const box of body.querySelectorAll<HTMLInputElement>('.fd-list-checkbox')) box.checked = false;\n drawChoice();\n });\n chooseAll.addEventListener('change', () => {\n for (const record of visible()) {\n if (chooseAll.checked) chosen.add(record.id);\n else chosen.delete(record.id);\n }\n for (const box of body.querySelectorAll<HTMLInputElement>('.fd-list-checkbox')) box.checked = chooseAll.checked;\n drawChoice();\n });\n\n function drawChoice() {\n const shown = visible();\n const onPage = shown.filter((record) => chosen.has(record.id)).length;\n chooseAll.checked = shown.length > 0 && onPage === shown.length;\n chooseAll.indeterminate = onPage > 0 && onPage < shown.length;\n selection.hidden = chosen.size === 0;\n count.textContent = fill(labels.selected, { n: chosen.size });\n for (const tr of body.querySelectorAll<HTMLElement>('.fd-list-row')) {\n tr.setAttribute('aria-selected', String([...chosen].some((id) => String(id) === tr.dataset['id'])));\n }\n }\n\n // ---- pages -------------------------------------------------------------------\n\n const range = el('span', { class: 'fd-pager-text' });\n const previous = el('button', { type: 'button', class: 'fd-button fd-pager-button', 'aria-label': labels.previousPage }, '\u2039');\n const next = el('button', { type: 'button', class: 'fd-button fd-pager-button', 'aria-label': labels.nextPage }, '\u203A');\n const pager = el('div', { class: 'fd-pager', role: 'group' }, range, previous, next);\n previous.addEventListener('click', () => {\n offset = Math.max(0, offset - pageSize);\n void load();\n });\n next.addEventListener('click', () => {\n offset += pageSize;\n void load();\n });\n\n function drawPager() {\n pager.hidden = total === 0;\n range.textContent = fill(labels.range, { from: offset + 1, to: Math.min(offset + rows.length, total), total });\n previous.disabled = offset === 0;\n next.disabled = offset + pageSize >= total;\n }\n\n function drawSort() {\n for (const th of headers) {\n const order = sort[0]?.field === th.dataset['field'] ? sort[0] : null;\n if (order) th.setAttribute('aria-sort', order.desc ? 'descending' : 'ascending');\n else th.removeAttribute('aria-sort');\n }\n }\n\n // ---- asking for the records ------------------------------------------------------\n\n /** Rows came or went: what is chosen keeps to the records on show. */\n function changed() {\n const shown = new Set(visible().map((record) => record.id));\n for (const id of [...chosen]) if (!shown.has(id)) chosen.delete(id);\n drawChoice();\n }\n\n const grouped = (source: DataSource): GroupContext => ({\n page,\n el,\n labels,\n fill,\n dataSource: source,\n model,\n fields,\n columns: node.columns.length + 1,\n pageSize,\n sort: () => sort,\n recordRow: row,\n changed,\n });\n\n async function load(): Promise<void> {\n const mine = ++asking;\n drawSort();\n table.setAttribute('aria-busy', 'true');\n let drawn: HTMLTableRowElement[] = [];\n try {\n const filter = facetsToFilter(facets, node);\n const grouping = groupByFields(facets);\n const source = context.dataSource;\n if (grouping.length && source?.groups && source.list) {\n // Grouped: a row for each value of the first field, each opening into the rest.\n const groups = await source.groups({ model, field: grouping[0], filter });\n if (mine !== asking || destroyed) return;\n rows = [];\n total = 0;\n drawn = groups.map((group) => groupRow(grouped(source), group, 0, filter, grouping));\n } else {\n const answer = source?.list ? await source.list({ model, fields, filter, sort, offset, limit: pageSize }) : { records: [], total: 0 };\n if (mine !== asking || destroyed) return;\n // Past the end, as when the last record of the last page went: back to the page that is left.\n if (!answer.records.length && answer.total > 0 && offset > 0) {\n offset = Math.floor((answer.total - 1) / pageSize) * pageSize;\n return load();\n }\n rows = answer.records;\n total = answer.total;\n drawn = rows.map((record) => row(record));\n }\n failed.hidden = true;\n } catch {\n if (mine !== asking || destroyed) return;\n rows = [];\n total = 0;\n failed.hidden = false;\n }\n body.replaceChildren(...drawn);\n empty.hidden = drawn.length > 0 || !failed.hidden;\n table.removeAttribute('aria-busy');\n drawPager();\n changed();\n }\n\n const search = searchBar({\n page,\n node,\n doc,\n el,\n labels,\n fill,\n uid: context.uid,\n icons: context.icons,\n preferences: context.preferences,\n facets,\n onChange(next) {\n facets = next;\n offset = 0;\n void load();\n },\n });\n const element = el(\n 'div',\n { class: 'fd-list', 'data-node': node.id },\n el('div', { class: 'fd-list-bar' }, search.element, pager),\n selection,\n el('div', { class: 'fd-list-scroll' }, table),\n empty,\n failed\n );\n void load();\n\n return {\n element,\n reload: load,\n destroy() {\n destroyed = true;\n search.destroy();\n },\n };\n}\n", "import type { Locale } from '@fieldia/core';\n\n/** Every word the viewer shows, so a page can be translated. `{n}`, `{total}` and `{time}` are filled in. */\nexport interface ViewerLabels {\n save: string;\n /** Switching a read-only form to editing, and back. */\n edit: string;\n done: string;\n discard: string;\n saving: string;\n saved: string;\n submit: string;\n next: string;\n back: string;\n /** Passing over an optional step. */\n skip: string;\n /** The list of a wizard's steps, for screen readers. */\n steps: string;\n stepOf: string;\n submitted: string;\n submitAnother: string;\n draftFound: string;\n restore: string;\n discardDraft: string;\n ok: string;\n cancel: string;\n loading: string;\n /** A form in a dialog: the button that saves it and closes the dialog, and the \u00D7 that closes it. */\n saveClose: string;\n close: string;\n /** The \u00D7 on an alert that may be dismissed. */\n dismiss: string;\n /** Saving again after a save failed. */\n retry: string;\n notSaved: string;\n notSent: string;\n /** What was not saved or sent, and the fields to look at. */\n checkFields: string;\n /** The banner when the server cannot be reached. */\n offline: string;\n /** A list: its pages (`{from}`, `{to}`, `{total}`), what is chosen in it, and an empty one. */\n previousPage: string;\n nextPage: string;\n range: string;\n selected: string;\n clearSelection: string;\n selectAll: string;\n selectRecord: string;\n noRecords: string;\n loadFailed: string;\n /**\n * A list's search bar: the box (`{field}` and `{text}` in a suggestion), its\n * chips (`{label}`), the Filters, Group By and Favourites menu (`{name}`),\n * and the conditions a custom filter offers.\n */\n search: string;\n searchLabel: string;\n searchFor: string;\n searchOptions: string;\n filters: string;\n groupBy: string;\n favourites: string;\n or: string;\n removeFacet: string;\n addCustomFilter: string;\n field: string;\n condition: string;\n value: string;\n apply: string;\n saveSearch: string;\n searchName: string;\n useByDefault: string;\n deleteFavourite: string;\n noFavourites: string;\n opIs: string;\n opIsNot: string;\n opContains: string;\n opGreater: string;\n opLess: string;\n opSet: string;\n opNotSet: string;\n yes: string;\n no: string;\n /** A list's groups: the one of records with no value, and the rest of a group's records (`{n}`). */\n none: string;\n loadMore: string;\n}\n\nexport const VIEWER_LABELS: Record<Locale, ViewerLabels> = {\n en: {\n save: 'Save',\n edit: 'Edit',\n done: 'Done',\n discard: 'Discard',\n saving: 'Saving\u2026',\n saved: 'Saved',\n submit: 'Submit',\n next: 'Next',\n back: 'Back',\n skip: 'Skip',\n steps: 'Steps',\n stepOf: 'Step {n} of {total}',\n submitted: 'Thank you. Your answers were sent.',\n submitAnother: 'Submit another response',\n draftFound: 'You have unsaved answers from {time}.',\n restore: 'Restore',\n discardDraft: 'Discard',\n ok: 'OK',\n cancel: 'Cancel',\n loading: 'Loading\u2026',\n saveClose: 'Save & Close',\n close: 'Close',\n dismiss: 'Dismiss',\n retry: 'Retry',\n notSaved: 'Not saved',\n notSent: 'Not sent',\n checkFields: '{what}. Check: {fields}',\n offline: 'Could not reach the server. Your changes are still here.',\n previousPage: 'Previous page',\n nextPage: 'Next page',\n range: '{from}\u2013{to} / {total}',\n selected: '{n} selected',\n clearSelection: 'Clear',\n selectAll: 'Select all',\n selectRecord: 'Select {name}',\n noRecords: 'No records match.',\n loadFailed: 'Could not load the records.',\n search: 'Search\u2026',\n searchLabel: 'Search',\n searchFor: 'Search {field} for: {text}',\n searchOptions: 'Search options',\n filters: 'Filters',\n groupBy: 'Group By',\n favourites: 'Favourites',\n or: 'or',\n removeFacet: 'Remove {label}',\n addCustomFilter: 'Add a custom filter',\n field: 'Field',\n condition: 'Condition',\n value: 'Value',\n apply: 'Apply',\n saveSearch: 'Save current search',\n searchName: 'Name of the search',\n useByDefault: 'Use by default',\n deleteFavourite: 'Delete {name}',\n noFavourites: 'No saved searches yet.',\n opIs: 'is',\n opIsNot: 'is not',\n opContains: 'contains',\n opGreater: 'greater than',\n opLess: 'less than',\n opSet: 'is set',\n opNotSet: 'is not set',\n yes: 'Yes',\n no: 'No',\n none: 'None',\n loadMore: 'Show {n} more',\n },\n ar: {\n save: '\u062D\u0641\u0638',\n edit: '\u062A\u0639\u062F\u064A\u0644',\n done: '\u062A\u0645',\n discard: '\u062A\u062C\u0627\u0647\u0644',\n saving: '\u062C\u0627\u0631\u064D \u0627\u0644\u062D\u0641\u0638\u2026',\n saved: '\u062A\u0645 \u0627\u0644\u062D\u0641\u0638',\n submit: '\u0625\u0631\u0633\u0627\u0644',\n next: '\u0627\u0644\u062A\u0627\u0644\u064A',\n back: '\u0631\u062C\u0648\u0639',\n skip: '\u062A\u062E\u0637\u064D\u0651',\n steps: '\u0627\u0644\u062E\u0637\u0648\u0627\u062A',\n stepOf: '\u0627\u0644\u062E\u0637\u0648\u0629 {n} \u0645\u0646 {total}',\n submitted: '\u0634\u0643\u0631\u064B\u0627 \u0644\u0643. \u062A\u0645 \u0625\u0631\u0633\u0627\u0644 \u0625\u062C\u0627\u0628\u0627\u062A\u0643.',\n submitAnother: '\u0625\u0631\u0633\u0627\u0644 \u0625\u062C\u0627\u0628\u0629 \u0623\u062E\u0631\u0649',\n draftFound: '\u0644\u062F\u064A\u0643 \u0625\u062C\u0627\u0628\u0627\u062A \u063A\u064A\u0631 \u0645\u062D\u0641\u0648\u0638\u0629 \u0645\u0646 {time}.',\n restore: '\u0627\u0633\u062A\u0639\u0627\u062F\u0629',\n discardDraft: '\u062A\u062C\u0627\u0647\u0644',\n ok: '\u0645\u0648\u0627\u0641\u0642',\n cancel: '\u0625\u0644\u063A\u0627\u0621',\n loading: '\u062C\u0627\u0631\u064D \u0627\u0644\u062A\u062D\u0645\u064A\u0644\u2026',\n saveClose: '\u062D\u0641\u0638 \u0648\u0625\u063A\u0644\u0627\u0642',\n close: '\u0625\u063A\u0644\u0627\u0642',\n dismiss: '\u0625\u062E\u0641\u0627\u0621',\n retry: '\u0623\u0639\u062F \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629',\n notSaved: '\u0644\u0645 \u064A\u064F\u062D\u0641\u0638',\n notSent: '\u0644\u0645 \u064A\u064F\u0631\u0633\u0644',\n checkFields: '{what}. \u0631\u0627\u062C\u0650\u0639: {fields}',\n offline: '\u062A\u0639\u0630\u0651\u0631 \u0627\u0644\u0648\u0635\u0648\u0644 \u0625\u0644\u0649 \u0627\u0644\u062E\u0627\u062F\u0645. \u062A\u0639\u062F\u064A\u0644\u0627\u062A\u0643 \u0645\u0627 \u0632\u0627\u0644\u062A \u0647\u0646\u0627.',\n previousPage: '\u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u0633\u0627\u0628\u0642\u0629',\n nextPage: '\u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u062A\u0627\u0644\u064A\u0629',\n range: '{from}\u2013{to} \u0645\u0646 {total}',\n selected: '\u062A\u0645 \u062A\u062D\u062F\u064A\u062F {n}',\n clearSelection: '\u0625\u0644\u063A\u0627\u0621 \u0627\u0644\u062A\u062D\u062F\u064A\u062F',\n selectAll: '\u062A\u062D\u062F\u064A\u062F \u0627\u0644\u0643\u0644',\n selectRecord: '\u062A\u062D\u062F\u064A\u062F {name}',\n noRecords: '\u0644\u0627 \u062A\u0648\u062C\u062F \u0633\u062C\u0644\u0627\u062A \u0645\u0637\u0627\u0628\u0642\u0629.',\n loadFailed: '\u062A\u0639\u0630\u0651\u0631 \u062A\u062D\u0645\u064A\u0644 \u0627\u0644\u0633\u062C\u0644\u0627\u062A.',\n search: '\u0628\u062D\u062B\u2026',\n searchLabel: '\u0628\u062D\u062B',\n searchFor: '\u0627\u0628\u062D\u062B \u0641\u064A {field} \u0639\u0646: {text}',\n searchOptions: '\u062E\u064A\u0627\u0631\u0627\u062A \u0627\u0644\u0628\u062D\u062B',\n filters: '\u0639\u0648\u0627\u0645\u0644 \u0627\u0644\u062A\u0635\u0641\u064A\u0629',\n groupBy: '\u062A\u062C\u0645\u064A\u0639 \u062D\u0633\u0628',\n favourites: '\u0627\u0644\u0645\u0641\u0636\u0644\u0629',\n or: '\u0623\u0648',\n removeFacet: '\u0625\u0632\u0627\u0644\u0629 {label}',\n addCustomFilter: '\u0625\u0636\u0627\u0641\u0629 \u0639\u0627\u0645\u0644 \u062A\u0635\u0641\u064A\u0629 \u0645\u062E\u0635\u0635',\n field: '\u0627\u0644\u062D\u0642\u0644',\n condition: '\u0627\u0644\u0634\u0631\u0637',\n value: '\u0627\u0644\u0642\u064A\u0645\u0629',\n apply: '\u062A\u0637\u0628\u064A\u0642',\n saveSearch: '\u062D\u0641\u0638 \u0627\u0644\u0628\u062D\u062B \u0627\u0644\u062D\u0627\u0644\u064A',\n searchName: '\u0627\u0633\u0645 \u0627\u0644\u0628\u062D\u062B',\n useByDefault: '\u0627\u0633\u062A\u062E\u062F\u0627\u0645\u0647 \u0627\u0641\u062A\u0631\u0627\u0636\u064A\u064B\u0627',\n deleteFavourite: '\u062D\u0630\u0641 {name}',\n noFavourites: '\u0644\u0627 \u062A\u0648\u062C\u062F \u0639\u0645\u0644\u064A\u0627\u062A \u0628\u062D\u062B \u0645\u062D\u0641\u0648\u0638\u0629 \u0628\u0639\u062F.',\n opIs: '\u064A\u0633\u0627\u0648\u064A',\n opIsNot: '\u0644\u0627 \u064A\u0633\u0627\u0648\u064A',\n opContains: '\u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649',\n opGreater: '\u0623\u0643\u0628\u0631 \u0645\u0646',\n opLess: '\u0623\u0635\u063A\u0631 \u0645\u0646',\n opSet: '\u0645\u062D\u062F\u062F',\n opNotSet: '\u063A\u064A\u0631 \u0645\u062D\u062F\u062F',\n yes: '\u0646\u0639\u0645',\n no: '\u0644\u0627',\n none: '\u0628\u0644\u0627 \u0642\u064A\u0645\u0629',\n loadMore: '\u0639\u0631\u0636 {n} \u0623\u062E\u0631\u0649',\n },\n de: {\n save: 'Speichern',\n edit: 'Bearbeiten',\n done: 'Fertig',\n discard: 'Verwerfen',\n saving: 'Wird gespeichert\u2026',\n saved: 'Gespeichert',\n submit: 'Absenden',\n next: 'Weiter',\n back: 'Zur\u00FCck',\n skip: '\u00DCberspringen',\n steps: 'Schritte',\n stepOf: 'Schritt {n} von {total}',\n submitted: 'Vielen Dank. Ihre Antworten wurden gesendet.',\n submitAnother: 'Weitere Antwort senden',\n draftFound: 'Sie haben ungespeicherte Antworten vom {time}.',\n restore: 'Wiederherstellen',\n discardDraft: 'Verwerfen',\n ok: 'OK',\n cancel: 'Abbrechen',\n loading: 'Wird geladen\u2026',\n saveClose: 'Speichern und schlie\u00DFen',\n close: 'Schlie\u00DFen',\n dismiss: 'Ausblenden',\n retry: 'Erneut versuchen',\n notSaved: 'Nicht gespeichert',\n notSent: 'Nicht gesendet',\n checkFields: '{what}. Bitte pr\u00FCfen: {fields}',\n offline: 'Der Server ist nicht erreichbar. Ihre \u00C4nderungen sind noch da.',\n previousPage: 'Vorherige Seite',\n nextPage: 'N\u00E4chste Seite',\n range: '{from}\u2013{to} / {total}',\n selected: '{n} ausgew\u00E4hlt',\n clearSelection: 'Auswahl aufheben',\n selectAll: 'Alle ausw\u00E4hlen',\n selectRecord: '{name} ausw\u00E4hlen',\n noRecords: 'Keine passenden Eintr\u00E4ge.',\n loadFailed: 'Die Eintr\u00E4ge konnten nicht geladen werden.',\n search: 'Suchen\u2026',\n searchLabel: 'Suchen',\n searchFor: '{field} durchsuchen nach: {text}',\n searchOptions: 'Suchoptionen',\n filters: 'Filter',\n groupBy: 'Gruppieren nach',\n favourites: 'Favoriten',\n or: 'oder',\n removeFacet: '{label} entfernen',\n addCustomFilter: 'Eigenen Filter hinzuf\u00FCgen',\n field: 'Feld',\n condition: 'Bedingung',\n value: 'Wert',\n apply: 'Anwenden',\n saveSearch: 'Aktuelle Suche speichern',\n searchName: 'Name der Suche',\n useByDefault: 'Standardm\u00E4\u00DFig verwenden',\n deleteFavourite: '{name} l\u00F6schen',\n noFavourites: 'Noch keine gespeicherten Suchen.',\n opIs: 'ist',\n opIsNot: 'ist nicht',\n opContains: 'enth\u00E4lt',\n opGreater: 'gr\u00F6\u00DFer als',\n opLess: 'kleiner als',\n opSet: 'ist gesetzt',\n opNotSet: 'ist nicht gesetzt',\n yes: 'Ja',\n no: 'Nein',\n none: 'Ohne Angabe',\n loadMore: '{n} weitere anzeigen',\n },\n fr: {\n save: 'Enregistrer',\n edit: 'Modifier',\n done: 'Termin\u00E9',\n discard: 'Annuler les modifications',\n saving: 'Enregistrement\u2026',\n saved: 'Enregistr\u00E9',\n submit: 'Envoyer',\n next: 'Suivant',\n back: 'Retour',\n skip: 'Passer',\n steps: '\u00C9tapes',\n stepOf: '\u00C9tape {n} sur {total}',\n submitted: 'Merci. Vos r\u00E9ponses ont \u00E9t\u00E9 envoy\u00E9es.',\n submitAnother: 'Envoyer une autre r\u00E9ponse',\n draftFound: 'Vous avez des r\u00E9ponses non enregistr\u00E9es du {time}.',\n restore: 'Restaurer',\n discardDraft: 'Ignorer',\n ok: 'OK',\n cancel: 'Annuler',\n loading: 'Chargement\u2026',\n saveClose: 'Enregistrer et fermer',\n close: 'Fermer',\n dismiss: 'Masquer',\n retry: 'R\u00E9essayer',\n notSaved: 'Non enregistr\u00E9',\n notSent: 'Non envoy\u00E9',\n checkFields: '{what}. \u00C0 v\u00E9rifier : {fields}',\n offline: 'Le serveur est injoignable. Vos modifications sont toujours l\u00E0.',\n previousPage: 'Page pr\u00E9c\u00E9dente',\n nextPage: 'Page suivante',\n range: '{from}\u2013{to} / {total}',\n selected: '{n} s\u00E9lectionn\u00E9(s)',\n clearSelection: 'D\u00E9s\u00E9lectionner',\n selectAll: 'Tout s\u00E9lectionner',\n selectRecord: 'S\u00E9lectionner {name}',\n noRecords: 'Aucun enregistrement ne correspond.',\n loadFailed: 'Impossible de charger les enregistrements.',\n search: 'Rechercher\u2026',\n searchLabel: 'Rechercher',\n searchFor: 'Rechercher {field} : {text}',\n searchOptions: 'Options de recherche',\n filters: 'Filtres',\n groupBy: 'Regrouper par',\n favourites: 'Favoris',\n or: 'ou',\n removeFacet: 'Retirer {label}',\n addCustomFilter: 'Ajouter un filtre personnalis\u00E9',\n field: 'Champ',\n condition: 'Condition',\n value: 'Valeur',\n apply: 'Appliquer',\n saveSearch: 'Enregistrer la recherche',\n searchName: 'Nom de la recherche',\n useByDefault: 'Utiliser par d\u00E9faut',\n deleteFavourite: 'Supprimer {name}',\n noFavourites: 'Aucune recherche enregistr\u00E9e.',\n opIs: 'est',\n opIsNot: 'n\u2019est pas',\n opContains: 'contient',\n opGreater: 'sup\u00E9rieur \u00E0',\n opLess: 'inf\u00E9rieur \u00E0',\n opSet: 'est d\u00E9fini',\n opNotSet: 'n\u2019est pas d\u00E9fini',\n yes: 'Oui',\n no: 'Non',\n none: 'Aucun',\n loadMore: 'Afficher {n} de plus',\n },\n};\n\n/** English, kept under its old name. */\nexport const DEFAULT_LABELS: ViewerLabels = VIEWER_LABELS.en;\n", "import {\n createForm,\n checkPage,\n translatePage,\n wideColumns,\n type ButtonNode,\n type FieldNode,\n type Form,\n type FormOptions,\n type FormState,\n type JsonValue,\n type LayoutNode,\n type Page,\n type RecordId,\n type SectionNode,\n type SheetNode,\n type SlotNode,\n type TabsNode,\n type TextNode,\n type WizardNode,\n type Locale,\n MESSAGES,\n} from '@fieldia/core';\nimport { browserPreferences, createWidget, drawIcon, installStyles, WIDGET_LABELS, type IconSet, type PreferenceStore, type WidgetFactory } from '@fieldia/widgets';\nimport { pageDialogs } from './related';\nimport { listView } from './list';\n\nexport type Skin = 'underline' | 'outlined';\n\nimport { VIEWER_LABELS, type ViewerLabels } from './labels';\nexport { VIEWER_LABELS, DEFAULT_LABELS, type ViewerLabels } from './labels';\n\n/** Fill a slot with the app's own content. Return a function to clean up. */\nexport type SlotRenderer = (element: HTMLElement, context: { form: Form; name: string }) => void | (() => void);\n\nexport interface ViewerOptions extends Omit<FormOptions, 'page'> {\n page: Page;\n /** A form made elsewhere, to share one record between two views. */\n form?: Form;\n skin?: Skin;\n /** Widgets that replace or add to the built-in ones, by `type` or `type.widget`. */\n widgets?: Record<string, WidgetFactory>;\n slots?: Record<string, SlotRenderer>;\n /** The page's language: viewer labels, validation messages and widget words. Arabic runs right to left. */\n locale?: Locale;\n /** Labels that win over the language's defaults. */\n labels?: Partial<ViewerLabels>;\n dir?: 'ltr' | 'rtl';\n /** How to ask before a button with `confirm` runs. Defaults to a small dialog. */\n confirm?: (message: string) => Promise<boolean>;\n /** Where a person's choices about the page's look are kept, such as a table's columns. The browser's storage by default. */\n preferences?: PreferenceStore;\n /** False when something around the page saves it, such as a dialog: the page's own Save, Discard and Submit stay hidden. */\n showActions?: boolean;\n /**\n * Pages for the models links point to, so a link can show its record in a\n * dialog: Create and edit\u2026, and the button that opens the linked record.\n */\n relatedPages?: Record<string, Page> | ((model: string) => Page | null | undefined);\n /**\n * The app's own icons, or replacements for Fieldia's, by the name a page\n * gives them: the inside of a 24\u00D724 SVG, drawn with lines in the text colour.\n */\n icons?: IconSet;\n /**\n * Keys around the fields. Ctrl+Enter (Cmd+Enter on a Mac) saves, from\n * wherever the cursor is, unless `saveWithCtrlEnter` is false. With\n * `enterMovesToNext`, Enter moves to the next field instead of sending the form.\n */\n keys?: { saveWithCtrlEnter?: boolean; enterMovesToNext?: boolean };\n /** A \u2713 by a field's label once someone has filled it in and it would pass its checks. */\n showValid?: boolean;\n /** Where a save's progress shows: beside Save (the default), as a toast in a corner, or as a bar across the top. */\n saveStatus?: 'inline' | 'toast' | 'bar';\n /** Show the whole form read-only: every field locked, no Save. Buttons still run. */\n readonly?: boolean;\n /** An Edit button that unlocks a read-only form, and a Done that saves and locks it again. */\n editSwitch?: boolean;\n /**\n * The app's own translator, for apps that keep translations by text or by\n * key: every word of the page goes through it. Record data never does.\n */\n translate?: (text: string) => string;\n /** A list page: a row was opened, by a click or by Enter. The app shows the record. */\n onOpenRecord?: (id: RecordId) => void;\n}\n\nexport interface ViewerHandle {\n readonly form: Form;\n readonly element: HTMLElement;\n setSkin(skin: Skin): void;\n /** Save the record, or take the focus to the first problem when the form refuses. */\n save(): Promise<boolean>;\n /** Check the form without saving, taking the focus to the first problem. */\n check(): boolean;\n /** Lock or unlock the whole form. */\n setReadonly(readonly: boolean): void;\n isReadonly(): boolean;\n destroy(): void;\n}\n\ntype Updater = (state: FormState) => void;\n\nlet mounts = 0;\n\n/**\n * Render a page into `host` and keep it in step with its form. Plain DOM: the\n * React, Angular and Vue bindings are thin shells around this function.\n * Throws when the page does not validate, listing every problem.\n */\nexport function mountViewer(host: HTMLElement, options: ViewerOptions): ViewerHandle {\n const doc = host.ownerDocument;\n // The quick check of names and conditions: the full one, with its validation library, belongs where pages are made.\n const checked = checkPage(options.page);\n if (!checked.ok) {\n throw new Error(`This page cannot be shown:\\n${checked.issues.map((i) => ` ${i.path}: ${i.message}`).join('\\n')}`);\n }\n const page = options.translate ? translatePage(checked.page, options.translate) : checked.page;\n const locale = options.locale ?? 'en';\n const preferences = options.preferences ?? browserPreferences();\n const dialogs = pageDialogs(options);\n const ownsForm = !options.form;\n const form = options.form ?? createForm({ ...options, page, messages: options.messages ?? MESSAGES[locale] });\n const labels: ViewerLabels = { ...VIEWER_LABELS[locale], ...options.labels };\n const widgetLabels = WIDGET_LABELS[locale];\n const dir = options.dir ?? (locale === 'ar' ? 'rtl' : undefined);\n const prefix = `fd${++mounts}`;\n const updaters: Updater[] = [];\n const cleanups: (() => void)[] = [];\n const uid = (id: string) => `${prefix}-${id.replace(/[^A-Za-z0-9_-]/g, '_')}`;\n const fill = (template: string, values: Record<string, string | number>) =>\n template.replace(/\\{(\\w+)\\}/g, (_, key: string) => String(values[key] ?? ''));\n\n installStyles(doc);\n\n function el<K extends keyof HTMLElementTagNameMap>(tag: K, attrs: Record<string, string | undefined> = {}, ...children: (Node | string)[]) {\n const node = doc.createElement(tag);\n for (const [name, value] of Object.entries(attrs)) if (value !== undefined) node.setAttribute(name, value);\n node.append(...children);\n return node;\n }\n\n /** Words with the icon a page names before them, when there is such an icon. */\n function withIcon(name: string | undefined, text: string): (Node | string)[] {\n const icon = drawIcon(doc, name, options.icons);\n return icon ? [icon, text] : [text];\n }\n\n const root = el('form', { class: 'fd-form', novalidate: '', 'data-fd-skin': options.skin ?? 'underline', dir, lang: options.locale, 'data-max-width': page.maxWidth });\n const confirm = options.confirm ?? dialogConfirm;\n\n // ---- the parts -------------------------------------------------------\n\n function fieldItem(node: FieldNode): HTMLElement {\n const def = page.fields[node.field];\n const id = uid(node.id);\n const wrapper = el('div', { class: 'fd-field', 'data-node': node.id, 'data-field': node.field, 'data-type': def.type });\n if (node.colspan) wrapper.style.setProperty('--fd-span', String(node.colspan));\n const label = el('label', { class: 'fd-label', id: `${id}-label`, for: id }, node.label ?? def.label);\n // The \u2713 of a field filled in right; never on a yes/no box, a table or a file, where it would say nothing.\n const mark = options.showValid && !NO_VALID_MARK.has(def.type) ? drawIcon(doc, 'check') : null;\n if (mark) {\n mark.classList.add('fd-valid-mark');\n label.append(mark);\n }\n const widget = createWidget({ form, name: node.field, field: def, node, id, document: doc, labels: widgetLabels, preferences, locale, dialogs }, options.widgets);\n if (!['INPUT', 'SELECT', 'TEXTAREA'].includes(widget.element.tagName)) {\n // `for` stays: a custom field that puts the id on its own input is\n // labelled natively. Only a wrapper with a role (a radio group, say) may\n // carry a name; ARIA forbids naming a plain div or span.\n if (widget.element.getAttribute('role')) widget.element.setAttribute('aria-labelledby', label.id);\n label.addEventListener('click', () => widget.focus());\n }\n const helpText = node.help ?? def.help;\n const help = helpText ? el('div', { class: 'fd-help', id: `${id}-help` }, helpText) : null;\n // Not an alert of its own: a refused save is announced once, naming every field to look at.\n const error = el('div', { class: 'fd-error', id: `${id}-error`, hidden: '' });\n // A warning from the data source's onchange, beside the field whose change brought it.\n const warning = el('div', { class: 'fd-warning', role: 'status', hidden: '' });\n wrapper.append(label, widget.element, ...(help ? [help] : []), error, warning);\n if (widget.destroy) cleanups.push(() => widget.destroy?.());\n\n updaters.push((state) => {\n const shown = form.node(node.id);\n wrapper.hidden = shown.invisible;\n wrapper.classList.toggle('fd-required', shown.required);\n const message = state.errors[node.field];\n error.hidden = !message;\n error.textContent = message ?? '';\n const warned = state.warning && state.warningField === node.field ? state.warning : '';\n warning.hidden = !warned;\n warning.textContent = warned;\n if (mark) {\n const value = state.values[node.field];\n const filled = value !== null && value !== undefined && value !== '' && !(Array.isArray(value) && !value.length);\n const valid = !shown.readonly && !message && filled && state.dirty.includes(node.field) && form.problem(node.field) === null;\n wrapper.classList.toggle('fd-valid', valid);\n mark.toggleAttribute('hidden', !valid);\n }\n widget.update({\n value: state.values[node.field],\n values: state.values,\n readonly: shown.readonly || locked,\n required: shown.required,\n invalid: !!message,\n describedBy: [help?.id, message ? error.id : undefined].filter(Boolean).join(' ') || undefined,\n });\n });\n return wrapper;\n }\n\n function hideWhen(element: HTMLElement, id: string) {\n updaters.push(() => {\n element.hidden = form.node(id).invisible;\n });\n }\n\n function buttonItem(node: ButtonNode): HTMLElement {\n const button = el('button', { type: 'button', class: `fd-button fd-button-${node.style ?? 'secondary'}`, 'data-node': node.id }, ...withIcon(node.icon, node.label));\n button.addEventListener('click', async () => {\n if (node.confirm && !(await confirm(node.confirm))) return;\n await form.runAction(node.id);\n });\n hideWhen(button, node.id);\n return button;\n }\n\n function textItem(node: TextNode): HTMLElement {\n const style = node.style ?? 'paragraph';\n const element = el(style === 'heading' ? 'h3' : 'p', { class: `fd-text-${style}`, 'data-node': node.id }, node.text);\n hideWhen(element, node.id);\n return element;\n }\n\n function slotItem(node: SlotNode): HTMLElement {\n const element = el('div', { class: 'fd-slot', 'data-slot': node.name, 'data-node': node.id });\n const cleanup = options.slots?.[node.name]?.(element, { form, name: node.name });\n if (cleanup) cleanups.push(cleanup);\n hideWhen(element, node.id);\n return element;\n }\n\n function grid(children: LayoutNode[], columns: SectionNode['columns'] = 1): HTMLElement {\n const box = el('div', { class: 'fd-grid' });\n box.style.setProperty('--fd-columns', String(wideColumns(columns)));\n // Counts given for the narrower widths replace the skin's own stacking there.\n if (typeof columns === 'object') {\n for (const width of ['medium', 'narrow'] as const) {\n const count = columns[width];\n if (count === undefined) continue;\n box.setAttribute(`data-columns-${width}`, String(count));\n box.style.setProperty(`--fd-columns-${width}`, String(count));\n }\n }\n box.append(...children.map(item));\n return box;\n }\n\n /** Folded sections, and how to open each: a problem inside one has to be seen. */\n const folds = new Map<HTMLElement, () => void>();\n\n function sectionItem(node: SectionNode): HTMLElement {\n const section = el('fieldset', { class: 'fd-section', 'data-node': node.id });\n const description = node.description ? el('p', { class: 'fd-section-description' }, node.description) : null;\n const content = grid(node.children, node.columns);\n if (node.title && node.collapsible) {\n content.id = uid(`${node.id}-content`);\n const toggle = el(\n 'button',\n { type: 'button', class: 'fd-section-toggle', 'aria-controls': content.id },\n el('span', { class: 'fd-section-chevron', 'aria-hidden': 'true' }),\n ...withIcon(node.icon, node.title)\n );\n let open = node.collapsed !== true;\n const show = (next: boolean) => {\n open = next;\n toggle.setAttribute('aria-expanded', String(open));\n content.hidden = !open;\n if (description) description.hidden = !open;\n section.classList.toggle('fd-section-folded', !open);\n };\n toggle.addEventListener('click', () => show(!open));\n folds.set(section, () => show(true));\n show(open);\n section.append(el('legend', { class: 'fd-section-title' }, toggle));\n } else if (node.title) {\n section.append(el('legend', { class: 'fd-section-title' }, ...withIcon(node.icon, node.title)));\n }\n if (description) section.append(description);\n section.append(content);\n hideWhen(section, node.id);\n return section;\n }\n\n function tabsItem(node: TabsNode): HTMLElement {\n const box = el('div', { class: 'fd-tabs', 'data-node': node.id });\n const list = el('div', { class: 'fd-tablist', role: 'tablist' });\n // The tab someone picked. Until they pick, the first visible tab is open \u2014\n // a tab hidden while the record loads must not leave its neighbour open.\n let picked: string | null = null;\n let active = node.children[0].id;\n const parts = node.children.map((tab) => {\n const tabId = uid(`${tab.id}-tab`);\n const panelId = uid(`${tab.id}-panel`);\n const button = el('button', { type: 'button', class: 'fd-tab', role: 'tab', id: tabId, 'aria-controls': panelId, 'data-node': tab.id }, ...withIcon(tab.icon, tab.label));\n const panel = el('div', { class: 'fd-tabpanel', role: 'tabpanel', id: panelId, 'aria-labelledby': tabId }, grid(tab.children));\n button.addEventListener('click', () => {\n picked = active = tab.id;\n render(form.getState());\n });\n list.append(button);\n return { tab, button, panel };\n });\n list.addEventListener('keydown', (event) => {\n const shown = parts.filter((p) => !p.button.hidden);\n const at = shown.findIndex((p) => p.tab.id === active);\n const move = { ArrowRight: 1, ArrowLeft: -1, Home: -at, End: shown.length - 1 - at }[event.key];\n if (move === undefined || at === -1) return;\n event.preventDefault();\n const rtl = root.getAttribute('dir') === 'rtl' && (event.key === 'ArrowRight' || event.key === 'ArrowLeft');\n const next = shown[(at + (rtl ? -move : move) + shown.length) % shown.length];\n picked = active = next.tab.id;\n render(form.getState());\n next.button.focus();\n });\n box.append(list, ...parts.map((p) => p.panel));\n updaters.push(() => {\n box.hidden = form.node(node.id).invisible;\n const shown = parts.filter((p) => !form.node(p.tab.id).invisible);\n const keep = picked !== null && shown.some((p) => p.tab.id === picked);\n if (keep) active = picked as string;\n else if (shown.length) active = shown[0].tab.id;\n for (const p of parts) {\n const selected = p.tab.id === active;\n p.button.hidden = !shown.includes(p);\n p.button.setAttribute('aria-selected', String(selected));\n p.button.tabIndex = selected ? 0 : -1;\n p.panel.hidden = !selected;\n }\n });\n return box;\n }\n\n function item(node: LayoutNode): HTMLElement {\n switch (node.type) {\n case 'field':\n return fieldItem(node);\n case 'button':\n return buttonItem(node);\n case 'text':\n return textItem(node);\n case 'slot':\n return slotItem(node);\n case 'section':\n return sectionItem(node);\n case 'tabs':\n return tabsItem(node);\n }\n }\n\n // ---- shared chrome ----------------------------------------------------------\n\n /** The whole form locked: every field read-only, no Save; buttons still run. */\n let locked = options.readonly === true;\n // Edit unlocks; Done saves what changed first, and locks only once that is saved.\n const editSwitch = options.editSwitch ? el('button', { type: 'button', class: 'fd-button fd-edit-switch' }) : null;\n editSwitch?.addEventListener('click', async () => {\n if (!locked) {\n if (form.getState().dirty.length) {\n const saved = await form.save();\n if (!saved) {\n if (!form.getState().saveProblem) announce(checkText(form.getState()));\n focusFirstProblem();\n return;\n }\n }\n locked = true;\n } else locked = false;\n root.toggleAttribute('data-readonly', locked);\n render(form.getState());\n });\n root.toggleAttribute('data-readonly', locked);\n updaters.push(() => {\n if (!editSwitch) return;\n editSwitch.textContent = locked ? labels.edit : labels.done;\n editSwitch.classList.toggle('fd-button-primary', locked);\n });\n\n // The status says its words alone, so a screen reader hears them; Retry sits beside it.\n const statusText = el('div', { class: 'fd-status', role: 'status', 'aria-live': 'polite' });\n const retry = el('button', { type: 'button', class: 'fd-button fd-button-link fd-retry', hidden: '' }, labels.retry);\n retry.addEventListener('click', () => void submitOrSave());\n const status = el('div', { class: 'fd-status-box' }, statusText, retry);\n const notDone = () => (page.data.kind === 'responses' ? labels.notSent : labels.notSaved);\n /** \"Not saved. Check: Email, Phone\": the fields with a problem, in the order they show. */\n function checkText(state: FormState): string {\n const names: string[] = [];\n for (const key of Object.keys(state.errors)) {\n const field = key.split('.')[0];\n const shown = root.querySelector(`.fd-field[data-field=\"${field}\"]:not([hidden]) > .fd-label`);\n const name = shown?.firstChild?.textContent ?? page.fields[field]?.label ?? field;\n if (!names.includes(name)) names.push(name);\n }\n const inOrder = [...root.querySelectorAll('.fd-field[data-field] > .fd-label')].map((label) => label.firstChild?.textContent ?? '');\n names.sort((a, b) => (inOrder.indexOf(a) + 1 || Infinity) - (inOrder.indexOf(b) + 1 || Infinity));\n return names.length ? fill(labels.checkFields, { what: notDone(), fields: names.join(', ') }) : notDone();\n }\n let quietTimer: ReturnType<typeof setTimeout> | undefined;\n updaters.push((state) => {\n const problem = state.saveProblem;\n const text =\n state.status === 'saving' ? labels.saving\n : state.status === 'saved' ? labels.saved\n : state.status === 'loading' ? labels.loading\n : state.status === 'error' && problem ? (problem.kind === 'fields' ? checkText(state) : problem.kind === 'other' ? problem.message : notDone())\n : state.status === 'error' ? state.error ?? ''\n : '';\n statusText.textContent = text;\n retry.hidden = !(state.status === 'error' && problem?.kind === 'other');\n statusText.classList.toggle('fd-status-error', state.status === 'error');\n statusText.classList.toggle('fd-status-saved', state.status === 'saved');\n // A toast shows while there is something to say, and lets \"Saved\" go after a moment.\n if (options.saveStatus === 'toast') {\n clearTimeout(quietTimer);\n status.hidden = !text;\n if (state.status === 'saved') quietTimer = setTimeout(() => (status.hidden = true), 2500);\n }\n });\n\n // A save the network failed: a banner over the page, with Retry.\n const bannerRetry = el('button', { type: 'button', class: 'fd-button fd-retry' }, labels.retry);\n bannerRetry.addEventListener('click', () => void submitOrSave());\n const banner = el('div', { class: 'fd-banner fd-tone-warning', role: 'alert', hidden: '' }, el('span', { class: 'fd-banner-text' }, labels.offline), bannerRetry);\n /** Said at once to a screen reader: why a save or send did not go through. */\n const announcer = el('div', { class: 'fd-announce', role: 'alert', 'aria-live': 'assertive' });\n function announce(text: string) {\n announcer.textContent = '';\n setTimeout(() => (announcer.textContent = text), 0);\n }\n // Each new reason a save was refused, from Save or from autosave, is shown where it belongs.\n let seenProblem: FormState['saveProblem'] = null;\n updaters.push((state) => {\n if (state.saveProblem === seenProblem) return;\n seenProblem = state.saveProblem;\n banner.hidden = seenProblem?.kind !== 'network';\n if (!seenProblem) return;\n if (seenProblem.kind === 'rule') void dialogConfirm(seenProblem.message, false);\n else if (seenProblem.kind === 'fields') announce(checkText(state));\n else if (seenProblem.kind === 'other') announce(seenProblem.message);\n });\n\n const draft = el('div', { class: 'fd-draft', hidden: '' });\n const draftText = el('span');\n const restore = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.restore);\n const discardDraft = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.discardDraft);\n restore.addEventListener('click', () => form.restoreDraft());\n discardDraft.addEventListener('click', () => form.discardDraft());\n draft.append(draftText, restore, discardDraft);\n updaters.push((state) => {\n draft.hidden = !state.draft;\n if (state.draft) draftText.textContent = fill(labels.draftFound, { time: new Date(state.draft.savedAt).toLocaleString() });\n });\n\n function focusFirstProblem() {\n const invalid = root.querySelector<HTMLElement>('[aria-invalid=\"true\"]');\n if (!invalid) return;\n for (let folded = invalid.closest<HTMLElement>('.fd-section-folded'); folded; folded = folded.parentElement?.closest<HTMLElement>('.fd-section-folded') ?? null) {\n folds.get(folded)?.();\n }\n // A widget that knows where its problem is (a cell of a grid) takes the focus there itself.\n if (!invalid.dispatchEvent(new CustomEvent('fd-focus-problem', { cancelable: true }))) return;\n const target = invalid.matches('input, select, textarea, button') ? invalid : invalid.querySelector<HTMLElement>('input, select, textarea, button');\n target?.focus();\n }\n\n const done = el('div', { class: 'fd-done', hidden: '' }, el('p', { class: 'fd-done-title' }, labels.submitted));\n const again = el('button', { type: 'button', class: 'fd-button' }, labels.submitAnother);\n done.append(again);\n const content = el('div', { class: 'fd-content' });\n\n async function submitOrSave() {\n const saved = await form.save();\n if (!saved) {\n // Stopped by the page's own checks: say which fields; a refused save says so above.\n if (!form.getState().saveProblem) announce(checkText(form.getState()));\n focusFirstProblem();\n return;\n }\n if (page.data.kind === 'responses') {\n content.hidden = true;\n done.hidden = false;\n }\n }\n again.addEventListener('click', () => {\n form.reset();\n content.hidden = false;\n done.hidden = true;\n });\n\n function pageHead(): HTMLElement | null {\n if (!page.title && !page.description) return null;\n const head = el('header', { class: 'fd-page-head' });\n if (page.title) head.append(el('h1', { class: 'fd-page-title' }, page.title));\n if (page.description) head.append(el('p', { class: 'fd-page-description' }, page.description));\n return head;\n }\n\n // ---- the four page layouts ---------------------------------------------------\n\n function sectionsLayout(node: { id: string; children: LayoutNode[] }): HTMLElement {\n const box = el('div', { class: 'fd-sections', 'data-node': node.id }, ...node.children.map(item));\n const action = el('button', { type: 'submit', class: 'fd-button fd-button-primary' }, page.data.kind === 'responses' ? labels.submit : labels.save);\n const actions = el('div', { class: 'fd-actions fd-actions-end' }, status, action);\n if (page.data.kind === 'record') {\n // A record offers Save and Discard once something changes, the same as on a sheet.\n const discard = el('button', { type: 'button', class: 'fd-button' }, labels.discard);\n discard.addEventListener('click', () => form.reset());\n actions.insertBefore(discard, action);\n updaters.push((state) => {\n const dirty = state.dirty.length > 0 && state.status !== 'saving' && !locked;\n action.hidden = !dirty;\n discard.hidden = !dirty;\n });\n } else updaters.push(() => (action.hidden = locked));\n if (editSwitch) actions.prepend(editSwitch);\n if (options.showActions === false) return el('div', {}, box);\n if (page.actionsPosition === 'top') {\n actions.classList.add('fd-actions-top');\n return el('div', {}, actions, box);\n }\n return el('div', {}, box, actions);\n }\n\n function wizardLayout(node: WizardNode): HTMLElement {\n const box = el('div', { class: 'fd-wizard', 'data-node': node.id });\n const progressText = el('div', { class: 'fd-progress-text' });\n const bar = el('span');\n box.append(el('div', { class: 'fd-progress' }, progressText, el('div', { class: 'fd-progress-bar' }, bar)));\n // A clickable wizard lists its steps: back to any, forward past those that are complete.\n const list = node.clickable ? el('ol', { class: 'fd-steps-list' }) : null;\n const stepButtons = new Map<string, HTMLButtonElement>();\n if (list) {\n for (const step of node.children) {\n const go = el('button', { type: 'button', class: 'fd-step-link' }, ...withIcon(step.icon, step.label));\n go.addEventListener('click', () => {\n if (form.goTo(step.id)) focusStep();\n else focusFirstProblem();\n });\n stepButtons.set(step.id, go);\n list.append(el('li', {}, go));\n }\n box.append(el('nav', { class: 'fd-steps', 'aria-label': labels.steps }, list));\n }\n const panels = node.children.map((step) => {\n const panel = el('section', { class: 'fd-step', 'data-node': step.id, 'aria-labelledby': uid(`${step.id}-title`) });\n panel.append(el('h2', { class: 'fd-step-title', id: uid(`${step.id}-title`) }, ...withIcon(step.icon, step.label)));\n if (step.description) panel.append(el('p', { class: 'fd-section-description' }, step.description));\n panel.append(grid(step.children));\n box.append(panel);\n return { step, panel };\n });\n const back = el('button', { type: 'button', class: 'fd-button' }, node.backLabel ?? labels.back);\n const skip = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.skip);\n const forward = el('button', { type: 'submit', class: 'fd-button fd-button-primary' });\n box.append(el('div', { class: 'fd-wizard-nav' }, back, el('span', { class: 'fd-spacer' }), status, skip, forward));\n back.addEventListener('click', () => {\n if (form.back()) focusStep();\n });\n skip.addEventListener('click', () => {\n if (form.skip()) focusStep();\n });\n const isLast = () => {\n const steps = form.steps();\n return steps.indexOf(form.getState().step ?? '') === steps.length - 1;\n };\n wizardForward = async () => {\n if (isLast()) return submitOrSave();\n if (form.next()) focusStep();\n else focusFirstProblem();\n };\n function focusStep() {\n const current = panels.find((p) => p.step.id === form.getState().step);\n current?.panel.querySelector<HTMLElement>('input, select, textarea, [role=radio]')?.focus();\n }\n updaters.push((state) => {\n const steps = form.steps();\n const index = Math.max(0, steps.indexOf(state.step ?? ''));\n progressText.textContent = fill(labels.stepOf, { n: index + 1, total: steps.length });\n bar.style.width = `${((index + 1) / Math.max(1, steps.length)) * 100}%`;\n for (const { step, panel } of panels) panel.hidden = step.id !== state.step;\n const last = index === steps.length - 1;\n back.hidden = index === 0;\n skip.hidden = last || !node.children.find((step) => step.id === state.step)?.optional;\n forward.textContent = last ? node.finishLabel ?? labels.submit : node.nextLabel ?? labels.next;\n for (const [id, go] of stepButtons) {\n const at = steps.indexOf(id);\n (go.parentElement as HTMLElement).hidden = at === -1;\n go.classList.toggle('fd-step-done', at !== -1 && at < index);\n go.classList.toggle('fd-step-skipped', state.skipped.includes(id));\n if (id === state.step) go.setAttribute('aria-current', 'step');\n else go.removeAttribute('aria-current');\n }\n });\n return box;\n }\n\n function sheetLayout(node: SheetNode): HTMLElement {\n const pageBox = el('div', { class: 'fd-sheet-page', 'data-node': node.id });\n const actions = el('div', { class: 'fd-actions' });\n const save = el('button', { type: 'submit', class: 'fd-button fd-button-primary' }, labels.save);\n const discard = el('button', { type: 'button', class: 'fd-button' }, labels.discard);\n discard.addEventListener('click', () => form.reset());\n // Save and Discard lead the header bar, or close the sheet when the page puts them at its foot.\n const atFoot = page.actionsPosition === 'bottom';\n const foot = el('div', { class: 'fd-actions fd-actions-end fd-sheet-foot' });\n if (options.showActions === false) actions.append(...(node.buttons ?? []).map(buttonItem));\n else if (atFoot) {\n actions.append(...(node.buttons ?? []).map(buttonItem));\n foot.append(status, discard, save);\n } else actions.append(save, discard, ...(node.buttons ?? []).map(buttonItem), status);\n // The Edit switch leads the header bar, before Save and the record's own buttons.\n if (editSwitch && options.showActions !== false) actions.prepend(editSwitch);\n updaters.push((state) => {\n const dirty = state.dirty.length > 0 && state.status !== 'saving' && !locked;\n save.hidden = !dirty;\n discard.hidden = !dirty;\n });\n const header = el('div', { class: 'fd-header' }, actions);\n const underTitle = node.statusbar?.position === 'title';\n if (node.statusbar && !underTitle) header.append(statusbar(node.statusbar));\n\n const card = el('div', { class: 'fd-card' });\n if (node.ribbon) {\n const ribbon = el('div', { class: `fd-ribbon fd-tone-${node.ribbon.tone ?? 'muted'}`, 'data-node': node.ribbon.id }, node.ribbon.label);\n hideWhen(ribbon, node.ribbon.id);\n // The ribbon is clipped to the card's corner by its own frame, so the card itself never clips: lists open past it.\n card.append(el('div', { class: 'fd-ribbon-frame' }, ribbon));\n }\n if (node.statButtons?.length) {\n const stats = el('div', { class: 'fd-stats' });\n for (const stat of node.statButtons) {\n const value = el('span', { class: 'fd-stat-value' });\n const icon = drawIcon(doc, stat.icon, options.icons);\n const words = el('span', { class: 'fd-stat-words' }, value, el('span', { class: 'fd-stat-label' }, stat.label));\n const button = el('button', { type: 'button', class: 'fd-stat', 'data-node': stat.id }, ...(icon ? [icon, words] : [words]));\n button.addEventListener('click', () => void form.runAction(stat.id));\n updaters.push((state) => {\n button.hidden = form.node(stat.id).invisible;\n const count = stat.field ? state.values[stat.field] : null;\n value.textContent = count === null || count === undefined ? '' : String(count);\n });\n stats.append(button);\n }\n card.append(stats);\n }\n for (const alert of node.alerts ?? []) {\n const box = el('div', { class: `fd-alert fd-tone-${alert.tone ?? 'info'}`, role: 'status', 'data-node': alert.id }, el('span', { class: 'fd-alert-message' }, alert.message));\n if (alert.dismissible) {\n // Closed, it stays closed while the page is open, whatever its condition does.\n let dismissed = false;\n const close = el('button', { type: 'button', class: 'fd-alert-close', 'aria-label': labels.dismiss }, '\u00D7');\n close.addEventListener('click', () => {\n dismissed = true;\n box.hidden = true;\n });\n box.append(close);\n updaters.push(() => {\n box.hidden = dismissed || form.node(alert.id).invisible;\n });\n } else hideWhen(box, alert.id);\n card.append(box);\n }\n if (node.badges?.length) {\n const badges = el('div', { class: 'fd-badges' });\n for (const badge of node.badges) {\n const chip = el('span', { class: `fd-badge fd-tone-${badge.tone ?? 'muted'}`, 'data-node': badge.id }, ...withIcon(badge.icon, badge.label));\n hideWhen(chip, badge.id);\n badges.append(chip);\n }\n updaters.push(() => {\n badges.hidden = [...badges.children].every((chip) => (chip as HTMLElement).hidden);\n });\n card.append(badges);\n }\n if (node.title) {\n const title = el('div', { class: 'fd-title' });\n if (node.title.above?.length) title.append(el('div', { class: 'fd-title-above' }, ...node.title.above.map(fieldItem)));\n title.append(fieldItem({ type: 'field', id: '#title', field: node.title.field, placeholder: node.title.placeholder }));\n if (node.title.subtitleField) title.append(fieldItem({ type: 'field', id: '#subtitle', field: node.title.subtitleField }));\n if (node.title.below?.length) title.append(el('div', { class: 'fd-title-below' }, ...node.title.below.map(fieldItem)));\n const row = el('div', { class: 'fd-title-row' }, title);\n if (node.title.avatarField) {\n const avatar = fieldItem({ type: 'field', id: '#avatar', field: node.title.avatarField });\n avatar.classList.add('fd-avatar');\n row.append(avatar);\n }\n card.append(row);\n }\n if (node.statusbar && underTitle) card.append(el('div', { class: 'fd-title-statusbar' }, statusbar(node.statusbar)));\n card.append(grid(node.children));\n if (atFoot && options.showActions !== false) {\n card.append(foot);\n updaters.push((state) => {\n foot.hidden = state.dirty.length === 0 && !statusText.textContent;\n });\n }\n\n const layout = el('div', { class: 'fd-sheet-layout' }, card);\n if (node.sidePanel) {\n layout.classList.add('fd-has-side');\n layout.append(el('aside', { class: 'fd-side' }, slotItem(node.sidePanel)));\n }\n pageBox.append(header, layout);\n return pageBox;\n }\n\n /** The sheet header's statusbar: the same widget a form can place anywhere. */\n function statusbar(config: NonNullable<SheetNode['statusbar']>): HTMLElement {\n const def = page.fields[config.field];\n const barOptions: { [key: string]: JsonValue } = { clickable: config.clickable === true };\n if (config.visibleStates) barOptions['visibleStates'] = config.visibleStates;\n const node: FieldNode = { type: 'field', id: '#statusbar', field: config.field, widget: 'statusbar', options: barOptions };\n const widget = createWidget(\n { form, name: config.field, field: def, node, id: uid('statusbar'), document: doc, labels: widgetLabels, preferences, locale, dialogs },\n options.widgets\n );\n updaters.push((state) =>\n widget.update({ value: state.values[config.field], values: state.values, readonly: form.node('#statusbar').readonly || locked, required: false, invalid: false })\n );\n return widget.element;\n }\n\n let wizardForward: (() => Promise<void>) | null = null;\n\n const layout = page.layout;\n let body: HTMLElement;\n if (layout.type === 'sheet') body = sheetLayout(layout);\n else if (layout.type === 'wizard') body = wizardLayout(layout);\n else if (layout.type === 'tabs') body = sectionsLayout({ id: `${layout.id}-page`, children: [layout] });\n else if (layout.type === 'list') {\n const list = listView({\n page,\n node: layout,\n form,\n dataSource: options.dataSource,\n doc,\n el,\n labels,\n locale,\n fill,\n confirm,\n withIcon,\n uid,\n icons: options.icons,\n preferences,\n onOpenRecord: options.onOpenRecord,\n });\n cleanups.push(list.destroy);\n body = list.element;\n }\n else body = sectionsLayout(layout);\n\n const head = layout.type === 'sheet' ? null : pageHead();\n content.append(...(head ? [head] : []), banner, draft, body);\n root.append(content, done, announcer);\n // The status leaves its place beside Save when the page wants it in a corner or across the top.\n if (options.saveStatus === 'toast') {\n status.classList.add('fd-toast');\n root.append(status);\n } else if (options.saveStatus === 'bar') {\n status.classList.add('fd-status-bar');\n content.prepend(status);\n }\n\n root.addEventListener('submit', (event) => {\n event.preventDefault();\n if (layout.type === 'list') return;\n if (wizardForward) void wizardForward();\n else void submitOrSave();\n });\n\n // ---- keys -------------------------------------------------------------------\n\n /** Text typed and not yet taken, such as a tag without its Enter, is taken now. */\n function commitTyping() {\n const active = doc.activeElement;\n if (active && root.contains(active) && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA')) {\n active.dispatchEvent(new Event('change', { bubbles: true }));\n }\n }\n\n /** The fields Enter can move between: on this page, shown, with a box to type or choose in, outside tables of lines. */\n function nextField(from: HTMLElement): HTMLElement | null {\n const fields = [...root.querySelectorAll<HTMLElement>('.fd-field')].filter(\n (field) => !field.closest('[hidden], [data-type=\"one2many\"] .fd-field, .fd-form-dialog') && !field.parentElement?.closest('[data-type=\"one2many\"]')\n );\n const here = from.closest('.fd-field');\n const after = fields.slice(fields.indexOf(here as HTMLElement) + 1);\n for (const field of after) {\n const control = field.querySelector<HTMLElement>('input:not([type=\"hidden\"]):not([readonly]):not([disabled]), select:not([disabled]), textarea:not([readonly]), [contenteditable=\"true\"]');\n if (control) return control;\n }\n return null;\n }\n\n root.addEventListener('keydown', (event) => {\n // A list has nothing to save, and its rows keep their own keys.\n if (event.isComposing || event.key !== 'Enter' || layout.type === 'list') return;\n // An app's own content in a slot, such as a chatter's composer, keeps its keys.\n if ((event.target as Element).closest('.fd-slot')) return;\n const keys = options.keys ?? {};\n if (event.ctrlKey || event.metaKey) {\n // Saves even after a field used the Enter (a tag box adding its tag); the grid keeps its own keys.\n if (keys.saveWithCtrlEnter === false || options.showActions === false) return;\n if ((event.target as Element).closest('.ag-root-wrapper')) return;\n event.preventDefault();\n commitTyping();\n if (wizardForward) void wizardForward();\n else void submitOrSave();\n return;\n }\n // A plain Enter a field used itself, such as picking from an open list, is the field's.\n if (event.defaultPrevented || !keys.enterMovesToNext || event.shiftKey || event.altKey) return;\n const from = event.target as HTMLElement;\n if (from.tagName !== 'INPUT' && from.tagName !== 'SELECT') return;\n if (from.closest('[data-type=\"one2many\"]')) return;\n if (['button', 'submit', 'reset', 'file'].includes((from as HTMLInputElement).type)) return;\n event.preventDefault();\n nextField(from)?.focus();\n });\n\n // ---- confirmation dialog -----------------------------------------------------\n\n /** A question with Cancel and OK, or with `withCancel` false a notice with OK alone. */\n function dialogConfirm(message: string, withCancel = true): Promise<boolean> {\n return new Promise((resolve) => {\n const text = el('p', { id: `${prefix}-confirm` }, message);\n const cancel = el('button', { type: 'button', class: 'fd-button' }, labels.cancel);\n const ok = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.ok);\n const dialog = el('div', { class: 'fd-dialog', role: 'alertdialog', 'aria-modal': 'true', 'aria-labelledby': text.id }, text, el('div', { class: 'fd-actions fd-actions-end' }, ...(withCancel ? [cancel, ok] : [ok])));\n const backdrop = el('div', { class: 'fd-dialog-backdrop' }, dialog);\n const close = (answer: boolean) => {\n backdrop.remove();\n resolve(answer);\n };\n cancel.addEventListener('click', () => close(false));\n ok.addEventListener('click', () => close(true));\n backdrop.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') close(false);\n });\n root.append(backdrop);\n ok.focus();\n });\n }\n\n // ---- go -------------------------------------------------------------------\n\n function render(state: FormState) {\n for (const update of updaters) update(state);\n }\n\n host.append(root);\n const unsubscribe = form.subscribe(render);\n render(form.getState());\n if (form.getState().status === 'idle') void form.load();\n\n return {\n form,\n element: root,\n setSkin(skin) {\n root.setAttribute('data-fd-skin', skin);\n },\n async save() {\n const saved = await form.save();\n if (!saved) focusFirstProblem();\n return saved;\n },\n check() {\n const valid = form.validate();\n if (!valid) focusFirstProblem();\n return valid;\n },\n setReadonly(readonly) {\n locked = readonly;\n root.toggleAttribute('data-readonly', locked);\n render(form.getState());\n },\n isReadonly: () => locked,\n destroy() {\n unsubscribe();\n for (const cleanup of cleanups) cleanup();\n root.remove();\n if (ownsForm) form.dispose();\n },\n };\n}\n\n/** Fields whose \u2713 would say nothing: a yes/no box is never wrong, a table or a file has its own look. */\nconst NO_VALID_MARK = new Set(['boolean', 'one2many', 'binary', 'image', 'html', 'json', 'properties']);\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * What the `<script>` bundle puts on `window.Fieldia`: everything a page with\n * no build step needs to show a form and handle what people enter.\n */\n// The runtime alone: the format's schemas and validation library stay out of a page with no build step.\nexport * from '../libs/core/src/runtime';\nexport * from '@fieldia/widgets';\nexport * from '@fieldia/viewer';\n\ndeclare const __FIELDIA_VERSION__: string;\n/** The version of @fieldia/viewer this bundle was built from. */\nexport const VERSION: string = __FIELDIA_VERSION__;\n", "/** Field names and kinds, apart from the schemas so code that runs a form never carries the validation library. */\n\n/** A field name: what expressions and layout nodes use to refer to a field. */\nexport const FIELD_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nexport const FIELD_TYPES = [\n 'char',\n 'text',\n 'html',\n 'integer',\n 'float',\n 'monetary',\n 'boolean',\n 'date',\n 'datetime',\n 'selection',\n 'binary',\n 'image',\n 'many2one',\n 'many2many',\n 'one2many',\n 'reference',\n 'properties',\n 'json',\n] as const;\n\nexport type FieldType = (typeof FIELD_TYPES)[number];\n", "import type { ColumnCount, ColumnsByWidth } from './layout';\n\n/** A section's columns at full width, whichever way they are written. */\nexport function wideColumns(columns: ColumnCount | ColumnsByWidth | undefined): ColumnCount {\n return typeof columns === 'object' ? columns.wide : columns ?? 1;\n}\n", "/** The page format version this build reads and writes. */\nexport const FORMAT_VERSION = '0.1' as const;\n", "/**\n * AST evaluator for modifiers, ported from the React form engine.\n *\n * Python semantics where the React version used JavaScript's: an empty list\n * or string is false, and an empty value is never smaller or larger than\n * anything \u2014 modifiers come from backends that think in Python.\n */\n\nimport type { ASTNode, BinaryOpNode, UnaryOpNode } from './parser';\n\n/**\n * Evaluate an AST node against a context object\n *\n * @param ast - The AST node to evaluate\n * @param context - Object containing field values\n * @returns The result of evaluation\n *\n * @example\n * const ast = { type: 'BinaryOp', operator: '==', left: {...}, right: {...} };\n * const context = { state: 'draft', amount: 100 };\n * evaluate(ast, context); // Returns boolean result\n */\nexport function evaluate(ast: ASTNode, context: Record<string, unknown>): unknown {\n switch (ast.type) {\n case 'BinaryOp':\n return evaluateBinaryOp(ast, context);\n\n case 'UnaryOp':\n return evaluateUnaryOp(ast, context);\n\n case 'Literal':\n return ast.value;\n\n case 'Identifier':\n return getNestedValue(context, ast.name);\n\n default:\n throw new Error(`Unknown AST node type: ${(ast as { type: string }).type}`);\n }\n}\n\n/**\n * Evaluate binary operations\n */\nfunction evaluateBinaryOp(node: BinaryOpNode, context: Record<string, unknown>): unknown {\n const left = normalize(evaluate(node.left, context));\n const right = normalize(evaluate(node.right, context));\n const operator = node.operator.toLowerCase();\n const ordered = left !== null && right !== null;\n\n switch (operator) {\n // Comparison operators\n case '==':\n return left === right;\n\n case '!=':\n case '<>':\n return left !== right;\n\n case '<':\n return ordered && (left as Comparable) < (right as Comparable);\n\n case '>':\n return ordered && (left as Comparable) > (right as Comparable);\n\n case '<=':\n return ordered && (left as Comparable) <= (right as Comparable);\n\n case '>=':\n return ordered && (left as Comparable) >= (right as Comparable);\n\n // In operators\n case 'in':\n return Array.isArray(right) && right.includes(left);\n\n case 'not in':\n return Array.isArray(right) && !right.includes(left);\n\n // Logical operators (use truthiness)\n case 'and':\n return truthy(left) && truthy(right);\n\n case 'or':\n return truthy(left) || truthy(right);\n\n default:\n throw new Error(`Unknown binary operator: ${node.operator}`);\n }\n}\n\n/**\n * Evaluate unary operations\n */\nfunction evaluateUnaryOp(node: UnaryOpNode, context: Record<string, unknown>): unknown {\n const operand = evaluate(node.operand, context);\n const operator = node.operator.toLowerCase();\n\n switch (operator) {\n case 'not':\n return !truthy(operand);\n\n default:\n throw new Error(`Unknown unary operator: ${node.operator}`);\n }\n}\n\n/** What `<` and `>` order: numbers with numbers, strings with strings. */\ntype Comparable = number | string;\n\n/** A missing value compares like None. */\nfunction normalize(value: unknown): unknown {\n return value === undefined ? null : value;\n}\n\n/** Python's truth test: empty lists, strings and objects, 0 and None are false. */\nexport function truthy(value: unknown): boolean {\n if (Array.isArray(value)) return value.length > 0;\n if (value !== null && typeof value === 'object') return Object.keys(value).length > 0;\n return Boolean(value);\n}\n\n/**\n * Get a nested value from an object using dot notation\n *\n * @param obj - The object to traverse\n * @param path - Dot-separated path (e.g., 'partner_id.country_id.name')\n * @returns The value at the path, or undefined if not found\n *\n * @example\n * getNestedValue({ a: { b: { c: 5 } } }, 'a.b.c') // Returns 5\n * getNestedValue({ a: null }, 'a.b.c') // Returns undefined\n */\nfunction getNestedValue(obj: unknown, path: string): unknown {\n const parts = path.split('.');\n let current: unknown = obj;\n\n for (const part of parts) {\n if (current === null || current === undefined) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n}\n", "/**\n * Tokenizer for modifier expressions.\n *\n * Ported from the React form engine, with one change in behaviour: a\n * character the language does not know is an error, not something to skip.\n * The React version dropped it silently, so `amount > -5` read as\n * `amount > 5` and `a && b` read as `a b`.\n */\n\nexport type TokenType =\n | 'IDENTIFIER' // Field names, including dotted notation (e.g., partner_id.country_id)\n | 'NUMBER' // Integer or float (e.g., 42, 3.14)\n | 'STRING' // Single or double quoted string (e.g., 'draft', \"draft\")\n | 'LIST' // List literal (e.g., ['draft', 'sent'])\n | 'OPERATOR' // Comparison operators (==, !=, <>, <, >, <=, >=, in, not in)\n | 'LOGICAL' // Logical operators (and, or, not)\n | 'CONSTANT' // True, False, None (and true, false, null)\n | 'PAREN'; // Parentheses ( )\n\nexport interface Token {\n type: TokenType;\n value: string;\n position: number;\n}\n\n/**\n * Tokenizes a Flectra modifier expression.\n *\n * @param expr - The expression string to tokenize\n * @returns Array of tokens\n *\n * @example\n * tokenize(\"state == 'draft'\")\n * // Returns: [\n * // { type: 'IDENTIFIER', value: 'state', position: 0 },\n * // { type: 'OPERATOR', value: '==', position: 1 },\n * // { type: 'STRING', value: \"'draft'\", position: 2 }\n * // ]\n */\n/** The words that are values, not field names. */\nexport const CONSTANTS: ReadonlyMap<string, boolean | null> = new Map<string, boolean | null>([\n ['True', true],\n ['False', false],\n ['None', null],\n ['true', true],\n ['false', false],\n ['null', null],\n]);\n\nexport function tokenize(expr: string): Token[] {\n const tokens: Token[] = [];\n if (!expr) return tokens;\n\n // Alternatives in priority order: \"not in\" before \"not\", operators of two\n // characters before one, a signed number before anything else that could\n // start with a digit. Sticky (`y`), so a position nothing matches is an\n // error instead of a gap.\n const token =\n /(\\(|\\)|==|!=|<=|>=|<>|<|>|not\\s+in\\b|in\\b|and\\b|or\\b|not\\b|\\[[^\\]]*\\]|'[^']*'|\"[^\"]*\"|-?\\d+\\.?\\d*|\\w+(?:\\.\\w+)*)/iy;\n const space = /\\s*/y;\n let at = 0;\n\n for (;;) {\n space.lastIndex = at;\n space.exec(expr);\n at = space.lastIndex;\n if (at >= expr.length) return tokens;\n\n token.lastIndex = at;\n const match = token.exec(expr);\n if (!match) {\n throw new Error(`Unexpected \"${expr[at]}\" at character ${at + 1} of: ${expr}`);\n }\n tokens.push({ type: getTokenType(match[0]), value: match[0], position: tokens.length });\n at = token.lastIndex;\n }\n}\n\n/**\n * Determines the type of a token based on its text value.\n */\nfunction getTokenType(text: string): TokenType {\n const lowerText = text.toLowerCase().trim();\n\n // Python's constants, and their JSON spellings\n if (CONSTANTS.has(text)) {\n return 'CONSTANT';\n }\n\n // Logical operators (case-insensitive)\n if (lowerText === 'and' || lowerText === 'or' || lowerText === 'not') {\n return 'LOGICAL';\n }\n\n // Comparison operators (case-insensitive for word operators)\n if (\n ['==', '!=', '<>', '<', '>', '<=', '>='].includes(text) ||\n lowerText === 'in' ||\n lowerText === 'not in'\n ) {\n return 'OPERATOR';\n }\n\n // Parentheses\n if (text === '(' || text === ')') {\n return 'PAREN';\n }\n\n // Lists (start with '[')\n if (text.startsWith('[')) {\n return 'LIST';\n }\n\n // Strings (start with ' or \")\n if (text.startsWith(\"'\") || text.startsWith('\"')) {\n return 'STRING';\n }\n\n // Numbers (matches integer or float, either sign)\n if (/^-?\\d+\\.?\\d*$/.test(text)) {\n return 'NUMBER';\n }\n\n // Default to identifier\n return 'IDENTIFIER';\n}\n", "/**\n * Expression parser for modifiers, ported from the React form engine.\n *\n * Recursive descent parser that converts tokens into an Abstract Syntax Tree (AST).\n * Implements Python-like operator precedence:\n * 1. OR (lowest precedence)\n * 2. AND\n * 3. NOT\n * 4. Comparison operators (==, !=, <, >, <=, >=, in, not in)\n * 5. Values/Identifiers (highest precedence)\n */\n\nimport { CONSTANTS, type Token } from './tokenizer';\n\n/**\n * AST Node Types\n */\nexport type ASTNode = BinaryOpNode | UnaryOpNode | LiteralNode | IdentifierNode;\n\nexport interface BinaryOpNode {\n type: 'BinaryOp';\n operator: string;\n left: ASTNode;\n right: ASTNode;\n}\n\nexport interface UnaryOpNode {\n type: 'UnaryOp';\n operator: string;\n operand: ASTNode;\n}\n\nexport interface LiteralNode {\n type: 'Literal';\n value: unknown;\n}\n\nexport interface IdentifierNode {\n type: 'Identifier';\n name: string;\n}\n\n/**\n * Recursive Descent Expression Parser\n */\nexport class ExpressionParser {\n private tokens: Token[];\n private position: number = 0;\n\n constructor(tokens: Token[]) {\n this.tokens = tokens;\n }\n\n /**\n * Parse tokens into an AST\n */\n parse(): ASTNode {\n if (this.tokens.length === 0) {\n throw new Error('Cannot parse empty expression');\n }\n\n const ast = this.parseOr();\n\n // Ensure all tokens were consumed\n if (!this.isAtEnd()) {\n throw new Error(`Unexpected token at position ${this.position}: ${this.peek()?.value}`);\n }\n\n return ast;\n }\n\n /**\n * Parse OR expressions (lowest precedence)\n * or_expr: and_expr ('or' and_expr)*\n */\n private parseOr(): ASTNode {\n let left = this.parseAnd();\n\n while (this.matchLogical('or')) {\n const operator = this.previous().value;\n const right = this.parseAnd();\n left = {\n type: 'BinaryOp',\n operator: operator.toLowerCase(),\n left,\n right,\n };\n }\n\n return left;\n }\n\n /**\n * Parse AND expressions\n * and_expr: not_expr ('and' not_expr)*\n */\n private parseAnd(): ASTNode {\n let left = this.parseNot();\n\n while (this.matchLogical('and')) {\n const operator = this.previous().value;\n const right = this.parseNot();\n left = {\n type: 'BinaryOp',\n operator: operator.toLowerCase(),\n left,\n right,\n };\n }\n\n return left;\n }\n\n /**\n * Parse NOT expressions\n * not_expr: 'not' comparison | comparison\n */\n private parseNot(): ASTNode {\n if (this.matchLogical('not')) {\n const operator = this.previous().value;\n const operand = this.parseComparison();\n return {\n type: 'UnaryOp',\n operator: operator.toLowerCase(),\n operand,\n };\n }\n\n return this.parseComparison();\n }\n\n /**\n * Parse comparison expressions\n * comparison: value (comp_op value)?\n * comp_op: '==' | '!=' | '<>' | '<' | '>' | '<=' | '>=' | 'in' | 'not in'\n */\n private parseComparison(): ASTNode {\n const left = this.parseValue();\n\n const compOperators = ['==', '!=', '<>', '<', '>', '<=', '>=', 'in', 'not in'];\n if (this.matchOperator(...compOperators)) {\n const operator = this.previous().value;\n const right = this.parseValue();\n return {\n type: 'BinaryOp',\n operator: operator.toLowerCase(),\n left,\n right,\n };\n }\n\n // If no comparison operator, return value as-is (truthiness check)\n return left;\n }\n\n /**\n * Parse value expressions (highest precedence)\n * value: '(' or_expr ')' | literal | identifier\n */\n private parseValue(): ASTNode {\n // Parenthesized expression\n if (this.match('PAREN', '(')) {\n const expr = this.parseOr();\n this.consume('PAREN', ')', 'Expected closing parenthesis');\n return expr;\n }\n\n // String literal\n if (this.check('STRING')) {\n const token = this.advance();\n // Remove quotes\n const value = token.value.slice(1, -1);\n return { type: 'Literal', value };\n }\n\n // True, False, None\n if (this.check('CONSTANT')) {\n const token = this.advance();\n return { type: 'Literal', value: CONSTANTS.get(token.value) ?? null };\n }\n\n // Number literal\n if (this.check('NUMBER')) {\n const token = this.advance();\n return { type: 'Literal', value: Number(token.value) };\n }\n\n // List literal\n if (this.check('LIST')) {\n const token = this.advance();\n const value = parseListLiteral(token.value);\n return { type: 'Literal', value };\n }\n\n // Identifier\n if (this.check('IDENTIFIER')) {\n const token = this.advance();\n return { type: 'Identifier', name: token.value };\n }\n\n throw new Error(`Unexpected token: ${this.peek()?.value || 'EOF'}`);\n }\n\n // ========== Helper Methods ==========\n\n /**\n * Check if current token matches any of the given types/values\n */\n private match(type: string, ...values: string[]): boolean {\n if (this.check(type)) {\n if (values.length === 0) {\n this.advance();\n return true;\n }\n const token = this.peek();\n if (token && values.includes(token.value)) {\n this.advance();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Match logical operators (case-insensitive)\n */\n private matchLogical(...operators: string[]): boolean {\n const token = this.peek();\n if (token && token.type === 'LOGICAL') {\n const lowerValue = token.value.toLowerCase();\n if (operators.map(op => op.toLowerCase()).includes(lowerValue)) {\n this.advance();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Match comparison operators (case-insensitive)\n */\n private matchOperator(...operators: string[]): boolean {\n const token = this.peek();\n if (token && token.type === 'OPERATOR') {\n const lowerValue = token.value.toLowerCase();\n if (operators.map(op => op.toLowerCase()).includes(lowerValue)) {\n this.advance();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Check if current token has given type\n */\n private check(type: string): boolean {\n const token = this.peek();\n return token?.type === type;\n }\n\n /**\n * Consume current token and advance\n */\n private advance(): Token {\n if (!this.isAtEnd()) {\n this.position++;\n }\n return this.previous();\n }\n\n /**\n * Get current token without advancing\n */\n private peek(): Token | null {\n if (this.isAtEnd()) {\n return null;\n }\n return this.tokens[this.position];\n }\n\n /**\n * Get previous token\n */\n private previous(): Token {\n return this.tokens[this.position - 1];\n }\n\n /**\n * Check if we've consumed all tokens\n */\n private isAtEnd(): boolean {\n return this.position >= this.tokens.length;\n }\n\n /**\n * Consume a token of specific type/value or throw error\n */\n private consume(type: string, value: string, message: string): Token {\n if (this.check(type)) {\n const token = this.peek();\n if (token && token.value === value) {\n return this.advance();\n }\n }\n throw new Error(message);\n }\n}\n\n/**\n * Parse a list literal string into an array\n * Example: \"['draft', 'sent']\" -> ['draft', 'sent']\n */\nfunction parseListLiteral(listStr: string): unknown[] {\n try {\n // Remove brackets\n const content = listStr.slice(1, -1).trim();\n if (!content) {\n return [];\n }\n\n // Split by comma and parse each element\n const elements: unknown[] = [];\n let current = '';\n let inString = false;\n let stringChar = '';\n\n for (let i = 0; i < content.length; i++) {\n const char = content[i];\n\n if ((char === \"'\" || char === '\"') && (i === 0 || content[i - 1] !== '\\\\')) {\n if (!inString) {\n inString = true;\n stringChar = char;\n } else if (char === stringChar) {\n inString = false;\n stringChar = '';\n }\n }\n\n if (char === ',' && !inString) {\n elements.push(parseElement(current.trim()));\n current = '';\n } else {\n current += char;\n }\n }\n\n if (current.trim()) {\n elements.push(parseElement(current.trim()));\n }\n\n return elements;\n } catch (error) {\n // A list that cannot be read is a syntax error, not an empty list.\n throw new Error(`Cannot read the list ${listStr}`, { cause: error });\n }\n}\n\n/**\n * Parse a single element from a list\n */\nfunction parseElement(element: string): unknown {\n // String\n if ((element.startsWith(\"'\") && element.endsWith(\"'\")) ||\n (element.startsWith('\"') && element.endsWith('\"'))) {\n return element.slice(1, -1);\n }\n\n // Number\n if (!isNaN(Number(element))) {\n return Number(element);\n }\n\n // Boolean\n if (element.toLowerCase() === 'true') return true;\n if (element.toLowerCase() === 'false') return false;\n\n // Default to string\n return element;\n}\n", "import type { Modifier } from '../format/layout';\nimport { evaluate, truthy } from './evaluator';\nimport { ExpressionParser, type ASTNode } from './parser';\nimport { tokenize } from './tokenizer';\n\n/** A modifier read once, ready to evaluate against a record's values. */\nexport interface CompiledModifier {\n readonly source: Modifier | undefined;\n /** The fields it reads, by their first name, in order of appearance. */\n readonly fields: readonly string[];\n evaluate(values: Readonly<Record<string, unknown>>): boolean;\n}\n\n/**\n * Read a modifier. `true`, `false` and a missing modifier become constants;\n * an expression is parsed now, so a mistake surfaces here and not on the\n * first keystroke. Throws when the expression cannot be read.\n */\nexport function compileModifier(modifier: Modifier | undefined): CompiledModifier {\n if (typeof modifier !== 'string') {\n const value = modifier === true;\n return { source: modifier, fields: [], evaluate: () => value };\n }\n const ast = new ExpressionParser(tokenize(modifier)).parse();\n return {\n source: modifier,\n fields: fieldsRead(ast),\n evaluate(values) {\n try {\n return truthy(evaluate(ast, values));\n } catch {\n return false;\n }\n },\n };\n}\n\nfunction fieldsRead(ast: ASTNode): string[] {\n const names: string[] = [];\n const visit = (node: ASTNode): void => {\n switch (node.type) {\n case 'Identifier': {\n const root = node.name.split('.')[0];\n if (!names.includes(root)) names.push(root);\n return;\n }\n case 'BinaryOp':\n visit(node.left);\n visit(node.right);\n return;\n case 'UnaryOp':\n visit(node.operand);\n return;\n default:\n return;\n }\n };\n visit(ast);\n return names;\n}\n", "import type { Field, Fields, FilterItem, LineField, LineKinds } from './field';\nimport type { FieldNode, LayoutNode, ListNode, RootLayout, SheetNode, TabsNode } from './layout';\nimport type { Page } from './page';\nimport { compileModifier } from '../expression/modifier';\n\nexport interface PageIssue {\n /** Where the problem is, as a path into the page: `layout.children[0].field`. */\n path: string;\n message: string;\n}\n\nexport type PageValidation = { ok: true; page: Page } | { ok: false; issues: PageIssue[] };\n\nconst has = (record: object, key: string) => Object.prototype.hasOwnProperty.call(record, key);\n\n/** The second pass of every check: ids unique, every name defined, every condition readable. */\nexport class ReferenceCheck {\n private readonly issues: PageIssue[] = [];\n private readonly ids = new Map<string, string>();\n\n constructor(private readonly page: Page) {}\n\n run(): PageIssue[] {\n this.checkFields(this.page.fields, 'fields');\n this.walkRoot(this.page.layout, 'layout');\n return this.issues;\n }\n\n private report(path: string, message: string) {\n this.issues.push({ path, message });\n }\n\n private claim(id: string, path: string) {\n const first = this.ids.get(id);\n if (first !== undefined) this.report(path, `duplicate id \"${id}\", also used at ${first}`);\n else this.ids.set(id, path);\n }\n\n /** The field a reference names, or a reported issue and undefined. */\n private need(name: string, path: string, scope: Record<string, Field | LineField> = this.page.fields) {\n if (has(scope, name)) return scope[name];\n this.report(path, `no field \"${name}\"`);\n return undefined;\n }\n\n /** Every modifier on `owner` must read, and read only fields of this page. */\n private checkModifiers(owner: object, path: string, keys: readonly string[] = ['invisible']) {\n for (const key of keys) {\n const value = (owner as Record<string, unknown>)[key];\n if (typeof value !== 'string') continue;\n let fields: readonly string[];\n try {\n fields = compileModifier(value).fields;\n } catch (error) {\n this.report(`${path}.${key}`, `cannot read \"${value}\": ${(error as Error).message}`);\n continue;\n }\n for (const name of fields) {\n if (!has(this.page.fields, name)) {\n this.report(`${path}.${key}`, `\"${value}\" reads \"${name}\", which is not a field of this page`);\n }\n }\n }\n }\n\n private checkFields(fields: Fields | Record<string, LineField>, base: string) {\n for (const [name, def] of Object.entries(fields)) {\n const path = `${base}.${name}`;\n if (def.type === 'monetary' && def.currencyField !== undefined) {\n const currency = this.need(def.currencyField, `${path}.currencyField`, fields);\n if (currency && !['many2one', 'selection', 'char'].includes(currency.type)) {\n this.report(\n `${path}.currencyField`,\n `\"${def.currencyField}\" is a ${currency.type}; a currency field must be a many2one, selection or char`\n );\n }\n }\n if ((def.type === 'many2one' || def.type === 'many2many') && def.filter) {\n // Groups nest: each valueFrom inside them must name a field too.\n const walk = (item: FilterItem, at: string): void => {\n if ('any' in item) return item.any.forEach((inner, i) => walk(inner, `${at}.any[${i}]`));\n if ('all' in item) return item.all.forEach((inner, i) => walk(inner, `${at}.all[${i}]`));\n if (item.valueFrom !== undefined) this.need(item.valueFrom, `${at}.valueFrom`, fields);\n };\n def.filter.forEach((item, i) => {\n walk(item, `${path}.filter[${i}]`);\n });\n }\n if (def.type === 'properties' && def.definitions) {\n const seen = new Set<string>();\n def.definitions.forEach((property, i) => {\n if (property.type === 'selection' && !property.options) {\n this.report(`${path}.definitions[${i}].options`, 'a choice property needs its choices');\n }\n if (seen.has(property.name)) this.report(`${path}.definitions[${i}].name`, `\"${property.name}\" is named twice`);\n seen.add(property.name);\n });\n }\n if (def.type === 'one2many') {\n this.checkFields(def.fields, `${path}.fields`);\n if (def.lineKinds) this.checkLineKinds(name, def.lineKinds, def.fields, `${path}.lineKinds`);\n if (def.sequenceField !== undefined) {\n const sequence = def.fields[def.sequenceField];\n if (!sequence) this.report(`${path}.sequenceField`, `\"${def.sequenceField}\" is not a field of the lines of \"${name}\"`);\n else if (sequence.type !== 'integer') {\n this.report(`${path}.sequenceField`, `\"${def.sequenceField}\" is a ${sequence.type}; the field that keeps the order of lines must be an integer`);\n }\n }\n }\n }\n }\n\n private checkLineKinds(field: string, kinds: LineKinds, lineFields: Record<string, LineField>, path: string) {\n const kindField = lineFields[kinds.field];\n if (!kindField) this.report(`${path}.field`, `\"${kinds.field}\" is not a field of the lines of \"${field}\"`);\n else if (kindField.type !== 'selection' && kindField.type !== 'char') {\n this.report(`${path}.field`, `\"${kinds.field}\" is a ${kindField.type}; the field that says what a line is must be a selection or char`);\n } else if (kindField.type === 'selection') {\n for (const which of ['section', 'note'] as const) {\n const value = kinds[which] ?? which;\n if (!kindField.options.some((o) => o.value === value)) this.report(`${path}.${which}`, `\"${kinds.field}\" has no option \"${value}\"`);\n }\n }\n const text = lineFields[kinds.text];\n if (!text) this.report(`${path}.text`, `\"${kinds.text}\" is not a field of the lines of \"${field}\"`);\n else if (text.type !== 'char' && text.type !== 'text') {\n this.report(`${path}.text`, `\"${kinds.text}\" is a ${text.type}; a section's or note's text must be a char or text field`);\n }\n }\n\n private walkRoot(root: RootLayout, path: string) {\n if (root.type === 'tabs') return this.walkNode(root, path);\n this.claim(root.id, path);\n if (root.type === 'sheet') return this.walkSheet(root, path);\n if (root.type === 'sections') return this.walkChildren(root.children, path);\n if (root.type === 'list') return this.walkList(root, path);\n root.children.forEach((step, i) => {\n const stepPath = `${path}.children[${i}]`;\n this.claim(step.id, stepPath);\n this.checkModifiers(step, stepPath);\n this.walkChildren(step.children, stepPath);\n });\n }\n\n private walkList(list: ListNode, path: string) {\n if (this.page.data.kind !== 'record') this.report('data', 'a list shows records: its data needs kind \"record\" and a model');\n list.columns.forEach((name, i) => this.need(name, `${path}.columns[${i}]`));\n list.sort?.forEach((order, i) => this.need(order.field, `${path}.sort[${i}].field`));\n list.searchFields?.forEach((name, i) => this.need(name, `${path}.searchFields[${i}]`));\n list.groupBy?.forEach((name, i) => this.need(name, `${path}.groupBy[${i}]`));\n // A list's filters are about its own records: their fields are the page's, and there is no record to take a value from.\n const walk = (item: FilterItem, at: string): void => {\n if ('any' in item) return item.any.forEach((inner, i) => walk(inner, `${at}.any[${i}]`));\n if ('all' in item) return item.all.forEach((inner, i) => walk(inner, `${at}.all[${i}]`));\n this.need(item.field, `${at}.field`);\n if (item.valueFrom !== undefined) this.report(`${at}.valueFrom`, \"a list's filter compares with values, not with another field\");\n };\n const named = new Set<string>();\n list.filters?.forEach((filter, i) => {\n this.claim(filter.id, `${path}.filters[${i}]`);\n named.add(filter.id);\n filter.filter.forEach((item, j) => walk(item, `${path}.filters[${i}].filter[${j}]`));\n });\n list.defaultFilters?.forEach((id, i) => {\n if (!named.has(id)) this.report(`${path}.defaultFilters[${i}]`, `no filter \"${id}\" in this list`);\n });\n list.actions?.forEach((button, i) => this.claim(button.id, `${path}.actions[${i}]`));\n }\n\n private walkChildren(children: LayoutNode[], path: string) {\n children.forEach((child, i) => this.walkNode(child, `${path}.children[${i}]`));\n }\n\n private walkNode(node: LayoutNode, path: string) {\n this.claim(node.id, path);\n this.checkModifiers(node, path, node.type === 'field' ? ['invisible', 'readonly', 'required'] : node.type === 'section' ? ['invisible', 'readonly'] : ['invisible']);\n switch (node.type) {\n case 'field':\n return this.checkFieldNode(node, path);\n case 'section':\n if (node.collapsible && !node.title) this.report(path, 'a collapsible section needs a title to fold it by');\n if (node.collapsed && !node.collapsible) this.report(path, 'collapsed needs collapsible: true');\n return this.walkChildren(node.children, path);\n case 'tabs':\n return this.walkTabs(node, path);\n default:\n return;\n }\n }\n\n private walkTabs(node: TabsNode, path: string) {\n node.children.forEach((tab, i) => {\n const tabPath = `${path}.children[${i}]`;\n this.claim(tab.id, tabPath);\n this.checkModifiers(tab, tabPath);\n this.walkChildren(tab.children, tabPath);\n });\n }\n\n private walkSheet(sheet: SheetNode, path: string) {\n if (sheet.title) {\n this.need(sheet.title.field, `${path}.title.field`);\n if (sheet.title.subtitleField !== undefined) this.need(sheet.title.subtitleField, `${path}.title.subtitleField`);\n if (sheet.title.avatarField !== undefined) this.need(sheet.title.avatarField, `${path}.title.avatarField`);\n }\n if (sheet.statusbar) {\n const { field, visibleStates } = sheet.statusbar;\n const def = this.need(field, `${path}.statusbar.field`);\n if (def && def.type !== 'selection' && def.type !== 'many2one') {\n this.report(`${path}.statusbar.field`, `\"${field}\" is a ${def.type}; a statusbar needs a selection or many2one`);\n }\n if (def?.type === 'selection' && visibleStates) {\n const values = new Set(def.options.map((o) => o.value));\n visibleStates.forEach((state, i) => {\n if (!values.has(state)) {\n this.report(`${path}.statusbar.visibleStates[${i}]`, `\"${state}\" is not an option of \"${field}\"`);\n }\n });\n }\n }\n sheet.buttons?.forEach((button, i) => {\n this.claim(button.id, `${path}.buttons[${i}]`);\n this.checkModifiers(button, `${path}.buttons[${i}]`);\n });\n sheet.statButtons?.forEach((stat, i) => {\n this.claim(stat.id, `${path}.statButtons[${i}]`);\n this.checkModifiers(stat, `${path}.statButtons[${i}]`);\n if (stat.field !== undefined) this.need(stat.field, `${path}.statButtons[${i}].field`);\n });\n if (sheet.ribbon) {\n this.claim(sheet.ribbon.id, `${path}.ribbon`);\n this.checkModifiers(sheet.ribbon, `${path}.ribbon`);\n }\n sheet.badges?.forEach((badge, i) => {\n this.claim(badge.id, `${path}.badges[${i}]`);\n this.checkModifiers(badge, `${path}.badges[${i}]`);\n });\n for (const place of ['above', 'below'] as const) {\n sheet.title?.[place]?.forEach((node, i) => this.walkNode(node, `${path}.title.${place}[${i}]`));\n }\n sheet.alerts?.forEach((alert, i) => {\n this.claim(alert.id, `${path}.alerts[${i}]`);\n this.checkModifiers(alert, `${path}.alerts[${i}]`);\n });\n this.walkChildren(sheet.children, path);\n if (sheet.sidePanel) {\n this.claim(sheet.sidePanel.id, `${path}.sidePanel`);\n this.checkModifiers(sheet.sidePanel, `${path}.sidePanel`);\n }\n }\n\n private checkFieldNode(node: FieldNode, path: string) {\n const def = this.need(node.field, `${path}.field`);\n if (def && node.totals) {\n if (def.type !== 'one2many') {\n this.report(`${path}.totals`, `totals only apply to one2many fields; \"${node.field}\" is a ${def.type}`);\n } else {\n node.totals.forEach((column, i) => {\n const sub = has(def.fields, column) ? def.fields[column] : undefined;\n if (!sub) this.report(`${path}.totals[${i}]`, `\"${column}\" is not a field of the lines of \"${node.field}\"`);\n else if (!['integer', 'float', 'monetary'].includes(sub.type)) {\n this.report(`${path}.totals[${i}]`, `\"${column}\" is a ${sub.type}; only integer, float and monetary columns add up`);\n }\n });\n }\n }\n // Options that point at another field: by convention their names end in \"Field\".\n for (const [key, value] of Object.entries(node.options ?? {})) {\n if (key.endsWith('Field') && typeof value === 'string') this.need(value, `${path}.options.${key}`);\n }\n if (def && node.editMode && def.type !== 'one2many') {\n this.report(`${path}.editMode`, `editMode only applies to one2many fields; \"${node.field}\" is a ${def.type}`);\n }\n if (def && node.optionalColumns) {\n if (def.type !== 'one2many') {\n this.report(`${path}.optionalColumns`, `optional columns only apply to one2many fields; \"${node.field}\" is a ${def.type}`);\n } else {\n // The columns the table shows: those named, or every line field but the structural ones.\n const shown = node.columns ?? Object.keys(def.fields).filter((c) => c !== def.lineKinds?.field && c !== def.sequenceField);\n for (const column of Object.keys(node.optionalColumns)) {\n if (!shown.includes(column)) this.report(`${path}.optionalColumns.${column}`, `\"${column}\" is not a column of \"${node.field}\"`);\n }\n }\n }\n if (!def || !node.columns) return;\n if (def.type === 'one2many') {\n node.columns.forEach((column, i) => {\n if (!has(def.fields, column)) {\n this.report(`${path}.columns[${i}]`, `\"${column}\" is not a field of the lines of \"${node.field}\"`);\n }\n });\n } else if (def.type !== 'many2many') {\n this.report(`${path}.columns`, `columns only apply to one2many and many2many fields; \"${node.field}\" is a ${def.type}`);\n }\n }\n}\n", "import { FIELD_TYPES } from './names';\nimport type { Page } from './page';\nimport { ReferenceCheck, type PageIssue, type PageValidation } from './references';\nimport { FORMAT_VERSION } from './version';\n\nconst isObject = (value: unknown): value is Record<string, unknown> => value !== null && typeof value === 'object' && !Array.isArray(value);\nconst LAYOUTS = ['sheet', 'sections', 'tabs', 'wizard'];\n\n/**\n * The check a page gets as it is shown: its outline, then every name and\n * condition in it, the same as `validatePage` finds them. It leaves out the\n * key-by-key check of the format, and so the validation library, which an app\n * showing forms need not carry; run `validatePage` where pages are made or\n * tested. A page that passes is handed back as it is.\n */\nexport function checkPage(input: unknown): PageValidation {\n if (!isObject(input)) return { ok: false, issues: [{ path: '(page)', message: 'a page is a JSON object' }] };\n const issues: PageIssue[] = [];\n const say = (path: string, message: string) => issues.push({ path, message });\n if (input['fieldia'] !== FORMAT_VERSION) say('fieldia', `this build reads format ${FORMAT_VERSION}`);\n if (typeof input['id'] !== 'string' || !input['id']) say('id', 'a page needs an id');\n const data = input['data'];\n if (!isObject(data) || !(data['kind'] === 'responses' || (data['kind'] === 'record' && typeof data['model'] === 'string' && data['model']))) {\n say('data', 'data is { \"kind\": \"record\", \"model\": \u2026 } or { \"kind\": \"responses\" }');\n }\n const fields = input['fields'];\n if (!isObject(fields)) say('fields', 'fields is an object of field definitions, by name');\n else {\n for (const [name, def] of Object.entries(fields)) {\n if (!isObject(def) || !(FIELD_TYPES as readonly unknown[]).includes(def['type']) || typeof def['label'] !== 'string') {\n say(`fields.${name}`, 'a field needs a type Fieldia knows and a label');\n }\n }\n }\n const layout = input['layout'];\n const isList = isObject(layout) && layout['type'] === 'list';\n if (!isObject(layout) || (isList ? !Array.isArray(layout['columns']) : !LAYOUTS.includes(layout['type'] as string) || !Array.isArray(layout['children']))) {\n say('layout', 'the layout is a sheet, sections, tabs or wizard, with children, or a list with columns');\n }\n if (issues.length) return { ok: false, issues };\n const page = input as unknown as Page;\n try {\n const found = new ReferenceCheck(page).run();\n return found.length ? { ok: false, issues: found } : { ok: true, page };\n } catch (error) {\n return { ok: false, issues: [{ path: '(page)', message: `a part of this page cannot be read: ${(error as Error).message}` }] };\n }\n}\n", "import type { Page } from './page';\n\n/** Keys whose text a person reads: titles, labels, help, prompts, messages and a wizard's buttons. */\nconst TEXT_KEYS = new Set(['title', 'description', 'label', 'help', 'placeholder', 'message', 'text', 'confirm', 'nextLabel', 'backLabel', 'finishLabel']);\n\n/**\n * Parts that hold names or data, never words to translate: which line fields\n * mark sections and notes, a link's filter, a default value, a widget's options,\n * and what the page's data is.\n */\nconst NOT_TEXT = new Set(['lineKinds', 'filter', 'default', 'data']);\n\n/**\n * The page with every word a person reads passed through the app's own\n * translator, for apps that keep their translations by text or by key. Ids,\n * field names, choice values, conditions and data stay as they are; the page\n * given is left alone.\n */\nexport function translatePage(page: Page, translate: (text: string) => string): Page {\n const walk = (value: unknown, key: string | null): unknown => {\n if (typeof value === 'string') return key !== null && TEXT_KEYS.has(key) ? translate(value) : value;\n if (Array.isArray(value)) return value.map((item) => walk(item, null));\n if (value === null || typeof value !== 'object') return value;\n const out: Record<string, unknown> = {};\n for (const [name, inner] of Object.entries(value)) {\n // A field node's `options` are its widget's settings, not a list of choices.\n const widgetOptions = name === 'options' && !Array.isArray(inner);\n out[name] = NOT_TEXT.has(name) || widgetOptions ? inner : walk(inner, name);\n }\n return out;\n };\n return walk(page, null) as Page;\n}\n", "/**\n * evaluateModifier - Evaluate modifier expressions with form context\n *\n * Phase 2 implementation with full expression parser.\n * Supports Python-like expressions used in Flectra modifiers.\n *\n * Structura Reference:\n * - DynBehaviorManager.evaluateCondition() method\n * - Supports Python-like expressions: \"state == 'draft' and amount > 100\"\n *\n * Supported features:\n * - Comparison operators: ==, !=, <>, <, >, <=, >=\n * - In operators: in, not in\n * - Logical operators: and, or, not\n * - Parentheses for precedence\n * - Nested field access: partner_id.country_id.name\n * - Truthiness checks: partner_id (true if partner_id has value)\n *\n * @param expression - The modifier expression to evaluate\n * @param context - Current form values\n * @returns Boolean result of evaluation\n *\n * @example\n * ```typescript\n * // Simple boolean\n * evaluateModifier(true, {}) // => true\n *\n * // String boolean\n * evaluateModifier('1', {}) // => true\n * evaluateModifier('True', {}) // => true\n *\n * // Field truthiness\n * evaluateModifier('is_company', { is_company: true }) // => true\n * evaluateModifier('partner_id', { partner_id: null }) // => false\n *\n * // Comparison expressions\n * evaluateModifier(\"state == 'done'\", { state: 'done' }) // => true\n * evaluateModifier(\"amount > 100\", { amount: 150 }) // => true\n *\n * // Logical expressions\n * evaluateModifier(\"state == 'draft' and amount > 100\", { state: 'draft', amount: 150 }) // => true\n * evaluateModifier(\"state in ['draft', 'sent']\", { state: 'draft' }) // => true\n *\n * // Nested field access\n * evaluateModifier(\"partner_id.country_id == 5\", { partner_id: { country_id: 5 } }) // => true\n * ```\n */\n\nimport { tokenize } from './tokenizer';\nimport { ExpressionParser } from './parser';\nimport { evaluate, truthy } from './evaluator';\n\nexport function evaluateModifier(\n expression: string | boolean | undefined,\n context: Record<string, unknown>\n): boolean {\n // Undefined modifier = false (field is not affected)\n if (expression === undefined) {\n return false;\n }\n\n // Direct boolean value\n if (typeof expression === 'boolean') {\n return expression;\n }\n\n // String representation of boolean\n if (expression === '1' || expression === 'True' || expression === 'true') {\n return true;\n }\n\n if (expression === '0' || expression === 'False' || expression === 'false') {\n return false;\n }\n\n // Empty string = false\n if (expression === '') {\n return false;\n }\n\n // Parse and evaluate complex expression\n try {\n const tokens = tokenize(expression);\n\n // Empty token list\n if (tokens.length === 0) {\n return false;\n }\n\n const parser = new ExpressionParser(tokens);\n const ast = parser.parse();\n const result = evaluate(ast, context);\n\n // Convert result to boolean\n return truthy(result);\n } catch {\n // A page is validated before it runs (validatePage reads every\n // expression), so this only guards pages that skipped validation.\n // Fail safely - return false so field is not hidden/disabled by broken modifier\n return false;\n }\n}\n\n/**\n * Check if a modifier expression is valid and can be parsed\n *\n * @param expression - The modifier expression to check\n * @returns true if expression is valid, false otherwise\n */\nexport function isModifierValid(expression: string | boolean | undefined): boolean {\n if (expression === undefined || typeof expression === 'boolean') {\n return true;\n }\n\n if (expression === '') {\n return true;\n }\n\n try {\n const tokens = tokenize(expression);\n if (tokens.length === 0) {\n return true;\n }\n const parser = new ExpressionParser(tokens);\n parser.parse();\n return true;\n } catch {\n return false;\n }\n}\n", "import type { Field, LineField } from '../format/field';\nimport type { JsonValue } from '../format/json';\n\n/**\n * The values a form holds while someone edits it. Plain JSON, so a draft can\n * be stored and a record handed to any data source.\n */\n\nexport type RecordId = number | string;\n\n/** A related record, as a many2one or many2many holds it: enough to show it. */\nexport interface RelatedRecord {\n id: RecordId;\n label: string;\n}\n\n/** A reference points at a record of one of several models. */\nexport interface ReferenceValue {\n model: string;\n id: RecordId;\n label: string;\n}\n\n/** An uploaded or stored file. `data` is base64; `url` is where a stored one lives. */\nexport interface FileValue {\n name: string;\n type: string;\n size: number;\n data?: string;\n url?: string;\n}\n\n/**\n * One line of a one2many. `key` is stable for the life of the form, so a line\n * keeps its identity while it is edited; `id` is the saved record's id, absent\n * until the line is saved.\n */\nexport interface Line {\n key: string;\n id?: RecordId;\n values: Values;\n}\n\nexport type Value =\n | JsonValue\n | RelatedRecord\n | RelatedRecord[]\n | ReferenceValue\n | FileValue\n | Line[];\n\nexport type Values = Record<string, Value>;\n\ntype AnyField = Field | LineField;\n\n/** What a field holds before anyone types in it. */\nexport function emptyValue(field: AnyField): Value {\n switch (field.type) {\n case 'boolean':\n return false;\n case 'many2many':\n case 'one2many':\n return [];\n case 'selection':\n return field.multiple ? [] : null;\n default:\n return null;\n }\n}\n\n/** A fresh record: each field's default, or its empty value. */\nexport function initialValues(fields: Record<string, AnyField>): Values {\n const values: Values = {};\n for (const [name, field] of Object.entries(fields)) {\n values[name] = field.default !== undefined ? structuredCopy(field.default) : emptyValue(field);\n }\n return values;\n}\n\n/** Nothing worth keeping: no value, blank text, or an empty list. Numbers and booleans never are. */\nexport function isEmpty(_field: AnyField, value: Value | undefined): boolean {\n if (value === null || value === undefined) return true;\n if (typeof value === 'string') return value.trim() === '';\n if (Array.isArray(value)) return value.length === 0;\n return false;\n}\n\n/**\n * The values as modifiers read them, matching what backends write in their\n * expressions: a many2one is its id, a many2many its ids, a reference\n * \"model,id\", a file its name, and lines a list (so `not child_ids` works).\n */\nexport function expressionContext(values: Values, fields: Record<string, AnyField>): Record<string, unknown> {\n const context: Record<string, unknown> = {};\n for (const [name, value] of Object.entries(values)) {\n const field = fields[name];\n context[name] = field ? forExpressions(field, value) : value;\n }\n return context;\n}\n\nfunction forExpressions(field: AnyField, value: Value): unknown {\n if (value === null || value === undefined) return null;\n switch (field.type) {\n case 'many2one':\n return (value as RelatedRecord).id;\n case 'many2many':\n return (value as RelatedRecord[]).map((record) => record.id);\n case 'one2many':\n return (value as Line[]).map((line) => line.key);\n case 'reference': {\n const ref = value as ReferenceValue;\n return `${ref.model},${ref.id}`;\n }\n case 'binary':\n case 'image':\n return (value as FileValue).name;\n default:\n return value;\n }\n}\n\n/**\n * What a line of a one2many is: a section heading, a note, or (null) an item.\n * Lines only have kinds when the field declares `lineKinds`.\n */\nexport function lineKind(field: Extract<Field, { type: 'one2many' }>, values: Values): 'section' | 'note' | null {\n const kinds = field.lineKinds;\n if (!kinds) return null;\n const value = values[kinds.field];\n if (value === (kinds.section ?? 'section')) return 'section';\n if (value === (kinds.note ?? 'note')) return 'note';\n return null;\n}\n\n/** A deep copy of plain JSON. */\nexport function structuredCopy<T>(value: T): T {\n return value === undefined ? value : (JSON.parse(JSON.stringify(value)) as T);\n}\n", "/**\n * Validation messages, by language. `{label}` is the field's label; the other\n * placeholders are named in each English message. English keeps the React\n * engine's wording; Arabic, German and French build on its translations.\n */\nexport interface Messages {\n required: string;\n maxLength: string;\n pattern: string;\n text: string;\n number: string;\n integer: string;\n min: string;\n max: string;\n decimals: string;\n boolean: string;\n dateFormat: string;\n dateInvalid: string;\n datetimeFormat: string;\n datetimeInvalid: string;\n choice: string;\n choices: string;\n record: string;\n records: string;\n reference: string;\n file: string;\n fileSize: string;\n fileType: string;\n /** Joins the last two items of a list: \"PDF or image\". */\n or: string;\n}\n\nexport type Locale = 'en' | 'ar' | 'de' | 'fr';\n\nexport const MESSAGES: Record<Locale, Messages> = {\n en: {\n required: '{label} is required',\n maxLength: 'Maximum {max} characters allowed',\n pattern: '{label} is not in the expected format',\n text: '{label} must be text',\n number: '{label} must be a number',\n integer: '{label} must be a whole number',\n min: '{label} must be at least {min}',\n max: '{label} must be at most {max}',\n decimals: 'Maximum {digits} decimal places allowed',\n boolean: '{label} must be yes or no',\n dateFormat: 'Invalid date format (expected YYYY-MM-DD)',\n dateInvalid: 'Invalid date (check month/day values)',\n datetimeFormat: 'Invalid date and time format (expected YYYY-MM-DDTHH:MM:SS)',\n datetimeInvalid: 'Invalid date and time (check the values)',\n choice: 'Must be one of: {options}',\n choices: '{label} must be a list of choices',\n record: '{label} must be a record',\n records: '{label} must be a list of records',\n reference: '{label} must point to {aModels}',\n file: '{label} must be a file',\n fileSize: '{label} is larger than {size}',\n fileType: '{label} must be {aTypes} file',\n or: 'or',\n },\n ar: {\n required: '{label} \u0645\u0637\u0644\u0648\u0628',\n maxLength: '\u0627\u0644\u062D\u062F \u0627\u0644\u0623\u0642\u0635\u0649 {max} \u062D\u0631\u0641\u064B\u0627',\n pattern: '\u0635\u064A\u063A\u0629 {label} \u063A\u064A\u0631 \u0635\u062D\u064A\u062D\u0629',\n text: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0646\u0635\u064B\u0627',\n number: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0631\u0642\u0645\u064B\u0627',\n integer: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0631\u0642\u0645\u064B\u0627 \u0635\u062D\u064A\u062D\u064B\u0627',\n min: '\u064A\u062C\u0628 \u0623\u0644\u0627 \u064A\u0642\u0644 {label} \u0639\u0646 {min}',\n max: '\u064A\u062C\u0628 \u0623\u0644\u0627 \u064A\u0632\u064A\u062F {label} \u0639\u0646 {max}',\n decimals: '\u0627\u0644\u062D\u062F \u0627\u0644\u0623\u0642\u0635\u0649 {digits} \u0645\u0646\u0627\u0632\u0644 \u0639\u0634\u0631\u064A\u0629',\n boolean: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0646\u0639\u0645 \u0623\u0648 \u0644\u0627',\n dateFormat: '\u0635\u064A\u063A\u0629 \u0627\u0644\u062A\u0627\u0631\u064A\u062E \u063A\u064A\u0631 \u0635\u062D\u064A\u062D\u0629 (\u0627\u0644\u0645\u062A\u0648\u0642\u0639 YYYY-MM-DD)',\n dateInvalid: '\u0627\u0644\u062A\u0627\u0631\u064A\u062E \u063A\u064A\u0631 \u0635\u062D\u064A\u062D (\u062A\u062D\u0642\u0642 \u0645\u0646 \u0627\u0644\u0634\u0647\u0631 \u0648\u0627\u0644\u064A\u0648\u0645)',\n datetimeFormat: '\u0635\u064A\u063A\u0629 \u0627\u0644\u062A\u0627\u0631\u064A\u062E \u0648\u0627\u0644\u0648\u0642\u062A \u063A\u064A\u0631 \u0635\u062D\u064A\u062D\u0629 (\u0627\u0644\u0645\u062A\u0648\u0642\u0639 YYYY-MM-DDTHH:MM:SS)',\n datetimeInvalid: '\u0627\u0644\u062A\u0627\u0631\u064A\u062E \u0648\u0627\u0644\u0648\u0642\u062A \u063A\u064A\u0631 \u0635\u062D\u064A\u062D\u064A\u0646',\n choice: '\u064A\u062C\u0628 \u0623\u0646 \u062A\u0643\u0648\u0646 \u0627\u0644\u0642\u064A\u0645\u0629 \u0648\u0627\u062D\u062F\u0629 \u0645\u0646: {options}',\n choices: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0642\u0627\u0626\u0645\u0629 \u0627\u062E\u062A\u064A\u0627\u0631\u0627\u062A',\n record: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0633\u062C\u0644\u064B\u0627',\n records: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0642\u0627\u0626\u0645\u0629 \u0633\u062C\u0644\u0627\u062A',\n reference: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0634\u064A\u0631 {label} \u0625\u0644\u0649 {models}',\n file: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0645\u0644\u0641\u064B\u0627',\n fileSize: '\u062D\u062C\u0645 {label} \u0623\u0643\u0628\u0631 \u0645\u0646 {size}',\n fileType: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0645\u0644\u0641 {types}',\n or: '\u0623\u0648',\n },\n de: {\n required: '{label} ist erforderlich',\n maxLength: 'Maximal {max} Zeichen erlaubt',\n pattern: '{label} hat nicht das erwartete Format',\n text: '{label} muss Text sein',\n number: '{label} muss eine Zahl sein',\n integer: '{label} muss eine ganze Zahl sein',\n min: '{label} muss mindestens {min} sein',\n max: '{label} darf h\u00F6chstens {max} sein',\n decimals: 'Maximal {digits} Nachkommastellen erlaubt',\n boolean: '{label} muss ja oder nein sein',\n dateFormat: 'Ung\u00FCltiges Datumsformat (erwartet JJJJ-MM-TT)',\n dateInvalid: 'Ung\u00FCltiges Datum (Monat und Tag pr\u00FCfen)',\n datetimeFormat: 'Ung\u00FCltiges Datums- und Zeitformat (erwartet JJJJ-MM-TTTHH:MM:SS)',\n datetimeInvalid: 'Ung\u00FCltiges Datum oder ung\u00FCltige Uhrzeit',\n choice: 'Muss eines davon sein: {options}',\n choices: '{label} muss eine Liste von Optionen sein',\n record: '{label} muss ein Datensatz sein',\n records: '{label} muss eine Liste von Datens\u00E4tzen sein',\n reference: '{label} muss auf {models} verweisen',\n file: '{label} muss eine Datei sein',\n fileSize: '{label} ist gr\u00F6\u00DFer als {size}',\n fileType: '{label} muss eine {types}-Datei sein',\n or: 'oder',\n },\n fr: {\n required: '{label} est obligatoire',\n maxLength: '{max} caract\u00E8res au maximum',\n pattern: \"{label} n'a pas le format attendu\",\n text: '{label} doit \u00EAtre du texte',\n number: '{label} doit \u00EAtre un nombre',\n integer: '{label} doit \u00EAtre un nombre entier',\n min: '{label} doit \u00EAtre au moins {min}',\n max: '{label} doit \u00EAtre au plus {max}',\n decimals: '{digits} d\u00E9cimales au maximum',\n boolean: '{label} doit \u00EAtre oui ou non',\n dateFormat: 'Format de date invalide (attendu AAAA-MM-JJ)',\n dateInvalid: 'Date invalide (v\u00E9rifiez le mois et le jour)',\n datetimeFormat: 'Format de date et heure invalide (attendu AAAA-MM-JJTHH:MM:SS)',\n datetimeInvalid: 'Date ou heure invalide',\n choice: 'Doit \u00EAtre parmi : {options}',\n choices: '{label} doit \u00EAtre une liste de choix',\n record: '{label} doit \u00EAtre un enregistrement',\n records: \"{label} doit \u00EAtre une liste d'enregistrements\",\n reference: '{label} doit pointer vers {models}',\n file: '{label} doit \u00EAtre un fichier',\n fileSize: '{label} d\u00E9passe {size}',\n fileType: '{label} doit \u00EAtre un fichier {types}',\n or: 'ou',\n },\n};\n\n/** Fill `{name}` placeholders. */\nexport function fill(template: string, values: Record<string, string | number>): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) => (name in values ? String(values[name]) : match));\n}\n", "import type { Field, LineField } from '../format/field';\nimport { fill, MESSAGES, type Messages } from './messages';\nimport { isEmpty, type FileValue, type ReferenceValue, type RelatedRecord, type Value } from './values';\n\n/**\n * Check one value against its field. Returns the message to show, or\n * undefined when the value is fine. The wording follows the React engine's\n * (\"Name is required\", \"Maximum 120 characters allowed\").\n *\n * An empty optional value passes everything: a pattern or a minimum applies\n * to what someone typed, not to a field they left alone.\n */\nexport function checkValue(\n field: Field | LineField,\n value: Value | undefined,\n required: boolean,\n messages: Messages = MESSAGES.en\n): string | undefined {\n const label = field.label || 'This field';\n const say = (key: keyof Messages, values: Record<string, string | number> = {}) => fill(messages[key], { label, ...values });\n if (isEmpty(field, value)) return required ? say('required') : undefined;\n\n switch (field.type) {\n case 'char':\n case 'text':\n case 'html': {\n if (typeof value !== 'string') return say('text');\n if ((field.type === 'char' || field.type === 'text') && field.size !== undefined && value.length > field.size) {\n return say('maxLength', { max: field.size });\n }\n if (field.type === 'char' && field.pattern !== undefined && !new RegExp(field.pattern).test(value)) {\n return say('pattern');\n }\n return undefined;\n }\n case 'integer':\n case 'float':\n case 'monetary': {\n if (typeof value !== 'number' || !Number.isFinite(value)) return say('number');\n if (field.type === 'integer' && !Number.isInteger(value)) return say('integer');\n if (field.min !== undefined && value < field.min) return say('min', { min: field.min });\n if (field.max !== undefined && value > field.max) return say('max', { max: field.max });\n if (field.type !== 'integer' && field.digits && decimals(value) > field.digits[1]) {\n return say('decimals', { digits: field.digits[1] });\n }\n return undefined;\n }\n case 'boolean':\n return typeof value === 'boolean' ? undefined : say('boolean');\n case 'date':\n return checkDate(value, say);\n case 'datetime':\n return checkDateTime(value, say);\n case 'selection': {\n const allowed = new Set(field.options.map((o) => o.value));\n const listing = say('choice', { options: field.options.map((o) => o.label).join(', ') });\n if (field.multiple) {\n if (!Array.isArray(value)) return say('choices');\n return value.every((v) => allowed.has(v as string | number)) ? undefined : listing;\n }\n return allowed.has(value as string | number) ? undefined : listing;\n }\n case 'many2one':\n return isRecord(value) ? undefined : say('record');\n case 'many2many':\n return Array.isArray(value) && value.every(isRecord) ? undefined : say('records');\n case 'reference': {\n const ref = value as ReferenceValue;\n if (!isRecord(value) || typeof ref.model !== 'string') return say('record');\n if (!field.models.some((m) => m.value === ref.model)) {\n const models = listOr(field.models.map((m) => m.label), messages.or);\n return say('reference', { models, aModels: article(models) });\n }\n return undefined;\n }\n case 'binary':\n case 'image':\n return checkFile(field, value, say, messages);\n default:\n return undefined;\n }\n}\n\nfunction decimals(value: number): number {\n const text = String(value);\n if (text.includes('e-')) return Number(text.split('e-')[1]);\n const dot = text.indexOf('.');\n return dot === -1 ? 0 : text.length - dot - 1;\n}\n\nfunction isRecord(value: unknown): value is RelatedRecord {\n return (\n value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n (typeof (value as RelatedRecord).id === 'number' || typeof (value as RelatedRecord).id === 'string') &&\n typeof (value as RelatedRecord).label === 'string'\n );\n}\n\ntype Say = (key: keyof Messages, values?: Record<string, string | number>) => string;\n\nfunction checkDate(value: Value | undefined, say: Say): string | undefined {\n if (typeof value !== 'string' || !/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return say('dateFormat');\n const [y, m, d] = value.split('-').map(Number);\n return realDay(y, m, d) ? undefined : say('dateInvalid');\n}\n\nconst ISO_DATETIME = /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d{1,9})?)?(?:Z|[+-]\\d{2}:\\d{2})?$/;\n\nfunction checkDateTime(value: Value | undefined, say: Say): string | undefined {\n const match = typeof value === 'string' ? ISO_DATETIME.exec(value) : null;\n if (!match) return say('datetimeFormat');\n const [y, mo, d, h, mi, s] = match.slice(1).map((part) => Number(part ?? 0));\n return realDay(y, mo, d) && h < 24 && mi < 60 && s < 60 ? undefined : say('datetimeInvalid');\n}\n\nfunction realDay(year: number, month: number, day: number): boolean {\n if (month < 1 || month > 12 || day < 1) return false;\n const lengths = [31, year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n return day <= lengths[month - 1];\n}\n\nfunction checkFile(field: Field | LineField, value: Value | undefined, say: Say, messages: Messages): string | undefined {\n const file = value as FileValue;\n if (!isFile(value)) return say('file');\n if ('maxSize' in field && field.maxSize !== undefined && file.size > field.maxSize) {\n return say('fileSize', { size: formatBytes(field.maxSize) });\n }\n if (field.type === 'binary' && field.accept && !field.accept.some((pattern) => matchesType(pattern, file.type))) {\n const types = listOr(field.accept.map(describeType), messages.or);\n return say('fileType', { types, aTypes: article(types) });\n }\n return undefined;\n}\n\nfunction isFile(value: unknown): value is FileValue {\n const file = value as FileValue;\n return value !== null && typeof value === 'object' && typeof file.name === 'string' && typeof file.size === 'number';\n}\n\nfunction matchesType(pattern: string, type: string): boolean {\n return pattern.endsWith('/*') ? type.startsWith(pattern.slice(0, -1)) : pattern === type;\n}\n\nfunction describeType(pattern: string): string {\n if (pattern.endsWith('/*')) return pattern.slice(0, -2);\n if (pattern === 'application/pdf') return 'PDF';\n return (pattern.split('/')[1] ?? pattern).toUpperCase();\n}\n\nfunction listOr(items: string[], or: string): string {\n if (items.length <= 1) return items.join('');\n return `${items.slice(0, -1).join(', ')} ${or} ${items[items.length - 1]}`;\n}\n\nfunction article(phrase: string): string {\n return /^[aeiou]/i.test(phrase) ? `an ${phrase}` : `a ${phrase}`;\n}\n\n/** 1048576 -> \"1 MB\". */\nexport function formatBytes(bytes: number): string {\n const units = ['bytes', 'KB', 'MB', 'GB'];\n let size = bytes;\n let unit = 0;\n while (size >= 1024 && unit < units.length - 1) {\n size /= 1024;\n unit++;\n }\n return `${Number(size.toFixed(1))} ${units[unit]}`;\n}\n", "import type { FilterCondition, Fields } from '../format/field';\nimport type { JsonValue } from '../format/json';\nimport type { RecordId, RelatedRecord, Values } from './values';\n\n/**\n * How Fieldia reaches data. Fieldia knows no backend: an app implements this\n * interface for its own (a Flectra adapter, a REST client, a survey store),\n * and every method is optional so a page uses only what it needs.\n */\nexport interface DataSource {\n /** Read a record. Needed to edit an existing record. */\n load?(request: LoadRequest): Promise<Values>;\n /** Create (`id: null`) or update a record. Needed to save a record page. */\n save?(request: SaveRequest): Promise<SaveResult>;\n /** Recalculate after a value changes, the way a backend's onchange does. */\n onchange?(request: OnchangeRequest): Promise<OnchangeResult>;\n /** Find records a many2one, many2many or reference may point to. */\n search?(request: SearchRequest): Promise<RelatedRecord[]>;\n /** Make a record from just its name, for \"Create 'xyz'\" in a link field (a backend's name_create). */\n create?(request: CreateRequest): Promise<RelatedRecord>;\n /** Store one response to a `responses` page, such as a survey. */\n submit?(request: SubmitRequest): Promise<SubmitResult>;\n /** Records for a list: filtered, sorted and one page of them, with how many there are in all. */\n list?(request: ListRequest): Promise<ListResult>;\n /** How many records fall under each value of a field, for a list's Group By. */\n groups?(request: GroupRequest): Promise<Group[]>;\n}\n\nexport interface CreateRequest {\n model: string;\n /** What the person typed: the new record's name. */\n name: string;\n}\n\nexport interface LoadRequest {\n model: string;\n id: RecordId;\n /** The page's fields, so the source reads exactly what the page shows. */\n fields: Fields;\n}\n\nexport interface SaveRequest {\n model: string;\n id: RecordId | null;\n /** The page's fields, so the source knows each relation's model. */\n fields: Fields;\n /** Only what changed since the record was loaded or last saved. */\n changes: RecordChanges;\n /** Every value, for sources that save whole records. */\n values: Values;\n}\n\nexport interface SaveResult {\n id: RecordId;\n /** The record as stored, when the source recalculated anything. */\n values?: Values;\n}\n\nexport interface OnchangeRequest {\n model: string;\n id: RecordId | null;\n /** The field that changed. */\n changed: string;\n values: Values;\n}\n\nexport interface OnchangeResult {\n /** New values for other fields. */\n values?: Values;\n /** Something to tell the person editing, without blocking them. */\n warning?: string;\n}\n\nexport interface SearchRequest {\n /** The related model, from the field's `relation`. */\n model: string;\n query: string;\n /** The field's filter, with every `valueFrom` already replaced by its value. */\n filter?: ResolvedFilter[];\n limit?: number;\n}\n\nexport type ResolvedFilterCondition = Omit<FilterCondition, 'valueFrom' | 'value'> & { value: JsonValue };\n\nexport interface SortOrder {\n field: string;\n desc?: boolean;\n}\n\nexport interface ListRequest {\n model: string;\n /** The fields the list shows. */\n fields: string[];\n /** What the search bar and the open groups ask for; an `any` group is an OR. */\n filter: ResolvedFilter[];\n /** By the first, then the next: a link by its label, empty values last. */\n sort: SortOrder[];\n offset: number;\n limit: number;\n}\n\nexport interface ListResult {\n records: { id: RecordId; values: Values }[];\n /** How many records match in all, for the pager. */\n total: number;\n}\n\nexport interface GroupRequest {\n model: string;\n field: string;\n filter: ResolvedFilter[];\n}\n\n/** The records under one value of a field: a link's by its id, and those with none as a group of their own (value null). */\nexport interface Group {\n value: JsonValue;\n label: string;\n count: number;\n}\n\n/**\n * A filter as a search receives it: each `valueFrom` already replaced by its\n * value. An adapter must keep the groups: `any` is an OR, `all` an AND.\n */\nexport type ResolvedFilter = ResolvedFilterCondition | { any: ResolvedFilter[] } | { all: ResolvedFilter[] };\n\nexport interface SubmitRequest {\n pageId: string;\n /** The answers to the questions that were shown. Skipped steps are left out. */\n values: Values;\n}\n\nexport interface SubmitResult {\n id?: RecordId;\n}\n\n/**\n * What changed, using the operation names Odoo gives its x2many commands, so\n * an adapter maps them one to one.\n */\nexport interface RecordChanges {\n /** Changed values of every field that is not one2many or many2many. */\n values: Values;\n /** one2many changes, per field. */\n lines: Record<string, LineOp[]>;\n /** many2many changes, per field. */\n links: Record<string, LinkOp[]>;\n}\n\nexport type LineOp =\n | { op: 'create'; key: string; values: Values }\n | { op: 'update'; id: RecordId; values: Values }\n | { op: 'delete'; id: RecordId };\n\nexport type LinkOp =\n | { op: 'link'; id: RecordId }\n | { op: 'unlink'; id: RecordId }\n | { op: 'set'; ids: RecordId[] }\n | { op: 'clear' };\n\n/**\n * Why a save was refused, so each kind is shown where it belongs: `fields`\n * under those fields, a `rule` (a backend's business rule) in a dialog,\n * `network` in a banner with Retry, and `other` beside Save with Retry.\n */\nexport interface SaveProblem {\n kind: 'fields' | 'rule' | 'network' | 'other';\n message: string;\n /** For `fields`: a message for each field, by name. */\n fields?: Record<string, string>;\n}\n\n/** An error for a data source's save to throw when the backend refuses it. */\nexport function saveRefused(problem: SaveProblem): Error & { problem: SaveProblem } {\n return Object.assign(new Error(problem.message), { problem });\n}\n\n/** What a failed save tells: its own problem, a failed fetch as the network, anything else as it is. */\nexport function saveProblemOf(error: unknown): SaveProblem {\n const carried = (error as { problem?: SaveProblem } | null)?.problem;\n if (carried && typeof carried.kind === 'string') return carried;\n const message = error instanceof Error ? error.message : String(error);\n if (error instanceof TypeError && /fetch|network|load failed/i.test(message)) return { kind: 'network', message };\n return { kind: 'other', message };\n}\n", "import type { JsonValue } from '../format/json';\nimport type { ResolvedFilter, ResolvedFilterCondition } from './data-source';\nimport type { RelatedRecord, Values } from './values';\n\n/**\n * Whether a record passes a filter, the way a search should judge it: every\n * item of the list holds, an `any` group when one of its items holds, an `all`\n * group when each does. The memory data source searches with it; an app may too.\n */\nexport function matchesFilter(values: Values, filter: readonly ResolvedFilter[]): boolean {\n return filter.every((item) => holds(values, item));\n}\n\nfunction holds(values: Values, item: ResolvedFilter): boolean {\n if ('any' in item) return item.any.some((inner) => holds(values, inner));\n if ('all' in item) return item.all.every((inner) => holds(values, inner));\n return meets(values, item);\n}\n\n/** Empty is not set: no value, empty text, an empty list. */\nfunction isSet(value: unknown): boolean {\n return value !== null && value !== undefined && value !== '' && value !== false && !(Array.isArray(value) && !value.length);\n}\n\nfunction meets(values: Values, condition: ResolvedFilterCondition): boolean {\n const raw = values[condition.field];\n // A link compares by its id.\n const actual = raw !== null && typeof raw === 'object' && !Array.isArray(raw) && 'id' in raw ? (raw as RelatedRecord).id : (raw as JsonValue | undefined);\n const expected = condition.value;\n // Text is looked for in a link's name, as a search by name does.\n const text = raw !== null && typeof raw === 'object' && !Array.isArray(raw) && 'label' in raw ? String((raw as RelatedRecord).label) : String(actual ?? '');\n switch (condition.op) {\n case '=':\n return actual === expected;\n case '!=':\n return actual !== expected;\n case '<':\n return isSet(actual) && (actual as number) < (expected as number);\n case '>':\n return isSet(actual) && (actual as number) > (expected as number);\n case '<=':\n return isSet(actual) && (actual as number) <= (expected as number);\n case '>=':\n return isSet(actual) && (actual as number) >= (expected as number);\n case 'in':\n return Array.isArray(expected) && expected.includes(actual as JsonValue);\n case 'not in':\n return Array.isArray(expected) && !expected.includes(actual as JsonValue);\n case 'like':\n return text.includes(String(expected));\n case 'ilike':\n return text.toLowerCase().includes(String(expected).toLowerCase());\n case 'startswith':\n return text.toLowerCase().startsWith(String(expected).toLowerCase());\n case 'endswith':\n return text.toLowerCase().endsWith(String(expected).toLowerCase());\n case 'set':\n return isSet(raw);\n case 'notset':\n return !isSet(raw);\n case 'between': {\n if (!isSet(actual) || !Array.isArray(expected)) return false;\n const [low, high] = expected as (number | string)[];\n return (actual as number | string) >= low && (actual as number | string) <= high;\n }\n }\n}\n", "import type { JsonValue } from '../format/json';\nimport type { ListNode } from '../format/layout';\nimport type { Page } from '../format/page';\nimport type { ResolvedFilter, ResolvedFilterCondition } from './data-source';\nimport { fill } from './messages';\n\n/**\n * What a list's search bar holds, each shown as a chip: values searched in\n * one field (any of them), named filters (any of them), a custom filter, or\n * the fields the list is grouped by. The facets all apply together.\n */\nexport type Facet =\n | { kind: 'field'; field: string; label: string; values: { op: ResolvedFilterCondition['op']; value: JsonValue; label: string }[] }\n | { kind: 'filters'; ids: string[]; labels: string[] }\n | { kind: 'custom'; label: string; filter: ResolvedFilter[] }\n | { kind: 'groupBy'; fields: string[]; labels: string[] };\n\n/** One way to search what was typed: a field, how to compare, and the words that say so. */\nexport interface Suggestion {\n field: string;\n fieldLabel: string;\n op: ResolvedFilterCondition['op'];\n value: JsonValue;\n valueLabel: string;\n label: string;\n}\n\nconst TEXT = new Set(['char', 'text', 'html']);\nconst NUMBER = new Set(['integer', 'float', 'monetary']);\nconst LINK = new Set(['many2one', 'many2many']);\n\n/**\n * The searches the typed text can be: text looked for in each text field, a\n * choice whose label it matches, a number where it is one, a link by its\n * record's name. Only the list's search fields, the columns unless it says.\n */\nexport function suggestions(typed: string, page: Page, list: ListNode, words: { searchFor: string } = { searchFor: 'Search {field} for: {text}' }): Suggestion[] {\n const text = typed.trim();\n if (!text) return [];\n const found: Suggestion[] = [];\n for (const field of list.searchFields ?? list.columns) {\n const def = page.fields[field];\n if (!def) continue;\n const say = (op: Suggestion['op'], value: JsonValue, valueLabel: string, label?: string) =>\n found.push({ field, fieldLabel: def.label, op, value, valueLabel, label: label ?? fill(words.searchFor, { field: def.label, text }) });\n if (TEXT.has(def.type) || LINK.has(def.type)) say('ilike', text, text);\n else if (def.type === 'selection') {\n const lower = text.toLowerCase();\n for (const option of def.options) if (option.label.toLowerCase().includes(lower)) say('=', option.value, option.label, `${def.label}: ${option.label}`);\n } else if (NUMBER.has(def.type)) {\n const number = Number(text.replace(/[\\s,]/g, ''));\n if (text && Number.isFinite(number)) say('=', number, text);\n }\n }\n // Text fields first, then the choices, then the links: the order a person looks in.\n const rank = (s: Suggestion) => {\n const type = page.fields[s.field]?.type ?? '';\n return TEXT.has(type) ? 0 : type === 'selection' ? 1 : NUMBER.has(type) ? 2 : 3;\n };\n return found.map((s, i) => ({ s, i })).sort((a, b) => rank(a.s) - rank(b.s) || a.i - b.i).map(({ s }) => s);\n}\n\n/** The filter a list's facets make: the values of one field any of them, named filters any of them, the facets all together. */\nexport function facetsToFilter(facets: readonly Facet[], list: ListNode): ResolvedFilter[] {\n const filter: ResolvedFilter[] = [];\n for (const facet of facets) {\n if (facet.kind === 'field') {\n const conditions = facet.values.map((v) => ({ field: facet.field, op: v.op, value: v.value }));\n filter.push(conditions.length === 1 ? conditions[0] : { any: conditions });\n } else if (facet.kind === 'filters') {\n // A list's own filters have no valueFrom: their conditions are already values.\n const chosen = facet.ids.map((id) => (list.filters?.find((f) => f.id === id)?.filter ?? []) as ResolvedFilter[]).filter((items) => items.length);\n if (chosen.length === 1) filter.push(...chosen[0]);\n else if (chosen.length > 1) filter.push({ any: chosen.map((items) => (items.length === 1 ? items[0] : { all: items })) });\n } else if (facet.kind === 'custom') {\n filter.push(...facet.filter);\n }\n }\n return filter;\n}\n\n/** The fields a list is grouped by, in order, from its Group By facet. */\nexport function groupByFields(facets: readonly Facet[]): string[] {\n return facets.find((f): f is Extract<Facet, { kind: 'groupBy' }> => f.kind === 'groupBy')?.fields ?? [];\n}\n", "/**\n * Timers, injected. Core compiles without the DOM or Node's types, and tests\n * drive time by hand instead of waiting for it.\n */\nexport interface Scheduler {\n setTimeout(callback: () => void, ms: number): unknown;\n clearTimeout(handle: unknown): void;\n}\n\ninterface HostTimers {\n setTimeout(callback: () => void, ms: number): unknown;\n clearTimeout(handle: unknown): void;\n}\n\n/** The host's own timers: the browser's or Node's, whichever is running. */\nexport const hostScheduler: Scheduler = {\n setTimeout: (callback, ms) => (globalThis as unknown as HostTimers).setTimeout(callback, ms),\n clearTimeout: (handle) => (globalThis as unknown as HostTimers).clearTimeout(handle),\n};\n\n/** Resolve after `ms`, on the given scheduler. */\nexport function wait(ms: number, scheduler: Scheduler = hostScheduler): Promise<void> {\n return new Promise((resolve) => {\n scheduler.setTimeout(resolve, ms);\n });\n}\n", "import type { Field, Fields } from '../format/field';\nimport type { JsonValue } from '../format/json';\nimport type {\n DataSource,\n Group,\n GroupRequest,\n ListRequest,\n ListResult,\n LineOp,\n LinkOp,\n LoadRequest,\n OnchangeRequest,\n OnchangeResult,\n SaveRequest,\n SaveResult,\n SearchRequest,\n CreateRequest,\n SubmitRequest,\n SubmitResult,\n} from './data-source';\nimport { matchesFilter } from './filter';\nimport { wait, type Scheduler } from './scheduler';\nimport { structuredCopy, type Line, type RecordId, type RelatedRecord, type Value, type Values } from './values';\n\nexport interface MemoryDataSourceOptions {\n /** Records by model, then by id. */\n records?: Record<string, Record<string, Values>>;\n /** Recalculation rules by model, then by the field that changed. */\n onchange?: Record<string, Record<string, (values: Values) => Values>>;\n /** Warnings by model, then by the field that changed: a message, or null for none. */\n warnings?: Record<string, Record<string, (values: Values) => string | null>>;\n /** Which value names a record in search results, per model. Defaults to `name`. */\n labelField?: Record<string, string>;\n /** Answer after this long, so a demo shows its loading states. */\n delayMs?: number;\n scheduler?: Scheduler;\n}\n\nexport interface MemoryDataSource extends Required<DataSource> {\n readonly records: Record<string, Record<string, Values>>;\n readonly responses: SubmitRequest[];\n readonly calls: { method: keyof DataSource; request: unknown }[];\n}\n\n/**\n * A data source that keeps everything in memory. It implements the whole\n * interface, the way a backend would, so tests and demos exercise the same\n * paths a real adapter takes.\n */\nexport function createMemoryDataSource(options: MemoryDataSourceOptions = {}): MemoryDataSource {\n const records = structuredCopy(options.records ?? {});\n const responses: SubmitRequest[] = [];\n const calls: MemoryDataSource['calls'] = [];\n let lineIds = 1000;\n\n const pause = () => (options.delayMs ? wait(options.delayMs, options.scheduler) : Promise.resolve());\n const table = (model: string) => (records[model] ??= {});\n const labelOf = (model: string, id: RecordId) => {\n const value = table(model)[String(id)]?.[options.labelField?.[model] ?? 'name'];\n return typeof value === 'string' ? value : String(id);\n };\n const nextId = (model: string) => Math.max(0, ...Object.keys(table(model)).map(Number).filter(Number.isFinite)) + 1;\n const asId = (key: string): RecordId => (Number.isFinite(Number(key)) ? Number(key) : key);\n\n function applyLines(current: Line[], ops: LineOp[]): Line[] {\n let lines = [...current];\n for (const op of ops) {\n if (op.op === 'create') lines.push({ key: op.key, id: ++lineIds, values: structuredCopy(op.values) });\n else if (op.op === 'update') lines = lines.map((l) => (l.id === op.id ? { ...l, values: { ...l.values, ...structuredCopy(op.values) } } : l));\n else lines = lines.filter((l) => l.id !== op.id);\n }\n return lines;\n }\n\n function applyLinks(current: RelatedRecord[], ops: LinkOp[], model: string): RelatedRecord[] {\n let links = [...current];\n const related = (id: RecordId): RelatedRecord => ({ id, label: labelOf(model, id) });\n for (const op of ops) {\n if (op.op === 'link' && !links.some((r) => r.id === op.id)) links.push(related(op.id));\n else if (op.op === 'unlink') links = links.filter((r) => r.id !== op.id);\n else if (op.op === 'set') links = op.ids.map(related);\n else if (op.op === 'clear') links = [];\n }\n return links;\n }\n\n function relationOf(fields: Fields, name: string): string {\n const field: Field | undefined = fields[name];\n return field && 'relation' in field ? field.relation : name;\n }\n\n return {\n records,\n responses,\n calls,\n\n async load(request: LoadRequest): Promise<Values> {\n calls.push({ method: 'load', request });\n await pause();\n const stored = table(request.model)[String(request.id)];\n if (!stored) throw new Error(`No ${request.model} record with id ${request.id}`);\n return structuredCopy(stored);\n },\n\n async save(request: SaveRequest): Promise<SaveResult> {\n calls.push({ method: 'save', request });\n await pause();\n const id = request.id ?? nextId(request.model);\n const stored: Values = { ...(table(request.model)[String(id)] ?? {}), ...structuredCopy(request.changes.values) };\n for (const [name, ops] of Object.entries(request.changes.lines)) {\n stored[name] = applyLines((stored[name] as Line[] | undefined) ?? [], ops);\n }\n for (const [name, ops] of Object.entries(request.changes.links)) {\n stored[name] = applyLinks((stored[name] as RelatedRecord[] | undefined) ?? [], ops, relationOf(request.fields, name));\n }\n table(request.model)[String(id)] = stored;\n return { id, values: structuredCopy(stored) };\n },\n\n async onchange(request: OnchangeRequest): Promise<OnchangeResult> {\n calls.push({ method: 'onchange', request });\n await pause();\n const rule = options.onchange?.[request.model]?.[request.changed];\n const warn = options.warnings?.[request.model]?.[request.changed];\n const result: OnchangeResult = rule ? { values: rule(structuredCopy(request.values)) } : {};\n const warning = warn?.(structuredCopy(request.values));\n return warning ? { ...result, warning } : result;\n },\n\n async search(request: SearchRequest): Promise<RelatedRecord[]> {\n calls.push({ method: 'search', request });\n await pause();\n const query = request.query.trim().toLowerCase();\n return Object.entries(table(request.model))\n .filter(([, values]) => matchesFilter(values, request.filter ?? []))\n .map(([key]) => ({ id: asId(key), label: labelOf(request.model, asId(key)) }))\n .filter((record) => record.label.toLowerCase().includes(query))\n .slice(0, request.limit ?? 8);\n },\n\n async list(request: ListRequest): Promise<ListResult> {\n calls.push({ method: 'list', request });\n await pause();\n const matching = Object.entries(table(request.model))\n .filter(([, values]) => matchesFilter(values, request.filter))\n .map(([key, values]) => ({ id: asId(key), values }));\n matching.sort((a, b) => {\n for (const order of request.sort) {\n const compared = compareValues(a.values[order.field], b.values[order.field]);\n // Empty last, whichever way the rest goes.\n if (compared.empty) return compared.result;\n if (compared.result) return order.desc ? -compared.result : compared.result;\n }\n return 0;\n });\n return {\n total: matching.length,\n records: matching.slice(request.offset, request.offset + request.limit).map(({ id, values }) => ({\n id,\n values: Object.fromEntries(request.fields.map((field) => [field, structuredCopy(values[field] ?? null) as Value])),\n })),\n };\n },\n\n async groups(request: GroupRequest): Promise<Group[]> {\n calls.push({ method: 'groups', request });\n await pause();\n const counted = new Map<string, Group>();\n for (const values of Object.values(table(request.model))) {\n if (!matchesFilter(values, request.filter)) continue;\n const raw = values[request.field] ?? null;\n const link = raw !== null && typeof raw === 'object' && !Array.isArray(raw) && 'id' in raw ? (raw as RelatedRecord) : null;\n const value = (link ? link.id : raw) as JsonValue;\n const key = JSON.stringify(value);\n const group = counted.get(key) ?? { value, label: link ? link.label : raw === null || raw === '' ? '' : String(raw), count: 0 };\n group.count++;\n counted.set(key, group);\n }\n return [...counted.values()].sort((a, b) => (a.value === null) === (b.value === null) ? a.label.localeCompare(b.label) : a.value === null ? 1 : -1);\n },\n\n async create(request: CreateRequest): Promise<RelatedRecord> {\n calls.push({ method: 'create', request });\n await pause();\n const rows = table(request.model);\n const id = Object.keys(rows).reduce((top, key) => Math.max(top, Number(key) || 0), 0) + 1;\n rows[String(id)] = { name: request.name };\n return { id, label: request.name };\n },\n\n async submit(request: SubmitRequest): Promise<SubmitResult> {\n calls.push({ method: 'submit', request });\n await pause();\n responses.push(structuredCopy(request));\n return { id: responses.length };\n },\n };\n}\n\n/** Two values in order: a link by its label, text by the reader's rules, numbers by size; `empty` says one of them had nothing. */\nfunction compareValues(a: unknown, b: unknown): { result: number; empty: boolean } {\n const blank = (v: unknown) => v === null || v === undefined || v === '';\n if (blank(a) || blank(b)) return { result: blank(a) === blank(b) ? 0 : blank(a) ? 1 : -1, empty: blank(a) !== blank(b) };\n const label = (v: unknown) => (typeof v === 'object' && v !== null && 'label' in v ? (v as RelatedRecord).label : v);\n const [x, y] = [label(a), label(b)];\n if (typeof x === 'number' && typeof y === 'number') return { result: x - y, empty: false };\n return { result: String(x).localeCompare(String(y)), empty: false };\n}\n", "import type { Field, FilterItem, LineField } from '../format/field';\nimport type { JsonValue } from '../format/json';\nimport type { ButtonNode, LayoutNode, Modifier, RootLayout, StatButton, StepNode } from '../format/layout';\nimport type { Page } from '../format/page';\nimport { compileModifier, type CompiledModifier } from '../expression/modifier';\nimport { checkValue } from './check';\nimport { MESSAGES, type Messages } from './messages';\nimport { saveProblemOf, type DataSource, type LineOp, type LinkOp, type RecordChanges, type ResolvedFilter, type SaveProblem } from './data-source';\nimport { hostScheduler, type Scheduler } from './scheduler';\nimport {\n emptyValue,\n expressionContext,\n initialValues,\n isEmpty,\n lineKind,\n structuredCopy,\n type Line,\n type RecordId,\n type RelatedRecord,\n type Value,\n type Values,\n} from './values';\n\nexport type FormStatus = 'idle' | 'loading' | 'ready' | 'saving' | 'saved' | 'error';\n\nexport interface FormState {\n readonly status: FormStatus;\n readonly recordId: RecordId | null;\n readonly values: Readonly<Values>;\n /** Messages by field name; a line's field is `field.lineKey.subfield`. */\n readonly errors: Readonly<Record<string, string>>;\n /** Fields that differ from the record as loaded or last saved. */\n readonly dirty: readonly string[];\n /** A warning from the data source's onchange, shown without blocking. */\n readonly warning: string | null;\n /** The field whose change brought the warning, so it can be shown beside it. */\n readonly warningField: string | null;\n /** Why loading or saving failed. */\n readonly error: string | null;\n /** A saved draft that can be restored. */\n readonly draft: { savedAt: string } | null;\n /** The wizard step on screen, for a wizard page. */\n readonly step: string | null;\n /** Optional steps passed over with Skip: their answers are left out, and not asked for. */\n readonly skipped: readonly string[];\n /** Why the last save was refused, until the next one starts or the form is reset. */\n readonly saveProblem: SaveProblem | null;\n}\n\n/** What a layout element looks like right now. */\nexport interface NodeState {\n invisible: boolean;\n readonly: boolean;\n required: boolean;\n}\n\n/** localStorage fits this, and so does anything else with the same three methods. */\nexport interface DraftStore {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\nexport interface ActionRequest {\n /** The button or stat button pressed. */\n id: string;\n action: string;\n params?: { [key: string]: JsonValue };\n recordId: RecordId | null;\n values: Values;\n /** The records chosen in a list, when the button belongs to one. */\n recordIds?: RecordId[];\n}\n\nexport interface FormOptions {\n page: Page;\n dataSource?: DataSource;\n /** The record to edit. Leave out for a new record or a survey. */\n recordId?: RecordId | null;\n /** Values to start with, on top of each field's default. */\n values?: Values;\n /** What a button does. Fieldia hands the press over; the app decides. */\n onAction?: (request: ActionRequest) => void | Promise<void>;\n drafts?: { store: DraftStore; restore?: 'auto' | 'ask'; delayMs?: number };\n autosave?: { delayMs: number };\n scheduler?: Scheduler;\n /** Validation messages in the page's language. English by default. */\n messages?: Messages;\n}\n\nexport interface Form {\n readonly page: Page;\n getState(): FormState;\n subscribe(listener: (state: FormState) => void): () => void;\n load(): Promise<void>;\n setValue(name: string, value: Value): void;\n node(id: string): NodeState;\n fieldReadonly(name: string): boolean;\n /** What a field would be told if the form were checked now, or null when it passes. Nothing is shown. */\n problem(field: string): string | null;\n validate(): boolean;\n save(): Promise<boolean>;\n reset(): void;\n changes(): RecordChanges;\n addLine(field: string, values?: Values): string;\n updateLine(field: string, key: string, name: string, value: Value): void;\n removeLine(field: string, key: string): void;\n /** Move a line to another place among its lines, numbering its sequence field again. */\n moveLine(field: string, key: string, to: number): void;\n /**\n * What a line would become with these values once the data source's onchange\n * has run, as a line edited in a dialog shows its subtotal follow. Nothing is\n * written: the record, its changes and its autosave stay as they are.\n */\n previewLine(field: string, key: string, values: Values): Promise<Values>;\n /** Records a many2one, many2many or reference may point to. A reference needs `options.model`. */\n search(field: string, query: string, limit?: number, options?: { model?: string }): Promise<RelatedRecord[]>;\n /** The same, for a relation inside a one2many line, filtered by that line's values. */\n searchLine(field: string, key: string, subfield: string, query: string, limit?: number): Promise<RelatedRecord[]>;\n /** Whether a link field can make a record from a typed name: the data source must be able to. */\n canCreate(field: string): boolean;\n /** Make a record from a typed name, for the link field to point to. */\n quickCreate(field: string, name: string): Promise<RelatedRecord>;\n /** The same, for a link inside a one2many's lines. */\n canCreateLine(field: string, subfield: string): boolean;\n quickCreateLine(field: string, subfield: string, name: string): Promise<RelatedRecord>;\n steps(): string[];\n next(): boolean;\n back(): boolean;\n /** Pass over the step on screen, when it is optional and not the last one. */\n skip(): boolean;\n /**\n * Go to a step that applies. Back, at once; forward, only past steps that are\n * complete: it stops at the first one with a problem and shows it, and skips\n * an optional one instead.\n */\n goTo(step: string): boolean;\n /** Run a button; a list's button passes the records chosen in it. */\n runAction(id: string, chosen?: { recordIds: RecordId[] }): Promise<void>;\n restoreDraft(): void;\n discardDraft(): void;\n /** Resolves once every onchange, save and autosave started so far has finished. */\n settled(): Promise<void>;\n dispose(): void;\n}\n\ninterface IndexedNode {\n id: string;\n parent: string | null;\n kind: 'field' | 'button' | 'stat' | 'other' | 'step';\n field?: string;\n invisible: CompiledModifier;\n readonly: CompiledModifier;\n required: CompiledModifier;\n source: LayoutNode | StepNode | ButtonNode | StatButton | RootLayout | { id: string; invisible?: Modifier };\n}\n\n/**\n * The record state behind a page: values, what changed, what is visible and\n * required, errors, loading and saving. No DOM and no framework \u2014 every\n * binding renders from `getState()` and calls these methods.\n */\nexport function createForm(options: FormOptions): Form {\n const { page } = options;\n const scheduler = options.scheduler ?? hostScheduler;\n const messages = options.messages ?? MESSAGES.en;\n const index = indexLayout(page.layout);\n const steps = page.layout.type === 'wizard' ? page.layout.children.map((step) => step.id) : [];\n const draftKey = () => `fieldia:draft:${page.id}:${state.recordId ?? 'new'}`;\n\n let baseline: Values = { ...initialValues(page.fields), ...structuredCopy(options.values ?? {}) };\n let state: FormState = {\n status: options.recordId != null ? 'idle' : 'ready',\n recordId: options.recordId ?? null,\n values: structuredCopy(baseline),\n errors: {},\n dirty: [],\n warning: null,\n warningField: null,\n error: null,\n draft: null,\n step: steps[0] ?? null,\n skipped: [],\n saveProblem: null,\n };\n /** Field errors a refused save brought, each kept until its field changes from the value it was refused with. */\n let serverErrors: Record<string, { message: string; value: string }> = {};\n let lineKeys = 0;\n let onchangeSeq = 0;\n let draftTimer: unknown = null;\n let autosaveTimer: unknown = null;\n const pending = new Set<Promise<unknown>>();\n const listeners = new Set<(state: FormState) => void>();\n let contextCache: { values: Values; context: Record<string, unknown> } | null = null;\n\n function set(patch: Partial<FormState>) {\n state = { ...state, ...patch };\n for (const listener of [...listeners]) listener(state);\n }\n\n function track<T>(promise: Promise<T>): Promise<T> {\n pending.add(promise);\n const done = () => pending.delete(promise);\n promise.then(done, done);\n return promise;\n }\n\n function context(): Record<string, unknown> {\n if (contextCache?.values !== state.values) {\n contextCache = { values: state.values as Values, context: expressionContext(state.values as Values, page.fields) };\n }\n return contextCache.context;\n }\n\n function fieldDef(name: string): Field {\n const def = page.fields[name];\n if (!def) throw new Error(`The page has no field \"${name}\"`);\n return def;\n }\n\n function dirtyFields(values: Values): string[] {\n return Object.keys(page.fields).filter((name) => JSON.stringify(values[name] ?? null) !== JSON.stringify(baseline[name] ?? null));\n }\n\n function nodeState(id: string): NodeState {\n const node = index.get(id);\n if (!node) throw new Error(`The page has no element \"${id}\"`);\n const ctx = context();\n let invisible = node.invisible.evaluate(ctx);\n for (let parent = node.parent; !invisible && parent; parent = index.get(parent)?.parent ?? null) {\n invisible = index.get(parent)?.invisible.evaluate(ctx) ?? false;\n }\n // A section read-only right now makes everything inside it read-only too.\n let readonly = node.readonly.evaluate(ctx);\n for (let parent = node.parent; !readonly && parent; parent = index.get(parent)?.parent ?? null) {\n readonly = index.get(parent)?.readonly.evaluate(ctx) ?? false;\n }\n const def = node.field ? page.fields[node.field] : undefined;\n return {\n invisible,\n readonly: readonly || def?.readonly === true,\n required: node.required.evaluate(ctx) || def?.required === true,\n };\n }\n\n /** Field nodes inside `root` (or the whole page), visible right now. */\n function visibleFieldNodes(root?: string): IndexedNode[] {\n const inside = (node: IndexedNode) => {\n if (!root) return true;\n for (let at: string | null = node.id; at; at = index.get(at)?.parent ?? null) if (at === root) return true;\n return false;\n };\n // The whole page leaves out the steps passed over with Skip.\n const skipped = (node: IndexedNode) => {\n if (root || !state.skipped.length) return false;\n for (let at: string | null = node.id; at; at = index.get(at)?.parent ?? null) if (state.skipped.includes(at)) return true;\n return false;\n };\n return [...index.values()].filter((node) => node.kind === 'field' && inside(node) && !skipped(node) && !nodeState(node.id).invisible);\n }\n\n /** Errors for the visible fields under `root`, without publishing them. */\n function collectErrors(root?: string): Record<string, string> {\n const errors: Record<string, string> = {};\n for (const node of visibleFieldNodes(root)) {\n const name = node.field as string;\n if (errors[name]) continue;\n const def = page.fields[name];\n const message = checkValue(def, state.values[name], nodeState(node.id).required, messages);\n if (message) errors[name] = message;\n if (def.type === 'one2many') {\n for (const line of (state.values[name] as Line[] | null) ?? []) {\n // A section or note answers only for its text, never for what an item needs.\n const kind = lineKind(def, line.values);\n for (const [sub, subDef] of Object.entries(def.fields)) {\n if (kind && sub !== def.lineKinds?.text) continue;\n const lineMessage = checkValue(subDef, line.values[sub], subDef.required === true, messages);\n if (lineMessage) errors[`${name}.${line.key}.${sub}`] = lineMessage;\n }\n }\n }\n }\n return errors;\n }\n\n function writeValues(values: Values, extra: Partial<FormState> = {}) {\n const errors = Object.keys(state.errors).length ? revalidateShown(values) : state.errors;\n set({ values, dirty: dirtyFields(values), errors, ...extra });\n }\n\n /** Once errors are on screen, keep them current as the person fixes things. */\n function revalidateShown(values: Values): Record<string, string> {\n const previous = state;\n state = { ...state, values };\n const fresh = collectErrors(state.step ?? undefined);\n state = previous;\n const kept: Record<string, string> = {};\n for (const key of Object.keys(state.errors)) if (fresh[key]) kept[key] = fresh[key];\n for (const [name, refused] of Object.entries(serverErrors)) {\n if (JSON.stringify(values[name] ?? null) === refused.value) kept[name] ??= refused.message;\n else delete serverErrors[name];\n }\n return kept;\n }\n\n function scheduleDraft() {\n const drafts = options.drafts;\n if (!drafts) return;\n if (draftTimer !== null) scheduler.clearTimeout(draftTimer);\n draftTimer = scheduler.setTimeout(() => {\n draftTimer = null;\n drafts.store.setItem(draftKey(), JSON.stringify({ savedAt: new Date().toISOString(), values: state.values }));\n }, drafts.delayMs ?? 400);\n }\n\n function forgetDraft() {\n if (draftTimer !== null) scheduler.clearTimeout(draftTimer);\n draftTimer = null;\n options.drafts?.store.removeItem(draftKey());\n }\n\n function offerDraft() {\n const drafts = options.drafts;\n if (!drafts) return;\n const raw = drafts.store.getItem(draftKey());\n if (!raw) return;\n let draft: { savedAt: string; values: Values };\n try {\n draft = JSON.parse(raw);\n } catch {\n drafts.store.removeItem(draftKey());\n return;\n }\n if (drafts.restore === 'auto') writeValues({ ...state.values, ...draft.values }, { draft: null });\n else set({ draft: { savedAt: draft.savedAt } });\n }\n\n function scheduleAutosave() {\n const autosave = options.autosave;\n if (!autosave || page.data.kind !== 'record') return;\n if (autosaveTimer !== null) scheduler.clearTimeout(autosaveTimer);\n autosaveTimer = scheduler.setTimeout(() => {\n autosaveTimer = null;\n if (state.dirty.length && Object.keys(collectErrors()).length === 0) void track(save());\n }, autosave.delayMs);\n }\n\n function runOnchange(changed: string) {\n const source = options.dataSource;\n if (!source?.onchange || page.data.kind !== 'record') return;\n const seq = ++onchangeSeq;\n const request = { model: page.data.model, id: state.recordId, changed, values: structuredCopy(state.values as Values) };\n void track(\n source.onchange(request).then(\n (result) => {\n if (seq !== onchangeSeq) return;\n const values = { ...(state.values as Values), ...(result.values ?? {}) };\n writeValues(values, { warning: result.warning ?? null, warningField: result.warning ? changed : null });\n },\n () => undefined\n )\n );\n }\n\n function afterEdit(changed: string) {\n scheduleDraft();\n scheduleAutosave();\n runOnchange(changed);\n }\n\n function changes(): RecordChanges {\n const result: RecordChanges = { values: {}, lines: {}, links: {} };\n // A new record sends every value it holds, those it started with and defaults\n // included; a stored one sends only what changed since it was loaded.\n const creating = state.recordId === null || state.recordId === undefined;\n const names = creating\n ? Object.keys(page.fields).filter((name) => state.dirty.includes(name) || !isEmpty(page.fields[name], state.values[name]))\n : state.dirty;\n for (const name of names) {\n const def = page.fields[name];\n const now = state.values[name];\n const before = creating ? emptyValue(def) : baseline[name];\n if (def.type === 'one2many') result.lines[name] = lineOps((before as Line[] | null) ?? [], (now as Line[] | null) ?? []);\n else if (def.type === 'many2many') result.links[name] = linkOps((before as RelatedRecord[] | null) ?? [], (now as RelatedRecord[] | null) ?? []);\n else result.values[name] = structuredCopy(now) as Value;\n }\n return result;\n }\n\n /** The values to submit: only fields a visible question shows. */\n function shownValues(): Values {\n const shown: Values = {};\n for (const node of visibleFieldNodes()) {\n const name = node.field as string;\n shown[name] = structuredCopy(state.values[name]) as Value;\n }\n return shown;\n }\n\n async function save(): Promise<boolean> {\n const errors = collectErrors();\n if (Object.keys(errors).length) {\n set({ errors });\n return false;\n }\n const source = options.dataSource;\n serverErrors = {};\n set({ status: 'saving', errors: {}, error: null, saveProblem: null });\n try {\n if (page.data.kind === 'responses') {\n if (!source?.submit) throw new Error('This page has no data source to send its answers to');\n await source.submit({ pageId: page.id, values: shownValues() });\n forgetDraft();\n set({ status: 'saved' });\n return true;\n }\n if (!source?.save) throw new Error('This page has no data source to save to');\n const result = await source.save({\n model: page.data.model,\n id: state.recordId,\n fields: page.fields,\n changes: changes(),\n values: structuredCopy(state.values as Values),\n });\n forgetDraft();\n const values = result.values ? { ...(state.values as Values), ...result.values } : (state.values as Values);\n baseline = structuredCopy(values);\n set({ status: 'saved', recordId: result.id, values, dirty: [] });\n return true;\n } catch (error) {\n const problem = saveProblemOf(error);\n const fields = problem.kind === 'fields' ? problem.fields ?? {} : {};\n serverErrors = Object.fromEntries(Object.entries(fields).map(([name, message]) => [name, { message, value: JSON.stringify(state.values[name] ?? null) }]));\n set({ status: 'error', error: problem.message, saveProblem: problem, errors: { ...fields } });\n return false;\n }\n }\n\n /** The model a link field's new record belongs to, or null when it cannot make one. */\n function creatable(def: Field | LineField | undefined): string | null {\n if (!options.dataSource?.create || !def || def.readonly) return null;\n return def.type === 'many2one' || def.type === 'many2many' ? def.relation : null;\n }\n\n async function runCreate(def: Field | LineField | undefined, name: string, typed: string): Promise<RelatedRecord> {\n const model = creatable(def);\n const source = options.dataSource;\n if (!model || !source?.create) throw new Error(`\"${name}\" cannot make records: its data source has no create, or it is not a link`);\n return track(source.create({ model, name: typed.trim() }));\n }\n\n async function runSearch(\n def: Field | LineField,\n name: string,\n ctx: Record<string, unknown>,\n query: string,\n limit: number,\n model?: string\n ): Promise<RelatedRecord[]> {\n if (def.type !== 'many2one' && def.type !== 'many2many' && def.type !== 'reference') {\n throw new Error(`\"${name}\" is not a many2one, many2many or reference`);\n }\n if (def.type === 'reference' && !model) throw new Error(`Searching \"${name}\" needs a model`);\n const source = options.dataSource;\n if (!source?.search) return [];\n // Every valueFrom, in groups too, becomes the value it names before the search goes out.\n const resolve = (item: FilterItem): ResolvedFilter =>\n 'any' in item\n ? { any: item.any.map(resolve) }\n : 'all' in item\n ? { all: item.all.map(resolve) }\n : { field: item.field, op: item.op, value: (item.valueFrom !== undefined ? ctx[item.valueFrom] ?? null : item.value ?? null) as JsonValue };\n const filter: ResolvedFilter[] | undefined = def.type === 'reference' ? undefined : def.filter?.map(resolve);\n const relation = def.type === 'reference' ? (model as string) : def.relation;\n return track(source.search({ model: relation, query, ...(filter ? { filter } : {}), limit }));\n }\n\n function lineField(field: string) {\n const def = fieldDef(field);\n if (def.type !== 'one2many') throw new Error(`\"${field}\" is a ${def.type}, not a one2many`);\n return def;\n }\n\n function stepIndex(): number {\n return state.step ? steps.indexOf(state.step) : -1;\n }\n\n /** Whether a step can be passed over with Skip. */\n function optionalStep(id: string): boolean {\n return (index.get(id)?.source as { optional?: boolean } | undefined)?.optional === true;\n }\n\n async function load(): Promise<void> {\n const source = options.dataSource;\n if (state.recordId == null || page.data.kind !== 'record') return;\n if (!source?.load) {\n set({ status: 'error', error: 'This page has no data source to load from' });\n return;\n }\n set({ status: 'loading', error: null });\n try {\n const loaded = await source.load({ model: page.data.model, id: state.recordId, fields: page.fields });\n baseline = { ...initialValues(page.fields), ...loaded };\n set({ status: 'ready', values: structuredCopy(baseline), dirty: [], errors: {} });\n offerDraft();\n } catch (error) {\n set({ status: 'error', error: (error as Error).message });\n }\n }\n\n const form: Form = {\n page,\n getState: () => state,\n\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n\n load: () => track(load()),\n\n setValue(name, value) {\n fieldDef(name);\n writeValues({ ...(state.values as Values), [name]: structuredCopy(value) });\n afterEdit(name);\n },\n\n node: nodeState,\n\n fieldReadonly: (name) => fieldDef(name).readonly === true,\n\n problem(name) {\n const def = fieldDef(name);\n // Only a field someone can see is asked anything, and required wherever it is shown so.\n const shown = visibleFieldNodes().filter((node) => node.field === name);\n if (!shown.length) return null;\n return checkValue(def, state.values[name], shown.some((node) => nodeState(node.id).required), messages) ?? null;\n },\n\n validate() {\n const errors = collectErrors();\n set({ errors });\n return Object.keys(errors).length === 0;\n },\n\n save: () => track(save()),\n\n reset() {\n forgetDraft();\n serverErrors = {};\n set({ values: structuredCopy(baseline), dirty: [], errors: {}, warning: null, warningField: null, draft: null, step: steps[0] ?? null, skipped: [], saveProblem: null });\n },\n\n changes,\n\n addLine(field, values = {}) {\n const def = lineField(field);\n const key = `new-${++lineKeys}`;\n const current = (state.values[field] as Line[] | null) ?? [];\n const line: Line = { key, values: { ...initialValues(def.fields as Record<string, LineField>), ...structuredCopy(values) } };\n // A new line comes last, so it is numbered after the last.\n if (def.sequenceField && line.values[def.sequenceField] == null) {\n const numbers = current.map((l) => l.values[def.sequenceField as string]).filter((n): n is number => typeof n === 'number');\n line.values[def.sequenceField] = numbers.length ? Math.max(...numbers) + 1 : 1;\n }\n const lines = [...current, line];\n writeValues({ ...(state.values as Values), [field]: lines });\n afterEdit(field);\n return key;\n },\n\n updateLine(field, key, name, value) {\n const def = lineField(field);\n if (!def.fields[name]) throw new Error(`The lines of \"${field}\" have no field \"${name}\"`);\n const lines = ((state.values[field] as Line[] | null) ?? []).map((line) =>\n line.key === key ? { ...line, values: { ...line.values, [name]: structuredCopy(value) } } : line\n );\n writeValues({ ...(state.values as Values), [field]: lines });\n afterEdit(field);\n },\n\n moveLine(field, key, to) {\n const def = lineField(field);\n const sequence = def.sequenceField;\n if (!sequence) throw new Error(`The lines of \"${field}\" keep no order: give the field a sequenceField`);\n const lines = [...((state.values[field] as Line[] | null) ?? [])];\n const from = lines.findIndex((line) => line.key === key);\n if (from < 0) throw new Error(`\"${field}\" has no line \"${key}\"`);\n const target = Math.max(0, Math.min(to, lines.length - 1));\n if (target === from) return;\n // The numbers can be reused only if they rise with the lines as shown.\n const before = lines.map((line) => line.values[sequence]);\n const trusted = before.every((n, i) => typeof n === 'number' && (i === 0 || n > (before[i - 1] as number)));\n lines.splice(target, 0, ...lines.splice(from, 1));\n // The lines that moved take the numbers they held between them, in their\n // new order, and the rest keep theirs; otherwise every line is numbered\n // afresh, 1, 2, 3\u2026, so the order saved is the order shown.\n const low = Math.min(from, target);\n const high = Math.max(from, target);\n const pool = trusted ? (before.slice(low, high + 1) as number[]) : [];\n const renumbered = lines.map((line, i) => {\n const value = trusted ? (i >= low && i <= high ? pool[i - low] : line.values[sequence]) : i + 1;\n return value === line.values[sequence] ? line : { ...line, values: { ...line.values, [sequence]: value } };\n });\n writeValues({ ...(state.values as Values), [field]: renumbered });\n afterEdit(field);\n },\n\n removeLine(field, key) {\n lineField(field);\n const lines = ((state.values[field] as Line[] | null) ?? []).filter((line) => line.key !== key);\n writeValues({ ...(state.values as Values), [field]: lines });\n afterEdit(field);\n },\n\n async search(field, query, limit = 8, options = {}) {\n return runSearch(fieldDef(field), field, context(), query, limit, options.model);\n },\n\n async previewLine(field, key, values) {\n lineField(field);\n const lines = (state.values[field] as Line[] | null) ?? [];\n const line = lines.find((l) => l.key === key);\n if (!line) throw new Error(`\"${field}\" has no line \"${key}\"`);\n const merged = { ...line.values, ...values };\n const source = options.dataSource;\n if (!source?.onchange || page.data.kind !== 'record') return merged;\n const changed = lines.map((l) => (l.key === key ? { ...l, values: merged } : l));\n const result = await source.onchange({ model: page.data.model, id: state.recordId, changed: field, values: structuredCopy({ ...(state.values as Values), [field]: changed }) });\n const after = ((result.values?.[field] as Line[] | undefined) ?? []).find((l) => l.key === key);\n return after ? { ...merged, ...after.values } : merged;\n },\n\n async searchLine(field, key, subfield, query, limit = 8) {\n const def = lineField(field);\n const sub = def.fields[subfield];\n if (!sub) throw new Error(`The lines of \"${field}\" have no field \"${subfield}\"`);\n const line = ((state.values[field] as Line[] | null) ?? []).find((l) => l.key === key);\n if (!line) throw new Error(`\"${field}\" has no line \"${key}\"`);\n return runSearch(sub, subfield, expressionContext(line.values, def.fields as Record<string, LineField>), query, limit);\n },\n\n canCreate: (field) => creatable(page.fields[field]) !== null,\n quickCreate: (field, typed) => runCreate(page.fields[field], field, typed),\n canCreateLine: (field, subfield) => creatable(lineField(field).fields[subfield]) !== null,\n quickCreateLine: (field, subfield, typed) => runCreate(lineField(field).fields[subfield], subfield, typed),\n\n steps: () => steps.filter((id) => !nodeState(id).invisible),\n\n next() {\n if (!state.step) return false;\n // A step skipped before and gone back to is answered now, and checked like any other.\n if (state.skipped.includes(state.step)) set({ skipped: state.skipped.filter((id) => id !== state.step) });\n const errors = collectErrors(state.step);\n if (Object.keys(errors).length) {\n set({ errors });\n return false;\n }\n const visible = form.steps();\n const following = steps.slice(stepIndex() + 1).find((id) => visible.includes(id));\n if (!following) return false;\n set({ step: following, errors: {} });\n return true;\n },\n\n back() {\n if (!state.step) return false;\n const visible = form.steps();\n const previous = steps.slice(0, stepIndex()).reverse().find((id) => visible.includes(id));\n if (!previous) return false;\n set({ step: previous, errors: {} });\n return true;\n },\n\n skip() {\n const current = state.step;\n if (!current || !optionalStep(current)) return false;\n const visible = form.steps();\n const following = visible[visible.indexOf(current) + 1];\n if (!following) return false;\n set({ step: following, errors: {}, skipped: [...state.skipped.filter((id) => id !== current), current] });\n return true;\n },\n\n goTo(target) {\n const visible = form.steps();\n const to = visible.indexOf(target);\n const at = state.step ? visible.indexOf(state.step) : -1;\n if (to === -1 || at === -1) return false;\n if (to <= at) {\n set({ step: target, errors: {} });\n return true;\n }\n const skipped = [...state.skipped];\n for (const id of visible.slice(at, to)) {\n if (skipped.includes(id)) continue;\n const errors = collectErrors(id);\n if (!Object.keys(errors).length) continue;\n if (optionalStep(id)) {\n skipped.push(id);\n continue;\n }\n set({ step: id, errors, skipped });\n return false;\n }\n set({ step: target, errors: {}, skipped });\n return true;\n },\n\n async runAction(id, chosen) {\n const node = index.get(id);\n if (!node || (node.kind !== 'button' && node.kind !== 'stat')) throw new Error(`The page has no button \"${id}\"`);\n if (nodeState(id).invisible) return;\n const source = node.source as ButtonNode | StatButton;\n await track(\n Promise.resolve(\n options.onAction?.({\n id,\n action: source.action,\n ...('params' in source && source.params ? { params: source.params } : {}),\n recordId: state.recordId,\n values: structuredCopy(state.values as Values),\n ...(chosen ? { recordIds: [...chosen.recordIds] } : {}),\n })\n )\n );\n },\n\n restoreDraft() {\n const raw = options.drafts?.store.getItem(draftKey());\n if (!raw) return;\n const draft = JSON.parse(raw) as { values: Values };\n writeValues({ ...(state.values as Values), ...draft.values }, { draft: null });\n },\n\n discardDraft() {\n forgetDraft();\n set({ draft: null });\n },\n\n async settled() {\n while (pending.size) await Promise.allSettled([...pending]);\n },\n\n dispose() {\n if (draftTimer !== null) scheduler.clearTimeout(draftTimer);\n if (autosaveTimer !== null) scheduler.clearTimeout(autosaveTimer);\n listeners.clear();\n },\n };\n\n if (state.recordId == null) offerDraft();\n return form;\n}\n\nfunction lineOps(before: Line[], now: Line[]): LineOp[] {\n const ops: LineOp[] = [];\n const old = new Map(before.filter((line) => line.id !== undefined).map((line) => [line.key, line]));\n for (const line of now) {\n const previous = old.get(line.key);\n if (line.id === undefined || !previous) {\n ops.push({ op: 'create', key: line.key, values: structuredCopy(line.values) });\n continue;\n }\n const changed: Values = {};\n for (const [name, value] of Object.entries(line.values)) {\n if (JSON.stringify(value) !== JSON.stringify(previous.values[name])) changed[name] = structuredCopy(value) as Value;\n }\n if (Object.keys(changed).length) ops.push({ op: 'update', id: line.id, values: changed });\n }\n const kept = new Set(now.map((line) => line.key));\n for (const line of before) if (line.id !== undefined && !kept.has(line.key)) ops.push({ op: 'delete', id: line.id });\n return ops;\n}\n\nfunction linkOps(before: RelatedRecord[], now: RelatedRecord[]): LinkOp[] {\n const had = new Set(before.map((r) => r.id));\n const has = new Set(now.map((r) => r.id));\n return [\n ...now.filter((r) => !had.has(r.id)).map((r): LinkOp => ({ op: 'link', id: r.id })),\n ...before.filter((r) => !has.has(r.id)).map((r): LinkOp => ({ op: 'unlink', id: r.id })),\n ];\n}\n\nfunction indexLayout(root: RootLayout): Map<string, IndexedNode> {\n const index = new Map<string, IndexedNode>();\n const add = (\n source: IndexedNode['source'],\n parent: string | null,\n kind: IndexedNode['kind'],\n modifiers: { invisible?: Modifier; readonly?: Modifier; required?: Modifier; field?: string }\n ) => {\n index.set(source.id, {\n id: source.id,\n parent,\n kind,\n field: modifiers.field,\n invisible: compileModifier(modifiers.invisible),\n readonly: compileModifier(modifiers.readonly),\n required: compileModifier(modifiers.required),\n source,\n });\n };\n const walk = (nodes: LayoutNode[], parent: string) => {\n for (const node of nodes) {\n if (node.type === 'field') {\n add(node, parent, 'field', { invisible: node.invisible, readonly: node.readonly, required: node.required, field: node.field });\n } else if (node.type === 'button') {\n add(node, parent, 'button', { invisible: node.invisible });\n } else if (node.type === 'tabs') {\n add(node, parent, 'other', { invisible: node.invisible });\n for (const tab of node.children) {\n add(tab, node.id, 'other', { invisible: tab.invisible });\n walk(tab.children, tab.id);\n }\n } else if (node.type === 'section') {\n add(node, parent, 'other', { invisible: node.invisible, readonly: node.readonly });\n walk(node.children, node.id);\n } else {\n add(node, parent, 'other', { invisible: node.invisible });\n }\n }\n };\n\n if (root.type === 'tabs') {\n walk([root], '');\n index.get(root.id)!.parent = null;\n return index;\n }\n add(root, null, 'other', {});\n if (root.type === 'wizard') {\n for (const step of root.children) {\n add(step, root.id, 'step', { invisible: step.invisible });\n walk(step.children, step.id);\n }\n } else if (root.type === 'sections') {\n walk(root.children, root.id);\n } else if (root.type === 'list') {\n // A list holds no fields of its own record: only the buttons for what is selected.\n for (const button of root.actions ?? []) add(button, root.id, 'button', { invisible: button.invisible });\n } else {\n // The title and statusbar show fields too, so they are validated like\n // any field node. Their ids start with \"#\", which no page id can.\n const shown = (id: string, field: string | undefined) => {\n if (field) add({ id }, root.id, 'field', { field });\n };\n shown('#title', root.title?.field);\n shown('#subtitle', root.title?.subtitleField);\n shown('#avatar', root.title?.avatarField);\n shown('#statusbar', root.statusbar?.field);\n for (const button of root.buttons ?? []) add(button, root.id, 'button', { invisible: button.invisible });\n for (const stat of root.statButtons ?? []) add(stat, root.id, 'stat', { invisible: stat.invisible });\n if (root.ribbon) add(root.ribbon, root.id, 'other', { invisible: root.ribbon.invisible });\n for (const alert of root.alerts ?? []) add(alert, root.id, 'other', { invisible: alert.invisible });\n for (const badge of root.badges ?? []) add(badge, root.id, 'other', { invisible: badge.invisible });\n // Fields over and under the title are field nodes like any other.\n walk([...(root.title?.above ?? []), ...(root.title?.below ?? [])], root.id);\n walk(root.children, root.id);\n if (root.sidePanel) add(root.sidePanel, root.id, 'other', { invisible: root.sidePanel.invisible });\n }\n return index;\n}\n", "import type { Locale } from '@fieldia/core';\n\n/**\n * Numbers as a reader of the page's language writes them: grouped, with a\n * field's decimals, in Latin digits (as business software in Arabic shows\n * them), and read back the same way. Shared by the number widget, the lines\n * grid and totals.\n */\n\nconst formats = new Map<string, Intl.NumberFormat>();\nfunction format(locale: Locale, decimals: number): Intl.NumberFormat {\n const key = `${locale}:${decimals}`;\n let found = formats.get(key);\n if (!found) {\n found = new Intl.NumberFormat(locale, { numberingSystem: 'latn', minimumFractionDigits: decimals, maximumFractionDigits: decimals });\n formats.set(key, found);\n }\n return found;\n}\n\n/** The language's grouping and decimal marks. */\nfunction marks(locale: Locale): { group: string; decimal: string } {\n const parts = format(locale, 1).formatToParts(12345.6);\n return { group: parts.find((p) => p.type === 'group')?.value ?? ',', decimal: parts.find((p) => p.type === 'decimal')?.value ?? '.' };\n}\n\n/** A number at rest: \"1,850,000.50\", \"1.850.000,50\". */\nexport function formatNumber(value: number, decimals: number, locale: Locale = 'en'): string {\n return format(locale, decimals).format(value);\n}\n\n/**\n * Typed text as a number in JavaScript's own spelling (\"1234.5\"), or the text\n * unchanged when it is not one. Arabic-Indic digits are read as digits.\n */\nexport function normalizeNumber(text: string, locale: Locale = 'en'): string {\n const { group, decimal } = marks(locale);\n let out = text\n .replace(/[\u0660-\u0669]/g, (d) => String(d.charCodeAt(0) - 0x0660))\n .replace(/[\u06F0-\u06F9]/g, (d) => String(d.charCodeAt(0) - 0x06f0))\n .replace(/\u066B/g, decimal)\n .replace(/\u066C/g, group);\n // Spaces of any width group digits too (French uses a narrow no-break space).\n out = out.replace(/[\\s\\u00a0\\u202f]/g, '');\n if (group.trim()) out = out.split(group).join('');\n return decimal === '.' ? out : out.split(decimal).join('.');\n}\n", "import type { Locale } from '@fieldia/core';\n\n/** Every word a widget shows on its own. `{label}` and `{name}` are filled in. */\nexport interface WidgetLabels {\n search: string;\n noResults: string;\n remove: string;\n clear: string;\n addLine: string;\n addSection: string;\n addNote: string;\n deleteLine: string;\n /** Heads the row that adds up a table's number columns. */\n total: string;\n /** A problem on one line of a table, under the table. `{n}` counts from 1. */\n lineProblem: string;\n /** Problems beyond the first few. */\n moreProblems: string;\n /** The choice that makes a new record from what was typed. `{name}` is filled in. */\n createNamed: string;\n /** Choices at the end of a link's list, and the button that opens the linked record (`{name}`). */\n createAndEdit: string;\n searchMore: string;\n openNamed: string;\n /** The button that opens a line of a table in a dialog. */\n openLine: string;\n /** The button that lets a person hide or show a table's optional columns. */\n chooseColumns: string;\n /** The button beside a date that opens its calendar. */\n chooseDate: string;\n previousMonth: string;\n nextMonth: string;\n /** Heads the column of week numbers: short, and in full. */\n weekShort: string;\n week: string;\n /** The formatted-text toolbar and its buttons. */\n formatting: string;\n bold: string;\n italic: string;\n underline: string;\n textStyle: string;\n paragraph: string;\n heading: string;\n subheading: string;\n bulletList: string;\n numberList: string;\n alignLeft: string;\n alignCenter: string;\n alignRight: string;\n link: string;\n linkAddress: string;\n applyLink: string;\n removeLink: string;\n upload: string;\n uploadImage: string;\n replace: string;\n removeFile: string;\n dropHere: string;\n invalidJson: string;\n}\n\nexport const WIDGET_LABELS: Record<Locale, WidgetLabels> = {\n en: {\n search: 'Search\u2026',\n noResults: 'No results',\n remove: 'Remove {name}',\n clear: 'Clear {label}',\n addLine: 'Add a line',\n addSection: 'Add a section',\n addNote: 'Add a note',\n deleteLine: 'Delete line',\n total: 'Total',\n lineProblem: 'Line {n}: {message}',\n moreProblems: 'and {n} more',\n chooseColumns: 'Choose columns',\n createNamed: 'Create \u201C{name}\u201D',\n createAndEdit: 'Create and edit\u2026',\n searchMore: 'Search more\u2026',\n openNamed: 'Open {name}',\n openLine: 'Open line',\n chooseDate: 'Choose a date',\n previousMonth: 'Previous month',\n nextMonth: 'Next month',\n weekShort: 'Wk',\n week: 'Week',\n formatting: 'Formatting',\n bold: 'Bold',\n italic: 'Italic',\n underline: 'Underline',\n textStyle: 'Text style',\n paragraph: 'Paragraph',\n heading: 'Heading',\n subheading: 'Subheading',\n bulletList: 'Bulleted list',\n numberList: 'Numbered list',\n alignLeft: 'Align left',\n alignCenter: 'Align centre',\n alignRight: 'Align right',\n link: 'Link',\n linkAddress: 'Link address',\n applyLink: 'Apply',\n removeLink: 'Remove link',\n upload: 'Upload a file',\n uploadImage: 'Add a photo',\n replace: 'Replace',\n removeFile: 'Remove',\n dropHere: 'or drop it here',\n invalidJson: 'Not valid JSON',\n },\n ar: {\n search: '\u0628\u062D\u062B\u2026',\n noResults: '\u0644\u0627 \u062A\u0648\u062C\u062F \u0646\u062A\u0627\u0626\u062C',\n remove: '\u0625\u0632\u0627\u0644\u0629 {name}',\n clear: '\u0645\u0633\u062D {label}',\n addLine: '\u0625\u0636\u0627\u0641\u0629 \u0633\u0637\u0631',\n addSection: '\u0625\u0636\u0627\u0641\u0629 \u0642\u0633\u0645',\n addNote: '\u0625\u0636\u0627\u0641\u0629 \u0645\u0644\u0627\u062D\u0638\u0629',\n deleteLine: '\u062D\u0630\u0641 \u0627\u0644\u0633\u0637\u0631',\n total: '\u0627\u0644\u0625\u062C\u0645\u0627\u0644\u064A',\n lineProblem: '\u0627\u0644\u0633\u0637\u0631 {n}: {message}',\n moreProblems: '\u0648{n} \u0623\u062E\u0631\u0649',\n chooseColumns: '\u0627\u062E\u062A\u064A\u0627\u0631 \u0627\u0644\u0623\u0639\u0645\u062F\u0629',\n createNamed: '\u0625\u0646\u0634\u0627\u0621 \u00AB{name}\u00BB',\n createAndEdit: '\u0625\u0646\u0634\u0627\u0621 \u0648\u062A\u0639\u062F\u064A\u0644\u2026',\n searchMore: '\u0628\u062D\u062B \u0645\u0648\u0633\u0651\u0639\u2026',\n openNamed: '\u0641\u062A\u062D {name}',\n openLine: '\u0641\u062A\u062D \u0627\u0644\u0633\u0637\u0631',\n chooseDate: '\u0627\u062E\u062A\u064A\u0627\u0631 \u062A\u0627\u0631\u064A\u062E',\n previousMonth: '\u0627\u0644\u0634\u0647\u0631 \u0627\u0644\u0633\u0627\u0628\u0642',\n nextMonth: '\u0627\u0644\u0634\u0647\u0631 \u0627\u0644\u062A\u0627\u0644\u064A',\n weekShort: '\u0623\u0633\u0628\u0648\u0639',\n week: '\u0627\u0644\u0623\u0633\u0628\u0648\u0639',\n formatting: '\u0627\u0644\u062A\u0646\u0633\u064A\u0642',\n bold: '\u063A\u0627\u0645\u0642',\n italic: '\u0645\u0627\u0626\u0644',\n underline: '\u062A\u0633\u0637\u064A\u0631',\n textStyle: '\u0646\u0645\u0637 \u0627\u0644\u0646\u0635',\n paragraph: '\u0641\u0642\u0631\u0629',\n heading: '\u0639\u0646\u0648\u0627\u0646',\n subheading: '\u0639\u0646\u0648\u0627\u0646 \u0641\u0631\u0639\u064A',\n bulletList: '\u0642\u0627\u0626\u0645\u0629 \u0646\u0642\u0637\u064A\u0629',\n numberList: '\u0642\u0627\u0626\u0645\u0629 \u0645\u0631\u0642\u0645\u0629',\n alignLeft: '\u0645\u062D\u0627\u0630\u0627\u0629 \u0644\u0644\u064A\u0633\u0627\u0631',\n alignCenter: '\u062A\u0648\u0633\u064A\u0637',\n alignRight: '\u0645\u062D\u0627\u0630\u0627\u0629 \u0644\u0644\u064A\u0645\u064A\u0646',\n link: '\u0631\u0627\u0628\u0637',\n linkAddress: '\u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0631\u0627\u0628\u0637',\n applyLink: '\u062A\u0637\u0628\u064A\u0642',\n removeLink: '\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0631\u0627\u0628\u0637',\n upload: '\u0631\u0641\u0639 \u0645\u0644\u0641',\n uploadImage: '\u0625\u0636\u0627\u0641\u0629 \u0635\u0648\u0631\u0629',\n replace: '\u0627\u0633\u062A\u0628\u062F\u0627\u0644',\n removeFile: '\u0625\u0632\u0627\u0644\u0629',\n dropHere: '\u0623\u0648 \u0623\u0641\u0644\u062A\u0647 \u0647\u0646\u0627',\n invalidJson: '\u0644\u064A\u0633 JSON \u0635\u0627\u0644\u062D\u064B\u0627',\n },\n de: {\n search: 'Suchen\u2026',\n noResults: 'Keine Ergebnisse',\n remove: '{name} entfernen',\n clear: '{label} leeren',\n addLine: 'Zeile hinzuf\u00FCgen',\n addSection: 'Abschnitt hinzuf\u00FCgen',\n addNote: 'Notiz hinzuf\u00FCgen',\n deleteLine: 'Zeile l\u00F6schen',\n total: 'Summe',\n lineProblem: 'Zeile {n}: {message}',\n moreProblems: 'und {n} weitere',\n chooseColumns: 'Spalten ausw\u00E4hlen',\n createNamed: '\u201E{name}\u201C anlegen',\n createAndEdit: 'Anlegen und bearbeiten\u2026',\n searchMore: 'Weitere suchen\u2026',\n openNamed: '{name} \u00F6ffnen',\n openLine: 'Zeile \u00F6ffnen',\n chooseDate: 'Datum ausw\u00E4hlen',\n previousMonth: 'Vorheriger Monat',\n nextMonth: 'N\u00E4chster Monat',\n weekShort: 'KW',\n week: 'Kalenderwoche',\n formatting: 'Formatierung',\n bold: 'Fett',\n italic: 'Kursiv',\n underline: 'Unterstrichen',\n textStyle: 'Textstil',\n paragraph: 'Absatz',\n heading: '\u00DCberschrift',\n subheading: 'Unter\u00FCberschrift',\n bulletList: 'Aufz\u00E4hlung',\n numberList: 'Nummerierte Liste',\n alignLeft: 'Linksb\u00FCndig',\n alignCenter: 'Zentriert',\n alignRight: 'Rechtsb\u00FCndig',\n link: 'Link',\n linkAddress: 'Linkadresse',\n applyLink: '\u00DCbernehmen',\n removeLink: 'Link entfernen',\n upload: 'Datei hochladen',\n uploadImage: 'Foto hinzuf\u00FCgen',\n replace: 'Ersetzen',\n removeFile: 'Entfernen',\n dropHere: 'oder hier ablegen',\n invalidJson: 'Kein g\u00FCltiges JSON',\n },\n fr: {\n search: 'Rechercher\u2026',\n noResults: 'Aucun r\u00E9sultat',\n remove: 'Retirer {name}',\n clear: 'Effacer {label}',\n addLine: 'Ajouter une ligne',\n addSection: 'Ajouter une section',\n addNote: 'Ajouter une note',\n deleteLine: 'Supprimer la ligne',\n total: 'Total',\n lineProblem: 'Ligne {n} : {message}',\n moreProblems: 'et {n} de plus',\n chooseColumns: 'Choisir les colonnes',\n createNamed: 'Cr\u00E9er \u00AB {name} \u00BB',\n createAndEdit: 'Cr\u00E9er et modifier\u2026',\n searchMore: 'Rechercher plus\u2026',\n openNamed: 'Ouvrir {name}',\n openLine: 'Ouvrir la ligne',\n chooseDate: 'Choisir une date',\n previousMonth: 'Mois pr\u00E9c\u00E9dent',\n nextMonth: 'Mois suivant',\n weekShort: 'Sem.',\n week: 'Semaine',\n formatting: 'Mise en forme',\n bold: 'Gras',\n italic: 'Italique',\n underline: 'Soulign\u00E9',\n textStyle: 'Style du texte',\n paragraph: 'Paragraphe',\n heading: 'Titre',\n subheading: 'Sous-titre',\n bulletList: 'Liste \u00E0 puces',\n numberList: 'Liste num\u00E9rot\u00E9e',\n alignLeft: 'Aligner \u00E0 gauche',\n alignCenter: 'Centrer',\n alignRight: 'Aligner \u00E0 droite',\n link: 'Lien',\n linkAddress: 'Adresse du lien',\n applyLink: 'Appliquer',\n removeLink: 'Supprimer le lien',\n upload: 'T\u00E9l\u00E9verser un fichier',\n uploadImage: 'Ajouter une photo',\n replace: 'Remplacer',\n removeFile: 'Retirer',\n dropHere: 'ou d\u00E9posez-le ici',\n invalidJson: 'JSON invalide',\n },\n};\n", "import type { FieldNode, Form, ReferenceValue, RelatedRecord } from '@fieldia/core';\nimport { WIDGET_LABELS, type WidgetLabels } from './labels';\nimport type { Widget, WidgetContext, WidgetFactory } from './widgets';\n\n/**\n * Pickers for related records: a search-as-you-type combobox (the ARIA 1.2\n * combobox pattern), tags for a many2many, and a reference picker. Results\n * come from the data source through the form, so a field's filter applies.\n */\n\nconst DEBOUNCE_MS = 180;\n/** How many matches a link's list shows, as the data source's search would. */\nconst SHOWN = 8;\n\nfunction fill(template: string, values: Record<string, string>) {\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) => values[name] ?? match);\n}\n\ninterface Combobox {\n element: HTMLElement;\n input: HTMLInputElement;\n /** Show this text when nobody is typing. */\n setText(text: string): void;\n setReadonly(readonly: boolean): void;\n close(): void;\n}\n\n/**\n * A text box with a list of matches under it. `search` finds records,\n * `pick` takes the chosen one, `exclude` hides records already chosen.\n */\nfunction combobox(options: {\n document: Document;\n id: string;\n labels: WidgetLabels;\n search: (query: string) => Promise<RelatedRecord[]>;\n pick: (record: RelatedRecord) => void;\n exclude?: () => Set<RelatedRecord['id']>;\n onEmptyBackspace?: () => void;\n onCommitEmpty?: () => void;\n /** Make a record from what was typed, offered when nothing found has that name. */\n create?: (text: string) => Promise<RelatedRecord>;\n /** How many found records the list shows; a search may find one more, to tell there are others. */\n shown?: number;\n /** Further choices at the end of the list: each acts on the typed text and may hand back a record to pick. */\n more?: (typed: string, overflow: boolean) => { label: string; act: (typed: string) => Promise<RelatedRecord | null> }[];\n}): Combobox {\n const { document: doc, id, labels } = options;\n const listId = `${id}-list`;\n const input = doc.createElement('input');\n Object.assign(input, { id, className: 'fd-input fd-combo-input', autocomplete: 'off' });\n input.setAttribute('role', 'combobox');\n input.setAttribute('aria-autocomplete', 'list');\n input.setAttribute('aria-expanded', 'false');\n input.setAttribute('aria-controls', listId);\n input.placeholder = labels.search;\n const list = doc.createElement('ul');\n list.id = listId;\n list.className = 'fd-listbox';\n list.setAttribute('role', 'listbox');\n list.hidden = true;\n const element = doc.createElement('div');\n element.className = 'fd-combo';\n element.append(input, list);\n\n let shown = '';\n /** The \"Create \u2026\" choice in the list, and the text it would make a record from. */\n let creating: RelatedRecord | null = null;\n let creatingText = '';\n /** The further choices at the end of the list, by the entry that stands for each. */\n let extras = new Map<RelatedRecord, (typed: string) => Promise<RelatedRecord | null>>();\n /** True while the person's own typing is in the box. */\n let editing = false;\n let results: RelatedRecord[] = [];\n let active = -1;\n let seq = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let readonly = false;\n\n function render() {\n list.replaceChildren();\n results.forEach((record, i) => {\n const option = doc.createElement('li');\n option.id = `${listId}-${i}`;\n option.setAttribute('role', 'option');\n option.setAttribute('aria-selected', String(i === active));\n option.className = `fd-option${i === active ? ' fd-active' : ''}${record === creating || extras.has(record) ? ' fd-option-create' : ''}`;\n option.textContent = record.label;\n option.addEventListener('mousedown', (event) => event.preventDefault()); // keep focus in the box\n option.addEventListener('click', () => choose(i));\n list.append(option);\n });\n if (!results.length) {\n const empty = doc.createElement('li');\n empty.className = 'fd-empty';\n empty.textContent = labels.noResults;\n list.append(empty);\n }\n if (active >= 0) input.setAttribute('aria-activedescendant', `${listId}-${active}`);\n else input.removeAttribute('aria-activedescendant');\n }\n\n function open() {\n list.hidden = false;\n input.setAttribute('aria-expanded', 'true');\n }\n\n function close() {\n // A search still on its way must not open the list again.\n clearTimeout(timer);\n seq++;\n list.hidden = true;\n input.setAttribute('aria-expanded', 'false');\n input.removeAttribute('aria-activedescendant');\n active = -1;\n }\n\n function choose(index: number) {\n const record = results[index];\n if (!record) return;\n const typed = creatingText;\n close();\n editing = false;\n if (record === creating && options.create) {\n void options.create(typed).then(options.pick, () => undefined);\n return;\n }\n const act = extras.get(record);\n if (act) {\n void act(typed).then((picked) => picked && options.pick(picked), () => undefined);\n return;\n }\n options.pick(record);\n }\n\n function lookUp(query: string) {\n clearTimeout(timer);\n const mine = ++seq;\n timer = setTimeout(async () => {\n const found = await options.search(query).catch(() => [] as RelatedRecord[]);\n if (mine !== seq || doc.activeElement !== input) return; // a newer search, or the person left\n // A record the arrow keys reached stays reached if the answer still lists it.\n const reached = results[active];\n const held = reached && reached !== creating && !extras.has(reached) ? reached.id : undefined;\n const hidden = options.exclude?.() ?? new Set();\n const kept = found.filter((record) => !hidden.has(record.id));\n const overflow = options.shown !== undefined && kept.length > options.shown;\n results = overflow ? kept.slice(0, options.shown) : kept;\n // Nothing found by that name: offer to make it.\n const typed = query.trim();\n creating = null;\n if (options.create && typed && !found.some((record) => record.label.trim().toLowerCase() === typed.toLowerCase())) {\n creatingText = typed;\n creating = { id: '__create__', label: fill(labels.createNamed, { name: typed }) };\n results = [...results, creating];\n }\n creatingText = typed;\n extras = new Map((options.more?.(typed, overflow) ?? []).map((extra, i) => [{ id: `__more_${i}__`, label: extra.label }, extra.act]));\n results = [...results, ...extras.keys()];\n active = held === undefined ? -1 : results.findIndex((record) => record.id === held);\n render();\n open();\n }, DEBOUNCE_MS);\n }\n\n input.addEventListener('input', () => {\n editing = true;\n if (!readonly) lookUp(input.value);\n });\n input.addEventListener('focus', () => {\n if (!readonly) lookUp('');\n });\n input.addEventListener('keydown', (event) => {\n if (readonly) return;\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowUp': {\n event.preventDefault();\n if (list.hidden) return lookUp(input.value);\n if (!results.length) return;\n active = (active + (event.key === 'ArrowDown' ? 1 : -1) + results.length) % results.length;\n render();\n list.children[active]?.scrollIntoView?.({ block: 'nearest' });\n return;\n }\n case 'Enter':\n if (!list.hidden && active >= 0) {\n event.preventDefault();\n choose(active);\n }\n return;\n case 'Escape':\n if (!list.hidden) event.preventDefault();\n close();\n editing = false;\n input.value = shown;\n return;\n case 'Backspace':\n if (input.value === '') options.onEmptyBackspace?.();\n return;\n }\n });\n input.addEventListener('blur', () => {\n seq++;\n clearTimeout(timer);\n close();\n const emptied = editing && input.value.trim() === '' && shown !== '';\n editing = false;\n if (emptied) options.onCommitEmpty?.();\n else input.value = shown;\n });\n\n return {\n element,\n input,\n setText(text) {\n shown = text;\n if (!editing) input.value = text;\n },\n setReadonly(next) {\n readonly = next;\n input.readOnly = next;\n if (next) close();\n },\n close,\n };\n}\n\n/** Making a record from a typed name, unless the page turns it off or the data source cannot. */\nfunction creator(form: Form, name: string, node: FieldNode): ((text: string) => Promise<RelatedRecord>) | undefined {\n return node.options?.['create'] !== false && form.canCreate(name) ? (text) => form.quickCreate(name, text) : undefined;\n}\n\nexport const many2oneWidget: WidgetFactory = ({ form, name, field, node, id, document, labels = WIDGET_LABELS.en, dialogs }) => {\n const relation = field.type === 'many2one' ? field.relation : '';\n const canOpen = !!dialogs && dialogs.canOpen(relation);\n let readonly = false;\n const box = combobox({\n document,\n id,\n labels,\n // One past what the list shows, to know whether Search more\u2026 has more to find.\n search: (query) => form.search(name, query, SHOWN + 1),\n shown: SHOWN,\n pick: (record) => form.setValue(name, record),\n onCommitEmpty: () => form.setValue(name, null),\n create: creator(form, name, node),\n // With dialogs: make a record in its own page, or pick from a full list when the short one has no room.\n more: (typed, overflow) => {\n if (!dialogs || readonly) return [];\n const choices: { label: string; act: (text: string) => Promise<RelatedRecord | null> }[] = [];\n if (typed && canOpen && node.options?.['create'] !== false) {\n choices.push({ label: labels.createAndEdit, act: (text) => dialogs.openRecord(relation, { name: text, title: field.label }) });\n }\n if (overflow) choices.push({ label: labels.searchMore, act: () => dialogs.searchMore({ title: field.label, search: (query, limit) => form.search(name, query, limit) }) });\n return choices;\n },\n });\n // The linked record, opened in a dialog where the app can show it; a new name it is saved with follows here.\n const open = canOpen ? document.createElement('button') : null;\n if (open) {\n open.type = 'button';\n open.className = 'fd-combo-open';\n open.textContent = '\u2197';\n open.hidden = true;\n open.addEventListener('click', async () => {\n const current = form.getState().values[name] as RelatedRecord | null;\n if (!current || !dialogs) return;\n const saved = await dialogs.openRecord(relation, { recordId: current.id, title: current.label });\n if (saved && saved.label !== current.label) form.setValue(name, saved);\n });\n }\n const clear = document.createElement('button');\n clear.type = 'button';\n clear.className = 'fd-combo-clear';\n clear.textContent = '\u00D7';\n clear.setAttribute('aria-label', fill(labels.clear, { label: field.label }));\n clear.addEventListener('click', () => {\n form.setValue(name, null);\n box.input.focus();\n });\n box.element.append(clear, ...(open ? [open] : []));\n return {\n element: box.element,\n focus: () => box.input.focus(),\n update(state) {\n const record = state.value as RelatedRecord | null | undefined;\n readonly = state.readonly;\n box.setText(record?.label ?? '');\n box.setReadonly(state.readonly);\n clear.hidden = !record || state.readonly;\n if (open) {\n open.hidden = !record;\n if (record) open.setAttribute('aria-label', fill(labels.openNamed, { name: record.label }));\n }\n box.input.setAttribute('aria-invalid', String(state.invalid));\n box.input.setAttribute('aria-required', String(state.required));\n if (state.describedBy) box.input.setAttribute('aria-describedby', state.describedBy);\n },\n } satisfies Widget;\n};\n\nexport const tagsWidget: WidgetFactory = ({ form, name, node, id, document, labels = WIDGET_LABELS.en }) => {\n const current = () => (form.getState().values[name] as RelatedRecord[] | null) ?? [];\n const element = document.createElement('div');\n element.className = 'fd-tags';\n element.setAttribute('role', 'group');\n const chips = document.createElement('ul');\n chips.className = 'fd-chips';\n const box = combobox({\n document,\n id,\n labels,\n search: (query) => form.search(name, query),\n pick: (record) => {\n form.setValue(name, [...current(), record]);\n box.input.value = '';\n },\n exclude: () => new Set(current().map((record) => record.id)),\n onEmptyBackspace: () => {\n const records = current();\n if (records.length) form.setValue(name, records.slice(0, -1));\n },\n create: creator(form, name, node),\n });\n element.append(chips, box.element);\n let readonly = false;\n let drawn = '';\n return {\n element,\n focus: () => box.input.focus(),\n update(state) {\n const records = (state.value as RelatedRecord[] | null) ?? [];\n // Rebuild the chips only when they change, not on every keystroke elsewhere.\n const key = JSON.stringify([state.readonly, records]);\n readonly = state.readonly;\n box.setReadonly(readonly);\n box.element.hidden = readonly;\n box.input.setAttribute('aria-invalid', String(state.invalid));\n if (state.describedBy) box.input.setAttribute('aria-describedby', state.describedBy);\n if (key === drawn) return;\n drawn = key;\n drawChips(chips, records, readonly, labels, (record) => form.setValue(name, current().filter((r) => r.id !== record.id)));\n box.setText('');\n },\n };\n};\n\n/** Chips for tags, each with a remove button unless read-only. */\nfunction drawChips(chips: HTMLElement, records: RelatedRecord[], readonly: boolean, labels: WidgetLabels, remove: (record: RelatedRecord) => void) {\n const doc = chips.ownerDocument;\n chips.replaceChildren(\n ...records.map((record) => {\n const chip = doc.createElement('li');\n chip.className = 'fd-chip';\n const text = doc.createElement('span');\n text.className = 'fd-chip-label';\n text.textContent = record.label;\n chip.append(text);\n if (!readonly) {\n const button = doc.createElement('button');\n button.type = 'button';\n button.className = 'fd-chip-remove';\n button.textContent = '\u00D7';\n button.setAttribute('aria-label', fill(labels.remove, { name: record.label }));\n button.addEventListener('click', () => remove(record));\n chip.append(button);\n }\n return chip;\n })\n );\n}\n\n/**\n * Free-text tags on a text field, kept as \"oak, glass\": Enter or a comma adds\n * what was typed, Backspace in an empty box takes the last one away, and the\n * node's `options.suggestions` are offered as you type. `options.separator`\n * is \",\" unless set.\n */\nexport const charTagsWidget: WidgetFactory = ({ form, name, node, id, document, labels = WIDGET_LABELS.en }) => {\n const options = node.options ?? {};\n const separator = typeof options['separator'] === 'string' && options['separator'] ? options['separator'] : ',';\n const suggestions = Array.isArray(options['suggestions']) ? options['suggestions'].filter((s): s is string => typeof s === 'string') : [];\n const split = (text: unknown) =>\n typeof text === 'string' ? text.split(separator).map((t) => t.trim()).filter((t) => t !== '') : [];\n const current = () => split(form.getState().values[name]);\n const write = (tags: string[]) => form.setValue(name, tags.length ? tags.join(`${separator} `) : null);\n const add = (raw: string) => {\n const tag = raw.trim();\n const tags = current();\n if (tag && !tags.some((t) => t.toLowerCase() === tag.toLowerCase())) write([...tags, tag]);\n };\n\n const element = document.createElement('div');\n element.className = 'fd-tags';\n element.setAttribute('role', 'group');\n const chips = document.createElement('ul');\n chips.className = 'fd-chips';\n const box = combobox({\n document,\n id,\n labels,\n search: async (query) => {\n const taken = new Set(current().map((t) => t.toLowerCase()));\n const wanted = query.trim().toLowerCase();\n return suggestions\n .filter((s) => !taken.has(s.toLowerCase()) && s.toLowerCase().includes(wanted))\n .map((s) => ({ id: s, label: s }));\n },\n pick: (record) => {\n add(record.label);\n box.input.value = '';\n },\n onEmptyBackspace: () => {\n const tags = current();\n if (tags.length) write(tags.slice(0, -1));\n },\n });\n // Enter with nothing chosen from the list adds what was typed.\n box.input.addEventListener('keydown', (event) => {\n if (event.key !== 'Enter' || event.defaultPrevented || box.input.value.trim() === '') return;\n event.preventDefault();\n add(box.input.value);\n box.input.value = '';\n box.close();\n });\n // A separator typed ends a tag.\n box.input.addEventListener('input', () => {\n const parts = box.input.value.split(separator);\n if (parts.length < 2) return;\n for (const part of parts.slice(0, -1)) add(part);\n box.input.value = parts[parts.length - 1].trimStart();\n });\n // Typed and left without Enter: kept. (change comes before blur clears the box.)\n box.input.addEventListener('change', () => {\n if (box.input.value.trim()) add(box.input.value);\n });\n element.append(chips, box.element);\n let drawn = '';\n return {\n element,\n focus: () => box.input.focus(),\n update(state) {\n const tags = split(state.value);\n box.setReadonly(state.readonly);\n box.element.hidden = state.readonly;\n box.input.setAttribute('aria-invalid', String(state.invalid));\n if (state.describedBy) box.input.setAttribute('aria-describedby', state.describedBy);\n const key = JSON.stringify([state.readonly, tags]);\n if (key === drawn) return;\n drawn = key;\n drawChips(chips, tags.map((t) => ({ id: t, label: t })), state.readonly, labels, (record) => write(current().filter((t) => t !== record.label)));\n box.setText('');\n },\n };\n};\n\n/** Every record as a checkbox. For short lists: it loads up to 50. */\nexport const linkCheckboxesWidget: WidgetFactory = ({ form, name, id, document }) => {\n const element = document.createElement('div');\n element.id = id;\n element.className = 'fd-choices fd-choices-checkbox';\n element.setAttribute('role', 'group');\n let boxes: { record: RelatedRecord; box: HTMLInputElement }[] = [];\n let latest = { readonly: false, value: [] as RelatedRecord[] };\n // Built once, when the records arrive; updates only tick boxes, so focus stays put.\n const sync = () => {\n const chosen = new Set(latest.value.map((r) => r.id));\n for (const { record, box } of boxes) {\n box.checked = chosen.has(record.id);\n box.disabled = latest.readonly;\n }\n };\n void form.search(name, '', 50).then((records) => {\n boxes = records.map((record, i) => {\n const box = document.createElement('input');\n box.type = 'checkbox';\n box.id = `${id}-${i}`;\n box.addEventListener('change', () => {\n const now = (form.getState().values[name] as RelatedRecord[] | null) ?? [];\n form.setValue(name, box.checked ? [...now, record] : now.filter((r) => r.id !== record.id));\n });\n const label = document.createElement('label');\n label.className = 'fd-choice';\n label.htmlFor = box.id;\n const text = document.createElement('span');\n text.textContent = record.label;\n label.append(box, text);\n element.append(label);\n return { record, box };\n });\n sync();\n });\n return {\n element,\n focus: () => element.querySelector('input')?.focus(),\n update(state) {\n latest = { readonly: state.readonly, value: (state.value as RelatedRecord[] | null) ?? [] };\n sync();\n },\n };\n};\n\nexport const referenceWidget: WidgetFactory = (context: WidgetContext) => {\n const { form, name, field, id, document, labels = WIDGET_LABELS.en } = context;\n const models = field.type === 'reference' ? field.models : [];\n const element = document.createElement('div');\n element.className = 'fd-reference';\n const select = document.createElement('select');\n select.className = 'fd-input fd-select';\n select.setAttribute('aria-label', field.label);\n select.append(document.createElement('option'));\n for (const model of models) {\n const option = document.createElement('option');\n option.value = String(model.value);\n option.textContent = model.label;\n select.append(option);\n }\n let model = '';\n select.addEventListener('change', () => {\n model = select.value;\n form.setValue(name, null);\n });\n const box = combobox({\n document,\n id,\n labels,\n search: (query) => (model ? form.search(name, query, 8, { model }) : Promise.resolve([])),\n pick: (record) => form.setValue(name, { model, id: record.id, label: record.label }),\n onCommitEmpty: () => form.setValue(name, null),\n });\n element.append(select, box.element);\n return {\n element,\n focus: () => (model ? box.input.focus() : select.focus()),\n update(state) {\n const value = state.value as ReferenceValue | null | undefined;\n if (value) model = value.model;\n select.value = model;\n select.disabled = state.readonly;\n box.setText(value?.label ?? '');\n box.setReadonly(state.readonly || !model);\n },\n };\n};\n", "import type { LineField, Locale, Value } from '@fieldia/core';\nimport { formatNumber } from './numbers';\n\n\nfunction localDate(text: string): Date | null {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})(?:[T ](\\d{2}):(\\d{2}))?/.exec(text);\n if (!match) return null;\n const [, y, m, d, hh, mm] = match;\n return new Date(Number(y), Number(m) - 1, Number(d), Number(hh ?? 0), Number(mm ?? 0));\n}\n\n/**\n * A value as a person reads it where it is not being edited: a cell of the\n * lines grid, a totals row. Shared by the plain lines table and @fieldia/grid.\n */\nexport function displayValue(def: LineField, value: Value | undefined, values: Record<string, Value> = {}, locale: Locale = 'en'): string {\n const number = (n: number, digits: number) => formatNumber(n, digits, locale);\n if (value === null || value === undefined || value === '') return '';\n switch (def.type) {\n case 'many2one':\n case 'reference':\n return (value as { label?: string }).label ?? '';\n case 'many2many':\n return ((value as { label: string }[]) ?? []).map((r) => r.label).join(', ');\n case 'selection': {\n const label = (v: unknown) => def.options.find((o) => o.value === v)?.label ?? String(v);\n return Array.isArray(value) ? value.map(label).join(', ') : label(value);\n }\n case 'integer':\n return number(Number(value), 0);\n case 'float':\n return number(Number(value), def.digits?.[1] ?? 2);\n case 'monetary': {\n const currency = def.currency ?? (def.currencyField ? (values[def.currencyField] as { label?: string } | null)?.label : undefined);\n const amount = number(Number(value), def.digits?.[1] ?? 2);\n return currency ? `${currency} ${amount}` : amount;\n }\n case 'date': {\n const date = localDate(String(value));\n return date ? new Intl.DateTimeFormat(locale === 'en' ? 'en-GB' : locale, { day: 'numeric', month: 'short', year: 'numeric', numberingSystem: 'latn' }).format(date) : String(value);\n }\n case 'datetime': {\n const date = localDate(String(value));\n return date\n ? new Intl.DateTimeFormat(locale === 'en' ? 'en-GB' : locale, { day: 'numeric', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', numberingSystem: 'latn' }).format(date)\n : String(value);\n }\n case 'html':\n return String(value).replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim();\n case 'binary':\n case 'image':\n return (value as { name?: string }).name ?? '';\n case 'boolean':\n return value ? '\u2713' : '';\n default:\n return String(value);\n }\n}\n", "import { lineKind, type Field, type FieldNode, type Form, type FormState, type Line, type LineField, type Value } from '@fieldia/core';\nimport { displayValue } from './display';\nimport { WIDGET_LABELS } from './labels';\nimport { createWidget, type Widget, type WidgetFactory } from './widgets';\n\n/**\n * A one2many as an editable table. Each cell is an ordinary widget; a small\n * adapter routes its edits to `updateLine` and its searches to `searchLine`,\n * so a many2one inside a line searches with that line's own values. Rows are\n * matched by line key, so adding or removing a line never rebuilds the others.\n * When the field declares `lineKinds`, a section or a note is one wide row of\n * its text.\n */\n\ninterface Row {\n element: HTMLTableRowElement;\n kind: 'section' | 'note' | null;\n cells: { name: string; def: LineField; widget: Widget; error: HTMLElement }[];\n remove: HTMLButtonElement;\n}\n\n/** The field a section or note is typed into: one line for a heading, a growing box for a note. */\nexport function kindTextField(def: LineField, kind: 'section' | 'note'): LineField {\n return kind === 'section' ? ({ ...def, type: 'char' } as LineField) : ({ ...def, type: 'text' } as LineField);\n}\n\n/** The form a cell sees: the line's values, written back into the line. Shared with @fieldia/grid. */\nexport function lineForm(form: Form, field: string, key: string): Form {\n const values = () => (((form.getState().values[field] as Line[] | null) ?? []).find((l) => l.key === key)?.values ?? {});\n return {\n ...form,\n getState: (): FormState => ({ ...form.getState(), values: values() }),\n setValue: (name: string, value: Value) => form.updateLine(field, key, name, value),\n search: (name: string, query: string, limit?: number) => form.searchLine(field, key, name, query, limit),\n canCreate: (name: string) => form.canCreateLine(field, name),\n quickCreate: (name: string, text: string) => form.quickCreateLine(field, name, text),\n };\n}\n\nexport const linesWidget: WidgetFactory = ({ form, name, field, node, id, document, labels = WIDGET_LABELS.en, locale, dialogs }) => {\n const def = field as Extract<Field, { type: 'one2many' }>;\n const kinds = def.lineKinds;\n // The fields that say what a line is and keep the lines' order never show as columns.\n // Optional columns the page starts hidden stay out of the plain table.\n const columns = (node.columns ?? Object.keys(def.fields)).filter(\n (column) => def.fields[column] && column !== kinds?.field && column !== def.sequenceField && node.optionalColumns?.[column] !== 'hide'\n );\n const element = document.createElement('div');\n element.className = 'fd-lines';\n element.id = id;\n element.setAttribute('role', 'group');\n const scroller = document.createElement('div');\n scroller.className = 'fd-lines-scroll';\n const table = document.createElement('table');\n table.className = 'fd-lines-table';\n const head = document.createElement('thead');\n const headRow = document.createElement('tr');\n for (const column of columns) {\n const th = document.createElement('th');\n th.scope = 'col';\n th.textContent = def.fields[column].label;\n headRow.append(th);\n }\n const lastTh = document.createElement('th');\n lastTh.className = 'fd-lines-tools';\n headRow.append(lastTh);\n head.append(headRow);\n const body = document.createElement('tbody');\n table.append(head, body);\n // Number columns the page asks to add up, in a row under the lines.\n const totals = (node.totals ?? []).filter((column) => columns.includes(column));\n const sums = new Map<string, HTMLTableCellElement>();\n if (totals.length) {\n const foot = document.createElement('tfoot');\n const row = document.createElement('tr');\n row.className = 'fd-lines-totals';\n columns.forEach((column, i) => {\n const td = document.createElement('td');\n if (totals.includes(column)) sums.set(column, td);\n else if (i === 0) td.textContent = labels.total;\n row.append(td);\n });\n row.append(document.createElement('td'));\n foot.append(row);\n table.append(foot);\n }\n scroller.append(table);\n const adds = document.createElement('div');\n adds.className = 'fd-lines-adds';\n const addButton = (text: string, values: Record<string, Value>, kind: string) => {\n const button = document.createElement('button');\n button.type = 'button';\n button.className = 'fd-button fd-button-link fd-lines-add';\n button.dataset['add'] = kind;\n button.textContent = `+ ${text}`;\n button.addEventListener('click', () => {\n focusNew = form.addLine(name, values);\n const row = rows.get(focusNew);\n if (row) {\n row.cells[0]?.widget.focus();\n focusNew = null;\n }\n });\n adds.append(button);\n };\n addButton(labels.addLine, {}, 'line');\n if (kinds) {\n addButton(labels.addSection, { [kinds.field]: kinds.section ?? 'section' }, 'section');\n addButton(labels.addNote, { [kinds.field]: kinds.note ?? 'note' }, 'note');\n }\n element.append(scroller, adds);\n\n const rows = new Map<string, Row>();\n let focusNew: string | null = null;\n let readonly = false;\n\n function makeCell(tr: HTMLTableRowElement, line: Line, column: string, sub: LineField, span = 1) {\n const cellId = `${id}-${line.key}-${column}`;\n const subNode: FieldNode = { type: 'field', id: `${node.id}.${line.key}.${column}`, field: column };\n const widget = createWidget({ form: lineForm(form, name, line.key), name: column, field: sub as Field, node: subNode, id: cellId, document, labels, locale, dialogs });\n const td = document.createElement('td');\n td.colSpan = span;\n const label = document.createElement('label');\n label.className = 'fd-sr-only';\n label.htmlFor = cellId;\n label.textContent = sub.label;\n const error = document.createElement('div');\n error.className = 'fd-cell-error';\n error.hidden = true;\n td.append(label, widget.element, error);\n tr.append(td);\n return { name: column, def: sub, widget, error };\n }\n\n function makeRow(line: Line): Row {\n const tr = document.createElement('tr');\n tr.dataset['line'] = line.key;\n const kind = lineKind(def, line.values);\n if (kind) tr.className = `fd-line-${kind}`;\n const cells =\n kind && kinds\n ? [makeCell(tr, line, kinds.text, kindTextField(def.fields[kinds.text], kind), columns.length)]\n : columns.map((column) => makeCell(tr, line, column, def.fields[column]));\n const tools = document.createElement('td');\n tools.className = 'fd-lines-tools';\n const remove = document.createElement('button');\n remove.type = 'button';\n remove.className = 'fd-line-delete';\n remove.textContent = '\u00D7';\n remove.setAttribute('aria-label', labels.deleteLine);\n remove.addEventListener('click', () => form.removeLine(name, line.key));\n tools.append(remove);\n tr.append(tools);\n return { element: tr, kind, cells, remove };\n }\n\n return {\n element,\n focus: () => (body.querySelector<HTMLElement>('input, select, textarea') ?? adds.querySelector('button'))?.focus(),\n update(state) {\n readonly = state.readonly;\n adds.hidden = readonly;\n const current = (state.value as Line[] | null) ?? [];\n const errors = form.getState().errors;\n const keep = new Set(current.map((line) => line.key));\n for (const [key, row] of rows) {\n if (!keep.has(key)) {\n row.element.remove();\n rows.delete(key);\n }\n }\n current.forEach((line, index) => {\n let row = rows.get(line.key);\n // A line that changed kind is drawn afresh.\n if (row && row.kind !== lineKind(def, line.values)) {\n row.element.remove();\n row = undefined;\n }\n if (!row) {\n row = makeRow(line);\n rows.set(line.key, row);\n }\n if (body.children[index] !== row.element) body.insertBefore(row.element, body.children[index] ?? null);\n row.remove.hidden = readonly;\n if (readonly) row.remove.remove();\n else if (!row.remove.isConnected) row.element.lastElementChild?.append(row.remove);\n for (const cell of row.cells) {\n const message = errors[`${name}.${line.key}.${cell.name}`];\n cell.error.hidden = !message;\n cell.error.textContent = message ?? '';\n cell.widget.update({\n value: line.values[cell.name],\n values: line.values,\n readonly: readonly || cell.def.readonly === true,\n required: cell.def.required === true,\n invalid: !!message,\n });\n }\n });\n for (const [column, td] of sums) {\n const sum = current.filter((line) => !lineKind(def, line.values)).reduce((total, line) => total + Number(line.values[column] ?? 0), 0);\n td.textContent = displayValue(def.fields[column], sum, current[0]?.values ?? {}, locale);\n }\n if (focusNew && rows.has(focusNew)) {\n rows.get(focusNew)?.cells[0]?.widget.focus();\n focusNew = null;\n }\n },\n };\n};\n", "import { formatBytes, type FileValue } from '@fieldia/core';\nimport { WIDGET_LABELS } from './labels';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * File and image fields. A chosen or dropped file is read into the value as\n * base64, the way a backend's binary fields carry it; a stored one may carry\n * a `url` instead. Size and type limits are checked by the field's validation.\n */\n\nfunction read(file: File): Promise<FileValue> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const url = String(reader.result ?? '');\n resolve({ name: file.name, type: file.type, size: file.size, data: url.slice(url.indexOf(',') + 1) });\n };\n reader.onerror = () => reject(reader.error);\n reader.readAsDataURL(file);\n });\n}\n\nfunction fileWidget(kind: 'binary' | 'image'): WidgetFactory {\n return ({ form, name, field, id, document, labels = WIDGET_LABELS.en }) => {\n const element = document.createElement('div');\n element.className = `fd-file fd-file-${kind}`;\n const input = document.createElement('input');\n input.type = 'file';\n input.id = id;\n input.className = 'fd-sr-only';\n const accept = field.type === 'binary' ? field.accept : kind === 'image' ? ['image/*'] : undefined;\n if (accept) input.accept = accept.join(',');\n\n const preview = document.createElement('img');\n preview.className = 'fd-image-preview';\n preview.alt = field.label;\n preview.hidden = true;\n\n const pick = document.createElement('label');\n pick.className = kind === 'image' ? 'fd-file-pick fd-image-pick' : 'fd-file-pick';\n pick.htmlFor = id;\n const pickText = document.createElement('span');\n pickText.className = 'fd-button';\n pickText.textContent = kind === 'image' ? labels.uploadImage : labels.upload;\n const hint = document.createElement('span');\n hint.className = 'fd-help';\n hint.textContent = labels.dropHere;\n pick.append(pickText, hint);\n\n const chosen = document.createElement('div');\n chosen.className = 'fd-file-chosen';\n const fileName = document.createElement('span');\n fileName.className = 'fd-file-name';\n const replace = document.createElement('button');\n replace.type = 'button';\n replace.className = 'fd-button fd-button-link';\n replace.textContent = labels.replace;\n replace.addEventListener('click', () => input.click());\n const remove = document.createElement('button');\n remove.type = 'button';\n remove.className = 'fd-button fd-button-link';\n remove.textContent = labels.removeFile;\n remove.addEventListener('click', () => form.setValue(name, null));\n chosen.append(fileName, replace, remove);\n\n element.append(input, ...(kind === 'image' ? [preview] : []), pick, chosen);\n\n let readonly = false;\n const take = async (file: File | undefined) => {\n if (!file || readonly) return;\n form.setValue(name, await read(file));\n };\n input.addEventListener('change', () => {\n void take(input.files?.[0]);\n input.value = '';\n });\n element.addEventListener('dragover', (event) => {\n if (readonly) return;\n event.preventDefault();\n element.classList.add('fd-dragging');\n });\n element.addEventListener('dragleave', () => element.classList.remove('fd-dragging'));\n element.addEventListener('drop', (event) => {\n event.preventDefault();\n element.classList.remove('fd-dragging');\n void take((event as DragEvent).dataTransfer?.files?.[0]);\n });\n\n return {\n element,\n focus: () => (pick.hidden ? replace : input).focus(),\n update(state) {\n readonly = state.readonly;\n const file = state.value as FileValue | null | undefined;\n pick.hidden = !!file || readonly;\n chosen.hidden = !file;\n replace.hidden = remove.hidden = readonly;\n input.disabled = readonly;\n input.setAttribute('aria-invalid', String(state.invalid));\n if (state.describedBy) input.setAttribute('aria-describedby', state.describedBy);\n fileName.textContent = file ? `${file.name} \u00B7 ${formatBytes(file.size)}` : '';\n if (kind === 'image') {\n const src = file ? (file.data ? `data:${file.type};base64,${file.data}` : file.url ?? '') : '';\n preview.hidden = !src;\n if (preview.getAttribute('src') !== src) {\n if (src) preview.src = src;\n else preview.removeAttribute('src');\n }\n }\n },\n };\n };\n}\n\nexport const binaryWidget = fileWidget('binary');\nexport const imageWidget = fileWidget('image');\n", "import type { Locale } from '@fieldia/core';\nimport { createWidget, type Widget, type WidgetFactory } from './widgets';\n\n/**\n * A number shown as a bar that fills towards a maximum, coloured by how far\n * it has come: red under 30 %, yellow under 70 %, green from there. Options:\n *\n * max the maximum, 100 by default (min 0)\n * maxField a number field that holds the maximum instead\n * color \"auto\", or always \"success\", \"warning\", \"danger\" or \"info\"\n * showPercent false to leave the percentage off the bar\n * editable true for a box beside the bar to type the value in\n */\n\nconst percents = new Map<Locale, Intl.NumberFormat>();\nfunction percent(value: number, locale: Locale) {\n let format = percents.get(locale);\n if (!format) {\n format = new Intl.NumberFormat(locale, { style: 'percent', maximumFractionDigits: 0, numberingSystem: 'latn' });\n percents.set(locale, format);\n }\n return format.format(value / 100);\n}\n\nexport const progressbarWidget: WidgetFactory = (context) => {\n const { node, id, document, locale = 'en' } = context;\n const options = node.options ?? {};\n const min = typeof options['min'] === 'number' ? options['min'] : 0;\n const fixedMax = typeof options['max'] === 'number' ? options['max'] : 100;\n const maxField = typeof options['maxField'] === 'string' ? options['maxField'] : null;\n const color = typeof options['color'] === 'string' ? options['color'] : 'auto';\n const showPercent = options['showPercent'] !== false;\n\n const bar = document.createElement('div');\n bar.className = 'fd-progressbar';\n bar.setAttribute('role', 'progressbar');\n const fill = document.createElement('div');\n fill.className = 'fd-progressbar-fill';\n const text = document.createElement('span');\n text.className = 'fd-progressbar-text';\n bar.append(fill, text);\n\n // Editable: the field's own number box takes the value; the bar beside it only shows it.\n let box: Widget | null = null;\n let element: HTMLElement = bar;\n if (options['editable'] === true) {\n box = createWidget({ ...context, node: { ...node, widget: undefined } });\n bar.setAttribute('aria-hidden', 'true');\n element = document.createElement('div');\n element.className = 'fd-progressbar-edit';\n element.append(bar, box.element);\n } else {\n bar.id = id;\n }\n\n return {\n element,\n focus: () => box?.focus(),\n update(state) {\n const value = typeof state.value === 'number' ? state.value : 0;\n const max = maxField ? Number(state.values[maxField] ?? 0) : fixedMax;\n const share = max > min ? Math.min(100, Math.max(0, ((value - min) / (max - min)) * 100)) : 0;\n const rounded = Math.round(share * 10) / 10;\n fill.style.width = `${rounded}%`;\n bar.setAttribute('aria-valuenow', String(value));\n bar.setAttribute('aria-valuemin', String(min));\n bar.setAttribute('aria-valuemax', String(max));\n bar.setAttribute('aria-valuetext', percent(share, locale));\n text.textContent = showPercent ? percent(share, locale) : '';\n bar.dataset['tone'] = color !== 'auto' ? color : share < 30 ? 'danger' : share < 70 ? 'warning' : 'success';\n box?.update(state);\n },\n };\n};\n", "import type { Locale, RelatedRecord, Value } from '@fieldia/core';\nimport { formatNumber } from './numbers';\nimport { summary, type WidgetFactory } from './widgets';\n\n/**\n * A value shown as text between a prefix and a suffix: \"24 months\",\n * \"240.0 m\". Never edited. Options:\n *\n * prefix, suffix words around the value\n * prefixField, suffixField a field whose value is the prefix or suffix instead\n */\n\n/** Another field's value as words: a link's label, or the value itself. */\nfunction words(value: Value | undefined): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'object' && 'label' in (value as object)) return (value as RelatedRecord).label;\n return String(value);\n}\n\nexport const labelWidget: WidgetFactory = ({ field, node, id, document, locale = 'en' as Locale }) => {\n const options = node.options ?? {};\n const text = (key: 'prefix' | 'suffix') => (typeof options[key] === 'string' ? (options[key] as string) : '');\n const from = (key: 'prefixField' | 'suffixField') => (typeof options[key] === 'string' ? (options[key] as string) : null);\n const decimals =\n field.type === 'integer' ? 0 : field.type === 'float' || field.type === 'monetary' ? (field.digits?.[1] ?? 2) : null;\n\n const output = document.createElement('output');\n output.id = id;\n output.className = 'fd-value-text';\n return {\n element: output,\n focus: () => undefined,\n update({ value, values }) {\n if (value === null || value === undefined || value === '') {\n output.textContent = '';\n return;\n }\n const shown = decimals !== null && typeof value === 'number' ? formatNumber(value, decimals, locale) : summary(value, field);\n const prefixField = from('prefixField');\n const suffixField = from('suffixField');\n const prefix = prefixField ? words(values[prefixField]) : text('prefix');\n const suffix = suffixField ? words(values[suffixField]) : text('suffix');\n output.textContent = [prefix, shown, suffix].filter((part) => part !== '').join(' ');\n },\n };\n};\n", "import type { RelatedRecord } from '@fieldia/core';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * Where a record stands, as a row of steps with the current one marked: a\n * selection's states, or the records a link may point to (stages). Used in a\n * sheet's header, and anywhere in a form with `\"widget\": \"statusbar\"`. Options:\n *\n * clickable true to let a click move the record to another step\n * visibleStates the values to show; the current one always shows\n */\n\ninterface Step {\n key: string;\n label: string;\n value: unknown;\n}\n\nexport const statusbarWidget: WidgetFactory = ({ form, name, field, node, id, document }) => {\n const options = node.options ?? {};\n const clickable = options['clickable'] === true;\n const visible = Array.isArray(options['visibleStates']) ? options['visibleStates'] : null;\n const list = document.createElement('ol');\n list.className = 'fd-statusbar';\n list.id = id;\n list.setAttribute('aria-label', field.label);\n\n const keyOf = (value: unknown) =>\n value && typeof value === 'object' && 'id' in value ? `id:${String((value as RelatedRecord).id)}` : `v:${String(value)}`;\n // A selection knows its steps; a link's are looked up once.\n let steps: Step[] =\n field.type === 'selection' ? field.options.map((o) => ({ key: keyOf(o.value), label: o.label, value: o.value })) : [];\n let lookedUp = field.type === 'selection';\n let last: { value: unknown; readonly: boolean } = { value: undefined, readonly: false };\n\n function draw() {\n const { value, readonly } = last;\n const currentKey = value === null || value === undefined ? null : keyOf(value);\n let shown = steps.filter((s) => !visible || visible.some((v) => keyOf(v) === s.key) || s.key === currentKey);\n if (currentKey && !shown.some((s) => s.key === currentKey) && value && typeof value === 'object') {\n shown = [...shown, { key: currentKey, label: (value as RelatedRecord).label, value }];\n }\n list.replaceChildren(\n ...shown.map((step) => {\n const label = document.createElement('span');\n label.textContent = step.label;\n const inner = document.createElement(clickable ? 'button' : 'span');\n if (inner instanceof HTMLButtonElement) {\n inner.type = 'button';\n inner.disabled = readonly;\n inner.addEventListener('click', () => form.setValue(name, step.value as never));\n }\n inner.append(label);\n if (step.key === currentKey) inner.setAttribute('aria-current', 'step');\n const item = document.createElement('li');\n item.append(inner);\n return item;\n })\n );\n }\n\n return {\n element: list,\n focus: () => list.querySelector<HTMLElement>('button:not([disabled])')?.focus(),\n update(state) {\n last = { value: state.value, readonly: state.readonly };\n draw();\n if (!lookedUp) {\n lookedUp = true;\n void form\n .search(name, '', 20)\n .then((records) => {\n steps = records.map((r) => ({ key: keyOf(r), label: r.label, value: r }));\n draw();\n })\n .catch(() => undefined);\n }\n },\n };\n};\n", "import type { Locale, Value } from '@fieldia/core';\nimport { WIDGET_LABELS, type WidgetLabels } from './labels';\nimport type { Widget, WidgetContext } from './widgets';\n\n/**\n * A calendar beside a date, for when the person needs the week numbers\n * (`options.weekNumbers` on a date or date-and-time node). The ARIA\n * date-picker dialog: a grid of days, Monday first, an ISO 8601 week number at\n * the start of each row, arrow keys by day and week, PageUp and PageDown by\n * month, Enter to pick, Escape to close.\n */\n\n/** The ISO 8601 week a day falls in: weeks start on Monday, week 1 holds the year's first Thursday. */\nexport function isoWeek(day: Date): number {\n const t = new Date(Date.UTC(day.getFullYear(), day.getMonth(), day.getDate()));\n t.setUTCDate(t.getUTCDate() + 4 - (t.getUTCDay() || 7));\n const yearStart = Date.UTC(t.getUTCFullYear(), 0, 1);\n return Math.ceil(((t.getTime() - yearStart) / 86400000 + 1) / 7);\n}\n\nconst pad = (n: number) => String(n).padStart(2, '0');\nconst sameDay = (a: Date, b: Date) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\nconst addDays = (d: Date, n: number) => new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);\n/** The same day of another month, or that month's last day when it is shorter. */\nfunction addMonths(d: Date, n: number) {\n const last = new Date(d.getFullYear(), d.getMonth() + n + 1, 0).getDate();\n return new Date(d.getFullYear(), d.getMonth() + n, Math.min(d.getDate(), last));\n}\n\n/** The day a date field holds (\"2026-10-11\"), or a date and time (an ISO instant), in local time. */\nfunction dayOf(kind: 'date' | 'datetime', value: Value | undefined): Date | null {\n if (typeof value !== 'string' || !value) return null;\n if (kind === 'date') {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})/.exec(value);\n return m ? new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3])) : null;\n }\n const d = new Date(value);\n return Number.isNaN(d.getTime()) ? null : d;\n}\n\nexport function withCalendar(inner: Widget, context: WidgetContext, kind: 'date' | 'datetime'): Widget {\n const { form, name, id, document: doc, locale = 'en' as Locale } = context;\n const labels: WidgetLabels = context.labels ?? WIDGET_LABELS.en;\n const lang = locale === 'en' ? 'en-GB' : locale;\n const monthName = new Intl.DateTimeFormat(lang, { month: 'long', year: 'numeric', numberingSystem: 'latn' });\n const dayName = new Intl.DateTimeFormat(lang, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric', numberingSystem: 'latn' });\n const weekdayShort = new Intl.DateTimeFormat(lang, { weekday: 'short' });\n const weekdayLong = new Intl.DateTimeFormat(lang, { weekday: 'long' });\n\n const button = doc.createElement('button');\n button.type = 'button';\n button.className = 'fd-calendar-button';\n // A drawn calendar: an emoji would look different on every system.\n const svg = 'http://www.w3.org/2000/svg';\n const icon = doc.createElementNS(svg, 'svg');\n icon.setAttribute('viewBox', '0 0 16 16');\n icon.setAttribute('aria-hidden', 'true');\n for (const [tag, attrs] of [\n ['rect', { x: '2', y: '3', width: '12', height: '11', rx: '1.5' }],\n ['path', { d: 'M2 6.5h12M5 1.5v3M11 1.5v3' }],\n ] as const) {\n const shape = doc.createElementNS(svg, tag);\n for (const [k, v] of Object.entries(attrs)) shape.setAttribute(k, v);\n icon.append(shape);\n }\n button.append(icon);\n button.setAttribute('aria-label', labels.chooseDate);\n button.setAttribute('aria-haspopup', 'dialog');\n button.setAttribute('aria-expanded', 'false');\n button.setAttribute('aria-controls', `${id}-calendar`);\n\n const dialog = doc.createElement('div');\n dialog.className = 'fd-calendar';\n dialog.id = `${id}-calendar`;\n dialog.setAttribute('role', 'dialog');\n dialog.hidden = true;\n const head = doc.createElement('div');\n head.className = 'fd-calendar-head';\n const prev = doc.createElement('button');\n prev.type = 'button';\n prev.textContent = '\u2039';\n prev.setAttribute('aria-label', labels.previousMonth);\n const title = doc.createElement('span');\n title.className = 'fd-calendar-title';\n title.setAttribute('aria-live', 'polite');\n const next = doc.createElement('button');\n next.type = 'button';\n next.textContent = '\u203A';\n next.setAttribute('aria-label', labels.nextMonth);\n head.append(prev, title, next);\n const grid = doc.createElement('table');\n grid.className = 'fd-calendar-grid';\n grid.setAttribute('role', 'grid');\n dialog.append(head, grid);\n\n const element = doc.createElement('span');\n element.className = 'fd-date-pick';\n element.append(inner.element, button, dialog);\n\n let focused = new Date();\n let readonly = false;\n\n function pick(day: Date) {\n if (kind === 'date') {\n form.setValue(name, `${day.getFullYear()}-${pad(day.getMonth() + 1)}-${pad(day.getDate())}`);\n } else {\n const was = dayOf('datetime', form.getState().values[name]);\n const at = new Date(day.getFullYear(), day.getMonth(), day.getDate(), was?.getHours() ?? 0, was?.getMinutes() ?? 0);\n form.setValue(name, at.toISOString());\n }\n close();\n }\n\n function draw(focus: boolean) {\n const chosen = dayOf(kind, form.getState().values[name]);\n const today = new Date();\n const label = monthName.format(focused);\n title.textContent = label;\n dialog.setAttribute('aria-label', label);\n const first = new Date(focused.getFullYear(), focused.getMonth(), 1);\n const start = addDays(first, -((first.getDay() + 6) % 7)); // back to Monday\n const headRow = doc.createElement('tr');\n const weekHead = doc.createElement('th');\n weekHead.scope = 'col';\n weekHead.textContent = labels.weekShort;\n weekHead.setAttribute('abbr', labels.week);\n headRow.append(weekHead);\n for (let i = 0; i < 7; i++) {\n const d = addDays(start, i);\n const th = doc.createElement('th');\n th.scope = 'col';\n th.textContent = weekdayShort.format(d).replace(/\\.$/, '');\n th.setAttribute('abbr', weekdayLong.format(d));\n headRow.append(th);\n }\n const thead = doc.createElement('thead');\n thead.append(headRow);\n const tbody = doc.createElement('tbody');\n for (let row = start; row <= new Date(focused.getFullYear(), focused.getMonth() + 1, 0); row = addDays(row, 7)) {\n const tr = doc.createElement('tr');\n const week = doc.createElement('th');\n week.scope = 'row';\n week.className = 'fd-week';\n week.textContent = String(isoWeek(row));\n tr.append(week);\n for (let i = 0; i < 7; i++) {\n const d = addDays(row, i);\n const cell = doc.createElement('td');\n const day = doc.createElement('button');\n day.type = 'button';\n day.textContent = String(d.getDate());\n day.setAttribute('aria-label', dayName.format(d));\n day.tabIndex = sameDay(d, focused) ? 0 : -1;\n if (d.getMonth() !== focused.getMonth()) day.classList.add('fd-outside');\n if (chosen && sameDay(d, chosen)) day.setAttribute('aria-selected', 'true');\n if (sameDay(d, today)) day.setAttribute('aria-current', 'date');\n day.disabled = readonly;\n day.addEventListener('click', () => pick(d));\n day.addEventListener('keydown', (event) => onKey(event, d));\n cell.append(day);\n tr.append(cell);\n }\n tbody.append(tr);\n }\n grid.replaceChildren(thead, tbody);\n if (focus) grid.querySelector<HTMLButtonElement>('button[tabindex=\"0\"]')?.focus();\n }\n\n function move(to: Date) {\n focused = to;\n draw(true);\n }\n\n function onKey(event: KeyboardEvent, day: Date) {\n const moves: Record<string, () => Date> = {\n ArrowLeft: () => addDays(day, -1),\n ArrowRight: () => addDays(day, 1),\n ArrowUp: () => addDays(day, -7),\n ArrowDown: () => addDays(day, 7),\n PageUp: () => addMonths(day, -1),\n PageDown: () => addMonths(day, 1),\n Home: () => addDays(day, -((day.getDay() + 6) % 7)),\n End: () => addDays(day, 6 - ((day.getDay() + 6) % 7)),\n };\n if (moves[event.key]) {\n event.preventDefault();\n move(moves[event.key]());\n } else if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n pick(day);\n }\n }\n\n function open() {\n focused = dayOf(kind, form.getState().values[name]) ?? new Date();\n dialog.hidden = false;\n button.setAttribute('aria-expanded', 'true');\n draw(true);\n }\n\n function close() {\n if (dialog.hidden) return;\n dialog.hidden = true;\n button.setAttribute('aria-expanded', 'false');\n button.focus();\n }\n\n button.addEventListener('click', () => (dialog.hidden ? open() : close()));\n prev.addEventListener('click', () => {\n focused = addMonths(focused, -1);\n draw(false);\n });\n next.addEventListener('click', () => {\n focused = addMonths(focused, 1);\n draw(false);\n });\n dialog.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n event.stopPropagation();\n close();\n }\n });\n const outside = (event: Event) => {\n if (!dialog.hidden && !element.contains(event.target as Node)) {\n dialog.hidden = true;\n button.setAttribute('aria-expanded', 'false');\n }\n };\n doc.addEventListener('mousedown', outside);\n\n return {\n element,\n focus: () => inner.focus(),\n update(state) {\n readonly = state.readonly;\n button.hidden = state.readonly;\n if (state.readonly) dialog.hidden = true;\n inner.update(state);\n },\n destroy() {\n doc.removeEventListener('mousedown', outside);\n inner.destroy?.();\n },\n };\n}\n", "import type { Field, FieldNode, Form, FormState, JsonValue, PropertyDefinition, Value } from '@fieldia/core';\nimport { createWidget, type Widget, type WidgetFactory } from './widgets';\n\n/**\n * A properties field, one row per property, each edited with the widget for\n * its type: text, numbers, yes/no, a choice, a date. The field's `definitions`\n * say which properties there are; without them, each property is worked out\n * from its value. The properties stay one value: an object by property name.\n */\n\n/** \"lift_access\" \u2192 \"Lift access\". */\nconst humanize = (name: string) => {\n const words = name.replace(/_/g, ' ').trim();\n return words.charAt(0).toUpperCase() + words.slice(1);\n};\n\n/** A property's type, from what it holds. */\nfunction guess(name: string, value: Value | undefined): PropertyDefinition {\n const label = humanize(name);\n if (typeof value === 'boolean') return { name, label, type: 'boolean' };\n if (typeof value === 'number') return { name, label, type: Number.isInteger(value) ? 'integer' : 'float' };\n if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return { name, label, type: 'date' };\n return { name, label, type: 'char' };\n}\n\nexport const propertiesWidget: WidgetFactory = (context) => {\n const { form, name, field, node, id, document } = context;\n const declared = field.type === 'properties' ? field.definitions : undefined;\n const current = () => {\n const value = form.getState().values[name];\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, Value>) : {};\n };\n // Each property's widget sees the properties as its record, and writes into them.\n const properties: Form = {\n ...form,\n getState: (): FormState => ({ ...form.getState(), values: current() }),\n // Property values are plain JSON: text, numbers, yes/no, a choice, a date.\n setValue: (property: string, value: Value) => form.setValue(name, { ...current(), [property]: value } as JsonValue),\n };\n\n const element = document.createElement('div');\n element.className = 'fd-properties';\n element.setAttribute('role', 'group');\n let rows: { definition: PropertyDefinition; widget: Widget }[] = [];\n let drawn = '';\n\n function draw(definitions: PropertyDefinition[]) {\n for (const row of rows) row.widget.destroy?.();\n rows = definitions.map((definition) => {\n const rowId = `${id}-${definition.name}`;\n const propertyField = { type: definition.type, label: definition.label, ...(definition.options ? { options: definition.options } : {}) } as Field;\n const propertyNode: FieldNode = { type: 'field', id: `${node.id}.${definition.name}`, field: definition.name };\n const widget = createWidget({ ...context, form: properties, name: definition.name, field: propertyField, node: propertyNode, id: rowId });\n return { definition, widget };\n });\n element.replaceChildren(\n ...rows.map(({ definition, widget }) => {\n const row = document.createElement('div');\n row.className = 'fd-property';\n row.dataset['type'] = definition.type;\n const label = document.createElement('label');\n label.htmlFor = `${id}-${definition.name}`;\n label.textContent = definition.label;\n row.append(label, widget.element);\n return row;\n })\n );\n }\n\n return {\n element,\n focus: () => rows[0]?.widget.focus(),\n destroy: () => rows.forEach((row) => row.widget.destroy?.()),\n update(state) {\n const values = current();\n const definitions = declared ?? Object.keys(values).map((key) => guess(key, values[key]));\n const key = JSON.stringify(definitions);\n if (key !== drawn) {\n drawn = key;\n draw(definitions);\n }\n for (const { definition, widget } of rows) {\n widget.update({ value: values[definition.name] ?? null, values, readonly: state.readonly, required: false, invalid: false });\n }\n },\n };\n};\n", "import { WIDGET_LABELS, type WidgetLabels } from './labels';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * Formatted text and JSON. Formatted text is edited in place, with a toolbar\n * (bold, italic, underline, headings, lists, alignment, links) that drives the\n * browser's own editing, so no editor library is loaded. Every value \u2014 typed,\n * pasted or loaded \u2014 passes through `sanitizeHtml`, so stored markup can never\n * run script in the page.\n */\n\nconst ALLOWED = new Set([\n 'P', 'BR', 'B', 'STRONG', 'I', 'EM', 'U', 'S', 'UL', 'OL', 'LI', 'A', 'H1', 'H2', 'H3', 'H4',\n 'BLOCKQUOTE', 'CODE', 'PRE', 'SPAN', 'DIV',\n]);\nconst DROPPED_WITH_CONTENT = new Set(['SCRIPT', 'STYLE', 'IFRAME', 'OBJECT', 'EMBED', 'TEMPLATE', 'NOSCRIPT', 'SVG', 'MATH']);\n/** Blocks that may keep their alignment, the one style the toolbar sets. */\nconst ALIGNABLE = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'LI', 'BLOCKQUOTE', 'PRE']);\nconst ALIGNMENTS = new Set(['left', 'center', 'right', 'justify', 'start', 'end']);\n\n/** Keep text structure, block alignment and http(s)/mailto links; drop every other element and attribute. */\nexport function sanitizeHtml(html: string, document: Document = globalThis.document): string {\n const box = document.createElement('template');\n box.innerHTML = html;\n const clean = (parent: ParentNode) => {\n for (const node of [...parent.childNodes]) {\n if (node.nodeType === Node.TEXT_NODE) continue;\n if (node.nodeType !== Node.ELEMENT_NODE) {\n node.remove();\n continue;\n }\n const element = node as Element;\n if (DROPPED_WITH_CONTENT.has(element.tagName)) {\n element.remove();\n continue;\n }\n clean(element);\n if (!ALLOWED.has(element.tagName)) {\n element.replaceWith(...element.childNodes);\n continue;\n }\n const href = element.tagName === 'A' ? element.getAttribute('href') : null;\n const align = ALIGNABLE.has(element.tagName) ? (element as HTMLElement).style?.textAlign?.trim().toLowerCase() : '';\n for (const attribute of [...element.attributes]) element.removeAttribute(attribute.name);\n if (href && /^(https?:|mailto:)/i.test(href.trim())) element.setAttribute('href', href.trim());\n if (align && ALIGNMENTS.has(align)) element.setAttribute('style', `text-align: ${align};`);\n }\n };\n clean(box.content);\n const out = document.createElement('div');\n out.append(box.content);\n return out.innerHTML;\n}\n\n/** A typed address as a link target: web and mail addresses only, \"https://\" added to a bare domain. */\nexport function linkAddress(typed: string): string | null {\n const text = typed.trim();\n if (/^(https?:\\/\\/|mailto:)\\S+$/i.test(text)) return text;\n if (/^[^\\s@:/]+@[^\\s@:/]+\\.[^\\s@:/]+$/.test(text)) return `mailto:${text}`;\n if (/^[\\w-]+(\\.[\\w-]+)+([/?#]\\S*)?$/.test(text)) return `https://${text}`;\n return null;\n}\n\n/** The toolbar's buttons: [label key, editing command, drawn icon]. */\nconst TOOLS: [keyof WidgetLabels, string, string][] = [\n ['bold', 'bold', '<b>B</b>'],\n ['italic', 'italic', '<i>I</i>'],\n ['underline', 'underline', '<u>U</u>'],\n ['bulletList', 'insertUnorderedList', '<svg viewBox=\"0 0 16 16\"><circle cx=\"3\" cy=\"4\" r=\"1.2\"/><circle cx=\"3\" cy=\"8\" r=\"1.2\"/><circle cx=\"3\" cy=\"12\" r=\"1.2\"/><path d=\"M6 4h8M6 8h8M6 12h8\"/></svg>'],\n ['numberList', 'insertOrderedList', '<svg viewBox=\"0 0 16 16\"><path d=\"M2.5 3h1v3M2 10.5c.5-.8 2-.8 2 .2 0 .8-2 1.3-2 2.3h2M6 4h8M6 8h8M6 12h8\"/></svg>'],\n ['alignLeft', 'justifyLeft', '<svg viewBox=\"0 0 16 16\"><path d=\"M2 3.5h12M2 6.5h8M2 9.5h12M2 12.5h8\"/></svg>'],\n ['alignCenter', 'justifyCenter', '<svg viewBox=\"0 0 16 16\"><path d=\"M2 3.5h12M4 6.5h8M2 9.5h12M4 12.5h8\"/></svg>'],\n ['alignRight', 'justifyRight', '<svg viewBox=\"0 0 16 16\"><path d=\"M2 3.5h12M6 6.5h8M2 9.5h12M6 12.5h8\"/></svg>'],\n ['link', 'createLink', '<svg viewBox=\"0 0 16 16\"><path d=\"M7 9a3 3 0 0 0 4.2 0l2.3-2.3a3 3 0 0 0-4.2-4.2L8.2 3.6M9 7a3 3 0 0 0-4.2 0L2.5 9.3a3 3 0 0 0 4.2 4.2l1.1-1.1\"/></svg>'],\n];\n\nexport const htmlWidget: WidgetFactory = ({ form, name, node, id, document, labels = WIDGET_LABELS.en }) => {\n const area = document.createElement('div');\n area.id = id;\n area.className = 'fd-input fd-richtext';\n area.setAttribute('role', 'textbox');\n area.setAttribute('aria-multiline', 'true');\n area.setAttribute('contenteditable', 'true');\n const withToolbar = node.options?.['toolbar'] !== false;\n let last = '';\n area.addEventListener('input', () => {\n const clean = sanitizeHtml(area.innerHTML, document);\n last = clean;\n form.setValue(name, clean.trim() === '' ? null : clean);\n });\n area.addEventListener('blur', () => {\n // Show what was stored: anything unsafe that was typed or pasted is gone.\n if (area.innerHTML !== last) area.innerHTML = last;\n });\n const toolbar = withToolbar ? formattingToolbar(area, document, labels) : null;\n let element: HTMLElement = area;\n if (toolbar) {\n // The box is labelled by the field's label; the text inside it says so too.\n element = document.createElement('div');\n element.className = 'fd-richtext-box';\n element.setAttribute('role', 'group');\n area.setAttribute('aria-labelledby', `${id}-label`);\n element.append(toolbar.bar, toolbar.linkRow, area);\n }\n return {\n element,\n focus: () => area.focus(),\n destroy: () => toolbar?.destroy(),\n update(state) {\n if (toolbar) {\n toolbar.bar.hidden = state.readonly;\n if (state.readonly) toolbar.linkRow.hidden = true;\n }\n const clean = sanitizeHtml(typeof state.value === 'string' ? state.value : '', document);\n if (clean !== last || document.activeElement !== area) {\n if (area.innerHTML !== clean) area.innerHTML = clean;\n last = clean;\n }\n area.setAttribute('contenteditable', String(!state.readonly));\n area.setAttribute('aria-readonly', String(state.readonly));\n area.setAttribute('aria-invalid', String(state.invalid));\n if (state.describedBy) area.setAttribute('aria-describedby', state.describedBy);\n },\n };\n};\n\n/**\n * The toolbar of a formatted text: buttons that keep the text's selection\n * (they act on mousedown's behalf), a text-style choice, and a row for a link's\n * address. One button takes Tab; the arrow keys move along the bar.\n */\nfunction formattingToolbar(area: HTMLElement, doc: Document, labels: WidgetLabels) {\n const bar = doc.createElement('div');\n bar.className = 'fd-richtext-bar';\n bar.setAttribute('role', 'toolbar');\n bar.setAttribute('aria-label', labels.formatting);\n // The last selection made in the text: the style box and the address box take\n // the focus, and a command must act where the person had selected.\n let lastRange: Range | null = null;\n const restore = () => {\n area.focus();\n const selection = doc.getSelection();\n if (lastRange && selection) {\n selection.removeAllRanges();\n selection.addRange(lastRange);\n }\n };\n const run = (command: string, value?: string) => {\n restore();\n doc.execCommand?.(command, false, value);\n };\n\n const style = doc.createElement('select');\n style.className = 'fd-richtext-style';\n style.setAttribute('aria-label', labels.textStyle);\n for (const [value, key] of [['p', 'paragraph'], ['h2', 'heading'], ['h3', 'subheading']] as const) {\n const option = doc.createElement('option');\n option.value = value;\n option.textContent = labels[key];\n style.append(option);\n }\n style.addEventListener('change', () => run('formatBlock', `<${style.value}>`));\n\n const linkRow = doc.createElement('div');\n linkRow.className = 'fd-link-row';\n linkRow.hidden = true;\n const address = doc.createElement('input');\n address.className = 'fd-input';\n address.type = 'url';\n address.placeholder = 'https://';\n address.setAttribute('aria-label', labels.linkAddress);\n const apply = doc.createElement('button');\n apply.type = 'button';\n apply.className = 'fd-button fd-link-apply';\n apply.textContent = labels.applyLink;\n const unlink = doc.createElement('button');\n unlink.type = 'button';\n unlink.className = 'fd-button fd-button-link fd-link-remove';\n unlink.textContent = labels.removeLink;\n linkRow.append(address, apply, unlink);\n apply.addEventListener('click', () => {\n const url = linkAddress(address.value);\n if (!url) {\n address.setAttribute('aria-invalid', 'true');\n return;\n }\n address.setAttribute('aria-invalid', 'false');\n restore();\n doc.execCommand?.('createLink', false, url);\n linkRow.hidden = true;\n });\n unlink.addEventListener('click', () => {\n restore();\n doc.execCommand?.('unlink', false);\n linkRow.hidden = true;\n });\n address.addEventListener('keydown', (event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n apply.click();\n } else if (event.key === 'Escape') {\n event.preventDefault();\n linkRow.hidden = true;\n restore();\n }\n });\n\n const buttons = TOOLS.map(([key, command, icon]) => {\n const button = doc.createElement('button');\n button.type = 'button';\n button.className = 'fd-richtext-tool';\n button.setAttribute('aria-label', labels[key]);\n button.title = labels[key];\n button.innerHTML = icon;\n button.querySelector('svg')?.setAttribute('aria-hidden', 'true');\n if (['bold', 'italic', 'underline'].includes(command)) button.setAttribute('aria-pressed', 'false');\n // Keep the text's selection when the button is pressed.\n button.addEventListener('mousedown', (event) => event.preventDefault());\n button.addEventListener('click', () => {\n if (command !== 'createLink') return run(command);\n linkRow.hidden = false;\n address.value = '';\n address.focus();\n });\n return button;\n });\n bar.append(style, ...buttons);\n\n // One stop on Tab; the arrow keys move along the bar.\n const stops = [style, ...buttons];\n stops.forEach((stop, i) => (stop.tabIndex = i === 0 ? 0 : -1));\n bar.addEventListener('keydown', (event) => {\n if (event.key !== 'ArrowRight' && event.key !== 'ArrowLeft') return;\n const at = stops.indexOf(doc.activeElement as HTMLButtonElement);\n if (at < 0) return;\n const rtl = getComputedStyle(bar).direction === 'rtl';\n const step = (event.key === 'ArrowRight') !== rtl ? 1 : -1;\n const next = stops[(at + step + stops.length) % stops.length];\n event.preventDefault();\n stops.forEach((stop) => (stop.tabIndex = stop === next ? 0 : -1));\n next.focus();\n });\n\n // Show which formats the selection already has.\n const reflect = () => {\n const selection = doc.getSelection();\n if (!selection || !selection.rangeCount || !area.contains(selection.anchorNode)) return;\n lastRange = selection.getRangeAt(0).cloneRange();\n for (const button of buttons) {\n const command = TOOLS[buttons.indexOf(button)][1];\n if (button.hasAttribute('aria-pressed')) button.setAttribute('aria-pressed', String(doc.queryCommandState?.(command) ?? false));\n }\n const block = String(doc.queryCommandValue?.('formatBlock') ?? '').toLowerCase().replace(/[<>]/g, '');\n style.value = block === 'h2' || block === 'h3' ? block : 'p';\n };\n doc.addEventListener('selectionchange', reflect);\n return { bar, linkRow, destroy: () => doc.removeEventListener('selectionchange', reflect) };\n}\n\nexport const jsonWidget: WidgetFactory = ({ form, name, id, document, labels = WIDGET_LABELS.en }) => {\n const element = document.createElement('div');\n element.className = 'fd-json';\n const area = document.createElement('textarea');\n area.id = id;\n area.className = 'fd-input fd-textarea fd-code';\n area.spellcheck = false;\n const error = document.createElement('div');\n error.className = 'fd-cell-error';\n error.hidden = true;\n element.append(area, error);\n area.addEventListener('input', () => {\n if (area.value.trim() === '') {\n error.hidden = true;\n form.setValue(name, null);\n return;\n }\n try {\n const parsed = JSON.parse(area.value);\n error.hidden = true;\n form.setValue(name, parsed);\n } catch {\n error.hidden = false;\n error.textContent = labels.invalidJson;\n }\n });\n return {\n element,\n focus: () => area.focus(),\n update(state) {\n if (document.activeElement !== area) {\n const text = state.value === null || state.value === undefined ? '' : JSON.stringify(state.value, null, 2);\n if (area.value !== text) area.value = text;\n }\n area.readOnly = state.readonly;\n area.setAttribute('aria-invalid', String(state.invalid || !error.hidden));\n },\n };\n};\n", "import type {\n Field,\n FieldNode,\n FileValue,\n Form,\n Line,\n Locale,\n RecordId,\n ReferenceValue,\n RelatedRecord,\n Value,\n Values,\n} from '@fieldia/core';\nimport type { PreferenceStore } from './preferences';\nimport { formatNumber, normalizeNumber } from './numbers';\nimport type { WidgetLabels } from './labels';\nimport { charTagsWidget, linkCheckboxesWidget, many2oneWidget, referenceWidget, tagsWidget } from './relations';\nimport { linesWidget } from './lines';\nimport { binaryWidget, imageWidget } from './files';\nimport { progressbarWidget } from './progress';\nimport { labelWidget } from './label';\nimport { statusbarWidget } from './statusbar';\nimport { withCalendar } from './calendar';\nimport { propertiesWidget } from './properties';\nimport { htmlWidget, jsonWidget } from './extras';\n\n/**\n * Field inputs in plain DOM. Each widget builds its element once and then only\n * patches it from state, so typing never loses focus or the caret, and the\n * same widget serves every framework binding.\n */\n\nexport interface WidgetContext {\n form: Form;\n /** The field's name in the page. */\n name: string;\n field: Field;\n node: FieldNode;\n /** The id the field's label points at. */\n id: string;\n document: Document;\n /** Words the widget shows itself, in the page's language. English when left out. */\n labels?: WidgetLabels;\n /** Where to keep a person's choices about how the widget looks, such as a table's columns. */\n preferences?: PreferenceStore;\n /** The page's language: numbers and dates are written as its readers write them. English when left out. */\n locale?: Locale;\n /** Dialogs the page can open: a related record, a searchable list, values to edit. Left out, widgets offer none. */\n dialogs?: WidgetDialogs;\n}\n\n/** What a widget may ask of the page around it in a dialog. The viewer provides these. */\nexport interface WidgetDialogs {\n /** Whether a record of this model can be shown in a dialog: the app gave a page for it. */\n canOpen(model: string): boolean;\n /**\n * A record in a dialog: an existing one (`recordId`) or a new one, whose name\n * starts as `name`. Resolves with the record once saved, or null.\n */\n openRecord(model: string, request: { recordId?: RecordId; name?: string; title: string }): Promise<RelatedRecord | null>;\n /** Pick a record from a searchable list. */\n searchMore(request: { title: string; search(query: string, limit: number): Promise<RelatedRecord[]> }): Promise<RelatedRecord | null>;\n /**\n * Values edited in a form made of these fields. Resolves with the new values,\n * or null. `recompute` recalculates them as they change, as a line's onchange.\n */\n editValues(request: { title: string; fields: Record<string, Field>; values: Values; readonly?: boolean; recompute?: (values: Values) => Promise<Values> }): Promise<Values | null>;\n}\n\nexport interface WidgetState {\n value: Value | undefined;\n /** Every value of the record, for widgets that show one field beside another. */\n values: Readonly<Values>;\n readonly: boolean;\n required: boolean;\n invalid: boolean;\n /** Ids of the help and error text, for assistive technology. */\n describedBy?: string;\n}\n\nexport interface Widget {\n element: HTMLElement;\n update(state: WidgetState): void;\n focus(): void;\n destroy?(): void;\n}\n\nexport type WidgetFactory = (context: WidgetContext) => Widget;\n\n/**\n * Pick the widget for a field: the app's or the built-in one for\n * `type.widget` (such as `selection.radio`), then for the type alone. A type\n * with no editor yet shows its value read-only.\n */\nexport function createWidget(context: WidgetContext, registry: Record<string, WidgetFactory> = {}): Widget {\n const { field, node } = context;\n const keys = [\n node.widget ? `${field.type}.${node.widget}` : null,\n field.type === 'selection' && field.multiple ? 'selection.checkboxes' : null,\n field.type,\n ].filter((key): key is string => key !== null);\n for (const key of keys) {\n const factory = registry[key] ?? builtInWidgets[key];\n if (factory) return factory(context);\n }\n return pendingWidget(context);\n}\n\n// ---------------------------------------------------------------------------\n\nfunction make<K extends keyof HTMLElementTagNameMap>(\n doc: Document,\n tag: K,\n props: Partial<Record<string, string>> = {},\n ...children: (Node | string)[]\n): HTMLElementTagNameMap[K] {\n const element = doc.createElement(tag);\n for (const [name, value] of Object.entries(props)) if (value !== undefined) element.setAttribute(name, value);\n element.append(...children);\n return element;\n}\n\nfunction describe(element: HTMLElement, state: WidgetState) {\n element.setAttribute('aria-invalid', String(state.invalid));\n element.setAttribute('aria-required', String(state.required));\n if (state.describedBy) element.setAttribute('aria-describedby', state.describedBy);\n else element.removeAttribute('aria-describedby');\n}\n\nconst textOf = (value: Value | undefined) => (value === null || value === undefined ? '' : String(value));\n\nfunction textWidget(inputType: string): WidgetFactory {\n return ({ form, name, field, node, id, document }) => {\n const input = make(document, 'input', { id, type: inputType, class: 'fd-input', autocomplete: 'off' });\n if (field.type === 'char' && field.size !== undefined) input.maxLength = field.size;\n if (node.placeholder) input.placeholder = node.placeholder;\n input.addEventListener('input', () => form.setValue(name, input.value === '' ? null : input.value));\n return {\n element: input,\n focus: () => input.focus(),\n update(state) {\n const text = textOf(state.value);\n if (input.value !== text) input.value = text;\n input.readOnly = state.readonly;\n describe(input, state);\n },\n };\n };\n}\n\nconst textareaWidget: WidgetFactory = ({ form, name, field, node, id, document }) => {\n const area = make(document, 'textarea', { id, class: 'fd-input fd-textarea', rows: '3' });\n if (field.type === 'text' && field.size !== undefined) area.maxLength = field.size;\n if (node.placeholder) area.placeholder = node.placeholder;\n area.addEventListener('input', () => form.setValue(name, area.value === '' ? null : area.value));\n return {\n element: area,\n focus: () => area.focus(),\n update(state) {\n const text = textOf(state.value);\n if (area.value !== text) area.value = text;\n area.readOnly = state.readonly;\n describe(area, state);\n },\n };\n};\n\nconst NUMBER = /^-?(\\d+\\.?\\d*|\\.\\d+)$/;\nconst UNFINISHED = /^-?\\.?$/;\n\n/**\n * Numbers are written as readers of the page's language write them, grouped,\n * with the field's decimals, and read back the same way. What is typed stays\n * as typed while focused: \"1.\" means 1 now and 1.5 a keystroke later. The box\n * keeps its spelling when entered, so a selection made on the way in holds.\n */\nconst numberWidget: WidgetFactory = (context) => {\n const { form, name, field, node, id, document, locale = 'en' } = context;\n const integer = field.type === 'integer';\n const decimals = integer ? 0 : (field.type === 'float' || field.type === 'monetary' ? field.digits?.[1] : undefined) ?? 2;\n const shown = (value: Value | undefined) => (typeof value === 'number' ? formatNumber(value, decimals, locale) : textOf(value));\n const input = make(document, 'input', { id, type: 'text', class: 'fd-input fd-number-input', autocomplete: 'off' });\n input.inputMode = integer ? 'numeric' : 'decimal';\n if (node.placeholder) input.placeholder = node.placeholder;\n\n const parse = (raw: string): Value | undefined => {\n const text = normalizeNumber(raw.trim(), locale);\n if (text === '') return null;\n if (NUMBER.test(text)) return Number(text);\n if (UNFINISHED.test(text)) return undefined; // \"-\" or \".\": keep typing\n return text; // not a number: validation names it\n };\n input.addEventListener('input', () => {\n const value = parse(input.value);\n if (value !== undefined) form.setValue(name, value);\n });\n input.addEventListener('blur', () => {\n input.value = shown(form.getState().values[name]);\n });\n\n // Money shows its currency beside the amount (options.symbol \"after\" puts it\n // after), or with options.pickCurrency the currency field's own widget, to change it.\n const options = node.options ?? {};\n const currencyField = field.type === 'monetary' ? field.currencyField : undefined;\n const currencyDef = currencyField ? form.page.fields[currencyField] : undefined;\n const picker =\n currencyField && currencyDef && options['pickCurrency'] === true\n ? createWidget({ ...context, name: currencyField, field: currencyDef, node: { type: 'field', id: `${node.id}.currency`, field: currencyField }, id: `${id}-currency` })\n : null;\n if (picker && currencyDef) picker.element.querySelector('input, select')?.setAttribute('aria-label', currencyDef.label);\n if (picker?.element.matches('input, select') && currencyDef) picker.element.setAttribute('aria-label', currencyDef.label);\n const currency = field.type === 'monetary' && !picker ? make(document, 'span', { class: 'fd-currency', 'aria-hidden': 'true' }) : null;\n const side = picker?.element ?? currency;\n const after = options['symbol'] === 'after';\n const element = side\n ? make(document, 'span', { class: `fd-number${after ? ' fd-currency-after' : ''}${picker ? ' fd-currency-picked' : ''}` }, ...(after ? [input, side] : [side, input]))\n : input;\n\n return {\n element,\n focus: () => input.focus(),\n update(state) {\n const typing = document.activeElement === input;\n const parsed = parse(input.value);\n const showsSame = parsed === undefined || parsed === state.value;\n if (!(typing && showsSame)) {\n const text = shown(state.value);\n if (input.value !== text) input.value = text;\n }\n input.readOnly = state.readonly;\n describe(input, state);\n if (picker && currencyField) {\n picker.update({ value: state.values[currencyField], values: state.values, readonly: state.readonly, required: false, invalid: false });\n }\n if (currency && field.type === 'monetary') {\n const holder = field.currencyField ? state.values[field.currencyField] : null;\n currency.textContent =\n holder && typeof holder === 'object' && 'label' in holder ? (holder as RelatedRecord).label : (typeof holder === 'string' ? holder : field.currency ?? '');\n }\n },\n };\n};\n\nfunction checkboxWidget(role?: 'switch'): WidgetFactory {\n return ({ form, name, id, document }) => {\n const box = make(document, 'input', { id, type: 'checkbox', class: role ? 'fd-switch' : 'fd-checkbox', role });\n box.addEventListener('change', () => form.setValue(name, box.checked));\n return {\n element: box,\n focus: () => box.focus(),\n update(state) {\n box.checked = state.value === true;\n box.disabled = state.readonly;\n describe(box, state);\n },\n };\n };\n}\n\nfunction options(field: Field) {\n return field.type === 'selection' ? field.options : [];\n}\n\nconst selectWidget: WidgetFactory = ({ form, name, field, id, document }) => {\n const choices = options(field);\n const select = make(document, 'select', { id, class: 'fd-input fd-select' }, make(document, 'option', { value: '' }));\n choices.forEach((option, i) => select.append(make(document, 'option', { value: String(i) }, option.label)));\n select.addEventListener('change', () => form.setValue(name, select.value === '' ? null : choices[Number(select.value)].value));\n return {\n element: select,\n focus: () => select.focus(),\n update(state) {\n const index = choices.findIndex((option) => option.value === state.value);\n select.value = index === -1 ? '' : String(index);\n select.disabled = state.readonly;\n describe(select, state);\n },\n };\n};\n\nfunction choiceGroup(kind: 'radio' | 'checkbox'): WidgetFactory {\n return ({ form, name, field, id, document }) => {\n const choices = options(field);\n const group = make(document, 'div', { id, class: `fd-choices fd-choices-${kind}`, role: kind === 'radio' ? 'radiogroup' : 'group' });\n const inputs = choices.map((option, i) => {\n const input = make(document, 'input', { type: kind, name: id, value: String(i), id: `${id}-${i}` });\n group.append(make(document, 'label', { class: 'fd-choice', for: `${id}-${i}` }, input, make(document, 'span', {}, option.label)));\n return input;\n });\n group.addEventListener('change', () => {\n if (kind === 'radio') {\n const chosen = inputs.findIndex((input) => input.checked);\n form.setValue(name, chosen === -1 ? null : choices[chosen].value);\n } else {\n form.setValue(name, choices.filter((_, i) => inputs[i].checked).map((option) => option.value));\n }\n });\n return {\n element: group,\n focus: () => (inputs.find((input) => input.checked) ?? inputs[0])?.focus(),\n update(state) {\n const chosen = Array.isArray(state.value) ? state.value : [state.value];\n inputs.forEach((input, i) => {\n input.checked = chosen.includes(choices[i].value as never);\n input.disabled = state.readonly;\n });\n describe(group, state);\n },\n };\n };\n}\n\n/** Stars or numbers to pick from, as a radio group with arrow-key support. */\nfunction pointsWidget(style: 'rating' | 'scale'): WidgetFactory {\n return ({ form, name, field, id, document }) => {\n const min = 'min' in field && field.min !== undefined ? field.min : style === 'rating' ? 1 : 0;\n const max = 'max' in field && field.max !== undefined ? field.max : style === 'rating' ? 5 : 10;\n const group = make(document, 'div', { id, class: `fd-points fd-${style}`, role: 'radiogroup' });\n const points: HTMLButtonElement[] = [];\n for (let n = min; n <= max; n++) {\n const point = make(document, 'button', { type: 'button', role: 'radio', 'aria-label': `${n} of ${max}`, 'data-value': String(n) }, style === 'rating' ? '\u2605' : String(n));\n if (style === 'scale') point.removeAttribute('aria-label');\n point.addEventListener('click', () => form.setValue(name, n));\n points.push(point);\n group.append(point);\n }\n group.addEventListener('keydown', (event) => {\n const current = form.getState().values[name];\n const value = typeof current === 'number' ? current : min - 1;\n const step = event.key === 'ArrowRight' || event.key === 'ArrowUp' ? 1 : event.key === 'ArrowLeft' || event.key === 'ArrowDown' ? -1 : 0;\n if (!step) return;\n event.preventDefault();\n const next = Math.min(max, Math.max(min, value + step));\n form.setValue(name, next);\n points[next - min]?.focus();\n });\n return {\n element: group,\n focus: () => (points.find((p) => p.getAttribute('aria-checked') === 'true') ?? points[0])?.focus(),\n update(state) {\n const value = typeof state.value === 'number' ? state.value : null;\n points.forEach((point, i) => {\n const n = min + i;\n point.setAttribute('aria-checked', String(n === value));\n point.classList.toggle('fd-on', style === 'rating' ? value !== null && n <= value : n === value);\n point.tabIndex = n === value || (value === null && i === 0) ? 0 : -1;\n point.disabled = state.readonly;\n });\n describe(group, state);\n },\n };\n };\n}\n\nconst dateWidget: WidgetFactory = (context) => {\n const { form, name, id, document, node } = context;\n const input = make(document, 'input', { id, type: 'date', class: 'fd-input fd-date' });\n input.addEventListener('input', () => form.setValue(name, input.value || null));\n const widget: Widget = {\n element: input,\n focus: () => input.focus(),\n update(state) {\n const text = textOf(state.value);\n if (input.value !== text) input.value = text;\n input.readOnly = state.readonly;\n describe(input, state);\n },\n };\n return node.options?.['weekNumbers'] === true ? withCalendar(widget, context, 'date') : widget;\n};\n\nconst pad = (n: number) => String(n).padStart(2, '0');\n\n/** Shown in local time, stored as an ISO instant in UTC. */\nconst dateTimeWidget: WidgetFactory = (context) => {\n const { form, name, id, document, node } = context;\n const input = make(document, 'input', { id, type: 'datetime-local', class: 'fd-input fd-datetime' });\n const local = (iso: Value | undefined) => {\n if (typeof iso !== 'string' || !iso) return '';\n const d = new Date(iso);\n return Number.isNaN(d.getTime()) ? '' : `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;\n };\n input.addEventListener('input', () => {\n if (!input.value) return form.setValue(name, null);\n const d = new Date(input.value);\n if (!Number.isNaN(d.getTime())) form.setValue(name, d.toISOString());\n });\n const widget: Widget = {\n element: input,\n focus: () => input.focus(),\n update(state) {\n const text = local(state.value);\n if (input.value !== text) input.value = text;\n input.readOnly = state.readonly;\n describe(input, state);\n },\n };\n return node.options?.['weekNumbers'] === true ? withCalendar(widget, context, 'datetime') : widget;\n};\n\n/** Until a type has its own editor (Phase 5), show what it holds. */\nfunction pendingWidget({ field, id, document }: WidgetContext): Widget {\n const span = make(document, 'span', { id, class: 'fd-pending', 'data-fd-pending': field.type });\n return {\n element: span,\n focus: () => undefined,\n update(state) {\n span.textContent = summary(state.value, field);\n },\n };\n}\n\nexport function summary(value: Value | undefined, field: Field): string {\n if (value === null || value === undefined) return '';\n switch (field.type) {\n case 'many2one':\n case 'reference':\n return (value as RelatedRecord | ReferenceValue).label;\n case 'many2many':\n return (value as RelatedRecord[]).map((record) => record.label).join(', ');\n case 'one2many': {\n const count = (value as Line[]).length;\n return `${count} ${count === 1 ? 'line' : 'lines'}`;\n }\n case 'binary':\n case 'image':\n return (value as FileValue).name;\n case 'html':\n return String(value).replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim();\n default:\n return typeof value === 'object' ? JSON.stringify(value) : String(value);\n }\n}\n\nexport const builtInWidgets: Record<string, WidgetFactory> = {\n char: textWidget('text'),\n 'char.email': textWidget('email'),\n 'char.phone': textWidget('tel'),\n 'char.url': textWidget('url'),\n 'char.password': textWidget('password'),\n 'char.tags': charTagsWidget,\n text: textareaWidget,\n integer: numberWidget,\n float: numberWidget,\n monetary: numberWidget,\n 'integer.rating': pointsWidget('rating'),\n 'integer.scale': pointsWidget('scale'),\n 'integer.progressbar': progressbarWidget,\n 'integer.label': labelWidget,\n 'float.label': labelWidget,\n 'monetary.label': labelWidget,\n 'float.progressbar': progressbarWidget,\n 'monetary.progressbar': progressbarWidget,\n boolean: checkboxWidget(),\n 'boolean.toggle': checkboxWidget('switch'),\n selection: selectWidget,\n 'selection.radio': choiceGroup('radio'),\n 'selection.checkboxes': choiceGroup('checkbox'),\n 'selection.statusbar': statusbarWidget,\n date: dateWidget,\n datetime: dateTimeWidget,\n many2one: many2oneWidget,\n 'many2one.statusbar': statusbarWidget,\n many2many: tagsWidget,\n 'many2many.tags': tagsWidget,\n 'many2many.checkboxes': linkCheckboxesWidget,\n reference: referenceWidget,\n one2many: linesWidget,\n binary: binaryWidget,\n image: imageWidget,\n html: htmlWidget,\n json: jsonWidget,\n properties: propertiesWidget,\n};\n", "/**\n * Fieldia's stylesheet: two skins and the layout chrome, all scoped to the\n * form's own root (`.fd-form[data-fd-skin=\u2026]`), so two forms on one page can\n * wear different skins and the host page's own controls are never touched.\n *\n * underline \u2014 the Flectra and Odoo style: flat inputs on a single line, labels\n * beside the field, navy accents.\n * outlined \u2014 the Ant Design style: boxed inputs with rounded corners, labels\n * above the field, a blue focus glow.\n *\n * Written with logical properties (inline/block, start/end), so a right-to-left\n * form mirrors without a second stylesheet.\n */\nexport const FIELDIA_CSS = /* css */ `.fd-form,.fd-theme{--fd-font: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Noto Sans\", \"Noto Sans Arabic\", sans-serif;--fd-text: #212529;--fd-muted: #6b7280;--fd-page: #f2f3f5;--fd-surface: #ffffff;--fd-border: #cfd4da;--fd-border-strong: #9aa3ad;--fd-accent: #002855;--fd-accent-text: #ffffff;--fd-accent-soft: #e6ebf2;--fd-focus: #002855;--fd-focus-ring: none;--fd-error: #c62828;--fd-error-soft: #fdecea;--fd-success: #2e7d32;--fd-success-soft: #e8f5e9;--fd-warning: #8a5300;--fd-warning-soft: #fff4e0;--fd-info: #0b5cad;--fd-info-soft: #e7f0fb;--fd-radius: 0px;--fd-control-radius: 0px;--fd-pad-y: 3px;--fd-pad-x: 4px;--fd-input-border: 0 0 1px 0;--fd-label-weight: 600;--fd-gap-x: 32px;--fd-gap-y: 14px;container-type:inline-size;font-family:var(--fd-font);font-size:14px;line-height:1.45;color:var(--fd-text);-webkit-text-size-adjust:100%}.fd-form[data-fd-skin=outlined],.fd-theme[data-fd-skin=outlined]{--fd-text: rgba(0, 0, 0, .88);--fd-muted: rgba(0, 0, 0, .55);--fd-page: #f5f5f5;--fd-border: #d9d9d9;--fd-border-strong: #bfbfbf;--fd-accent: #1677ff;--fd-accent-soft: #e6f4ff;--fd-focus: #1677ff;--fd-focus-ring: 0 0 0 2px rgba(5, 145, 255, .12);--fd-error: #ff4d4f;--fd-error-soft: #fff2f0;--fd-radius: 8px;--fd-control-radius: 6px;--fd-pad-y: 4px;--fd-pad-x: 11px;--fd-input-border: 1px;--fd-label-weight: 400;--fd-gap-x: 24px;--fd-gap-y: 18px}.fd-form *,.fd-form *:before,.fd-form *:after{box-sizing:border-box}.fd-form [hidden]{display:none!important}.fd-page-head{display:grid;gap:4px;margin-block-end:20px}.fd-page-title{font-size:22px;font-weight:650;margin:0;line-height:1.25}.fd-page-description{color:var(--fd-muted);margin:0}.fd-form[data-max-width=narrow]{--fd-page-max: 640px}.fd-form[data-max-width=medium]{--fd-page-max: 900px}.fd-form[data-max-width=wide]{--fd-page-max: 1180px}.fd-form[data-max-width=full]{--fd-page-max: none}.fd-form[data-max-width]>.fd-content:not(:has(>.fd-sheet-page)){max-width:var(--fd-page-max);margin-inline:auto}.fd-actions.fd-actions-top{margin-block-start:0;padding-block-end:14px;margin-block-end:18px;border-block-end:1px solid var(--fd-border)}.fd-icon{width:1.15em;height:1.15em;flex:none;vertical-align:-.2em}.fd-section-title .fd-icon,.fd-tab .fd-icon,.fd-button .fd-icon,.fd-step-title .fd-icon{margin-inline-end:.4em}.fd-section-title .fd-icon{color:var(--fd-muted)}.fd-grid{display:grid;grid-template-columns:repeat(var(--fd-columns, 1),minmax(0,1fr));gap:var(--fd-gap-y) var(--fd-gap-x);align-items:start}.fd-field{display:grid;gap:4px;min-width:0;grid-column:span min(var(--fd-span, 1),var(--fd-columns, 1))}.fd-label{font-weight:var(--fd-label-weight);color:var(--fd-text)}.fd-valid-mark{color:var(--fd-success);width:1em;height:1em;margin-inline-start:6px;vertical-align:-.15em;stroke-width:2.4}.fd-field.fd-required>.fd-label:after{content:\" *\";color:var(--fd-error)}.fd-form[data-fd-skin=outlined] .fd-field.fd-required>.fd-label:after{content:\"\"}.fd-form[data-fd-skin=outlined] .fd-field.fd-required>.fd-label:before{content:\"* \";color:var(--fd-error)}.fd-help{color:var(--fd-muted);font-size:12.5px}.fd-error{color:var(--fd-error);font-size:12.5px}.fd-warning{color:var(--fd-warning);background:var(--fd-warning-soft);font-size:12.5px;padding:3px 8px;border-radius:var(--fd-control-radius);justify-self:start}.fd-form[data-fd-skin=underline] .fd-field{grid-template-columns:var(--fd-label-width, 11em) minmax(0,1fr);column-gap:12px;align-items:baseline}.fd-form[data-fd-skin=underline] .fd-field>.fd-label{grid-column:1}.fd-form[data-fd-skin=underline] .fd-field[data-type=one2many]{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-field[data-type=one2many]>*{grid-column:1!important}.fd-form[data-fd-skin=underline] .fd-field>:not(.fd-label){grid-column:2}@container (max-width: 760px){.fd-form[data-fd-skin=underline] .fd-grid{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-field{grid-column:auto}.fd-form .fd-grid[data-columns-medium]{grid-template-columns:repeat(var(--fd-columns-medium),minmax(0,1fr))}.fd-form .fd-grid[data-columns-medium]>.fd-field{grid-column:span min(var(--fd-span, 1),var(--fd-columns-medium))}.fd-form[data-fd-skin=underline] .fd-grid[data-columns-medium]:not([data-columns-medium=\"1\"]) .fd-field{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-grid[data-columns-medium]:not([data-columns-medium=\"1\"]) .fd-field>*{grid-column:1!important}}@container (max-width: 520px){.fd-grid{grid-template-columns:minmax(0,1fr)}.fd-field{grid-column:auto}.fd-form[data-fd-skin=underline] .fd-field{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-field>*{grid-column:1!important}.fd-form .fd-grid[data-columns-medium],.fd-form .fd-grid[data-columns-narrow]{grid-template-columns:repeat(var(--fd-columns-narrow, 1),minmax(0,1fr))}.fd-form .fd-grid[data-columns-medium]>.fd-field,.fd-form .fd-grid[data-columns-narrow]>.fd-field{grid-column:span min(var(--fd-span, 1),var(--fd-columns-narrow, 1))}}.fd-input{width:100%;min-width:0;font:inherit;color:inherit;background:var(--fd-surface);border:solid var(--fd-border);border-width:var(--fd-input-border);border-radius:var(--fd-control-radius);padding:var(--fd-pad-y) var(--fd-pad-x);min-height:30px;transition:border-color .15s ease,box-shadow .15s ease}.fd-input::placeholder{color:var(--fd-muted);opacity:.8}.fd-input:hover{border-color:var(--fd-border-strong)}.fd-input:focus{outline:none;border-color:var(--fd-focus);box-shadow:var(--fd-focus-ring)}.fd-form[data-fd-skin=underline] .fd-input{background:transparent}.fd-form[data-fd-skin=underline] .fd-input:focus{box-shadow:0 1px 0 0 var(--fd-focus)}.fd-form[data-fd-skin=underline] .fd-field.fd-required .fd-input{border-color:var(--fd-accent)}.fd-input[readonly]{background:transparent;border-color:transparent;padding-inline:0}.fd-form[data-fd-skin=outlined] .fd-input[readonly]{background:#0000000a;border-color:var(--fd-border);padding-inline:var(--fd-pad-x);color:var(--fd-muted)}.fd-form[data-readonly] .fd-input[readonly]{background:transparent;border-color:transparent;padding-inline:0;color:var(--fd-text)}.fd-form[data-readonly] .fd-input::placeholder{color:transparent}.fd-form[data-readonly] select.fd-input:disabled{appearance:none;background:transparent;border-color:transparent;padding-inline:0;color:var(--fd-text);opacity:1}.fd-input[aria-invalid=true]{border-color:var(--fd-error)}.fd-form[data-fd-skin=outlined] .fd-input[aria-invalid=true]:focus{box-shadow:0 0 0 2px #ff26050f}.fd-textarea{resize:vertical;min-height:64px}.fd-select{appearance:auto}.fd-number{display:flex;align-items:baseline;gap:6px}.fd-number-input{font-variant-numeric:tabular-nums}.fd-currency{color:var(--fd-muted);font-size:12.5px;font-weight:600}.fd-currency-after>.fd-number-input{text-align:end}.fd-currency-picked{align-items:center}.fd-currency-picked>:not(.fd-number-input){flex:0 0 104px;min-width:0}.fd-currency-picked>.fd-number-input{flex:1 1 auto;min-width:0}.fd-pending{color:var(--fd-muted);font-style:italic}.fd-pending:empty:before{content:\"\u2014\"}.fd-checkbox,.fd-choice input{width:16px;height:16px;accent-color:var(--fd-accent);margin:0}.fd-switch{appearance:none;width:34px;height:20px;margin:0;border-radius:999px;position:relative;background:var(--fd-border-strong);cursor:pointer;transition:background .2s ease}.fd-switch:after{content:\"\";position:absolute;inset-block-start:2px;inset-inline-start:2px;width:16px;height:16px;border-radius:50%;background:#fff;transition:transform .2s ease;box-shadow:0 1px 2px #00000040}.fd-switch:checked{background:var(--fd-accent)}.fd-switch:checked:after{transform:translate(14px)}[dir=rtl] .fd-switch:checked:after{transform:translate(-14px)}.fd-choices{display:flex;flex-wrap:wrap;gap:6px 18px}.fd-choice{display:inline-flex;align-items:center;gap:8px;cursor:pointer}.fd-points{display:flex;flex-wrap:wrap;gap:6px}.fd-points button{font:inherit;cursor:pointer;border:1px solid var(--fd-border);background:var(--fd-surface);color:var(--fd-text);border-radius:var(--fd-control-radius);min-width:34px;height:34px;padding:0 8px}.fd-points button.fd-on{background:var(--fd-accent);color:var(--fd-accent-text);border-color:var(--fd-accent)}.fd-rating button{border:none;background:none;font-size:24px;color:var(--fd-border-strong);padding:0 2px;min-width:0}.fd-rating button.fd-on{background:none;color:#f5a623}.fd-points button:disabled,.fd-choice input:disabled{cursor:default}.fd-form :focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px}.fd-form .fd-input:focus-visible{outline:none}.fd-combo{position:relative;display:flex;align-items:center;min-width:0}.fd-combo-input{padding-inline-end:28px}.fd-combo-clear{position:absolute;inset-inline-end:4px;border:none;background:none;cursor:pointer;color:var(--fd-muted);font-size:16px;line-height:1;padding:2px 6px;border-radius:4px}.fd-combo-clear:hover{color:var(--fd-text);background:var(--fd-page)}.fd-combo:has(>.fd-combo-open:not([hidden])) .fd-combo-input{padding-inline-end:52px}.fd-combo-open{position:absolute;inset-inline-end:28px;border:none;background:none;cursor:pointer;color:var(--fd-accent);font-size:14px;line-height:1;padding:2px 6px;border-radius:4px}.fd-combo-open:hover{background:var(--fd-page)}.fd-listbox{position:absolute;inset-inline:0;inset-block-start:calc(100% + 2px);z-index:20;margin:0;padding:4px 0;list-style:none;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:max(var(--fd-control-radius),4px);box-shadow:0 8px 24px #0f14191f;max-height:240px;overflow-y:auto}.fd-option{padding:6px 12px;cursor:pointer}.fd-option:hover,.fd-option.fd-active{background:var(--fd-accent-soft)}.fd-option-create{color:var(--fd-accent);border-block-start:1px solid var(--fd-border)}.fd-empty{padding:6px 12px;color:var(--fd-muted);font-style:italic}.fd-tags{display:flex;flex-wrap:wrap;gap:6px;align-items:center;min-width:0}.fd-chips{display:contents;list-style:none;margin:0;padding:0}.fd-chip{display:inline-flex;align-items:center;gap:4px;padding:1px 4px 1px 10px;border-radius:999px;background:var(--fd-accent-soft);color:var(--fd-text);font-size:13px;line-height:22px}.fd-chip-remove{border:none;background:none;cursor:pointer;color:var(--fd-muted);font-size:15px;line-height:1;padding:0 4px;border-radius:999px}.fd-chip-remove:hover{color:var(--fd-error)}.fd-tags .fd-combo{flex:1 1 140px}.fd-reference{display:grid;grid-template-columns:minmax(7em,34%) minmax(0,1fr);gap:8px}.fd-lines{display:grid;grid-template-columns:minmax(0,1fr);gap:6px;min-width:0}.fd-lines-scroll{overflow-x:auto;min-width:0;position:relative}.fd-lines-table{width:100%;border-collapse:collapse;font-size:13.5px}.fd-lines-table th{text-align:start;font-weight:600;color:var(--fd-muted);font-size:12.5px;padding:6px 8px;border-block-end:1px solid var(--fd-border);white-space:nowrap}.fd-lines-table td{padding:4px 8px;border-block-end:1px solid var(--fd-border);vertical-align:top;min-width:7em}.fd-lines-table td.fd-lines-tools,.fd-lines-table th.fd-lines-tools{width:32px;min-width:32px;padding-inline:0;text-align:center}.fd-lines-table .fd-input{min-height:28px}.fd-lines-table td>.fd-checkbox,.fd-lines-table td>.fd-switch{margin-block-start:6px}.fd-line-delete{border:none;background:none;cursor:pointer;color:var(--fd-muted);font-size:16px;line-height:1;padding:4px 6px;border-radius:4px}.fd-line-delete:hover{color:var(--fd-error);background:var(--fd-error-soft)}.fd-lines-totals td{padding:8px;font-weight:600;border-block-start:1px solid var(--fd-border);font-variant-numeric:tabular-nums}.fd-lines-adds{display:flex;flex-wrap:wrap;gap:4px 16px;justify-self:start}.fd-line-section td{background:var(--fd-page)}.fd-line-section .fd-input{font-weight:600}.fd-line-note .fd-input{font-style:italic}.fd-cell-error{color:var(--fd-error);font-size:12px}.fd-sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-file{display:grid;gap:8px;justify-items:start;padding:6px 0;border-radius:var(--fd-control-radius)}.fd-file.fd-dragging{outline:2px dashed var(--fd-accent);outline-offset:4px}.fd-file-pick{display:inline-flex;flex-wrap:wrap;gap:8px;align-items:center;cursor:pointer}.fd-file-chosen{display:inline-flex;flex-wrap:wrap;gap:4px 10px;align-items:center}.fd-file-name{font-variant-numeric:tabular-nums}.fd-image-pick{width:120px;height:120px;border:1px dashed var(--fd-border-strong);border-radius:var(--fd-control-radius);display:grid;place-content:center;justify-items:center;text-align:center;padding:8px;background:var(--fd-page)}.fd-avatar .fd-image-pick{width:88px;height:88px}.fd-image-preview{max-width:160px;max-height:160px;border-radius:var(--fd-control-radius);border:1px solid var(--fd-border);object-fit:cover;background:var(--fd-page)}.fd-richtext{min-height:96px;line-height:1.5;overflow-wrap:anywhere}.fd-richtext-box{display:grid;gap:0;min-width:0}.fd-richtext-box>.fd-richtext{border-start-start-radius:0;border-start-end-radius:0}.fd-richtext-bar{display:flex;flex-wrap:wrap;align-items:center;gap:2px;padding:4px;min-width:0;border:1px solid var(--fd-border);border-block-end:none;border-start-start-radius:var(--fd-control-radius);border-start-end-radius:var(--fd-control-radius);background:var(--fd-page)}.fd-richtext-style{font:inherit;font-size:12.5px;padding:3px 6px;margin-inline-end:4px;border:1px solid var(--fd-border);border-radius:4px;background:var(--fd-surface);color:var(--fd-text)}.fd-richtext-tool{display:grid;place-items:center;width:28px;height:28px;padding:0;border:none;border-radius:4px;background:none;cursor:pointer;color:var(--fd-text);font:inherit;font-size:14px}.fd-richtext-tool:hover{background:var(--fd-surface)}.fd-richtext-tool[aria-pressed=true]{background:var(--fd-accent-soft);color:var(--fd-accent)}.fd-richtext-tool svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.3;stroke-linecap:round}.fd-richtext-tool svg circle{fill:currentColor;stroke:none}.fd-link-row{display:flex;flex-wrap:wrap;gap:6px;align-items:center;padding:6px;border:1px solid var(--fd-border);border-block-end:none;background:var(--fd-surface)}.fd-link-row>.fd-input{flex:1 1 200px;min-width:0}.fd-richtext[contenteditable=false]{background:transparent;border-color:transparent;padding-inline:0;min-height:0}.fd-richtext p{margin:0 0 6px}.fd-code{font-family:ui-monospace,SF Mono,Menlo,Consolas,monospace;font-size:12.5px;min-height:96px}.fd-sections{display:grid;gap:24px}.fd-section{border:0;margin:0;padding:0;min-width:0;display:grid;gap:14px}.fd-section-title{font-size:15px;font-weight:650;padding:0;margin:0;float:inline-start;width:100%}.fd-section-title+*{clear:both}.fd-form[data-fd-skin=underline] .fd-section-title{text-transform:uppercase;letter-spacing:.05em;font-size:12.5px;color:var(--fd-muted);border-block-end:1px solid var(--fd-border);padding-block-end:6px;width:100%}.fd-section-description{color:var(--fd-muted);margin:0}.fd-section-toggle{font:inherit;color:inherit;background:none;border:0;padding:0;margin:0;cursor:pointer;display:inline-flex;align-items:center;gap:8px;text-align:start}.fd-section-toggle:focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px;border-radius:2px}.fd-section-chevron{width:.5em;height:.5em;border:solid currentColor;border-width:0 2px 2px 0;transform:rotate(45deg);margin-block-start:-.2em;transition:transform .15s ease;flex:none}.fd-section-folded .fd-section-chevron{transform:rotate(-45deg);margin-block-start:0}[dir=rtl] .fd-section-folded .fd-section-chevron{transform:rotate(135deg)}.fd-form[data-fd-skin=outlined] .fd-sections>.fd-section{background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius);padding:20px 24px}.fd-tablist{display:flex;gap:2px;border-block-end:1px solid var(--fd-border);overflow-x:auto}.fd-tab{font:inherit;background:none;border:none;cursor:pointer;padding:8px 14px;color:var(--fd-muted);border-block-end:2px solid transparent;margin-block-end:-1px;white-space:nowrap}.fd-tab[aria-selected=true]{color:var(--fd-accent);border-block-end-color:var(--fd-accent);font-weight:600}.fd-tabpanel{padding-block:16px;display:grid;gap:16px}.fd-button{font:inherit;cursor:pointer;display:inline-flex;align-items:center;gap:6px;justify-content:center;min-height:32px;padding:4px 14px;border-radius:var(--fd-control-radius);border:1px solid var(--fd-border);background:var(--fd-surface);color:var(--fd-text)}.fd-button:hover{border-color:var(--fd-accent);color:var(--fd-accent)}.fd-button-primary{background:var(--fd-accent);border-color:var(--fd-accent);color:var(--fd-accent-text)}.fd-button-primary:hover{color:var(--fd-accent-text);filter:brightness(1.12)}.fd-button-danger{color:var(--fd-error);border-color:var(--fd-error)}.fd-button-danger:hover{background:var(--fd-error);color:#fff}.fd-button-link{border-color:transparent;background:none;color:var(--fd-accent);padding-inline:4px}.fd-form[data-fd-skin=underline] .fd-button{border-radius:3px}.fd-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.fd-actions-end{justify-content:flex-end;margin-block-start:24px}.fd-sheet-page{background:var(--fd-page);padding:0 0 32px;min-width:0}.fd-header{display:flex;flex-wrap:wrap;gap:10px 16px;align-items:center;justify-content:space-between;background:var(--fd-surface);border-block-end:1px solid var(--fd-border);padding:8px 16px}.fd-statusbar{display:flex;list-style:none;margin:0;padding:0;overflow-x:auto}.fd-statusbar li{display:flex}.fd-statusbar button,.fd-statusbar span{font:inherit;font-size:13px;border:none;background:var(--fd-page);color:var(--fd-muted);padding:5px 18px 5px 22px;margin-inline-start:-6px;white-space:nowrap;clip-path:polygon(0 0,calc(100% - 10px) 0,100% 50%,calc(100% - 10px) 100%,0 100%,10px 50%)}.fd-statusbar li:first-child button,.fd-statusbar li:first-child span{margin-inline-start:0;padding-inline-start:14px;clip-path:polygon(0 0,calc(100% - 10px) 0,100% 50%,calc(100% - 10px) 100%,0 100%)}.fd-statusbar button{cursor:pointer}.fd-statusbar [aria-current=step]{background:var(--fd-accent);color:var(--fd-accent-text);font-weight:600}[dir=rtl] .fd-statusbar button,[dir=rtl] .fd-statusbar span{transform:scaleX(-1)}[dir=rtl] .fd-statusbar button>*,[dir=rtl] .fd-statusbar span>*{display:inline-block;transform:scaleX(-1)}.fd-sheet-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:16px;max-width:var(--fd-page-max, 1180px);margin:16px auto 0;padding-inline:16px}.fd-sheet-layout{align-items:start}.fd-sheet-foot{margin:4px -28px -28px;padding:12px 28px;border-block-start:1px solid var(--fd-border);border-end-start-radius:inherit;border-end-end-radius:inherit}.fd-sheet-layout.fd-has-side{grid-template-columns:minmax(0,1fr) minmax(260px,360px)}@container (max-width: 1000px){.fd-sheet-layout.fd-has-side{grid-template-columns:minmax(0,1fr)}}.fd-card{position:relative;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius);padding:24px 28px 28px;display:grid;gap:18px;min-width:0;container-type:inline-size}.fd-ribbon-frame{position:absolute;inset:0;overflow:hidden;border-radius:inherit;pointer-events:none}.fd-ribbon{position:absolute;inset-block-start:18px;inset-inline-end:-42px;transform:rotate(45deg);width:160px;text-align:center;font-size:12px;font-weight:700;padding:4px 0;color:#fff;background:var(--fd-muted);text-transform:uppercase;letter-spacing:.06em;pointer-events:none}[dir=rtl] .fd-ribbon{transform:rotate(-45deg)}.fd-ribbon.fd-tone-danger{background:var(--fd-error)}.fd-ribbon.fd-tone-success{background:var(--fd-success)}.fd-ribbon.fd-tone-warning{background:#d97706}.fd-ribbon.fd-tone-info{background:var(--fd-info)}.fd-alert{padding:10px 14px;border-radius:var(--fd-control-radius);border:1px solid;font-size:13.5px;display:flex;align-items:flex-start;gap:10px}.fd-alert-message{flex:1 1 auto;min-width:0}.fd-alert-close{border:none;background:none;color:inherit;cursor:pointer;font:inherit;font-size:18px;line-height:1;padding:0 4px;border-radius:4px;opacity:.75}.fd-alert-close:hover{opacity:1}.fd-alert-close:focus-visible{outline:2px solid var(--fd-focus);opacity:1}.fd-alert.fd-tone-warning{background:var(--fd-warning-soft);border-color:#f0c47a;color:var(--fd-warning)}.fd-alert.fd-tone-danger{background:var(--fd-error-soft);border-color:#f1a7a7;color:var(--fd-error)}.fd-alert.fd-tone-success{background:var(--fd-success-soft);border-color:#a7d7ab;color:var(--fd-success)}.fd-alert.fd-tone-info,.fd-alert:not([class*=fd-tone-]){background:var(--fd-info-soft);border-color:#a9c8ef;color:var(--fd-info)}.fd-stats{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:0;margin:-24px -28px 0;border-block-end:1px solid var(--fd-border)}.fd-stats:empty{display:none}.fd-card:has(>.fd-ribbon-frame>.fd-ribbon:not([hidden])) .fd-stats{padding-inline-end:104px}.fd-stat{font:inherit;background:none;border:none;border-inline-start:1px solid var(--fd-border);cursor:pointer;padding:8px 18px;display:grid;justify-items:start;line-height:1.2;color:var(--fd-text);min-width:120px}.fd-stat:hover{background:var(--fd-page)}.fd-stat:has(>.fd-icon){grid-template-columns:auto minmax(0,1fr);align-items:center;column-gap:10px}.fd-stat>.fd-icon{width:22px;height:22px;color:var(--fd-muted)}.fd-stat-words{display:grid;justify-items:start}.fd-stat-value{font-weight:700;font-size:15px;color:var(--fd-accent);font-variant-numeric:tabular-nums}.fd-stat-label{font-size:12.5px;color:var(--fd-muted)}.fd-title-row{display:flex;gap:16px;align-items:flex-start;justify-content:space-between}.fd-title{display:grid;gap:4px;flex:1 1 auto;min-width:0}.fd-avatar{flex:none}.fd-avatar>.fd-label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-form[data-fd-skin=underline] .fd-avatar{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-avatar>*{grid-column:1!important}.fd-avatar .fd-image-pick{width:120px;height:120px;border:1px dashed var(--fd-border-strong);border-radius:var(--fd-control-radius);display:grid;place-content:center;justify-items:center;text-align:center;padding:8px;background:var(--fd-page)}.fd-image-pick .fd-button{border:none;background:none;color:var(--fd-accent);padding:0;min-height:0}.fd-image-pick:hover{border-color:var(--fd-accent)}.fd-avatar .fd-image-pick,.fd-image-preview{width:88px;height:88px}.fd-avatar .fd-file-pick .fd-help,.fd-avatar .fd-file-name{display:none}.fd-avatar .fd-file{justify-items:center;gap:2px;padding:0}.fd-avatar .fd-file-chosen{gap:2px 8px;justify-content:center;font-size:12.5px}.fd-title>.fd-field .fd-input{font-size:24px;font-weight:600;min-height:40px}.fd-form[data-fd-skin=underline] .fd-title>.fd-field{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-title>.fd-field>*{grid-column:1}.fd-title>.fd-field>.fd-label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-title-above,.fd-title-below{display:flex;flex-wrap:wrap;align-items:center;gap:6px 24px}.fd-title-above{margin-block-end:4px}.fd-title-below{margin-block-start:6px}.fd-form .fd-title-above>.fd-field,.fd-form .fd-title-below>.fd-field{display:flex;align-items:center;gap:8px;grid-template-columns:none}.fd-form .fd-title-above>.fd-field>*,.fd-form .fd-title-below>.fd-field>*{grid-column:auto!important}.fd-title-above .fd-label:empty,.fd-title-below .fd-label:empty{display:none}.fd-title-above>.fd-field>.fd-label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-title-statusbar{display:flex}.fd-badges{display:flex;flex-wrap:wrap;gap:6px}.fd-badge{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:600;line-height:1;padding:5px 10px;border-radius:999px;border:1px solid var(--fd-border);background:var(--fd-page);color:var(--fd-muted)}.fd-badge .fd-icon{width:13px;height:13px}.fd-badge.fd-tone-info{background:var(--fd-info-soft);border-color:#a9c8ef;color:var(--fd-info)}.fd-badge.fd-tone-success{background:var(--fd-success-soft);border-color:#a7d7ab;color:var(--fd-success)}.fd-badge.fd-tone-warning{background:var(--fd-warning-soft);border-color:#f0c47a;color:var(--fd-warning)}.fd-badge.fd-tone-danger{background:var(--fd-error-soft);border-color:#f1a7a7;color:var(--fd-error)}.fd-side{display:grid;gap:12px;align-content:start;min-width:0}.fd-wizard{display:grid;gap:20px}.fd-progress{display:grid;gap:8px}.fd-progress-text{color:var(--fd-muted);font-size:13px}.fd-value-text{display:block;padding-block:6px;font-variant-numeric:tabular-nums}.fd-date-pick{position:relative;display:flex;align-items:center;gap:6px;min-width:0}.fd-date-pick>.fd-input{flex:1 1 auto;min-width:0}.fd-calendar-button{flex:0 0 auto;display:grid;place-items:center;width:32px;height:32px;padding:0;cursor:pointer;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);background:var(--fd-surface);color:var(--fd-muted)}.fd-calendar-button:hover,.fd-calendar-button[aria-expanded=true]{color:var(--fd-text);background:var(--fd-page)}.fd-calendar-button svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.4;stroke-linecap:round}.fd-calendar{position:absolute;inset-block-start:calc(100% + 4px);inset-inline-end:0;z-index:30;padding:8px;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:max(var(--fd-control-radius),6px);box-shadow:0 8px 24px #0f141924}.fd-calendar-head{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:2px 4px 6px}.fd-calendar-head button{border:none;background:none;cursor:pointer;font-size:18px;line-height:1;padding:4px 8px;border-radius:4px;color:var(--fd-text)}.fd-calendar-head button:hover{background:var(--fd-page)}.fd-calendar-title{font-weight:600}.fd-calendar-grid{border-collapse:collapse;font-variant-numeric:tabular-nums}.fd-calendar-grid th{font-size:11.5px;font-weight:600;color:var(--fd-muted);padding:4px 0;width:34px;text-align:center}.fd-calendar-grid .fd-week{color:var(--fd-accent);font-weight:600;border-inline-end:1px solid var(--fd-border)}.fd-calendar-grid td{padding:1px}.fd-calendar-grid td button{width:32px;height:30px;border:none;border-radius:4px;background:none;cursor:pointer;color:var(--fd-text);font:inherit;font-size:13px}.fd-calendar-grid td button:hover{background:var(--fd-accent-soft)}.fd-calendar-grid td button.fd-outside{color:var(--fd-muted);opacity:.6}.fd-calendar-grid td button[aria-current=date]{box-shadow:inset 0 0 0 1px var(--fd-accent)}.fd-calendar-grid td button[aria-selected=true]{background:var(--fd-accent);color:var(--fd-accent-text);font-weight:600}.fd-calendar-grid td button:focus-visible{outline:2px solid var(--fd-focus);outline-offset:1px}.fd-properties{display:grid;gap:8px;min-width:0}.fd-property{display:grid;grid-template-columns:minmax(120px,30%) minmax(0,1fr);align-items:center;gap:12px;min-width:0}.fd-property>label{color:var(--fd-muted);font-size:13px}.fd-property[data-type=boolean]>:last-child{justify-self:start}@container (max-width: 520px){.fd-property{grid-template-columns:minmax(0,1fr);gap:4px}}.fd-progressbar{position:relative;height:22px;min-width:120px;border-radius:999px;overflow:hidden;background:var(--fd-page);border:1px solid var(--fd-border);font-variant-numeric:tabular-nums}.fd-progressbar-fill{height:100%;background:var(--fd-success);transition:width .2s ease}.fd-progressbar[data-tone=warning] .fd-progressbar-fill{background:#d97706}.fd-progressbar[data-tone=danger] .fd-progressbar-fill{background:var(--fd-error)}.fd-progressbar[data-tone=info] .fd-progressbar-fill{background:var(--fd-info)}.fd-progressbar-text{position:absolute;inset:0;display:grid;place-items:center;font-size:12px;font-weight:600;color:var(--fd-text)}.fd-progressbar-edit{display:flex;align-items:center;gap:12px;min-width:0}.fd-progressbar-edit>.fd-progressbar{flex:1 1 auto}.fd-progressbar-edit>.fd-input{flex:0 0 96px}.fd-progress-bar{height:4px;background:var(--fd-border);border-radius:999px;overflow:hidden}.fd-progress-bar>span{display:block;height:100%;background:var(--fd-accent);transition:width .25s ease}.fd-step{display:grid;gap:18px}.fd-step-title{font-size:18px;font-weight:650;margin:0}.fd-wizard-nav{display:flex;gap:8px;justify-content:space-between}.fd-steps-list{display:flex;flex-wrap:wrap;gap:8px;list-style:none;margin:0;padding:0;counter-reset:fd-step}.fd-steps-list>li{counter-increment:fd-step}.fd-step-link{font:inherit;font-size:13.5px;display:inline-flex;align-items:center;gap:6px;cursor:pointer;border:1px solid var(--fd-border);background:var(--fd-surface);color:var(--fd-muted);border-radius:999px;padding:4px 12px 4px 6px}.fd-step-link:before{content:counter(fd-step);display:inline-grid;place-items:center;width:20px;height:20px;border-radius:50%;background:var(--fd-page);color:var(--fd-muted);font-size:12px;font-weight:600;font-variant-numeric:tabular-nums}.fd-step-link:hover{border-color:var(--fd-accent);color:var(--fd-text)}.fd-step-link:focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px}.fd-step-link.fd-step-done{color:var(--fd-text)}.fd-step-link.fd-step-done:before{content:\"\u2713\";background:var(--fd-accent-soft);color:var(--fd-accent)}.fd-step-link.fd-step-skipped{border-style:dashed;color:var(--fd-muted)}.fd-step-link.fd-step-skipped:before{content:\"\u2013\";background:var(--fd-page);color:var(--fd-muted)}.fd-step-link[aria-current=step]{border-color:var(--fd-accent);color:var(--fd-accent);font-weight:600}.fd-step-link[aria-current=step]:before{content:counter(fd-step);background:var(--fd-accent);color:var(--fd-accent-text)}.fd-wizard-nav .fd-spacer{flex:1}.fd-text-heading{font-size:16px;font-weight:650;margin:0}.fd-text-paragraph{margin:0}.fd-text-note{margin:0;color:var(--fd-muted);font-size:13px}.fd-status{min-height:1.4em;color:var(--fd-muted);font-size:13px}.fd-status-box{display:inline-flex;align-items:center;gap:6px;min-width:0}.fd-status-box .fd-retry{font-size:13px}.fd-announce{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-banner{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;padding:10px 14px;margin-block-end:16px;border:1px solid #f0c47a;border-radius:var(--fd-control-radius);background:var(--fd-warning-soft);color:var(--fd-warning);font-size:13.5px}.fd-banner-text{flex:1 1 16em;min-width:0}.fd-content>.fd-banner:has(+.fd-draft+.fd-sheet-page),.fd-content>.fd-banner:has(+.fd-sheet-page){margin:12px 16px 0}.fd-status-box.fd-toast{position:fixed;inset-block-end:max(20px,env(safe-area-inset-bottom,0px));inset-inline-end:20px;z-index:900;padding:10px 16px;border-radius:8px;background:var(--fd-text);box-shadow:0 8px 24px #0f141940}.fd-toast .fd-status,.fd-toast .fd-status.fd-status-saved,.fd-toast .fd-status.fd-status-error{color:var(--fd-surface);font-size:13.5px;min-height:0}.fd-toast .fd-retry{color:var(--fd-surface);text-decoration:underline}.fd-toast:has(.fd-status-error){background:var(--fd-error)}.fd-status-box.fd-status-bar{display:flex;justify-content:center;min-height:32px;padding:6px 16px;background:var(--fd-surface);border-block-end:1px solid var(--fd-border)}.fd-status-bar .fd-status-error,.fd-status.fd-status-error{color:var(--fd-error)}.fd-status.fd-status-saved{color:var(--fd-success)}.fd-draft{display:flex;flex-wrap:wrap;gap:8px 12px;align-items:center;padding:10px 14px;margin-block-end:16px;background:var(--fd-info-soft);border:1px solid #a9c8ef;border-radius:var(--fd-control-radius)}.fd-done{padding:40px 0;text-align:center;display:grid;gap:12px;justify-items:center}.fd-done-title{font-size:20px;font-weight:650;margin:0}.fd-dialog-backdrop{position:fixed;inset:0;background:#0f141973;display:grid;place-items:center;z-index:1000;padding:16px}.fd-dialog{background:var(--fd-surface);color:var(--fd-text);border-radius:max(var(--fd-radius),6px);max-width:420px;width:100%;padding:20px 22px;display:grid;gap:16px;box-shadow:0 10px 30px #0003;font-family:var(--fd-font)}.fd-dialog p{margin:0}.fd-form-dialog{display:flex;flex-direction:column;width:100%;max-height:min(90vh,100%);min-height:0;background:var(--fd-page);color:var(--fd-text);border-radius:max(var(--fd-radius),8px);box-shadow:0 24px 64px #0f14194d;overflow:hidden}.fd-form-dialog:focus{outline:none}.fd-form-dialog.fd-size-small{max-width:440px}.fd-form-dialog.fd-size-medium{max-width:760px}.fd-form-dialog.fd-size-large{max-width:1080px}.fd-form-dialog-backdrop:has(>.fd-size-full){padding:0}.fd-form-dialog.fd-size-full{max-width:none;max-height:none;height:100%;border-radius:0}.fd-form-dialog-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;border-block-end:1px solid var(--fd-border);background:var(--fd-surface)}.fd-form-dialog-title{margin:0;font-size:16px;font-weight:600}.fd-dialog-close{border:none;background:none;cursor:pointer;font-size:22px;line-height:1;padding:2px 8px;border-radius:4px;color:var(--fd-muted)}.fd-dialog-close:hover{background:var(--fd-page);color:var(--fd-text)}.fd-form-dialog-body{flex:1 1 auto;min-height:0;overflow:auto;container-type:inline-size}.fd-form-dialog-body .fd-sheet-layout{margin-block-start:12px}.fd-form-dialog-body .fd-page-title{display:none}.fd-form-dialog-body .fd-page-head:not(:has(.fd-page-description)){display:none}.fd-form-dialog-body .fd-sheet-layout.fd-has-side{grid-template-columns:minmax(0,1fr)}.fd-form-dialog-body .fd-side{display:none}.fd-search-body{display:grid;gap:12px;align-content:start}.fd-search-list{list-style:none;margin:0;padding:0;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);overflow:auto;max-height:min(60vh,520px)}.fd-search-list .fd-option{padding:8px 12px}.fd-search-list .fd-option+.fd-option{border-block-start:1px solid var(--fd-border)}.fd-search-list .fd-empty{padding:10px 12px;color:var(--fd-muted)}.fd-form-dialog-body:not(:has(.fd-sheet-layout)){background:var(--fd-surface);padding:16px 20px 20px}.fd-form-dialog-foot{padding:12px 16px;border-block-start:1px solid var(--fd-border);background:var(--fd-surface);margin:0}@media(prefers-reduced-motion:reduce){.fd-form *,.fd-form *:before,.fd-form *:after{transition:none!important}}`;\n\nconst STYLE_ID = 'fieldia-styles';\n\n/** Add Fieldia's stylesheet to a document, once. */\nexport function installStyles(document: Document): void {\n if (document.getElementById(STYLE_ID)) return;\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = FIELDIA_CSS;\n (document.head ?? document.documentElement).append(style);\n}\n", "import type { JsonValue } from '@fieldia/core';\n\n/**\n * Where a person's choices about how a page looks are kept between visits:\n * a table's column widths, their order, which columns show. Never data, and\n * never anything a page needs to work: a store that forgets is fine.\n */\nexport interface PreferenceStore {\n get(key: string): JsonValue | null;\n set(key: string, value: JsonValue): void;\n}\n\n/** Preferences in the browser's local storage, under `fieldia:`. A browser that refuses storage just forgets. */\nexport function browserPreferences(storage?: Storage): PreferenceStore {\n const area = () => {\n try {\n return storage ?? globalThis.localStorage ?? null;\n } catch {\n return null; // reading localStorage itself throws where site data is blocked\n }\n };\n return {\n get(key) {\n try {\n const text = area()?.getItem(`fieldia:${key}`);\n return text == null ? null : (JSON.parse(text) as JsonValue);\n } catch {\n return null;\n }\n },\n set(key, value) {\n try {\n area()?.setItem(`fieldia:${key}`, JSON.stringify(value));\n } catch {\n // Full, private or blocked: the choice lasts until the page closes.\n }\n },\n };\n}\n\n/** Preferences that last as long as the page: for tests, and apps that keep nothing. */\nexport function memoryPreferences(): PreferenceStore {\n const values = new Map<string, JsonValue>();\n return {\n get: (key) => (values.has(key) ? structuredCloneSafe(values.get(key) as JsonValue) : null),\n set: (key, value) => void values.set(key, structuredCloneSafe(value)),\n };\n}\n\nconst structuredCloneSafe = (value: JsonValue): JsonValue => JSON.parse(JSON.stringify(value)) as JsonValue;\n", "/**\n * Icons by name, for sections, tabs, buttons, stat buttons, badges and steps.\n * Each is the inside of a 24\u00D724 SVG drawn with lines in the text colour, so it\n * takes the colour and size of the words beside it. An app adds its own, or\n * replaces one of these, with the viewer's `icons` option, in the same form.\n */\nexport type IconSet = Readonly<Record<string, string>>;\n\nconst SVG = 'http://www.w3.org/2000/svg';\n\nexport const ICONS: IconSet = {\n user: '<circle cx=\"12\" cy=\"8\" r=\"4\"/><path d=\"M4 21c0-4 3.6-6 8-6s8 2 8 6\"/>',\n users: '<circle cx=\"9\" cy=\"8\" r=\"3.5\"/><path d=\"M2 20c0-3.5 3-5.5 7-5.5s7 2 7 5.5\"/><circle cx=\"17\" cy=\"9\" r=\"2.5\"/><path d=\"M16.5 14.5c3 0 5.5 1.6 5.5 4.5\"/>',\n building: '<rect x=\"4\" y=\"3\" width=\"16\" height=\"18\" rx=\"1\"/><path d=\"M9 21v-4h6v4M8 7h2M14 7h2M8 11h2M14 11h2\"/>',\n home: '<path d=\"M3 11l9-7 9 7\"/><path d=\"M5 10v10h14V10\"/><path d=\"M10 20v-6h4v6\"/>',\n phone: '<rect x=\"7\" y=\"2\" width=\"10\" height=\"20\" rx=\"2\"/><path d=\"M11 18h2\"/>',\n mail: '<rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\"/><path d=\"M3 7l9 6 9-6\"/>',\n pin: '<path d=\"M12 21s-7-6.5-7-12a7 7 0 0 1 14 0c0 5.5-7 12-7 12z\"/><circle cx=\"12\" cy=\"9\" r=\"2.5\"/>',\n globe: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M3 12h18M12 3c3 3.2 3 14.8 0 18M12 3c-3 3.2-3 14.8 0 18\"/>',\n calendar: '<rect x=\"3\" y=\"5\" width=\"18\" height=\"16\" rx=\"2\"/><path d=\"M3 10h18M8 3v4M16 3v4\"/>',\n clock: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M12 7v5l3 3\"/>',\n money: '<rect x=\"2\" y=\"6\" width=\"20\" height=\"12\" rx=\"2\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M6 9.5v0M18 14.5v0\"/>',\n cart: '<path d=\"M3 4h2l2.5 11h11L21 7H6.4\"/><circle cx=\"9\" cy=\"19.5\" r=\"1.5\"/><circle cx=\"17\" cy=\"19.5\" r=\"1.5\"/>',\n box: '<path d=\"M12 3l8 4.5v9L12 21l-8-4.5v-9z\"/><path d=\"M4 7.5l8 4.5 8-4.5M12 12v9\"/>',\n truck: '<path d=\"M2 6h12v10H2zM14 9h4l3 3.5V16h-7\"/><circle cx=\"6.5\" cy=\"17.5\" r=\"1.8\"/><circle cx=\"17\" cy=\"17.5\" r=\"1.8\"/>',\n receipt: '<path d=\"M6 3h12v18l-3-2-3 2-3-2-3 2z\"/><path d=\"M9 8h6M9 12h6\"/>',\n file: '<path d=\"M6 3h8l4 4v14H6z\"/><path d=\"M14 3v4h4M9 12h6M9 16h6\"/>',\n edit: '<path d=\"M4 20h4L19 9l-4-4L4 16z\"/><path d=\"M13.5 6.5l4 4\"/>',\n tag: '<path d=\"M3 12V4h8l10 10-8 8z\"/><circle cx=\"7.5\" cy=\"8\" r=\"1.5\"/>',\n star: '<path d=\"M12 3l2.8 6 6.2.6-4.7 4.2 1.4 6.2L12 16.8 6.3 20l1.4-6.2L3 9.6 9.2 9z\"/>',\n lock: '<rect x=\"5\" y=\"11\" width=\"14\" height=\"10\" rx=\"2\"/><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"/>',\n check: '<path d=\"M5 12.5l4.5 4.5L19 7.5\"/>',\n info: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M12 11v6M12 7.5v0\"/>',\n warning: '<path d=\"M12 3l10 18H2z\"/><path d=\"M12 10v5M12 18v0\"/>',\n settings: '<path d=\"M4 6h9M17 6h3M4 12h3M11 12h9M4 18h11M19 18h1\"/><circle cx=\"15\" cy=\"6\" r=\"2\"/><circle cx=\"9\" cy=\"12\" r=\"2\"/><circle cx=\"17\" cy=\"18\" r=\"2\"/>',\n chart: '<path d=\"M3 20h18M6 20v-8M11 20V5M16 20v-6\"/>',\n link: '<path d=\"M10 14a4 4 0 0 0 5.6 0l3-3a4 4 0 0 0-5.6-5.6l-1 1\"/><path d=\"M14 10a4 4 0 0 0-5.6 0l-3 3a4 4 0 0 0 5.6 5.6l1-1\"/>',\n list: '<path d=\"M8 6h12M8 12h12M8 18h12M4 6v0M4 12v0M4 18v0\"/>',\n chat: '<path d=\"M4 5h16v11H9l-5 4z\"/>',\n search: '<circle cx=\"11\" cy=\"11\" r=\"6.5\"/><path d=\"M16 16l5 5\"/>',\n filter: '<path d=\"M3 5h18l-7 8.5V20l-4-2v-4.5z\"/>',\n layers: '<path d=\"M12 3l9 5-9 5-9-5z\"/><path d=\"M3 13l9 5 9-5\"/>',\n};\n\n/** An icon by name, the app's own first and then Fieldia's; null for a name neither has. */\nexport function drawIcon(doc: Document, name: string | undefined, own?: IconSet): SVGSVGElement | null {\n const inside = name ? own?.[name] ?? ICONS[name] : undefined;\n if (inside === undefined) return null;\n const svg = doc.createElementNS(SVG, 'svg');\n for (const [key, value] of Object.entries({\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n 'stroke-width': '1.8',\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round',\n 'aria-hidden': 'true',\n focusable: 'false',\n class: 'fd-icon',\n 'data-icon': name as string,\n })) {\n svg.setAttribute(key, value);\n }\n svg.innerHTML = inside;\n return svg;\n}\n", "import type { Locale, RecordId, RelatedRecord, Values } from '@fieldia/core';\nimport { WIDGET_LABELS } from '@fieldia/widgets';\nimport { mountViewer, VIEWER_LABELS, type Skin, type ViewerHandle, type ViewerOptions } from './viewer';\n\n/**\n * A page in a dialog: a new related record, a line to edit, a quick task. The\n * dialog saves (Save & Close) or closes without saving (Discard, \u00D7, Escape);\n * the page's own Save and Discard stay hidden. The focus moves into the dialog,\n * Tab stays inside it, and the focus goes back where it was when it closes.\n */\n\nexport interface FormDialogOptions extends ViewerOptions {\n title: string;\n size?: 'small' | 'medium' | 'large' | 'full';\n /**\n * \"save\" (the default) saves the record through the data source. \"values\"\n * only checks the form and hands its values back, for something saved with\n * a bigger record, such as a line.\n */\n mode?: 'save' | 'values';\n /**\n * Recalculates the values as they change, for a dialog with no data source of\n * its own: a line's subtotal following its quantity. What comes back is shown.\n */\n recompute?: (values: Values) => Promise<Values>;\n /** Where the dialog goes: the document's body by default. */\n container?: HTMLElement;\n}\n\nexport interface FormDialogResult {\n /** True when Save & Close was pressed and the form accepted. */\n saved: boolean;\n recordId: RecordId | null;\n values: Values;\n}\n\nlet dialogs = 0;\n\nconst FOCUSABLE = 'button, [href], input, select, textarea, [contenteditable=\"true\"], [tabindex]:not([tabindex=\"-1\"])';\n\nexport function openFormDialog(options: FormDialogOptions): Promise<FormDialogResult> {\n const doc = options.container?.ownerDocument ?? document;\n const container = options.container ?? doc.body;\n const opener = doc.activeElement instanceof doc.defaultView!.HTMLElement ? (doc.activeElement as HTMLElement) : null;\n const labels = { ...VIEWER_LABELS[options.locale ?? 'en'], ...options.labels };\n const id = `fd-dialog-${++dialogs}`;\n const make = <K extends keyof HTMLElementTagNameMap>(tag: K, attrs: Record<string, string> = {}, text?: string) => {\n const element = doc.createElement(tag);\n for (const [name, value] of Object.entries(attrs)) element.setAttribute(name, value);\n if (text !== undefined) element.textContent = text;\n return element;\n };\n\n const title = make('h2', { id: `${id}-title`, class: 'fd-form-dialog-title' }, options.title);\n const closeButton = make('button', { type: 'button', class: 'fd-dialog-close', 'aria-label': labels.close }, '\u00D7');\n const body = make('div', { class: 'fd-form-dialog-body' });\n const discard = make('button', { type: 'button', class: 'fd-button' }, labels.discard);\n const saveClose = make('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.saveClose);\n const box = make('div', {\n // Its own tokens and skin: the dialog sits outside the page that opened it.\n class: `fd-theme fd-form-dialog fd-size-${options.size ?? 'medium'}`,\n 'data-fd-skin': options.skin ?? 'underline',\n role: 'dialog',\n 'aria-modal': 'true',\n 'aria-labelledby': title.id,\n tabindex: '-1',\n });\n if (options.dir) box.setAttribute('dir', options.dir);\n box.append(make('div', { class: 'fd-form-dialog-head' }), body, make('div', { class: 'fd-actions fd-actions-end fd-form-dialog-foot' }));\n box.firstElementChild?.append(title, closeButton);\n box.lastElementChild?.append(discard, saveClose);\n const backdrop = make('div', { class: 'fd-dialog-backdrop fd-form-dialog-backdrop' });\n backdrop.append(box);\n container.append(backdrop);\n\n const handle = mountViewer(body, { ...options, showActions: false });\n let done = false;\n if (options.recompute) recalculate(handle.form, options.page.fields, options.recompute, () => done);\n\n const focusables = () =>\n [...box.querySelectorAll<HTMLElement>(FOCUSABLE)].filter(\n (element) => !element.closest('[hidden], [inert]') && !(element as HTMLButtonElement).disabled\n );\n // Into the dialog: its first field, once the record is in, or the dialog itself meanwhile.\n const firstField = () => body.querySelector<HTMLElement>('input:not([type=\"hidden\"]), select, textarea, [contenteditable=\"true\"]');\n (firstField() ?? box).focus();\n void handle.form.settled().then(() => {\n if (doc.activeElement === box || !box.contains(doc.activeElement)) firstField()?.focus();\n });\n\n return new Promise((resolve) => {\n const close = (saved: boolean) => {\n if (done) return;\n done = true;\n const state = handle.form.getState();\n // The form never changes its values in place, so these are safe to hand back.\n const result: FormDialogResult = { saved, recordId: state.recordId ?? null, values: state.values as Values };\n handle.destroy();\n backdrop.remove();\n opener?.focus();\n resolve(result);\n };\n saveClose.addEventListener('click', async () => {\n saveClose.disabled = true;\n const accepted = options.mode === 'values' ? handle.check() : await handle.save();\n saveClose.disabled = false;\n if (accepted) close(true);\n });\n discard.addEventListener('click', () => close(false));\n closeButton.addEventListener('click', () => close(false));\n box.addEventListener('keydown', (event) => {\n // Ctrl+Enter is Save & Close from wherever the cursor is, even after a field used the Enter\n // (a tag box adding its tag), taking what is still being typed. The grid keeps its own keys.\n if (event.key === 'Enter' && (event.ctrlKey || event.metaKey) && !event.isComposing) {\n if ((event.target as Element).closest('.ag-root-wrapper')) return;\n event.preventDefault();\n doc.activeElement?.dispatchEvent(new Event('change', { bubbles: true }));\n saveClose.click();\n return;\n }\n // A key a field used itself (Escape closing a list) is not the dialog's.\n if (event.defaultPrevented) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n close(false);\n } else if (event.key === 'Tab') {\n const all = focusables();\n if (!all.length) return;\n const first = all[0];\n const last = all[all.length - 1];\n if (event.shiftKey && doc.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && doc.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n }\n });\n });\n}\n\n/** Each change of the values asks for them recalculated, and shows the answer unless they changed again meanwhile. */\nfunction recalculate(form: ViewerHandle['form'], fields: Record<string, unknown>, recompute: (values: Values) => Promise<Values>, closed: () => boolean) {\n let seen = JSON.stringify(form.getState().values);\n let writing = false;\n form.subscribe(() => {\n const values = form.getState().values as Values;\n const now = JSON.stringify(values);\n if (writing || now === seen) return;\n seen = now;\n recompute(values).then(\n (next) => {\n if (closed() || JSON.stringify(form.getState().values) !== now) return; // a newer answer is on its way\n writing = true;\n for (const [name, value] of Object.entries(next)) {\n if (name in fields && JSON.stringify(values[name] ?? null) !== JSON.stringify(value ?? null)) form.setValue(name, value);\n }\n writing = false;\n seen = JSON.stringify(form.getState().values);\n },\n () => undefined\n );\n });\n}\n\nexport interface SearchDialogOptions {\n title: string;\n /** Finds records for what is typed: the field's own search, filter and all. */\n search(query: string, limit: number): Promise<RelatedRecord[]>;\n locale?: Locale;\n skin?: Skin;\n dir?: 'ltr' | 'rtl';\n /** Where the dialog goes: the document's body by default. */\n container?: HTMLElement;\n}\n\n/**\n * A searchable list in a dialog, for \"Search more\u2026\": every record the field may\n * point to, narrowed as the person types, picked with a click or the keyboard.\n * Resolves with the record picked, or null when closed.\n */\nexport function openSearchDialog(options: SearchDialogOptions): Promise<RelatedRecord | null> {\n const doc = options.container?.ownerDocument ?? document;\n const container = options.container ?? doc.body;\n const opener = doc.activeElement instanceof doc.defaultView!.HTMLElement ? (doc.activeElement as HTMLElement) : null;\n const labels = VIEWER_LABELS[options.locale ?? 'en'];\n const words = WIDGET_LABELS[options.locale ?? 'en'];\n const id = `fd-dialog-${++dialogs}`;\n const make = <K extends keyof HTMLElementTagNameMap>(tag: K, attrs: Record<string, string> = {}, text?: string) => {\n const element = doc.createElement(tag);\n for (const [name, value] of Object.entries(attrs)) element.setAttribute(name, value);\n if (text !== undefined) element.textContent = text;\n return element;\n };\n const title = make('h2', { id: `${id}-title`, class: 'fd-form-dialog-title' }, options.title);\n const closeButton = make('button', { type: 'button', class: 'fd-dialog-close', 'aria-label': labels.close }, '\u00D7');\n const query = make('input', { type: 'search', class: 'fd-input', 'aria-label': words.search, placeholder: words.search, 'aria-controls': `${id}-list`, autocomplete: 'off' });\n const list = make('ul', { id: `${id}-list`, class: 'fd-search-list', role: 'listbox', 'aria-labelledby': title.id });\n const cancel = make('button', { type: 'button', class: 'fd-button' }, labels.cancel);\n const box = make('div', {\n class: `fd-theme fd-form-dialog fd-search-dialog fd-size-small`,\n 'data-fd-skin': options.skin ?? 'underline',\n role: 'dialog',\n 'aria-modal': 'true',\n 'aria-labelledby': title.id,\n });\n if (options.dir) box.setAttribute('dir', options.dir);\n const head = make('div', { class: 'fd-form-dialog-head' });\n head.append(title, closeButton);\n const body = make('div', { class: 'fd-form-dialog-body fd-search-body' });\n body.append(query, list);\n const foot = make('div', { class: 'fd-actions fd-actions-end fd-form-dialog-foot' });\n foot.append(cancel);\n box.append(head, body, foot);\n const backdrop = make('div', { class: 'fd-dialog-backdrop fd-form-dialog-backdrop' });\n backdrop.append(box);\n container.append(backdrop);\n query.focus();\n\n return new Promise((resolve) => {\n let found: RelatedRecord[] = [];\n let active = -1;\n let asked = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const close = (picked: RelatedRecord | null) => {\n clearTimeout(timer);\n asked++;\n backdrop.remove();\n opener?.focus();\n resolve(picked);\n };\n const draw = () => {\n list.replaceChildren(\n ...found.map((record, i) => {\n const option = make('li', { id: `${id}-option-${i}`, role: 'option', class: `fd-option${i === active ? ' fd-active' : ''}`, 'aria-selected': String(i === active) }, record.label);\n option.addEventListener('click', () => close(record));\n return option;\n })\n );\n if (!found.length) list.append(make('li', { class: 'fd-empty' }, words.noResults));\n if (active >= 0) query.setAttribute('aria-activedescendant', `${id}-option-${active}`);\n else query.removeAttribute('aria-activedescendant');\n };\n const look = () => {\n clearTimeout(timer);\n const mine = ++asked;\n timer = setTimeout(async () => {\n const records = await options.search(query.value, 80).catch(() => [] as RelatedRecord[]);\n if (mine !== asked) return; // a newer search, or the dialog closed\n found = records;\n active = -1;\n draw();\n }, 180);\n };\n query.addEventListener('input', look);\n query.addEventListener('keydown', (event) => {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n if (!found.length) return;\n active = (active + (event.key === 'ArrowDown' ? 1 : -1) + found.length) % found.length;\n draw();\n list.children[active]?.scrollIntoView?.({ block: 'nearest' });\n } else if (event.key === 'Enter' && active >= 0) {\n event.preventDefault();\n close(found[active]);\n }\n });\n cancel.addEventListener('click', () => close(null));\n closeButton.addEventListener('click', () => close(null));\n box.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n close(null);\n }\n });\n look();\n });\n}\n", "import type { CreateRequest, DataSource, Field, Page, SearchRequest } from '@fieldia/core';\nimport type { WidgetDialogs } from '@fieldia/widgets';\nimport { openFormDialog, openSearchDialog } from './dialog';\nimport type { ViewerOptions } from './viewer';\n\n/** The field a page's records are named by: its title, or \"name\", or its first line of text. */\nexport function nameFieldOf(page: Page): string | null {\n if (page.layout.type === 'sheet' && page.layout.title?.field) return page.layout.title.field;\n if (page.fields['name']) return 'name';\n return Object.entries(page.fields).find(([, def]) => def.type === 'char')?.[0] ?? null;\n}\n\n\n\n/** A form made of fields, for values edited in a dialog (a line, for one). */\nfunction valuesPage(fields: Record<string, Field>, title: string, readonly: boolean): Page {\n const shown = Object.fromEntries(Object.entries(fields).map(([name, def]) => [name, readonly ? { ...def, readonly: true } : def])) as Page['fields'];\n return {\n fieldia: '0.1',\n id: 'values',\n title,\n data: { kind: 'record', model: 'values' },\n fields: shown,\n layout: {\n type: 'sections',\n id: 'values',\n children: [{ type: 'section', id: 'values-section', columns: 2, children: Object.keys(shown).map((name) => ({ type: 'field' as const, id: `values-${name}`, field: name })) }],\n },\n };\n}\n\n/** Only finding and making linked records: values edited in a dialog are no record of the source's to load, save or recalculate. */\nfunction lookupsOf(source: DataSource | undefined): DataSource | undefined {\n if (!source) return undefined;\n return {\n ...(source.search ? { search: (request: SearchRequest) => source.search!(request) } : {}),\n ...(source.create ? { create: (request: CreateRequest) => source.create!(request) } : {}),\n };\n}\n\n/** The dialogs a page's widgets may open, made from the viewer's own options. */\nexport function pageDialogs(options: ViewerOptions): WidgetDialogs {\n const pageFor = (model: string) =>\n (typeof options.relatedPages === 'function' ? options.relatedPages(model) : options.relatedPages?.[model]) ?? null;\n // A dialog's page looks and reads like the page that opened it, and can open dialogs of its own.\n const shared = {\n locale: options.locale,\n skin: options.skin,\n dir: options.dir,\n widgets: options.widgets,\n preferences: options.preferences,\n relatedPages: options.relatedPages,\n translate: options.translate,\n };\n return {\n canOpen: (model) => pageFor(model) !== null,\n async openRecord(model, request) {\n const related = pageFor(model);\n if (!related) return null;\n const nameField = nameFieldOf(related);\n const result = await openFormDialog({\n ...shared,\n page: related,\n dataSource: options.dataSource,\n recordId: request.recordId ?? null,\n values: request.name && nameField ? { [nameField]: request.name } : undefined,\n title: request.title,\n size: 'large',\n });\n if (!result.saved || result.recordId === null) return null;\n const name = nameField ? result.values[nameField] : null;\n return { id: result.recordId, label: typeof name === 'string' && name ? name : request.name ?? request.title };\n },\n searchMore: (request) => openSearchDialog({ title: request.title, search: request.search, locale: options.locale, skin: options.skin, dir: options.dir }),\n async editValues(request) {\n const result = await openFormDialog({\n ...shared,\n page: valuesPage(request.fields, request.title, request.readonly === true),\n dataSource: lookupsOf(options.dataSource),\n values: request.values,\n title: request.title,\n mode: 'values',\n ...(request.recompute ? { recompute: request.recompute } : {}),\n });\n return result.saved ? result.values : null;\n },\n };\n}\n", "import type { Facet, JsonValue, ListNode, Page } from '@fieldia/core';\nimport type { PreferenceStore } from '@fieldia/widgets';\nimport type { El } from './dom';\nimport type { ViewerLabels } from './labels';\n\n/** A search a person kept, by its name; the one used by default opens the list. */\nexport interface Favourite {\n name: string;\n facets: Facet[];\n isDefault?: boolean;\n}\n\nconst key = (page: Page) => `favourites:${page.id}`;\n\nexport function readFavourites(preferences: PreferenceStore, page: Page): Favourite[] {\n const kept = preferences.get(key(page));\n return Array.isArray(kept) ? (kept as unknown as Favourite[]) : [];\n}\n\n/** What a list starts with: the favourite used by default, or else the list's own default filters. */\nexport function startingFacets(node: ListNode, preferences: PreferenceStore, page: Page): Facet[] {\n const chosen = readFavourites(preferences, page).find((favourite) => favourite.isDefault);\n if (chosen) return chosen.facets;\n if (!node.defaultFilters?.length) return [];\n return [{ kind: 'filters', ids: [...node.defaultFilters], labels: node.defaultFilters.map((id) => node.filters?.find((f) => f.id === id)?.label ?? id) }];\n}\n\n/**\n * The Favourites of the search menu: searches kept by name, each one put back\n * with a click or deleted, and the search on screen kept as a new one, used by\n * default if the person says so. Kept where the page keeps its preferences.\n */\nexport function favouritesPart(context: { page: Page; el: El; labels: ViewerLabels; fill: (template: string, values: Record<string, string>) => string; preferences: PreferenceStore; current: () => Facet[]; apply: (facets: Facet[]) => void }) {\n const { page, el, labels, fill, preferences } = context;\n const list = el('ul', { class: 'fd-favourite-list' });\n const none = el('p', { class: 'fd-favourites-none' }, labels.noFavourites);\n const name = el('input', { class: 'fd-input', 'aria-label': labels.searchName, placeholder: labels.searchName });\n const byDefault = el('input', { type: 'checkbox' });\n const save = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.save);\n const form = el('div', { class: 'fd-favourite-form', hidden: '' }, name, el('label', { class: 'fd-favourite-default' }, byDefault, labels.useByDefault), save);\n const open = el('button', { type: 'button', class: 'fd-search-option fd-search-add', 'aria-expanded': 'false' }, labels.saveSearch);\n\n const write = (favourites: Favourite[]) => preferences.set(key(page), favourites as unknown as JsonValue);\n\n function draw() {\n const favourites = readFavourites(preferences, page);\n none.hidden = favourites.length > 0;\n list.replaceChildren(\n ...favourites.map((favourite) => {\n const use = el('button', { type: 'button', class: 'fd-search-option', 'data-default': favourite.isDefault ? 'true' : undefined }, favourite.name);\n use.addEventListener('click', () => context.apply(favourite.facets));\n const remove = el('button', { type: 'button', class: 'fd-favourite-remove', 'aria-label': fill(labels.deleteFavourite, { name: favourite.name }) }, '\u00D7');\n remove.addEventListener('click', () => {\n write(readFavourites(preferences, page).filter((f) => f.name !== favourite.name));\n draw();\n });\n return el('li', { class: 'fd-favourite' }, use, remove);\n })\n );\n }\n\n open.addEventListener('click', () => {\n form.hidden = !form.hidden;\n open.setAttribute('aria-expanded', String(!form.hidden));\n if (!form.hidden) name.focus();\n });\n save.addEventListener('click', () => {\n const named = name.value.trim();\n if (!named) return name.focus();\n const kept: Favourite = { name: named, facets: context.current(), ...(byDefault.checked ? { isDefault: true } : {}) };\n // A name kept again replaces the old search; one default at a time.\n const others = readFavourites(preferences, page)\n .filter((f) => f.name !== named)\n .map((f) => (byDefault.checked ? { name: f.name, facets: f.facets } : f));\n write([...others, kept]);\n name.value = '';\n byDefault.checked = false;\n form.hidden = true;\n open.setAttribute('aria-expanded', 'false');\n draw();\n });\n\n draw();\n return { list, none, open, form };\n}\n", "import type { DataSource, Group, Page, RecordId, ResolvedFilter, SortOrder, Value } from '@fieldia/core';\nimport type { El } from './dom';\nimport type { ViewerLabels } from './labels';\n\nexport type Row = { id: RecordId; values: Record<string, Value> };\n\nexport interface GroupContext {\n page: Page;\n el: El;\n labels: ViewerLabels;\n fill: (template: string, values: Record<string, string | number>) => string;\n dataSource: DataSource;\n model: string;\n fields: string[];\n columns: number;\n pageSize: number;\n sort: () => SortOrder[];\n /** A record's row, at a depth under its groups. */\n recordRow: (record: Row, level: number) => HTMLTableRowElement;\n /** Rows came or went. */\n changed: () => void;\n}\n\n/** A group's name as a person reads it: the choice's label, yes or no, the linked record's name, or None. */\nfunction groupName(context: GroupContext, field: string, group: Group): string {\n const def = context.page.fields[field];\n if (group.value === null) return context.labels.none;\n if (def.type === 'selection') return def.options.find((o) => o.value === group.value)?.label ?? group.label;\n if (def.type === 'boolean') return group.value ? context.labels.yes : context.labels.no;\n return group.label || String(group.value);\n}\n\n/** Take away every row under a group: its records, its groups and theirs. */\nfunction closeUnder(tr: HTMLElement) {\n const level = Number(tr.dataset['level']);\n let next = tr.nextElementSibling as HTMLElement | null;\n while (next && Number(next.dataset['level'] ?? 0) > level) {\n const after = next.nextElementSibling as HTMLElement | null;\n next.remove();\n next = after;\n }\n}\n\n/**\n * A group's row: its name and how many records it holds. Opened, it shows\n * the next field's groups under it, or at the last field its records, a page\n * at a time; closed, everything under it goes.\n */\nexport function groupRow(context: GroupContext, group: Group, level: number, within: ResolvedFilter[], grouping: string[]): HTMLTableRowElement {\n const { el, labels } = context;\n const field = grouping[level];\n const filter: ResolvedFilter[] = [...within, group.value === null ? { field, op: 'notset', value: null } : { field, op: '=', value: group.value }];\n const toggle = el(\n 'button',\n { type: 'button', class: 'fd-group-toggle', 'aria-expanded': 'false' },\n el('span', { class: 'fd-group-label' }, groupName(context, field, group)),\n ' ',\n el('span', { class: 'fd-group-count' }, `(${group.count})`)\n );\n const tr = el('tr', { class: 'fd-list-group', 'data-level': String(level), 'aria-level': String(level + 1) }, el('td', { colspan: String(context.columns) }, toggle));\n tr.style.setProperty('--fd-level', String(level));\n let opening = false;\n\n async function open() {\n opening = true;\n try {\n const rows =\n level + 1 < grouping.length\n ? (await context.dataSource.groups?.({ model: context.model, field: grouping[level + 1], filter }))?.map((inner) => groupRow(context, inner, level + 1, filter, grouping)) ?? []\n : await recordsFrom(0);\n // Closed, or the list drawn again, while the answer was on its way.\n if (!tr.isConnected || toggle.getAttribute('aria-expanded') !== 'true') return;\n tr.after(...rows);\n context.changed();\n } finally {\n opening = false;\n }\n }\n\n /** A page of the group's records, from `offset`, and a row for the rest when there are more. */\n async function recordsFrom(offset: number): Promise<HTMLTableRowElement[]> {\n const answer = await context.dataSource.list!({ model: context.model, fields: context.fields, filter, sort: context.sort(), offset, limit: context.pageSize });\n const rows = answer.records.map((record) => context.recordRow(record, level + 1));\n const left = answer.total - offset - answer.records.length;\n if (left <= 0) return rows;\n const more = el('button', { type: 'button', class: 'fd-button fd-button-link' }, context.fill(labels.loadMore, { n: left }));\n const moreRow = el('tr', { class: 'fd-list-more', 'data-level': String(level + 1) }, el('td', { colspan: String(context.columns) }, more));\n moreRow.style.setProperty('--fd-level', String(level));\n more.addEventListener('click', async () => {\n more.disabled = true;\n const next = await recordsFrom(offset + answer.records.length);\n if (!moreRow.isConnected) return;\n moreRow.replaceWith(...next);\n context.changed();\n });\n return [...rows, moreRow];\n }\n\n toggle.addEventListener('click', () => {\n const opened = toggle.getAttribute('aria-expanded') === 'true';\n toggle.setAttribute('aria-expanded', String(!opened));\n if (opened) {\n closeUnder(tr);\n context.changed();\n } else if (!opening) void open();\n });\n return tr;\n}\n", "/** The list's look, on the same tokens as the forms it opens. */\nexport const LIST_STYLES = `.fd-list{display:grid;gap:10px;min-width:0}.fd-list [hidden]{display:none!important}.fd-list-bar{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;min-height:34px}.fd-search{position:relative;flex:1 1 360px;max-width:680px;min-width:0;container:fd-search / inline-size}.fd-search-field{display:flex;flex-wrap:wrap;align-items:center;gap:4px;min-height:34px;box-sizing:border-box;padding:2px 2px 2px 8px;padding-inline:8px 2px;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);background:var(--fd-surface)}.fd-search-field:focus-within{border-color:var(--fd-focus);box-shadow:var(--fd-focus-ring)}.fd-search-field>.fd-icon,.fd-search-field>svg{width:16px;height:16px;color:var(--fd-muted);flex:none}.fd-facets{display:contents}.fd-facet{display:inline-flex;align-items:center;gap:4px;max-width:100%;min-width:0;padding-block:2px;padding-inline:6px 2px;border-radius:3px;background:var(--fd-accent-soft);color:var(--fd-accent);font-size:13px;line-height:18px}.fd-facet svg{width:13px;height:13px;flex:none}.fd-facet[data-kind=groupBy]{background:var(--fd-success-soft);color:var(--fd-success)}.fd-facet-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fd-facet-remove{all:unset;cursor:pointer;display:grid;place-items:center;width:18px;height:18px;border-radius:2px;font-size:15px;line-height:1;opacity:.7}.fd-facet-remove:hover,.fd-facet-remove:focus-visible{opacity:1;background:var(--fd-surface)}.fd-search-input{flex:1 1 140px;min-width:100px;border:none;outline:none;background:none;font:inherit;font-size:14px;color:var(--fd-text);padding:5px 4px}.fd-form .fd-search-input:focus-visible{outline:none}.fd-search-toggle{all:unset;cursor:pointer;display:grid;place-items:center;width:30px;height:28px;border-radius:3px;color:var(--fd-muted)}.fd-search-toggle:before{content:\"\";width:7px;height:7px;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:translateY(-2px) rotate(45deg)}.fd-search-toggle[aria-expanded=true]:before{transform:translateY(2px) rotate(-135deg)}.fd-search-toggle:hover,.fd-search-toggle[aria-expanded=true]{background:var(--fd-page);color:var(--fd-text)}.fd-search-toggle:focus-visible{outline:2px solid var(--fd-focus)}.fd-search-suggestions,.fd-search-panel{position:absolute;z-index:30;inset-inline:0;top:calc(100% + 4px);box-sizing:border-box;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius);box-shadow:0 10px 28px #0f172a24}.fd-search-suggestions{list-style:none;margin:0;padding:4px 0}.fd-search-suggestions [role=option]{padding:7px 12px;cursor:pointer;font-size:14px}.fd-search-suggestions [role=option][aria-selected=true]{background:var(--fd-accent-soft)}.fd-search-panel{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);padding-block:6px}.fd-search-group{display:flex;flex-direction:column;align-items:stretch;gap:1px;padding:4px 10px 8px;min-width:0}.fd-search-group+.fd-search-group{border-inline-start:1px solid var(--fd-border)}@container fd-search (max-width: 540px){.fd-search-panel{grid-auto-flow:row}.fd-search-group+.fd-search-group{border-inline-start:none;border-block-start:1px solid var(--fd-border);padding-block-start:8px}}.fd-search-heading{display:flex;align-items:center;gap:6px;font-weight:600;font-size:13.5px;padding:4px 6px 6px}.fd-search-heading svg{width:15px;height:15px}.fd-search-group[data-group-kind=filters] .fd-search-heading svg{color:var(--fd-accent)}.fd-search-group[data-group-kind=groupBy] .fd-search-heading svg{color:var(--fd-success)}.fd-search-group[data-group-kind=favourites] .fd-search-heading svg{color:var(--fd-warning)}.fd-search-option{all:unset;box-sizing:border-box;cursor:pointer;display:flex;align-items:center;gap:6px;padding:5px 6px;border-radius:4px;font-size:14px;color:var(--fd-text)}.fd-search-option:before{content:\"\";width:14px;flex:none;text-align:center;color:var(--fd-accent);font-weight:700}.fd-search-option[aria-pressed=true]:before{content:\"\u2713\"}.fd-search-option:hover,.fd-search-option:focus-visible{background:var(--fd-page)}.fd-search-add{color:var(--fd-muted);margin-block-start:4px}.fd-search-add:before{content:\"+\";color:var(--fd-muted);font-weight:400}.fd-custom-filter,.fd-favourite-form{display:grid;gap:6px;padding:6px}.fd-custom-filter .fd-input,.fd-favourite-form .fd-input{width:100%;box-sizing:border-box;min-height:30px;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);padding:3px 6px;font:inherit;font-size:13.5px;background:var(--fd-surface);color:var(--fd-text)}.fd-favourite-default{display:flex;align-items:center;gap:6px;font-size:13.5px}.fd-favourite-list{list-style:none;margin:0;padding:0}.fd-favourite{display:flex;align-items:center}.fd-favourite .fd-search-option{flex:1;min-width:0}.fd-favourite .fd-search-option[data-default=true]:before{content:\"\u2605\";color:var(--fd-warning)}.fd-favourite-remove{all:unset;cursor:pointer;width:24px;height:24px;display:grid;place-items:center;border-radius:4px;color:var(--fd-muted)}.fd-favourite-remove:hover{background:var(--fd-page);color:var(--fd-error)}.fd-favourites-none{margin:0;padding:4px 6px;color:var(--fd-muted);font-size:13px}.fd-list-selection{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:3px 4px 3px 10px;border-radius:var(--fd-control-radius);background:var(--fd-accent-soft)}.fd-list-count{font-weight:600;font-size:13.5px;color:var(--fd-accent);font-variant-numeric:tabular-nums}.fd-pager{display:flex;align-items:center;gap:4px;margin-inline-start:auto}.fd-pager-text{color:var(--fd-muted);font-size:13.5px;font-variant-numeric:tabular-nums;margin-inline-end:6px;white-space:nowrap}.fd-pager-button{min-width:32px;padding-inline:0;font-size:18px;line-height:1}.fd-list-scroll{overflow-x:auto;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius)}.fd-list-table{width:100%;border-collapse:collapse;font-size:14px}.fd-list-table th{text-align:start;font-weight:600;font-size:13px;color:var(--fd-text);padding:8px 10px;border-block-end:1px solid var(--fd-border-strong);white-space:nowrap;background:var(--fd-surface)}.fd-list-table td{padding:7px 10px;border-block-end:1px solid var(--fd-border);max-width:28em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fd-list-table tbody tr:last-child td{border-block-end:none}.fd-list-table .fd-num{text-align:end;font-variant-numeric:tabular-nums}.fd-list-table th.fd-list-check,.fd-list-table td.fd-list-check{width:36px;padding-inline:10px 0}.fd-list-checkbox{width:16px;height:16px;margin:0;vertical-align:middle;accent-color:var(--fd-accent);cursor:pointer}.fd-list-sort{all:unset;box-sizing:border-box;width:100%;cursor:pointer;display:flex;align-items:center;gap:4px;font:inherit;color:inherit}.fd-list-sort:after{content:\"\";width:0;height:0;border-inline:4px solid transparent;opacity:0}.fd-list-sort:hover:after{opacity:.35;border-block-start:5px solid currentColor}.fd-list-table th[aria-sort=ascending] .fd-list-sort:after{opacity:1;border-block-start:none;border-block-end:5px solid currentColor}.fd-list-table th[aria-sort=descending] .fd-list-sort:after{opacity:1;border-block-end:none;border-block-start:5px solid currentColor}.fd-list-table th.fd-num .fd-list-sort{justify-content:flex-end}.fd-list-table th.fd-num .fd-list-sort:after{order:-1}.fd-list-sort:focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px}.fd-list-row:hover td{background:var(--fd-page)}.fd-list-openable{cursor:pointer}.fd-list-row[aria-selected=true] td{background:var(--fd-accent-soft)}.fd-list-row:focus-visible{outline:2px solid var(--fd-focus);outline-offset:-2px}.fd-list-table[aria-busy=true] tbody{opacity:.6;transition:opacity .2s .15s}.fd-list-group td{padding:0;background:var(--fd-page)}.fd-group-toggle{all:unset;box-sizing:border-box;cursor:pointer;display:flex;align-items:center;gap:8px;width:100%;padding:8px 10px;padding-inline-start:calc(12px + var(--fd-level, 0) * 22px);font-weight:600;font-size:13.5px;color:var(--fd-text)}.fd-group-toggle:before{content:\"\";flex:none;width:6px;height:6px;border-top:1.5px solid currentColor;border-right:1.5px solid currentColor;transform:rotate(45deg);transition:transform .12s}.fd-group-toggle:dir(rtl):before{transform:rotate(-135deg)}.fd-group-toggle[aria-expanded=true]:before{transform:rotate(135deg)}.fd-group-toggle:hover{background:var(--fd-accent-soft)}.fd-group-toggle:focus-visible{outline:2px solid var(--fd-focus);outline-offset:-2px}.fd-group-count{color:var(--fd-muted);font-weight:400;font-variant-numeric:tabular-nums}.fd-list-more td{padding:4px 10px;padding-inline-start:calc(46px + var(--fd-level, 0) * 22px)}.fd-list-empty,.fd-list-failed{margin:0;padding:28px 12px;text-align:center;color:var(--fd-muted)}.fd-list-failed{color:var(--fd-error)}`;\n\n/** Puts the list's look in the document once. */\nexport function installListStyles(doc: Document): void {\n if (doc.getElementById('fd-list-styles')) return;\n const style = doc.createElement('style');\n style.id = 'fd-list-styles';\n style.textContent = LIST_STYLES;\n doc.head.append(style);\n}\n", "import type { Facet, Field, JsonValue, Page, ResolvedFilterCondition } from '@fieldia/core';\nimport type { El } from './dom';\nimport type { ViewerLabels } from './labels';\n\ntype Op = ResolvedFilterCondition['op'];\ntype Words = Pick<ViewerLabels, 'opIs' | 'opIsNot' | 'opContains' | 'opGreater' | 'opLess' | 'opSet' | 'opNotSet'>;\n\nconst TEXT: [Op, keyof Words][] = [['ilike', 'opContains'], ['=', 'opIs'], ['!=', 'opIsNot'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst LINK: [Op, keyof Words][] = [['ilike', 'opContains'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst CHOICE: [Op, keyof Words][] = [['=', 'opIs'], ['!=', 'opIsNot'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst NUMBER: [Op, keyof Words][] = [['=', 'opIs'], ['!=', 'opIsNot'], ['>', 'opGreater'], ['<', 'opLess'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst DATE: [Op, keyof Words][] = [['=', 'opIs'], ['>', 'opGreater'], ['<', 'opLess'], ['set', 'opSet'], ['notset', 'opNotSet']];\n\n/** The conditions that suit a field, or none for a field a custom filter cannot look at. */\nfunction conditionsFor(def: Field): [Op, keyof Words][] {\n switch (def.type) {\n case 'char':\n case 'text':\n case 'html':\n return TEXT;\n case 'many2one':\n case 'many2many':\n return LINK;\n case 'selection':\n return CHOICE;\n case 'integer':\n case 'float':\n case 'monetary':\n return NUMBER;\n case 'date':\n case 'datetime':\n return DATE;\n case 'boolean':\n return [['=', 'opIs']];\n default:\n return [];\n }\n}\n\n/**\n * A filter of a person's own, under the list's filters: a field, a condition\n * that suits it, and a value of its kind. Applied, it becomes a chip.\n */\nexport function customFilterPart(context: { page: Page; el: El; labels: ViewerLabels; add: (facet: Facet) => void }) {\n const { page, el, labels } = context;\n const fields = Object.entries(page.fields).filter(([, def]) => conditionsFor(def).length);\n const field = el('select', { class: 'fd-input', 'aria-label': labels.field }, ...fields.map(([name, def]) => el('option', { value: name }, def.label)));\n const condition = el('select', { class: 'fd-input', 'aria-label': labels.condition });\n const valueBox = el('span', { class: 'fd-custom-filter-value' });\n const apply = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.apply);\n const form = el('div', { class: 'fd-custom-filter', hidden: '' }, field, condition, valueBox, apply);\n const button = el('button', { type: 'button', class: 'fd-search-option fd-search-add', 'aria-expanded': 'false' }, labels.addCustomFilter);\n let value: HTMLInputElement | HTMLSelectElement = el('input', { class: 'fd-input', 'aria-label': labels.value });\n\n const def = () => page.fields[field.value];\n\n function drawConditions() {\n condition.replaceChildren(...conditionsFor(def()).map(([op, word]) => el('option', { value: op }, labels[word])));\n drawValue();\n }\n\n /** A box of the field's kind: its choices, yes or no, a number, a day, or text. */\n function drawValue() {\n const current = def();\n if (current.type === 'selection') value = el('select', { class: 'fd-input', 'aria-label': labels.value }, ...current.options.map((o) => el('option', { value: String(o.value) }, o.label)));\n else if (current.type === 'boolean') value = el('select', { class: 'fd-input', 'aria-label': labels.value }, el('option', { value: 'true' }, labels.yes), el('option', { value: 'false' }, labels.no));\n else {\n const type = ['integer', 'float', 'monetary'].includes(current.type) ? 'number' : current.type === 'date' ? 'date' : current.type === 'datetime' ? 'datetime-local' : 'text';\n value = el('input', { class: 'fd-input', type, 'aria-label': labels.value });\n }\n valueBox.replaceChildren(value);\n valueBox.hidden = condition.value === 'set' || condition.value === 'notset';\n }\n\n field.addEventListener('change', drawConditions);\n condition.addEventListener('change', () => (valueBox.hidden = condition.value === 'set' || condition.value === 'notset'));\n button.addEventListener('click', () => {\n form.hidden = !form.hidden;\n button.setAttribute('aria-expanded', String(!form.hidden));\n if (!form.hidden) field.focus();\n });\n\n apply.addEventListener('click', () => {\n const current = def();\n const op = condition.value as Op;\n const word = labels[conditionsFor(current).find(([o]) => o === op)?.[1] ?? 'opIs'];\n let wanted: JsonValue = null;\n let shown = '';\n if (!valueBox.hidden) {\n const text = value.value.trim();\n if (!text) return value.focus();\n if (current.type === 'selection') {\n const option = current.options.find((o) => String(o.value) === text);\n wanted = option?.value ?? text;\n shown = option?.label ?? text;\n } else if (current.type === 'boolean') {\n wanted = text === 'true';\n shown = wanted ? labels.yes : labels.no;\n } else if (['integer', 'float', 'monetary'].includes(current.type)) {\n wanted = Number(text);\n if (!Number.isFinite(wanted)) return value.focus();\n shown = text;\n } else {\n wanted = text;\n shown = text;\n }\n }\n context.add({ kind: 'custom', label: [current.label, word, shown].filter(Boolean).join(' '), filter: [{ field: field.value, op, value: wanted }] });\n form.hidden = true;\n button.setAttribute('aria-expanded', 'false');\n });\n\n drawConditions();\n return { button, form };\n}\n", "import { suggestions, type Facet, type ListNode, type Page, type Suggestion } from '@fieldia/core';\nimport { drawIcon, type IconSet, type PreferenceStore } from '@fieldia/widgets';\nimport { customFilterPart } from './custom-filter';\nimport type { El } from './dom';\nimport { favouritesPart } from './favourites';\nimport type { ViewerLabels } from './labels';\n\ntype FieldFacet = Extract<Facet, { kind: 'field' }>;\n\nexport interface SearchContext {\n page: Page;\n node: ListNode;\n doc: Document;\n el: El;\n labels: ViewerLabels;\n fill: (template: string, values: Record<string, string | number>) => string;\n uid: (id: string) => string;\n icons?: IconSet;\n preferences: PreferenceStore;\n /** What the list starts with. */\n facets: Facet[];\n onChange: (facets: Facet[]) => void;\n}\n\n/** A chip's words: a field and the values looked for in it, filters any of which apply, or the fields grouped by. */\nexport function facetText(facet: Facet, labels: Pick<ViewerLabels, 'or'>): string {\n const or = ` ${labels.or} `;\n switch (facet.kind) {\n case 'field':\n return `${facet.label}: ${facet.values.map((v) => v.label).join(or)}`;\n case 'filters':\n return facet.labels.join(or);\n case 'groupBy':\n return facet.labels.join(' > ');\n case 'custom':\n return facet.label;\n }\n}\n\n/**\n * A list's search bar: what is typed becomes a search in one of the list's\n * fields, chosen from suggestions; the menu turns the list's filters on and\n * off, groups by its fields, builds a filter, and keeps searches as\n * favourites. Everything chosen shows as a chip, and all of it applies.\n */\nexport function searchBar(context: SearchContext) {\n const { page, node, doc, el, labels, fill, uid } = context;\n let facets = context.facets;\n const icon = (name: string) => {\n const drawn = drawIcon(doc, name, context.icons);\n drawn?.setAttribute('aria-hidden', 'true');\n return drawn ? [drawn] : [];\n };\n\n function change(next: Facet[]) {\n facets = next;\n drawChips();\n drawPanel();\n context.onChange(facets);\n }\n\n // ---- the box, its chips and its suggestions -----------------------------------------\n\n const listId = uid(`${node.id}-suggestions`);\n const panelId = uid(`${node.id}-search-panel`);\n const input = el('input', {\n class: 'fd-search-input',\n role: 'combobox',\n autocomplete: 'off',\n placeholder: labels.search,\n 'aria-label': labels.searchLabel,\n 'aria-autocomplete': 'list',\n 'aria-expanded': 'false',\n 'aria-controls': listId,\n });\n const chips = el('div', { class: 'fd-facets' });\n const offeredList = el('ul', { class: 'fd-search-suggestions', role: 'listbox', id: listId, 'aria-label': labels.searchLabel, hidden: '' });\n const toggle = el('button', { type: 'button', class: 'fd-search-toggle', 'aria-label': labels.searchOptions, 'aria-expanded': 'false', 'aria-controls': panelId });\n let offered: Suggestion[] = [];\n let active = 0;\n\n function drawChips() {\n chips.replaceChildren(\n ...facets.map((facet, index) => {\n const text = facetText(facet, labels);\n const remove = el('button', { type: 'button', class: 'fd-facet-remove', 'aria-label': fill(labels.removeFacet, { label: text }) }, '\u00D7');\n remove.addEventListener('click', () => {\n change(facets.filter((_, i) => i !== index));\n input.focus();\n });\n const kind = facet.kind === 'groupBy' ? 'layers' : facet.kind === 'field' ? '' : 'filter';\n return el('span', { class: 'fd-facet', 'data-kind': facet.kind }, ...(kind ? icon(kind) : []), el('span', { class: 'fd-facet-text' }, text), remove);\n })\n );\n }\n\n function drawOffered() {\n offeredList.replaceChildren(\n ...offered.map((suggestion, index) => {\n const option = el('li', { role: 'option', id: `${listId}-${index}`, 'aria-selected': String(index === active) }, suggestion.label);\n // The box keeps the focus while a suggestion is clicked.\n option.addEventListener('mousedown', (event) => event.preventDefault());\n option.addEventListener('click', () => pick(suggestion));\n return option;\n })\n );\n offeredList.hidden = offered.length === 0;\n input.setAttribute('aria-expanded', String(!offeredList.hidden));\n if (offeredList.hidden) input.removeAttribute('aria-activedescendant');\n else input.setAttribute('aria-activedescendant', `${listId}-${active}`);\n }\n\n function closeOffered() {\n offered = [];\n drawOffered();\n }\n\n /** A search in a field joins the field's chip, any of its values; the same value twice is once. */\n function pick(suggestion: Suggestion) {\n const value = { op: suggestion.op, value: suggestion.value, label: suggestion.valueLabel };\n const at = facets.findIndex((f) => f.kind === 'field' && f.field === suggestion.field);\n const next = [...facets];\n if (at < 0) next.push({ kind: 'field', field: suggestion.field, label: suggestion.fieldLabel, values: [value] });\n else {\n const facet = next[at] as FieldFacet;\n const known = facet.values.some((v) => v.op === value.op && JSON.stringify(v.value) === JSON.stringify(value.value));\n if (!known) next[at] = { ...facet, values: [...facet.values, value] };\n }\n input.value = '';\n closeOffered();\n change(next);\n }\n\n input.addEventListener('input', () => {\n offered = suggestions(input.value, page, node, { searchFor: labels.searchFor });\n active = 0;\n drawOffered();\n });\n input.addEventListener('blur', closeOffered);\n input.addEventListener('keydown', (event) => {\n if (event.isComposing) return;\n if ((event.key === 'ArrowDown' || event.key === 'ArrowUp') && offered.length) {\n event.preventDefault();\n active = (active + (event.key === 'ArrowDown' ? 1 : offered.length - 1)) % offered.length;\n drawOffered();\n } else if (event.key === 'Enter') {\n // Never the form's Enter: a list has nothing to send.\n event.preventDefault();\n if (offered.length) pick(offered[active]);\n } else if (event.key === 'Backspace' && !input.value && facets.length) {\n change(facets.slice(0, -1));\n } else if (event.key === 'Escape' && !offeredList.hidden) {\n event.preventDefault();\n closeOffered();\n }\n });\n\n // ---- the menu: filters, group by, favourites ---------------------------------------\n\n const heading = (iconName: string, text: string, id: string) => el('div', { class: 'fd-search-heading', id }, ...icon(iconName), text);\n const toggleIn = (kind: 'filters' | 'groupBy', key: string) => {\n const at = facets.findIndex((f) => f.kind === kind);\n const now = at < 0 ? [] : kind === 'filters' ? (facets[at] as Extract<Facet, { kind: 'filters' }>).ids : (facets[at] as Extract<Facet, { kind: 'groupBy' }>).fields;\n const keys = now.includes(key) ? now.filter((k) => k !== key) : [...now, key];\n const facet: Facet =\n kind === 'filters'\n ? { kind, ids: keys, labels: keys.map((id) => node.filters?.find((f) => f.id === id)?.label ?? id) }\n : { kind, fields: keys, labels: keys.map((field) => page.fields[field]?.label ?? field) };\n const next = [...facets];\n if (at < 0) next.push(facet);\n else if (keys.length) next[at] = facet;\n else next.splice(at, 1);\n change(next);\n };\n\n const filterButtons = (node.filters ?? []).map((filter) => {\n const button = el('button', { type: 'button', class: 'fd-search-option', 'aria-pressed': 'false', 'data-filter': filter.id }, filter.label);\n button.addEventListener('click', () => toggleIn('filters', filter.id));\n return button;\n });\n const groupButtons = (node.groupBy ?? []).map((field) => {\n const button = el('button', { type: 'button', class: 'fd-search-option', 'aria-pressed': 'false', 'data-group': field }, page.fields[field].label);\n button.addEventListener('click', () => toggleIn('groupBy', field));\n return button;\n });\n const custom = customFilterPart({ page, el, labels, add: (facet) => change([...facets, facet]) });\n const favourites = favouritesPart({ page, el, labels, fill, preferences: context.preferences, current: () => facets, apply: change });\n\n const group = (kind: string, iconName: string, title: string, ...parts: HTMLElement[]) =>\n el('div', { class: 'fd-search-group', 'data-group-kind': kind, role: 'group', 'aria-labelledby': `${panelId}-${kind}` }, heading(iconName, title, `${panelId}-${kind}`), ...parts);\n const panel = el(\n 'div',\n { class: 'fd-search-panel', id: panelId, hidden: '' },\n group('filters', 'filter', labels.filters, ...filterButtons, custom.button, custom.form),\n ...(groupButtons.length ? [group('groupBy', 'layers', labels.groupBy, ...groupButtons)] : []),\n group('favourites', 'star', labels.favourites, favourites.list, favourites.none, favourites.open, favourites.form)\n );\n\n function drawPanel() {\n const ids = (facets.find((f) => f.kind === 'filters') as Extract<Facet, { kind: 'filters' }> | undefined)?.ids ?? [];\n const fields = (facets.find((f) => f.kind === 'groupBy') as Extract<Facet, { kind: 'groupBy' }> | undefined)?.fields ?? [];\n for (const button of filterButtons) button.setAttribute('aria-pressed', String(ids.includes(button.dataset['filter'] ?? '')));\n for (const button of groupButtons) button.setAttribute('aria-pressed', String(fields.includes(button.dataset['group'] ?? '')));\n }\n\n function showPanel(open: boolean) {\n panel.hidden = !open;\n toggle.setAttribute('aria-expanded', String(open));\n if (open) closeOffered();\n }\n toggle.addEventListener('click', () => showPanel(panel.hidden));\n panel.addEventListener('keydown', (event) => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n showPanel(false);\n toggle.focus();\n });\n const element = el('div', { class: 'fd-search' }, el('div', { class: 'fd-search-field' }, ...icon('search'), chips, input, toggle), offeredList, panel);\n // A press anywhere else closes the menu.\n const outside = (event: Event) => {\n if (!panel.hidden && !element.contains(event.target as Node)) showPanel(false);\n };\n doc.addEventListener('pointerdown', outside);\n\n drawChips();\n drawPanel();\n return {\n element,\n destroy: () => doc.removeEventListener('pointerdown', outside),\n };\n}\n", "import {\n facetsToFilter,\n groupByFields,\n type ButtonNode,\n type DataSource,\n type Facet,\n type Form,\n type LineField,\n type ListNode,\n type Locale,\n type Page,\n type RecordId,\n type SortOrder,\n type Value,\n} from '@fieldia/core';\nimport { displayValue, type IconSet, type PreferenceStore } from '@fieldia/widgets';\nimport type { El } from './dom';\nimport { startingFacets } from './favourites';\nimport type { ViewerLabels } from './labels';\nimport { groupRow, type GroupContext, type Row } from './list-groups';\nimport { installListStyles } from './list-styles';\nimport { searchBar } from './search-bar';\n\nexport interface ListContext {\n page: Page;\n node: ListNode;\n form: Form;\n dataSource: DataSource | undefined;\n doc: Document;\n el: El;\n labels: ViewerLabels;\n locale: Locale;\n fill: (template: string, values: Record<string, string | number>) => string;\n confirm: (message: string) => Promise<boolean>;\n withIcon: (icon: string | undefined, text: string) => (Node | string)[];\n uid: (id: string) => string;\n icons?: IconSet;\n /** Where the list's favourite searches are kept. */\n preferences: PreferenceStore;\n onOpenRecord?: (id: RecordId) => void;\n}\n\nexport interface ListView {\n element: HTMLElement;\n /** Ask for the records again, keeping the page, the order and what is chosen where it still applies. */\n reload(): Promise<void>;\n destroy(): void;\n}\n\n/** Numbers line up on the end of their column. */\nconst NUMBERS = new Set(['integer', 'float', 'monetary']);\n/** Fields no list can put in order. */\nconst UNSORTABLE = new Set(['one2many', 'many2many', 'binary', 'image', 'html', 'json', 'properties']);\n\n/**\n * Records as a table: one page at a time, in the order a header asks for, each\n * row opening its record. Chosen rows get the list's buttons, which hand the\n * app their ids. A plain table, so it reads the same in every binding.\n */\nexport function listView(context: ListContext): ListView {\n const { page, node, form, el, labels, fill, locale, doc } = context;\n installListStyles(doc);\n const pageSize = node.pageSize ?? 40;\n const defaultSort = node.sort ?? [];\n let sort: SortOrder[] = defaultSort;\n let offset = 0;\n let total = 0;\n /** The page of records, when the list is not grouped. */\n let rows: Row[] = [];\n /** Each record's row, for the records on show however they are grouped. */\n const recordOf = new WeakMap<Element, Row>();\n const visible = () => [...body.querySelectorAll('.fd-list-row')].map((tr) => recordOf.get(tr) as Row);\n // Only a page of records gets this far: the page check refuses a list of anything else.\n const model = page.data.kind === 'record' ? page.data.model : '';\n let facets: Facet[] = startingFacets(node, context.preferences, page);\n /** In the order they were chosen, which is the order the app gets them. */\n const chosen = new Set<RecordId>();\n let asking = 0;\n let destroyed = false;\n\n // The columns, and what an amount needs to be read: its currency, from the record.\n const fields = [...new Set(node.columns.flatMap((name) => {\n const def = page.fields[name];\n return def.type === 'monetary' && def.currencyField ? [name, def.currencyField] : [name];\n }))];\n const show = (name: string, values: Record<string, Value>) => displayValue(page.fields[name] as LineField, values[name], values, locale);\n\n // ---- the table ---------------------------------------------------------------\n\n const chooseAll = el('input', { type: 'checkbox', class: 'fd-list-checkbox', 'aria-label': labels.selectAll });\n const headers = node.columns.map((name) => {\n const def = page.fields[name];\n const th = el('th', { scope: 'col', 'data-field': name, class: NUMBERS.has(def.type) ? 'fd-num' : undefined });\n if (UNSORTABLE.has(def.type)) th.append(def.label);\n else {\n const button = el('button', { type: 'button', class: 'fd-list-sort' }, def.label);\n button.addEventListener('click', () => {\n // The header's field leads; the list's own order breaks the ties.\n const desc = sort[0]?.field === name ? !sort[0].desc : false;\n sort = [{ field: name, ...(desc ? { desc } : {}) }, ...defaultSort.filter((order) => order.field !== name)];\n offset = 0;\n void load();\n });\n th.append(button);\n }\n return th;\n });\n const body = el('tbody');\n const table = el(\n 'table',\n { class: 'fd-list-table', 'aria-label': page.title },\n el('thead', {}, el('tr', {}, el('th', { class: 'fd-list-check', scope: 'col' }, chooseAll), ...headers)),\n body\n );\n const empty = el('p', { class: 'fd-list-empty', hidden: '' }, labels.noRecords);\n const retry = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.retry);\n const failed = el('p', { class: 'fd-list-failed', role: 'alert', hidden: '' }, labels.loadFailed, ' ', retry);\n retry.addEventListener('click', () => void load());\n\n function row(record: Row, level = 0): HTMLTableRowElement {\n const name = show(node.columns[0], record.values) || String(record.id);\n const box = el('input', { type: 'checkbox', class: 'fd-list-checkbox', 'aria-label': fill(labels.selectRecord, { name }) });\n box.checked = chosen.has(record.id);\n box.addEventListener('change', () => {\n if (box.checked) chosen.add(record.id);\n else chosen.delete(record.id);\n drawChoice();\n });\n const tr = el(\n 'tr',\n { class: context.onOpenRecord ? 'fd-list-row fd-list-openable' : 'fd-list-row', tabindex: '0', 'data-id': String(record.id), 'data-level': level ? String(level) : undefined },\n el('td', { class: 'fd-list-check' }, box),\n // Each value in its own direction: a phone number or an amount reads left to right on a right-to-left page.\n ...node.columns.map((name) => el('td', { class: NUMBERS.has(page.fields[name].type) ? 'fd-num' : undefined }, el('bdi', {}, show(name, record.values))))\n );\n tr.addEventListener('click', (event) => {\n const cell = (event.target as Element).closest('td');\n // The box's own cell is a bigger target for the box.\n if (cell?.classList.contains('fd-list-check')) {\n if (event.target === cell) box.click();\n return;\n }\n context.onOpenRecord?.(record.id);\n });\n tr.addEventListener('keydown', (event) => {\n if (event.target !== tr) return;\n if (event.key === 'Enter') {\n event.preventDefault();\n context.onOpenRecord?.(record.id);\n } else if (event.key === ' ') {\n event.preventDefault();\n box.click();\n } else if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n const next = event.key === 'ArrowDown' ? tr.nextElementSibling : tr.previousElementSibling;\n (next as HTMLElement | null)?.focus();\n }\n });\n recordOf.set(tr, record);\n return tr;\n }\n\n // ---- what is chosen, and the buttons for it --------------------------------------\n\n const count = el('span', { class: 'fd-list-count', role: 'status' });\n const clear = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.clearSelection);\n const buttons = (node.actions ?? []).map((action: ButtonNode) => {\n const button = el('button', { type: 'button', class: `fd-button fd-button-${action.style ?? 'secondary'}`, 'data-node': action.id }, ...context.withIcon(action.icon, action.label));\n button.addEventListener('click', async () => {\n if (action.confirm && !(await context.confirm(action.confirm))) return;\n await form.runAction(action.id, { recordIds: [...chosen] });\n await load();\n });\n return button;\n });\n const selection = el('div', { class: 'fd-list-selection', hidden: '' }, count, ...buttons, clear);\n clear.addEventListener('click', () => {\n chosen.clear();\n for (const box of body.querySelectorAll<HTMLInputElement>('.fd-list-checkbox')) box.checked = false;\n drawChoice();\n });\n chooseAll.addEventListener('change', () => {\n for (const record of visible()) {\n if (chooseAll.checked) chosen.add(record.id);\n else chosen.delete(record.id);\n }\n for (const box of body.querySelectorAll<HTMLInputElement>('.fd-list-checkbox')) box.checked = chooseAll.checked;\n drawChoice();\n });\n\n function drawChoice() {\n const shown = visible();\n const onPage = shown.filter((record) => chosen.has(record.id)).length;\n chooseAll.checked = shown.length > 0 && onPage === shown.length;\n chooseAll.indeterminate = onPage > 0 && onPage < shown.length;\n selection.hidden = chosen.size === 0;\n count.textContent = fill(labels.selected, { n: chosen.size });\n for (const tr of body.querySelectorAll<HTMLElement>('.fd-list-row')) {\n tr.setAttribute('aria-selected', String([...chosen].some((id) => String(id) === tr.dataset['id'])));\n }\n }\n\n // ---- pages -------------------------------------------------------------------\n\n const range = el('span', { class: 'fd-pager-text' });\n const previous = el('button', { type: 'button', class: 'fd-button fd-pager-button', 'aria-label': labels.previousPage }, '\u2039');\n const next = el('button', { type: 'button', class: 'fd-button fd-pager-button', 'aria-label': labels.nextPage }, '\u203A');\n const pager = el('div', { class: 'fd-pager', role: 'group' }, range, previous, next);\n previous.addEventListener('click', () => {\n offset = Math.max(0, offset - pageSize);\n void load();\n });\n next.addEventListener('click', () => {\n offset += pageSize;\n void load();\n });\n\n function drawPager() {\n pager.hidden = total === 0;\n range.textContent = fill(labels.range, { from: offset + 1, to: Math.min(offset + rows.length, total), total });\n previous.disabled = offset === 0;\n next.disabled = offset + pageSize >= total;\n }\n\n function drawSort() {\n for (const th of headers) {\n const order = sort[0]?.field === th.dataset['field'] ? sort[0] : null;\n if (order) th.setAttribute('aria-sort', order.desc ? 'descending' : 'ascending');\n else th.removeAttribute('aria-sort');\n }\n }\n\n // ---- asking for the records ------------------------------------------------------\n\n /** Rows came or went: what is chosen keeps to the records on show. */\n function changed() {\n const shown = new Set(visible().map((record) => record.id));\n for (const id of [...chosen]) if (!shown.has(id)) chosen.delete(id);\n drawChoice();\n }\n\n const grouped = (source: DataSource): GroupContext => ({\n page,\n el,\n labels,\n fill,\n dataSource: source,\n model,\n fields,\n columns: node.columns.length + 1,\n pageSize,\n sort: () => sort,\n recordRow: row,\n changed,\n });\n\n async function load(): Promise<void> {\n const mine = ++asking;\n drawSort();\n table.setAttribute('aria-busy', 'true');\n let drawn: HTMLTableRowElement[] = [];\n try {\n const filter = facetsToFilter(facets, node);\n const grouping = groupByFields(facets);\n const source = context.dataSource;\n if (grouping.length && source?.groups && source.list) {\n // Grouped: a row for each value of the first field, each opening into the rest.\n const groups = await source.groups({ model, field: grouping[0], filter });\n if (mine !== asking || destroyed) return;\n rows = [];\n total = 0;\n drawn = groups.map((group) => groupRow(grouped(source), group, 0, filter, grouping));\n } else {\n const answer = source?.list ? await source.list({ model, fields, filter, sort, offset, limit: pageSize }) : { records: [], total: 0 };\n if (mine !== asking || destroyed) return;\n // Past the end, as when the last record of the last page went: back to the page that is left.\n if (!answer.records.length && answer.total > 0 && offset > 0) {\n offset = Math.floor((answer.total - 1) / pageSize) * pageSize;\n return load();\n }\n rows = answer.records;\n total = answer.total;\n drawn = rows.map((record) => row(record));\n }\n failed.hidden = true;\n } catch {\n if (mine !== asking || destroyed) return;\n rows = [];\n total = 0;\n failed.hidden = false;\n }\n body.replaceChildren(...drawn);\n empty.hidden = drawn.length > 0 || !failed.hidden;\n table.removeAttribute('aria-busy');\n drawPager();\n changed();\n }\n\n const search = searchBar({\n page,\n node,\n doc,\n el,\n labels,\n fill,\n uid: context.uid,\n icons: context.icons,\n preferences: context.preferences,\n facets,\n onChange(next) {\n facets = next;\n offset = 0;\n void load();\n },\n });\n const element = el(\n 'div',\n { class: 'fd-list', 'data-node': node.id },\n el('div', { class: 'fd-list-bar' }, search.element, pager),\n selection,\n el('div', { class: 'fd-list-scroll' }, table),\n empty,\n failed\n );\n void load();\n\n return {\n element,\n reload: load,\n destroy() {\n destroyed = true;\n search.destroy();\n },\n };\n}\n", "import type { Locale } from '@fieldia/core';\n\n/** Every word the viewer shows, so a page can be translated. `{n}`, `{total}` and `{time}` are filled in. */\nexport interface ViewerLabels {\n save: string;\n /** Switching a read-only form to editing, and back. */\n edit: string;\n done: string;\n discard: string;\n saving: string;\n saved: string;\n submit: string;\n next: string;\n back: string;\n /** Passing over an optional step. */\n skip: string;\n /** The list of a wizard's steps, for screen readers. */\n steps: string;\n stepOf: string;\n submitted: string;\n submitAnother: string;\n draftFound: string;\n restore: string;\n discardDraft: string;\n ok: string;\n cancel: string;\n loading: string;\n /** A form in a dialog: the button that saves it and closes the dialog, and the \u00D7 that closes it. */\n saveClose: string;\n close: string;\n /** The \u00D7 on an alert that may be dismissed. */\n dismiss: string;\n /** Saving again after a save failed. */\n retry: string;\n notSaved: string;\n notSent: string;\n /** What was not saved or sent, and the fields to look at. */\n checkFields: string;\n /** The banner when the server cannot be reached. */\n offline: string;\n /** A list: its pages (`{from}`, `{to}`, `{total}`), what is chosen in it, and an empty one. */\n previousPage: string;\n nextPage: string;\n range: string;\n selected: string;\n clearSelection: string;\n selectAll: string;\n selectRecord: string;\n noRecords: string;\n loadFailed: string;\n /**\n * A list's search bar: the box (`{field}` and `{text}` in a suggestion), its\n * chips (`{label}`), the Filters, Group By and Favourites menu (`{name}`),\n * and the conditions a custom filter offers.\n */\n search: string;\n searchLabel: string;\n searchFor: string;\n searchOptions: string;\n filters: string;\n groupBy: string;\n favourites: string;\n or: string;\n removeFacet: string;\n addCustomFilter: string;\n field: string;\n condition: string;\n value: string;\n apply: string;\n saveSearch: string;\n searchName: string;\n useByDefault: string;\n deleteFavourite: string;\n noFavourites: string;\n opIs: string;\n opIsNot: string;\n opContains: string;\n opGreater: string;\n opLess: string;\n opSet: string;\n opNotSet: string;\n yes: string;\n no: string;\n /** A list's groups: the one of records with no value, and the rest of a group's records (`{n}`). */\n none: string;\n loadMore: string;\n}\n\nexport const VIEWER_LABELS: Record<Locale, ViewerLabels> = {\n en: {\n save: 'Save',\n edit: 'Edit',\n done: 'Done',\n discard: 'Discard',\n saving: 'Saving\u2026',\n saved: 'Saved',\n submit: 'Submit',\n next: 'Next',\n back: 'Back',\n skip: 'Skip',\n steps: 'Steps',\n stepOf: 'Step {n} of {total}',\n submitted: 'Thank you. Your answers were sent.',\n submitAnother: 'Submit another response',\n draftFound: 'You have unsaved answers from {time}.',\n restore: 'Restore',\n discardDraft: 'Discard',\n ok: 'OK',\n cancel: 'Cancel',\n loading: 'Loading\u2026',\n saveClose: 'Save & Close',\n close: 'Close',\n dismiss: 'Dismiss',\n retry: 'Retry',\n notSaved: 'Not saved',\n notSent: 'Not sent',\n checkFields: '{what}. Check: {fields}',\n offline: 'Could not reach the server. Your changes are still here.',\n previousPage: 'Previous page',\n nextPage: 'Next page',\n range: '{from}\u2013{to} / {total}',\n selected: '{n} selected',\n clearSelection: 'Clear',\n selectAll: 'Select all',\n selectRecord: 'Select {name}',\n noRecords: 'No records match.',\n loadFailed: 'Could not load the records.',\n search: 'Search\u2026',\n searchLabel: 'Search',\n searchFor: 'Search {field} for: {text}',\n searchOptions: 'Search options',\n filters: 'Filters',\n groupBy: 'Group By',\n favourites: 'Favourites',\n or: 'or',\n removeFacet: 'Remove {label}',\n addCustomFilter: 'Add a custom filter',\n field: 'Field',\n condition: 'Condition',\n value: 'Value',\n apply: 'Apply',\n saveSearch: 'Save current search',\n searchName: 'Name of the search',\n useByDefault: 'Use by default',\n deleteFavourite: 'Delete {name}',\n noFavourites: 'No saved searches yet.',\n opIs: 'is',\n opIsNot: 'is not',\n opContains: 'contains',\n opGreater: 'greater than',\n opLess: 'less than',\n opSet: 'is set',\n opNotSet: 'is not set',\n yes: 'Yes',\n no: 'No',\n none: 'None',\n loadMore: 'Show {n} more',\n },\n ar: {\n save: '\u062D\u0641\u0638',\n edit: '\u062A\u0639\u062F\u064A\u0644',\n done: '\u062A\u0645',\n discard: '\u062A\u062C\u0627\u0647\u0644',\n saving: '\u062C\u0627\u0631\u064D \u0627\u0644\u062D\u0641\u0638\u2026',\n saved: '\u062A\u0645 \u0627\u0644\u062D\u0641\u0638',\n submit: '\u0625\u0631\u0633\u0627\u0644',\n next: '\u0627\u0644\u062A\u0627\u0644\u064A',\n back: '\u0631\u062C\u0648\u0639',\n skip: '\u062A\u062E\u0637\u064D\u0651',\n steps: '\u0627\u0644\u062E\u0637\u0648\u0627\u062A',\n stepOf: '\u0627\u0644\u062E\u0637\u0648\u0629 {n} \u0645\u0646 {total}',\n submitted: '\u0634\u0643\u0631\u064B\u0627 \u0644\u0643. \u062A\u0645 \u0625\u0631\u0633\u0627\u0644 \u0625\u062C\u0627\u0628\u0627\u062A\u0643.',\n submitAnother: '\u0625\u0631\u0633\u0627\u0644 \u0625\u062C\u0627\u0628\u0629 \u0623\u062E\u0631\u0649',\n draftFound: '\u0644\u062F\u064A\u0643 \u0625\u062C\u0627\u0628\u0627\u062A \u063A\u064A\u0631 \u0645\u062D\u0641\u0648\u0638\u0629 \u0645\u0646 {time}.',\n restore: '\u0627\u0633\u062A\u0639\u0627\u062F\u0629',\n discardDraft: '\u062A\u062C\u0627\u0647\u0644',\n ok: '\u0645\u0648\u0627\u0641\u0642',\n cancel: '\u0625\u0644\u063A\u0627\u0621',\n loading: '\u062C\u0627\u0631\u064D \u0627\u0644\u062A\u062D\u0645\u064A\u0644\u2026',\n saveClose: '\u062D\u0641\u0638 \u0648\u0625\u063A\u0644\u0627\u0642',\n close: '\u0625\u063A\u0644\u0627\u0642',\n dismiss: '\u0625\u062E\u0641\u0627\u0621',\n retry: '\u0623\u0639\u062F \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629',\n notSaved: '\u0644\u0645 \u064A\u064F\u062D\u0641\u0638',\n notSent: '\u0644\u0645 \u064A\u064F\u0631\u0633\u0644',\n checkFields: '{what}. \u0631\u0627\u062C\u0650\u0639: {fields}',\n offline: '\u062A\u0639\u0630\u0651\u0631 \u0627\u0644\u0648\u0635\u0648\u0644 \u0625\u0644\u0649 \u0627\u0644\u062E\u0627\u062F\u0645. \u062A\u0639\u062F\u064A\u0644\u0627\u062A\u0643 \u0645\u0627 \u0632\u0627\u0644\u062A \u0647\u0646\u0627.',\n previousPage: '\u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u0633\u0627\u0628\u0642\u0629',\n nextPage: '\u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u062A\u0627\u0644\u064A\u0629',\n range: '{from}\u2013{to} \u0645\u0646 {total}',\n selected: '\u062A\u0645 \u062A\u062D\u062F\u064A\u062F {n}',\n clearSelection: '\u0625\u0644\u063A\u0627\u0621 \u0627\u0644\u062A\u062D\u062F\u064A\u062F',\n selectAll: '\u062A\u062D\u062F\u064A\u062F \u0627\u0644\u0643\u0644',\n selectRecord: '\u062A\u062D\u062F\u064A\u062F {name}',\n noRecords: '\u0644\u0627 \u062A\u0648\u062C\u062F \u0633\u062C\u0644\u0627\u062A \u0645\u0637\u0627\u0628\u0642\u0629.',\n loadFailed: '\u062A\u0639\u0630\u0651\u0631 \u062A\u062D\u0645\u064A\u0644 \u0627\u0644\u0633\u062C\u0644\u0627\u062A.',\n search: '\u0628\u062D\u062B\u2026',\n searchLabel: '\u0628\u062D\u062B',\n searchFor: '\u0627\u0628\u062D\u062B \u0641\u064A {field} \u0639\u0646: {text}',\n searchOptions: '\u062E\u064A\u0627\u0631\u0627\u062A \u0627\u0644\u0628\u062D\u062B',\n filters: '\u0639\u0648\u0627\u0645\u0644 \u0627\u0644\u062A\u0635\u0641\u064A\u0629',\n groupBy: '\u062A\u062C\u0645\u064A\u0639 \u062D\u0633\u0628',\n favourites: '\u0627\u0644\u0645\u0641\u0636\u0644\u0629',\n or: '\u0623\u0648',\n removeFacet: '\u0625\u0632\u0627\u0644\u0629 {label}',\n addCustomFilter: '\u0625\u0636\u0627\u0641\u0629 \u0639\u0627\u0645\u0644 \u062A\u0635\u0641\u064A\u0629 \u0645\u062E\u0635\u0635',\n field: '\u0627\u0644\u062D\u0642\u0644',\n condition: '\u0627\u0644\u0634\u0631\u0637',\n value: '\u0627\u0644\u0642\u064A\u0645\u0629',\n apply: '\u062A\u0637\u0628\u064A\u0642',\n saveSearch: '\u062D\u0641\u0638 \u0627\u0644\u0628\u062D\u062B \u0627\u0644\u062D\u0627\u0644\u064A',\n searchName: '\u0627\u0633\u0645 \u0627\u0644\u0628\u062D\u062B',\n useByDefault: '\u0627\u0633\u062A\u062E\u062F\u0627\u0645\u0647 \u0627\u0641\u062A\u0631\u0627\u0636\u064A\u064B\u0627',\n deleteFavourite: '\u062D\u0630\u0641 {name}',\n noFavourites: '\u0644\u0627 \u062A\u0648\u062C\u062F \u0639\u0645\u0644\u064A\u0627\u062A \u0628\u062D\u062B \u0645\u062D\u0641\u0648\u0638\u0629 \u0628\u0639\u062F.',\n opIs: '\u064A\u0633\u0627\u0648\u064A',\n opIsNot: '\u0644\u0627 \u064A\u0633\u0627\u0648\u064A',\n opContains: '\u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649',\n opGreater: '\u0623\u0643\u0628\u0631 \u0645\u0646',\n opLess: '\u0623\u0635\u063A\u0631 \u0645\u0646',\n opSet: '\u0645\u062D\u062F\u062F',\n opNotSet: '\u063A\u064A\u0631 \u0645\u062D\u062F\u062F',\n yes: '\u0646\u0639\u0645',\n no: '\u0644\u0627',\n none: '\u0628\u0644\u0627 \u0642\u064A\u0645\u0629',\n loadMore: '\u0639\u0631\u0636 {n} \u0623\u062E\u0631\u0649',\n },\n de: {\n save: 'Speichern',\n edit: 'Bearbeiten',\n done: 'Fertig',\n discard: 'Verwerfen',\n saving: 'Wird gespeichert\u2026',\n saved: 'Gespeichert',\n submit: 'Absenden',\n next: 'Weiter',\n back: 'Zur\u00FCck',\n skip: '\u00DCberspringen',\n steps: 'Schritte',\n stepOf: 'Schritt {n} von {total}',\n submitted: 'Vielen Dank. Ihre Antworten wurden gesendet.',\n submitAnother: 'Weitere Antwort senden',\n draftFound: 'Sie haben ungespeicherte Antworten vom {time}.',\n restore: 'Wiederherstellen',\n discardDraft: 'Verwerfen',\n ok: 'OK',\n cancel: 'Abbrechen',\n loading: 'Wird geladen\u2026',\n saveClose: 'Speichern und schlie\u00DFen',\n close: 'Schlie\u00DFen',\n dismiss: 'Ausblenden',\n retry: 'Erneut versuchen',\n notSaved: 'Nicht gespeichert',\n notSent: 'Nicht gesendet',\n checkFields: '{what}. Bitte pr\u00FCfen: {fields}',\n offline: 'Der Server ist nicht erreichbar. Ihre \u00C4nderungen sind noch da.',\n previousPage: 'Vorherige Seite',\n nextPage: 'N\u00E4chste Seite',\n range: '{from}\u2013{to} / {total}',\n selected: '{n} ausgew\u00E4hlt',\n clearSelection: 'Auswahl aufheben',\n selectAll: 'Alle ausw\u00E4hlen',\n selectRecord: '{name} ausw\u00E4hlen',\n noRecords: 'Keine passenden Eintr\u00E4ge.',\n loadFailed: 'Die Eintr\u00E4ge konnten nicht geladen werden.',\n search: 'Suchen\u2026',\n searchLabel: 'Suchen',\n searchFor: '{field} durchsuchen nach: {text}',\n searchOptions: 'Suchoptionen',\n filters: 'Filter',\n groupBy: 'Gruppieren nach',\n favourites: 'Favoriten',\n or: 'oder',\n removeFacet: '{label} entfernen',\n addCustomFilter: 'Eigenen Filter hinzuf\u00FCgen',\n field: 'Feld',\n condition: 'Bedingung',\n value: 'Wert',\n apply: 'Anwenden',\n saveSearch: 'Aktuelle Suche speichern',\n searchName: 'Name der Suche',\n useByDefault: 'Standardm\u00E4\u00DFig verwenden',\n deleteFavourite: '{name} l\u00F6schen',\n noFavourites: 'Noch keine gespeicherten Suchen.',\n opIs: 'ist',\n opIsNot: 'ist nicht',\n opContains: 'enth\u00E4lt',\n opGreater: 'gr\u00F6\u00DFer als',\n opLess: 'kleiner als',\n opSet: 'ist gesetzt',\n opNotSet: 'ist nicht gesetzt',\n yes: 'Ja',\n no: 'Nein',\n none: 'Ohne Angabe',\n loadMore: '{n} weitere anzeigen',\n },\n fr: {\n save: 'Enregistrer',\n edit: 'Modifier',\n done: 'Termin\u00E9',\n discard: 'Annuler les modifications',\n saving: 'Enregistrement\u2026',\n saved: 'Enregistr\u00E9',\n submit: 'Envoyer',\n next: 'Suivant',\n back: 'Retour',\n skip: 'Passer',\n steps: '\u00C9tapes',\n stepOf: '\u00C9tape {n} sur {total}',\n submitted: 'Merci. Vos r\u00E9ponses ont \u00E9t\u00E9 envoy\u00E9es.',\n submitAnother: 'Envoyer une autre r\u00E9ponse',\n draftFound: 'Vous avez des r\u00E9ponses non enregistr\u00E9es du {time}.',\n restore: 'Restaurer',\n discardDraft: 'Ignorer',\n ok: 'OK',\n cancel: 'Annuler',\n loading: 'Chargement\u2026',\n saveClose: 'Enregistrer et fermer',\n close: 'Fermer',\n dismiss: 'Masquer',\n retry: 'R\u00E9essayer',\n notSaved: 'Non enregistr\u00E9',\n notSent: 'Non envoy\u00E9',\n checkFields: '{what}. \u00C0 v\u00E9rifier : {fields}',\n offline: 'Le serveur est injoignable. Vos modifications sont toujours l\u00E0.',\n previousPage: 'Page pr\u00E9c\u00E9dente',\n nextPage: 'Page suivante',\n range: '{from}\u2013{to} / {total}',\n selected: '{n} s\u00E9lectionn\u00E9(s)',\n clearSelection: 'D\u00E9s\u00E9lectionner',\n selectAll: 'Tout s\u00E9lectionner',\n selectRecord: 'S\u00E9lectionner {name}',\n noRecords: 'Aucun enregistrement ne correspond.',\n loadFailed: 'Impossible de charger les enregistrements.',\n search: 'Rechercher\u2026',\n searchLabel: 'Rechercher',\n searchFor: 'Rechercher {field} : {text}',\n searchOptions: 'Options de recherche',\n filters: 'Filtres',\n groupBy: 'Regrouper par',\n favourites: 'Favoris',\n or: 'ou',\n removeFacet: 'Retirer {label}',\n addCustomFilter: 'Ajouter un filtre personnalis\u00E9',\n field: 'Champ',\n condition: 'Condition',\n value: 'Valeur',\n apply: 'Appliquer',\n saveSearch: 'Enregistrer la recherche',\n searchName: 'Nom de la recherche',\n useByDefault: 'Utiliser par d\u00E9faut',\n deleteFavourite: 'Supprimer {name}',\n noFavourites: 'Aucune recherche enregistr\u00E9e.',\n opIs: 'est',\n opIsNot: 'n\u2019est pas',\n opContains: 'contient',\n opGreater: 'sup\u00E9rieur \u00E0',\n opLess: 'inf\u00E9rieur \u00E0',\n opSet: 'est d\u00E9fini',\n opNotSet: 'n\u2019est pas d\u00E9fini',\n yes: 'Oui',\n no: 'Non',\n none: 'Aucun',\n loadMore: 'Afficher {n} de plus',\n },\n};\n\n/** English, kept under its old name. */\nexport const DEFAULT_LABELS: ViewerLabels = VIEWER_LABELS.en;\n", "import {\n createForm,\n checkPage,\n translatePage,\n wideColumns,\n type ButtonNode,\n type FieldNode,\n type Form,\n type FormOptions,\n type FormState,\n type JsonValue,\n type LayoutNode,\n type Page,\n type RecordId,\n type SectionNode,\n type SheetNode,\n type SlotNode,\n type TabsNode,\n type TextNode,\n type WizardNode,\n type Locale,\n MESSAGES,\n} from '@fieldia/core';\nimport { browserPreferences, createWidget, drawIcon, installStyles, WIDGET_LABELS, type IconSet, type PreferenceStore, type WidgetFactory } from '@fieldia/widgets';\nimport { pageDialogs } from './related';\nimport { listView } from './list';\n\nexport type Skin = 'underline' | 'outlined';\n\nimport { VIEWER_LABELS, type ViewerLabels } from './labels';\nexport { VIEWER_LABELS, DEFAULT_LABELS, type ViewerLabels } from './labels';\n\n/** Fill a slot with the app's own content. Return a function to clean up. */\nexport type SlotRenderer = (element: HTMLElement, context: { form: Form; name: string }) => void | (() => void);\n\nexport interface ViewerOptions extends Omit<FormOptions, 'page'> {\n page: Page;\n /** A form made elsewhere, to share one record between two views. */\n form?: Form;\n skin?: Skin;\n /** Widgets that replace or add to the built-in ones, by `type` or `type.widget`. */\n widgets?: Record<string, WidgetFactory>;\n slots?: Record<string, SlotRenderer>;\n /** The page's language: viewer labels, validation messages and widget words. Arabic runs right to left. */\n locale?: Locale;\n /** Labels that win over the language's defaults. */\n labels?: Partial<ViewerLabels>;\n dir?: 'ltr' | 'rtl';\n /** How to ask before a button with `confirm` runs. Defaults to a small dialog. */\n confirm?: (message: string) => Promise<boolean>;\n /** Where a person's choices about the page's look are kept, such as a table's columns. The browser's storage by default. */\n preferences?: PreferenceStore;\n /** False when something around the page saves it, such as a dialog: the page's own Save, Discard and Submit stay hidden. */\n showActions?: boolean;\n /**\n * Pages for the models links point to, so a link can show its record in a\n * dialog: Create and edit\u2026, and the button that opens the linked record.\n */\n relatedPages?: Record<string, Page> | ((model: string) => Page | null | undefined);\n /**\n * The app's own icons, or replacements for Fieldia's, by the name a page\n * gives them: the inside of a 24\u00D724 SVG, drawn with lines in the text colour.\n */\n icons?: IconSet;\n /**\n * Keys around the fields. Ctrl+Enter (Cmd+Enter on a Mac) saves, from\n * wherever the cursor is, unless `saveWithCtrlEnter` is false. With\n * `enterMovesToNext`, Enter moves to the next field instead of sending the form.\n */\n keys?: { saveWithCtrlEnter?: boolean; enterMovesToNext?: boolean };\n /** A \u2713 by a field's label once someone has filled it in and it would pass its checks. */\n showValid?: boolean;\n /** Where a save's progress shows: beside Save (the default), as a toast in a corner, or as a bar across the top. */\n saveStatus?: 'inline' | 'toast' | 'bar';\n /** Show the whole form read-only: every field locked, no Save. Buttons still run. */\n readonly?: boolean;\n /** An Edit button that unlocks a read-only form, and a Done that saves and locks it again. */\n editSwitch?: boolean;\n /**\n * The app's own translator, for apps that keep translations by text or by\n * key: every word of the page goes through it. Record data never does.\n */\n translate?: (text: string) => string;\n /** A list page: a row was opened, by a click or by Enter. The app shows the record. */\n onOpenRecord?: (id: RecordId) => void;\n}\n\nexport interface ViewerHandle {\n readonly form: Form;\n readonly element: HTMLElement;\n setSkin(skin: Skin): void;\n /** Save the record, or take the focus to the first problem when the form refuses. */\n save(): Promise<boolean>;\n /** Check the form without saving, taking the focus to the first problem. */\n check(): boolean;\n /** Lock or unlock the whole form. */\n setReadonly(readonly: boolean): void;\n isReadonly(): boolean;\n destroy(): void;\n}\n\ntype Updater = (state: FormState) => void;\n\nlet mounts = 0;\n\n/**\n * Render a page into `host` and keep it in step with its form. Plain DOM: the\n * React, Angular and Vue bindings are thin shells around this function.\n * Throws when the page does not validate, listing every problem.\n */\nexport function mountViewer(host: HTMLElement, options: ViewerOptions): ViewerHandle {\n const doc = host.ownerDocument;\n // The quick check of names and conditions: the full one, with its validation library, belongs where pages are made.\n const checked = checkPage(options.page);\n if (!checked.ok) {\n throw new Error(`This page cannot be shown:\\n${checked.issues.map((i) => ` ${i.path}: ${i.message}`).join('\\n')}`);\n }\n const page = options.translate ? translatePage(checked.page, options.translate) : checked.page;\n const locale = options.locale ?? 'en';\n const preferences = options.preferences ?? browserPreferences();\n const dialogs = pageDialogs(options);\n const ownsForm = !options.form;\n const form = options.form ?? createForm({ ...options, page, messages: options.messages ?? MESSAGES[locale] });\n const labels: ViewerLabels = { ...VIEWER_LABELS[locale], ...options.labels };\n const widgetLabels = WIDGET_LABELS[locale];\n const dir = options.dir ?? (locale === 'ar' ? 'rtl' : undefined);\n const prefix = `fd${++mounts}`;\n const updaters: Updater[] = [];\n const cleanups: (() => void)[] = [];\n const uid = (id: string) => `${prefix}-${id.replace(/[^A-Za-z0-9_-]/g, '_')}`;\n const fill = (template: string, values: Record<string, string | number>) =>\n template.replace(/\\{(\\w+)\\}/g, (_, key: string) => String(values[key] ?? ''));\n\n installStyles(doc);\n\n function el<K extends keyof HTMLElementTagNameMap>(tag: K, attrs: Record<string, string | undefined> = {}, ...children: (Node | string)[]) {\n const node = doc.createElement(tag);\n for (const [name, value] of Object.entries(attrs)) if (value !== undefined) node.setAttribute(name, value);\n node.append(...children);\n return node;\n }\n\n /** Words with the icon a page names before them, when there is such an icon. */\n function withIcon(name: string | undefined, text: string): (Node | string)[] {\n const icon = drawIcon(doc, name, options.icons);\n return icon ? [icon, text] : [text];\n }\n\n const root = el('form', { class: 'fd-form', novalidate: '', 'data-fd-skin': options.skin ?? 'underline', dir, lang: options.locale, 'data-max-width': page.maxWidth });\n const confirm = options.confirm ?? dialogConfirm;\n\n // ---- the parts -------------------------------------------------------\n\n function fieldItem(node: FieldNode): HTMLElement {\n const def = page.fields[node.field];\n const id = uid(node.id);\n const wrapper = el('div', { class: 'fd-field', 'data-node': node.id, 'data-field': node.field, 'data-type': def.type });\n if (node.colspan) wrapper.style.setProperty('--fd-span', String(node.colspan));\n const label = el('label', { class: 'fd-label', id: `${id}-label`, for: id }, node.label ?? def.label);\n // The \u2713 of a field filled in right; never on a yes/no box, a table or a file, where it would say nothing.\n const mark = options.showValid && !NO_VALID_MARK.has(def.type) ? drawIcon(doc, 'check') : null;\n if (mark) {\n mark.classList.add('fd-valid-mark');\n label.append(mark);\n }\n const widget = createWidget({ form, name: node.field, field: def, node, id, document: doc, labels: widgetLabels, preferences, locale, dialogs }, options.widgets);\n if (!['INPUT', 'SELECT', 'TEXTAREA'].includes(widget.element.tagName)) {\n // `for` stays: a custom field that puts the id on its own input is\n // labelled natively. Only a wrapper with a role (a radio group, say) may\n // carry a name; ARIA forbids naming a plain div or span.\n if (widget.element.getAttribute('role')) widget.element.setAttribute('aria-labelledby', label.id);\n label.addEventListener('click', () => widget.focus());\n }\n const helpText = node.help ?? def.help;\n const help = helpText ? el('div', { class: 'fd-help', id: `${id}-help` }, helpText) : null;\n // Not an alert of its own: a refused save is announced once, naming every field to look at.\n const error = el('div', { class: 'fd-error', id: `${id}-error`, hidden: '' });\n // A warning from the data source's onchange, beside the field whose change brought it.\n const warning = el('div', { class: 'fd-warning', role: 'status', hidden: '' });\n wrapper.append(label, widget.element, ...(help ? [help] : []), error, warning);\n if (widget.destroy) cleanups.push(() => widget.destroy?.());\n\n updaters.push((state) => {\n const shown = form.node(node.id);\n wrapper.hidden = shown.invisible;\n wrapper.classList.toggle('fd-required', shown.required);\n const message = state.errors[node.field];\n error.hidden = !message;\n error.textContent = message ?? '';\n const warned = state.warning && state.warningField === node.field ? state.warning : '';\n warning.hidden = !warned;\n warning.textContent = warned;\n if (mark) {\n const value = state.values[node.field];\n const filled = value !== null && value !== undefined && value !== '' && !(Array.isArray(value) && !value.length);\n const valid = !shown.readonly && !message && filled && state.dirty.includes(node.field) && form.problem(node.field) === null;\n wrapper.classList.toggle('fd-valid', valid);\n mark.toggleAttribute('hidden', !valid);\n }\n widget.update({\n value: state.values[node.field],\n values: state.values,\n readonly: shown.readonly || locked,\n required: shown.required,\n invalid: !!message,\n describedBy: [help?.id, message ? error.id : undefined].filter(Boolean).join(' ') || undefined,\n });\n });\n return wrapper;\n }\n\n function hideWhen(element: HTMLElement, id: string) {\n updaters.push(() => {\n element.hidden = form.node(id).invisible;\n });\n }\n\n function buttonItem(node: ButtonNode): HTMLElement {\n const button = el('button', { type: 'button', class: `fd-button fd-button-${node.style ?? 'secondary'}`, 'data-node': node.id }, ...withIcon(node.icon, node.label));\n button.addEventListener('click', async () => {\n if (node.confirm && !(await confirm(node.confirm))) return;\n await form.runAction(node.id);\n });\n hideWhen(button, node.id);\n return button;\n }\n\n function textItem(node: TextNode): HTMLElement {\n const style = node.style ?? 'paragraph';\n const element = el(style === 'heading' ? 'h3' : 'p', { class: `fd-text-${style}`, 'data-node': node.id }, node.text);\n hideWhen(element, node.id);\n return element;\n }\n\n function slotItem(node: SlotNode): HTMLElement {\n const element = el('div', { class: 'fd-slot', 'data-slot': node.name, 'data-node': node.id });\n const cleanup = options.slots?.[node.name]?.(element, { form, name: node.name });\n if (cleanup) cleanups.push(cleanup);\n hideWhen(element, node.id);\n return element;\n }\n\n function grid(children: LayoutNode[], columns: SectionNode['columns'] = 1): HTMLElement {\n const box = el('div', { class: 'fd-grid' });\n box.style.setProperty('--fd-columns', String(wideColumns(columns)));\n // Counts given for the narrower widths replace the skin's own stacking there.\n if (typeof columns === 'object') {\n for (const width of ['medium', 'narrow'] as const) {\n const count = columns[width];\n if (count === undefined) continue;\n box.setAttribute(`data-columns-${width}`, String(count));\n box.style.setProperty(`--fd-columns-${width}`, String(count));\n }\n }\n box.append(...children.map(item));\n return box;\n }\n\n /** Folded sections, and how to open each: a problem inside one has to be seen. */\n const folds = new Map<HTMLElement, () => void>();\n\n function sectionItem(node: SectionNode): HTMLElement {\n const section = el('fieldset', { class: 'fd-section', 'data-node': node.id });\n const description = node.description ? el('p', { class: 'fd-section-description' }, node.description) : null;\n const content = grid(node.children, node.columns);\n if (node.title && node.collapsible) {\n content.id = uid(`${node.id}-content`);\n const toggle = el(\n 'button',\n { type: 'button', class: 'fd-section-toggle', 'aria-controls': content.id },\n el('span', { class: 'fd-section-chevron', 'aria-hidden': 'true' }),\n ...withIcon(node.icon, node.title)\n );\n let open = node.collapsed !== true;\n const show = (next: boolean) => {\n open = next;\n toggle.setAttribute('aria-expanded', String(open));\n content.hidden = !open;\n if (description) description.hidden = !open;\n section.classList.toggle('fd-section-folded', !open);\n };\n toggle.addEventListener('click', () => show(!open));\n folds.set(section, () => show(true));\n show(open);\n section.append(el('legend', { class: 'fd-section-title' }, toggle));\n } else if (node.title) {\n section.append(el('legend', { class: 'fd-section-title' }, ...withIcon(node.icon, node.title)));\n }\n if (description) section.append(description);\n section.append(content);\n hideWhen(section, node.id);\n return section;\n }\n\n function tabsItem(node: TabsNode): HTMLElement {\n const box = el('div', { class: 'fd-tabs', 'data-node': node.id });\n const list = el('div', { class: 'fd-tablist', role: 'tablist' });\n // The tab someone picked. Until they pick, the first visible tab is open \u2014\n // a tab hidden while the record loads must not leave its neighbour open.\n let picked: string | null = null;\n let active = node.children[0].id;\n const parts = node.children.map((tab) => {\n const tabId = uid(`${tab.id}-tab`);\n const panelId = uid(`${tab.id}-panel`);\n const button = el('button', { type: 'button', class: 'fd-tab', role: 'tab', id: tabId, 'aria-controls': panelId, 'data-node': tab.id }, ...withIcon(tab.icon, tab.label));\n const panel = el('div', { class: 'fd-tabpanel', role: 'tabpanel', id: panelId, 'aria-labelledby': tabId }, grid(tab.children));\n button.addEventListener('click', () => {\n picked = active = tab.id;\n render(form.getState());\n });\n list.append(button);\n return { tab, button, panel };\n });\n list.addEventListener('keydown', (event) => {\n const shown = parts.filter((p) => !p.button.hidden);\n const at = shown.findIndex((p) => p.tab.id === active);\n const move = { ArrowRight: 1, ArrowLeft: -1, Home: -at, End: shown.length - 1 - at }[event.key];\n if (move === undefined || at === -1) return;\n event.preventDefault();\n const rtl = root.getAttribute('dir') === 'rtl' && (event.key === 'ArrowRight' || event.key === 'ArrowLeft');\n const next = shown[(at + (rtl ? -move : move) + shown.length) % shown.length];\n picked = active = next.tab.id;\n render(form.getState());\n next.button.focus();\n });\n box.append(list, ...parts.map((p) => p.panel));\n updaters.push(() => {\n box.hidden = form.node(node.id).invisible;\n const shown = parts.filter((p) => !form.node(p.tab.id).invisible);\n const keep = picked !== null && shown.some((p) => p.tab.id === picked);\n if (keep) active = picked as string;\n else if (shown.length) active = shown[0].tab.id;\n for (const p of parts) {\n const selected = p.tab.id === active;\n p.button.hidden = !shown.includes(p);\n p.button.setAttribute('aria-selected', String(selected));\n p.button.tabIndex = selected ? 0 : -1;\n p.panel.hidden = !selected;\n }\n });\n return box;\n }\n\n function item(node: LayoutNode): HTMLElement {\n switch (node.type) {\n case 'field':\n return fieldItem(node);\n case 'button':\n return buttonItem(node);\n case 'text':\n return textItem(node);\n case 'slot':\n return slotItem(node);\n case 'section':\n return sectionItem(node);\n case 'tabs':\n return tabsItem(node);\n }\n }\n\n // ---- shared chrome ----------------------------------------------------------\n\n /** The whole form locked: every field read-only, no Save; buttons still run. */\n let locked = options.readonly === true;\n // Edit unlocks; Done saves what changed first, and locks only once that is saved.\n const editSwitch = options.editSwitch ? el('button', { type: 'button', class: 'fd-button fd-edit-switch' }) : null;\n editSwitch?.addEventListener('click', async () => {\n if (!locked) {\n if (form.getState().dirty.length) {\n const saved = await form.save();\n if (!saved) {\n if (!form.getState().saveProblem) announce(checkText(form.getState()));\n focusFirstProblem();\n return;\n }\n }\n locked = true;\n } else locked = false;\n root.toggleAttribute('data-readonly', locked);\n render(form.getState());\n });\n root.toggleAttribute('data-readonly', locked);\n updaters.push(() => {\n if (!editSwitch) return;\n editSwitch.textContent = locked ? labels.edit : labels.done;\n editSwitch.classList.toggle('fd-button-primary', locked);\n });\n\n // The status says its words alone, so a screen reader hears them; Retry sits beside it.\n const statusText = el('div', { class: 'fd-status', role: 'status', 'aria-live': 'polite' });\n const retry = el('button', { type: 'button', class: 'fd-button fd-button-link fd-retry', hidden: '' }, labels.retry);\n retry.addEventListener('click', () => void submitOrSave());\n const status = el('div', { class: 'fd-status-box' }, statusText, retry);\n const notDone = () => (page.data.kind === 'responses' ? labels.notSent : labels.notSaved);\n /** \"Not saved. Check: Email, Phone\": the fields with a problem, in the order they show. */\n function checkText(state: FormState): string {\n const names: string[] = [];\n for (const key of Object.keys(state.errors)) {\n const field = key.split('.')[0];\n const shown = root.querySelector(`.fd-field[data-field=\"${field}\"]:not([hidden]) > .fd-label`);\n const name = shown?.firstChild?.textContent ?? page.fields[field]?.label ?? field;\n if (!names.includes(name)) names.push(name);\n }\n const inOrder = [...root.querySelectorAll('.fd-field[data-field] > .fd-label')].map((label) => label.firstChild?.textContent ?? '');\n names.sort((a, b) => (inOrder.indexOf(a) + 1 || Infinity) - (inOrder.indexOf(b) + 1 || Infinity));\n return names.length ? fill(labels.checkFields, { what: notDone(), fields: names.join(', ') }) : notDone();\n }\n let quietTimer: ReturnType<typeof setTimeout> | undefined;\n updaters.push((state) => {\n const problem = state.saveProblem;\n const text =\n state.status === 'saving' ? labels.saving\n : state.status === 'saved' ? labels.saved\n : state.status === 'loading' ? labels.loading\n : state.status === 'error' && problem ? (problem.kind === 'fields' ? checkText(state) : problem.kind === 'other' ? problem.message : notDone())\n : state.status === 'error' ? state.error ?? ''\n : '';\n statusText.textContent = text;\n retry.hidden = !(state.status === 'error' && problem?.kind === 'other');\n statusText.classList.toggle('fd-status-error', state.status === 'error');\n statusText.classList.toggle('fd-status-saved', state.status === 'saved');\n // A toast shows while there is something to say, and lets \"Saved\" go after a moment.\n if (options.saveStatus === 'toast') {\n clearTimeout(quietTimer);\n status.hidden = !text;\n if (state.status === 'saved') quietTimer = setTimeout(() => (status.hidden = true), 2500);\n }\n });\n\n // A save the network failed: a banner over the page, with Retry.\n const bannerRetry = el('button', { type: 'button', class: 'fd-button fd-retry' }, labels.retry);\n bannerRetry.addEventListener('click', () => void submitOrSave());\n const banner = el('div', { class: 'fd-banner fd-tone-warning', role: 'alert', hidden: '' }, el('span', { class: 'fd-banner-text' }, labels.offline), bannerRetry);\n /** Said at once to a screen reader: why a save or send did not go through. */\n const announcer = el('div', { class: 'fd-announce', role: 'alert', 'aria-live': 'assertive' });\n function announce(text: string) {\n announcer.textContent = '';\n setTimeout(() => (announcer.textContent = text), 0);\n }\n // Each new reason a save was refused, from Save or from autosave, is shown where it belongs.\n let seenProblem: FormState['saveProblem'] = null;\n updaters.push((state) => {\n if (state.saveProblem === seenProblem) return;\n seenProblem = state.saveProblem;\n banner.hidden = seenProblem?.kind !== 'network';\n if (!seenProblem) return;\n if (seenProblem.kind === 'rule') void dialogConfirm(seenProblem.message, false);\n else if (seenProblem.kind === 'fields') announce(checkText(state));\n else if (seenProblem.kind === 'other') announce(seenProblem.message);\n });\n\n const draft = el('div', { class: 'fd-draft', hidden: '' });\n const draftText = el('span');\n const restore = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.restore);\n const discardDraft = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.discardDraft);\n restore.addEventListener('click', () => form.restoreDraft());\n discardDraft.addEventListener('click', () => form.discardDraft());\n draft.append(draftText, restore, discardDraft);\n updaters.push((state) => {\n draft.hidden = !state.draft;\n if (state.draft) draftText.textContent = fill(labels.draftFound, { time: new Date(state.draft.savedAt).toLocaleString() });\n });\n\n function focusFirstProblem() {\n const invalid = root.querySelector<HTMLElement>('[aria-invalid=\"true\"]');\n if (!invalid) return;\n for (let folded = invalid.closest<HTMLElement>('.fd-section-folded'); folded; folded = folded.parentElement?.closest<HTMLElement>('.fd-section-folded') ?? null) {\n folds.get(folded)?.();\n }\n // A widget that knows where its problem is (a cell of a grid) takes the focus there itself.\n if (!invalid.dispatchEvent(new CustomEvent('fd-focus-problem', { cancelable: true }))) return;\n const target = invalid.matches('input, select, textarea, button') ? invalid : invalid.querySelector<HTMLElement>('input, select, textarea, button');\n target?.focus();\n }\n\n const done = el('div', { class: 'fd-done', hidden: '' }, el('p', { class: 'fd-done-title' }, labels.submitted));\n const again = el('button', { type: 'button', class: 'fd-button' }, labels.submitAnother);\n done.append(again);\n const content = el('div', { class: 'fd-content' });\n\n async function submitOrSave() {\n const saved = await form.save();\n if (!saved) {\n // Stopped by the page's own checks: say which fields; a refused save says so above.\n if (!form.getState().saveProblem) announce(checkText(form.getState()));\n focusFirstProblem();\n return;\n }\n if (page.data.kind === 'responses') {\n content.hidden = true;\n done.hidden = false;\n }\n }\n again.addEventListener('click', () => {\n form.reset();\n content.hidden = false;\n done.hidden = true;\n });\n\n function pageHead(): HTMLElement | null {\n if (!page.title && !page.description) return null;\n const head = el('header', { class: 'fd-page-head' });\n if (page.title) head.append(el('h1', { class: 'fd-page-title' }, page.title));\n if (page.description) head.append(el('p', { class: 'fd-page-description' }, page.description));\n return head;\n }\n\n // ---- the four page layouts ---------------------------------------------------\n\n function sectionsLayout(node: { id: string; children: LayoutNode[] }): HTMLElement {\n const box = el('div', { class: 'fd-sections', 'data-node': node.id }, ...node.children.map(item));\n const action = el('button', { type: 'submit', class: 'fd-button fd-button-primary' }, page.data.kind === 'responses' ? labels.submit : labels.save);\n const actions = el('div', { class: 'fd-actions fd-actions-end' }, status, action);\n if (page.data.kind === 'record') {\n // A record offers Save and Discard once something changes, the same as on a sheet.\n const discard = el('button', { type: 'button', class: 'fd-button' }, labels.discard);\n discard.addEventListener('click', () => form.reset());\n actions.insertBefore(discard, action);\n updaters.push((state) => {\n const dirty = state.dirty.length > 0 && state.status !== 'saving' && !locked;\n action.hidden = !dirty;\n discard.hidden = !dirty;\n });\n } else updaters.push(() => (action.hidden = locked));\n if (editSwitch) actions.prepend(editSwitch);\n if (options.showActions === false) return el('div', {}, box);\n if (page.actionsPosition === 'top') {\n actions.classList.add('fd-actions-top');\n return el('div', {}, actions, box);\n }\n return el('div', {}, box, actions);\n }\n\n function wizardLayout(node: WizardNode): HTMLElement {\n const box = el('div', { class: 'fd-wizard', 'data-node': node.id });\n const progressText = el('div', { class: 'fd-progress-text' });\n const bar = el('span');\n box.append(el('div', { class: 'fd-progress' }, progressText, el('div', { class: 'fd-progress-bar' }, bar)));\n // A clickable wizard lists its steps: back to any, forward past those that are complete.\n const list = node.clickable ? el('ol', { class: 'fd-steps-list' }) : null;\n const stepButtons = new Map<string, HTMLButtonElement>();\n if (list) {\n for (const step of node.children) {\n const go = el('button', { type: 'button', class: 'fd-step-link' }, ...withIcon(step.icon, step.label));\n go.addEventListener('click', () => {\n if (form.goTo(step.id)) focusStep();\n else focusFirstProblem();\n });\n stepButtons.set(step.id, go);\n list.append(el('li', {}, go));\n }\n box.append(el('nav', { class: 'fd-steps', 'aria-label': labels.steps }, list));\n }\n const panels = node.children.map((step) => {\n const panel = el('section', { class: 'fd-step', 'data-node': step.id, 'aria-labelledby': uid(`${step.id}-title`) });\n panel.append(el('h2', { class: 'fd-step-title', id: uid(`${step.id}-title`) }, ...withIcon(step.icon, step.label)));\n if (step.description) panel.append(el('p', { class: 'fd-section-description' }, step.description));\n panel.append(grid(step.children));\n box.append(panel);\n return { step, panel };\n });\n const back = el('button', { type: 'button', class: 'fd-button' }, node.backLabel ?? labels.back);\n const skip = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.skip);\n const forward = el('button', { type: 'submit', class: 'fd-button fd-button-primary' });\n box.append(el('div', { class: 'fd-wizard-nav' }, back, el('span', { class: 'fd-spacer' }), status, skip, forward));\n back.addEventListener('click', () => {\n if (form.back()) focusStep();\n });\n skip.addEventListener('click', () => {\n if (form.skip()) focusStep();\n });\n const isLast = () => {\n const steps = form.steps();\n return steps.indexOf(form.getState().step ?? '') === steps.length - 1;\n };\n wizardForward = async () => {\n if (isLast()) return submitOrSave();\n if (form.next()) focusStep();\n else focusFirstProblem();\n };\n function focusStep() {\n const current = panels.find((p) => p.step.id === form.getState().step);\n current?.panel.querySelector<HTMLElement>('input, select, textarea, [role=radio]')?.focus();\n }\n updaters.push((state) => {\n const steps = form.steps();\n const index = Math.max(0, steps.indexOf(state.step ?? ''));\n progressText.textContent = fill(labels.stepOf, { n: index + 1, total: steps.length });\n bar.style.width = `${((index + 1) / Math.max(1, steps.length)) * 100}%`;\n for (const { step, panel } of panels) panel.hidden = step.id !== state.step;\n const last = index === steps.length - 1;\n back.hidden = index === 0;\n skip.hidden = last || !node.children.find((step) => step.id === state.step)?.optional;\n forward.textContent = last ? node.finishLabel ?? labels.submit : node.nextLabel ?? labels.next;\n for (const [id, go] of stepButtons) {\n const at = steps.indexOf(id);\n (go.parentElement as HTMLElement).hidden = at === -1;\n go.classList.toggle('fd-step-done', at !== -1 && at < index);\n go.classList.toggle('fd-step-skipped', state.skipped.includes(id));\n if (id === state.step) go.setAttribute('aria-current', 'step');\n else go.removeAttribute('aria-current');\n }\n });\n return box;\n }\n\n function sheetLayout(node: SheetNode): HTMLElement {\n const pageBox = el('div', { class: 'fd-sheet-page', 'data-node': node.id });\n const actions = el('div', { class: 'fd-actions' });\n const save = el('button', { type: 'submit', class: 'fd-button fd-button-primary' }, labels.save);\n const discard = el('button', { type: 'button', class: 'fd-button' }, labels.discard);\n discard.addEventListener('click', () => form.reset());\n // Save and Discard lead the header bar, or close the sheet when the page puts them at its foot.\n const atFoot = page.actionsPosition === 'bottom';\n const foot = el('div', { class: 'fd-actions fd-actions-end fd-sheet-foot' });\n if (options.showActions === false) actions.append(...(node.buttons ?? []).map(buttonItem));\n else if (atFoot) {\n actions.append(...(node.buttons ?? []).map(buttonItem));\n foot.append(status, discard, save);\n } else actions.append(save, discard, ...(node.buttons ?? []).map(buttonItem), status);\n // The Edit switch leads the header bar, before Save and the record's own buttons.\n if (editSwitch && options.showActions !== false) actions.prepend(editSwitch);\n updaters.push((state) => {\n const dirty = state.dirty.length > 0 && state.status !== 'saving' && !locked;\n save.hidden = !dirty;\n discard.hidden = !dirty;\n });\n const header = el('div', { class: 'fd-header' }, actions);\n const underTitle = node.statusbar?.position === 'title';\n if (node.statusbar && !underTitle) header.append(statusbar(node.statusbar));\n\n const card = el('div', { class: 'fd-card' });\n if (node.ribbon) {\n const ribbon = el('div', { class: `fd-ribbon fd-tone-${node.ribbon.tone ?? 'muted'}`, 'data-node': node.ribbon.id }, node.ribbon.label);\n hideWhen(ribbon, node.ribbon.id);\n // The ribbon is clipped to the card's corner by its own frame, so the card itself never clips: lists open past it.\n card.append(el('div', { class: 'fd-ribbon-frame' }, ribbon));\n }\n if (node.statButtons?.length) {\n const stats = el('div', { class: 'fd-stats' });\n for (const stat of node.statButtons) {\n const value = el('span', { class: 'fd-stat-value' });\n const icon = drawIcon(doc, stat.icon, options.icons);\n const words = el('span', { class: 'fd-stat-words' }, value, el('span', { class: 'fd-stat-label' }, stat.label));\n const button = el('button', { type: 'button', class: 'fd-stat', 'data-node': stat.id }, ...(icon ? [icon, words] : [words]));\n button.addEventListener('click', () => void form.runAction(stat.id));\n updaters.push((state) => {\n button.hidden = form.node(stat.id).invisible;\n const count = stat.field ? state.values[stat.field] : null;\n value.textContent = count === null || count === undefined ? '' : String(count);\n });\n stats.append(button);\n }\n card.append(stats);\n }\n for (const alert of node.alerts ?? []) {\n const box = el('div', { class: `fd-alert fd-tone-${alert.tone ?? 'info'}`, role: 'status', 'data-node': alert.id }, el('span', { class: 'fd-alert-message' }, alert.message));\n if (alert.dismissible) {\n // Closed, it stays closed while the page is open, whatever its condition does.\n let dismissed = false;\n const close = el('button', { type: 'button', class: 'fd-alert-close', 'aria-label': labels.dismiss }, '\u00D7');\n close.addEventListener('click', () => {\n dismissed = true;\n box.hidden = true;\n });\n box.append(close);\n updaters.push(() => {\n box.hidden = dismissed || form.node(alert.id).invisible;\n });\n } else hideWhen(box, alert.id);\n card.append(box);\n }\n if (node.badges?.length) {\n const badges = el('div', { class: 'fd-badges' });\n for (const badge of node.badges) {\n const chip = el('span', { class: `fd-badge fd-tone-${badge.tone ?? 'muted'}`, 'data-node': badge.id }, ...withIcon(badge.icon, badge.label));\n hideWhen(chip, badge.id);\n badges.append(chip);\n }\n updaters.push(() => {\n badges.hidden = [...badges.children].every((chip) => (chip as HTMLElement).hidden);\n });\n card.append(badges);\n }\n if (node.title) {\n const title = el('div', { class: 'fd-title' });\n if (node.title.above?.length) title.append(el('div', { class: 'fd-title-above' }, ...node.title.above.map(fieldItem)));\n title.append(fieldItem({ type: 'field', id: '#title', field: node.title.field, placeholder: node.title.placeholder }));\n if (node.title.subtitleField) title.append(fieldItem({ type: 'field', id: '#subtitle', field: node.title.subtitleField }));\n if (node.title.below?.length) title.append(el('div', { class: 'fd-title-below' }, ...node.title.below.map(fieldItem)));\n const row = el('div', { class: 'fd-title-row' }, title);\n if (node.title.avatarField) {\n const avatar = fieldItem({ type: 'field', id: '#avatar', field: node.title.avatarField });\n avatar.classList.add('fd-avatar');\n row.append(avatar);\n }\n card.append(row);\n }\n if (node.statusbar && underTitle) card.append(el('div', { class: 'fd-title-statusbar' }, statusbar(node.statusbar)));\n card.append(grid(node.children));\n if (atFoot && options.showActions !== false) {\n card.append(foot);\n updaters.push((state) => {\n foot.hidden = state.dirty.length === 0 && !statusText.textContent;\n });\n }\n\n const layout = el('div', { class: 'fd-sheet-layout' }, card);\n if (node.sidePanel) {\n layout.classList.add('fd-has-side');\n layout.append(el('aside', { class: 'fd-side' }, slotItem(node.sidePanel)));\n }\n pageBox.append(header, layout);\n return pageBox;\n }\n\n /** The sheet header's statusbar: the same widget a form can place anywhere. */\n function statusbar(config: NonNullable<SheetNode['statusbar']>): HTMLElement {\n const def = page.fields[config.field];\n const barOptions: { [key: string]: JsonValue } = { clickable: config.clickable === true };\n if (config.visibleStates) barOptions['visibleStates'] = config.visibleStates;\n const node: FieldNode = { type: 'field', id: '#statusbar', field: config.field, widget: 'statusbar', options: barOptions };\n const widget = createWidget(\n { form, name: config.field, field: def, node, id: uid('statusbar'), document: doc, labels: widgetLabels, preferences, locale, dialogs },\n options.widgets\n );\n updaters.push((state) =>\n widget.update({ value: state.values[config.field], values: state.values, readonly: form.node('#statusbar').readonly || locked, required: false, invalid: false })\n );\n return widget.element;\n }\n\n let wizardForward: (() => Promise<void>) | null = null;\n\n const layout = page.layout;\n let body: HTMLElement;\n if (layout.type === 'sheet') body = sheetLayout(layout);\n else if (layout.type === 'wizard') body = wizardLayout(layout);\n else if (layout.type === 'tabs') body = sectionsLayout({ id: `${layout.id}-page`, children: [layout] });\n else if (layout.type === 'list') {\n const list = listView({\n page,\n node: layout,\n form,\n dataSource: options.dataSource,\n doc,\n el,\n labels,\n locale,\n fill,\n confirm,\n withIcon,\n uid,\n icons: options.icons,\n preferences,\n onOpenRecord: options.onOpenRecord,\n });\n cleanups.push(list.destroy);\n body = list.element;\n }\n else body = sectionsLayout(layout);\n\n const head = layout.type === 'sheet' ? null : pageHead();\n content.append(...(head ? [head] : []), banner, draft, body);\n root.append(content, done, announcer);\n // The status leaves its place beside Save when the page wants it in a corner or across the top.\n if (options.saveStatus === 'toast') {\n status.classList.add('fd-toast');\n root.append(status);\n } else if (options.saveStatus === 'bar') {\n status.classList.add('fd-status-bar');\n content.prepend(status);\n }\n\n root.addEventListener('submit', (event) => {\n event.preventDefault();\n if (layout.type === 'list') return;\n if (wizardForward) void wizardForward();\n else void submitOrSave();\n });\n\n // ---- keys -------------------------------------------------------------------\n\n /** Text typed and not yet taken, such as a tag without its Enter, is taken now. */\n function commitTyping() {\n const active = doc.activeElement;\n if (active && root.contains(active) && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA')) {\n active.dispatchEvent(new Event('change', { bubbles: true }));\n }\n }\n\n /** The fields Enter can move between: on this page, shown, with a box to type or choose in, outside tables of lines. */\n function nextField(from: HTMLElement): HTMLElement | null {\n const fields = [...root.querySelectorAll<HTMLElement>('.fd-field')].filter(\n (field) => !field.closest('[hidden], [data-type=\"one2many\"] .fd-field, .fd-form-dialog') && !field.parentElement?.closest('[data-type=\"one2many\"]')\n );\n const here = from.closest('.fd-field');\n const after = fields.slice(fields.indexOf(here as HTMLElement) + 1);\n for (const field of after) {\n const control = field.querySelector<HTMLElement>('input:not([type=\"hidden\"]):not([readonly]):not([disabled]), select:not([disabled]), textarea:not([readonly]), [contenteditable=\"true\"]');\n if (control) return control;\n }\n return null;\n }\n\n root.addEventListener('keydown', (event) => {\n // A list has nothing to save, and its rows keep their own keys.\n if (event.isComposing || event.key !== 'Enter' || layout.type === 'list') return;\n // An app's own content in a slot, such as a chatter's composer, keeps its keys.\n if ((event.target as Element).closest('.fd-slot')) return;\n const keys = options.keys ?? {};\n if (event.ctrlKey || event.metaKey) {\n // Saves even after a field used the Enter (a tag box adding its tag); the grid keeps its own keys.\n if (keys.saveWithCtrlEnter === false || options.showActions === false) return;\n if ((event.target as Element).closest('.ag-root-wrapper')) return;\n event.preventDefault();\n commitTyping();\n if (wizardForward) void wizardForward();\n else void submitOrSave();\n return;\n }\n // A plain Enter a field used itself, such as picking from an open list, is the field's.\n if (event.defaultPrevented || !keys.enterMovesToNext || event.shiftKey || event.altKey) return;\n const from = event.target as HTMLElement;\n if (from.tagName !== 'INPUT' && from.tagName !== 'SELECT') return;\n if (from.closest('[data-type=\"one2many\"]')) return;\n if (['button', 'submit', 'reset', 'file'].includes((from as HTMLInputElement).type)) return;\n event.preventDefault();\n nextField(from)?.focus();\n });\n\n // ---- confirmation dialog -----------------------------------------------------\n\n /** A question with Cancel and OK, or with `withCancel` false a notice with OK alone. */\n function dialogConfirm(message: string, withCancel = true): Promise<boolean> {\n return new Promise((resolve) => {\n const text = el('p', { id: `${prefix}-confirm` }, message);\n const cancel = el('button', { type: 'button', class: 'fd-button' }, labels.cancel);\n const ok = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.ok);\n const dialog = el('div', { class: 'fd-dialog', role: 'alertdialog', 'aria-modal': 'true', 'aria-labelledby': text.id }, text, el('div', { class: 'fd-actions fd-actions-end' }, ...(withCancel ? [cancel, ok] : [ok])));\n const backdrop = el('div', { class: 'fd-dialog-backdrop' }, dialog);\n const close = (answer: boolean) => {\n backdrop.remove();\n resolve(answer);\n };\n cancel.addEventListener('click', () => close(false));\n ok.addEventListener('click', () => close(true));\n backdrop.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') close(false);\n });\n root.append(backdrop);\n ok.focus();\n });\n }\n\n // ---- go -------------------------------------------------------------------\n\n function render(state: FormState) {\n for (const update of updaters) update(state);\n }\n\n host.append(root);\n const unsubscribe = form.subscribe(render);\n render(form.getState());\n if (form.getState().status === 'idle') void form.load();\n\n return {\n form,\n element: root,\n setSkin(skin) {\n root.setAttribute('data-fd-skin', skin);\n },\n async save() {\n const saved = await form.save();\n if (!saved) focusFirstProblem();\n return saved;\n },\n check() {\n const valid = form.validate();\n if (!valid) focusFirstProblem();\n return valid;\n },\n setReadonly(readonly) {\n locked = readonly;\n root.toggleAttribute('data-readonly', locked);\n render(form.getState());\n },\n isReadonly: () => locked,\n destroy() {\n unsubscribe();\n for (const cleanup of cleanups) cleanup();\n root.remove();\n if (ownsForm) form.dispose();\n },\n };\n}\n\n/** Fields whose \u2713 would say nothing: a yes/no box is never wrong, a table or a file has its own look. */\nconst NO_VALID_MARK = new Set(['boolean', 'one2many', 'binary', 'image', 'html', 'json', 'properties']);\n"],
5
+ "mappings": "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",
6
6
  "names": ["script_entry_exports", "__export", "DEFAULT_LABELS", "FIELDIA_CSS", "FIELD_NAME", "FIELD_TYPES", "FORMAT_VERSION", "ICONS", "MESSAGES", "VERSION", "VIEWER_LABELS", "WIDGET_LABELS", "binaryWidget", "browserPreferences", "builtInWidgets", "charTagsWidget", "checkPage", "checkValue", "compileModifier", "createForm", "createMemoryDataSource", "createWidget", "displayValue", "drawIcon", "emptyValue", "evaluateModifier", "expressionContext", "facetsToFilter", "fill", "formatBytes", "formatNumber", "groupByFields", "hostScheduler", "htmlWidget", "imageWidget", "initialValues", "installStyles", "isEmpty", "isModifierValid", "isoWeek", "jsonWidget", "kindTextField", "labelWidget", "lineForm", "lineKind", "linesWidget", "linkAddress", "linkCheckboxesWidget", "many2oneWidget", "matchesFilter", "memoryPreferences", "mountViewer", "normalizeNumber", "openFormDialog", "openSearchDialog", "progressbarWidget", "propertiesWidget", "referenceWidget", "sanitizeHtml", "saveProblemOf", "saveRefused", "statusbarWidget", "suggestions", "summary", "tagsWidget", "translatePage", "wait", "wideColumns", "withCalendar", "FIELD_NAME", "FIELD_TYPES", "wideColumns", "columns", "FORMAT_VERSION", "evaluate", "ast", "context", "evaluateBinaryOp", "evaluateUnaryOp", "getNestedValue", "node", "left", "normalize", "right", "operator", "ordered", "truthy", "operand", "value", "obj", "path", "parts", "current", "part", "CONSTANTS", "tokenize", "expr", "tokens", "token", "space", "at", "match", "getTokenType", "text", "lowerText", "ExpressionParser", "tokens", "__publicField", "ast", "left", "operator", "right", "operand", "compOperators", "expr", "token", "CONSTANTS", "parseListLiteral", "type", "values", "operators", "lowerValue", "op", "value", "message", "listStr", "content", "elements", "current", "inString", "stringChar", "i", "char", "parseElement", "error", "element", "compileModifier", "modifier", "value", "ast", "ExpressionParser", "tokenize", "fieldsRead", "values", "truthy", "evaluate", "names", "visit", "node", "root", "has", "record", "key", "ReferenceCheck", "page", "__publicField", "path", "message", "id", "first", "name", "scope", "owner", "keys", "value", "fields", "compileModifier", "error", "base", "def", "currency", "walk", "item", "at", "inner", "i", "seen", "property", "sequence", "field", "kinds", "lineFields", "kindField", "which", "o", "text", "root", "step", "stepPath", "list", "order", "named", "filter", "j", "button", "children", "child", "node", "tab", "tabPath", "sheet", "visibleStates", "values", "state", "stat", "badge", "place", "alert", "column", "sub", "shown", "c", "isObject", "value", "LAYOUTS", "checkPage", "input", "issues", "say", "path", "message", "data", "fields", "name", "def", "FIELD_TYPES", "layout", "isList", "page", "found", "ReferenceCheck", "error", "TEXT_KEYS", "NOT_TEXT", "translatePage", "page", "translate", "walk", "value", "key", "item", "out", "name", "inner", "widgetOptions", "evaluateModifier", "expression", "context", "tokens", "tokenize", "ast", "ExpressionParser", "result", "evaluate", "truthy", "isModifierValid", "emptyValue", "field", "initialValues", "fields", "values", "name", "structuredCopy", "isEmpty", "_field", "value", "expressionContext", "context", "forExpressions", "record", "line", "ref", "lineKind", "kinds", "MESSAGES", "fill", "template", "values", "match", "name", "checkValue", "field", "value", "required", "messages", "MESSAGES", "label", "say", "key", "values", "fill", "isEmpty", "decimals", "checkDate", "checkDateTime", "allowed", "o", "listing", "v", "isRecord", "ref", "m", "models", "listOr", "article", "checkFile", "text", "dot", "y", "d", "realDay", "ISO_DATETIME", "match", "mo", "h", "mi", "part", "year", "month", "day", "lengths", "file", "isFile", "formatBytes", "pattern", "matchesType", "types", "describeType", "type", "items", "or", "phrase", "bytes", "units", "size", "unit", "saveRefused", "problem", "saveProblemOf", "error", "carried", "message", "matchesFilter", "values", "filter", "item", "holds", "inner", "meets", "isSet", "value", "condition", "raw", "actual", "expected", "text", "low", "high", "TEXT", "NUMBER", "LINK", "suggestions", "typed", "page", "list", "words", "text", "found", "field", "def", "say", "op", "value", "valueLabel", "label", "fill", "lower", "option", "number", "rank", "s", "type", "i", "a", "b", "facetsToFilter", "facets", "filter", "facet", "conditions", "v", "chosen", "id", "f", "items", "groupByFields", "hostScheduler", "callback", "ms", "handle", "wait", "scheduler", "resolve", "createMemoryDataSource", "options", "records", "structuredCopy", "responses", "calls", "lineIds", "pause", "wait", "table", "model", "labelOf", "id", "value", "nextId", "asId", "key", "applyLines", "current", "ops", "lines", "op", "l", "applyLinks", "links", "related", "r", "relationOf", "fields", "name", "field", "request", "stored", "rule", "warn", "result", "warning", "query", "values", "matchesFilter", "record", "matching", "a", "b", "order", "compared", "compareValues", "counted", "raw", "link", "group", "rows", "top", "blank", "v", "label", "x", "y", "createForm", "options", "page", "scheduler", "hostScheduler", "messages", "MESSAGES", "index", "indexLayout", "steps", "step", "draftKey", "state", "baseline", "initialValues", "structuredCopy", "serverErrors", "lineKeys", "onchangeSeq", "draftTimer", "autosaveTimer", "pending", "listeners", "contextCache", "set", "patch", "listener", "track", "promise", "done", "context", "expressionContext", "fieldDef", "name", "def", "dirtyFields", "values", "nodeState", "id", "node", "ctx", "invisible", "parent", "readonly", "visibleFieldNodes", "root", "inside", "at", "skipped", "collectErrors", "errors", "message", "checkValue", "line", "kind", "lineKind", "sub", "subDef", "lineMessage", "writeValues", "extra", "revalidateShown", "previous", "fresh", "kept", "key", "refused", "scheduleDraft", "drafts", "forgetDraft", "offerDraft", "raw", "draft", "scheduleAutosave", "autosave", "save", "runOnchange", "changed", "source", "seq", "request", "result", "afterEdit", "changes", "creating", "names", "isEmpty", "now", "before", "emptyValue", "lineOps", "linkOps", "shownValues", "shown", "error", "problem", "saveProblemOf", "fields", "creatable", "runCreate", "typed", "model", "runSearch", "query", "limit", "resolve", "item", "filter", "relation", "lineField", "field", "stepIndex", "optionalStep", "load", "loaded", "form", "value", "current", "numbers", "l", "n", "lines", "to", "sequence", "from", "target", "trusted", "i", "low", "high", "pool", "renumbered", "merged", "after", "subfield", "visible", "following", "chosen", "ops", "old", "had", "r", "has", "add", "modifiers", "compileModifier", "walk", "nodes", "tab", "button", "stat", "alert", "badge", "formats", "format", "locale", "decimals", "key", "found", "marks", "parts", "p", "formatNumber", "value", "normalizeNumber", "text", "group", "decimal", "out", "d", "WIDGET_LABELS", "DEBOUNCE_MS", "SHOWN", "fill", "template", "values", "match", "name", "combobox", "options", "doc", "id", "labels", "listId", "input", "list", "element", "shown", "creating", "creatingText", "extras", "editing", "results", "active", "seq", "timer", "readonly", "render", "record", "i", "option", "event", "choose", "empty", "open", "close", "index", "typed", "act", "picked", "lookUp", "query", "mine", "found", "reached", "held", "hidden", "kept", "overflow", "extra", "emptied", "text", "next", "creator", "form", "node", "many2oneWidget", "field", "document", "WIDGET_LABELS", "dialogs", "relation", "canOpen", "box", "choices", "limit", "current", "saved", "clear", "state", "tagsWidget", "chips", "records", "drawn", "key", "drawChips", "r", "remove", "chip", "button", "charTagsWidget", "separator", "suggestions", "s", "split", "t", "write", "tags", "add", "raw", "tag", "taken", "wanted", "parts", "part", "linkCheckboxesWidget", "boxes", "latest", "sync", "chosen", "now", "label", "referenceWidget", "context", "models", "select", "model", "value", "localDate", "text", "match", "y", "m", "d", "hh", "mm", "displayValue", "def", "value", "values", "locale", "number", "n", "digits", "formatNumber", "label", "v", "o", "currency", "amount", "date", "kindTextField", "def", "kind", "lineForm", "form", "field", "key", "values", "l", "name", "value", "query", "limit", "text", "linesWidget", "node", "id", "document", "labels", "WIDGET_LABELS", "locale", "dialogs", "kinds", "columns", "column", "element", "scroller", "table", "head", "headRow", "th", "lastTh", "body", "totals", "sums", "foot", "row", "i", "td", "adds", "addButton", "button", "focusNew", "rows", "readonly", "makeCell", "tr", "line", "sub", "span", "cellId", "subNode", "widget", "createWidget", "label", "error", "makeRow", "lineKind", "cells", "tools", "remove", "state", "current", "errors", "keep", "index", "cell", "message", "sum", "total", "displayValue", "read", "file", "resolve", "reject", "reader", "url", "fileWidget", "kind", "form", "name", "field", "id", "document", "labels", "WIDGET_LABELS", "element", "input", "accept", "preview", "pick", "pickText", "hint", "chosen", "fileName", "replace", "remove", "readonly", "take", "event", "state", "formatBytes", "src", "binaryWidget", "imageWidget", "percents", "percent", "value", "locale", "format", "progressbarWidget", "context", "node", "id", "document", "options", "min", "fixedMax", "maxField", "color", "showPercent", "bar", "fill", "text", "box", "element", "createWidget", "state", "max", "share", "rounded", "words", "value", "labelWidget", "field", "node", "id", "document", "locale", "options", "text", "key", "from", "decimals", "output", "values", "shown", "formatNumber", "summary", "prefixField", "suffixField", "prefix", "suffix", "part", "statusbarWidget", "form", "name", "field", "node", "id", "document", "options", "clickable", "visible", "list", "keyOf", "value", "steps", "o", "lookedUp", "last", "draw", "readonly", "currentKey", "shown", "s", "v", "step", "label", "inner", "item", "state", "records", "r", "isoWeek", "day", "yearStart", "pad", "n", "sameDay", "a", "b", "addDays", "d", "addMonths", "last", "dayOf", "kind", "value", "m", "withCalendar", "inner", "context", "form", "name", "id", "doc", "locale", "labels", "WIDGET_LABELS", "lang", "monthName", "dayName", "weekdayShort", "weekdayLong", "button", "svg", "icon", "tag", "attrs", "shape", "k", "v", "dialog", "head", "prev", "title", "next", "grid", "element", "focused", "readonly", "pick", "was", "at", "close", "draw", "focus", "chosen", "today", "label", "first", "start", "headRow", "weekHead", "i", "th", "thead", "tbody", "row", "tr", "week", "cell", "event", "onKey", "move", "to", "moves", "open", "outside", "state", "humanize", "name", "words", "guess", "value", "label", "propertiesWidget", "context", "form", "field", "node", "id", "document", "declared", "current", "properties", "property", "element", "rows", "drawn", "draw", "definitions", "row", "definition", "rowId", "propertyField", "propertyNode", "widget", "createWidget", "state", "values", "key", "ALLOWED", "DROPPED_WITH_CONTENT", "ALIGNABLE", "ALIGNMENTS", "sanitizeHtml", "html", "document", "box", "clean", "parent", "node", "element", "href", "align", "attribute", "out", "linkAddress", "typed", "text", "TOOLS", "htmlWidget", "form", "name", "id", "labels", "WIDGET_LABELS", "area", "withToolbar", "last", "toolbar", "formattingToolbar", "state", "doc", "bar", "lastRange", "restore", "selection", "run", "command", "value", "style", "key", "option", "linkRow", "address", "apply", "unlink", "url", "event", "buttons", "icon", "button", "stops", "stop", "i", "at", "rtl", "step", "next", "reflect", "block", "jsonWidget", "error", "parsed", "createWidget", "context", "registry", "field", "node", "keys", "key", "factory", "builtInWidgets", "pendingWidget", "make", "doc", "tag", "props", "children", "element", "name", "value", "describe", "state", "textOf", "textWidget", "inputType", "form", "id", "document", "input", "text", "textareaWidget", "area", "NUMBER", "UNFINISHED", "numberWidget", "locale", "integer", "decimals", "shown", "formatNumber", "parse", "raw", "normalizeNumber", "options", "currencyField", "currencyDef", "picker", "currency", "side", "after", "typing", "parsed", "showsSame", "holder", "checkboxWidget", "role", "box", "selectWidget", "choices", "select", "option", "i", "index", "choiceGroup", "kind", "group", "inputs", "chosen", "_", "pointsWidget", "style", "min", "max", "points", "n", "point", "event", "current", "step", "next", "p", "dateWidget", "widget", "withCalendar", "pad", "dateTimeWidget", "local", "iso", "d", "span", "summary", "record", "count", "charTagsWidget", "progressbarWidget", "labelWidget", "statusbarWidget", "many2oneWidget", "tagsWidget", "linkCheckboxesWidget", "referenceWidget", "linesWidget", "binaryWidget", "imageWidget", "htmlWidget", "jsonWidget", "propertiesWidget", "FIELDIA_CSS", "STYLE_ID", "installStyles", "document", "style", "browserPreferences", "storage", "area", "key", "text", "value", "memoryPreferences", "values", "structuredCloneSafe", "SVG", "ICONS", "drawIcon", "doc", "name", "own", "inside", "svg", "key", "value", "dialogs", "FOCUSABLE", "openFormDialog", "options", "doc", "container", "opener", "labels", "VIEWER_LABELS", "id", "make", "tag", "attrs", "text", "element", "name", "value", "title", "closeButton", "body", "discard", "saveClose", "box", "backdrop", "handle", "mountViewer", "done", "recalculate", "focusables", "firstField", "resolve", "close", "saved", "state", "result", "accepted", "event", "all", "first", "last", "form", "fields", "recompute", "closed", "seen", "writing", "values", "now", "next", "openSearchDialog", "words", "WIDGET_LABELS", "query", "list", "cancel", "head", "foot", "found", "active", "asked", "timer", "picked", "draw", "record", "i", "option", "look", "mine", "records", "nameFieldOf", "page", "def", "valuesPage", "fields", "title", "readonly", "shown", "name", "lookupsOf", "source", "request", "pageDialogs", "options", "pageFor", "model", "shared", "related", "nameField", "result", "openFormDialog", "openSearchDialog", "key", "page", "readFavourites", "preferences", "kept", "startingFacets", "node", "chosen", "favourite", "id", "f", "favouritesPart", "context", "el", "labels", "fill", "list", "none", "name", "byDefault", "save", "form", "open", "write", "favourites", "draw", "use", "remove", "named", "others", "groupName", "context", "field", "group", "def", "o", "closeUnder", "tr", "level", "next", "after", "groupRow", "within", "grouping", "el", "labels", "filter", "toggle", "opening", "open", "rows", "inner", "recordsFrom", "offset", "answer", "record", "left", "more", "moreRow", "opened", "LIST_STYLES", "installListStyles", "doc", "style", "TEXT", "LINK", "CHOICE", "NUMBER", "DATE", "conditionsFor", "def", "customFilterPart", "context", "page", "el", "labels", "fields", "field", "name", "condition", "valueBox", "apply", "form", "button", "value", "drawConditions", "op", "word", "drawValue", "current", "o", "type", "wanted", "shown", "text", "option", "facetText", "facet", "labels", "or", "v", "searchBar", "context", "page", "node", "doc", "el", "fill", "uid", "facets", "icon", "name", "drawn", "drawIcon", "change", "next", "drawChips", "drawPanel", "listId", "panelId", "input", "chips", "offeredList", "toggle", "offered", "active", "index", "text", "remove", "_", "i", "kind", "drawOffered", "suggestion", "option", "event", "pick", "closeOffered", "value", "at", "f", "suggestions", "heading", "iconName", "id", "toggleIn", "key", "now", "keys", "k", "field", "filterButtons", "filter", "button", "groupButtons", "custom", "customFilterPart", "favourites", "favouritesPart", "group", "title", "parts", "panel", "ids", "fields", "showPanel", "open", "element", "outside", "NUMBERS", "UNSORTABLE", "listView", "context", "page", "node", "form", "el", "labels", "fill", "locale", "doc", "installListStyles", "pageSize", "defaultSort", "sort", "offset", "total", "rows", "recordOf", "visible", "body", "tr", "model", "facets", "startingFacets", "chosen", "asking", "destroyed", "fields", "name", "def", "show", "values", "displayValue", "chooseAll", "headers", "th", "button", "desc", "order", "load", "table", "empty", "retry", "failed", "row", "record", "level", "box", "drawChoice", "event", "cell", "count", "clear", "buttons", "action", "selection", "shown", "onPage", "id", "range", "previous", "next", "pager", "drawPager", "drawSort", "changed", "grouped", "source", "mine", "drawn", "filter", "facetsToFilter", "grouping", "groupByFields", "groups", "group", "groupRow", "answer", "search", "searchBar", "element", "VIEWER_LABELS", "DEFAULT_LABELS", "mounts", "mountViewer", "host", "options", "doc", "checked", "checkPage", "i", "page", "translatePage", "locale", "preferences", "browserPreferences", "dialogs", "pageDialogs", "ownsForm", "form", "createForm", "MESSAGES", "labels", "VIEWER_LABELS", "widgetLabels", "WIDGET_LABELS", "dir", "prefix", "updaters", "cleanups", "uid", "id", "fill", "template", "values", "_", "key", "installStyles", "el", "tag", "attrs", "children", "node", "name", "value", "withIcon", "text", "icon", "drawIcon", "root", "confirm", "dialogConfirm", "fieldItem", "def", "wrapper", "label", "mark", "NO_VALID_MARK", "widget", "createWidget", "helpText", "help", "error", "warning", "state", "shown", "message", "warned", "filled", "valid", "locked", "hideWhen", "element", "buttonItem", "button", "textItem", "style", "slotItem", "cleanup", "grid", "columns", "box", "wideColumns", "width", "count", "item", "folds", "sectionItem", "section", "description", "content", "toggle", "open", "show", "next", "tabsItem", "list", "picked", "active", "parts", "tab", "tabId", "panelId", "panel", "render", "event", "p", "at", "move", "rtl", "selected", "editSwitch", "announce", "checkText", "focusFirstProblem", "statusText", "retry", "submitOrSave", "status", "notDone", "names", "field", "inOrder", "a", "b", "quietTimer", "problem", "bannerRetry", "banner", "announcer", "seenProblem", "draft", "draftText", "restore", "discardDraft", "invalid", "folded", "done", "again", "pageHead", "head", "sectionsLayout", "action", "actions", "discard", "dirty", "wizardLayout", "progressText", "bar", "stepButtons", "step", "go", "focusStep", "panels", "back", "skip", "forward", "isLast", "steps", "wizardForward", "index", "last", "sheetLayout", "pageBox", "save", "atFoot", "foot", "header", "underTitle", "statusbar", "card", "ribbon", "stats", "stat", "words", "alert", "dismissed", "close", "badges", "badge", "chip", "title", "row", "avatar", "layout", "config", "barOptions", "body", "listView", "commitTyping", "nextField", "from", "fields", "here", "after", "control", "keys", "withCancel", "resolve", "cancel", "ok", "dialog", "backdrop", "answer", "update", "unsubscribe", "skin", "saved", "readonly", "VERSION"]
7
7
  }