@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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +28 -0
  3. package/bin/hc-cli.mjs +70 -0
  4. package/lib/recipes.mjs +77 -0
  5. package/package.json +30 -0
  6. package/recipes/chart/contract.md +136 -0
  7. package/recipes/chart/expanded.html +40 -0
  8. package/recipes/chart/recipe.html +16 -0
  9. package/recipes/confirm-action/contract.md +28 -0
  10. package/recipes/confirm-action/expanded.html +17 -0
  11. package/recipes/confirm-action/recipe.html +10 -0
  12. package/recipes/data-region/contract.md +25 -0
  13. package/recipes/data-region/expanded.html +17 -0
  14. package/recipes/data-region/recipe.html +9 -0
  15. package/recipes/datagrid-pager/contract.md +73 -0
  16. package/recipes/datagrid-pager/expanded.html +50 -0
  17. package/recipes/datagrid-pager/recipe.html +30 -0
  18. package/recipes/field-errors/contract.md +98 -0
  19. package/recipes/field-errors/expanded.html +44 -0
  20. package/recipes/field-errors/recipe.html +21 -0
  21. package/recipes/filter-popover/contract.md +18 -0
  22. package/recipes/filter-popover/expanded.html +25 -0
  23. package/recipes/filter-popover/recipe.html +17 -0
  24. package/recipes/inline-edit/contract.md +58 -0
  25. package/recipes/inline-edit/expanded.html +70 -0
  26. package/recipes/inline-edit/recipe.html +12 -0
  27. package/recipes/lazy-panel/contract.md +67 -0
  28. package/recipes/lazy-panel/expanded.html +68 -0
  29. package/recipes/lazy-panel/recipe.html +11 -0
  30. package/recipes/live-search/contract.md +21 -0
  31. package/recipes/live-search/expanded.html +17 -0
  32. package/recipes/live-search/recipe.html +15 -0
  33. package/recipes/remote-dialog/contract.md +20 -0
  34. package/recipes/remote-dialog/expanded.html +18 -0
  35. package/recipes/remote-dialog/recipe.html +10 -0
  36. package/recipes/request-action/contract.md +29 -0
  37. package/recipes/request-action/expanded.html +15 -0
  38. package/recipes/request-action/recipe.html +14 -0
  39. package/recipes/toast/contract.md +71 -0
  40. package/recipes/toast/expanded.html +42 -0
  41. 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>