Skip to content

Commit 9d6778e

Browse files
committed
feat: hx-on-, hx-target completions
1 parent 8888786 commit 9d6778e

File tree

3 files changed

+88
-64
lines changed

3 files changed

+88
-64
lines changed

example/pnpm-lock.yaml

Lines changed: 16 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/jsx.d.ts

Lines changed: 71 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -34,51 +34,69 @@ type HxSync = ":drop" | ":abort" | ":replace" | ":queue" | ":queue first" | ":qu
3434
/**
3535
* Any of the standard DOM events, or htmx-specific events.
3636
*/
37-
type HxTriggers = keyof GlobalEventHandlersEventMap | HtmxEvents;
37+
type HxTriggers = keyof GlobalEventHandlersEventMap | HtmxUtils.HtmxEvents;
3838

39-
type HtmxEvents =
40-
| "htmx:abort"
41-
| "htmx:afterOnLoad"
42-
| "htmx:afterProcessNode"
43-
| "htmx:afterRequest"
44-
| "htmx:afterSettle"
45-
| "htmx:afterSwap"
46-
| "htmx:beforeCleanupElement"
47-
| "htmx:beforeOnLoad"
48-
| "htmx:beforeProcessNode"
49-
| "htmx:beforeRequest"
50-
| "htmx:beforeSwap"
51-
| "htmx:beforeSend"
52-
| "htmx:configRequest"
53-
| "htmx:confirm"
54-
| "htmx:historyCacheError"
55-
| "htmx:historyCacheMiss"
56-
| "htmx:historyCacheMissError"
57-
| "htmx:historyCacheMissLoad"
58-
| "htmx:historyRestore"
59-
| "htmx:beforeHistorySave"
60-
| "htmx:load"
61-
| "htmx:noSSESourceError"
62-
| "htmx:onLoadError"
63-
| "htmx:oobAfterSwap"
64-
| "htmx:oobBeforeSwap"
65-
| "htmx:oobErrorNoTarget"
66-
| "htmx:prompt"
67-
| "htmx:pushedIntoHistory"
68-
| "htmx:responseError"
69-
| "htmx:sendError"
70-
| "htmx:sseError"
71-
| "htmx:sseOpen"
72-
| "htmx:swapError"
73-
| "htmx:targetError"
74-
| "htmx:timeout"
75-
| "htmx:validation:validate"
76-
| "htmx:vaildation:failed"
77-
| "htmx:validation:halted"
78-
| "htmx:xhr:abort"
79-
| "htmx:xhr:loadend"
80-
| "htmx:xhr:loadstart"
81-
| "htmx:xhr:progress"
39+
/** @ignore */
40+
declare namespace HtmxUtils {
41+
type HxOnMap =
42+
{ [K in keyof GlobalEventHandlersEventMap as `hx-on-${K}`]?: string; } &
43+
{ [K in HxOnHtmxEvents as `hx-on--${K}`]?: string; }
44+
45+
type HxOnHtmxEvents =
46+
| JsxHtmxEvents
47+
| keyof { [K in keyof HxSubevents as `${K}-${HxSubevents[K]}`]: never }
48+
49+
type JsxHtmxEvents =
50+
| "abort"
51+
| "after-on-load"
52+
| "after-process-node"
53+
| "after-request"
54+
| "after-settle"
55+
| "after-swap"
56+
| "before-cleanup-element"
57+
| "before-on-load"
58+
| "before-process-node"
59+
| "before-request"
60+
| "before-swap"
61+
| "before-send"
62+
| "config-request"
63+
| "confirm"
64+
| "history-cache-error"
65+
| "history-cache-miss"
66+
| "history-cache-miss-error"
67+
| "history-cache-miss-load"
68+
| "history-restore"
69+
| "before-history-save"
70+
| "load"
71+
| "no-sse-source-error"
72+
| "on-load-error"
73+
| "oob-after-swap"
74+
| "oob-before-swap"
75+
| "oob-error-no-target"
76+
| "prompt"
77+
| "pushed-into-history"
78+
| "response-error"
79+
| "send-error"
80+
| "sse-error"
81+
| "sse-open"
82+
| "swap-error"
83+
| "target-error"
84+
| "timeout"
85+
86+
type HxSubevents = {
87+
validation: 'validate' | 'failed' | 'halted';
88+
xhr: 'abort' | 'loadend' | 'loadstart' | 'progress';
89+
}
90+
91+
type KebabToCamel<T extends string> =
92+
T extends `${infer Head}-${infer Rest}`
93+
? `${Head}${KebabToCamel<Capitalize<Rest>>}`
94+
: T
95+
96+
type HtmxEvents =
97+
| `htmx:${KebabToCamel<JsxHtmxEvents>}`
98+
| keyof { [K in keyof HxSubevents as `htmx:${K}:${HxSubevents[K]}`]: never }
99+
}
82100

83101
/**
84102
* An event followed by one of these modifiers, e.g. `click once`.
@@ -111,14 +129,15 @@ type HxTriggerModifier =
111129
* }
112130
* interface HtmlTag {
113131
* /** Describe your attribute *\/
114-
* ["my-extension-attr"]?: string;
132+
* ["my-extension-attr"]?: "true" | "false";
115133
* // Add any other attributes your extension uses here
116134
* }
117135
* }
118136
* }
119137
*
120138
* <div hx-ext="my-extension">
121-
* <span my-extension-attr="foo">Hello</span>
139+
* <span my-extension-attr="true">Hello</span>
140+
* // ^?
122141
* </div>
123142
* ```
124143
*/
@@ -298,12 +317,12 @@ interface HtmxBuiltinExtensions {
298317
* `hx-get`, `hx-post` and other request attributes can include path variables by
299318
* using the {@linkcode HtmxBuiltinExtensions.pathParams path-params} extension.
300319
* Once used as a path variable, it will not be included in the request body.
301-
* ```jsx
302-
* <button hx-post="/api/user/{id}" hx-vals="{'id': 1,'foo':true}" hx-ext="path-params">...</a>
320+
* ```jsx twoslash
321+
* <button hx-post="/api/user/{id}" hx-vals="{'id': 1,'foo':true}" hx-ext="path-params">...</button>
303322
* // Only 'foo' will be included in the request body
304323
* ```
305324
*/
306-
interface HtmxAttributes {
325+
interface HtmxAttributes extends HtmxUtils.HxOnMap {
307326
/** @ignore For React compatibility only. */
308327
children?: {} | null;
309328
/** @ignore For React compatibility only. */
@@ -766,11 +785,11 @@ interface HtmxAttributes {
766785

767786
/** @ignore */
768787
declare namespace JSX {
769-
interface HtmxExtensions extends HtmxBuiltinExtensions {}
788+
interface HtmxExtensions extends HtmxBuiltinExtensions { }
770789

771790
// typed-html
772-
interface HtmlTag extends HtmxAttributes {}
791+
interface HtmlTag extends HtmxAttributes { }
773792
}
774793

775794
/** @ignore */
776-
interface HTMLElement extends HtmxAttributes {}
795+
interface HTMLElement extends HtmxAttributes { }

src/typed-html/jsx-runtime.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
/// <reference path="../jsx.d.ts" />
21
/// <reference types="typed-html" />
2+
/// <reference path="../jsx.d.ts" />
33

44
import { createElement } from "typed-html";
55
import { jsxConfig } from "../index.js";

0 commit comments

Comments
 (0)