@lo-tek/interfaces 0.41.0 → 0.43.0

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.
Files changed (63) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/agent/astro.md +1 -1
  3. package/agent/bundles.md +1 -1
  4. package/agent/datastar.md +57 -50
  5. package/agent/html.md +53 -53
  6. package/agent/kotlin.md +4 -4
  7. package/agent/react.md +1 -1
  8. package/agent/templates.md +50 -50
  9. package/dist/components/frame/dialog/lt-dialog.d.ts +11 -3
  10. package/dist/components/frame/dialog/lt-dialog.d.ts.map +1 -1
  11. package/dist/components/frame/dialog/lt-dialog.js +59 -46
  12. package/dist/components/frame/dialog/lt-dialog.js.map +1 -1
  13. package/dist/components/frame/error-summary/lt-error-summary.d.ts +9 -6
  14. package/dist/components/frame/error-summary/lt-error-summary.d.ts.map +1 -1
  15. package/dist/components/frame/error-summary/lt-error-summary.js +38 -57
  16. package/dist/components/frame/error-summary/lt-error-summary.js.map +1 -1
  17. package/dist/components/frame/field/lt-field.d.ts +17 -26
  18. package/dist/components/frame/field/lt-field.d.ts.map +1 -1
  19. package/dist/components/frame/field/lt-field.js +81 -143
  20. package/dist/components/frame/field/lt-field.js.map +1 -1
  21. package/dist/components/frame/popover/lt-popover.d.ts +1 -1
  22. package/dist/components/frame/popover/lt-popover.d.ts.map +1 -1
  23. package/dist/components/frame/popover/lt-popover.js +31 -33
  24. package/dist/components/frame/popover/lt-popover.js.map +1 -1
  25. package/dist/components/frame/session-timeout/lt-session-timeout.d.ts +14 -2
  26. package/dist/components/frame/session-timeout/lt-session-timeout.d.ts.map +1 -1
  27. package/dist/components/frame/session-timeout/lt-session-timeout.js +73 -46
  28. package/dist/components/frame/session-timeout/lt-session-timeout.js.map +1 -1
  29. package/dist/components/frame/suggestion/lt-suggestion.d.ts +5 -7
  30. package/dist/components/frame/suggestion/lt-suggestion.d.ts.map +1 -1
  31. package/dist/components/frame/suggestion/lt-suggestion.js +57 -72
  32. package/dist/components/frame/suggestion/lt-suggestion.js.map +1 -1
  33. package/dist/components/frame/tabs/lt-tabs.d.ts +14 -5
  34. package/dist/components/frame/tabs/lt-tabs.d.ts.map +1 -1
  35. package/dist/components/frame/tabs/lt-tabs.js +86 -106
  36. package/dist/components/frame/tabs/lt-tabs.js.map +1 -1
  37. package/dist/components/frame/term/lt-term.d.ts +5 -1
  38. package/dist/components/frame/term/lt-term.d.ts.map +1 -1
  39. package/dist/components/frame/term/lt-term.js +23 -21
  40. package/dist/components/frame/term/lt-term.js.map +1 -1
  41. package/dist/components/host-element.d.ts +137 -2
  42. package/dist/components/host-element.d.ts.map +1 -1
  43. package/dist/components/host-element.js +187 -4
  44. package/dist/components/host-element.js.map +1 -1
  45. package/dist/lotek.css +1 -1
  46. package/dist/react.d.ts +51 -437
  47. package/dist/react.d.ts.map +1 -1
  48. package/dist/react.js +48 -208
  49. package/dist/react.js.map +1 -1
  50. package/live-templates-kotlin.xml +4 -6
  51. package/manifest/manifest.json +1 -1
  52. package/package.json +7 -3
  53. package/src/components/frame/dialog/lt-dialog.ts +56 -50
  54. package/src/components/frame/error-summary/lt-error-summary.ts +33 -46
  55. package/src/components/frame/field/lt-field.ts +99 -207
  56. package/src/components/frame/popover/lt-popover.ts +37 -35
  57. package/src/components/frame/session-timeout/lt-session-timeout.ts +88 -46
  58. package/src/components/frame/suggestion/lt-suggestion.ts +59 -73
  59. package/src/components/frame/tabs/lt-tabs.ts +96 -122
  60. package/src/components/frame/term/lt-term.ts +27 -21
  61. package/src/components/host-element.ts +306 -3
  62. package/src/react.ts +125 -240
  63. package/web-types.json +1 -1
