From 6615bb633444b6b9a2999b27100a129c99ba38a5 Mon Sep 17 00:00:00 2001
From: Andrew Jakubowicz
Date: Tue, 9 May 2023 16:56:50 -0700
Subject: [PATCH 01/33] Copy over all unversioned content into a versioned
directory
The only file changed in the move is the root `docs.json` file. Instead
a `v2.json` file was added.
---
.../lit-dev-content/site/docs/components/components.json | 1 -
packages/lit-dev-content/site/docs/docs.json | 5 ++---
packages/lit-dev-content/site/docs/{ => v2}/api/api.html | 4 ++--
packages/lit-dev-content/site/docs/{ => v2}/api/index.md | 0
.../site/docs/{ => v2}/components/decorators.md | 0
.../site/docs/{ => v2}/components/defining.md | 0
.../lit-dev-content/site/docs/{ => v2}/components/events.md | 0
.../lit-dev-content/site/docs/{ => v2}/components/index.md | 0
.../site/docs/{ => v2}/components/lifecycle.md | 0
.../site/docs/{ => v2}/components/overview.md | 0
.../site/docs/{ => v2}/components/properties.md | 0
.../site/docs/{ => v2}/components/rendering.md | 0
.../site/docs/{ => v2}/components/shadow-dom.md | 0
.../lit-dev-content/site/docs/{ => v2}/components/styles.md | 0
.../site/docs/{ => v2}/composition/component-composition.md | 0
.../site/docs/{ => v2}/composition/controllers.md | 0
.../lit-dev-content/site/docs/{ => v2}/composition/index.md | 0
.../lit-dev-content/site/docs/{ => v2}/composition/mixins.md | 0
.../site/docs/{ => v2}/composition/overview.md | 0
packages/lit-dev-content/site/docs/{ => v2}/data/context.md | 0
packages/lit-dev-content/site/docs/{ => v2}/data/index.md | 0
.../lit-dev-content/site/docs/{ => v2}/frameworks/index.md | 0
.../lit-dev-content/site/docs/{ => v2}/frameworks/react.md | 0
.../lit-dev-content/site/docs/{ => v2}/getting-started.md | 0
packages/lit-dev-content/site/docs/{ => v2}/index.md | 0
.../lit-dev-content/site/docs/{ => v2}/internal/demos.md | 0
.../lit-dev-content/site/docs/{ => v2}/internal/styles.md | 0
packages/lit-dev-content/site/docs/{ => v2}/introduction.md | 0
.../lit-dev-content/site/docs/{ => v2}/libraries/index.md | 0
.../lit-dev-content/site/docs/{ => v2}/libraries/labs.md | 0
.../site/docs/{ => v2}/libraries/standalone-templates.md | 0
.../site/docs/{ => v2}/localization/best-practices.md | 0
.../site/docs/{ => v2}/localization/cli-and-config.md | 0
.../lit-dev-content/site/docs/{ => v2}/localization/index.md | 0
.../site/docs/{ => v2}/localization/overview.md | 0
.../site/docs/{ => v2}/localization/runtime-mode.md | 0
.../site/docs/{ => v2}/localization/transform-mode.md | 0
.../lit-dev-content/site/docs/{ => v2}/releases/index.md | 0
.../site/docs/{ => v2}/releases/release-notes/1.2.0.md | 0
.../site/docs/{ => v2}/releases/release-notes/1.3.0.md | 0
.../docs/{ => v2}/releases/release-notes/release-notes.json | 0
.../lit-dev-content/site/docs/{ => v2}/releases/upgrade.md | 0
.../site/docs/{ => v2}/resources/community.md | 0
.../lit-dev-content/site/docs/{ => v2}/resources/index.md | 0
packages/lit-dev-content/site/docs/{ => v2}/ssr/authoring.md | 0
.../lit-dev-content/site/docs/{ => v2}/ssr/client-usage.md | 0
.../lit-dev-content/site/docs/{ => v2}/ssr/dom-emulation.md | 0
packages/lit-dev-content/site/docs/{ => v2}/ssr/index.md | 0
packages/lit-dev-content/site/docs/{ => v2}/ssr/overview.md | 0
.../lit-dev-content/site/docs/{ => v2}/ssr/server-usage.md | 0
.../site/docs/{ => v2}/templates/conditionals.md | 0
.../site/docs/{ => v2}/templates/custom-directives.md | 0
.../site/docs/{ => v2}/templates/directives.md | 0
.../site/docs/{ => v2}/templates/expressions.md | 0
.../lit-dev-content/site/docs/{ => v2}/templates/index.md | 0
.../lit-dev-content/site/docs/{ => v2}/templates/lists.md | 0
.../lit-dev-content/site/docs/{ => v2}/templates/overview.md | 0
.../lit-dev-content/site/docs/{ => v2}/tools/adding-lit.md | 0
.../lit-dev-content/site/docs/{ => v2}/tools/development.md | 0
packages/lit-dev-content/site/docs/{ => v2}/tools/index.md | 0
.../lit-dev-content/site/docs/{ => v2}/tools/overview.md | 0
.../lit-dev-content/site/docs/{ => v2}/tools/production.md | 0
.../lit-dev-content/site/docs/{ => v2}/tools/publishing.md | 0
.../lit-dev-content/site/docs/{ => v2}/tools/requirements.md | 0
.../lit-dev-content/site/docs/{ => v2}/tools/starter-kits.md | 0
packages/lit-dev-content/site/docs/{ => v2}/tools/testing.md | 0
packages/lit-dev-content/site/docs/v2/v2.json | 3 +++
67 files changed, 7 insertions(+), 6 deletions(-)
delete mode 100644 packages/lit-dev-content/site/docs/components/components.json
rename packages/lit-dev-content/site/docs/{ => v2}/api/api.html (78%)
rename packages/lit-dev-content/site/docs/{ => v2}/api/index.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/components/decorators.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/components/defining.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/components/events.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/components/index.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/components/lifecycle.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/components/overview.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/components/properties.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/components/rendering.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/components/shadow-dom.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/components/styles.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/composition/component-composition.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/composition/controllers.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/composition/index.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/composition/mixins.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/composition/overview.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/data/context.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/data/index.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/frameworks/index.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/frameworks/react.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/getting-started.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/index.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/internal/demos.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/internal/styles.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/introduction.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/libraries/index.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/libraries/labs.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/libraries/standalone-templates.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/localization/best-practices.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/localization/cli-and-config.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/localization/index.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/localization/overview.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/localization/runtime-mode.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/localization/transform-mode.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/releases/index.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/releases/release-notes/1.2.0.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/releases/release-notes/1.3.0.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/releases/release-notes/release-notes.json (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/releases/upgrade.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/resources/community.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/resources/index.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/ssr/authoring.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/ssr/client-usage.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/ssr/dom-emulation.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/ssr/index.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/ssr/overview.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/ssr/server-usage.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/templates/conditionals.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/templates/custom-directives.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/templates/directives.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/templates/expressions.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/templates/index.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/templates/lists.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/templates/overview.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/tools/adding-lit.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/tools/development.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/tools/index.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/tools/overview.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/tools/production.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/tools/publishing.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/tools/requirements.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/tools/starter-kits.md (100%)
rename packages/lit-dev-content/site/docs/{ => v2}/tools/testing.md (100%)
create mode 100644 packages/lit-dev-content/site/docs/v2/v2.json
diff --git a/packages/lit-dev-content/site/docs/components/components.json b/packages/lit-dev-content/site/docs/components/components.json
deleted file mode 100644
index 0967ef424..000000000
--- a/packages/lit-dev-content/site/docs/components/components.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/packages/lit-dev-content/site/docs/docs.json b/packages/lit-dev-content/site/docs/docs.json
index 8d90bcdb3..891f1b7c3 100644
--- a/packages/lit-dev-content/site/docs/docs.json
+++ b/packages/lit-dev-content/site/docs/docs.json
@@ -1,4 +1,3 @@
{
- "layout": "docs",
- "collection": "docs-v2"
-}
+ "layout": "docs"
+}
\ No newline at end of file
diff --git a/packages/lit-dev-content/site/docs/api/api.html b/packages/lit-dev-content/site/docs/v2/api/api.html
similarity index 78%
rename from packages/lit-dev-content/site/docs/api/api.html
rename to packages/lit-dev-content/site/docs/v2/api/api.html
index 11299de03..b0cd8cebc 100644
--- a/packages/lit-dev-content/site/docs/api/api.html
+++ b/packages/lit-dev-content/site/docs/v2/api/api.html
@@ -7,12 +7,12 @@
alias: data
addAllPagesToCollections: true
-permalink: "docs/api/{{ data.slug }}/"
+permalink: "docs/v2/api/{{ data.slug }}/"
eleventyComputed:
title: "{{ data.title }}"
eleventyNavigation:
key: "{{ data.title }}"
parent: API
- apiPath: /docs/api
+ apiPath: /docs/v2/api
---
diff --git a/packages/lit-dev-content/site/docs/api/index.md b/packages/lit-dev-content/site/docs/v2/api/index.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/api/index.md
rename to packages/lit-dev-content/site/docs/v2/api/index.md
diff --git a/packages/lit-dev-content/site/docs/components/decorators.md b/packages/lit-dev-content/site/docs/v2/components/decorators.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/components/decorators.md
rename to packages/lit-dev-content/site/docs/v2/components/decorators.md
diff --git a/packages/lit-dev-content/site/docs/components/defining.md b/packages/lit-dev-content/site/docs/v2/components/defining.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/components/defining.md
rename to packages/lit-dev-content/site/docs/v2/components/defining.md
diff --git a/packages/lit-dev-content/site/docs/components/events.md b/packages/lit-dev-content/site/docs/v2/components/events.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/components/events.md
rename to packages/lit-dev-content/site/docs/v2/components/events.md
diff --git a/packages/lit-dev-content/site/docs/components/index.md b/packages/lit-dev-content/site/docs/v2/components/index.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/components/index.md
rename to packages/lit-dev-content/site/docs/v2/components/index.md
diff --git a/packages/lit-dev-content/site/docs/components/lifecycle.md b/packages/lit-dev-content/site/docs/v2/components/lifecycle.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/components/lifecycle.md
rename to packages/lit-dev-content/site/docs/v2/components/lifecycle.md
diff --git a/packages/lit-dev-content/site/docs/components/overview.md b/packages/lit-dev-content/site/docs/v2/components/overview.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/components/overview.md
rename to packages/lit-dev-content/site/docs/v2/components/overview.md
diff --git a/packages/lit-dev-content/site/docs/components/properties.md b/packages/lit-dev-content/site/docs/v2/components/properties.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/components/properties.md
rename to packages/lit-dev-content/site/docs/v2/components/properties.md
diff --git a/packages/lit-dev-content/site/docs/components/rendering.md b/packages/lit-dev-content/site/docs/v2/components/rendering.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/components/rendering.md
rename to packages/lit-dev-content/site/docs/v2/components/rendering.md
diff --git a/packages/lit-dev-content/site/docs/components/shadow-dom.md b/packages/lit-dev-content/site/docs/v2/components/shadow-dom.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/components/shadow-dom.md
rename to packages/lit-dev-content/site/docs/v2/components/shadow-dom.md
diff --git a/packages/lit-dev-content/site/docs/components/styles.md b/packages/lit-dev-content/site/docs/v2/components/styles.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/components/styles.md
rename to packages/lit-dev-content/site/docs/v2/components/styles.md
diff --git a/packages/lit-dev-content/site/docs/composition/component-composition.md b/packages/lit-dev-content/site/docs/v2/composition/component-composition.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/composition/component-composition.md
rename to packages/lit-dev-content/site/docs/v2/composition/component-composition.md
diff --git a/packages/lit-dev-content/site/docs/composition/controllers.md b/packages/lit-dev-content/site/docs/v2/composition/controllers.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/composition/controllers.md
rename to packages/lit-dev-content/site/docs/v2/composition/controllers.md
diff --git a/packages/lit-dev-content/site/docs/composition/index.md b/packages/lit-dev-content/site/docs/v2/composition/index.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/composition/index.md
rename to packages/lit-dev-content/site/docs/v2/composition/index.md
diff --git a/packages/lit-dev-content/site/docs/composition/mixins.md b/packages/lit-dev-content/site/docs/v2/composition/mixins.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/composition/mixins.md
rename to packages/lit-dev-content/site/docs/v2/composition/mixins.md
diff --git a/packages/lit-dev-content/site/docs/composition/overview.md b/packages/lit-dev-content/site/docs/v2/composition/overview.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/composition/overview.md
rename to packages/lit-dev-content/site/docs/v2/composition/overview.md
diff --git a/packages/lit-dev-content/site/docs/data/context.md b/packages/lit-dev-content/site/docs/v2/data/context.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/data/context.md
rename to packages/lit-dev-content/site/docs/v2/data/context.md
diff --git a/packages/lit-dev-content/site/docs/data/index.md b/packages/lit-dev-content/site/docs/v2/data/index.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/data/index.md
rename to packages/lit-dev-content/site/docs/v2/data/index.md
diff --git a/packages/lit-dev-content/site/docs/frameworks/index.md b/packages/lit-dev-content/site/docs/v2/frameworks/index.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/frameworks/index.md
rename to packages/lit-dev-content/site/docs/v2/frameworks/index.md
diff --git a/packages/lit-dev-content/site/docs/frameworks/react.md b/packages/lit-dev-content/site/docs/v2/frameworks/react.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/frameworks/react.md
rename to packages/lit-dev-content/site/docs/v2/frameworks/react.md
diff --git a/packages/lit-dev-content/site/docs/getting-started.md b/packages/lit-dev-content/site/docs/v2/getting-started.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/getting-started.md
rename to packages/lit-dev-content/site/docs/v2/getting-started.md
diff --git a/packages/lit-dev-content/site/docs/index.md b/packages/lit-dev-content/site/docs/v2/index.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/index.md
rename to packages/lit-dev-content/site/docs/v2/index.md
diff --git a/packages/lit-dev-content/site/docs/internal/demos.md b/packages/lit-dev-content/site/docs/v2/internal/demos.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/internal/demos.md
rename to packages/lit-dev-content/site/docs/v2/internal/demos.md
diff --git a/packages/lit-dev-content/site/docs/internal/styles.md b/packages/lit-dev-content/site/docs/v2/internal/styles.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/internal/styles.md
rename to packages/lit-dev-content/site/docs/v2/internal/styles.md
diff --git a/packages/lit-dev-content/site/docs/introduction.md b/packages/lit-dev-content/site/docs/v2/introduction.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/introduction.md
rename to packages/lit-dev-content/site/docs/v2/introduction.md
diff --git a/packages/lit-dev-content/site/docs/libraries/index.md b/packages/lit-dev-content/site/docs/v2/libraries/index.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/libraries/index.md
rename to packages/lit-dev-content/site/docs/v2/libraries/index.md
diff --git a/packages/lit-dev-content/site/docs/libraries/labs.md b/packages/lit-dev-content/site/docs/v2/libraries/labs.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/libraries/labs.md
rename to packages/lit-dev-content/site/docs/v2/libraries/labs.md
diff --git a/packages/lit-dev-content/site/docs/libraries/standalone-templates.md b/packages/lit-dev-content/site/docs/v2/libraries/standalone-templates.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/libraries/standalone-templates.md
rename to packages/lit-dev-content/site/docs/v2/libraries/standalone-templates.md
diff --git a/packages/lit-dev-content/site/docs/localization/best-practices.md b/packages/lit-dev-content/site/docs/v2/localization/best-practices.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/localization/best-practices.md
rename to packages/lit-dev-content/site/docs/v2/localization/best-practices.md
diff --git a/packages/lit-dev-content/site/docs/localization/cli-and-config.md b/packages/lit-dev-content/site/docs/v2/localization/cli-and-config.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/localization/cli-and-config.md
rename to packages/lit-dev-content/site/docs/v2/localization/cli-and-config.md
diff --git a/packages/lit-dev-content/site/docs/localization/index.md b/packages/lit-dev-content/site/docs/v2/localization/index.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/localization/index.md
rename to packages/lit-dev-content/site/docs/v2/localization/index.md
diff --git a/packages/lit-dev-content/site/docs/localization/overview.md b/packages/lit-dev-content/site/docs/v2/localization/overview.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/localization/overview.md
rename to packages/lit-dev-content/site/docs/v2/localization/overview.md
diff --git a/packages/lit-dev-content/site/docs/localization/runtime-mode.md b/packages/lit-dev-content/site/docs/v2/localization/runtime-mode.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/localization/runtime-mode.md
rename to packages/lit-dev-content/site/docs/v2/localization/runtime-mode.md
diff --git a/packages/lit-dev-content/site/docs/localization/transform-mode.md b/packages/lit-dev-content/site/docs/v2/localization/transform-mode.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/localization/transform-mode.md
rename to packages/lit-dev-content/site/docs/v2/localization/transform-mode.md
diff --git a/packages/lit-dev-content/site/docs/releases/index.md b/packages/lit-dev-content/site/docs/v2/releases/index.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/releases/index.md
rename to packages/lit-dev-content/site/docs/v2/releases/index.md
diff --git a/packages/lit-dev-content/site/docs/releases/release-notes/1.2.0.md b/packages/lit-dev-content/site/docs/v2/releases/release-notes/1.2.0.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/releases/release-notes/1.2.0.md
rename to packages/lit-dev-content/site/docs/v2/releases/release-notes/1.2.0.md
diff --git a/packages/lit-dev-content/site/docs/releases/release-notes/1.3.0.md b/packages/lit-dev-content/site/docs/v2/releases/release-notes/1.3.0.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/releases/release-notes/1.3.0.md
rename to packages/lit-dev-content/site/docs/v2/releases/release-notes/1.3.0.md
diff --git a/packages/lit-dev-content/site/docs/releases/release-notes/release-notes.json b/packages/lit-dev-content/site/docs/v2/releases/release-notes/release-notes.json
similarity index 100%
rename from packages/lit-dev-content/site/docs/releases/release-notes/release-notes.json
rename to packages/lit-dev-content/site/docs/v2/releases/release-notes/release-notes.json
diff --git a/packages/lit-dev-content/site/docs/releases/upgrade.md b/packages/lit-dev-content/site/docs/v2/releases/upgrade.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/releases/upgrade.md
rename to packages/lit-dev-content/site/docs/v2/releases/upgrade.md
diff --git a/packages/lit-dev-content/site/docs/resources/community.md b/packages/lit-dev-content/site/docs/v2/resources/community.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/resources/community.md
rename to packages/lit-dev-content/site/docs/v2/resources/community.md
diff --git a/packages/lit-dev-content/site/docs/resources/index.md b/packages/lit-dev-content/site/docs/v2/resources/index.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/resources/index.md
rename to packages/lit-dev-content/site/docs/v2/resources/index.md
diff --git a/packages/lit-dev-content/site/docs/ssr/authoring.md b/packages/lit-dev-content/site/docs/v2/ssr/authoring.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/ssr/authoring.md
rename to packages/lit-dev-content/site/docs/v2/ssr/authoring.md
diff --git a/packages/lit-dev-content/site/docs/ssr/client-usage.md b/packages/lit-dev-content/site/docs/v2/ssr/client-usage.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/ssr/client-usage.md
rename to packages/lit-dev-content/site/docs/v2/ssr/client-usage.md
diff --git a/packages/lit-dev-content/site/docs/ssr/dom-emulation.md b/packages/lit-dev-content/site/docs/v2/ssr/dom-emulation.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/ssr/dom-emulation.md
rename to packages/lit-dev-content/site/docs/v2/ssr/dom-emulation.md
diff --git a/packages/lit-dev-content/site/docs/ssr/index.md b/packages/lit-dev-content/site/docs/v2/ssr/index.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/ssr/index.md
rename to packages/lit-dev-content/site/docs/v2/ssr/index.md
diff --git a/packages/lit-dev-content/site/docs/ssr/overview.md b/packages/lit-dev-content/site/docs/v2/ssr/overview.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/ssr/overview.md
rename to packages/lit-dev-content/site/docs/v2/ssr/overview.md
diff --git a/packages/lit-dev-content/site/docs/ssr/server-usage.md b/packages/lit-dev-content/site/docs/v2/ssr/server-usage.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/ssr/server-usage.md
rename to packages/lit-dev-content/site/docs/v2/ssr/server-usage.md
diff --git a/packages/lit-dev-content/site/docs/templates/conditionals.md b/packages/lit-dev-content/site/docs/v2/templates/conditionals.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/templates/conditionals.md
rename to packages/lit-dev-content/site/docs/v2/templates/conditionals.md
diff --git a/packages/lit-dev-content/site/docs/templates/custom-directives.md b/packages/lit-dev-content/site/docs/v2/templates/custom-directives.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/templates/custom-directives.md
rename to packages/lit-dev-content/site/docs/v2/templates/custom-directives.md
diff --git a/packages/lit-dev-content/site/docs/templates/directives.md b/packages/lit-dev-content/site/docs/v2/templates/directives.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/templates/directives.md
rename to packages/lit-dev-content/site/docs/v2/templates/directives.md
diff --git a/packages/lit-dev-content/site/docs/templates/expressions.md b/packages/lit-dev-content/site/docs/v2/templates/expressions.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/templates/expressions.md
rename to packages/lit-dev-content/site/docs/v2/templates/expressions.md
diff --git a/packages/lit-dev-content/site/docs/templates/index.md b/packages/lit-dev-content/site/docs/v2/templates/index.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/templates/index.md
rename to packages/lit-dev-content/site/docs/v2/templates/index.md
diff --git a/packages/lit-dev-content/site/docs/templates/lists.md b/packages/lit-dev-content/site/docs/v2/templates/lists.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/templates/lists.md
rename to packages/lit-dev-content/site/docs/v2/templates/lists.md
diff --git a/packages/lit-dev-content/site/docs/templates/overview.md b/packages/lit-dev-content/site/docs/v2/templates/overview.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/templates/overview.md
rename to packages/lit-dev-content/site/docs/v2/templates/overview.md
diff --git a/packages/lit-dev-content/site/docs/tools/adding-lit.md b/packages/lit-dev-content/site/docs/v2/tools/adding-lit.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/tools/adding-lit.md
rename to packages/lit-dev-content/site/docs/v2/tools/adding-lit.md
diff --git a/packages/lit-dev-content/site/docs/tools/development.md b/packages/lit-dev-content/site/docs/v2/tools/development.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/tools/development.md
rename to packages/lit-dev-content/site/docs/v2/tools/development.md
diff --git a/packages/lit-dev-content/site/docs/tools/index.md b/packages/lit-dev-content/site/docs/v2/tools/index.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/tools/index.md
rename to packages/lit-dev-content/site/docs/v2/tools/index.md
diff --git a/packages/lit-dev-content/site/docs/tools/overview.md b/packages/lit-dev-content/site/docs/v2/tools/overview.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/tools/overview.md
rename to packages/lit-dev-content/site/docs/v2/tools/overview.md
diff --git a/packages/lit-dev-content/site/docs/tools/production.md b/packages/lit-dev-content/site/docs/v2/tools/production.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/tools/production.md
rename to packages/lit-dev-content/site/docs/v2/tools/production.md
diff --git a/packages/lit-dev-content/site/docs/tools/publishing.md b/packages/lit-dev-content/site/docs/v2/tools/publishing.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/tools/publishing.md
rename to packages/lit-dev-content/site/docs/v2/tools/publishing.md
diff --git a/packages/lit-dev-content/site/docs/tools/requirements.md b/packages/lit-dev-content/site/docs/v2/tools/requirements.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/tools/requirements.md
rename to packages/lit-dev-content/site/docs/v2/tools/requirements.md
diff --git a/packages/lit-dev-content/site/docs/tools/starter-kits.md b/packages/lit-dev-content/site/docs/v2/tools/starter-kits.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/tools/starter-kits.md
rename to packages/lit-dev-content/site/docs/v2/tools/starter-kits.md
diff --git a/packages/lit-dev-content/site/docs/tools/testing.md b/packages/lit-dev-content/site/docs/v2/tools/testing.md
similarity index 100%
rename from packages/lit-dev-content/site/docs/tools/testing.md
rename to packages/lit-dev-content/site/docs/v2/tools/testing.md
diff --git a/packages/lit-dev-content/site/docs/v2/v2.json b/packages/lit-dev-content/site/docs/v2/v2.json
new file mode 100644
index 000000000..4a1be1b03
--- /dev/null
+++ b/packages/lit-dev-content/site/docs/v2/v2.json
@@ -0,0 +1,3 @@
+{
+ "collection": "docs-v2"
+}
From 19a07fb3b2338d047896186be67d53e8076694a8 Mon Sep 17 00:00:00 2001
From: Andrew Jakubowicz
Date: Tue, 9 May 2023 17:00:09 -0700
Subject: [PATCH 02/33] Add initial build-unversioned-docs script.
This copies over and adds the correct permalinks to the selected
version content. Currently moving `v2` -> `unversioned`.
---
.gitignore | 4 +
packages/lit-dev-content/.eleventy.js | 22 ++-
packages/lit-dev-content/package.json | 14 +-
.../src/build-unversioned-docs.ts | 154 ++++++++++++++++++
4 files changed, 191 insertions(+), 3 deletions(-)
create mode 100644 packages/lit-dev-tools-esm/src/build-unversioned-docs.ts
diff --git a/.gitignore b/.gitignore
index 8f464b6da..35c4ebb08 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,10 @@ packages/lit-dev-content/site/fonts/manrope
packages/lit-dev-content/temp
packages/lit-dev-content/samples/js
packages/lit-dev-content/src/public-vars.ts
+# The unversioned docs are generated by:
+#
+# `npm run build:unversioned-docs -w lit-dev-content`
+packages/lit-dev-content/site/docs/unversioned
packages/lit-dev-api/api-data/*/repo/
packages/lit-dev-api/api-data/*/INSTALLED
diff --git a/packages/lit-dev-content/.eleventy.js b/packages/lit-dev-content/.eleventy.js
index 8f7e453e5..3cd758c37 100644
--- a/packages/lit-dev-content/.eleventy.js
+++ b/packages/lit-dev-content/.eleventy.js
@@ -42,6 +42,10 @@ const DEV = ENV.eleventyMode === 'dev';
const cspInlineScriptHashes = new Set();
+/**
+ * @param {import("@11ty/eleventy/src/UserConfig")} eleventyConfig
+ * @returns {ReturnType}
+ */
module.exports = function (eleventyConfig) {
// https://github.com/JordanShurmer/eleventy-plugin-toc#readme
eleventyConfig.addPlugin(pluginTOC, {
@@ -194,7 +198,19 @@ ${content}
eleventyConfig.addCollection('docs-v2', function (collection) {
const docs = collection
- .getFilteredByGlob(['site/docs/*', 'site/docs/!(v1)/**'])
+ .getFilteredByGlob(['site/docs/v2/**'])
+ .sort(sortDocs);
+ for (const page of docs) {
+ documentByUrl.set(page.url, page);
+ }
+ return docs;
+ });
+
+ // Collection that contains the built duplicate docs for the current
+ // recommended version of Lit.
+ eleventyConfig.addCollection('docs-unversioned', function (collection) {
+ const docs = collection
+ .getFilteredByGlob(['site/docs/unversioned/**'])
.sort(sortDocs);
for (const page of docs) {
documentByUrl.set(page.url, page);
@@ -487,8 +503,10 @@ ${content}
ENV.eleventyOutDir + '/docs/*/index.html',
ENV.eleventyOutDir + '/docs/v1/introduction.html',
ENV.eleventyOutDir + '/docs/v1/*/index.html',
+ ENV.eleventyOutDir + '/docs/v2/introduction.html',
+ ENV.eleventyOutDir + '/docs/v2/*/index.html',
],
- {ignore: ENV.eleventyOutDir + '/docs/v1/index.html'}
+ {ignore: ENV.eleventyOutDir + '/docs/(v1|v2)/index.html'}
)
).filter(
// TODO(aomarks) This is brittle, we need a way to annotate inside an md
diff --git a/packages/lit-dev-content/package.json b/packages/lit-dev-content/package.json
index 5ee0a1080..61cb00cab 100644
--- a/packages/lit-dev-content/package.json
+++ b/packages/lit-dev-content/package.json
@@ -12,6 +12,7 @@
"build:ts": "wireit",
"build:rollup": "wireit",
"build:samples": "wireit",
+ "build:unversioned-docs": "wireit",
"dev:build": "wireit",
"dev:serve": "wireit",
"prod:build": "wireit",
@@ -36,6 +37,7 @@
"dependencies": [
"build:ts",
"fonts:manrope",
+ "build:unversioned-docs",
{
"script": "build:samples",
"cascade": false
@@ -86,7 +88,8 @@
"build:ts",
"build:samples",
"build:rollup",
- "fonts:manrope"
+ "fonts:manrope",
+ "build:unversioned-docs"
]
},
"fonts:manrope": {
@@ -135,6 +138,15 @@
"output": [
"samples/js/**"
]
+ },
+ "build:unversioned-docs": {
+ "command": "node ../lit-dev-tools-esm/lib/build-unversioned-docs.js",
+ "dependencies": [
+ "../lit-dev-tools-esm:build"
+ ],
+ "output": [
+ "site/docs/unversioned"
+ ]
}
},
"devDependencies": {
diff --git a/packages/lit-dev-tools-esm/src/build-unversioned-docs.ts b/packages/lit-dev-tools-esm/src/build-unversioned-docs.ts
new file mode 100644
index 000000000..55cf205ad
--- /dev/null
+++ b/packages/lit-dev-tools-esm/src/build-unversioned-docs.ts
@@ -0,0 +1,154 @@
+/**
+ * @license
+ * Copyright 2023 Google LLC
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import {fileURLToPath} from 'url';
+import * as pathlib from 'path';
+import * as fs from 'fs';
+import * as fsPromise from 'fs/promises';
+
+const THIS_DIR = pathlib.dirname(fileURLToPath(import.meta.url));
+const REPO_ROOT = pathlib.resolve(THIS_DIR, '..', '..', '..');
+const CONTENT_PKG = pathlib.resolve(REPO_ROOT, 'packages', 'lit-dev-content');
+const SITE_JSON = pathlib.resolve(CONTENT_PKG, 'site', 'site.json');
+
+interface SiteJSON {
+ selectedVersion: 'v1' | 'v2';
+}
+
+type EleventyFrontMatterData = string[];
+
+const SITE_SELECTED_VERSION = (
+ JSON.parse(fs.readFileSync(SITE_JSON, 'utf8')) as SiteJSON
+).selectedVersion;
+const SELECTED_VERSION_CONTENT = pathlib.resolve(
+ CONTENT_PKG,
+ 'site',
+ 'docs',
+ SITE_SELECTED_VERSION
+);
+console.log(SELECTED_VERSION_CONTENT);
+const UNVERSIONED_VERSION_LOCATION = pathlib.resolve(
+ CONTENT_PKG,
+ 'site',
+ 'docs',
+ 'unversioned'
+);
+
+/**
+ * This script builds our unversioned latest documentation for lit.dev. It
+ * locates the current selectedVersion of Lit to show from `site.json`, then
+ * copies that documentation from the versioned subdirectory into an unversioned
+ * subdirectory.
+ *
+ * The following transforms are then applied on the files:
+ * - Permalink frontmatter is added to strip the version from the URL. E.g.,
+ * /docs/v2/* becomes /docs/*.
+ * - Versioned cross links are detected and made unversioned.
+ */
+const buildAndTransformUnverionedDocs = async () => {
+ const walk = async (dirPath: string): Promise => {
+ const entries = await fsPromise.readdir(dirPath, {withFileTypes: true});
+ await Promise.all(
+ entries.map(async (entry) => {
+ const childPath = pathlib.join(dirPath, entry.name);
+ if (entry.isDirectory()) {
+ return walk(childPath);
+ } else {
+ transformFile(childPath);
+ }
+ })
+ );
+ };
+
+ console.log('Starting build-unversioned-docs.js script');
+ await walk(SELECTED_VERSION_CONTENT);
+ console.log('Completed build-unversioned-docs.js script');
+};
+
+/**
+ * Transform the given versioned content file and copy it to the unversioned
+ * directory.
+ */
+function transformFile(path: string) {
+ let fileContents = fs.readFileSync(path, {encoding: 'utf8'});
+ const relativeChildPath = pathlib.relative(SELECTED_VERSION_CONTENT, path);
+ const ext = pathlib.extname(relativeChildPath);
+ let unversionedLocation = pathlib.join(
+ UNVERSIONED_VERSION_LOCATION,
+ relativeChildPath
+ );
+
+ if (ext === '.md') {
+ const fileName = pathlib.basename(unversionedLocation, '.md');
+ const [frontMatterData, restOfFile] = getFrontMatterData(fileContents);
+ const existingPermalink = frontMatterData.findIndex((val) =>
+ val.includes('permalink:')
+ );
+ if (existingPermalink !== -1) {
+ throw new Error(
+ 'Unhandled case: Handle this by transforming the permalink here.'
+ );
+ }
+ if (fileName === 'index') {
+ frontMatterData.push(
+ `permalink: docs/${relativeChildPath.slice(0, -3)}.html`
+ );
+ } else {
+ frontMatterData.push(
+ `permalink: docs/${relativeChildPath.slice(0, -3)}/index.html`
+ );
+ }
+
+ fileContents = writeFrontMatter(frontMatterData) + restOfFile;
+ } else if (ext === '.json') {
+ if (
+ pathlib.basename(unversionedLocation, '.json') === SITE_SELECTED_VERSION
+ ) {
+ unversionedLocation = pathlib.join(
+ pathlib.dirname(unversionedLocation),
+ 'unversioned.json'
+ );
+ fileContents = JSON.stringify({
+ collection: 'docs-unversioned',
+ selectedversion: SITE_SELECTED_VERSION,
+ });
+ }
+ } else if (ext === '.html') {
+ if (pathlib.basename(unversionedLocation, '.html') === 'api') {
+ const [frontMatterData, _] = getFrontMatterData(fileContents);
+ const transformedFrontMatter = frontMatterData.map((line) => {
+ return line.replace(`/${SITE_SELECTED_VERSION}/`, '/');
+ });
+ fileContents = writeFrontMatter(transformedFrontMatter);
+ } else {
+ throw new Error(`Unhandled html document: '${path}'`);
+ }
+ } else {
+ throw new Error(`Unhandled extension '${ext}' for '${path}'`);
+ }
+
+ fs.mkdirSync(pathlib.dirname(unversionedLocation), {recursive: true});
+ fs.writeFileSync(unversionedLocation, fileContents);
+}
+
+/**
+ * Retrieve the 11ty frontmatter from our docs. This is not a full fledged YAML
+ * parser.
+ */
+function getFrontMatterData(
+ fileData: string
+): [EleventyFrontMatterData, string] {
+ const splitFile = fileData.split('---');
+ const frontMatterData = splitFile[1].split('\n').slice(1, -1);
+ const restOfFile = splitFile.slice(2).join('---');
+ return [frontMatterData, restOfFile];
+}
+
+function writeFrontMatter(frontmatter: EleventyFrontMatterData): string {
+ return '---\n' + frontmatter.join('\n') + '\n---';
+}
+
+buildAndTransformUnverionedDocs();
From abfec328dac37066bdbeb770db0765e241f86fb5 Mon Sep 17 00:00:00 2001
From: Andrew Jakubowicz
Date: Wed, 10 May 2023 09:51:36 -0700
Subject: [PATCH 03/33] Fix wireit so npm run dev doesnt spin infinitely.
---
packages/lit-dev-content/package.json | 6 ++++-
.../src/build-unversioned-docs.ts | 24 +++++++++----------
2 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/packages/lit-dev-content/package.json b/packages/lit-dev-content/package.json
index 61cb00cab..6dc04edbf 100644
--- a/packages/lit-dev-content/package.json
+++ b/packages/lit-dev-content/package.json
@@ -144,8 +144,12 @@
"dependencies": [
"../lit-dev-tools-esm:build"
],
+ "files": [
+ "site/docs/**",
+ "!site/docs/unversioned"
+ ],
"output": [
- "site/docs/unversioned"
+ "site/docs/unversioned/**"
]
}
},
diff --git a/packages/lit-dev-tools-esm/src/build-unversioned-docs.ts b/packages/lit-dev-tools-esm/src/build-unversioned-docs.ts
index 55cf205ad..54b8d33c8 100644
--- a/packages/lit-dev-tools-esm/src/build-unversioned-docs.ts
+++ b/packages/lit-dev-tools-esm/src/build-unversioned-docs.ts
@@ -15,21 +15,21 @@ const CONTENT_PKG = pathlib.resolve(REPO_ROOT, 'packages', 'lit-dev-content');
const SITE_JSON = pathlib.resolve(CONTENT_PKG, 'site', 'site.json');
interface SiteJSON {
- selectedVersion: 'v1' | 'v2';
+ latestVersion: 'v1' | 'v2';
}
type EleventyFrontMatterData = string[];
-const SITE_SELECTED_VERSION = (
+const SITE_LATEST_VERSION = (
JSON.parse(fs.readFileSync(SITE_JSON, 'utf8')) as SiteJSON
-).selectedVersion;
-const SELECTED_VERSION_CONTENT = pathlib.resolve(
+).latestVersion;
+const LATEST_VERSION_CONTENT = pathlib.resolve(
CONTENT_PKG,
'site',
'docs',
- SITE_SELECTED_VERSION
+ SITE_LATEST_VERSION
);
-console.log(SELECTED_VERSION_CONTENT);
+console.log(LATEST_VERSION_CONTENT);
const UNVERSIONED_VERSION_LOCATION = pathlib.resolve(
CONTENT_PKG,
'site',
@@ -39,7 +39,7 @@ const UNVERSIONED_VERSION_LOCATION = pathlib.resolve(
/**
* This script builds our unversioned latest documentation for lit.dev. It
- * locates the current selectedVersion of Lit to show from `site.json`, then
+ * locates the current latestVersion of Lit to show from `site.json`, then
* copies that documentation from the versioned subdirectory into an unversioned
* subdirectory.
*
@@ -64,7 +64,7 @@ const buildAndTransformUnverionedDocs = async () => {
};
console.log('Starting build-unversioned-docs.js script');
- await walk(SELECTED_VERSION_CONTENT);
+ await walk(LATEST_VERSION_CONTENT);
console.log('Completed build-unversioned-docs.js script');
};
@@ -74,7 +74,7 @@ const buildAndTransformUnverionedDocs = async () => {
*/
function transformFile(path: string) {
let fileContents = fs.readFileSync(path, {encoding: 'utf8'});
- const relativeChildPath = pathlib.relative(SELECTED_VERSION_CONTENT, path);
+ const relativeChildPath = pathlib.relative(LATEST_VERSION_CONTENT, path);
const ext = pathlib.extname(relativeChildPath);
let unversionedLocation = pathlib.join(
UNVERSIONED_VERSION_LOCATION,
@@ -105,7 +105,7 @@ function transformFile(path: string) {
fileContents = writeFrontMatter(frontMatterData) + restOfFile;
} else if (ext === '.json') {
if (
- pathlib.basename(unversionedLocation, '.json') === SITE_SELECTED_VERSION
+ pathlib.basename(unversionedLocation, '.json') === SITE_LATEST_VERSION
) {
unversionedLocation = pathlib.join(
pathlib.dirname(unversionedLocation),
@@ -113,14 +113,14 @@ function transformFile(path: string) {
);
fileContents = JSON.stringify({
collection: 'docs-unversioned',
- selectedversion: SITE_SELECTED_VERSION,
+ latestVersion: SITE_LATEST_VERSION,
});
}
} else if (ext === '.html') {
if (pathlib.basename(unversionedLocation, '.html') === 'api') {
const [frontMatterData, _] = getFrontMatterData(fileContents);
const transformedFrontMatter = frontMatterData.map((line) => {
- return line.replace(`/${SITE_SELECTED_VERSION}/`, '/');
+ return line.replace(`/${SITE_LATEST_VERSION}/`, '/');
});
fileContents = writeFrontMatter(transformedFrontMatter);
} else {
From e56c92bea52a5bb710b2dc0510c808a681fc5ddc Mon Sep 17 00:00:00 2001
From: Andrew Jakubowicz
Date: Wed, 10 May 2023 11:14:48 -0700
Subject: [PATCH 04/33] Add rel=canonical link from latestVersion to
unversioned page.
---
packages/lit-dev-content/.eleventy.js | 21 +++++++++++++++++++
.../lit-dev-content/site/_includes/docs.html | 7 +++++++
2 files changed, 28 insertions(+)
diff --git a/packages/lit-dev-content/.eleventy.js b/packages/lit-dev-content/.eleventy.js
index 3cd758c37..0a119efa7 100644
--- a/packages/lit-dev-content/.eleventy.js
+++ b/packages/lit-dev-content/.eleventy.js
@@ -162,6 +162,27 @@ ${content}
return content.replace(//g, '');
});
+ /**
+ * For the latest versioned urls, this filter returns the unversioned url
+ * which is used in the rel=canonical link.
+ */
+ eleventyConfig.addFilter(
+ 'removeLatestVersionFromUrl',
+ function (url, latestVersion) {
+ if (!latestVersion) {
+ throw new Error(
+ `No latestVersion provided to 'removeLatestVersionFromUrl`
+ );
+ }
+ if (!url.includes(`/${latestVersion}/`)) {
+ throw new Error(
+ `'${url}' does not include the latestVersion versioned path segment`
+ );
+ }
+ return url.replace(`/${latestVersion}/`, '/');
+ }
+ );
+
eleventyConfig.addFilter('removeExtension', function (url) {
const extension = path.extname(url);
return url.substring(0, url.length - extension.length);
diff --git a/packages/lit-dev-content/site/_includes/docs.html b/packages/lit-dev-content/site/_includes/docs.html
index d35c3a7f9..bd5b69279 100644
--- a/packages/lit-dev-content/site/_includes/docs.html
+++ b/packages/lit-dev-content/site/_includes/docs.html
@@ -20,6 +20,13 @@
{% endif %}
+ {% if selectedVersion == latestVersion and page.url.includes("/" + latestVersion + "/") %}
+
+
+ {% endif %}
{% endblock %}
{% block content %}
From 487ac0ca286e424ceaf1ea18f8f0ffdb80b79820 Mon Sep 17 00:00:00 2001
From: Andrew Jakubowicz
Date: Wed, 10 May 2023 12:22:45 -0700
Subject: [PATCH 05/33] Make all authored cross links versioned.
Unversioned links will be generated automatically by the generated
unversioned pages.
---
.../lit-dev-api/api-data/lit-2/pages.json | 30 +++++++--------
.../site/docs/v2/components/decorators.md | 20 +++++-----
.../site/docs/v2/components/events.md | 4 +-
.../site/docs/v2/components/lifecycle.md | 16 ++++----
.../site/docs/v2/components/overview.md | 10 ++---
.../site/docs/v2/components/properties.md | 12 +++---
.../site/docs/v2/components/rendering.md | 18 ++++-----
.../site/docs/v2/components/shadow-dom.md | 10 ++---
.../site/docs/v2/components/styles.md | 6 +--
.../v2/composition/component-composition.md | 4 +-
.../site/docs/v2/composition/controllers.md | 10 ++---
.../site/docs/v2/composition/mixins.md | 10 ++---
.../site/docs/v2/composition/overview.md | 6 +--
.../site/docs/v2/data/context.md | 2 +-
.../site/docs/v2/getting-started.md | 4 +-
.../lit-dev-content/site/docs/v2/index.md | 16 ++++----
.../site/docs/v2/libraries/labs.md | 4 +-
.../docs/v2/libraries/standalone-templates.md | 20 +++++-----
.../docs/v2/localization/cli-and-config.md | 2 +-
.../site/docs/v2/localization/overview.md | 12 +++---
.../site/docs/v2/localization/runtime-mode.md | 4 +-
.../docs/v2/localization/transform-mode.md | 2 +-
.../docs/v2/releases/release-notes/1.2.0.md | 8 ++--
.../site/docs/v2/ssr/authoring.md | 2 +-
.../site/docs/v2/ssr/client-usage.md | 2 +-
.../site/docs/v2/ssr/overview.md | 2 +-
.../site/docs/v2/ssr/server-usage.md | 2 +-
.../site/docs/v2/templates/conditionals.md | 6 +--
.../docs/v2/templates/custom-directives.md | 2 +-
.../site/docs/v2/templates/directives.md | 4 +-
.../site/docs/v2/templates/expressions.md | 38 +++++++++----------
.../site/docs/v2/templates/overview.md | 12 +++---
.../site/docs/v2/tools/adding-lit.md | 4 +-
.../site/docs/v2/tools/development.md | 2 +-
.../site/docs/v2/tools/overview.md | 14 +++----
.../site/docs/v2/tools/production.md | 8 ++--
.../site/docs/v2/tools/publishing.md | 4 +-
.../site/docs/v2/tools/requirements.md | 2 +-
.../site/docs/v2/tools/starter-kits.md | 8 ++--
.../site/docs/v2/tools/testing.md | 6 +--
.../src/api-docs/configs/lit-2.ts | 2 +-
41 files changed, 175 insertions(+), 175 deletions(-)
diff --git a/packages/lit-dev-api/api-data/lit-2/pages.json b/packages/lit-dev-api/api-data/lit-2/pages.json
index e4c34714b..81406b2b1 100644
--- a/packages/lit-dev-api/api-data/lit-2/pages.json
+++ b/packages/lit-dev-api/api-data/lit-2/pages.json
@@ -12,7 +12,7 @@
"name": "LitElement",
"comment": {
"shortText": "Base element class that manages element properties and attributes, and\nrenders a lit-html template.",
- "text": "To define a component, subclass `LitElement` and implement a\n`render` method to provide the component's template. Define properties\nusing the [`properties`](/docs/api/LitElement/#LitElement.properties) property or the\n[`property`](/docs/api/decorators/#property) decorator.\n"
+ "text": "To define a component, subclass `LitElement` and implement a\n`render` method to provide the component's template. Define properties\nusing the [`properties`](/docs/v2/api/LitElement/#LitElement.properties) property or the\n[`property`](/docs/v2/api/decorators/#property) decorator.\n"
},
"sources": [
{
@@ -949,7 +949,7 @@
"tag": "@nocollapse"
}
],
- "shortText": "Creates a property accessor on the element prototype if one does not exist\nand stores a [`PropertyDeclaration`](/docs/api/ReactiveElement/#PropertyDeclaration) for the property with the\ngiven options. The property setter calls the property's `hasChanged`\nproperty option or uses a strict identity check to determine whether or not\nto request an update.",
+ "shortText": "Creates a property accessor on the element prototype if one does not exist\nand stores a [`PropertyDeclaration`](/docs/v2/api/ReactiveElement/#PropertyDeclaration) for the property with the\ngiven options. The property setter calls the property's `hasChanged`\nproperty option or uses a strict identity check to determine whether or not\nto request an update.",
"text": "This method may be overridden to customize properties; however,\nwhen doing so, it's important to call `super.createProperty` to ensure\nthe property is setup correctly. This method calls\n`getPropertyDescriptor` internally to get a descriptor to install.\nTo customize what properties do when they are get or set, override\n`getPropertyDescriptor`. To customize the options for a property,\nimplement `createProperty` like this:\n```ts\nstatic createProperty(name, options) {\n options = Object.assign(options, {myOption: true});\n super.createProperty(name, options);\n}\n```\n"
},
"sources": [
@@ -1222,7 +1222,7 @@
}
],
"shortText": "Returns the property options associated with the given property.\nThese options are defined with a `PropertyDeclaration` via the `properties`\nobject or the `@property` decorator and are registered in\n`createProperty(...)`.",
- "text": "Note, this method should be considered \"final\" and not overridden. To\ncustomize the options for a given property, override\n[`createProperty`](/docs/api/LitElement/#LitElement.createProperty).\n"
+ "text": "Note, this method should be considered \"final\" and not overridden. To\ncustomize the options for a given property, override\n[`createProperty`](/docs/v2/api/LitElement/#LitElement.createProperty).\n"
},
"sources": [
{
@@ -1760,7 +1760,7 @@
"tag": "@nocollapse"
}
],
- "shortText": "Array of styles to apply to the element. The styles should be defined\nusing the [`css`](/docs/api/styles/#css) tag function, via constructible stylesheets, or\nimported from native CSS module scripts.",
+ "shortText": "Array of styles to apply to the element. The styles should be defined\nusing the [`css`](/docs/v2/api/styles/#css) tag function, via constructible stylesheets, or\nimported from native CSS module scripts.",
"text": "Note on Content Security Policy:\nElement styles are implemented with `
+ template content
+ `;
+}
+```
+
+
+
+**Limitations in the ShadyCSS polyfill around per instance styling.** Per instance styling is not supported using the ShadyCSS polyfill. See the [ShadyCSS limitations](https://github.com/webcomponents/polyfills/tree/master/packages/shadycss#limitations) for details.
+
+
+
+#### Expressions and style elements
+
+Using expressions inside style elements has some important limitations and performance issues.
+
+```js
+render() {
+ return html`
+
+ template content
+ `;
+}
+```
+
+
+
+**Limitations in the ShadyCSS polyfill around expressions.** Expressions in ``;
+ return html`${this.red ? redStyle : ''}`
+
+```
+
+### Import an external stylesheet (not recommended) {#external-stylesheet}
+
+While you can include an external style sheet in your template with a `
`, we do not recommend this approach. Instead, styles should be placed in the [static `styles` class field](#add-styles).
+
+
+
+**External stylesheet caveats.**
+
+* The [ShadyCSS polyfill](https://github.com/webcomponents/polyfills/tree/master/packages/shadycss#limitations) doesn't support external style sheets.
+* External styles can cause a flash-of-unstyled-content (FOUC) while they load.
+* The URL in the `href` attribute is relative to the **main document**. This is okay if you're building an app and your asset URLs are well-known, but avoid using external style sheets when building a reusable element.
+
+
+
+## Dynamic classes and styles
+
+One way to make styles dynamic is to add expressions to the `class` or `style` attributes in your template.
+
+Lit offers two directives, `classMap` and `styleMap`, to conveniently apply classes and styles in HTML templates.
+
+For more information on these and other directives, see the documentation on [built-in directives](/docs/v2/templates/directives/).
+
+To use `styleMap` and/or `classMap`:
+
+1. Import `classMap` and/or `styleMap`:
+
+ ```js
+ import { classMap } from 'lit/directives/class-map.js';
+ import { styleMap } from 'lit/directives/style-map.js';
+ ```
+
+2. Use `classMap` and/or `styleMap` in your element template:
+
+{% playground-example "docs/components/style/maps" "my-element.ts" %}
+
+See [classMap](/docs/v2/templates/directives/#classmap) and [styleMap](/docs/v2/templates/directives/#stylemap) for more information.
+
+## Theming {#theming}
+
+By using [CSS inheritance](#inheritance) and [CSS variables and custom properties](#customprops) together, it's easy to create themable elements. By applying css selectors to customize CSS custom properties, tree-based and per-instance theming is straightforward to apply. Here's an example:
+
+{% playground-example "docs/components/style/theming" "my-element.ts" %}
+
+### CSS inheritance {#inheritance}
+
+CSS inheritance lets parent and host elements propagate certain CSS properties to their descendants.
+
+Not all CSS properties inherit. Inherited CSS properties include:
+
+* `color`
+* `font-family` and other `font-*` properties
+* All CSS custom properties (`--*`)
+
+See [CSS Inheritance on MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/inheritance) for more information.
+
+You can use CSS inheritance to set styles on an ancestor element that are inherited by its descendants:
+
+```html
+
+
+ #shadow-root
+ Will be green
+
+```
+
+### CSS custom properties {#customprops}
+
+All CSS custom properties (
--custom-property-name
) inherit. You can use this to make your component's styles configurable from outside.
+
+The following component sets its background color to a CSS variable. The CSS variable uses the value of `--my-background` if it's been set by a selector matching an ancestor in the DOM tree, and otherwise defaults to `yellow`:
+
+```js
+class MyElement extends LitElement {
+ static styles = css`
+ :host {
+ background-color: var(--my-background, yellow);
+ }
+ `;
+ render() {
+ return html`
Hello world
`;
+ }
+}
+```
+
+Users of this component can set the value of `--my-background`, using the `my-element` tag as a CSS selector:
+
+```html
+
+
+```
+
+`--my-background` is configurable per instance of `my-element`:
+
+```html
+
+
+
+```
+
+See [CSS Custom Properties on MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/--*) for more information.
diff --git a/packages/lit-dev-content/site/docs/v3/composition/component-composition.md b/packages/lit-dev-content/site/docs/v3/composition/component-composition.md
new file mode 100644
index 000000000..68cb2921e
--- /dev/null
+++ b/packages/lit-dev-content/site/docs/v3/composition/component-composition.md
@@ -0,0 +1,111 @@
+---
+title: Component composition
+eleventyNavigation:
+ parent: Composition
+ key: Component composition
+ order: 2
+---
+
+The most common way to handle complexity and factor Lit code into separate units is _component composition_: that is, the process of building a large, complex component out of smaller, simpler components. Imagine you've been tasked with implementing a screen of UI:
+
+
+
+
+You can probably identify the areas which will involve some complexity to implement. Chances are, those could be components.
+
+By isolating the complexity into specific components, you make the job much simpler, and you can then compose these components together to create the overall design.
+
+For example, the fairly simple screenshot above involves a number of possible components: a top bar, a menu button, a drawer with menu items for navigating the current section; and a main content area. Each of these could be represented by a component. A complex component, like a drawer with a navigation menu, might be broken into many smaller components: the drawer itself, a button to open and close the drawer, the menu, individual menu items.
+
+Lit lets you compose by adding elements to your template—whether those are built-in HTML elements or custom elements.
+
+```js
+render() {
+ return html`
+
+
+ Fuzzy
+
+ `;
+}
+```
+
+## What makes a good component
+
+When deciding how to break up functionality, there are several things that help identify when to make a new component. A piece of UI may be a good candidate for a component if one or more of the following applies:
+
+* It has its own state.
+* It has its own template.
+* It's used in more than one place, either in this component or in multiple components.
+* It focuses on doing one thing well.
+* It has a well-defined API.
+
+Reusable controls like buttons, checkboxes, and input fields can make great components. But more complex UI pieces like drawers and carousels are also great candidates for componentization.
+
+
+## Passing data up and down the tree
+
+When exchanging data with subcomponents, the general rule is to follow the model of the DOM: _properties down_, _events up_.
+
+* Properties down. Setting properties on a subcomponent is usually preferable to calling methods on the subcomponent. It's easy to set properties in Lit templates and other declarative template systems.
+
+* Events up. In the web platform, firing events is the default method for elements to send information up the tree, often in response to user interactions. This lets the host component respond to the event, or transform or re-fire the event for ancestors farther up the tree.
+
+A few implications of this model:
+
+* A component should be the source of truth for the subcomponents in its shadow DOM. Subcomponents shouldn't set properties or call methods on their host component.
+
+* If a component changes a public property on itself, it should fire an event to notify components higher in the tree. Generally these changes will be the result of user actions—like pressing a button or selecting a menu item. Think of the native `input` element, which fires an event when the user changes the value of the input.
+
+Consider a menu component that includes a set of menu items and exposes `items` and `selectedItem` properties as part of its public API. Its DOM structure might look like this:
+
+
+
+
+When the user selects an item, the `my-menu` element should update its `selectedItem` property. It should also fire an event to notify any owning component that the selection has changed. The complete sequence would be something like this:
+
+- The user interacts with an item, causing an event to fire (either a standard event like `click`, or some event specific to the `my-item` component).
+- The `my-menu` element gets the event, and updates its `selectedItem` property. It may also change some state so that the selected item is highlighted.
+- The `my-menu` element fires a semantic event indicating that the selection has changed. This event might be called `selected-item-changed`, for example. Since this event is part of the API for `my-menu`, it should be semantically meaningful in that context.
+
+For more information on dispatching and listening for events, see [Events](/docs/v2/components/events/).
+
+
+## Passing data across the tree
+
+Properties down and events up is a good rule to start with. But what if you need to exchange data between two components that don't have a direct descendant relationship? For example, two components that are siblings in the shadow tree?
+
+One solution to this problem is to use the _mediator pattern_. In the mediator pattern, peer components don't communicate with each other directly. Instead, interactions are _mediated_ by a third party.
+
+A simple way to implement the mediator pattern is by having the owning component handle events from its children, and in turn update the state of its children as necessary by passing changed data back down the tree. By adding a mediator, you can pass data across the tree using the familiar events-up, properties-down principle.
+
+In the following example, the mediator element listens for events from the input and button elements in its shadow DOM. It controls the enabled state of the button so the user can only click **Submit** when there's text in the input.
+
+{% playground-example "docs/composition/mediator-pattern" "mediator-element.ts" %}
+
+Other mediator patterns include flux/Redux-style patterns where a store mediates changes and updates components via subscriptions. Having components directly subscribe to changes can help avoid needing every parent to pass along all data required by its children.
+
+## Light DOM children
+
+In addition to the nodes in your shadow DOM, you can render child nodes provided by the component user, like the standard `
` element can take a set of `` elements as children and render them as menu items.
+
+Child nodes are sometimes referred to as "light DOM" to distinguish them from the component's shadow DOM. For example:
+
+```html
+
+
+ Fuzzy
+
+```
+
+
+Here the `top-bar` element has two light DOM children supplied by the user: a navigation button, and a title.
+
+Interacting with light DOM children is different from interacting with nodes in the shadow DOM. Nodes in a component's shadow DOM are managed by the component, and shouldn't be accessed from outside the component. Light DOM children are managed from outside the component, but can be accessed by the component as well. The component's user can add or remove light DOM children at any time, so the component can't assume a static set of child nodes.
+
+The component has control over whether and where the child nodes are rendered, using the `` element in its shadow DOM. And it can receive notifications when child nodes are added and removed by listening for the `slotchange` event.
+
+For more information, see the sections on [rendering children with slots](/docs/v2/components/shadow-dom/#slots) and [accessing slotted children](/docs/v2/components/shadow-dom/#accessing-slotted-children).
+
+
+_Meerkat photo by [Anggit Rizkianto](https://unsplash.com/@anggit_mr) on [Unsplash](https://unsplash.com/photos/x3-OP_X0aH0)._
diff --git a/packages/lit-dev-content/site/docs/v3/composition/controllers.md b/packages/lit-dev-content/site/docs/v3/composition/controllers.md
new file mode 100644
index 000000000..efcfef3f5
--- /dev/null
+++ b/packages/lit-dev-content/site/docs/v3/composition/controllers.md
@@ -0,0 +1,296 @@
+---
+title: Reactive Controllers
+eleventyNavigation:
+ parent: Composition
+ key: Controllers
+ order: 4
+---
+
+Lit 2 introduces a new concept for code reuse and composition called _reactive controllers_.
+
+A reactive controller is an object that can hook into a component's [reactive update cycle](/docs/v2/components/lifecycle/#reactive-update-cycle). Controllers can bundle state and behavior related to a feature, making it reusable across multiple component definitions.
+
+You can use controllers to implement features that require their own state and access to the component's lifecycle, such as:
+
+* Handling global events like mouse events
+* Managing asynchronous tasks like fetching data over the network
+* Running animations
+
+
+Reactive controllers allow you to build components by composing smaller pieces that aren't themselves components. They can be thought of as reusable, partial component definitions, with their own identity and state.
+
+{% playground-ide "docs/controllers/overview" "clock-controller.ts" %}
+
+Reactive controllers are similar in many ways to class mixins. The main difference is that they have their own identity and don't add to the component's prototype, which helps contain their APIs and lets you use multiple controller instances per host component. See [Controllers and mixins](/docs/v2/composition/overview/#controllers-and-mixins) for more details.
+
+## Using a controller
+
+Each controller has its own creation API, but typically you will create an instance and store it with the component:
+
+```ts
+class MyElement extends LitElement {
+ private clock = new ClockController(this, 1000);
+}
+```
+
+The component associated with a controller instance is called the host component.
+
+The controller instance registers itself to receive lifecycle callbacks from the host component, and triggers a host update when the controller has new data to render. This is how the `ClockController` example periodically renders the current time.
+
+A controller will typically expose some functionality to be used in the host's `render()` method. For example, many controllers will have some state, like a current value:
+
+```ts
+ render() {
+ return html`
+ Current time: ${this.clock.value}
+ `;
+ }
+```
+
+Since each controller has it's own API, refer to specific controller documentation on how to use them.
+
+## Writing a controller
+
+A reactive controller is an object associated with a host component, which implements one or more host lifecycle callbacks or interacts with its host. It can be implemented in a number of ways, but we'll focus on using JavaScript classes, with constructors for initialization and methods for lifecycles.
+
+### Controller initialization
+
+A controller registers itself with its host component by calling `host.addController(this)`. Usually a controller stores a reference to its host component so that it can interact with it later.
+
+{% switchable-sample %}
+
+```ts
+class ClockController implements ReactiveController {
+ private host: ReactiveControllerHost;
+
+ constructor(host: ReactiveControllerHost) {
+ // Store a reference to the host
+ this.host = host;
+ // Register for lifecycle updates
+ host.addController(this);
+ }
+}
+```
+
+```js
+class ClockController {
+ constructor(host) {
+ // Store a reference to the host
+ this.host = host;
+ // Register for lifecycle updates
+ host.addController(this);
+ }
+}
+```
+
+{% endswitchable-sample %}
+
+You can add other constructor parameters for one-time configuration.
+
+{% switchable-sample %}
+
+```ts
+class ClockController implements ReactiveController {
+ private host: ReactiveControllerHost;
+ timeout: number
+
+ constructor(host: ReactiveControllerHost, timeout: number) {
+ this.host = host;
+ this.timeout = timeout;
+ host.addController(this);
+ }
+```
+
+```js
+class ClockController {
+ constructor(host, timeout) {
+ this.host = host;
+ this.timeout = timeout;
+ host.addController(this);
+ }
+```
+
+{% endswitchable-sample %}
+
+
+Once your controller is registered with the host component, you can add lifecycle callbacks and other class fields and methods to the controller to implement the desired state and behavior.
+
+### Lifecycle
+
+The reactive controller lifecycle, defined in the {% api "ReactiveController" %} interface, is a subset of the reactive update cycle. LitElement calls into any installed controllers during its lifecycle callbacks. These callbacks are optional.
+
+* `hostConnected()`:
+ * Called when the host is connected.
+ * Called after creating the `renderRoot`, so a shadow root will exist at this point.
+ * Useful for setting up event listeners, observers, etc.
+* `hostUpdate()`:
+ * Called before the host's `update()` and `render()` methods.
+ * Useful for reading DOM before it's updated (for example, for animations).
+* `hostUpdated()`:
+ * Called after updates, before the host's `updated()` method.
+ * Useful for reading DOM after it's modified (for example, for animations).
+* `hostDisconnected()`:
+ * Called when the host is disconnected.
+ * Useful for cleaning up things added in `hostConnected()`, such as event listeners and observers.
+
+For more information, see [Reactive update cycle](/docs/v2/components/lifecycle/#reactive-update-cycle).
+### Controller host API
+
+A reactive controller host implements a small API for adding controllers and requesting updates, and is responsible for calling its controller's lifecycle methods.
+
+This is the minimum API exposed on a controller host:
+
+* `addController(controller: ReactiveController)`
+* `removeController(controller: ReactiveController)`
+* `requestUpdate()`
+* `updateComplete: Promise`
+
+You can also create controllers that are specific to `HTMLElement`, `ReactiveElement`, `LitElement` and require more of those APIs; or even controllers that are tied to a specific element class or other interface.
+
+`LitElement` and `ReactiveElement` are controller hosts, but hosts can also be other objects like base classes from other web components libraries, components from frameworks, or other controllers.
+
+### Building controllers from other controllers
+
+Controllers can be composed of other controllers as well. To do this create a child controller and forward the host to it.
+
+{% switchable-sample %}
+
+```ts
+class DualClockController implements ReactiveController {
+ private clock1: ClockController;
+ private clock2: ClockController;
+
+ constructor(host: ReactiveControllerHost, delay1: number, delay2: number) {
+ this.clock1 = new ClockController(host, delay1);
+ this.clock2 = new ClockController(host, delay2);
+ }
+
+ get time1() { return this.clock1.value; }
+ get time2() { return this.clock2.value; }
+}
+```
+
+```js
+class DualClockController {
+ constructor(host, delay1, delay2) {
+ this.clock1 = new ClockController(host, delay1);
+ this.clock2 = new ClockController(host, delay2);
+ }
+
+ get time1() { return this.clock1.value; }
+ get time2() { return this.clock2.value; }
+}
+```
+
+{% endswitchable-sample %}
+
+### Controllers and directives
+
+Combining controllers with directives can be a very powerful technique, especially for directives that need to do work before or after rendering, like animation directives; or controllers that need references to specific elements in a template.
+
+There are two main patterns of using controllers with directives:
+* Controller directives. These are directives that themselves are controllers in order to hook into the host lifecycle.
+* Controllers that own directives. These are controllers that create one or more directives for use in the host's template.
+
+For more information about writing directives, see [Custom directives](/docs/v2/templates/custom-directives/).
+
+#### Controller directives
+
+Reactive controllers do not need to be stored as instance fields on the host. Anything added to a host using `addController()` is a controller. In particular, a directive can also be a controller. This enables a directive to hook into the host lifecycle.
+
+#### Controllers that own directives
+
+Directives do not need to be standalone functions, they can be methods on other objects as well, such as controllers. This can be useful in cases where a controller needs a specific reference to an element in a template.
+
+For example, imagine a ResizeController that lets you observe an element's size with a ResizeObserver. To work we need both a ResizeController instance, and a directive that is placed on the element we want to observe:
+
+{% switchable-sample %}
+
+```ts
+class MyElement extends LitElement {
+ private _textSize = new ResizeController(this);
+
+ render() {
+ return html`
+
+ The width is ${this._textSize.contentRect?.width}
+ `;
+ }
+}
+```
+
+```js
+class MyElement extends LitElement {
+ _textSize = new ResizeController(this);
+
+ render() {
+ return html`
+
+ The width is ${this._textSize.contentRect?.width}
+ `;
+ }
+}
+```
+
+{% endswitchable-sample %}
+
+To implement this, you create a directive and call it from a method:
+
+```ts
+class ResizeDirective {
+ /* ... */
+}
+const resizeDirective = directive(ResizeDirective);
+
+export class ResizeController {
+ /* ... */
+ observe() {
+ // Pass a reference to the controller so the directive can
+ // notify the controller on size changes.
+ return resizeDirective(this);
+ }
+}
+```
+
+{% todo %}
+
+- Review and cleanup this example
+
+{% endtodo %}
+
+## Use cases
+
+Reactive controllers are very general and have a very broad set of possible use cases. They are particularly good for connecting a component to an external resource, like user input, state management, or remote APIs. Here are a few common use cases.
+
+### External inputs
+
+Reactive controllers can be used to connect to external inputs. For example, keyboard and mouse events, resize observers, or mutation observers. The controller can provide the current value of the input to use in rendering, and request a host update when the value changes.
+
+#### Example: MouseMoveController
+
+This example shows how a controller can perform setup and cleanup work when its host is connected and disconnected, and request an update when an input changes:
+
+{% playground-ide "docs/controllers/mouse" "my-element.ts" %}
+
+### Asynchronous tasks
+
+Asynchronous tasks, such as long running computations or network I/O, typically have state that changes over time, and will need to notify the host when the task state changes (completes, errors, etc.).
+
+Controllers are a great way to bundle task execution and state to make it easy to use inside a component. A task written as a controller usually has inputs that a host can set, and outputs that a host can render.
+
+`@lit-labs/task` contains a generic `Task` controller that can pull inputs from the host, execute a task function, and render different templates depending on the task state.
+
+You can use `Task` to create a custom controller with an API tailored for your specific task. Here we wrap `Task` in a `NamesController` that can fetch one of a specified list of names from a demo REST API. `NameController` exposes a `kind` property as an input, and a `render()` method that can render one of four templates depending on the task state. The task logic, and how it updates the host, are abstracted from the host component.
+
+{% playground-ide "docs/controllers/names" %}
+
+{% todo %}
+
+- Animations
+
+{% endtodo %}
+
+## See also
+
+* [Reactive update cycle](/docs/v2/components/lifecycle/#reactive-update-cycle)
+* [@lit-labs/task](https://www.npmjs.com/package/@lit-labs/task)
diff --git a/packages/lit-dev-content/site/docs/v3/composition/index.md b/packages/lit-dev-content/site/docs/v3/composition/index.md
new file mode 100644
index 000000000..5512bfb29
--- /dev/null
+++ b/packages/lit-dev-content/site/docs/v3/composition/index.md
@@ -0,0 +1,10 @@
+---
+title: Composition
+eleventyNavigation:
+ title: Composition
+ key: Composition
+ order: 4
+---
+
+
diff --git a/packages/lit-dev-content/site/docs/v3/composition/mixins.md b/packages/lit-dev-content/site/docs/v3/composition/mixins.md
new file mode 100644
index 000000000..99f7bd651
--- /dev/null
+++ b/packages/lit-dev-content/site/docs/v3/composition/mixins.md
@@ -0,0 +1,262 @@
+---
+title: Mixins
+eleventyNavigation:
+ parent: Composition
+ key: Mixins
+ order: 3
+---
+
+Class mixins are a pattern for sharing code between classes using standard JavaScript. As opposed to "has-a" composition patterns like [reactive
+controllers](/docs/v2/composition/controllers/), where a class can _own_ a controller to add
+behavior, mixins implement "is-a" composition, where the mixin causes the class
+itself to _be_ an instance of the behavior being shared.
+
+You can use mixins to customize a Lit component by adding API or overriding its lifecycle callbacks.
+
+## Mixin basics
+
+Mixins can be thought of as "subclass factories" that override the class they
+are applied to and return a subclass, extended with the behavior in the mixin.
+Because mixins are implemented using standard JavaScript class expressions, they
+can use all of the idioms available to subclassing, such as adding new
+fields/methods, overriding existing superclass methods, and using `super`.
+
+
+
+For ease of reading, the samples on this page elide some of the TypeScript types
+for mixin functions. See [Mixins in TypeScript](#mixins-in-typescript) for details on proper
+typing of mixins in TypeScript.
+
+
+
+To define a mixin, write a function that takes a
+`superClass`, and returns a new class that extends it, adding fields and methods
+as needed:
+
+```ts
+const MyMixin = (superClass) => class extends superClass {
+ /* class fields & methods to extend superClass with */
+};
+```
+
+To apply a mixin, simply pass a class to generate a subclass with the mixin
+applied. Most commonly, users will apply the mixin directly to a base class when defining
+a new class:
+
+```ts
+class MyElement extends MyMixin(LitElement) {
+ /* user code */
+}
+```
+
+Mixins can also be used to create concrete subclasses that users can then extend
+like a normal class, where the mixin is an implementation detail:
+
+```ts
+export const LitElementWithMixin = MyMixin(LitElement);
+```
+
+```ts
+import {LitElementWithMixin} from './lit-element-with-mixin.js';
+
+class MyElement extends LitElementWithMixin {
+ /* user code */
+}
+```
+
+Because class mixins are a standard JavaScript pattern and not Lit-specific,
+there is a good deal of information in the community on leveraging mixins for
+code reuse. For more reading on mixins, here are a few good references:
+
+* [Class mixins](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#mix-ins) on MDN
+* [Real Mixins with JavaScript
+ Classes](https://justinfagnani.com/2015/12/21/real-mixins-with-JavaScript-classes/)
+ by Justin Fagnani
+* [Mixins](https://www.TypeScriptlang.org/docs/handbook/mixins.html) in the TypeScript handbook.
+* [Dedupe mixin library](https://open-wc.org/docs/development/dedupe-mixin/) by
+ open-wc, including a discussion of when mixin usage may lead to duplication,
+ and how to use a deduping library to avoid it.
+* [Mixin conventions](https://component.kitchen/elix/mixins) followed by Elix
+ web component library. While not Lit-specific, contains thoughtful suggestions
+ around applying conventions when defining mixins for web components.
+
+## Creating mixins for LitElement
+
+Mixins applied to LitElement can implement or override any of the standard
+[custom element lifecycle](/docs/v2/components/lifecycle/#custom-element-lifecycle)
+callbacks like the `constructor()` or `connectedCallback()`, as well as any of
+the [reactive update lifecycle](/docs/v2/components/lifecycle/#reactive-update-cycle)
+callbacks like `render()` or `updated()`.
+
+For example, the following mixin would log when the element is created,
+connected, and updated:
+
+```ts
+const LoggingMixin = (superClass) => class extends superClass {
+ constructor() {
+ super();
+ console.log(`${this.localName} was created`);
+ }
+ connectedCallback() {
+ super.connectedCallback();
+ console.log(`${this.localName} was connected`);
+ }
+ updated(changedProperties) {
+ super.updated?.(changedProperties);
+ console.log(`${this.localName} was updated`);
+ }
+}
+```
+
+Note that a mixin should always make a super call to the standard custom element lifecycle
+methods implemented by `LitElement`. When overriding a reactive update lifecycle
+callback, it is good practice to call the super method if it already exists on
+the superclass (as shown above with the optional-chaining call to
+`super.updated?.()`).
+
+Also note that mixins can choose to do work either before or after the base
+implementation of the standard lifecycle callbacks via its choice of when to
+make the super call.
+
+Mixins can also add [reactive properties](/docs/v2/components/properties/),
+[styles](/docs/v2/components/styles/), and API to the subclassed element.
+
+The mixin in the example below adds a `highlight` reactive property to the
+element and a `renderHighlight()` method that the user can call to wrap some
+content. The wrapped content is styled yellow when the `highlight` property/attribute is set.
+
+{% playground-ide "docs/mixins/highlightable/" "highlightable.ts" %}
+
+Note in the example above, the user of the mixin is expected to call the
+`renderHighlight()` method from their `render()` method, as well as take care to add
+the `static styles` defined by the mixin to the subclass styles. The nature of
+this contract between mixin and user is up to the mixin definition and should be
+documented by the mixin author.
+
+## Mixins in TypeScript
+
+When writing `LitElement` mixins in TypeScript, there are a few details to be
+aware of.
+
+### Typing the superclass
+
+You should constrain the `superClass` argument to the type of class you expect
+users to extend, if any. This can be accomplished using a generic `Constructor`
+helper type as shown below:
+
+```ts
+import {LitElement} from 'lit';
+
+type Constructor = new (...args: any[]) => T;
+
+export const MyMixin = >(superClass: T) => {
+ class MyMixinClass extends superClass {
+ /* ... */
+ };
+ return MyMixinClass as /* see "typing the subclass" below */;
+}
+```
+
+The above example ensures that the class being passed to the mixin extends from
+`LitElement`, so that your mixin can rely on callbacks and other API provided by
+Lit.
+
+### Typing the subclass
+
+Although TypeScript has basic support for inferring the return type for the
+subclass generated using the mixin pattern, it has a severe limitation in that
+the inferred class must not contain members with `private` or `protected`
+access modifiers.
+
+
+
+Because `LitElement` itself does have private and protected members, by default
+TypeScript will error with _"Property '...' of exported class expression may not
+be private or protected."_ when returning a class that extends `LitElement`.
+
+
+
+There are two workarounds that both involve casting the return type
+from the mixin function to avoid the error above.
+
+#### When a mixin does not add new public/protected API
+
+If your mixin only overrides `LitElement` methods or properties and does not
+add any new API of its own, you can simply cast the generated class to the super
+class type `T` that was passed in:
+
+```ts
+export const MyMixin = >(superClass: T) => {
+ class MyMixinClass extends superClass {
+ connectedCallback() {
+ super.connectedCallback();
+ this.doSomethingPrivate();
+ }
+ private doSomethingPrivate() {
+ /* does not need to be part of the interface */
+ }
+ };
+ // Cast return type to the superClass type passed in
+ return MyMixinClass as T;
+}
+```
+
+#### When a mixin adds new public/protected API
+
+If your mixin does add new protected or public API that you need users to be
+able to use on their class, you need to define the interface for the mixin
+separately from the implementation, and cast the return type as the intersection
+of your mixin interface and the super class type:
+
+```ts
+// Define the interface for the mixin
+export declare class MyMixinInterface {
+ highlight: boolean;
+ protected renderHighlight(): unknown;
+}
+
+export const MyMixin = >(superClass: T) => {
+ class MyMixinClass extends superClass {
+ @property() highlight = false;
+ protected renderHighlight() {
+ /* ... */
+ }
+ };
+ // Cast return type to your mixin's interface intersected with the superClass type
+ return MyMixinClass as Constructor & T;
+}
+```
+
+### Applying decorators in mixins
+
+Due to limitations of TypeScript's type system, decorators (such as
+`@property()`) must be applied to a class declaration statement and not a class
+expression.
+
+In practice this means mixins in TypeScript need to declare a class
+and then return it, rather than return a class expression directly from the
+arrow function.
+
+Supported:
+```ts
+export const MyMixin = (superClass: T) => {
+ // ✅ Defining a class in a function body, and then returning it
+ class MyMixinClass extends superClass {
+ @property()
+ mode = 'on';
+ /* ... */
+ };
+ return MyMixinClass;
+}
+```
+
+Not supported:
+```ts
+export const MyMixin = (superClass: T) =>
+ // ❌ Returning class expression directly using arrow-function shorthand
+ class extends superClass {
+ @property()
+ mode = 'on';
+ /* ... */
+ }
+```
diff --git a/packages/lit-dev-content/site/docs/v3/composition/overview.md b/packages/lit-dev-content/site/docs/v3/composition/overview.md
new file mode 100644
index 000000000..8e80c1a4a
--- /dev/null
+++ b/packages/lit-dev-content/site/docs/v3/composition/overview.md
@@ -0,0 +1,38 @@
+---
+title: Composition overview
+eleventyNavigation:
+ parent: Composition
+ key: Overview
+ order: 1
+---
+
+Composition is a strategy for managing complexity and organizing code into reusable pieces. Lit provides a few options for composition and code reuse:
+
+* Component composition.
+* Reactive controllers.
+* Class mixins.
+
+[_Component composition_](/docs/v2/composition/component-composition/) is the process of assembling complex components from simpler components. A component can use subcomponents in its template. Components can use standard DOM mechanisms to communicate: setting properties on subcomponents, and listening for events from subcomponents.
+
+Although component composition is the default way to think about breaking a complex Lit project down into smaller units, there are two other notable code patterns useful for factoring your Lit code:
+
+[_Reactive controllers_](/docs/v2/composition/controllers/) are objects that can hook into the update lifecycle of a Lit component, encapsulating state and behavior related to a feature into a separate unit of code.
+
+[_Class mixins_](/docs/v2/composition/mixins/) let you write reusable partial component definitions and "mix them in" to a component's inheritance chain.
+
+Both mixins and reactive controllers let you factor component logic related to a given feature into a reusable unit. See the next section for a comparison of controllers and mixins.
+
+## Controllers and mixins
+
+Controllers and class mixins are very similar in some ways. They both can hook into a host component's lifecycle, maintain state, and trigger host updates.
+
+The primary difference between controllers and mixins is their relationship with the component. A component has a "has-a" relationship with a reactive controller, since it owns the controller. A component has an "is-a" relationship with a mixin, since the component is an instance of the mixin class.
+
+A reactive controller is a separate object owned by a component. The controller can access methods and fields on the component, and the component can access methods and fields on the controller. But the controller can't (easily) be accessed by someone using the component, unless the component exposes a public API to it. The controller's lifecycle methods are called _before_ the corresponding lifecycle method on the component.
+
+A mixin, on the other hand, becomes part of the component's prototype chain. Any public fields or methods defined by the mixin are part of the component's API. And because a mixin is part of the prototype chain, your component has some control of when the mixin's lifecycle callbacks are called.
+
+In general, if you're trying to decide whether to package a feature as a controller or a mixin, you should choose a controller _unless_ the feature requires one of the following:
+
+* Adding public API to the component.
+* Very granular access to the component lifecycle.
diff --git a/packages/lit-dev-content/site/docs/v3/data/context.md b/packages/lit-dev-content/site/docs/v3/data/context.md
new file mode 100644
index 000000000..fdfb12e74
--- /dev/null
+++ b/packages/lit-dev-content/site/docs/v3/data/context.md
@@ -0,0 +1,525 @@
+---
+title: Context
+eleventyNavigation:
+ key: Context
+ parent: Managing Data
+ order: 1
+ labs: true
+---
+
+{% labs-disclaimer %}
+
+Context is a way of making data available to entire component subtrees without having to manually bind properties to every component. The data is "contextually" available, such that ancestor elements in between a provider of data and consumer of data aren't even aware of it.
+
+Lit's context implementation is part of [Lit Labs](/docs/v2/libraries/labs/) and available in the `@lit-labs/context` package:
+
+```bash
+npm i @lit-labs/context
+```
+
+Context is useful for data that needs to be consumed by a wide variety and large number of components - things like an app's data store, the current user, a UI theme - or when data-binding isn't an option, such as when an element needs to provide data to its light DOM children.
+
+Context is very similar to React's Context, or to dependency injection systems like Angular's, with some important differences that make Context work with the dynamic nature of the DOM, and enable interoperability across different web components libraries, frameworks and plain JavaScript.
+
+## Example
+
+Using context involves a _context object_ (sometimes called a key), a _provider_ and a _consumer_, which communicate using the context object.
+
+Context definition (`logger-context.ts`):
+```ts
+import {createContext} from '@lit-labs/context';
+import type {Logger} from 'my-logging-library';
+export type {Logger} from 'my-logging-library';
+export const loggerContext = createContext('logger');
+```
+
+Provider:
+```ts
+import {LitElement, property, html} from 'lit';
+import {provide} from '@lit-labs/context';
+
+import {Logger} from 'my-logging-library';
+import {loggerContext} from './logger-context.js';
+
+@customElement('my-app')
+class MyApp extends LitElement {
+
+ @provide({context: loggerContext})
+ logger = new Logger();
+
+ render() {
+ return html`...`;
+ }
+}
+```
+
+Consumer:
+```ts
+import {LitElement, property} from 'lit';
+import {consume} from '@lit-labs/context';
+
+import {type Logger, loggerContext} from './logger-context.js';
+
+export class MyElement extends LitElement {
+
+ @consume({context: loggerContext})
+ @property({attribute: false})
+ public logger?: Logger;
+
+ private doThing() {
+ this.logger?.log('A thing was done');
+ }
+}
+```
+
+## Key Concepts
+
+### Context Protocol
+Lit's context is based on the [Context Community Protocol](https://github.com/webcomponents-cg/community-protocols/blob/main/proposals/context.md) by the W3C's [Web Components Community Group](https://www.w3.org/community/webcomponents/).
+
+This protocol enables interoperability between elements (or even non-element code) regardless of how they were built. Via the context protocol, a Lit-based element can provide data to a consumer not built with Lit, or vice versa.
+
+The Context Protocol is based on DOM events. A consumer fires a `context-request` event that carries the context key that it wants, and any element above it can listen for the `context-request` event and provide data for that context key.
+
+`@lit-labs/context` implements this event-based protocol and makes it available via a few reactive controllers and decorators.
+
+### Context Objects
+
+Contexts are identified by _context objects_ or _context keys_. They are objects that represent some potential data to be shared by the context object identity. You can think of them as similar to Map keys.
+
+### Providers
+
+Providers are usually elements (but can be any event handler code) that provide data for specific context keys.
+
+### Consumers
+
+Consumers request data for specific context keys.
+
+### Subscriptions
+
+When a consumer requests data for a context, it can tell the provider that it wants to _subscribe_ to changes in the context. If the provider has new data, the consumer will be notified and can automatically update.
+
+## Usage
+
+### Defining a context
+
+Every usage of context must have a context object to coordinate the data request. This context object represents the identity and type of data that is provided.
+
+Context objects are created with the `createContext()` function:
+
+```ts
+export const myContext = createContext(Symbol('my-context'));
+```
+
+It is recommended to put context objects in their own module so that they're importable independent of specific providers and consumers.
+
+#### Context type-checking
+
+`createContext()` takes any value and returns it directly. In TypeScript, the value is cast to a typed `Context` object, which carries the type of the context _value_ with it.
+
+In case of a mistake like this:
+```ts
+const myContext = createContext(Symbol('logger'));
+
+class MyElement extends LitElement {
+ @provide({context: myContext})
+ name: string
+}
+```
+
+TypeScript will warn that the type `string` is not assignable to the type `Logger`.
+
+#### Context equality
+
+Context objects are used by providers to match a context request event to a value. Contexts are compared with strict equality (`===`), so a provider will only handle a context request if its context key equals the context key of the request.
+
+This means that there are two main ways to create a context object:
+1. With a value that is globally unique, like an object (`{}`) or symbol (`Symbol()`)
+2. With a value that is not globally unique, so that it can be equal under strict equality, like a string (`'logger'`) or _global_ symbol (`Symbol.for('logger')`).
+
+If you want two _separate_ `createContext()` calls to refer to the same
+context, then use a key that will be equal under strict equality like a
+string:
+```ts
+// true
+createContext('my-context') === createContext('my-context')
+```
+
+Beware though that two modules in your app could use the same context key to refer to different objects. To avoid unintended collisions you may want to use a relatively unique string, e.g. like `'console-logger'` instead of `'logger'`.
+
+Usually it's best to use a globally unique context object. Symbols are one of the easiest ways to do this.
+
+### Providing a context
+
+There are two ways in `@lit-labs/context` to provide a context value: the ContextProvider controller and the `@provide()` decorator.
+
+#### `@provide()`
+
+The `@provide()` decorator is the easiest way to provide a value if you're using decorators. It creates a ContextProvider controller for you.
+
+Decorate a property with `@provide()` and give it the context key:
+```ts
+import {LitElement, html} from 'lit';
+import {property} from 'lit/decorators.js';
+import {provide} from '@lit-labs/context';
+import {myContext, MyData} from './my-context.js';
+
+class MyApp extends LitElement {
+ @provide({context: myContext})
+ myData: MyData;
+}
+```
+
+You can make the property also a reactive property with `@property()` or `@state()` so that setting it will update the provider element as well as context consumers.
+
+```ts
+ @provide({context: myContext})
+ @property({attribute: false})
+ myData: MyData;
+```
+
+Context properties are often intended to be private. You can make private properties reactive with `@state()`:
+
+```ts
+ @provide({context: myContext})
+ @state()
+ private _myData: MyData;
+```
+
+Making a context property public lets an element provide a public field to its child tree:
+
+```ts
+ html``
+```
+
+#### ContextProvider
+
+`ContextProvider` is a reactive controller that manages `context-request` event handlers for you.
+
+```ts
+import {LitElement, html} from 'lit';
+import {ContextProvider} from '@lit-labs/context';
+import {myContext, MyData} from './my-context.js';
+
+export class MyApp extends LitElement {
+ private _provider = new ContextProvider(this, myContext);
+}
+```
+
+ContextProvider can take an initial value in its constructor:
+
+```ts
+ private _provider = new ContextProvider(this, myContext, initialData);
+```
+
+Or you can call `setValue()`:
+```ts
+ this._provider.setValue(myData);
+```
+
+### Consuming a context
+
+#### `@consume()` decorator
+
+The `@consume()` decorator is the easiest way to consume a value if you're using decorators. It creates a ContextConsumer controller for you.
+
+Decorate a property with `@consume()` and give it the context key:
+```ts
+import {LitElement, html} from 'lit';
+import {consume} from '@lit-labs/context';
+import {myContext, MyData} from './my-context.js';
+
+class MyElement extends LitElement {
+ @consume({context: myContext})
+ myData: MyData;
+}
+```
+
+When this element is connected to the document, it will automatically fire a `context-request` event, get a provided value, assign it to the property, and trigger an update of the element.
+
+#### ContextConsumer
+
+ContextConsumer is a reactive controller that manages dispatching the `context-request` event for you. The controller will cause the host element to update when new values are provided. The provided value is then available at the `.value` property of the controller.
+
+```ts
+import {LitElement, property} from 'lit';
+import {ContextConsumer} from '@lit-labs/context';
+import {Logger, loggerContext} from './logger.js';
+
+export class MyElement extends LitElement {
+ private _myData = new ContextConsumer(this, myContext);
+
+ render() {
+ const myData = this._myData.value;
+ return html`...`;
+ }
+}
+```
+
+#### Subscribing to contexts
+
+Consumers can subscribe to context values so that if a provider has a new value, it can give it to all subscribed consumers, causing them to update.
+
+You can subscribe with the `@consume()` decorator:
+
+```ts
+ @consume({context: myContext, subscribe: true})
+ myData: MyData;
+```
+
+and the ContextConsumer controller:
+
+```ts
+ private _myData = new ContextConsumer(this,
+ myContext,
+ undefined, /* callback */
+ true /* subscribe */
+ );
+```
+
+## Example Use Cases
+
+### Current user, locale, etc.
+
+The most common context use cases involve data that is global to a page and possibly only sparsely needed in components throughout the page. Without context it's possible that most or all components would need to accept and propagate reactive properties for the data.
+
+### Services
+
+App-global services, like loggers, analytics, data stores, can be provided by context. An advantage of context over importing from a common module are the late coupling and tree-scoping that context provides. Tests can easily provide mock services, or different parts of the page can be given different service instances.
+
+### Themes
+
+Themes are sets of styles that apply to the entire page or entire subtrees within the page - exactly the kind of scope of data that context provides.
+
+One way of building a theme system would be to define a `Theme` type that containers can provide that holds named styles. Elements that want to apply a theme can consume the theme object and look up styles by name. Custom theme reactive controllers can wrap ContextProvider and ContextConsumer to reduce boilerplate.
+
+### HTML-based plugins
+
+Context can be used to pass data from a parent to its light DOM children. Since the parent does usually not create the light DOM children, it cannot leverage template-based data-binding to pass data to them, but it can listen to and respond to `context-request` events.
+
+For example, consider a code editor element with plugins for different language modes. You can make a plain HTML system for adding features using context:
+
+```html
+
+
+
+
+```
+
+In this case `` would provide an API for adding language modes via context, and plugin elements would consume that API and add themselves to the editor.
+
+### Data formatters, link generators, etc.
+
+Sometimes reusable components will need to format data or URLs in an application-specific way. For example, a documentation viewer that renders a link to another item. The component will not know the URL space of the application.
+
+In these cases the component can depend on a context-provided function that will apply the application-specific formatting to the data or link.
+
+## API
+
+
+
+These API docs are a summary until generated API docs are available
+
+
+
+### `createContext()`
+
+Creates a typed Context object
+
+**Import**:
+
+```ts
+import {property} from '@lit-labs/context';
+```
+
+**Signature**:
+
+```ts
+function createContext(key: K): Context;
+```
+
+
+Contexts are compared with with strict equality.
+
+If you want two separate `createContext()` calls to referrer to the same context, then use a key that will by equal under strict equality like a string for `Symbol.for()`:
+
+```ts
+// true
+createContext('my-context') === createContext('my-context')
+// true
+createContext(Symbol.for('my-context')) === createContext(Symbol.for('my-context'))
+```
+
+If you want a context to be unique so that it's guaranteed to not collide with other contexts, use a key that's unique under strict equality, like a `Symbol()` or object.:
+
+```ts
+// false
+createContext(Symbol('my-context')) === createContext(Symbol('my-context'))
+// false
+createContext({}) === createContext({})
+```
+
+The `ValueType` type parameter is the type of value that can be provided by this context. It's uses to provide accurate types in the other context APIs.
+
+### `@provide()`
+
+A property decorator that adds a ContextConsumer controller to the component which will try and retrieve a value for the property via the Context API.
+
+**Import**:
+
+```ts
+import {provide} from '@lit-labs/context';
+```
+
+**Signature**:
+
+```ts
+@provide({context: Context})
+```
+
+### `@consume()`
+
+A property decorator that adds a ContextConsumer controller to the component which will retrieve a value for the property via the Context protocol.
+
+**Import**:
+
+```ts
+import {consume} from '@lit-labs/context';
+```
+
+**Signature**:
+
+```ts
+@consume({context: Context, subscribe?: boolean})
+```
+
+`subscribe` is `false` by default. Set it to `true` to subscribe to updates to the context provided value.
+
+### `ContextProvider`
+
+A ReactiveController which adds context provider behavior to a custom element by listening to `context-request` events.
+
+**Import**:
+
+```ts
+import {ContextProvider} from '@lit-labs/context';
+```
+
+**Constructor**:
+
+```ts
+ContextProvider(
+ host: ReactiveElement,
+ context: T,
+ initialValue?: ContextType
+)
+```
+
+**Members**
+
+- `setValue(v: T, force = false): void`
+
+ Sets the value provided, and notifies any subscribed consumers of the new value if the value changed. `force` causes a notification even if the value didn't change, which can be useful if an object had a deep property change.
+
+
+### `ContextConsumer`
+
+A ReactiveController which adds context consuming behavior to a custom element by dispatching `context-request` events.
+
+**Import**:
+
+```ts
+import {ContextConsumer} from '@lit-labs/context';
+```
+
+**Constructor**:
+```ts
+ContextConsumer(
+ host: HostElement,
+ context: C,
+ callback?: (value: ContextType, dispose?: () => void) => void,
+ subscribe: boolean = false
+)
+```
+
+**Members**
+
+- `value: ContextType`
+
+ The current value for the context.
+
+When the host element is connected to the document it will emit a `context-request` event with its context key. When the context request is satisfied the controller will invoke the callback, if present, and trigger a host update so it can respond to the new value.
+
+It will also call the dispose method given by the provider when the host element is disconnected.
+
+### `ContextRoot`
+
+A ContextRoot can be used to gather unsatisfied context requests and re-dispatch them when new providers which satisfy matching context keys are available. This allows providers to be added to a DOM tree, or upgraded, after the consumers.
+
+**Import**:
+
+```ts
+import {ContextRoot} from '@lit-labs/context';
+```
+
+**Constructor**:
+```ts
+ContextRoot()
+```
+
+**Members**
+
+- `attach(element: HTMLElement): void`
+
+ Attaches the ContextRoot to this element and starts listening to `context-request` events.
+
+- `detach(element: HTMLElement): void`
+
+ Detaches the ContextRoot from this element, stops listening to `context-request` events.
+
+### `ContextRequestEvent`
+
+The event fired by consumers to request a context value. The API and behavior of this event is specified by the [Context Protocol](https://github.com/webcomponents-cg/community-protocols/blob/main/proposals/context.md).
+
+**Import**:
+
+```ts
+import {ContextRequestEvent} from '@lit-labs/context';
+```
+
+The `context-request` bubbles and is composed.
+
+**Members**
+
+- `readonly context: C`
+
+ The context object this event is requesting a value for
+
+- `readonly callback: ContextCallback>`
+
+ The function to call to provide a context value
+
+- `readonly subscribe?: boolean`
+
+ Whether the consumers wants to subscribe to new context values
+
+### `ContextCallback`
+
+A callback which is provided by a context requester and is called with the value satisfying the request.
+
+This callback can be called multiple times by context providers as the requested value is changed.
+
+**Import**:
+
+```ts
+import {type ContextCallback} from '@lit-labs/context';
+```
+
+**Signature**:
+
+```ts
+type ContextCallback = (
+ value: ValueType,
+ unsubscribe?: () => void
+) => void;
+```
diff --git a/packages/lit-dev-content/site/docs/v3/data/index.md b/packages/lit-dev-content/site/docs/v3/data/index.md
new file mode 100644
index 000000000..0d7b0628d
--- /dev/null
+++ b/packages/lit-dev-content/site/docs/v3/data/index.md
@@ -0,0 +1,9 @@
+---
+title: Managing Data
+eleventyNavigation:
+ key: Managing Data
+ order: 5
+---
+
+
diff --git a/packages/lit-dev-content/site/docs/v3/frameworks/index.md b/packages/lit-dev-content/site/docs/v3/frameworks/index.md
new file mode 100644
index 000000000..2d806e432
--- /dev/null
+++ b/packages/lit-dev-content/site/docs/v3/frameworks/index.md
@@ -0,0 +1,9 @@
+---
+title: Frameworks
+eleventyNavigation:
+ key: Frameworks
+ order: 8
+---
+
+
diff --git a/packages/lit-dev-content/site/docs/v3/frameworks/react.md b/packages/lit-dev-content/site/docs/v3/frameworks/react.md
new file mode 100644
index 000000000..5c987d43a
--- /dev/null
+++ b/packages/lit-dev-content/site/docs/v3/frameworks/react.md
@@ -0,0 +1,210 @@
+---
+title: React
+eleventyNavigation:
+ key: React
+ parent: Frameworks
+ order: 1
+ labs: true
+---
+
+{% labs-disclaimer %}
+
+The [@lit-labs/react](https://github.com/lit/lit/tree/main/packages/labs/react) package provides utilities to create React wrapper components for web components, and custom hooks from [reactive controllers](../../composition/controllers/).
+
+The React component wrapper enables setting properties on custom elements (instead of just attributes), mapping DOM events to React-style callbacks, and enables correct type-checking in JSX by TypeScript.
+
+The wrappers are targeted at two different audiences:
+- Users of web components can wrap components and controllers for their own use in their own React projects.
+- Vendors of components can publish React wrappers so that their React users have idiomatic versions of their components.
+
+### Why are wrappers needed?
+
+React can already render web components, since custom elements are just HTML elements and React knows how to render HTML. But React makes some assumptions about HTML elements that don't always hold for custom elements, and it treats lower-case tag names differently from upper-case component names in ways that can make custom elements harder than necessary to use.
+
+For instance, React assumes that all JSX properties map to HTML element attributes, and provides no way to set properties. This makes it difficult to pass complex data (like objects, arrays, or functions) to web components. React also assumes that all DOM events have corresponding "event properties" (`onclick`, `onmousemove`, etc), and uses those instead of calling `addEventListener()`. This means that to properly use more complex web components you often have to use `ref()` and imperative code. (For more information on the limitations of React's web component integration, see [Custom Elements Everywhere](https://custom-elements-everywhere.com/libraries/react/results/results.html).)
+
+React is working on fixes to these issues, but in the meantime, our wrappers take care of setting properties and listening to events for you.
+
+The `@lit-labs/react` package provides two main exports:
+
+- `createComponent()` creates a React component that _wraps_ an existing web component. The wrapper allows you to set props on the component and add event listeners to the component like you would any other React component.
+
+- `useController()` lets you use a Lit reactive controller as a React hook.
+
+## createComponent
+
+The `createComponent()` function makes a React component wrapper for a custom element class. The wrapper correctly passes React `props` to properties accepted by the custom element and listens for events dispatched by the custom element.
+
+### Usage
+
+Import `React`, a custom element class, and `createComponent`.
+
+```js
+import React from 'react';
+import {createComponent} from '@lit-labs/react';
+import {MyElement} from './my-element.js';
+
+export const MyElementComponent = createComponent({
+ tagName: 'my-element',
+ elementClass: MyElement,
+ react: React,
+ events: {
+ onactivate: 'activate',
+ onchange: 'change',
+ },
+});
+```
+
+After defining the React component, you can use it just as you would any other React component.
+
+```jsx
+ setIsActive(e.active)}
+ onchange={handleChange}
+/>
+```
+
+{% aside "positive" "no-header" %}
+
+See it in action in the [React playground examples](/playground/#sample=examples/react-basics).
+
+{% endaside %}
+
+#### Options
+
+`createComponent` takes an options object with the following properties:
+
+- `tagName`: The custom element's tag name.
+- `elementClass`: The custom element class.
+- `react`: The imported `React` object. This is used to create the wrapper component with the user supplied `React`. This can also be an import of `preact-compat`.
+- `events`: An object that maps an event handler prop to an event name fired by the custom element.
+
+#### Using slots
+
+Children of component created with `createComponent()` will render to the default slot of the custom element.
+
+```jsx
+
+ This will render in the default slot.
+
+```
+
+To render the child to a specific named slot, the standard `slot` attribute can be added.
+
+```jsx
+
+ This will render in the slot named "foo".
+
+```
+
+Since React components are not themselves HTML elements, they usually cannot directly have a `slot` attribute. To render into a named slot, the component will need to be wrapped with a container element that has a `slot` attribute. If a wrapper element interferes with styling, like for grid and flexbox layouts, giving it a `display: contents;` style ([See MDN for details](https://developer.mozilla.org/en-US/docs/Web/CSS/display#box)) will remove the container from rendering, and only render its children.
+
+```jsx
+
+
+
+
+
+```
+
+{% aside "positive" "no-header" %}
+
+Try it out in the [React slots playground example](/playground/#sample=examples/react-slots).
+
+{% endaside %}
+
+#### Events
+
+The `events` option takes an object that maps React prop names to event names. When a component user passes a callback prop with one of the event prop names, the wrapper will add it as an event handler for the corresponding event.
+
+While the the React prop name can be whatever you want, the recommended convention is to add `on` in front of the event name. This matches how React is planning to implement event support for custom elements. You should also make sure this prop name does not collide with any existing properties on the element.
+
+In TypeScript, the event type can be specified by casting the event name to the `EventName` utility type. This is a good practice to do so that React users will get the most accurate types for their event callbacks.
+
+The `EventName` type is a string that takes an event interface as a type parameter. Here we cast the `'my-event'` name to an `EventName` to provide the right event type:
+
+```ts
+
+import React from 'react';
+import {createComponent} from '@lit-labs/react';
+import {MyElement, type EventName} from './my-element.js';
+
+export const MyElementComponent = createComponent({
+ tagName: 'my-element',
+ elementClass: MyElement,
+ react: React,
+ events: {
+ 'onmy-event': 'my-event' as EventName,
+ },
+});
+```
+
+Casting the event name to `EventName` causes the React component to have an `onMyEvent` callback prop that accepts a `MyEvent` parameter instead of a plain `Event`:
+
+```tsx
+ {
+ console.log(e.myEventData);
+ }}
+/>
+```
+
+### How it works
+
+During a render, the wrapper receives props from React and based on the options and the custom element class, changes the behavior of some of the props:
+
+* If a prop name is a property on the custom element, as determined with an `in` check, the wrapper sets that property on the element to the prop value
+* If a prop name is an event name passed to the `events` option, the prop value is passed to `addEventListener()` with the name of the event.
+* Otherwise the prop is passed to React's `createElement()` to be rendered as an attribute.
+
+Both properties and events are added in `componentDidMount()` and `componentDidUpdate()` callbacks, because the element must have already been instantiated by React in order to access it.
+
+For events, `createComponent()` accepts a mapping of React event prop names to events fired by the custom element. For example passing `{onfoo: 'foo'}` means a function passed via a prop named `onfoo` will be called when the custom element fires the `foo` event with the event as an argument.
+
+## useController
+
+Reactive controllers allow developers to hook in to a component's lifecycle to bundle
+together state and behavior related to a feature. They are similar to React
+hooks in the user cases and capabilities, but are plain JavaScript objects
+instead of functions with hidden state.
+
+`useController()` lets you make React hooks out of reactive controllers allowing for the sharing of state and behaviors across web components and React.
+
+### Usage
+
+```jsx
+import React from 'react';
+import {useController} from '@lit-labs/react/use-controller.js';
+import {MouseController} from '@example/mouse-controller';
+
+// Write a custom React hook function:
+const useMouse = () => {
+ // Use useController to create and store a controller instance:
+ const controller = useController(React, (host) => new MouseController(host));
+ // Return relevant data for consumption by the component:
+ return controller.pos;
+};
+
+// Now use the new hook in a React component:
+const Component = (props) => {
+ const mousePosition = useMouse();
+ return (
+
+ x: {mousePosition.x}
+ y: {mousePosition.y}
+
+ );
+};
+```
+
+See the [mouse controller example](../../composition/controllers/#example:-mousemovecontroller) in the reactive controller docs for its implementation.
+
+### How it works
+
+`useController()` creates a custom host object for the controller passed to it and drives the controller's lifecycle by using React hooks.
+
+- `useState()` is used to store an instance of a controller and a `ReactControllerHost`
+- The hook body and `useLayoutEffect()` callbacks emulate the `ReactiveElement` lifecycle as closely as possible.
+- `ReactControllerHost` implements `addController()` so that controller composition works and nested controller lifecycles are called correctly.
+- `ReactControllerHost` also implements `requestUpdate()` by calling a `useState()` setter, so that a controller can cause its host component to re-render.
diff --git a/packages/lit-dev-content/site/docs/v3/getting-started.md b/packages/lit-dev-content/site/docs/v3/getting-started.md
new file mode 100644
index 000000000..514736a2f
--- /dev/null
+++ b/packages/lit-dev-content/site/docs/v3/getting-started.md
@@ -0,0 +1,105 @@
+---
+title: Getting Started
+eleventyNavigation:
+ key: Getting Started
+ parent: Introduction
+ order: 3
+versionLinks:
+ v1: getting-started/
+---
+
+There are many ways to get started using Lit, from our Playground and interactive tutorial to installing into an existing project.
+
+## Lit Playground
+
+Get started right away with the interactive playground and examples. Start with "[Hello World](/playground)", then customize it or move on to more examples.
+
+## Interactive tutorial
+
+Take our [step-by-step tutorial](/tutorials/intro-to-lit) to learn how to build a Lit component in minutes.
+
+## Lit starter kits
+
+We provide TypeScript and JavaScript component starter kits for creating standalone reusable components. See [Starter Kits](/docs/v2/tools/starter-kits/).
+
+## Install locally from npm
+
+Lit is available as the `lit` package via npm.
+
+```sh
+npm i lit
+```
+
+Then import into JavaScript or TypeScript files:
+
+{% switchable-sample %}
+
+```ts
+import {LitElement, html} from 'lit';
+import {customElement, property} from 'lit/decorators.js';
+```
+
+```js
+import {LitElement, html} from 'lit';
+```
+
+{% endswitchable-sample %}
+
+## Use bundles
+
+Lit is also available as pre-built, single-file bundles. These are provided for
+more flexibility around development workflows: for example, if you would prefer
+to download a single file rather than use npm and build tools. The bundles are
+standard JavaScript modules with no dependencies - any modern browser should be
+able to import and run the bundles from within a `
+
+
+
+
+
+
+
+
+
+
+
+```
+
+If you are [bundling](/docs/v2/tools/production/) your code, make sure the `lit/expriemntal-hydrate-support.js` is imported first:
+```js
+// index.js
+import 'lit/experimental-hydrate-support.js';
+import './app-components.js';
+```
+
+### Using the `template-shadowroot` polyfill
+The HTML snippet below includes an optional strategy to hide the body until the polyfill is loaded to prevent layout shifts.
+
+```html
+
+
+