Skip to content

Commit

Permalink
feat(callout): refactor, improve accessibility (#1175)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arturo Castillo Delgado authored and nowseemee committed Oct 27, 2022
1 parent 806a94a commit 23f4b8a
Show file tree
Hide file tree
Showing 9 changed files with 393 additions and 327 deletions.
118 changes: 47 additions & 71 deletions packages/components/src/components/callout/callout.css
Original file line number Diff line number Diff line change
@@ -1,95 +1,71 @@
:host {
--inner-width-small: var(--telekom-spacing-unit-x20);
--inner-height-small: var(--telekom-spacing-unit-x20);
--inner-width-large: 126.5px;
--inner-height-large: 96px;
--width-small: 120px;
--height-small: 120px;
--height-large: 160px;
--width-large: 160px;
/* FIXME variables shouldn't have color names */
--color-blue: var(--telekom-color-functional-informational-standard);
/* FIXME variables are used sometimes as background and sometimes as font color */
--color-white: var(--telekom-color-background-surface);
--color-black: var(--telekom-color-text-and-icon-functional-black);
--color-primary: var(--telekom-color-primary-standard);
--font-family: var(--telekom-typography-font-family-sans);
/* FIXME is this calc necessary? */
--font-size: calc(var(--telekom-typography-font-size-callout) * 3);
--font-size-prefix: var(--telekom-typography-font-size-callout);
}
--position: absolute;
--background: var(--telekom-color-ui-extra-strong);
--color: var(--telekom-color-text-and-icon-inverted-standard);
--spacing: var(--telekom-spacing-unit-x6);
--min-width: 6rem;
--aspect-ratio: 1;
--rotation: 0deg;
--font-standard: var(--telekom-text-style-lead-text);
--font-small: var(--telekom-text-style-body-bold);
--font-large: var(--telekom-text-style-heading-1);

.callout {
display: flex;
justify-content: center;
box-sizing: border-box;
display: inline-flex;
align-items: center;
border-radius: 100%;
background: var(--color-primary);
font-family: var(--font-family);
color: var(--color-white);
justify-content: center;
text-align: center;
border-radius: 50%;
position: var(--position);
background: var(--background);
color: var(--color);
min-width: var(--min-width);
aspect-ratio: var(--aspect-ratio);
transform: rotateZ(var(--rotation, 0deg));
}

.callout.callout--color-primary {
background: var(--color-primary);
}
.callout.callout--color-white {
background: var(--color-white);
color: var(--color-black);
}
.callout.callout--color-blue {
background: var(--color-blue);
color: var(--telekom-color-text-and-icon-white-standard);
}
.callout.callout--color-black {
background: var(--telekom-color-ui-extra-strong);
color: var(--telekom-color-text-and-icon-inverted-standard);
[part='base'] {
box-sizing: border-box;
padding: var(--spacing);
font: var(--font-standard);
font-weight: var(--telekom-typography-font-weight-bold);
line-height: var(--telekom-typography-line-spacing-tight);
}

.callout.callout--size-large {
width: var(--width-large);
height: var(--height-large);
}
/* Color variants */

.callout.callout--size-small {
width: var(--width-small);
height: var(--height-small);
:host([variant='primary']) {
--background: var(--telekom-color-primary-standard);
--color: var(--telekom-color-text-and-icon-white-standard);
}

.callout.callout--size-large .callout__inner {
width: var(--inner-width-large);
height: var(--inner-height-large);
:host([variant='black']) {
--background: var(--telekom-color-ui-black, #000000);
--color: var(--telekom-color-text-and-icon-white-standard);
}

.callout.callout--size-small .callout__inner {
width: var(--inner-width-small);
height: var(--inner-height-small);
:host([variant='white']) {
--background: var(--telekom-color-ui-white, #ffffff);
--color: var(--telekom-color-text-and-icon-black-standard);
}

.callout__inner {
transform: rotateZ(var(--rotation));
overflow: hidden;
:host([variant='blue']) {
--background: var(--telekom-color-additional-cyan-400);
--color: var(--telekom-color-text-and-icon-black-standard);
}

.callout__prefix {
font-size: var(--font-size-prefix);
font-weight: 400;
}
/* Enforce "line break" for every direct child of scale-callout */

.callout__text {
font-size: var(--font-size);
font-weight: 700;
::slotted(*) {
display: block;
}

.callout__sup {
font-size: 30px;
cursor: help;
}
/* Font style options (medium is default) */

.callout.callout--size-large.callout--asterisk .callout__prefix {
margin-bottom: 10px;
::slotted(.scl-callout-text-small) {
font: var(--font-small);
}

.callout.callout--size-small .callout__prefix {
margin-bottom: 10px;
::slotted(.scl-callout-text-large) {
font: var(--font-large);
}
32 changes: 0 additions & 32 deletions packages/components/src/components/callout/callout.spec.ts

This file was deleted.

135 changes: 85 additions & 50 deletions packages/components/src/components/callout/callout.tsx
Original file line number Diff line number Diff line change
@@ -1,75 +1,110 @@
import { Component, h, Host, Prop, Element } from '@stencil/core';
import classNames from 'classnames';
import { Component, h, Host, Prop, Element, Watch } from '@stencil/core';
import statusNote from '../../utils/status-note';

/**
* Adds the `px` suffix to a string number
* but leaves other units untouched.
* 1 -> 1px
* 5% -> 5%
*/
const numToPx = (val: string) => (Number.isNaN(Number(val)) ? val : val + 'px');

@Component({
tag: 'scale-callout',
styleUrl: 'callout.css',
shadow: true,
})
export class Callout {
@Element() hostElement: HTMLElement;
/** (optional) Variant size of the callout itself */
@Prop({ mutable: true }) size: 'large' | 'small' = 'large';
/** (optional) Variant filling of the callout */
@Prop({ mutable: true }) variant: 'primary' | 'white' | 'black' | 'blue';
/** (optional) Variant rotation of the callout/circle */
@Prop({ mutable: true }) rotation: number = 0;
/** (optional) text when hovering with asterisk */
@Prop({ mutable: true }) asterisk: string;

baseEl: HTMLElement;
mo: MutationObserver;

/** (optional) Color variant of the callout */
@Prop() variant?: 'primary' | 'blue' | 'white' | 'black' | string;
/** (optional) Degree of rotation */
@Prop() rotation?: number = 0;
/** (optional) CSS `top` value for absolute position */
@Prop() top?: string;
/** (optional) CSS `right` value for absolute position */
@Prop() right?: string;
/** (optional) CSS `bottom` value for absolute position */
@Prop() bottom?: string;
/** (optional) CSS `left` value for absolute position */
@Prop() left?: string;
/** (optional) Injected CSS styles */
@Prop() styles?: string;

connectedCallback() {
statusNote({ source: this.hostElement, tag: 'beta' });
this.syncPropsToCSS();
}

displayStyle() {
return `:host {
--rotation: ${this.rotation}deg;
}`;
componentDidLoad() {
const observer = new MutationObserver(() => {
this.adjustSize();
});
observer.observe(this.hostElement, {
attributes: false,
childList: true,
subtree: true,
characterData: true,
});
this.mo = observer;
// Wait for full styles before measuring
window.requestAnimationFrame(this.adjustSize);
}

render() {
return (
<Host>
<style>{this.displayStyle()}</style>
<div part={this.getBasePartMap()} class={this.getCssClassMap()}>
<div part="inner" class="callout__inner">
<div class="callout__prefix">
<slot name="prefix" />
</div>
<div class="callout__text">
<span>
<slot></slot>
</span>
{this.asterisk && (
<sup title={this.asterisk} class="callout__sup">
*
</sup>
)}
</div>
</div>
</div>
</Host>
);
disconnectedCallback() {
if (this.mo) {
this.mo.disconnect();
}
}

getBasePartMap() {
return this.getCssOrBasePartMap('basePart');
@Watch('rotation')
@Watch('top')
@Watch('right')
@Watch('bottom')
@Watch('left')
rotationChanged() {
this.syncPropsToCSS();
}

getCssClassMap() {
return this.getCssOrBasePartMap('css');
}
/**
* `aspect-ratio` is not enough when dealing with text :(
*/
adjustSize = () => {
const { width, height } = this.baseEl.getBoundingClientRect();
const largest = Math.max(width, height);
this.hostElement.style.setProperty('--min-width', `${largest}px`);
};

syncPropsToCSS() {
this.hostElement.style.setProperty('--rotation', `${this.rotation}deg`);

getCssOrBasePartMap(mode: 'basePart' | 'css') {
const name = 'callout';
const prefix = mode === 'basePart' ? '' : `${name}--`;
if (
this.top != null ||
this.right != null ||
this.bottom != null ||
this.left != null
) {
Object.assign(this.hostElement.style, {
top: numToPx(this.top),
right: numToPx(this.right),
bottom: numToPx(this.bottom),
left: numToPx(this.left),
});
}
}

return classNames(
name,
this.variant && `${prefix}color-${this.variant}`,
this.size && `${prefix}size-${this.size}`,
this.asterisk && `${prefix}asterisk`
render() {
return (
<Host>
{this.styles && <style>{this.styles}</style>}
<div part="base" ref={(el) => (this.baseEl = el)}>
<slot></slot>
</div>
</Host>
);
}
}
21 changes: 12 additions & 9 deletions packages/components/src/components/callout/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,22 @@

## Properties

| Property | Attribute | Description | Type | Default |
| ---------- | ---------- | ------------------------------------------------- | ------------------------------------------- | ----------- |
| `asterisk` | `asterisk` | (optional) text when hovering with asterisk | `string` | `undefined` |
| `rotation` | `rotation` | (optional) Variant rotation of the callout/circle | `number` | `0` |
| `size` | `size` | (optional) Variant size of the callout itself | `"large" \| "small"` | `'large'` |
| `variant` | `variant` | (optional) Variant filling of the callout | `"black" \| "blue" \| "primary" \| "white"` | `undefined` |
| Property | Attribute | Description | Type | Default |
| ---------- | ---------- | --------------------------------------------------- | -------- | ----------- |
| `bottom` | `bottom` | (optional) CSS `bottom` value for absolute position | `string` | `undefined` |
| `left` | `left` | (optional) CSS `left` value for absolute position | `string` | `undefined` |
| `right` | `right` | (optional) CSS `right` value for absolute position | `string` | `undefined` |
| `rotation` | `rotation` | (optional) Degree of rotation | `number` | `0` |
| `styles` | `styles` | (optional) Injected CSS styles | `string` | `undefined` |
| `top` | `top` | (optional) CSS `top` value for absolute position | `string` | `undefined` |
| `variant` | `variant` | (optional) Color variant of the callout | `string` | `undefined` |


## Shadow Parts

| Part | Description |
| --------- | ----------- |
| `"inner"` | |
| Part | Description |
| -------- | ----------- |
| `"base"` | |


----------------------------------------------
Expand Down
Loading

0 comments on commit 23f4b8a

Please sign in to comment.