diff --git a/README.md b/README.md index 67e6c3d..bca3ad1 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,10 @@ function MyComponent({ children }) { } ``` +If your frontend library injects its own JSX types, you'll need to augment it. +See the [example project](https://github.com/Desdaemon/typed-htmx/tree/main/example) +for a demo. typed-html and React are supported out of the box. + ### As a JSX templating engine If you prefer to use JSX only for its templating capabilities in the vein of diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..0e18658 --- /dev/null +++ b/example/README.md @@ -0,0 +1,5 @@ +# Example + +A demo of library-agnostic type augmentation by typed-htmx. + +Try swapping out different `tsconfig.json`s to see the types of different libraries. diff --git a/example/package.json b/example/package.json index ef86d38..df5a598 100644 --- a/example/package.json +++ b/example/package.json @@ -13,6 +13,6 @@ "typed-htmx": "link:.." }, "devDependencies": { - "@types/react": "^18.2.15" + "hono": "^3.11.12" } } diff --git a/example/pnpm-lock.yaml b/example/pnpm-lock.yaml index 06a1e37..d48a021 100644 --- a/example/pnpm-lock.yaml +++ b/example/pnpm-lock.yaml @@ -10,28 +10,13 @@ dependencies: version: link:.. devDependencies: - '@types/react': - specifier: ^18.2.15 - version: 18.2.15 + hono: + specifier: ^3.11.12 + version: 3.11.12 packages: - /@types/prop-types@15.7.5: - resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} - dev: true - - /@types/react@18.2.15: - resolution: {integrity: sha512-oEjE7TQt1fFTFSbf8kkNuc798ahTUzn3Le67/PWjE8MAfYAD/qB7O8hSTcromLFqHCt9bcdOg5GXMokzTjJ5SA==} - dependencies: - '@types/prop-types': 15.7.5 - '@types/scheduler': 0.16.3 - csstype: 3.1.2 - dev: true - - /@types/scheduler@0.16.3: - resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==} - dev: true - - /csstype@3.1.2: - resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + /hono@3.11.12: + resolution: {integrity: sha512-TrxH75bc0m2UbvrhaXkoo32A9OhkJtvICAYgYWtxqLDOxBjRqSikyp4K7HTbnWkPeg9Z+2Q3nv0dN4o8kL6yLg==} + engines: {node: '>=16.0.0'} dev: true diff --git a/example/index.jsx b/example/src/index.jsx similarity index 100% rename from example/index.jsx rename to example/src/index.jsx diff --git a/example/src/types.d.ts b/example/src/types.d.ts new file mode 100644 index 0000000..6240ea6 --- /dev/null +++ b/example/src/types.d.ts @@ -0,0 +1,11 @@ +// typed-htmx declares mostly ambient types so this is all you need. +import 'typed-htmx'; + +// A demo of how to augment foreign types with htmx attributes. +// In this case, Hono sources its types from its own namespace, so we do the same +// and directly extend its namespace. +declare global { + namespace Hono { + interface HTMLAttributes extends HtmxAttributes {} + } +} diff --git a/example/tsconfig.hono.json b/example/tsconfig.hono.json new file mode 100644 index 0000000..9990edd --- /dev/null +++ b/example/tsconfig.hono.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + // This is (usually) the only setting to change when swapping renderers. + "jsxImportSource": "hono/jsx" + } +} diff --git a/example/tsconfig.json b/example/tsconfig.json index 81eb727..4aef383 100644 --- a/example/tsconfig.json +++ b/example/tsconfig.json @@ -1,20 +1,25 @@ { - "files": ["index.jsx"], "compilerOptions": { "target": "es6" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - // "jsx": "react", /* Specify what JSX code is generated. */ - "jsx": "react-jsx" /* Specify what JSX code is generated. */, + // "jsx": "react", + "jsx": "react-jsx", /* Specify what JSX code is generated. */ + // If your frontend framework prescribes a JSX source, change it here. + // In this example, we will use typed-htmx's own text renderer based on typed-html. "jsxImportSource": "typed-htmx/typed-html", - "module": "commonjs", + "module": "node16", "moduleResolution": "node16" /* Specify how TypeScript looks up a file from a given module specifier. */, - "types": ["typed-htmx"], "allowJs": true /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */, "checkJs": true /* Enable error reporting in type-checked JavaScript files. */, + "noEmit": true, + "rootDir": ".", "outDir": "./dist", "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, "strict": true /* Enable all strict type-checking options. */, "skipDefaultLibCheck": true /* Skip type checking .d.ts files that are included with TypeScript. */, "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } + }, + "include": [ + "src/**/*", + ] } diff --git a/src/jsx.d.ts b/src/jsx.d.ts index 3ac510c..d1dfdae 100644 --- a/src/jsx.d.ts +++ b/src/jsx.d.ts @@ -1,5 +1,3 @@ -/// - /** * Provides type definitions in JSX for htmx attributes. * @module @@ -54,6 +52,8 @@ type HxTriggerModifier = * ## Declaring a new extension * * ```tsx twoslash + * // in foo.d.ts: + * * declare global { * namespace JSX { * interface HtmxExtensions { @@ -160,10 +160,17 @@ interface HtmxBuiltinExtensions { morphdom: "morphdom"; } +/** + * Alternative attribute variants 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 { +interface HtmxAttributes extends HtmxData { /** @ignore For React compatibility only. */ children?: {}; /** @ignore For React compatibility only. */ @@ -403,8 +410,11 @@ interface HtmxAttributes { /** @ignore */ declare namespace JSX { interface HtmxExtensions extends HtmxBuiltinExtensions {} + + // typed-html interface HtmlTag extends HtmxAttributes {} } +// React (and other similar frameworks) /** @ignore */ -interface HTMLElement extends JSX.HtmlTag {} +interface HTMLElement extends HtmxAttributes {} diff --git a/src/typed-html/jsx-runtime.ts b/src/typed-html/jsx-runtime.ts index 75192e7..33950c2 100644 --- a/src/typed-html/jsx-runtime.ts +++ b/src/typed-html/jsx-runtime.ts @@ -1,4 +1,5 @@ /// +/// import { createElement } from "typed-html"; import { jsxConfig } from "../index";