@hypermedia-components/cli 0.1.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/LICENSE +21 -0
- package/README.md +28 -0
- package/bin/hc-cli.mjs +70 -0
- package/lib/recipes.mjs +77 -0
- package/package.json +30 -0
- package/recipes/chart/contract.md +136 -0
- package/recipes/chart/expanded.html +40 -0
- package/recipes/chart/recipe.html +16 -0
- package/recipes/confirm-action/contract.md +28 -0
- package/recipes/confirm-action/expanded.html +17 -0
- package/recipes/confirm-action/recipe.html +10 -0
- package/recipes/data-region/contract.md +25 -0
- package/recipes/data-region/expanded.html +17 -0
- package/recipes/data-region/recipe.html +9 -0
- package/recipes/datagrid-pager/contract.md +73 -0
- package/recipes/datagrid-pager/expanded.html +50 -0
- package/recipes/datagrid-pager/recipe.html +30 -0
- package/recipes/field-errors/contract.md +98 -0
- package/recipes/field-errors/expanded.html +44 -0
- package/recipes/field-errors/recipe.html +21 -0
- package/recipes/filter-popover/contract.md +18 -0
- package/recipes/filter-popover/expanded.html +25 -0
- package/recipes/filter-popover/recipe.html +17 -0
- package/recipes/inline-edit/contract.md +58 -0
- package/recipes/inline-edit/expanded.html +70 -0
- package/recipes/inline-edit/recipe.html +12 -0
- package/recipes/lazy-panel/contract.md +67 -0
- package/recipes/lazy-panel/expanded.html +68 -0
- package/recipes/lazy-panel/recipe.html +11 -0
- package/recipes/live-search/contract.md +21 -0
- package/recipes/live-search/expanded.html +17 -0
- package/recipes/live-search/recipe.html +15 -0
- package/recipes/remote-dialog/contract.md +20 -0
- package/recipes/remote-dialog/expanded.html +18 -0
- package/recipes/remote-dialog/recipe.html +10 -0
- package/recipes/request-action/contract.md +29 -0
- package/recipes/request-action/expanded.html +15 -0
- package/recipes/request-action/recipe.html +14 -0
- package/recipes/toast/contract.md +71 -0
- package/recipes/toast/expanded.html +42 -0
- package/recipes/toast/recipe.html +10 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# request-action — server response contract
|
|
2
|
+
|
|
3
|
+
Purpose: trigger a server request from a button and swap the response into a target.
|
|
4
|
+
|
|
5
|
+
## Required client markup
|
|
6
|
+
|
|
7
|
+
- `data-hx-{get|post|put|patch|delete}` — request method and URL.
|
|
8
|
+
- `data-hx-target` — element to swap.
|
|
9
|
+
- `data-hx-swap` — swap strategy (default `outerHTML`).
|
|
10
|
+
- `data-hx-disabled-elt="this"` — disable the button during the request.
|
|
11
|
+
- `data-hx-indicator="closest .hc-action"` — show the loading indicator.
|
|
12
|
+
|
|
13
|
+
## Server response
|
|
14
|
+
|
|
15
|
+
Return either:
|
|
16
|
+
|
|
17
|
+
- HTML fragment for the target area; or
|
|
18
|
+
- `HX-Trigger` header with events such as `hc:toast`; or
|
|
19
|
+
- both.
|
|
20
|
+
|
|
21
|
+
## Example
|
|
22
|
+
|
|
23
|
+
```http
|
|
24
|
+
HTTP/1.1 200 OK
|
|
25
|
+
Content-Type: text/html; charset=utf-8
|
|
26
|
+
HX-Trigger: {"hc:toast":{"message":"Saved","variant":"success"}}
|
|
27
|
+
|
|
28
|
+
<tr id="item-123">...</tr>
|
|
29
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!-- Fully expanded HTML. TODO: fill in. -->
|
|
2
|
+
<span class="hc-action">
|
|
3
|
+
<button
|
|
4
|
+
class="hc-button"
|
|
5
|
+
data-variant="primary"
|
|
6
|
+
type="button"
|
|
7
|
+
data-hx-post="/items"
|
|
8
|
+
data-hx-target="#items"
|
|
9
|
+
data-hx-swap="outerHTML"
|
|
10
|
+
data-hx-disabled-elt="this"
|
|
11
|
+
data-hx-indicator="closest .hc-action">
|
|
12
|
+
Save
|
|
13
|
+
</button>
|
|
14
|
+
<span class="hc-spinner htmx-indicator" aria-hidden="true"></span>
|
|
15
|
+
</span>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!-- Short recommended usage. -->
|
|
2
|
+
<span class="hc-action">
|
|
3
|
+
<button
|
|
4
|
+
class="hc-button"
|
|
5
|
+
data-variant="primary"
|
|
6
|
+
type="button"
|
|
7
|
+
data-hx-post="/items"
|
|
8
|
+
data-hx-target="#items"
|
|
9
|
+
data-hx-disabled-elt="this"
|
|
10
|
+
data-hx-indicator="closest .hc-action">
|
|
11
|
+
Save
|
|
12
|
+
</button>
|
|
13
|
+
<span class="hc-spinner htmx-indicator" aria-hidden="true"></span>
|
|
14
|
+
</span>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# toast — server response contract
|
|
2
|
+
|
|
3
|
+
Purpose: surface a short, time-limited notification triggered by the server
|
|
4
|
+
or by client code, without coupling the trigger to a specific DOM
|
|
5
|
+
location.
|
|
6
|
+
|
|
7
|
+
## Required client markup
|
|
8
|
+
|
|
9
|
+
- A single `<div class="hc-toast-region" data-hc-toast-region
|
|
10
|
+
role="region" aria-label="Notifications">` somewhere on the page.
|
|
11
|
+
`installToast` lazy-creates one if it is missing, but rendering it
|
|
12
|
+
explicitly avoids a layout shift on the first toast.
|
|
13
|
+
- `installToast()` must be installed (the auto-init
|
|
14
|
+
`@hypermedia-components/core/behaviors` entry does this on
|
|
15
|
+
`DOMContentLoaded`).
|
|
16
|
+
|
|
17
|
+
## Trigger flow
|
|
18
|
+
|
|
19
|
+
Two equivalent triggers:
|
|
20
|
+
|
|
21
|
+
1. **From the server** — return an `HX-Trigger` response header. htmx
|
|
22
|
+
parses it and dispatches the named event on `<body>`:
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
HX-Trigger: {"hc:toast":{"message":"Saved","variant":"success"}}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
2. **From the client** — dispatch the same event directly:
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
document.body.dispatchEvent(new CustomEvent('hc:toast', {
|
|
32
|
+
bubbles: true,
|
|
33
|
+
detail: { message: 'Saved', variant: 'success' },
|
|
34
|
+
}));
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The behavior listens for `hc:toast` on `document.body`, renders a
|
|
38
|
+
`.hc-toast` element into the region, and removes it after
|
|
39
|
+
`detail.duration` ms.
|
|
40
|
+
|
|
41
|
+
## Event detail shape
|
|
42
|
+
|
|
43
|
+
| Field | Type | Default | Notes |
|
|
44
|
+
| ---------- | ------ | ------------ | ---------------------------------------------- |
|
|
45
|
+
| `message` | string | _(required)_ | Body text. |
|
|
46
|
+
| `title` | string | _(omitted)_ | Bold one-liner above the message. |
|
|
47
|
+
| `variant` | string | `'info'` | `info` / `success` / `warning` / `error`. |
|
|
48
|
+
| `duration` | number | `4500` | Milliseconds. `0` keeps the toast indefinitely. |
|
|
49
|
+
|
|
50
|
+
`variant="error"` is mapped to `role="alert"` /
|
|
51
|
+
`aria-live="assertive"` so screen readers interrupt to announce it.
|
|
52
|
+
Other variants use `role="status"` / `aria-live="polite"`.
|
|
53
|
+
|
|
54
|
+
## Server response examples
|
|
55
|
+
|
|
56
|
+
Multi-event responses combine `hc:toast` with other application
|
|
57
|
+
events:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
HX-Trigger: {"hc:toast":{"message":"Saved"}, "items:refresh":true}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Sticky error toasts use `duration: 0`:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
HX-Trigger: {"hc:toast":{"title":"Sync failed","message":"Could not reach the server","variant":"error","duration":0}}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Status: the toast is header-driven, not swap-driven — a `204 No Content`
|
|
70
|
+
plus the `HX-Trigger` header is the minimal success response when
|
|
71
|
+
nothing on the page changes.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<!-- Fully expanded HTML.
|
|
2
|
+
|
|
3
|
+
The page hosts a single corner-pinned region. Triggers can be the
|
|
4
|
+
server (HX-Trigger response header) or any client-side dispatcher;
|
|
5
|
+
the behavior renders toasts into the region and auto-dismisses
|
|
6
|
+
them according to the event detail. -->
|
|
7
|
+
<!doctype html>
|
|
8
|
+
<html lang="en">
|
|
9
|
+
<head>
|
|
10
|
+
<link rel="stylesheet" href="/dist/hc.css">
|
|
11
|
+
<script type="module" src="/dist/hc.behaviors.js"></script>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<!-- Server-driven path: any response carrying this header dispatches
|
|
15
|
+
an `hc:toast` event on body, which the behavior picks up. -->
|
|
16
|
+
<!--
|
|
17
|
+
HTTP/1.1 200 OK
|
|
18
|
+
HX-Trigger: {"hc:toast":{"message":"Saved","variant":"success"}}
|
|
19
|
+
-->
|
|
20
|
+
|
|
21
|
+
<!-- Client-driven path: dispatch the same event from JS. -->
|
|
22
|
+
<button
|
|
23
|
+
class="hc-button"
|
|
24
|
+
type="button"
|
|
25
|
+
onclick="document.body.dispatchEvent(new CustomEvent('hc:toast', {
|
|
26
|
+
bubbles: true,
|
|
27
|
+
detail: { title: 'Sync failed', message: 'Could not reach the server.', variant: 'error', duration: 0 }
|
|
28
|
+
}))">
|
|
29
|
+
Trigger error toast
|
|
30
|
+
</button>
|
|
31
|
+
|
|
32
|
+
<!-- Single region, near the end of <body>. installToast lazy-creates
|
|
33
|
+
this element if it is missing, but rendering it explicitly avoids
|
|
34
|
+
a layout shift on the very first toast. -->
|
|
35
|
+
<div
|
|
36
|
+
class="hc-toast-region"
|
|
37
|
+
data-hc-toast-region
|
|
38
|
+
role="region"
|
|
39
|
+
aria-label="Notifications">
|
|
40
|
+
</div>
|
|
41
|
+
</body>
|
|
42
|
+
</html>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<!-- Short recommended usage.
|
|
2
|
+
|
|
3
|
+
Place the region once in the page chrome. The installToast behavior
|
|
4
|
+
finds it (or creates one) when an `hc:toast` event reaches body. -->
|
|
5
|
+
<div
|
|
6
|
+
class="hc-toast-region"
|
|
7
|
+
data-hc-toast-region
|
|
8
|
+
role="region"
|
|
9
|
+
aria-label="Notifications">
|
|
10
|
+
</div>
|