@loadbare/app 0.18.0 → 0.18.2

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.
@@ -35,8 +35,11 @@ export type Kind = typeof KIND_ROW | typeof KIND_ROWS;
35
35
  */
36
36
  export type RowsResult = Row[] | Patch;
37
37
  export declare function isPatch(result: RowsResult): result is Patch;
38
- /** What any one query answers with, as the application writes it. */
39
- export type HubResult = Row | RowsResult;
38
+ /**
39
+ * What any one query answers with, as the application writes it. A `row`
40
+ * query that finds no row answers `null`.
41
+ */
42
+ export type HubResult = Row | RowsResult | null;
40
43
  /**
41
44
  * What application code hands the engine: answers by query name. The engine
42
45
  * turns each into a response item, adding the kind and key the query
@@ -56,7 +59,7 @@ export interface ResponseItem {
56
59
  query: string;
57
60
  kind: Kind;
58
61
  key: string;
59
- row?: Row;
62
+ row?: Row | null;
60
63
  rows?: Row[];
61
64
  patch?: Patch;
62
65
  order?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"lb-types.d.ts","sourceRoot":"","sources":["../../core/lb-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lb-types.d.ts","sourceRoot":"","sources":["../../core/lb-types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"lb-types.js","sourceRoot":"","sources":["../../core/lb-types.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference lib=\"dom\" />\n\n// The wire vocabulary. Shared by browser and server.\n\nimport {\n COLUMN_TYPES,\n KIND_ROW,\n FILTER_OPERATORS,\n KIND_ROWS,\n LB_RESERVED_PREFIX,\n LB_ROW_REQUESTS,\n ORDER_DESCENDING,\n URL_COLUMN_PATH,\n} from \"./lb-constants.js\";\n\n/**\n * One row: its columns, by name.\n *\n * A value is whatever the server serialized. The hub knows nothing about its\n * type and enforces nothing: it hands each value to the browser untouched,\n * and the browser renders it as it sees fit. What a number, a date or a null\n * should look like is the application's decision, made in the query.\n */\nexport type Row = Record<string, unknown>;\n\n/**\n * Part of a `rows` query's answer — see docs/reference/server.md, \"Queries\".\n *\n * Rows named here are added or updated, keys in `drop` are removed, and\n * anything unnamed is left alone. The hub places what it names by the\n * query's order. Add and remove are one result rather than two because the\n * interesting cases are both at once — a row whose sort key changed has to\n * move, a swap is one out and one in — and two messages would paint the\n * intermediate state.\n */\nexport interface Patch {\n rows?: Row[];\n drop?: unknown[];\n}\n\n/** A type a `rows` query may declare for a column — see COLUMN_TYPES. */\nexport type ColumnType = (typeof COLUMN_TYPES)[number];\n\n/** The types a `rows` query declares for its columns, by column. */\nexport type ColumnTypes = Record<string, ColumnType>;\n\n/** A query's kind, declared by the server and carried by every answer. */\nexport type Kind = typeof KIND_ROW | typeof KIND_ROWS;\n\n/**\n * What a `rows` query answers with: all rows, or a patch. `Array.isArray`\n * tells the two apart. All rows arrive in the order the server chose, which\n * is the order they show in when the query declares none.\n */\nexport type RowsResult = Row[] | Patch;\n\nexport function isPatch(result: RowsResult): result is Patch {\n return !Array.isArray(result);\n}\n\n/** What any one query answers with, as the application writes it. */\nexport type HubResult = Row | RowsResult;\n\n/**\n * What application code hands the engine: answers by query name. The engine\n * turns each into a response item, adding the kind and key the query\n * declared.\n */\nexport type HubData = Record<string, HubResult>;\n\n/**\n * One query's answer on the wire: its name, its kind, its key's column name,\n * and exactly one of a row, all rows, or a patch. A patch answers a `rows`\n * query only.\n *\n * A `rows` query also carries the order and column types it declared, once,\n * on the answer that loads the page. The hub keeps them with the answer for\n * every answer after it.\n */\nexport interface ResponseItem {\n query: string;\n kind: Kind;\n key: string;\n row?: Row;\n rows?: Row[];\n patch?: Patch;\n order?: string;\n types?: ColumnTypes;\n}\n\n/** Every response the server sends: a page load and a request alike. */\nexport type HubResponse = ResponseItem[];\n\n/**\n * Every request has one shape. The name picks the handler; the rest is\n * present when the hub found it.\n */\nexport interface HubRequest {\n name: string;\n query?: string;\n key?: string;\n /**\n * The rows a request acts on together, by key: those the user selected,\n * for a request that names no one row. Never sent beside `key`.\n */\n keys?: string[];\n values?: Record<string, string>;\n /**\n * The rows of the queries nested in a form, by query name, each with the\n * values of its own controls: a set of rows gathered beside the form's\n * own values.\n */\n rows?: Record<string, GatheredRow[]>;\n}\n\n/** One nested row a form gathered: its key, and its controls' values. */\nexport interface GatheredRow {\n key: string;\n values: Record<string, string>;\n}\n\n/**\n * The detail of the `lb-request-done` event: the request as the hub\n * completed and sent it, and what came of it. `items` is every response\n * item that landed because of it, in the order it landed. `error` is set\n * when the request's own round trip failed, and then nothing landed.\n */\nexport interface HubRequestDone {\n request: HubRequest;\n items: ResponseItem[];\n error?: Error;\n /** Set beside `error` when the handler refused the request. */\n refusal?: HubRefusal;\n}\n\n/**\n * Why a handler refused a request, in words written for the user: a\n * message for the request as a whole, a message per column the request\n * gathered, or both. Sent with status 422; any other failure sends nothing.\n */\nexport interface HubRefusal {\n message?: string;\n columns?: Record<string, string>;\n}\n\n/** The fields a handler receives: the request, less its name. */\nexport type RequestFields = Omit<HubRequest, \"name\">;\n\n/** Whether a name is one of the requests Loadbare provides. */\nexport function isRowRequest(name: string): boolean {\n return (LB_ROW_REQUESTS as readonly string[]).includes(name);\n}\n\n/**\n * A query string with some parms set, and the rest as they were. An empty\n * value takes its parm out, since empty is every parm's default and a\n * default is left out of the URL.\n *\n * One rule on both sides of the wire: the hub applies it to the address bar,\n * and the server to the query string it loads the page at after a request\n * returned `lb-url`. The two must agree, or what the page shows would differ\n * from what the address bar says.\n */\nexport function withQueryParms(\n search: URLSearchParams,\n parms: Record<string, string>,\n): URLSearchParams {\n const next = new URLSearchParams(search);\n for (const [name, value] of Object.entries(parms)) {\n if (value === \"\") next.delete(name);\n else next.set(name, value);\n }\n return next;\n}\n\n/**\n * A path names a page by its stub, and nothing finer. The bare path resolves\n * to `index`, the same convention a static file server follows.\n */\nexport function pageNameFor(path: string): string {\n const name = path.replace(/^\\/+|\\/+$/g, \"\");\n return name === \"\" ? \"index\" : name;\n}\n\n/** One term of an order: a column, and whether it sorts descending. */\nexport interface OrderTerm {\n column: string;\n descending: boolean;\n}\n\n/**\n * An order's terms, from its text: columns separated by commas, each\n * descending when it begins with `-`. Throws on a term that names no column.\n * An empty text is no order.\n */\nexport function parseOrder(text: string): OrderTerm[] {\n if (text.trim() === \"\") return [];\n return text.split(\",\").map((raw) => {\n const term = raw.trim();\n const descending = term.startsWith(ORDER_DESCENDING);\n const column = descending ? term.slice(ORDER_DESCENDING.length) : term;\n if (column === \"\" || column.startsWith(ORDER_DESCENDING)) {\n throw new Error(`the order '${text}' has a term naming no column`);\n }\n return { column, descending };\n });\n}\n\n/** Strings compare as the user's language orders them. */\nconst collator = new Intl.Collator();\n\n/** How a value sorts among values of other types: by its JSON type. */\nfunction rank(value: unknown): number {\n switch (typeof value) {\n case \"boolean\":\n return 0;\n case \"number\":\n return 1;\n case \"string\":\n return 2;\n default:\n return 3;\n }\n}\n\n/**\n * Compare two column values, ascending.\n *\n * A value compares by its JSON type, and nothing is guessed: numbers\n * numerically, booleans false before true, strings as the user's language\n * orders them. A number that arrives as a string sorts as a string, so a\n * numeric sort column is sent as a JSON number. Null and a missing value\n * sort after everything, as Postgres sorts them ascending, and so first\n * descending.\n */\nexport function compareValues(a: unknown, b: unknown): number {\n const missingA = a === null || a === undefined;\n const missingB = b === null || b === undefined;\n if (missingA || missingB) return missingA === missingB ? 0 : missingA ? 1 : -1;\n const ra = rank(a);\n const rb = rank(b);\n if (ra !== rb) return ra - rb;\n if (typeof a === \"number\") return a - (b as number);\n if (typeof a === \"boolean\") return Number(a) - Number(b);\n if (typeof a === \"string\") return collator.compare(a, b as string);\n return collator.compare(JSON.stringify(a), JSON.stringify(b));\n}\n\n/**\n * A value read as a declared column type: a number for `number`, a boolean\n * for `boolean`, text for `text`. A value that is no value of its type reads\n * as missing, and compares as a null does. A column with no declared type\n * reads as it arrived.\n */\nexport function readAs(value: unknown, type: ColumnType | undefined): unknown {\n if (type === undefined || value === null || value === undefined) return value;\n switch (type) {\n case \"number\": {\n if (typeof value === \"number\") return value;\n if (typeof value !== \"string\" || value.trim() === \"\") return undefined;\n const n = Number(value);\n return Number.isNaN(n) ? undefined : n;\n }\n case \"boolean\":\n if (typeof value === \"boolean\") return value;\n return value === \"true\" ? true : value === \"false\" ? false : undefined;\n default:\n return typeof value === \"object\" ? JSON.stringify(value) : String(value);\n }\n}\n\n/** Compare two rows by an order's terms, each column read as its type. */\nexport function compareRows(\n a: Row,\n b: Row,\n terms: OrderTerm[],\n types: ColumnTypes = {},\n): number {\n for (const { column, descending } of terms) {\n const c = compareValues(\n readAs(a[column], types[column]),\n readAs(b[column], types[column]),\n );\n if (c !== 0) return descending ? -c : c;\n }\n return 0;\n}\n\n/** A filter's operator — see FILTER_OPERATORS. */\nexport type FilterOperator = (typeof FILTER_OPERATORS)[number];\n\n/** One term of a filter: an operator, and the value it compares with. */\nexport interface FilterTerm {\n operator: FilterOperator;\n value: string;\n}\n\n/** Where a filter's next term begins: whitespace before an operator. */\nconst NEXT_TERM = new RegExp(\n `\\\\s+(?=${FILTER_OPERATORS.map((op) => op.replace(/[$^*]/g, \"\\\\$&\")).join(\"|\")})`,\n);\n\n/**\n * A filter's terms, from its text: each an operator and the value after it,\n * a new term beginning wherever whitespace comes before an operator, so a\n * value may hold spaces. Text with no operator before it is `*=`. A term\n * with no value is not yet a term, and is left out, so a filter being typed\n * filters nothing until it says something. Nothing is evaluated.\n */\nexport function parseFilter(text: string): FilterTerm[] {\n const terms: FilterTerm[] = [];\n for (const raw of text.trim().split(NEXT_TERM)) {\n const operator =\n FILTER_OPERATORS.find((op) => raw.startsWith(op)) ?? \"*=\";\n const value = raw.slice(raw.startsWith(operator) ? operator.length : 0);\n if (value.trim() !== \"\") terms.push({ operator, value: value.trim() });\n }\n return terms;\n}\n\n/**\n * The filter's value as the column's own type, so a comparison is the one\n * the order makes: a number for a number, a boolean for a boolean, text for\n * anything else. Undefined when the text is no value of that type.\n */\nfunction asTypeOf(text: string, like: unknown): unknown {\n if (typeof like === \"number\") {\n const n = Number(text);\n return text.trim() === \"\" || Number.isNaN(n) ? undefined : n;\n }\n if (typeof like === \"boolean\") {\n return text === \"true\" ? true : text === \"false\" ? false : undefined;\n }\n return text;\n}\n\n/**\n * Whether a column's value passes one term.\n *\n * `^=`, `$=` and `*=` read the value as text, ignoring case: it begins with,\n * ends with or contains the term's value. The rest compare as the order\n * compares, with the column read as its declared type, if it has one, and\n * the term's value read as the column's type. A missing value, and one that\n * is no value of its declared type, passes only `!=`.\n */\nexport function passesTerm(\n value: unknown,\n { operator, value: text }: FilterTerm,\n type?: ColumnType,\n): boolean {\n if (value === null || value === undefined) return operator === \"!=\";\n if (operator === \"^=\" || operator === \"$=\" || operator === \"*=\") {\n const have = String(value).toLocaleLowerCase();\n const want = text.toLocaleLowerCase();\n if (operator === \"^=\") return have.startsWith(want);\n if (operator === \"$=\") return have.endsWith(want);\n return have.includes(want);\n }\n const read = readAs(value, type);\n const typed = read === undefined ? undefined : asTypeOf(text, read);\n if (typed === undefined) return operator === \"!=\";\n const c = compareValues(read, typed);\n switch (operator) {\n case \"=\":\n return c === 0;\n case \"!=\":\n return c !== 0;\n case \"<\":\n return c < 0;\n case \"<=\":\n return c <= 0;\n case \">\":\n return c > 0;\n default:\n return c >= 0;\n }\n}\n\n/** Whether a column's value passes every term of a filter. */\nexport function passes(\n value: unknown,\n terms: FilterTerm[],\n type?: ColumnType,\n): boolean {\n return terms.every((term) => passesTerm(value, term, type));\n}\n\n/**\n * Where a row for `lb-url` leads, from a page and its query parms.\n *\n * A column whose name begins with `lb-` is Loadbare's, and never a query\n * parm; every other column is one. An `lb-path` naming another page enters\n * it with only the parms the row names. Otherwise the named parms are set,\n * or taken out when empty, and the rest are kept.\n *\n * One rule on both sides of the wire: the server loads the page it names,\n * and the hub writes the URL it names. The two must agree, or what the page\n * shows would differ from what the address bar says.\n */\nexport function nextLocation(\n page: string,\n parms: URLSearchParams,\n row: Row,\n): { page: string; parms: URLSearchParams; moved: boolean } {\n const named: Record<string, string> = {};\n for (const [name, value] of Object.entries(row)) {\n if (name.startsWith(LB_RESERVED_PREFIX)) continue;\n named[name] = value === null || value === undefined ? \"\" : String(value);\n }\n const path = row[URL_COLUMN_PATH];\n const next = typeof path === \"string\" ? pageNameFor(path) : page;\n const moved = next !== page;\n return {\n page: next,\n parms: withQueryParms(moved ? new URLSearchParams() : parms, named),\n moved,\n };\n}\n\n/**\n * What the hub tells a custom element it did, in its own terms rather than\n * the browser's: a custom element implements any of these in place of\n * `connectedCallback` and its kin, which the builder refuses.\n *\n * Each is a method on an element the hub does not own, so it carries the\n * `lb` prefix Loadbare reserves for exactly that — see\n * docs/reference/custom-elements.md.\n */\nexport interface HubLifecycle {\n /**\n * Called once, after the hub has placed the element and every column has\n * landed on it. An element under an `lb-show` that is off is placed inside\n * its template, so it may not be rendered.\n */\n lbAttached?(): void;\n /**\n * Called once after a result has landed on an element holding rows, with\n * every row in place and every stamp set. The hub reconciles and places\n * every row itself, by the query's order, so a custom element reacts to\n * rows and never places them.\n */\n lbRowsLanded?(): void;\n /**\n * Called once a request committed by this element, or by one inside it,\n * has finished, innermost first and before `lb-request-done` is\n * dispatched. `origin` is the element that committed.\n */\n lbRequestDone?(detail: HubRequestDone, origin: Element): void;\n /** Called once, after the hub has removed the element. */\n lbDetached?(): void;\n}\n"]}
