Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into ianlet/main
Browse files Browse the repository at this point in the history
  • Loading branch information
mhevery committed Aug 28, 2023
2 parents 16cd7f8 + 2b856e3 commit 823b610
Show file tree
Hide file tree
Showing 17 changed files with 455 additions and 258 deletions.
30 changes: 1 addition & 29 deletions packages/docs/src/routes/api/qwik-city/api.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,34 +30,6 @@
"editUrl": "https://github.com/BuilderIO/qwik/tree/main/packages/qwik-city/runtime/src/types.ts",
"mdFile": "qwik-city.actionconstructor.md"
},
{
"name": "ActionOptions",
"id": "actionoptions",
"hierarchy": [
{
"name": "ActionOptions",
"id": "actionoptions"
}
],
"kind": "Interface",
"content": "```typescript\nexport interface ActionOptions \n```\n\n\n| Property | Modifiers | Type | Description |\n| --- | --- | --- | --- |\n| [id?](#) | <code>readonly</code> | string | _(Optional)_ |\n| [validation?](#) | <code>readonly</code> | DataValidator\\[\\] | _(Optional)_ |",
"editUrl": "https://github.com/BuilderIO/qwik/tree/main/packages/qwik-city/runtime/src/types.ts",
"mdFile": "qwik-city.actionoptions.md"
},
{
"name": "ActionOptionsWithValidation",
"id": "actionoptionswithvalidation",
"hierarchy": [
{
"name": "ActionOptionsWithValidation",
"id": "actionoptionswithvalidation"
}
],
"kind": "Interface",
"content": "```typescript\nexport interface ActionOptionsWithValidation<B extends TypedDataValidator = TypedDataValidator> \n```\n\n\n| Property | Modifiers | Type | Description |\n| --- | --- | --- | --- |\n| [id?](#) | <code>readonly</code> | string | _(Optional)_ |\n| [validation](#) | <code>readonly</code> | \\[val: B, ...a: DataValidator\\[\\]\\] | |",
"editUrl": "https://github.com/BuilderIO/qwik/tree/main/packages/qwik-city/runtime/src/types.ts",
"mdFile": "qwik-city.actionoptionswithvalidation.md"
},
{
"name": "ActionStore",
"id": "actionstore",
Expand Down Expand Up @@ -348,7 +320,7 @@
}
],
"kind": "TypeAlias",
"content": "```typescript\nexport type LoaderSignal<T> = T extends () => ValueOrPromise<infer B> ? ReadonlySignal<ValueOrPromise<B>> : ReadonlySignal<T>;\n```",
"content": "```typescript\nexport type LoaderSignal<TYPE> = TYPE extends () => ValueOrPromise<infer VALIDATOR> ? ReadonlySignal<ValueOrPromise<VALIDATOR>> : ReadonlySignal<TYPE>;\n```",
"editUrl": "https://github.com/BuilderIO/qwik/tree/main/packages/qwik-city/runtime/src/types.ts",
"mdFile": "qwik-city.loadersignal.md"
},
Expand Down
34 changes: 5 additions & 29 deletions packages/docs/src/routes/api/qwik-city/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,6 @@ export interface ActionConstructor