package/src/react.ts CHANGED
@@ -1,65 +1,12 @@
1
- import { accordion } from "./components/css/accordion/accordion.js"
2
- import { alert } from "./components/css/alert/alert.js"
3
- import { avatar } from "./components/css/avatar/avatar.js"
4
- import { badge } from "./components/css/badge/badge.js"
5
- import { breadcrumbs } from "./components/css/breadcrumbs/breadcrumbs.js"
6
- import { button } from "./components/css/button/button.js"
7
- import { card } from "./components/css/card/card.js"
8
- import { checkbox } from "./components/css/checkbox/checkbox.js"
9
- import { divider } from "./components/css/divider/divider.js"
10
- import { errorText } from "./components/css/error-text/error-text.js"
11
- import { fieldset, legend } from "./components/css/fieldset/fieldset.js"
12
- import { fileUpload } from "./components/css/file-upload/file-upload.js"
13
- import { heading } from "./components/css/heading/heading.js"
14
- import { helpText } from "./components/css/help-text/help-text.js"
15
- import { icon } from "./components/css/icon/icon.js"
16
- import { input } from "./components/css/input/input.js"
17
- import { label } from "./components/css/label/label.js"
18
- import { link } from "./components/css/link/link.js"
19
- import { list } from "./components/css/list/list.js"
20
- import { pagination } from "./components/css/pagination/pagination.js"
21
- import { paragraph } from "./components/css/paragraph/paragraph.js"
22
- import { progress } from "./components/css/progress/progress.js"
23
- import { radio } from "./components/css/radio/radio.js"
24
- import { search } from "./components/css/search/search.js"
25
- import { select } from "./components/css/select/select.js"
26
- import {
27
- fieldStates,
28
- isFieldState,
29
- isRequiredMarker,
30
- managedNames,
31
- rememberManaged,
32
- requiredMarkers,
33
- } from "./components/css/shared.js"
34
- import { skeleton } from "./components/css/skeleton/skeleton.js"
35
- import { skipLink } from "./components/css/skip-link/skip-link.js"
36
- import { spinner } from "./components/css/spinner/spinner.js"
37
- import { srOnly } from "./components/css/sr-only/sr-only.js"
38
- import { steps } from "./components/css/steps/steps.js"
39
- import { switchControl } from "./components/css/switch/switch.js"
40
- import { table, tableSort } from "./components/css/table/table.js"
41
- import { tag } from "./components/css/tag/tag.js"
42
- import { textarea } from "./components/css/textarea/textarea.js"
43
- import { toggleGroup } from "./components/css/toggle-group/toggle-group.js"
44
- import { tooltip } from "./components/css/tooltip/tooltip.js"
45
- import { dialog } from "./components/frame/dialog/dialog.js"
46
- import { errorSummary } from "./components/frame/error-summary/error-summary.js"
47
- import {
48
- computeFieldAttributes,
49
- createFieldId,
50
- type FieldOptions,
51
- } from "./components/frame/field/field-core.js"
52
- import { popover } from "./components/frame/popover/popover.js"
53
- import { sessionTimeout } from "./components/frame/session-timeout/session-timeout.js"
54
- import { suggestion } from "./components/frame/suggestion/suggestion.js"
1
+ import { managedNames, rememberManaged } from "./components/css/shared.js"
2
+ import { createFieldId } from "./components/frame/field/field-core.js"
55
3
  import {
56
4
  type TabsWithStateOptions,
57
5
  tabsWithState,
58
6
  } from "./components/frame/tabs/tabs.js"
59
7
  import { termWithState } from "./components/frame/term/term.js"
60
- import { connectionStatus } from "./components/standalone/connection-status/connection-status.js"
61
- import { toast } from "./components/standalone/toast/toast.js"
62
8
  import { type Attributes, setAttributes as setHtmlAttributes } from "./dom.js"
9
+ import { lt as html, type Lt } from "./lt.js"
63
10
 
64
11
  // The types of the events, so `addEventListener` is typed also for someone
65
12
  // who only imports this entry point. Without the line the import disappeared
@@ -208,17 +155,98 @@ export function setAttributes(
208
155
  }
209
156
 
