Skip to content

Commit

Permalink
Merge pull request #76 from 8845musign/update-icon-component
Browse files Browse the repository at this point in the history
Update icon component page
  • Loading branch information
takanorip authored Jun 4, 2024
2 parents ef1686e + 100014a commit 2d32d77
Show file tree
Hide file tree
Showing 12 changed files with 185 additions and 41 deletions.
4 changes: 4 additions & 0 deletions src/components/react/CopyButton.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,7 @@
top: -1px;
font-size: 16px;
}

.block {
width: 100%;
}
10 changes: 8 additions & 2 deletions src/components/react/CopyButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ interface Props {
className?: string;
label?: string;
invert?: boolean;
block: boolean;
}

const ButtonCopy: FC<Props> = ({ text, className = '', label, invert }) => {
const ButtonCopy: FC<Props> = ({ text, className = '', label, invert, block }) => {
const [copied, setCopied] = useState(false);

const handleClick = () => {
Expand All @@ -28,7 +29,12 @@ const ButtonCopy: FC<Props> = ({ text, className = '', label, invert }) => {
<>
<button
type="button"
className={clsx([styles.button, { [`${styles.invert}`]: invert }, className])}
className={clsx(
styles.button,
invert !== undefined ? styles.invert : null,
block !== undefined ? styles.block : null,
className,
)}
onClick={handleClick}
title={label}
aria-label={label ? `コピー: ${label}` : 'コピー'}
Expand Down
54 changes: 51 additions & 3 deletions src/components/react/IconList/IconWrapper.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,59 @@
word-wrap: normal;
}

.copyOuter {
position: absolute;
top: 100%;
left: 50%;
z-index: 1;
display: none;
width: 115%;
translate: -50% 0;
}

.copyOuter.show {
display: block;
}

.copy {
position: relative;
width: 100%;
background-color: #fff;
isolation: isolate;
border: 2px solid var(--color-primary);
border-radius: var(--radius-md);
transform: 0 -100%;
}

.copy::before {
position: absolute;
top: 0;
right: 0;
opacity: 0.001;
top: -8px;
left: 50%;
display: block;
width: 12px;
height: calc(tan(60deg) * 12px / 3);
clip-path: polygon(50% 0, 100% 100%, 0 100%);
content: '';
background: var(--color-primary);
translate: -50% 0;
}

.copy::after {
position: absolute;
top: -5px;
left: 50%;
display: block;
width: 10px;
height: calc(tan(60deg) * 10px / 3 + 1px);
clip-path: polygon(50% 0, 100% 100%, 0 100%);
content: '';
background: var(--color-ubie-white);
translate: -50% 0;
}

.copyInner {
overflow: hidden;
border-radius: var(--radius-md);
}

.copy:focus,
Expand Down
84 changes: 76 additions & 8 deletions src/components/react/IconList/IconWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,100 @@
import { Text, Box } from '@ubie/ubie-ui';
import clsx from 'clsx';
import { useState, useRef, useCallback, useEffect } from 'react';
import iconNames from '@metadata/iconNames.json';
import styles from './IconWrapper.module.css';
import CopyButton from '../CopyButton';
import type { FC, JSX } from 'react';
import type { FC, JSX, FocusEvent } from 'react';

interface Props {
children: JSX.Element;
index: number;
}

const convertToIconComponentName = (iconName: string) => {
const toUbieIconsStatement = (iconName: string): string => {
return `import { ${iconName} } from '@ubie/ubie-icons'`;
};

const toUbieUIStatement = (iconName: string): string => {
return `<Icon icon="${iconName}" />`;
};

const IconWrapper: FC<Props> = ({ children, index }) => {
const name = iconNames[index];

if (!name) return null;

const humanReadableName = name.split(/(?=[A-Z])/).join(' ');

const [showCopyBubble, setShowCopyBubble] = useState(false);

const handleMouseEnter = useCallback(() => {
setShowCopyBubble(true);
}, []);
const handleMouseLeave = useCallback(() => {
setShowCopyBubble(false);
}, []);

const handleFocus = useCallback(() => {
setShowCopyBubble(true);
}, []);
const wrapperRef = useRef<HTMLDivElement>(null);
const handleBlur = (e: FocusEvent) => {
if (wrapperRef.current == null) return;

if (!wrapperRef.current.contains(e.relatedTarget as Node)) {
setShowCopyBubble(false);
}
};

const handleKeyDownEsc = useCallback((e: KeyboardEvent) => {
if (e.key === 'Escape') {
setShowCopyBubble(false);
}
}, []);
useEffect(() => {
window.addEventListener('keydown', handleKeyDownEsc);

return () => {
window.removeEventListener('keydown', handleKeyDownEsc);
};
}, []);

return (
<div className={styles.wrapper}>
<div className={styles.icon} aria-label={`アイコン ${humanReadableName}`} role="img">
{children}
<>
{/* eslint-disable jsx-a11y/no-noninteractive-tabindex */}
<div
className={styles.wrapper}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
onFocus={handleFocus}
onBlur={handleBlur}
tabIndex={0}
ref={wrapperRef}
>
{/* eslint-enable */}
<div className={styles.wrapperInner}>
<div className={styles.icon} aria-label={`アイコン ${humanReadableName}`} role="img">
{children}
</div>
<p className={styles.name}>{humanReadableName}</p>
</div>

<div className={clsx(styles.copyOuter, showCopyBubble && styles.show)}>
<div className={styles.copy}>
<div className={styles.copyInner}>
<Box pt="xxs" pb="xxs">
<Text type="note" size="lg" color="main" bold textAlign="center">
copy
</Text>
</Box>
<CopyButton label="Ubie UI" text={toUbieUIStatement(name)} block />
<CopyButton label="Ubie Icons" text={toUbieIconsStatement(name)} block />
</div>
</div>
</div>
</div>
<p className={styles.name}>{humanReadableName}</p>
<CopyButton label="React" text={convertToIconComponentName(name)} className={styles.copy} />
</div>
</>
);
};

Expand Down
4 changes: 2 additions & 2 deletions src/components/react/examples/icon/DefaultExample.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { UbieIcon } from '@ubie/ubie-icons';
import { Icon } from '@ubie/ubie-ui';
import type { FC } from 'react';

const DefaultExample: FC = () => <UbieIcon />;
const DefaultExample: FC = () => <Icon icon="UbieIcon" />;

export default DefaultExample;
6 changes: 6 additions & 0 deletions src/components/react/examples/icon/StylingExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Icon } from '@ubie/ubie-ui';
import type { FC } from 'react';

export const StylingExample: FC = () => {
return <Icon color="alert" icon="AlertIcon" size="2xl" />;
};
2 changes: 1 addition & 1 deletion src/pages/components/checkbox.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ repositoryUrl: 'https://github.com/ubie-oss/ubie-ui/tree/main/src/components/Che
<CheckboxGroup label="候補日">
<Checkbox>3/10</Checkbox>
<Checkbox>3/11</Checkbox>
</fieldset>
</CheckboxGroup>
```

`role=group``aria-labelledby` でも対応可能です。
Expand Down
8 changes: 8 additions & 0 deletions src/pages/components/examples/icon/styling.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
import { StylingExample } from '@components/react/examples/icon/StylingExample';
import ExampleLayout from '@layouts/ExampleLayout.astro';
---

<ExampleLayout title="Styling Example | Icon">
<StylingExample client:only="react" />
</ExampleLayout>
48 changes: 26 additions & 22 deletions src/pages/components/icons.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,47 @@ description: '視覚的な「手がかり」を提供'
thumbnail: '/assets/images/components/thumbnail-icon.svg'
---

## Feature

- ユーザーの注目を引き、形から連想される意味によってユーザーの理解を助けることができます
- `@ubie-oss/ubie-icons`に存在するアイコンを使用できます
- `@ubie-oss/ubie-icons`を単独で使う場合と比べスタイリングが容易です

## Usage

アイコンのバリエーションは[Elements/Icons](/elements/icons)を参照してください。

CSS でスタイリングをすることができます:
### スタイリング

- `font-size` で大きさを変更
- `color` で色を変更
propを通して可能です。

## Accessibility
```jsx
<Icon icon="AlertIcon" color="alert" />
<Icon icon="UbieIcon" size="2xl" />
```

### テキスト情報を付与する
色を指定しない場合は、親要素の`color`の影響を受けます。
次の場合は、アイコンは`primary`カラーとなります。

`<Icon>` 自体にはテキスト情報が含まれていません。
そのため、スクリーンリーダーのようなテキストに依存した環境ではアイコンの意味がユーザーに伝わりません。
`<Icon>` のみを含むボタンを実装した場合、ユーザーには理解できないボタンが提示されてしまうかもしれません。
```
<Color color="primary">
<Icon icon="UbieIcon" /> Ubie Vitals
</Color>
```

これを解決するにはアイコンを利用する親要素に `aria-label``aria-labelledby` 属性を付与します。テキストによりユーザーに内容を伝達します。
### アイコン単独での使用

```jsx
<Button aria-lable="閉じる">
<CloseAIcon />
</Button>
```
基本的には、アイコンはテキストと併用して利用することを推奨します。アイコンの持つ意味が100%ユーザーに伝わるとは限りません。

<small>※ `<Icon>` そのものにはテキスト情報を付与しません</small>
単独で使用する場合は、`label` propにそのアイコンがどういった意味を持つかを記述してください。
`label`を使わない場合、支援技術等からはアイコン自体がみえません[^1]

`<Icon>` とテキストを併用しても良いでしょう。
[^1]: [Windows NVDAの場合 - ユビー AI 受診相談でほんとうに起きていた怖い話](https://docs.google.com/presentation/d/1phP267dInvtrxTBQhlrxYkoTOTHJbKq6nTD5ljD-xSI/edit#slide=id.g107361d2158_0_136)

```jsx
<Button>
<CloseAIcon /> 閉じる
</Button>
<Icon icon="SetupIcon" label="設定" />
```

参考: [ユビー AI 受診相談でほんとうに起きていた怖い話 - アイコンをボタンやリンクに使うときは](https://docs.google.com/presentation/d/1phP267dInvtrxTBQhlrxYkoTOTHJbKq6nTD5ljD-xSI/edit#slide=id.g107361d2158_0_251)

### コントラストを確保する

テキストと同様に、コントラストを確保し視覚的にアイコンを見やすくしましょう。特にアイコン単体で使うような場合、必ずコントラストを確保すべきです。
Expand All @@ -59,4 +63,4 @@ WCAG では隣接した色とのコントラスト比を 3:1 以上とするこ
- [Elements/Icons](/elements/icons)
- [ubie-oss/ubie-icons](https://github.com/ubie-oss/ubie-icons)
- [Figma - Ubie Icons](https://www.figma.com/file/6dWoWbMuEHiVN5qi1ybDAa/Ubie-Icons?type=design&node-id=0%3A1&mode=design&t=yddL2kJ5U8BIO59w-1)
- [ユビー AI 受診相談でほんとうに起きていた怖い話 - アイコンをボタンやリンクに使うときは](https://docs.google.com/presentation/d/1phP267dInvtrxTBQhlrxYkoTOTHJbKq6nTD5ljD-xSI/edit#slide=id.g107361d2158_0_251)
- [アイコンをボタンやリンクに使うときは - ユビー AI 受診相談でほんとうに起きていた怖い話](https://docs.google.com/presentation/d/1phP267dInvtrxTBQhlrxYkoTOTHJbKq6nTD5ljD-xSI/edit#slide=id.g107361d2158_0_251)
2 changes: 1 addition & 1 deletion src/pages/components/link-card.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ thumbnail: '/assets/images/components/thumbnail-link-card.svg'
repositoryUrl: 'https://github.com/ubie-oss/ubie-ui/tree/main/src/components/LinkCard'
---

## Introduction
## Feature

- タイトル以外にも、アイコンや説明などの情報/表現を含んだリンクを提供します
- リンク先の情報を事前に提示できるため、ユーザーが内容を把握しやすくなります
Expand Down
2 changes: 1 addition & 1 deletion src/pages/components/stack.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ thumbnail: '/assets/images/components/thumbnail-stack.svg'
repositoryUrl: 'https://github.com/ubie-oss/ubie-ui/tree/main/src/components/Stack'
---

## Introduction
## Feature

- 要素をStackしてレイアウトします
- 同じマージン間隔を取るため、規則性が生まれます
Expand Down
2 changes: 1 addition & 1 deletion src/pages/components/text.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ thumbnail: '/assets/images/components/thumbnail-text.svg'
repositoryUrl: 'https://github.com/ubie-oss/ubie-ui/tree/main/src/components/Text'
---

## Introduction
## Feature

[Typography トークン](/tokens/typography)に基づいたスタイルを提供します。

Expand Down

0 comments on commit 2d32d77

Please sign in to comment.