1
+ {"version":3,"file":"lb-types.js","sourceRoot":"","sources":["../../core/lb-types.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference lib=\"dom\" />\n\n// The wire vocabulary. Shared by browser and server.\n\nimport {\n COLUMN_TYPES,\n KIND_ROW,\n FILTER_OPERATORS,\n KIND_ROWS,\n LB_RESERVED_PREFIX,\n LB_ROW_REQUESTS,\n ORDER_DESCENDING,\n URL_COLUMN_PATH,\n} from \"./lb-constants.js\";\n\n/**\n * One row: its columns, by name.\n *\n * A value is whatever the server serialized. The hub knows nothing about its\n * type and enforces nothing: it hands each value to the browser untouched,\n * and the browser renders it as it sees fit. What a number, a date or a null\n * should look like is the application's decision, made in the query.\n */\nexport type Row = Record<string, unknown>;\n\n/**\n * Part of a `rows` query's answer — see docs/reference/server.md, \"Queries\".\n *\n * Rows named here are added or updated, keys in `drop` are removed, and\n * anything unnamed is left alone. The hub places what it names by the\n * query's order. Add and remove are one result rather than two because the\n * interesting cases are both at once — a row whose sort key changed has to\n * move, a swap is one out and one in — and two messages would paint the\n * intermediate state.\n */\nexport interface Patch {\n rows?: Row[];\n drop?: unknown[];\n}\n\n/** A type a `rows` query may declare for a column — see COLUMN_TYPES. */\nexport type ColumnType = (typeof COLUMN_TYPES)[number];\n\n/** The types a `rows` query declares for its columns, by column. */\nexport type ColumnTypes = Record<string, ColumnType>;\n\n/** A query's kind, declared by the server and carried by every answer. */\nexport type Kind = typeof KIND_ROW | typeof KIND_ROWS;\n\n/**\n * What a `rows` query answers with: all rows, or a patch. `Array.isArray`\n * tells the two apart. All rows arrive in the order the server chose, which\n * is the order they show in when the query declares none.\n */\nexport type RowsResult = Row[] | Patch;\n\nexport function isPatch(result: RowsResult): result is Patch {\n return !Array.isArray(result);\n}\n\n/**\n * What any one query answers with, as the application writes it. A `row`\n * query that finds no row answers `null`.\n */\nexport type HubResult = Row | RowsResult | null;\n\n/**\n * What application code hands the engine: answers by query name. The engine\n * turns each into a response item, adding the kind and key the query\n * declared.\n */\nexport type HubData = Record<string, HubResult>;\n\n/**\n * One query's answer on the wire: its name, its kind, its key's column name,\n * and exactly one of a row, all rows, or a patch. A patch answers a `rows`\n * query only.\n *\n * A `rows` query also carries the order and column types it declared, once,\n * on the answer that loads the page. The hub keeps them with the answer for\n * every answer after it.\n */\nexport interface ResponseItem {\n query: string;\n kind: Kind;\n key: string;\n row?: Row | null;\n rows?: Row[];\n patch?: Patch;\n order?: string;\n types?: ColumnTypes;\n}\n\n/** Every response the server sends: a page load and a request alike. */\nexport type HubResponse = ResponseItem[];\n\n/**\n * Every request has one shape. The name picks the handler; the rest is\n * present when the hub found it.\n */\nexport interface HubRequest {\n name: string;\n query?: string;\n key?: string;\n /**\n * The rows a request acts on together, by key: those the user selected,\n * for a request that names no one row. Never sent beside `key`.\n */\n keys?: string[];\n values?: Record<string, string>;\n /**\n * The rows of the queries nested in a form, by query name, each with the\n * values of its own controls: a set of rows gathered beside the form's\n * own values.\n */\n rows?: Record<string, GatheredRow[]>;\n}\n\n/** One nested row a form gathered: its key, and its controls' values. */\nexport interface GatheredRow {\n key: string;\n values: Record<string, string>;\n}\n\n/**\n * The detail of the `lb-request-done` event: the request as the hub\n * completed and sent it, and what came of it. `items` is every response\n * item that landed because of it, in the order it landed. `error` is set\n * when the request's own round trip failed, and then nothing landed.\n */\nexport interface HubRequestDone {\n request: HubRequest;\n items: ResponseItem[];\n error?: Error;\n /** Set beside `error` when the handler refused the request. */\n refusal?: HubRefusal;\n}\n\n/**\n * Why a handler refused a request, in words written for the user: a\n * message for the request as a whole, a message per column the request\n * gathered, or both. Sent with status 422; any other failure sends nothing.\n */\nexport interface HubRefusal {\n message?: string;\n columns?: Record<string, string>;\n}\n\n/** The fields a handler receives: the request, less its name. */\nexport type RequestFields = Omit<HubRequest, \"name\">;\n\n/** Whether a name is one of the requests Loadbare provides. */\nexport function isRowRequest(name: string): boolean {\n return (LB_ROW_REQUESTS as readonly string[]).includes(name);\n}\n\n/**\n * A query string with some parms set, and the rest as they were. An empty\n * value takes its parm out, since empty is every parm's default and a\n * default is left out of the URL.\n *\n * One rule on both sides of the wire: the hub applies it to the address bar,\n * and the server to the query string it loads the page at after a request\n * returned `lb-url`. The two must agree, or what the page shows would differ\n * from what the address bar says.\n */\nexport function withQueryParms(\n search: URLSearchParams,\n parms: Record<string, string>,\n): URLSearchParams {\n const next = new URLSearchParams(search);\n for (const [name, value] of Object.entries(parms)) {\n if (value === \"\") next.delete(name);\n else next.set(name, value);\n }\n return next;\n}\n\n/**\n * A path names a page by its stub, and nothing finer. The bare path resolves\n * to `index`, the same convention a static file server follows.\n */\nexport function pageNameFor(path: string): string {\n const name = path.replace(/^\\/+|\\/+$/g, \"\");\n return name === \"\" ? \"index\" : name;\n}\n\n/** One term of an order: a column, and whether it sorts descending. */\nexport interface OrderTerm {\n column: string;\n descending: boolean;\n}\n\n/**\n * An order's terms, from its text: columns separated by commas, each\n * descending when it begins with `-`. Throws on a term that names no column.\n * An empty text is no order.\n */\nexport function parseOrder(text: string): OrderTerm[] {\n if (text.trim() === \"\") return [];\n return text.split(\",\").map((raw) => {\n const term = raw.trim();\n const descending = term.startsWith(ORDER_DESCENDING);\n const column = descending ? term.slice(ORDER_DESCENDING.length) : term;\n if (column === \"\" || column.startsWith(ORDER_DESCENDING)) {\n throw new Error(`the order '${text}' has a term naming no column`);\n }\n return { column, descending };\n });\n}\n\n/** Strings compare as the user's language orders them. */\nconst collator = new Intl.Collator();\n\n/** How a value sorts among values of other types: by its JSON type. */\nfunction rank(value: unknown): number {\n switch (typeof value) {\n case \"boolean\":\n return 0;\n case \"number\":\n return 1;\n case \"string\":\n return 2;\n default:\n return 3;\n }\n}\n\n/**\n * Compare two column values, ascending.\n *\n * A value compares by its JSON type, and nothing is guessed: numbers\n * numerically, booleans false before true, strings as the user's language\n * orders them. A number that arrives as a string sorts as a string, so a\n * numeric sort column is sent as a JSON number. Null and a missing value\n * sort after everything, as Postgres sorts them ascending, and so first\n * descending.\n */\nexport function compareValues(a: unknown, b: unknown): number {\n const missingA = a === null || a === undefined;\n const missingB = b === null || b === undefined;\n if (missingA || missingB) return missingA === missingB ? 0 : missingA ? 1 : -1;\n const ra = rank(a);\n const rb = rank(b);\n if (ra !== rb) return ra - rb;\n if (typeof a === \"number\") return a - (b as number);\n if (typeof a === \"boolean\") return Number(a) - Number(b);\n if (typeof a === \"string\") return collator.compare(a, b as string);\n return collator.compare(JSON.stringify(a), JSON.stringify(b));\n}\n\n/**\n * A value read as a declared column type: a number for `number`, a boolean\n * for `boolean`, text for `text`. A value that is no value of its type reads\n * as missing, and compares as a null does. A column with no declared type\n * reads as it arrived.\n */\nexport function readAs(value: unknown, type: ColumnType | undefined): unknown {\n if (type === undefined || value === null || value === undefined) return value;\n switch (type) {\n case \"number\": {\n if (typeof value === \"number\") return value;\n if (typeof value !== \"string\" || value.trim() === \"\") return undefined;\n const n = Number(value);\n return Number.isNaN(n) ? undefined : n;\n }\n case \"boolean\":\n if (typeof value === \"boolean\") return value;\n return value === \"true\" ? true : value === \"false\" ? false : undefined;\n default:\n return typeof value === \"object\" ? JSON.stringify(value) : String(value);\n }\n}\n\n/** Compare two rows by an order's terms, each column read as its type. */\nexport function compareRows(\n a: Row,\n b: Row,\n terms: OrderTerm[],\n types: ColumnTypes = {},\n): number {\n for (const { column, descending } of terms) {\n const c = compareValues(\n readAs(a[column], types[column]),\n readAs(b[column], types[column]),\n );\n if (c !== 0) return descending ? -c : c;\n }\n return 0;\n}\n\n/** A filter's operator — see FILTER_OPERATORS. */\nexport type FilterOperator = (typeof FILTER_OPERATORS)[number];\n\n/** One term of a filter: an operator, and the value it compares with. */\nexport interface FilterTerm {\n operator: FilterOperator;\n value: string;\n}\n\n/** Where a filter's next term begins: whitespace before an operator. */\nconst NEXT_TERM = new RegExp(\n `\\\\s+(?=${FILTER_OPERATORS.map((op) => op.replace(/[$^*]/g, \"\\\\$&\")).join(\"|\")})`,\n);\n\n/**\n * A filter's terms, from its text: each an operator and the value after it,\n * a new term beginning wherever whitespace comes before an operator, so a\n * value may hold spaces. Text with no operator before it is `*=`. A term\n * with no value is not yet a term, and is left out, so a filter being typed\n * filters nothing until it says something. Nothing is evaluated.\n */\nexport function parseFilter(text: string): FilterTerm[] {\n const terms: FilterTerm[] = [];\n for (const raw of text.trim().split(NEXT_TERM)) {\n const operator =\n FILTER_OPERATORS.find((op) => raw.startsWith(op)) ?? \"*=\";\n const value = raw.slice(raw.startsWith(operator) ? operator.length : 0);\n if (value.trim() !== \"\") terms.push({ operator, value: value.trim() });\n }\n return terms;\n}\n\n/**\n * The filter's value as the column's own type, so a comparison is the one\n * the order makes: a number for a number, a boolean for a boolean, text for\n * anything else. Undefined when the text is no value of that type.\n */\nfunction asTypeOf(text: string, like: unknown): unknown {\n if (typeof like === \"number\") {\n const n = Number(text);\n return text.trim() === \"\" || Number.isNaN(n) ? undefined : n;\n }\n if (typeof like === \"boolean\") {\n return text === \"true\" ? true : text === \"false\" ? false : undefined;\n }\n return text;\n}\n\n/**\n * Whether a column's value passes one term.\n *\n * `^=`, `$=` and `*=` read the value as text, ignoring case: it begins with,\n * ends with or contains the term's value. The rest compare as the order\n * compares, with the column read as its declared type, if it has one, and\n * the term's value read as the column's type. A missing value, and one that\n * is no value of its declared type, passes only `!=`.\n */\nexport function passesTerm(\n value: unknown,\n { operator, value: text }: FilterTerm,\n type?: ColumnType,\n): boolean {\n if (value === null || value === undefined) return operator === \"!=\";\n if (operator === \"^=\" || operator === \"$=\" || operator === \"*=\") {\n const have = String(value).toLocaleLowerCase();\n const want = text.toLocaleLowerCase();\n if (operator === \"^=\") return have.startsWith(want);\n if (operator === \"$=\") return have.endsWith(want);\n return have.includes(want);\n }\n const read = readAs(value, type);\n const typed = read === undefined ? undefined : asTypeOf(text, read);\n if (typed === undefined) return operator === \"!=\";\n const c = compareValues(read, typed);\n switch (operator) {\n case \"=\":\n return c === 0;\n case \"!=\":\n return c !== 0;\n case \"<\":\n return c < 0;\n case \"<=\":\n return c <= 0;\n case \">\":\n return c > 0;\n default:\n return c >= 0;\n }\n}\n\n/** Whether a column's value passes every term of a filter. */\nexport function passes(\n value: unknown,\n terms: FilterTerm[],\n type?: ColumnType,\n): boolean {\n return terms.every((term) => passesTerm(value, term, type));\n}\n\n/**\n * Where a row for `lb-url` leads, from a page and its query parms.\n *\n * A column whose name begins with `lb-` is Loadbare's, and never a query\n * parm; every other column is one. An `lb-path` naming another page enters\n * it with only the parms the row names. Otherwise the named parms are set,\n * or taken out when empty, and the rest are kept.\n *\n * One rule on both sides of the wire: the server loads the page it names,\n * and the hub writes the URL it names. The two must agree, or what the page\n * shows would differ from what the address bar says.\n */\nexport function nextLocation(\n page: string,\n parms: URLSearchParams,\n row: Row,\n): { page: string; parms: URLSearchParams; moved: boolean } {\n const named: Record<string, string> = {};\n for (const [name, value] of Object.entries(row)) {\n if (name.startsWith(LB_RESERVED_PREFIX)) continue;\n named[name] = value === null || value === undefined ? \"\" : String(value);\n }\n const path = row[URL_COLUMN_PATH];\n const next = typeof path === \"string\" ? pageNameFor(path) : page;\n const moved = next !== page;\n return {\n page: next,\n parms: withQueryParms(moved ? new URLSearchParams() : parms, named),\n moved,\n };\n}\n\n/**\n * What the hub tells a custom element it did, in its own terms rather than\n * the browser's: a custom element implements any of these in place of\n * `connectedCallback` and its kin, which the builder refuses.\n *\n * Each is a method on an element the hub does not own, so it carries the\n * `lb` prefix Loadbare reserves for exactly that — see\n * docs/reference/custom-elements.md.\n */\nexport interface HubLifecycle {\n /**\n * Called once, after the hub has placed the element and every column has\n * landed on it. An element under an `lb-show` that is off is placed inside\n * its template, so it may not be rendered.\n */\n lbAttached?(): void;\n /**\n * Called once after a result has landed on an element holding rows, with\n * every row in place and every stamp set. The hub reconciles and places\n * every row itself, by the query's order, so a custom element reacts to\n * rows and never places them.\n */\n lbRowsLanded?(): void;\n /**\n * Called once a request committed by this element, or by one inside it,\n * has finished, innermost first and before `lb-request-done` is\n * dispatched. `origin` is the element that committed.\n */\n lbRequestDone?(detail: HubRequestDone, origin: Element): void;\n /** Called once, after the hub has removed the element. */\n lbDetached?(): void;\n}\n"]}
@@ -3,23 +3,31 @@ import { type ColumnTypes, type ResponseItem, type Row, type RowsResult } from "
3
3
  export interface Control extends Element {
4
4
  value: string;
5
5
  }
