diff --git a/examples/minimal-ts-vite/examples/web-components/index.html b/examples/minimal-ts-vite/examples/web-components/index.html index e8ad1e28..7bd65916 100644 --- a/examples/minimal-ts-vite/examples/web-components/index.html +++ b/examples/minimal-ts-vite/examples/web-components/index.html @@ -14,13 +14,16 @@ interactive style="float: right; position: relative; top: 40px; left: -10px" > - + - + test image diff --git a/examples/react-ts-vite/src/App.tsx b/examples/react-ts-vite/src/App.tsx index f2f7847c..51b922bd 100644 --- a/examples/react-ts-vite/src/App.tsx +++ b/examples/react-ts-vite/src/App.tsx @@ -116,11 +116,14 @@ function WebComponents({ return (
- + test image {manifestStore ? (
- + `, + icon: html``, }, { pattern: /adobe\sstock/i, - icon: html``, + icon: html``, }, { pattern: /adobe/i, - icon: html``, + icon: html``, }, { pattern: /behance\.net/i, - icon: html``, + icon: html``, }, { pattern: /facebook\.com/i, - icon: html``, + icon: html``, }, { pattern: /instagram\.com/i, - icon: html``, + icon: html``, }, { pattern: /truepic/i, - icon: html``, + icon: html``, }, { pattern: /twitter\.com/i, - icon: html``, + icon: html``, }, { pattern: /lightroom/i, - icon: html``, + icon: html``, }, { pattern: /solana/i, - icon: html``, }, { pattern: /ethereum/i, - icon: html``, + icon: html``, }, { pattern: /linkedin/i, - icon: html``, + icon: html``, }, ]; diff --git a/packages/c2pa-wc/src/components/Indicator/Indicator.ts b/packages/c2pa-wc/src/components/Indicator/Indicator.ts index 5ecc417b..9c650182 100644 --- a/packages/c2pa-wc/src/components/Indicator/Indicator.ts +++ b/packages/c2pa-wc/src/components/Indicator/Indicator.ts @@ -42,11 +42,17 @@ export class Indicator extends LitElement { display: inline-block; width: var(--cai-indicator-size, 24px); height: var(--cai-indicator-size, 24px); + border-radius: 50% 50% 0 50%; + line-height: 0; } .icon { --cai-icon-width: var(--cai-indicator-size, 24px); --cai-icon-height: var(--cai-indicator-size, 24px); } + :host:focus-visible { + outline-color: var(--cai-focus-ring-color, #1473e6); + outline-offset: 1px; + } `, ]; } diff --git a/packages/c2pa-wc/src/components/ManifestSummary/ManifestSummary.ts b/packages/c2pa-wc/src/components/ManifestSummary/ManifestSummary.ts index 9628d3a3..66f0d049 100644 --- a/packages/c2pa-wc/src/components/ManifestSummary/ManifestSummary.ts +++ b/packages/c2pa-wc/src/components/ManifestSummary/ManifestSummary.ts @@ -128,7 +128,6 @@ export class ManifestSummary extends Configurable( #view-more { display: block; transition: all 150ms ease-in-out; - background-color: transparent; border-radius: 9999px; border: 2px solid var(--cai-button-color); padding: 8px 0; @@ -137,6 +136,8 @@ export class ManifestSummary extends Configurable( text-decoration: none; width: 100%; color: var(--cai-primary-color); + outline-offset: 3px; + outline-color: var(--cai-focus-ring-color, #1473e6); background-color: var(--cai-button-color); } diff --git a/packages/c2pa-wc/src/components/MinimumViableProvenance/MinimumViableProvenance.ts b/packages/c2pa-wc/src/components/MinimumViableProvenance/MinimumViableProvenance.ts index 864d16d5..fbd06e87 100644 --- a/packages/c2pa-wc/src/components/MinimumViableProvenance/MinimumViableProvenance.ts +++ b/packages/c2pa-wc/src/components/MinimumViableProvenance/MinimumViableProvenance.ts @@ -100,7 +100,7 @@ export class MinimumViableProvenance extends Configurable( return html`
-
+
${this.strings['minimum-viable-provenance.header']}
diff --git a/packages/c2pa-wc/src/components/PanelSection/PanelSection.ts b/packages/c2pa-wc/src/components/PanelSection/PanelSection.ts index 4ee6e261..525cdcde 100644 --- a/packages/c2pa-wc/src/components/PanelSection/PanelSection.ts +++ b/packages/c2pa-wc/src/components/PanelSection/PanelSection.ts @@ -33,6 +33,9 @@ export class PanelSection extends LitElement { @property({ type: String }) helpText: string | null = null; + @property({ type: String }) + headingLevel: '1' | '2' | '3' | '4' | '5' | '6' = '3'; + static get styles() { return [ defaultStyles, diff --git a/packages/c2pa-wc/src/components/Popover/Popover.ts b/packages/c2pa-wc/src/components/Popover/Popover.ts index 3bb71011..7aadb14a 100644 --- a/packages/c2pa-wc/src/components/Popover/Popover.ts +++ b/packages/c2pa-wc/src/components/Popover/Popover.ts @@ -84,7 +84,7 @@ export class Popover extends LitElement { interactive = false; @property({ type: String }) - trigger: string = 'mouseenter:mouseleave focus:blur'; + trigger: string = 'mouseenter:mouseleave click'; @property({ type: Number }) zIndex = 10; @@ -101,6 +101,18 @@ export class Popover extends LitElement { @query('#trigger') triggerElement: HTMLElement | undefined; + private _triggerElementSlot: HTMLSlotElement | undefined; + + private _triggerSlotAssignedNodes: Node[] = []; + + private _triggerElementButton: HTMLElement | undefined; + + private _contentElementSlot: HTMLSlotElement | undefined; + + private _contentSlotAssignedNodes: Node[] = []; + + private _hasTooltipRole = false; + // @TODO: respect updated properties protected updated( _changedProperties: PropertyValueMap | Map, @@ -196,10 +208,59 @@ export class Popover extends LitElement { private _showTooltip() { this._isShown = true; this._updatePosition(); + this.hostElement!.ownerDocument!.addEventListener( + 'keydown', + this._onKeyDownEsc.bind(this), + ); + if (!this._hasTooltipRole) { + this._triggerElementButton?.setAttribute('aria-expanded', 'true'); + } } private _hideTooltip() { this._isShown = false; + this.hostElement!.ownerDocument!.removeEventListener( + 'keydown', + this._onKeyDownEsc.bind(this), + ); + if (!this._hasTooltipRole) { + this._triggerElementButton?.setAttribute('aria-expanded', 'false'); + } + } + + private _toogleTooltip() { + if (!this._isShown) { + this._showTooltip(); + } else { + this._hideTooltip(); + } + } + + private _onKeyDownEsc(e: KeyboardEvent) { + switch (e.key) { + case 'Escape': + if (this._isShown) { + e.stopPropagation(); + e.preventDefault(); + const restoreFocus = this.contains(document.activeElement); + this._hideTooltip(); + if (restoreFocus) { + this._triggerElementButton!.focus(); + } + } + break; + } + } + + private _onKeyDownTrigger(e: KeyboardEvent) { + switch (e.key) { + case 'Enter': + case ' ': + e.stopPropagation(); + e.preventDefault(); + (e.target as HTMLElement).click(); + break; + } } private _cleanupTriggers() { @@ -212,27 +273,51 @@ export class Popover extends LitElement { private _setTriggers() { this._cleanupTriggers(); const triggers = this.trigger.split(/\s+/); + const toggleTooltipFn = this._toogleTooltip.bind(this); + const showTooltipFn = this._showTooltip.bind(this); + const hideTooltipFn = this._hideTooltip.bind(this); + const keydownTriggerFn = this._onKeyDownTrigger.bind(this); this._eventCleanupFns = triggers.map((trigger) => { const [show, hide] = trigger.split(':'); - this.triggerElement!.addEventListener(show, this._showTooltip.bind(this)); - if (this.interactive && hide === 'mouseleave') { - this.hostElement!.addEventListener(hide, this._hideTooltip.bind(this)); + if (show === 'click') { + this.triggerElement!.addEventListener(show, toggleTooltipFn); + this.triggerElement!.addEventListener('keydown', keydownTriggerFn); } else { this.triggerElement!.addEventListener( - hide, - this._hideTooltip.bind(this), + show, + showTooltipFn, + show === 'focus', ); - } - return () => { - this.triggerElement!.removeEventListener(show, this._showTooltip); if (this.interactive && hide === 'mouseleave') { - this.contentElement!.addEventListener( + this.hostElement!.addEventListener(hide, hideTooltipFn); + } else { + this.triggerElement!.addEventListener( hide, - this._hideTooltip.bind(this), + hideTooltipFn, + hide === 'blur', ); + } + } + return () => { + if (show === 'click') { + this.triggerElement!.removeEventListener(show, toggleTooltipFn); + this.triggerElement!.removeEventListener('keydown', keydownTriggerFn); } else { - this.triggerElement!.removeEventListener(hide, this._hideTooltip); + this.triggerElement!.removeEventListener( + show, + showTooltipFn, + show === 'focus', + ); + if (this.interactive && hide === 'mouseleave') { + this.contentElement!.addEventListener(hide, hideTooltipFn); + } else { + this.triggerElement!.removeEventListener( + hide, + hideTooltipFn, + hide === 'blur', + ); + } } }; }); @@ -315,6 +400,29 @@ export class Popover extends LitElement { ); this.contentElement?.classList.add('hidden'); + + this._contentElementSlot = this.contentElement?.querySelector( + 'slot[name="content"]', + ) as HTMLSlotElement; + this._contentSlotAssignedNodes = + this._contentElementSlot?.assignedElements({ flatten: true }) ?? []; + this._hasTooltipRole = this._contentSlotAssignedNodes.some( + (node) => + node instanceof HTMLElement && node.getAttribute('role') === 'tooltip', + ); + + this._triggerElementSlot = this.triggerElement?.querySelector( + 'slot[name="trigger"]', + ) as HTMLSlotElement; + this._triggerSlotAssignedNodes = + this._triggerElementSlot?.assignedElements({ flatten: true }) ?? []; + this._triggerElementButton = this + ._triggerSlotAssignedNodes[0] as HTMLElement; + this._triggerElementButton.setAttribute('role', 'button'); + this._triggerElementButton.setAttribute('tabindex', '0'); + if (!this._hasTooltipRole) { + this._triggerElementButton.setAttribute('aria-expanded', 'false'); + } } disconnectedCallback(): void { @@ -333,6 +441,10 @@ export class Popover extends LitElement { }; return html`
+
+
+ +
${this.arrow ? html`
` : null}
-
-
- -
`; } } diff --git a/packages/c2pa-wc/src/components/SocialMedia/SocialMedia.ts b/packages/c2pa-wc/src/components/SocialMedia/SocialMedia.ts index da6f6620..050a84e6 100644 --- a/packages/c2pa-wc/src/components/SocialMedia/SocialMedia.ts +++ b/packages/c2pa-wc/src/components/SocialMedia/SocialMedia.ts @@ -10,6 +10,8 @@ import { L2SocialAccount } from 'c2pa'; import { css, html, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; +import { Configurable } from '../../mixins/configurable'; +import { ifDefined } from 'lit/directives/if-defined.js'; import { baseSectionStyles, defaultStyles } from '../../styles'; import { Localizable } from '../../mixins/localizable'; @@ -43,7 +45,6 @@ export class SocialMedia extends Localizable(LitElement) { list-style: none; padding: 0px 0px 0px 2px; margin: 0; - overflow: hidden; } .section-social-media-list-item { @@ -71,13 +72,13 @@ export class SocialMedia extends Localizable(LitElement) { helpText=${this.strings['social-media.helpText']} >
${this.strings['social-media.header']}
-