Design system.
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 

347 righe
7.4 KiB

  1. import { css } from '@tesseract-design/goofy-goober'
  2. export enum CheckControlAppearance {
  3. TICK_BOX = 'tick-box',
  4. BUTTON = 'button',
  5. SWITCH = 'switch',
  6. }
  7. export enum CheckControlType {
  8. /**
  9. * One or more of this component within its group can be selected.
  10. */
  11. CHECKBOX = 'checkbox',
  12. /**
  13. * At most one of this component within its group can be selected.
  14. */
  15. RADIO = 'radio',
  16. }
  17. export type CheckControlBaseArgs = {
  18. /**
  19. * Will the component conserve visual space?
  20. */
  21. compact: boolean,
  22. /**
  23. * Appearance of the component.
  24. */
  25. appearance: CheckControlAppearance,
  26. /**
  27. * Will the component occupy the whole width of its container?
  28. */
  29. block: boolean,
  30. /**
  31. * Type of the component defining its behavior.
  32. */
  33. type: CheckControlType,
  34. /**
  35. * Label to display signifying the component's unselected state.
  36. */
  37. uncheckedLabel: boolean,
  38. }
  39. export const CheckStateContainer = ({
  40. appearance,
  41. type,
  42. }: CheckControlBaseArgs): string => css.cx(
  43. css`
  44. position: absolute;
  45. width: 1px;
  46. height: 1px;
  47. padding: 0;
  48. margin: -1px;
  49. overflow: hidden;
  50. clip: rect(0, 0, 0, 0);
  51. white-space: nowrap;
  52. border-width: 0;
  53. &:disabled + * {
  54. cursor: not-allowed;
  55. }
  56. &:first-child + * > :first-child + * + * {
  57. align-items: flex-start;
  58. text-align: left;
  59. }
  60. &:checked + * {
  61. --color-accent: var(--color-active, Highlight);
  62. outline: 0;
  63. }
  64. &:indeterminate[type="checkbox"] + * {
  65. --color-accent: var(--color-active, Highlight);
  66. outline: 0;
  67. }
  68. &:indeterminate[type="checkbox"] + * > :first-child + * > * > :first-child {
  69. display: none;
  70. }
  71. &:checked + * > :first-child + * > * > :first-child + * {
  72. display: none;
  73. }
  74. &:focus + * {
  75. --color-accent: var(--color-hover, red);
  76. outline: 0;
  77. }
  78. &:focus[type="checkbox"] + * {
  79. --color-accent: var(--color-hover, red);
  80. outline: 0;
  81. }
  82. &:focus + * > :first-child::before {
  83. box-shadow: 0 0 0 0.375rem var(--color-accent, blue);
  84. }
  85. `,
  86. css.nest('&:checked + * > :first-child + * > *') (
  87. css.if (
  88. appearance === CheckControlAppearance.TICK_BOX
  89. || appearance === CheckControlAppearance.BUTTON
  90. ) (
  91. css.if (type === 'checkbox') (
  92. css`
  93. width: 1.5em;
  94. height: 1.5em;
  95. `
  96. ),
  97. css.if (type === 'radio') (
  98. css`
  99. width: 1em;
  100. height: 1em;
  101. `
  102. ),
  103. ),
  104. css.if (appearance === CheckControlAppearance.SWITCH) (
  105. css`
  106. width: 1em;
  107. height: 1em;
  108. margin-right: 0;
  109. margin-left: 1em;
  110. `
  111. ),
  112. ),
  113. css.nest('&:first-child + *') (
  114. css`
  115. cursor: pointer;
  116. `,
  117. css.if (appearance === CheckControlAppearance.BUTTON) (
  118. css`
  119. display: flex;
  120. `,
  121. ),
  122. css.if (appearance === CheckControlAppearance.SWITCH) (
  123. css`
  124. width: 1em;
  125. height: 1em;
  126. `,
  127. ),
  128. ),
  129. css.nest('&:indeterminate[type="checkbox"] + * > :first-child + * > *') (
  130. css.if (
  131. appearance === CheckControlAppearance.BUTTON
  132. || appearance === CheckControlAppearance.TICK_BOX
  133. ) (
  134. css`
  135. width: 1.5em;
  136. height: 1.5em;
  137. `
  138. ),
  139. css.if (appearance === CheckControlAppearance.SWITCH) (
  140. css`
  141. width: 1em;
  142. height: 1em;
  143. margin-right: 0.5em;
  144. margin-left: 0.5em;
  145. `
  146. )
  147. ),
  148. css.nest('&:indeterminate[type="checkbox"] + * > :first-child + * > * > :first-child + *') (
  149. css.if (
  150. appearance === CheckControlAppearance.BUTTON
  151. || appearance === CheckControlAppearance.TICK_BOX
  152. ) (
  153. css`
  154. display: block;
  155. `
  156. ),
  157. ),
  158. css.nest('&:checked + * > :first-child + * > * > :first-child') (
  159. css.if (
  160. appearance === CheckControlAppearance.BUTTON
  161. || appearance === CheckControlAppearance.TICK_BOX
  162. ) (
  163. css`
  164. display: block;
  165. `
  166. ),
  167. ),
  168. );
  169. export const ClickArea = (): string => css.cx(
  170. css`
  171. display: contents;
  172. `
  173. );
  174. export const CheckIndicatorArea = ({
  175. compact,
  176. appearance,
  177. type,
  178. uncheckedLabel,
  179. }: CheckControlBaseArgs): string => css.cx(
  180. css`
  181. display: inline-grid;
  182. vertical-align: middle;
  183. place-content: center;
  184. position: relative;
  185. background-color: var(--color-bg, white);
  186. box-shadow: 0 0 0 0.125rem var(--color-bg, white);
  187. color: var(--color-accent, blue);
  188. overflow: hidden;
  189. &::before {
  190. content: '';
  191. width: 100%;
  192. height: 100%;
  193. position: absolute;
  194. top: 0;
  195. left: 0;
  196. border-radius: inherit;
  197. border-width: 0.125rem;
  198. border-style: solid;
  199. box-sizing: border-box;
  200. }
  201. `,
  202. css.if (appearance === CheckControlAppearance.TICK_BOX) (
  203. css`
  204. width: 1.5em;
  205. height: 1.5em;
  206. `,
  207. css.if (type === CheckControlType.CHECKBOX) (
  208. css`
  209. border-radius: 0.25rem;
  210. `
  211. ),
  212. css.if (type === CheckControlType.RADIO) (
  213. css`
  214. border-radius: 50%;
  215. `
  216. ),
  217. ),
  218. css.if (appearance === CheckControlAppearance.BUTTON) (
  219. css`
  220. width: 1.5em;
  221. height: 1.5em;
  222. `,
  223. css.if (!compact) (
  224. css`
  225. margin-left: -0.25rem;
  226. `
  227. ),
  228. css.if (type === CheckControlType.CHECKBOX) (
  229. css`
  230. border-radius: 0.25rem;
  231. `
  232. ),
  233. css.if (type === CheckControlType.RADIO) (
  234. css`
  235. border-radius: 50%;
  236. `
  237. ),
  238. ),
  239. css.if (appearance === CheckControlAppearance.SWITCH) (
  240. css`
  241. width: 2.5em;
  242. height: 1.5em;
  243. border-radius: 0.75em;
  244. `,
  245. css.if(uncheckedLabel) (
  246. css.dynamic({
  247. 'margin-left': compact ? '0.375rem' : '0.75rem',
  248. })
  249. ),
  250. ),
  251. css.nest('& + *') (
  252. css.dynamic({
  253. 'margin-left': compact ? '0.375rem' : '0.75rem',
  254. })
  255. )
  256. );
  257. export const CheckIndicatorWrapper = ({
  258. appearance,
  259. }: CheckControlBaseArgs): string => css.cx(
  260. css`
  261. flex-shrink: 0;
  262. display: grid;
  263. position: relative;
  264. background-color: var(--color-accent, blue);
  265. overflow: hidden;
  266. border-radius: inherit;
  267. `,
  268. css.if(
  269. appearance === CheckControlAppearance.TICK_BOX
  270. || appearance === CheckControlAppearance.BUTTON
  271. ) (
  272. css`
  273. width: 0;
  274. height: 0;
  275. `
  276. ),
  277. css.if(appearance === CheckControlAppearance.SWITCH) (
  278. css`
  279. width: 1em;
  280. height: 1em;
  281. margin-right: 1em;
  282. transition-property: margin-left, margin-right;
  283. transition-duration: 150ms;
  284. transition-timing-function: ease-out;
  285. `,
  286. ),
  287. );
  288. export const CheckIndicator = ({
  289. appearance,
  290. }: CheckControlBaseArgs) => css.cx(
  291. css`
  292. fill: none;
  293. stroke: var(--color-bg, white);
  294. stroke-width: 2;
  295. stroke-linecap: round;
  296. stroke-linejoin: round;
  297. width: 1.5em;
  298. height: 1.5em;
  299. `,
  300. css.if(appearance === CheckControlAppearance.SWITCH) (
  301. css`
  302. display: none;
  303. `
  304. )
  305. );
  306. export const ClickAreaWrapper = ({
  307. block,
  308. appearance,
  309. uncheckedLabel,
  310. }: CheckControlBaseArgs) => css.cx(
  311. css`
  312. vertical-align: middle;
  313. `,
  314. css.dynamic({
  315. display: block ? 'block' : 'inline-block',
  316. }),
  317. css.if (appearance === CheckControlAppearance.TICK_BOX) (
  318. css`
  319. padding-left: 2.25rem;
  320. text-indent: -2.25rem;
  321. `
  322. ),
  323. css.if (appearance === CheckControlAppearance.SWITCH) (
  324. css.if (!uncheckedLabel) (
  325. css`
  326. padding-left: 3.25rem;
  327. text-indent: -3.25rem;
  328. `
  329. ),
  330. ),
  331. );
  332. export const Subtext = () => css.cx(
  333. css`
  334. font-size: 0.875em;
  335. `
  336. );