diff --git a/js/apps/docs/components/CEM.vue b/js/apps/docs/components/CEM.vue index e165a101..cb3dcaaa 100644 --- a/js/apps/docs/components/CEM.vue +++ b/js/apps/docs/components/CEM.vue @@ -1,5 +1,8 @@ @@ -45,7 +49,11 @@ const sources = ["canary_webpage", "canary_issue"]; - + +import '@getcanary/web/components/canary-root.js' +import '@getcanary/web/components/canary-provider-pagefind.js' +import '@getcanary/web/components/canary-modal.js' +import '@getcanary/web/components/canary-trigger-searchbar.js' +import '@getcanary/web/components/canary-content.js' +import '@getcanary/web/components/canary-input.js' +import '@getcanary/web/components/canary-search.js' +import '@getcanary/web/components/canary-search-results.js' + + + + + + + + + + + + + + + +``` diff --git a/js/apps/docs/contents/docs/open.md b/js/apps/docs/contents/docs/open.md new file mode 100644 index 00000000..c337b27c --- /dev/null +++ b/js/apps/docs/contents/docs/open.md @@ -0,0 +1,7 @@ +# Open + +## NPM Downloads + +## Github + +### Stars diff --git a/js/apps/docs/contents/docs/reference/components.md b/js/apps/docs/contents/docs/reference/components.md index 94b6a936..f5007766 100644 --- a/js/apps/docs/contents/docs/reference/components.md +++ b/js/apps/docs/contents/docs/reference/components.md @@ -4,4 +4,18 @@ # Components +::: tip + +For visual reference and code example, please refer to our [Storybook](https://storybook.getcanary.dev). + +::: + +This page is generated from [`custom-elements-manifest`](https://custom-elements-manifest.open-wc.org/analyzer/getting-started/#supported-jsdoc). + +If you find something missing here, there's three places to fix it: + +1. [`CEM.vue`](https://github.com/fastrepl/canary/blob/main/js/apps/docs/components/CEM.vue) for rendering the data. +2. [Each component's source code](https://github.com/fastrepl/canary/tree/main/js/packages/web/src/components) for adding the missing data. +3. [`vite.config.ts`](https://github.com/fastrepl/canary/blob/main/js/packages/web/vite.config.ts) for adding the missing component. + diff --git a/js/apps/docs/contents/docs/reference/packages.md b/js/apps/docs/contents/docs/reference/packages.md index 7c52bb5c..b4d90431 100644 --- a/js/apps/docs/contents/docs/reference/packages.md +++ b/js/apps/docs/contents/docs/reference/packages.md @@ -7,12 +7,16 @@ import { data as docusaurus } from "../../../data/version_docusaurus.data.js"; ## `@getcanary/web` +[npm](https://www.npmjs.com/package/@getcanary/web) + ```bash-vue npm install @getcanary/web@{{ web.version }} ``` ## `@getcanary/docusaurus-theme-search-pagefind` +[npm](https://www.npmjs.com/package/@getcanary/docusaurus-theme-search-pagefind) + ```bash-vue npm install @getcanary/docusaurus-theme-search-pagefind@{{ docusaurus.version }} ``` diff --git a/js/apps/docs/contents/docs/why.md b/js/apps/docs/contents/docs/why.md index 603d7495..2e6dbb86 100644 --- a/js/apps/docs/contents/docs/why.md +++ b/js/apps/docs/contents/docs/why.md @@ -25,6 +25,8 @@ const packages = { We're fully [open-source](https://github.com/fastrepl/canary), and encourage anyone to contribute to our UI components. Also, we put a lot of effort into making the **core parts of `Canary` as modular as possible**. +## Attention to detail, for technical docs + ## Tiny components that works anywhere `Canary` use [Web components](https://developer.mozilla.org/en-US/docs/Web/Web_Components), so browsers know how to render it. diff --git a/js/apps/docs/package.json b/js/apps/docs/package.json index f4e07bca..c990eb10 100644 --- a/js/apps/docs/package.json +++ b/js/apps/docs/package.json @@ -20,7 +20,7 @@ "vue": "^3.4.35" }, "dependencies": { - "@getcanary/web": "^1.0.0-rc.14", + "@getcanary/web": "^1.0.0-rc.15", "@mux/blurup": "^0.2.3", "@mux/mux-player": "^3.0.0", "@vercel/analytics": "^1.3.1", diff --git a/js/package-lock.json b/js/package-lock.json index e046763b..7fa90f01 100644 --- a/js/package-lock.json +++ b/js/package-lock.json @@ -16,7 +16,7 @@ "apps/docs": { "name": "@getcanary/docs", "dependencies": { - "@getcanary/web": "^1.0.0-rc.14", + "@getcanary/web": "^1.0.0-rc.15", "@mux/blurup": "^0.2.3", "@mux/mux-player": "^3.0.0", "@vercel/analytics": "^1.3.1", @@ -34057,7 +34057,7 @@ }, "packages/web": { "name": "@getcanary/web", - "version": "1.0.0-rc.14", + "version": "1.0.0-rc.15", "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.6.8", diff --git a/js/packages/web/package.json b/js/packages/web/package.json index 6e364699..4d8dd948 100644 --- a/js/packages/web/package.json +++ b/js/packages/web/package.json @@ -1,6 +1,6 @@ { "name": "@getcanary/web", - "version": "1.0.0-rc.14", + "version": "1.0.0-rc.15", "license": "MIT", "type": "module", "main": "dist/components/canary-root.js", diff --git a/js/packages/web/src/components/canary-filter-tags.ts b/js/packages/web/src/components/canary-filter-tags.ts index c5402869..39da5114 100644 --- a/js/packages/web/src/components/canary-filter-tags.ts +++ b/js/packages/web/src/components/canary-filter-tags.ts @@ -1,5 +1,5 @@ import { LitElement, css, html, PropertyValues } from "lit"; -import { customElement, property } from "lit/decorators.js"; +import { customElement, property, state } from "lit/decorators.js"; import { classMap } from "lit/directives/class-map.js"; import pm from "picomatch"; @@ -12,82 +12,139 @@ const NAME = "canary-filter-tags"; @customElement(NAME) export class CanaryFilterTags extends LitElement { + /** + * @attr {string} tags - comma separated list of tags + */ @property({ converter: StringArray }) tags: string[] = []; + /** + * @attr {object} url-sync - sync tags with URL + */ @property({ type: Object, attribute: "url-sync" }) syncURL?: TagUrlSyncDefinition; @property({ type: String, attribute: "local-storage-key" }) localStorageKey?: string; - @property({ type: String }) - selected = ""; + @state() + private _selected = ""; connectedCallback() { super.connectedCallback(); this._ensureTagsConverted(); this._initializeSelected(); + + window.addEventListener("popstate", this._handlePopState.bind(this)); + this._patchHistory(); + } + + disconnectedCallback() { + super.disconnectedCallback(); + window.removeEventListener("popstate", this._handlePopState.bind(this)); } - updated(changed: PropertyValues) { - if (changed.has("selected") && this.localStorageKey) { - localStorage.setItem(this.localStorageKey, this.selected); + updated(changed: PropertyValues) { + if (changed.has("_selected") && this.localStorageKey) { + localStorage.setItem(this.localStorageKey, this._selected); } - if (changed.has("selected")) { + if (changed.has("_selected")) { this.dispatchEvent( - createEvent({ type: "set_query", data: { tags: [this.selected] } }), + createEvent({ type: "set_query", data: { tags: [this._selected] } }), ); } } + private _handlePopState() { + this._initializeSelected(); + } + + private _patchHistory() { + if (window["__history_patched__"]) { + return; + } + + window["__history_patched__"] = true; + + window.history.pushState = new Proxy(window.history.pushState, { + apply: ( + target: History["pushState"], + thisArg: History, + argArray: Parameters, + ): ReturnType => { + const url = + typeof argArray[2] === "string" + ? new URL(argArray[2], window.location.href).href + : window.location.href; + + this._initializeSelected(url); + return target.apply(thisArg, argArray); + }, + }); + } + private _ensureTagsConverted() { if (typeof this.tags === "string") { this.tags = StringArray.fromAttribute(this.tags, null); } } - private _initializeSelected() { - if (this.selected) { + private _initializeSelected(url?: string) { + if (this._handleSyncURL(url)) { return; } - if (this.syncURL) { - const { hostname, pathname } = new URL(window.location.href); - const found = this.syncURL.find(({ pattern }) => - pm(pattern)(`${hostname}${pathname}`), - ); + if (this._applyLocalStorage()) { + return; + } + + this._selected = this.tags[0]; + } - if (found) { - this.selected = found.tag; - return; - } + private _handleSyncURL(url?: string) { + if (!this.syncURL) { + return false; } + const { hostname, pathname } = new URL(url ?? window.location.href); + const found = this.syncURL.find(({ pattern }) => + pm(pattern)(`${hostname}${pathname}`), + ); + + if (found) { + this._selected = found.tag; + return true; + } + + return false; + } + + private _applyLocalStorage() { if (!this.localStorageKey) { - this.selected = this.tags[0]; - return; + return false; } const storedValue = localStorage.getItem(this.localStorageKey); if (storedValue && this.tags.includes(storedValue)) { - this.selected = storedValue; - } else { - this.selected = this.tags[0]; + this._selected = storedValue; + return true; } + + return false; } render() { return html`
${this.tags.map((tag) => { - const selected = tag === this.selected; + const selected = tag === this._selected; return html``; @@ -135,3 +192,9 @@ export class CanaryFilterTags extends LitElement { } `; } + +declare global { + interface Window { + __history_patched__?: boolean; + } +} diff --git a/js/packages/web/src/components/canary-search-match-base.ts b/js/packages/web/src/components/canary-search-match-base.ts index 8d10b52a..77631dd3 100644 --- a/js/packages/web/src/components/canary-search-match-base.ts +++ b/js/packages/web/src/components/canary-search-match-base.ts @@ -6,6 +6,17 @@ import { MODAL_CLOSE_EVENT } from "./canary-modal"; const NAME = "canary-search-match-base"; +/** + * @csspart container - Container of the match + * + * @slot content-before - Content before the match + * @slot url - URL of the match + * @slot title-icon - Icon for the title + * @slot title - Title of the match + * @slot title-badge - Badge displayed next to the title + * @slot excerpt - Excerpt of the match + * @slot sub-results - Sub-results related to the match + */ @customElement(NAME) export class CanarySearchMatchBase extends LitElement { @property({ type: String })