6
+ /**
7
+ * A radio button, whose state is `checked` as well. It is checked when its
8
+ * own `value` is the value that landed, so a group of them naming one column
9
+ * shows that value, and gathers the one checked.
10
+ */
11
+ export declare function isRadio(el: Element): boolean;
6
12
  /**
7
13
  * A form-associated custom element with a `value` property. HTML marks one
8
14
  * with `static formAssociated = true` on its class, and a control has a value.
9
15
  */
10
16
  export declare function isFormAssociated(el: Element): boolean;
11
17
  /**
12
- * A control: an `<input>`, `<select>` or `<textarea>`, a checkbox, or a
18
+ * A control: an `<input>`, `<select>` or `<textarea>`, a checkbox, a radio
19
+ * button, or a
13
20
  * form-associated custom element with a `value` property. Landing and
14
21
  * gathering draw the same line, so a value read back is the one that landed
15
22
  * there.
16
23
  */
17
24
  export declare function isControl(el: Element): el is Control;
18
25
  /**
19
- * What a control gathers: a checkbox `"true"` or `"false"`, so unchecked
20
- * still says so, and any other control its `value`.
26
+ * Gather a control into `values` under its column. Of the radio buttons
27
+ * naming one column, the one checked gives the value, and `""` stands when
28
+ * none is.
21
29
  */
