-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Imple heading component #15
Changes from all commits
907c692
04ea7f2
c791cf8
2e48a68
68b1118
de685c9
66ae893
a37528b
3e78fe8
a0fcf65
71c29c7
0ac9ca8
bc5edf2
86aba03
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
build | ||
|
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
.heading { | ||
font-weight: bold; | ||
box-sizing: border-box; | ||
color: var(--color-text-main); | ||
position: relative; | ||
|
||
--medium-leading-border-width: 4px; | ||
--large-leading-border-width: 5px; | ||
} | ||
|
||
:where(.heading) { | ||
margin: 0; | ||
} | ||
|
||
.heading.left { | ||
text-align: left; | ||
} | ||
|
||
.heading.center { | ||
text-align: center; | ||
} | ||
|
||
.heading.right { | ||
text-align: right; | ||
} | ||
|
||
.heading.secondary { | ||
color: var(--color-text-main); | ||
} | ||
|
||
.heading.primary { | ||
color: var(--color-primary); | ||
} | ||
|
||
.heading > a { | ||
color: var(--color-text-link); | ||
} | ||
|
||
@media (hover: hover) { | ||
.heading > a:hover { | ||
color: var(--color-primary-darken); | ||
} | ||
} | ||
|
||
.heading > a:active { | ||
text-decoration: none; | ||
} | ||
|
||
.heading.accent, | ||
.heading.accent > a { | ||
color: var(--color-accent); | ||
} | ||
|
||
@media (hover: hover) { | ||
.heading.accent > a:hover { | ||
color: var(--color-accent-darken); | ||
} | ||
} | ||
|
||
.heading.white { | ||
color: var(--color-text-white); | ||
} | ||
|
||
.heading.white, | ||
.heading.white > a { | ||
color: var(--color-text-white); | ||
} | ||
|
||
@media (hover: hover) { | ||
.heading.white > a:hover { | ||
text-decoration: none; | ||
} | ||
} | ||
|
||
.heading.white > a:active { | ||
position: relative; | ||
top: 1px; | ||
text-decoration: underline; | ||
} | ||
|
||
.heading.xs { | ||
font-size: var(--text-heading-xs-size); | ||
line-height: var(--text-heading-xs-line); | ||
} | ||
|
||
.heading.sm { | ||
font-size: var(--text-heading-sm-size); | ||
line-height: var(--text-heading-sm-line); | ||
} | ||
|
||
.heading.md { | ||
font-size: var(--text-heading-md-size); | ||
line-height: var(--text-heading-md-line); | ||
} | ||
|
||
.heading.lg { | ||
font-size: var(--text-heading-lg-size); | ||
line-height: var(--text-heading-lg-line); | ||
} | ||
|
||
.heading.xl { | ||
font-size: var(--text-heading-xl-size); | ||
line-height: var(--text-heading-xl-line); | ||
} | ||
|
||
.heading.leadingBorder { | ||
padding-left: calc(var(--size-spacing-sm) + var(--medium-leading-border-width)); | ||
} | ||
|
||
.heading.leadingBorder::before { | ||
position: absolute; | ||
display: block; | ||
top: 0; | ||
left: 0; | ||
content: ''; | ||
width: var(--medium-leading-border-width); | ||
border-radius: 3px; | ||
background-color: var(--color-primary); | ||
vertical-align: top; | ||
height: 100%; | ||
} | ||
|
||
.heading.lg.leadingBorder, | ||
.heading.xl.leadingBorder { | ||
padding-left: calc(var(--size-spacing-sm) + var(--large-leading-border-width)); | ||
} | ||
|
||
.heading.lg.leadingBorder::before, | ||
.heading.xl.leadingBorder::before { | ||
width: var(--large-leading-border-width); | ||
} | ||
|
||
.icon { | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
display: inline-block; | ||
} | ||
|
||
.icon.primary { | ||
color: var(--color-primary); | ||
} | ||
|
||
.icon.accent { | ||
color: var(--color-accent); | ||
} | ||
|
||
.icon.white { | ||
color: var(--color-text-white); | ||
} | ||
|
||
.icon > svg { | ||
vertical-align: baseline; | ||
width: 100%; | ||
height: 100%; | ||
} | ||
|
||
.heading.xs.hasIcon { | ||
padding-left: calc(var(--text-heading-xs-size) * var(--text-heading-xs-line) + 0.5em); | ||
} | ||
|
||
.heading.sm.hasIcon { | ||
padding-left: calc(var(--text-heading-sm-size) * var(--text-heading-sm-line) + 0.5em); | ||
} | ||
|
||
.heading.md.hasIcon { | ||
padding-left: calc(var(--text-heading-md-size) * var(--text-heading-md-line) + 0.5em); | ||
} | ||
|
||
.heading.lg.hasIcon { | ||
padding-left: calc(var(--text-heading-lg-size) * var(--text-heading-lg-line) + 0.5em); | ||
} | ||
|
||
.heading.xl.hasIcon { | ||
padding-left: calc(var(--text-heading-xl-size) * var(--text-heading-xl-line) + 0.5em); | ||
} | ||
|
||
.heading.xs > .icon { | ||
width: calc(var(--text-heading-xs-size) * var(--text-heading-xs-line)); | ||
height: calc(var(--text-heading-xs-size) * var(--text-heading-xs-line)); | ||
} | ||
|
||
.heading.sm > .icon { | ||
width: calc(var(--text-heading-sm-size) * var(--text-heading-sm-line)); | ||
height: calc(var(--text-heading-sm-size) * var(--text-heading-sm-line)); | ||
} | ||
|
||
.heading.md > .icon { | ||
width: calc(var(--text-heading-md-size) * var(--text-heading-md-line)); | ||
height: calc(var(--text-heading-md-size) * var(--text-heading-md-line)); | ||
} | ||
|
||
.heading.lg > .icon { | ||
width: calc(var(--text-heading-lg-size) * var(--text-heading-lg-line)); | ||
height: calc(var(--text-heading-lg-size) * var(--text-heading-lg-line)); | ||
} | ||
|
||
.heading.xl > .icon { | ||
width: calc(var(--text-heading-xl-size) * var(--text-heading-xl-line)); | ||
height: calc(var(--text-heading-xl-size) * var(--text-heading-xl-line)); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { clsx } from 'clsx'; | ||
import styles from './Heading.module.css'; | ||
import { HTMLTagname } from '../../utils/types'; | ||
import type { FC, PropsWithChildren, ReactNode } from 'react'; | ||
|
||
type Props = { | ||
/** | ||
* テキストの配置 | ||
* @default left | ||
*/ | ||
textAlign?: 'left' | 'center' | 'right'; | ||
/** | ||
* アイコン。プライマラーカラーで表示。icon propはどれかひとつのみを指定してください | ||
*/ | ||
primaryIcon?: ReactNode; | ||
/** | ||
* アイコン。アクセントカラーで表示。icon propはどれかひとつのみを指定してください | ||
*/ | ||
accentIcon?: ReactNode; | ||
/** | ||
* アイコン。ホワイトカラーで表示。icon propはどれかひとつのみを指定してください | ||
*/ | ||
whiteIcon?: ReactNode; | ||
/** | ||
* サイズ。Typographyトークンの値を指定 | ||
* @default md | ||
*/ | ||
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'; | ||
/** | ||
* 行の先頭にボーダーを表示 | ||
* @default false | ||
*/ | ||
leadingBorder?: boolean; | ||
/** | ||
* レンダリングされるHTML要素 | ||
* @default p | ||
*/ | ||
as: HTMLTagname; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added 4/19 Element constraints removed |
||
/** | ||
* テキストのカラーバリエーション | ||
* @default secondary | ||
*/ | ||
variant?: 'primary' | 'secondary' | 'accent' | 'white'; | ||
/** | ||
* HTMLのID属性 | ||
*/ | ||
id?: string; | ||
/** | ||
* HTMLのfor属性。label要素の場合に使用 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added 4/19 I checked the product and found a comment asking for a label with the look and feel of a heading. |
||
*/ | ||
htmlFor?: string; | ||
}; | ||
|
||
const Heading: FC<PropsWithChildren<Props>> = ({ | ||
textAlign = 'left', | ||
children, | ||
primaryIcon, | ||
accentIcon, | ||
whiteIcon, | ||
size = 'md', | ||
variant = 'secondary', | ||
leadingBorder, | ||
as: HeadingComponent = 'p', | ||
id, | ||
htmlFor, | ||
}) => { | ||
const className = clsx( | ||
styles.heading, | ||
primaryIcon || accentIcon || whiteIcon ? styles.hasIcon : null, | ||
styles[textAlign], | ||
styles[size], | ||
leadingBorder ? styles.secondary : styles[variant], | ||
leadingBorder ? styles.leadingBorder : null, | ||
); | ||
|
||
return ( | ||
<HeadingComponent className={className} id={id} htmlFor={htmlFor}> | ||
{primaryIcon && ( | ||
<span aria-hidden className={clsx(styles.icon, styles.primary)}> | ||
{primaryIcon} | ||
</span> | ||
)} | ||
{accentIcon && ( | ||
<span aria-hidden className={clsx(styles.icon, styles.accent)}> | ||
{accentIcon} | ||
</span> | ||
)} | ||
{whiteIcon && ( | ||
<span aria-hidden className={clsx(styles.icon, styles.white)}> | ||
{whiteIcon} | ||
</span> | ||
)} | ||
{children} | ||
</HeadingComponent> | ||
); | ||
}; | ||
|
||
Heading.displayName = 'Heading'; | ||
|
||
export { Heading }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,7 +34,7 @@ export const RadioButton: FC<Props> = ({ | |
...otherProps | ||
}) => { | ||
return ( | ||
<div className={clsx(styles.container, styles[size])}> | ||
<div className={clsx(styles[size])}> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
<label className={styles.label}> | ||
<input | ||
type="radio" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added 4/19
I have dared to use the p element as the default.
I think it would be less problematic if it were a p element rather than specifying the wrong heading element.