Compare commits

...

52 Commits

Author SHA1 Message Date
Lakr 486e047b6d feat: done create new doc 2025-04-15 11:44:20 +08:00
Lakr a7db5c5027 chore: update code gen 2025-04-15 11:44:19 +08:00
LongYinan 5bb67e66c2 docs: format releases.md 2025-04-15 11:37:39 +08:00
glitched-w0rld 2b9ccf8fcf docs: improve grammar of contributing releases.md (#10032) 2025-04-15 10:26:34 +08:00
renovate aaa81e7d12 chore: bump up all non-major dependencies (#11670)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [@ai-sdk/google](https://sdk.vercel.ai/docs) ([source](https://redirect.github.com/vercel/ai)) | [`1.2.10` -> `1.2.11`](https://renovatebot.com/diffs/npm/@ai-sdk%2fgoogle/1.2.10/1.2.11) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@ai-sdk%2fgoogle/1.2.11?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@ai-sdk%2fgoogle/1.2.11?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@ai-sdk%2fgoogle/1.2.10/1.2.11?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@ai-sdk%2fgoogle/1.2.10/1.2.11?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@ai-sdk/openai](https://sdk.vercel.ai/docs) ([source](https://redirect.github.com/vercel/ai)) | [`1.3.10` -> `1.3.12`](https://renovatebot.com/diffs/npm/@ai-sdk%2fopenai/1.3.10/1.3.12) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@ai-sdk%2fopenai/1.3.12?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@ai-sdk%2fopenai/1.3.12?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@ai-sdk%2fopenai/1.3.10/1.3.12?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@ai-sdk%2fopenai/1.3.10/1.3.12?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@ai-sdk/perplexity](https://sdk.vercel.ai/docs) ([source](https://redirect.github.com/vercel/ai)) | [`1.1.6` -> `1.1.7`](https://renovatebot.com/diffs/npm/@ai-sdk%2fperplexity/1.1.6/1.1.7) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@ai-sdk%2fperplexity/1.1.7?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@ai-sdk%2fperplexity/1.1.7?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@ai-sdk%2fperplexity/1.1.6/1.1.7?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@ai-sdk%2fperplexity/1.1.6/1.1.7?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@swc/core](https://swc.rs) ([source](https://redirect.github.com/swc-project/swc)) | [`1.11.20` -> `1.11.21`](https://renovatebot.com/diffs/npm/@swc%2fcore/1.11.20/1.11.21) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@swc%2fcore/1.11.21?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@swc%2fcore/1.11.21?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@swc%2fcore/1.11.20/1.11.21?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@swc%2fcore/1.11.20/1.11.21?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@tailwindcss/postcss](https://tailwindcss.com) ([source](https://redirect.github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss)) | [`4.1.3` -> `4.1.4`](https://renovatebot.com/diffs/npm/@tailwindcss%2fpostcss/4.1.3/4.1.4) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@tailwindcss%2fpostcss/4.1.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@tailwindcss%2fpostcss/4.1.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@tailwindcss%2fpostcss/4.1.3/4.1.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@tailwindcss%2fpostcss/4.1.3/4.1.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@tailwindcss/vite](https://tailwindcss.com) ([source](https://redirect.github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite)) | [`4.1.3` -> `4.1.4`](https://renovatebot.com/diffs/npm/@tailwindcss%2fvite/4.1.3/4.1.4) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@tailwindcss%2fvite/4.1.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@tailwindcss%2fvite/4.1.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@tailwindcss%2fvite/4.1.3/4.1.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@tailwindcss%2fvite/4.1.3/4.1.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@tanstack/react-table](https://tanstack.com/table) ([source](https://redirect.github.com/TanStack/table/tree/HEAD/packages/react-table)) | [`8.21.2` -> `8.21.3`](https://renovatebot.com/diffs/npm/@tanstack%2freact-table/8.21.2/8.21.3) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@tanstack%2freact-table/8.21.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@tanstack%2freact-table/8.21.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@tanstack%2freact-table/8.21.2/8.21.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@tanstack%2freact-table/8.21.2/8.21.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@types/react](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react) ([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react)) | [`19.1.1` -> `19.1.2`](https://renovatebot.com/diffs/npm/@types%2freact/19.1.1/19.1.2) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2freact/19.1.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@types%2freact/19.1.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@types%2freact/19.1.1/19.1.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2freact/19.1.1/19.1.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [ai](https://sdk.vercel.ai/docs) ([source](https://redirect.github.com/vercel/ai)) | [`4.3.5` -> `4.3.6`](https://renovatebot.com/diffs/npm/ai/4.3.5/4.3.6) | [![age](https://developer.mend.io/api/mc/badges/age/npm/ai/4.3.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/ai/4.3.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/ai/4.3.5/4.3.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/ai/4.3.5/4.3.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [react-day-picker](https://daypicker.dev) ([source](https://redirect.github.com/gpbl/react-day-picker)) | [`9.6.6` -> `9.6.7`](https://renovatebot.com/diffs/npm/react-day-picker/9.6.6/9.6.7) | [![age](https://developer.mend.io/api/mc/badges/age/npm/react-day-picker/9.6.7?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/react-day-picker/9.6.7?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/react-day-picker/9.6.6/9.6.7?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/react-day-picker/9.6.6/9.6.7?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [tailwindcss](https://tailwindcss.com) ([source](https://redirect.github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss)) | [`4.1.3` -> `4.1.4`](https://renovatebot.com/diffs/npm/tailwindcss/4.1.3/4.1.4) | [![age](https://developer.mend.io/api/mc/badges/age/npm/tailwindcss/4.1.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/tailwindcss/4.1.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/tailwindcss/4.1.3/4.1.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/tailwindcss/4.1.3/4.1.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [typescript-eslint](https://typescript-eslint.io/packages/typescript-eslint) ([source](https://redirect.github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint)) | [`8.29.1` -> `8.30.1`](https://renovatebot.com/diffs/npm/typescript-eslint/8.29.1/8.30.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/typescript-eslint/8.30.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/typescript-eslint/8.30.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/typescript-eslint/8.29.1/8.30.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/typescript-eslint/8.29.1/8.30.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [yarn](https://redirect.github.com/yarnpkg/berry) ([source](https://redirect.github.com/yarnpkg/berry/tree/HEAD/packages/yarnpkg-cli)) | [`4.9.0` -> `4.9.1`](https://renovatebot.com/diffs/npm/yarn/4.9.0/4.9.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@yarnpkg%2fcli/4.9.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@yarnpkg%2fcli/4.9.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@yarnpkg%2fcli/4.9.0/4.9.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@yarnpkg%2fcli/4.9.0/4.9.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>vercel/ai (@&#8203;ai-sdk/google)</summary>

### [`v1.2.11`](https://redirect.github.com/vercel/ai/releases/tag/%40ai-sdk/google%401.2.11)

[Compare Source](https://redirect.github.com/vercel/ai/compare/@ai-sdk/google@1.2.10...@ai-sdk/google@1.2.11)

##### Patch Changes

-   Updated dependencies \[[`beef951`](https://redirect.github.com/vercel/ai/commit/beef951)]
    -   [@&#8203;ai-sdk/provider](https://redirect.github.com/ai-sdk/provider)[@&#8203;1](https://redirect.github.com/1).1.3
    -   [@&#8203;ai-sdk/provider-utils](https://redirect.github.com/ai-sdk/provider-utils)[@&#8203;2](https://redirect.github.com/2).2.7

</details>

<details>
<summary>swc-project/swc (@&#8203;swc/core)</summary>

### [`v1.11.21`](https://redirect.github.com/swc-project/swc/blob/HEAD/CHANGELOG.md#11121---2025-04-14)

[Compare Source](https://redirect.github.com/swc-project/swc/compare/v1.11.20...v1.11.21)

##### Bug Fixes

-   **(es/helpers)** Sync tslib `_ts_generator` implementation ([#&#8203;10366](https://redirect.github.com/swc-project/swc/issues/10366)) ([d3fb992](https://redirect.github.com/swc-project/swc/commit/d3fb992a2f16882837cef4b6932be5d5415e7268))

-   **(es/proposal)** Fix scope of declarations for `explicit-resource-management` ([#&#8203;10362](https://redirect.github.com/swc-project/swc/issues/10362)) ([eb7f7e9](https://redirect.github.com/swc-project/swc/commit/eb7f7e9ff99ad639cc65e5ea702194c75a013f02))

-   **(ts/fast-strip)** Increase Wasm stack size ([#&#8203;10359](https://redirect.github.com/swc-project/swc/issues/10359)) ([6d444a5](https://redirect.github.com/swc-project/swc/commit/6d444a55921a6836db80661254b855bcb01376bc))

##### Miscellaneous Tasks

-   **(es/parser)** Remove useless check ([#&#8203;10363](https://redirect.github.com/swc-project/swc/issues/10363)) ([0f6a8c3](https://redirect.github.com/swc-project/swc/commit/0f6a8c3f3d64ef80b888bf7d4d7fed31d28d81f5))

##### Performance

-   **(es/parser)** Reduce string comparison ([#&#8203;10355](https://redirect.github.com/swc-project/swc/issues/10355)) ([21789c4](https://redirect.github.com/swc-project/swc/commit/21789c407795189b6ac1383e728763fcb44f5790))

-   **(es/parser)** Add initial capacitity for some vectors ([#&#8203;10361](https://redirect.github.com/swc-project/swc/issues/10361)) ([7b7b50e](https://redirect.github.com/swc-project/swc/commit/7b7b50e6cd96e49f2db7d564ad7724ee17909be2))

-   **(es/parser)** Reduce clone of token contexts ([#&#8203;10364](https://redirect.github.com/swc-project/swc/issues/10364)) ([3ab47b2](https://redirect.github.com/swc-project/swc/commit/3ab47b291f846d12aa26f209999978a91dc31719))

-   **(es/parser)** Use `bitflags` to reduce parser context size ([#&#8203;10367](https://redirect.github.com/swc-project/swc/issues/10367)) ([a2d3596](https://redirect.github.com/swc-project/swc/commit/a2d35960ad39799e105d15cb30a90b5344345646))

-   **(es/parser)** Replace byte arguments with generics ([#&#8203;10370](https://redirect.github.com/swc-project/swc/issues/10370)) ([68f7667](https://redirect.github.com/swc-project/swc/commit/68f76679b4a46205cb129be44f36ca31fac953c3))

-   **(es/parser)** Use `arrayvec` and unsafe `push` to optimize escaped string parsing ([#&#8203;10369](https://redirect.github.com/swc-project/swc/issues/10369)) ([e12ae1c](https://redirect.github.com/swc-project/swc/commit/e12ae1c994d901caab57335d16678d6e2aad7e0e))

</details>

<details>
<summary>tailwindlabs/tailwindcss (@&#8203;tailwindcss/postcss)</summary>

### [`v4.1.4`](https://redirect.github.com/tailwindlabs/tailwindcss/blob/HEAD/CHANGELOG.md#414---2025-04-14)

[Compare Source](https://redirect.github.com/tailwindlabs/tailwindcss/compare/v4.1.3...v4.1.4)

##### Added

-   Add experimental `@tailwindcss/oxide-wasm32-wasi` target for running Tailwind in browser environments like StackBlitz ([#&#8203;17558](https://redirect.github.com/tailwindlabs/tailwindcss/pull/17558))

##### Fixed

-   Ensure `color-mix(…)` polyfills do not cause used CSS variables to be removed ([#&#8203;17555](https://redirect.github.com/tailwindlabs/tailwindcss/pull/17555))
-   Ensure `color-mix(…)` polyfills create fallbacks for theme variables that reference other theme variables ([#&#8203;17562](https://redirect.github.com/tailwindlabs/tailwindcss/pull/17562))
-   Fix brace expansion in declining ranges like `{10..0..5}` and `{0..10..-5}` ([#&#8203;17591](https://redirect.github.com/tailwindlabs/tailwindcss/pull/17591))
-   Work around a Chrome rendering bug when using the `skew-*` utilities ([#&#8203;17627](https://redirect.github.com/tailwindlabs/tailwindcss/pull/17627))
-   Ensure container query variant names can contain hyphens ([#&#8203;17628](https://redirect.github.com/tailwindlabs/tailwindcss/pull/17628))
-   Ensure `shadow-inherit`, `inset-shadow-inherit`, `drop-shadow-inherit`, and `text-shadow-inherit` inherit the shadow color ([#&#8203;17647](https://redirect.github.com/tailwindlabs/tailwindcss/pull/17647))
-   Ensure compatibility with array tuples used in `fontSize` JS theme keys ([#&#8203;17630](https://redirect.github.com/tailwindlabs/tailwindcss/pull/17630))
-   Ensure folders with binary file extensions in their names are scanned for utilities ([#&#8203;17595](https://redirect.github.com/tailwindlabs/tailwindcss/pull/17595))
-   Upgrade: Convert `fontSize` array tuple syntax to CSS theme variables ([#&#8203;17630](https://redirect.github.com/tailwindlabs/tailwindcss/pull/17630))

</details>

<details>
<summary>TanStack/table (@&#8203;tanstack/react-table)</summary>

### [`v8.21.3`](https://redirect.github.com/TanStack/table/releases/tag/v8.21.3)

[Compare Source](https://redirect.github.com/TanStack/table/compare/v8.21.2...v8.21.3)

Version 8.21.3 - 4/14/25, 8:19 PM

#### Changes

##### Fix

-   table-core: use right Document instance on getResizeHandler (column-sizing feature) ([#&#8203;5989](https://redirect.github.com/TanStack/table/issues/5989)) ([`54ce673`](https://redirect.github.com/TanStack/table/commit/54ce673)) by [@&#8203;riccardoperra](https://redirect.github.com/riccardoperra)

##### Docs

-   fix all 158 broken links ([#&#8203;5972](https://redirect.github.com/TanStack/table/issues/5972)) ([`f7bf6f1`](https://redirect.github.com/TanStack/table/commit/f7bf6f1)) by [@&#8203;kisaragi-hiu](https://redirect.github.com/kisaragi-hiu)
-   add vue example for grouping ([#&#8203;5941](https://redirect.github.com/TanStack/table/issues/5941)) ([`3efa59c`](https://redirect.github.com/TanStack/table/commit/3efa59c)) by Harshil Patel

#### Packages

-   [@&#8203;tanstack/table-core](https://redirect.github.com/tanstack/table-core)[@&#8203;8](https://redirect.github.com/8).21.3
-   [@&#8203;tanstack/angular-table](https://redirect.github.com/tanstack/angular-table)[@&#8203;8](https://redirect.github.com/8).21.3
-   [@&#8203;tanstack/lit-table](https://redirect.github.com/tanstack/lit-table)[@&#8203;8](https://redirect.github.com/8).21.3
-   [@&#8203;tanstack/qwik-table](https://redirect.github.com/tanstack/qwik-table)[@&#8203;8](https://redirect.github.com/8).21.3
-   [@&#8203;tanstack/react-table](https://redirect.github.com/tanstack/react-table)[@&#8203;8](https://redirect.github.com/8).21.3
-   [@&#8203;tanstack/solid-table](https://redirect.github.com/tanstack/solid-table)[@&#8203;8](https://redirect.github.com/8).21.3
-   [@&#8203;tanstack/svelte-table](https://redirect.github.com/tanstack/svelte-table)[@&#8203;8](https://redirect.github.com/8).21.3
-   [@&#8203;tanstack/vue-table](https://redirect.github.com/tanstack/vue-table)[@&#8203;8](https://redirect.github.com/8).21.3
-   [@&#8203;tanstack/react-table-devtools](https://redirect.github.com/tanstack/react-table-devtools)[@&#8203;8](https://redirect.github.com/8).21.3

</details>

<details>
<summary>gpbl/react-day-picker (react-day-picker)</summary>

### [`v9.6.7`](https://redirect.github.com/gpbl/react-day-picker/releases/tag/v9.6.7)

[Compare Source](https://redirect.github.com/gpbl/react-day-picker/compare/v9.6.6...v9.6.7)

Improved handling of timezones, fixed alignment with the Left/Right navigation icons.

#### What's Changed

-   fix: improve left/right icon alignment by [@&#8203;AlecRust](https://redirect.github.com/AlecRust) in [https://github.com/gpbl/react-day-picker/pull/2734](https://redirect.github.com/gpbl/react-day-picker/pull/2734)
-   fix: prevent timezone override when `initialMonth` is `Date` type by [@&#8203;lovebuizel](https://redirect.github.com/lovebuizel) in [https://github.com/gpbl/react-day-picker/pull/2737](https://redirect.github.com/gpbl/react-day-picker/pull/2737)

#### New Contributors

-   [@&#8203;lovebuizel](https://redirect.github.com/lovebuizel) made their first contribution in [https://github.com/gpbl/react-day-picker/pull/2737](https://redirect.github.com/gpbl/react-day-picker/pull/2737)

**Full Changelog**: https://github.com/gpbl/react-day-picker/compare/v9.6.6...v9.6.7

</details>

<details>
<summary>typescript-eslint/typescript-eslint (typescript-eslint)</summary>

### [`v8.30.1`](https://redirect.github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8301-2025-04-14)

[Compare Source](https://redirect.github.com/typescript-eslint/typescript-eslint/compare/v8.30.0...v8.30.1)

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website.

### [`v8.30.0`](https://redirect.github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8300-2025-04-14)

[Compare Source](https://redirect.github.com/typescript-eslint/typescript-eslint/compare/v8.29.1...v8.30.0)

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website.

</details>

<details>
<summary>yarnpkg/berry (yarn)</summary>

### [`v4.9.1`](https://redirect.github.com/yarnpkg/berry/compare/2b26e3dff6fae778931445e8aca469e4bc2abac2...1908ee79fdf80fc8397d8ff928f3bfe25f30e715)

[Compare Source](https://redirect.github.com/yarnpkg/berry/compare/2b26e3dff6fae778931445e8aca469e4bc2abac2...1908ee79fdf80fc8397d8ff928f3bfe25f30e715)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4yMzguMCIsInVwZGF0ZWRJblZlciI6IjM5LjIzOC4wIiwidGFyZ2V0QnJhbmNoIjoiY2FuYXJ5IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyJdfQ==-->
2025-04-15 02:08:17 +00:00
renovate b70a0dfbc7 chore: bump up nestjs to v11.0.17 (#11676)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [@nestjs/common](https://nestjs.com) ([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/common)) | [`11.0.16` -> `11.0.17`](https://renovatebot.com/diffs/npm/@nestjs%2fcommon/11.0.16/11.0.17) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fcommon/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@nestjs%2fcommon/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@nestjs%2fcommon/11.0.16/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fcommon/11.0.16/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@nestjs/core](https://nestjs.com) ([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/core)) | [`11.0.16` -> `11.0.17`](https://renovatebot.com/diffs/npm/@nestjs%2fcore/11.0.16/11.0.17) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fcore/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@nestjs%2fcore/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@nestjs%2fcore/11.0.16/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fcore/11.0.16/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@nestjs/platform-express](https://nestjs.com) ([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/platform-express)) | [`11.0.16` -> `11.0.17`](https://renovatebot.com/diffs/npm/@nestjs%2fplatform-express/11.0.16/11.0.17) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fplatform-express/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@nestjs%2fplatform-express/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@nestjs%2fplatform-express/11.0.16/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fplatform-express/11.0.16/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@nestjs/platform-socket.io](https://nestjs.com) ([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/platform-socket.io)) | [`11.0.16` -> `11.0.17`](https://renovatebot.com/diffs/npm/@nestjs%2fplatform-socket.io/11.0.16/11.0.17) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fplatform-socket.io/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@nestjs%2fplatform-socket.io/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@nestjs%2fplatform-socket.io/11.0.16/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fplatform-socket.io/11.0.16/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@nestjs/websockets](https://redirect.github.com/nestjs/nest) ([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/websockets)) | [`11.0.16` -> `11.0.17`](https://renovatebot.com/diffs/npm/@nestjs%2fwebsockets/11.0.16/11.0.17) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fwebsockets/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@nestjs%2fwebsockets/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@nestjs%2fwebsockets/11.0.16/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fwebsockets/11.0.16/11.0.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>nestjs/nest (@&#8203;nestjs/common)</summary>

### [`v11.0.17`](https://redirect.github.com/nestjs/nest/compare/v11.0.16...f8a171c4cb3f663a7e949fdc8fe1e4c9b49640e6)

[Compare Source](https://redirect.github.com/nestjs/nest/compare/v11.0.16...v11.0.17)

</details>

<details>
<summary>nestjs/nest (@&#8203;nestjs/core)</summary>

### [`v11.0.17`](https://redirect.github.com/nestjs/nest/compare/v11.0.16...f8a171c4cb3f663a7e949fdc8fe1e4c9b49640e6)

[Compare Source](https://redirect.github.com/nestjs/nest/compare/v11.0.16...v11.0.17)

</details>

<details>
<summary>nestjs/nest (@&#8203;nestjs/platform-express)</summary>

### [`v11.0.17`](https://redirect.github.com/nestjs/nest/compare/v11.0.16...f8a171c4cb3f663a7e949fdc8fe1e4c9b49640e6)

[Compare Source](https://redirect.github.com/nestjs/nest/compare/v11.0.16...v11.0.17)

</details>

<details>
<summary>nestjs/nest (@&#8203;nestjs/platform-socket.io)</summary>

### [`v11.0.17`](https://redirect.github.com/nestjs/nest/compare/v11.0.16...v11.0.17)

[Compare Source](https://redirect.github.com/nestjs/nest/compare/v11.0.16...v11.0.17)

</details>

<details>
<summary>nestjs/nest (@&#8203;nestjs/websockets)</summary>

### [`v11.0.17`](https://redirect.github.com/nestjs/nest/compare/v11.0.16...v11.0.17)

[Compare Source](https://redirect.github.com/nestjs/nest/compare/v11.0.16...v11.0.17)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4yMzguMCIsInVwZGF0ZWRJblZlciI6IjM5LjIzOC4wIiwidGFyZ2V0QnJhbmNoIjoiY2FuYXJ5IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyJdfQ==-->
2025-04-15 01:54:22 +00:00
Yifeng Wang 594e896f74 Merge pull request #11661 from toeverything/0414/vtr_test_layout
test(editor): add tests for turbo renderer layout cache
2025-04-15 09:46:14 +08:00
Yifeng Wang 760a689c07 Merge branch 'canary' into 0414/vtr_test_layout 2025-04-15 09:20:25 +08:00
doodlewind b8967a8a7b test(editor): add tests for turbo renderer state machine (#11659) 2025-04-14 15:54:02 +00:00
Aki Chang 1a2d6f25be fix(android): nbstore laod error (#11674) 2025-04-14 17:19:14 +08:00
Yifeng Wang e9d04de399 test(editor): add tests for turbo renderer layout cache 2025-04-14 17:06:13 +08:00
Yifeng Wang e68947c792 fix(editor): integration vitest config warning 2025-04-14 17:04:57 +08:00
Yifeng Wang 2cd0e75810 fix: flaky 2025-04-14 17:04:22 +08:00
doodlewind 6457c979f5 test(editor): add tests for turbo renderer state machine (#11659) 2025-04-14 17:01:27 +08:00
donteatfriedrice 7aa87de5f7 fix(editor): markdown code preprocessor should handle link correctly (#11671)
Close [BS-3117](https://linear.app/affine-design/issue/BS-3117/代码粘贴后出现多余的-和-符号)
2025-04-14 08:28:43 +00:00
Saul-Mirone efecce9bf2 test(editor): enable basic test for cross platform (#11667) 2025-04-14 07:36:56 +00:00
pengx17 ee15b364d1 fix(electron): use CG* instead of NS* (#11668)
I encounter the following error when developing locally. Not sure if the current PR is the correct fix.

```
thread '<unnamed>' panicked at packages/frontend/native/media_capture/src/macos/screen_capture_kit.rs:253:11:
invalid message send to -[NSImage initWithSize:]: expected argument at index 0 to have type code '{CGSize=dd}', but found '{NSSize=dd}'
```
2025-04-14 07:21:49 +00:00
renovate 2db7dea46f chore: bump up all non-major dependencies (#11618)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence | Type | Update |
|---|---|---|---|---|---|---|---|
| [@ai-sdk/openai](https://sdk.vercel.ai/docs) ([source](https://redirect.github.com/vercel/ai)) | [`1.3.9` -> `1.3.10`](https://renovatebot.com/diffs/npm/@ai-sdk%2fopenai/1.3.9/1.3.10) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@ai-sdk%2fopenai/1.3.10?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@ai-sdk%2fopenai/1.3.10?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@ai-sdk%2fopenai/1.3.9/1.3.10?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@ai-sdk%2fopenai/1.3.9/1.3.10?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | patch |
| [@aws-sdk/client-s3](https://redirect.github.com/aws/aws-sdk-js-v3/tree/main/clients/client-s3) ([source](https://redirect.github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-s3)) | [`3.782.0` -> `3.787.0`](https://renovatebot.com/diffs/npm/@aws-sdk%2fclient-s3/3.782.0/3.787.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@aws-sdk%2fclient-s3/3.787.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@aws-sdk%2fclient-s3/3.787.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@aws-sdk%2fclient-s3/3.782.0/3.787.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@aws-sdk%2fclient-s3/3.782.0/3.787.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | minor |
| [@aws-sdk/s3-request-presigner](https://redirect.github.com/aws/aws-sdk-js-v3/tree/main/packages/s3-request-presigner) ([source](https://redirect.github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/s3-request-presigner)) | [`3.782.0` -> `3.787.0`](https://renovatebot.com/diffs/npm/@aws-sdk%2fs3-request-presigner/3.782.0/3.787.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@aws-sdk%2fs3-request-presigner/3.787.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@aws-sdk%2fs3-request-presigner/3.787.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@aws-sdk%2fs3-request-presigner/3.782.0/3.787.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@aws-sdk%2fs3-request-presigner/3.782.0/3.787.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | minor |
| [@faker-js/faker](https://fakerjs.dev) ([source](https://redirect.github.com/faker-js/faker)) | [`9.6.0` -> `9.7.0`](https://renovatebot.com/diffs/npm/@faker-js%2ffaker/9.6.0/9.7.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@faker-js%2ffaker/9.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@faker-js%2ffaker/9.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@faker-js%2ffaker/9.6.0/9.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@faker-js%2ffaker/9.6.0/9.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | devDependencies | minor |
| [@lit/context](https://lit.dev/) ([source](https://redirect.github.com/lit/lit/tree/HEAD/packages/context)) | [`1.1.4` -> `1.1.5`](https://renovatebot.com/diffs/npm/@lit%2fcontext/1.1.4/1.1.5) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@lit%2fcontext/1.1.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@lit%2fcontext/1.1.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@lit%2fcontext/1.1.4/1.1.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@lit%2fcontext/1.1.4/1.1.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | patch |
| [@smarttools/eslint-plugin-rxjs](https://redirect.github.com/DaveMBush/eslint-plugin-rxjs) | [`1.0.18` -> `1.0.19`](https://renovatebot.com/diffs/npm/@smarttools%2feslint-plugin-rxjs/1.0.18/1.0.19) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@smarttools%2feslint-plugin-rxjs/1.0.19?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@smarttools%2feslint-plugin-rxjs/1.0.19?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@smarttools%2feslint-plugin-rxjs/1.0.18/1.0.19?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@smarttools%2feslint-plugin-rxjs/1.0.18/1.0.19?slim=true)](https://docs.renovatebot.com/merge-confidence/) | devDependencies | patch |
| [@swc/core](https://swc.rs) ([source](https://redirect.github.com/swc-project/swc)) | [`1.11.18` -> `1.11.20`](https://renovatebot.com/diffs/npm/@swc%2fcore/1.11.18/1.11.20) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@swc%2fcore/1.11.20?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@swc%2fcore/1.11.20?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@swc%2fcore/1.11.18/1.11.20?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@swc%2fcore/1.11.18/1.11.20?slim=true)](https://docs.renovatebot.com/merge-confidence/) | devDependencies | patch |
| [@types/node](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node) ([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)) | [`22.14.0` -> `22.14.1`](https://renovatebot.com/diffs/npm/@types%2fnode/22.14.0/22.14.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2fnode/22.14.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@types%2fnode/22.14.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@types%2fnode/22.14.0/22.14.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2fnode/22.14.0/22.14.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | patch |
| [@types/node](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node) ([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)) | [`22.14.0` -> `22.14.1`](https://renovatebot.com/diffs/npm/@types%2fnode/22.14.0/22.14.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2fnode/22.14.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@types%2fnode/22.14.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@types%2fnode/22.14.0/22.14.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2fnode/22.14.0/22.14.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | devDependencies | patch |
| [@types/react](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react) ([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react)) | [`19.1.0` -> `19.1.1`](https://renovatebot.com/diffs/npm/@types%2freact/19.1.0/19.1.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2freact/19.1.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@types%2freact/19.1.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@types%2freact/19.1.0/19.1.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2freact/19.1.0/19.1.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | devDependencies | patch |
| [ai](https://sdk.vercel.ai/docs) ([source](https://redirect.github.com/vercel/ai)) | [`4.3.4` -> `4.3.5`](https://renovatebot.com/diffs/npm/ai/4.3.4/4.3.5) | [![age](https://developer.mend.io/api/mc/badges/age/npm/ai/4.3.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/ai/4.3.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/ai/4.3.4/4.3.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/ai/4.3.4/4.3.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | patch |
| [animejs](https://animejs.com) ([source](https://redirect.github.com/juliangarnier/anime)) | [`4.0.0` -> `4.0.1`](https://renovatebot.com/diffs/npm/animejs/4.0.0/4.0.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/animejs/4.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/animejs/4.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/animejs/4.0.0/4.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/animejs/4.0.0/4.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | patch |
| [anyhow](https://redirect.github.com/dtolnay/anyhow) | `1.0.97` -> `1.0.98` | [![age](https://developer.mend.io/api/mc/badges/age/crate/anyhow/1.0.98?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/crate/anyhow/1.0.98?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/crate/anyhow/1.0.97/1.0.98?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/crate/anyhow/1.0.97/1.0.98?slim=true)](https://docs.renovatebot.com/merge-confidence/) | workspace.dependencies | patch |
| [cc](https://redirect.github.com/rust-lang/cc-rs) | `1.2.18` -> `1.2.19` | [![age](https://developer.mend.io/api/mc/badges/age/crate/cc/1.2.19?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/crate/cc/1.2.19?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/crate/cc/1.2.18/1.2.19?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/crate/cc/1.2.18/1.2.19?slim=true)](https://docs.renovatebot.com/merge-confidence/) | build-dependencies | patch |
| [dotenv](https://redirect.github.com/motdotla/dotenv) | [`16.4.7` -> `16.5.0`](https://renovatebot.com/diffs/npm/dotenv/16.4.7/16.5.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/dotenv/16.5.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/dotenv/16.5.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/dotenv/16.4.7/16.5.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/dotenv/16.4.7/16.5.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | minor |
| [html-validate](https://html-validate.org) ([source](https://gitlab.com/html-validate/html-validate)) | [`9.5.2` -> `9.5.3`](https://renovatebot.com/diffs/npm/html-validate/9.5.2/9.5.3) | [![age](https://developer.mend.io/api/mc/badges/age/npm/html-validate/9.5.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/html-validate/9.5.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/html-validate/9.5.2/9.5.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/html-validate/9.5.2/9.5.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | patch |
| [ioredis](https://redirect.github.com/luin/ioredis) | [`5.6.0` -> `5.6.1`](https://renovatebot.com/diffs/npm/ioredis/5.6.0/5.6.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/ioredis/5.6.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/ioredis/5.6.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/ioredis/5.6.0/5.6.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/ioredis/5.6.0/5.6.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | patch |
| [jotai](https://redirect.github.com/pmndrs/jotai) | [`2.12.2` -> `2.12.3`](https://renovatebot.com/diffs/npm/jotai/2.12.2/2.12.3) | [![age](https://developer.mend.io/api/mc/badges/age/npm/jotai/2.12.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/jotai/2.12.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/jotai/2.12.2/2.12.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/jotai/2.12.2/2.12.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | patch |
| [lib0](https://redirect.github.com/dmonad/lib0) | [`0.2.102` -> `0.2.104`](https://renovatebot.com/diffs/npm/lib0/0.2.102/0.2.104) | [![age](https://developer.mend.io/api/mc/badges/age/npm/lib0/0.2.104?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/lib0/0.2.104?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/lib0/0.2.102/0.2.104?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/lib0/0.2.102/0.2.104?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | patch |
| [lib0](https://redirect.github.com/dmonad/lib0) | [`0.2.102` -> `0.2.104`](https://renovatebot.com/diffs/npm/lib0/0.2.102/0.2.104) | [![age](https://developer.mend.io/api/mc/badges/age/npm/lib0/0.2.104?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/lib0/0.2.104?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/lib0/0.2.102/0.2.104?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/lib0/0.2.102/0.2.104?slim=true)](https://docs.renovatebot.com/merge-confidence/) | devDependencies | patch |
| [lint-staged](https://redirect.github.com/lint-staged/lint-staged) | [`15.5.0` -> `15.5.1`](https://renovatebot.com/diffs/npm/lint-staged/15.5.0/15.5.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/lint-staged/15.5.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/lint-staged/15.5.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/lint-staged/15.5.0/15.5.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/lint-staged/15.5.0/15.5.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | devDependencies | patch |
| [lit](https://lit.dev/) ([source](https://redirect.github.com/lit/lit/tree/HEAD/packages/lit)) | [`3.2.1` -> `3.3.0`](https://renovatebot.com/diffs/npm/lit/3.2.1/3.3.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/lit/3.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/lit/3.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/lit/3.2.1/3.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/lit/3.2.1/3.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | minor |
| [lit-html](https://lit.dev/) ([source](https://redirect.github.com/lit/lit/tree/HEAD/packages/lit-html)) | [`3.2.1` -> `3.3.0`](https://renovatebot.com/diffs/npm/lit-html/3.2.1/3.3.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/lit-html/3.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/lit-html/3.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/lit-html/3.2.1/3.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/lit-html/3.2.1/3.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | minor |
| [lucide-react](https://lucide.dev) ([source](https://redirect.github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react)) | [`^0.487.0` -> `^0.488.0`](https://renovatebot.com/diffs/npm/lucide-react/0.487.0/0.488.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/lucide-react/0.488.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/lucide-react/0.488.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/lucide-react/0.487.0/0.488.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/lucide-react/0.487.0/0.488.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | minor |
| [msw](https://mswjs.io) ([source](https://redirect.github.com/mswjs/msw)) | [`2.7.3` -> `2.7.4`](https://renovatebot.com/diffs/npm/msw/2.7.3/2.7.4) | [![age](https://developer.mend.io/api/mc/badges/age/npm/msw/2.7.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/msw/2.7.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/msw/2.7.3/2.7.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/msw/2.7.3/2.7.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | devDependencies | patch |
| [nodemailer](https://nodemailer.com/) ([source](https://redirect.github.com/nodemailer/nodemailer)) | [`6.10.0` -> `6.10.1`](https://renovatebot.com/diffs/npm/nodemailer/6.10.0/6.10.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/nodemailer/6.10.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/nodemailer/6.10.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/nodemailer/6.10.0/6.10.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/nodemailer/6.10.0/6.10.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | patch |
| [react-day-picker](https://daypicker.dev) ([source](https://redirect.github.com/gpbl/react-day-picker)) | [`9.6.5` -> `9.6.6`](https://renovatebot.com/diffs/npm/react-day-picker/9.6.5/9.6.6) | [![age](https://developer.mend.io/api/mc/badges/age/npm/react-day-picker/9.6.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/react-day-picker/9.6.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/react-day-picker/9.6.5/9.6.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/react-day-picker/9.6.5/9.6.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | patch |
| [sqlx](https://redirect.github.com/launchbadge/sqlx) | `0.8.3` -> `0.8.4` | [![age](https://developer.mend.io/api/mc/badges/age/crate/sqlx/0.8.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/crate/sqlx/0.8.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/crate/sqlx/0.8.3/0.8.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/crate/sqlx/0.8.3/0.8.4?slim=true)](https://docs.renovatebot.com/merge-confidence/) | workspace.dependencies | patch |
| [com.google.devtools.ksp](https://goo.gle/ksp) ([source](https://redirect.github.com/google/ksp)) | `2.1.20-1.0.32` -> `2.1.20-2.0.0` | [![age](https://developer.mend.io/api/mc/badges/age/maven/com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin/2.1.20-2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin/2.1.20-2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin/2.1.20-1.0.32/2.1.20-2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin/2.1.20-1.0.32/2.1.20-2.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | plugin | patch |
| [org.jetbrains.kotlinx:kotlinx-serialization-json](https://redirect.github.com/Kotlin/kotlinx.serialization) | `1.8.0` -> `1.8.1` | [![age](https://developer.mend.io/api/mc/badges/age/maven/org.jetbrains.kotlinx:kotlinx-serialization-json/1.8.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/org.jetbrains.kotlinx:kotlinx-serialization-json/1.8.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/org.jetbrains.kotlinx:kotlinx-serialization-json/1.8.0/1.8.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/org.jetbrains.kotlinx:kotlinx-serialization-json/1.8.0/1.8.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | patch |
| [org.jetbrains.kotlinx:kotlinx-coroutines-android](https://redirect.github.com/Kotlin/kotlinx.coroutines) | `1.10.1` -> `1.10.2` | [![age](https://developer.mend.io/api/mc/badges/age/maven/org.jetbrains.kotlinx:kotlinx-coroutines-android/1.10.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/org.jetbrains.kotlinx:kotlinx-coroutines-android/1.10.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/org.jetbrains.kotlinx:kotlinx-coroutines-android/1.10.1/1.10.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/org.jetbrains.kotlinx:kotlinx-coroutines-android/1.10.1/1.10.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | patch |
| [com.android.tools.build:gradle](https://developer.android.com/studio/build) ([source](https://android.googlesource.com/platform/tools/base)) | `8.7.2` -> `8.9.1` | [![age](https://developer.mend.io/api/mc/badges/age/maven/com.android.tools.build:gradle/8.9.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/com.android.tools.build:gradle/8.9.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/com.android.tools.build:gradle/8.7.2/8.9.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/com.android.tools.build:gradle/8.7.2/8.9.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | minor |
| [androidx.core:core-ktx](https://developer.android.com/jetpack/androidx/releases/core#1.16.0) ([source](https://cs.android.com/androidx/platform/frameworks/support)) | `1.15.0` -> `1.16.0` | [![age](https://developer.mend.io/api/mc/badges/age/maven/androidx.core:core-ktx/1.16.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/androidx.core:core-ktx/1.16.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/androidx.core:core-ktx/1.15.0/1.16.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/androidx.core:core-ktx/1.15.0/1.16.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | minor |
| [androidx.compose:compose-bom](https://developer.android.com/jetpack) | `2025.03.01` -> `2025.04.00` | [![age](https://developer.mend.io/api/mc/badges/age/maven/androidx.compose:compose-bom/2025.04.00?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/androidx.compose:compose-bom/2025.04.00?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/androidx.compose:compose-bom/2025.03.01/2025.04.00?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/androidx.compose:compose-bom/2025.03.01/2025.04.00?slim=true)](https://docs.renovatebot.com/merge-confidence/) | dependencies | minor |

---

### Release Notes

<details>
<summary>vercel/ai (@&#8203;ai-sdk/openai)</summary>

### [`v1.3.10`](https://redirect.github.com/vercel/ai/releases/tag/%40ai-sdk/openai%401.3.10)

[Compare Source](https://redirect.github.com/vercel/ai/compare/@ai-sdk/openai@1.3.9...@ai-sdk/openai@1.3.10)

##### Patch Changes

-   [`dbe53e7`](https://redirect.github.com/vercel/ai/commit/dbe53e7): adding support for gpt-4o-search-preview and handling unsupported parameters
-   [`84ffaba`](https://redirect.github.com/vercel/ai/commit/84ffaba): fix: propagate openai transcription fixes

</details>

<details>
<summary>aws/aws-sdk-js-v3 (@&#8203;aws-sdk/client-s3)</summary>

### [`v3.787.0`](https://redirect.github.com/aws/aws-sdk-js-v3/blob/HEAD/clients/client-s3/CHANGELOG.md#37870-2025-04-10)

[Compare Source](https://redirect.github.com/aws/aws-sdk-js-v3/compare/v3.782.0...v3.787.0)

**Note:** Version bump only for package [@&#8203;aws-sdk/client-s3](https://redirect.github.com/aws-sdk/client-s3)

</details>

<details>
<summary>aws/aws-sdk-js-v3 (@&#8203;aws-sdk/s3-request-presigner)</summary>

### [`v3.787.0`](https://redirect.github.com/aws/aws-sdk-js-v3/blob/HEAD/packages/s3-request-presigner/CHANGELOG.md#37870-2025-04-10)

[Compare Source](https://redirect.github.com/aws/aws-sdk-js-v3/compare/v3.782.0...v3.787.0)

**Note:** Version bump only for package [@&#8203;aws-sdk/s3-request-presigner](https://redirect.github.com/aws-sdk/s3-request-presigner)

</details>

<details>
<summary>faker-js/faker (@&#8203;faker-js/faker)</summary>

### [`v9.7.0`](https://redirect.github.com/faker-js/faker/blob/HEAD/CHANGELOG.md#970-2025-04-13)

[Compare Source](https://redirect.github.com/faker-js/faker/compare/v9.6.0...v9.7.0)

##### New Locales

-   **locale:** Add bn_BD locale ([#&#8203;3439](https://redirect.github.com/faker-js/faker/issues/3439)) ([fef0ad7](https://redirect.github.com/faker-js/faker/commit/fef0ad7859ff5994947c2c02afd6bdf13dffd234))
-   **locale:** add cy locale, start with date ([#&#8203;3462](https://redirect.github.com/faker-js/faker/issues/3462)) ([f70a6f7](https://redirect.github.com/faker-js/faker/commit/f70a6f7a656090ed900ea18b39961d0d5ff78be0))
-   **locale:** add finance support for ja locale ([#&#8203;3449](https://redirect.github.com/faker-js/faker/issues/3449)) ([b2c5298](https://redirect.github.com/faker-js/faker/commit/b2c5298c94f632681937fc6d62da2f84252b5c66))
-   **locale:** add localize sex support for zh_CN & zh_TW ([#&#8203;3450](https://redirect.github.com/faker-js/faker/issues/3450)) ([048c325](https://redirect.github.com/faker-js/faker/commit/048c32581bd5d15f333ef63e4ca968e02793373d))
-   **locale:** add Tamil language support ([#&#8203;3468](https://redirect.github.com/faker-js/faker/issues/3468)) ([cdf6dc4](https://redirect.github.com/faker-js/faker/commit/cdf6dc4a973b8e64069f8b8d98e6921188f08575))

##### Bug Fixes

-   **airline:** Air France and KLM Royal Dutch Airlines ([#&#8203;3440](https://redirect.github.com/faker-js/faker/issues/3440)) ([8a2d168](https://redirect.github.com/faker-js/faker/commit/8a2d168f62307af8c4b04ab8ab4624786009671b))
-   **iban:** more strict pattern for IE and PS ([#&#8203;3464](https://redirect.github.com/faker-js/faker/issues/3464)) ([7b12056](https://redirect.github.com/faker-js/faker/commit/7b120567139b2ac84d052f42f1f352c6697f2aa2))
-   **locale:** rename ja and zh_CN company affix files ([#&#8203;3448](https://redirect.github.com/faker-js/faker/issues/3448)) ([1e551c5](https://redirect.github.com/faker-js/faker/commit/1e551c5f47e292d3dc6bbefae9eaf75664a052a1))
-   **number:** don't ignore multipleOf in float when min=max ([#&#8203;3417](https://redirect.github.com/faker-js/faker/issues/3417)) ([e4cc4e5](https://redirect.github.com/faker-js/faker/commit/e4cc4e50d1d4103c26f06fd2db0ca187dbb537cd))

</details>

<details>
<summary>lit/lit (@&#8203;lit/context)</summary>

### [`v1.1.5`](https://redirect.github.com/lit/lit/blob/HEAD/packages/context/CHANGELOG.md#115)

[Compare Source](https://redirect.github.com/lit/lit/compare/7db8eadb285c2a55fe4aa78c491585e1e90d3b1c...@lit/context@1.1.5)

##### Patch Changes

-   [#&#8203;4917](https://redirect.github.com/lit/lit/pull/4917) [`aced5a93`](https://redirect.github.com/lit/lit/commit/aced5a93b70a17aa34e6b5ee9654d161eb484031) Thanks [@&#8203;djrenren](https://redirect.github.com/djrenren)! - Fixed a bug where initial values were not handled by the [@&#8203;provide](https://redirect.github.com/provide)() decorator
    when using standard decorators ([#&#8203;4675](https://redirect.github.com/lit/lit/issues/4675))
-   Updated dependencies \[[`c9160405`](https://redirect.github.com/lit/lit/commit/c9160405deaf8de68bb1e587ef9b2484cb58b353), [`3e2f87f6`](https://redirect.github.com/lit/lit/commit/3e2f87f688d7f447f5bd8517cc5a2f29ee1f3ce5), [`4824c4ce`](https://redirect.github.com/lit/lit/commit/4824c4ce094fabf9d96c92f0d986827b046b2705)]:
    -   [@&#8203;lit/reactive-element](https://redirect.github.com/lit/reactive-element)[@&#8203;2](https://redirect.github.com/2).1.0

</details>

<details>
<summary>DaveMBush/eslint-plugin-rxjs (@&#8203;smarttools/eslint-plugin-rxjs)</summary>

### [`v1.0.19`](https://redirect.github.com/DaveMBush/eslint-plugin-rxjs/releases/tag/v1.0.19): (2025-04-11)

[Compare Source](https://redirect.github.com/DaveMBush/eslint-plugin-rxjs/compare/v1.0.18...v1.0.19)

Fix issue 131

</details>

<details>
<summary>swc-project/swc (@&#8203;swc/core)</summary>

### [`v1.11.20`](https://redirect.github.com/swc-project/swc/blob/HEAD/CHANGELOG.md#11120---2025-04-11)

[Compare Source](https://redirect.github.com/swc-project/swc/compare/v1.11.18...v1.11.20)

##### Bug Fixes

-   **(error_reporters)** Removing unused code to fix clippy check ([#&#8203;10338](https://redirect.github.com/swc-project/swc/issues/10338)) ([5970f93](https://redirect.github.com/swc-project/swc/commit/5970f937f7dec526fc45d0c33f28e2f0c3f86758))

-   **(es/minifier)** Preserve block with block scoped declaration ([#&#8203;10335](https://redirect.github.com/swc-project/swc/issues/10335)) ([a4ac3b7](https://redirect.github.com/swc-project/swc/commit/a4ac3b7188c595aa76d0f28c75d302da7fe25ccc))

-   **(es/parser)** Allow abstract method named `accessor` ([#&#8203;10327](https://redirect.github.com/swc-project/swc/issues/10327)) ([3f71776](https://redirect.github.com/swc-project/swc/commit/3f7177665cda8497961bdaf8d8cff5a41e09df00))

-   **(es/preset-env)** Consider `browserslist` config if `env.target` is not configured ([#&#8203;8921](https://redirect.github.com/swc-project/swc/issues/8921)) ([a2dc372](https://redirect.github.com/swc-project/swc/commit/a2dc372f9ce8f89c2446ee5df3e205223616d229))

-   **(es/resolver)** Handle using declarations ([#&#8203;10354](https://redirect.github.com/swc-project/swc/issues/10354)) ([dad815c](https://redirect.github.com/swc-project/swc/commit/dad815cee63f89fbdb393bdf8c02751ea4c4e929))

-   fix(es/compat): Remove one promise tick in yield\* ([tc39/ecma262#2819](https://redirect.github.com/tc39/ecma262/issues/2819)) ([#&#8203;10317](https://redirect.github.com/swc-project/swc/issues/10317))

**Related issue:**

-   [babel/babel#14877](https://redirect.github.com/babel/babel/issues/14877)
-   [tc39/ecma262#2819](https://redirect.github.com/tc39/ecma262/issues/2819) ([3fb1950](https://redirect.github.com/swc-project/swc/commit/3fb19505b58039eb3d2b1e7790321567c4b3b124))

##### Features

-   **(errors)** Integrate `miette` for enhanced diagnostic reporting ([#&#8203;10241](https://redirect.github.com/swc-project/swc/issues/10241)) ([156c3b1](https://redirect.github.com/swc-project/swc/commit/156c3b1cdcf4c0937c20daac99d07b1d96b2c739))

-   **(es/codegen)** Support `sourceMap.url` option of `terser` ([#&#8203;10346](https://redirect.github.com/swc-project/swc/issues/10346)) ([566bc7c](https://redirect.github.com/swc-project/swc/commit/566bc7c06e66805c2c03f8284016711029539111))

-   **(plugin/runner)** Support `pluginEnvVars` ([#&#8203;10318](https://redirect.github.com/swc-project/swc/issues/10318)) ([795fedc](https://redirect.github.com/swc-project/swc/commit/795fedc6aec7f3dac7be0dd4a3237fe27d05dc7f))

##### Miscellaneous Tasks

-   **(es/helpers)** Update peer dependency version for `@swc/helpers` to `>=0.5.17` ([#&#8203;10321](https://redirect.github.com/swc-project/swc/issues/10321)) ([ddbf3e1](https://redirect.github.com/swc-project/swc/commit/ddbf3e1d8c3f81f86593c09d1ec260fd1c44a647))

-   **(ide)** Disable RA diagnostics ([#&#8203;10324](https://redirect.github.com/swc-project/swc/issues/10324)) ([fcf280f](https://redirect.github.com/swc-project/swc/commit/fcf280fc62a9df6b041ae294abf4566b5307df9e))

##### Performance

-   **(es/ast)** Reduce redundant string comparison for `Atom`s ([#&#8203;10323](https://redirect.github.com/swc-project/swc/issues/10323)) ([3ce9d81](https://redirect.github.com/swc-project/swc/commit/3ce9d8119ea0a053eb27b8c40cd760679bbada64))

-   **(es/jsx)** Cache FileName for JSX pass ([#&#8203;9951](https://redirect.github.com/swc-project/swc/issues/9951)) ([#&#8203;10322](https://redirect.github.com/swc-project/swc/issues/10322)) ([9852940](https://redirect.github.com/swc-project/swc/commit/98529404bcb5f2a24c449f023fcd14a2f0128510))

-   **(es/parser)** Remove redundant `is_ascii` calls ([#&#8203;10334](https://redirect.github.com/swc-project/swc/issues/10334)) ([e66b4d6](https://redirect.github.com/swc-project/swc/commit/e66b4d660c36a491f06e8d79f6d49a815dadebdc))

-   **(es/parser)** Remove ascii check for no-ascii ([#&#8203;10350](https://redirect.github.com/swc-project/swc/issues/10350)) ([4279b96](https://redirect.github.com/swc-project/swc/commit/4279b96d12f259bd3205a71b3402402fe4880d5b))

##### Testing

-   **(es)** Unignore tests and update node to `20` in exec tests ([#&#8203;10348](https://redirect.github.com/swc-project/swc/issues/10348)) ([eee73ce](https://redirect.github.com/swc-project/swc/commit/eee73cec761d1c28f6d1b87be9082fdf2af6e226))

</details>

<details>
<summary>juliangarnier/anime (animejs)</summary>

### [`v4.0.1`](https://redirect.github.com/juliangarnier/anime/releases/tag/v4.0.1)

[Compare Source](https://redirect.github.com/juliangarnier/anime/compare/4.0.0...v4.0.1)

#### fixes

-   Fix `createScope` root param type for `ReactRef` ([#&#8203;971](https://redirect.github.com/juliangarnier/anime/issues/971)) thanks [@&#8203;Jimmydalecleveland](https://redirect.github.com/Jimmydalecleveland)

</details>

<details>
<summary>dtolnay/anyhow (anyhow)</summary>

### [`v1.0.98`](https://redirect.github.com/dtolnay/anyhow/releases/tag/1.0.98)

[Compare Source](https://redirect.github.com/dtolnay/anyhow/compare/1.0.97...1.0.98)

-   Add [`self.into_boxed_dyn_error()`](https://docs.rs/anyhow/1/anyhow/struct.Error.html#method.into_boxed_dyn_error) and [`self.reallocate_into_boxed_dyn_error_without_backtrace()`](https://docs.rs/anyhow/1/anyhow/struct.Error.html#method.reallocate_into_boxed_dyn_error_without_backtrace) methods for anyhow::Error ([#&#8203;415](https://redirect.github.com/dtolnay/anyhow/issues/415))

</details>

<details>
<summary>rust-lang/cc-rs (cc)</summary>

### [`v1.2.19`](https://redirect.github.com/rust-lang/cc-rs/blob/HEAD/CHANGELOG.md#1219---2025-04-11)

[Compare Source](https://redirect.github.com/rust-lang/cc-rs/compare/cc-v1.2.18...cc-v1.2.19)

##### Other

-   Fix musl compilation: Add musl as a prefix fallback ([#&#8203;1455](https://redirect.github.com/rust-lang/cc-rs/pull/1455))

</details>

<details>
<summary>motdotla/dotenv (dotenv)</summary>

### [`v16.5.0`](https://redirect.github.com/motdotla/dotenv/blob/HEAD/CHANGELOG.md#1650-2025-04-07)

[Compare Source](https://redirect.github.com/motdotla/dotenv/compare/v16.4.7...v16.5.0)

##### Added

-   🎉 Added new sponsor [Graphite](https://graphite.dev/?utm_source=github\&utm_medium=repo\&utm_campaign=dotenv) - *the AI developer productivity platform helping teams on GitHub ship higher quality software, faster*.

> \[!TIP]
> **[Become a sponsor](https://redirect.github.com/sponsors/motdotla)**
>
> The dotenvx README is viewed thousands of times DAILY on GitHub and NPM.
> Sponsoring dotenv is a great way to get in front of developers and give back to the developer community at the same time.

##### Changed

-   Remove `_log` method. Use `_debug` [#&#8203;862](https://redirect.github.com/motdotla/dotenv/pull/862)

</details>

<details>
<summary>html-validate/html-validate (html-validate)</summary>

### [`v9.5.3`](https://gitlab.com/html-validate/html-validate/blob/HEAD/CHANGELOG.md#953-2025-04-13)

[Compare Source](https://gitlab.com/html-validate/html-validate/compare/v9.5.2...v9.5.3)

##### Bug Fixes

-   fix crash when aria attribute references id with comma ([fb91b7c](https://gitlab.com/html-validate/html-validate/commit/fb91b7c7e7b4c3a3b01998c0bd348e4a43eb817f)), closes [#&#8203;299](https://gitlab.com/html-validate/html-validate/issues/299)
-   fix crash when attribute selector `[..]` contains escaped characters ([0c19b82](https://gitlab.com/html-validate/html-validate/commit/0c19b8267deac4f957558ed4149ee2ba52cd0a06))

</details>

<details>
<summary>luin/ioredis (ioredis)</summary>

### [`v5.6.1`](https://redirect.github.com/luin/ioredis/blob/HEAD/CHANGELOG.md#561-2025-04-11)

[Compare Source](https://redirect.github.com/luin/ioredis/compare/v5.6.0...v5.6.1)

##### Bug Fixes

-   adding debug log on cluster.slots initial connection error ([bedcfb5](https://redirect.github.com/luin/ioredis/commit/bedcfb5d4b462c3f0a804ab32152d80029e72710))

</details>

<details>
<summary>pmndrs/jotai (jotai)</summary>

### [`v2.12.3`](https://redirect.github.com/pmndrs/jotai/releases/tag/v2.12.3)

[Compare Source](https://redirect.github.com/pmndrs/jotai/compare/v2.12.2...v2.12.3)

This introduces an internal capability for jotai-devtools.

#### What's Changed

-   fix: expose an internal function for devtools by [@&#8203;dai-shi](https://redirect.github.com/dai-shi) in [https://github.com/pmndrs/jotai/pull/3045](https://redirect.github.com/pmndrs/jotai/pull/3045)
-   fix(react): experimental option to make attaching promise status controllable by [@&#8203;dai-shi](https://redirect.github.com/dai-shi) in [https://github.com/pmndrs/jotai/pull/3026](https://redirect.github.com/pmndrs/jotai/pull/3026)

#### New Contributors

-   [@&#8203;siyou](https://redirect.github.com/siyou) made their first contribution in [https://github.com/pmndrs/jotai/pull/3029](https://redirect.github.com/pmndrs/jotai/pull/3029)

**Full Changelog**: https://github.com/pmndrs/jotai/compare/v2.12.2...v2.12.3

</details>

<details>
<summary>dmonad/lib0 (lib0)</summary>

### [`v0.2.104`](https://redirect.github.com/dmonad/lib0/releases/tag/v0.2.104)

[Compare Source](https://redirect.github.com/dmonad/lib0/compare/v0.2.103...v0.2.104)

-   \[array/bubblesortItem] fix edge case  [`cffe349`](https://redirect.github.com/dmonad/lib0/commit/cffe349)

***

### [`v0.2.103`](https://redirect.github.com/dmonad/lib0/releases/tag/v0.2.103)

[Compare Source](https://redirect.github.com/dmonad/lib0/compare/v0.2.102...v0.2.103)

-   \[array] add bubblesortItem  [`98544a4`](https://redirect.github.com/dmonad/lib0/commit/98544a4)

***

</details>

<details>
<summary>lint-staged/lint-staged (lint-staged)</summary>

### [`v15.5.1`](https://redirect.github.com/lint-staged/lint-staged/blob/HEAD/CHANGELOG.md#1551)

[Compare Source](https://redirect.github.com/lint-staged/lint-staged/compare/v15.5.0...v15.5.1)

##### Patch Changes

-   [#&#8203;1533](https://redirect.github.com/lint-staged/lint-staged/pull/1533) [`5d53534`](https://redirect.github.com/lint-staged/lint-staged/commit/5d535349958a939cd17d87180196bb2b9dfc452b) Thanks [@&#8203;iiroj](https://redirect.github.com/iiroj)! - Improve listing of staged files so that *lint-staged* doesn't crash when encountering an uninitialized submodule. This should result in less errors like:

        ✖ Failed to get staged files!

</details>

<details>
<summary>lit/lit (lit)</summary>

### [`v3.3.0`](https://redirect.github.com/lit/lit/blob/HEAD/packages/lit/CHANGELOG.md#330)

[Compare Source](https://redirect.github.com/lit/lit/compare/lit@3.2.1...lit@3.3.0)

##### Minor Changes

-   [#&#8203;4901](https://redirect.github.com/lit/lit/pull/4901) [`c9160405`](https://redirect.github.com/lit/lit/commit/c9160405deaf8de68bb1e587ef9b2484cb58b353) Thanks [@&#8203;maxpatiiuk](https://redirect.github.com/maxpatiiuk)! - Dev mode warnings are now emitted on the next microtask after package import, allowing for a wider opportunity to suppress the warnings by consumers.

-   [#&#8203;4934](https://redirect.github.com/lit/lit/pull/4934) [`4824c4ce`](https://redirect.github.com/lit/lit/commit/4824c4ce094fabf9d96c92f0d986827b046b2705) - Adds property option for `useDefault`. When set, the initial default value is not considered a change and does *not* reflect when `reflect` is set. In addition, when the attribute is removed, the default value is restored.

##### Patch Changes

-   [#&#8203;4949](https://redirect.github.com/lit/lit/pull/4949) [`3e2f87f6`](https://redirect.github.com/lit/lit/commit/3e2f87f688d7f447f5bd8517cc5a2f29ee1f3ce5) - fixes inconsistent initial changed properties values

-   [#&#8203;4956](https://redirect.github.com/lit/lit/pull/4956) [`0a9bc720`](https://redirect.github.com/lit/lit/commit/0a9bc72016812f3c3cfb00e1e41e1cae418dde0b) Thanks [@&#8203;louis-bompart](https://redirect.github.com/louis-bompart)! - Import barrels explicitly for compatibility with modern Node resolution w/ ESM

-   Updated dependencies \[[`c9160405`](https://redirect.github.com/lit/lit/commit/c9160405deaf8de68bb1e587ef9b2484cb58b353), [`3e2f87f6`](https://redirect.github.com/lit/lit/commit/3e2f87f688d7f447f5bd8517cc5a2f29ee1f3ce5), [`4824c4ce`](https://redirect.github.com/lit/lit/commit/4824c4ce094fabf9d96c92f0d986827b046b2705), [`0a9bc720`](https://redirect.github.com/lit/lit/commit/0a9bc72016812f3c3cfb00e1e41e1cae418dde0b)]:
    -   [@&#8203;lit/reactive-element](https://redirect.github.com/lit/reactive-element)[@&#8203;2](https://redirect.github.com/2).1.0
    -   lit-element@4.2.0
    -   lit-html@3.3.0

</details>

<details>
<summary>lit/lit (lit-html)</summary>

### [`v3.3.0`](https://redirect.github.com/lit/lit/blob/HEAD/packages/lit-html/CHANGELOG.md#330)

[Compare Source](https://redirect.github.com/lit/lit/compare/lit-html@3.2.1...lit-html@3.3.0)

##### Minor Changes

-   [#&#8203;4901](https://redirect.github.com/lit/lit/pull/4901) [`c9160405`](https://redirect.github.com/lit/lit/commit/c9160405deaf8de68bb1e587ef9b2484cb58b353) Thanks [@&#8203;maxpatiiuk](https://redirect.github.com/maxpatiiuk)! - Dev mode warnings are now emitted on the next microtask after package import, allowing for a wider opportunity to suppress the warnings by consumers.

##### Patch Changes

-   [#&#8203;4956](https://redirect.github.com/lit/lit/pull/4956) [`0a9bc720`](https://redirect.github.com/lit/lit/commit/0a9bc72016812f3c3cfb00e1e41e1cae418dde0b) Thanks [@&#8203;louis-bompart](https://redirect.github.com/louis-bompart)! - Import barrels explicitly for compatibility with modern Node resolution w/ ESM

</details>

<details>
<summary>lucide-icons/lucide (lucide-react)</summary>

### [`v0.488.0`](https://redirect.github.com/lucide-icons/lucide/releases/tag/0.488.0): Version 0.488.0

[Compare Source](https://redirect.github.com/lucide-icons/lucide/compare/0.487.0...0.488.0)

##### What's Changed

-   docs(readme): fix packages table by [@&#8203;realguse](https://redirect.github.com/realguse) in [https://github.com/lucide-icons/lucide/pull/2976](https://redirect.github.com/lucide-icons/lucide/pull/2976)
-   fix(dev): point urls on packages page to correct page by [@&#8203;briz123](https://redirect.github.com/briz123) in [https://github.com/lucide-icons/lucide/pull/2983](https://redirect.github.com/lucide-icons/lucide/pull/2983)
-   build(deps-dev): bump vite from 5.4.14 to 5.4.15 by [@&#8203;dependabot](https://redirect.github.com/dependabot) in [https://github.com/lucide-icons/lucide/pull/2946](https://redirect.github.com/lucide-icons/lucide/pull/2946)
-   Typo fix for [@&#8203;lucide/astro](https://redirect.github.com/lucide/astro) badge by [@&#8203;dotspencer](https://redirect.github.com/dotspencer) in [https://github.com/lucide-icons/lucide/pull/3004](https://redirect.github.com/lucide-icons/lucide/pull/3004)
-   removed flutter package link by [@&#8203;shamaamahh](https://redirect.github.com/shamaamahh) in [https://github.com/lucide-icons/lucide/pull/2999](https://redirect.github.com/lucide-icons/lucide/pull/2999)
-   feat(ci): added npm package provenance attestation by [@&#8203;jguddas](https://redirect.github.com/jguddas) in [https://github.com/lucide-icons/lucide/pull/3016](https://redirect.github.com/lucide-icons/lucide/pull/3016)
-   fix(icons): changed `text` icon by [@&#8203;jguddas](https://redirect.github.com/jguddas) in [https://github.com/lucide-icons/lucide/pull/3029](https://redirect.github.com/lucide-icons/lucide/pull/3029)
-   fix(icons): changed `letter-text` icon by [@&#8203;jguddas](https://redirect.github.com/jguddas) in [https://github.com/lucide-icons/lucide/pull/3030](https://redirect.github.com/lucide-icons/lucide/pull/3030)
-   fix(icons): changed `text-select` icon by [@&#8203;jguddas](https://redirect.github.com/jguddas) in [https://github.com/lucide-icons/lucide/pull/3028](https://redirect.github.com/lucide-icons/lucide/pull/3028)

##### New Contributors

-   [@&#8203;dotspencer](https://redirect.github.com/dotspencer) made their first contribution in [https://github.com/lucide-icons/lucide/pull/3004](https://redirect.github.com/lucide-icons/lucide/pull/3004)
-   [@&#8203;shamaamahh](https://redirect.github.com/shamaamahh) made their first contribution in [https://github.com/lucide-icons/lucide/pull/2999](https://redirect.github.com/lucide-icons/lucide/pull/2999)

**Full Changelog**: https://github.com/lucide-icons/lucide/compare/0.487.0...0.488.0

</details>

<details>
<summary>mswjs/msw (msw)</summary>

### [`v2.7.4`](https://redirect.github.com/mswjs/msw/releases/tag/v2.7.4)

[Compare Source](https://redirect.github.com/mswjs/msw/compare/v2.7.3...v2.7.4)

#### v2.7.4 (2025-04-12)

##### Bug Fixes

-   resolve relative URLs against `location.href` ([#&#8203;2471](https://redirect.github.com/mswjs/msw/issues/2471)) ([`fa9b07f`](https://redirect.github.com/mswjs/msw/commit/fa9b07f7b98ed2f5e2ef53a5ee0c2daa6770a256)) [@&#8203;kettanaito](https://redirect.github.com/kettanaito)
-   **graphql:** add `extensions` property to the `GraphQLResponseBody` type ([#&#8203;2468](https://redirect.github.com/mswjs/msw/issues/2468)) ([`827a5dc`](https://redirect.github.com/mswjs/msw/commit/827a5dc0552f0c07822c0b178c85d6bca3d3bd6c)) [@&#8203;ytoshiki](https://redirect.github.com/ytoshiki)

</details>

<details>
<summary>nodemailer/nodemailer (nodemailer)</summary>

### [`v6.10.1`](https://redirect.github.com/nodemailer/nodemailer/blob/HEAD/CHANGELOG.md#6101-2025-02-06)

[Compare Source](https://redirect.github.com/nodemailer/nodemailer/compare/v6.10.0...v6.10.1)

##### Bug Fixes

-   close correct socket ([a18062c](https://redirect.github.com/nodemailer/nodemailer/commit/a18062c04d0e05ca4357fbe8f0a59b690fa5391e))

</details>

<details>
<summary>gpbl/react-day-picker (react-day-picker)</summary>

### [`v9.6.6`](https://redirect.github.com/gpbl/react-day-picker/releases/tag/v9.6.6)

[Compare Source](https://redirect.github.com/gpbl/react-day-picker/compare/v9.6.5...v9.6.6)

Includes a fix for `autoFocus` prop not correctly autofocusing the selected day.

#### What's Changed

-   fix: calculateFocusTarget logic by [@&#8203;rodgobbi](https://redirect.github.com/rodgobbi) in [https://github.com/gpbl/react-day-picker/pull/2727](https://redirect.github.com/gpbl/react-day-picker/pull/2727)

**Full Changelog**: https://github.com/gpbl/react-day-picker/compare/v9.6.5...v9.6.6

</details>

<details>
<summary>launchbadge/sqlx (sqlx)</summary>

### [`v0.8.4`](https://redirect.github.com/launchbadge/sqlx/blob/HEAD/CHANGELOG.md#084---2025-04-13)

50 pull requests were merged this release cycle.

As of this release, development of `0.9.0` has begun on `main`.
Barring urgent hotfixes, this is expected to be the last release of `0.8.x`.

##### Added

-   \[[#&#8203;3603]]: Added missing special casing for encoding embedded arrays of custom types \[\[[@&#8203;nico-incubiq](https://redirect.github.com/nico-incubiq)]]
-   \[[#&#8203;3625]]: feat(sqlite): add preupdate hook \[\[[@&#8203;aschey](https://redirect.github.com/aschey)]]
-   \[[#&#8203;3655]]: docs: add example for postgres enums with type TEXT \[\[[@&#8203;tisonkun](https://redirect.github.com/tisonkun)]]
-   \[[#&#8203;3677]]: Add json(nullable) macro attribute \[\[[@&#8203;seanaye](https://redirect.github.com/seanaye)]]
-   \[[#&#8203;3687]]: Derive clone and debug for postgresql arguments \[\[[@&#8203;remysaissy](https://redirect.github.com/remysaissy)]]
-   \[[#&#8203;3690]]: feat: add postres geometry line segment \[\[[@&#8203;jayy-lmao](https://redirect.github.com/jayy-lmao)]]
-   \[[#&#8203;3707]]: feat(Sqlite): add LockedSqliteHandle::last_error \[\[[@&#8203;joeydewaal](https://redirect.github.com/joeydewaal)]]
-   \[[#&#8203;3710]]: feat: add ipnet support \[\[[@&#8203;BeauGieskens](https://redirect.github.com/BeauGieskens)]]
-   \[[#&#8203;3711]]: feat(postgres): add geometry box \[\[[@&#8203;jayy-lmao](https://redirect.github.com/jayy-lmao)]]
-   \[[#&#8203;3714]]: chore: expose bstr feature \[\[[@&#8203;joeydewaal](https://redirect.github.com/joeydewaal)]]
-   \[[#&#8203;3716]]: feat(postgres): add geometry path \[\[[@&#8203;jayy-lmao](https://redirect.github.com/jayy-lmao)]]
-   \[[#&#8203;3724]]: feat(sqlx-cli): Add flag to disable automatic loading of .env files \[\[[@&#8203;benwilber](https://redirect.github.com/benwilber)]]
-   \[[#&#8203;3734]]: QueryBuilder: add debug_assert when `push_values` is passed an empty set of tuples \[\[[@&#8203;chanmaoganda](https://redirect.github.com/chanmaoganda)]]
-   \[[#&#8203;3745]]: feat: sqlx sqlite expose de/serialize \[\[[@&#8203;mattrighetti](https://redirect.github.com/mattrighetti)]]
-   \[[#&#8203;3765]]: Merge of [#&#8203;3427](https://redirect.github.com/launchbadge/sqlx/issues/3427) (by [@&#8203;mpyw](https://redirect.github.com/mpyw)) and [#&#8203;3614](https://redirect.github.com/launchbadge/sqlx/issues/3614) (by [@&#8203;bonsairobo](https://redirect.github.com/bonsairobo)) \[\[[@&#8203;abonander](https://redirect.github.com/abonander)]]
    -   \[[#&#8203;3427]] Expose `transaction_depth` through `get_transaction_depth()` method \[\[[@&#8203;mpyw](https://redirect.github.com/mpyw)]]
        -   Changed to `Connection::is_in_transaction` in \[[#&#8203;3765]]
    -   \[[#&#8203;3614]] Add `begin_with` methods to support database-specific transaction options \[\[[@&#8203;bonsairobo](https://redirect.github.com/bonsairobo)]]
-   \[[#&#8203;3769]]: feat(postgres): add geometry polygon \[\[[@&#8203;jayy-lmao](https://redirect.github.com/jayy-lmao)]]
-   \[[#&#8203;3773]]: feat(postgres): add geometry circle \[\[[@&#8203;jayy-lmao](https://redirect.github.com/jayy-lmao)]]

##### Changed

-   \[[#&#8203;3665]]: build(deps): bump semver compatible dependencies \[\[[@&#8203;paolobarbolini](https://redirect.github.com/paolobarbolini)]]
-   \[[#&#8203;3669]]: refactor(cli): replace promptly with dialoguer \[\[[@&#8203;paolobarbolini](https://redirect.github.com/paolobarbolini)]]
-   \[[#&#8203;3672]]: add `#[track_caller]` to `Row::get()` \[\[[@&#8203;karambarakat](https://redirect.github.com/karambarakat)]]
-   \[[#&#8203;3708]]: chore(MySql): Remove unnecessary box \[\[[@&#8203;joeydewaal](https://redirect.github.com/joeydewaal)]]
-   \[[#&#8203;3715]]: chore: add pg_copy regression tests \[\[[@&#8203;joeydewaal](https://redirect.github.com/joeydewaal)]]
-   \[[#&#8203;3721]]: Replace some `futures-core` / `futures-util` APIs with `std` variants \[\[[@&#8203;paolobarbolini](https://redirect.github.com/paolobarbolini)]]
-   \[[#&#8203;3725]]: chore: replace rustls-pemfile with rustls-pki-types \[\[[@&#8203;tottoto](https://redirect.github.com/tottoto)]]
-   \[[#&#8203;3754]]: chore(cli): remove unused async-trait crate from dependencies \[\[[@&#8203;tottoto](https://redirect.github.com/tottoto)]]
-   \[[#&#8203;3762]]: docs(pool): recommend actix-web ThinData over Data to avoid two Arcs \[\[[@&#8203;jonasmalacofilho](https://redirect.github.com/jonasmalacofilho)]]

##### Fixed

-   \[[#&#8203;3289]]: Always set `SQLITE_OPEN_URI` on in-memory sqlite \[\[[@&#8203;LecrisUT](https://redirect.github.com/LecrisUT)]]
-   \[[#&#8203;3334]]: Fix: nextest cleanup race condition \[\[[@&#8203;bonega](https://redirect.github.com/bonega)]]
-   \[[#&#8203;3666]]: fix(cli): running tests on 32bit platforms \[\[[@&#8203;paolobarbolini](https://redirect.github.com/paolobarbolini)]]
-   \[[#&#8203;3686]]: fix: handle nullable values by printing NULL instead of panicking \[\[[@&#8203;joeydewaal](https://redirect.github.com/joeydewaal)]]
-   \[[#&#8203;3700]]: fix(Sqlite): stop sending rows after first error \[\[[@&#8203;joeydewaal](https://redirect.github.com/joeydewaal)]]
-   \[[#&#8203;3701]]: fix(postgres) use signed int for length prefix in `PgCopyIn` \[\[[@&#8203;joeydewaal](https://redirect.github.com/joeydewaal)]]
-   \[[#&#8203;3703]]: fix(Postgres) chunk pg_copy data \[\[[@&#8203;joeydewaal](https://redirect.github.com/joeydewaal)]]
-   \[[#&#8203;3712]]: FromRow: Fix documentation order \[\[[@&#8203;Turbo87](https://redirect.github.com/Turbo87)]]
-   \[[#&#8203;3720]]: Fix readme: uuid feature is gating for all repos \[\[[@&#8203;jthacker](https://redirect.github.com/jthacker)]]
-   \[[#&#8203;3728]]: postgres: Fix tracing span when dropping PgListener \[\[[@&#8203;chitoku-k](https://redirect.github.com/chitoku-k)]]
-   \[[#&#8203;3741]]: Fix example calculation in docs \[\[[@&#8203;dns2utf8](https://redirect.github.com/dns2utf8)]]
-   \[[#&#8203;3749]]: docs: add some missing backticks \[\[[@&#8203;soulwa](https://redirect.github.com/soulwa)]]
-   \[[#&#8203;3753]]: Avoid privilege requirements by using an advisory lock in test setup (postgres). \[\[[@&#8203;kildrens](https://redirect.github.com/kildrens)]]
-   \[[#&#8203;3755]]: Fix FromRow docs for tuples \[\[[@&#8203;xvapx](https://redirect.github.com/xvapx)]]
-   \[[#&#8203;3768]]: chore(Sqlite): remove ci.db from repo \[\[[@&#8203;joeydewaal](https://redirect.github.com/joeydewaal)]]
-   \[[#&#8203;3771]]: fix(ci): breakage from Rustup 1.28 \[\[[@&#8203;abonander](https://redirect.github.com/abonander)]]
-   \[[#&#8203;3786]]: Fix a copy-paste error on get_username docs \[\[[@&#8203;sulami](https://redirect.github.com/sulami)]]
-   \[[#&#8203;3801]]: Fix: Enable Json type when db feature isn't enabled \[\[[@&#8203;thriller08](https://redirect.github.com/thriller08)]]
-   \[[#&#8203;3809]]: fix: PgConnectOptions docs \[\[[@&#820

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4yMzguMCIsInVwZGF0ZWRJblZlciI6IjM5LjIzOC4wIiwidGFyZ2V0QnJhbmNoIjoiY2FuYXJ5IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyJdfQ==-->
2025-04-14 07:07:39 +00:00
renovate 2fd2c149a5 chore: bump up tldts version to v7 (#11662)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [tldts](https://redirect.github.com/remusao/tldts) | [`^6.1.68` -> `^7.0.0`](https://renovatebot.com/diffs/npm/tldts/6.1.85/7.0.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/tldts/7.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/tldts/7.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/tldts/6.1.85/7.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/tldts/6.1.85/7.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>remusao/tldts (tldts)</summary>

### [`v7.0.0`](https://redirect.github.com/remusao/tldts/blob/HEAD/CHANGELOG.md#v700-Sat-Apr-12-2025)

[Compare Source](https://redirect.github.com/remusao/tldts/compare/v6.1.86...v7.0.0)

##### 💥 Breaking Change

-   `tldts-core`, `tldts-tests`
    -   Fix inconsistent hostname validation in `getHostname` and `parse(url).hostname` when `validateHostname` is enabled [#&#8203;2262](https://redirect.github.com/remusao/tldts/pull/2262) ([@&#8203;remusao](https://redirect.github.com/remusao))

##### Authors: 1

-   Rémi ([@&#8203;remusao](https://redirect.github.com/remusao))

***

### [`v6.1.86`](https://redirect.github.com/remusao/tldts/blob/HEAD/CHANGELOG.md#v6186-Sat-Apr-12-2025)

[Compare Source](https://redirect.github.com/remusao/tldts/compare/v6.1.85...v6.1.86)

##### 📜 Update Public Suffix List

-   `tldts-experimental`, `tldts-icann`, `tldts`
    -   Update upstream public suffix list [#&#8203;2311](https://redirect.github.com/remusao/tldts/pull/2311) ([@&#8203;remusao](https://redirect.github.com/remusao))

##### 🔩 Dependencies

-   Bump axios from 1.7.7 to 1.8.4 [#&#8203;2318](https://redirect.github.com/remusao/tldts/pull/2318) ([@&#8203;dependabot\[bot\]](https://redirect.github.com/dependabot\[bot]))
-   Bump [@&#8203;rollup/plugin-node-resolve](https://redirect.github.com/rollup/plugin-node-resolve) from 16.0.0 to 16.0.1 [#&#8203;2303](https://redirect.github.com/remusao/tldts/pull/2303) ([@&#8203;dependabot\[bot\]](https://redirect.github.com/dependabot\[bot]))
-   Bump [@&#8203;babel/helpers](https://redirect.github.com/babel/helpers) from 7.24.7 to 7.26.10 [#&#8203;2306](https://redirect.github.com/remusao/tldts/pull/2306) ([@&#8203;dependabot\[bot\]](https://redirect.github.com/dependabot\[bot]))
-   Bump rollup from 4.34.8 to 4.39.0 [#&#8203;2314](https://redirect.github.com/remusao/tldts/pull/2314) ([@&#8203;dependabot\[bot\]](https://redirect.github.com/dependabot\[bot]))
-   Bump [@&#8203;types/node](https://redirect.github.com/types/node) from 22.13.5 to 22.14.0 [#&#8203;2315](https://redirect.github.com/remusao/tldts/pull/2315) ([@&#8203;dependabot\[bot\]](https://redirect.github.com/dependabot\[bot]))
-   Bump typescript from 5.7.3 to 5.8.3 [#&#8203;2316](https://redirect.github.com/remusao/tldts/pull/2316) ([@&#8203;dependabot\[bot\]](https://redirect.github.com/dependabot\[bot]))
-   Bump lerna from 8.2.0 to 8.2.2 [#&#8203;2317](https://redirect.github.com/remusao/tldts/pull/2317) ([@&#8203;dependabot\[bot\]](https://redirect.github.com/dependabot\[bot]))

##### Authors: 2

-   [@&#8203;dependabot\[bot\]](https://redirect.github.com/dependabot\[bot])
-   Rémi ([@&#8203;remusao](https://redirect.github.com/remusao))

***

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4yMzguMCIsInVwZGF0ZWRJblZlciI6IjM5LjIzOC4wIiwidGFyZ2V0QnJhbmNoIjoiY2FuYXJ5IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyJdfQ==-->
2025-04-14 06:29:31 +00:00
renovate be759dc118 chore: bump up oxlint version to v0.16.6 (#11664)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [oxlint](https://oxc.rs) ([source](https://redirect.github.com/oxc-project/oxc/tree/HEAD/npm/oxlint)) | [`0.16.5` -> `0.16.6`](https://renovatebot.com/diffs/npm/oxlint/0.16.5/0.16.6) | [![age](https://developer.mend.io/api/mc/badges/age/npm/oxlint/0.16.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/oxlint/0.16.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/oxlint/0.16.5/0.16.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/oxlint/0.16.5/0.16.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>oxc-project/oxc (oxlint)</summary>

### [`v0.16.6`](https://redirect.github.com/oxc-project/oxc/releases/tag/oxlint_v0.16.6): oxlint v0.16.6

[Compare Source](https://redirect.github.com/oxc-project/oxc/compare/oxlint_v0.16.5...oxlint_v0.16.6)

#### \[0.16.6] - 2025-04-14

##### Features

-   [`0370363`](https://redirect.github.com/oxc-project/oxc/commit/0370363) language_server: Switch `tower-lsp` to `tower-lsp-server` ([#&#8203;10298](https://redirect.github.com/oxc-project/oxc/issues/10298)) (Boshen)
-   [`d48e886`](https://redirect.github.com/oxc-project/oxc/commit/d48e886) linter: Add `import/group-exports` rule ([#&#8203;10330](https://redirect.github.com/oxc-project/oxc/issues/10330)) (yefan)

##### Bug Fixes

-   [`664342b`](https://redirect.github.com/oxc-project/oxc/commit/664342b) language_server: Diable nested configuration when config path is provided ([#&#8203;10385](https://redirect.github.com/oxc-project/oxc/issues/10385)) (Sysix)
-   [`04e2fd4`](https://redirect.github.com/oxc-project/oxc/commit/04e2fd4) linter: Fix false positives for `no-control-regex` ([#&#8203;10345](https://redirect.github.com/oxc-project/oxc/issues/10345)) (Cam McHenry)
-   [`e000f60`](https://redirect.github.com/oxc-project/oxc/commit/e000f60) linter: Make extended configs properly inherit plugins ([#&#8203;10174](https://redirect.github.com/oxc-project/oxc/issues/10174)) (Sub)
-   [`81867c4`](https://redirect.github.com/oxc-project/oxc/commit/81867c4) linter: Fix stack overflow in react/exhaustive deps ([#&#8203;10322](https://redirect.github.com/oxc-project/oxc/issues/10322)) (camc314)
-   [`9aaba69`](https://redirect.github.com/oxc-project/oxc/commit/9aaba69) linter: Nested configuration directory resolution ([#&#8203;10157](https://redirect.github.com/oxc-project/oxc/issues/10157)) (Sub)

##### Performance

-   [`e0057c3`](https://redirect.github.com/oxc-project/oxc/commit/e0057c3) language_server: Only restart internal linter once when multiple config changes detected ([#&#8203;10256](https://redirect.github.com/oxc-project/oxc/issues/10256)) (Sysix)
-   [`1bb61c6`](https://redirect.github.com/oxc-project/oxc/commit/1bb61c6) linter: Replace `phf_set` with `array` in `unicorn/prefer-native-coercion-functions` ([#&#8203;10384](https://redirect.github.com/oxc-project/oxc/issues/10384)) (shulaoda)
-   [`e1e7a19`](https://redirect.github.com/oxc-project/oxc/commit/e1e7a19) linter: Replace `phf_set` with `array` in `unicorn/no-array-for-each` ([#&#8203;10377](https://redirect.github.com/oxc-project/oxc/issues/10377)) (dalaoshu)
-   [`5f0e66c`](https://redirect.github.com/oxc-project/oxc/commit/5f0e66c) linter: Replace `phf_set` with `array` in `unicorn/prefer-spread` ([#&#8203;10376](https://redirect.github.com/oxc-project/oxc/issues/10376)) (dalaoshu)
-   [`8d9559d`](https://redirect.github.com/oxc-project/oxc/commit/8d9559d) linter: Replace `phf_set` with `array` in `react/jsx-key` ([#&#8203;10375](https://redirect.github.com/oxc-project/oxc/issues/10375)) (dalaoshu)
-   [`fbd4f92`](https://redirect.github.com/oxc-project/oxc/commit/fbd4f92) linter: Replace `phf_set` with `array` in `utils::jest` ([#&#8203;10369](https://redirect.github.com/oxc-project/oxc/issues/10369)) (shulaoda)
-   [`8d0eb33`](https://redirect.github.com/oxc-project/oxc/commit/8d0eb33) linter: Replace `phf_set` with `array` in `utils::express` ([#&#8203;10370](https://redirect.github.com/oxc-project/oxc/issues/10370)) (shulaoda)
-   [`ba538ff`](https://redirect.github.com/oxc-project/oxc/commit/ba538ff) linter: Use `binary_search` for arrays with more than `7` elements ([#&#8203;10357](https://redirect.github.com/oxc-project/oxc/issues/10357)) (shulaoda)
-   [`283e4c7`](https://redirect.github.com/oxc-project/oxc/commit/283e4c7) linter: Replace `phf_set` with `array` in `react/exhaustive-deps` ([#&#8203;10337](https://redirect.github.com/oxc-project/oxc/issues/10337)) (shulaoda)
-   [`8b8d708`](https://redirect.github.com/oxc-project/oxc/commit/8b8d708) linter: Replace `phf_set` with `array` in `nextjs/no-typos` ([#&#8203;10336](https://redirect.github.com/oxc-project/oxc/issues/10336)) (shulaoda)
-   [`0fd93d6`](https://redirect.github.com/oxc-project/oxc/commit/0fd93d6) linter: Replace `phf_set` with `array` in `utils::promise` ([#&#8203;10335](https://redirect.github.com/oxc-project/oxc/issues/10335)) (shulaoda)
-   [`485ba19`](https://redirect.github.com/oxc-project/oxc/commit/485ba19) linter: Replace `phf_set` with `array` in `jest/prefer-jest-mocked` ([#&#8203;10302](https://redirect.github.com/oxc-project/oxc/issues/10302)) (shulaoda)
-   [`83931ec`](https://redirect.github.com/oxc-project/oxc/commit/83931ec) linter: Replace `phf_set` with `array` in `jsdoc/check-access` ([#&#8203;10303](https://redirect.github.com/oxc-project/oxc/issues/10303)) (shulaoda)
-   [`651b56f`](https://redirect.github.com/oxc-project/oxc/commit/651b56f) linter: Replace `phf_set` with `array` in `jsdoc/empty-tags` ([#&#8203;10304](https://redirect.github.com/oxc-project/oxc/issues/10304)) (shulaoda)
-   [`7ffb7aa`](https://redirect.github.com/oxc-project/oxc/commit/7ffb7aa) linter: Replace `phf_set` with `array` in `jsdoc/require-returns` ([#&#8203;10305](https://redirect.github.com/oxc-project/oxc/issues/10305)) (shulaoda)
-   [`d7399c4`](https://redirect.github.com/oxc-project/oxc/commit/d7399c4) linter: Replace `phf_set` with `array` in `jsx-a11y/no-noninteractive-tabindex` ([#&#8203;10306](https://redirect.github.com/oxc-project/oxc/issues/10306)) (shulaoda)
-   [`afe663b`](https://redirect.github.com/oxc-project/oxc/commit/afe663b) linter: Replace `phf_set` with `array` in `jest/no-restricted-matchers` ([#&#8203;10297](https://redirect.github.com/oxc-project/oxc/issues/10297)) (shulaoda)
-   [`bd27959`](https://redirect.github.com/oxc-project/oxc/commit/bd27959) linter: Replace `phf_set` with `array` in `eslint/array-callback-return` ([#&#8203;10296](https://redirect.github.com/oxc-project/oxc/issues/10296)) (shulaoda)
-   [`1aa0d71`](https://redirect.github.com/oxc-project/oxc/commit/1aa0d71) linter: Replace `phf_set` with `array` in `react/no-array-index-key` ([#&#8203;10294](https://redirect.github.com/oxc-project/oxc/issues/10294)) (shulaoda)
-   [`d9c4891`](https://redirect.github.com/oxc-project/oxc/commit/d9c4891) linter: Replace `phf_set` with `array` in `eslint/valid-typeof` ([#&#8203;10293](https://redirect.github.com/oxc-project/oxc/issues/10293)) (shulaoda)

##### Refactor

-   [`a95ba40`](https://redirect.github.com/oxc-project/oxc/commit/a95ba40) language_server: Make server more error resistance by falling back to default config ([#&#8203;10257](https://redirect.github.com/oxc-project/oxc/issues/10257)) (Sysix)
-   [`2e1ef4c`](https://redirect.github.com/oxc-project/oxc/commit/2e1ef4c) linter: Extract common logic from `jsdoc/require-yields` and `jsdoc/require-returns` ([#&#8203;10383](https://redirect.github.com/oxc-project/oxc/issues/10383)) (shulaoda)
-   [`9533d09`](https://redirect.github.com/oxc-project/oxc/commit/9533d09) linter: Remove duplicate ARIA property lists ([#&#8203;10326](https://redirect.github.com/oxc-project/oxc/issues/10326)) (camchenry)
-   [`67bd7aa`](https://redirect.github.com/oxc-project/oxc/commit/67bd7aa) linter: Add `AriaProperty` enum ([#&#8203;10325](https://redirect.github.com/oxc-project/oxc/issues/10325)) (camchenry)
-   [`52ea978`](https://redirect.github.com/oxc-project/oxc/commit/52ea978) linter: Update comments, improve tests, add variant All to LintFilterKind ([#&#8203;10259](https://redirect.github.com/oxc-project/oxc/issues/10259)) (Ulrich Stark)

##### Testing

-   [`62f7d76`](https://redirect.github.com/oxc-project/oxc/commit/62f7d76) editor: Refactor tests to use fixtures ([#&#8203;10381](https://redirect.github.com/oxc-project/oxc/issues/10381)) (Sysix)
-   [`4a6bb21`](https://redirect.github.com/oxc-project/oxc/commit/4a6bb21) language_server: Add test for `import` plugin integration ([#&#8203;10364](https://redirect.github.com/oxc-project/oxc/issues/10364)) (Sysix)
-   [`aa6ccd2`](https://redirect.github.com/oxc-project/oxc/commit/aa6ccd2) oxlint: Add test for nested and extended configuration with import plugin ([#&#8203;10372](https://redirect.github.com/oxc-project/oxc/issues/10372)) (Sysix)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4yMzguMCIsInVwZGF0ZWRJblZlciI6IjM5LjIzOC4wIiwidGFyZ2V0QnJhbmNoIjoiY2FuYXJ5IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyJdfQ==-->
2025-04-14 06:13:38 +00:00
Aki Chang 00bd05897e feat(android): ai chat scaffold (#11124)
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: eyhn <cneyhn@gmail.com>
2025-04-14 06:05:47 +00:00
renovate 08dbaae19b chore: bump up jotai-effect version to v2 (#10262)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [jotai-effect](https://jotai.org/docs/extensions/effect) ([source](https://redirect.github.com/jotaijs/jotai-effect)) | [`^1.0.5` -> `^2.0.0`](https://renovatebot.com/diffs/npm/jotai-effect/1.1.6/2.0.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/jotai-effect/2.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/jotai-effect/2.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/jotai-effect/1.1.6/2.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/jotai-effect/1.1.6/2.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>jotaijs/jotai-effect (jotai-effect)</summary>

### [`v2.0.1`](https://redirect.github.com/jotaijs/jotai-effect/compare/v2.0.0...v2.0.1)

[Compare Source](https://redirect.github.com/jotaijs/jotai-effect/compare/v2.0.0...v2.0.1)

### [`v2.0.0`](https://redirect.github.com/jotaijs/jotai-effect/releases/tag/v2.0.0)

[Compare Source](https://redirect.github.com/jotaijs/jotai-effect/compare/v1.1.6...v2.0.0)

We’re excited to announce the release of **jotai-effect v2**, which brings a single but significant change to the core API: **`atomEffect` now runs synchronously** whenever it mounts or its dependencies change. This update improves consistency, helps avoid race conditions, and keeps related state changes in sync.

***

#### What’s New?

##### Synchronous `atomEffect`

-   In v1, `atomEffect` would run **asynchronously** in the next microtask.
-   In v2, `atomEffect` runs **synchronously** on mount and whenever the dependencies it uses have changed.
-   **Batching is still supported** when you update multiple dependencies in a single writable atom. The effect runs only after that writable atom has finished all its updates, preventing partial updates or intermediate states.

**Example:**

```ts
const syncEffect = atomEffect((get, set) => {
  get(someAtom)
  set(anotherAtom)
})

const store = createStore()
store.set(someAtom, (v) => v + 1)
// The effect above runs immediately, so anotherAtom is updated in the same microtask
console.log(store.get(anotherAtom)) // Updated by atomEffect synchronously
```

When `someAtom` is updated, the effect runs **immediately**, updating `anotherAtom` in the same turn. If you update multiple atoms in the same writable atom, these changes are batched together, and `atomEffect` runs after those updates complete.

***

#### Migration Guide

For most users, **no change is required**. If you depended on the old microtask delay or cross-atom batching, read on.

##### 1. Adding back the microtask delay

If your logic explicitly relied on `atomEffect` running in a separate microtask, you can reintroduce the delay yourself:

**Before (v1)**

```ts
const effect = atomEffect((get, set) => {
  console.log('effect')
  return () => {
    console.log('cleanup')
  }
})
```

**After (v2)**

```ts
const effect = atomEffect((get, set) => {
  queueMicrotask(() => {
    console.log('effect')
  })
  return () => {
    queueMicrotask(() => {
      console.log('cleanup')
    })
  }
})
```

##### 2. Batching updates

In v1, updates to separate atoms were implicitly batched in the next microtask. In v2, **batching only occurs within a single writable atom update**:

**Before (v1)**

```ts
store.set(atomA, (v) => v + 1)
store.set(atomB, (v) => v + 1)
// atomEffect would 'see' both changes together in the next microtask
```

**After (v2)**

```ts
const actionAtom = atom(null, (get, set) => {
  set(atomA, (v) => v + 1)
  set(atomB, (v) => v + 1)
})

store.set(actionAtom)
// atomEffect now runs after both updates, in one batch
```

***

##### A Special Thanks to Daishi Kato

I’d like to extend my deepest gratitude to **Daishi Kato**, author of Jotai. Daishi dedicated months of tireless work to rework and rewrite significant parts of the Jotai core—primarily to empower community library authors such as myself to implement features such as **synchronous effects** in jotai-effect. His willingness to refine Jotai’s internals and his thoughtfulness in API design made this effort possible. Thank you.

##### Final Thoughts

-   **Most code will just work** without any changes.
-   If you have specialized scenarios relying on microtask delays or separate updates to multiple atoms, you’ll need to wrap them in a single writable atom or manually queue the microtask.

We hope these improvements make your state management more predictable and easier to reason about. If you have any issues, please feel free to open a GitHub [Discussion](https://redirect.github.com/jotaijs/jotai-effect/discussions). Happy coding!

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xNjcuMSIsInVwZGF0ZWRJblZlciI6IjM5LjE2Ny4xIiwidGFyZ2V0QnJhbmNoIjoiY2FuYXJ5IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyJdfQ==-->
2025-04-14 05:34:38 +00:00
renovate 1ab9f1376d chore: bump up nestjs (#11658)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [@nestjs/apollo](https://redirect.github.com/nestjs/graphql) | [`13.0.4` -> `13.1.0`](https://renovatebot.com/diffs/npm/@nestjs%2fapollo/13.0.4/13.1.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fapollo/13.1.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@nestjs%2fapollo/13.1.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@nestjs%2fapollo/13.0.4/13.1.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fapollo/13.0.4/13.1.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@nestjs/core](https://nestjs.com) ([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/core)) | [`11.0.15` -> `11.0.16`](https://renovatebot.com/diffs/npm/@nestjs%2fcore/11.0.15/11.0.16) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fcore/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@nestjs%2fcore/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@nestjs%2fcore/11.0.15/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fcore/11.0.15/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@nestjs/graphql](https://redirect.github.com/nestjs/graphql) | [`13.0.4` -> `13.1.0`](https://renovatebot.com/diffs/npm/@nestjs%2fgraphql/13.0.4/13.1.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fgraphql/13.1.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@nestjs%2fgraphql/13.1.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@nestjs%2fgraphql/13.0.4/13.1.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fgraphql/13.0.4/13.1.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@nestjs/platform-express](https://nestjs.com) ([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/platform-express)) | [`11.0.15` -> `11.0.16`](https://renovatebot.com/diffs/npm/@nestjs%2fplatform-express/11.0.15/11.0.16) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fplatform-express/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@nestjs%2fplatform-express/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@nestjs%2fplatform-express/11.0.15/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fplatform-express/11.0.15/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@nestjs/platform-socket.io](https://nestjs.com) ([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/platform-socket.io)) | [`11.0.15` -> `11.0.16`](https://renovatebot.com/diffs/npm/@nestjs%2fplatform-socket.io/11.0.15/11.0.16) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fplatform-socket.io/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@nestjs%2fplatform-socket.io/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@nestjs%2fplatform-socket.io/11.0.15/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fplatform-socket.io/11.0.15/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@nestjs/websockets](https://redirect.github.com/nestjs/nest) ([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/websockets)) | [`11.0.15` -> `11.0.16`](https://renovatebot.com/diffs/npm/@nestjs%2fwebsockets/11.0.15/11.0.16) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fwebsockets/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@nestjs%2fwebsockets/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@nestjs%2fwebsockets/11.0.15/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fwebsockets/11.0.15/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>nestjs/graphql (@&#8203;nestjs/apollo)</summary>

### [`v13.1.0`](https://redirect.github.com/nestjs/graphql/releases/tag/v13.1.0)

[Compare Source](https://redirect.github.com/nestjs/graphql/compare/v13.0.4...v13.1.0)

##### 13.1.0 (2025-04-11)

##### Enhancements

-   `apollo`
    -   [#&#8203;3544](https://redirect.github.com/nestjs/graphql/pull/3544) feat(apollo): add graphiql playground support ([@&#8203;kamilmysliwiec](https://redirect.github.com/kamilmysliwiec))

##### Committers: 1

-   Kamil Mysliwiec ([@&#8203;kamilmysliwiec](https://redirect.github.com/kamilmysliwiec))

</details>

<details>
<summary>nestjs/nest (@&#8203;nestjs/core)</summary>

### [`v11.0.16`](https://redirect.github.com/nestjs/nest/compare/v11.0.15...v11.0.16)

[Compare Source](https://redirect.github.com/nestjs/nest/compare/v11.0.15...v11.0.16)

</details>

<details>
<summary>nestjs/nest (@&#8203;nestjs/platform-express)</summary>

### [`v11.0.16`](https://redirect.github.com/nestjs/nest/compare/v11.0.15...v11.0.16)

[Compare Source](https://redirect.github.com/nestjs/nest/compare/v11.0.15...v11.0.16)

</details>

<details>
<summary>nestjs/nest (@&#8203;nestjs/platform-socket.io)</summary>

### [`v11.0.16`](https://redirect.github.com/nestjs/nest/releases/tag/v11.0.16)

[Compare Source](https://redirect.github.com/nestjs/nest/compare/v11.0.15...v11.0.16)

#### v11.0.16 (2025-04-11)

-   fix(common): use `file-type` to validate file mimetypes by [@&#8203;Chathula](https://redirect.github.com/Chathula) in [https://github.com/nestjs/nest/pull/14881](https://redirect.github.com/nestjs/nest/pull/14881)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4yMzguMCIsInVwZGF0ZWRJblZlciI6IjM5LjIzOC4wIiwidGFyZ2V0QnJhbmNoIjoiY2FuYXJ5IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyJdfQ==-->
2025-04-14 02:57:54 +00:00
yoyoyohamapi d494394c8d test(core): common setup for ai tests (#11644)
### TL:DR

By sharing initialization logic, accelerate test case execution.

### What Changed

* Global setup for copilot e2e
  * Login
  * Create Workspace
* Enable fully parallel for ci

### Optimization Comparison​

Comparing with PR [fix(core): ask AI input box in the whiteboard is blocked by the menu …](https://github.com/toeverything/AFFiNE/pull/11634):

|           |    Shard 1   |2|3|4|5|6|7|8|
| ------|----|----|----|----|----|---|---|--|
|Before|15min|14min|14min|14min|14min|13min|15min|10min|
|After|8min|11min|8min|8min|8min|8min|8min|7min|

### Trade-Off

Since all copilot use cases currently share a single user and workspace, some test cases need to focus on **isolation** and **independence**.
For example, when testing Embedding-related workflows:
* Different document contents should be used to avoid interference.
* After each test case execution, **cleanup** operations are also required.
* Some tests should be configured to **serial** mode.

```ts
test.describe.configure({ mode: 'serial' });

test.describe('AIChatWith/Collections', () => {
  test.beforeEach(async ({ loggedInPage: page, utils }) => {
    await utils.testUtils.setupTestEnvironment(page);
    await utils.chatPanel.openChatPanel(page);
    await utils.editor.clearAllCollections(page);

    await utils.testUtils.createNewPage(page);
  });

  test.afterEach(async ({ loggedInPage: page, utils }) => {
    // clear all collections
    await utils.editor.clearAllCollections(page);
  });

  test('should support chat with collection', async ({
    loggedInPage: page,
    utils,
  }) => {
    // Create two collections
    await utils.editor.createCollectionAndDoc(
      page,
      'Collection 1',
      'CollectionAAaa is a cute dog'
    );

    await utils.chatPanel.chatWithCollections(page, ['Collection 1']);
    await utils.chatPanel.makeChat(page, 'What is CollectionAAaa(Use English)');
    // ...
  });

  test('should support chat with multiple collections', async ({
    loggedInPage: page,
    utils,
  }) => {
    // Create two collections
    await utils.editor.createCollectionAndDoc(
      page,
      'Collection 2',
      'CollectionEEee is a cute cat'
    );

    await utils.editor.createCollectionAndDoc(
      page,
      'Collection 3',
      'CollectionFFff is a cute dog'
    );

    await utils.chatPanel.chatWithCollections(page, [
      'Collection 2',
      'Collection 3',
    ]);
    await utils.chatPanel.makeChat(
      page,
      'What is CollectionEEee? What is CollectionFFff?(Use English)'
    );
    // ...
  });
});

```

> CLOSE AI-51
2025-04-14 02:42:06 +00:00
renovate 11d1b2fae5 chore: bump up @nestjs/common version to v11.0.16 [SECURITY] (#11645)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [@nestjs/common](https://nestjs.com) ([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/common)) | [`11.0.15` -> `11.0.16`](https://renovatebot.com/diffs/npm/@nestjs%2fcommon/11.0.15/11.0.16) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fcommon/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@nestjs%2fcommon/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@nestjs%2fcommon/11.0.15/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fcommon/11.0.15/11.0.16?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

### GitHub Vulnerability Alerts

#### [CVE-2024-29409](https://nvd.nist.gov/vuln/detail/CVE-2024-29409)

File Upload vulnerability in nestjs nest prior to v.11.0.16 allows a remote attacker to execute arbitrary code via the Content-Type header.

---

### Release Notes

<details>
<summary>nestjs/nest (@&#8203;nestjs/common)</summary>

### [`v11.0.16`](https://redirect.github.com/nestjs/nest/compare/v11.0.15...v11.0.16)

[Compare Source](https://redirect.github.com/nestjs/nest/compare/v11.0.15...v11.0.16)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "" (UTC), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4yMzguMCIsInVwZGF0ZWRJblZlciI6IjM5LjIzOC4wIiwidGFyZ2V0QnJhbmNoIjoiY2FuYXJ5IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyJdfQ==-->
2025-04-14 02:18:12 +00:00
renovate 1fc51bf95e chore: bump up animejs version to v4 (#11466)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [animejs](https://animejs.com) ([source](https://redirect.github.com/juliangarnier/anime)) | [`^3.2.2` -> `^4.0.0`](https://renovatebot.com/diffs/npm/animejs/3.2.2/4.0.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/animejs/4.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/animejs/4.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/animejs/3.2.2/4.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/animejs/3.2.2/4.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>juliangarnier/anime (animejs)</summary>

### [`v4.0.0`](https://redirect.github.com/juliangarnier/anime/releases/tag/4.0.0)

[Compare Source](https://redirect.github.com/juliangarnier/anime/compare/v3.2.2...4.0.0)

> **I'm still finalizing the release notes as there are MANY changes, but in the meantime, you can check out the brand new documentation [here](https://animejs.com/documentation).**

The brand new Anime.js.

### API Breaking changes

Every Anime.js feature is now exported as an ES Module.
This is great for tree shaking, you don't have to ship the entire library anymore, only what you need.

#### Animation

The `anime(parameters)` function has been replaced with the `animate(targets, parameters)` module.
The `targets` parameter has been replaced with a dedicated function parameter: `animate(targets, parameters)`.

V3:

```javascript
import anime from 'animejs';

const animation = anime({
  targets: 'div',
  translateX: 100,
});
```

V4:

```javascript
import { animate } from 'animejs';

const animation = animate('div', {
  translateX: 100,
});
```

#### Easings names

The `ease` prefix has been removed: 'easeInOutQuad' -> 'inOutQuad'.

#### Callbacks

Callbacks have have been renamed like this:

-   `begin()` -> `onBegin()`
-   `update()` -> `onUpdate()`

Here's all the change to the API

```diff
- import anime from 'animejs';
+ import { animate, createSpring, utils } from 'animejs';

- anime({
-   targets: 'div',
+ animate('div', {
    translateX: 100,
      rotate: {
-     value: 360,
+     to: 360,
-     easing: 'spring(.7, 80, 10, .5)',
+     ease: createSpring({ mass: .7, damping: 80, stiffness: 10, velocity: .5}),
    },
-   easing: 'easeinOutExpo',
+   ease: 'inOutExpo',
-   easing: () => t => Math.cos(t),
+   ease: t => Math.cos(t),
-   direction: 'reverse',
+   reversed: true,
-   direction: 'alternate',
+   alternate: true,
-   loop: 1,
+   loop: 0,
-   round: 100,
+   modifier: utils.round(2),
-   begin: () => {},
+   onBegin: () => {},
-   update: () => {},
+   onUpdate: () => {},
-   change: () => {},
+   onRender: () => {},
-   changeBegin: () => {},
-   changeComplete: () => {},
-   loopBegin: () => {},
-   loopComplete: () => {},
+   onLoop: () => {},
-   complete: () => {},
+   onComplete: () => {},
  });
```

#### Promises

No more `.finished` property, promises are now handled directly with `animation.then()`:

```diff
- import anime from 'animejs';
+ import { animate, utils } from 'animejs';

- anime({ targets: target, prop: x }).finished.then(() => {});
+ animate(target, { prop: x }).then(() => {});
```

#### Values

##### To

The object syntax `value` property has been renamed `to`:

```diff
- translateX: { value: 100 }
+ translateX: { to: 100 }
```

#### Animation parameters

##### Default `easing`

The new default easing is `'outQuad'` instead of `'easeOutElastic(1, .5)'`.

##### `composition`

In V3 all animations coexist and overlaps with each other. This can cause animations with the same targets and animated properties to create weird results.
V4 cancels a running tween if a new one is created on the same target with the same property. This behaviour can be confifugred using the new `composition` parameter.

`composition: 'none'` // The old V3 behaviour, animations can overlaps
`composition: 'replace'` // The new V4 default
`composition: 'add'` // Creates additive animations by adding the values of the currently running animations with the new ones

##### `round` -> `modifier`

The `round` parameter has been replaced with a more flexible parameters that allows you to define custom functions to transform the numerical value of an animation just before the rendering.

```diff
- round: 100
+ modifier: utils.round(2)
```

You can of course defines your own modifier functions like this:

```javascript
const animation = animate('div', {
  translateX: '100rem',
  modifier: v => v % 10 // Note that the unit 'rem' will automatically be passed to the rendered value
});
```

#### Playback parameters

##### `direction`

The `direction` parameter has been replaced with an `alternate` and `reversed` parameters

V3:

```javascript
const animation = anime({
  targets: 'div',
  direction: 'reverse',
  // direction: 'alternate' It wasn't possible to combined reverse and alternate direction before
});
```

V4:

```javascript
import { animate } from 'animejs';

const animation = animate('div', {
  translateX: 100,
  reversed: true,
  alternate: true,
});
```

#### Timelines:

```diff
- import anime from 'animejs';
+ import { createTimeline, stagger } from 'animejs';

- anime.timeline({
+ createTimeline({
-   duration: 500,
-   easing: 'easeInOutQuad',
+   defaults: {
+     duration: 500,
+     ease: 'inOutQuad',
+   }
-   loop: 2,
+   loop: 1,
- }).add({
-   targets: 'div',
+ }).add('div', {
    rotate: 90,
  })
- .add('.target:nth-child(1)', { opacity: 0, onComplete }, 0)
- .add('.target:nth-child(2)', { opacity: 0, onComplete }, 100)
- .add('.target:nth-child(3)', { opacity: 0, onComplete }, 200)
- .add('.target:nth-child(4)', { opacity: 0, onComplete }, 300)
+ .add('.target', { opacity: 0, onComplete }, stagger(100))
```

##### Stagger

```diff
- import anime from 'animejs';
+ import { animate, stagger } from 'animejs';

- anime({
-   targets: 'div',
+ animate('div', {
-   translateX: anime.stagger(100),
+   translateX: stagger(100),
-   delay: anime.stagger(100, { direction: 'reversed' }),
+   translateX: stagger(100, { reversed: true }),
  });
```

#### SVG

```diff
- import anime from 'animejs';
+ import { animate, svg } from 'animejs';

- const path = anime.path('path');
+ const { x, y, angle } = svg.createMotionPath('path');

- anime({
-   targets: '#shape1',
+ animate('#shape1', {
-   points: '70 41 118.574 59.369 111.145 132.631 60.855 84.631 20.426 60.369',
+   points: svg.morphTo('#shape2'),
-   strokeDashoffset: [anime.setDashoffset, 0],
+   strokeDashoffset: svg.drawLine(),
-   translateX: path('x'),
-   translateY: path('y'),
-   rotate: path('angle'),
+   translateX: x,
+   translateY: y,
+   rotate: angle,
  });
```

#### Utils

```diff
- import anime from 'animejs';
+ import { utils } from 'animejs';

- const value = anime.get('#target1', 'translateX');
+ const value = utils.get('#target1', 'translateX');

- anime.set('#target1', { translateX: 100 });
+ utils.set('#target1', { translateX: 100 });

- anime.remove('#target1');
+ utils.remove('#target1');

- const rounded = anime.round(value);
+ const rounded = utils.round(value, 0);
```

#### Engine

```diff
- import anime from 'animejs';
+ import { engine } from 'animejs';

- anime.suspendWhenDocumentHidden = false;
+ engine.pauseWhenHidden = false;

- anime.speed = .5;
+ engine.playbackRate = .5;
```

### Improvements

#### Performances

Major performance boost and lower memory footprint.
V4 has bee re-written from scratch by keeping performance in mind at every steps.

#### Better tween composition

The tween system has been refactored to improve animations behaviours when they overlaps.
This fix lots of issues, especially when creating multiple animations with the same property on the same target.

#### Additive animations

You can also blend animations together with the new `composition: 'add'` parameter.

#### Improved Timelines

-   Child animations can new be looped and reversed
-   Add supports for labels
-   Add supports for `.set()` in timeline
-   New position operators for more flexibility
-   Multi-target child animation can be positioned using the `stagger` function
-   Easier children defaults configuration
-   Greatly improved support for CSS transforms composition from one child animation to another

```javascript

const tl = createTimeline({
  playbackRate: .2,
  defaults: {
    duration: 500,
    easing: 'outQuad',
  }
});

tl.add('START', 100) // Add a label a 100ms
  .set('.target', { opacity: 0 })
  .add('.target', {
    translateY: 100,
    opacity: 1,
    onComplete: () => {},
  }, stagger(100))
  .add('.target', {
    scale: .75,
  }, 'START')
  .add('.target', {
    rotate: '1turn',
  }, '<<+=200')

```

#### Properties

##### CSS Variables

You can now use CSS variables directly like any other property:

```javascript
// Animate the values of the CSS variables '--radius'
animate('#target', { '--radius': '20px' });
```

##### Animating *from*

Animate *from* a value

```diff
+ translateX: { from: 50 }
```

##### From -> To

Even if the `[from, to]` shortcut is still valid in V4, you can now also write it like this:

```diff
+ translateX: { from: 50, to: 100 }
```

##### Colors

You can now animate hex colors with an alpha channel like '#F443' or '#FF444433'.

#### Timers

You can now create timers with the `createTimer` module.

Timers can be use as replacement for `setTimeout`or `setInterval` but with all the playbacks parameters, callbacks and the `Promise` system provided by anime.js.

```
const interval = createTimer({
  onLoop: () => { // do something every 500ms },
  duration: 500,
});

const timeout = createTimer({
  onComplete: () => { // do something in 500ms },
  duration: 500,
});

const gameLogicLoop = createTimer({
  frameRate: 30,
  onUpdate: gameSystems,
});

const gameRenderLoop = createTimer({
  frameRate: 60,
  onUpdate: gameRender,
});

```

#### Variable frame rate

You can now change the frame rate to all animations or to a specific Timeline / Animation / Timer

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4yMjcuMyIsInVwZGF0ZWRJblZlciI6IjM5LjIyNy4zIiwidGFyZ2V0QnJhbmNoIjoiY2FuYXJ5IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyJdfQ==-->
2025-04-14 01:29:09 +00:00
CatsJuice d6b4ee8172 feat(mobile): ios selfhost server support (#11563) 2025-04-14 01:13:23 +00:00
L-Sun e1cb8198f1 fix(editor): android bs keyboard provider error (#11647)
### What Changes
- fixed keyboard service can not be initialized since a anonymous `BSKeyboardWithActionService` class was provider to di
- fixed tool panel was not closed when focus on other pragraph by clicking
- optimized code structure of fallback `show` and `hide` of keyboard
2025-04-13 09:59:24 +00:00
L-Sun 076c5ba044 fix(editor): repeat trigger keys of at-menu was added (#11631)
Close [BS-2716](https://linear.app/affine-design/issue/BS-2716/移动端通过toolpanel唤起的at-menu,出现两个)
2025-04-13 06:46:37 +00:00
L-Sun 26d2ed8afb chore(editor): hide file and doc import entries for mobile (#11648)
Close [BS-2926](https://linear.app/affine-design/issue/BS-2926/【移动端-ios】-选择import,无反应)
Close [BS-2927](https://linear.app/affine-design/issue/BS-2927/【移动端-ios】隐藏toolbar上附件入口)
2025-04-13 05:32:15 +00:00
L-Sun f860f77a24 fix(editor): can not query in mobile at menu (#11649)
This PR addresses an issue where queries cannot be performed in the mobile menu, particularly on Android devices. The root cause was that the `event.key` of keypress returns 'Unidentified' on Android, which prevented proper query handling.

Changes made:
- Replaced the keydown event observer with a beforeinput event listener
- Removed unnecessary keyboard event handling code that was causing issues
2025-04-13 02:39:05 +00:00
doouding cac817c896 fix: cannot drop image as list child (#11635)
Fixes [BS-3103](https://linear.app/affine-design/issue/BS-3103/drag-and-drop-bug-白板图片无法拖动到-list-的子项下面)
2025-04-13 02:21:57 +00:00
darkskygit ac8464068d test(server): improve server copilot test (#11596) 2025-04-12 16:36:51 +08:00
donteatfriedrice 4da00eba0d fix(editor): cut and paste surface-ref to same doc should remain surface-ref (#11639)
Close [BS-3107](https://linear.app/affine-design/issue/BS-3107/剪切-surface-ref-block-会变成指向当前文档的link-card)
2025-04-12 01:56:24 +00:00
fundon afdc40b510 feat(editor): add shortcut to highlighter tool (#11604)
Closes: [BS-3092](https://linear.app/affine-design/issue/BS-3092/highlighter-快捷键)

### What's Changed!

* Added shortcut `⇧ P` to highlighter tool

[Screen Recording 2025-04-10 at 16.33.30.mov <span class="graphite__hidden">(uploaded via Graphite)</span> <img class="graphite__hidden" src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/8ypiIKZXudF5a0tIgIzf/38aadc08-ed18-4b48-9d91-b4876d14a2d3.mov" />](https://app.graphite.dev/media/video/8ypiIKZXudF5a0tIgIzf/38aadc08-ed18-4b48-9d91-b4876d14a2d3.mov)
2025-04-11 13:08:59 +00:00
L-Sun aabb09b31f fix(editor): ime input error at empty line (#11636)
Close [BS-3106](https://linear.app/affine-design/issue/BS-3106/mac-chrom在空行使用ime输入,文档卡住)
2025-04-11 10:39:16 +00:00
doodlewind e1e5e8fc14 feat(editor): add basic image support in turbo renderer (#11620)
This PR adds basic support for image block:

![image.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/lEGcysB4lFTEbCwZ8jMv/4785fc76-fe09-4002-b3fb-aafa9cac34bb.png)
2025-04-11 10:16:07 +00:00
forehalo e73d68cac4 chore(server): fix spotify link preview (#11638)
close AF-2499
2025-04-11 09:36:20 +00:00
forehalo 2f5647ac77 fix(editor): use img tag for link preview icon and banner (#11637)
close AF-2377
2025-04-11 08:48:04 +00:00
yoyoyohamapi 9c6d94f597 fix(core): hide start-with-ai if service feature is not enabled (#11633)
> CLOSE BS-3062
2025-04-11 08:31:05 +00:00
akumatus 883b1d50f2 fix(core): ask AI input box in the whiteboard is blocked by the menu (#11634)
Close [AI-50](https://linear.app/affine-design/issue/AI-50).

![截屏2025-04-11 15.27.58.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/sJGviKxfE3Ap685cl5bj/caf7a19e-7332-47bb-82c6-c5a4db0af2eb.png)
2025-04-11 08:13:00 +00:00
doouding 4e1fcca876 fix: mind map preview rendering (#11565)
Fixes [BS-3080](https://linear.app/affine-design/issue/BS-3080/ai-生成-mindmap-预览失败)
2025-04-11 07:05:36 +00:00
donteatfriedrice 74ebec007d fix(editor): surface-ref refFlavour should be affine:frame when reference to a frame (#11632) 2025-04-11 06:51:31 +00:00
Saul-Mirone 4f9a4e739a feat(editor): extract linked doc widget package (#11589)
Close [BS-2738](https://github.com/toeverything/AFFiNE/pull/11589)
2025-04-11 14:06:16 +08:00
yoyoyohamapi 149433b8d0 fix(core): cannot focus inside shape in test (#11630) 2025-04-11 05:26:27 +00:00
doodlewind a5ab66d6cd feat(editor): add basic code support in turbo renderer (#11619)
This PR adds basic support for code block:

[Screen Recording 2025-04-10 at 8.13.26 PM.mov <span class="graphite__hidden">(uploaded via Graphite)</span> <img class="graphite__hidden" src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/lEGcysB4lFTEbCwZ8jMv/5d749979-f7f1-4e4d-ba5b-bc4ba29f8b83.mov" />](https://app.graphite.dev/media/video/lEGcysB4lFTEbCwZ8jMv/5d749979-f7f1-4e4d-ba5b-bc4ba29f8b83.mov)
2025-04-11 04:28:51 +00:00
doouding 714f2e79dc fix: cannot exit editing mode when click frame body (#11603) 2025-04-11 03:23:27 +00:00
Kieran Cui bcd1cd2629 fix(editor): the switch button style set in the TOC does not effect (#11622)
Co-authored-by: Chen <99816898+donteatfriedrice@users.noreply.github.com>
2025-04-11 11:22:24 +08:00
renovate 5670eb4d02 chore: bump up opentelemetry (#11093)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [@opentelemetry/exporter-prometheus](https://redirect.github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-exporter-prometheus) ([source](https://redirect.github.com/open-telemetry/opentelemetry-js)) | [`^0.57.0` -> `^0.200.0`](https://renovatebot.com/diffs/npm/@opentelemetry%2fexporter-prometheus/0.57.2/0.200.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@opentelemetry%2fexporter-prometheus/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@opentelemetry%2fexporter-prometheus/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@opentelemetry%2fexporter-prometheus/0.57.2/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@opentelemetry%2fexporter-prometheus/0.57.2/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@opentelemetry/host-metrics](https://redirect.github.com/open-telemetry/opentelemetry-js-contrib/tree/main/packages/opentelemetry-host-metrics#readme) ([source](https://redirect.github.com/open-telemetry/opentelemetry-js-contrib)) | [`^0.35.4` -> `^0.36.0`](https://renovatebot.com/diffs/npm/@opentelemetry%2fhost-metrics/0.35.5/0.36.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@opentelemetry%2fhost-metrics/0.36.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@opentelemetry%2fhost-metrics/0.36.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@opentelemetry%2fhost-metrics/0.35.5/0.36.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@opentelemetry%2fhost-metrics/0.35.5/0.36.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@opentelemetry/instrumentation](https://redirect.github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation) ([source](https://redirect.github.com/open-telemetry/opentelemetry-js)) | [`^0.57.0` -> `^0.200.0`](https://renovatebot.com/diffs/npm/@opentelemetry%2finstrumentation/0.57.2/0.200.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@opentelemetry%2finstrumentation/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@opentelemetry%2finstrumentation/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@opentelemetry%2finstrumentation/0.57.2/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@opentelemetry%2finstrumentation/0.57.2/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@opentelemetry/instrumentation-graphql](https://redirect.github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-graphql#readme) ([source](https://redirect.github.com/open-telemetry/opentelemetry-js-contrib)) | [`^0.47.0` -> `^0.48.0`](https://renovatebot.com/diffs/npm/@opentelemetry%2finstrumentation-graphql/0.47.1/0.48.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@opentelemetry%2finstrumentation-graphql/0.48.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@opentelemetry%2finstrumentation-graphql/0.48.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@opentelemetry%2finstrumentation-graphql/0.47.1/0.48.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@opentelemetry%2finstrumentation-graphql/0.47.1/0.48.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@opentelemetry/instrumentation-http](https://redirect.github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation-http) ([source](https://redirect.github.com/open-telemetry/opentelemetry-js)) | [`^0.57.0` -> `^0.200.0`](https://renovatebot.com/diffs/npm/@opentelemetry%2finstrumentation-http/0.57.2/0.200.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@opentelemetry%2finstrumentation-http/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@opentelemetry%2finstrumentation-http/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@opentelemetry%2finstrumentation-http/0.57.2/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@opentelemetry%2finstrumentation-http/0.57.2/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@opentelemetry/instrumentation-ioredis](https://redirect.github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-ioredis#readme) ([source](https://redirect.github.com/open-telemetry/opentelemetry-js-contrib)) | [`^0.47.0` -> `^0.48.0`](https://renovatebot.com/diffs/npm/@opentelemetry%2finstrumentation-ioredis/0.47.1/0.48.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@opentelemetry%2finstrumentation-ioredis/0.48.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@opentelemetry%2finstrumentation-ioredis/0.48.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@opentelemetry%2finstrumentation-ioredis/0.47.1/0.48.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@opentelemetry%2finstrumentation-ioredis/0.47.1/0.48.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@opentelemetry/instrumentation-nestjs-core](https://redirect.github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-nestjs-core#readme) ([source](https://redirect.github.com/open-telemetry/opentelemetry-js-contrib)) | [`^0.44.0` -> `^0.46.0`](https://renovatebot.com/diffs/npm/@opentelemetry%2finstrumentation-nestjs-core/0.44.1/0.46.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@opentelemetry%2finstrumentation-nestjs-core/0.46.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@opentelemetry%2finstrumentation-nestjs-core/0.46.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@opentelemetry%2finstrumentation-nestjs-core/0.44.1/0.46.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@opentelemetry%2finstrumentation-nestjs-core/0.44.1/0.46.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@opentelemetry/instrumentation-socket.io](https://redirect.github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/instrumentation-socket.io#readme) ([source](https://redirect.github.com/open-telemetry/opentelemetry-js-contrib)) | [`^0.46.0` -> `^0.47.0`](https://renovatebot.com/diffs/npm/@opentelemetry%2finstrumentation-socket.io/0.46.1/0.47.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@opentelemetry%2finstrumentation-socket.io/0.47.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@opentelemetry%2finstrumentation-socket.io/0.47.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@opentelemetry%2finstrumentation-socket.io/0.46.1/0.47.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@opentelemetry%2finstrumentation-socket.io/0.46.1/0.47.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@opentelemetry/sdk-node](https://redirect.github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-sdk-node) ([source](https://redirect.github.com/open-telemetry/opentelemetry-js)) | [`^0.57.0` -> `^0.200.0`](https://renovatebot.com/diffs/npm/@opentelemetry%2fsdk-node/0.57.2/0.200.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@opentelemetry%2fsdk-node/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@opentelemetry%2fsdk-node/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@opentelemetry%2fsdk-node/0.57.2/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@opentelemetry%2fsdk-node/0.57.2/0.200.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |
| [@opentelemetry/semantic-conventions](https://redirect.github.com/open-telemetry/opentelemetry-js/tree/main/semantic-conventions) ([source](https://redirect.github.com/open-telemetry/opentelemetry-js)) | [`1.31.0` -> `1.32.0`](https://renovatebot.com/diffs/npm/@opentelemetry%2fsemantic-conventions/1.31.0/1.32.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@opentelemetry%2fsemantic-conventions/1.32.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@opentelemetry%2fsemantic-conventions/1.32.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@opentelemetry%2fsemantic-conventions/1.31.0/1.32.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@opentelemetry%2fsemantic-conventions/1.31.0/1.32.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>open-telemetry/opentelemetry-js (@&#8203;opentelemetry/exporter-prometheus)</summary>

### [`v0.200.0`](https://redirect.github.com/open-telemetry/opentelemetry-js/compare/ac8641a5dbb5df1169bd5ed25a6667a6a6f730ca...7fde94081ed141c7d61db269b77d5765887a9665)

[Compare Source](https://redirect.github.com/open-telemetry/opentelemetry-js/compare/ac8641a5dbb5df1169bd5ed25a6667a6a6f730ca...7fde94081ed141c7d61db269b77d5765887a9665)

</details>

<details>
<summary>open-telemetry/opentelemetry-js-contrib (@&#8203;opentelemetry/host-metrics)</summary>

### [`v0.36.0`](https://redirect.github.com/open-telemetry/opentelemetry-js-contrib/compare/32204a362d9dffd4cd69a1300e1f7d245df9df52...fcea8ca0c83cb1dcd8ac736e5ea4d22ff20dc982)

[Compare Source](https://redirect.github.com/open-telemetry/opentelemetry-js-contrib/compare/d4d3c4f14faa634de960a7616ec2e6115b1b6347...32abc4c3c01d0e78e10022c74b6805b06e0e1fe7)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4yMDcuMSIsInVwZGF0ZWRJblZlciI6IjM5LjIzOC4wIiwidGFyZ2V0QnJhbmNoIjoiY2FuYXJ5IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyJdfQ==-->
2025-04-11 03:01:02 +00:00
L-Sun cb7f15296a chore(ios): rename keyboard css var (#11595) 2025-04-11 02:47:29 +00:00
EYHN 16d5b0df95 fix(core): fix event timing in storage (#11628) 2025-04-11 02:32:12 +00:00
Saul-Mirone a2f879066f ci(editor): enable cross platform test (#11566) 2025-04-10 16:52:15 +00:00
292 changed files with 6847 additions and 4517 deletions
+38 -1
View File
@@ -218,7 +218,43 @@ jobs:
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-e2e-legacy-bs-${{ matrix.shard }}
name: test-results-e2e-bs-${{ matrix.shard }}
path: ./test-results
if-no-files-found: ignore
e2e-blocksuite-cross-browser-test:
name: E2E BlockSuite Cross Browser Test
runs-on: ubuntu-latest
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
strategy:
fail-fast: false
matrix:
shard: [1, 2]
browser: ['chromium', 'firefox', 'webkit']
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: ./.github/actions/setup-node
with:
playwright-install: true
playwright-platform: ${{ matrix.browser }}
electron-install: false
full-cache: true
- name: Run playground build
run: yarn workspace @blocksuite/playground build
- name: Run playwright tests
env:
BROWSER: ${{ matrix.browser }}
run: yarn workspace @affine-test/blocksuite test "cross-platform/" --forbid-only --shard=${{ matrix.shard }}/${{ strategy.job-total }}
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-e2e-bs-cross-browser-${{ matrix.browser }}-${{ matrix.shard }}
path: ./test-results
if-no-files-found: ignore
@@ -1141,6 +1177,7 @@ jobs:
- check-yarn-binary
- e2e-test
- e2e-blocksuite-test
- e2e-blocksuite-cross-browser-test
- e2e-mobile-test
- unit-test
- build-native
+1 -1
View File
@@ -263,5 +263,5 @@ jobs:
packageName: app.affine.pro
releaseFiles: packages/frontend/apps/android/App/app/build/outputs/bundle/${{ env.BUILD_TYPE }}Release/app-${{ env.BUILD_TYPE }}-release-signed.aab
track: internal
status: draft
status: complete
existingEditId: ${{ steps.bump.outputs.EDIT_ID }}
+3
View File
@@ -85,3 +85,6 @@ packages/frontend/core/public/static/templates
af
af.cmd
*.resolved
# playwright
storageState.json
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -12,4 +12,4 @@ npmPublishAccess: public
npmPublishRegistry: "https://registry.npmjs.org"
yarnPath: .yarn/releases/yarn-4.9.0.cjs
yarnPath: .yarn/releases/yarn-4.9.1.cjs
Generated
+23 -84
View File
@@ -286,9 +286,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.97"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "arbitrary"
@@ -601,9 +601,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.18"
version = "1.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
dependencies = [
"shlex",
]
@@ -1669,7 +1669,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
"windows-core 0.61.0",
"windows-core 0.58.0",
]
[[package]]
@@ -1986,7 +1986,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
"windows-targets 0.48.5",
"windows-targets 0.52.6",
]
[[package]]
@@ -3101,15 +3101,6 @@ dependencies = [
"zeroize",
]
[[package]]
name = "rustls-pemfile"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "rustls-pki-types"
version = "1.11.0"
@@ -3393,9 +3384,9 @@ dependencies = [
[[package]]
name = "sqlx"
version = "0.8.3"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4410e73b3c0d8442c5f99b425d7a435b5ee0ae4167b3196771dd3f7a01be745f"
checksum = "14e22987355fbf8cfb813a0cf8cd97b1b4ec834b94dbd759a9e8679d41fabe83"
dependencies = [
"sqlx-core",
"sqlx-macros",
@@ -3406,10 +3397,11 @@ dependencies = [
[[package]]
name = "sqlx-core"
version = "0.8.3"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0"
checksum = "55c4720d7d4cd3d5b00f61d03751c685ad09c33ae8290c8a2c11335e0604300b"
dependencies = [
"base64 0.22.1",
"bytes",
"chrono",
"crc",
@@ -3428,7 +3420,6 @@ dependencies = [
"once_cell",
"percent-encoding",
"rustls",
"rustls-pemfile",
"serde",
"serde_json",
"sha2",
@@ -3443,9 +3434,9 @@ dependencies = [
[[package]]
name = "sqlx-macros"
version = "0.8.3"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3112e2ad78643fef903618d78cf0aec1cb3134b019730edb039b69eaf531f310"
checksum = "175147fcb75f353ac7675509bc58abb2cb291caf0fd24a3623b8f7e3eb0a754b"
dependencies = [
"proc-macro2",
"quote",
@@ -3456,9 +3447,9 @@ dependencies = [
[[package]]
name = "sqlx-macros-core"
version = "0.8.3"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e9f90acc5ab146a99bf5061a7eb4976b573f560bc898ef3bf8435448dd5e7ad"
checksum = "1cde983058e53bfa75998e1982086c5efe3c370f3250bf0357e344fa3352e32b"
dependencies = [
"dotenvy",
"either",
@@ -3482,9 +3473,9 @@ dependencies = [
[[package]]
name = "sqlx-mysql"
version = "0.8.3"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233"
checksum = "847d2e5393a4f39e47e4f36cab419709bc2b83cbe4223c60e86e1471655be333"
dependencies = [
"atoi",
"base64 0.22.1",
@@ -3525,9 +3516,9 @@ dependencies = [
[[package]]
name = "sqlx-postgres"
version = "0.8.3"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613"
checksum = "cc35947a541b9e0a2e3d85da444f1c4137c13040267141b208395a0d0ca4659f"
dependencies = [
"atoi",
"base64 0.22.1",
@@ -3563,9 +3554,9 @@ dependencies = [
[[package]]
name = "sqlx-sqlite"
version = "0.8.3"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540"
checksum = "6c48291dac4e5ed32da0927a0b981788be65674aeb62666d19873ab4289febde"
dependencies = [
"atoi",
"chrono",
@@ -3581,6 +3572,7 @@ dependencies = [
"serde",
"serde_urlencoded",
"sqlx-core",
"thiserror 2.0.12",
"tracing",
"url",
]
@@ -4773,23 +4765,10 @@ dependencies = [
"windows-implement 0.58.0",
"windows-interface 0.58.0",
"windows-result 0.2.0",
"windows-strings 0.1.0",
"windows-strings",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.61.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
dependencies = [
"windows-implement 0.60.0",
"windows-interface 0.59.1",
"windows-link",
"windows-result 0.3.2",
"windows-strings 0.4.0",
]
[[package]]
name = "windows-implement"
version = "0.57.0"
@@ -4812,17 +4791,6 @@ dependencies = [
"syn 2.0.100",
]
[[package]]
name = "windows-implement"
version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "windows-interface"
version = "0.57.0"
@@ -4845,17 +4813,6 @@ dependencies = [
"syn 2.0.100",
]
[[package]]
name = "windows-interface"
version = "0.59.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "windows-link"
version = "0.1.1"
@@ -4880,15 +4837,6 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-result"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.1.0"
@@ -4899,15 +4847,6 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-strings"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
+2
View File
@@ -55,6 +55,7 @@
"@blocksuite/affine-widget-edgeless-auto-connect": "workspace:*",
"@blocksuite/affine-widget-edgeless-toolbar": "workspace:*",
"@blocksuite/affine-widget-frame-title": "workspace:*",
"@blocksuite/affine-widget-linked-doc": "workspace:*",
"@blocksuite/affine-widget-remote-selection": "workspace:*",
"@blocksuite/affine-widget-scroll-anchoring": "workspace:*",
"@blocksuite/affine-widget-slash-menu": "workspace:*",
@@ -115,6 +116,7 @@
"./widgets/edgeless-auto-connect": "./src/widgets/edgeless-auto-connect.ts",
"./widgets/edgeless-toolbar": "./src/widgets/edgeless-toolbar.ts",
"./widgets/frame-title": "./src/widgets/frame-title.ts",
"./widgets/linked-doc": "./src/widgets/linked-doc.ts",
"./widgets/remote-selection": "./src/widgets/remote-selection.ts",
"./widgets/scroll-anchoring": "./src/widgets/scroll-anchoring.ts",
"./widgets/slash-menu": "./src/widgets/slash-menu.ts",
@@ -4091,4 +4091,55 @@ hhh
});
expect(nanoidReplacement(rawBlockSnapshot)).toEqual(blockSnapshot);
});
test('should not wrap url with angle brackets if it is not a url', async () => {
const markdown = 'prompt: How many people will live in the world in 2040?';
const sliceSnapshot: SliceSnapshot = {
type: 'slice',
content: [
{
type: 'block',
id: 'matchesReplaceMap[0]',
flavour: 'affine:note',
props: {
xywh: '[0,0,800,95]',
background: DefaultTheme.noteBackgrounColor,
index: 'a0',
hidden: false,
displayMode: NoteDisplayMode.DocAndEdgeless,
},
children: [
{
type: 'block',
id: 'matchesReplaceMap[1]',
flavour: 'affine:paragraph',
props: {
type: 'text',
text: {
'$blocksuite:internal:text$': true,
delta: [
{
insert:
'prompt: How many people will live in the world in 2040?',
},
],
},
},
children: [],
},
],
},
],
workspaceId: '',
pageId: '',
};
const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({
file: markdown,
workspaceId: '',
pageId: '',
});
expect(nanoidReplacement(rawSliceSnapshot!)).toEqual(sliceSnapshot);
});
});
@@ -0,0 +1 @@
export * from '@blocksuite/affine-widget-linked-doc';
+1
View File
@@ -52,6 +52,7 @@
{ "path": "../widgets/edgeless-auto-connect" },
{ "path": "../widgets/edgeless-toolbar" },
{ "path": "../widgets/frame-title" },
{ "path": "../widgets/linked-doc" },
{ "path": "../widgets/remote-selection" },
{ "path": "../widgets/scroll-anchoring" },
{ "path": "../widgets/slash-menu" },
@@ -81,21 +81,10 @@ export class BookmarkCard extends SignalWatcher(
const theme = this.bookmark.std.get(ThemeProvider).theme;
const { LoadingIcon, EmbedCardBannerIcon } = getEmbedCardIcons(theme);
const titleIconType =
!icon?.split('.').pop() || icon?.split('.').pop() === 'svg'
? 'svg+xml'
: icon?.split('.').pop();
const titleIcon = this.loading
? LoadingIcon
: icon
? html`<object
type="image/${titleIconType}"
data=${icon}
draggable="false"
>
${WebIcon16}
</object>`
? html`<img src=${icon} alt="icon" />`
: WebIcon16;
const descriptionText = this.loading
@@ -108,9 +97,7 @@ export class BookmarkCard extends SignalWatcher(
const bannerImage =
!this.loading && image
? html`<object type="image/webp" data=${image} draggable="false">
${EmbedCardBannerIcon}
</object>`
? html`<img src=${image} alt="banner" />`
: EmbedCardBannerIcon;
return html`
+3 -1
View File
@@ -11,6 +11,7 @@
"license": "MIT",
"dependencies": {
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-gfx-turbo-renderer": "workspace:*",
"@blocksuite/affine-inline-latex": "workspace:*",
"@blocksuite/affine-inline-link": "workspace:*",
"@blocksuite/affine-inline-preset": "workspace:*",
@@ -35,7 +36,8 @@
},
"exports": {
".": "./src/index.ts",
"./effects": "./src/effects.ts"
"./effects": "./src/effects.ts",
"./turbo-painter": "./src/turbo/code-painter.worker.ts"
},
"files": [
"src",
@@ -2,6 +2,7 @@ import {
type MarkdownAdapterPreprocessor,
MarkdownPreprocessorExtension,
} from '@blocksuite/affine-shared/adapters';
import { isValidUrl } from '@blocksuite/affine-shared/utils';
const codePreprocessor: MarkdownAdapterPreprocessor = {
name: 'code',
@@ -53,14 +54,9 @@ const codePreprocessor: MarkdownAdapterPreprocessor = {
//
// eg. /MuawcBMT1Mzvoar09-_66?mode=page&blockIds=rL2_GXbtLU2SsJVfCSmh_
// https://www.markdownguide.org/basic-syntax/#urls-and-email-addresses
try {
const valid =
URL.canParse?.(trimmedLine) ?? Boolean(new URL(trimmedLine));
if (valid) {
return `<${trimmedLine}>`;
}
} catch (err) {
console.log(err);
const valid = isValidUrl(trimmedLine);
if (valid) {
return `<${trimmedLine}>`;
}
}
@@ -1,7 +1,7 @@
import { affineTextStyles } from '@blocksuite/affine-shared/styles';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import { ShadowlessElement } from '@blocksuite/std';
import { ZERO_WIDTH_SPACE } from '@blocksuite/std/inline';
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '@blocksuite/std/inline';
import type { DeltaInsert } from '@blocksuite/store';
import { html } from 'lit';
import { property } from 'lit/decorators.js';
@@ -111,7 +111,7 @@ export class AffineCodeUnit extends ShadowlessElement {
@property({ type: Object })
accessor delta: DeltaInsert<AffineTextAttributes> = {
insert: ZERO_WIDTH_SPACE,
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
};
}
@@ -3,3 +3,5 @@ export * from './code-block';
export * from './code-block-config';
export * from './code-block-spec';
export * from './code-toolbar';
export * from './turbo/code-layout-handler';
export * from './turbo/code-painter.worker';
@@ -0,0 +1,71 @@
import type { Rect } from '@blocksuite/affine-gfx-turbo-renderer';
import {
BlockLayoutHandlerExtension,
BlockLayoutHandlersIdentifier,
} from '@blocksuite/affine-gfx-turbo-renderer';
import type { Container } from '@blocksuite/global/di';
import type { EditorHost, GfxBlockComponent } from '@blocksuite/std';
import { clientToModelCoord, type ViewportRecord } from '@blocksuite/std/gfx';
import type { BlockModel } from '@blocksuite/store';
import type { CodeLayout } from './code-painter.worker';
export class CodeLayoutHandlerExtension extends BlockLayoutHandlerExtension<CodeLayout> {
readonly blockType = 'affine:code';
static override setup(di: Container) {
di.addImpl(
BlockLayoutHandlersIdentifier('code'),
CodeLayoutHandlerExtension
);
}
override queryLayout(
model: BlockModel,
host: EditorHost,
viewportRecord: ViewportRecord
): CodeLayout | null {
const component = host.std.view.getBlock(model.id) as GfxBlockComponent;
if (!component) return null;
const codeBlockElement = component.querySelector(
'.affine-code-block-container'
);
if (!codeBlockElement) return null;
const { zoom, viewScale } = viewportRecord;
const codeLayout: CodeLayout = {
type: 'affine:code',
blockId: model.id,
rect: { x: 0, y: 0, w: 0, h: 0 },
};
// Get the bounding rect of the code block
const clientRect = codeBlockElement.getBoundingClientRect();
if (!clientRect) return null;
// Convert client coordinates to model coordinates
const [modelX, modelY] = clientToModelCoord(viewportRecord, [
clientRect.x,
clientRect.y,
]);
codeLayout.rect = {
x: modelX,
y: modelY,
w: clientRect.width / zoom / viewScale,
h: clientRect.height / zoom / viewScale,
};
return codeLayout;
}
calculateBound(layout: CodeLayout) {
const rect: Rect = layout.rect;
return {
rect,
subRects: [rect],
};
}
}
@@ -0,0 +1,53 @@
import type {
BlockLayout,
BlockLayoutPainter,
WorkerToHostMessage,
} from '@blocksuite/affine-gfx-turbo-renderer';
import { BlockLayoutPainterExtension } from '@blocksuite/affine-gfx-turbo-renderer/painter';
export interface CodeLayout extends BlockLayout {
type: 'affine:code';
}
function isCodeLayout(layout: BlockLayout): layout is CodeLayout {
return layout.type === 'affine:code';
}
class CodeLayoutPainter implements BlockLayoutPainter {
paint(
ctx: OffscreenCanvasRenderingContext2D,
layout: BlockLayout,
layoutBaseX: number,
layoutBaseY: number
): void {
if (!isCodeLayout(layout)) {
const message: WorkerToHostMessage = {
type: 'paintError',
error: 'Invalid layout format',
blockType: 'affine:code',
};
self.postMessage(message);
return;
}
// Get the layout dimensions
const x = layout.rect.x - layoutBaseX;
const y = layout.rect.y - layoutBaseY;
const width = layout.rect.w;
const height = layout.rect.h;
// Simple white rectangle for now
ctx.fillStyle = 'white';
ctx.fillRect(x, y, width, height);
// Add a border to visualize the code block
ctx.strokeStyle = 'rgba(0, 0, 0, 0.1)';
ctx.lineWidth = 1;
ctx.strokeRect(x, y, width, height);
}
}
export const CodeLayoutPainterExtension = BlockLayoutPainterExtension(
'affine:code',
CodeLayoutPainter
);
@@ -8,6 +8,7 @@
"include": ["./src"],
"references": [
{ "path": "../../components" },
{ "path": "../../gfx/turbo-renderer" },
{ "path": "../../inlines/latex" },
{ "path": "../../inlines/link" },
{ "path": "../../inlines/preset" },
@@ -259,7 +259,7 @@ export class EdgelessTextBlockComponent extends GfxBlockComponent<EdgelessTextBl
};
}
override onSelected(context: SelectedContext) {
override onSelected(context: SelectedContext): void | boolean {
const { selected, multiSelect, event: e } = context;
const { editing } = this.gfx.selection;
const alreadySelected = this.gfx.selection.has(this.model.id);
@@ -318,7 +318,7 @@ export class EdgelessTextBlockComponent extends GfxBlockComponent<EdgelessTextBl
})
.catch(console.error);
} else {
super.onSelected(context);
return super.onSelected(context);
}
}
@@ -1,8 +1,5 @@
import { EmbedLinkedDocBlockSchema } from '@blocksuite/affine-model';
import {
getInlineEditorByModel,
insertContent,
} from '@blocksuite/affine-rich-text';
import { insertContent } from '@blocksuite/affine-rich-text';
import { REFERENCE_NODE } from '@blocksuite/affine-shared/consts';
import { createDefaultDoc } from '@blocksuite/affine-shared/utils';
import {
@@ -68,22 +65,7 @@ const linkedDocSlashMenuConfig: SlashMenuConfig = {
if (!linkedDocWidget) return;
// TODO(@L-Sun): make linked-doc-widget as extension
// @ts-expect-error same as above
const triggerKey = linkedDocWidget.config.triggerKeys[0];
insertContent(std, model, triggerKey);
const inlineEditor = getInlineEditorByModel(std, model);
if (inlineEditor) {
// Wait for range to be updated
const subscription = inlineEditor.slots.inlineRangeSync.subscribe(
() => {
// TODO(@L-Sun): make linked-doc-widget as extension
subscription.unsubscribe();
// @ts-expect-error same as above
linkedDocWidget.show({ addTriggerKey: true });
}
);
}
linkedDocWidget.show({ addTriggerKey: true });
},
},
],
@@ -53,7 +53,7 @@ export class FrameBlockComponent extends GfxBlockComponent<FrameBlockModel> {
};
}
override onSelected(context: SelectedContext): void {
override onSelected(context: SelectedContext): boolean | void {
const { x, y } = context.position;
if (
@@ -63,10 +63,10 @@ export class FrameBlockComponent extends GfxBlockComponent<FrameBlockModel> {
// otherwise if the frame has title, then ignore it because in this case the frame cannot be selected by frame body
this.model.props.title.length)
) {
return;
return false;
}
super.onSelected(context);
return super.onSelected(context);
}
override renderGfxBlock() {
@@ -80,7 +80,7 @@ const builtinSurfaceToolbarConfig = {
ctx.store.addBlock(
SurfaceRefBlockSchema.model.flavour,
{ reference: frameId, refFlavour: NoteBlockSchema.model.flavour },
{ reference: frameId, refFlavour: FrameBlockSchema.model.flavour },
lastNoteId
);
+3 -1
View File
@@ -13,6 +13,7 @@
"@blocksuite/affine-block-note": "workspace:*",
"@blocksuite/affine-block-surface": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-gfx-turbo-renderer": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",
"@blocksuite/affine-widget-slash-menu": "workspace:*",
@@ -32,7 +33,8 @@
},
"exports": {
".": "./src/index.ts",
"./effects": "./src/effects.ts"
"./effects": "./src/effects.ts",
"./turbo-painter": "./src/turbo/image-painter.worker.ts"
},
"files": [
"src",
@@ -7,5 +7,7 @@ export { ImageProxyService } from './image-proxy-service';
export * from './image-service';
export * from './image-spec';
export * from './styles';
export * from './turbo/image-layout-handler';
export * from './turbo/image-painter.worker';
export { addImages, downloadImageBlob, uploadBlobForImage } from './utils';
export { ImageSelection } from '@blocksuite/affine-shared/selection';
@@ -0,0 +1,69 @@
import type { Rect } from '@blocksuite/affine-gfx-turbo-renderer';
import {
BlockLayoutHandlerExtension,
BlockLayoutHandlersIdentifier,
} from '@blocksuite/affine-gfx-turbo-renderer';
import type { Container } from '@blocksuite/global/di';
import type { EditorHost, GfxBlockComponent } from '@blocksuite/std';
import { clientToModelCoord, type ViewportRecord } from '@blocksuite/std/gfx';
import type { BlockModel } from '@blocksuite/store';
import type { ImageLayout } from './image-painter.worker';
export class ImageLayoutHandlerExtension extends BlockLayoutHandlerExtension<ImageLayout> {
readonly blockType = 'affine:image';
static override setup(di: Container) {
di.addImpl(
BlockLayoutHandlersIdentifier('image'),
ImageLayoutHandlerExtension
);
}
override queryLayout(
model: BlockModel,
host: EditorHost,
viewportRecord: ViewportRecord
): ImageLayout | null {
const component = host.std.view.getBlock(model.id) as GfxBlockComponent;
if (!component) return null;
const imageContainer = component.querySelector('.affine-image-container');
if (!imageContainer) return null;
const resizableImg = component.querySelector(
'.resizable-img'
) as HTMLElement;
if (!resizableImg) return null;
const { zoom, viewScale } = viewportRecord;
const rect = resizableImg.getBoundingClientRect();
const [modelX, modelY] = clientToModelCoord(viewportRecord, [
rect.x,
rect.y,
]);
const imageLayout: ImageLayout = {
type: 'affine:image',
blockId: model.id,
rect: {
x: modelX,
y: modelY,
w: rect.width / zoom / viewScale,
h: rect.height / zoom / viewScale,
},
};
return imageLayout;
}
calculateBound(layout: ImageLayout) {
const rect: Rect = layout.rect;
return {
rect,
subRects: [rect],
};
}
}
@@ -0,0 +1,56 @@
import type {
BlockLayout,
BlockLayoutPainter,
} from '@blocksuite/affine-gfx-turbo-renderer';
import { BlockLayoutPainterExtension } from '@blocksuite/affine-gfx-turbo-renderer/painter';
export interface ImageLayout extends BlockLayout {
type: 'affine:image';
rect: {
x: number;
y: number;
w: number;
h: number;
};
}
function isImageLayout(layout: BlockLayout): layout is ImageLayout {
return layout.type === 'affine:image';
}
class ImageLayoutPainter implements BlockLayoutPainter {
paint(
ctx: OffscreenCanvasRenderingContext2D,
layout: BlockLayout,
layoutBaseX: number,
layoutBaseY: number
): void {
if (!isImageLayout(layout)) {
console.warn(
'Expected image layout but received different format:',
layout
);
return;
}
// For now, just paint a white rectangle
const x = layout.rect.x - layoutBaseX;
const y = layout.rect.y - layoutBaseY;
const width = layout.rect.w;
const height = layout.rect.h;
// Draw a white rectangle with border
ctx.fillStyle = 'white';
ctx.fillRect(x, y, width, height);
// Add a border
ctx.strokeStyle = '#e0e0e0';
ctx.lineWidth = 1;
ctx.strokeRect(x, y, width, height);
}
}
export const ImageLayoutPainterExtension = BlockLayoutPainterExtension(
'affine:image',
ImageLayoutPainter
);
@@ -10,6 +10,7 @@
{ "path": "../note" },
{ "path": "../surface" },
{ "path": "../../components" },
{ "path": "../../gfx/turbo-renderer" },
{ "path": "../../model" },
{ "path": "../../shared" },
{ "path": "../../widgets/slash-menu" },
@@ -46,6 +46,7 @@
"@blocksuite/affine-widget-edgeless-auto-connect": "workspace:*",
"@blocksuite/affine-widget-edgeless-toolbar": "workspace:*",
"@blocksuite/affine-widget-frame-title": "workspace:*",
"@blocksuite/affine-widget-linked-doc": "workspace:*",
"@blocksuite/affine-widget-remote-selection": "workspace:*",
"@blocksuite/affine-widget-scroll-anchoring": "workspace:*",
"@blocksuite/affine-widget-slash-menu": "workspace:*",
@@ -33,6 +33,7 @@ import {
ToolbarRegistryExtension,
} from '@blocksuite/affine-shared/services';
import { dragHandleWidget } from '@blocksuite/affine-widget-drag-handle';
import { linkedDocWidget } from '@blocksuite/affine-widget-linked-doc';
import { docRemoteSelectionWidget } from '@blocksuite/affine-widget-remote-selection';
import { scrollAnchoringWidget } from '@blocksuite/affine-widget-scroll-anchoring';
import { SlashMenuExtension } from '@blocksuite/affine-widget-slash-menu';
@@ -44,7 +45,7 @@ import { RootBlockAdapterExtensions } from '../adapters/extension';
import { clipboardConfigs } from '../clipboard';
import { builtinToolbarConfig } from '../configs/toolbar';
import { fallbackKeymap } from '../keyboard/keymap';
import { linkedDocWidget, modalWidget, viewportOverlayWidget } from './widgets';
import { modalWidget, viewportOverlayWidget } from './widgets';
/**
* Why do we add these extensions into CommonSpecs?
@@ -1,7 +1,6 @@
import { WidgetViewExtension } from '@blocksuite/std';
import { literal, unsafeStatic } from 'lit/static-html.js';
import { AFFINE_LINKED_DOC_WIDGET } from '../widgets/linked-doc/config.js';
import { AFFINE_MODAL_WIDGET } from '../widgets/modal/modal.js';
import { AFFINE_VIEWPORT_OVERLAY_WIDGET } from '../widgets/viewport-overlay/viewport-overlay.js';
@@ -10,11 +9,6 @@ export const modalWidget = WidgetViewExtension(
AFFINE_MODAL_WIDGET,
literal`${unsafeStatic(AFFINE_MODAL_WIDGET)}`
);
export const linkedDocWidget = WidgetViewExtension(
'affine:page',
AFFINE_LINKED_DOC_WIDGET,
literal`${unsafeStatic(AFFINE_LINKED_DOC_WIDGET)}`
);
export const viewportOverlayWidget = WidgetViewExtension(
'affine:page',
AFFINE_VIEWPORT_OVERLAY_WIDGET,
@@ -88,6 +88,9 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager {
p: () => {
this._setEdgelessTool('brush');
},
'Shift-p': () => {
this._setEdgelessTool('highlighter');
},
e: () => {
this._setEdgelessTool('eraser');
},
@@ -45,7 +45,6 @@ import { css, html } from 'lit';
import { query } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import type { EdgelessRootBlockWidgetName } from '../types.js';
import type { EdgelessSelectedRectWidget } from './components/rects/edgeless-selected-rect.js';
import { EdgelessPageKeyboardManager } from './edgeless-keyboard.js';
import type { EdgelessRootService } from './edgeless-root-service.js';
@@ -53,8 +52,7 @@ import { isCanvasElement } from './utils/query.js';
export class EdgelessRootBlockComponent extends BlockComponent<
RootBlockModel,
EdgelessRootService,
EdgelessRootBlockWidgetName
EdgelessRootService
> {
static override styles = css`
affine-edgeless-root {
@@ -25,14 +25,12 @@ import { css, html } from 'lit';
import { query, state } from 'lit/decorators.js';
import { type StyleInfo, styleMap } from 'lit/directives/style-map.js';
import type { EdgelessRootBlockWidgetName } from '../types.js';
import type { EdgelessRootService } from './edgeless-root-service.js';
import { isCanvasElement } from './utils/query.js';
export class EdgelessRootPreviewBlockComponent extends BlockComponent<
RootBlockModel,
EdgelessRootService,
EdgelessRootBlockWidgetName
EdgelessRootService
> {
static override styles = css`
affine-edgeless-root-preview {
+1 -5
View File
@@ -7,6 +7,7 @@ import { effects as gfxShapeEffects } from '@blocksuite/affine-gfx-shape/effects
import { effects as gfxTemplateEffects } from '@blocksuite/affine-gfx-template/effects';
import { effects as gfxCanvasTextEffects } from '@blocksuite/affine-gfx-text/effects';
import { effects as widgetEdgelessToolbarEffects } from '@blocksuite/affine-widget-edgeless-toolbar/effects';
import { effects as widgetLinkedDocEffects } from '@blocksuite/affine-widget-linked-doc/effects';
import { EdgelessAutoCompletePanel } from './edgeless/components/auto-complete/auto-complete-panel.js';
import { EdgelessAutoComplete } from './edgeless/components/auto-complete/edgeless-auto-complete.js';
@@ -44,8 +45,6 @@ import {
import { ZoomBarToggleButton } from './widgets/edgeless-zoom-toolbar/zoom-bar-toggle-button.js';
import { EdgelessZoomToolbar } from './widgets/edgeless-zoom-toolbar/zoom-toolbar.js';
import { effects as widgetMobileToolbarEffects } from './widgets/keyboard-toolbar/effects.js';
import { effects as widgetLinkedDocEffects } from './widgets/linked-doc/effects.js';
import { Loader } from './widgets/linked-doc/import-doc/loader.js';
import { AffineCustomModal } from './widgets/modal/custom-modal.js';
import { AFFINE_MODAL_WIDGET } from './widgets/modal/modal.js';
import {
@@ -127,9 +126,6 @@ function registerMiscComponents() {
// Modal and menu components
customElements.define('affine-custom-modal', AffineCustomModal);
// Loading and preview components
customElements.define('loader-element', Loader);
// Toolbar and UI components
customElements.define('edgeless-zoom-toolbar', EdgelessZoomToolbar);
customElements.define('zoom-bar-toggle-button', ZoomBarToggleButton);
@@ -10,7 +10,6 @@ export * from './page/page-root-spec.js';
export * from './preview/preview-root-block.js';
export * from './root-config.js';
export { RootService } from './root-service.js';
export * from './transformers/index.js';
export * from './types.js';
export * from './utils/index.js';
export * from './widgets/index.js';
@@ -27,7 +27,6 @@ import { css, html } from 'lit';
import { query } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import type { PageRootBlockWidgetName } from '../index.js';
import { PageKeyboardManager } from '../keyboard/keyboard-manager.js';
import type { PageRootService } from './page-root-service.js';
@@ -52,8 +51,7 @@ function testClickOnBlankArea(
export class PageRootBlockComponent extends BlockComponent<
RootBlockModel,
PageRootService,
PageRootBlockWidgetName
PageRootService
> {
static override styles = css`
editor-host:has(> affine-page-root, * > affine-page-root) {
@@ -1,4 +1,5 @@
import { ViewportElementExtension } from '@blocksuite/affine-shared/services';
import { IS_MOBILE } from '@blocksuite/global/env';
import { BlockViewExtension, WidgetViewExtension } from '@blocksuite/std';
import type { ExtensionType } from '@blocksuite/store';
import { literal, unsafeStatic } from 'lit/static-html.js';
@@ -31,7 +32,7 @@ const PageCommonExtension: ExtensionType[] = [
export const PageRootBlockSpec: ExtensionType[] = [
...PageCommonExtension,
BlockViewExtension('affine:page', literal`affine-page-root`),
keyboardToolbarWidget,
IS_MOBILE ? [keyboardToolbarWidget] : [],
PageClipboard,
].flat();
@@ -1,10 +1,8 @@
import { ConfigExtensionFactory } from '@blocksuite/std';
import type { KeyboardToolbarConfig } from './widgets/keyboard-toolbar/config.js';
import type { LinkedWidgetConfig } from './widgets/linked-doc/index.js';
export interface RootBlockConfig {
linkedWidget?: Partial<LinkedWidgetConfig>;
keyboardToolbar?: Partial<KeyboardToolbarConfig>;
}
@@ -1,40 +1,5 @@
import type { AFFINE_DRAG_HANDLE_WIDGET } from '@blocksuite/affine-widget-drag-handle';
import type { AFFINE_FRAME_TITLE_WIDGET } from '@blocksuite/affine-widget-frame-title';
import type {
AFFINE_DOC_REMOTE_SELECTION_WIDGET,
AFFINE_EDGELESS_REMOTE_SELECTION_WIDGET,
} from '@blocksuite/affine-widget-remote-selection';
import type { AFFINE_SLASH_MENU_WIDGET } from '@blocksuite/affine-widget-slash-menu';
import type { EdgelessRootBlockComponent } from './edgeless/edgeless-root-block.js';
import type { PageRootBlockComponent } from './page/page-root-block.js';
import type { AFFINE_EDGELESS_ZOOM_TOOLBAR_WIDGET } from './widgets/edgeless-zoom-toolbar/index.js';
import type { AFFINE_KEYBOARD_TOOLBAR_WIDGET } from './widgets/index.js';
import type { AFFINE_LINKED_DOC_WIDGET } from './widgets/linked-doc/config.js';
import type { AFFINE_MODAL_WIDGET } from './widgets/modal/modal.js';
import type { AFFINE_PAGE_DRAGGING_AREA_WIDGET } from './widgets/page-dragging-area/page-dragging-area.js';
import type { AFFINE_VIEWPORT_OVERLAY_WIDGET } from './widgets/viewport-overlay/viewport-overlay.js';
export type PageRootBlockWidgetName =
| typeof AFFINE_KEYBOARD_TOOLBAR_WIDGET
| typeof AFFINE_MODAL_WIDGET
| typeof AFFINE_SLASH_MENU_WIDGET
| typeof AFFINE_LINKED_DOC_WIDGET
| typeof AFFINE_PAGE_DRAGGING_AREA_WIDGET
| typeof AFFINE_DRAG_HANDLE_WIDGET
| typeof AFFINE_DOC_REMOTE_SELECTION_WIDGET
| typeof AFFINE_VIEWPORT_OVERLAY_WIDGET;
export type EdgelessRootBlockWidgetName =
| typeof AFFINE_MODAL_WIDGET
| typeof AFFINE_SLASH_MENU_WIDGET
| typeof AFFINE_LINKED_DOC_WIDGET
| typeof AFFINE_DRAG_HANDLE_WIDGET
| typeof AFFINE_DOC_REMOTE_SELECTION_WIDGET
| typeof AFFINE_EDGELESS_REMOTE_SELECTION_WIDGET
| typeof AFFINE_EDGELESS_ZOOM_TOOLBAR_WIDGET
| typeof AFFINE_VIEWPORT_OVERLAY_WIDGET
| typeof AFFINE_FRAME_TITLE_WIDGET;
export type RootBlockComponent =
| PageRootBlockComponent
@@ -1,17 +1,5 @@
export { AffineEdgelessZoomToolbarWidget } from './edgeless-zoom-toolbar/index.js';
export * from './keyboard-toolbar/index.js';
export {
type LinkedMenuAction,
type LinkedMenuGroup,
type LinkedMenuItem,
type LinkedWidgetConfig,
LinkedWidgetUtils,
} from './linked-doc/config.js';
export {
// It's used in the AFFiNE!
showImportModal,
} from './linked-doc/import-doc/index.js';
export { AffineLinkedDocWidget } from './linked-doc/index.js';
export { AffineModalWidget } from './modal/modal.js';
export { AffinePageDraggingAreaWidget } from './page-dragging-area/page-dragging-area.js';
export * from './viewport-overlay/viewport-overlay.js';
@@ -34,10 +34,7 @@ import {
toggleUnderline,
} from '@blocksuite/affine-inline-preset';
import type { FrameBlockModel } from '@blocksuite/affine-model';
import {
getInlineEditorByModel,
insertContent,
} from '@blocksuite/affine-rich-text';
import { insertContent } from '@blocksuite/affine-rich-text';
import {
copySelectedModelsCommand,
deleteSelectedModelsCommand,
@@ -55,6 +52,7 @@ import {
openFileOrFiles,
type Signal,
} from '@blocksuite/affine-shared/utils';
import type { AffineLinkedDocWidget } from '@blocksuite/affine-widget-linked-doc';
import { viewPresets } from '@blocksuite/data-view/view-presets';
import { assertType } from '@blocksuite/global/utils';
import {
@@ -105,7 +103,6 @@ import { cssVarV2 } from '@toeverything/theme/v2';
import type { TemplateResult } from 'lit';
import type { PageRootBlockComponent } from '../../page/page-root-block.js';
import type { AffineLinkedDocWidget } from '../linked-doc/index.js';
import {
FigmaDuotoneIcon,
HeadingIcon,
@@ -348,35 +345,11 @@ const pageToolGroup: KeyboardToolPanelGroup = {
);
if (!linkedDocWidget) return;
assertType<AffineLinkedDocWidget>(linkedDocWidget);
const triggerKey = linkedDocWidget.config.triggerKeys[0];
std.command
.chain()
.pipe(getSelectedModelsCommand)
.pipe(ctx => {
const { selectedModels } = ctx;
if (!selectedModels?.length) return;
const currentModel = selectedModels[0];
insertContent(std, currentModel, triggerKey);
const inlineEditor = getInlineEditorByModel(std, currentModel);
// Wait for range to be updated
if (inlineEditor) {
const subscription = inlineEditor.slots.inlineRangeSync.subscribe(
() => {
subscription.unsubscribe();
linkedDocWidget.show({
mode: 'mobile',
addTriggerKey: true,
});
closeToolPanel();
}
);
}
})
.run();
linkedDocWidget.show({
mode: 'mobile',
addTriggerKey: true,
});
closeToolPanel();
},
},
],
@@ -428,8 +401,7 @@ const contentMediaToolGroup: KeyboardToolPanelGroup = {
{
name: 'Attachment',
icon: AttachmentIcon(),
showWhen: ({ std }) =>
std.store.schema.flavourSchemaMap.has('affine:attachment'),
showWhen: () => false,
action: async ({ std }) => {
const [_, { selectedModels }] = std.command.exec(
getSelectedModelsCommand
@@ -1029,8 +1001,7 @@ export const defaultKeyboardToolbarConfig: KeyboardToolbarConfig = {
{
name: 'Attachment',
icon: AttachmentIcon(),
showWhen: ({ std }) =>
std.store.schema.flavourSchemaMap.has('affine:attachment'),
showWhen: () => false,
action: async ({ std }) => {
const [_, { selectedModels }] = std.command.exec(
getSelectedModelsCommand
@@ -2,6 +2,7 @@ import { getDocTitleByEditorHost } from '@blocksuite/affine-fragment-doc-title';
import type { RootBlockModel } from '@blocksuite/affine-model';
import {
FeatureFlagService,
isVirtualKeyboardProviderWithAction,
VirtualKeyboardProvider,
type VirtualKeyboardProviderWithAction,
} from '@blocksuite/affine-shared/services';
@@ -34,7 +35,10 @@ export class AffineKeyboardToolbarWidget extends WidgetComponent<RootBlockModel>
private _initialInputMode: string = '';
get keyboard(): VirtualKeyboardProviderWithAction {
get keyboard(): VirtualKeyboardProviderWithAction & { fallback?: boolean } {
const provider = this.std.get(VirtualKeyboardProvider);
if (isVirtualKeyboardProviderWithAction(provider)) return provider;
return {
// fallback keyboard actions
show: () => {
@@ -49,7 +53,7 @@ export class AffineKeyboardToolbarWidget extends WidgetComponent<RootBlockModel>
rootComponent.inputMode = 'none';
}
},
...this.std.get(VirtualKeyboardProvider),
...provider,
};
}
@@ -70,10 +74,6 @@ export class AffineKeyboardToolbarWidget extends WidgetComponent<RootBlockModel>
const rootComponent = this.block?.rootComponent;
if (rootComponent) {
this._initialInputMode = rootComponent.inputMode;
this.disposables.add(() => {
rootComponent.inputMode = this._initialInputMode;
});
this.disposables.addFromEvent(rootComponent, 'focus', () => {
this._show$.value = true;
});
@@ -81,14 +81,20 @@ export class AffineKeyboardToolbarWidget extends WidgetComponent<RootBlockModel>
this._show$.value = false;
});
this.disposables.add(
effect(() => {
// recover input mode when keyboard toolbar is hidden
if (!this._show$.value) {
rootComponent.inputMode = this._initialInputMode;
}
})
);
if (this.keyboard.fallback) {
this._initialInputMode = rootComponent.inputMode;
this.disposables.add(() => {
rootComponent.inputMode = this._initialInputMode;
});
this.disposables.add(
effect(() => {
// recover input mode when keyboard toolbar is hidden
if (!this._show$.value) {
rootComponent.inputMode = this._initialInputMode;
}
})
);
}
}
if (this._docTitle) {
@@ -55,10 +55,8 @@ export class AffineKeyboardToolbar extends SignalWatcher(
}
private readonly _closeToolPanel = () => {
if (!this.panelOpened) return;
this._currentPanelIndex$.value = -1;
this.keyboard.show();
if (!this.keyboard.visible$.peek()) this.keyboard.show();
};
private readonly _currentPanelIndex$ = signal(-1);
@@ -255,6 +253,16 @@ export class AffineKeyboardToolbar extends SignalWatcher(
})
);
this.disposables.add(
effect(() => {
// sometime the keyboard will auto show when user click into different paragraph in Android,
// so we need to close the tool panel explicitly when the keyboard is visible
if (this.keyboard.visible$.value) {
this._closeToolPanel();
}
})
);
this._watchAutoShow();
}
@@ -43,6 +43,7 @@
{ "path": "../../widgets/edgeless-auto-connect" },
{ "path": "../../widgets/edgeless-toolbar" },
{ "path": "../../widgets/frame-title" },
{ "path": "../../widgets/linked-doc" },
{ "path": "../../widgets/remote-selection" },
{ "path": "../../widgets/scroll-anchoring" },
{ "path": "../../widgets/slash-menu" },
@@ -38,11 +38,11 @@ const styles = css`
transition: 0.1s;
}
label.subscribe {
label.on {
background: var(--affine-primary-color);
}
label.subscribe:after {
label.on:after {
left: calc(100% - 1px);
transform: translateX(-100%);
}
@@ -1,5 +1,6 @@
import { css, html, LitElement } from 'lit';
import { property } from 'lit/decorators.js';
import { repeat } from 'lit-html/directives/repeat.js';
export class TooltipContentWithShortcut extends LitElement {
static override styles = css`
@@ -9,6 +10,10 @@ export class TooltipContentWithShortcut extends LitElement {
align-items: center;
gap: 10px;
}
.tooltip__shortcuts {
display: flex;
gap: 2px;
}
.tooltip__shortcut {
font-size: 12px;
position: relative;
@@ -28,19 +33,30 @@ export class TooltipContentWithShortcut extends LitElement {
opacity: 0.2;
}
.tooltip__label {
display: flex;
flex: 1;
white-space: pre;
}
`;
get shortcuts() {
let shortcut = this.shortcut;
if (!shortcut) return [];
return shortcut.split(' ');
}
override render() {
const { tip, shortcut, postfix } = this;
const { tip, shortcuts, postfix } = this;
return html`
<div class="tooltip-with-shortcut">
<span class="tooltip__label">${tip}</span>
${shortcut
? html`<span class="tooltip__shortcut">${shortcut}</span>`
: ''}
<div class="tooltip__shortcuts">
${repeat(
shortcuts,
shortcut => html`<span class="tooltip__shortcut">${shortcut}</span>`
)}
</div>
${postfix ? html`<span class="tooltip__postfix">${postfix}</span>` : ''}
</div>
`;
@@ -0,0 +1,29 @@
import {
EdgelessBrushDarkIcon,
EdgelessBrushLightIcon,
EdgelessHighlighterDarkIcon,
EdgelessHighlighterLightIcon,
} from './icons';
import type { Pen } from './types';
export const penIconMap = {
dark: {
brush: EdgelessBrushDarkIcon,
highlighter: EdgelessHighlighterDarkIcon,
},
light: {
brush: EdgelessBrushLightIcon,
highlighter: EdgelessHighlighterLightIcon,
},
};
export const penInfoMap: { [k in Pen]: { tip: string; shortcut: string } } = {
brush: {
tip: 'Pen',
shortcut: 'P',
},
highlighter: {
tip: 'Highlighter',
shortcut: '⇧ P',
},
};
@@ -7,11 +7,16 @@ import {
import type { ColorEvent } from '@blocksuite/affine-shared/utils';
import { EdgelessToolbarToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar';
import { SignalWatcher } from '@blocksuite/global/lit';
import { computed, type Signal } from '@preact/signals-core';
import {
computed,
type ReadonlySignal,
type Signal,
} from '@preact/signals-core';
import { css, html, LitElement, type TemplateResult } from 'lit';
import { property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { penInfoMap } from './consts';
import type { Pen, PenMap } from './types';
export class EdgelessPenMenu extends EdgelessToolbarToolMixin(
@@ -26,8 +31,14 @@ export class EdgelessPenMenu extends EdgelessToolbarToolMixin(
.pens {
display: flex;
height: 100%;
padding: 0 4px;
align-items: center;
align-items: flex-end;
edgeless-tool-icon-button {
display: flex;
align-self: flex-start;
}
.pen-wrapper {
display: flex;
@@ -36,7 +47,7 @@ export class EdgelessPenMenu extends EdgelessToolbarToolMixin(
align-items: flex-end;
justify-content: center;
position: relative;
transform: translateY(10px);
transform: translateY(-2px);
transition-property: color, transform;
transition-duration: 300ms;
transition-timing-function: ease-in-out;
@@ -46,7 +57,7 @@ export class EdgelessPenMenu extends EdgelessToolbarToolMixin(
.pen-wrapper:hover,
.pen-wrapper:active,
.pen-wrapper[data-active] {
transform: translateY(-10px);
transform: translateY(-22px);
}
}
@@ -56,6 +67,8 @@ export class EdgelessPenMenu extends EdgelessToolbarToolMixin(
}
menu-divider {
display: flex;
align-self: center;
height: 24px;
margin: 0 9px;
}
@@ -83,42 +96,64 @@ export class EdgelessPenMenu extends EdgelessToolbarToolMixin(
override render() {
const {
_theme$: { value: theme },
color$: { value: currentColor },
colors$: {
value: { brush: brushColor, highlighter: highlighterColor },
},
pen$: { value: pen },
penIconMap$: {
value: { brush: brushIcon, highlighter: highlighterIcon },
},
penInfo$: {
value: { type, color },
},
} = this;
return html`
<edgeless-slide-menu>
<div class="pens" slot="prefix">
<div
class="pen-wrapper edgeless-brush-button"
?data-active="${pen === 'brush'}"
style=${styleMap({ color: brushColor })}
<edgeless-tool-icon-button
class="edgeless-brush-button"
.tooltip=${html`<affine-tooltip-content-with-shortcut
data-tip="${penInfoMap.brush.tip}"
data-shortcut="${penInfoMap.brush.shortcut}"
></affine-tooltip-content-with-shortcut>`}
.tooltipOffset=${20}
.hover=${false}
@click=${() => this._onPickPen('brush')}
>
${brushIcon}
</div>
<div
class="pen-wrapper edgeless-highlighter-button"
?data-active="${pen === 'highlighter'}"
style=${styleMap({ color: highlighterColor })}
<div
class="pen-wrapper"
style=${styleMap({ color: brushColor })}
?data-active="${type === 'brush'}"
>
${brushIcon}
</div>
</edgeless-tool-icon-button>
<edgeless-tool-icon-button
class="edgeless-highlighter-button"
.tooltip=${html`<affine-tooltip-content-with-shortcut
data-tip="${penInfoMap.highlighter.tip}"
data-shortcut="${penInfoMap.highlighter.shortcut}"
></affine-tooltip-content-with-shortcut>`}
.tooltipOffset=${20}
.hover=${false}
@click=${() => this._onPickPen('highlighter')}
>
${highlighterIcon}
</div>
<div
class="pen-wrapper"
style=${styleMap({ color: highlighterColor })}
?data-active="${type === 'highlighter'}"
>
${highlighterIcon}
</div>
</edgeless-tool-icon-button>
<menu-divider .vertical=${true}></menu-divider>
</div>
<div class="menu-content">
<edgeless-color-panel
class="one-way"
@select=${this._onPickColor}
.value=${currentColor}
.value=${color}
.theme=${theme}
.palettes=${DefaultTheme.StrokeColorShortPalettes}
.shouldKeepColor=${true}
@@ -135,14 +170,20 @@ export class EdgelessPenMenu extends EdgelessToolbarToolMixin(
accessor onChange!: (props: Record<string, unknown>) => void;
@property({ attribute: false })
accessor colors$!: Signal<PenMap<string>>;
accessor colors$!: ReadonlySignal<PenMap<string>>;
@property({ attribute: false })
accessor color$!: Signal<string>;
accessor penIconMap$!: ReadonlySignal<PenMap<TemplateResult>>;
@property({ attribute: false })
accessor pen$!: Signal<Pen>;
@property({ attribute: false })
accessor penIconMap$!: Signal<PenMap<TemplateResult>>;
accessor penInfo$!: ReadonlySignal<{
type: Pen;
color: string;
icon: TemplateResult<1>;
tip: string;
shortcut: string;
}>;
}
@@ -10,7 +10,7 @@ import { css, html, LitElement, nothing } from 'lit';
import { styleMap } from 'lit/directives/style-map.js';
import { when } from 'lit/directives/when.js';
import { penIconMap } from './icons';
import { penIconMap, penInfoMap } from './consts';
import type { Pen } from './types';
export class EdgelessPenToolButton extends EdgelessToolbarToolMixin(
@@ -81,6 +81,18 @@ export class EdgelessPenToolButton extends EdgelessToolbarToolMixin(
return this.penIconMap$.value[pen];
});
private readonly penInfo$ = computed(() => {
const type = this.pen$.value;
const icon = this.penIcon$.value;
const color = this.color$.value;
return {
...penInfoMap[type],
color,
icon,
type,
};
});
private readonly pen$ = signal<Pen>('brush');
override enableActiveBackground = true;
@@ -89,9 +101,20 @@ export class EdgelessPenToolButton extends EdgelessToolbarToolMixin(
override firstUpdated() {
this.disposables.add(
this.gfx.tool.currentToolName$.subscribe(tool => {
if (this.type.map(String).includes(tool)) return;
this.tryDisposePopper();
this.gfx.tool.currentToolName$.subscribe(name => {
const tool = this.type.find(t => t === name);
if (!tool) {
this.tryDisposePopper();
return;
}
if (tool !== this.pen$.peek()) {
this.pen$.value = tool;
}
if (this.active) return;
this._togglePenMenu();
})
);
}
@@ -101,10 +124,10 @@ export class EdgelessPenToolButton extends EdgelessToolbarToolMixin(
!this.active && this.setEdgelessTool(this.pen$.peek());
const menu = this.createPopper('edgeless-pen-menu', this);
Object.assign(menu.element, {
color$: this.color$,
colors$: this.colors$,
pen$: this.pen$,
penIconMap$: this.penIconMap$,
pen$: this.pen$,
penInfo$: this.penInfo$,
edgeless: this.edgeless,
onChange: (props: Record<string, unknown>) => {
const pen = this.pen$.peek();
@@ -117,20 +140,22 @@ export class EdgelessPenToolButton extends EdgelessToolbarToolMixin(
override render() {
const {
active,
penIcon$: { value: icon },
color$: { value: color },
penInfo$: {
value: { type, color, icon, tip, shortcut },
},
} = this;
return html`
<edgeless-toolbar-button
class="edgeless-pen-button"
data-drawing-tool="${type}"
.tooltip=${when(
this.popper,
() => nothing,
() =>
html`<affine-tooltip-content-with-shortcut
data-tip="${'Pen'}"
data-shortcut="${'P'}"
data-tip="${tip}"
data-shortcut="${shortcut}"
></affine-tooltip-content-with-shortcut>`
)}
.tooltipOffset=${4}
@@ -73,16 +73,20 @@ export const TurboRendererConfigFactory =
export class ViewportTurboRendererExtension extends GfxExtension {
static override key = 'viewportTurboRenderer';
private readonly state$ = new BehaviorSubject<RenderingState>('inactive');
public readonly state$ = new BehaviorSubject<RenderingState>('inactive');
public readonly canvas: HTMLCanvasElement = document.createElement('canvas');
public layoutCacheData: ViewportLayoutTree | null = null;
private readonly worker: Worker;
private readonly disposables = new DisposableGroup();
private layoutCacheData: ViewportLayoutTree | null = null;
private layoutVersion = 0;
private bitmap: ImageBitmap | null = null;
private viewportElement: GfxViewportElement | null = null;
private readonly refresh$ = new Subject<void>();
public get currentState(): RenderingState {
return this.state$.value;
}
constructor(gfx: GfxController) {
super(gfx);
@@ -12,8 +12,8 @@ import {
import {
INLINE_ROOT_ATTR,
type InlineRootElement,
ZERO_WIDTH_NON_JOINER,
ZERO_WIDTH_SPACE,
ZERO_WIDTH_FOR_EMBED_NODE,
ZERO_WIDTH_FOR_EMPTY_LINE,
} from '@blocksuite/std/inline';
import type { DeltaInsert } from '@blocksuite/store';
import { shift } from '@floating-ui/dom';
@@ -186,7 +186,7 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
return html`<span
${this.hidePopup ? '' : ref(this._whenHover.setReference)}
class=${nodeClasses}
>${node}<v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text
>${node}<v-text .str=${ZERO_WIDTH_FOR_EMBED_NODE}></v-text
></span>`;
}
@@ -195,7 +195,7 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
@property({ type: Object })
accessor delta: DeltaInsert<AffineTextAttributes> = {
insert: ZERO_WIDTH_SPACE,
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
attributes: {},
};
@@ -1,6 +1,6 @@
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import { ShadowlessElement } from '@blocksuite/std';
import { ZERO_WIDTH_SPACE } from '@blocksuite/std/inline';
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '@blocksuite/std/inline';
import type { DeltaInsert } from '@blocksuite/store';
import { html } from 'lit';
import { property } from 'lit/decorators.js';
@@ -50,6 +50,6 @@ export class LatexEditorUnit extends ShadowlessElement {
@property({ attribute: false })
accessor delta: DeltaInsert<AffineTextAttributes> = {
insert: ZERO_WIDTH_SPACE,
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
};
}
@@ -9,8 +9,8 @@ import {
} from '@blocksuite/std';
import {
type InlineEditor,
ZERO_WIDTH_NON_JOINER,
ZERO_WIDTH_SPACE,
ZERO_WIDTH_FOR_EMBED_NODE,
ZERO_WIDTH_FOR_EMPTY_LINE,
} from '@blocksuite/std/inline';
import type { DeltaInsert } from '@blocksuite/store';
import { signal } from '@preact/signals-core';
@@ -178,7 +178,7 @@ export class AffineLatexNode extends SignalWatcher(
override render() {
return html`<span class="affine-latex" data-selected=${this.selected}
><div class="latex-container"></div>
<v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text
<v-text .str=${ZERO_WIDTH_FOR_EMBED_NODE}></v-text
></span>`;
}
@@ -244,7 +244,7 @@ export class AffineLatexNode extends SignalWatcher(
@property({ attribute: false })
accessor delta: DeltaInsert<AffineTextAttributes> = {
insert: ZERO_WIDTH_SPACE,
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
};
@property({ attribute: false })
@@ -13,7 +13,7 @@ import { BLOCK_ID_ATTR, ShadowlessElement } from '@blocksuite/std';
import {
INLINE_ROOT_ATTR,
type InlineRootElement,
ZERO_WIDTH_SPACE,
ZERO_WIDTH_FOR_EMPTY_LINE,
} from '@blocksuite/std/inline';
import type { DeltaInsert } from '@blocksuite/store';
import { css, html } from 'lit';
@@ -177,7 +177,7 @@ export class AffineLink extends WithDisposable(ShadowlessElement) {
@property({ type: Object })
accessor delta: DeltaInsert<AffineTextAttributes> = {
insert: ZERO_WIDTH_SPACE,
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
};
@property({ attribute: false })
@@ -5,8 +5,8 @@ import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
import type { BlockStdScope } from '@blocksuite/std';
import { ShadowlessElement } from '@blocksuite/std';
import {
ZERO_WIDTH_NON_JOINER,
ZERO_WIDTH_SPACE,
ZERO_WIDTH_FOR_EMBED_NODE,
ZERO_WIDTH_FOR_EMPTY_LINE,
} from '@blocksuite/std/inline';
import type { DeltaInsert } from '@blocksuite/store';
import { css, html } from 'lit';
@@ -88,7 +88,7 @@ export class AffineMention extends SignalWatcher(
data-selected=${this.selected}
data-type="error"
class="affine-mention"
>@Unknown Member<v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text
>@Unknown Member<v-text .str=${ZERO_WIDTH_FOR_EMBED_NODE}></v-text
></span>`;
const userService = this.std.getOptional(UserProvider);
@@ -107,7 +107,7 @@ export class AffineMention extends SignalWatcher(
data-selected=${this.selected}
data-type="removed"
class="affine-mention"
>@Inactive Member<v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text
>@Inactive Member<v-text .str=${ZERO_WIDTH_FOR_EMBED_NODE}></v-text
></span>`;
} else {
return html`<span
@@ -115,7 +115,7 @@ export class AffineMention extends SignalWatcher(
data-type="default"
class="affine-mention"
>@${userInfo$.value.name ?? 'Unknown'}<v-text
.str=${ZERO_WIDTH_NON_JOINER}
.str=${ZERO_WIDTH_FOR_EMBED_NODE}
></v-text
></span>`;
}
@@ -129,7 +129,7 @@ export class AffineMention extends SignalWatcher(
>@loading<span class="dots"
><span class="dot">.</span><span class="dot">.</span
><span class="dot">.</span></span
><v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text
><v-text .str=${ZERO_WIDTH_FOR_EMBED_NODE}></v-text
></span>`;
}
@@ -138,7 +138,7 @@ export class AffineMention extends SignalWatcher(
@property({ type: Object })
accessor delta: DeltaInsert<AffineTextAttributes> = {
insert: ZERO_WIDTH_SPACE,
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
attributes: {},
};
@@ -1,7 +1,7 @@
import { affineTextStyles } from '@blocksuite/affine-shared/styles';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import { ShadowlessElement } from '@blocksuite/std';
import { ZERO_WIDTH_SPACE } from '@blocksuite/std/inline';
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '@blocksuite/std/inline';
import type { DeltaInsert } from '@blocksuite/store';
import { html } from 'lit';
import { property } from 'lit/decorators.js';
@@ -30,6 +30,6 @@ export class AffineText extends ShadowlessElement {
@property({ type: Object })
accessor delta: DeltaInsert<AffineTextAttributes> = {
insert: ZERO_WIDTH_SPACE,
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
};
}
@@ -22,8 +22,8 @@ import { BLOCK_ID_ATTR, ShadowlessElement } from '@blocksuite/std';
import {
INLINE_ROOT_ATTR,
type InlineRootElement,
ZERO_WIDTH_NON_JOINER,
ZERO_WIDTH_SPACE,
ZERO_WIDTH_FOR_EMBED_NODE,
ZERO_WIDTH_FOR_EMPTY_LINE,
} from '@blocksuite/std/inline';
import type { DeltaInsert, DocMeta, Store } from '@blocksuite/store';
import { css, html, nothing } from 'lit';
@@ -274,14 +274,14 @@ export class AffineReference extends WithDisposable(ShadowlessElement) {
>${title}</span
>`;
// we need to add `<v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text>` in an
// we need to add `<v-text .str=${ZERO_WIDTH_FOR_EMBED_NODE}></v-text>` in an
// embed element to make sure inline range calculation is correct
return html`<span
data-selected=${this.selected}
class="affine-reference"
style=${styleMap(style)}
@click=${(event: MouseEvent) => this.open({ event })}
>${content}<v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text
>${content}<v-text .str=${ZERO_WIDTH_FOR_EMBED_NODE}></v-text
></span>`;
}
@@ -299,7 +299,7 @@ export class AffineReference extends WithDisposable(ShadowlessElement) {
@property({ type: Object })
accessor delta: DeltaInsert<AffineTextAttributes> = {
insert: ZERO_WIDTH_SPACE,
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
attributes: {},
};
@@ -11,12 +11,16 @@ export const surfaceRefToEmbed =
}
});
slots.beforeImport.subscribe(payload => {
// only handle surface-ref block snapshot
if (
pageId &&
payload.type === 'block' &&
payload.snapshot.flavour === 'affine:surface-ref' &&
!std.store.hasBlock(payload.snapshot.id)
) {
payload.type !== 'block' ||
payload.snapshot.flavour !== 'affine:surface-ref'
)
return;
// turn into embed-linked-doc if the current doc is different from the pageId of the surface-ref block
const isNotSameDoc = pageId !== std.store.doc.id;
if (pageId && isNotSameDoc) {
// The blockId of the original surface-ref block
const blockId = payload.snapshot.id;
payload.snapshot.id = std.workspace.idGenerator();
@@ -15,3 +15,9 @@ export interface VirtualKeyboardProviderWithAction
export const VirtualKeyboardProvider = createIdentifier<
VirtualKeyboardProvider | VirtualKeyboardProviderWithAction
>('VirtualKeyboardProvider');
export function isVirtualKeyboardProviderWithAction(
provider: VirtualKeyboardProvider
): provider is VirtualKeyboardProviderWithAction {
return 'show' in provider && 'hide' in provider;
}
@@ -99,9 +99,6 @@ export class AffineDragHandleWidget extends WidgetComponent<RootBlockModel> {
}
this._anchorModelDisposables = new DisposableGroup();
this._anchorModelDisposables.add(
blockModel.propsUpdated.subscribe(() => this.hide())
);
this._anchorModelDisposables.add(
blockModel.deleted.subscribe(() => this.hide())
@@ -195,25 +195,25 @@ export class DragEventWatcher {
dragPayload: DragBlockPayload,
dropPayload: DropPayload
): DropResult | null => {
const model = dropBlock.model;
const dropModel = dropBlock.model;
const snapshot = dragPayload?.bsEntity?.snapshot;
if (
!snapshot ||
snapshot.content.length === 0 ||
!dragPayload?.from ||
matchModels(model, [DatabaseBlockModel])
matchModels(dropModel, [DatabaseBlockModel])
)
return null;
const isDropOnNoteBlock = matchModels(model, [NoteBlockModel]);
const isDropOnNoteBlock = matchModels(dropModel, [NoteBlockModel]);
const schema = this.std.store.schema;
const edge = dropPayload.edge;
const scale = this.widget.scale.peek();
let result: DropResult | null = null;
if (edge === 'right' && matchModels(dropBlock.model, [ListBlockModel])) {
if (edge === 'right' && matchModels(dropModel, [ListBlockModel])) {
const domRect = getRectByBlockComponent(dropBlock);
const placement = 'in';
@@ -279,7 +279,7 @@ export class DragEventWatcher {
placement,
rect: Rect.fromLWTH(domRect.left, domRect.width, y, 3 * scale),
modelState: {
model,
model: dropModel,
rect: domRect,
element: dropBlock,
},
@@ -548,145 +548,6 @@ export class DragEventWatcher {
if (!parent) return;
if (dragPayload.bsEntity?.fromMode === 'gfx') {
if (!matchModels(parent, [NoteBlockModel])) {
return;
}
// if not all blocks can be dropped in note block, merge the snapshot to the current doc
if (
!snapshot.content.every(block =>
schema.safeValidate(block.flavour, 'affine:note')
) &&
// if all blocks are note blocks, merge it to the current parent note
!snapshot.content.every(block => block.flavour === 'affine:note')
) {
// merge the snapshot to the current doc if the snapshot comes from other doc
if (dragPayload.from?.docId !== this.widget.doc.id) {
this._mergeSnapshotToCurDoc(snapshot)
.then(idRemap => {
let largestElem!: {
size: number;
id: string;
flavour: string;
};
idRemap.forEach(val => {
const gfxElement = this.gfx.getElementById(val) as GfxModel;
if (gfxElement?.elementBound) {
const elemBound = gfxElement.elementBound;
const flavour = isPrimitiveModel(gfxElement)
? gfxElement.type
: gfxElement.flavour;
largestElem =
(largestElem?.size ?? 0) < elemBound.w * elemBound.h
? { size: elemBound.w * elemBound.h, id: val, flavour }
: largestElem;
}
});
if (!largestElem) {
store.addBlock(
'affine:embed-linked-doc',
{
pageId: store.doc.id,
},
parent.id,
index
);
} else {
store.addBlock(
'affine:surface-ref',
{
reference: largestElem.id,
refFlavour: largestElem.flavour,
},
parent.id,
index
);
}
})
.catch(console.error);
}
// otherwise, just to create a surface-ref block
else {
let largestElem!: {
size: number;
id: string;
flavour: string;
};
const walk = (block: BlockSnapshot) => {
if (block.flavour === 'affine:surface') {
Object.values(
block.props.elements as Record<
string,
{ id: string; xywh: SerializedXYWH; type: string }
>
).forEach(elem => {
if (elem.xywh) {
const bound = Bound.deserialize(elem.xywh);
const size = bound.w * bound.h;
if ((largestElem?.size ?? 0) < size) {
largestElem = { size, id: elem.id, flavour: elem.type };
}
}
});
block.children.forEach(walk);
} else {
if (block.props.xywh) {
const bound = Bound.deserialize(
block.props.xywh as SerializedXYWH
);
const size = bound.w * bound.h;
if ((largestElem?.size ?? 0) < size) {
largestElem = { size, id: block.id, flavour: block.flavour };
}
}
}
};
snapshot.content.forEach(walk);
if (largestElem) {
store.addBlock(
'affine:surface-ref',
{
reference: largestElem.id,
refFlavour: largestElem.flavour,
},
parent.id,
index
);
} else {
store.addBlock(
'affine:embed-linked-doc',
{
pageId: store.doc.id,
},
parent.id,
index
);
}
}
return;
}
}
// drop a note on other note
if (matchModels(parent, [NoteBlockModel])) {
const [first] = snapshot.content;
if (first.flavour === 'affine:note') {
if (parent.id !== first.id) {
this._onDropNoteOnNote(snapshot, parent.id, index);
}
return;
}
}
// drop on the same place, do nothing
if (
(dragPayload.from?.docId === this.widget.doc.id &&
@@ -698,7 +559,148 @@ export class DragEventWatcher {
return;
}
this._dropToModel(snapshot, parent.id, index).catch(console.error);
// drop a note on other note
if (
matchModels(parent, [NoteBlockModel]) &&
snapshot.content.every(block => block.flavour === 'affine:note')
) {
snapshot.content = snapshot.content.filter(
block =>
dragPayload.from?.docId !== this.widget.doc.id ||
block.id !== parent.id
);
if (snapshot.content.length) {
this._onDropNoteOnNote(snapshot, parent.id, index);
}
return;
}
// all blocks can be safely dropped in the target parent
if (
snapshot.content.every(block =>
schema.safeValidate(block.flavour, parent.flavour)
)
) {
this._dropToModel(snapshot, parent.id, index).catch(console.error);
return;
}
if (
dragPayload.bsEntity?.fromMode === 'gfx' &&
matchModels(parent, [NoteBlockModel])
) {
// if the snapshot comes from the same doc, just create a surface-ref block
if (dragPayload.from?.docId === this.widget.doc.id) {
let largestElem!: {
size: number;
id: string;
flavour: string;
};
const walk = (block: BlockSnapshot) => {
if (block.flavour === 'affine:surface') {
Object.values(
block.props.elements as Record<
string,
{ id: string; xywh: SerializedXYWH; type: string }
>
).forEach(elem => {
if (elem.xywh) {
const bound = Bound.deserialize(elem.xywh);
const size = bound.w * bound.h;
if ((largestElem?.size ?? 0) < size) {
largestElem = { size, id: elem.id, flavour: elem.type };
}
}
});
block.children.forEach(walk);
} else {
if (block.props.xywh) {
const bound = Bound.deserialize(
block.props.xywh as SerializedXYWH
);
const size = bound.w * bound.h;
if ((largestElem?.size ?? 0) < size) {
largestElem = { size, id: block.id, flavour: block.flavour };
}
}
}
};
snapshot.content.forEach(walk);
if (largestElem) {
store.addBlock(
'affine:surface-ref',
{
reference: largestElem.id,
refFlavour: largestElem.flavour,
},
parent.id,
index
);
} else {
store.addBlock(
'affine:embed-linked-doc',
{
pageId: store.doc.id,
},
parent.id,
index
);
}
}
// otherwise, merge the snapshot into the current doc
// and create a surface-ref block or embed-linked-doc block
else {
this._mergeSnapshotToCurDoc(snapshot)
.then(idRemap => {
let largestElem!: {
size: number;
id: string;
flavour: string;
};
idRemap.forEach(val => {
const gfxElement = this.gfx.getElementById(val) as GfxModel;
if (gfxElement?.elementBound) {
const elemBound = gfxElement.elementBound;
const flavour = isPrimitiveModel(gfxElement)
? gfxElement.type
: gfxElement.flavour;
largestElem =
(largestElem?.size ?? 0) < elemBound.w * elemBound.h
? { size: elemBound.w * elemBound.h, id: val, flavour }
: largestElem;
}
});
if (!largestElem) {
store.addBlock(
'affine:embed-linked-doc',
{
pageId: store.doc.id,
},
parent.id,
index
);
} else {
store.addBlock(
'affine:surface-ref',
{
reference: largestElem.id,
refFlavour: largestElem.flavour,
},
parent.id,
index
);
}
})
.catch(console.error);
}
}
};
private readonly _onDrop = (
@@ -1,7 +1,4 @@
import {
EdgelessLegacySlotIdentifier,
type SurfaceBlockComponent,
} from '@blocksuite/affine-block-surface';
import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine-block-surface';
import { getSelectedRect } from '@blocksuite/affine-shared/utils';
import { type IVec, Rect } from '@blocksuite/global/gfx';
import {
@@ -54,20 +51,14 @@ export class EdgelessWatcher {
}
if (this.widget.isGfxDragHandleVisible) {
this._showDragHandle().catch(console.error);
this._showDragHandle();
this._updateDragHoverRectTopLevelBlock();
} else if (this.widget.activeDragHandle) {
this.widget.hide();
}
};
private readonly _showDragHandle = async () => {
const surfaceModel = this.widget.doc.getModelsByFlavour('affine:surface');
const surface = this.widget.std.view.getBlock(
surfaceModel[0]!.id
) as SurfaceBlockComponent;
await surface.updateComplete;
private readonly _showDragHandle = () => {
if (!this.widget.anchorBlockId) return;
const container = this.widget.dragHandleContainer;
@@ -119,7 +110,7 @@ export class EdgelessWatcher {
this.widget.anchorBlockId.value = selectedElement.id;
this._showDragHandle().catch(console.error);
this._showDragHandle();
};
get hoveredElemAreaRect() {
@@ -212,11 +203,27 @@ export class EdgelessWatcher {
})
);
disposables.add(
std.store.slots.blockUpdated.subscribe(payload => {
if (
this.widget.isGfxDragHandleVisible &&
payload.id === this.widget.anchorBlockId.peek()
) {
if (payload.type === 'delete') {
this.widget.hide();
}
if (payload.type === 'update') {
this._showDragHandle();
}
}
})
);
if (surface) {
disposables.add(
surface.elementUpdated.subscribe(() => {
if (this.widget.isGfxDragHandleVisible) {
this._showDragHandle().catch(console.error);
this._showDragHandle();
}
})
);
@@ -0,0 +1,43 @@
{
"name": "@blocksuite/affine-widget-linked-doc",
"description": "Affine linked doc widget.",
"type": "module",
"scripts": {
"build": "tsc"
},
"sideEffects": false,
"keywords": [],
"author": "toeverything",
"license": "MIT",
"dependencies": {
"@blocksuite/affine-block-image": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-inline-reference": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",
"@blocksuite/global": "workspace:*",
"@blocksuite/icons": "^2.2.10",
"@blocksuite/std": "workspace:*",
"@blocksuite/store": "workspace:*",
"@lit/context": "^1.1.2",
"@preact/signals-core": "^1.8.0",
"@toeverything/theme": "^1.1.12",
"@types/lodash-es": "^4.17.12",
"fflate": "^0.8.2",
"lit": "^3.2.0",
"lodash-es": "^4.17.21",
"rxjs": "^7.8.1"
},
"exports": {
".": "./src/index.ts",
"./effects": "./src/effects.ts"
},
"files": [
"src",
"dist",
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.21.0"
}
@@ -16,7 +16,12 @@ import {
isFuzzyMatch,
type Signal,
} from '@blocksuite/affine-shared/utils';
import type { BlockStdScope, EditorHost } from '@blocksuite/std';
import { IS_MOBILE } from '@blocksuite/global/env';
import {
type BlockStdScope,
ConfigExtensionFactory,
type EditorHost,
} from '@blocksuite/std';
import type { InlineRange } from '@blocksuite/std/inline';
import type { TemplateResult } from 'lit';
@@ -107,6 +112,7 @@ export type LinkedDocContext = {
std: BlockStdScope;
inlineEditor: AffineInlineEditor;
startRange: InlineRange;
startNativeRange: Range;
triggerKey: string;
config: LinkedWidgetConfig;
close: () => void;
@@ -171,73 +177,77 @@ export function createNewDocMenuGroup(
docName.slice(0, DISPLAY_NAME_LENGTH) +
(docName.length > DISPLAY_NAME_LENGTH ? '..' : '');
const items: LinkedMenuItem[] = [
{
key: 'create',
name: `Create "${displayDocName}" doc`,
icon: NewDocIcon,
action: () => {
abort();
const docName = query;
const newDoc = createDefaultDoc(doc.workspace, {
title: docName,
});
insertLinkedNode({
inlineEditor,
docId: newDoc.id,
});
const telemetryService = editorHost.std.getOptional(TelemetryProvider);
telemetryService?.track('LinkedDocCreated', {
control: 'new doc',
module: 'inline @',
type: 'doc',
other: 'new doc',
});
telemetryService?.track('DocCreated', {
control: 'new doc',
module: 'inline @',
type: 'doc',
});
},
},
];
if (!IS_MOBILE) {
items.push({
key: 'import',
name: 'Import',
icon: ImportIcon,
action: () => {
abort();
const onSuccess = (
docIds: string[],
options: {
importedCount: number;
}
) => {
toast(
editorHost,
`Successfully imported ${options.importedCount} Doc${options.importedCount > 1 ? 's' : ''}.`
);
for (const docId of docIds) {
insertLinkedNode({
inlineEditor,
docId,
});
}
};
const onFail = (message: string) => {
toast(editorHost, message);
};
showImportModal({
collection: doc.workspace,
schema: doc.schema,
onSuccess,
onFail,
});
},
});
}
return {
name: 'New Doc',
items: [
{
key: 'create',
name: `Create "${displayDocName}" doc`,
icon: NewDocIcon,
action: () => {
abort();
const docName = query;
const newDoc = createDefaultDoc(doc.workspace, {
title: docName,
});
insertLinkedNode({
inlineEditor,
docId: newDoc.id,
});
const telemetryService =
editorHost.std.getOptional(TelemetryProvider);
telemetryService?.track('LinkedDocCreated', {
control: 'new doc',
module: 'inline @',
type: 'doc',
other: 'new doc',
});
telemetryService?.track('DocCreated', {
control: 'new doc',
module: 'inline @',
type: 'doc',
});
},
},
{
key: 'import',
name: 'Import',
icon: ImportIcon,
action: () => {
abort();
const onSuccess = (
docIds: string[],
options: {
importedCount: number;
}
) => {
toast(
editorHost,
`Successfully imported ${options.importedCount} Doc${options.importedCount > 1 ? 's' : ''}.`
);
for (const docId of docIds) {
insertLinkedNode({
inlineEditor,
docId,
});
}
};
const onFail = (message: string) => {
toast(editorHost, message);
};
showImportModal({
collection: doc.workspace,
schema: doc.schema,
onSuccess,
onFail,
});
},
},
],
items,
};
}
@@ -260,3 +270,7 @@ export const LinkedWidgetUtils = {
};
export const AFFINE_LINKED_DOC_WIDGET = 'affine-linked-doc-widget';
export const LinkedWidgetConfigExtension = ConfigExtensionFactory<
Partial<LinkedWidgetConfig>
>('affine:widget-linked-doc');
@@ -1,5 +1,6 @@
import { AFFINE_LINKED_DOC_WIDGET } from './config.js';
import { ImportDoc } from './import-doc/import-doc.js';
import { Loader } from './import-doc/loader.js';
import { AffineLinkedDocWidget } from './index.js';
import { LinkedDocPopover } from './linked-doc-popover.js';
import { AffineMobileLinkedDocMenu } from './mobile-linked-doc-menu.js';
@@ -8,9 +9,9 @@ export function effects() {
customElements.define('affine-linked-doc-popover', LinkedDocPopover);
customElements.define(AFFINE_LINKED_DOC_WIDGET, AffineLinkedDocWidget);
customElements.define('import-doc', ImportDoc);
customElements.define(
'affine-mobile-linked-doc-menu',
AffineMobileLinkedDocMenu
);
customElements.define('loader-element', Loader);
}
@@ -12,9 +12,9 @@ import type { Schema, Workspace } from '@blocksuite/store';
import { html, LitElement, type PropertyValues } from 'lit';
import { query, state } from 'lit/decorators.js';
import { HtmlTransformer } from '../../../transformers/html.js';
import { MarkdownTransformer } from '../../../transformers/markdown.js';
import { NotionHtmlTransformer } from '../../../transformers/notion-html.js';
import { HtmlTransformer } from '../transformers/html.js';
import { MarkdownTransformer } from '../transformers/markdown.js';
import { NotionHtmlTransformer } from '../transformers/notion-html.js';
import { styles } from './styles.js';
export type OnSuccessHandler = (
@@ -0,0 +1,4 @@
export * from './config';
export * from './import-doc';
export * from './transformers';
export * from './widget';
@@ -7,7 +7,6 @@ import {
import { unsafeCSSVar } from '@blocksuite/affine-shared/theme';
import {
createKeydownObserver,
getCurrentNativeRange,
getPopperPosition,
getViewportElement,
} from '@blocksuite/affine-shared/utils';
@@ -160,11 +159,15 @@ export class LinkedDocPopover extends SignalWatcher(
// init
this._updateLinkedDocGroup().catch(console.error);
this._disposables.addFromEvent(this, 'mousedown', e => {
this._disposables.addFromEvent(this, 'pointerdown', e => {
// Prevent input from losing focus
e.preventDefault();
});
this._disposables.addFromEvent(window, 'mousedown', e => {
this._disposables.addFromEvent(this, 'mousedown', e => {
// Prevent input from losing focus in electron
e.preventDefault();
});
this._disposables.addFromEvent(window, 'pointerdown', e => {
if (e.target === this) return;
// We don't clear the query when clicking outside the popover
this.context.close();
@@ -338,11 +341,8 @@ export class LinkedDocPopover extends SignalWatcher(
override willUpdate() {
if (!this.hasUpdated) {
const curRange = getCurrentNativeRange();
if (!curRange) return;
const updatePosition = throttle(() => {
this._position = getPopperPosition(this, curRange);
this._position = getPopperPosition(this, this.context.startNativeRange);
}, 10);
this.disposables.addFromEvent(window, 'resize', updatePosition);
@@ -3,10 +3,7 @@ import {
getTextContentFromInlineRange,
} from '@blocksuite/affine-rich-text';
import { VirtualKeyboardProvider } from '@blocksuite/affine-shared/services';
import {
createKeydownObserver,
getViewportElement,
} from '@blocksuite/affine-shared/utils';
import { getViewportElement } from '@blocksuite/affine-shared/utils';
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
import { MoreHorizontalIcon } from '@blocksuite/icons/lit';
import { PropTypes, requiredProperties } from '@blocksuite/std';
@@ -16,7 +13,6 @@ import { property } from 'lit/decorators.js';
import { join } from 'lit/directives/join.js';
import { repeat } from 'lit/directives/repeat.js';
import { PageRootBlockComponent } from '../../index.js';
import type {
LinkedDocContext,
LinkedMenuGroup,
@@ -29,7 +25,6 @@ export const AFFINE_MOBILE_LINKED_DOC_MENU = 'affine-mobile-linked-doc-menu';
@requiredProperties({
context: PropTypes.object,
rootComponent: PropTypes.instanceOf(PageRootBlockComponent),
})
export class AffineMobileLinkedDocMenu extends SignalWatcher(
WithDisposable(LitElement)
@@ -38,8 +33,6 @@ export class AffineMobileLinkedDocMenu extends SignalWatcher(
private readonly _expand = new Set<string>();
private _firstActionItem: LinkedMenuItem | null = null;
private readonly _linkedDocGroup$ = signal<LinkedMenuGroup[]>([]);
private readonly _renderGroup = (group: LinkedMenuGroup) => {
@@ -189,42 +182,14 @@ export class AffineMobileLinkedDocMenu extends SignalWatcher(
const keydownObserverAbortController = new AbortController();
this._disposables.add(() => keydownObserverAbortController.abort());
createKeydownObserver({
target: eventSource,
signal: keydownObserverAbortController.signal,
onInput: isComposition => {
if (isComposition) {
this._updateLinkedDocGroup().catch(console.error);
} else {
const subscription = inlineEditor.slots.renderComplete.subscribe(
() => {
subscription.unsubscribe();
this._updateLinkedDocGroup().catch(console.error);
}
);
}
},
onDelete: () => {
const subscription = inlineEditor.slots.renderComplete.subscribe(
() => {
subscription.unsubscribe();
const curRange = inlineEditor.getInlineRange();
if (!this.context.startRange || !curRange) return;
if (curRange.index < this.context.startRange.index) {
this.context.close();
}
this._updateLinkedDocGroup().catch(console.error);
}
);
},
onConfirm: () => {
this._firstActionItem?.action()?.catch(console.error);
},
onAbort: () => {
// we need use beforeinput because the event.key of keypress event usually is `Unidentified` in Android
this.disposables.addFromEvent(eventSource, 'beforeinput', () => {
const curRange = inlineEditor.getInlineRange();
if (curRange && curRange.index < this.context.startRange.index) {
this.context.close();
},
return;
}
this._updateLinkedDocGroup().catch(console.error);
});
}
}
@@ -239,8 +204,6 @@ export class AffineMobileLinkedDocMenu extends SignalWatcher(
return nothing;
}
this._firstActionItem = resolveSignal(groups[0].items)[0];
this.style.bottom = `${this.keyboard.height$.value}px`;
return html`
@@ -250,7 +213,4 @@ export class AffineMobileLinkedDocMenu extends SignalWatcher(
@property({ attribute: false })
accessor context!: LinkedDocContext;
@property({ attribute: false })
accessor rootComponent!: PageRootBlockComponent;
}
@@ -6,7 +6,7 @@ import { sha } from '@blocksuite/global/utils';
import type { DocSnapshot, Schema, Store, Workspace } from '@blocksuite/store';
import { extMimeMap, getAssetName, Transformer } from '@blocksuite/store';
import { download, Unzip, Zip } from '../transformers/utils.js';
import { download, Unzip, Zip } from './utils.js';
async function exportDocs(
collection: Workspace,
@@ -7,7 +7,11 @@ import { FeatureFlagService } from '@blocksuite/affine-shared/services';
import { getViewportElement } from '@blocksuite/affine-shared/utils';
import { IS_MOBILE } from '@blocksuite/global/env';
import type { BlockComponent } from '@blocksuite/std';
import { BLOCK_ID_ATTR, WidgetComponent } from '@blocksuite/std';
import {
BLOCK_ID_ATTR,
WidgetComponent,
WidgetViewExtension,
} from '@blocksuite/std';
import { GfxControllerIdentifier } from '@blocksuite/std/gfx';
import {
INLINE_ROOT_ATTR,
@@ -19,22 +23,18 @@ import { html, nothing } from 'lit';
import { choose } from 'lit/directives/choose.js';
import { repeat } from 'lit/directives/repeat.js';
import { styleMap } from 'lit/directives/style-map.js';
import { literal, unsafeStatic } from 'lit/static-html.js';
import type { PageRootBlockComponent } from '../../page/page-root-block.js';
import { RootBlockConfigExtension } from '../../root-config.js';
import {
type AFFINE_LINKED_DOC_WIDGET,
AFFINE_LINKED_DOC_WIDGET,
getMenus,
type LinkedDocContext,
type LinkedWidgetConfig,
LinkedWidgetConfigExtension,
} from './config.js';
import { linkedDocWidgetStyles } from './styles.js';
export { type LinkedWidgetConfig } from './config.js';
export class AffineLinkedDocWidget extends WidgetComponent<
RootBlockModel,
PageRootBlockComponent
> {
export class AffineLinkedDocWidget extends WidgetComponent<RootBlockModel> {
static override styles = linkedDocWidgetStyles;
private _context: LinkedDocContext | null = null;
@@ -43,6 +43,19 @@ export class AffineLinkedDocWidget extends WidgetComponent<
private readonly _mode$ = signal<'desktop' | 'mobile' | 'none'>('none');
private _addTriggerKey(inlineEditor: InlineEditor, triggerKey: string) {
const inlineRange = inlineEditor.getInlineRange();
if (!inlineRange) return;
inlineEditor.insertText(
{ index: inlineRange.index, length: 0 },
triggerKey
);
inlineEditor.setInlineRange({
index: inlineRange.index + triggerKey.length,
length: 0,
});
}
private _updateInputRects() {
if (!this._context) return;
const { inlineEditor, startRange, triggerKey } = this._context;
@@ -217,8 +230,7 @@ export class AffineLinkedDocWidget extends WidgetComponent<
scrollContainer: getViewportElement(this.std.host) ?? window,
scrollTopOffset: 46,
},
...this.std.getOptional(RootBlockConfigExtension.identifier)
?.linkedWidget,
...this.std.getOptional(LinkedWidgetConfigExtension.identifier),
};
}
@@ -259,27 +271,30 @@ export class AffineLinkedDocWidget extends WidgetComponent<
inlineEditor = props.inlineEditor;
}
const inlineRange = inlineEditor.getInlineRange();
if (!inlineRange) return;
if (addTriggerKey) {
inlineEditor.insertText(
{ index: inlineRange.index, length: 0 },
primaryTriggerKey
);
inlineEditor.setInlineRange({
index: inlineRange.index + primaryTriggerKey.length,
length: 0,
this._addTriggerKey(inlineEditor, primaryTriggerKey);
// we need to wait the range sync to get the correct startNativeRange
const subscription = inlineEditor.slots.inlineRangeSync.subscribe(() => {
this.show({ ...props, addTriggerKey: false });
subscription.unsubscribe();
});
return;
}
const startRange = inlineEditor.getInlineRange();
if (!startRange) return;
const startNativeRange = inlineEditor.getNativeRange();
if (!startNativeRange) return;
const disposable = inlineEditor.slots.renderComplete.subscribe(() => {
this._updateInputRects();
});
this._context = {
std: this.std,
inlineEditor,
startRange: inlineRange,
startRange,
startNativeRange,
triggerKey: primaryTriggerKey,
config: this.config,
close: () => {
@@ -316,6 +331,12 @@ export class AffineLinkedDocWidget extends WidgetComponent<
}
}
export const linkedDocWidget = WidgetViewExtension(
'affine:page',
AFFINE_LINKED_DOC_WIDGET,
literal`${unsafeStatic(AFFINE_LINKED_DOC_WIDGET)}`
);
declare global {
interface HTMLElementTagNameMap {
[AFFINE_LINKED_DOC_WIDGET]: AffineLinkedDocWidget;
@@ -0,0 +1,20 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist",
"tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo"
},
"include": ["./src"],
"references": [
{ "path": "../../blocks/image" },
{ "path": "../../components" },
{ "path": "../../inlines/reference" },
{ "path": "../../model" },
{ "path": "../../rich-text" },
{ "path": "../../shared" },
{ "path": "../../../framework/global" },
{ "path": "../../../framework/std" },
{ "path": "../../../framework/store" }
]
}
@@ -115,8 +115,8 @@ export class ElementTransformManager extends GfxExtension {
fallback: lockedElement !== picked,
};
view?.onSelected(context);
return true;
const selected = view?.onSelected(context);
return selected ?? true;
}
return false;
@@ -193,13 +193,15 @@ export class GfxElementModelView<
this.model.xywh = currentBound.moveDelta(dx, dy).serialize();
}
onSelected(context: SelectedContext) {
onSelected(context: SelectedContext): void | boolean {
if (this.model instanceof GfxPrimitiveElementModel) {
if (context.multiSelect) {
this.gfx.selection.toggle(this.model);
} else {
this.gfx.selection.set({ elements: [this.model.id] });
}
return true;
}
}
@@ -7,7 +7,7 @@ import { html, LitElement } from 'lit';
import { property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { ZERO_WIDTH_SPACE } from '../consts.js';
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js';
import type { InlineEditor } from '../inline-editor.js';
import { isInlineRangeIntersect } from '../utils/inline-range.js';
@@ -90,7 +90,7 @@ export class VElement<
@property({ type: Object })
accessor delta: DeltaInsert<T> = {
insert: ZERO_WIDTH_SPACE,
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
};
@property({ attribute: false })
@@ -4,7 +4,7 @@ import { html, LitElement, type TemplateResult } from 'lit';
import { property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { INLINE_ROOT_ATTR, ZERO_WIDTH_SPACE } from '../consts.js';
import { INLINE_ROOT_ATTR, ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js';
import type { InlineRootElement } from '../inline-editor.js';
import { EmbedGap } from './embed-gap.js';
@@ -89,7 +89,9 @@ export class VLine extends LitElement {
renderVElements() {
if (this.elements.length === 0) {
// don't use v-element because it not correspond to the actual delta
return html`<div><v-text .str=${ZERO_WIDTH_SPACE}></v-text></div>`;
return html`
<div><v-text .str=${ZERO_WIDTH_FOR_EMPTY_LINE}></v-text></div>
`;
}
const inlineEditor = this.inlineEditor;
@@ -2,7 +2,7 @@ import { html, LitElement } from 'lit';
import { property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { ZERO_WIDTH_SPACE } from '../consts.js';
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js';
export class VText extends LitElement {
override createRenderRoot() {
@@ -24,7 +24,7 @@ export class VText extends LitElement {
}
@property({ attribute: false })
accessor str: string = ZERO_WIDTH_SPACE;
accessor str: string = ZERO_WIDTH_FOR_EMPTY_LINE;
}
declare global {
@@ -1,5 +1,6 @@
export const ZERO_WIDTH_SPACE = '\u200C';
// see https://en.wikipedia.org/wiki/Zero-width_non-joiner
export const ZERO_WIDTH_NON_JOINER = '\u200B';
import { IS_SAFARI } from '@blocksuite/global/env';
export const ZERO_WIDTH_FOR_EMPTY_LINE = IS_SAFARI ? '\u200C' : '\u200B';
export const ZERO_WIDTH_FOR_EMBED_NODE = IS_SAFARI ? '\u200B' : '\u200C';
export const INLINE_ROOT_ATTR = 'data-v-root';
@@ -1,7 +1,7 @@
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import type { VElement, VLine } from '../components/index.js';
import { INLINE_ROOT_ATTR, ZERO_WIDTH_SPACE } from '../consts.js';
import { INLINE_ROOT_ATTR, ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js';
import type { DomPoint, TextPoint } from '../types.js';
import {
isInlineRoot,
@@ -76,7 +76,7 @@ export function textPointToDomPoint(
index += calculateTextLength(text);
}
if (text.wholeText !== ZERO_WIDTH_SPACE) {
if (text.wholeText !== ZERO_WIDTH_FOR_EMPTY_LINE) {
index += offset;
}
@@ -1,7 +1,7 @@
import { ZERO_WIDTH_SPACE } from '../consts.js';
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js';
export function calculateTextLength(text: Text): number {
if (text.wholeText === ZERO_WIDTH_SPACE) {
if (text.wholeText === ZERO_WIDTH_FOR_EMPTY_LINE) {
return 0;
} else {
return text.wholeText.length;
@@ -103,12 +103,14 @@ export abstract class GfxBlockComponent<
this.model.pop('xywh');
}
onSelected(context: SelectedContext) {
onSelected(context: SelectedContext): void | boolean {
if (context.multiSelect) {
this.gfx.selection.toggle(this.model);
} else {
this.gfx.selection.set({ elements: [this.model.id] });
}
return true;
}
onRotate() {}
@@ -219,12 +221,14 @@ export function toGfxBlockComponent<
}
// eslint-disable-next-line sonarjs/no-identical-functions
onSelected(context: SelectedContext) {
onSelected(context: SelectedContext): void | boolean {
if (context.multiSelect) {
this.gfx.selection.toggle(this.model);
} else {
this.gfx.selection.set({ elements: [this.model.id] });
}
return true;
}
onRotate() {}
+27
View File
@@ -1,3 +1,30 @@
# `@blocksuite/integration-test`
Integration test for BlockSuite.
## Running Tests
You can run all integration tests using:
```bash
cd blocksuite/integration-test
yarn test:unit
```
To run a specific test or test file, use the `-t` flag with a test name pattern:
```bash
# Run a specific test
yarn test:unit -t "should access turbo renderer instance"
# Run all tests in a specific file
yarn test:unit src/__tests__/edgeless/viewport-renderer.spec.ts
```
For debugging tests with the Playwright debugger:
```bash
yarn test:debug
yarn test:debug -t "should access turbo renderer instance"
```
@@ -0,0 +1,109 @@
/**
* Please refer to integration-test/README.md for commands to run tests.
*/
import { ParagraphLayoutHandlerExtension } from '@blocksuite/affine/blocks/paragraph';
import { noop } from '@blocksuite/affine/global/utils';
import {
TurboRendererConfigFactory,
ViewportTurboRendererExtension,
} from '@blocksuite/affine-gfx-turbo-renderer';
import { beforeEach, describe, expect, test } from 'vitest';
import { wait } from '../utils/common.js';
import { addSampleNotes } from '../utils/doc-generator.js';
import {
createPainterWorker,
getRenderer,
setupEditor,
} from '../utils/setup.js';
describe('viewport turbo renderer', () => {
beforeEach(async () => {
const cleanup = await setupEditor('edgeless', [
ParagraphLayoutHandlerExtension,
TurboRendererConfigFactory({
painterWorkerEntry: createPainterWorker,
}),
ViewportTurboRendererExtension,
]);
return cleanup;
});
test('should render 6 notes in viewport', async () => {
addSampleNotes(doc, 6);
await wait();
const notes = document.querySelectorAll('affine-edgeless-note');
expect(notes.length).toBe(6);
});
test('should access turbo renderer instance', async () => {
const renderer = getRenderer();
expect(renderer).toBeDefined();
expect(renderer instanceof ViewportTurboRendererExtension).toBe(true);
expect(renderer.canvas).toBeInstanceOf(HTMLCanvasElement);
});
test('initial state should be pending', async () => {
const renderer = getRenderer();
expect(renderer.state$.value).toBe('pending');
});
test('zooming should change state to zooming', async () => {
const renderer = getRenderer();
renderer.viewport.zooming$.next(true);
await wait();
expect(renderer.state$.value).toBe('zooming');
renderer.viewport.zooming$.next(false);
await wait();
expect(renderer.state$.value).not.toBe('zooming');
});
test('state transitions between pending and ready', async () => {
const renderer = getRenderer();
// Initial state should be pending after adding content
addSampleNotes(doc, 1);
await wait(100); // Short wait for initial processing
expect(renderer.state$.value).toBe('pending');
// Ensure zooming is off and wait for debounce + buffer
renderer.viewport.zooming$.next(false);
await wait(renderer.options.debounceTime + 500);
expect(renderer.state$.value).toBe('ready');
});
test('initial layout cache data should be null', () => {
const renderer = getRenderer();
expect(renderer.layoutCacheData).toBeNull();
});
test('invalidation should reset layout cache data to null', async () => {
const renderer = getRenderer();
addSampleNotes(doc, 1);
await wait(100);
// Access getter to populate cache
const _cache = renderer.layoutCache;
noop(_cache);
expect(renderer.layoutCacheData).not.toBeNull();
// Invalidate
addSampleNotes(doc, 1);
await wait(100);
expect(renderer.layoutCacheData).toBeNull();
});
test('accessing layoutCache getter should populate cache data', async () => {
const renderer = getRenderer();
addSampleNotes(doc, 1);
await wait();
expect(renderer.layoutCacheData).toBeNull(); // Check internal state before access
const _cache = renderer.layoutCache; // Access getter to populate cache
noop(_cache);
expect(renderer.layoutCacheData).not.toBeNull(); // Check internal state after access
expect(renderer.layoutCache?.roots.length).toBeGreaterThan(0); // Check public getter result
});
});
@@ -1,31 +0,0 @@
import { ParagraphLayoutHandlerExtension } from '@blocksuite/affine/blocks/paragraph';
import {
TurboRendererConfigFactory,
ViewportTurboRendererExtension,
} from '@blocksuite/affine-gfx-turbo-renderer';
import { beforeEach, describe, expect, test } from 'vitest';
import { wait } from '../utils/common.js';
import { addSampleNotes } from '../utils/doc-generator.js';
import { createPainterWorker, setupEditor } from '../utils/setup.js';
describe('viewport turbo renderer', () => {
beforeEach(async () => {
const cleanup = await setupEditor('edgeless', [
ParagraphLayoutHandlerExtension,
TurboRendererConfigFactory({
painterWorkerEntry: createPainterWorker,
}),
ViewportTurboRendererExtension,
]);
return cleanup;
});
test('should render 6 notes in viewport', async () => {
addSampleNotes(doc, 6);
await wait();
const notes = document.querySelectorAll('affine-edgeless-note');
expect(notes.length).toBe(6);
});
});
@@ -1,6 +1,6 @@
import { ZipTransformer } from '@blocksuite/affine/blocks/root';
import type { SurfaceBlockModel } from '@blocksuite/affine/blocks/surface';
import { AffineSchemas } from '@blocksuite/affine/schemas';
import { ZipTransformer } from '@blocksuite/affine/widgets/linked-doc';
import type { PointLocation } from '@blocksuite/global/gfx';
import { Schema } from '@blocksuite/store';
import { beforeEach, expect, test } from 'vitest';
@@ -1,3 +1,4 @@
import { ImageLayoutHandlerExtension } from '@blocksuite/affine/blocks/image';
import { ListLayoutHandlerExtension } from '@blocksuite/affine/blocks/list';
import { ParagraphLayoutHandlerExtension } from '@blocksuite/affine/blocks/paragraph';
import {
@@ -13,6 +14,7 @@ async function init() {
setupEditor('edgeless', [
ParagraphLayoutHandlerExtension,
ListLayoutHandlerExtension,
ImageLayoutHandlerExtension,
TurboRendererConfigFactory({
painterWorkerEntry: createPainterWorker,
}),
@@ -8,29 +8,36 @@ import {
registerStoreSpecs,
StoreExtensions,
} from '@blocksuite/affine/extensions';
import type { ExtensionType, Store, Transformer } from '@blocksuite/store';
import { effects } from '../../effects.js';
registerStoreSpecs();
blocksEffects();
effects();
import type { DocMode } from '@blocksuite/affine/model';
import { AffineSchemas } from '@blocksuite/affine/schemas';
import {
CommunityCanvasTextFonts,
FontConfigExtension,
} from '@blocksuite/affine/shared/services';
import type { ViewportTurboRendererExtension } from '@blocksuite/affine-gfx-turbo-renderer';
import {
type ViewportTurboRendererExtension,
ViewportTurboRendererIdentifier,
} from '@blocksuite/affine-gfx-turbo-renderer';
import type { ExtensionType, Store, Transformer } from '@blocksuite/store';
import { Schema, Text } from '@blocksuite/store';
import {
createAutoIncrementIdGenerator,
TestWorkspace,
} from '@blocksuite/store/test';
import { effects } from '../../effects.js';
import { TestAffineEditorContainer } from '../../index.js';
registerStoreSpecs();
blocksEffects();
effects();
export function getRenderer() {
return editor.std.get(
ViewportTurboRendererIdentifier
) as ViewportTurboRendererExtension;
}
function createCollectionOptions() {
const schema = new Schema();
const room = Math.random().toString(16).slice(2, 8);
@@ -1,3 +1,4 @@
import { ImageLayoutPainterExtension } from '@blocksuite/affine-block-image/turbo-painter';
import { ListLayoutPainterExtension } from '@blocksuite/affine-block-list/turbo-painter';
import { NoteLayoutPainterExtension } from '@blocksuite/affine-block-note/turbo-painter';
import { ParagraphLayoutPainterExtension } from '@blocksuite/affine-block-paragraph/turbo-painter';
@@ -7,4 +8,5 @@ new ViewportLayoutPainter([
ParagraphLayoutPainterExtension,
ListLayoutPainterExtension,
NoteLayoutPainterExtension,
ImageLayoutPainterExtension,
]);
+1 -2
View File
@@ -18,10 +18,9 @@ export default defineConfig(_configEnv =>
browser: {
enabled: true,
headless: process.env.CI === 'true',
name: 'chromium',
instances: [{ browser: 'chromium' }],
provider: 'playwright',
isolate: false,
providerOptions: {},
viewport: {
width: 1024,
height: 768,
@@ -17,14 +17,6 @@ import '@shoelace-style/shoelace/dist/themes/dark.css';
import './left-side-panel.js';
import { defaultImageProxyMiddleware } from '@blocksuite/affine/blocks/image';
import {
createAssetsArchive,
download,
HtmlTransformer,
MarkdownTransformer,
NotionHtmlTransformer,
ZipTransformer,
} from '@blocksuite/affine/blocks/root';
import { ExportManager } from '@blocksuite/affine/blocks/surface';
import { toast } from '@blocksuite/affine/components/toast';
import {
@@ -55,6 +47,14 @@ import {
Text,
type Workspace,
} from '@blocksuite/affine/store';
import {
createAssetsArchive,
download,
HtmlTransformer,
MarkdownTransformer,
NotionHtmlTransformer,
ZipTransformer,
} from '@blocksuite/affine/widgets/linked-doc';
import { NotionHtmlAdapter } from '@blocksuite/affine-shared/adapters';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import { TestAffineEditorContainer } from '@blocksuite/integration-test';

Some files were not shown because too many files have changed in this diff Show More