diff --git a/docs/docs/howto/intro.md b/docs/docs/howto/intro.md
index 9dc1bf5..7b9e924 100644
--- a/docs/docs/howto/intro.md
+++ b/docs/docs/howto/intro.md
@@ -2,7 +2,7 @@
## Demo
-```tsx twoslash
+```jsx twoslash
// @errors: 2322
function MyComponent({ children }) {
@@ -103,7 +103,7 @@ Configure your `tsconfig.json` as follows:
If you don't have any other JSX runtimes like React or Preact set up, you can use
`typed-htmx/typed-html`, which will convert JSX into strings at runtime.
-You can configure the runtime using [`jsxConfig`](/typed-htmx/docs/api/module.index/Variables/variable.jsxConfig-1):
+You can configure the runtime using [`jsxConfig`](/typed-htmx/docs/api/index/variables/jsxConfig):
```js twoslash
import { jsxConfig } from "typed-htmx";
diff --git a/docs/docs/howto/xternal.md b/docs/docs/howto/xternal.md
new file mode 100644
index 0000000..38a3b80
--- /dev/null
+++ b/docs/docs/howto/xternal.md
@@ -0,0 +1,65 @@
+# Augmenting external JSX libraries
+
+typed-htmx is extremely minimal and requires the user to manually augment external JSX libraries that provide their own types.
+
+## Common guidance
+
+- Create a `types.d.ts` (any name is fine, as long as it ends in `.d.ts`) at the top of your src/ folder,
+ or anywhere within the configured `include` of your tsconfig.json
+- Write a JSX element, e.g. `
`, and inspect its type
+- If you see React-related types, you are good to go
+- If not, try to discover the common namespace under which all HTML attributes go.
+
+Let's use [Hono](https://hono.dev/top) as an example.
+
+```tsx twoslash
+// @jsxImportSource: hono/jsx
+// In tsconfig.json, jsxImportSource = "hono/jsx"
+
+// The type we are augmenting in this case is `Hono.HTMLAttributes`.
+// hx-boost is not recognized as a proper attribute yet.
+
+//^?
+```
+
+With this knowledge, we can now augment the type of `Hono.HTMLAttributes` assuming it is an interface:
+
+```tsx twoslash
+// @errors: 2322
+// @jsxImportSource: hono/jsx
+///
+
+declare global {
+ namespace Hono {
+ interface HTMLAttributes extends HtmxAttributes {}
+ }
+}
+
+
+```
+
+## Hono
+
+```ts twoslash
+import 'typed-htmx';
+
+declare global {
+ namespace Hono {
+ interface HTMLAttributes extends HtmxAttributes {}
+ }
+}
+```
+
+## Astro
+
+```ts twoslash
+import 'typed-htmx';
+
+declare global {
+ namespace astroHTML.JSX {
+ interface IntrinsicAttributes extends HtmxAttributes {}
+ }
+}
+```
diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js
index 94cd39d..dd93ad3 100644
--- a/docs/docusaurus.config.js
+++ b/docs/docusaurus.config.js
@@ -21,8 +21,8 @@ const config = {
markdown: {
format: 'md'
},
- onBrokenLinks: "throw",
- onBrokenMarkdownLinks: "ignore",
+ onBrokenLinks: "warn",
+ onBrokenMarkdownLinks: "warn",
i18n: {
defaultLocale: "en",
@@ -36,12 +36,10 @@ const config = {
({
entryPoints: ["../src/index.ts", "../src/jsx.d.ts"],
tsconfig: "../tsconfig.json",
- readme: "none",
hideInPageTOC: true,
+ readme: 'none',
watch: process.env.npm_lifecycle_event === "start",
- // cleanOutputDir: process.env.NODE_ENV !== 'production',
- cleanOutputDir: false,
- excludeExternals: true,
+ cleanOutputDir: true,
externalPattern: ["node_modules/**/*"],
plugin: ["typedoc-plugin-mdn-links"],
}),
@@ -70,19 +68,17 @@ const config = {
defaultOptions: {
noErrors: false,
},
- /** @type {import('typescript').CompilerOptions} */
defaultCompilerOptions: {
- types: ["typed-htmx"],
jsx: 4, // react-jsx
- jsxImportSource: "typed-htmx/typed-html",
+ jsxImportSource: 'typed-htmx/typed-html',
target: 99, // esnext,
strict: true,
+ checkJs: true,
noImplicitAny: false,
module: 199, // nodenext,
moduleResolution: 99, // nodenext
},
includeJSDocInHover: true,
- wrapFragments: true,
alwayRaiseForTwoslashExceptions: true,
disableImplicitReactImport: true,
}),
diff --git a/docs/package.json b/docs/package.json
index d5477de..e36992b 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -21,11 +21,11 @@
"clsx": "^1.2.1",
"docusaurus-plugin-typedoc": "next",
"docusaurus-preset-shiki-twoslash": "^1.1.41",
+ "hono": "^3.11.12",
"object-assign": "^4.1.1",
"prism-react-renderer": "^1.3.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
- "rehype-raw": "^7.0.0",
"typed-htmx": "link:..",
"typedoc": "^0.25.6",
"typedoc-plugin-markdown": "next",
@@ -34,8 +34,7 @@
},
"devDependencies": {
"@docusaurus/module-type-aliases": "3.0.1",
- "@docusaurus/types": "^3.0.1",
- "remark-shiki-twoslash": "^3.1.3"
+ "@docusaurus/types": "^3.0.1"
},
"browserslist": {
"production": [
diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml
index ebabc29..6f87673 100644
--- a/docs/pnpm-lock.yaml
+++ b/docs/pnpm-lock.yaml
@@ -26,6 +26,9 @@ dependencies:
docusaurus-preset-shiki-twoslash:
specifier: ^1.1.41
version: 1.1.41
+ hono:
+ specifier: ^3.11.12
+ version: 3.11.12
object-assign:
specifier: ^4.1.1
version: 4.1.1
@@ -38,9 +41,6 @@ dependencies:
react-dom:
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
- rehype-raw:
- specifier: ^7.0.0
- version: 7.0.0
typed-htmx:
specifier: link:..
version: link:..
@@ -64,9 +64,6 @@ devDependencies:
'@docusaurus/types':
specifier: ^3.0.1
version: 3.0.1(react-dom@18.2.0)(react@18.2.0)
- remark-shiki-twoslash:
- specifier: ^3.1.3
- version: 3.1.3(typescript@5.3.3)
packages:
@@ -2946,6 +2943,7 @@ packages:
/@types/unist@2.0.10:
resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==}
+ dev: false
/@types/unist@3.0.2:
resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==}
@@ -2975,6 +2973,7 @@ packages:
lz-string: 1.5.0
transitivePeerDependencies:
- supports-color
+ dev: false
/@typescript/vfs@1.3.4:
resolution: {integrity: sha512-RbyJiaAGQPIcAGWFa3jAXSuAexU4BFiDRF1g3hy7LmRqfNpYlTQWGXjcrOaVZjJ8YkkpuwG0FcsYvtWQpd9igQ==}
@@ -2982,6 +2981,7 @@ packages:
debug: 4.3.4
transitivePeerDependencies:
- supports-color
+ dev: false
/@typescript/vfs@1.3.5:
resolution: {integrity: sha512-pI8Saqjupf9MfLw7w2+og+fmb0fZS0J6vsKXXrp4/PDXEFvntgzXmChCXC/KefZZS0YGS6AT8e0hGAJcTsdJlg==}
@@ -2989,6 +2989,7 @@ packages:
debug: 4.3.4
transitivePeerDependencies:
- supports-color
+ dev: false
/@ungap/structured-clone@1.2.0:
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
@@ -4142,6 +4143,7 @@ packages:
optional: true
dependencies:
ms: 2.1.2
+ dev: false
/decode-named-character-reference@1.0.2:
resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
@@ -4685,6 +4687,7 @@ packages:
/fenceparser@1.1.1:
resolution: {integrity: sha512-VdkTsK7GWLT0VWMK5S5WTAPn61wJ98WPFwJiRHumhg4ESNUO/tnkU8bzzzc62o6Uk1SVhuZFLnakmDA4SGV7wA==}
engines: {node: '>=12'}
+ dev: false
/file-loader@6.2.0(webpack@5.89.0):
resolution: {integrity: sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==}
@@ -5189,6 +5192,11 @@ packages:
react-is: 16.13.1
dev: false
+ /hono@3.11.12:
+ resolution: {integrity: sha512-TrxH75bc0m2UbvrhaXkoo32A9OhkJtvICAYgYWtxqLDOxBjRqSikyp4K7HTbnWkPeg9Z+2Q3nv0dN4o8kL6yLg==}
+ engines: {node: '>=16.0.0'}
+ dev: false
+
/hpack.js@2.1.6:
resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==}
dependencies:
@@ -5748,6 +5756,7 @@ packages:
/jsonc-parser@3.2.0:
resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==}
+ dev: false
/jsonfile@6.1.0:
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
@@ -5897,6 +5906,7 @@ packages:
/lz-string@1.5.0:
resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
hasBin: true
+ dev: false
/markdown-extensions@2.0.0:
resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==}
@@ -6638,6 +6648,7 @@ packages:
/ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+ dev: false
/ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -7786,6 +7797,7 @@ packages:
/regenerator-runtime@0.13.11:
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
+ dev: false
/regenerator-runtime@0.14.1:
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
@@ -7935,6 +7947,7 @@ packages:
unist-util-visit: 2.0.3
transitivePeerDependencies:
- supports-color
+ dev: false
/remark-stringify@11.0.0:
resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
@@ -8256,6 +8269,7 @@ packages:
typescript: 5.3.3
transitivePeerDependencies:
- supports-color
+ dev: false
/shiki@0.10.1:
resolution: {integrity: sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==}
@@ -8263,6 +8277,7 @@ packages:
jsonc-parser: 3.2.0
vscode-oniguruma: 1.7.0
vscode-textmate: 5.2.0
+ dev: false
/shiki@0.14.7:
resolution: {integrity: sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==}
@@ -8653,6 +8668,7 @@ packages:
/tslib@2.1.0:
resolution: {integrity: sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==}
+ dev: false
/tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
@@ -8716,6 +8732,7 @@ packages:
resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==}
engines: {node: '>=14.17'}
hasBin: true
+ dev: false
/undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
@@ -8769,6 +8786,7 @@ packages:
/unist-util-is@4.1.0:
resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==}
+ dev: false
/unist-util-is@6.0.0:
resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
@@ -8806,6 +8824,7 @@ packages:
dependencies:
'@types/unist': 2.0.10
unist-util-is: 4.1.0
+ dev: false
/unist-util-visit-parents@6.0.1:
resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==}
@@ -8820,6 +8839,7 @@ packages:
'@types/unist': 2.0.10
unist-util-is: 4.1.0
unist-util-visit-parents: 3.1.1
+ dev: false
/unist-util-visit@5.0.0:
resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
@@ -8946,9 +8966,11 @@ packages:
/vscode-oniguruma@1.7.0:
resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==}
+ dev: false
/vscode-textmate@5.2.0:
resolution: {integrity: sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==}
+ dev: false
/vscode-textmate@8.0.0:
resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==}
diff --git a/docs/typedoc.json b/docs/typedoc.json
index 08c463a..9785dc3 100644
--- a/docs/typedoc.json
+++ b/docs/typedoc.json
@@ -1,3 +1,13 @@
{
- "categoryOrder": ["core", "*"]
+ "$schema": "https://typedoc.org/schema.json",
+ "categoryOrder": ["core", "*"],
+ "sourceLinkExternal": true,
+ "excludeExternals": true,
+ "externalPattern": [
+ "**/node_modules/**/*"
+ ],
+ "readme": "bogus",
+ "searchCategoryBoosts": {
+ "Core": 2
+ }
}
diff --git a/src/index.ts b/src/index.ts
index ff535f1..3e84f1a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -95,6 +95,20 @@ function htmlTransformChildren(value: InterpValue): string {
return out.join(" ");
}
+/**
+ * A [tagged template](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates)
+ * that interprets different kinds of {@link InterpValue values} into escaped HTML.
+ *
+ * ```ts twoslash
+ * import { html } from 'typed-htmx';
+ * function assertEqual(left: any, right: any) {}
+ * // ---cut---
+ * const template = html`
+ *
+ * `;
+ * assertEqual(template, ``);
+ * ```
+ */
export const html: HtmlTemplator = (raw, ...values) => {
const values_ = values.map(htmlTransformChildren);
return String.raw(raw, ...values_);
diff --git a/src/jsx.d.ts b/src/jsx.d.ts
index 9f41109..6bfd6a7 100644
--- a/src/jsx.d.ts
+++ b/src/jsx.d.ts
@@ -49,22 +49,22 @@ type HxTriggerModifier =
/**
* An extensible directory of htmx extensions.
*
- * ## Declaring a new extension
+ * ### Declaring a new extension
*
* ```tsx twoslash
* // in foo.d.ts:
*
* declare global {
- * namespace JSX {
- * interface HtmxExtensions {
- * myExtension: "my-extension";
- * }
- * interface HtmlTag {
- * /** Describe your attribute *\/
- * ["my-extension-attr"]?: string;
- * // Add any other attributes your extension uses here
- * }
- * }
+ * namespace JSX {
+ * interface HtmxExtensions {
+ * myExtension: "my-extension";
+ * }
+ * interface HtmlTag {
+ * /** Describe your attribute *\/
+ * ["my-extension-attr"]?: string;
+ * // Add any other attributes your extension uses here
+ * }
+ * }
* }
*
*
@@ -160,17 +160,10 @@ interface HtmxBuiltinExtensions {
morphdom: "morphdom";
}
-/**
- * Variants of attributes also recognized by htmx.
- */
-type HtmxData
= {
- [K in keyof T as K extends `hx-${string}` ? `data-${K}` : never]: T[K]
-}
-
/**
* Definitions for htmx attributes up to 1.9.3.
*/
-interface HtmxAttributes extends HtmxData {
+interface HtmxAttributes {
/** @ignore For React compatibility only. */
children?: {};
/** @ignore For React compatibility only. */
@@ -178,13 +171,13 @@ interface HtmxAttributes extends HtmxData {
/**
* Issues a `GET` to the specified URL.
* @see https://htmx.org/attributes/hx-get/
- * @category core
+ * @category Core
*/
["hx-get"]?: string;
/**
* Issues a `POST` to the specified URL.
* @see https://htmx.org/attributes/hx-post/
- * @category core
+ * @category Core
*/
["hx-post"]?: string;
/**
@@ -207,13 +200,13 @@ interface HtmxAttributes extends HtmxData {
* for links and forms.
*
* @see https://htmx.org/attributes/hx-boost/
- * @category core
+ * @category Core
*/
["hx-boost"]?: BoolStr;
/**
* Handle any event with a script inline.
* @see https://htmx.org/attributes/hx-on/
- * @category core
+ * @category Core
* @remarks Event listeners on htmx-specific events need to be specified with a spread attribute, and
* are otherwise not supported in vanilla JSX.
* ```jsx
@@ -232,26 +225,26 @@ interface HtmxAttributes extends HtmxData {
/**
* Pushes the URL into the browser location bar, creating a new history entry.
* @see https://htmx.org/attributes/hx-push-url/
- * @category core
+ * @category Core
*/
["hx-push-url"]?: BoolStr | AnyStr;
/**
* Select content to swap in from a response.
* @see https://htmx.org/attributes/hx-select/
- * @category core
+ * @category Core
*/
["hx-select"]?: string;
/**
* Select content to swap in from a response, out of band (somewhere other than the target).
* @see https://htmx.org/attributes/hx-select-oob/
- * @category core
+ * @category Core
*/
["hx-select-oob"]?: string;
/**
* Controls how content is swapped in (`outerHTML`, `beforeend`, `afterend`, …).
* @see https://htmx.org/attributes/hx-swap/
- * @see {@linkcode InsertPosition} which is used in [{@linkcode Element.insertAdjacentHTML}](https://developer.mozilla.org/docs/Web/API/Element/insertAdjacentHTML)
- * @category core
+ * @see [`InsertPosition`](https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML#position) which is used in `Element.insertAdjacentHTML`.
+ * @category Core
* @remarks
* - `morph` swaps are part of the {@linkcode HtmxBuiltinExtensions.idiomorph idiomorph} extension.
* - `morphdom` swaps are part of the {@linkcode HtmxBuiltinExtensions.morphdom morphdom} extension.
@@ -265,19 +258,19 @@ interface HtmxAttributes extends HtmxData {
/**
* Specifies the target element to be swapped.
* @see https://htmx.org/attributes/hx-target/
- * @category core
+ * @category Core
*/
["hx-target"]?: HxTarget | AnyStr;
/**
* Specifies the event that triggers the request.
* @see https://htmx.org/attributes/hx-trigger/
- * @category core
+ * @category Core
*/
["hx-trigger"]?: "every " | HxTriggerModifier | AnyStr;
/**
* Adds values to the parameters to submit with the request (JSON-formatted).
* @see https://htmx.org/attributes/hx-params/
- * @category core
+ * @category Core
*/
["hx-vals"]?: AnyStr | "javascript:" | "js:" | Record;
/**
@@ -426,6 +419,5 @@ declare namespace JSX {
interface HtmlTag extends HtmxAttributes {}
}
-// React (and other similar frameworks)
/** @ignore */
interface HTMLElement extends HtmxAttributes {}
diff --git a/tsconfig.json b/tsconfig.json
index c9cea6c..dec6343 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,5 +1,5 @@
{
- "include": ["./src/**/*"],
+ "include": ["src/**/*"],
"compilerOptions": {
"target": "es2022",
"module": "commonjs",