210
157
  /**
211
- * Wraps a builder function so the return value gets the React names.
212
- *
213
- * The signature is written as an intersection type so TypeScript can infer
214
- * both the options type and the extra fields attached to the function, that
215
- * is `variants`, `isVariant` and the others, in one go.
158
+ * A builder function's result with the React names: every attribute set in
159
+ * it, in an object or a list as deep as it goes. A set is an object whose
160
+ * values are all plain values; anything else is gone through.
161
+ */
162
+ export type ReactResult<R> = R extends readonly (infer Item)[]
163
+ ? ReactResult<Item>[]
164
+ : R extends object
165
+ ? R[keyof R] extends string | number | boolean | null | undefined
166
+ ? ReactAttributes<R>
167
+ : { [K in keyof R]: ReactResult<R[K]> }
168
+ : R
169
+
170
+ /**
171
+ * The result with the React names. A set is recognised by what
172
+ * `attributes()` notes on every set a builder function makes, not by its
173
+ * shape, so a compound whose parts are all absent is not taken for one.
216
174
  */
217
- function forReact<Options, Result extends Record<string, unknown>, Extra>(
218
- fn: ((options?: Options) => Result) & Extra,
219
- ): ((options?: Options) => ReactAttributes<Result>) & Extra {
220
- const wrapped = (options?: Options) => toReactAttributes(fn(options))
221
- return Object.assign(wrapped, fn)
175
+ function toReactResult(value: unknown): unknown {
176
+ if (Array.isArray(value)) return value.map(toReactResult)
177
+ if (!value || typeof value !== "object") return value
178
+ if (managedNames(value))
179
+ return toReactAttributes(value as Record<string, unknown>)
180
+ return Object.fromEntries(
181
+ Object.entries(value).map(([name, child]) => [name, toReactResult(child)]),
182
+ )
183
+ }
184
+
185
+ /**
186
+ * Wraps a builder function so the result gets the React names, and keeps
187
+ * what hangs on the function: `variants`, `isVariant` and the others.
188
+ */
189
+ function forReact<F extends (...args: never[]) => unknown>(
190
+ fn: F,
191
+ ): ForReactFn<F> {
192
+ const wrapped = (...args: Parameters<F>) => toReactResult(fn(...args))
193
+ return Object.assign(wrapped, fn) as unknown as ForReactFn<F>
194
+ }
195
+
196
+ /**
197
+ * The type of a member of `lt` in `/react`. A guard, which answers
198
+ * `value is T`, is the same function: no builder function answers a
199
+ * boolean, and at run time `isGuard` tells it by its name. A builder function
200
+ * takes the same options, named `options` as in the editor, and gives the
201
+ * React result.
202
+ */
203
+ type ForReactFn<F> = F extends (...args: never[]) => boolean
204
+ ? F
205
+ : F extends (...args: never[]) => infer R
206
+ ? Parameters<F> extends []
207
+ ? (() => ReactResult<R>) & { [K in keyof F]: F[K] }
208
+ : ForReactOptions<F>
209
+ : F
210
+
211
+ type ForReactOptions<F> = F extends (options?: infer O) => infer R
212
+ ? ((options?: O) => ReactResult<R>) & { [K in keyof F]: F[K] }
213
+ : F extends (options: infer O) => infer R
214
+ ? ((options: O) => ReactResult<R>) & { [K in keyof F]: F[K] }
215
+ : F
216
+
217
+ /**
218
+ * A guard on `lt`, such as `isState`: it builds nothing, and passes through
219
+ * as the same function. Named `is` and a capital letter, as every guard in
220
+ * the package is.
221
+ */
222
+ const isGuard = (name: string) => /^is[A-Z]/.test(name)
223
+
224
+ /**
225
+ * What stands by hand in `lt` below: the two that give the whole state, and
226
+ * `setAttributes`, which takes an element and builds nothing.
227
+ */
228
+ const BY_HAND = ["tabs", "term", "setAttributes"] as const
229
+ type ByHand = (typeof BY_HAND)[number]
230
+
231
+ /**
232
+ * Every member of `lt` but those by hand, with the React names. Mapped over
233
+ * `keyof Lt`, and named on `lt` below, so the declaration file refers to it
234
+ * and the documentation on each member in `lt.ts` comes along to the
235
+ * consumer's editor.
236
+ */
237
+ type ForReact = {
238
+ [K in keyof Lt as K extends ByHand ? never : K]: ForReactFn<Lt[K]>
239
+ }
240
+
241
+ function everyBuilder(): ForReact {
242
+ const result: Record<string, unknown> = {}
243
+ for (const [name, value] of Object.entries(html))
244
+ if (!(BY_HAND as readonly string[]).includes(name))
245
+ result[name] =
246
+ typeof value === "function" && !isGuard(name)
247
+ ? forReact(value as (...args: never[]) => unknown)
248
+ : value
249
+ return result as ForReact
222
250
  }
223
251
 
224
252
  /**
@@ -232,195 +260,52 @@ function forReact<Options, Result extends Record<string, unknown>, Extra>(
232
260
  */
233
261
  export { createFieldId }
234
262
 
235
- export const lt = {
236
- accordion: forReact(accordion),
237
- alert: forReact(alert),
238
- avatar: forReact(avatar),
239
- badge: forReact(badge),
240
- breadcrumbs: forReact(breadcrumbs),
241
- button: forReact(button),
242
- card: forReact(card),
243
- checkbox: forReact(checkbox),
244
- divider: forReact(divider),
245
- errorText: forReact(errorText),
246
- fieldset: forReact(fieldset),
247
- heading: forReact(heading),
248
- fileUpload: forReact(fileUpload),
249
- helpText: forReact(helpText),
250
- icon: forReact(icon),
251
- input: forReact(input),
252
- label: forReact(label),
253
- legend: forReact(legend),
254
- link: forReact(link),
255
- list: forReact(list),
256
- pagination: forReact(pagination),
257
- paragraph: forReact(paragraph),
258
- radio: forReact(radio),
259
- search: forReact(search),
260
- select: forReact(select),
261
- skeleton: forReact(skeleton),
262
- skipLink: forReact(skipLink),
263
- progress: forReact(progress),
264
- spinner: forReact(spinner),
265
- srOnly: forReact(srOnly),
266
- steps: forReact(steps),
267
- switch: forReact(switchControl),
268
- toggleGroup: forReact(toggleGroup),
269
- tooltip: forReact(tooltip),
270
- table: forReact(table),
271
- tableSort: Object.assign(
272
- (options?: Parameters<typeof tableSort>[0]) => {
273
- const built = tableSort(options)
274
- return {
275
- header: built.header,
276
- button: toReactAttributes(built.button),
277
- }
278
- },
279
- { isDirection: tableSort.isDirection },
280
- ),
281
- tag: forReact(tag),
282
- textarea: forReact(textarea),
283
-
263
+ /** The type of `lt` in `/react`. */
264
+ export type ReactLt = ForReact & {
284
265
  /**
285
- * Wires a whole field, with `className` and `htmlFor` on the label.
286
- *
287
- * `control`, `help` and `error` have no keys that need renaming, and are
288
- * therefore the same in both entry points.
266
+ * The whole state, not just the links: React reports a mismatch for every
267
+ * attribute the component writes on an element React has rendered. See
268
+ * `tabsWithState`.
289
269
  */
290
- field: (options: FieldOptions) => {
291
- const field = computeFieldAttributes(options)
292
- return { ...field, label: toReactAttributes(field.label) }
293
- },
294
-
270
+ readonly tabs: (
271
+ options: TabsWithStateOptions,
272
+ ) => ReactResult<ReturnType<typeof tabsWithState>>
295
273
  /**
296
- * The compound builder functions return one attribute set per element,
297
- * and each set must be renamed on its own. `host` has `tabindex`, and the
298
- * panels in `lt.tabs()` have both `tabindex` and `class`.
274
+ * With `aria-expanded`, which `<lt-term>` writes: React reports a mismatch
275
+ * for an attribute it did not render. See `termWithState`.
299
276
  */
300
- errorSummary: (options: Parameters<typeof errorSummary>[0] = {}) => {
301
- const built = errorSummary(options)
302
- return {
303
- host: toReactAttributes(built.host),
304
- title: toReactAttributes(built.title),
305
- }
306
- },
307
-
308
- dialog: Object.assign(
309
- (options: Parameters<typeof dialog>[0]) => {
310
- const built = dialog(options)
311
- return {
312
- host: built.host,
313
- dialog: toReactAttributes(built.dialog),
314
- header: toReactAttributes(built.header),
315
- title: toReactAttributes(built.title),
316
- subtitle: toReactAttributes(built.subtitle),
317
- body: toReactAttributes(built.body),
318
- footer: toReactAttributes(built.footer),
319
- }
320
- },
321
- {
322
- dialog: dialog.dialog,
323
- header: dialog.header,
324
- title: dialog.title,
325
- subtitle: dialog.subtitle,
326
- body: dialog.body,
327
- footer: dialog.footer,
328
- colors: dialog.colors,
329
- isColor: dialog.isColor,
330
- },
331
- ),
277
+ readonly term: (
278
+ options: Parameters<typeof termWithState>[0],
279
+ ) => ReactResult<ReturnType<typeof termWithState>>
280
+ /** Like `lt.setAttributes` in the main entry, for the sets from here. */
281
+ readonly setAttributes: typeof setAttributes
282
+ }
332
283
 
333
- popover: Object.assign(
334
- (options: Parameters<typeof popover>[0]) => {
335
- const built = popover(options)
336
- return {
337
- host: built.host,
338
- trigger: toReactAttributes(built.trigger),
339
- panel: toReactAttributes(built.panel),
340
- }
341
- },
342
- { isPlacement: popover.isPlacement },
343
- ),
284
+ /**
285
+ * Every builder function from the main entry, with the React names. A new
286
+ * component comes along by itself; only the exceptions stand here.
287
+ */
288
+ export const lt: ReactLt = {
289
+ ...everyBuilder(),
344
290
 
345
291
  /**
346
292
  * The whole state, not just the links: React reports a mismatch for every
347
293
  * attribute the component writes on an element React has rendered. See
348
294
  * `tabsWithState`.
349
295
  */
350
- tabs: (options: TabsWithStateOptions) => {
351
- const built = tabsWithState(options)
352
- return {
353
- list: toReactAttributes(built.list),
354
- item: toReactAttributes(built.item),
355
- tabs: built.tabs.map(toReactAttributes),
356
- panels: built.panels.map(toReactAttributes),
357
- }
358
- },
296
+ tabs: (options: TabsWithStateOptions) =>
297
+ toReactResult(tabsWithState(options)) as ReactResult<
298
+ ReturnType<typeof tabsWithState>
299
+ >,
359
300
 
360
301
  /**
361
302
  * With `aria-expanded`, which `<lt-term>` writes: React reports a mismatch
362
303
  * for an attribute it did not render. See `termWithState`.
363
304
  */
364
- term: (options: Parameters<typeof termWithState>[0]) => {
365
- const built = termWithState(options)
366
- return {
367
- word: toReactAttributes(built.word),
368
- entry: toReactAttributes(built.entry),
369
- }
370
- },
371
-
372
- suggestion: (options: Parameters<typeof suggestion>[0]) => {
373
- const built = suggestion(options)
374
- return {
375
- ...built,
376
- label: toReactAttributes(built.label),
377
- control: toReactAttributes(built.control),
378
- list: toReactAttributes(built.list),
379
- options: built.options.map(toReactAttributes),
380
- empty: toReactAttributes(built.empty),
381
- status: toReactAttributes(built.status),
382
- value: toReactAttributes(built.value),
383
- }
384
- },
385
-
386
- toast: (options: Parameters<typeof toast>[0] = {}) => {
387
- const built = toast(options)
388
- return {
389
- host: toReactAttributes(built.host),
390
- message: toReactAttributes(built.message),
391
- close: toReactAttributes(built.close),
392
- }
393
- },
394
-
395
- sessionTimeout: Object.assign(
396
- (options: Parameters<typeof sessionTimeout>[0]) => {
397
- const built = sessionTimeout(options)
398
- return {
399
- host: toReactAttributes(built.host),
400
- dialog: toReactAttributes(built.dialog),
401
- title: toReactAttributes(built.title),
402
- text: toReactAttributes(built.text),
403
- count: toReactAttributes(built.count),
404
- live: toReactAttributes(built.live),
405
- actions: toReactAttributes(built.actions),
406
- extend: toReactAttributes(built.extend),
407
- logout: toReactAttributes(built.logout),
408
- }
409
- },
410
- {
411
- dialog: sessionTimeout.dialog,
412
- title: sessionTimeout.title,
413
- text: sessionTimeout.text,
414
- count: sessionTimeout.count,
415
- actions: sessionTimeout.actions,
416
- },
417
- ),
418
- connectionStatus: forReact(connectionStatus),
305
+ term: (options: Parameters<typeof termWithState>[0]) =>
306
+ toReactResult(termWithState(options)) as ReactResult<
307
+ ReturnType<typeof termWithState>
308
+ >,
419
309
 
420
310
  setAttributes,
421
-
422
- states: fieldStates,
423
- isState: isFieldState,
424
- markers: requiredMarkers,
425
- isMarker: isRequiredMarker,
426
- } as const
311
+ }
package/web-types.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json",
3
3
  "name": "@lo-tek/interfaces",
4
- "version": "0.41.0",
4
+ "version": "0.43.0",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {