From 391b3cab70a5a49ad65baaab9eea1a9d63e93a9f Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 9 Oct 2024 14:50:59 +0800 Subject: [PATCH 001/121] Revert "chore: viteconf 24 cta (#2953)" This reverts commit 3ba5add9ca593e4fa21b02a3c57e8d0745887562. --- .vitepress/theme/components/SponsorsAside.vue | 72 +------------------ src/public/viteconf.svg | 24 ------- 2 files changed, 1 insertion(+), 95 deletions(-) delete mode 100644 src/public/viteconf.svg diff --git a/.vitepress/theme/components/SponsorsAside.vue b/.vitepress/theme/components/SponsorsAside.vue index eff6a97fd8..879ae16729 100644 --- a/.vitepress/theme/components/SponsorsAside.vue +++ b/.vitepress/theme/components/SponsorsAside.vue @@ -5,18 +5,6 @@ const { frontmatter } = useData() From f7a80d4eac57d45f170cd8ae50e88613b703017f Mon Sep 17 00:00:00 2001 From: Evan You Date: Mon, 11 Nov 2024 21:49:53 +0800 Subject: [PATCH 026/121] move hcy and rahul to team emiriti --- src/about/team/members-core.json | 44 ----------------------------- src/about/team/members-emeriti.json | 44 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/about/team/members-core.json b/src/about/team/members-core.json index 6df9b31ddb..33a12cc625 100644 --- a/src/about/team/members-core.json +++ b/src/about/team/members-core.json @@ -169,34 +169,6 @@ }, "sponsor": true }, - { - "name": "Rahul Kadyan", - "title": "Software Engineer", - "company": "Grammarly", - "companyLink": "https://grammarly.com/", - "projects": [ - { - "label": "vuejs/core", - "url": "https://github.com/vuejs/core" - }, - { "label": "VueDX", "url": "https://github.com/vuedx" }, - { - "label": "rollup-plugin-vue", - "url": "https://github.com/vuejs/rollup-plugin-vue" - } - ], - "location": "Bangalore, India", - "languages": ["Hindi", "English"], - "socials": { - "github": "znck", - "twitter": "znck0" - }, - "website": { - "label": "https://znck.me/", - "url": "https://znck.me/" - }, - "sponsor": true - }, { "name": "Linusborg", "title": "Hive-Mind Community Wrangler (Probably a Bot)", @@ -429,22 +401,6 @@ }, "sponsor": true }, - { - "name": "HcySunYang", - "title": "Developer", - "projects": [ - { - "label": "vuejs/core", - "url": "https://github.com/vuejs/core" - } - ], - "location": "Beijing, China", - "languages": ["Chinese", "English"], - "socials": { - "github": "HcySunYang", - "twitter": "HcySunYang" - } - }, { "name": "Johnson Chu", "title": "Developer", diff --git a/src/about/team/members-emeriti.json b/src/about/team/members-emeriti.json index 9d1d5aac94..bfc036c572 100644 --- a/src/about/team/members-emeriti.json +++ b/src/about/team/members-emeriti.json @@ -258,5 +258,49 @@ "twitter": "DamianDulisz" }, "sponsor": true + }, + { + "name": "HcySunYang", + "title": "Developer", + "projects": [ + { + "label": "vuejs/core", + "url": "https://github.com/vuejs/core" + } + ], + "location": "Beijing, China", + "languages": ["Chinese", "English"], + "socials": { + "github": "HcySunYang", + "twitter": "HcySunYang" + } + }, + { + "name": "Rahul Kadyan", + "title": "Software Engineer", + "company": "Grammarly", + "companyLink": "https://grammarly.com/", + "projects": [ + { + "label": "vuejs/core", + "url": "https://github.com/vuejs/core" + }, + { "label": "VueDX", "url": "https://github.com/vuedx" }, + { + "label": "rollup-plugin-vue", + "url": "https://github.com/vuejs/rollup-plugin-vue" + } + ], + "location": "Bangalore, India", + "languages": ["Hindi", "English"], + "socials": { + "github": "znck", + "twitter": "znck0" + }, + "website": { + "label": "https://znck.me/", + "url": "https://znck.me/" + }, + "sponsor": true } ] From dcf9415318cb6c4105b51dd83852304988f065c2 Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 14 Nov 2024 00:22:10 +0800 Subject: [PATCH 027/121] add funding.json --- src/public/funding.json | 120 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 src/public/funding.json diff --git a/src/public/funding.json b/src/public/funding.json new file mode 100644 index 0000000000..c436bcfa0e --- /dev/null +++ b/src/public/funding.json @@ -0,0 +1,120 @@ +{ + "version": "v1.0.0", + + "entity": { + "type": "organisation", + "role": "owner", + "name": "Vue Technology LLC", + "email": "evan@vuejs.org", + "phone": "", + "description": "Vue Technology LLC is the legal entity representing Vue's business operations and fund distribution to team members", + "webpageUrl": { + "url": "https://vuejs.org/", + "wellKnown": "" + } + }, + + "projects": [ + { + "guid": "vuejs", + "name": "Vue.js", + "description": "Vue.js is one of the most widely adopted frontend frameworks, with over 5.5 million weekly downloads and 2 million weekly active users. It is also the technology powering Zerodha's frontend.", + "webpageUrl": { + "url": "https://vuejs.org/", + "wellKnown": "" + }, + "repositoryUrl": { + "url": "https://github.com/vuejs/core", + "wellKnown": "https://github.com/vuejs/core/blob/main/.well-known/funding-manifest-urls" + }, + "licenses": ["spdx:MIT"], + "tags": ["frontend", "javascript", "web-development", "ui"] + } + ], + + "funding": { + "channels": [ + { + "guid": "github-sponsors", + "type": "other", + "address": "https://github.com/sponsors/yyx990803", + "description": "GitHub supports payment via credit card or invoice-based billing." + }, + { + "guid": "open-collective", + "type": "other", + "address": "https://opencollective.com/vuejs", + "description": "OpenCollective supports payment via credit card, Google Pay, or US bank ACH transfer." + }, + { + "guid": "bank-of-america", + "type": "bank", + "address": "", + "description": "For donations via bank transfers, please get in touch for bank details." + } + ], + + "plans": [ + { + "guid": "special", + "status": "active", + "name": "Global Special Sponsor", + "description": "Exclusive above-the-fold logo placement on vuejs.org home page / Most prominent logo placement in on the right sidebar of every content page on vuejs.org (3M+ page views per month / 500k+ unique MAU) / Most prominent logo placement in the README and BACKERS files of the vuejs/core repo.", + "amount": 5000, + "currency": "USD", + "frequency": "monthly", + "channels": [ + "github-sponsors", + "open-collective", + "bank-of-america" + ] + }, + { + "guid": "platinum", + "status": "active", + "name": "Platinum Sponsor", + "description": "Logo on the right sidebar of every content page on vuejs.org (3M+ page views per month / 500k+ unique MAU) / Large logo placement on vuejs.org front page + sponsors page + in the README and BACKERS files of the vuejs/core repo.", + "amount": 2000, + "currency": "USD", + "frequency": "monthly", + "channels": [ + "github-sponsors", + "open-collective", + "bank-of-america" + ] + }, + { + "guid": "gold", + "status": "active", + "name": "Gold Sponsor", + "description": "Medium logo placement on vuejs.org front page + sponsors page + in the README and BACKERS files of the vuejs/core repo.", + "amount": 500, + "currency": "USD", + "frequency": "monthly", + "channels": ["github-sponsors", "open-collective"] + }, + { + "guid": "silver", + "status": "active", + "name": "Silver Sponsor", + "description": "Small logo placement on vuejs.org sponsors page + in the README and BACKERS files of the vuejs/core repo.", + "amount": 250, + "currency": "USD", + "frequency": "monthly", + "channels": ["github-sponsors", "open-collective"] + }, + { + "guid": "bronze", + "status": "active", + "name": "Bronze Sponsor", + "description": "Small logo placement in the README and BACKERS files of the vuejs/core repo.", + "amount": 100, + "currency": "USD", + "frequency": "monthly", + "channels": ["github-sponsors", "open-collective"] + } + ], + + "history": [] + } +} From 901fa8ee0d7638dcf4a11a6fb7446eb735be2bba Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 15 Nov 2024 21:39:21 +0800 Subject: [PATCH 028/121] Revert "Add VueToronto banner to the docs (#3099)" This reverts commit 58c4b8992527c252b18b834e4712ebe682e43db2. --- .../inlined-scripts/restorePreference.js | 4 +- .vitepress/theme/components/Banner.vue | 88 +++---------------- .vitepress/theme/index.ts | 4 +- 3 files changed, 17 insertions(+), 79 deletions(-) diff --git a/.vitepress/inlined-scripts/restorePreference.js b/.vitepress/inlined-scripts/restorePreference.js index b84fa63965..5e18b50ffa 100644 --- a/.vitepress/inlined-scripts/restorePreference.js +++ b/.vitepress/inlined-scripts/restorePreference.js @@ -8,6 +8,6 @@ restore('vue-docs-prefer-composition', 'prefer-composition', true) restore('vue-docs-prefer-sfc', 'prefer-sfc', true) - window.__VUE_BANNER_ID__ = 'vt2024_1' - restore(`vue-docs-banner-${__VUE_BANNER_ID__}`, 'banner-dismissed') + // window.__VUE_BANNER_ID__ = '' + // restore(`vue-docs-banner-${__VUE_BANNER_ID__}`, 'banner-dismissed') })() diff --git a/.vitepress/theme/components/Banner.vue b/.vitepress/theme/components/Banner.vue index 8700ff7897..6730fcd48d 100644 --- a/.vitepress/theme/components/Banner.vue +++ b/.vitepress/theme/components/Banner.vue @@ -22,31 +22,16 @@ function dismiss() { @@ -65,10 +50,12 @@ html:not(.banner-dismissed) { font-weight: 600; color: #fff; background-color: var(--vt-c-green); - background: #11252b; - display: flex; - justify-content: center; - align-items: center; + background: linear-gradient( + 90deg, + rgba(66, 184, 131, 1) 0%, + rgba(39, 179, 137, 1) 19%, + rgba(100, 126, 255, 1) 100% + ); } .banner-dismissed .banner { @@ -83,7 +70,7 @@ button { position: absolute; right: 0; top: 0; - padding: 20px 10px; + padding: 5px; } .close { @@ -92,59 +79,10 @@ button { fill: #fff; transform: rotate(45deg); } - -.vt-banner-text { - color: #fff; - font-size: 16px; -} - -.vt-text-primary { - color: #75c05e; -} - -.vt-primary-action { - background: #75c05e; - color: #121c1a; - padding: 8px 15px; - border-radius: 5px; - font-size: 14px; - text-decoration: none; - margin: 0 20px; - font-weight: bold; -} -.vt-primary-action:hover { - text-decoration: none; - background: #5a9f45; -} - -@media (max-width: 1280px) { - .banner .vt-banner-text { - font-size: 14px; - } - .vt-tagline { - display: none; - } -} - -@media (max-width: 780px) { - .vt-tagline { - display: none; - } - .vt-coupon { - display: none; - } - .vt-primary-action { - margin: 0 10px; - padding: 7px 10px; - } - .vt-time-now { - display: none; - } -} - -@media (max-width: 560px) { - .vt-place { +/* +@media (max-width: 720px) { + a > span { display: none; } -} +} */ diff --git a/.vitepress/theme/index.ts b/.vitepress/theme/index.ts index 9ea1fb93ff..3aa1dac274 100644 --- a/.vitepress/theme/index.ts +++ b/.vitepress/theme/index.ts @@ -10,14 +10,14 @@ import { } from './components/preferences' import SponsorsAside from './components/SponsorsAside.vue' import VueSchoolLink from './components/VueSchoolLink.vue' -import Banner from './components/Banner.vue' +// import Banner from './components/Banner.vue' // import TextAd from './components/TextAd.vue' export default Object.assign({}, VPTheme, { Layout: () => { // @ts-ignore return h(VPTheme.Layout, null, { - banner: () => h(Banner), + // banner: () => h(Banner), 'sidebar-top': () => h(PreferenceSwitch), 'sidebar-bottom': () => h(SecurityUpdateBtn), 'aside-mid': () => h(SponsorsAside) From 8061bb2ae936a6ea2522dbb58cb740625c1b0685 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2024 10:21:21 +0100 Subject: [PATCH 029/121] chore(deps): bump vitepress from 1.4.3 to 1.5.0 (#3091) Bumps [vitepress](https://github.com/vuejs/vitepress) from 1.4.3 to 1.5.0. - [Release notes](https://github.com/vuejs/vitepress/releases) - [Changelog](https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md) - [Commits](https://github.com/vuejs/vitepress/compare/v1.4.3...v1.5.0) --- updated-dependencies: - dependency-name: vitepress dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 009f95c74c..eae4a2e21d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,7 +13,7 @@ importers: version: 4.4.2 '@vue/theme': specifier: ^2.3.0 - version: 2.3.0(@algolia/client-search@4.24.0)(search-insights@2.17.2)(vitepress@1.4.3(@algolia/client-search@4.24.0)(@types/node@22.7.5)(postcss@8.4.47)(search-insights@2.17.2)(typescript@5.6.3))(vue@3.5.12(typescript@5.6.3)) + version: 2.3.0(@algolia/client-search@4.24.0)(search-insights@2.17.2)(vitepress@1.5.0(@algolia/client-search@4.24.0)(@types/node@22.7.5)(postcss@8.4.47)(search-insights@2.17.2)(typescript@5.6.3))(vue@3.5.12(typescript@5.6.3)) dynamics.js: specifier: ^1.1.5 version: 1.1.5 @@ -22,7 +22,7 @@ importers: version: 3.12.5 vitepress: specifier: ^1.4.3 - version: 1.4.3(@algolia/client-search@4.24.0)(@types/node@22.7.5)(postcss@8.4.47)(search-insights@2.17.2)(typescript@5.6.3) + version: 1.5.0(@algolia/client-search@4.24.0)(@types/node@22.7.5)(postcss@8.4.47)(search-insights@2.17.2)(typescript@5.6.3) vue: specifier: ^3.5.12 version: 3.5.12(typescript@5.6.3) @@ -288,6 +288,12 @@ packages: cpu: [x64] os: [win32] + '@iconify-json/simple-icons@1.2.10': + resolution: {integrity: sha512-9OK1dsSjXlH36lhu5n+BlSoXuqFjHUErGLtNdzHpq0vHq4YFBuGYWtZ+vZTHLreRQ8ijPRv/6EsgkV+nf6AReQ==} + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} @@ -827,8 +833,8 @@ packages: terser: optional: true - vitepress@1.4.3: - resolution: {integrity: sha512-956c2K2Mr0ubY9bTc2lCJD3g0mgo0mARB1iJC/BqUt4s0AM8Wl60wSU4zbFnzV7X2miFK1XJDKzGZnuEN90umw==} + vitepress@1.5.0: + resolution: {integrity: sha512-q4Q/G2zjvynvizdB3/bupdYkCJe2umSAMv9Ju4d92E6/NXJ59z70xB0q5p/4lpRyAwflDsbwy1mLV9Q5+nlB+g==} hasBin: true peerDependencies: markdown-it-mathjax3: ^4 @@ -1083,6 +1089,12 @@ snapshots: '@esbuild/win32-x64@0.21.5': optional: true + '@iconify-json/simple-icons@1.2.10': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/types@2.0.0': {} + '@jridgewell/sourcemap-codec@1.5.0': {} '@rollup/rollup-android-arm-eabi@4.24.0': @@ -1304,7 +1316,7 @@ snapshots: '@vue/shared@3.5.12': {} - '@vue/theme@2.3.0(@algolia/client-search@4.24.0)(search-insights@2.17.2)(vitepress@1.4.3(@algolia/client-search@4.24.0)(@types/node@22.7.5)(postcss@8.4.47)(search-insights@2.17.2)(typescript@5.6.3))(vue@3.5.12(typescript@5.6.3))': + '@vue/theme@2.3.0(@algolia/client-search@4.24.0)(search-insights@2.17.2)(vitepress@1.5.0(@algolia/client-search@4.24.0)(@types/node@22.7.5)(postcss@8.4.47)(search-insights@2.17.2)(typescript@5.6.3))(vue@3.5.12(typescript@5.6.3))': dependencies: '@docsearch/css': 3.6.2 '@docsearch/js': 3.6.2(@algolia/client-search@4.24.0)(search-insights@2.17.2) @@ -1312,7 +1324,7 @@ snapshots: body-scroll-lock: 4.0.0-beta.0 normalize.css: 8.0.1 tiny-decode: 0.1.3 - vitepress: 1.4.3(@algolia/client-search@4.24.0)(@types/node@22.7.5)(postcss@8.4.47)(search-insights@2.17.2)(typescript@5.6.3) + vitepress: 1.5.0(@algolia/client-search@4.24.0)(@types/node@22.7.5)(postcss@8.4.47)(search-insights@2.17.2)(typescript@5.6.3) transitivePeerDependencies: - '@algolia/client-search' - '@types/react' @@ -1669,10 +1681,11 @@ snapshots: '@types/node': 22.7.5 fsevents: 2.3.3 - vitepress@1.4.3(@algolia/client-search@4.24.0)(@types/node@22.7.5)(postcss@8.4.47)(search-insights@2.17.2)(typescript@5.6.3): + vitepress@1.5.0(@algolia/client-search@4.24.0)(@types/node@22.7.5)(postcss@8.4.47)(search-insights@2.17.2)(typescript@5.6.3): dependencies: '@docsearch/css': 3.6.2 '@docsearch/js': 3.6.2(@algolia/client-search@4.24.0)(search-insights@2.17.2) + '@iconify-json/simple-icons': 1.2.10 '@shikijs/core': 1.22.2 '@shikijs/transformers': 1.22.2 '@shikijs/types': 1.22.2 From b266b8191d62a21d71e2f619f2543cff4fcbd086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isma=C3=ABl=20Maurice?= <55036198+tisma95@users.noreply.github.com> Date: Tue, 19 Nov 2024 10:21:56 +0100 Subject: [PATCH 030/121] Update the transition group (#3092) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix(developpers): Remove duplicate * Fix(transition-group): Add relativ url and anchor --------- Co-authored-by: Tuo N. Ismaël --- src/guide/built-ins/transition-group.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/guide/built-ins/transition-group.md b/src/guide/built-ins/transition-group.md index 0fa3ce2467..030745b122 100644 --- a/src/guide/built-ins/transition-group.md +++ b/src/guide/built-ins/transition-group.md @@ -80,9 +80,9 @@ Now it looks much better - even animating smoothly when the whole list is shuffl [Full Example](/examples/#list-transition) -### Custom TransitionGroup classes +### Custom TransitionGroup classes {#custom-transitiongroup-classes} -You can also specify custom transition classes for the moving element by passing the `moveClass` prop to ``, just like [custom transition classes on ``](https://vuejs.org/guide/built-ins/transition.html#custom-transition-classes). +You can also specify custom transition classes for the moving element by passing the `moveClass` prop to ``, just like [custom transition classes on ``](/guide/built-ins/transition.html#custom-transition-classes). ## Staggering List Transitions {#staggering-list-transitions} From 6e1090cb895c206e4634811ca236740b8f940f60 Mon Sep 17 00:00:00 2001 From: Nick Mousavi <52695644+biomousavi@users.noreply.github.com> Date: Tue, 19 Nov 2024 13:23:15 +0400 Subject: [PATCH 031/121] docs: align custom-directive example with content (#3093) docs: align example description with content --- src/guide/reusability/custom-directives.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/guide/reusability/custom-directives.md b/src/guide/reusability/custom-directives.md index 6b6aa435b9..a8b51935f7 100644 --- a/src/guide/reusability/custom-directives.md +++ b/src/guide/reusability/custom-directives.md @@ -25,7 +25,7 @@ In addition to the default set of directives shipped in core (like `v-model` or We have introduced two forms of code reuse in Vue: [components](/guide/essentials/component-basics) and [composables](./composables). Components are the main building blocks, while composables are focused on reusing stateful logic. Custom directives, on the other hand, are mainly intended for reusing logic that involves low-level DOM access on plain elements. -A custom directive is defined as an object containing lifecycle hooks similar to those of a component. The hooks receive the element the directive is bound to. Here is an example of a directive that focuses an input when the element is inserted into the DOM by Vue: +A custom directive is defined as an object containing lifecycle hooks similar to those of a component. The hooks receive the element the directive is bound to. Here is an example of a directive that adds a class to an element when it is inserted into the DOM by Vue:
From 1cea4314f762939ab2c52ecfb20cafb6eb40e16d Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Tue, 19 Nov 2024 01:28:38 -0800 Subject: [PATCH 032/121] Corrected and improved docs on type definitions for Custom Elements. (#3073) Corrected and improved documentation on type definitions for Custom Elements. The doc was incorrect for two reasons: - For Vue-based custom elements, the types passed into `GlobalComponents` need to be the Vue component types, not the custom element types, or the custom elements will not be type checked in Vue templates. - The name of the elements need to have at least two words and a hyphen, otherwise with single words the custom elements will not work at all. --- src/guide/extras/web-components.md | 270 +++++++++++++++++++++++++++-- 1 file changed, 259 insertions(+), 11 deletions(-) diff --git a/src/guide/extras/web-components.md b/src/guide/extras/web-components.md index 6bf9a5de45..75b72bbc17 100644 --- a/src/guide/extras/web-components.md +++ b/src/guide/extras/web-components.md @@ -220,6 +220,8 @@ If the custom elements will be used in an application that is also using Vue, yo It is recommended to export the individual element constructors to give your users the flexibility to import them on-demand and register them with desired tag names. You can also export a convenience function to automatically register all elements. Here's an example entry point of a Vue custom element library: ```js +// elements.js + import { defineCustomElement } from 'vue' import Foo from './MyFoo.ce.vue' import Bar from './MyBar.ce.vue' @@ -236,31 +238,277 @@ export function register() { } ``` -If you have many components, you can also leverage build tool features such as Vite's [glob import](https://vitejs.dev/guide/features.html#glob-import) or webpack's [`require.context`](https://webpack.js.org/guides/dependency-management/#requirecontext) to load all components from a directory. +A consumer can use the elements in a Vue file, + +```vue + + + +``` + +or in any other framework such as one with JSX, and with custom names: -### Web Components and TypeScript {#web-components-and-typescript} +```jsx +import { MyFoo, MyBar } from 'path/to/elements.js' + +customElements.define('some-foo', MyFoo) +customElements.define('some-bar', MyBar) + +export function MyComponent() { + return <> + + + + +} +``` -If you are developing an application or a library, you may want to [type check](/guide/scaling-up/tooling.html#typescript) your Vue components, including those that are defined as custom elements. +### Vue-based Web Components and TypeScript {#web-components-and-typescript} -Custom elements are registered globally using native APIs, so by default they won't have type inference when used in Vue templates. To provide type support for Vue components registered as custom elements, we can register global component typings using the the [`GlobalComponents` interface](https://github.com/vuejs/language-tools/blob/master/packages/vscode-vue/README.md#usage) in Vue templates and/or in [JSX](https://www.typescriptlang.org/docs/handbook/jsx.html#intrinsic-elements): +When writing Vue SFC templates, you may want to [type check](/guide/scaling-up/tooling.html#typescript) your Vue components, including those that are defined as custom elements. + +Custom elements are registered globally in browsers using their built-in APIs, and by default they won't have type inference when used in Vue templates. To provide type support for Vue components registered as custom elements, we can register global component typings by augmenting the [`GlobalComponents` interface](https://github.com/vuejs/language-tools/blob/master/packages/vscode-vue/README.md#usage) for type checking in Vue templates (JSX users can augment the [JSX.IntrinsicElements](https://www.typescriptlang.org/docs/handbook/jsx.html#intrinsic-elements) type instead, which is not shown here). + +Here is how to define the type for a custom element made with Vue: ```typescript import { defineCustomElement } from 'vue' -// vue SFC -import CounterSFC from './src/components/counter.ce.vue' +// Import the Vue component. +import SomeComponent from './src/components/SomeComponent.ce.vue' + +// Turn the Vue component into a Custom Element class. +export const SomeElement = defineCustomElement(SomeComponent) + +// Remember to register the element class with the browser. +customElements.define('some-element', SomeElement) + +// Add the new element type to Vue's GlobalComponents type. +declare module 'vue' { + interface GlobalComponents { + // Be sure to pass in the Vue component type here (SomeComponent, *not* SomeElement). + // Custom Elements require a hyphen in their name, so use the hyphenated element name here. + 'some-element': typeof SomeComponent + } +} +``` + +## Non-Vue Web Components and TypeScript + +Here is the recommended way to enable type checking in SFC templates of Custom +Elements that are not built with Vue. + +> [!Note] +> This approach is one possible way to do it, but it may vary depending on the +> framework being used to create the custom elements. + +Suppose we have a custom element with some JS properties and events defined, and +it is shipped in a library called `some-lib`: + +```ts +// file: some-lib/src/SomeElement.ts + +// Define a class with typed JS properties. +export class SomeElement extends HTMLElement { + foo: number = 123 + bar: string = 'blah' + + lorem: boolean = false + + // This method should not be exposed to template types. + someMethod() { + /* ... */ + } + + // ... implementation details omitted ... + // ... assume the element dispatches events named "apple-fell" ... +} + +customElements.define('some-element', SomeElement) + +// This is a list of properties of SomeElement that will be selected for type +// checking in framework templates (f.e. Vue SFC templates). Any other +// properties will not be exposed. +export type SomeElementAttributes = 'foo' | 'bar' + +// Define the event types that SomeElement dispatches. +export type SomeElementEvents = { + 'apple-fell': AppleFellEvent +} + +export class AppleFellEvent extends Event { + /* ... details omitted ... */ +} +``` + +The implementation details have been omitted, but the important part is that we +have type definitions for two things: prop types and event types. + +Let's create a type helper for easily registering custom element type +definitions in Vue: + +```ts +// file: some-lib/src/DefineCustomElement.ts + +// We can re-use this type helper per each element we need to define. +type DefineCustomElement< + ElementType extends HTMLElement, + Events extends EventMap = {}, + SelectedAttributes extends keyof ElementType = keyof ElementType +> = new () => ElementType & { + // Use $props to define the properties exposed to template type checking. Vue + // specifically reads prop definitions from the `$props` type. Note that we + // combine the element's props with the global HTML props and Vue's special + // props. + /** @deprecated Do not use the $props property on a Custom Element ref, this is for template prop types only. */ + $props: HTMLAttributes & + Partial> & + PublicProps + + // Use $emit to specifically define event types. Vue specifically reads event + // types from the `$emit` type. Note that `$emit` expects a particular format + // that we map `Events` to. + /** @deprecated Do not use the $emit property on a Custom Element ref, this is for template prop types only. */ + $emit: VueEmit +} + +type EventMap = { + [event: string]: Event +} + +// This maps an EventMap to the format that Vue's $emit type expects. +type VueEmit = EmitFn<{ + [K in keyof T]: (event: T[K]) => void +}> +``` + +> [!Note] +> We marked `$props` and `$emit` as deprecated so that when we get a `ref` to a +> custom element we will not be tempted to use these properties, as these +> properties are for type checking purposes only when it comes to custom elements. +> These properties do not actually exist on the custom element instances. + +Using the type helper we can now select the JS properties that should be exposed +for type checking in Vue templates: + +```ts +// file: some-lib/src/SomeElement.vue.ts + +import { + SomeElement, + SomeElementAttributes, + SomeElementEvents +} from './SomeElement.js' +import type { Component } from 'vue' +import type { DefineCustomElement } from './DefineCustomElement' + +// Add the new element type to Vue's GlobalComponents type. +declare module 'vue' { + interface GlobalComponents { + 'some-element': DefineCustomElement< + SomeElement, + SomeElementAttributes, + SomeElementEvents + > + } +} +``` -// turn component into web components -export const Counter = defineCustomElement(CounterSFC) +Suppose that `some-lib` builds its source TypeScript files into a `dist/` folder. A user of +`some-lib` can then import `SomeElement` and use it in a Vue SFC like so: -// register global typings +```vue + + + +``` + +If an element does not have type definitions, the types of the properties and events can be +defined in a more manual fashion: + +```vue + + + ``` +Custom Element authors should not automatically export framework-specific custom +element type definitions from their libraries, for example they should not +export them from an `index.ts` file that also exports the rest of the library, +otherwise users will have unexpected module augmentation errors. Users should +import the framework-specific type definition file that they need. + ## Web Components vs. Vue Components {#web-components-vs-vue-components} Some developers believe that framework-proprietary component models should be avoided, and that exclusively using Custom Elements makes an application "future-proof". Here we will try to explain why we believe that this is an overly simplistic take on the problem. From 0773ed439c142d140ac6eebbe858b250a73be441 Mon Sep 17 00:00:00 2001 From: Vincent Anjiri Date: Tue, 19 Nov 2024 12:46:44 +0300 Subject: [PATCH 033/121] Refactor api.data.ts: Add comments and improve code clarity (#3098) - Added comments to explain the purpose and functionality of key functions. - Clarified the logic behind header parsing, slug generation, and file caching. - Documented the use of regular expressions for header cleaning and anchor extraction. - Improved readability and maintainability of the codebase. --- src/api/api.data.ts | 146 ++++++++++++++++++++++++++------------------ 1 file changed, 88 insertions(+), 58 deletions(-) diff --git a/src/api/api.data.ts b/src/api/api.data.ts index 719054fd1b..5c4f023b35 100644 --- a/src/api/api.data.ts +++ b/src/api/api.data.ts @@ -1,15 +1,16 @@ // api.data.ts -// a file ending with data.(j|t)s will be evaluated in Node.js import fs from 'fs' import path from 'path' import type { MultiSidebarConfig } from '@vue/theme/src/vitepress/config.ts' import { sidebar } from '../../.vitepress/config' +// Interface defining the structure of a single header in the API interface APIHeader { anchor: string text: string } +// Interface defining the structure of an API group with text, anchor, and items export interface APIGroup { text: string anchor: string @@ -20,79 +21,108 @@ export interface APIGroup { }[] } -// declare resolved data type +// Declare the resolved data type for API groups export declare const data: APIGroup[] -export default { - // declare files that should trigger HMR - watch: './*.md', - // read from fs and generate the data - load(): APIGroup[] { - return (sidebar as MultiSidebarConfig)['/api/'].map((group) => ({ - text: group.text, - anchor: slugify(group.text), - items: group.items.map((item) => ({ - ...item, - headers: parsePageHeaders(item.link) - })) - })) - } +// Utility function to generate a slug from a string (used for anchor links) +function slugify(text: string): string { + return ( + text + // Replace special characters and spaces with hyphens + .replace(/[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'<>,.?/]+/g, '-') + // Remove continuous separators + .replace(/-{2,}/g, '-') + // Remove leading/trailing hyphens + .replace(/^-+|-+$/g, '') + // Ensure it doesn't start with a number (e.g. #121) + .replace(/^(\d)/, '_$1') + // Convert to lowercase + .toLowerCase() + ) } -const headersCache = new Map< - string, - { - headers: APIHeader[] - timestamp: number - } ->() - -function parsePageHeaders(link: string) { - const fullPath = path.join(__dirname, '../', link) + '.md' - const timestamp = fs.statSync(fullPath).mtimeMs +// Utility function to parse headers from a markdown file at a given link +function parsePageHeaders(link: string): APIHeader[] { + const fullPath = path.join(__dirname, '../', link) + '.md' // Resolve the full file path + const timestamp = fs.statSync(fullPath).mtimeMs // Get the last modified timestamp of the file + // Check if the file is cached and if its timestamp matches const cached = headersCache.get(fullPath) if (cached && timestamp === cached.timestamp) { - return cached.headers + return cached.headers // Return cached headers if they're up-to-date } - const src = fs.readFileSync(fullPath, 'utf-8') - const h2s = src.match(/^## [^\n]+/gm) + const src = fs.readFileSync(fullPath, 'utf-8') // Read the markdown file + const headers = extractHeadersFromMarkdown(src) // Extract headers from the file content + + // Store the extracted headers along with the file's timestamp in the cache + headersCache.set(fullPath, { + timestamp, + headers + }) + + return headers +} + +// Helper function to extract all headers (h2) from markdown content +function extractHeadersFromMarkdown(src: string): APIHeader[] { + const h2s = src.match(/^## [^\n]+/gm) // Match all h2 headers (## header) + const anchorRE = /\{#([^}]+)\}/ // Regular expression to match the anchor link in header (e.g. {#some-anchor}) let headers: APIHeader[] = [] + if (h2s) { - const anchorRE = /\{#([^}]+)\}/ + // Process each h2 header and extract text and anchor headers = h2s.map((h) => { - const text = h - .slice(2) - .replace(/