@markout-lang/bootstrap-kit 0.2.0 → 0.2.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.
package/README.md CHANGED
@@ -33,54 +33,10 @@ Bootstrap out:
33
33
  <:import src="/npm/@markout-lang/bootstrap-kit/parts/card.htm" />
34
34
  ```
35
35
 
36
- Run the showcase every component below, live with:
37
-
38
- ```sh
39
- npm run dev
40
- ```
41
-
42
- That serves [the site](../../sites/site/), which is where the pages built on
43
- this kit live: `/demos/kitchen-sink.html`, every component one after another;
44
- and `/demos/orbit.html`, an operations dashboard built out of them, which is
45
- what they look like wired to one page's data.
46
-
47
- The site is a plain Express app rather than markout's `Server`, because Orbit
48
- is a whole application: it has an API of its own, served from a fake
49
- in-memory database (`orbit-db.ts`), and markout is the middleware that
50
- renders its pages. Orbit reads that API with `std-data` from the std kit,
51
- which fetches while the page renders — so the served console is complete and
52
- the browser asks for nothing.
53
-
54
- Orbit is four files, which is the shape an application takes:
55
- `demos/orbit.html` for its state, layout and logic; `demos/orbit/components.htm`
56
- for the tags it defines on top of the kit's; `demos/orbit/sources.htm` for
57
- where its data comes from; and `server.ts` for its API. The first is imported,
58
- the second included — a definition wants to arrive once per page however often
59
- it is named, and an instance wants to be spliced exactly where it is written,
60
- because that is where its name resolves.
61
-
62
- `orbit/sources.htm` also shows the token pattern working for an application's
63
- own fragment: its root carries `:apiBase="/api"`, which lands on whatever
64
- contains the `<:include>` unless that element declares it, so a page points
65
- Orbit at another host without the fragment changing. That is the same
66
- mechanism as `bsCssUrl` below — not something kits get and applications
67
- don't.
68
-
69
- ## Tests
70
-
71
- `packages/cli/test/kits/bootstrap-kit.test.ts`, in two tiers:
72
-
73
- - **compiled**, which is most of it: every part compiles on its own, the
74
- showcase compiles and server-renders with nothing reported, and the id
75
- wiring is checked mechanically — every `aria-controls`, `aria-labelledby`,
76
- `for`, `data-bs-target` and `data-bs-parent` has to name an element that
77
- exists. That last one is the kit's whole reason for existing, so it is
78
- worth a test that can't be argued with.
79
- - **live**, in Playwright: the value-driven components actually driven, and
80
- a stubbed Bootstrap asserting the plugin calls. Skipped when no browser is
81
- installed (`npx playwright install chromium`).
82
-
83
- Nothing reaches the network: the tests set the URL tokens to local files.
36
+ Every component below is shown one after another in the [kitchen
37
+ sink](https://markout.dev/demos/kitchen-sink), and
38
+ [Orbit](https://markout.dev/demos/orbit) is an operations dashboard built out
39
+ of them — what they look like wired to one page's data.
84
40
 
85
41
  ## What is and isn't a component
86
42
 
@@ -152,6 +108,19 @@ That holds however deeply the component sits: a `bs-toast :aka="saved"`
152
108
  written inside a `bs-toast-container` is still named where you wrote it, so
153
109
  `saved.open = true` reaches it from anywhere on the page.
154
110
 
111
+ `bs-input` and `bs-textarea` answer `valid` the same way -- is there a value,
112
+ and does it pass `check`? -- which is what a submit button needs:
113
+
114
+ ```html
115
+ <bs-input :aka="email" :label="Email" :check=${v => v.includes('@')} />
116
+ <bs-button :disabled=${!email.valid}>Send</bs-button>
117
+ ```
118
+
119
+ It is not the negation of the error state. An empty field is not marked
120
+ wrong, which is what keeps a form from opening in red, and it is not
121
+ something to submit either -- so it shows nothing and answers `false`.
122
+ `required` is what makes empty an error as well as a gap.
123
+
155
124
  **Optional regions are `:if`.** A region that exists only when a parameter
156
125
  was given is written `:if=${header}`, and nothing inside it evaluates while
157
126
  the condition is false — which is what makes `${user.name}` safe to write in
@@ -274,6 +243,9 @@ commented.
274
243
  | `bs-range` | `label` `name` `min` `max` `step` `value` `disabled` `showValue` |
275
244
  | `bs-input-group` | `prefix` `suffix` `size` |
276
245
 
246
+ `bs-input` and `bs-textarea` also answer `valid`, which is read rather than
247
+ passed -- see *Values are read and written* above.
248
+
277
249
  ### Components
278
250
 
279
251
  | Tag | Parameters |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markout-lang/bootstrap-kit",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Bootstrap 5.3 as Markout components: one part per component, with the id wiring, the ARIA attributes and the repetition written once",
5
5
  "repository": {
6
6
  "type": "git",
package/parts/input.htm CHANGED
@@ -19,6 +19,17 @@
19
19
  invalid once it is non-empty and fails `:check`. Empty is neutral, so a
20
20
  form doesn't open covered in errors. `:required` extends that to empty.
21
21
 
22
+ `:valid` is the other side of that, and what a form's own controls read —
23
+
24
+ <bs-input :aka="email" :label="Email" :check=${v => v.includes('@')} />
25
+ <bs-button :disabled=${!email.valid}>Send</bs-button>
26
+
27
+ It is deliberately NOT the negation of the error state, which is the one
28
+ thing about it worth knowing. An untouched field is not wrong — that is
29
+ what keeps the form out of red — and it is also not something to submit.
30
+ So empty answers `false` here while showing nothing, and `:required` is
31
+ what makes empty an error as well as a gap.
32
+
22
33
  Floating labels are the same control with the label after the input
23
34
  instead of before it — Bootstrap's CSS keys off that order — so the two
24
35
  layouts are two regions rather than one with a class toggled on it.
@@ -49,6 +60,9 @@
49
60
  :_invalid=${_empty ? required : !check(value)}
50
61
  :_class=${['form-control', size ? `form-control-${size}` : '']
51
62
  .filter(s => s).join(' ')}
63
+
64
+ // read from outside: is there a value, and does it pass?
65
+ :valid=${!_empty && check(value)}
52
66
  >
53
67
  <!--- plain layout: label, control, feedback -->
54
68
  <div :if=${!floating}>
@@ -123,6 +137,9 @@
123
137
  :_helpId=${`bs-textarea-help-${$id}`}
124
138
  :_empty=${value === '' || value == null}
125
139
  :_invalid=${_empty ? required : !check(value)}
140
+
141
+ // read from outside, as bs-input's is
142
+ :valid=${!_empty && check(value)}
126
143
  >
127
144
  <label class="form-label"
128
145
  for=${_id}
package/parts/navbar.htm CHANGED
@@ -40,6 +40,17 @@
40
40
  extra,
41
41
  ].filter(s => s).join(' ')}
42
42
 
43
+ // The gap under the links is only wanted while they are stacked, which
44
+ // is up to `expand` and not to any one breakpoint: left at `mb-lg-0` it
45
+ // would survive into a bar that has already gone horizontal and push the
46
+ // links up off the brand's line. A navbar that never collapses has no
47
+ // stacked state to space out, hence the plain `mb-0`.
48
+ :_navClass=${[
49
+ 'navbar-nav',
50
+ 'me-auto',
51
+ expand ? `mb-2 mb-${expand}-0` : 'mb-0',
52
+ ].join(' ')}
53
+
43
54
  class=${_class}
44
55
  :class-sticky-top=${sticky}
45
56
  :class-fixed-top=${fixed}
@@ -59,7 +70,7 @@
59
70
  </button>
60
71
 
61
72
  <div class="collapse navbar-collapse" id=${_id}>
62
- <ul class="navbar-nav me-auto mb-2 mb-lg-0">
73
+ <ul class=${_navClass}>
63
74
  <li class="nav-item" :for-each=${items} :for-as="item">
64
75
  <a class="nav-link"
65
76
  :class-active=${item.active}