[Edit this section](https://github.com/BuilderIO/qwik/tree/main/packages/qwik-city/runtime/src/types.ts)

## ActionOptions

```typescript
export interface ActionOptions
```

| Property | Modifiers | Type | Description |
| ---------------- | --------------------- | --------------- | ------------ |
| [id?](#) | <code>readonly</code> | string | _(Optional)_ |
| [validation?](#) | <code>readonly</code> | DataValidator[] | _(Optional)_ |

[Edit this section](https://github.com/BuilderIO/qwik/tree/main/packages/qwik-city/runtime/src/types.ts)

## ActionOptionsWithValidation

```typescript
export interface ActionOptionsWithValidation<B extends TypedDataValidator = TypedDataValidator>
```

| Property | Modifiers | Type | Description |
| --------------- | --------------------- | ------------------------------- | ------------ |
| [id?](#) | <code>readonly</code> | string | _(Optional)_ |
| [validation](#) | <code>readonly</code> | [val: B, ...a: DataValidator[]] | |

[Edit this section](https://github.com/BuilderIO/qwik/tree/main/packages/qwik-city/runtime/src/types.ts)

## ActionStore

```typescript
Expand Down Expand Up @@ -350,9 +324,11 @@ export interface Loader<RETURN>
## LoaderSignal
```typescript
export type LoaderSignal<T> = T extends () => ValueOrPromise<infer B>
? ReadonlySignal<ValueOrPromise<B>>
: ReadonlySignal<T>;
export type LoaderSignal<TYPE> = TYPE extends () => ValueOrPromise<
infer VALIDATOR
>
? ReadonlySignal<ValueOrPromise<VALIDATOR>>
: ReadonlySignal<TYPE>;
```
[Edit this section](https://github.com/BuilderIO/qwik/tree/main/packages/qwik-city/runtime/src/types.ts)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { $, component$, useOnWindow, useSignal } from '@builder.io/qwik';

// Custom hook to manage the dropdown state. Listens to click events on the window.
// If the clicked element is not the dropdown toggle button, it closes the dropdown.
function useCloseDropdown() {
// Signal to manage the open/close state of the dropdown
const isOpen = useSignal(false);
// Signal to hold a reference to the dropdown toggle button
const dropdownToggleBtn = useSignal<HTMLElement | null>(null);

// Event listener function for window clicks
const closeDropdown = $((event: Event): void => {
// If the clicked element is not contained within the dropdown toggle button, close the dropdown
if (
dropdownToggleBtn.value &&
!dropdownToggleBtn.value.contains(event.target as Node)
) {
isOpen.value = false;
}
});
// Attach the window click event listener
useOnWindow('click', closeDropdown);

return {
isOpen,
dropdownToggleBtn,
};
}

export default component$(() => {
// Use the custom hook in the component
const { isOpen, dropdownToggleBtn } = useCloseDropdown();

// Function to set the reference of the dropdown toggle button
const setDropdownToggleBtnRef = (item: Element): void => {
dropdownToggleBtn.value = item as HTMLElement;
};

return (
<div>
<button
ref={setDropdownToggleBtnRef}
onClick$={() => (isOpen.value = true)}
>
Click me!
</button>
{isOpen.value && (
<>
<div>
<i>The dropdown is open!</i>
</div>
<div style={{ margin: '1.5rem', marginLeft: '1.5rem' }}>
<b>CLICK OUTSIDE</b>
</div>
</>
)}
</div>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ contributors:
- mhevery
- AnthonyPAlicea
- khalilou88
- n8sabes
---

import CodeSandbox from '../../../../../components/code-sandbox/index.tsx';
Expand Down
8 changes: 8 additions & 0 deletions packages/docs/src/routes/docs/(qwikcity)/server$/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,11 @@ A `server$()` wraps a function and returns an async proxy to the function. On th
On the client, the proxy function invokes the wrapped function via an HTTP request, using `fetch()`.

> Note: The `server$()` function must ensure that the server and client have the same version of the code executing. If there is a version skew the behavior is undefined and may result in an error. If version skew is a common problem then a more formal RPC mechanism should be used such as a tRPC or other library.
## Middleware and `server$`

When using `server$`, it's important to understand how [middleware functions](/docs/middleware/#middleware-function) are executed. Middleware functions defined in `layout` files do not run for `server$` requests. This can lead to confusion, especially when developers expect certain middleware to be executed for both page requests and `server$` requests.

To ensure that a middleware function runs for both types of requests, it should be defined in the `plugin.ts` file. This ensures that the middleware is executed consistently for all incoming requests, regardless of whether they are normal page requests or `server$` requests.

By [defining middleware in the `plugin.ts`](/docs/advanced/routing/#plugints) file, developers can maintain a centralized location for shared middleware logic, ensuring consistency and reducing potential errors or oversights.
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ export default component$(() => {
validate: zodForm$(loginSchema),
});

const handleSubmit: SubmitHandler<LoginForm> = $((values, event) => {
const handleSubmit = $<SubmitHandler<LoginForm>>((values, event) => {
// Runs on client
console.log(values);
});
Expand Down
4 changes: 4 additions & 0 deletions packages/eslint-plugin-qwik/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { jsxNoScriptUrl } from './src/jsxNoScriptUrl';
import { jsxKey } from './src/jsxKey';
import { unusedServer } from './src/unusedServer';
import { jsxImg } from './src/jsxImg';
import { jsxAtag } from './src/jsxAtag';

export const rules = {
'use-method-usage': useMethodUsage,
Expand All @@ -18,6 +19,7 @@ export const rules = {
'jsx-key': jsxKey,
'unused-server': unusedServer,
'jsx-img': jsxImg,
'jsx-a': jsxAtag,
};

export const configs = {
Expand All @@ -33,6 +35,7 @@ export const configs = {
'qwik/jsx-key': 'warn',
'qwik/unused-server': 'error',
'qwik/jsx-img': 'warn',
'qwik/jsx-a': 'warn',
},
},
strict: {
Expand All @@ -47,6 +50,7 @@ export const configs = {
'qwik/jsx-key': 'error',
'qwik/unused-server': 'error',
'qwik/jsx-img': 'error',
'qwik/jsx-a': 'error',
},
},
};
16 changes: 15 additions & 1 deletion packages/eslint-plugin-qwik/qwik.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// @ts-ignore
import { RuleTester } from '@typescript-eslint/rule-tester';
import { fileURLToPath } from 'node:url';
import { suite } from 'uvu';
import { rules } from './index';
import { suite } from 'uvu';

const lintSuite = suite('lint');
const testConfig = {
Expand Down Expand Up @@ -663,6 +663,20 @@ ruleTester.run('jsx-img', rules['jsx-img'], {
],
});

ruleTester.run('jsx-a', rules['jsx-a'], {
valid: [`<a href={value} />`, `<a {...props}/>`],
invalid: [
{
code: `<a/>`,
errors: [{ messageId: 'noHref' }],
},
{
code: `<a style='display:block;' />`,
errors: [{ messageId: 'noHref' }],
},
],
});

lintSuite.run();

export {};
49 changes: 49 additions & 0 deletions packages/eslint-plugin-qwik/src/jsxAtag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { ESLintUtils, TSESTree } from '@typescript-eslint/utils';

const createRule = ESLintUtils.RuleCreator(() => 'https://qwik.builder.io/docs/advanced/dollar/');

export const jsxAtag = createRule({
defaultOptions: [],
name: 'jsx-a-tag',
meta: {
type: 'problem',
docs: {
description: 'For a perfect SEO score, always provide href attribute for <a> elements.',
recommended: 'warn',
},
fixable: 'code',
schema: [],
messages: {
noHref: 'For a perfect SEO score, always provide href attribute for <a> elements.',
},
},
create(context) {
return {
JSXElement(node: TSESTree.JSXElement) {
if (
node.openingElement.name.type === 'JSXIdentifier' &&
node.openingElement.name.name === 'a'
) {
const hasSpread = node.openingElement.attributes.some(
(attr) => attr.type === 'JSXSpreadAttribute'
);

if (!hasSpread) {
const hasHref = node.openingElement.attributes.some(
(attr) =>
attr.type === 'JSXAttribute' &&
attr.name.type === 'JSXIdentifier' &&
attr.name.name === 'href'
);
if (!hasHref) {
context.report({
node: node as any,
messageId: 'noHref',
});
}
}
}
},
};
},
});
40 changes: 20 additions & 20 deletions packages/qwik-city/runtime/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,36 +34,36 @@ export interface Action<RETURN, INPUT = Record<string, any>, OPTIONAL extends bo
// @public (undocumented)
export interface ActionConstructor {
// Warning: (ae-forgotten-export) The symbol "TypedDataValidator" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "DataValidator" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "GetValidatorType" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "StrictUnion" needs to be exported by the entry point index.d.ts
//
// (undocumented)
<O extends Record<string, any> | void | null, B extends TypedDataValidator>(actionQrl: (data: GetValidatorType<B>, event: RequestEventAction) => ValueOrPromise<O>, options: B | ActionOptionsWithValidation<B>): Action<StrictUnion<O | FailReturn<zod.typeToFlattenedError<GetValidatorType<B>>>>, GetValidatorType<B>, false>;
// Warning: (ae-forgotten-export) The symbol "DataValidator" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "FailOfRest" needs to be exported by the entry point index.d.ts
//
// (undocumented)
<O extends Record<string, any> | void | null, B extends TypedDataValidator, REST extends DataValidator[]>(actionQrl: (data: GetValidatorType<B>, event: RequestEventAction) => ValueOrPromise<O>, options: B, ...rest: REST): Action<StrictUnion<O | FailReturn<zod.typeToFlattenedError<GetValidatorType<B>>> | FailOfRest<REST>>, GetValidatorType<B>, false>;
<OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: (data: GetValidatorType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>, options: {
readonly id?: string;
readonly validation: [VALIDATOR, ...REST];
}): Action<StrictUnion<OBJ | FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>> | FailOfRest<REST>>, GetValidatorType<VALIDATOR>, false>;
// (undocumented)
<O>(actionQrl: (form: JSONObject, event: RequestEventAction, options: ActionOptions) => ValueOrPromise<O>, options?: ActionOptions): Action<StrictUnion<O>>;
<OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator>(actionQrl: (data: GetValidatorType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>, options: {
readonly id?: string;
readonly validation: [VALIDATOR];
}): Action<StrictUnion<OBJ | FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>>>, GetValidatorType<VALIDATOR>, false>;
// (undocumented)
<O extends Record<string, any> | void | null, REST extends DataValidator[]>(actionQrl: (form: JSONObject, event: RequestEventAction) => ValueOrPromise<O>, ...rest: REST): Action<StrictUnion<O | FailReturn<FailOfRest<REST>>>>;
}

// @public (undocumented)
export interface ActionOptions {
<OBJ extends Record<string, any> | void | null, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: (data: JSONObject, event: RequestEventAction) => ValueOrPromise<OBJ>, options: {
readonly id?: string;
readonly validation: REST;
}): Action<StrictUnion<OBJ | FailReturn<FailOfRest<REST>>>>;
// (undocumented)
readonly id?: string;
<OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: (data: GetValidatorType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>, options: VALIDATOR, ...rest: REST): Action<StrictUnion<OBJ | FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>> | FailOfRest<REST>>, GetValidatorType<VALIDATOR>, false>;
// (undocumented)
readonly validation?: DataValidator[];
}

// @public (undocumented)
export interface ActionOptionsWithValidation<B extends TypedDataValidator = TypedDataValidator> {
<OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator>(actionQrl: (data: GetValidatorType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>, options: VALIDATOR): Action<StrictUnion<OBJ | FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>>>, GetValidatorType<VALIDATOR>, false>;
// (undocumented)
readonly id?: string;
<OBJ extends Record<string, any> | void | null, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: (form: JSONObject, event: RequestEventAction) => ValueOrPromise<OBJ>, ...rest: REST): Action<StrictUnion<OBJ | FailReturn<FailOfRest<REST>>>>;
// (undocumented)
readonly validation: [val: B, ...a: DataValidator[]];
<OBJ>(actionQrl: (form: JSONObject, event: RequestEventAction) => ValueOrPromise<OBJ>, options?: {
readonly id?: string;
}): Action<StrictUnion<OBJ>>;
}

// @public (undocumented)
Expand Down Expand Up @@ -273,7 +273,7 @@ export interface Loader<RETURN> {
}

// @public (undocumented)
export type LoaderSignal<T> = T extends () => ValueOrPromise<infer B> ? ReadonlySignal<ValueOrPromise<B>> : ReadonlySignal<T>;
export type LoaderSignal<TYPE> = TYPE extends () => ValueOrPromise<infer VALIDATOR> ? ReadonlySignal<ValueOrPromise<VALIDATOR>> : ReadonlySignal<TYPE>;

// Warning: (ae-forgotten-export) The symbol "MenuModuleLoader" needs to be exported by the entry point index.d.ts
//
Expand Down
2 changes: 0 additions & 2 deletions packages/qwik-city/runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ export type {
ActionStore,
LoaderSignal,
ActionConstructor,
ActionOptions,
ActionOptionsWithValidation,
FailReturn,
ZodConstructor,
StaticGenerate,
Expand Down
Loading

0 comments on commit 823b610

Please sign in to comment.