├── .bitmap ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── docs └── scope-screenshot.png ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── src ├── App.css ├── App.test.tsx ├── App.tsx ├── constants │ ├── sizes.ts │ └── storage │ │ ├── _storage.module.scss │ │ └── index.ts ├── css-components │ ├── elevation │ │ ├── elevation-height.ts │ │ ├── elevations.module.scss │ │ └── index.ts │ ├── pill │ │ ├── index.ts │ │ └── pill.module.scss │ └── roundness │ │ ├── index.ts │ │ ├── roundness-values.ts │ │ └── roundness.module.scss ├── effects │ └── ref-tooltip │ │ ├── index.ts │ │ ├── ref-tooltip.module.scss │ │ └── ref-tooltip.tsx ├── elements │ ├── dots-loader │ │ ├── dots-loader.module.scss │ │ ├── dots-loader.tsx │ │ └── index.ts │ ├── icon │ │ ├── base-icon.tsx │ │ └── index.ts │ ├── image │ │ ├── image.module.scss │ │ ├── image.spec.tsx │ │ ├── image.tsx │ │ └── index.ts │ ├── label │ │ ├── index.tsx │ │ ├── label.module.scss │ │ ├── label.spec.tsx │ │ └── label.tsx │ ├── link │ │ ├── index.ts │ │ └── link.tsx │ └── separator │ │ ├── index.tsx │ │ ├── separator.module.scss │ │ ├── separator.spec.tsx │ │ └── separator.tsx ├── geometry │ └── curve-peek │ │ ├── curve-peek.tsx │ │ ├── filling.module.scss │ │ └── indext.ts ├── index.css ├── index.tsx ├── input │ ├── button │ │ ├── button.module.scss │ │ ├── button.spec.tsx │ │ ├── button.tsx │ │ └── index.ts │ └── error │ │ ├── error.module.scss │ │ ├── error.tsx │ │ └── index.ts ├── layout │ ├── _breakpoints.scss │ ├── align │ │ ├── README.md │ │ ├── align.module.scss │ │ └── index.ts │ ├── col-span │ │ ├── README.md │ │ ├── col-span.module.scss │ │ ├── index.ts │ │ └── make-spans.ts │ ├── grid-component │ │ ├── README.md │ │ ├── grid-template │ │ │ ├── grid-template.module.scss │ │ │ └── index.ts │ │ ├── grid.module.scss │ │ ├── grid.tsx │ │ └── index.ts │ ├── grid-presets │ │ ├── four-way-grid │ │ │ ├── four-way-grid.module.scss │ │ │ └── index.ts │ │ └── z-grid │ │ │ ├── index.ts │ │ │ └── z-grid.module.scss │ └── page-frame │ │ ├── README.md │ │ ├── index.ts │ │ └── page-frame.module.scss ├── logo.svg ├── react-app-env.d.ts ├── serviceWorker.ts ├── setupTests.ts ├── surfaces │ ├── abs-container │ │ ├── abs-container.module.scss │ │ ├── containee │ │ │ ├── containee.tsx │ │ │ ├── displacement.module.scss │ │ │ ├── index.ts │ │ │ └── positions.module.scss │ │ ├── container │ │ │ ├── container.tsx │ │ │ └── index.ts │ │ └── index.ts │ ├── background │ │ ├── background.module.scss │ │ └── index.ts │ ├── bedrock │ │ ├── bedrock.tsx │ │ └── index.ts │ ├── card │ │ ├── card.module.scss │ │ ├── card.spec.tsx │ │ ├── card.tsx │ │ └── index.tsx │ ├── click-outside │ │ ├── click-outside.tsx │ │ └── index.ts │ └── drawer │ │ ├── default-placeholder.tsx │ │ ├── drawer.module.scss │ │ ├── drawer.tsx │ │ └── index.ts ├── text │ ├── heading │ │ ├── heading.spec.tsx │ │ ├── heading.tsx │ │ └── index.ts │ ├── muted-text │ │ ├── index.ts │ │ ├── muted-text.module.scss │ │ └── muted-text.tsx │ ├── paragraph │ │ ├── index.tsx │ │ ├── paragraph.module.scss │ │ ├── paragraph.spec.tsx │ │ └── paragraph.tsx │ ├── text-separator │ │ ├── index.ts │ │ ├── text-separator.module.scss │ │ └── text-separator.tsx │ └── themed-text │ │ ├── index.ts │ │ ├── themed-text.module.scss │ │ └── themed-text.tsx ├── themes │ ├── book-font.module.scss │ ├── brand-colors.module.scss │ ├── brand-definition.module.scss │ ├── color-definition.module.scss │ ├── color-palette │ │ ├── color-palette.module.scss │ │ └── index.ts │ ├── colors.module.scss │ ├── heading-margin-definition.module.scss │ ├── shadow-definition.module.scss │ ├── size-definition.module.scss │ └── theme-provider │ │ ├── index.tsx │ │ ├── texts.module.scss │ │ └── theme-provider.tsx └── utils │ └── popper-js │ ├── ignore-popper-size │ ├── ignore-popper-size.tsx │ └── index.ts │ └── resize-to-match-reference │ ├── index.ts │ └── resize-to-match-reference.tsx ├── tsconfig.json └── yarn.lock /.bitmap: -------------------------------------------------------------------------------- 1 | /* THIS IS A BIT-AUTO-GENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. */ 2 | 3 | { 4 | "bit.base-ui/constants/storage@1.0.5": { 5 | "files": [ 6 | { 7 | "name": "_storage.module.scss", 8 | "relativePath": "src/constants/storage/_storage.module.scss", 9 | "test": false 10 | }, 11 | { 12 | "name": "index.ts", 13 | "relativePath": "src/constants/storage/index.ts", 14 | "test": false 15 | } 16 | ], 17 | "mainFile": "src/constants/storage/index.ts", 18 | "trackDir": "src/constants/storage", 19 | "origin": "AUTHORED", 20 | "exported": true 21 | }, 22 | "bit.base-ui/css-components/elevation@0.0.1": { 23 | "files": [ 24 | { 25 | "relativePath": "src/css-components/elevation/elevation-height.ts", 26 | "test": false, 27 | "name": "elevation-height.ts" 28 | }, 29 | { 30 | "relativePath": "src/css-components/elevation/elevations.module.scss", 31 | "test": false, 32 | "name": "elevations.module.scss" 33 | }, 34 | { 35 | "relativePath": "src/css-components/elevation/index.ts", 36 | "test": false, 37 | "name": "index.ts" 38 | } 39 | ], 40 | "mainFile": "src/css-components/elevation/index.ts", 41 | "trackDir": "src/css-components/elevation", 42 | "origin": "AUTHORED", 43 | "exported": true 44 | }, 45 | "bit.base-ui/css-components/pill@1.0.1": { 46 | "files": [ 47 | { 48 | "name": "index.ts", 49 | "relativePath": "src/css-components/pill/index.ts", 50 | "test": false 51 | }, 52 | { 53 | "name": "pill.module.scss", 54 | "relativePath": "src/css-components/pill/pill.module.scss", 55 | "test": false 56 | } 57 | ], 58 | "mainFile": "src/css-components/pill/index.ts", 59 | "trackDir": "src/css-components/pill", 60 | "origin": "AUTHORED", 61 | "exported": true 62 | }, 63 | "bit.base-ui/css-components/roundness@0.0.1": { 64 | "files": [ 65 | { 66 | "relativePath": "src/css-components/roundness/index.ts", 67 | "test": false, 68 | "name": "index.ts" 69 | }, 70 | { 71 | "relativePath": "src/css-components/roundness/roundness-values.ts", 72 | "test": false, 73 | "name": "roundness-values.ts" 74 | }, 75 | { 76 | "relativePath": "src/css-components/roundness/roundness.module.scss", 77 | "test": false, 78 | "name": "roundness.module.scss" 79 | } 80 | ], 81 | "mainFile": "src/css-components/roundness/index.ts", 82 | "trackDir": "src/css-components/roundness", 83 | "origin": "AUTHORED", 84 | "exported": true 85 | }, 86 | "bit.base-ui/elements/dots-loader@0.0.2": { 87 | "files": [ 88 | { 89 | "relativePath": "src/elements/dots-loader/dots-loader.module.scss", 90 | "test": false, 91 | "name": "dots-loader.module.scss" 92 | }, 93 | { 94 | "relativePath": "src/elements/dots-loader/dots-loader.tsx", 95 | "test": false, 96 | "name": "dots-loader.tsx" 97 | }, 98 | { 99 | "relativePath": "src/elements/dots-loader/index.ts", 100 | "test": false, 101 | "name": "index.ts" 102 | } 103 | ], 104 | "mainFile": "src/elements/dots-loader/index.ts", 105 | "trackDir": "src/elements/dots-loader", 106 | "origin": "AUTHORED", 107 | "exported": true 108 | }, 109 | "bit.base-ui/elements/icon@1.0.2": { 110 | "files": [ 111 | { 112 | "name": "base-icon.tsx", 113 | "relativePath": "src/elements/icon/base-icon.tsx", 114 | "test": false 115 | }, 116 | { 117 | "name": "index.ts", 118 | "relativePath": "src/elements/icon/index.ts", 119 | "test": false 120 | } 121 | ], 122 | "mainFile": "src/elements/icon/index.ts", 123 | "trackDir": "src/elements/icon", 124 | "origin": "AUTHORED", 125 | "exported": true 126 | }, 127 | "bit.base-ui/elements/image@1.0.2": { 128 | "files": [ 129 | { 130 | "name": "image.module.scss", 131 | "relativePath": "src/elements/image/image.module.scss", 132 | "test": false 133 | }, 134 | { 135 | "name": "image.spec.tsx", 136 | "relativePath": "src/elements/image/image.spec.tsx", 137 | "test": true 138 | }, 139 | { 140 | "name": "image.tsx", 141 | "relativePath": "src/elements/image/image.tsx", 142 | "test": false 143 | }, 144 | { 145 | "name": "index.ts", 146 | "relativePath": "src/elements/image/index.ts", 147 | "test": false 148 | } 149 | ], 150 | "mainFile": "src/elements/image/index.ts", 151 | "trackDir": "src/elements/image", 152 | "origin": "AUTHORED", 153 | "exported": true 154 | }, 155 | "bit.base-ui/elements/label@1.0.2": { 156 | "files": [ 157 | { 158 | "name": "index.tsx", 159 | "relativePath": "src/elements/label/index.tsx", 160 | "test": false 161 | }, 162 | { 163 | "name": "label.module.scss", 164 | "relativePath": "src/elements/label/label.module.scss", 165 | "test": false 166 | }, 167 | { 168 | "name": "label.spec.tsx", 169 | "relativePath": "src/elements/label/label.spec.tsx", 170 | "test": true 171 | }, 172 | { 173 | "name": "label.tsx", 174 | "relativePath": "src/elements/label/label.tsx", 175 | "test": false 176 | } 177 | ], 178 | "mainFile": "src/elements/label/index.tsx", 179 | "trackDir": "src/elements/label", 180 | "origin": "AUTHORED", 181 | "exported": true 182 | }, 183 | "bit.base-ui/elements/link@1.0.2": { 184 | "files": [ 185 | { 186 | "name": "index.ts", 187 | "relativePath": "src/elements/link/index.ts", 188 | "test": false 189 | }, 190 | { 191 | "name": "link.tsx", 192 | "relativePath": "src/elements/link/link.tsx", 193 | "test": false 194 | } 195 | ], 196 | "mainFile": "src/elements/link/index.ts", 197 | "trackDir": "src/elements/link", 198 | "origin": "AUTHORED", 199 | "exported": true 200 | }, 201 | "bit.base-ui/elements/separator@1.0.3": { 202 | "files": [ 203 | { 204 | "name": "index.tsx", 205 | "relativePath": "src/elements/separator/index.tsx", 206 | "test": false 207 | }, 208 | { 209 | "name": "separator.module.scss", 210 | "relativePath": "src/elements/separator/separator.module.scss", 211 | "test": false 212 | }, 213 | { 214 | "name": "separator.tsx", 215 | "relativePath": "src/elements/separator/separator.tsx", 216 | "test": false 217 | }, 218 | { 219 | "name": "separator.spec.tsx", 220 | "relativePath": "src/elements/separator/separator.spec.tsx", 221 | "test": false 222 | } 223 | ], 224 | "mainFile": "src/elements/separator/index.tsx", 225 | "trackDir": "src/elements/separator", 226 | "origin": "AUTHORED", 227 | "exported": true 228 | }, 229 | "bit.base-ui/geometry/curve-peek@1.0.1": { 230 | "files": [ 231 | { 232 | "relativePath": "src/geometry/curve-peek/curve-peek.tsx", 233 | "test": false, 234 | "name": "curve-peek.tsx" 235 | }, 236 | { 237 | "relativePath": "src/geometry/curve-peek/filling.module.scss", 238 | "test": false, 239 | "name": "filling.module.scss" 240 | }, 241 | { 242 | "relativePath": "src/geometry/curve-peek/indext.ts", 243 | "test": false, 244 | "name": "indext.ts" 245 | } 246 | ], 247 | "mainFile": "src/geometry/curve-peek/curve-peek.tsx", 248 | "trackDir": "src/geometry/curve-peek", 249 | "origin": "AUTHORED", 250 | "exported": true 251 | }, 252 | "bit.base-ui/input/button@1.1.1": { 253 | "files": [ 254 | { 255 | "name": "button.module.scss", 256 | "relativePath": "src/input/button/button.module.scss", 257 | "test": false 258 | }, 259 | { 260 | "name": "button.spec.tsx", 261 | "relativePath": "src/input/button/button.spec.tsx", 262 | "test": false 263 | }, 264 | { 265 | "name": "button.tsx", 266 | "relativePath": "src/input/button/button.tsx", 267 | "test": false 268 | }, 269 | { 270 | "name": "index.ts", 271 | "relativePath": "src/input/button/index.ts", 272 | "test": false 273 | } 274 | ], 275 | "mainFile": "src/input/button/index.ts", 276 | "trackDir": "src/input/button", 277 | "origin": "AUTHORED", 278 | "exported": true 279 | }, 280 | "bit.base-ui/input/error@1.0.1": { 281 | "files": [ 282 | { 283 | "relativePath": "src/input/error/error.module.scss", 284 | "test": false, 285 | "name": "error.module.scss" 286 | }, 287 | { 288 | "relativePath": "src/input/error/error.tsx", 289 | "test": false, 290 | "name": "error.tsx" 291 | }, 292 | { 293 | "relativePath": "src/input/error/index.ts", 294 | "test": false, 295 | "name": "index.ts" 296 | } 297 | ], 298 | "mainFile": "src/input/error/index.ts", 299 | "trackDir": "src/input/error", 300 | "origin": "AUTHORED", 301 | "exported": true 302 | }, 303 | "bit.base-ui/layout/align@1.1.1": { 304 | "files": [ 305 | { 306 | "name": "README.md", 307 | "relativePath": "src/layout/align/README.md", 308 | "test": false 309 | }, 310 | { 311 | "name": "align.module.scss", 312 | "relativePath": "src/layout/align/align.module.scss", 313 | "test": false 314 | }, 315 | { 316 | "name": "index.ts", 317 | "relativePath": "src/layout/align/index.ts", 318 | "test": false 319 | } 320 | ], 321 | "mainFile": "src/layout/align/index.ts", 322 | "trackDir": "src/layout/align", 323 | "origin": "AUTHORED", 324 | "exported": true 325 | }, 326 | "bit.base-ui/layout/breakpoints@1.0.7": { 327 | "files": [ 328 | { 329 | "name": "_breakpoints.scss", 330 | "relativePath": "src/layout/_breakpoints.scss", 331 | "test": false 332 | } 333 | ], 334 | "mainFile": "src/layout/_breakpoints.scss", 335 | "origin": "AUTHORED", 336 | "exported": true 337 | }, 338 | "bit.base-ui/layout/col-span@1.0.7": { 339 | "files": [ 340 | { 341 | "name": "README.md", 342 | "relativePath": "src/layout/col-span/README.md", 343 | "test": false 344 | }, 345 | { 346 | "name": "col-span.module.scss", 347 | "relativePath": "src/layout/col-span/col-span.module.scss", 348 | "test": false 349 | }, 350 | { 351 | "name": "index.ts", 352 | "relativePath": "src/layout/col-span/index.ts", 353 | "test": false 354 | }, 355 | { 356 | "name": "make-spans.ts", 357 | "relativePath": "src/layout/col-span/make-spans.ts", 358 | "test": false 359 | } 360 | ], 361 | "mainFile": "src/layout/col-span/index.ts", 362 | "trackDir": "src/layout/col-span", 363 | "origin": "AUTHORED", 364 | "exported": true 365 | }, 366 | "bit.base-ui/layout/grid-component@1.0.11": { 367 | "files": [ 368 | { 369 | "name": "README.md", 370 | "relativePath": "src/layout/grid-component/README.md", 371 | "test": false 372 | }, 373 | { 374 | "name": "grid-template.module.scss", 375 | "relativePath": "src/layout/grid-component/grid-template/grid-template.module.scss", 376 | "test": false 377 | }, 378 | { 379 | "name": "index.ts", 380 | "relativePath": "src/layout/grid-component/grid-template/index.ts", 381 | "test": false 382 | }, 383 | { 384 | "name": "grid.module.scss", 385 | "relativePath": "src/layout/grid-component/grid.module.scss", 386 | "test": false 387 | }, 388 | { 389 | "name": "grid.tsx", 390 | "relativePath": "src/layout/grid-component/grid.tsx", 391 | "test": false 392 | }, 393 | { 394 | "name": "index.ts", 395 | "relativePath": "src/layout/grid-component/index.ts", 396 | "test": false 397 | } 398 | ], 399 | "mainFile": "src/layout/grid-component/index.ts", 400 | "trackDir": "src/layout/grid-component", 401 | "origin": "AUTHORED", 402 | "exported": true 403 | }, 404 | "bit.base-ui/layout/grid-presets/four-way-grid@1.0.6": { 405 | "files": [ 406 | { 407 | "name": "four-way-grid.module.scss", 408 | "relativePath": "src/layout/grid-presets/four-way-grid/four-way-grid.module.scss", 409 | "test": false 410 | }, 411 | { 412 | "name": "index.ts", 413 | "relativePath": "src/layout/grid-presets/four-way-grid/index.ts", 414 | "test": false 415 | } 416 | ], 417 | "mainFile": "src/layout/grid-presets/four-way-grid/index.ts", 418 | "trackDir": "src/layout/grid-presets/four-way-grid", 419 | "origin": "AUTHORED", 420 | "exported": true 421 | }, 422 | "bit.base-ui/layout/grid-presets/z-grid@1.0.7": { 423 | "files": [ 424 | { 425 | "name": "index.ts", 426 | "relativePath": "src/layout/grid-presets/z-grid/index.ts", 427 | "test": false 428 | }, 429 | { 430 | "name": "z-grid.module.scss", 431 | "relativePath": "src/layout/grid-presets/z-grid/z-grid.module.scss", 432 | "test": false 433 | } 434 | ], 435 | "mainFile": "src/layout/grid-presets/z-grid/index.ts", 436 | "trackDir": "src/layout/grid-presets/z-grid", 437 | "origin": "AUTHORED", 438 | "exported": true 439 | }, 440 | "bit.base-ui/layout/page-frame@1.0.5": { 441 | "files": [ 442 | { 443 | "name": "README.md", 444 | "relativePath": "src/layout/page-frame/README.md", 445 | "test": false 446 | }, 447 | { 448 | "name": "index.ts", 449 | "relativePath": "src/layout/page-frame/index.ts", 450 | "test": false 451 | }, 452 | { 453 | "name": "page-frame.module.scss", 454 | "relativePath": "src/layout/page-frame/page-frame.module.scss", 455 | "test": false 456 | } 457 | ], 458 | "mainFile": "src/layout/page-frame/index.ts", 459 | "trackDir": "src/layout/page-frame", 460 | "origin": "AUTHORED", 461 | "exported": true 462 | }, 463 | "bit.base-ui/placement/ref-tooltip@1.1.2": { 464 | "files": [ 465 | { 466 | "name": "index.ts", 467 | "relativePath": "src/effects/ref-tooltip/index.ts", 468 | "test": false 469 | }, 470 | { 471 | "name": "ref-tooltip.module.scss", 472 | "relativePath": "src/effects/ref-tooltip/ref-tooltip.module.scss", 473 | "test": false 474 | }, 475 | { 476 | "name": "ref-tooltip.tsx", 477 | "relativePath": "src/effects/ref-tooltip/ref-tooltip.tsx", 478 | "test": false 479 | } 480 | ], 481 | "mainFile": "src/effects/ref-tooltip/index.ts", 482 | "trackDir": "src/effects/ref-tooltip", 483 | "origin": "AUTHORED", 484 | "exported": true 485 | }, 486 | "bit.base-ui/surfaces/abs-container@0.0.3": { 487 | "files": [ 488 | { 489 | "relativePath": "src/surfaces/abs-container/abs-container.module.scss", 490 | "test": false, 491 | "name": "abs-container.module.scss" 492 | }, 493 | { 494 | "relativePath": "src/surfaces/abs-container/containee/containee.tsx", 495 | "test": false, 496 | "name": "containee.tsx" 497 | }, 498 | { 499 | "relativePath": "src/surfaces/abs-container/containee/displacement.module.scss", 500 | "test": false, 501 | "name": "displacement.module.scss" 502 | }, 503 | { 504 | "relativePath": "src/surfaces/abs-container/containee/index.ts", 505 | "test": false, 506 | "name": "index.ts" 507 | }, 508 | { 509 | "relativePath": "src/surfaces/abs-container/containee/positions.module.scss", 510 | "test": false, 511 | "name": "positions.module.scss" 512 | }, 513 | { 514 | "relativePath": "src/surfaces/abs-container/container/container.tsx", 515 | "test": false, 516 | "name": "container.tsx" 517 | }, 518 | { 519 | "relativePath": "src/surfaces/abs-container/container/index.ts", 520 | "test": false, 521 | "name": "index.ts" 522 | }, 523 | { 524 | "relativePath": "src/surfaces/abs-container/index.ts", 525 | "test": false, 526 | "name": "index.ts" 527 | } 528 | ], 529 | "mainFile": "src/surfaces/abs-container/index.ts", 530 | "trackDir": "src/surfaces/abs-container", 531 | "origin": "AUTHORED", 532 | "exported": true 533 | }, 534 | "bit.base-ui/surfaces/background@0.0.2": { 535 | "files": [ 536 | { 537 | "relativePath": "src/surfaces/background/background.module.scss", 538 | "test": false, 539 | "name": "background.module.scss" 540 | }, 541 | { 542 | "relativePath": "src/surfaces/background/index.ts", 543 | "test": false, 544 | "name": "index.ts" 545 | } 546 | ], 547 | "mainFile": "src/surfaces/background/index.ts", 548 | "trackDir": "src/surfaces/background", 549 | "origin": "AUTHORED", 550 | "exported": true 551 | }, 552 | "bit.base-ui/surfaces/bedrock@0.0.4": { 553 | "files": [ 554 | { 555 | "relativePath": "src/surfaces/bedrock/bedrock.tsx", 556 | "test": false, 557 | "name": "bedrock.tsx" 558 | }, 559 | { 560 | "relativePath": "src/surfaces/bedrock/index.ts", 561 | "test": false, 562 | "name": "index.ts" 563 | } 564 | ], 565 | "mainFile": "src/surfaces/bedrock/index.ts", 566 | "trackDir": "src/surfaces/bedrock", 567 | "origin": "AUTHORED", 568 | "exported": true 569 | }, 570 | "bit.base-ui/surfaces/card@2.0.2": { 571 | "files": [ 572 | { 573 | "name": "card.module.scss", 574 | "relativePath": "src/surfaces/card/card.module.scss", 575 | "test": false 576 | }, 577 | { 578 | "name": "card.spec.tsx", 579 | "relativePath": "src/surfaces/card/card.spec.tsx", 580 | "test": true 581 | }, 582 | { 583 | "name": "card.tsx", 584 | "relativePath": "src/surfaces/card/card.tsx", 585 | "test": false 586 | }, 587 | { 588 | "name": "index.tsx", 589 | "relativePath": "src/surfaces/card/index.tsx", 590 | "test": false 591 | } 592 | ], 593 | "mainFile": "src/surfaces/card/index.tsx", 594 | "trackDir": "src/surfaces/card", 595 | "origin": "AUTHORED", 596 | "exported": true 597 | }, 598 | "bit.base-ui/surfaces/click-outside@0.0.1": { 599 | "files": [ 600 | { 601 | "relativePath": "src/surfaces/click-outside/click-outside.tsx", 602 | "test": false, 603 | "name": "click-outside.tsx" 604 | }, 605 | { 606 | "relativePath": "src/surfaces/click-outside/index.ts", 607 | "test": false, 608 | "name": "index.ts" 609 | } 610 | ], 611 | "mainFile": "src/surfaces/click-outside/index.ts", 612 | "trackDir": "src/surfaces/click-outside", 613 | "origin": "AUTHORED", 614 | "exported": true 615 | }, 616 | "bit.base-ui/surfaces/drawer@0.0.3": { 617 | "files": [ 618 | { 619 | "relativePath": "src/surfaces/drawer/default-placeholder.tsx", 620 | "test": false, 621 | "name": "default-placeholder.tsx" 622 | }, 623 | { 624 | "relativePath": "src/surfaces/drawer/drawer.module.scss", 625 | "test": false, 626 | "name": "drawer.module.scss" 627 | }, 628 | { 629 | "relativePath": "src/surfaces/drawer/drawer.tsx", 630 | "test": false, 631 | "name": "drawer.tsx" 632 | }, 633 | { 634 | "relativePath": "src/surfaces/drawer/index.ts", 635 | "test": false, 636 | "name": "index.ts" 637 | } 638 | ], 639 | "mainFile": "src/surfaces/drawer/index.ts", 640 | "trackDir": "src/surfaces/drawer", 641 | "origin": "AUTHORED", 642 | "exported": true 643 | }, 644 | "bit.base-ui/text/heading@1.0.2": { 645 | "files": [ 646 | { 647 | "name": "heading.spec.tsx", 648 | "relativePath": "src/text/heading/heading.spec.tsx", 649 | "test": true 650 | }, 651 | { 652 | "name": "heading.tsx", 653 | "relativePath": "src/text/heading/heading.tsx", 654 | "test": false 655 | }, 656 | { 657 | "name": "index.ts", 658 | "relativePath": "src/text/heading/index.ts", 659 | "test": false 660 | } 661 | ], 662 | "mainFile": "src/text/heading/index.ts", 663 | "trackDir": "src/text/heading", 664 | "origin": "AUTHORED", 665 | "exported": true 666 | }, 667 | "bit.base-ui/text/muted-text@1.0.1": { 668 | "files": [ 669 | { 670 | "relativePath": "src/text/muted-text/index.ts", 671 | "test": false, 672 | "name": "index.ts" 673 | }, 674 | { 675 | "relativePath": "src/text/muted-text/muted-text.module.scss", 676 | "test": false, 677 | "name": "muted-text.module.scss" 678 | }, 679 | { 680 | "relativePath": "src/text/muted-text/muted-text.tsx", 681 | "test": false, 682 | "name": "muted-text.tsx" 683 | } 684 | ], 685 | "mainFile": "src/text/muted-text/index.ts", 686 | "trackDir": "src/text/muted-text", 687 | "origin": "AUTHORED", 688 | "exported": true 689 | }, 690 | "bit.base-ui/text/paragraph@1.0.2": { 691 | "files": [ 692 | { 693 | "name": "index.tsx", 694 | "relativePath": "src/text/paragraph/index.tsx", 695 | "test": false 696 | }, 697 | { 698 | "name": "paragraph.module.scss", 699 | "relativePath": "src/text/paragraph/paragraph.module.scss", 700 | "test": false 701 | }, 702 | { 703 | "name": "paragraph.spec.tsx", 704 | "relativePath": "src/text/paragraph/paragraph.spec.tsx", 705 | "test": true 706 | }, 707 | { 708 | "name": "paragraph.tsx", 709 | "relativePath": "src/text/paragraph/paragraph.tsx", 710 | "test": false 711 | } 712 | ], 713 | "mainFile": "src/text/paragraph/index.tsx", 714 | "trackDir": "src/text/paragraph", 715 | "origin": "AUTHORED", 716 | "exported": true 717 | }, 718 | "bit.base-ui/text/text-separator@1.0.1": { 719 | "files": [ 720 | { 721 | "relativePath": "src/text/text-separator/index.ts", 722 | "test": false, 723 | "name": "index.ts" 724 | }, 725 | { 726 | "relativePath": "src/text/text-separator/text-separator.module.scss", 727 | "test": false, 728 | "name": "text-separator.module.scss" 729 | }, 730 | { 731 | "relativePath": "src/text/text-separator/text-separator.tsx", 732 | "test": false, 733 | "name": "text-separator.tsx" 734 | } 735 | ], 736 | "mainFile": "src/text/text-separator/index.ts", 737 | "trackDir": "src/text/text-separator", 738 | "origin": "AUTHORED", 739 | "exported": true 740 | }, 741 | "bit.base-ui/text/themed-text@1.0.3": { 742 | "files": [ 743 | { 744 | "relativePath": "src/text/themed-text/index.ts", 745 | "test": false, 746 | "name": "index.ts" 747 | }, 748 | { 749 | "relativePath": "src/text/themed-text/themed-text.module.scss", 750 | "test": false, 751 | "name": "themed-text.module.scss" 752 | }, 753 | { 754 | "relativePath": "src/text/themed-text/themed-text.tsx", 755 | "test": false, 756 | "name": "themed-text.tsx" 757 | } 758 | ], 759 | "mainFile": "src/text/themed-text/index.ts", 760 | "trackDir": "src/text/themed-text", 761 | "origin": "AUTHORED", 762 | "exported": true 763 | }, 764 | "bit.base-ui/theme/brand-colors@1.0.4": { 765 | "files": [ 766 | { 767 | "name": "brand-colors.module.scss", 768 | "relativePath": "src/themes/brand-colors.module.scss", 769 | "test": false 770 | } 771 | ], 772 | "mainFile": "src/themes/brand-colors.module.scss", 773 | "origin": "AUTHORED", 774 | "exported": true 775 | }, 776 | "bit.base-ui/theme/brand-definition@1.0.7": { 777 | "files": [ 778 | { 779 | "name": "brand-definition.module.scss", 780 | "relativePath": "src/themes/brand-definition.module.scss", 781 | "test": false 782 | } 783 | ], 784 | "mainFile": "src/themes/brand-definition.module.scss", 785 | "origin": "AUTHORED", 786 | "exported": true 787 | }, 788 | "bit.base-ui/theme/color-definition@2.1.3": { 789 | "files": [ 790 | { 791 | "name": "color-definition.module.scss", 792 | "relativePath": "src/themes/color-definition.module.scss", 793 | "test": false 794 | } 795 | ], 796 | "mainFile": "src/themes/color-definition.module.scss", 797 | "origin": "AUTHORED", 798 | "exported": true 799 | }, 800 | "bit.base-ui/theme/color-palette@1.1.0": { 801 | "files": [ 802 | { 803 | "relativePath": "src/themes/color-palette/color-palette.module.scss", 804 | "test": false, 805 | "name": "color-palette.module.scss" 806 | }, 807 | { 808 | "relativePath": "src/themes/color-palette/index.ts", 809 | "test": false, 810 | "name": "index.ts" 811 | } 812 | ], 813 | "mainFile": "src/themes/color-palette/index.ts", 814 | "trackDir": "src/themes/color-palette", 815 | "origin": "AUTHORED", 816 | "exported": true 817 | }, 818 | "bit.base-ui/theme/colors@1.1.1": { 819 | "files": [ 820 | { 821 | "name": "colors.module.scss", 822 | "relativePath": "src/themes/colors.module.scss", 823 | "test": false 824 | } 825 | ], 826 | "mainFile": "src/themes/colors.module.scss", 827 | "origin": "AUTHORED", 828 | "exported": true 829 | }, 830 | "bit.base-ui/theme/fonts/book@1.1.1": { 831 | "files": [ 832 | { 833 | "name": "book-font.module.scss", 834 | "relativePath": "src/themes/book-font.module.scss", 835 | "test": false 836 | } 837 | ], 838 | "mainFile": "src/themes/book-font.module.scss", 839 | "origin": "AUTHORED", 840 | "exported": true 841 | }, 842 | "bit.base-ui/theme/heading-margin-definition@1.0.3": { 843 | "files": [ 844 | { 845 | "name": "heading-margin-definition.module.scss", 846 | "relativePath": "src/themes/heading-margin-definition.module.scss", 847 | "test": false 848 | } 849 | ], 850 | "mainFile": "src/themes/heading-margin-definition.module.scss", 851 | "origin": "AUTHORED", 852 | "exported": true 853 | }, 854 | "bit.base-ui/theme/shadow-definition@2.1.0": { 855 | "files": [ 856 | { 857 | "name": "shadow-definition.module.scss", 858 | "relativePath": "src/themes/shadow-definition.module.scss", 859 | "test": false 860 | } 861 | ], 862 | "mainFile": "src/themes/shadow-definition.module.scss", 863 | "origin": "AUTHORED", 864 | "exported": true 865 | }, 866 | "bit.base-ui/theme/size-definition@1.0.3": { 867 | "files": [ 868 | { 869 | "name": "size-definition.module.scss", 870 | "relativePath": "src/themes/size-definition.module.scss", 871 | "test": false 872 | } 873 | ], 874 | "mainFile": "src/themes/size-definition.module.scss", 875 | "origin": "AUTHORED", 876 | "exported": true 877 | }, 878 | "bit.base-ui/theme/sizes@1.0.4": { 879 | "files": [ 880 | { 881 | "name": "sizes.ts", 882 | "relativePath": "src/constants/sizes.ts", 883 | "test": false 884 | } 885 | ], 886 | "mainFile": "src/constants/sizes.ts", 887 | "origin": "AUTHORED", 888 | "exported": true 889 | }, 890 | "bit.base-ui/theme/theme-provider@2.1.3": { 891 | "files": [ 892 | { 893 | "name": "index.tsx", 894 | "relativePath": "src/themes/theme-provider/index.tsx", 895 | "test": false 896 | }, 897 | { 898 | "name": "texts.module.scss", 899 | "relativePath": "src/themes/theme-provider/texts.module.scss", 900 | "test": false 901 | }, 902 | { 903 | "name": "theme-provider.tsx", 904 | "relativePath": "src/themes/theme-provider/theme-provider.tsx", 905 | "test": false 906 | } 907 | ], 908 | "mainFile": "src/themes/theme-provider/index.tsx", 909 | "origin": "AUTHORED", 910 | "exported": true 911 | }, 912 | "bit.base-ui/utils/popper-js/ignore-popper-size@1.0.6": { 913 | "files": [ 914 | { 915 | "name": "ignore-popper-size.tsx", 916 | "relativePath": "src/utils/popper-js/ignore-popper-size/ignore-popper-size.tsx", 917 | "test": false 918 | }, 919 | { 920 | "name": "index.ts", 921 | "relativePath": "src/utils/popper-js/ignore-popper-size/index.ts", 922 | "test": false 923 | } 924 | ], 925 | "mainFile": "src/utils/popper-js/ignore-popper-size/index.ts", 926 | "trackDir": "src/utils/popper-js/ignore-popper-size", 927 | "origin": "AUTHORED", 928 | "exported": true 929 | }, 930 | "bit.base-ui/utils/popper-js/resize-to-match-reference@1.0.5": { 931 | "files": [ 932 | { 933 | "name": "index.ts", 934 | "relativePath": "src/utils/popper-js/resize-to-match-reference/index.ts", 935 | "test": false 936 | }, 937 | { 938 | "name": "resize-to-match-reference.tsx", 939 | "relativePath": "src/utils/popper-js/resize-to-match-reference/resize-to-match-reference.tsx", 940 | "test": false 941 | } 942 | ], 943 | "mainFile": "src/utils/popper-js/resize-to-match-reference/index.ts", 944 | "trackDir": "src/utils/popper-js/resize-to-match-reference", 945 | "origin": "AUTHORED", 946 | "exported": true 947 | }, 948 | "version": "14.8.0-dev.5" 949 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # bit 9 | dist 10 | 11 | # testing 12 | /coverage 13 | 14 | # production 15 | /build 16 | 17 | # misc 18 | .DS_Store 19 | .env.local 20 | .env.development.local 21 | .env.test.local 22 | .env.production.local 23 | 24 | yarn.lock 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "typescript", 3 | "semi": true, 4 | "printWidth": 96, 5 | "useTabs": true, 6 | "tabWidth": 4, 7 | "singleQuote": true, 8 | "trailingComma": "es5", 9 | "jsxBracketSameLine": false 10 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Bit - Distributed code component manager. 2 | 3 | Copyright (C) 2017 Cocycles LTD. 4 | 5 | Can be contacted at: team@bit.dev 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![bit components](https://img.shields.io/badge/dynamic/json.svg?color=6e3991&label=bit%20components&query=payload.totalComponents&url=https://api.bit.dev/scope/bit/base-ui?UseCache=1)](https://bit.dev/bit/base-ui) 2 | apache 3 | prs 4 | 5 | # Base component design system of Bit.dev 6 | 7 | The [reusable set of infra-level React components](https://bit.dev/bit/base-ui) 8 | used to build [Bit.dev](https://bit.dev). 9 | 10 | ![screenshot](./docs/scope-screenshot.png) 11 | 12 | 13 | ## Components 14 | 15 | All components in this frontend codebase were [contained and exposed using Bit](https://github.com/teambit/bit) as a set of independently-usable components. See the **[base collection on bit.dev](https://bit.dev/teambit/base-ui)** to explore and integrate any component into your project. 16 | 17 | - Install independent components with npm/yarn. 18 | - Use `bbit import` to source and edit components locally for quick editing and integration. 19 | - Try any component hands-on in a live playground. 20 | 21 | 22 | ## This is a component-based micro-frontend 23 | 24 | Wait.. what? 25 | 26 | - Install independent components with `bbit install` 27 | - Use `bbit import` to explore components in your local workspace and modify them to your own needs. 28 | - Try any component hands-on in the docs' live playground and in the 'compositions' page. 29 | 30 | ### Show me an example! 31 | 32 | Take a look at the [bit.dev homepage](https://bit.dev/). 33 | 34 | You will notice that it's built from components that live in different front-end codebases: 35 | 36 | - ["Evangelist" marketing components](https://github.com/teambit/evangelist). 37 | - [base-ui components](https://github.com/teambit/base-ui). 38 | - Container application (private). 39 | - etc 40 | 41 | We use [Bit](https://github.com/teambit/bit) to contain and expose components from any codebase as a set of APIs in [bit.dev](https://bit.dev) that can be integrated into different pages and applications. For example: 42 | 43 | - Exposed ["Evangelist" marketing components] on bit.dev. 44 | - Exposed [base-ui components on bit.dev](https://bit.dev/teambit/base-ui). 45 | 46 | 47 | ## Structure: 48 | 49 | ### Theme 50 | All shared styles, colors, sizes, fonts, and css variables, belong here. 51 | [Theme-provider](https://bit.dev/teambit/base-ui/theme/theme-provider) applies all of these styles at the root of your app, and different apps may implement their own unique theme. 52 | 53 | ### Constants 54 | Hard coded singleton values, like storage-url and enums. In case of change, this central location could update all other components. 55 | 56 | ### Layout 57 | Components controlling the position of elements in the document. (Grid, breakpoints, etc) 58 | 59 | ### Atoms 60 | Generic building blocks for any front end application. 61 | These components are 'vanilla', meaning they should not contain content (like texts or icons) and no specific styles. This is because different designs could look entirely different, so any styles in the base component could lead to a 'CSS Specificity War'. So, add the bare minimum of css here and keep these components purely logical! 62 | 63 | ### Utils 64 | Pure logic components and helpers. (no visual components) 65 | 66 | ## Setup 67 | 1. Install Bit: `npm install @teambit/bit --global` 68 | 2. Clone this Bit Workspace: `git clone https://github.com/teambit/evangelist.git evangelist` 69 | 3. Go to the workspace directory: `cd evangelist` 70 | 4. Install all packages and import all components: `bbit install` 71 | 5. Run the Workspace UI to explore the Evangalist components: `bbit start` and go to https://localhost:3000 72 | 6. Enjoy! 73 | -------------------------------------------------------------------------------- /docs/scope-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teambit/base-ui/268e0473497f15040a026dc2281faa8572217b0b/docs/scope-screenshot.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "base-ui", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "react-scripts start", 7 | "build": "react-scripts build", 8 | "test": "react-scripts test", 9 | "eject": "react-scripts eject" 10 | }, 11 | "eslintConfig": { 12 | "extends": "react-app" 13 | }, 14 | "browserslist": { 15 | "production": [ 16 | ">0.2%", 17 | "not dead", 18 | "not op_mini all" 19 | ], 20 | "development": [ 21 | "last 1 chrome version", 22 | "last 1 firefox version", 23 | "last 1 safari version" 24 | ] 25 | }, 26 | "dependencies": { 27 | "@bit/bit.base-ui.ellipsis": "^1.1.7", 28 | "@popperjs/core": "~2.3.3", 29 | "@testing-library/jest-dom": "^4.2.4", 30 | "@testing-library/react": "^9.3.2", 31 | "@testing-library/user-event": "^7.1.2", 32 | "classnames": "^2.2.6", 33 | "lodash.debounce": "^4.0.8", 34 | "node-sass": "^4.13.1", 35 | "number-abbreviate": "^2.0.0", 36 | "react": "^16.x.x", 37 | "react-create-ref": "^1.0.1", 38 | "react-dom": "^16.x.x", 39 | "react-onclickoutside": "^6.9.0", 40 | "react-scripts": "3.4.0", 41 | "react-slick": "^0.25.2", 42 | "reset-css": "^5.0.1", 43 | "resize-observer-polyfill": "^1.5.1", 44 | "typescript": "^3.8.3" 45 | }, 46 | "devDependencies": { 47 | "@types/chai": "^4.2.8", 48 | "@types/classnames": "^2.2.9", 49 | "@types/lodash.debounce": "^4.0.6", 50 | "@types/mocha": "^7.0.2", 51 | "@types/node": "^12.0.0", 52 | "@types/react": "^16.x.x", 53 | "@types/react-dom": "^16.x.x", 54 | "@types/react-onclickoutside": "^6.7.3", 55 | "@types/react-slick": "^0.23.4", 56 | "@types/sinon": "^7.5.1", 57 | "chai": "^4.2.0", 58 | "eslint-plugin-chai-friendly": "^0.5.0", 59 | "mocha": "^7.0.1", 60 | "sinon": "^8.1.1" 61 | }, 62 | "bit": { 63 | "env": { 64 | "compiler": "bit.envs/compilers/react-typescript@3.1.43", 65 | "tester": "bit.envs/testers/mocha@5.0.2" 66 | }, 67 | "componentsDefaultDirectory": "src/bit-components/{name}", 68 | "defaultScope": "bit.base-ui", 69 | "packageManager": "yarn", 70 | "overrides": { 71 | "*": { 72 | "dependencies": { 73 | "react": "-", 74 | "react-dom": "-" 75 | }, 76 | "devDependencies": { 77 | "@types/chai": "^4.2.8", 78 | "@types/sinon": "^7.5.1", 79 | "@types/mocha": "^5.0.0", 80 | "chai": "^4.2.0", 81 | "sinon": "^8.1.1" 82 | }, 83 | "env": { 84 | "compiler": { 85 | "bit.envs/compilers/react-typescript@3.1.43": { 86 | "rawConfig": { 87 | "tsconfig": { 88 | "compilerOptions": { 89 | "target": "ES5", 90 | "module": "CommonJS", 91 | "inlineSourceMap": true, 92 | "removeComments": false, 93 | "experimentalDecorators": true 94 | } 95 | } 96 | } 97 | } 98 | } 99 | } 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teambit/base-ui/268e0473497f15040a026dc2281faa8572217b0b/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teambit/base-ui/268e0473497f15040a026dc2281faa8572217b0b/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teambit/base-ui/268e0473497f15040a026dc2281faa8572217b0b/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import { expect } from 'chai'; 4 | 5 | import App from './App'; 6 | 7 | test('renders learn react link', () => { 8 | const { getByText } = render(); 9 | const linkElement = getByText(/learn react/i); 10 | expect(linkElement).that.exist; 11 | }); 12 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | 5 | function App() { 6 | return ( 7 |
8 |
9 | logo 10 |

11 | Edit src/App.tsx and save to reload. 12 |

13 | 19 | Learn React 20 | 21 |
22 |
23 | ); 24 | } 25 | 26 | export default App; 27 | -------------------------------------------------------------------------------- /src/constants/sizes.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Preset sizes enum, used across the application 4 | * @name PossibleSizes 5 | * @example 6 | * 7 | */ 8 | 9 | export enum PossibleSizes { 10 | xxs = "xxs", 11 | xs = "xs", 12 | sm = "sm", 13 | md = "md", 14 | lg = "lg", 15 | xl = "xl", 16 | xxl = "xxl" 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/constants/storage/_storage.module.scss: -------------------------------------------------------------------------------- 1 | $staticStorageUrl: 'https://static.bit.dev'; 2 | // or... uncached for dev: 3 | // $staticStorageUrl: 'https://storage.cloud.google.com/static.bit.dev'; 4 | 5 | :export { 6 | staticStorageUrl: $staticStorageUrl 7 | } -------------------------------------------------------------------------------- /src/constants/storage/index.ts: -------------------------------------------------------------------------------- 1 | import definitions from './_storage.module.scss'; 2 | 3 | /** 4 | * Provides constant url for images CDN. 5 | * @example 6 | * //in ts/js file: 7 | * 8 | * @example 9 | * //in scss file: 10 | * background-image: url($staticStorageUrl + '/some/image.svg'); 11 | */ 12 | 13 | export const staticStorageUrl = definitions.staticStorageUrl.replace(/["']/g, ''); 14 | -------------------------------------------------------------------------------- /src/css-components/elevation/elevation-height.ts: -------------------------------------------------------------------------------- 1 | export type ElevationHeight = 'low' | 'medium' | 'high' | 'none'; 2 | -------------------------------------------------------------------------------- /src/css-components/elevation/elevations.module.scss: -------------------------------------------------------------------------------- 1 | .low { 2 | box-shadow: var(--shadow-hover-low); 3 | } 4 | .medium { 5 | box-shadow: var(--shadow-hover-medium); 6 | } 7 | .high { 8 | box-shadow: var(--shadow-hover-high); 9 | } -------------------------------------------------------------------------------- /src/css-components/elevation/index.ts: -------------------------------------------------------------------------------- 1 | import { ElevationHeight } from './elevation-height'; 2 | import styles from './elevations.module.scss'; 3 | export * from './elevation-height'; 4 | 5 | export const elevationClass: { [key in ElevationHeight]: string | undefined } = { 6 | low: styles.low, 7 | medium: styles.medium, 8 | high: styles.high, 9 | none: undefined, 10 | }; 11 | -------------------------------------------------------------------------------- /src/css-components/pill/index.ts: -------------------------------------------------------------------------------- 1 | import styles from './pill.module.scss'; 2 | 3 | /** 4 | * Tried and tested pure css pill component. 5 | * Add border-radius to dom elements in a safe and predicable way. 6 | * The component also inclues `overflow: hidden` to prevent artifacts and border issues when zoomed out. 7 | * 8 | * @example 9 | *
this is a pill
10 | */ 11 | export const pillClass = styles.pill; 12 | -------------------------------------------------------------------------------- /src/css-components/pill/pill.module.scss: -------------------------------------------------------------------------------- 1 | .pill { 2 | border-radius: 11px / 50%; 3 | overflow: hidden; 4 | } -------------------------------------------------------------------------------- /src/css-components/roundness/index.ts: -------------------------------------------------------------------------------- 1 | import styles from './roundness.module.scss'; 2 | import { Roundness } from './roundness-values'; 3 | export * from './roundness-values'; 4 | 5 | export const roundnessClass: { [key in Roundness]: string } = { 6 | circle: styles.circle, 7 | default: styles.default, 8 | medium: styles.medium, 9 | sharp: styles.sharp, 10 | }; 11 | -------------------------------------------------------------------------------- /src/css-components/roundness/roundness-values.ts: -------------------------------------------------------------------------------- 1 | export type Roundness = 'sharp' | 'default' | 'medium' | 'circle'; 2 | -------------------------------------------------------------------------------- /src/css-components/roundness/roundness.module.scss: -------------------------------------------------------------------------------- 1 | .sharp { 2 | border-radius: 2px; 3 | } 4 | 5 | .default { 6 | border-radius: 5px; 7 | } 8 | 9 | .medium { 10 | border-radius: 10px; 11 | } 12 | 13 | .circle { 14 | border-radius: 50%; 15 | } -------------------------------------------------------------------------------- /src/effects/ref-tooltip/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ref-tooltip'; 2 | -------------------------------------------------------------------------------- /src/effects/ref-tooltip/ref-tooltip.module.scss: -------------------------------------------------------------------------------- 1 | .tooltipWrapper { 2 | //provides an 'interactive border' 3 | //where the user can mouse over without losing tooltip 4 | padding: 4px 9px 9px 9px; 5 | } -------------------------------------------------------------------------------- /src/effects/ref-tooltip/ref-tooltip.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import classNames from 'classnames'; 3 | import { createPopper, Instance, Options } from '@popperjs/core'; 4 | //@ts-ignore 5 | import createRef from 'react-create-ref'; 6 | 7 | import styles from './ref-tooltip.module.scss'; 8 | 9 | export type RefTooltipProps = { 10 | /** dom element to attach to */ 11 | targetElement?: HTMLElement, 12 | /** options for the underlying Popper.js position engine */ 13 | popperOptions?: Partial, 14 | /** Actively recalculate position, to support moving elements */ 15 | motionTracking?: boolean, 16 | } & React.HTMLAttributes; 17 | 18 | /** 19 | * A [Popper.js](https://popper.js.org/) react wrapper that repositions children to be adjacent to a target element. 20 | * This component is a container only, with no visual styling. 21 | * 22 | * @example 23 | * 24 | * I will show up next to the element! 25 | * 26 | */ 27 | export class RefTooltip extends Component { 28 | ref: any = createRef(); 29 | popperInstance: Instance | undefined; 30 | 31 | componentWillUnmount() { 32 | this.destroy(); 33 | } 34 | 35 | componentDidUpdate(prevProps: RefTooltipProps) { 36 | const nextProps = this.props; 37 | 38 | if (prevProps.targetElement !== nextProps.targetElement) { 39 | this.reposition(nextProps.targetElement); 40 | } 41 | } 42 | 43 | reposition = (targetElement?: HTMLElement) => { 44 | const { popperOptions = popperDefaultOptions } = this.props; 45 | const popperElement = this.ref.current; 46 | 47 | if (!targetElement) { 48 | this.destroy(); 49 | } 50 | 51 | if (!targetElement || !popperElement) return; 52 | 53 | this.popperInstance = createPopper(targetElement, popperElement, popperOptions); 54 | 55 | window.requestAnimationFrame(this.step); 56 | }; 57 | 58 | private step = () => { 59 | if (!this.popperInstance || !this.props.motionTracking) return; 60 | 61 | this.popperInstance.update(); 62 | window.requestAnimationFrame(this.step); 63 | }; 64 | 65 | destroy = () => { 66 | if (!this.popperInstance) return; 67 | 68 | this.popperInstance.destroy(); 69 | this.popperInstance = undefined; 70 | }; 71 | 72 | render() { 73 | const { className, targetElement, popperOptions, motionTracking, ...rest } = this.props; 74 | return ( 75 |
81 | ); 82 | } 83 | } 84 | 85 | const popperDefaultOptions: Partial = { 86 | placement: 'top', 87 | modifiers: [ 88 | { 89 | name: 'flip', 90 | enabled: false, 91 | }, 92 | ], 93 | }; 94 | -------------------------------------------------------------------------------- /src/elements/dots-loader/dots-loader.module.scss: -------------------------------------------------------------------------------- 1 | $blinkMs: 185ms; 2 | $exaggeratedMs: 1270ms; 3 | 4 | .dotsLoader { 5 | letter-spacing: 0.6em; 6 | text-indent: 0.6em; 7 | 8 | > * { 9 | animation: $exaggeratedMs infinite ease-in-out both; 10 | animation-name: scale-down; 11 | display: inline-block; 12 | 13 | &:nth-child(1) { 14 | animation-delay: -$blinkMs * 2; 15 | } 16 | &:nth-child(2) { 17 | animation-delay: -$blinkMs; 18 | } 19 | } 20 | } 21 | 22 | @keyframes scale-down { 23 | 0%, 24 | 20%, 25 | 100% { 26 | transform: scale(0); 27 | } 28 | 29 | 60% { 30 | transform: scale(1); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/elements/dots-loader/dots-loader.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | 4 | import styles from './dots-loader.module.scss'; 5 | 6 | type LoaderProps = React.HTMLAttributes; 7 | 8 | export function DotsLoader({ className, ...rest }: LoaderProps) { 9 | return ( 10 | 11 | 12 | 13 | 14 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src/elements/dots-loader/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dots-loader'; -------------------------------------------------------------------------------- /src/elements/icon/base-icon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classnames from 'classnames'; 3 | 4 | export type BaseIconProps = { 5 | /** 6 | * icon id (class name) 7 | */ 8 | of: string; 9 | } & React.HTMLAttributes; 10 | 11 | /** 12 | * Base template component for icons. 13 | * Compose this class to make a specific icon component for a font-set, like [bit-icon](https://bit.dev/bit/evangelist/atom/bit-icon). 14 | * @example 15 | * const iconset = "eva-icons"; 16 | * const EvaButton = (props) => ; 17 | */ 18 | export function BaseIcon({ of: iconName, className, ...rest }: BaseIconProps) { 19 | return ; 24 | } 25 | -------------------------------------------------------------------------------- /src/elements/icon/index.ts: -------------------------------------------------------------------------------- 1 | export * from './base-icon'; 2 | -------------------------------------------------------------------------------- /src/elements/image/image.module.scss: -------------------------------------------------------------------------------- 1 | .image { 2 | 3 | } 4 | 5 | .fullWidth { 6 | width: 100%; 7 | } -------------------------------------------------------------------------------- /src/elements/image/image.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import { expect } from 'chai'; 4 | 5 | import { BaseImage } from './image'; 6 | 7 | it('should render', () => { 8 | const { getByTestId } = render( 9 | 10 | ); 11 | const rendered = getByTestId('test-img'); 12 | 13 | expect(rendered.tagName).to.equal('IMG'); 14 | expect(rendered.getAttribute('alt')).to.equal('alt world'); 15 | expect(rendered.getAttribute('src')).to.equal('https://bit.dev'); 16 | }); 17 | 18 | it('should pass classname', () => { 19 | const { getByTestId } = render( 20 | 21 | ); 22 | const rendered = getByTestId('test-img'); 23 | 24 | expect(rendered.className).to.include('testclass'); 25 | }); 26 | -------------------------------------------------------------------------------- /src/elements/image/image.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import styles from './image.module.scss'; 4 | 5 | export type BaseImageProps = { 6 | /** 7 | * alt text (to comply a11y standards) 8 | */ 9 | alt: string; 10 | /** 11 | * Makes image fill the whole width of container. 12 | * same as `width: 100%` 13 | */ 14 | fullWidth?: boolean; 15 | } & React.ImgHTMLAttributes; 16 | 17 | /** 18 | * Template component for images. 19 | * Accepts all the arguments of native html image. 20 | * @example 21 | * 22 | */ 23 | export function BaseImage({ alt, className, fullWidth, ...rest }: BaseImageProps) { 24 | return ( 25 | {alt} 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /src/elements/image/index.ts: -------------------------------------------------------------------------------- 1 | export * from './image'; -------------------------------------------------------------------------------- /src/elements/label/index.tsx: -------------------------------------------------------------------------------- 1 | export * from "./label"; 2 | -------------------------------------------------------------------------------- /src/elements/label/label.module.scss: -------------------------------------------------------------------------------- 1 | .label { 2 | display: flex; 3 | 4 | justify-content: center; 5 | align-items: center; 6 | 7 | border-radius: 6px; 8 | max-width: var(--primary-label-width, 50px); 9 | width: 100%; 10 | height: var(--primary-label-height, 30px); 11 | padding: 0 15px; 12 | 13 | font-size: 12px; 14 | font-weight: bold; 15 | 16 | background-color: var(--base-color, #6c5ce7); 17 | color: var(--primary-label-text, white); 18 | } -------------------------------------------------------------------------------- /src/elements/label/label.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import { expect } from 'chai'; 4 | 5 | import { Label } from './label'; 6 | 7 | it('should render correct text in Label', () => { 8 | const { getByText } = render(); 9 | const rendered = getByText('label'); 10 | expect(rendered).to.exist; 11 | }); 12 | 13 | it('should apply background color', () => { 14 | const { getByText } = render(); 15 | const rendered = getByText('label'); 16 | 17 | const styles = window.getComputedStyle(rendered); 18 | 19 | expect(styles.background).to.equal('blue'); 20 | }); 21 | -------------------------------------------------------------------------------- /src/elements/label/label.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import styles from './label.module.scss'; 4 | 5 | export type LabelProps = { 6 | /** 7 | * override label background color 8 | */ 9 | color?: string; 10 | } & React.HTMLAttributes; 11 | 12 | /** 13 | * Short text block with background. 14 | * 15 | * ### CSS variables: 16 | * The following variables apply to this component 17 | * - `--base-color` (background color) 18 | * - `--primary-label-text` (text color) 19 | * - `--primary-label-width` (max-width) 20 | * - `--primary-label-height` (height) 21 | */ 22 | export function Label({ color, className, ...rest }: LabelProps) { 23 | return ( 24 |
30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /src/elements/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | -------------------------------------------------------------------------------- /src/elements/link/link.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export type LinkProps = { 4 | /** 5 | * opens link in a new tab 6 | */ 7 | external?: boolean; 8 | } & React.AnchorHTMLAttributes; 9 | 10 | /** 11 | * Base component for link, equivalent to a `` tag. 12 | * 13 | * This component is a placeholder for future implementations, 14 | * where different applications can override this component with their underlying navigation system. 15 | */ 16 | export function Link(props: LinkProps) { 17 | const { external, children, ...rest } = props; 18 | 19 | const externalProps = external ? { rel: 'noopener', target: '_blank' } : {}; 20 | 21 | return ( 22 | 23 | {children} 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /src/elements/separator/index.tsx: -------------------------------------------------------------------------------- 1 | export { Separator } from "./separator"; 2 | -------------------------------------------------------------------------------- /src/elements/separator/separator.module.scss: -------------------------------------------------------------------------------- 1 | .separator { 2 | border-bottom: 1px solid var(--separator-color, #ededed); 3 | width: 100%; 4 | } 5 | 6 | .vertical { 7 | width: 1px; 8 | height: 100%; 9 | border-bottom-width: 0px; 10 | border-right: 1px solid var(--separator-color, #ededed); 11 | } -------------------------------------------------------------------------------- /src/elements/separator/separator.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import { expect } from 'chai'; 4 | 5 | import { Separator } from './separator'; 6 | 7 | it('should render', () => { 8 | const { getByTestId } = render(); 9 | const rendered = getByTestId('test-sep'); 10 | 11 | expect(rendered).to.exist; 12 | }); 13 | 14 | it('should pass classname', () => { 15 | const { getByTestId } = render(); 16 | const rendered = getByTestId('test-sep'); 17 | 18 | expect(rendered.className).to.include('separata'); 19 | }); 20 | 21 | // css-modules tests are not available in mocha yet 22 | 23 | // it('should be horizontal by default', () => { 24 | // const { getByTestId } = render(); 25 | // const rendered = getByTestId('test-sep'); 26 | 27 | // expect(rendered.className).to.include('horizontal'); 28 | // }); 29 | 30 | // it('should be vertical when set', () => { 31 | // const { getByTestId } = render( 32 | // 33 | // ); 34 | // const rendered = getByTestId('test-sep'); 35 | 36 | // expect(rendered.className).to.include('vertical'); 37 | // }); 38 | -------------------------------------------------------------------------------- /src/elements/separator/separator.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import styles from './separator.module.scss'; 4 | 5 | export type SeparatorProps = { 6 | /** 7 | * set as vertical / horizontal separator 8 | */ 9 | layout: 'vertical' | 'horizontal', 10 | } & React.HTMLAttributes; 11 | 12 | /** 13 | * Separating line. 14 | * 15 | * Use these implicit CSS variables to style: 16 | * - `--separator-color` 17 | * @name Separator 18 | * @example 19 | * 20 | */ 21 | export function Separator({ layout, className, ...rest }: SeparatorProps) { 22 | return ( 23 |
28 | ); 29 | } 30 | 31 | Separator.defaultProps = { 32 | layout: 'horizontal', 33 | }; 34 | -------------------------------------------------------------------------------- /src/geometry/curve-peek/curve-peek.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | 4 | import fillingStyle from './filling.module.scss'; 5 | 6 | type PossibleFilling = 'none' | 'white' | 'cloud'; 7 | 8 | export type SemicircleProps = { 9 | /** Select the color for the curve background. */ 10 | filling: PossibleFilling; 11 | } & React.SVGProps; 12 | 13 | /** 14 | * An SVG component shaped like a parabola. Useful for separating two sections.
15 | * Being an html element, this component is very light and don't require an additional network request.
16 | * 17 | * The component comes with 2 predefined colors, 'white' and 'cloud'.
18 | * To use a custom color, set fillings to be "none", and apply the color with a css rule, e.g. `{ filling: '#7f1ae5' }` 19 | * @name CurvePeek 20 | */ 21 | export function CurvePeek(props: SemicircleProps) { 22 | const { className, filling, ...rest } = props; 23 | 24 | return ( 25 | 31 | 36 | 37 | ); 38 | } 39 | 40 | CurvePeek.defaultProps = { 41 | filling: 'white', 42 | }; 43 | -------------------------------------------------------------------------------- /src/geometry/curve-peek/filling.module.scss: -------------------------------------------------------------------------------- 1 | @import '~@bit/bit.base-ui.theme.colors'; 2 | 3 | .white { 4 | fill: white; 5 | } 6 | 7 | .cloud { 8 | fill: $w20; 9 | } 10 | -------------------------------------------------------------------------------- /src/geometry/curve-peek/indext.ts: -------------------------------------------------------------------------------- 1 | export * from './curve-peek'; -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want your app to work offline and load faster, you can change 15 | // unregister() to register() below. Note this comes with some pitfalls. 16 | // Learn more about service workers: https://bit.ly/CRA-PWA 17 | serviceWorker.unregister(); 18 | -------------------------------------------------------------------------------- /src/input/button/button.module.scss: -------------------------------------------------------------------------------- 1 | .vanillaButton { 2 | transition: all 180ms ease-in-out; 3 | 4 | user-select: none; 5 | cursor: pointer; 6 | } 7 | -------------------------------------------------------------------------------- /src/input/button/button.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, fireEvent, waitForElementToBeRemoved } from '@testing-library/react'; 3 | import { expect } from 'chai'; 4 | import { fake } from 'sinon'; 5 | 6 | import Button from './button'; 7 | 8 | const testLoader = loading...; 9 | 10 | it('should render with children', () => { 11 | const { getByText } = render(); 12 | const rendered = getByText('actual button'); 13 | expect(rendered).to.exist; 14 | }); 15 | 16 | it('should trigger onClick', () => { 17 | const onClick = fake(); 18 | const { getByText } = render(); 19 | const rendered = getByText('actual button'); 20 | 21 | //could use userEvents.click(), in @testing-library/user-event 22 | fireEvent.click(rendered); 23 | 24 | expect(onClick.called).to.be.true; 25 | }); 26 | 27 | it('should remove loader after onClick has been resolved', async () => { 28 | let resolveClick = () => {}; 29 | const onClick = () => new Promise(res => (resolveClick = res)); 30 | const { getByTestId, queryByTestId } = render( 31 | ); 67 | 68 | expect(queryByText('actual children')).not.to.exist; 69 | }); 70 | 71 | it('should remove loader when changing loading back to ={false}', () => { 72 | const { queryByTestId, rerender } = render( 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/input/button/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './button'; 2 | export * from './button'; 3 | -------------------------------------------------------------------------------- /src/input/error/error.module.scss: -------------------------------------------------------------------------------- 1 | .error { 2 | color: var(--error-color, #e62e5c); 3 | } 4 | -------------------------------------------------------------------------------- /src/input/error/error.tsx: -------------------------------------------------------------------------------- 1 | import React, { HTMLAttributes } from 'react'; 2 | import classNames from 'classnames'; 3 | import styles from './error.module.scss'; 4 | 5 | /** 6 | * Shows an error message. Avoids rendering when prop `children` is empty.
7 | * 8 | * Uses error color from css variable `--error-color` 9 | * @name Error 10 | */ 11 | export function Error(props: HTMLAttributes) { 12 | const { className, children, ...rest } = props; 13 | if (!children) return null; 14 | 15 | return
{children}
; 16 | } 17 | -------------------------------------------------------------------------------- /src/input/error/index.ts: -------------------------------------------------------------------------------- 1 | export * from './error'; 2 | -------------------------------------------------------------------------------- /src/layout/_breakpoints.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Preset breakpoints for the whole app. 3 | * 4 | * Use `(min-width: xxx)` to keep a consistent mobile-first experience (and not `max-width`). 5 | * 6 | * ```scss 7 | * $br-xs: 360px; 8 | * $br-sm: 480px; //mobile 9 | * $br-md: 768px; 10 | * $br-l: 920px; //tablet 11 | * $br-lg-new: 1200px; //laptop 12 | * $br-xl: 1440px; 13 | * $br-xxl: 1920px; 14 | * ``` 15 | * 16 | * ## example 17 | * ```scss 18 | * .content @media screen and (min-width: $br-l) { 19 | * display: flex; 20 | * } 21 | * ``` 22 | */ 23 | 24 | $br-xs: 360px; 25 | $br-sm: 480px; //mobile 26 | $br-md: 768px; 27 | $br-l: 920px; //tablet 28 | // $br-lg: 1080px; //(this is being phased out) 29 | $br-lg: 1200px; 30 | $br-xl: 1440px; 31 | $br-xxl: 1920px; -------------------------------------------------------------------------------- /src/layout/align/README.md: -------------------------------------------------------------------------------- 1 | ## Align 2 | 3 | A set of CSS components to align elements. 4 | 5 | ### text 6 | 7 | Same as css property text-align. 8 | 9 | ```tsx 10 | import { text } from '@bit/bit.base-ui.layout.align'; 11 | function A() { 12 | return
a
; 13 | } 14 | ``` 15 | 16 | ### Breakpoints 17 | 18 | Align elements according to html breakpoints. 19 | 20 | ```tsx 21 | import { text } from '@bit/bit.base-ui.layout.align'; 22 | function B() { 23 | return
24 | b 25 |
26 | } 27 | ``` 28 | 29 | ### Margin center 30 | 31 | Same as `margin-left: auto; margin-right: auto`. 32 | 33 | ```tsx 34 | import { marginCenter } from '@bit/bit.base-ui.layout.align'; 35 | 36 | function C() { 37 | return
this is centered
; 38 | } 39 | ``` 40 | 41 | ## Breakpoints: 42 | - (default) `(all)` 43 | - xs `360px` 44 | - sm `480px` 45 | - md `768px` 46 | - l `920px` 47 | - lg `1080px` 48 | - xl `1440px` 49 | -------------------------------------------------------------------------------- /src/layout/align/align.module.scss: -------------------------------------------------------------------------------- 1 | @import '../_breakpoints.scss'; 2 | 3 | $breakpoints: //name val 4 | xs $br-xs, 5 | sm $br-sm, 6 | md $br-md, 7 | l $br-l, 8 | lg $br-lg, 9 | xl $br-xl; 10 | 11 | .fullWidth { 12 | width: 100%; 13 | box-sizing: border-box; 14 | } 15 | 16 | .text { 17 | &-left { 18 | text-align: left; 19 | } 20 | 21 | &-center { 22 | text-align: center; 23 | } 24 | 25 | &-right { 26 | text-align: right; 27 | } 28 | @each $breakpoint in $breakpoints { 29 | $brName: nth($breakpoint, 1); 30 | $brVal: nth($breakpoint, 2); 31 | @media only screen and (min-width: $brVal) { 32 | &-#{$brName} { 33 | &-left { 34 | text-align: left; 35 | } 36 | 37 | &-center { 38 | text-align: center; 39 | } 40 | 41 | &-right { 42 | text-align: right; 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | 50 | .justifyItems { 51 | &-left { 52 | justify-items: left; 53 | } 54 | 55 | &-center { 56 | justify-items: center; 57 | } 58 | 59 | &-right { 60 | justify-items: right; 61 | } 62 | } 63 | 64 | .alignItems { 65 | &-start { 66 | align-items: start; 67 | } 68 | 69 | &-center { 70 | align-items: center; 71 | } 72 | 73 | &-end { 74 | align-items: end; 75 | } 76 | } 77 | 78 | //TODO - rename justifySelf and add alignSelf 79 | .self { 80 | &-left { 81 | justify-self: left; 82 | } 83 | 84 | &-center { 85 | justify-self: center; 86 | } 87 | 88 | &-right { 89 | justify-self: right; 90 | } 91 | } 92 | 93 | .marginCenter { 94 | margin-right: auto; 95 | margin-left: auto; 96 | } -------------------------------------------------------------------------------- /src/layout/align/index.ts: -------------------------------------------------------------------------------- 1 | import styles from './align.module.scss'; 2 | 3 | enum BreakPoints { 4 | xs = 'xs', 5 | sm = 'sm', 6 | md = 'md', 7 | l = 'l', 8 | lg = 'lg', 9 | xl = 'xl', 10 | } 11 | 12 | type TextOptions = { 13 | left: string; 14 | center: string; 15 | right: string; 16 | }; 17 | 18 | type TextProps = { 19 | left: string; 20 | center: string; 21 | right: string; 22 | 23 | xs: TextOptions; 24 | sm: TextOptions; 25 | md: TextOptions; 26 | l: TextOptions; 27 | lg: TextOptions; 28 | xl: TextOptions; 29 | }; 30 | 31 | export const fullWidth = styles.fullWidth; 32 | 33 | export const text = (() => { 34 | const baseStyle = { 35 | left: styles['text-left'], 36 | center: styles['text-center'], 37 | right: styles['text-right'], 38 | }; 39 | 40 | const medias = Object.keys(BreakPoints) 41 | .map(br => ({ 42 | [br]: { 43 | left: styles[`text-${br}-left`], 44 | center: styles[`text-${br}-center`], 45 | right: styles[`text-${br}-right`], 46 | }, 47 | })) 48 | .reduce((prev, next) => Object.assign(prev, next), {}); 49 | 50 | return { 51 | ...baseStyle, 52 | ...medias, 53 | } as TextProps; 54 | })(); 55 | 56 | export const marginCenter = styles.marginCenter; 57 | 58 | //consider moving this logic to 59 | export const justifyItems = { 60 | left: styles['justifyItems-left'], 61 | center: styles['justifyItems-center'], 62 | right: styles['justifyItems-right'], 63 | }; 64 | 65 | export const alignItems = { 66 | start: styles['alignItems-start'], 67 | center: styles['alignItems-center'], 68 | end: styles['alignItems-end'], 69 | }; 70 | -------------------------------------------------------------------------------- /src/layout/col-span/README.md: -------------------------------------------------------------------------------- 1 | ## Column Span 2 | 3 | Preset columns spans, for a 12-column CSS-grid. 4 | 5 | ```tsx 6 | import { colSpan } from '@bit/bit.base-ui.layout.col-span'; 7 | 8 | //... 9 | 10 | return
I'm taking up 3/4 of the line
; 11 | ``` 12 | 13 | ## Responsive presets: 14 | 15 | ```tsx 16 | import { colSpanL, colSpan } from '@bit/bit.base-ui.layout.col-span'; 17 | 18 | //... 19 | 20 |
I'm taking up 3/4 of the line
; 21 | ``` 22 | 23 | ## breakpoints: 24 | 25 | - colSpan `(all)` 26 | - colSpanXs `360px` 27 | - colSpanSm `480px` 28 | - colSpanMd `768px` 29 | - colSpanL `920px` 30 | - colSpanLg `1080px` 31 | - colSpanXl `1440px` 32 | -------------------------------------------------------------------------------- /src/layout/col-span/col-span.module.scss: -------------------------------------------------------------------------------- 1 | @import '../_breakpoints.scss'; 2 | 3 | $breakpoints: //name val 4 | xs $br-xs, 5 | sm $br-sm, 6 | md $br-md, 7 | l $br-l, 8 | lg $br-lg, 9 | // lg $br-lg, 10 | xl $br-xl; 11 | 12 | 13 | @for $i from 1 through 12 { 14 | @each $breakpoint in $breakpoints { 15 | $brName: nth($breakpoint, 1); 16 | $brVal: nth($breakpoint, 2); 17 | 18 | @media only screen and (min-width: $brVal) { 19 | .colSpan { 20 | &--#{$brName}-#{$i} { 21 | grid-column-end: span $i; 22 | } 23 | } 24 | } 25 | } 26 | 27 | .colSpan { 28 | &---#{$i} { 29 | grid-column-end: span $i; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/layout/col-span/index.ts: -------------------------------------------------------------------------------- 1 | import { makeSpans } from './make-spans'; 2 | 3 | export const colSpan = makeSpans(); 4 | export const colSpanXs = makeSpans('xs'); 5 | export const colSpanSm = makeSpans('sm'); 6 | export const colSpanMd = makeSpans('md'); 7 | export const colSpanL = makeSpans('l'); 8 | export const colSpanLg = makeSpans('lg'); 9 | export const colSpanXl = makeSpans('xl'); 10 | -------------------------------------------------------------------------------- /src/layout/col-span/make-spans.ts: -------------------------------------------------------------------------------- 1 | import styles from './col-span.module.scss'; 2 | 3 | type ColSpans = { 4 | 1: string; 5 | 2: string; 6 | 3: string; 7 | 4: string; 8 | 5: string; 9 | 6: string; 10 | 7: string; 11 | 8: string; 12 | 9: string; 13 | 10: string; 14 | 11: string; 15 | 12: string; 16 | }; 17 | 18 | export function makeSpans(breakPoints: string = ''): ColSpans { 19 | const obj: any = {}; 20 | 21 | for (var i = 1; i <= 12; i++) { 22 | obj[i] = styles[`colSpan--${breakPoints}-${i}`]; 23 | } 24 | 25 | return obj; 26 | } 27 | -------------------------------------------------------------------------------- /src/layout/grid-component/README.md: -------------------------------------------------------------------------------- 1 | ## Grid Component 2 | 3 | Basic grid element for 1-12 columns. 4 | Accepts all props of native html div element. 5 | 6 | ```tsx 7 | import { grid } from '@bit/bit.base-ui.layout.grid-component'; 8 | 9 | //... 10 | 11 | 12 |
column 1
13 |
column 2
14 |
; 15 | ``` 16 | 17 | It has built in responsive support, using it's `colX` props: 18 | 19 | ```tsx 20 | //single column by default, 2 columns for large screens: 21 | 22 |
column 1
23 |
column 2
24 |
25 | ``` 26 | 27 | ### breakpoints: 28 | 29 | - col `(all)` 30 | - colXs `360px` 31 | - colSm `480px` 32 | - colMd `768px` 33 | - colL `920px` 34 | - colLg `1080px` 35 | - colXl `1440px` 36 | -------------------------------------------------------------------------------- /src/layout/grid-component/grid-template/grid-template.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../_breakpoints.scss'; 2 | 3 | $breakpoints: //name val 4 | xs $br-xs, 5 | sm $br-sm, 6 | md $br-md, 7 | l $br-l, 8 | lg $br-lg, 9 | // lg $br-lg, 10 | xl $br-xl; 11 | 12 | 13 | @for $i from 1 through 12 { 14 | @each $breakpoint in $breakpoints { 15 | $brName: nth($breakpoint, 1); 16 | $brVal: nth($breakpoint, 2); 17 | 18 | @media only screen and (min-width: $brVal) { 19 | .colTemplate { 20 | &--#{$brName}-#{$i} { 21 | grid-template-columns: repeat($i, 1fr); 22 | } 23 | } 24 | } 25 | } 26 | 27 | .colTemplate { 28 | &--all-#{$i} { 29 | grid-template-columns: repeat($i, 1fr); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/layout/grid-component/grid-template/index.ts: -------------------------------------------------------------------------------- 1 | import styles from './grid-template.module.scss'; 2 | 3 | type ColumnPreset = { 4 | 1: string; 5 | 2: string; 6 | 3: string; 7 | 4: string; 8 | 5: string; 9 | 6: string; 10 | 7: string; 11 | 8: string; 12 | 9: string; 13 | 10: string; 14 | 11: string; 15 | 12: string; 16 | }; 17 | 18 | export const colGrid = makePreset('all'); 19 | export const colGridXs = makePreset('xs'); 20 | export const colGridSm = makePreset('sm'); 21 | export const colGridMd = makePreset('md'); 22 | export const colGridL = makePreset('l'); 23 | export const colGridLg = makePreset('lg'); 24 | export const colGridXl = makePreset('xl'); 25 | 26 | function makePreset(breakPoints: string): ColumnPreset { 27 | const obj: any = {}; 28 | 29 | for (var i = 1; i <= 12; i++) { 30 | obj[i] = styles[`colTemplate--${breakPoints}-${i}`]; 31 | } 32 | 33 | return obj; 34 | } 35 | -------------------------------------------------------------------------------- /src/layout/grid-component/grid.module.scss: -------------------------------------------------------------------------------- 1 | .gridContainer { 2 | display: grid; 3 | grid-gap: 16px 16px; 4 | } 5 | 6 | -------------------------------------------------------------------------------- /src/layout/grid-component/grid.tsx: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import classNames from 'classnames'; 3 | import styles from './grid.module.scss'; 4 | 5 | import { 6 | colGrid, 7 | colGridL, 8 | colGridLg, 9 | colGridMd, 10 | colGridSm, 11 | colGridXl, 12 | colGridXs, 13 | } from './grid-template'; 14 | 15 | type ColCount = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; 16 | 17 | type GridProps = { 18 | /** 19 | * default column count (1-12) 20 | */ 21 | col?: ColCount, 22 | /** 23 | * column count at extremely small devices 24 | */ 25 | colXs?: ColCount, 26 | /** 27 | * column count at mobile screens 28 | */ 29 | colSm?: ColCount, 30 | /** 31 | * column count at medium devices 32 | */ 33 | colMd?: ColCount, 34 | /** 35 | * column count at tablets 36 | */ 37 | colL?: ColCount, 38 | /** 39 | * default column count at laptops 40 | */ 41 | colLg?: ColCount, 42 | /** 43 | * default column count at desktop 44 | */ 45 | colXl?: ColCount, 46 | } & React.HTMLAttributes; 47 | 48 | /** 49 | * A responsive css-grid wrapper. 50 | * Use the `col` properties to set column count in each resolution. 51 | */ 52 | 53 | export class Grid extends PureComponent { 54 | render() { 55 | const { className, col, colL, colLg, colMd, colSm, colXl, colXs, ...rest } = this.props; 56 | 57 | const classes = [className, styles.gridContainer]; 58 | 59 | //yup, it's dirty, but it does exactly what it is supposed to do. 60 | // don't abuse it 61 | 62 | if (col !== undefined) classes.push(colGrid[col]); 63 | if (colL !== undefined) classes.push(colGridL[colL]); 64 | if (colLg !== undefined) classes.push(colGridLg[colLg]); 65 | if (colMd !== undefined) classes.push(colGridMd[colMd]); 66 | if (colSm !== undefined) classes.push(colGridSm[colSm]); 67 | if (colXl !== undefined) classes.push(colGridXl[colXl]); 68 | if (colXs !== undefined) classes.push(colGridXs[colXs]); 69 | 70 | return ( 71 |
76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/layout/grid-component/index.ts: -------------------------------------------------------------------------------- 1 | export * from './grid'; 2 | -------------------------------------------------------------------------------- /src/layout/grid-presets/four-way-grid/four-way-grid.module.scss: -------------------------------------------------------------------------------- 1 | @import "../../_breakpoints.scss"; 2 | 3 | .fourWayGrid { 4 | display: grid; 5 | 6 | grid-template-columns: 1fr; 7 | grid-template-rows: repeat(3, auto auto 50px) auto auto; 8 | 9 | grid-template-areas: 10 | "txt1" 11 | "img1" 12 | "." 13 | "txt2" 14 | "img2" 15 | "." 16 | "txt3" 17 | "img3" 18 | "." 19 | "txt4" 20 | "img4"; 21 | 22 | &>:nth-child(1) { 23 | grid-area: txt1; 24 | } 25 | 26 | &>:nth-child(2) { 27 | grid-area: img1; 28 | } 29 | 30 | &>:nth-child(3) { 31 | grid-area: txt2; 32 | } 33 | 34 | &>:nth-child(4) { 35 | grid-area: img2; 36 | } 37 | 38 | &>:nth-child(5) { 39 | grid-area: txt3; 40 | } 41 | 42 | &>:nth-child(6) { 43 | grid-area: img3; 44 | } 45 | 46 | &>:nth-child(7) { 47 | grid-area: txt4; 48 | } 49 | 50 | &>:nth-child(8) { 51 | grid-area: img4; 52 | } 53 | 54 | @media (min-width: $br-sm) { 55 | grid-template-columns: 1fr 1fr; 56 | grid-template-rows: repeat(3, 1fr 40px) 1fr; 57 | grid-template-areas: 58 | "img1 txt1" 59 | ". ." 60 | "img2 txt2" 61 | ". ." 62 | "img3 txt3" 63 | ". ." 64 | "img4 txt4"; 65 | } 66 | 67 | @media (min-width: $br-l) { 68 | grid-template-columns: 1fr 1fr; 69 | grid-template-rows: auto auto 80px auto auto; 70 | grid-template-areas: 71 | "img1 img2" 72 | "txt1 txt2" 73 | ". ." 74 | "img3 img4" 75 | "txt3 txt4"; 76 | 77 | align-items: start; 78 | } 79 | } -------------------------------------------------------------------------------- /src/layout/grid-presets/four-way-grid/index.ts: -------------------------------------------------------------------------------- 1 | import styles from './four-way-grid.module.scss'; 2 | 3 | /** 4 | * @name fourWayGrid 5 | * @description 6 | * A a pure CSS component, let the preset arrange your grid elements! 7 | * 8 | * Default view: 9 | * ``` 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * ``` 19 | * 20 | * Tablet: 21 | * ``` 22 | * image-1 text-1 23 | * image-2 text-2 24 | * image-3 text-3 25 | * image-4 text-4 26 | * ``` 27 | * 28 | * Desktop: 29 | * ``` 30 | * image-1 image-2 31 | * text-1 text-2 32 | * image-3 image-4 33 | * text-3 text-4 34 | * ``` 35 | * 36 | * @example 37 | * 38 | *
element 1
39 | * 40 | *
element 2
41 | * 42 | *
element 3
43 | * 44 | *
element 4
45 | * 46 | *
47 | */ 48 | 49 | export const fourWayGrid = styles.fourWayGrid; 50 | -------------------------------------------------------------------------------- /src/layout/grid-presets/z-grid/index.ts: -------------------------------------------------------------------------------- 1 | import styles from './z-grid.module.scss'; 2 | 3 | /** 4 | * @name zGrid 5 | * @description 6 | * A a pure CSS component, let the preset arrange your grid elements! 7 | * 8 | * 9 | * Default view: 10 | * ``` 11 | * 12 | * 13 | * 14 | * 15 | * ``` 16 | * 17 | * Tablet and above: 18 | * ``` 19 | * 20 | * 21 | * ``` 22 | * 23 | * @example 24 | * 25 | *
element 1
26 | * 27 | *
element 2
28 | * 29 | *
30 | */ 31 | 32 | export const zGrid = styles.zGrid; 33 | export const halfZGrid = styles.halfZGrid; 34 | -------------------------------------------------------------------------------- /src/layout/grid-presets/z-grid/z-grid.module.scss: -------------------------------------------------------------------------------- 1 | @import "../../_breakpoints.scss"; 2 | 3 | .zGrid { 4 | grid-row-gap: 50px; 5 | margin-bottom: 50px; 6 | 7 | grid-template-areas: 8 | "it1" 9 | "im1" 10 | "." 11 | "it2" 12 | "im2" 13 | "."; 14 | 15 | :nth-child(1) { 16 | grid-area: it1; 17 | } 18 | 19 | :nth-child(2) { 20 | grid-area: im1; 21 | } 22 | 23 | :nth-child(3) { 24 | grid-area: it2; 25 | } 26 | 27 | :nth-child(4) { 28 | grid-area: im2; 29 | } 30 | 31 | @media (min-width: $br-md) { 32 | grid-template-areas: 33 | "it1 it1 it1 it1 it1 it1 im1 im1 im1 im1 im1 im1" 34 | "im2 im2 im2 im2 im2 im2 it2 it2 it2 it2 it2 it2"; 35 | 36 | grid-row-gap: 80px; 37 | margin-bottom: 80px; 38 | } 39 | 40 | @media (min-width: $br-lg) { 41 | grid-template-areas: 42 | "it1 it1 it1 it1 it1 im1 im1 im1 im1 im1 im1 im1" 43 | "im2 im2 im2 im2 im2 im2 im2 it2 it2 it2 it2 it2"; 44 | 45 | grid-row-gap: 80px; 46 | margin-bottom: 80px; 47 | } 48 | } 49 | 50 | .halfZGrid { 51 | grid-template-areas: 52 | "it1" 53 | "im1"; 54 | 55 | :nth-child(1) { 56 | grid-area: it1; 57 | } 58 | 59 | :nth-child(2) { 60 | grid-area: im1; 61 | } 62 | 63 | @media (min-width: $br-md) { 64 | grid-template-areas: 65 | "it1 it1 it1 it1 it1 it1 im1 im1 im1 im1 im1 im1"; 66 | } 67 | 68 | @media (min-width: $br-lg) { 69 | grid-template-areas: 70 | "it1 it1 it1 it1 it1 im1 im1 im1 im1 im1 im1 im1"; 71 | } 72 | } -------------------------------------------------------------------------------- /src/layout/page-frame/README.md: -------------------------------------------------------------------------------- 1 | ## Page frame 2 | 3 | CSS components for readable columns. 4 | 5 | `centerColumn` - main display width for most content, including images and text. 6 | 7 | `wideColumn` - 'extra wide' display width, e.g. when putting large elements side by side. 8 | 9 | `textColumn` - display width for readable areas. (headlines, paragraphs, etc) 10 | 11 | ## Example 12 | ```tsx 13 | import { centerColumn, wideColumn, textColumn } from '@bit/bit.base-ui.layout.page-frame'; 14 | 15 | // ... 16 | 17 |
18 | normal content 19 | 20 |
nice title
21 |
22 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 23 | Suspendisse et sodales diam, sed sodales tellus. 24 | Nam sodales interdum dolor, eget euismod purus. 25 |
26 |
27 | 28 |
29 | Content breaking out of regular layout 30 | {/* ... */} 31 |
32 | ``` -------------------------------------------------------------------------------- /src/layout/page-frame/index.ts: -------------------------------------------------------------------------------- 1 | import styles from './page-frame.module.scss'; 2 | 3 | export const centerColumn = styles.centerColumn; 4 | export const wideColumn = styles.wideColumn; 5 | export const textColumn = styles.textColumn; 6 | -------------------------------------------------------------------------------- /src/layout/page-frame/page-frame.module.scss: -------------------------------------------------------------------------------- 1 | .centerColumn { 2 | width: calc(100% - 40px); 3 | max-width: 1000px; 4 | margin-right: auto; 5 | margin-left: auto; 6 | } 7 | 8 | .wideColumn { 9 | width: calc(100% - 40px); 10 | max-width: 1440px; 11 | margin-right: auto; 12 | margin-left: auto; 13 | } 14 | 15 | .textColumn { 16 | max-width: 700px; 17 | } -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/serviceWorker.ts: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.0/8 are considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | type Config = { 24 | onSuccess?: (registration: ServiceWorkerRegistration) => void; 25 | onUpdate?: (registration: ServiceWorkerRegistration) => void; 26 | }; 27 | 28 | export function register(config?: Config) { 29 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 30 | // The URL constructor is available in all browsers that support SW. 31 | const publicUrl = new URL( 32 | process.env.PUBLIC_URL, 33 | window.location.href 34 | ); 35 | if (publicUrl.origin !== window.location.origin) { 36 | // Our service worker won't work if PUBLIC_URL is on a different origin 37 | // from what our page is served on. This might happen if a CDN is used to 38 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 39 | return; 40 | } 41 | 42 | window.addEventListener('load', () => { 43 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 44 | 45 | if (isLocalhost) { 46 | // This is running on localhost. Let's check if a service worker still exists or not. 47 | checkValidServiceWorker(swUrl, config); 48 | 49 | // Add some additional logging to localhost, pointing developers to the 50 | // service worker/PWA documentation. 51 | navigator.serviceWorker.ready.then(() => { 52 | console.log( 53 | 'This web app is being served cache-first by a service ' + 54 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 55 | ); 56 | }); 57 | } else { 58 | // Is not localhost. Just register service worker 59 | registerValidSW(swUrl, config); 60 | } 61 | }); 62 | } 63 | } 64 | 65 | function registerValidSW(swUrl: string, config?: Config) { 66 | navigator.serviceWorker 67 | .register(swUrl) 68 | .then(registration => { 69 | registration.onupdatefound = () => { 70 | const installingWorker = registration.installing; 71 | if (installingWorker == null) { 72 | return; 73 | } 74 | installingWorker.onstatechange = () => { 75 | if (installingWorker.state === 'installed') { 76 | if (navigator.serviceWorker.controller) { 77 | // At this point, the updated precached content has been fetched, 78 | // but the previous service worker will still serve the older 79 | // content until all client tabs are closed. 80 | console.log( 81 | 'New content is available and will be used when all ' + 82 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 83 | ); 84 | 85 | // Execute callback 86 | if (config && config.onUpdate) { 87 | config.onUpdate(registration); 88 | } 89 | } else { 90 | // At this point, everything has been precached. 91 | // It's the perfect time to display a 92 | // "Content is cached for offline use." message. 93 | console.log('Content is cached for offline use.'); 94 | 95 | // Execute callback 96 | if (config && config.onSuccess) { 97 | config.onSuccess(registration); 98 | } 99 | } 100 | } 101 | }; 102 | }; 103 | }) 104 | .catch(error => { 105 | console.error('Error during service worker registration:', error); 106 | }); 107 | } 108 | 109 | function checkValidServiceWorker(swUrl: string, config?: Config) { 110 | // Check if the service worker can be found. If it can't reload the page. 111 | fetch(swUrl, { 112 | headers: { 'Service-Worker': 'script' } 113 | }) 114 | .then(response => { 115 | // Ensure service worker exists, and that we really are getting a JS file. 116 | const contentType = response.headers.get('content-type'); 117 | if ( 118 | response.status === 404 || 119 | (contentType != null && contentType.indexOf('javascript') === -1) 120 | ) { 121 | // No service worker found. Probably a different app. Reload the page. 122 | navigator.serviceWorker.ready.then(registration => { 123 | registration.unregister().then(() => { 124 | window.location.reload(); 125 | }); 126 | }); 127 | } else { 128 | // Service worker found. Proceed as normal. 129 | registerValidSW(swUrl, config); 130 | } 131 | }) 132 | .catch(() => { 133 | console.log( 134 | 'No internet connection found. App is running in offline mode.' 135 | ); 136 | }); 137 | } 138 | 139 | export function unregister() { 140 | if ('serviceWorker' in navigator) { 141 | navigator.serviceWorker.ready 142 | .then(registration => { 143 | registration.unregister(); 144 | }) 145 | .catch(error => { 146 | console.error(error.message); 147 | }); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom/extend-expect'; 6 | -------------------------------------------------------------------------------- /src/surfaces/abs-container/abs-container.module.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | position: relative; 3 | } 4 | 5 | .containee { 6 | position: absolute; 7 | 8 | visibility: hidden; 9 | [data-open='true'] & { 10 | visibility: visible; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/surfaces/abs-container/containee/containee.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component, RefObject } from 'react'; 2 | import classNames from 'classnames'; 3 | //@ts-ignore 4 | import createRef from 'react-create-ref'; 5 | 6 | import styles from '../abs-container.module.scss'; 7 | import positionStyles from './positions.module.scss'; 8 | import displacementStyles from './displacement.module.scss'; 9 | 10 | export type Position = 11 | | 'top' 12 | | 'right' 13 | | 'bottom' 14 | | 'left' 15 | | 'cover' 16 | | 'none' 17 | | 'top-start' 18 | | 'right-start' 19 | | 'bottom-start' 20 | | 'left-start' 21 | | 'top-end' 22 | | 'right-end' 23 | | 'bottom-end' 24 | | 'left-end'; 25 | 26 | export type ContaineeProps = { position?: Position } & React.HTMLAttributes; 27 | 28 | export class Containee extends Component { 29 | private ref: RefObject = createRef(); 30 | 31 | render() { 32 | const { className, position = 'bottom', ...rest } = this.props; 33 | const positionClass = positionStyles[position]; 34 | const displacement = displacementStyles.displacement; 35 | 36 | return ( 37 |
43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/surfaces/abs-container/containee/displacement.module.scss: -------------------------------------------------------------------------------- 1 | .displacement { 2 | &[data-position^='top'] { 3 | margin-bottom: var(--drawer-margin); 4 | } 5 | &[data-position^='right'] { 6 | margin-left: var(--drawer-margin); 7 | } 8 | &[data-position^='bottom'] { 9 | margin-top: var(--drawer-margin); 10 | } 11 | &[data-position^='left'] { 12 | margin-right: var(--drawer-margin); 13 | } 14 | } 15 | 16 | .displacement { 17 | &[data-position='bottom-start'], &[data-position='top-start'] { 18 | margin-left: var(--drawer-indent); 19 | } 20 | &[data-position='bottom-end'], &[data-position='top-end'] { 21 | margin-right: var(--drawer-indent); 22 | } 23 | 24 | &[data-position^='right-start'], &[data-position^='left-start'] { 25 | margin-top: var(--drawer-indent); 26 | } 27 | &[data-position^='right-end'], &[data-position^='left-end'] { 28 | margin-bottom: var(--drawer-indent); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/surfaces/abs-container/containee/index.ts: -------------------------------------------------------------------------------- 1 | export * from './containee'; 2 | -------------------------------------------------------------------------------- /src/surfaces/abs-container/containee/positions.module.scss: -------------------------------------------------------------------------------- 1 | .top { 2 | bottom: 100%; 3 | 4 | &-start { 5 | bottom: 100%; 6 | left: 0%; 7 | } 8 | 9 | &-end { 10 | bottom: 100%; 11 | right: 0%; 12 | } 13 | } 14 | 15 | .right { 16 | left: 100%; 17 | 18 | &-start { 19 | left: 100%; 20 | top: 0%; 21 | } 22 | 23 | &-end { 24 | left: 100%; 25 | bottom: 0%; 26 | } 27 | } 28 | 29 | .bottom { 30 | top: 100%; 31 | 32 | &-start { 33 | top: 100%; 34 | left: 0%; 35 | } 36 | 37 | &-end { 38 | top: 100%; 39 | right: 0%; 40 | } 41 | } 42 | 43 | .left { 44 | right: 100%; 45 | 46 | &-start { 47 | right: 100%; 48 | top: 0%; 49 | } 50 | 51 | &-end { 52 | right: 100%; 53 | bottom: 0%; 54 | } 55 | } 56 | 57 | .cover { 58 | top: 0%; 59 | left: 0%; 60 | } 61 | 62 | // .none {} 63 | -------------------------------------------------------------------------------- /src/surfaces/abs-container/container/container.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import cn from 'classnames'; 3 | import styles from '../abs-container.module.scss'; 4 | 5 | export type ContainerProps = { open?: boolean } & React.HTMLAttributes; 6 | 7 | export function Container(props: ContainerProps) { 8 | const { className, open, ...rest } = props; 9 | 10 | return
; 11 | } 12 | -------------------------------------------------------------------------------- /src/surfaces/abs-container/container/index.ts: -------------------------------------------------------------------------------- 1 | export * from './container'; 2 | -------------------------------------------------------------------------------- /src/surfaces/abs-container/index.ts: -------------------------------------------------------------------------------- 1 | import styles from './abs-container.module.scss'; 2 | 3 | export * from './containee'; 4 | export * from './container'; 5 | 6 | export const containerClass = styles.container; 7 | export const containeeClass = styles.containee; -------------------------------------------------------------------------------- /src/surfaces/background/background.module.scss: -------------------------------------------------------------------------------- 1 | .bedrock { 2 | background: var(--bg-bedrock); 3 | } 4 | 5 | .base { 6 | background: var(--bg-base); 7 | } 8 | 9 | .layer { 10 | background: var(--bg-layer); 11 | } 12 | 13 | .crust { 14 | background: var(--bg-crust); 15 | } 16 | 17 | .topping { 18 | background: var(--bg-topping); 19 | &:hover { 20 | background: var(--bg-topping-highlight); 21 | } 22 | } 23 | 24 | .dent { 25 | background: var(--bg-dent); 26 | } 27 | -------------------------------------------------------------------------------- /src/surfaces/background/index.ts: -------------------------------------------------------------------------------- 1 | import styles from './background.module.scss'; 2 | 3 | type BackgroundLayer = 'bedrock' | 'base' | 'layer' | 'crust' | 'topping' | 'dent'; 4 | 5 | export const backgrounds: { [key in BackgroundLayer]: string } = { 6 | bedrock: styles.bedrock, 7 | base: styles.base, 8 | layer: styles.layer, 9 | crust: styles.crust, 10 | topping: styles.topping, 11 | dent: styles.dent, 12 | }; 13 | -------------------------------------------------------------------------------- /src/surfaces/bedrock/bedrock.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import { backgrounds } from '../background'; 4 | 5 | type BedrockProps = React.HTMLAttributes; 6 | 7 | export function Bedrock(props: BedrockProps) { 8 | return
; 9 | } 10 | -------------------------------------------------------------------------------- /src/surfaces/bedrock/index.ts: -------------------------------------------------------------------------------- 1 | export * from './bedrock'; 2 | -------------------------------------------------------------------------------- /src/surfaces/card/card.module.scss: -------------------------------------------------------------------------------- 1 | .card { 2 | padding: 20px; 3 | box-sizing: border-box; 4 | } 5 | -------------------------------------------------------------------------------- /src/surfaces/card/card.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | import { expect } from "chai"; 4 | 5 | import { Card } from "./card"; 6 | 7 | it("should render default card", () => { 8 | const { getByText } = render(base Card); 9 | const rendered = getByText("base Card"); 10 | expect(rendered).to.exist; 11 | }); 12 | 13 | // it("should render card with high elevation", () => { 14 | // const { getByText } = render(base Card); 15 | // const rendered = getByText("base Card"); 16 | // expect(rendered.classList.contains('elevation-high')).to.equal(true); 17 | // }); 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/surfaces/card/card.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import styles from './card.module.scss'; 4 | import { elevationClass, ElevationHeight } from '../../css-components/elevation'; 5 | import { roundnessClass, Roundness } from '../../css-components/roundness'; 6 | import { backgrounds } from '../background'; 7 | 8 | export type CardProps = { 9 | /** 10 | * Controls the shadow cast by the card, to generate a "stacking" effects. 11 | * For example, a modal floating over elements may have a 'high' elevation 12 | */ 13 | elevation?: ElevationHeight; 14 | /** Controls the border radius of the card */ 15 | roundness?: Roundness; 16 | } & React.HTMLAttributes; 17 | 18 | /** 19 | * A wrapper resembling a physical card, grouping elements and improve readability. 20 | * @example 21 | * 22 | * Lorem ipsum dolor sit amet, consectetur adipiscing elit. 23 | * 24 | */ 25 | export function Card({ 26 | className, 27 | elevation = 'low', 28 | roundness = 'default', 29 | ...rest 30 | }: CardProps) { 31 | return ( 32 |
43 | ); 44 | } 45 | 46 | Card.defaultProps = { 47 | elevation: 'low', 48 | roundness: 'default', 49 | }; 50 | -------------------------------------------------------------------------------- /src/surfaces/card/index.tsx: -------------------------------------------------------------------------------- 1 | export * from "./card"; 2 | -------------------------------------------------------------------------------- /src/surfaces/click-outside/click-outside.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component, ReactNode } from 'react'; 2 | import onClickOutside, { 3 | OnClickOutProps, 4 | InjectedOnClickOutProps, 5 | } from 'react-onclickoutside'; 6 | 7 | type Props = { 8 | children: ReactNode; 9 | disable?: boolean; 10 | onClick: (e: React.MouseEvent) => void; 11 | } & InjectedOnClickOutProps; 12 | 13 | class MyComponent extends Component implements OnClickOutProps { 14 | componentDidUpdate(prevProps: Props) { 15 | const nextProps = this.props; 16 | 17 | if (prevProps.disable !== nextProps.disable) { 18 | if (nextProps.disable) { 19 | this.props.disableOnClickOutside(); 20 | } else { 21 | this.props.enableOnClickOutside(); 22 | } 23 | } 24 | } 25 | 26 | handleClickOutside = (evt: React.MouseEvent) => { 27 | this.props.onClick(evt); 28 | }; 29 | 30 | render() { 31 | return this.props.children; 32 | } 33 | } 34 | 35 | export const ClickOutside = onClickOutside(MyComponent); 36 | -------------------------------------------------------------------------------- /src/surfaces/click-outside/index.ts: -------------------------------------------------------------------------------- 1 | export * from './click-outside'; -------------------------------------------------------------------------------- /src/surfaces/drawer/default-placeholder.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import styles from './drawer.module.scss'; 4 | 5 | export type DrawerPlaceholderProps = React.HTMLAttributes; 6 | 7 | export function DefaultPlaceholder(props: DrawerPlaceholderProps) { 8 | return ( 9 |
10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /src/surfaces/drawer/drawer.module.scss: -------------------------------------------------------------------------------- 1 | .placeholder { 2 | cursor: pointer; 3 | user-select: none; 4 | } 5 | -------------------------------------------------------------------------------- /src/surfaces/drawer/drawer.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component, ReactNode, ComponentType } from 'react'; 2 | 3 | import { Container } from '../abs-container'; 4 | import { ClickOutside } from '../click-outside'; 5 | 6 | import { DefaultPlaceholder, DrawerPlaceholderProps } from './default-placeholder'; 7 | 8 | export type DrawerProps = { 9 | open?: boolean; 10 | PlaceholderComponent?: ComponentType; 11 | placeholder: ReactNode; 12 | 13 | clickToggles?: boolean; 14 | clickPlaceholderToggles?: boolean; 15 | clickOutside?: boolean; 16 | hoverToOpen?: boolean; 17 | 18 | onChange?: (evt: React.MouseEvent | undefined, open: boolean) => void; 19 | onContainerToggle?: (e: React.MouseEvent) => void; 20 | onPlaceholderToggle?: (e: React.MouseEvent) => void; 21 | onContaineeToggle?: (e: React.MouseEvent) => void; 22 | onClickOutside?: (e: React.MouseEvent) => void; 23 | } & React.HTMLAttributes; 24 | 25 | type DrawerState = { 26 | isOpen: boolean; 27 | }; 28 | 29 | export class Drawer extends Component { 30 | state: DrawerState = { 31 | isOpen: this.props.open || false, 32 | }; 33 | 34 | static defaultProps = { 35 | PlaceholderComponent: DefaultPlaceholder, 36 | clickPlaceholderToggles: true, 37 | clickOutside: true, 38 | clickToggles: true, 39 | }; 40 | 41 | componentWillReceiveProps(nextProps: DrawerProps) { 42 | const prevProps = this.props; 43 | 44 | if (prevProps.open !== nextProps.open && nextProps.open !== undefined) { 45 | this.setState({ isOpen: nextProps.open }); 46 | } 47 | } 48 | 49 | private get isControlled() { 50 | return this.props.open !== undefined; 51 | } 52 | 53 | toggle = (evt: React.MouseEvent) => { 54 | const { isOpen } = this.state; 55 | const nextOpen = !isOpen; 56 | 57 | if (!this.isControlled) { 58 | this.setState({ isOpen: nextOpen }); 59 | } 60 | 61 | this.props.onChange && this.props.onChange(evt, nextOpen); 62 | }; 63 | 64 | close = (evt: React.MouseEvent) => { 65 | const { isOpen } = this.state; 66 | const nextOpen = false; 67 | 68 | if (!this.isControlled && isOpen) { 69 | this.setState({ isOpen: nextOpen }); 70 | } 71 | 72 | this.props.onChange && this.props.onChange(evt, nextOpen); 73 | }; 74 | 75 | open = (evt: React.MouseEvent) => { 76 | const { isOpen } = this.state; 77 | const nextOpen = true; 78 | 79 | if (!this.isControlled && !isOpen) { 80 | this.setState({ isOpen: true }); 81 | } 82 | 83 | this.props.onChange && this.props.onChange(evt, nextOpen); 84 | }; 85 | 86 | private handePlaceholderClick = (e: React.MouseEvent) => { 87 | //TODO - consider stopping event propagation 88 | this.props.clickPlaceholderToggles && this.toggle(e); 89 | 90 | this.props.onPlaceholderToggle && this.props.onPlaceholderToggle(e); 91 | }; 92 | 93 | private handleContainerClick = (e: React.MouseEvent) => { 94 | this.props.clickToggles && this.toggle(e); 95 | 96 | this.props.onClick && this.props.onClick(e); 97 | }; 98 | 99 | private handleClickOutside = (e: React.MouseEvent) => { 100 | this.props.clickOutside && this.close(e); 101 | 102 | this.props.onClickOutside && this.props.onClickOutside(e); 103 | }; 104 | 105 | private handleLeaveContainer = (e: React.MouseEvent) => { 106 | //TODO - add grace period 107 | this.props.hoverToOpen && this.close(e); 108 | 109 | this.props.onMouseLeave && this.props.onMouseLeave(e); 110 | }; 111 | 112 | private handleEnterContainer = (e: React.MouseEvent) => { 113 | this.props.hoverToOpen && this.open(e); 114 | 115 | this.props.onMouseEnter && this.props.onMouseEnter(e); 116 | }; 117 | 118 | render() { 119 | const { 120 | placeholder, 121 | children, 122 | PlaceholderComponent = DefaultPlaceholder, 123 | clickOutside, 124 | 125 | //replaced by handlers: 126 | onMouseEnter, 127 | onMouseLeave, 128 | 129 | //virtualProps (should not be included in 'rest') 130 | open, 131 | hoverToOpen, 132 | 133 | onChange, 134 | onPlaceholderToggle, 135 | onContaineeToggle, 136 | onClickOutside, 137 | 138 | ...rest 139 | } = this.props; 140 | const { isOpen } = this.state; 141 | 142 | return ( 143 | 149 | 156 | {children} 157 | 158 | {placeholder} 159 | 160 | 161 | 162 | ); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/surfaces/drawer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './drawer'; 2 | -------------------------------------------------------------------------------- /src/text/heading/heading.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | import { expect } from "chai"; 4 | 5 | import { Heading } from "./heading"; 6 | 7 | it("should render correct text in Heading", () => { 8 | const { getByText } = render(Heading); 9 | const rendered = getByText("Heading"); 10 | expect(rendered).to.exist; 11 | }); 12 | 13 | it("should render as h1 by default", () => { 14 | const { getByText } = render(h1 heading); 15 | const rendered = getByText("h1 heading"); 16 | expect(rendered.tagName).to.be.equal("H1"); 17 | }); 18 | 19 | it("should render as h3 when defined", () => { 20 | const { getByText } = render(h3 heading); 21 | const rendered = getByText("h3 heading"); 22 | expect(rendered.tagName).to.be.equal("H3"); 23 | }); 24 | -------------------------------------------------------------------------------- /src/text/heading/heading.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export type HeadingProps = { 4 | /** 5 | * underlying html element ("h1", "h2", etc) 6 | */ 7 | element?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6', 8 | } & React.HTMLAttributes; 9 | 10 | /** 11 | * Base title component, to be styled by composing components. 12 | * May have more logic in the future. 13 | * @example 14 | * This is a title 15 | */ 16 | export function Heading(props: HeadingProps) { 17 | const { element, ...rest } = props; 18 | const Element = element || 'h1'; 19 | 20 | return ; 21 | } 22 | 23 | Heading.defaultProps = { 24 | element: 'h1', 25 | }; 26 | -------------------------------------------------------------------------------- /src/text/heading/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./heading"; 2 | 3 | -------------------------------------------------------------------------------- /src/text/muted-text/index.ts: -------------------------------------------------------------------------------- 1 | export * from './muted-text'; 2 | -------------------------------------------------------------------------------- /src/text/muted-text/muted-text.module.scss: -------------------------------------------------------------------------------- 1 | .mutedText { 2 | color: var(--text-muted, #6c707c); 3 | } 4 | -------------------------------------------------------------------------------- /src/text/muted-text/muted-text.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | 4 | import styles from './muted-text.module.scss'; 5 | 6 | /** 7 | * Text with muted (gray) color. Behaves like a regular *span* element.
8 | * Applies text color with css variable `--text-muted` 9 | * @name MutedText 10 | */ 11 | export function MutedText(props: React.HTMLAttributes) { 12 | return ; 13 | } 14 | 15 | /** 16 | * Pure css class name, colors text as muted (gray).
17 | * Use this directly as a class name without creating a DOM element
18 | * 19 | * Colors derives from css variable `--text-muted` 20 | * @name mutedText 21 | */ 22 | export const mutedText = styles.mutedText; 23 | -------------------------------------------------------------------------------- /src/text/paragraph/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './paragraph'; 2 | -------------------------------------------------------------------------------- /src/text/paragraph/paragraph.module.scss: -------------------------------------------------------------------------------- 1 | // font sizes only! 2 | 3 | .xxs { 4 | font-size: var(--p-xxs, 12px); 5 | } 6 | 7 | .xs { 8 | font-size: var(--p-xs, 14px); 9 | } 10 | 11 | .sm { 12 | font-size: var(--p-sm, 15px); 13 | } 14 | 15 | .md { 16 | font-size: var(--p-md, 16px); 17 | } 18 | 19 | .lg { 20 | font-size: var(--p-lg, 18px); 21 | } 22 | 23 | .xl { 24 | font-size: var(--p-xl, 20px); 25 | } 26 | 27 | .xxl { 28 | font-size: var(--p-xxl, 24px); 29 | } -------------------------------------------------------------------------------- /src/text/paragraph/paragraph.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import { expect } from 'chai'; 4 | 5 | import { Paragraph } from './paragraph'; 6 | import { PossibleSizes } from '../../constants/sizes'; 7 | 8 | it('should render', () => { 9 | const { getByText } = render(test text); 10 | 11 | const rendered = getByText('test text'); 12 | 13 | expect(rendered).to.exist; 14 | }); 15 | 16 | it('should render with different size', () => { 17 | const { getByText } = render(test text); 18 | 19 | const rendered = getByText('test text'); 20 | // cannot test classnames with Mocha 21 | // expect(rendered.className).to.include('xs'); 22 | 23 | expect(rendered).to.exist; 24 | }); -------------------------------------------------------------------------------- /src/text/paragraph/paragraph.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | 4 | import { PossibleSizes } from '../../constants/sizes'; 5 | import styles from './paragraph.module.scss'; 6 | 7 | export type ParagraphProps = { 8 | /** 9 | * Font size (from a list of presets). 10 | */ 11 | size: PossibleSizes, 12 | /** 13 | * The underlying html element 14 | */ 15 | element: 'p' | 'div' | 'span', 16 | } & React.HTMLAttributes; 17 | 18 | /** 19 | * Paragraph component prototype. Accepts all properties of a native Paragraph element, 20 | * @name paragraph 21 | * @example 22 | * This is some text 23 | */ 24 | export function Paragraph({ className, size, element: Element, ...rest }: ParagraphProps) { 25 | return ( 26 | 31 | ); 32 | } 33 | 34 | Paragraph.defaultProps = { 35 | size: 'md', 36 | element: 'p', 37 | }; 38 | -------------------------------------------------------------------------------- /src/text/text-separator/index.ts: -------------------------------------------------------------------------------- 1 | export * from './text-separator'; 2 | -------------------------------------------------------------------------------- /src/text/text-separator/text-separator.module.scss: -------------------------------------------------------------------------------- 1 | .textSeparator { 2 | display: flex; 3 | align-items: center; 4 | } 5 | 6 | .line { 7 | flex: 1 1 100%; 8 | border-bottom: 2px dashed var(--separator-color, #ededed); 9 | 10 | &:first-child { 11 | margin-right: 11px; 12 | } 13 | 14 | &:last-child { 15 | margin-left: 11px; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/text/text-separator/text-separator.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './text-separator.module.scss'; 3 | import classNames from 'classnames'; 4 | 5 | /** 6 | * Separating line spanning the whole line, with room for text. Behaves like a regular `div` element.
7 | * Currently, there is no way to customize the border-style. 8 | * 9 | * Border color is applied from css variable `--separator-color` 10 | * @name TextSeparator 11 | */ 12 | export function TextSeparator(props: React.HTMLAttributes) { 13 | const { children, className, ...rest } = props; 14 | 15 | return ( 16 |
17 |
18 | {children} 19 |
20 |
21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /src/text/themed-text/index.ts: -------------------------------------------------------------------------------- 1 | export * from './themed-text'; -------------------------------------------------------------------------------- /src/text/themed-text/themed-text.module.scss: -------------------------------------------------------------------------------- 1 | .themedText { 2 | color: var(--base-color, #6c5ce7); 3 | } -------------------------------------------------------------------------------- /src/text/themed-text/themed-text.tsx: -------------------------------------------------------------------------------- 1 | import React, { HTMLAttributes } from 'react'; 2 | import classNames from 'classnames'; 3 | import styles from './themed-text.module.scss'; 4 | 5 | export type ThemedTextProps = HTMLAttributes; 6 | 7 | /** 8 | * Text colored with the current base color. 9 | * 10 | * using css variable: 11 | * - --base-color 12 | * @name ThemedText 13 | */ 14 | export function ThemedText(props: ThemedTextProps) { 15 | return ( 16 | 21 | ); 22 | } 23 | 24 | /** 25 | * Same component as a pure-css class. 26 | * @name themedText 27 | */ 28 | export const themedText = styles.themedText; -------------------------------------------------------------------------------- /src/themes/book-font.module.scss: -------------------------------------------------------------------------------- 1 | //@HACK - fonts don't work with storage.cloud.google.com 2 | $staticStorageUrl: 'https://static.bit.dev'; 3 | 4 | /** 5 | * Define `@font-face` rules for font-family Circular Pro Book, including bold and italic. 6 | * Provides a handy class name to add to root component. 7 | * 8 | * @example 9 | * import { bookFont } from '@bit/bit.base-ui.theme.fonts.book'; 10 | * //... 11 | * 12 | * 13 | *
I'm using font!
14 | *
I am BOLD
15 | * 16 | */ 17 | 18 | // default 19 | @font-face { 20 | font-family: "CircularPro"; 21 | src: url($staticStorageUrl + '/fonts/CircularPro-Book.otf'); 22 | } 23 | 24 | // bold 25 | @font-face { 26 | font-family: "CircularPro"; 27 | src: url($staticStorageUrl + '/fonts/CircularPro-Bold.otf'); 28 | font-weight: bold; 29 | } 30 | 31 | // // bold-er 32 | @font-face { 33 | font-family: "CircularPro"; 34 | src: url($staticStorageUrl + '/fonts/CircularPro-Black.otf'); 35 | font-weight: 800; 36 | } 37 | 38 | // italic 39 | @font-face { 40 | font-family: "CircularPro"; 41 | src: url($staticStorageUrl + '/fonts/CircularPro-BookItalic.otf'); 42 | font-style: italic; 43 | } 44 | 45 | // bold + italic 46 | @font-face { 47 | font-family: "CircularPro"; 48 | src: url($staticStorageUrl + '/fonts/CircularPro-BoldItalic.otf'); 49 | font-style: italic; 50 | font-weight: bold; 51 | } 52 | 53 | // bold-er + italic 54 | @font-face { 55 | font-family: "CircularPro"; 56 | src: url($staticStorageUrl + '/fonts/CircularPro-BlackItalic.otf'); 57 | font-style: italic; 58 | font-weight: 800; 59 | } 60 | 61 | .bookFont { 62 | font-family: "CircularPro", "Gill Sans", "Gill Sans MT", "Helvetica Neue", Helvetica, Arial, sans-serif; 63 | } -------------------------------------------------------------------------------- /src/themes/brand-colors.module.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Sass variables for brands we use in the page. 3 | * ```scss 4 | * $twitter: #1da1f2; 5 | * $slack: #4a154b; 6 | * $github: #2b2b2b; 7 | * ``` 8 | */ 9 | 10 | $twitter: #1da1f2; 11 | $slack: #4a154b; 12 | $github: #2b2b2b; -------------------------------------------------------------------------------- /src/themes/brand-definition.module.scss: -------------------------------------------------------------------------------- 1 | @import "./colors.module.scss"; 2 | 3 | /** 4 | * css variables definition, for brand colors. 5 | * @example 6 | *
{children}
7 | */ 8 | 9 | .brands { 10 | --github-bg: #2b2b2b; 11 | --brand-text: #{$w10}; 12 | --slack-bg: #4a154b; 13 | --twitter-bg: #1da1f2; 14 | } -------------------------------------------------------------------------------- /src/themes/color-definition.module.scss: -------------------------------------------------------------------------------- 1 | @import './colors.module.scss'; 2 | 3 | /** 4 | * CSS colors and variables for the app. 5 | * 6 | * - Sets default text color 7 | * - `--base-color` - default color (cta color, etc) 8 | * - `--base-highlight` - default color for highlight (cta hover, etc) 9 | * - `--border-color` 10 | * - `--bg-color` - background color 11 | * - `--separator-color` 12 | * 13 | * ### backgrounds: 14 | * As elements stacks closer to the user, its color changes. their color change. 15 | * This is especially noticeable in dark mode (higher elements are lighter). 16 | * 17 | * We created 4 levels of possible backgrounds, from bottom to top: 18 | * - `--bg-bedrock` - i.e. background 19 | * - `--bg-base` - e.g. navigation elements and wireframes 20 | * - `--bg-layer` - workspaces, e.g. card. (may be sub-divided in the future) 21 | * - `--bg-crust` - overlay ui, e.g. tooltip. 22 | * - `--bg-topping` - "bumps" on top level surfaces e.g. button, input, etc 23 | */ 24 | 25 | .primaryPalette { 26 | color: $d50; 27 | --text-highlight: #{$d60}; 28 | --text-color: #{$d50}; 29 | --text-muted: #{$d40}; 30 | 31 | --base-color: #{$p50}; 32 | --base-highlight: #{$p60}; 33 | 34 | --border-color: #{$d10}; 35 | --bg-color: #{$w10}; 36 | --separator-color: #{$d20}; 37 | 38 | --muted-color: #{$p20}; //unsettled 39 | --muted-highlight: #{$p30}; //unsettled 40 | 41 | --error-color: #{$r50}; 42 | --error-highlight: #{$r60}; 43 | --bg-error: #{$r20}; 44 | 45 | --bg-bedrock: #{$w10}; // i.e. background 46 | --bg-base: #{$w10}; // e.g. navigation 47 | --bg-layer: #{$w10}; // e.g. card 48 | --bg-crust: #{$w10}; // e.g. tooltip 49 | --bg-topping: #{$w10}; // e.g. button, input, etc 50 | --bg-topping-highlight: #{$w20}; 51 | --bg-dent: #{$w20}; 52 | 53 | // deprecated (overly specific): 54 | --primary-button-width: 199px; 55 | --primary-button-height: 46px; 56 | --cta-button-text: #{$w10}; 57 | --primary-label-bg: #{$p50}; 58 | --primary-label-text: #{$w10}; 59 | --primary-label-width: 50px; 60 | } 61 | -------------------------------------------------------------------------------- /src/themes/color-palette/color-palette.module.scss: -------------------------------------------------------------------------------- 1 | @import '../colors.module.scss'; 2 | 3 | // brand colors 4 | .primary { 5 | --base-color: #{$p50}; 6 | --base-highlight: #{$p60}; 7 | } 8 | 9 | .secondary { 10 | --base-color: #{$b50}; 11 | --base-highlight: #{$b60}; 12 | } 13 | 14 | .complementary { 15 | --base-color: #{$pink50}; 16 | --base-highlight: #{$pink60}; 17 | } 18 | 19 | // intents 20 | .impulsive { 21 | --base-color: #{$r50}; 22 | --base-highlight: #{$r60}; 23 | } 24 | 25 | .hungry { 26 | --base-color: #{$y50}; 27 | --base-highlight: #{$y60}; 28 | } 29 | 30 | .success { 31 | --base-color: #{$g50}; 32 | --base-highlight: #{$g60}; 33 | } 34 | 35 | // weight 36 | .emphasized { 37 | --base-color: #{$d60}; 38 | --base-highlight: #{$d70}; 39 | } 40 | 41 | .neutral { 42 | --base-color: #{$d50}; 43 | --base-highlight: #{$d60}; 44 | } 45 | 46 | .muted { 47 | --base-color: #{$d40}; 48 | --base-highlight: #{$d50}; 49 | 50 | //unsettled: 51 | --bg-topping: #{$p20}; 52 | --bg-topping-highlight: #{$p30}; 53 | } 54 | -------------------------------------------------------------------------------- /src/themes/color-palette/index.ts: -------------------------------------------------------------------------------- 1 | import colorStyles from './color-palette.module.scss'; 2 | 3 | /** 4 | * Sets the `--base-color` and `--base-highlight` for the specific use case.
5 | * Effects the color of many elements, such as `` and `