22
- export declare function controlValue(el: Control): string;
30
+ export declare function gatherInto(values: Record<string, string>, column: string, el: Control): void;
23
31
  /**
24
32
  * Root if it matches, then every descendant in root's query that does.
25
33
  * Gathering finds columns through here. It does not reach into an absent
@@ -1 +1 @@
1
- {"version":3,"file":"lb-apply.d.ts","sourceRoot":"","sources":["../../hub/lb-apply.ts"],"names":[],"mappings":"AA+EA,OAAO,EASL,KAAK,WAAW,EAKhB,KAAK,YAAY,EACjB,KAAK,GAAG,EACR,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAyB7B,mEAAmE;AACnE,MAAM,WAAW,OAAQ,SAAQ,OAAO;IACtC,KAAK,EAAE,MAAM,CAAC;CACf;AA4BD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAGrD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,OAAO,GAAG,EAAE,IAAI,OAAO,CAEpD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,OAAO,GAAG,MAAM,CAEhD;AAsFD;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,CAMjE;AA0CD;;;GAGG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CAGtD;AA6LD;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,GAAG,EACR,IAAI,UAAQ,EACZ,IAAI,CAAC,EAAE,MAAM,GACZ,IAAI,CAEN;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,GAAG,CAU3C;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CAKlE;AAQD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAS3C;AAwmBD,4EAA4E;AAC5E,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,mDAAmD;IACnD,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,oDAAoD;IACpD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CACvB,EAAE,EAAE,OAAO,EACX,QAAQ,EAAE,mBAAmB,EAC7B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,WAAgB,GACxB,IAAI,CAgIN;AAmFD,uDAAuD;AACvD,wBAAgB,UAAU,CACxB,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,GACZ,YAAY,GAAG,SAAS,CAE1B;AAgBD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAE7C;AAoGD,+BAA+B;AAC/B,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,YAAY,EAAE,EACrB,OAAO,GAAE,WAAgB,GACxB,IAAI,CA2BN"}
1
+ {"version":3,"file":"lb-apply.d.ts","sourceRoot":"","sources":["../../hub/lb-apply.ts"],"names":[],"mappings":"AA+EA,OAAO,EASL,KAAK,WAAW,EAKhB,KAAK,YAAY,EACjB,KAAK,GAAG,EACR,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AA0B7B,mEAAmE;AACnE,MAAM,WAAW,OAAQ,SAAQ,OAAO;IACtC,KAAK,EAAE,MAAM,CAAC;CACf;AA4BD;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAE5C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAGrD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,OAAO,GAAG,EAAE,IAAI,OAAO,CAIpD;AAUD;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,OAAO,GACV,IAAI,CAMN;AA0FD;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,CAMjE;AA0CD;;;GAGG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CAGtD;AA6LD;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,GAAG,EACR,IAAI,UAAQ,EACZ,IAAI,CAAC,EAAE,MAAM,GACZ,IAAI,CAEN;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,GAAG,CAU3C;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CAKlE;AAQD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAS3C;AAsnBD,4EAA4E;AAC5E,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,mDAAmD;IACnD,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,oDAAoD;IACpD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CACvB,EAAE,EAAE,OAAO,EACX,QAAQ,EAAE,mBAAmB,EAC7B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,WAAgB,GACxB,IAAI,CAgIN;AA0FD,uDAAuD;AACvD,wBAAgB,UAAU,CACxB,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,GACZ,YAAY,GAAG,SAAS,CAE1B;AAgBD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAE7C;AAoGD,+BAA+B;AAC/B,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,YAAY,EAAE,EACrB,OAAO,GAAE,WAAgB,GACxB,IAAI,CA2BN"}
@@ -49,7 +49,8 @@ const ELEMENT_NODE = 1;
49
49
  const TEXT_NODE = 3;
50
50
  /**
51
51
  * The input types whose state is not their `value`, or cannot be set. A
52
- * checkbox's state is `checked`, and it is a control by its own rule.
52
+ * checkbox's and a radio button's state is `checked`, and each is a control
53
+ * by its own rule.
53
54
  */
