From b1c7cd33e1e82d5ae9926a5fb8d9fcfd79a6ecc3 Mon Sep 17 00:00:00 2001 From: Martin Oppitz Date: Tue, 21 Mar 2023 08:15:06 +0100 Subject: [PATCH 1/2] feat: add a new quote component --- .../src/components/component-list.ts | 2 + .../src/components/quote/component.tsx | 98 +++++++++++++++++++ .../components/src/components/quote/readme.md | 13 +++ .../components/src/components/quote/style.css | 16 +++ .../src/components/quote/test/html.mock.ts | 46 +++++++++ .../components/quote/test/snapshot.spec.tsx | 25 +++++ .../components/src/components/quote/types.ts | 28 ++++++ packages/components/src/index.bak.html | 50 ++++++++++ packages/components/src/index.html | 50 ++++++++++ packages/components/stencil.config.ts | 1 + 10 files changed, 329 insertions(+) create mode 100644 packages/components/src/components/quote/component.tsx create mode 100644 packages/components/src/components/quote/readme.md create mode 100644 packages/components/src/components/quote/style.css create mode 100644 packages/components/src/components/quote/test/html.mock.ts create mode 100644 packages/components/src/components/quote/test/snapshot.spec.tsx create mode 100644 packages/components/src/components/quote/types.ts diff --git a/packages/components/src/components/component-list.ts b/packages/components/src/components/component-list.ts index d5f53a6758..38b32e16ef 100644 --- a/packages/components/src/components/component-list.ts +++ b/packages/components/src/components/component-list.ts @@ -41,6 +41,7 @@ import { KolModal } from './modal/component'; import { KolNav } from './nav/component'; import { KolPagination } from './pagination/component'; import { KolProcess } from './progress/component'; +import { KolQuote } from './quote/component'; import { KolSelect } from './select/component'; import { KolSkipNav } from './skip-nav/component'; import { KolSpanWc } from './span/component'; @@ -98,6 +99,7 @@ export const COMPONENTS = [ KolNav, KolPagination, KolProcess, + KolQuote, KolSelect, KolSkipNav, KolSpan, diff --git a/packages/components/src/components/quote/component.tsx b/packages/components/src/components/quote/component.tsx new file mode 100644 index 0000000000..63e3f66934 --- /dev/null +++ b/packages/components/src/components/quote/component.tsx @@ -0,0 +1,98 @@ +import { h, Component, Host, JSX, Prop, State, Watch } from '@stencil/core'; +import { watchString, watchValidator } from '../../utils/prop.validators'; +import { ComponentApi, KoliBriQuoteVariant, States } from './types'; + +@Component({ + tag: 'kol-quote', + styleUrls: { + default: './style.css', + }, + shadow: true, +}) +export class KolQuote implements ComponentApi { + /** + * The caption of the quote. + */ + @Prop() public _caption?: string; + + /** + * The cite of the quote. + */ + @Prop() public _cite!: string; + + /** + * The quote of the quote. + */ + @Prop() public _quote!: string; + + /** + * The variant of the quote. + */ + @Prop() public _variant?: KoliBriQuoteVariant = 'inline'; + + @State() public state: States = { + _cite: '…', // ⚠ required + _quote: '…', // ⚠ required + _variant: 'inline', + }; + + @Watch('_caption') + public validateCaption(value?: string): void { + watchString(this, '_caption', value); + } + + @Watch('_cite') + public validateCite(value?: string): void { + watchString(this, '_cite', value); + } + + @Watch('_quote') + public validateQuote(value?: string): void { + watchString(this, '_quote', value); + } + + @Watch('_variant') + public validateVariant(value?: KoliBriQuoteVariant): void { + watchValidator(this, '_variant', (value) => value === 'block' || value === 'inline', new Set(['block', 'inline']), value); + } + + public componentWillLoad(): void { + this.validateCaption(this._caption); + this.validateCite(this._cite); + this.validateQuote(this._quote); + this.validateVariant(this._variant); + } + + public render(): JSX.Element { + const hideExpertSlot = this.state._quote !== ''; + return ( + +
+ {this.state._variant === 'block' ? ( +
+ {this.state._quote} + +
+ ) : ( + + {this.state._quote} + + + )} + {typeof this.state._caption === 'string' && this.state._caption.length > 0 && ( +
+ {` — `} + + + +
+ )} +
+
+ ); + } +} diff --git a/packages/components/src/components/quote/readme.md b/packages/components/src/components/quote/readme.md new file mode 100644 index 0000000000..d25ae2b545 --- /dev/null +++ b/packages/components/src/components/quote/readme.md @@ -0,0 +1,13 @@ +# Quote + +The quote component is implements in two variants. The first variant is the default `short` variant as inline quote with quotation marks. The second variant is the indented `long` variant. The indented variant is used to highlight a text passage or information visually. + +Both variants can be extended with a `cite` element. The `cite` element is used to identify the source of a quotation and will be displayed below the quote as link. + +## References + +- https://developer.mozilla.org/en-US/docs/Web/HTML/Element/quote +- https://developer.mozilla.org/en-US/docs/Web/HTML/Element/cite +- https://www.mediaevent.de/html/quote.html +- https://www.mediaevent.de/html/cite.html +- https://accessibleweb.com/question-answer/what-is-a-block-quote-and-when-should-i-use-it/ diff --git a/packages/components/src/components/quote/style.css b/packages/components/src/components/quote/style.css new file mode 100644 index 0000000000..4cd21a2719 --- /dev/null +++ b/packages/components/src/components/quote/style.css @@ -0,0 +1,16 @@ +@import '../style.css'; + +cite, +figure, +q + figcaption { + display: inline; + margin: 0; + padding: 0; +} + +quote::before { + content: '» '; +} +quote::after { + content: ' «'; +} diff --git a/packages/components/src/components/quote/test/html.mock.ts b/packages/components/src/components/quote/test/html.mock.ts new file mode 100644 index 0000000000..034938d316 --- /dev/null +++ b/packages/components/src/components/quote/test/html.mock.ts @@ -0,0 +1,46 @@ +import { mixMembers } from 'stencil-awesome-test'; +import { getLinkHtml } from '../../link/test/html.mock'; +import { Props, States } from '../types'; + +type Slot = { + expert?: string; +}; + +export const getQuoteHtml = (props: Props, slots: Slot = {}): string => { + const state = mixMembers( + { + _cite: '…', // ⚠ required + _quote: '…', // ⚠ required + _variant: 'inline', + }, + props + ); + const showExpertSlot = state._quote === ''; + return ` + +
+ <${state._variant === 'block' ? 'blockquote' : 'q'} cite="${state._cite}"> + ${state._quote} +
+
+
`; +}; diff --git a/packages/components/src/components/quote/test/snapshot.spec.tsx b/packages/components/src/components/quote/test/snapshot.spec.tsx new file mode 100644 index 0000000000..976667c750 --- /dev/null +++ b/packages/components/src/components/quote/test/snapshot.spec.tsx @@ -0,0 +1,25 @@ +import { h } from '@stencil/core'; +import { newSpecPage, SpecPage } from '@stencil/core/testing'; + +import { COMPONENTS } from '../../component-list'; +import { executeTests } from 'stencil-awesome-test'; +import { Props } from '../types'; +import { getQuoteHtml } from './html.mock'; + +executeTests( + 'Quote', + async (props): Promise => { + const page = await newSpecPage({ + components: COMPONENTS, + template: () => , + }); + return page; + }, + { + _caption: ['Caption'], + _cite: ['https://www.example.com'], + _quote: ['Text of the Quote'], + _variant: ['block', 'inline'], + }, + getQuoteHtml +); diff --git a/packages/components/src/components/quote/types.ts b/packages/components/src/components/quote/types.ts new file mode 100644 index 0000000000..7beb6b95f8 --- /dev/null +++ b/packages/components/src/components/quote/types.ts @@ -0,0 +1,28 @@ +import { Generic } from '@a11y-ui/core'; + +export type KoliBriQuoteVariant = 'block' | 'inline'; + +/** + * API for the Quote component. + */ +type RequiredProps = { + cite: string; + quote: string; +}; +type OptionalProps = { + caption: string; + variant: KoliBriQuoteVariant; +}; +export type Props = Generic.Element.Members; + +type RequiredStates = { + cite: string; + quote: string; + variant: KoliBriQuoteVariant; +}; +type OptionalStates = { + caption: string; +}; +export type States = Generic.Element.Members; + +export type ComponentApi = Generic.Element.ComponentApi; diff --git a/packages/components/src/index.bak.html b/packages/components/src/index.bak.html index 34ac0a0201..c216eede0b 100644 --- a/packages/components/src/index.bak.html +++ b/packages/components/src/index.bak.html @@ -1448,6 +1448,56 @@ +
  • +
    +
    + Blockquote & Quote +
    +
    +
    + Long bockquote + + + + Avian carriers can provide high delay, low throughput, and low altitude service. The connection topology is limited to a single + point-to-point path for each carrier, used with standard carriers, but many carriers can be used without significant interference with each + other, outside early spring. This is because of the 3D ether space available to the carriers, in contrast to the 1D ether used by IEEE802.3. + The carriers have an intrinsic collision avoidance system, which increases availability. + + +
    +
    + Short quote +

    + According to Mozilla's website, + +

    +

    + According to Mozilla's website, + + Firefox 1.0 was released in 2004 and became a big success. + +

    +
    +
    +
    +
  • diff --git a/packages/components/src/index.html b/packages/components/src/index.html index 34ac0a0201..c216eede0b 100644 --- a/packages/components/src/index.html +++ b/packages/components/src/index.html @@ -1448,6 +1448,56 @@
  • +
  • +
    +
    + Blockquote & Quote +
    +
    +
    + Long bockquote + + + + Avian carriers can provide high delay, low throughput, and low altitude service. The connection topology is limited to a single + point-to-point path for each carrier, used with standard carriers, but many carriers can be used without significant interference with each + other, outside early spring. This is because of the 3D ether space available to the carriers, in contrast to the 1D ether used by IEEE802.3. + The carriers have an intrinsic collision avoidance system, which increases availability. + + +
    +
    + Short quote +

    + According to Mozilla's website, + +

    +

    + According to Mozilla's website, + + Firefox 1.0 was released in 2004 and became a big success. + +

    +
    +
    +
    +
  • diff --git a/packages/components/stencil.config.ts b/packages/components/stencil.config.ts index 23aafd94a4..c532c1e995 100644 --- a/packages/components/stencil.config.ts +++ b/packages/components/stencil.config.ts @@ -45,6 +45,7 @@ const TAGS = [ 'kol-nav', 'kol-pagination', 'kol-progress', + 'kol-quote', 'kol-select', 'kol-skip-nav', 'kol-span', From b5054078934010301910df6d8e0609b758a825b9 Mon Sep 17 00:00:00 2001 From: Martin Oppitz Date: Tue, 21 Mar 2023 10:04:33 +0100 Subject: [PATCH 2/2] refactor: quote --- .../src/components/quote/component.tsx | 29 ++++++++++--------- .../components/src/components/quote/readme.md | 4 +-- .../components/src/components/quote/style.css | 16 ++++++++-- .../src/components/quote/test/html.mock.ts | 8 ++--- .../components/quote/test/snapshot.spec.tsx | 2 +- .../components/src/components/quote/types.ts | 4 +-- 6 files changed, 39 insertions(+), 24 deletions(-) diff --git a/packages/components/src/components/quote/component.tsx b/packages/components/src/components/quote/component.tsx index 63e3f66934..572b5fe27a 100644 --- a/packages/components/src/components/quote/component.tsx +++ b/packages/components/src/components/quote/component.tsx @@ -16,12 +16,12 @@ export class KolQuote implements ComponentApi { @Prop() public _caption?: string; /** - * The cite of the quote. + * The href is a URL that designates a source document or message for the information quoted. */ - @Prop() public _cite!: string; + @Prop() public _href!: string; /** - * The quote of the quote. + * The text of the quote. */ @Prop() public _quote!: string; @@ -31,7 +31,7 @@ export class KolQuote implements ComponentApi { @Prop() public _variant?: KoliBriQuoteVariant = 'inline'; @State() public state: States = { - _cite: '…', // ⚠ required + _href: '…', // ⚠ required _quote: '…', // ⚠ required _variant: 'inline', }; @@ -41,9 +41,9 @@ export class KolQuote implements ComponentApi { watchString(this, '_caption', value); } - @Watch('_cite') - public validateCite(value?: string): void { - watchString(this, '_cite', value); + @Watch('_href') + public validateHref(value?: string): void { + watchString(this, '_href', value); } @Watch('_quote') @@ -58,7 +58,7 @@ export class KolQuote implements ComponentApi { public componentWillLoad(): void { this.validateCaption(this._caption); - this.validateCite(this._cite); + this.validateHref(this._href); this.validateQuote(this._quote); this.validateVariant(this._variant); } @@ -67,16 +67,20 @@ export class KolQuote implements ComponentApi { const hideExpertSlot = this.state._quote !== ''; return ( -
    +
    {this.state._variant === 'block' ? ( -
    +
    {this.state._quote}
    ) : ( - + {this.state._quote}