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..aed7c7c 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 @@ -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: 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",