54
55
  const UNLANDED_INPUTS = ["checkbox", "radio", "file"];
55
56
  /**
@@ -73,6 +74,14 @@ function isNativeControl(el) {
73
74
  function isCheckbox(el) {
74
75
  return (el.localName === "input" && el.type === "checkbox");
75
76
  }
77
+ /**
78
+ * A radio button, whose state is `checked` as well. It is checked when its
79
+ * own `value` is the value that landed, so a group of them naming one column
80
+ * shows that value, and gathers the one checked.
81
+ */
82
+ export function isRadio(el) {
83
+ return el.localName === "input" && el.type === "radio";
84
+ }
76
85
  /**
77
86
  * A form-associated custom element with a `value` property. HTML marks one
78
87
  * with `static formAssociated = true` on its class, and a control has a value.
@@ -82,21 +91,34 @@ export function isFormAssociated(el) {
82
91
  return ctor.formAssociated === true && "value" in el;
83
92
  }
84
93
  /**
85
- * A control: an `<input>`, `<select>` or `<textarea>`, a checkbox, or a
94
+ * A control: an `<input>`, `<select>` or `<textarea>`, a checkbox, a radio
95
+ * button, or a
86
96
  * form-associated custom element with a `value` property. Landing and
87
97
  * gathering draw the same line, so a value read back is the one that landed
88
98
  * there.
89
99
  */
