@edvisor/product-language 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +12 -0
- package/.eslintrc.json +139 -0
- package/.storybook/main.js +57 -0
- package/.storybook/manager.js +7 -0
- package/.storybook/preview-head.html +1 -0
- package/.storybook/preview.js +15 -0
- package/.storybook/tsconfig.json +30 -0
- package/README.md +33 -0
- package/jest.config.ts +15 -0
- package/jest.setup.ts +2 -0
- package/package.json +30 -0
- package/project.json +75 -0
- package/src/assets/svg/example_icon.svg +3 -0
- package/src/assets/svg/example_icon_white.svg +3 -0
- package/src/assets/svg/spinner.svg +3 -0
- package/src/assets/svg/spinner_white.svg +3 -0
- package/src/helpers/index.ts +3 -0
- package/src/helpers/talesOf.tsx +42 -0
- package/src/index.ts +2 -0
- package/src/lib/components/README.md +49 -0
- package/src/lib/components/alert-banner/alert-banner.tsx +34 -0
- package/src/lib/components/alert-banner/alert-level-flags.ts +77 -0
- package/src/lib/components/alert-banner/index.ts +1 -0
- package/src/lib/components/badge/badge-type-flags.ts +72 -0
- package/src/lib/components/badge/badge.stories.tsx +16 -0
- package/src/lib/components/badge/badge.test.tsx +29 -0
- package/src/lib/components/badge/badge.tsx +31 -0
- package/src/lib/components/badge/index.ts +1 -0
- package/src/lib/components/card/atoms/card-frame.tsx +17 -0
- package/src/lib/components/card/atoms/index.ts +1 -0
- package/src/lib/components/card/card.test.tsx +163 -0
- package/src/lib/components/card/card.tsx +78 -0
- package/src/lib/components/card/components/card-alert-banner-slot.tsx +16 -0
- package/src/lib/components/card/components/card-controls-slot.tsx +19 -0
- package/src/lib/components/card/components/card-section-slot.tsx +51 -0
- package/src/lib/components/card/components/index.ts +3 -0
- package/src/lib/components/card/index.ts +2 -0
- package/src/lib/components/card/molecules/index.ts +1 -0
- package/src/lib/components/card/molecules/left-right-card.test.tsx +89 -0
- package/src/lib/components/card/molecules/left-right-card.tsx +63 -0
- package/src/lib/components/card/storybook/card.stories.mdx +100 -0
- package/src/lib/components/card/storybook/components.tsx +240 -0
- package/src/lib/components/checkbox/checkbox.test.tsx +39 -0
- package/src/lib/components/checkbox/checkbox.tsx +124 -0
- package/src/lib/components/checkbox/components/components.tsx +59 -0
- package/src/lib/components/checkbox/index.tsx +1 -0
- package/src/lib/components/checkbox/stories/checkbox.stories.mdx +54 -0
- package/src/lib/components/checkbox/stories/components.tsx +36 -0
- package/src/lib/components/checkbox/stories/index.tsx +1 -0
- package/src/lib/components/divider/divider-type-flags.tsx +37 -0
- package/src/lib/components/divider/divider.test.tsx +34 -0
- package/src/lib/components/divider/divider.tsx +37 -0
- package/src/lib/components/divider/index.tsx +1 -0
- package/src/lib/components/divider/stories/components.tsx +13 -0
- package/src/lib/components/divider/stories/divider.stories.mdx +50 -0
- package/src/lib/components/index.ts +14 -0
- package/src/lib/components/input-field/components/index.ts +2 -0
- package/src/lib/components/input-field/components/labeled-input.tsx +61 -0
- package/src/lib/components/input-field/components/stepper.tsx +59 -0
- package/src/lib/components/input-field/index.ts +6 -0
- package/src/lib/components/input-field/input-field.test.tsx +108 -0
- package/src/lib/components/input-field/input-field.tsx +126 -0
- package/src/lib/components/input-field/input-number.tsx +41 -0
- package/src/lib/components/input-field/input-text.tsx +30 -0
- package/src/lib/components/input-field/storybook/components.tsx +334 -0
- package/src/lib/components/input-field/storybook/input-field.stories.mdx +113 -0
- package/src/lib/components/layout/flex.tsx +22 -0
- package/src/lib/components/layout/grid-layout.tsx +40 -0
- package/src/lib/components/layout/index.ts +3 -0
- package/src/lib/components/layout/left-right-layout.tsx +67 -0
- package/src/lib/components/link/index.ts +1 -0
- package/src/lib/components/link/link.test.tsx +29 -0
- package/src/lib/components/link/link.tsx +56 -0
- package/src/lib/components/link/storybook/link.stories.mdx +51 -0
- package/src/lib/components/molecules/avatar/avatar-size-flags.tsx +55 -0
- package/src/lib/components/molecules/avatar/avatar.test.tsx +114 -0
- package/src/lib/components/molecules/avatar/avatar.tsx +80 -0
- package/src/lib/components/molecules/avatar/index.tsx +1 -0
- package/src/lib/components/molecules/avatar/stories/avatar.stories.mdx +55 -0
- package/src/lib/components/molecules/avatar/stories/components.tsx +36 -0
- package/src/lib/components/molecules/button/button-flags.tsx +235 -0
- package/src/lib/components/molecules/button/button.test.tsx +77 -0
- package/src/lib/components/molecules/button/button.tsx +231 -0
- package/src/lib/components/molecules/button/index.tsx +1 -0
- package/src/lib/components/molecules/button/stories/button.stories.mdx +104 -0
- package/src/lib/components/molecules/button/stories/components.tsx +86 -0
- package/src/lib/components/molecules/index.ts +3 -0
- package/src/lib/components/molecules/input-checkbox/index.tsx +1 -0
- package/src/lib/components/molecules/input-checkbox/input-checkbox.test.tsx +34 -0
- package/src/lib/components/molecules/input-checkbox/input-checkbox.tsx +50 -0
- package/src/lib/components/molecules/input-checkbox/stories/components.tsx +36 -0
- package/src/lib/components/molecules/input-checkbox/stories/index.tsx +1 -0
- package/src/lib/components/molecules/input-checkbox/stories/input-checkbox.stories.mdx +51 -0
- package/src/lib/components/organisms/index.ts +1 -0
- package/src/lib/components/organisms/multi-choice-list/index.tsx +1 -0
- package/src/lib/components/organisms/multi-choice-list/multi-choice-list.test.tsx +33 -0
- package/src/lib/components/organisms/multi-choice-list/multi-choice-list.tsx +53 -0
- package/src/lib/components/organisms/multi-choice-list/stories/components.tsx +126 -0
- package/src/lib/components/organisms/multi-choice-list/stories/index.tsx +1 -0
- package/src/lib/components/organisms/multi-choice-list/stories/multi-choice-list.stories.mdx +99 -0
- package/src/lib/components/spinner/index.tsx +1 -0
- package/src/lib/components/spinner/spinner-size-flags.tsx +39 -0
- package/src/lib/components/spinner/spinner.test.tsx +31 -0
- package/src/lib/components/spinner/spinner.tsx +67 -0
- package/src/lib/components/spinner/stories/components.tsx +8 -0
- package/src/lib/components/spinner/stories/spinner.stories.mdx +42 -0
- package/src/lib/components/thumbnail/index.tsx +1 -0
- package/src/lib/components/thumbnail/stories/thumbnail.stories.mdx +34 -0
- package/src/lib/components/thumbnail/thumbnail-size-flags.tsx +41 -0
- package/src/lib/components/thumbnail/thumbnail.test.tsx +51 -0
- package/src/lib/components/thumbnail/thumbnail.tsx +40 -0
- package/src/lib/components/typography/index.ts +1 -0
- package/src/lib/components/typography/storybook/components.tsx +256 -0
- package/src/lib/components/typography/storybook/typography.stories.mdx +88 -0
- package/src/lib/components/typography/typography.test.tsx +93 -0
- package/src/lib/components/typography/typography.tsx +57 -0
- package/src/lib/foundations/color-system/base-palette/base-palette.stories.tsx +123 -0
- package/src/lib/foundations/color-system/base-palette/base-palette.ts +94 -0
- package/src/lib/foundations/color-system/base-palette/index.ts +1 -0
- package/src/lib/foundations/color-system/color-guidelines/color-guidelines.stories.mdx +85 -0
- package/src/lib/foundations/color-system/color-guidelines/color-guidelines.stories.tsx +231 -0
- package/src/lib/foundations/color-system/color-guidelines/color-guidelines.ts +159 -0
- package/src/lib/foundations/color-system/color-guidelines/index.ts +1 -0
- package/src/lib/foundations/color-system/components/color-sample.tsx +99 -0
- package/src/lib/foundations/color-system/components/index.ts +1 -0
- package/src/lib/foundations/color-system/index.ts +1 -0
- package/src/lib/foundations/index.ts +4 -0
- package/src/lib/foundations/shadows/components.tsx +59 -0
- package/src/lib/foundations/shadows/index.ts +1 -0
- package/src/lib/foundations/shadows/shadows.stories.mdx +71 -0
- package/src/lib/foundations/shadows/shadows.tsx +47 -0
- package/src/lib/foundations/spacing/index.ts +1 -0
- package/src/lib/foundations/spacing/spacing-guidelines.ts +24 -0
- package/src/lib/foundations/spacing/spacing.stories.mdx +51 -0
- package/src/lib/foundations/spacing/spacing.ts +18 -0
- package/src/lib/foundations/typography/constants.ts +25 -0
- package/src/lib/foundations/typography/index.tsx +1 -0
- package/src/lib/foundations/typography/text-aspect-flags.ts +54 -0
- package/src/lib/foundations/typography/typography.tsx +97 -0
- package/src/lib/helpers/generic-types.ts +44 -0
- package/src/lib/helpers/index.ts +6 -0
- package/src/lib/helpers/nothing.tsx +18 -0
- package/src/lib/helpers/numbers.ts +53 -0
- package/src/lib/helpers/safe-navigation.ts +34 -0
- package/src/lib/helpers/slots.tsx +76 -0
- package/src/lib/helpers/strings.test.ts +47 -0
- package/src/lib/helpers/strings.ts +16 -0
- package/tsconfig.json +35 -0
- package/tsconfig.lib.json +28 -0
- package/tsconfig.spec.json +21 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import styled from 'styled-components'
|
|
2
|
+
import { Surface } from '../color-system'
|
|
3
|
+
import { Padding } from '../spacing'
|
|
4
|
+
import {
|
|
5
|
+
shadowSm,
|
|
6
|
+
shadow,
|
|
7
|
+
shadowMd,
|
|
8
|
+
shadowLg,
|
|
9
|
+
shadowXl,
|
|
10
|
+
shadow2Xl,
|
|
11
|
+
shadowInner,
|
|
12
|
+
} from './shadows'
|
|
13
|
+
|
|
14
|
+
const Container = styled.div`
|
|
15
|
+
width: 128px;
|
|
16
|
+
height: 128px;
|
|
17
|
+
background: ${Surface.Default};
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: row;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
align-items: center;
|
|
22
|
+
padding: ${Padding.none};
|
|
23
|
+
`
|
|
24
|
+
|
|
25
|
+
const ShadowSm = styled(Container)`
|
|
26
|
+
${shadowSm}
|
|
27
|
+
`
|
|
28
|
+
const Shadow = styled(Container)`
|
|
29
|
+
${shadow}
|
|
30
|
+
`
|
|
31
|
+
|
|
32
|
+
const ShadowMd = styled(Container)`
|
|
33
|
+
${shadowMd}
|
|
34
|
+
`
|
|
35
|
+
const ShadowLg = styled(Container)`
|
|
36
|
+
${shadowLg}
|
|
37
|
+
`
|
|
38
|
+
|
|
39
|
+
const ShadowXl = styled(Container)`
|
|
40
|
+
${shadowXl}
|
|
41
|
+
`
|
|
42
|
+
|
|
43
|
+
const Shadow2Xl = styled(Container)`
|
|
44
|
+
${shadow2Xl}
|
|
45
|
+
`
|
|
46
|
+
|
|
47
|
+
const ShadowInner = styled(Container)`
|
|
48
|
+
${shadowInner}
|
|
49
|
+
`
|
|
50
|
+
|
|
51
|
+
export {
|
|
52
|
+
ShadowSm,
|
|
53
|
+
Shadow,
|
|
54
|
+
ShadowLg,
|
|
55
|
+
ShadowMd,
|
|
56
|
+
ShadowXl,
|
|
57
|
+
Shadow2Xl,
|
|
58
|
+
ShadowInner,
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './shadows'
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Canvas, Meta } from '@storybook/addon-docs';
|
|
2
|
+
import {
|
|
3
|
+
ShadowSm,
|
|
4
|
+
Shadow,
|
|
5
|
+
Shadow2Xl,
|
|
6
|
+
ShadowInner,
|
|
7
|
+
ShadowMd,
|
|
8
|
+
ShadowLg,
|
|
9
|
+
ShadowXl
|
|
10
|
+
} from './components'
|
|
11
|
+
|
|
12
|
+
<Meta title="Foundations/Shadows"/>
|
|
13
|
+
|
|
14
|
+
# Shadows
|
|
15
|
+
|
|
16
|
+
For more details, check out the guidelines on [Figma](https://www.figma.com/file/ue1CurHfZ426o2T2l8Dk64/UI-Library-(in-progress)?node-id=743%3A7913)
|
|
17
|
+
|
|
18
|
+
## How to use
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
// Import the shadow that we'd like to use.
|
|
22
|
+
import {
|
|
23
|
+
shadowSm,
|
|
24
|
+
} from './shadows';
|
|
25
|
+
|
|
26
|
+
import styled from 'styled-components';
|
|
27
|
+
|
|
28
|
+
// Add them to the styled strucute that you'd like to add the shadow
|
|
29
|
+
const ShadowSm = styled.div`
|
|
30
|
+
${shadowSm}
|
|
31
|
+
`
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Examples
|
|
35
|
+
|
|
36
|
+
<Canvas>
|
|
37
|
+
<ShadowSm>
|
|
38
|
+
.shadow-sm
|
|
39
|
+
</ShadowSm>
|
|
40
|
+
<Shadow>
|
|
41
|
+
.shadow
|
|
42
|
+
</Shadow>
|
|
43
|
+
<ShadowMd>
|
|
44
|
+
.shadow-md
|
|
45
|
+
</ShadowMd>
|
|
46
|
+
<ShadowLg>
|
|
47
|
+
.shadow-lg
|
|
48
|
+
</ShadowLg>
|
|
49
|
+
<ShadowXl>
|
|
50
|
+
.shadow-xl
|
|
51
|
+
</ShadowXl>
|
|
52
|
+
<Shadow2Xl>
|
|
53
|
+
.shadow-2xl
|
|
54
|
+
</Shadow2Xl>
|
|
55
|
+
<ShadowInner>
|
|
56
|
+
.shadow-inner
|
|
57
|
+
</ShadowInner>
|
|
58
|
+
</Canvas>
|
|
59
|
+
|
|
60
|
+
## List of Values
|
|
61
|
+
|
|
62
|
+
| Name |
|
|
63
|
+
| ---- |
|
|
64
|
+
| `shadowSm` |
|
|
65
|
+
| `shadow` |
|
|
66
|
+
| `shadowMd` |
|
|
67
|
+
| `shadowLg` |
|
|
68
|
+
| `shadowXl` |
|
|
69
|
+
| `shadow2Xl` |
|
|
70
|
+
| `shadowInner` |
|
|
71
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { css } from 'styled-components'
|
|
2
|
+
|
|
3
|
+
const shadowSm = css`
|
|
4
|
+
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.05);
|
|
5
|
+
border-radius: 6px;
|
|
6
|
+
`
|
|
7
|
+
|
|
8
|
+
const shadow = css`
|
|
9
|
+
box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1), 0px 1px 2px rgba(0, 0, 0, 0.06);
|
|
10
|
+
border-radius: 6px;
|
|
11
|
+
`
|
|
12
|
+
|
|
13
|
+
const shadowMd = css`
|
|
14
|
+
box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1);
|
|
15
|
+
border-radius: 6px;
|
|
16
|
+
`
|
|
17
|
+
|
|
18
|
+
const shadowLg = css`
|
|
19
|
+
box-shadow: 0px 10px 15px -3px rgba(0, 0, 0, 0.1), 0px 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
20
|
+
border-radius: 6px;
|
|
21
|
+
`
|
|
22
|
+
|
|
23
|
+
const shadowXl = css`
|
|
24
|
+
box-shadow: 0px 20px 25px -5px rgba(0, 0, 0, 0.1), 0px 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
25
|
+
border-radius: 6px;
|
|
26
|
+
`
|
|
27
|
+
|
|
28
|
+
const shadow2Xl = css`
|
|
29
|
+
box-shadow: 0px 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
30
|
+
border-radius: 6px;
|
|
31
|
+
`
|
|
32
|
+
|
|
33
|
+
const shadowInner = css`
|
|
34
|
+
box-shadow: inset 0px 2px 4px rgba(0, 0, 0, 0.06);
|
|
35
|
+
border-radius: 6px;
|
|
36
|
+
`
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
shadowSm,
|
|
40
|
+
shadow,
|
|
41
|
+
shadowMd,
|
|
42
|
+
shadowLg,
|
|
43
|
+
shadowXl,
|
|
44
|
+
shadow2Xl,
|
|
45
|
+
shadowInner,
|
|
46
|
+
}
|
|
47
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './spacing-guidelines'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SPACING } from './spacing'
|
|
2
|
+
|
|
3
|
+
export const Padding = {
|
|
4
|
+
none: 0,
|
|
5
|
+
xxxs: SPACING.Size2,
|
|
6
|
+
xxs: SPACING.Size4,
|
|
7
|
+
xs: SPACING.Size8,
|
|
8
|
+
s: SPACING.Size12,
|
|
9
|
+
m: SPACING.Size16,
|
|
10
|
+
l: SPACING.Size24,
|
|
11
|
+
xl: SPACING.Size32,
|
|
12
|
+
} as const
|
|
13
|
+
|
|
14
|
+
export const Margin = {
|
|
15
|
+
none: 0,
|
|
16
|
+
xxxs: SPACING.Size2,
|
|
17
|
+
xxs: SPACING.Size4,
|
|
18
|
+
xs: SPACING.Size8,
|
|
19
|
+
s: SPACING.Size12,
|
|
20
|
+
m: SPACING.Size16,
|
|
21
|
+
l: SPACING.Size24,
|
|
22
|
+
xl: SPACING.Size32,
|
|
23
|
+
xxl: SPACING.Size64,
|
|
24
|
+
} as const
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Meta, Description } from '@storybook/addon-docs';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
<Meta title="Foundations/Spacing" />
|
|
5
|
+
|
|
6
|
+
# Spacing System
|
|
7
|
+
|
|
8
|
+
All spacing for components and typography is done in increments of 8 pixels.
|
|
9
|
+
This forms the basic unit of measurement for spacing.
|
|
10
|
+
|
|
11
|
+
For more details, check out the guidelines on [Figma](https://www.figma.com/file/ue1CurHfZ426o2T2l8Dk64/UI-Library-(in-progress)?node-id=388%3A364)
|
|
12
|
+
|
|
13
|
+
## How to use
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
import SPACING from './spacing'
|
|
17
|
+
|
|
18
|
+
//get the token value
|
|
19
|
+
SPACING.[`YOUR-VALUE-HERE`]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## When to use
|
|
23
|
+
|
|
24
|
+
You can set this values from this props:
|
|
25
|
+
|
|
26
|
+
- width
|
|
27
|
+
- heigth
|
|
28
|
+
- margin
|
|
29
|
+
- padding
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
## List of Values
|
|
33
|
+
|
|
34
|
+
| Name | Value |
|
|
35
|
+
| ---- | ----- |
|
|
36
|
+
| `Size2` | 2px|
|
|
37
|
+
| `Size4` | 4px|
|
|
38
|
+
| `Size8` | 8px|
|
|
39
|
+
| `Size12` | 12px|
|
|
40
|
+
| `Size16` | 16px|
|
|
41
|
+
| `Size24` | 24px|
|
|
42
|
+
| `Size32` | 32px|
|
|
43
|
+
| `Size64` | 64px|
|
|
44
|
+
| `Size96` | 96px|
|
|
45
|
+
| `Size128` | 128px|
|
|
46
|
+
| `Size192` | 192px|
|
|
47
|
+
| `Size256` | 256px|
|
|
48
|
+
| `Size384` | 384px|
|
|
49
|
+
| `Size512` | 512px|
|
|
50
|
+
| `Size640` | 640px|
|
|
51
|
+
| `Size768` | 768px|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export enum SPACING {
|
|
2
|
+
Size2 = '2px',
|
|
3
|
+
Size4 = '4px',
|
|
4
|
+
Size8 = '8px',
|
|
5
|
+
Size12 = '12px',
|
|
6
|
+
Size16 = '16px',
|
|
7
|
+
Size24 = '24px',
|
|
8
|
+
Size32 = '32px',
|
|
9
|
+
Size64 = '64px',
|
|
10
|
+
Size96 = '96px',
|
|
11
|
+
Size128 = '128px',
|
|
12
|
+
Size192 = '192px',
|
|
13
|
+
Size256 = '256px',
|
|
14
|
+
Size384 = '384px',
|
|
15
|
+
Size512 = '512px',
|
|
16
|
+
Size640 = '640px',
|
|
17
|
+
Size768 = '768px',
|
|
18
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
|
|
2
|
+
export const enum FontWeight {
|
|
3
|
+
Regular = '400',
|
|
4
|
+
Medium = '500',
|
|
5
|
+
SemiBold = '600',
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const FontSize = {
|
|
9
|
+
a: '13px',
|
|
10
|
+
b: '14px',
|
|
11
|
+
c: '16px',
|
|
12
|
+
d: '18px',
|
|
13
|
+
e: '20px',
|
|
14
|
+
f: '28px',
|
|
15
|
+
g: '36px',
|
|
16
|
+
} as const
|
|
17
|
+
|
|
18
|
+
export const LineHeight = {
|
|
19
|
+
a: '16px',
|
|
20
|
+
b: '20px',
|
|
21
|
+
c: '24px',
|
|
22
|
+
d: '28px',
|
|
23
|
+
e: '32px',
|
|
24
|
+
f: '44px',
|
|
25
|
+
} as const
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './typography'
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { bitwiseOr, MappedEnum, PropsWithChildren, RequireOnlyOne } from '@helpers'
|
|
2
|
+
import { Text } from '../color-system'
|
|
3
|
+
|
|
4
|
+
export const enum TextAspects {
|
|
5
|
+
default = 1,
|
|
6
|
+
subdued = 2,
|
|
7
|
+
light = 4,
|
|
8
|
+
critical = 8,
|
|
9
|
+
success = 16,
|
|
10
|
+
onPrimary = 32,
|
|
11
|
+
onCritical = 64,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type TextOptions<T> = MappedEnum<typeof TextAspects, T>
|
|
15
|
+
|
|
16
|
+
function toTextAspect(n: number): TextAspects {
|
|
17
|
+
switch (n) {
|
|
18
|
+
case TextAspects.subdued: return TextAspects.subdued
|
|
19
|
+
case TextAspects.light: return TextAspects.light
|
|
20
|
+
case TextAspects.critical: return TextAspects.critical
|
|
21
|
+
case TextAspects.success: return TextAspects.success
|
|
22
|
+
case TextAspects.onPrimary: return TextAspects.onPrimary
|
|
23
|
+
case TextAspects.onCritical: return TextAspects.onCritical
|
|
24
|
+
default: return TextAspects.default
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const TextAspectColors = {
|
|
29
|
+
[TextAspects.default]: Text.Default,
|
|
30
|
+
[TextAspects.subdued]: Text.Subdued,
|
|
31
|
+
[TextAspects.light]: Text.Light,
|
|
32
|
+
[TextAspects.onPrimary]: Text.OnPrimary,
|
|
33
|
+
[TextAspects.onCritical]: Text.OnPrimary,
|
|
34
|
+
[TextAspects.success]: Text.Success,
|
|
35
|
+
[TextAspects.critical]: Text.Critical,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type ITextAspectProps = Partial<RequireOnlyOne<TextOptions<boolean>>> & PropsWithChildren
|
|
39
|
+
|
|
40
|
+
export function getTextAspect(props: ITextAspectProps) {
|
|
41
|
+
return TextAspectColors[
|
|
42
|
+
toTextAspect(
|
|
43
|
+
bitwiseOr([
|
|
44
|
+
props.default,
|
|
45
|
+
props.subdued,
|
|
46
|
+
props.light,
|
|
47
|
+
props.critical,
|
|
48
|
+
props.success,
|
|
49
|
+
props.onPrimary,
|
|
50
|
+
props.onCritical,
|
|
51
|
+
])
|
|
52
|
+
)
|
|
53
|
+
]
|
|
54
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { css } from 'styled-components'
|
|
2
|
+
import { getTextAspect, ITextAspectProps } from './text-aspect-flags'
|
|
3
|
+
import { FontWeight, FontSize, LineHeight } from './constants'
|
|
4
|
+
import { is } from '@helpers'
|
|
5
|
+
|
|
6
|
+
export type ITextProps = ITextAspectProps & { emphasis?: boolean }
|
|
7
|
+
|
|
8
|
+
const LightText = css`
|
|
9
|
+
color: ${getTextAspect({ light: true })};
|
|
10
|
+
`
|
|
11
|
+
|
|
12
|
+
const Base = css<ITextProps>`
|
|
13
|
+
color: ${(props) => getTextAspect(props)};
|
|
14
|
+
font-family: 'Inter';
|
|
15
|
+
`
|
|
16
|
+
|
|
17
|
+
const Display = css<ITextProps>`
|
|
18
|
+
${Base}
|
|
19
|
+
font-weight: ${FontWeight.Regular};
|
|
20
|
+
font-size: ${FontSize.g};
|
|
21
|
+
line-height: ${LineHeight.f};
|
|
22
|
+
`
|
|
23
|
+
|
|
24
|
+
const Heading1 = css<ITextProps>`
|
|
25
|
+
${Base}
|
|
26
|
+
font-weight: ${FontWeight.SemiBold};
|
|
27
|
+
font-size: ${FontSize.f};
|
|
28
|
+
line-height: ${LineHeight.e};
|
|
29
|
+
`
|
|
30
|
+
|
|
31
|
+
const Heading2 = css<ITextProps>`
|
|
32
|
+
${Heading1}
|
|
33
|
+
font-size: ${FontSize.e};
|
|
34
|
+
line-height: ${LineHeight.d};
|
|
35
|
+
`
|
|
36
|
+
|
|
37
|
+
const Heading3 = css<ITextProps>`
|
|
38
|
+
${Heading1}
|
|
39
|
+
font-size: ${FontSize.c};
|
|
40
|
+
line-height: ${LineHeight.c};
|
|
41
|
+
`
|
|
42
|
+
|
|
43
|
+
const Heading4 = css<ITextProps>`
|
|
44
|
+
${Heading1}
|
|
45
|
+
font-size: ${FontSize.b};
|
|
46
|
+
line-height: ${LineHeight.b};
|
|
47
|
+
`
|
|
48
|
+
|
|
49
|
+
const BodyLarge = css<ITextProps>`
|
|
50
|
+
${Base}
|
|
51
|
+
font-weight: ${({ emphasis }) => is(emphasis) ? FontWeight.SemiBold : FontWeight.Regular};
|
|
52
|
+
font-size: ${FontSize.d};
|
|
53
|
+
line-height: ${LineHeight.d};
|
|
54
|
+
`
|
|
55
|
+
|
|
56
|
+
const Body = css<ITextProps>`
|
|
57
|
+
${BodyLarge}
|
|
58
|
+
font-weight: ${({ emphasis }) => is(emphasis) ? FontWeight.Medium : FontWeight.Regular};
|
|
59
|
+
font-size: ${FontSize.b};
|
|
60
|
+
line-height: ${LineHeight.b};
|
|
61
|
+
`
|
|
62
|
+
|
|
63
|
+
const Caption = css<ITextProps>`
|
|
64
|
+
${BodyLarge}
|
|
65
|
+
font-size: ${FontSize.a};
|
|
66
|
+
line-height: ${LineHeight.a};
|
|
67
|
+
`
|
|
68
|
+
|
|
69
|
+
const Label1 = css<ITextProps>`
|
|
70
|
+
${BodyLarge}
|
|
71
|
+
font-weight: ${({ emphasis }) => is(emphasis) ? FontWeight.Medium : FontWeight.Regular};
|
|
72
|
+
font-size: ${FontSize.b};
|
|
73
|
+
line-height: ${LineHeight.b};
|
|
74
|
+
`
|
|
75
|
+
|
|
76
|
+
const Label2 = css<ITextProps>`
|
|
77
|
+
${BodyLarge}
|
|
78
|
+
font-size: ${FontSize.a};
|
|
79
|
+
line-height: ${LineHeight.a};
|
|
80
|
+
`
|
|
81
|
+
|
|
82
|
+
export const Typography = {
|
|
83
|
+
Display,
|
|
84
|
+
Heading1,
|
|
85
|
+
Heading2,
|
|
86
|
+
Heading3,
|
|
87
|
+
Heading4,
|
|
88
|
+
BodyLarge,
|
|
89
|
+
Body,
|
|
90
|
+
Caption,
|
|
91
|
+
Label1,
|
|
92
|
+
Label2,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const _Typography = {
|
|
96
|
+
LightText,
|
|
97
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
2
|
+
import React, { FC as FunctionComponent, ForwardRefExoticComponent, ForwardRefRenderFunction, PropsWithChildren as PWC, PropsWithoutRef, RefAttributes } from 'react'
|
|
3
|
+
import { Slot } from './slots'
|
|
4
|
+
|
|
5
|
+
/** @see https://stackoverflow.com/a/49725198/29182 */
|
|
6
|
+
export type RequireOnlyOne<T, Keys extends keyof T = keyof T> = Pick<
|
|
7
|
+
T,
|
|
8
|
+
Exclude<keyof T, Keys>
|
|
9
|
+
> &
|
|
10
|
+
{
|
|
11
|
+
[K in Keys]-?: Required<Pick<T, K>> &
|
|
12
|
+
Partial<Record<Exclude<Keys, K>, undefined>>;
|
|
13
|
+
}[Keys];
|
|
14
|
+
|
|
15
|
+
export type MappedEnum<E, T> = {
|
|
16
|
+
[key in keyof E]: T;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type Values<T> = T[keyof T];
|
|
20
|
+
|
|
21
|
+
export type PropsWithChildren<T = unknown> = PWC<T>
|
|
22
|
+
|
|
23
|
+
// Our FC type adds the ability to specify sub-components such as Slots
|
|
24
|
+
// also, just good to wrap imports from 3rd parties in general
|
|
25
|
+
export type FC<
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
27
|
+
P = {},
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
29
|
+
E extends { [x: symbol]: FunctionComponent<PropsWithChildren> | typeof Slot } = {}
|
|
30
|
+
> = FunctionComponent<P>
|
|
31
|
+
& {
|
|
32
|
+
[key in keyof E]: E[key]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
36
|
+
type ExtensibleForwardRef<T, P = {}, E = {}> = ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>
|
|
37
|
+
& {
|
|
38
|
+
[key in keyof E]: E[key]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
42
|
+
export function forwardRef<T, P = {}, E = {}>(render: ForwardRefRenderFunction<T, P>): ExtensibleForwardRef<T, P, E> {
|
|
43
|
+
return React.forwardRef(render) as ExtensibleForwardRef<T, P, E>
|
|
44
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { FC, PropsWithChildren } from './generic-types'
|
|
2
|
+
import { isDefined } from './safe-navigation'
|
|
3
|
+
|
|
4
|
+
// eslint-disable-next-line no-null/no-null
|
|
5
|
+
export const Nothing: FC = () => null
|
|
6
|
+
|
|
7
|
+
export function maybeRender<T>(prop: T, JSX: JSX.Element) {
|
|
8
|
+
return isDefined(prop) && Boolean(prop) ? JSX : <Nothing />
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface IIfProps {
|
|
12
|
+
is: unknown
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const If: FC<PropsWithChildren<IIfProps>> = (props) => {
|
|
16
|
+
// eslint-disable-next-line react/jsx-no-useless-fragment
|
|
17
|
+
return maybeRender(props.is, <>{props.children}</>)
|
|
18
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export type Hex = `#${string}`
|
|
2
|
+
|
|
3
|
+
export function clamp(a: number, b: number, c: number) {
|
|
4
|
+
return Math.max(a, Math.min(b, c))
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function toHex(n: number, length: number): Hex {
|
|
8
|
+
return `#${n.toString(16).padStart(length, '0').toUpperCase()}`
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function concatHex(a: Hex, b: Hex): Hex {
|
|
12
|
+
return `#${a.slice(1) + b.slice(1)}`
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** given an array of boolean flags, bitwiseOr interprets them as an unsigned integer
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* bitwiseOr([false, true, false, true]) => 5 // 0b0101
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* This is useful for indexing into an enum:
|
|
22
|
+
*
|
|
23
|
+
* ```ts
|
|
24
|
+
* const enum Level {
|
|
25
|
+
* default = 0,
|
|
26
|
+
* info = 0,
|
|
27
|
+
* danger = 1,
|
|
28
|
+
* warning = 2
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* interface IProps {
|
|
32
|
+
* info?: boolean
|
|
33
|
+
* danger?: boolean
|
|
34
|
+
* warning?: boolean
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* function toLevel(n: number): Level {
|
|
38
|
+
* switch (n) {
|
|
39
|
+
* case Level.info: return Level.info
|
|
40
|
+
* case Level.danger: return Level.danger
|
|
41
|
+
* case Level.warning: return Level.warning
|
|
42
|
+
* default: return Level.default
|
|
43
|
+
* }
|
|
44
|
+
* }
|
|
45
|
+
*
|
|
46
|
+
* const level = bitwiseOr([props.info, props.danger, props.warning])
|
|
47
|
+
*
|
|
48
|
+
* const levelEnum = toLevel(level)
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export function bitwiseOr(flags: unknown[]): number {
|
|
52
|
+
return flags.reduce((mask: number, flag, i) => mask | (Number(flag) << i), 0)
|
|
53
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
|
|
2
|
+
/** even though we have null disabled in the repo,
|
|
3
|
+
* I still would not want isNil to skip checking null
|
|
4
|
+
* it is for juuuuust in case a third party sends us a null
|
|
5
|
+
* or something, and the types are not correct
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/* eslint-disable no-null/no-null */
|
|
9
|
+
/* eslint-disable @typescript-eslint/ban-types */
|
|
10
|
+
|
|
11
|
+
export function isNil<T>(value: T | undefined | null): value is undefined | null {
|
|
12
|
+
return value === null || value === undefined
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function isDefined<T>(value: T | undefined | null): value is T {
|
|
16
|
+
return !isNil(value)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function defaultTo<T>(value: T | undefined | null, fallback: T): T {
|
|
20
|
+
return isDefined(value) ? value : fallback
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function isEmpty<T extends { length: number }>(obj: T) {
|
|
24
|
+
return obj.length < 1
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** used for evaluating tri-state logic (true | false | undefined) */
|
|
28
|
+
export function is (pred?: boolean): boolean {
|
|
29
|
+
return isDefined(pred) && pred
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function safeArray<T>(arr: T[] | undefined | null): T[] {
|
|
33
|
+
return isDefined(arr) ? arr : []
|
|
34
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Children, PureComponent, ReactElement, ReactNode } from 'react'
|
|
2
|
+
import { PropsWithChildren } from './generic-types'
|
|
3
|
+
import { isDefined, isNil } from './safe-navigation'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @TODO these aren't quiiiiite right
|
|
7
|
+
*
|
|
8
|
+
* They all say they return ReactNode but I feel like JSX.Element or something
|
|
9
|
+
* is more accurate? The child type needs to include _anything react can render_
|
|
10
|
+
* but it should also allow the caller to cloneElement on the results so that
|
|
11
|
+
* they can do stuff like
|
|
12
|
+
*
|
|
13
|
+
* const sections = getSlots(Section, children)
|
|
14
|
+
* .map((el, i) => i === 0 ? cloneElement(el, { first: true }) : el)
|
|
15
|
+
*
|
|
16
|
+
* Right? I want this...
|
|
17
|
+
* */
|
|
18
|
+
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
function isReactElement (obj?: any): obj is ReactElement {
|
|
21
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
22
|
+
return isDefined(obj) && obj.hasOwnProperty('type')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
+
const isSlotOfType = <T extends typeof Slot>(type: T) => (obj?: any): obj is T => {
|
|
27
|
+
return isDefined(obj) && isReactElement(obj) && (Object.getPrototypeOf(obj.type) === type || obj.type === type)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const findSlotByType = <T extends typeof Slot>(type: T, children?: ReactNode): ReactNode => {
|
|
31
|
+
return Children.toArray(children).find(isSlotOfType(type))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const filterSlotByType = <T extends typeof Slot>(type: T, children?: ReactNode): ReactNode[] => {
|
|
35
|
+
return Children.toArray(children).filter(isSlotOfType(type))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class Slot<T = unknown> extends PureComponent<PropsWithChildren<T>> {
|
|
39
|
+
override render () {
|
|
40
|
+
return this.props.children
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function getChildren(children?: ReactNode): ReactNode[] {
|
|
45
|
+
return Children.toArray(children).filter((child) => !isSlotOfType(Slot)(child))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function getSlots<T extends typeof Slot>(slot: T, children?: ReactNode): ReactNode[] {
|
|
49
|
+
const result = filterSlotByType(slot, children)
|
|
50
|
+
|
|
51
|
+
if (isNil(result)) {
|
|
52
|
+
return []
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return result
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
|
+
function hasProps (obj: any): obj is { props: { children: ReactNode }} {
|
|
60
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
61
|
+
return isDefined(obj) && obj.hasOwnProperty('props')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function getSlot<T extends typeof Slot>(slot: T, children?: ReactNode): ReactNode {
|
|
65
|
+
const result = findSlotByType(slot, children)
|
|
66
|
+
|
|
67
|
+
if (isNil(result)) {
|
|
68
|
+
return undefined
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (hasProps(result)) {
|
|
72
|
+
return result
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return result
|
|
76
|
+
}
|