@lo-tek/interfaces 0.39.0 → 0.41.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.
- package/CHANGELOG.md +178 -0
- package/README.md +1 -1
- package/agent/astro.md +16 -14
- package/agent/bundles.md +18 -16
- package/agent/datastar.md +70 -68
- package/agent/html.md +63 -61
- package/agent/kotlin.md +622 -0
- package/agent/react.md +18 -16
- package/agent/templates.md +72 -68
- package/core/lotek-core.wasm +0 -0
- package/core/lotek.wasm +0 -0
- package/dist/components/css/accordion/accordion.d.ts +1 -1
- package/dist/components/css/accordion/accordion.js +1 -1
- package/dist/components/css/alert/alert.d.ts +1 -1
- package/dist/components/css/alert/alert.js +1 -1
- package/dist/components/css/avatar/avatar.d.ts +1 -1
- package/dist/components/css/avatar/avatar.js +1 -1
- package/dist/components/css/badge/badge.d.ts +1 -1
- package/dist/components/css/badge/badge.js +1 -1
- package/dist/components/css/breadcrumbs/breadcrumbs.d.ts +1 -1
- package/dist/components/css/breadcrumbs/breadcrumbs.js +1 -1
- package/dist/components/css/card/card.d.ts +1 -1
- package/dist/components/css/card/card.js +1 -1
- package/dist/components/css/file-upload/file-upload.d.ts +1 -1
- package/dist/components/css/file-upload/file-upload.js +1 -1
- package/dist/components/css/icon/icon.d.ts +1 -1
- package/dist/components/css/icon/icon.js +1 -1
- package/dist/components/css/label/label.d.ts +1 -1
- package/dist/components/css/label/label.js +1 -1
- package/dist/components/css/link/link.d.ts +1 -1
- package/dist/components/css/link/link.js +1 -1
- package/dist/components/css/spinner/spinner.d.ts +7 -5
- package/dist/components/css/spinner/spinner.d.ts.map +1 -1
- package/dist/components/css/spinner/spinner.js +7 -5
- package/dist/components/css/spinner/spinner.js.map +1 -1
- package/dist/components/css/steps/steps.d.ts +23 -0
- package/dist/components/css/steps/steps.d.ts.map +1 -0
- package/dist/components/css/steps/steps.js +21 -0
- package/dist/components/css/steps/steps.js.map +1 -0
- package/dist/components/css/tag/tag.d.ts +1 -1
- package/dist/components/css/tag/tag.js +1 -1
- package/dist/components/css/toggle-group/toggle-group.d.ts +1 -1
- package/dist/components/css/toggle-group/toggle-group.js +1 -1
- package/dist/components/css/tooltip/tooltip.d.ts +2 -2
- package/dist/components/css/tooltip/tooltip.js +2 -2
- package/dist/components/events.d.ts +3 -1
- package/dist/components/events.d.ts.map +1 -1
- package/dist/components/frame/dialog/dialog.d.ts +11 -6
- package/dist/components/frame/dialog/dialog.d.ts.map +1 -1
- package/dist/components/frame/dialog/dialog.js +4 -4
- package/dist/components/frame/dialog/dialog.js.map +1 -1
- package/dist/components/frame/dialog/lt-dialog.d.ts +1 -1
- package/dist/components/frame/dialog/lt-dialog.js +7 -7
- package/dist/components/frame/error-summary/error-summary.d.ts +6 -2
- package/dist/components/frame/error-summary/error-summary.d.ts.map +1 -1
- package/dist/components/frame/error-summary/error-summary.js +1 -1
- package/dist/components/frame/error-summary/error-summary.js.map +1 -1
- package/dist/components/frame/error-summary/lt-error-summary.d.ts +1 -1
- package/dist/components/frame/error-summary/lt-error-summary.js +6 -6
- package/dist/components/frame/field/field-core.d.ts +4 -2
- package/dist/components/frame/field/field-core.d.ts.map +1 -1
- package/dist/components/frame/field/field-core.js.map +1 -1
- package/dist/components/frame/field/lt-field.d.ts +5 -4
- package/dist/components/frame/field/lt-field.d.ts.map +1 -1
- package/dist/components/frame/field/lt-field.js +5 -4
- package/dist/components/frame/field/lt-field.js.map +1 -1
- package/dist/components/frame/popover/lt-popover.d.ts +3 -3
- package/dist/components/frame/popover/lt-popover.d.ts.map +1 -1
- package/dist/components/frame/popover/lt-popover.js +7 -22
- package/dist/components/frame/popover/lt-popover.js.map +1 -1
- package/dist/components/frame/popover/popover.d.ts +7 -3
- package/dist/components/frame/popover/popover.d.ts.map +1 -1
- package/dist/components/frame/popover/popover.js +2 -2
- package/dist/components/frame/popover/popover.js.map +1 -1
- package/dist/components/frame/session-timeout/lt-session-timeout.d.ts +8 -8
- package/dist/components/frame/session-timeout/lt-session-timeout.js +7 -7
- package/dist/components/frame/session-timeout/session-timeout.d.ts +10 -5
- package/dist/components/frame/session-timeout/session-timeout.d.ts.map +1 -1
- package/dist/components/frame/session-timeout/session-timeout.js +4 -4
- package/dist/components/frame/session-timeout/session-timeout.js.map +1 -1
- package/dist/components/frame/suggestion/lt-suggestion.d.ts +12 -11
- package/dist/components/frame/suggestion/lt-suggestion.d.ts.map +1 -1
- package/dist/components/frame/suggestion/lt-suggestion.js +11 -10
- package/dist/components/frame/suggestion/lt-suggestion.js.map +1 -1
- package/dist/components/frame/suggestion/suggestion.d.ts +3 -1
- package/dist/components/frame/suggestion/suggestion.d.ts.map +1 -1
- package/dist/components/frame/suggestion/suggestion.js.map +1 -1
- package/dist/components/frame/tabs/lt-tabs.d.ts +3 -3
- package/dist/components/frame/tabs/lt-tabs.js +5 -5
- package/dist/components/frame/tabs/lt-tabs.js.map +1 -1
- package/dist/components/frame/tabs/tabs.d.ts +8 -6
- package/dist/components/frame/tabs/tabs.d.ts.map +1 -1
- package/dist/components/frame/tabs/tabs.js +4 -4
- package/dist/components/frame/tabs/tabs.js.map +1 -1
- package/dist/components/frame/term/lt-term.d.ts +114 -0
- package/dist/components/frame/term/lt-term.d.ts.map +1 -0
- package/dist/components/frame/term/lt-term.js +530 -0
- package/dist/components/frame/term/lt-term.js.map +1 -0
- package/dist/components/frame/term/term.d.ts +55 -0
- package/dist/components/frame/term/term.d.ts.map +1 -0
- package/dist/components/frame/term/term.js +55 -0
- package/dist/components/frame/term/term.js.map +1 -0
- package/dist/components/host-element.d.ts +19 -0
- package/dist/components/host-element.d.ts.map +1 -1
- package/dist/components/host-element.js +37 -0
- package/dist/components/host-element.js.map +1 -1
- package/dist/components/standalone/connection-status/lt-connection-status.d.ts +1 -1
- package/dist/components/standalone/connection-status/lt-connection-status.js +1 -1
- package/dist/components/standalone/toast/lt-toast.d.ts +1 -1
- package/dist/components/standalone/toast/lt-toast.js +1 -1
- package/dist/diagnostics/index.d.ts +2 -2
- package/dist/diagnostics/index.js +2 -2
- package/dist/dom.d.ts +2 -1
- package/dist/dom.d.ts.map +1 -1
- package/dist/dom.js +2 -1
- package/dist/dom.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/jsx/react.d.ts +3 -1
- package/dist/jsx/react.d.ts.map +1 -1
- package/dist/lotek.css +370 -1
- package/dist/lt.d.ts +13 -6
- package/dist/lt.d.ts.map +1 -1
- package/dist/lt.js +14 -6
- package/dist/lt.js.map +1 -1
- package/dist/react.d.ts +19 -0
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +14 -0
- package/dist/react.js.map +1 -1
- package/dist/register.d.ts.map +1 -1
- package/dist/register.js +2 -0
- package/dist/register.js.map +1 -1
- package/dist/vocabulary/classes.d.ts.map +1 -1
- package/dist/vocabulary/classes.js +60 -6
- package/dist/vocabulary/classes.js.map +1 -1
- package/dist/vocabulary/elements.d.ts.map +1 -1
- package/dist/vocabulary/elements.js +16 -3
- package/dist/vocabulary/elements.js.map +1 -1
- package/dist/vocabulary/types.d.ts +28 -3
- package/dist/vocabulary/types.d.ts.map +1 -1
- package/live-templates-kotlin.xml +69 -0
- package/live-templates.xml +29 -23
- package/manifest/files.json +18 -0
- package/manifest/manifest.json +510 -87
- package/manifest/manifest.schema.json +54 -7
- package/package.json +16 -5
- package/src/components/css/accordion/accordion.ts +1 -1
- package/src/components/css/alert/alert.ts +1 -1
- package/src/components/css/avatar/avatar.ts +1 -1
- package/src/components/css/badge/badge.ts +1 -1
- package/src/components/css/breadcrumbs/breadcrumbs.ts +1 -1
- package/src/components/css/card/card.ts +1 -1
- package/src/components/css/file-upload/file-upload.ts +1 -1
- package/src/components/css/icon/icon.ts +1 -1
- package/src/components/css/input/input.css +21 -0
- package/src/components/css/label/label.ts +1 -1
- package/src/components/css/link/link.ts +1 -1
- package/src/components/css/spinner/spinner.ts +8 -5
- package/src/components/css/steps/steps.css +240 -0
- package/src/components/css/steps/steps.ts +26 -0
- package/src/components/css/tag/tag.ts +1 -1
- package/src/components/css/toggle-group/toggle-group.ts +1 -1
- package/src/components/css/tooltip/tooltip.ts +2 -2
- package/src/components/events.ts +3 -1
- package/src/components/frame/dialog/dialog.ts +11 -6
- package/src/components/frame/dialog/lt-dialog.ts +7 -7
- package/src/components/frame/error-summary/error-summary.ts +6 -2
- package/src/components/frame/error-summary/lt-error-summary.ts +6 -6
- package/src/components/frame/field/field-core.ts +4 -2
- package/src/components/frame/field/lt-field.ts +5 -4
- package/src/components/frame/popover/lt-popover.ts +7 -27
- package/src/components/frame/popover/popover.ts +7 -3
- package/src/components/frame/session-timeout/lt-session-timeout.ts +8 -8
- package/src/components/frame/session-timeout/session-timeout.ts +10 -5
- package/src/components/frame/suggestion/lt-suggestion.ts +13 -12
- package/src/components/frame/suggestion/suggestion.css +1 -1
- package/src/components/frame/suggestion/suggestion.ts +3 -1
- package/src/components/frame/tabs/lt-tabs.ts +5 -5
- package/src/components/frame/tabs/tabs.css +1 -1
- package/src/components/frame/tabs/tabs.ts +8 -6
- package/src/components/frame/term/lt-term.ts +573 -0
- package/src/components/frame/term/term.css +177 -0
- package/src/components/frame/term/term.ts +87 -0
- package/src/components/host-element.ts +46 -0
- package/src/components/standalone/connection-status/lt-connection-status.ts +1 -1
- package/src/components/standalone/toast/lt-toast.ts +1 -1
- package/src/diagnostics/index.ts +2 -2
- package/src/dom.ts +2 -1
- package/src/index.ts +4 -0
- package/src/jsx/react.ts +4 -0
- package/src/lt.ts +14 -6
- package/src/react.ts +15 -0
- package/src/register.ts +2 -0
- package/src/tokens/boundary.css +4 -0
- package/src/tokens/tokens.css +4 -0
- package/src/vocabulary/classes.ts +60 -6
- package/src/vocabulary/elements.ts +16 -3
- package/src/vocabulary/types.ts +25 -3
- package/web-types.json +32 -11
package/CHANGELOG.md
CHANGED
|
@@ -24,6 +24,184 @@ including 0.36.0 were written in Norwegian, and list them under "Brytende".
|
|
|
24
24
|
|
|
25
25
|
## Unreleased
|
|
26
26
|
|
|
27
|
+
## 0.41.0 (2026-11-05)
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **A rulebook for coding agents on a Kotlin or Java server, `agent/kotlin.md`.**
|
|
32
|
+
It covers `Lt` with a table of every enum and its constants, kotlinx.html
|
|
33
|
+
and strings, the WebJar and `LotekWebJar`, ids from a key in the data,
|
|
34
|
+
`assertLotek` in tests, the Gradle plugin and `lotek.jar`. `llms.txt`
|
|
35
|
+
names Kotlin and the check without Node.
|
|
36
|
+
- **`<lt-term>` and `lt.term()`: a word in the text that shows its entry
|
|
37
|
+
from a glossary on the same page.** The word is a link to the entry, a
|
|
38
|
+
`<div>` with a `<dt>` and a `<dd>` in a `<dl>`, and stays one without
|
|
39
|
+
JavaScript. The web component shows the entry itself as a card by the
|
|
40
|
+
word, in the top layer: the mouse opens it after a rest, a click, a tap or
|
|
41
|
+
Enter pins it, and Escape, a click outside or the word scrolling out of
|
|
42
|
+
view closes it. Below the `sm` breakpoint the card is a sheet across the
|
|
43
|
+
bottom of the window, or the top when the word is down there. Nothing is
|
|
44
|
+
copied and no id is made in the browser, so the card survives an update
|
|
45
|
+
from the server. `lt.term({ id })` writes `href` and `aria-details` on the
|
|
46
|
+
link, the classes `lt-term` and `lt-term__entry`, and the id; `/react`
|
|
47
|
+
adds `aria-expanded="false"`. `Lt.term()` in Kotlin, and `ltTerm` and
|
|
48
|
+
`ltTermEntry` in kotlinx.html. New entry points `./term` and
|
|
49
|
+
`./term.css`, new component variables `--lt-term-width`,
|
|
50
|
+
`--lt-term-gap`, `--lt-term-padding`, `--lt-term-radius`,
|
|
51
|
+
`--lt-term-accent-color`, `--lt-term-underline-color`,
|
|
52
|
+
`--lt-term-label-text`, `--lt-term-label-font` and
|
|
53
|
+
`--lt-term-sheet-height`, and the default text "Glossary".
|
|
54
|
+
- **`lt-steps` and `lt.steps()`: a step indicator for a task over several
|
|
55
|
+
pages.** The class goes on an `<ol>` with one `<li>` per step, and
|
|
56
|
+
`aria-current="step"` on the step the user is on. The steps before it are
|
|
57
|
+
drawn as done, with a check the screen reader reads as "Completed", as part
|
|
58
|
+
of the step's link when it has one. Below `28rem` of the list's own width
|
|
59
|
+
the steps stand in a column. `Lt.steps()` in Kotlin. New entry points
|
|
60
|
+
`./steps` and `./steps.css`, new component variables
|
|
61
|
+
`--lt-steps-marker-size`, `--lt-steps-done-icon` and
|
|
62
|
+
`--lt-steps-done-text`, and the default text
|
|
63
|
+
"Completed ".
|
|
64
|
+
- **The check reports `untranslated-text` for the step indicator's
|
|
65
|
+
"Completed "** on a page in another language, as for the other texts in
|
|
66
|
+
the stylesheets. In the manifest's `texts` on a class,
|
|
67
|
+
`siblingsBefore: true` is a text shown on the children before the one with
|
|
68
|
+
the attribute, and the Kotlin `CssText` has `siblingsBefore`. The term's
|
|
69
|
+
"Glossary" is not checked, since the card shows it only while it is open.
|
|
70
|
+
- **The check reports `term-without-entry`** on a whole page, when a word
|
|
71
|
+
in `<lt-term>` points at an id the page does not have, or at something
|
|
72
|
+
that is not a glossary entry.
|
|
73
|
+
- **`place()` in `@lo-tek/interfaces/host-element`**, the placement
|
|
74
|
+
`<lt-popover>` worked out, now shared with `<lt-term>`.
|
|
75
|
+
|
|
76
|
+
### Changed
|
|
77
|
+
|
|
78
|
+
- **`lotek agent` gives the Kotlin rulebook in a folder with
|
|
79
|
+
`build.gradle.kts`, `build.gradle`, `settings.gradle.kts`,
|
|
80
|
+
`settings.gradle` or `pom.xml`,** unless `package.json` names a framework
|
|
81
|
+
other than Vite. Such a folder used to get `templates`, or `bundles` when it
|
|
82
|
+
also had a `package.json`. `--framework=templates` and
|
|
83
|
+
`--framework=bundles` still give those.
|
|
84
|
+
|
|
85
|
+
### Fixed
|
|
86
|
+
|
|
87
|
+
- **The snippets and the live templates follow the corrected recipes.** In
|
|
88
|
+
the HTML snippets and live templates the error summary and the field post
|
|
89
|
+
to the server, the popover's actions are forms that post, and the session
|
|
90
|
+
timeout logs out with a post. In the Kotlin live templates the error
|
|
91
|
+
summary has no script, and it and the field take what was typed; the
|
|
92
|
+
popover, the tabs and the suggestion have no script; the dialog's Cancel
|
|
93
|
+
and the session timeout's Log out post to the server; and the toast tells
|
|
94
|
+
a refused restart from one that got no answer, and a redirect from a
|
|
95
|
+
restart. The switch saves only an answer that is not a redirect, and
|
|
96
|
+
stands in a `<form autocomplete="off">`, since HTML does not allow the
|
|
97
|
+
attribute on a checkbox. The Kotlin live template for the error summary
|
|
98
|
+
inserted the browser validation from the HTML recipe, which a Kotlin
|
|
99
|
+
server does itself.
|
|
100
|
+
- **The editor descriptions of `session-logout` and `<lt-dialog>`.**
|
|
101
|
+
`session-logout` comes only from a Log out button that closes the dialog;
|
|
102
|
+
one with `formmethod="post"` submits instead. `<lt-dialog>` makes a dialog
|
|
103
|
+
the server sends open a real modal.
|
|
104
|
+
|
|
105
|
+
## 0.40.0 (2026-11-03)
|
|
106
|
+
|
|
107
|
+
### Breaking
|
|
108
|
+
|
|
109
|
+
- **`lt.spinner()` without `label` writes `aria-hidden="true"`,** as
|
|
110
|
+
`lt.icon()` without a label does. The page told you to write it yourself,
|
|
111
|
+
so the HTML tab had it and the TypeScript tab had it by hand. A spinner
|
|
112
|
+
named by hand, `lt.spinner()` with `role="status"` and `aria-label` written
|
|
113
|
+
next to it, is now hidden from screen readers: pass the name as `label`,
|
|
114
|
+
which gives the role and the name and no `aria-hidden`.
|
|
115
|
+
- **In Kotlin every builder function is a member of `Lt`.** `field`,
|
|
116
|
+
`suggestion`, `tabs`, `errorSummary`, `label` and `legend` were extension
|
|
117
|
+
functions on `Lt` in `Handwritten.kt`. A call such as `Lt.field(…)` reads
|
|
118
|
+
the same, but `import no.lotek.field` no longer compiles and has to go,
|
|
119
|
+
and code compiled against the old version calls a method that is gone, so
|
|
120
|
+
it must be compiled again.
|
|
121
|
+
|
|
122
|
+
### Added
|
|
123
|
+
|
|
124
|
+
- **Each builder function in the manifest has `description`, `example` and
|
|
125
|
+
`docs`, and an option with a closed list has `default`.** The description
|
|
126
|
+
is the comment on the function in TypeScript without the code examples,
|
|
127
|
+
the example is those examples, and `docs` is the component page. The
|
|
128
|
+
default is read from the answers: the value that gives the same answer as
|
|
129
|
+
leaving the option out, and the build stops when the comment on the
|
|
130
|
+
option names another one. A builder function with several sets has
|
|
131
|
+
`parts`, which says which part of a web component each set fills:
|
|
132
|
+
`field.control` fills `control` in `lt-field`, with its selector there.
|
|
133
|
+
All are optional, so `schemaVersion` is still 1, and a manifest from
|
|
134
|
+
before reads as before.
|
|
135
|
+
- **The Kotlin API has the documentation from the manifest.** Every member
|
|
136
|
+
of `Lt` has the description, an example call, a link to the component
|
|
137
|
+
page and an `@param` per option with the default as the Kotlin constant,
|
|
138
|
+
in the sources jar, so IntelliJ shows it in Quick Documentation.
|
|
139
|
+
- **The builder functions can be called from Java.** They are `@JvmStatic`
|
|
140
|
+
and `@JvmOverloads`, with the required options first, `ButtonVariant.of(…)`
|
|
141
|
+
and the other lookups are static, and `Lt.card.title` is a field:
|
|
142
|
+
`Lt.field("fixer")` rather than `HandwrittenKt.field(Lt.INSTANCE, "fixer",
|
|
143
|
+
null, …)`. In Kotlin the options are passed by name as before, but
|
|
144
|
+
`Lt.suggestion` called with its options in order now has `id` first.
|
|
145
|
+
`JavaCallTest` compiles the calls in Java.
|
|
146
|
+
- **`lo-tek-kotlinx-html` has one function per web component**, such as
|
|
147
|
+
`ltField { … }` and `ltTabs { … }`, since kotlinx.html knows only the
|
|
148
|
+
elements in HTML.
|
|
149
|
+
- **`live-templates-kotlin.xml`, live templates for Kotlin in IntelliJ,**
|
|
150
|
+
one per web component, generated from the kotlinx.html tab on its page.
|
|
151
|
+
The ids are empty variables, as in `live-templates.xml`.
|
|
152
|
+
- **Every component page has a kotlinx.html tab,** for a Kotlin or Java
|
|
153
|
+
server with `lo-tek-kotlinx-html`. `RecipesTest` compiles each, renders it,
|
|
154
|
+
and requires the elements, the texts, the classes and the attributes of
|
|
155
|
+
the page's HTML recipe, with `lotek check` on the result.
|
|
156
|
+
|
|
157
|
+
### Changed
|
|
158
|
+
|
|
159
|
+
- **The snippets and the live templates leave the ids empty.** They filled
|
|
160
|
+
in the id from the recipe, such as `codename`, and a snippet pasted twice
|
|
161
|
+
on a page, or in a loop, then gave two fields with the same id, which a
|
|
162
|
+
morph matches wrongly. The id is still one tab stop, mirrored in `for`
|
|
163
|
+
and `href`.
|
|
164
|
+
- **The documentation says "with a builder function" where it said "with
|
|
165
|
+
JavaScript".** A Kotlin or Java server renders without JavaScript and calls
|
|
166
|
+
`Lt.field()` all the same, so the line between `lt.field()` and
|
|
167
|
+
`<lt-field>` is whether the code that renders can call a builder function.
|
|
168
|
+
The description of `<lt-field>` in the vocabulary, which the editors show,
|
|
169
|
+
says the same.
|
|
170
|
+
- **The documentation of every id option says to make it from a key in the
|
|
171
|
+
data**, never from the loop index or a counter, so it is unique on the
|
|
172
|
+
page and the same on every render. The message when `Lt.field` and the
|
|
173
|
+
others get an empty id in Kotlin says the same; it used to suggest "the
|
|
174
|
+
field's name or another fixed id", which in a loop is the duplicate.
|
|
175
|
+
- **The examples come from the world LO-TEK belongs to, not from a housing
|
|
176
|
+
benefit application.** Every recipe, demo, snippet, live template and
|
|
177
|
+
rulebook now shows a system LO-TEK delivered to a client: the job
|
|
178
|
+
console on floor 222, the operations console of Meridian Lattice, a claim
|
|
179
|
+
at Aster & Vale, and others. Each component page shows one client, and the
|
|
180
|
+
pages on accessibility stay neutral. The markup, the classes and the
|
|
181
|
+
attributes are the same as before; only the text, the ids and the values
|
|
182
|
+
in the examples have changed. The warning `<lt-tabs>` gives for a tab list
|
|
183
|
+
without a name suggests `aria-label="Parts of the claim"`.
|
|
184
|
+
|
|
185
|
+
### Fixed
|
|
186
|
+
|
|
187
|
+
- **The recipe for the connection status reports a server that stopped
|
|
188
|
+
answering.** Its script declared `saveRoute` inside a module, where no
|
|
189
|
+
other code on the page could call it, and called the methods without
|
|
190
|
+
waiting for the registration. It now puts `saveRoute` on `window`, where
|
|
191
|
+
the app's other scripts call it, as a comment there shows. It sends the
|
|
192
|
+
request first, counts a request without an answer and a gateway's 502, 503
|
|
193
|
+
or 504 as a lost connection and any other answer as the server being
|
|
194
|
+
there. It reports with `reportSuccess` and `reportFailure`, which wait for
|
|
195
|
+
the registration, and returns the answer without awaiting them. The React
|
|
196
|
+
tab and the example under "`navigator.onLine` is not enough" follow the
|
|
197
|
+
same rule.
|
|
198
|
+
|
|
199
|
+
- **A date or time field fits its container in iOS Safari.** With the
|
|
200
|
+
native appearance, `.lt-input` with `data-variant` `date`, `time` or
|
|
201
|
+
`datetime-local` stood wider than the form around it. In iOS Safari
|
|
202
|
+
these fields now have `appearance: none`, and the value starts at the
|
|
203
|
+
start of the field.
|
|
204
|
+
|
|
27
205
|
## 0.39.0 (2026-11-01)
|
|
28
206
|
|
|
29
207
|
### Added
|
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ Without a build step you link the combined file, which has everything in it:
|
|
|
36
36
|
The markup is the same whichever of the two you chose:
|
|
37
37
|
|
|
38
38
|
```html
|
|
39
|
-
<button class="lt-button">
|
|
39
|
+
<button class="lt-button">Order the job</button>
|
|
40
40
|
<button class="lt-button" data-variant="secondary">Save draft</button>
|
|
41
41
|
```
|
|
42
42
|
|
package/agent/astro.md
CHANGED
|
@@ -9,7 +9,7 @@ this runs at build time: out comes plain HTML, and `lt` is gone once the page
|
|
|
9
9
|
is built. The only JavaScript the browser gets from the package is the
|
|
10
10
|
registration of the web components you use, in a `<script>`.
|
|
11
11
|
|
|
12
|
-
This is @lo-tek/interfaces 0.
|
|
12
|
+
This is @lo-tek/interfaces 0.41.0. The file is generated by the package and
|
|
13
13
|
follows its version, so it can never say anything other than the code next to
|
|
14
14
|
it.
|
|
15
15
|
|
|
@@ -59,7 +59,7 @@ component, `tokens.css` belongs there, once for the whole page.
|
|
|
59
59
|
|
|
60
60
|
## 2. What exists
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
36 CSS components and 10 web components, and this is the whole list. The
|
|
63
63
|
classes are `lt-` + kebab-case. Variants are always `data-*` attributes, never
|
|
64
64
|
classes of their own: `data-variant="secondary"`, not `lt-button--secondary`.
|
|
65
65
|
The default variant has no attribute.
|
|
@@ -97,6 +97,7 @@ The default variant has no attribute.
|
|
|
97
97
|
| `lt-skip-link` | `@lo-tek/interfaces/skip-link.css` | none |
|
|
98
98
|
| `lt-spinner` | `@lo-tek/interfaces/spinner.css` | `data-size`: small, large |
|
|
99
99
|
| `lt-sr-only` | `@lo-tek/interfaces/sr-only.css` | none |
|
|
100
|
+
| `lt-steps` | `@lo-tek/interfaces/steps.css` | none |
|
|
100
101
|
| `lt-switch`<br>`lt-switch-row` | `@lo-tek/interfaces/switch.css` | none |
|
|
101
102
|
| `lt-table`<br>`lt-table__sort`<br>`lt-table-scroll` | `@lo-tek/interfaces/table.css` | `data-variant`: striped<br>`data-hoverable` (flag) |
|
|
102
103
|
| `lt-tag` | `@lo-tek/interfaces/tag.css` | `data-variant`: filled<br>`data-selectable` (flag) |
|
|
@@ -279,6 +280,7 @@ Three rules apply to all of them:
|
|
|
279
280
|
| `<lt-tabs>` | frame | `@lo-tek/interfaces/tabs.css` | `defineLtTabs()` from `@lo-tek/interfaces/tabs` | `server-controlled` (flag)<br>`activation`: manual, automatic | `tab-select` (index) | `lt-tabs__list`<br>`lt-tabs__panel` |
|
|
280
281
|
| `<lt-error-summary>` | frame | `@lo-tek/interfaces/error-summary.css` | `defineLtErrorSummary()` from `@lo-tek/interfaces/error-summary` | `data-autofocus`: false, true<br>`hidden` (flag) | none | `lt-error-summary`<br>`lt-error-summary__title` |
|
|
281
282
|
| `<lt-popover>` | frame | `@lo-tek/interfaces/popover.css` | `defineLtPopover()` from `@lo-tek/interfaces/popover` | `open` (flag)<br>`placement`: bottom-start, bottom-end, top-start, top-end<br>`server-controlled` (flag) | `popover-toggle` (open) | `lt-popover` |
|
|
283
|
+
| `<lt-term>` | frame | `@lo-tek/interfaces/term.css` | `defineLtTerm()` from `@lo-tek/interfaces/term` | none | none | `lt-term`<br>`lt-term__entry` |
|
|
282
284
|
| `<lt-suggestion>` | frame | `@lo-tek/interfaces/suggestion.css` | `defineLtSuggestion()` from `@lo-tek/interfaces/suggestion` | `prefiltered` (flag)<br>`count-none` (text)<br>`count-zero` (text)<br>`count-one` (text)<br>`count-two` (text)<br>`count-few` (text)<br>`count-many` (text)<br>`count-other` (text)<br>`server-controlled` (flag) | `suggestion-select` (value, label) | `lt-suggestion__list`<br>`lt-suggestion__option`<br>`lt-suggestion__value`<br>`lt-suggestion__empty` |
|
|
283
285
|
| `<lt-dialog>` | frame | `@lo-tek/interfaces/dialog.css` | `defineLtDialog()` from `@lo-tek/interfaces/dialog` | `open` (flag)<br>`server-controlled` (flag) | `dialog-toggle` (open, returnValue) | `lt-dialog` (`data-color`: brand, info, success, warning, danger)<br>`lt-dialog__body`<br>`lt-dialog__title`<br>`lt-dialog__footer`<br>`lt-dialog__header`<br>`lt-dialog__subtitle` |
|
|
284
286
|
| `<lt-toast>` | standalone | `@lo-tek/interfaces/toast.css` | `defineLtToast()` from `@lo-tek/interfaces/toast` | `duration` (number)<br>`label` (text)<br>`close-label` (text) | `toast-dismiss` | `lt-toast`<br>`lt-toast__message`<br>`lt-toast__close` |
|
|
@@ -309,7 +311,7 @@ Runs at build time. Out comes plain HTML:
|
|
|
309
311
|
<span class="lt-badge" data-color="success">Approved</span>
|
|
310
312
|
```
|
|
311
313
|
|
|
312
|
-
`lt` is imported from the main entry, which gives `class` and `for`. The
|
|
314
|
+
`lt` is imported from the main entry, which gives `class` and `for`. The 48
|
|
313
315
|
builder functions:
|
|
314
316
|
|
|
315
317
|
`lt.accordion()`, `lt.alert()`, `lt.avatar()`, `lt.badge()`,
|
|
@@ -320,9 +322,9 @@ builder functions:
|
|
|
320
322
|
`lt.legend()`, `lt.link()`, `lt.list()`, `lt.pagination()`, `lt.paragraph()`,
|
|
321
323
|
`lt.popover()`, `lt.progress()`, `lt.radio()`, `lt.search()`, `lt.select()`,
|
|
322
324
|
`lt.sessionTimeout()`, `lt.skeleton()`, `lt.skipLink()`, `lt.spinner()`,
|
|
323
|
-
`lt.srOnly()`, `lt.suggestion()`, `lt.switch()`, `lt.table()`,
|
|
324
|
-
`lt.tableSort()`, `lt.tabs()`, `lt.tag()`, `lt.
|
|
325
|
-
`lt.toggleGroup()`, `lt.tooltip()`
|
|
325
|
+
`lt.srOnly()`, `lt.steps()`, `lt.suggestion()`, `lt.switch()`, `lt.table()`,
|
|
326
|
+
`lt.tableSort()`, `lt.tabs()`, `lt.tag()`, `lt.term()`, `lt.textarea()`,
|
|
327
|
+
`lt.toast()`, `lt.toggleGroup()`, `lt.tooltip()`
|
|
326
328
|
|
|
327
329
|
## 6. Fields without JavaScript
|
|
328
330
|
|
|
@@ -335,13 +337,13 @@ import { lt } from "@lo-tek/interfaces"
|
|
|
335
337
|
import "@lo-tek/interfaces/tokens.css"
|
|
336
338
|
import "@lo-tek/interfaces/field.css"
|
|
337
339
|
|
|
338
|
-
const
|
|
340
|
+
const fixer = lt.field({ id: "fixer", required: "symbol", help: true, error: true })
|
|
339
341
|
---
|
|
340
342
|
|
|
341
|
-
<label {...
|
|
342
|
-
<input {...lt.input({ type: "email" })} {...
|
|
343
|
-
<p {...lt.helpText()} {...
|
|
344
|
-
<p {...lt.errorText()} {...
|
|
343
|
+
<label {...fixer.label}>Fixer's address</label>
|
|
344
|
+
<input {...lt.input({ type: "email" })} {...fixer.control} name="fixer" required />
|
|
345
|
+
<p {...lt.helpText()} {...fixer.help}>The board writes to the fixer, never to the crew.</p>
|
|
346
|
+
<p {...lt.errorText()} {...fixer.error}>Enter the fixer's address, for example fixer@relay.example.</p>
|
|
345
347
|
```
|
|
346
348
|
|
|
347
349
|
No `<lt-field>`, no runtime.
|
|
@@ -359,9 +361,9 @@ import "@lo-tek/interfaces/field.css"
|
|
|
359
361
|
---
|
|
360
362
|
|
|
361
363
|
<lt-field>
|
|
362
|
-
<label class="lt-label" for="
|
|
363
|
-
<input class="lt-input" id="
|
|
364
|
-
<p class="lt-error-text" hidden>Enter
|
|
364
|
+
<label class="lt-label" for="codename" data-required="symbol">Codename</label>
|
|
365
|
+
<input class="lt-input" id="codename" type="text" name="codename" required />
|
|
366
|
+
<p class="lt-error-text" hidden>Enter a codename.</p>
|
|
365
367
|
</lt-field>
|
|
366
368
|
|
|
367
369
|
<script>
|
package/agent/bundles.md
CHANGED
|
@@ -10,7 +10,7 @@ names, and `defineLt*()` runs at the top of `main.ts`. If you write React, the
|
|
|
10
10
|
attribute names differ and `react.md` applies instead. If you write Astro, the
|
|
11
11
|
stylesheets are imported in the frontmatter and `astro.md` applies.
|
|
12
12
|
|
|
13
|
-
This is @lo-tek/interfaces 0.
|
|
13
|
+
This is @lo-tek/interfaces 0.41.0. The file is generated by the package and
|
|
14
14
|
follows its version, so it can never say anything other than the code next to
|
|
15
15
|
it.
|
|
16
16
|
|
|
@@ -63,7 +63,7 @@ page does not use.
|
|
|
63
63
|
|
|
64
64
|
## 2. What exists
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
36 CSS components and 10 web components, and this is the whole list. The
|
|
67
67
|
classes are `lt-` + kebab-case. Variants are always `data-*` attributes, never
|
|
68
68
|
classes of their own: `data-variant="secondary"`, not `lt-button--secondary`.
|
|
69
69
|
The default variant has no attribute.
|
|
@@ -101,6 +101,7 @@ The default variant has no attribute.
|
|
|
101
101
|
| `lt-skip-link` | `@lo-tek/interfaces/skip-link.css` | none |
|
|
102
102
|
| `lt-spinner` | `@lo-tek/interfaces/spinner.css` | `data-size`: small, large |
|
|
103
103
|
| `lt-sr-only` | `@lo-tek/interfaces/sr-only.css` | none |
|
|
104
|
+
| `lt-steps` | `@lo-tek/interfaces/steps.css` | none |
|
|
104
105
|
| `lt-switch`<br>`lt-switch-row` | `@lo-tek/interfaces/switch.css` | none |
|
|
105
106
|
| `lt-table`<br>`lt-table__sort`<br>`lt-table-scroll` | `@lo-tek/interfaces/table.css` | `data-variant`: striped<br>`data-hoverable` (flag) |
|
|
106
107
|
| `lt-tag` | `@lo-tek/interfaces/tag.css` | `data-variant`: filled<br>`data-selectable` (flag) |
|
|
@@ -283,6 +284,7 @@ Three rules apply to all of them:
|
|
|
283
284
|
| `<lt-tabs>` | frame | `@lo-tek/interfaces/tabs.css` | `defineLtTabs()` from `@lo-tek/interfaces/tabs` | `server-controlled` (flag)<br>`activation`: manual, automatic | `tab-select` (index) | `lt-tabs__list`<br>`lt-tabs__panel` |
|
|
284
285
|
| `<lt-error-summary>` | frame | `@lo-tek/interfaces/error-summary.css` | `defineLtErrorSummary()` from `@lo-tek/interfaces/error-summary` | `data-autofocus`: false, true<br>`hidden` (flag) | none | `lt-error-summary`<br>`lt-error-summary__title` |
|
|
285
286
|
| `<lt-popover>` | frame | `@lo-tek/interfaces/popover.css` | `defineLtPopover()` from `@lo-tek/interfaces/popover` | `open` (flag)<br>`placement`: bottom-start, bottom-end, top-start, top-end<br>`server-controlled` (flag) | `popover-toggle` (open) | `lt-popover` |
|
|
287
|
+
| `<lt-term>` | frame | `@lo-tek/interfaces/term.css` | `defineLtTerm()` from `@lo-tek/interfaces/term` | none | none | `lt-term`<br>`lt-term__entry` |
|
|
286
288
|
| `<lt-suggestion>` | frame | `@lo-tek/interfaces/suggestion.css` | `defineLtSuggestion()` from `@lo-tek/interfaces/suggestion` | `prefiltered` (flag)<br>`count-none` (text)<br>`count-zero` (text)<br>`count-one` (text)<br>`count-two` (text)<br>`count-few` (text)<br>`count-many` (text)<br>`count-other` (text)<br>`server-controlled` (flag) | `suggestion-select` (value, label) | `lt-suggestion__list`<br>`lt-suggestion__option`<br>`lt-suggestion__value`<br>`lt-suggestion__empty` |
|
|
287
289
|
| `<lt-dialog>` | frame | `@lo-tek/interfaces/dialog.css` | `defineLtDialog()` from `@lo-tek/interfaces/dialog` | `open` (flag)<br>`server-controlled` (flag) | `dialog-toggle` (open, returnValue) | `lt-dialog` (`data-color`: brand, info, success, warning, danger)<br>`lt-dialog__body`<br>`lt-dialog__title`<br>`lt-dialog__footer`<br>`lt-dialog__header`<br>`lt-dialog__subtitle` |
|
|
288
290
|
| `<lt-toast>` | standalone | `@lo-tek/interfaces/toast.css` | `defineLtToast()` from `@lo-tek/interfaces/toast` | `duration` (number)<br>`label` (text)<br>`close-label` (text) | `toast-dismiss` | `lt-toast`<br>`lt-toast__message`<br>`lt-toast__close` |
|
|
@@ -314,12 +316,12 @@ The markup is ordinary HTML, in whatever template your framework uses:
|
|
|
314
316
|
|
|
315
317
|
```html
|
|
316
318
|
<lt-field>
|
|
317
|
-
<label class="lt-label" for="
|
|
318
|
-
<input class="lt-input" id="
|
|
319
|
-
<p class="lt-error-text" hidden>Enter
|
|
319
|
+
<label class="lt-label" for="codename" data-required="symbol">Codename</label>
|
|
320
|
+
<input class="lt-input" id="codename" type="text" name="codename" required />
|
|
321
|
+
<p class="lt-error-text" hidden>Enter a codename.</p>
|
|
320
322
|
</lt-field>
|
|
321
323
|
|
|
322
|
-
<button class="lt-button" type="submit">
|
|
324
|
+
<button class="lt-button" type="submit">Order the job</button>
|
|
323
325
|
```
|
|
324
326
|
|
|
325
327
|
`class` and `for`, not `className` and `htmlFor`. It is React that rewrites
|
|
@@ -327,9 +329,8 @@ the attribute names, and that does not apply here.
|
|
|
327
329
|
|
|
328
330
|
## 6. Typed builder functions
|
|
329
331
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
error:
|
|
332
|
+
The classes can come from `lt` instead of being written as strings. With
|
|
333
|
+
TypeScript, a variant that does not exist then becomes a compile error:
|
|
333
334
|
|
|
334
335
|
```ts
|
|
335
336
|
import { lt } from "@lo-tek/interfaces"
|
|
@@ -340,7 +341,7 @@ lt.button({ variant: "secondary" })
|
|
|
340
341
|
|
|
341
342
|
The builder functions return an object with HTML attribute names, which is
|
|
342
343
|
spread in where the template language supports spreading, or read out field by
|
|
343
|
-
field. The
|
|
344
|
+
field. The 48 builder functions:
|
|
344
345
|
|
|
345
346
|
`lt.accordion()`, `lt.alert()`, `lt.avatar()`, `lt.badge()`,
|
|
346
347
|
`lt.breadcrumbs()`, `lt.button()`, `lt.card()`, `lt.checkbox()`,
|
|
@@ -350,16 +351,16 @@ field. The 46 builder functions:
|
|
|
350
351
|
`lt.legend()`, `lt.link()`, `lt.list()`, `lt.pagination()`, `lt.paragraph()`,
|
|
351
352
|
`lt.popover()`, `lt.progress()`, `lt.radio()`, `lt.search()`, `lt.select()`,
|
|
352
353
|
`lt.sessionTimeout()`, `lt.skeleton()`, `lt.skipLink()`, `lt.spinner()`,
|
|
353
|
-
`lt.srOnly()`, `lt.suggestion()`, `lt.switch()`, `lt.table()`,
|
|
354
|
-
`lt.tableSort()`, `lt.tabs()`, `lt.tag()`, `lt.
|
|
355
|
-
`lt.toggleGroup()`, `lt.tooltip()`
|
|
354
|
+
`lt.srOnly()`, `lt.steps()`, `lt.suggestion()`, `lt.switch()`, `lt.table()`,
|
|
355
|
+
`lt.tableSort()`, `lt.tabs()`, `lt.tag()`, `lt.term()`, `lt.textarea()`,
|
|
356
|
+
`lt.toast()`, `lt.toggleGroup()`, `lt.tooltip()`
|
|
356
357
|
|
|
357
358
|
Where the template language cannot spread an object, `lt.setAttributes()` sets
|
|
358
359
|
the attributes on an element in plain DOM:
|
|
359
360
|
|
|
360
361
|
```ts
|
|
361
|
-
const field = document.querySelector<HTMLInputElement>("#
|
|
362
|
-
const wiring = lt.field({ id: "
|
|
362
|
+
const field = document.querySelector<HTMLInputElement>("#fixer")
|
|
363
|
+
const wiring = lt.field({ id: "fixer", error: true, invalid: true })
|
|
363
364
|
|
|
364
365
|
lt.setAttributes(field, lt.input({ type: "email" }), wiring.control)
|
|
365
366
|
```
|
|
@@ -368,7 +369,8 @@ Call it again to change state. Three rules:
|
|
|
368
369
|
|
|
369
370
|
- **When the builder function has an option for an attribute, a call without
|
|
370
371
|
the option removes the attribute.** So pass the options again every time.
|
|
371
|
-
`lt.spinner()` without `label` removes `role` and `aria-label
|
|
372
|
+
`lt.spinner()` without `label` removes `role` and `aria-label`, and writes
|
|
373
|
+
`aria-hidden`.
|
|
372
374
|
- **What the builder function has no option for stays.** `lt.button()` does
|
|
373
375
|
not touch `disabled` or `type`. `id` and `for` are never removed.
|
|
374
376
|
- **Two sets on the same element are passed separately**, as above. If they
|