90
100
  export function isControl(el) {
91
- return isNativeControl(el) || isCheckbox(el) || isFormAssociated(el);
101
+ return (isNativeControl(el) || isCheckbox(el) || isRadio(el) || isFormAssociated(el));
92
102
  }
93
103
  /**
94
104
  * What a control gathers: a checkbox `"true"` or `"false"`, so unchecked
95
105
  * still says so, and any other control its `value`.
96
106
  */
97
- export function controlValue(el) {
107
+ function controlValue(el) {
98
108
  return isCheckbox(el) ? String(el.checked) : el.value;
99
109
  }
110
+ /**
111
+ * Gather a control into `values` under its column. Of the radio buttons
112
+ * naming one column, the one checked gives the value, and `""` stands when
113
+ * none is.
114
+ */
115
+ export function gatherInto(values, column, el) {
116
+ if (isRadio(el) && !el.checked) {
117
+ values[column] ??= "";
118
+ return;
119
+ }
120
+ values[column] = controlValue(el);
121
+ }
100
122
  /**
101
123
  * Set an element from a column. A control's `value` is set. A custom element
102
124
  * that is not a control keeps its content, which the builder placed there
@@ -107,8 +129,9 @@ function land(el, value) {
107
129
  // Untouched, whatever the server sent: the browser decides what a
108
130
  // non-string looks like. See Row in core/lb-types.ts.
109
131
  if (value === null || value === undefined) {
110
- if (isCheckbox(el))
132
+ if (isCheckbox(el) || isRadio(el)) {
111
133
  el.checked = false;
134
+ }
112
135
  else if (isControl(el))
113
136
  el.value = "";
114
137
  else if (!el.localName.includes("-") && el.localName !== "input") {
@@ -122,6 +145,10 @@ function land(el, value) {
122
145
  // and no string is read.
123
146
  el.checked = value !== false;
124
147
  }
148
+ else if (isRadio(el)) {
149
+ el.checked =
150
+ el.value === String(value);
151
+ }
125
152
  else if (isControl(el)) {
126
153
  el.value = value;
127
154
  }
@@ -587,6 +614,7 @@ function create(list, doc, key) {
587
614
  placed(el);
588
615
  el.setAttribute(ATTR_ROW_LIVE, "");
589
616
  el.setAttribute(ATTR_KEY_VALUE, key);
617
+ nameRadios(el, key);
590
618
  const entry = {
591
619
  key,
592
620
  el,
@@ -597,6 +625,18 @@ function create(list, doc, key) {
597
625
  list.byKey.set(key, entry);
598
626
  return entry;
599
627
  }
628
+ /**
629
+ * Give each radio button of a new live row a group of its own. The browser
630
+ * groups radio buttons by `name`, and a row template repeats one `name` in
631
+ * every live row, so the hub follows the `name` written, or the column when
632
+ * none is, with the row's key.
633
+ */
634
+ function nameRadios(row, key) {
635
+ for (const el of below(row, `input[type=radio][${ATTR_COLUMN}]`)) {
636
+ const name = el.getAttribute("name") || el.getAttribute(ATTR_COLUMN);
637
+ el.setAttribute("name", `${name}-${key}`);
638
+ }
639
+ }
600
640
  /** A group's identity among its siblings: its column and its value there. */
601
641
  function groupId(column, value) {
602
642
  return `${column}\u0000${JSON.stringify(value ?? null)}`;
@@ -1155,9 +1195,16 @@ function refocus(list, focused) {
1155
1195
  function landItem(el, item, options = {}) {
1156
1196
  const template = lists.get(el)?.top ?? templateIn(el);
1157
1197
  if (item.kind === KIND_ROW) {
1158
- const row = item.row ?? {};
1198
+ const row = item.row;
1159
1199
  if (template) {
1160
- applyRows(el, template, item.key, [row], options);
1200
+ applyRows(el, template, item.key, row ? [row] : [], options);
1201
+ return;
1202
+ }
1203
+ // No row: every column the element shows lands null, and the element
1204
+ // names no row.
1205
+ if (!row) {
1206
+ applyRow(el, blankRow(el));
1207
+ el.removeAttribute(ATTR_KEY_VALUE);
1161
1208
  return;
1162
1209
  }
1163
1210
  applyRow(el, row);
@@ -1197,7 +1244,7 @@ function rowsOptions(state, item) {
1197
1244
  return {
1198
1245
  order: declared.order,
1199
1246
  types: declared.types,
1200
- choices: state.answers.get(CHOICES_QUERY)?.row,
1247
+ choices: state.answers.get(CHOICES_QUERY)?.row ?? undefined,
1201
1248
  };
1202
1249
  }
1203
1250
  /**