Compare commits

...

17 Commits

Author SHA1 Message Date
Kelsey Jackson
e6c92ca2f7 updated link 2025-12-19 11:20:38 -06:00
Kelsey Jackson
5ed32c38de updated changelog 2025-12-19 11:05:03 -06:00
Kelsey Jackson
9d735da9af Merge branch 'next' into kj/update-sidebar 2025-12-19 11:04:01 -06:00
Kelsey Jackson
56b1196265 got it working, but may revert to use on repo (#1888) 2025-12-19 10:54:45 -06:00
Cory LaViska
7e5f18ea97 update changelog (#1889) 2025-12-18 14:25:22 -05:00
Kelsey Jackson
4c1df98053 removed planned video text in sidebar 2025-12-18 10:17:05 -06:00
Kelsey Jackson
bd029b8a36 merging 2025-12-18 10:14:52 -06:00
Kelsey Jackson
c60c62beb0 updated sidebar 2025-12-18 10:11:47 -06:00
Brian Talbot
c748721f12 adding event tracking to site search (#1872) 2025-12-17 15:22:18 -05:00
konnorrogers
6e5a720f51 update lockfiles and prettierignore 2025-12-16 13:42:13 -05:00
konnorrogers
f739121aaf updae lockfile 2025-12-16 13:30:16 -05:00
konnorrogers
5fb3625ee5 fix script 2025-12-16 13:22:32 -05:00
konnorrogers
da206a8787 update versions 2025-12-16 13:21:46 -05:00
Kelsey Jackson
fc62edc581 fixed pr 2025-10-30 08:52:43 -05:00
Kelsey Jackson
9f731325bb Update packages/webawesome/docs/_includes/sidebar.njk
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-30 08:43:54 -05:00
Kelsey Jackson
89b7a4c71b Merge branch 'next' into kj/update-sidebar 2025-10-30 08:42:12 -05:00
Kelsey Jackson
1ebfd31877 updated sidebar 2025-10-29 21:50:05 -05:00
10 changed files with 214 additions and 41 deletions

View File

@@ -20,4 +20,5 @@ packages/**/*/src/react/index.ts
node_modules
packages/**/*/_site
packages/**/*/_bundle_
packages/webawesome/docs/assets/scripts/prism-downloaded.js

View File

@@ -1 +1,2 @@
3.0.0
3.1.0

8
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@webawesome/monorepo",
"version": "3.0.0",
"version": "3.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@webawesome/monorepo",
"version": "3.0.0",
"version": "3.1.0",
"license": "MIT",
"workspaces": [
"packages/*"
@@ -14023,7 +14023,7 @@
},
"packages/webawesome": {
"name": "@awesome.me/webawesome",
"version": "3.0.0",
"version": "3.1.0",
"license": "MIT",
"dependencies": {
"@ctrl/tinycolor": "4.1.0",
@@ -14048,7 +14048,7 @@
},
"packages/webawesome-pro": {
"name": "@awesome.me/webawesome-pro",
"version": "3.0.0",
"version": "3.1.0",
"dependencies": {
"@ctrl/tinycolor": "4.1.0",
"@floating-ui/dom": "^1.6.13",

View File

@@ -2,7 +2,7 @@
"name": "@webawesome/monorepo",
"private": true,
"description": "A forward-thinking library of web components.",
"version": "3.0.0",
"version": "3.1.0",
"homepage": "https://webawesome.com/",
"author": "Web Awesome",
"license": "MIT",

View File

@@ -29,8 +29,6 @@
<li><a href="/docs/resources/contributing">Contributing</a></li>
<li><a href="/docs/resources/changelog">Changelog</a></li>
<li><a href="/docs/resources/visual-tests">Visual Tests</a></li>
</ul>
<!-- Components -->
@@ -156,13 +154,26 @@
<li><a href="/docs/components/textarea/">Textarea</a></li>
<li><span class="is-planned wa-split">Toast <span><a href="https://github.com/shoelace-style/webawesome/issues/105" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a>{{ proBadge( { description: "This will require access to Web Awesome Pro" }) }}</span></span></li>
<li><a href="/docs/components/tooltip/">Tooltip</a></li>
<li><a href="/docs/components/tree/">Tree</a></li>
<li><a href="/docs/components/tree-item/">Tree Item</a></li>
<li>
<a href="/docs/components/tree/">Tree</a>
<span class="wa-split">
<a class="wa-cluster wa-gap-xs" href="/docs/components/video/">
Video <wa-icon name="flask" aria-hidden="true" class="icon-shrink"></wa-icon>
</a>
{{ proBadge() }}
</span>
<ul>
<li><a href="/docs/components/tree-item/">Tree Item</a></li>
<li>
<span class="wa-split">
<a href="/docs/components/video-item/">
Video Item <wa-icon name="flask" aria-hidden="true" class="icon-shrink"></wa-icon>
</a>
{{ proBadge() }}
</span>
</li>
</ul>
</li>
<li><span class="is-planned wa-split">Video <span><a href="https://github.com/shoelace-style/webawesome/issues/985" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a>{{ proBadge( { description: "This will require access to Web Awesome Pro" }) }}</span></span></li>
<li><a href="/docs/components/zoomable-frame">Zoomable Frame</a></li>
{# PLOP_NEW_COMPONENT_PLACEHOLDER #}
</ul>

View File

@@ -1,12 +1,24 @@
// Search data
const version = document.documentElement.getAttribute('data-version') || '';
const res = await Promise.all([import('https://cdn.jsdelivr.net/npm/lunr/+esm'), fetch(`/search.json?v=${version}`)]);
const res = await Promise.all([
import('https://cdn.jsdelivr.net/npm/lunr/+esm'),
fetch(`/search.json?v=${version}`),
import('/assets/scripts/track.js').catch(() => null),
]);
const lunr = res[0].default;
const searchData = await res[1].json();
const searchIndex = lunr.Index.load(searchData.searchIndex);
const map = searchData.map;
const searchDebounce = 200;
const queryTrackDelay = 1000;
let searchTimeout;
let queryTrackTimeout;
let lastTrackedQuery = '';
let resultSelected = false;
// Optional event tracking - works standalone if track.js isn't available
const trackModule = res[2];
const trackEvent = trackModule?.trackEvent || window.trackEvent || (() => {});
// We're using Turbo, so references to these elements aren't guaranteed to remain intact
function getElements() {
@@ -17,6 +29,24 @@ function getElements() {
};
}
function trackQuerySubmit(query, resultSelectedValue) {
if (!query || query.length === 0) return;
const { results } = getElements();
if (!results) return;
const matches = results.querySelectorAll('li').length;
const truncatedQuery = query.length > 500 ? query.substring(0, 500) : query;
trackEvent('navigation:search_query_submit', {
query: truncatedQuery,
query_length: query.length,
result_count: matches,
has_results: matches > 0,
result_selected: resultSelectedValue,
});
}
// Show the search dialog when slash (or CMD+K) is pressed and focus is not inside a form element
document.addEventListener('keydown', event => {
if (
@@ -42,40 +72,98 @@ document.addEventListener('click', event => {
function show() {
const { dialog, input, results } = getElements();
if (!dialog || !input || !results) return;
const wasAlreadyOpen = dialog.open;
// Remove existing listeners before adding to prevent duplicates
input.removeEventListener('input', handleInput);
results.removeEventListener('click', handleSelection);
dialog.removeEventListener('keydown', handleKeyDown);
dialog.removeEventListener('wa-hide', handleClose);
resultSelected = false;
lastTrackedQuery = '';
input.addEventListener('input', handleInput);
results.addEventListener('click', handleSelection);
dialog.addEventListener('keydown', handleKeyDown);
dialog.addEventListener('wa-hide', handleClose);
dialog.open = true;
if (!wasAlreadyOpen) {
trackEvent('navigation:search_dialog_open');
}
}
function hide() {
function cleanup() {
const { dialog, input, results } = getElements();
if (!dialog || !input || !results) return;
clearTimeout(searchTimeout);
clearTimeout(queryTrackTimeout);
input.removeEventListener('input', handleInput);
results.removeEventListener('click', handleSelection);
dialog.removeEventListener('keydown', handleKeyDown);
dialog.removeEventListener('wa-hide', handleClose);
dialog.open = false;
// Reset state to prevent leakage between dialog sessions
resultSelected = false;
lastTrackedQuery = '';
}
function handleClose() {
const { input } = getElements();
async function handleClose() {
const { dialog, input } = getElements();
if (!dialog || !input) return;
clearTimeout(queryTrackTimeout);
queryTrackTimeout = null;
dialog.removeEventListener('wa-hide', handleClose);
if (!resultSelected) {
const query = input.value.trim();
if (query.length > 0 && query !== lastTrackedQuery) {
trackQuerySubmit(query, false);
lastTrackedQuery = query;
}
}
input.value = '';
updateResults();
try {
await updateResults();
} catch (error) {
// Silently handle errors - UI cleanup should continue
}
cleanup();
trackEvent('navigation:search_dialog_close');
}
function handleInput() {
const { input } = getElements();
if (!input) return;
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => updateResults(input.value), searchDebounce);
clearTimeout(queryTrackTimeout);
const query = input.value.trim();
if (query.length === 0) {
lastTrackedQuery = '';
}
searchTimeout = setTimeout(async () => {
await updateResults(query);
if (query.length > 0 && query !== lastTrackedQuery) {
queryTrackTimeout = setTimeout(() => {
const { input: currentInput, results } = getElements();
if (!currentInput || resultSelected) return;
const currentQuery = currentInput.value.trim();
if (currentQuery === query && currentQuery !== lastTrackedQuery) {
trackQuerySubmit(currentQuery, false);
lastTrackedQuery = currentQuery;
}
}, queryTrackDelay);
}
}, searchDebounce);
}
function handleKeyDown(event) {
const { input, results } = getElements();
if (!input || !results) return;
// Handle keyboard selections
if (['ArrowDown', 'ArrowUp', 'Home', 'End', 'Enter'].includes(event.key)) {
@@ -104,7 +192,12 @@ function handleKeyDown(event) {
nextEl = items[items.length - 1];
break;
case 'Enter':
currentEl?.querySelector('a')?.click();
if (currentEl) {
const link = currentEl.querySelector('a');
if (link) {
selectResult(link, 'keyboard_enter');
}
}
break;
}
@@ -121,27 +214,62 @@ function handleKeyDown(event) {
}
}
function selectResult(link, selectionMethod) {
const { input, results } = getElements();
if (!input || !link) return;
// Clear pending query tracking timeout to prevent duplicate events
clearTimeout(queryTrackTimeout);
queryTrackTimeout = null;
resultSelected = true; // Set immediately so timeout callback (if executing) sees it
const query = input.value.trim();
if (!link.dataset.searchResultIndex) return;
const resultIndex = parseInt(link.dataset.searchResultIndex, 10);
if (isNaN(resultIndex) || resultIndex < 1) return;
const resultUrl = link.dataset.searchResultUrl || link.getAttribute('href');
if (!resultUrl) return;
lastTrackedQuery = query;
trackQuerySubmit(query, true);
trackEvent('navigation:search_result_click', {
query,
result_index: resultIndex,
result_url: resultUrl,
selection_method: selectionMethod,
});
const { dialog } = getElements();
if (dialog) {
dialog.removeEventListener('wa-hide', handleClose);
cleanup();
trackEvent('navigation:search_dialog_close');
dialog.open = false;
}
if (window.Turbo) {
Turbo.visit(resultUrl);
} else {
location.href = resultUrl;
}
}
function handleSelection(event) {
const link = event.target.closest('a');
if (link) {
event.preventDefault();
hide();
if (window.Turbo) {
Turbo.visit(link.href);
} else {
location.href = link.href;
}
selectResult(link, 'mouse_click');
}
}
// Queries the search index and updates the results
async function updateResults(query = '') {
const { dialog, input, results } = getElements();
if (!dialog || !input || !results) return;
try {
const hasQuery = query.length > 0;
const trimmedQuery = query.trim();
const hasQuery = trimmedQuery.length > 0;
let matches = [];
if (hasQuery) {
@@ -149,13 +277,13 @@ async function updateResults(query = '') {
const seenRefs = new Set();
// Start with a standard search to get the best "exact match" result
searchIndex.search(`${query}`).forEach(match => {
searchIndex.search(`${trimmedQuery}`).forEach(match => {
matches.push(match);
seenRefs.add(match.ref);
});
// Add wildcard matches if not already included
searchIndex.search(`${query}*`).forEach(match => {
searchIndex.search(`${trimmedQuery}*`).forEach(match => {
if (!seenRefs.has(match.ref)) {
matches.push(match);
seenRefs.add(match.ref);
@@ -163,11 +291,10 @@ async function updateResults(query = '') {
});
// Add fuzzy search matches last
const fuzzyTokens = query
const fuzzyTokens = trimmedQuery
.split(' ')
.map(term => `${term}~1`)
.join(' ');
searchIndex.search(fuzzyTokens).forEach(match => {
if (!seenRefs.has(match.ref)) {
matches.push(match);
@@ -180,12 +307,12 @@ async function updateResults(query = '') {
dialog.classList.toggle('has-results', hasQuery && hasResults);
dialog.classList.toggle('no-results', hasQuery && !hasResults);
input.setAttribute('aria-activedescendant', '');
results.innerHTML = '';
matches.forEach((match, index) => {
const page = map[match.ref];
if (!page || !page.url) return;
const li = document.createElement('li');
const a = document.createElement('a');
const displayTitle = page.title ?? '';
@@ -197,12 +324,10 @@ async function updateResults(query = '') {
li.setAttribute('role', 'option');
li.setAttribute('id', `search-result-item-${match.ref}`);
li.setAttribute('data-selected', index === 0 ? 'true' : 'false');
if (page.url === '/') icon = 'home';
if (page.url.startsWith('/docs/utilities/native')) icon = 'code';
if (page.url.startsWith('/docs/components')) icon = 'puzzle-piece';
if (page.url.startsWith('/docs/theme') || page.url.startsWith('/docs/restyle')) icon = 'palette';
a.href = page.url;
a.innerHTML = `
<div class="site-search-result-icon" aria-hidden="true">
@@ -218,6 +343,9 @@ async function updateResults(query = '') {
a.querySelector('.site-search-result-description').textContent = displayDescription;
a.querySelector('.site-search-result-url').textContent = displayUrl;
// Use 1-based indexing for analytics
a.dataset.searchResultIndex = (index + 1).toString();
a.dataset.searchResultUrl = page.url;
li.appendChild(a);
results.appendChild(li);
});

View File

@@ -11,8 +11,13 @@ Web Awesome follows [Semantic Versioning](https://semver.org/). Breaking changes
Components with the <wa-badge variant="warning">Experimental</wa-badge> badge should not be used in production. They are made available as release candidates for development and testing purposes. As such, changes to experimental components will not be subject to semantic versioning.
## Next
- Fixed a bug in `<wa-combobox>` that prevented the listbox from opening when options were preselected [issue:1883]
## 3.1.0
- Added `<wa-video>` as an experimental pro component
- Added `<wa-combobox>` as an experimental pro component [issue:1074]
- Added version 2.0.0 of the [official Web Awesome Figma Design Kit](/docs/resources/figma)
- Added npm support for Web Awesome Pro
@@ -516,4 +521,4 @@ Many of these changes and improvements were the direct result of feedback from u
</details>
Did we miss something? [Let us know!](https://github.com/shoelace-style/webawesome/discussions)
Did we miss something? [Let us know!](https://github.com/shoelace-style/webawesome/discussions)

View File

@@ -10,8 +10,8 @@ const monorepoRoot = path.resolve(__dirname, '..', '..', '..');
const rootPackageJSONFile = path.join(monorepoRoot, 'package.json');
const webawesomePackageJSONFile = path.join(path.resolve(__dirname, '..'), 'package.json');
const rootPackageJSON = JSON.parse(fs.readFileSync(rootPackageJSONFile, { encoding: "utf8" }));
const webawesomePackageJSON = JSON.parse(fs.readFileSync(webawesomePackageJSONFile, { encoding: "utf8" }));
const rootPackageJSON = JSON.parse(fs.readFileSync(rootPackageJSONFile, { encoding: 'utf8' }));
const webawesomePackageJSON = JSON.parse(fs.readFileSync(webawesomePackageJSONFile, { encoding: 'utf8' }));
const currentVersion = webawesomePackageJSON.version;
rootPackageJSON.version = currentVersion;
@@ -19,7 +19,7 @@ rootPackageJSON.version = currentVersion;
fs.writeFileSync(rootPackageJSONFile, JSON.stringify(rootPackageJSON, null, 2));
const versionsFile = path.join(monorepoRoot, 'VERSIONS.txt');
const versions = fs.readFileSync(versionsFile, { encoding: "utf8" }).split(/\r?\n/);
const versions = fs.readFileSync(versionsFile, { encoding: 'utf8' }).split(/\r?\n/);
// TODO: Make this smart and understand semver and "insert" in the correct spot instead of appending.
if (!versions.includes(currentVersion)) {

View File

@@ -28,3 +28,4 @@ export type { WaSlideChangeEvent } from './slide-change.js';
export type { WaStartEvent } from './start.js';
export type { WaTabHideEvent } from './tab-hide.js';
export type { WaTabShowEvent } from './tab-show.js';
export type { WaVideoChangeEvent } from './video-change.js';

View File

@@ -0,0 +1,26 @@
export class WaVideoChangeEvent extends Event {
readonly detail: WaVideoChangeEventDetail;
constructor(detail: WaVideoChangeEventDetail) {
super('wa-video-change', { bubbles: true, cancelable: false, composed: true });
this.detail = detail;
}
}
export interface WaVideoChangeEventDetail {
previousIndex: number;
currentIndex: number;
video: {
title?: string;
poster?: string;
duration?: string;
sources: { src: string; type: string }[];
tracks: { src: string; kind: string; srclang: string; label: string }[];
};
}
declare global {
interface GlobalEventHandlersEventMap {
'wa-video-change': WaVideoChangeEvent;
}
}