diff --git a/.changeset/non-qrl-api-compat.md b/.changeset/non-qrl-api-compat.md new file mode 100644 index 00000000000..1517ca2df86 --- /dev/null +++ b/.changeset/non-qrl-api-compat.md @@ -0,0 +1,7 @@ +--- +'@qwik.dev/core': patch +'@qwik.dev/router': patch +'@qwik.dev/react': patch +--- + +feat: add non-QRL aliases for callback APIs diff --git a/e2e/qwik-e2e/apps/e2e/src/components/events/events.tsx b/e2e/qwik-e2e/apps/e2e/src/components/events/events.tsx index 3913d9c3849..61c076aed9f 100644 --- a/e2e/qwik-e2e/apps/e2e/src/components/events/events.tsx +++ b/e2e/qwik-e2e/apps/e2e/src/components/events/events.tsx @@ -28,6 +28,7 @@ const EventsParent = component$(() => { passivePreventDefaultState: 'unset', passiveDocumentCount: 0, passiveWindowCount: 0, + qrlNoDollarClickCount: 0, hoverOrderLog: '', }); return ( @@ -190,6 +191,15 @@ const EventsParent = component$(() => {

countPassiveDocument: {store.passiveDocumentCount}

countPassiveWindow: {store.passiveWindowCount}

+ +

countQrlNoDollarClick: {store.qrlNoDollarClickCount}

diff --git a/e2e/qwik-e2e/tests/events.e2e.ts b/e2e/qwik-e2e/tests/events.e2e.ts index 352169c02c9..d97df2d4d29 100644 --- a/e2e/qwik-e2e/tests/events.e2e.ts +++ b/e2e/qwik-e2e/tests/events.e2e.ts @@ -81,6 +81,15 @@ test.describe('events', () => { await expect(page.locator('#hover-order-log')).toHaveText('red mouse out|blue mouse in'); }); + test('should execute qrl handler passed to no-dollar event', async ({ page }) => { + const button = page.locator('#qrl-no-dollar-click'); + const count = page.locator('#count-qrl-no-dollar-click'); + + await expect(count).toHaveText('countQrlNoDollarClick: 0'); + await button.click(); + await expect(count).toHaveText('countQrlNoDollarClick: 1'); + }); + test(`GIVEN "stoppropagation" is set as a attribute THEN it should stop propagation`, async ({ page }) => { const stoppedPropagationButton = page.locator('#stop-propagation'); diff --git a/packages/docs/src/routes/api/qwik-router/api.json b/packages/docs/src/routes/api/qwik-router/api.json index 2b9d6ce93fb..0e01db9b973 100644 --- a/packages/docs/src/routes/api/qwik-router/api.json +++ b/packages/docs/src/routes/api/qwik-router/api.json @@ -394,6 +394,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/types.ts", "mdFile": "router.getvalidatortype.md" }, + { + "name": "globalAction", + "id": "globalaction", + "hierarchy": [ + { + "name": "globalAction", + "id": "globalaction" + } + ], + "kind": "Variable", + "content": "```typescript\nglobalAction: ActionConstructor & ActionConstructorQRL\n```", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts", + "mdFile": "router.globalaction.md" + }, { "name": "globalAction$", "id": "globalaction_", @@ -842,6 +856,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/types.ts", "mdFile": "router.resolveddocumenthead.md" }, + { + "name": "routeAction", + "id": "routeaction", + "hierarchy": [ + { + "name": "routeAction", + "id": "routeaction" + } + ], + "kind": "Variable", + "content": "```typescript\nrouteAction: ActionConstructor & ActionConstructorQRL\n```", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts", + "mdFile": "router.routeaction.md" + }, { "name": "routeAction$", "id": "routeaction_", @@ -898,6 +926,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/types.ts", "mdFile": "router.routedata.md" }, + { + "name": "routeLoader", + "id": "routeloader", + "hierarchy": [ + { + "name": "routeLoader", + "id": "routeloader" + } + ], + "kind": "Variable", + "content": "```typescript\nrouteLoader: LoaderConstructor & LoaderConstructorQRL\n```", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts", + "mdFile": "router.routeloader.md" + }, { "name": "routeLoader$", "id": "routeloader_", @@ -954,6 +996,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/router-outlet-component.tsx", "mdFile": "router.routeroutlet.md" }, + { + "name": "server", + "id": "server", + "hierarchy": [ + { + "name": "server", + "id": "server" + } + ], + "kind": "Function", + "content": "```typescript\nserver: (fn: T | QRL, options?: ServerConfig) => ServerQRL\n```\n\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nfn\n\n\n\n\nT \\| QRL<T>\n\n\n\n\n\n
\n\noptions\n\n\n\n\nServerConfig\n\n\n\n\n_(Optional)_\n\n\n
\n\n**Returns:**\n\n[ServerQRL](#serverqrl)<T>", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts", + "mdFile": "router.server.md" + }, { "name": "server$", "id": "server_", @@ -1164,6 +1220,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/use-functions.ts", "mdFile": "router.usenavigate.md" }, + { + "name": "usePreventNavigate", + "id": "usepreventnavigate", + "hierarchy": [ + { + "name": "usePreventNavigate", + "id": "usepreventnavigate" + } + ], + "kind": "Function", + "content": "```typescript\nusePreventNavigate: (fn: PreventNavigateCallback | QRL) => void\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nfn\n\n\n\n\n[PreventNavigateCallback](#preventnavigatecallback) \\| QRL<[PreventNavigateCallback](#preventnavigatecallback)>\n\n\n\n\n\n
\n\n**Returns:**\n\nvoid", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/use-functions.ts", + "mdFile": "router.usepreventnavigate.md" + }, { "name": "usePreventNavigate$", "id": "usepreventnavigate_", @@ -1192,6 +1262,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/qwik-router-component.tsx", "mdFile": "router.useqwikrouter.md" }, + { + "name": "valibot", + "id": "valibot", + "hierarchy": [ + { + "name": "valibot", + "id": "valibot" + } + ], + "kind": "Variable", + "content": "> This API is provided as a beta preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.\n> \n\n\n\n```typescript\nvalibot: ValibotConstructor & ValibotConstructorQRL\n```", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts", + "mdFile": "router.valibot.md" + }, { "name": "valibot$", "id": "valibot_", @@ -1206,6 +1290,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts", "mdFile": "router.valibot_.md" }, + { + "name": "validator", + "id": "validator", + "hierarchy": [ + { + "name": "validator", + "id": "validator" + } + ], + "kind": "Variable", + "content": "```typescript\nvalidator: ValidatorConstructor & ValidatorConstructorQRL\n```", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts", + "mdFile": "router.validator.md" + }, { "name": "validator$", "id": "validator_", @@ -1262,6 +1360,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/types.ts", "mdFile": "router.validatorreturn.md" }, + { + "name": "zod", + "id": "zod", + "hierarchy": [ + { + "name": "zod", + "id": "zod" + } + ], + "kind": "Variable", + "content": "```typescript\nzod: ZodConstructor & ZodConstructorQRL\n```", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts", + "mdFile": "router.zod.md" + }, { "name": "zod$", "id": "zod_", diff --git a/packages/docs/src/routes/api/qwik-router/index.mdx b/packages/docs/src/routes/api/qwik-router/index.mdx index 86181b2d5eb..dfe242ddb6a 100644 --- a/packages/docs/src/routes/api/qwik-router/index.mdx +++ b/packages/docs/src/routes/api/qwik-router/index.mdx @@ -1053,6 +1053,14 @@ export type GetValidatorType = [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/types.ts) +

globalAction

+ +```typescript +globalAction: ActionConstructor & ActionConstructorQRL; +``` + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts) +

globalAction$

```typescript @@ -2031,6 +2039,14 @@ export type ResolvedDocumentHead< [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/types.ts) +

routeAction

+ +```typescript +routeAction: ActionConstructor & ActionConstructorQRL; +``` + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts) +

routeAction$

```typescript @@ -2335,6 +2351,14 @@ _(Optional)_ The parameter name when this node is reached via `_W` or `_A` from [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/types.ts) +

routeLoader

+ +```typescript +routeLoader: LoaderConstructor & LoaderConstructorQRL; +``` + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts) +

routeLoader$

```typescript @@ -2460,6 +2484,58 @@ RouterOutlet: import("@qwik.dev/core").Component; [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/router-outlet-component.tsx) +

server

+ +```typescript +server: (fn: T | QRL, options?: ServerConfig) => + ServerQRL; +``` + + + + +
+ +Parameter + + + +Type + + + +Description + +
+ +fn + + + +T \| QRL<T> + + + +
+ +options + + + +ServerConfig + + + +_(Optional)_ + +
+ +**Returns:** + +[ServerQRL](#serverqrl)<T> + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts) +

server$

```typescript @@ -2810,6 +2886,44 @@ useNavigate: () => RouteNavigate; [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/use-functions.ts) +

usePreventNavigate

+ +```typescript +usePreventNavigate: (fn: PreventNavigateCallback | QRL) => void +``` + + + +
+ +Parameter + + + +Type + + + +Description + +
+ +fn + + + +[PreventNavigateCallback](#preventnavigatecallback) \| QRL<[PreventNavigateCallback](#preventnavigatecallback)> + + + +
+ +**Returns:** + +void + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/use-functions.ts) +

usePreventNavigate$

Prevent navigation attempts. This hook registers a callback that will be called before SPA or browser navigation. @@ -2912,6 +3026,16 @@ void [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/qwik-router-component.tsx) +

valibot

+ +> This API is provided as a beta preview for developers and may change based on feedback that we receive. Do not use this API in a production environment. + +```typescript +valibot: ValibotConstructor & ValibotConstructorQRL; +``` + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts) +

valibot$

> This API is provided as a beta preview for developers and may change based on feedback that we receive. Do not use this API in a production environment. @@ -2922,6 +3046,14 @@ valibot$: ValibotConstructor; [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts) +

validator

+ +```typescript +validator: ValidatorConstructor & ValidatorConstructorQRL; +``` + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts) +

validator$

```typescript @@ -2986,6 +3118,14 @@ export type ValidatorReturn = {}> = [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/types.ts) +

zod

+ +```typescript +zod: ZodConstructor & ZodConstructorQRL; +``` + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/server-functions.ts) +

zod$

```typescript diff --git a/packages/docs/src/routes/api/qwik-worker/api.json b/packages/docs/src/routes/api/qwik-worker/api.json index a37a1e77352..1194dbd9804 100644 --- a/packages/docs/src/routes/api/qwik-worker/api.json +++ b/packages/docs/src/routes/api/qwik-worker/api.json @@ -2,6 +2,20 @@ "id": "qwik-worker", "package": "@qwik.dev/qwik/worker", "members": [ + { + "name": "worker", + "id": "worker", + "hierarchy": [ + { + "name": "worker", + "id": "worker" + } + ], + "kind": "Variable", + "content": "```typescript\nworker: WorkerConstructor\n```", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/web-worker/worker-qrl.ts", + "mdFile": "core.worker.md" + }, { "name": "worker$", "id": "worker_", @@ -16,6 +30,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/web-worker/worker-qrl.ts", "mdFile": "core.worker_.md" }, + { + "name": "WorkerConstructor", + "id": "workerconstructor", + "hierarchy": [ + { + "name": "WorkerConstructor", + "id": "workerconstructor" + } + ], + "kind": "Interface", + "content": "```typescript\nexport interface WorkerConstructor \n```", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/web-worker/worker-qrl.ts", + "mdFile": "core.workerconstructor.md" + }, { "name": "WorkerConstructorQRL", "id": "workerconstructorqrl", diff --git a/packages/docs/src/routes/api/qwik-worker/index.mdx b/packages/docs/src/routes/api/qwik-worker/index.mdx index d225e051b34..37c98bbdd70 100644 --- a/packages/docs/src/routes/api/qwik-worker/index.mdx +++ b/packages/docs/src/routes/api/qwik-worker/index.mdx @@ -4,6 +4,14 @@ title: \@qwik.dev/qwik/worker API Reference # [API](/api) › @qwik.dev/qwik/worker +

worker

+ +```typescript +worker: WorkerConstructor; +``` + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/web-worker/worker-qrl.ts) +

worker$

```typescript @@ -42,6 +50,14 @@ QRL<T> [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/web-worker/worker-qrl.ts) +

WorkerConstructor

+ +```typescript +export interface WorkerConstructor +``` + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/web-worker/worker-qrl.ts) +

WorkerConstructorQRL

```typescript diff --git a/packages/docs/src/routes/api/qwik/api.json b/packages/docs/src/routes/api/qwik/api.json index d075be6b8d1..2cc915152c8 100644 --- a/packages/docs/src/routes/api/qwik/api.json +++ b/packages/docs/src/routes/api/qwik/api.json @@ -327,6 +327,20 @@ "content": "```typescript\ncleanup(): void;\n```\n**Returns:**\n\nvoid", "mdFile": "core.renderresult.cleanup.md" }, + { + "name": "component", + "id": "component", + "hierarchy": [ + { + "name": "component", + "id": "component" + } + ], + "kind": "Function", + "content": "Type representing the Qwik component.\n\n`Component` is the type returned by invoking `component$`.\n\n```tsx\ninterface MyComponentProps {\n someProp: string;\n}\nconst MyComponent: Component = component$((props: MyComponentProps) => {\n return {props.someProp};\n});\n```\n\n\n```typescript\nexport type Component = FunctionComponent>;\n```\n**References:** [FunctionComponent](#functioncomponent), [PublicProps](#publicprops)", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/component.public.ts", + "mdFile": "core.component.md" + }, { "name": "Component", "id": "component", @@ -351,7 +365,7 @@ } ], "kind": "Function", - "content": "Declare a Qwik component that can be used to create UI.\n\nUse `component$` to declare a Qwik component. A Qwik component is a special kind of component that allows the Qwik framework to lazy load and execute the component independently of other Qwik components as well as lazy load the component's life-cycle hooks and event handlers.\n\nSide note: You can also declare regular (standard JSX) components that will have standard synchronous behavior.\n\nQwik component is a facade that describes how the component should be used without forcing the implementation of the component to be eagerly loaded. A minimum Qwik definition consists of:\n\n\\#\\#\\# Example\n\nAn example showing how to create a counter component:\n\n```tsx\nexport interface CounterProps {\n initialValue?: number;\n step?: number;\n}\nexport const Counter = component$((props: CounterProps) => {\n const state = useSignal(props.initialValue || 0);\n return (\n
\n {state.value}\n \n
\n );\n});\n```\n- `component$` is how a component gets declared. - `{ value?: number; step?: number }` declares the public (props) interface of the component. - `{ count: number }` declares the private (state) interface of the component.\n\nThe above can then be used like so:\n\n```tsx\nexport const OtherComponent = component$(() => {\n return ;\n});\n```\nSee also: `component`, `useCleanup`, `onResume`, `onPause`, `useOn`, `useOnDocument`, `useOnWindow`, `useStyles`\n\n\n```typescript\ncomponent$: (onMount: OnRenderFn) => Component\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nonMount\n\n\n\n\n[OnRenderFn](#onrenderfn)<PROPS>\n\n\n\n\n\n
\n\n**Returns:**\n\n[Component](#component)<PROPS>", + "content": "Declare a Qwik component that can be used to create UI.\n\nUse `component$` to declare a Qwik component. A Qwik component is a special kind of component that allows the Qwik framework to lazy load and execute the component independently of other Qwik components as well as lazy load the component's life-cycle hooks and event handlers.\n\nSide note: You can also declare regular (standard JSX) components that will have standard synchronous behavior.\n\nQwik component is a facade that describes how the component should be used without forcing the implementation of the component to be eagerly loaded. A minimum Qwik definition consists of:\n\n\\#\\#\\# Example\n\nAn example showing how to create a counter component:\n\n```tsx\nexport interface CounterProps {\n initialValue?: number;\n step?: number;\n}\nexport const Counter = component$((props: CounterProps) => {\n const state = useSignal(props.initialValue || 0);\n return (\n
\n {state.value}\n \n
\n );\n});\n```\n- `component$` is how a component gets declared. - `{ value?: number; step?: number }` declares the public (props) interface of the component. - `{ count: number }` declares the private (state) interface of the component.\n\nThe above can then be used like so:\n\n```tsx\nexport const OtherComponent = component$(() => {\n return ;\n});\n```\nSee also: `component`, `useCleanup`, `onResume`, `onPause`, `useOn`, `useOnDocument`, `useOnWindow`, `useStyles`\n\n\n```typescript\ncomponent$: (onMount: OnRenderFn) => Component\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nonMount\n\n\n\n\n[OnRenderFn](#onrenderfn)<PROPS>\n\n\n\n\n\n
\n\n**Returns:**\n\n[Component](#component-type-alias)<PROPS>", "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/component.public.ts", "mdFile": "core.component_.md" }, @@ -467,6 +481,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/types/jsx-qwik-attributes.ts", "mdFile": "core.correctedtoggleevent.md" }, + { + "name": "createAsync", + "id": "createasync", + "hierarchy": [ + { + "name": "createAsync", + "id": "createasync" + } + ], + "kind": "Function", + "content": "```typescript\ncreateAsync: (fn: ((arg: AsyncCtx) => Promise) | QRL<(arg: AsyncCtx) => Promise>, options?: AsyncSignalOptions) => AsyncSignal\n```\n\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nfn\n\n\n\n\n((arg: AsyncCtx) => Promise<T>) \\| [QRL](#qrl-type-alias)<(arg: AsyncCtx) => Promise<T>>\n\n\n\n\n\n
\n\noptions\n\n\n\n\n[AsyncSignalOptions](#asyncsignaloptions)<T>\n\n\n\n\n_(Optional)_\n\n\n
\n\n**Returns:**\n\n[AsyncSignal](#asyncsignal)<T>", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/reactive-primitives/signal.public.ts", + "mdFile": "core.createasync.md" + }, { "name": "createAsync$", "id": "createasync_", @@ -481,6 +509,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/reactive-primitives/signal.public.ts", "mdFile": "core.createasync_.md" }, + { + "name": "createComputed", + "id": "createcomputed", + "hierarchy": [ + { + "name": "createComputed", + "id": "createcomputed" + } + ], + "kind": "Function", + "content": "```typescript\ncreateComputed: (fn: (() => T) | QRL<() => T>, options?: ComputedOptions) => ComputedReturnType\n```\n\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nfn\n\n\n\n\n(() => T) \\| [QRL](#qrl-type-alias)<() => T>\n\n\n\n\n\n
\n\noptions\n\n\n\n\n[ComputedOptions](#computedoptions)\n\n\n\n\n_(Optional)_\n\n\n
\n\n**Returns:**\n\n[ComputedReturnType](#computedreturntype)<T>", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/reactive-primitives/signal.public.ts", + "mdFile": "core.createcomputed.md" + }, { "name": "createComputed$", "id": "createcomputed_", @@ -509,6 +551,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-context.ts", "mdFile": "core.createcontextid.md" }, + { + "name": "createSerializer", + "id": "createserializer", + "hierarchy": [ + { + "name": "createSerializer", + "id": "createserializer" + } + ], + "kind": "Function", + "content": "```typescript\ncreateSerializer: (arg: SerializerArg | QRL>) => T extends Promise ? never : SerializerSignal\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\narg\n\n\n\n\nSerializerArg<T, S> \\| [QRL](#qrl-type-alias)<SerializerArg<T, S>>\n\n\n\n\n\n
\n\n**Returns:**\n\nT extends Promise<any> ? never : [SerializerSignal](#serializersignal)<T>", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/reactive-primitives/signal.public.ts", + "mdFile": "core.createserializer.md" + }, { "name": "createSerializer$", "id": "createserializer_", @@ -519,7 +575,7 @@ } ], "kind": "Function", - "content": "Create a signal that holds a custom serializable value. See [useSerializer$](#useserializer_) for more details.\n\n\n```typescript\ncreateSerializer$: (arg: SerializerArg) => T extends Promise ? never : SerializerSignal\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\narg\n\n\n\n\nSerializerArg<T, S>\n\n\n\n\n\n
\n\n**Returns:**\n\nT extends Promise<any> ? never : SerializerSignal<T>", + "content": "Create a signal that holds a custom serializable value. See [useSerializer$](#useserializer_) for more details.\n\n\n```typescript\ncreateSerializer$: (arg: SerializerArg) => T extends Promise ? never : SerializerSignal\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\narg\n\n\n\n\nSerializerArg<T, S>\n\n\n\n\n\n
\n\n**Returns:**\n\nT extends Promise<any> ? never : [SerializerSignal](#serializersignal)<T>", "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/reactive-primitives/signal.public.ts", "mdFile": "core.createserializer_.md" }, @@ -1341,7 +1397,7 @@ } ], "kind": "TypeAlias", - "content": "Infers `Props` from the component or tag.\n\n\n```typescript\nexport type PropsOf = COMP extends string ? COMP extends keyof QwikIntrinsicElements ? QwikIntrinsicElements[COMP] : QwikIntrinsicElements['span'] : NonNullable extends never ? never : COMP extends FunctionComponent ? PROPS extends Record ? IsAny extends true ? never : ObjectProps : COMP extends Component ? ObjectProps : PROPS : never;\n```\n**References:** [QwikIntrinsicElements](#qwikintrinsicelements), [FunctionComponent](#functioncomponent), [Component](#component)\n\n\n\n```tsx\nconst Desc = component$(({desc, ...props}: { desc: string } & PropsOf<'div'>) => {\n return
{desc}
;\n});\n\nconst TitleBox = component$(({title, ...props}: { title: string } & PropsOf) => {\n return

{title}

;\n});\n```", + "content": "Infers `Props` from the component or tag.\n\n\n```typescript\nexport type PropsOf = COMP extends string ? COMP extends keyof QwikIntrinsicElements ? QwikIntrinsicElements[COMP] : QwikIntrinsicElements['span'] : NonNullable extends never ? never : COMP extends FunctionComponent ? PROPS extends Record ? IsAny extends true ? never : ObjectProps : COMP extends Component ? ObjectProps : PROPS : never;\n```\n**References:** [QwikIntrinsicElements](#qwikintrinsicelements), [FunctionComponent](#functioncomponent), [Component](#component-type-alias)\n\n\n\n```tsx\nconst Desc = component$(({desc, ...props}: { desc: string } & PropsOf<'div'>) => {\n return
{desc}
;\n});\n\nconst TitleBox = component$(({title, ...props}: { title: string } & PropsOf) => {\n return

{title}

;\n});\n```", "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/component.public.ts", "mdFile": "core.propsof.md" }, @@ -2045,6 +2101,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/types.ts", "mdFile": "core.serializationstrategy.md" }, + { + "name": "SerializerSignal", + "id": "serializersignal", + "hierarchy": [ + { + "name": "SerializerSignal", + "id": "serializersignal" + } + ], + "kind": "Interface", + "content": "A serializer signal holds a custom serializable value. See `useSerializer$` for more details.\n\n\n```typescript\nexport interface SerializerSignal extends ComputedSignal \n```\n**Extends:** [ComputedSignal](#computedsignal)<T>\n\n\n\n\n
\n\nProperty\n\n\n\n\nModifiers\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\n\\_\\_no\\_serialize\\_\\_\n\n\n\n\n\n\n\ntrue\n\n\n\n\nFake property to make the serialization linter happy\n\n\n
", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/reactive-primitives/signal.public.ts", + "mdFile": "core.serializersignal.md" + }, { "name": "SerializerSymbol", "id": "serializersymbol", @@ -2482,6 +2552,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/reactive-primitives/impl/store.ts", "mdFile": "core.unwrapstore.md" }, + { + "name": "useAsync", + "id": "useasync", + "hierarchy": [ + { + "name": "useAsync", + "id": "useasync" + } + ], + "kind": "Function", + "content": "```typescript\nuseAsync: (fn: AsyncFn | QRL>, options?: AsyncSignalOptions) => AsyncSignal\n```\n\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nfn\n\n\n\n\n[AsyncFn](#asyncfn)<T> \\| [QRL](#qrl-type-alias)<[AsyncFn](#asyncfn)<T>>\n\n\n\n\n\n
\n\noptions\n\n\n\n\n[AsyncSignalOptions](#asyncsignaloptions)<T>\n\n\n\n\n_(Optional)_\n\n\n
\n\n**Returns:**\n\n[AsyncSignal](#asyncsignal)<T>", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-async.ts", + "mdFile": "core.useasync.md" + }, { "name": "useAsync$", "id": "useasync_", @@ -2496,6 +2580,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-async.ts", "mdFile": "core.useasync_.md" }, + { + "name": "useComputed", + "id": "usecomputed", + "hierarchy": [ + { + "name": "useComputed", + "id": "usecomputed" + } + ], + "kind": "Function", + "content": "```typescript\nuseComputed: (fn: ComputedFn | QRL>, options?: ComputedOptions) => ComputedReturnType\n```\n\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nfn\n\n\n\n\n[ComputedFn](#computedfn)<T> \\| [QRL](#qrl-type-alias)<[ComputedFn](#computedfn)<T>>\n\n\n\n\n\n
\n\noptions\n\n\n\n\n[ComputedOptions](#computedoptions)\n\n\n\n\n_(Optional)_\n\n\n
\n\n**Returns:**\n\n[ComputedReturnType](#computedreturntype)<T>", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-computed.ts", + "mdFile": "core.usecomputed.md" + }, { "name": "useComputed$", "id": "usecomputed_", @@ -2590,7 +2688,7 @@ } ], "kind": "Function", - "content": "Register a listener on the current component's host element.\n\nUsed to programmatically add event listeners. Useful from custom `use*` methods, which do not have access to the JSX. Otherwise, it's adding a JSX listener in the `
` is a better idea.\n\nEvents are case sensitive.\n\n\n```typescript\nuseOn: (event: T | T[], eventQrl: EventQRL, options?: UseOnOptions) => void\n```\n\n\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nevent\n\n\n\n\nT \\| T\\[\\]\n\n\n\n\n\n
\n\neventQrl\n\n\n\n\nEventQRL<T>\n\n\n\n\n\n
\n\noptions\n\n\n\n\n[UseOnOptions](#useonoptions)\n\n\n\n\n_(Optional)_\n\n\n
\n\n**Returns:**\n\nvoid", + "content": "Register a listener on the current component's host element.\n\nUsed to programmatically add event listeners. Useful from custom `use*` methods, which do not have access to the JSX. Otherwise, it's adding a JSX listener in the `
` is a better idea.\n\nEvents are case sensitive.\n\n\n```typescript\nuseOn: (event: T | T[], eventQrl: EventQRL | EventHandler, Element>, options?: UseOnOptions) => void\n```\n\n\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nevent\n\n\n\n\nT \\| T\\[\\]\n\n\n\n\n\n
\n\neventQrl\n\n\n\n\nEventQRL<T> \\| [EventHandler](#eventhandler)<EventFromName<T>, Element>\n\n\n\n\n\n
\n\noptions\n\n\n\n\n[UseOnOptions](#useonoptions)\n\n\n\n\n_(Optional)_\n\n\n
\n\n**Returns:**\n\nvoid", "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-on.ts", "mdFile": "core.useon.md" }, @@ -2604,7 +2702,7 @@ } ], "kind": "Function", - "content": "Register a listener on `document`.\n\nUsed to programmatically add event listeners. Useful from custom `use*` methods, which do not have access to the JSX.\n\nEvents are case sensitive.\n\n\n```typescript\nuseOnDocument: (event: T | T[], eventQrl: EventQRL, options?: UseOnOptions) => void\n```\n\n\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nevent\n\n\n\n\nT \\| T\\[\\]\n\n\n\n\n\n
\n\neventQrl\n\n\n\n\nEventQRL<T>\n\n\n\n\n\n
\n\noptions\n\n\n\n\n[UseOnOptions](#useonoptions)\n\n\n\n\n_(Optional)_\n\n\n
\n\n**Returns:**\n\nvoid", + "content": "Register a listener on `document`.\n\nUsed to programmatically add event listeners. Useful from custom `use*` methods, which do not have access to the JSX.\n\nEvents are case sensitive.\n\n\n```typescript\nuseOnDocument: (event: T | T[], eventQrl: EventQRL | EventHandler, Element>, options?: UseOnOptions) => void\n```\n\n\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nevent\n\n\n\n\nT \\| T\\[\\]\n\n\n\n\n\n
\n\neventQrl\n\n\n\n\nEventQRL<T> \\| [EventHandler](#eventhandler)<EventFromName<T>, Element>\n\n\n\n\n\n
\n\noptions\n\n\n\n\n[UseOnOptions](#useonoptions)\n\n\n\n\n_(Optional)_\n\n\n
\n\n**Returns:**\n\nvoid", "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-on.ts", "mdFile": "core.useondocument.md" }, @@ -2632,10 +2730,24 @@ } ], "kind": "Function", - "content": "Register a listener on `window`.\n\nUsed to programmatically add event listeners. Useful from custom `use*` methods, which do not have access to the JSX.\n\nEvents are case sensitive.\n\n\n```typescript\nuseOnWindow: (event: T | T[], eventQrl: EventQRL, options?: UseOnOptions) => void\n```\n\n\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nevent\n\n\n\n\nT \\| T\\[\\]\n\n\n\n\n\n
\n\neventQrl\n\n\n\n\nEventQRL<T>\n\n\n\n\n\n
\n\noptions\n\n\n\n\n[UseOnOptions](#useonoptions)\n\n\n\n\n_(Optional)_\n\n\n
\n\n**Returns:**\n\nvoid", + "content": "Register a listener on `window`.\n\nUsed to programmatically add event listeners. Useful from custom `use*` methods, which do not have access to the JSX.\n\nEvents are case sensitive.\n\n\n```typescript\nuseOnWindow: (event: T | T[], eventQrl: EventQRL | EventHandler, Element>, options?: UseOnOptions) => void\n```\n\n\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nevent\n\n\n\n\nT \\| T\\[\\]\n\n\n\n\n\n
\n\neventQrl\n\n\n\n\nEventQRL<T> \\| [EventHandler](#eventhandler)<EventFromName<T>, Element>\n\n\n\n\n\n
\n\noptions\n\n\n\n\n[UseOnOptions](#useonoptions)\n\n\n\n\n_(Optional)_\n\n\n
\n\n**Returns:**\n\nvoid", "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-on.ts", "mdFile": "core.useonwindow.md" }, + { + "name": "useResource", + "id": "useresource", + "hierarchy": [ + { + "name": "useResource", + "id": "useresource" + } + ], + "kind": "Function", + "content": "```typescript\nuseResource: (fn: ResourceFn | QRL>, opts?: ResourceOptions) => ResourceReturn\n```\n\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nfn\n\n\n\n\n[ResourceFn](#resourcefn)<T> \\| [QRL](#qrl-type-alias)<[ResourceFn](#resourcefn)<T>>\n\n\n\n\n\n
\n\nopts\n\n\n\n\n[ResourceOptions](#resourceoptions)\n\n\n\n\n_(Optional)_\n\n\n
\n\n**Returns:**\n\n[ResourceReturn](#resourcereturn)<T>", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-resource.ts", + "mdFile": "core.useresource.md" + }, { "name": "useResource$", "id": "useresource_", @@ -2650,6 +2762,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-resource-dollar.ts", "mdFile": "core.useresource_.md" }, + { + "name": "useSerializer", + "id": "useserializer", + "hierarchy": [ + { + "name": "useSerializer", + "id": "useserializer" + } + ], + "kind": "Function", + "content": "```typescript\nuseSerializer: (arg: SerializerArg | QRL>) => T extends Promise ? never : SerializerSignal\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\narg\n\n\n\n\nSerializerArg<T, S> \\| [QRL](#qrl-type-alias)<SerializerArg<T, S>>\n\n\n\n\n\n
\n\n**Returns:**\n\nT extends Promise<any> ? never : [SerializerSignal](#serializersignal)<T>", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-serializer.ts", + "mdFile": "core.useserializer.md" + }, { "name": "useSerializer$", "id": "useserializer_", @@ -2734,6 +2860,34 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-store.public.ts", "mdFile": "core.usestoreoptions.md" }, + { + "name": "useStyles", + "id": "usestyles", + "hierarchy": [ + { + "name": "useStyles", + "id": "usestyles" + } + ], + "kind": "Function", + "content": "```typescript\nexport interface UseStyles \n```\n\n\n\n\n
\n\nProperty\n\n\n\n\nModifiers\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nstyleId\n\n\n\n\n\n\n\nstring\n\n\n\n\n\n
", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-styles.ts", + "mdFile": "core.usestyles.md" + }, + { + "name": "UseStyles", + "id": "usestyles", + "hierarchy": [ + { + "name": "UseStyles", + "id": "usestyles" + } + ], + "kind": "Interface", + "content": "```typescript\nexport interface UseStyles \n```\n\n\n\n\n
\n\nProperty\n\n\n\n\nModifiers\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nstyleId\n\n\n\n\n\n\n\nstring\n\n\n\n\n\n
", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-styles.ts", + "mdFile": "core.usestyles.md" + }, { "name": "useStyles$", "id": "usestyles_", @@ -2744,10 +2898,24 @@ } ], "kind": "Function", - "content": "A lazy-loadable reference to a component's styles.\n\nComponent styles allow Qwik to lazy load the style information for the component only when needed. (And avoid double loading it in case of SSR hydration.)\n\n```tsx\nimport styles from './code-block.css?inline';\n\nexport const CmpStyles = component$(() => {\n useStyles$(styles);\n\n return
Some text
;\n});\n```\n\n\n```typescript\nuseStyles$: (qrl: string) => UseStyles\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nqrl\n\n\n\n\nstring\n\n\n\n\n\n
\n\n**Returns:**\n\nUseStyles", + "content": "A lazy-loadable reference to a component's styles.\n\nComponent styles allow Qwik to lazy load the style information for the component only when needed. (And avoid double loading it in case of SSR hydration.)\n\n```tsx\nimport styles from './code-block.css?inline';\n\nexport const CmpStyles = component$(() => {\n useStyles$(styles);\n\n return
Some text
;\n});\n```\n\n\n```typescript\nuseStyles$: (qrl: string) => UseStyles\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nqrl\n\n\n\n\nstring\n\n\n\n\n\n
\n\n**Returns:**\n\n[UseStyles](#usestyles-interface)", "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-styles.ts", "mdFile": "core.usestyles_.md" }, + { + "name": "useStylesScoped", + "id": "usestylesscoped", + "hierarchy": [ + { + "name": "useStylesScoped", + "id": "usestylesscoped" + } + ], + "kind": "Function", + "content": "```typescript\nexport interface UseStylesScoped \n```\n\n\n\n\n
\n\nProperty\n\n\n\n\nModifiers\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nscopeId\n\n\n\n\n\n\n\nstring\n\n\n\n\n\n
", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-styles.ts", + "mdFile": "core.usestylesscoped.md" + }, { "name": "UseStylesScoped", "id": "usestylesscoped", @@ -2772,10 +2940,24 @@ } ], "kind": "Function", - "content": "A lazy-loadable reference to a component's styles, that is scoped to the component.\n\nComponent styles allow Qwik to lazy load the style information for the component only when needed. (And avoid double loading it in case of SSR hydration.)\n\n```tsx\nimport scoped from './code-block.css?inline';\n\nexport const CmpScopedStyles = component$(() => {\n useStylesScoped$(scoped);\n\n return
Some text
;\n});\n```\n\n\n```typescript\nuseStylesScoped$: (qrl: string) => UseStylesScoped\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nqrl\n\n\n\n\nstring\n\n\n\n\n\n
\n\n**Returns:**\n\n[UseStylesScoped](#usestylesscoped)", + "content": "A lazy-loadable reference to a component's styles, that is scoped to the component.\n\nComponent styles allow Qwik to lazy load the style information for the component only when needed. (And avoid double loading it in case of SSR hydration.)\n\n```tsx\nimport scoped from './code-block.css?inline';\n\nexport const CmpScopedStyles = component$(() => {\n useStylesScoped$(scoped);\n\n return
Some text
;\n});\n```\n\n\n```typescript\nuseStylesScoped$: (qrl: string) => UseStylesScoped\n```\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nqrl\n\n\n\n\nstring\n\n\n\n\n\n
\n\n**Returns:**\n\n[UseStylesScoped](#usestylesscoped-interface)", "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-styles.ts", "mdFile": "core.usestylesscoped_.md" }, + { + "name": "useTask", + "id": "usetask", + "hierarchy": [ + { + "name": "useTask", + "id": "usetask" + } + ], + "kind": "Function", + "content": "```typescript\nuseTask: (fn: TaskFn | QRL, opts?: TaskOptions) => void\n```\n\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nfn\n\n\n\n\n[TaskFn](#taskfn) \\| [QRL](#qrl-type-alias)<[TaskFn](#taskfn)>\n\n\n\n\n\n
\n\nopts\n\n\n\n\n[TaskOptions](#taskoptions)\n\n\n\n\n_(Optional)_\n\n\n
\n\n**Returns:**\n\nvoid", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-task.ts", + "mdFile": "core.usetask.md" + }, { "name": "useTask$", "id": "usetask_", @@ -2790,6 +2972,20 @@ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-task-dollar.ts", "mdFile": "core.usetask_.md" }, + { + "name": "useVisibleTask", + "id": "usevisibletask", + "hierarchy": [ + { + "name": "useVisibleTask", + "id": "usevisibletask" + } + ], + "kind": "Function", + "content": "```typescript\nuseVisibleTask: (fn: TaskFn | QRL, opts?: OnVisibleTaskOptions) => void\n```\n\n\n\n\n\n
\n\nParameter\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\nfn\n\n\n\n\n[TaskFn](#taskfn) \\| [QRL](#qrl-type-alias)<[TaskFn](#taskfn)>\n\n\n\n\n\n
\n\nopts\n\n\n\n\n[OnVisibleTaskOptions](#onvisibletaskoptions)\n\n\n\n\n_(Optional)_\n\n\n
\n\n**Returns:**\n\nvoid", + "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-visible-task.ts", + "mdFile": "core.usevisibletask.md" + }, { "name": "useVisibleTask$", "id": "usevisibletask_", diff --git a/packages/docs/src/routes/api/qwik/index.mdx b/packages/docs/src/routes/api/qwik/index.mdx index 5770fc9833a..23ddd719761 100644 --- a/packages/docs/src/routes/api/qwik/index.mdx +++ b/packages/docs/src/routes/api/qwik/index.mdx @@ -632,7 +632,32 @@ cleanup(): void; void -

Component

+

component

+ +Type representing the Qwik component. + +`Component` is the type returned by invoking `component$`. + +```tsx +interface MyComponentProps { + someProp: string; +} +const MyComponent: Component = component$( + (props: MyComponentProps) => { + return {props.someProp}; + }, +); +``` + +```typescript +export type Component = FunctionComponent>; +``` + +**References:** [FunctionComponent](#functioncomponent), [PublicProps](#publicprops) + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/component.public.ts) + +

Component

Type representing the Qwik component. @@ -731,7 +756,7 @@ onMount **Returns:** -[Component](#component)<PROPS> +[Component](#component-type-alias)<PROPS> [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/component.public.ts) @@ -1172,6 +1197,60 @@ prevState [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/types/jsx-qwik-attributes.ts) +

createAsync

+ +```typescript +createAsync: ( + fn: ((arg: AsyncCtx) => Promise) | QRL<(arg: AsyncCtx) => Promise>, + options?: AsyncSignalOptions, +) => AsyncSignal; +``` + + + + +
+ +Parameter + + + +Type + + + +Description + +
+ +fn + + + +((arg: AsyncCtx) => Promise<T>) \| [QRL](#qrl-type-alias)<(arg: AsyncCtx) => Promise<T>> + + + +
+ +options + + + +[AsyncSignalOptions](#asyncsignaloptions)<T> + + + +_(Optional)_ + +
+ +**Returns:** + +[AsyncSignal](#asyncsignal)<T> + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/reactive-primitives/signal.public.ts) +

createAsync$

Create a signal holding a `.value` which is calculated from the given async function (QRL). The standalone version of `useAsync$`. @@ -1228,6 +1307,58 @@ _(Optional)_ [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/reactive-primitives/signal.public.ts) +

createComputed

+ +```typescript +createComputed: (fn: (() => T) | QRL<() => T>, options?: ComputedOptions) => + ComputedReturnType; +``` + + + + +
+ +Parameter + + + +Type + + + +Description + +
+ +fn + + + +(() => T) \| [QRL](#qrl-type-alias)<() => T> + + + +
+ +options + + + +[ComputedOptions](#computedoptions) + + + +_(Optional)_ + +
+ +**Returns:** + +[ComputedReturnType](#computedreturntype)<T> + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/reactive-primitives/signal.public.ts) +

createComputed$

Create a computed signal which is calculated from the given QRL. A computed signal is a signal which is calculated from other signals. When the signals change, the computed signal is recalculated. @@ -1368,6 +1499,44 @@ The name of the context. [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-context.ts) +

createSerializer

+ +```typescript +createSerializer: (arg: SerializerArg | QRL>) => T extends Promise ? never : SerializerSignal +``` + + + +
+ +Parameter + + + +Type + + + +Description + +
+ +arg + + + +SerializerArg<T, S> \| [QRL](#qrl-type-alias)<SerializerArg<T, S>> + + + +
+ +**Returns:** + +T extends Promise<any> ? never : [SerializerSignal](#serializersignal)<T> + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/reactive-primitives/signal.public.ts) +

createSerializer$

Create a signal that holds a custom serializable value. See [useSerializer$](#useserializer_) for more details. @@ -1404,7 +1573,7 @@ SerializerArg<T, S> **Returns:** -T extends Promise<any> ? never : SerializerSignal<T> +T extends Promise<any> ? never : [SerializerSignal](#serializersignal)<T> [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/reactive-primitives/signal.public.ts) @@ -3069,7 +3238,7 @@ export type PropsOf = COMP extends string : never; ``` -**References:** [QwikIntrinsicElements](#qwikintrinsicelements), [FunctionComponent](#functioncomponent), [Component](#component) +**References:** [QwikIntrinsicElements](#qwikintrinsicelements), [FunctionComponent](#functioncomponent), [Component](#component-type-alias) ```tsx const Desc = component$( @@ -4443,6 +4612,52 @@ export type SerializationStrategy = "never" | "always"; [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/types.ts) +

SerializerSignal

+ +A serializer signal holds a custom serializable value. See `useSerializer$` for more details. + +```typescript +export interface SerializerSignal extends ComputedSignal +``` + +**Extends:** [ComputedSignal](#computedsignal)<T> + + + +
+ +Property + + + +Modifiers + + + +Type + + + +Description + +
+ +\_\_no_serialize\_\_ + + + + + +true + + + +Fake property to make the serialization linter happy + +
+ +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/reactive-primitives/signal.public.ts) +

SerializerSymbol

If an object has this property as a function, it will be called with the object and should return a serializable value. @@ -9322,21 +9537,13 @@ T [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/reactive-primitives/impl/store.ts) -

useAsync$

- -Creates an AsyncSignal which holds the result of the given async function. If the function uses `track()` to track reactive state, and that state changes, the AsyncSignal is recalculated, and if the result changed, all tasks which are tracking the AsyncSignal will be re-run and all subscribers (components, tasks etc) that read the AsyncSignal will be updated. - -If the async function throws an error, the AsyncSignal will capture the error and set the `error` property. The error can be cleared by re-running the async function successfully. - -While the async function is running, the `loading` property will be set to `true`. Once the function completes, `loading` will be set to `false`. - -If the value has not yet been resolved, reading the AsyncSignal will throw a Promise, which will retry the component or task once the value resolves. - -If the value has been resolved, but the async function is re-running, reading the AsyncSignal will subscribe to it and return the last resolved value until the new value is ready. As soon as the new value is ready, the subscribers will be updated. +

useAsync

```typescript -useAsync$: (qrl: AsyncFn, options?: AsyncSignalOptions | undefined) => - AsyncSignal; +useAsync: ( + fn: AsyncFn | QRL>, + options?: AsyncSignalOptions, +) => AsyncSignal; ```
@@ -9354,11 +9561,11 @@ Description
-qrl +fn -[AsyncFn](#asyncfn)<T> +[AsyncFn](#asyncfn)<T> \| [QRL](#qrl-type-alias)<[AsyncFn](#asyncfn)<T>> @@ -9369,7 +9576,7 @@ options -[AsyncSignalOptions](#asyncsignaloptions)<T> \| undefined +[AsyncSignalOptions](#asyncsignaloptions)<T> @@ -9384,15 +9591,21 @@ _(Optional)_ [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-async.ts) -

useComputed$

+

useAsync$

-Creates a computed signal which is calculated from the given function. A computed signal is a signal which is calculated from other signals. When the signals change, the computed signal is recalculated, and if the result changed, all tasks which are tracking the signal will be re-run and all components that read the signal will be re-rendered. +Creates an AsyncSignal which holds the result of the given async function. If the function uses `track()` to track reactive state, and that state changes, the AsyncSignal is recalculated, and if the result changed, all tasks which are tracking the AsyncSignal will be re-run and all subscribers (components, tasks etc) that read the AsyncSignal will be updated. -The function must be synchronous and must not have any side effects. +If the async function throws an error, the AsyncSignal will capture the error and set the `error` property. The error can be cleared by re-running the async function successfully. + +While the async function is running, the `loading` property will be set to `true`. Once the function completes, `loading` will be set to `false`. + +If the value has not yet been resolved, reading the AsyncSignal will throw a Promise, which will retry the component or task once the value resolves. + +If the value has been resolved, but the async function is re-running, reading the AsyncSignal will subscribe to it and return the last resolved value until the new value is ready. As soon as the new value is ready, the subscribers will be updated. ```typescript -useComputed$: (qrl: ComputedFn, options?: ComputedOptions | undefined) => - ComputedReturnType; +useAsync$: (qrl: AsyncFn, options?: AsyncSignalOptions | undefined) => + AsyncSignal; ```
@@ -9414,7 +9627,7 @@ qrl -[ComputedFn](#computedfn)<T> +[AsyncFn](#asyncfn)<T> @@ -9425,7 +9638,7 @@ options -[ComputedOptions](#computedoptions) \| undefined +[AsyncSignalOptions](#asyncsignaloptions)<T> \| undefined @@ -9436,19 +9649,17 @@ _(Optional)_ **Returns:** -[ComputedReturnType](#computedreturntype)<T> - -[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-computed.ts) - -

useConstant

+[AsyncSignal](#asyncsignal)<T> -Stores a value which is retained for the lifetime of the component. Subsequent calls to `useConstant` will always return the first value given. +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-async.ts) -If the value is a function, the function is invoked once to calculate the actual value. You can then also pass arguments to call the function with, so that you don't need to create a new function on every render. +

useComputed

```typescript -useConstant: (value: ((...args: A) => T) | T, ...args: A) => - T; +useComputed: ( + fn: ComputedFn | QRL>, + options?: ComputedOptions, +) => ComputedReturnType; ``` +_(Optional)_ + + +
@@ -9466,26 +9677,138 @@ Description
-value +fn -((...args: A) => T) \| T +[ComputedFn](#computedfn)<T> \| [QRL](#qrl-type-alias)<[ComputedFn](#computedfn)<T>>
-args +options -A +[ComputedOptions](#computedoptions) -
+ +**Returns:** + +[ComputedReturnType](#computedreturntype)<T> + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-computed.ts) + +

useComputed$

+ +Creates a computed signal which is calculated from the given function. A computed signal is a signal which is calculated from other signals. When the signals change, the computed signal is recalculated, and if the result changed, all tasks which are tracking the signal will be re-run and all components that read the signal will be re-rendered. + +The function must be synchronous and must not have any side effects. + +```typescript +useComputed$: (qrl: ComputedFn, options?: ComputedOptions | undefined) => + ComputedReturnType; +``` + + + + +
+ +Parameter + + + +Type + + + +Description + +
+ +qrl + + + +[ComputedFn](#computedfn)<T> + + + +
+ +options + + + +[ComputedOptions](#computedoptions) \| undefined + + + +_(Optional)_ + +
+ +**Returns:** + +[ComputedReturnType](#computedreturntype)<T> + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-computed.ts) + +

useConstant

+ +Stores a value which is retained for the lifetime of the component. Subsequent calls to `useConstant` will always return the first value given. + +If the value is a function, the function is invoked once to calculate the actual value. You can then also pass arguments to call the function with, so that you don't need to create a new function on every render. + +```typescript +useConstant: (value: ((...args: A) => T) | T, ...args: A) => + T; +``` + + + +
+ +Parameter + + + +Type + + + +Description + +
+ +value + + + +((...args: A) => T) \| T + + + +
+ +args + + + +A + + + +
**Returns:** @@ -9676,7 +9999,7 @@ Used to programmatically add event listeners. Useful from custom `use*` methods, Events are case sensitive. ```typescript -useOn: (event: T | T[], eventQrl: EventQRL, options?: UseOnOptions) => void +useOn: (event: T | T[], eventQrl: EventQRL | EventHandler, Element>, options?: UseOnOptions) => void ```
@@ -9709,7 +10032,7 @@ eventQrl -EventQRL<T> +EventQRL<T> \| [EventHandler](#eventhandler)<EventFromName<T>, Element> @@ -9744,7 +10067,7 @@ Used to programmatically add event listeners. Useful from custom `use*` methods, Events are case sensitive. ```typescript -useOnDocument: (event: T | T[], eventQrl: EventQRL, options?: UseOnOptions) => void +useOnDocument: (event: T | T[], eventQrl: EventQRL | EventHandler, Element>, options?: UseOnOptions) => void ```
@@ -9777,7 +10100,7 @@ eventQrl -EventQRL<T> +EventQRL<T> \| [EventHandler](#eventhandler)<EventFromName<T>, Element> @@ -9830,7 +10153,7 @@ Used to programmatically add event listeners. Useful from custom `use*` methods, Events are case sensitive. ```typescript -useOnWindow: (event: T | T[], eventQrl: EventQRL, options?: UseOnOptions) => void +useOnWindow: (event: T | T[], eventQrl: EventQRL | EventHandler, Element>, options?: UseOnOptions) => void ```
@@ -9863,7 +10186,7 @@ eventQrl -EventQRL<T> +EventQRL<T> \| [EventHandler](#eventhandler)<EventFromName<T>, Element> @@ -9889,6 +10212,60 @@ void [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-on.ts) +

useResource

+ +```typescript +useResource: ( + fn: ResourceFn | QRL>, + opts?: ResourceOptions, +) => ResourceReturn; +``` + + + + +
+ +Parameter + + + +Type + + + +Description + +
+ +fn + + + +[ResourceFn](#resourcefn)<T> \| [QRL](#qrl-type-alias)<[ResourceFn](#resourcefn)<T>> + + + +
+ +opts + + + +[ResourceOptions](#resourceoptions) + + + +_(Optional)_ + +
+ +**Returns:** + +[ResourceReturn](#resourcereturn)<T> + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-resource.ts) +

useResource$

> Warning: This API is now obsolete. @@ -9957,6 +10334,44 @@ import("./use-resource").[ResourceReturn](#resourcereturn)<T> [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-resource-dollar.ts) +

useSerializer

+ +```typescript +useSerializer: (arg: SerializerArg | QRL>) => T extends Promise ? never : SerializerSignal +``` + + + +
+ +Parameter + + + +Type + + + +Description + +
+ +arg + + + +SerializerArg<T, S> \| [QRL](#qrl-type-alias)<SerializerArg<T, S>> + + + +
+ +**Returns:** + +T extends Promise<any> ? never : [SerializerSignal](#serializersignal)<T> + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-serializer.ts) +

useSerializer$

Creates a signal which holds a custom serializable value. It requires that the value implements the `CustomSerializable` type, which means having a function under the `[SerializeSymbol]` property that returns a serializable value when called. @@ -10306,6 +10721,86 @@ _(Optional)_ If `false` then the object will not be tracked for changes. Default [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-store.public.ts) +

useStyles

+ +```typescript +export interface UseStyles +``` + + + +
+ +Property + + + +Modifiers + + + +Type + + + +Description + +
+ +styleId + + + + + +string + + + +
+ +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-styles.ts) + +

UseStyles

+ +```typescript +export interface UseStyles +``` + + + +
+ +Property + + + +Modifiers + + + +Type + + + +Description + +
+ +styleId + + + + + +string + + + +
+ +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-styles.ts) +

useStyles$

A lazy-loadable reference to a component's styles. @@ -10354,11 +10849,51 @@ string **Returns:** -UseStyles +[UseStyles](#usestyles-interface) [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-styles.ts) -

UseStylesScoped

+

useStylesScoped

+ +```typescript +export interface UseStylesScoped +``` + + + +
+ +Property + + + +Modifiers + + + +Type + + + +Description + +
+ +scopeId + + + + + +string + + + +
+ +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-styles.ts) + +

UseStylesScoped

```typescript export interface UseStylesScoped @@ -10446,10 +10981,61 @@ string **Returns:** -[UseStylesScoped](#usestylesscoped) +[UseStylesScoped](#usestylesscoped-interface) [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-styles.ts) +

useTask

+ +```typescript +useTask: (fn: TaskFn | QRL, opts?: TaskOptions) => void +``` + + + + +
+ +Parameter + + + +Type + + + +Description + +
+ +fn + + + +[TaskFn](#taskfn) \| [QRL](#qrl-type-alias)<[TaskFn](#taskfn)> + + + +
+ +opts + + + +[TaskOptions](#taskoptions) + + + +_(Optional)_ + +
+ +**Returns:** + +void + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-task.ts) +

useTask$

Reruns the `taskFn` when the observed inputs change. @@ -10507,6 +11093,57 @@ void [Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-task-dollar.ts) +

useVisibleTask

+ +```typescript +useVisibleTask: (fn: TaskFn | QRL, opts?: OnVisibleTaskOptions) => void +``` + + + + +
+ +Parameter + + + +Type + + + +Description + +
+ +fn + + + +[TaskFn](#taskfn) \| [QRL](#qrl-type-alias)<[TaskFn](#taskfn)> + + + +
+ +opts + + + +[OnVisibleTaskOptions](#onvisibletaskoptions) + + + +_(Optional)_ + +
+ +**Returns:** + +void + +[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-visible-task.ts) +

useVisibleTask$

```tsx diff --git a/packages/optimizer/core/src/snapshots/qwik_core__test__example_1.snap b/packages/optimizer/core/src/snapshots/qwik_core__test__example_1.snap index 9e56c67954c..8bd89f38afd 100644 --- a/packages/optimizer/core/src/snapshots/qwik_core__test__example_1.snap +++ b/packages/optimizer/core/src/snapshots/qwik_core__test__example_1.snap @@ -1,6 +1,5 @@ --- source: packages/optimizer/core/src/test.rs -assertion_line: 92 expression: output --- ==INPUT== @@ -18,20 +17,20 @@ const renderHeader2 = component($(() => { return render; })); -============================= test.tsx_renderHeader1_div_onClick_USi8k1jUb40.tsx (ENTRY POINT)== +============================= test.tsx_renderHeader1_div_q_e_click_fjy1WIjm9hw.tsx (ENTRY POINT)== -export const renderHeader1_div_onClick_USi8k1jUb40 = (ctx)=>console.log(ctx); +export const renderHeader1_div_q_e_click_fjy1WIjm9hw = (ctx)=>console.log(ctx); -Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\"qDAKkB,CAAC,MAAQ,QAAQ,GAAG,CAAC\"}") +Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\"uDAKkB,CAAC,MAAQ,QAAQ,GAAG,CAAC\"}") /* { "origin": "test.tsx", - "name": "renderHeader1_div_onClick_USi8k1jUb40", + "name": "renderHeader1_div_q_e_click_fjy1WIjm9hw", "entry": null, - "displayName": "test.tsx_renderHeader1_div_onClick", - "hash": "USi8k1jUb40", - "canonicalFilename": "test.tsx_renderHeader1_div_onClick_USi8k1jUb40", + "displayName": "test.tsx_renderHeader1_div_q_e_click", + "hash": "fjy1WIjm9hw", + "canonicalFilename": "test.tsx_renderHeader1_div_q_e_click_fjy1WIjm9hw", "path": "", "extension": "tsx", "parent": "renderHeader1_jMxQsjbyDss", @@ -64,10 +63,10 @@ Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"ma import { qrl } from "@qwik.dev/core"; // -const q_renderHeader1_div_onClick_USi8k1jUb40 = /*#__PURE__*/ qrl(()=>import("./test.tsx_renderHeader1_div_onClick_USi8k1jUb40"), "renderHeader1_div_onClick_USi8k1jUb40"); +const q_renderHeader1_div_q_e_click_fjy1WIjm9hw = /*#__PURE__*/ qrl(()=>import("./test.tsx_renderHeader1_div_q_e_click_fjy1WIjm9hw"), "renderHeader1_div_q_e_click_fjy1WIjm9hw"); // export const renderHeader1_jMxQsjbyDss = ()=>{ - return
; + return
; }; diff --git a/packages/optimizer/core/src/snapshots/qwik_core__test__example_10.snap b/packages/optimizer/core/src/snapshots/qwik_core__test__example_10.snap index 9b4a8e027c2..26f21d56f35 100644 --- a/packages/optimizer/core/src/snapshots/qwik_core__test__example_10.snap +++ b/packages/optimizer/core/src/snapshots/qwik_core__test__example_10.snap @@ -1,6 +1,5 @@ --- source: packages/optimizer/core/src/test.rs -assertion_line: 269 expression: output --- ==INPUT== @@ -46,11 +45,11 @@ export const Header_WlR3xnI6u38 = (decl1, { decl2 }, [decl3])=>{ return ident10; } } - return
ident11 + ident12} required={false}/>; + return
ident11 + ident12} required={false}/>; }; -Some("{\"version\":3,\"sources\":[\"/user/qwik/src/project/test.tsx\"],\"names\":[],\"mappings\":\"kCAEiB,CAAC,OAAO,EAAC,KAAK,EAAC,EAAE,CAAC,MAAM;IAE3B,OAAO,EAAE;IACtB;IACU,QAAS;IACT,QAAS;IACnB,OAAO,QAAQ;QAAC;KAAO,EAAE;QAAC;IAAM,GAAG;QAAC,KAAK;IAAM;IAC/C,MAAM;QACL,OAAO,OAAO;QACd,SAAS;YACR,OAAO;QACR;IACD;IAEA,QACE,IAAI,SAAS,CAAC,UAAY,UAAU,SAAS,UAAU;AAE1D\"}") +Some("{\"version\":3,\"sources\":[\"/user/qwik/src/project/test.tsx\"],\"names\":[],\"mappings\":\"kCAEiB,CAAC,OAAO,EAAC,KAAK,EAAC,EAAE,CAAC,MAAM;IAE3B,OAAO,EAAE;IACtB;IACU,QAAS;IACT,QAAS;IACnB,OAAO,QAAQ;QAAC;KAAO,EAAE;QAAC;IAAM,GAAG;QAAC,KAAK;IAAM;IAC/C,MAAM;QACL,OAAO,OAAO;QACd,SAAS;YACR,OAAO;QACR;IACD;IAEA,QACE,IAAI,WAAS,CAAC,UAAY,UAAU,SAAS,UAAU;AAE1D\"}") /* { "origin": "project/test.tsx", diff --git a/packages/optimizer/core/src/snapshots/qwik_core__test__example_2.snap b/packages/optimizer/core/src/snapshots/qwik_core__test__example_2.snap index 4da7b33081c..efe6f348f16 100644 --- a/packages/optimizer/core/src/snapshots/qwik_core__test__example_2.snap +++ b/packages/optimizer/core/src/snapshots/qwik_core__test__example_2.snap @@ -1,6 +1,5 @@ --- source: packages/optimizer/core/src/test.rs -assertion_line: 113 expression: output --- ==INPUT== @@ -14,15 +13,44 @@ export const Header = component$(() => { ); }); +============================= test.tsx_Header_component_div_q_e_click_aMxtmYKxCwA.tsx (ENTRY POINT)== + +export const Header_component_div_q_e_click_aMxtmYKxCwA = (ctx)=>console.log(ctx); + + +Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\"0DAKkB,CAAC,MAAQ,QAAQ,GAAG,CAAC\"}") +/* +{ + "origin": "test.tsx", + "name": "Header_component_div_q_e_click_aMxtmYKxCwA", + "entry": null, + "displayName": "test.tsx_Header_component_div_q_e_click", + "hash": "aMxtmYKxCwA", + "canonicalFilename": "test.tsx_Header_component_div_q_e_click_aMxtmYKxCwA", + "path": "", + "extension": "tsx", + "parent": "Header_component_J4uyIhaBNR4", + "ctxKind": "function", + "ctxName": "$", + "captures": false, + "loc": [ + 142, + 167 + ], + "paramNames": [ + "ctx" + ] +} +*/ ============================= test.tsx_Header_component_J4uyIhaBNR4.tsx (ENTRY POINT)== import { qrl } from "@qwik.dev/core"; // -const q_Header_component_div_onClick_i7ekvWH3674 = /*#__PURE__*/ qrl(()=>import("./test.tsx_Header_component_div_onClick_i7ekvWH3674"), "Header_component_div_onClick_i7ekvWH3674"); +const q_Header_component_div_q_e_click_aMxtmYKxCwA = /*#__PURE__*/ qrl(()=>import("./test.tsx_Header_component_div_q_e_click_aMxtmYKxCwA"), "Header_component_div_q_e_click_aMxtmYKxCwA"); // export const Header_component_J4uyIhaBNR4 = ()=>{ console.log("mount"); - return
; + return
; }; @@ -58,35 +86,6 @@ export const Header = /*#__PURE__*/ componentQrl(q_Header_component_J4uyIhaBNR4) Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;AAEA,OAAO,MAAM,uBAAS,6CAKnB\"}") -============================= test.tsx_Header_component_div_onClick_i7ekvWH3674.tsx (ENTRY POINT)== - -export const Header_component_div_onClick_i7ekvWH3674 = (ctx)=>console.log(ctx); - - -Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\"wDAKkB,CAAC,MAAQ,QAAQ,GAAG,CAAC\"}") -/* -{ - "origin": "test.tsx", - "name": "Header_component_div_onClick_i7ekvWH3674", - "entry": null, - "displayName": "test.tsx_Header_component_div_onClick", - "hash": "i7ekvWH3674", - "canonicalFilename": "test.tsx_Header_component_div_onClick_i7ekvWH3674", - "path": "", - "extension": "tsx", - "parent": "Header_component_J4uyIhaBNR4", - "ctxKind": "function", - "ctxName": "$", - "captures": false, - "loc": [ - 142, - 167 - ], - "paramNames": [ - "ctx" - ] -} -*/ == DIAGNOSTICS == [] diff --git a/packages/optimizer/core/src/snapshots/qwik_core__test__example_3.snap b/packages/optimizer/core/src/snapshots/qwik_core__test__example_3.snap index 35b45fad2c0..19736f95ed9 100644 --- a/packages/optimizer/core/src/snapshots/qwik_core__test__example_3.snap +++ b/packages/optimizer/core/src/snapshots/qwik_core__test__example_3.snap @@ -1,6 +1,5 @@ --- source: packages/optimizer/core/src/test.rs -assertion_line: 130 expression: output --- ==INPUT== @@ -21,11 +20,11 @@ export const App = () => { import { qrl } from "@qwik.dev/core"; // -const q_App_Header_component_div_onClick_aO7uI7Iw6oQ = /*#__PURE__*/ qrl(()=>import("./test.tsx_App_Header_component_div_onClick_aO7uI7Iw6oQ"), "App_Header_component_div_onClick_aO7uI7Iw6oQ"); +const q_App_Header_component_div_q_e_click_tbeQzUb0b9Q = /*#__PURE__*/ qrl(()=>import("./test.tsx_App_Header_component_div_q_e_click_tbeQzUb0b9Q"), "App_Header_component_div_q_e_click_tbeQzUb0b9Q"); // export const App_Header_component_B9F3YeqcO1w = ()=>{ console.log("mount"); - return
; + return
; }; @@ -50,20 +49,34 @@ Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"ma ] } */ -============================= test.tsx_App_Header_component_div_onClick_aO7uI7Iw6oQ.tsx (ENTRY POINT)== +============================= test.tsx == + +import { componentQrl } from "@qwik.dev/core"; +import { qrl } from "@qwik.dev/core"; +// +const q_App_Header_component_B9F3YeqcO1w = /*#__PURE__*/ qrl(()=>import("./test.tsx_App_Header_component_B9F3YeqcO1w"), "App_Header_component_B9F3YeqcO1w"); +// +export const App = ()=>{ + const Header = /*#__PURE__*/ componentQrl(q_App_Header_component_B9F3YeqcO1w); + return Header; +}; + + +Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;AAEA,OAAO,MAAM,MAAM;IAClB,MAAM,uBAAS;IAMf,OAAO;AACR,EAAG\"}") +============================= test.tsx_App_Header_component_div_q_e_click_tbeQzUb0b9Q.tsx (ENTRY POINT)== -export const App_Header_component_div_onClick_aO7uI7Iw6oQ = (ctx)=>console.log(ctx); +export const App_Header_component_div_q_e_click_tbeQzUb0b9Q = (ctx)=>console.log(ctx); -Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\"4DAMmB,CAAC,MAAQ,QAAQ,GAAG,CAAC\"}") +Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\"8DAMmB,CAAC,MAAQ,QAAQ,GAAG,CAAC\"}") /* { "origin": "test.tsx", - "name": "App_Header_component_div_onClick_aO7uI7Iw6oQ", + "name": "App_Header_component_div_q_e_click_tbeQzUb0b9Q", "entry": null, - "displayName": "test.tsx_App_Header_component_div_onClick", - "hash": "aO7uI7Iw6oQ", - "canonicalFilename": "test.tsx_App_Header_component_div_onClick_aO7uI7Iw6oQ", + "displayName": "test.tsx_App_Header_component_div_q_e_click", + "hash": "tbeQzUb0b9Q", + "canonicalFilename": "test.tsx_App_Header_component_div_q_e_click_tbeQzUb0b9Q", "path": "", "extension": "tsx", "parent": "App_Header_component_B9F3YeqcO1w", @@ -79,20 +92,6 @@ Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"ma ] } */ -============================= test.tsx == - -import { componentQrl } from "@qwik.dev/core"; -import { qrl } from "@qwik.dev/core"; -// -const q_App_Header_component_B9F3YeqcO1w = /*#__PURE__*/ qrl(()=>import("./test.tsx_App_Header_component_B9F3YeqcO1w"), "App_Header_component_B9F3YeqcO1w"); -// -export const App = ()=>{ - const Header = /*#__PURE__*/ componentQrl(q_App_Header_component_B9F3YeqcO1w); - return Header; -}; - - -Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;AAEA,OAAO,MAAM,MAAM;IAClB,MAAM,uBAAS;IAMf,OAAO;AACR,EAAG\"}") == DIAGNOSTICS == [] diff --git a/packages/optimizer/core/src/snapshots/qwik_core__test__example_4.snap b/packages/optimizer/core/src/snapshots/qwik_core__test__example_4.snap index c48b8916256..f762b818953 100644 --- a/packages/optimizer/core/src/snapshots/qwik_core__test__example_4.snap +++ b/packages/optimizer/core/src/snapshots/qwik_core__test__example_4.snap @@ -1,6 +1,5 @@ --- source: packages/optimizer/core/src/test.rs -assertion_line: 150 expression: output --- ==INPUT== @@ -21,11 +20,11 @@ export function App() { import { qrl } from "@qwik.dev/core"; // -const q_App_Header_component_div_onClick_aO7uI7Iw6oQ = /*#__PURE__*/ qrl(()=>import("./test.tsx_App_Header_component_div_onClick_aO7uI7Iw6oQ"), "App_Header_component_div_onClick_aO7uI7Iw6oQ"); +const q_App_Header_component_div_q_e_click_tbeQzUb0b9Q = /*#__PURE__*/ qrl(()=>import("./test.tsx_App_Header_component_div_q_e_click_tbeQzUb0b9Q"), "App_Header_component_div_q_e_click_tbeQzUb0b9Q"); // export const App_Header_component_B9F3YeqcO1w = ()=>{ console.log("mount"); - return
; + return
; }; @@ -50,20 +49,34 @@ Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"ma ] } */ -============================= test.tsx_App_Header_component_div_onClick_aO7uI7Iw6oQ.tsx (ENTRY POINT)== +============================= test.tsx == + +import { componentQrl } from "@qwik.dev/core"; +import { qrl } from "@qwik.dev/core"; +// +const q_App_Header_component_B9F3YeqcO1w = /*#__PURE__*/ qrl(()=>import("./test.tsx_App_Header_component_B9F3YeqcO1w"), "App_Header_component_B9F3YeqcO1w"); +// +export function App() { + const Header = /*#__PURE__*/ componentQrl(q_App_Header_component_B9F3YeqcO1w); + return Header; +} + + +Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;AAEA,OAAO,SAAS;IACf,MAAM,uBAAS;IAMf,OAAO;AACR\"}") +============================= test.tsx_App_Header_component_div_q_e_click_tbeQzUb0b9Q.tsx (ENTRY POINT)== -export const App_Header_component_div_onClick_aO7uI7Iw6oQ = (ctx)=>console.log(ctx); +export const App_Header_component_div_q_e_click_tbeQzUb0b9Q = (ctx)=>console.log(ctx); -Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\"4DAMmB,CAAC,MAAQ,QAAQ,GAAG,CAAC\"}") +Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\"8DAMmB,CAAC,MAAQ,QAAQ,GAAG,CAAC\"}") /* { "origin": "test.tsx", - "name": "App_Header_component_div_onClick_aO7uI7Iw6oQ", + "name": "App_Header_component_div_q_e_click_tbeQzUb0b9Q", "entry": null, - "displayName": "test.tsx_App_Header_component_div_onClick", - "hash": "aO7uI7Iw6oQ", - "canonicalFilename": "test.tsx_App_Header_component_div_onClick_aO7uI7Iw6oQ", + "displayName": "test.tsx_App_Header_component_div_q_e_click", + "hash": "tbeQzUb0b9Q", + "canonicalFilename": "test.tsx_App_Header_component_div_q_e_click_tbeQzUb0b9Q", "path": "", "extension": "tsx", "parent": "App_Header_component_B9F3YeqcO1w", @@ -79,20 +92,6 @@ Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"ma ] } */ -============================= test.tsx == - -import { componentQrl } from "@qwik.dev/core"; -import { qrl } from "@qwik.dev/core"; -// -const q_App_Header_component_B9F3YeqcO1w = /*#__PURE__*/ qrl(()=>import("./test.tsx_App_Header_component_B9F3YeqcO1w"), "App_Header_component_B9F3YeqcO1w"); -// -export function App() { - const Header = /*#__PURE__*/ componentQrl(q_App_Header_component_B9F3YeqcO1w); - return Header; -} - - -Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;AAEA,OAAO,SAAS;IACf,MAAM,uBAAS;IAMf,OAAO;AACR\"}") == DIAGNOSTICS == [] diff --git a/packages/optimizer/core/src/snapshots/qwik_core__test__example_5.snap b/packages/optimizer/core/src/snapshots/qwik_core__test__example_5.snap index 34b089dda34..b6cb8a35d6c 100644 --- a/packages/optimizer/core/src/snapshots/qwik_core__test__example_5.snap +++ b/packages/optimizer/core/src/snapshots/qwik_core__test__example_5.snap @@ -1,6 +1,5 @@ --- source: packages/optimizer/core/src/test.rs -assertion_line: 170 expression: output --- ==INPUT== @@ -16,21 +15,50 @@ export const Header = component$(() => { ); }); +============================= test.tsx_Header_component_div_q_e_click_aMxtmYKxCwA.tsx (ENTRY POINT)== + +export const Header_component_div_q_e_click_aMxtmYKxCwA = (ctx)=>console.log("2"); + + +Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\"0DAMmB,CAAC,MAAQ,QAAQ,GAAG,CAAC\"}") +/* +{ + "origin": "test.tsx", + "name": "Header_component_div_q_e_click_aMxtmYKxCwA", + "entry": null, + "displayName": "test.tsx_Header_component_div_q_e_click", + "hash": "aMxtmYKxCwA", + "canonicalFilename": "test.tsx_Header_component_div_q_e_click_aMxtmYKxCwA", + "path": "", + "extension": "tsx", + "parent": "Header_component_J4uyIhaBNR4", + "ctxKind": "function", + "ctxName": "$", + "captures": false, + "loc": [ + 171, + 196 + ], + "paramNames": [ + "ctx" + ] +} +*/ ============================= test.tsx_Header_component_J4uyIhaBNR4.tsx (ENTRY POINT)== import { qrl } from "@qwik.dev/core"; // -const q_Header_component_div_onClick_i7ekvWH3674 = /*#__PURE__*/ qrl(()=>import("./test.tsx_Header_component_div_onClick_i7ekvWH3674"), "Header_component_div_onClick_i7ekvWH3674"); +const q_Header_component_div_q_e_click_aMxtmYKxCwA = /*#__PURE__*/ qrl(()=>import("./test.tsx_Header_component_div_q_e_click_aMxtmYKxCwA"), "Header_component_div_q_e_click_aMxtmYKxCwA"); // export const Header_component_J4uyIhaBNR4 = ()=>{ return <> -
console.log("1")}/> -
+
console.log("1")}/> +
; }; -Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;4CAEiC;IAChC,SACG;GACD,CAAC,IAAI,SAAS,CAAC,MAAQ,QAAQ,GAAG,CAAC,OAAO;GAC1C,CAAC,IAAI,sDAAwC;EAC9C;AAEF\"}") +Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;4CAEiC;IAChC,SACG;GACD,CAAC,IAAI,WAAS,CAAC,MAAQ,QAAQ,GAAG,CAAC,OAAO;GAC1C,CAAC,IAAI,0DAAwC;EAC9C;AAEF\"}") /* { "origin": "test.tsx", @@ -62,35 +90,6 @@ export const Header = /*#__PURE__*/ componentQrl(q_Header_component_J4uyIhaBNR4) Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;AAEA,OAAO,MAAM,uBAAS,6CAOnB\"}") -============================= test.tsx_Header_component_div_onClick_i7ekvWH3674.tsx (ENTRY POINT)== - -export const Header_component_div_onClick_i7ekvWH3674 = (ctx)=>console.log("2"); - - -Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\"wDAMmB,CAAC,MAAQ,QAAQ,GAAG,CAAC\"}") -/* -{ - "origin": "test.tsx", - "name": "Header_component_div_onClick_i7ekvWH3674", - "entry": null, - "displayName": "test.tsx_Header_component_div_onClick", - "hash": "i7ekvWH3674", - "canonicalFilename": "test.tsx_Header_component_div_onClick_i7ekvWH3674", - "path": "", - "extension": "tsx", - "parent": "Header_component_J4uyIhaBNR4", - "ctxKind": "function", - "ctxName": "$", - "captures": false, - "loc": [ - 171, - 196 - ], - "paramNames": [ - "ctx" - ] -} -*/ == DIAGNOSTICS == [] diff --git a/packages/optimizer/core/src/snapshots/qwik_core__test__example_7.snap b/packages/optimizer/core/src/snapshots/qwik_core__test__example_7.snap index 9cbded92485..1bc722f0a98 100644 --- a/packages/optimizer/core/src/snapshots/qwik_core__test__example_7.snap +++ b/packages/optimizer/core/src/snapshots/qwik_core__test__example_7.snap @@ -1,6 +1,5 @@ --- source: packages/optimizer/core/src/test.rs -assertion_line: 201 expression: output --- ==INPUT== @@ -21,15 +20,44 @@ const App = component$(() => { ); }); +============================= test.tsx_Header_component_div_q_e_click_aMxtmYKxCwA.tsx (ENTRY POINT)== + +export const Header_component_div_q_e_click_aMxtmYKxCwA = (ctx)=>console.log(ctx); + + +Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\"0DAMkB,CAAC,MAAQ,QAAQ,GAAG,CAAC\"}") +/* +{ + "origin": "test.tsx", + "name": "Header_component_div_q_e_click_aMxtmYKxCwA", + "entry": null, + "displayName": "test.tsx_Header_component_div_q_e_click", + "hash": "aMxtmYKxCwA", + "canonicalFilename": "test.tsx_Header_component_div_q_e_click_aMxtmYKxCwA", + "path": "", + "extension": "tsx", + "parent": "Header_component_J4uyIhaBNR4", + "ctxKind": "function", + "ctxName": "$", + "captures": false, + "loc": [ + 143, + 168 + ], + "paramNames": [ + "ctx" + ] +} +*/ ============================= test.tsx_Header_component_J4uyIhaBNR4.tsx (ENTRY POINT)== import { qrl } from "@qwik.dev/core"; // -const q_Header_component_div_onClick_i7ekvWH3674 = /*#__PURE__*/ qrl(()=>import("./test.tsx_Header_component_div_onClick_i7ekvWH3674"), "Header_component_div_onClick_i7ekvWH3674"); +const q_Header_component_div_q_e_click_aMxtmYKxCwA = /*#__PURE__*/ qrl(()=>import("./test.tsx_Header_component_div_q_e_click_aMxtmYKxCwA"), "Header_component_div_q_e_click_aMxtmYKxCwA"); // export const Header_component_J4uyIhaBNR4 = ()=>{ console.log("mount"); - return
; + return
; }; @@ -97,35 +125,6 @@ Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"ma ] } */ -============================= test.tsx_Header_component_div_onClick_i7ekvWH3674.tsx (ENTRY POINT)== - -export const Header_component_div_onClick_i7ekvWH3674 = (ctx)=>console.log(ctx); - - -Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\"wDAMkB,CAAC,MAAQ,QAAQ,GAAG,CAAC\"}") -/* -{ - "origin": "test.tsx", - "name": "Header_component_div_onClick_i7ekvWH3674", - "entry": null, - "displayName": "test.tsx_Header_component_div_onClick", - "hash": "i7ekvWH3674", - "canonicalFilename": "test.tsx_Header_component_div_onClick_i7ekvWH3674", - "path": "", - "extension": "tsx", - "parent": "Header_component_J4uyIhaBNR4", - "ctxKind": "function", - "ctxName": "$", - "captures": false, - "loc": [ - 143, - 168 - ], - "paramNames": [ - "ctx" - ] -} -*/ == DIAGNOSTICS == [] diff --git a/packages/optimizer/core/src/transform.rs b/packages/optimizer/core/src/transform.rs index 93e8d32fd0f..4044cedf508 100644 --- a/packages/optimizer/core/src/transform.rs +++ b/packages/optimizer/core/src/transform.rs @@ -1795,7 +1795,7 @@ impl<'a> QwikTransform<'a> { } } - // Transform event props (e.g., onClick$ -> q-e:click) + // Transform event props (e.g., onClick$/onClick -> q-e:click) let is_passive = jsx_event_to_event_name(kw.as_ref()) .is_some_and(|event_name| context.passive_events.contains(&event_name)); if let Some(html_attr) = jsx_event_to_html_attribute(kw.as_ref(), is_passive) { @@ -3979,7 +3979,7 @@ impl<'a> Fold for QwikTransform<'a> { ast::JSXAttrName::Ident(ref ident) => { let new_word = convert_qrl_word(&ident.sym); - // Transform event names (onClick$ -> q-e:click) only on native HTML elements + // Transform event names (onClick$/onClick -> q-e:click) only on native HTML elements let is_native_element = self.jsx_element_is_native.last().copied().unwrap_or(false); let transformed_name = if is_native_element { let passive_events = self.jsx_element_passive_events.last(); @@ -4806,19 +4806,15 @@ fn normalize_jsx_event_name(name: &str) -> String { } fn jsx_event_to_event_name(jsx_event: &str) -> Option { - if !jsx_event.ends_with('$') { - return None; - } - let (_, idx) = get_event_scope_data_from_jsx_event(jsx_event, false); if idx == usize::MAX { return None; } - Some(normalize_jsx_event_name( - &jsx_event[idx..jsx_event.len() - 1], - )) + let end = jsx_event_name_end(jsx_event, idx)?; + + Some(normalize_jsx_event_name(&jsx_event[idx..end])) } fn passive_attr_to_event_name(passive_attr: &str) -> Option { @@ -4869,26 +4865,41 @@ fn collect_passive_event_names_from_jsx_attrs(attrs: &[ast::JSXAttrOrSpread]) -> .collect() } -/// Converts JSX event names (e.g., onClick$) to HTML attribute names (e.g., q-e:click) +/// Converts JSX event names (e.g., onClick$/onClick) to HTML attribute names (e.g., q-e:click) /// Follows the same logic as jsxEventToHtmlAttribute in event-names.ts fn jsx_event_to_html_attribute(jsx_event: &str, is_passive: bool) -> Option { - if !jsx_event.ends_with('$') { - return None; - } - let (prefix, idx) = get_event_scope_data_from_jsx_event(jsx_event, is_passive); if idx == usize::MAX { return None; } + let end = jsx_event_name_end(jsx_event, idx)?; + Some(Atom::from(format!( "{}{}", prefix, - normalize_jsx_event_name(&jsx_event[idx..jsx_event.len() - 1]) + normalize_jsx_event_name(&jsx_event[idx..end]) ))) } +fn jsx_event_name_end(jsx_event: &str, idx: usize) -> Option { + if jsx_event.ends_with('$') { + let end = jsx_event.len() - 1; + if end > idx { + return Some(end); + } + return None; + } + + let first_event_char = jsx_event[idx..].chars().next()?; + if first_event_char.is_ascii_uppercase() || first_event_char == '-' { + Some(jsx_event.len()) + } else { + None + } +} + /// Get the event scope prefix and starting index from a JSX event name fn get_event_scope_data_from_jsx_event(jsx_event: &str, is_passive: bool) -> (&str, usize) { if jsx_event.starts_with("window:on") { diff --git a/packages/qwik-react/src/index.qwik.ts b/packages/qwik-react/src/index.qwik.ts index 28e972d6b47..93704734f45 100644 --- a/packages/qwik-react/src/index.qwik.ts +++ b/packages/qwik-react/src/index.qwik.ts @@ -1,4 +1,4 @@ -export { qwikify$, qwikifyQrl } from './react/qwikify'; -export { reactify$, reactifyQrl } from './react/reactify'; +export { qwikify, qwikify$, qwikifyQrl } from './react/qwikify'; +export { reactify, reactify$, reactifyQrl } from './react/reactify'; export type { QwikifyProps } from './react/types'; diff --git a/packages/qwik-react/src/react/qwik-react-aliases.unit.tsx b/packages/qwik-react/src/react/qwik-react-aliases.unit.tsx new file mode 100644 index 00000000000..a6a92f57e04 --- /dev/null +++ b/packages/qwik-react/src/react/qwik-react-aliases.unit.tsx @@ -0,0 +1,24 @@ +import { component$, type QRL } from '@qwik.dev/core'; +import { describe, expectTypeOf, test } from 'vitest'; +import type { FunctionComponent as ReactFC } from 'react'; +import { qwikify, qwikify$, qwikifyQrl } from './qwikify'; +import { reactify, reactify$, reactifyQrl } from './reactify'; + +describe('qwik react aliases', () => { + test('qwikify and reactify accept plain values and QRLs', () => () => { + const ReactCmp: ReactFC<{ count: number; children?: unknown }> = () => null; + const ReactCmpQrl = true as any as QRL; + const QwikCmp = component$<{ count: number }>(() => null); + const QwikCmpQrl = true as any as QRL; + + expectTypeOf(qwikify(ReactCmp)).not.toBeAny(); + expectTypeOf(qwikify(ReactCmpQrl)).not.toBeAny(); + expectTypeOf(qwikify$(() => null)).not.toBeAny(); + expectTypeOf(qwikifyQrl(ReactCmpQrl)).not.toBeAny(); + + expectTypeOf(reactify(QwikCmp)).toBeAny(); + expectTypeOf(reactify(QwikCmpQrl)).toBeAny(); + expectTypeOf(reactify$(() => null)).toBeAny(); + expectTypeOf(reactifyQrl(QwikCmpQrl)).toBeAny(); + }); +}); diff --git a/packages/qwik-react/src/react/qwikify.tsx b/packages/qwik-react/src/react/qwikify.tsx index 21d7f75492b..ae4357fa76c 100644 --- a/packages/qwik-react/src/react/qwikify.tsx +++ b/packages/qwik-react/src/react/qwikify.tsx @@ -24,6 +24,10 @@ import { getHostProps, main, mainExactProps, useWakeupSignal } from './slot'; import type { QwikProjectionState } from './slot'; import type { Internal, QwikifyOptions, QwikifyProps } from './types'; +const toQrl = (value: T | QRL): QRL => { + return value as QRL; +}; + export function qwikifyQrl>( reactCmp$: QRL>, opts?: QwikifyOptions @@ -162,3 +166,10 @@ export function qwikifyQrl>( } export const qwikify$ = /*#__PURE__*/ implicit$FirstArg(qwikifyQrl); + +export const qwikify = >( + reactCmp: ReactFC | QRL>, + opts?: QwikifyOptions +) => { + return qwikifyQrl(toQrl(reactCmp), opts); +}; diff --git a/packages/qwik-react/src/react/reactify.ts b/packages/qwik-react/src/react/reactify.ts index 0a385fe667d..b864fd22821 100644 --- a/packages/qwik-react/src/react/reactify.ts +++ b/packages/qwik-react/src/react/reactify.ts @@ -13,6 +13,10 @@ import { type QwikProjectionState, } from './slot'; +const toQrl = (value: T | QRL): QRL => { + return value as QRL; +}; + let slotCounter = 0; /** @@ -180,3 +184,8 @@ export function reactifyQrl(qwikCompQrl: QRL): any { * @returns A React component that renders the Qwik component */ export const reactify$ = /*#__PURE__*/ implicit$FirstArg(reactifyQrl); + +/** @public */ +export const reactify = (qwikComp: any | QRL): any => { + return reactifyQrl(toQrl(qwikComp)); +}; diff --git a/packages/qwik-router/src/runtime/src/index.ts b/packages/qwik-router/src/runtime/src/index.ts index c2e2c4a6732..ac12e7a69e8 100644 --- a/packages/qwik-router/src/runtime/src/index.ts +++ b/packages/qwik-router/src/runtime/src/index.ts @@ -72,18 +72,25 @@ export { } from './qwik-router-component'; export { RouterOutlet } from './router-outlet-component'; export { + globalAction, globalAction$, globalActionQrl, + routeAction, routeAction$, routeActionQrl, + routeLoader, routeLoader$, routeLoaderQrl, + server, server$, serverQrl, + valibot, valibot$, valibotQrl, + validator, validator$, validatorQrl, + zod, zod$, zodQrl, } from './server-functions'; @@ -94,6 +101,7 @@ export { useHttpStatus, useLocation, useNavigate, + usePreventNavigate, usePreventNavigate$, usePreventNavigateQrl, } from './use-functions'; diff --git a/packages/qwik-router/src/runtime/src/qwik-router.runtime.api.md b/packages/qwik-router/src/runtime/src/qwik-router.runtime.api.md index 30358e7d8b5..0a80f5f784c 100644 --- a/packages/qwik-router/src/runtime/src/qwik-router.runtime.api.md +++ b/packages/qwik-router/src/runtime/src/qwik-router.runtime.api.md @@ -236,6 +236,10 @@ export type GetValidatorType = GetValidato export const globalAction$: ActionConstructor; // Warning: (ae-forgotten-export) The symbol "ActionConstructorQRL" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export const globalAction: ActionConstructor & ActionConstructorQRL; + // Warning: (ae-internal-missing-underscore) The name "globalActionQrl" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) @@ -449,6 +453,9 @@ export type ResolvedDocumentHead = Recor // @public (undocumented) export const routeAction$: ActionConstructor; +// @public (undocumented) +export const routeAction: ActionConstructor & ActionConstructorQRL; + // Warning: (ae-internal-missing-underscore) The name "routeActionQrl" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) @@ -492,6 +499,10 @@ export interface RouteData { export const routeLoader$: LoaderConstructor; // Warning: (ae-forgotten-export) The symbol "LoaderConstructorQRL" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export const routeLoader: LoaderConstructor & LoaderConstructorQRL; + // Warning: (ae-internal-missing-underscore) The name "routeLoaderQrl" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) @@ -525,6 +536,9 @@ export const RouterOutlet: Component; // @public (undocumented) export const server$: (qrl: T, options?: ServerConfig | undefined) => ServerQRL; +// @public (undocumented) +export const server: (fn: T | QRL, options?: ServerConfig) => ServerQRL; + // @public export type ServerData = { url: string; @@ -600,6 +614,9 @@ export const useNavigate: () => RouteNavigate; // @public export const usePreventNavigate$: (qrl: PreventNavigateCallback) => void; +// @public (undocumented) +export const usePreventNavigate: (fn: PreventNavigateCallback | QRL) => void; + // Warning: (ae-internal-missing-underscore) The name "usePreventNavigateQrl" should be prefixed with an underscore because the declaration is marked as @internal // // @internal @@ -614,6 +631,10 @@ export const useQwikRouter: (props?: QwikRouterProps) => void; export const valibot$: ValibotConstructor; // Warning: (ae-forgotten-export) The symbol "ValibotConstructorQRL" needs to be exported by the entry point index.d.ts +// +// @beta (undocumented) +export const valibot: ValibotConstructor & ValibotConstructorQRL; + // Warning: (ae-internal-missing-underscore) The name "valibotQrl" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) @@ -624,6 +645,11 @@ export const valibotQrl: ValibotConstructorQRL; // @public (undocumented) export const validator$: ValidatorConstructor; +// Warning: (ae-forgotten-export) The symbol "ValidatorConstructorQRL" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export const validator: ValidatorConstructor & ValidatorConstructorQRL; + // Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts // // @public (undocumented) @@ -639,7 +665,6 @@ export type ValidatorErrorType = { }>; }; -// Warning: (ae-forgotten-export) The symbol "ValidatorConstructorQRL" needs to be exported by the entry point index.d.ts // Warning: (ae-internal-missing-underscore) The name "validatorQrl" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) @@ -656,6 +681,11 @@ export { z } // @public (undocumented) export const zod$: ZodConstructor; +// Warning: (ae-forgotten-export) The symbol "ZodConstructorQRL" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export const zod: ZodConstructor & ZodConstructorQRL; + // @public (undocumented) export type ZodConstructor = { (schema: T): ZodDataValidator>; @@ -664,7 +694,6 @@ export type ZodConstructor = { (schema: (zod: typeof z_2.z, ev: RequestEvent) => T): ZodDataValidator; }; -// Warning: (ae-forgotten-export) The symbol "ZodConstructorQRL" needs to be exported by the entry point index.d.ts // Warning: (ae-internal-missing-underscore) The name "zodQrl" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) diff --git a/packages/qwik-router/src/runtime/src/server-functions.ts b/packages/qwik-router/src/runtime/src/server-functions.ts index b10357a36c9..fe1fc3bfc32 100644 --- a/packages/qwik-router/src/runtime/src/server-functions.ts +++ b/packages/qwik-router/src/runtime/src/server-functions.ts @@ -63,6 +63,36 @@ import type { } from './types'; import { useAction, useLocation, useQwikRouterEnv } from './use-functions'; +const toQrl = (value: T | QRL): QRL => { + return value as QRL; +}; + +type ActionCompatInput = + | QRL<(form: JSONObject, event: RequestEventAction) => ValueOrPromise> + | ((form: JSONObject, event: RequestEventAction) => ValueOrPromise); + +type LoaderCompatInput = + | QRL<(event: RequestEventLoader) => ValueOrPromise> + | ((event: RequestEventLoader) => ValueOrPromise); + +type ValidatorCompatInput = + | QRL<(ev: RequestEvent, data: unknown) => ValueOrPromise> + | ((ev: RequestEvent, data: unknown) => ValueOrPromise); + +type ValibotCompatInput = + | QRL + | QRL<(ev: RequestEvent) => v.GenericSchema | v.GenericSchemaAsync> + | v.GenericSchema + | v.GenericSchemaAsync + | ((ev: RequestEvent) => v.GenericSchema | v.GenericSchemaAsync); + +type ZodCompatInput = + | QRL + | QRL<(zod: typeof z.z, ev: RequestEvent) => z.ZodRawShape | z.Schema> + | z.ZodRawShape + | z.Schema + | ((zod: typeof z.z, ev: RequestEvent) => z.ZodRawShape | z.Schema); + /** @internal */ export const routeActionQrl = (( actionQrl: QRL<(form: JSONObject, event: RequestEventAction) => unknown>, @@ -187,11 +217,27 @@ export const routeAction$: ActionConstructor = /*#__PURE__*/ implicit$FirstArg( routeActionQrl ) as any; +/** @public */ +export const routeAction: ActionConstructor & ActionConstructorQRL = (( + action: ActionCompatInput, + ...rest: (ActionOptions | DataValidator)[] +) => { + return routeActionQrl(toQrl(action), ...(rest as any)); +}) as any; + /** @public */ export const globalAction$: ActionConstructor = /*#__PURE__*/ implicit$FirstArg( globalActionQrl ) as any; +/** @public */ +export const globalAction: ActionConstructor & ActionConstructorQRL = (( + action: ActionCompatInput, + ...rest: (ActionOptions | DataValidator)[] +) => { + return globalActionQrl(toQrl(action), ...(rest as any)); +}) as any; + const getValue = (obj: T) => obj.value; /** @internal */ export const routeLoaderQrl = (( @@ -235,6 +281,14 @@ export const routeLoaderQrl = (( /** @public */ export const routeLoader$: LoaderConstructor = /*#__PURE__*/ implicit$FirstArg(routeLoaderQrl); +/** @public */ +export const routeLoader: LoaderConstructor & LoaderConstructorQRL = (( + loader: LoaderCompatInput, + ...rest: (LoaderOptions | DataValidator)[] +) => { + return routeLoaderQrl(toQrl(loader), ...(rest as any)); +}) as any; + /** @internal */ export const validatorQrl = (( validator: QRL<(ev: RequestEvent, data: unknown) => ValueOrPromise> @@ -250,6 +304,13 @@ export const validatorQrl = (( /** @public */ export const validator$: ValidatorConstructor = /*#__PURE__*/ implicit$FirstArg(validatorQrl); +/** @public */ +export const validator: ValidatorConstructor & ValidatorConstructorQRL = (( + fn: ValidatorCompatInput +) => { + return validatorQrl(toQrl(fn)); +}) as any; + const flattenValibotIssues = (issues: v.GenericIssue[]) => { return issues.reduce>((acc, issue) => { if (issue.path) { @@ -323,6 +384,13 @@ export const valibotQrl: ValibotConstructorQRL = ( /** @beta */ export const valibot$: ValibotConstructor = /*#__PURE__*/ implicit$FirstArg(valibotQrl); +/** @beta */ +export const valibot: ValibotConstructor & ValibotConstructorQRL = (( + schema: ValibotCompatInput +) => { + return valibotQrl(toQrl(schema) as Parameters[0]); +}) as any; + const flattenZodIssues = (issues: z.ZodIssue | z.ZodIssue[]) => { issues = Array.isArray(issues) ? issues : [issues]; return issues.reduce>((acc, issue) => { @@ -393,6 +461,11 @@ export const zodQrl: ZodConstructorQRL = ( /** @public */ export const zod$: ZodConstructor = /*#__PURE__*/ implicit$FirstArg(zodQrl); +/** @public */ +export const zod: ZodConstructor & ZodConstructorQRL = ((schema: ZodCompatInput) => { + return zodQrl(toQrl(schema) as Parameters[0]); +}) as any; + /** @internal */ export const serverQrl = ( qrl: QRL, @@ -518,6 +591,14 @@ export const serverQrl = ( /** @public */ export const server$ = /*#__PURE__*/ implicit$FirstArg(serverQrl); +/** @public */ +export const server = ( + fn: T | QRL, + options?: ServerConfig +): ServerQRL => { + return serverQrl(toQrl(fn), options); +}; + const getValidators = (rest: (LoaderOptions | DataValidator)[], qrl: QRL) => { let id: string | undefined; let serializationStrategy: SerializationStrategy = DEFAULT_LOADERS_SERIALIZATION_STRATEGY; diff --git a/packages/qwik-router/src/runtime/src/server-functions.unit.ts b/packages/qwik-router/src/runtime/src/server-functions.unit.ts index 1b8e3c2014b..59eab62a4d5 100644 --- a/packages/qwik-router/src/runtime/src/server-functions.unit.ts +++ b/packages/qwik-router/src/runtime/src/server-functions.unit.ts @@ -1,25 +1,50 @@ import { describe, expectTypeOf, test } from 'vitest'; +import { $, type QRL } from '@qwik.dev/core'; +import * as v from 'valibot'; import * as z from 'zod'; -import { server$ } from './server-functions'; -import type { RequestEventBase, ValidatorErrorType } from './types'; +import { + globalAction, + globalAction$, + routeAction, + routeAction$, + routeLoader, + routeLoader$, + server, + server$, + valibot, + valibot$, + validator, + validator$, + zod, + zod$, +} from './server-functions'; +import type { JSONObject, RequestEventBase, ValidatorErrorType } from './types'; describe('types', () => { test('matching', () => () => { const foo = () => server$(() => 'hello'); + const plain = () => server(() => 'hello'); + const qrl = () => server($(() => 'hello')); expectTypeOf(foo).not.toBeAny(); expectTypeOf(foo).returns.toMatchTypeOf<() => Promise>(); expectTypeOf(foo).returns.toMatchTypeOf<(sig: AbortSignal) => Promise>(); expectTypeOf(foo).returns.not.toMatchTypeOf<(meep: boolean) => Promise>(); + expectTypeOf(plain).returns.toMatchTypeOf<() => Promise>(); + expectTypeOf(qrl).returns.toMatchTypeOf<() => Promise>(); }); test('matching with args', () => () => { const foo = () => server$((name: string) => 'hello ' + name); + const plain = () => server((name: string) => 'hello ' + name); + const qrl = () => server($((name: string) => 'hello ' + name)); expectTypeOf(foo).not.toBeAny(); expectTypeOf(foo).returns.toMatchTypeOf<(name: string) => Promise>(); expectTypeOf(foo).returns.toMatchTypeOf<(sig: AbortSignal, name: string) => Promise>(); expectTypeOf(foo).returns.not.toMatchTypeOf<(meep: boolean) => Promise>(); + expectTypeOf(plain).returns.toMatchTypeOf<(name: string) => Promise>(); + expectTypeOf(qrl).returns.toMatchTypeOf<(name: string) => Promise>(); }); test('inferring', () => () => { @@ -161,4 +186,52 @@ describe('types', () => { someAnyType?: string; }>(); }); + + test('non-dollar constructors accept plain and QRL inputs', () => () => { + const action = routeAction((form) => ({ ok: form != null })); + const actionQrl = routeAction($((form: JSONObject) => ({ ok: form != null }))); + const actionLegacy = routeAction$((form) => ({ ok: form != null })); + const global = globalAction((form) => ({ ok: form != null })); + const globalQrl = globalAction($((form: JSONObject) => ({ ok: form != null }))); + const globalLegacy = globalAction$((form) => ({ ok: form != null })); + + expectTypeOf(action).toEqualTypeOf(actionLegacy); + expectTypeOf(actionQrl).toEqualTypeOf(actionLegacy); + expectTypeOf(global).toEqualTypeOf(globalLegacy); + expectTypeOf(globalQrl).toEqualTypeOf(globalLegacy); + + const loader = routeLoader(() => ({ value: 1 })); + const loaderQrl = routeLoader($(() => ({ value: 1 }))); + const loaderLegacy = routeLoader$(() => ({ value: 1 })); + + expectTypeOf(loader).toEqualTypeOf(loaderLegacy); + expectTypeOf(loaderQrl).toEqualTypeOf(loaderLegacy); + + const validate = validator(() => ({ success: true as const, data: { ok: true } })); + const validateQrl = validator($(() => ({ success: true as const, data: { ok: true } }))); + const validateLegacy = validator$(() => ({ success: true as const, data: { ok: true } })); + + expectTypeOf(validate).toEqualTypeOf(validateLegacy); + expectTypeOf(validateQrl).toEqualTypeOf(validateLegacy); + + const valibotSchema = v.object({ username: v.string() }); + const valibotSchemaQrl = true as any as QRL; + expectTypeOf(valibot(valibotSchema)).not.toBeAny(); + expectTypeOf(valibot(valibotSchemaQrl)).not.toBeAny(); + expectTypeOf(valibot(() => valibotSchema)).not.toBeAny(); + expectTypeOf(valibot($(() => v.object({ username: v.string() })))).toEqualTypeOf( + valibot$(() => v.object({ username: v.string() })) + ); + + const zodSchema = z.object({ username: z.string() }); + const zodSchemaQrl = true as any as QRL; + expectTypeOf(zod(zodSchema)).not.toBeAny(); + expectTypeOf(zod(zodSchemaQrl)).not.toBeAny(); + expectTypeOf(zod((zod) => ({ username: zod.string() }))).toEqualTypeOf( + zod$((zod) => ({ username: zod.string() })) + ); + expectTypeOf( + zod($((zodInstance: typeof z.z) => ({ username: zodInstance.string() }))) + ).toEqualTypeOf(zod$((zod) => ({ username: zod.string() }))); + }); }); diff --git a/packages/qwik-router/src/runtime/src/use-functions.ts b/packages/qwik-router/src/runtime/src/use-functions.ts index 9766493fd0d..8f67431e4f5 100644 --- a/packages/qwik-router/src/runtime/src/use-functions.ts +++ b/packages/qwik-router/src/runtime/src/use-functions.ts @@ -24,6 +24,10 @@ import type { RouteNavigate, } from './types'; +const toQrl = (value: T | QRL): QRL => { + return value as QRL; +}; + /** @public */ export const useHttpStatus = () => useContext(HttpStatusContext).value; @@ -91,6 +95,11 @@ export const usePreventNavigateQrl = (fn: QRL): void => */ export const usePreventNavigate$ = implicit$FirstArg(usePreventNavigateQrl); +/** @public */ +export const usePreventNavigate = (fn: PreventNavigateCallback | QRL) => { + return usePreventNavigateQrl(toQrl(fn)); +}; + export const useAction = (): RouteAction => useContext(RouteActionContext); export const useQwikRouterEnv = () => noSerialize(useServerData('qwikrouter')); diff --git a/packages/qwik-router/src/runtime/src/use-functions.unit.ts b/packages/qwik-router/src/runtime/src/use-functions.unit.ts new file mode 100644 index 00000000000..3dbdc29c6fa --- /dev/null +++ b/packages/qwik-router/src/runtime/src/use-functions.unit.ts @@ -0,0 +1,12 @@ +import { $ } from '@qwik.dev/core'; +import { describe, expectTypeOf, test } from 'vitest'; +import { usePreventNavigate, usePreventNavigate$, usePreventNavigateQrl } from './use-functions'; + +describe('use-functions types', () => { + test('usePreventNavigate accepts plain callbacks and QRLs', () => () => { + expectTypeOf(usePreventNavigate((url) => !!url)).toEqualTypeOf(); + expectTypeOf(usePreventNavigate($((url) => !!url))).toEqualTypeOf(); + expectTypeOf(usePreventNavigate$((url) => !!url)).toEqualTypeOf(); + expectTypeOf(usePreventNavigateQrl($((url) => !!url))).toEqualTypeOf(); + }); +}); diff --git a/packages/qwik/src/core/index.ts b/packages/qwik/src/core/index.ts index d05d435b0a1..81dee43cfb9 100644 --- a/packages/qwik/src/core/index.ts +++ b/packages/qwik/src/core/index.ts @@ -18,7 +18,7 @@ if (import.meta.hot) { ////////////////////////////////////////////////////////////////////////////////////////// // Developer Core API ////////////////////////////////////////////////////////////////////////////////////////// -export { componentQrl, component$ } from './shared/component.public'; +export { componentQrl, component$, component } from './shared/component.public'; export type { PropsOf, OnRenderFn, Component, PublicProps } from './shared/component.public'; @@ -125,20 +125,27 @@ export { untrack } from './use/use-core'; export { useId } from './use/use-id'; export { useContext, useContextProvider, createContextId } from './use/use-context'; export { useServerData } from './use/use-env-data'; -export { useStylesQrl, useStyles$, useStylesScopedQrl, useStylesScoped$ } from './use/use-styles'; +export { + useStylesQrl, + useStyles$, + useStyles, + useStylesScopedQrl, + useStylesScoped$, + useStylesScoped, +} from './use/use-styles'; export { useOn, useOnDocument, useOnWindow, type UseOnOptions } from './use/use-on'; export { useSignal, useConstant } from './use/use-signal'; export { withLocale, getLocale } from './use/use-locale'; -export type { UseStylesScoped } from './use/use-styles'; +export type { UseStyles, UseStylesScoped } from './use/use-styles'; export type { UseSignal } from './use/use-signal'; export type { ContextId } from './use/use-context'; export type { UseStoreOptions } from './use/use-store.public'; export type { ComputedFn, ComputedReturnType } from './use/use-computed'; export { useComputedQrl } from './use/use-computed'; -export { useSerializerQrl, useSerializer$ } from './use/use-serializer'; +export { useSerializerQrl, useSerializer$, useSerializer } from './use/use-serializer'; export type { OnVisibleTaskOptions, VisibleTaskStrategy } from './use/use-visible-task'; -export { useVisibleTaskQrl } from './use/use-visible-task'; +export { useVisibleTaskQrl, useVisibleTask } from './use/use-visible-task'; export type { TaskCtx, TaskFn, Tracker, TaskOptions } from './use/use-task'; export type { ResourceProps, @@ -150,14 +157,14 @@ export type { ResourceResolved, ResourceReturn, } from './use/use-resource'; -export { useResourceQrl, Resource } from './use/use-resource'; +export { useResourceQrl, useResource, Resource } from './use/use-resource'; export { useResource$ } from './use/use-resource-dollar'; -export { useTaskQrl } from './use/use-task'; +export { useTaskQrl, useTask } from './use/use-task'; export { useTask$ } from './use/use-task-dollar'; export { useVisibleTask$ } from './use/use-visible-task-dollar'; -export { useComputed$ } from './use/use-computed'; +export { useComputed$, useComputed } from './use/use-computed'; export type { AsyncFn } from './use/use-async'; -export { useAsyncQrl, useAsync$ } from './use/use-async'; +export { useAsyncQrl, useAsync$, useAsync } from './use/use-async'; export { useErrorBoundary } from './use/use-error-boundary'; export type { ErrorBoundaryStore } from './shared/error/error-handling'; export { @@ -165,16 +172,20 @@ export { type AsyncSignal, type Signal, type ComputedSignal, + type SerializerSignal, } from './reactive-primitives/signal.public'; export { isSignal, createSignal, createComputedQrl, createComputed$, + createComputed, createSerializerQrl, createSerializer$, + createSerializer, createAsyncQrl, createAsync$, + createAsync, } from './reactive-primitives/signal.public'; export type { ComputedOptions } from './reactive-primitives/types'; diff --git a/packages/qwik/src/core/qwik.core.api.md b/packages/qwik/src/core/qwik.core.api.md index c6f3266e6f0..c4c7b97e0da 100644 --- a/packages/qwik/src/core/qwik.core.api.md +++ b/packages/qwik/src/core/qwik.core.api.md @@ -95,6 +95,9 @@ export const component$: (onMount: OnRenderFn) => Compon // @public export type Component = FunctionComponent>; +// @public (undocumented) +export const component: (onMount: OnRenderFn | QRL>) => Component; + // @public (undocumented) export interface ComponentBaseProps { // (undocumented) @@ -232,6 +235,9 @@ export interface CorrectedToggleEvent extends Event { // @public export const createAsync$: (qrl: (arg: AsyncCtx) => Promise, options?: AsyncSignalOptions) => AsyncSignal; +// @public (undocumented) +export const createAsync: (fn: ((arg: AsyncCtx) => Promise) | QRL<(arg: AsyncCtx) => Promise>, options?: AsyncSignalOptions) => AsyncSignal; + // Warning: (ae-forgotten-export) The symbol "AsyncSignalImpl" needs to be exported by the entry point index.d.ts // Warning: (ae-internal-missing-underscore) The name "createAsyncQrl" should be prefixed with an underscore because the declaration is marked as @internal // @@ -241,6 +247,9 @@ export const createAsyncQrl: (qrl: QRL>, options?: AsyncSignalOpti // @public export const createComputed$: (qrl: () => T, options?: ComputedOptions) => ComputedReturnType; +// @public (undocumented) +export const createComputed: (fn: (() => T) | QRL<() => T>, options?: ComputedOptions) => ComputedReturnType; + // Warning: (ae-forgotten-export) The symbol "ComputedSignalImpl" needs to be exported by the entry point index.d.ts // Warning: (ae-internal-missing-underscore) The name "createComputedQrl" should be prefixed with an underscore because the declaration is marked as @internal // @@ -259,11 +268,13 @@ export function _createDeserializeContainer(stateData: unknown[]): DeserializeCo export const _createQRL: (chunk: string | null, symbol: string, symbolRef?: null | ValueOrPromise, symbolFn?: null | (() => Promise>), captures?: Readonly | string | null, container?: _Container) => _QRLInternal; // Warning: (ae-forgotten-export) The symbol "SerializerArg" needs to be exported by the entry point index.d.ts -// Warning: (ae-forgotten-export) The symbol "SerializerSignal" needs to be exported by the entry point index.d.ts // // @public export const createSerializer$: (arg: SerializerArg) => T extends Promise ? never : SerializerSignal; +// @public (undocumented) +export const createSerializer: (arg: SerializerArg | QRL>) => T extends Promise ? never : SerializerSignal; + // Warning: (ae-forgotten-export) The symbol "SerializerSignalImpl" needs to be exported by the entry point index.d.ts // Warning: (ae-internal-missing-underscore) The name "createSerializerQrl" should be prefixed with an underscore because the declaration is marked as @internal // @@ -1076,6 +1087,11 @@ export type SerializationStrategy = 'never' | 'always'; // @internal export function _serialize(data: T): Promise; +// @public +export interface SerializerSignal extends ComputedSignal { + __no_serialize__: true; +} + // @public export const SerializerSymbol: unique symbol; @@ -1902,6 +1918,9 @@ export function _updateProjectionProps(container: _Container, vnode: _VirtualVNo // @public export const useAsync$: (qrl: AsyncFn, options?: AsyncSignalOptions | undefined) => AsyncSignal; +// @public (undocumented) +export const useAsync: (fn: AsyncFn | QRL>, options?: AsyncSignalOptions) => AsyncSignal; + // Warning: (ae-internal-missing-underscore) The name "useAsyncQrl" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) @@ -1910,6 +1929,9 @@ export const useAsyncQrl: (qrl: QRL>, options?: AsyncSignalOptions // @public export const useComputed$: (qrl: ComputedFn, options?: ComputedOptions | undefined) => ComputedReturnType; +// @public (undocumented) +export const useComputed: (fn: ComputedFn | QRL>, options?: ComputedOptions) => ComputedReturnType; + // Warning: (ae-internal-missing-underscore) The name "useComputedQrl" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) @@ -1941,12 +1963,13 @@ export const useId: () => string; export const useLexicalScope: () => VARS; // Warning: (ae-forgotten-export) The symbol "EventQRL" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "EventFromName" needs to be exported by the entry point index.d.ts // // @public -export const useOn: (event: T | T[], eventQrl: EventQRL, options?: UseOnOptions) => void; +export const useOn: (event: T | T[], eventQrl: EventQRL | EventHandler, Element>, options?: UseOnOptions) => void; // @public -export const useOnDocument: (event: T | T[], eventQrl: EventQRL, options?: UseOnOptions) => void; +export const useOnDocument: (event: T | T[], eventQrl: EventQRL | EventHandler, Element>, options?: UseOnOptions) => void; // Warning: (ae-forgotten-export) The symbol "UseOnOptionsBase" needs to be exported by the entry point index.d.ts // @@ -1960,11 +1983,14 @@ export type UseOnOptions = UseOnOptionsBase & ({ }); // @public -export const useOnWindow: (event: T | T[], eventQrl: EventQRL, options?: UseOnOptions) => void; +export const useOnWindow: (event: T | T[], eventQrl: EventQRL | EventHandler, Element>, options?: UseOnOptions) => void; // @public @deprecated export const useResource$: (qrl: ResourceFn, opts?: ResourceOptions | undefined) => ResourceReturn; +// @public (undocumented) +export const useResource: (fn: ResourceFn | QRL>, opts?: ResourceOptions) => ResourceReturn; + // Warning: (ae-internal-missing-underscore) The name "useResourceQrl" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) @@ -1973,6 +1999,9 @@ export const useResourceQrl: (qrl: QRL>, opts?: ResourceOptions // @public export const useSerializer$: typeof createSerializer$; +// @public (undocumented) +export const useSerializer: (arg: SerializerArg | QRL>) => T extends Promise ? never : SerializerSignal; + // Warning: (ae-internal-missing-underscore) The name "useSerializerQrl" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) @@ -2004,11 +2033,18 @@ export interface UseStoreOptions { reactive?: boolean; } -// Warning: (ae-forgotten-export) The symbol "UseStyles" needs to be exported by the entry point index.d.ts -// // @public export const useStyles$: (qrl: string) => UseStyles; +// @public (undocumented) +export interface UseStyles { + // (undocumented) + styleId: string; +} + +// @public (undocumented) +export const useStyles: (styles: string | QRL) => UseStyles; + // Warning: (ae-internal-missing-underscore) The name "useStylesQrl" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) @@ -2023,6 +2059,9 @@ export interface UseStylesScoped { scopeId: string; } +// @public (undocumented) +export const useStylesScoped: (styles: string | QRL) => UseStylesScoped; + // Warning: (ae-internal-missing-underscore) The name "useStylesScopedQrl" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) @@ -2031,6 +2070,9 @@ export const useStylesScopedQrl: (styles: QRL) => UseStylesScoped; // @public export const useTask$: (fn: TaskFn, opts?: TaskOptions) => void; +// @public (undocumented) +export const useTask: (fn: TaskFn | QRL, opts?: TaskOptions) => void; + // Warning: (ae-internal-missing-underscore) The name "useTaskQrl" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) @@ -2039,6 +2081,9 @@ export const useTaskQrl: (qrl: QRL, opts?: TaskOptions) => void; // @public export const useVisibleTask$: (fn: TaskFn, opts?: OnVisibleTaskOptions) => void; +// @public (undocumented) +export const useVisibleTask: (fn: TaskFn | QRL, opts?: OnVisibleTaskOptions) => void; + // Warning: (ae-internal-missing-underscore) The name "useVisibleTaskQrl" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) diff --git a/packages/qwik/src/core/reactive-primitives/impl/signal.unit.tsx b/packages/qwik/src/core/reactive-primitives/impl/signal.unit.tsx index f72c04a4e28..cfd761c8963 100644 --- a/packages/qwik/src/core/reactive-primitives/impl/signal.unit.tsx +++ b/packages/qwik/src/core/reactive-primitives/impl/signal.unit.tsx @@ -13,9 +13,12 @@ import { retryOnPromise } from '../../shared/utils/promises'; import { invoke, newInvokeContext } from '../../use/use-core'; import { Task } from '../../use/use-task'; import { + createAsync, createAsync$, + createComputed, createComputed$, createComputedQrl, + createSerializer, createSerializer$, createSignal, type AsyncSignal, @@ -44,6 +47,10 @@ describe('signal types', () => { expectTypeOf(signal).toEqualTypeOf>(); const signal2 = createComputed$(() => 1); expectTypeOf(signal2).toEqualTypeOf>(); + const signal3 = createComputed(() => 1); + expectTypeOf(signal3).toEqualTypeOf>(); + const signal4 = createComputed($(() => 1)); + expectTypeOf(signal4).toEqualTypeOf>(); }); it('SerializerSignal', () => () => { { @@ -102,6 +109,30 @@ describe('signal types', () => { expectTypeOf(signal).toEqualTypeOf>(); expectTypeOf(signal.value).toEqualTypeOf(); } + { + const signal = createSerializer({ + deserialize: () => new Foo(), + serialize: (obj) => { + expect(obj).toBeInstanceOf(Foo); + return 1; + }, + }); + expectTypeOf(signal).toEqualTypeOf>(); + expectTypeOf(signal.value).toEqualTypeOf(); + } + { + const signal = createSerializer( + $(() => ({ + deserialize: () => new Foo(), + serialize: (obj: Foo) => { + expect(obj).toBeInstanceOf(Foo); + return 1; + }, + })) + ); + expectTypeOf(signal).toEqualTypeOf>(); + expectTypeOf(signal.value).toEqualTypeOf(); + } }); it('AsyncSignal', () => async () => { const signal = createAsync$(() => Promise.resolve(42)); @@ -117,6 +148,10 @@ describe('signal types', () => { expectTypeOf(signal.abort()).toEqualTypeOf(); expectTypeOf(signal.invalidate()).toEqualTypeOf(); expectTypeOf(signal.invalidate('info')).toEqualTypeOf(); + const signal2 = createAsync(() => Promise.resolve(42)); + expectTypeOf(signal2).toEqualTypeOf>(); + const signal3 = createAsync($(() => Promise.resolve(42))); + expectTypeOf(signal3).toEqualTypeOf>(); }); }); diff --git a/packages/qwik/src/core/reactive-primitives/signal.public.ts b/packages/qwik/src/core/reactive-primitives/signal.public.ts index c94fe0190e1..bd2032fe1e9 100644 --- a/packages/qwik/src/core/reactive-primitives/signal.public.ts +++ b/packages/qwik/src/core/reactive-primitives/signal.public.ts @@ -1,4 +1,6 @@ import { implicit$FirstArg } from '../shared/qrl/implicit_dollar'; +import { dollar, type QRL } from '../shared/qrl/qrl.public'; +import { isQrl } from '../shared/qrl/qrl-utils'; import type { AsyncCtx, AsyncSignalOptions, ComputedOptions, SerializerArg } from './types'; import { createSignal as _createSignal, @@ -173,6 +175,17 @@ export const createComputed$: ( qrl: () => T, options?: ComputedOptions ) => ComputedReturnType = /*#__PURE__*/ implicit$FirstArg(createComputedQrl as any); + +/** @public */ +export const createComputed = ( + fn: (() => T) | QRL<() => T>, + options?: ComputedOptions +): ComputedReturnType => { + return createComputedQrl( + isQrl(fn) ? (fn as QRL<() => T>) : dollar(fn as () => T), + options + ) as any; +}; export { createComputedQrl }; /** @@ -185,6 +198,17 @@ export const createAsync$: ( qrl: (arg: AsyncCtx) => Promise, options?: AsyncSignalOptions ) => AsyncSignal = /*#__PURE__*/ implicit$FirstArg(createAsyncQrl as any); + +/** @public */ +export const createAsync = ( + fn: ((arg: AsyncCtx) => Promise) | QRL<(arg: AsyncCtx) => Promise>, + options?: AsyncSignalOptions +): AsyncSignal => { + return createAsyncQrl( + (isQrl(fn) ? fn : dollar(fn as (arg: AsyncCtx) => Promise)) as any, + options + ); +}; export { createAsyncQrl }; /** @@ -198,4 +222,11 @@ export const createSerializer$: ( ) => T extends Promise ? never : SerializerSignal = implicit$FirstArg( createSerializerQrl as any ); + +/** @public */ +export const createSerializer = ( + arg: SerializerArg | QRL> +): T extends Promise ? never : SerializerSignal => { + return createSerializerQrl((isQrl(arg) ? arg : dollar(arg as SerializerArg)) as any) as any; +}; export { createSerializerQrl }; diff --git a/packages/qwik/src/core/shared/component.public.ts b/packages/qwik/src/core/shared/component.public.ts index c3ff1df0b37..9fcc8860ec9 100644 --- a/packages/qwik/src/core/shared/component.public.ts +++ b/packages/qwik/src/core/shared/component.public.ts @@ -11,7 +11,7 @@ import { _jsxSplit } from '../internal'; import type { QwikIntrinsicElements } from './jsx/types/jsx-qwik-elements'; import { assertNumber } from './error/assert'; import { qTest } from './utils/qdev'; -import { assertQrl } from './qrl/qrl-utils'; +import { assertQrl, isQrl } from './qrl/qrl-utils'; import { isDev } from '@qwik.dev/core/build'; import type { QRLInternal } from './qrl/qrl-class'; @@ -213,5 +213,14 @@ export const component$ = (onMount: OnRenderFn): Compone return componentQrl(dollar(onMount)); }; +/** @public */ +export const component = ( + onMount: OnRenderFn | QRL> +): Component => { + return componentQrl( + isQrl(onMount) ? (onMount as QRL>) : dollar(onMount as OnRenderFn) + ); +}; + /** @public */ export type OnRenderFn = (props: PROPS) => JSXOutput; diff --git a/packages/qwik/src/core/shared/jsx/jsx-internal.ts b/packages/qwik/src/core/shared/jsx/jsx-internal.ts index 03a8831c22f..b89d4b9c72c 100644 --- a/packages/qwik/src/core/shared/jsx/jsx-internal.ts +++ b/packages/qwik/src/core/shared/jsx/jsx-internal.ts @@ -55,14 +55,9 @@ const removePassiveMarkers = ( }; const getPassiveEventKey = (key: string): string | null => { - if (key.startsWith('on') && key.endsWith('$')) { - return normalizeJsxEventName(key.slice(2, -1)); - } - if (key.startsWith('window:on') && key.endsWith('$')) { - return normalizeJsxEventName(key.slice(9, -1)); - } - if (key.startsWith('document:on') && key.endsWith('$')) { - return normalizeJsxEventName(key.slice(11, -1)); + const attr = jsxEventToHtmlAttribute(key); + if (attr) { + return attr.slice(attr.indexOf(':') + 1); } return null; }; diff --git a/packages/qwik/src/core/shared/jsx/types/jsx-qwik-attributes.ts b/packages/qwik/src/core/shared/jsx/types/jsx-qwik-attributes.ts index 284c717ecd4..484f5ad55f3 100644 --- a/packages/qwik/src/core/shared/jsx/types/jsx-qwik-attributes.ts +++ b/packages/qwik/src/core/shared/jsx/types/jsx-qwik-attributes.ts @@ -94,6 +94,25 @@ type LcEventNameMap = { type PascalCaseName = T extends keyof LcEventNameMap ? LcEventNameMap[T] : Capitalize; +type LiteralEventName = K extends string ? (string extends K ? never : K) : never; +type ElementEventPropName = + LiteralEventName extends infer E + ? E extends string + ? `on${PascalCaseName}$` | `on${PascalCaseName}` + : never + : never; +type DocumentEventPropName = + LiteralEventName extends infer E + ? E extends string + ? `document:on${PascalCaseName}$` | `document:on${PascalCaseName}` + : never + : never; +type WindowEventPropName = + LiteralEventName extends infer E + ? E extends string + ? `window:on${PascalCaseName}$` | `window:on${PascalCaseName}` + : never + : never; type PreventDefault = { [K in keyof HTMLElementEventMap as `preventdefault:${K}`]?: boolean; @@ -193,13 +212,13 @@ export type QRLEventHandlerMulti = | QRLEventHandlerMulti[]; type JSXElementEvents = { - [K in keyof QwikHTMLElementEventMap as `on${PascalCaseName}$`]: QwikHTMLElementEventMap[K]; + [K in keyof QwikHTMLElementEventMap as ElementEventPropName]: QwikHTMLElementEventMap[K]; }; type JSXDocumentEvents = { - [K in keyof QwikDocumentEventMap as `document:on${PascalCaseName}$`]: QwikDocumentEventMap[K]; + [K in keyof QwikDocumentEventMap as DocumentEventPropName]: QwikDocumentEventMap[K]; }; type JSXWindowEvents = { - [K in keyof QwikWindowEventMap as `window:on${PascalCaseName}$`]: QwikWindowEventMap[K]; + [K in keyof QwikWindowEventMap as WindowEventPropName]: QwikWindowEventMap[K]; }; type QwikJSXEvents = JSXElementEvents & JSXDocumentEvents & JSXWindowEvents; type QwikKnownEvents = { diff --git a/packages/qwik/src/core/shared/jsx/types/jsx-types.unit.tsx b/packages/qwik/src/core/shared/jsx/types/jsx-types.unit.tsx index ab0c02bacf5..a2055d4b704 100644 --- a/packages/qwik/src/core/shared/jsx/types/jsx-types.unit.tsx +++ b/packages/qwik/src/core/shared/jsx/types/jsx-types.unit.tsx @@ -15,7 +15,7 @@ import type { QwikViewTransitionEvent, QwikVisibleEvent, } from '@qwik.dev/core'; -import { $, component$, sync$ } from '@qwik.dev/core'; +import { $, component, component$, sync$ } from '@qwik.dev/core'; import { assertType, describe, expectTypeOf, test } from 'vitest'; const Fn = () =>
; @@ -41,8 +41,12 @@ describe('types', () => { return
; }); const NoP = component$(() =>
); + const NoPDollarless = component(() =>
); + const NoPQrl = component($(() =>
)); expectTypeOf>().toEqualTypeOf(); expectTypeOf>().toEqualTypeOf(); + expectTypeOf>().toEqualTypeOf(); + expectTypeOf>().toEqualTypeOf(); component$(() => { return ( <> @@ -52,6 +56,12 @@ describe('types', () => {
+ +
+ + +
+ ); }); @@ -94,8 +104,9 @@ describe('types', () => { test('component', () => () => { const Cmp = component$((props: PropsOf<'svg'>) => { - const { width = '240', height = '56', onClick$, ...rest } = props; + const { width = '240', height = '56', onClick$, onClick, ...rest } = props; expectTypeOf(onClick$).toEqualTypeOf>(); + expectTypeOf(onClick).toEqualTypeOf>(); return ( { expectTypeOf[0]['onClick$']>().toMatchTypeOf< EventHandler | QRLEventHandlerMulti >(); + expectTypeOf[0]['onClick']>().toMatchTypeOf< + QRLEventHandlerMulti + >(); return (

@@ -117,6 +131,35 @@ describe('types', () => { ); }); + test('no-dollar event handlers', () => () => { + expectTypeOf().toEqualTypeOf< + QRLEventHandlerMulti + >(); + + const t = ( + <> +