diff --git a/README.md b/README.md
deleted file mode 120000
index f0e93b5..0000000
--- a/README.md
+++ /dev/null
@@ -1 +0,0 @@
-packages/react-common-docs/src/pages/index.md
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f5fcd78
--- /dev/null
+++ b/README.md
@@ -0,0 +1,94 @@
+# Tesseract Design - React Common
+
+Common front-end components for Web using the [Tesseract design system](https://make.modal.sh/tesseract/design), written for [React](https://reactjs.org).
+
+Package:
+
+[![@tesseract-design/react-common](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=package&color=C78AB3&kind=name)](https://js.pack.modal.sh/-/web/detail/@tesseract-design/react-common)
+[![Version List](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=package&color=C78AB3&kind=version)](https://js.pack.modal.sh/-/web/detail/@tesseract-design/react-common#versions)
+
+Dependencies:
+
+[![React](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=react&kind=peerDependencies)](https://github.com/facebook/react)
+[![Styled Components](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=styled-components&kind=peerDependencies)](https://github.com/styled-components/styled-components)
+[![TypeScript](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=typescript&kind=devDependencies)](https://github.com/microsoft/typescript)
+[![Jest](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=jest&kind=devDependencies)](https://github.com/facebook/jest)
+[![Rollup](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=rollup&kind=devDependencies)](https://github.com/rollup/rollup)
+
+Check the [documentation](https://make.modal.sh/tesseract/web/react/common) for more details.
+
+## Installation
+
+This package resides primarily in the [Modal.sh JavaScript Package Registry](https://js.pack.modal.sh/). You will need to
+adjust configuration in your chosen package manager.
+
+With [Yarn v.1.x](https://classic.arnpkg.com), add this to your `.yarnrc` file:
+
+```yarnrc
+"@tesseract-design:registry" "https://js.pack.modal.sh/"
+```
+
+Then, install the package by running the following command:
+
+```shell script
+yarn add @tesseract-design/react-common
+```
+
+## Usage
+
+The package includes components as named exports. Simply import the components you need individually or use a namespace
+import, like so:
+
+```jsx harmony
+import * as React from 'react'
+import ReactDOM from 'react-dom'
+import * as T from '@tesseract-design/react-common'
+
+const LoginForm = etcProps => (
+
+)
+
+const mountNode = window.document.createElement('div')
+
+ReactDOM.render(
+ ,
+ mountNode,
+)
+
+window.document.body.appendChild(mountNode)
+```
+
+Detailed usage guides can be found in the documentation linked above.
+
+## TypeScript
+
+The package is written and tested using TypeScript. Thus, typings for consumption in TypeScript are bundled with the
+compiled source.
+
+## License
+
+MIT. See the LICENSE file on the package repository for the full text.
diff --git a/package.json b/package.json
index 509251f..fb29916 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "@tesseract-design/react-common",
"title": "React Common",
"org": "Tesseract Design",
- "version": "0.2.4",
+ "version": "0.2.5",
"description": "Common front-end components for Web using the Tesseract design system, written in React.",
"directories": {
"lib": "dist"
@@ -52,8 +52,7 @@
"prepublishOnly": "NODE_ENV=production rm -rf dist/ && rollup -c",
"test": "jest",
"build": "rm -rf dist/ && rollup -c",
- "generate": "plop",
- "docs": "docz"
+ "generate": "plop"
},
"peerDependencies": {
"@reach/slider": "^0.10.5",
diff --git a/packages/react-common-docs/brand.tsx b/packages/react-common-docs/brand.tsx
index f44677b..a0d68e3 100644
--- a/packages/react-common-docs/brand.tsx
+++ b/packages/react-common-docs/brand.tsx
@@ -19,7 +19,7 @@ const Title = styled('strong')({
const Org = styled('small')({
position: 'absolute',
- top: '-0.25em',
+ top: '-0.375em',
right: 0,
fontWeight: 600,
textTransform: 'lowercase',
diff --git a/packages/react-common-docs/public/theme.css b/packages/react-common-docs/public/theme.css
index 55009d0..c52b026 100644
--- a/packages/react-common-docs/public/theme.css
+++ b/packages/react-common-docs/public/theme.css
@@ -46,7 +46,7 @@
--font-family-base: 'Encode Sans', system-ui;
--font-stretch-base: semi-expanded;
--font-weight-base: 400;
- --line-height-base: 2;
+ --line-height-base: 2em;
--font-family-headings: 'Encode Sans', system-ui;
--font-stretch-headings: condensed;
--font-weight-headings: 100;
diff --git a/packages/react-common-docs/src/docgen.json b/packages/react-common-docs/src/docgen.json
index 55fd5e6..3a1b582 100644
--- a/packages/react-common-docs/src/docgen.json
+++ b/packages/react-common-docs/src/docgen.json
@@ -228,6 +228,24 @@
"type": {
"name": "(...args: any[]) => any"
}
+ },
+ "value": {
+ "defaultValue": null,
+ "description": "Value of the component.",
+ "name": "value",
+ "required": false,
+ "type": {
+ "name": "any"
+ }
+ },
+ "checked": {
+ "defaultValue": null,
+ "description": "Checked state of the component.",
+ "name": "checked",
+ "required": false,
+ "type": {
+ "name": "boolean"
+ }
}
}
},
@@ -331,6 +349,24 @@
"type": {
"name": "(...args: any[]) => any"
}
+ },
+ "value": {
+ "defaultValue": null,
+ "description": "Value of the component.",
+ "name": "value",
+ "required": false,
+ "type": {
+ "name": "any"
+ }
+ },
+ "checked": {
+ "defaultValue": null,
+ "description": "Checked state of the component.",
+ "name": "checked",
+ "required": false,
+ "type": {
+ "name": "boolean"
+ }
}
}
},
@@ -431,6 +467,15 @@
"name": "(...args: any[]) => any"
}
},
+ "value": {
+ "defaultValue": null,
+ "description": "Value of the component.",
+ "name": "value",
+ "required": false,
+ "type": {
+ "name": "any"
+ }
+ },
"hint": {
"defaultValue": {
"value": ""
@@ -452,6 +497,15 @@
"type": {
"name": "boolean"
}
+ },
+ "defaultValue": {
+ "defaultValue": null,
+ "description": "Default value of the component.",
+ "name": "defaultValue",
+ "required": false,
+ "type": {
+ "name": "any"
+ }
}
}
},
@@ -491,6 +545,24 @@
"name": "(...args: any[]) => any"
}
},
+ "value": {
+ "defaultValue": null,
+ "description": "Value of the component.",
+ "name": "value",
+ "required": false,
+ "type": {
+ "name": "any"
+ }
+ },
+ "defaultValue": {
+ "defaultValue": null,
+ "description": "Default value of the component.",
+ "name": "defaultValue",
+ "required": false,
+ "type": {
+ "name": "any"
+ }
+ },
"orientation": {
"defaultValue": {
"value": "horizontal"
@@ -521,6 +593,17 @@
"type": {
"name": "ReactText"
}
+ },
+ "fallback": {
+ "defaultValue": {
+ "value": false
+ },
+ "description": "Use the sSR-friendly rendering of the component.",
+ "name": "fallback",
+ "required": false,
+ "type": {
+ "name": "boolean"
+ }
}
}
},
@@ -612,6 +695,15 @@
"name": "(...args: any[]) => any"
}
},
+ "value": {
+ "defaultValue": null,
+ "description": "Value of the component.",
+ "name": "value",
+ "required": false,
+ "type": {
+ "name": "any"
+ }
+ },
"hint": {
"defaultValue": {
"value": ""
@@ -623,6 +715,15 @@
"name": "any"
}
},
+ "defaultValue": {
+ "defaultValue": null,
+ "description": "Default value of the component.",
+ "name": "defaultValue",
+ "required": false,
+ "type": {
+ "name": "any"
+ }
+ },
"indicator": {
"defaultValue": {
"value": null
diff --git a/packages/react-common-docs/src/pages/components/Icon.mdx b/packages/react-common-docs/src/pages/components/Icon.mdx
index b4a8cca..0d497f9 100644
--- a/packages/react-common-docs/src/pages/components/Icon.mdx
+++ b/packages/react-common-docs/src/pages/components/Icon.mdx
@@ -19,3 +19,7 @@ import Header from '../../components/Header/Header'
## Props
+
+## See Also
+
+- [Feather Icons](https://feathericons.com) for a list of icon names.
diff --git a/packages/react-common-docs/src/pages/components/TextInput.mdx b/packages/react-common-docs/src/pages/components/TextInput.mdx
index 28b9bfa..9632a02 100644
--- a/packages/react-common-docs/src/pages/components/TextInput.mdx
+++ b/packages/react-common-docs/src/pages/components/TextInput.mdx
@@ -70,7 +70,13 @@ some content that is best displayed outside the component instead of putting in
-
+
Consult the fees table for shipping fee details.
diff --git a/packages/react-common/src/components/Button/Button.test.tsx b/packages/react-common/src/components/Button/Button.test.tsx
index da96c88..3294aae 100644
--- a/packages/react-common/src/components/Button/Button.test.tsx
+++ b/packages/react-common/src/components/Button/Button.test.tsx
@@ -6,7 +6,7 @@ import * as Enzyme from 'enzyme'
import * as Axe from 'jest-axe'
import * as React from 'react'
import Button, { Variant, ButtonElement } from './Button'
-import stringify from '../../services/stringify'
+import stringify from '../../utilities/stringify'
const CUSTOM_VARIANTS: string[] = ['primary']
diff --git a/packages/react-common/src/components/Button/Button.tsx b/packages/react-common/src/components/Button/Button.tsx
index fabe63c..99dde99 100644
--- a/packages/react-common/src/components/Button/Button.tsx
+++ b/packages/react-common/src/components/Button/Button.tsx
@@ -1,8 +1,8 @@
import * as React from 'react'
import * as PropTypes from 'prop-types'
import styled, { CSSObject } from 'styled-components'
-import { Size, SizeMap } from '../../services/utilities'
-import stringify from '../../services/stringify'
+import { Size, SizeMap } from '../../utilities/utilities'
+import stringify from '../../utilities/stringify'
export type Variant = 'outline' | 'primary'
diff --git a/packages/react-common/src/components/Checkbox/Checkbox.test.tsx b/packages/react-common/src/components/Checkbox/Checkbox.test.tsx
index 8260f98..8821096 100644
--- a/packages/react-common/src/components/Checkbox/Checkbox.test.tsx
+++ b/packages/react-common/src/components/Checkbox/Checkbox.test.tsx
@@ -6,7 +6,7 @@ import * as Enzyme from 'enzyme'
import * as Axe from 'jest-axe'
import * as React from 'react'
import Checkbox from './Checkbox'
-import stringify from '../../services/stringify'
+import stringify from '../../utilities/stringify'
it('should exist', () => {
expect(Checkbox).toBeDefined()
diff --git a/packages/react-common/src/components/Checkbox/Checkbox.tsx b/packages/react-common/src/components/Checkbox/Checkbox.tsx
index 562d7cb..fa57e0d 100644
--- a/packages/react-common/src/components/Checkbox/Checkbox.tsx
+++ b/packages/react-common/src/components/Checkbox/Checkbox.tsx
@@ -1,7 +1,7 @@
import * as React from 'react'
import * as PropTypes from 'prop-types'
import styled from 'styled-components'
-import stringify from '../../services/stringify'
+import stringify from '../../utilities/stringify'
import Icon from '../Icon/Icon'
const Base = styled('div')({
@@ -107,6 +107,7 @@ const Label = styled('span')({
width: 'calc(100% - 2.5rem)',
fontFamily: 'var(--font-family-base, sans-serif)',
pointerEvents: 'none',
+ marginTop: '-0.25em',
})
const LabelContent = styled('span')({
@@ -135,6 +136,14 @@ const propTypes = {
* Event handler triggered when the component loses focus.
*/
onBlur: PropTypes.func,
+ /**
+ * Value of the component.
+ */
+ value: PropTypes.any,
+ /**
+ * Checked state of the component.
+ */
+ checked: PropTypes.bool,
}
type Props = PropTypes.InferProps
@@ -143,9 +152,8 @@ type Props = PropTypes.InferProps
* Component for values that have an on/off state.
* @see {@link Select} for a similar component suitable for selecting more values.
* @see {@link RadioButton} for a similar component on selecting a single value among very few choices.
- * @type {React.ComponentType<{readonly label?: string} & React.ClassAttributes>}
*/
-const Checkbox = React.forwardRef(({ label = '', name, onChange, onFocus, onBlur }, ref) => (
+const Checkbox = React.forwardRef(({ label = '', name, onChange, onFocus, onBlur, value, checked, }, ref) => (
(({ label = '', name,
onChange={onChange as React.ChangeEventHandler}
onFocus={onFocus as React.FocusEventHandler}
onBlur={onBlur as React.FocusEventHandler}
+ value={value}
+ checked={checked}
/>
diff --git a/packages/react-common/src/components/Icon/Icon.tsx b/packages/react-common/src/components/Icon/Icon.tsx
index 31dd102..da8025d 100644
--- a/packages/react-common/src/components/Icon/Icon.tsx
+++ b/packages/react-common/src/components/Icon/Icon.tsx
@@ -3,7 +3,7 @@ import * as PropTypes from 'prop-types'
import * as FeatherIcon from 'react-feather'
import styled from 'styled-components'
import { pascalCase, pascalCaseTransformMerge } from 'pascal-case'
-import splitValueAndUnit from '../../services/splitValueAndUnit'
+import splitValueAndUnit from '../../utilities/splitValueAndUnit'
const Label = styled('span')({
position: 'absolute',
@@ -45,11 +45,11 @@ type Props = PropTypes.InferProps
/**
* Component for displaying graphics.
- * @param name
- * @param weight
- * @param size
- * @param label
- * @constructor
+ * @param name - Name of the icon to display.
+ * @param weight - Width of the icon's strokes.
+ * @param size - Size of the icon. This controls both the width and the height.
+ * @param label - Description of what the component represents.
+ * @see {@link https://feathericons.com|Feather Icons} for a list of icon names.
*/
const Icon: React.FC = ({ name, weight = '0.125rem', size = '1.5rem', label = name }) => {
const iconName = pascalCase(name, { transform: pascalCaseTransformMerge })
diff --git a/packages/react-common/src/components/RadioButton/RadioButton.test.tsx b/packages/react-common/src/components/RadioButton/RadioButton.test.tsx
index b16f788..48abdb7 100644
--- a/packages/react-common/src/components/RadioButton/RadioButton.test.tsx
+++ b/packages/react-common/src/components/RadioButton/RadioButton.test.tsx
@@ -6,7 +6,7 @@ import * as Enzyme from 'enzyme'
import * as Axe from 'jest-axe'
import * as React from 'react'
import RadioButton from './RadioButton'
-import stringify from '../../services/stringify'
+import stringify from '../../utilities/stringify'
it('should exist', () => {
expect(RadioButton).toBeDefined()
diff --git a/packages/react-common/src/components/RadioButton/RadioButton.tsx b/packages/react-common/src/components/RadioButton/RadioButton.tsx
index 64f0550..18d2a78 100644
--- a/packages/react-common/src/components/RadioButton/RadioButton.tsx
+++ b/packages/react-common/src/components/RadioButton/RadioButton.tsx
@@ -1,7 +1,7 @@
import * as React from 'react'
import * as PropTypes from 'prop-types'
import styled from 'styled-components'
-import stringify from '../../services/stringify'
+import stringify from '../../utilities/stringify'
const Base = styled('div')({
display: 'block',
@@ -105,6 +105,7 @@ const Label = styled('span')({
width: 'calc(100% - 2.5rem)',
fontFamily: 'var(--font-family-base, sans-serif)',
pointerEvents: 'none',
+ marginTop: '-0.25em',
})
const LabelContent = styled('span')({
@@ -133,6 +134,14 @@ const propTypes = {
* Event handler triggered when the component loses focus.
*/
onBlur: PropTypes.func,
+ /**
+ * Value of the component.
+ */
+ value: PropTypes.any,
+ /**
+ * Checked state of the component.
+ */
+ checked: PropTypes.bool,
}
type Props = PropTypes.InferProps
@@ -144,7 +153,7 @@ type Props = PropTypes.InferProps
* @type {React.ComponentType<{readonly label?: string, readonly name?: string} & React.ClassAttributes>}
*/
const RadioButton = React.forwardRef(
- ({ label = '', name, onChange, onFocus, onBlur }, ref) => (
+ ({ label = '', name, onChange, onFocus, onBlur, value, checked, }, ref) => (
(
onChange={onChange as React.ChangeEventHandler}
onFocus={onFocus as React.FocusEventHandler}
onBlur={onBlur as React.FocusEventHandler}
+ value={value}
+ checked={checked}
/>
diff --git a/packages/react-common/src/components/Select/Select.test.tsx b/packages/react-common/src/components/Select/Select.test.tsx
index 7722302..21e6132 100644
--- a/packages/react-common/src/components/Select/Select.test.tsx
+++ b/packages/react-common/src/components/Select/Select.test.tsx
@@ -6,7 +6,7 @@ import * as Enzyme from 'enzyme'
import * as Axe from 'jest-axe'
import * as React from 'react'
import Select from './Select'
-import stringify from '../../services/stringify'
+import stringify from '../../utilities/stringify'
it('should exist', () => {
expect(Select).toBeDefined()
diff --git a/packages/react-common/src/components/Select/Select.tsx b/packages/react-common/src/components/Select/Select.tsx
index c0fe2f2..3ff87ea 100644
--- a/packages/react-common/src/components/Select/Select.tsx
+++ b/packages/react-common/src/components/Select/Select.tsx
@@ -1,8 +1,8 @@
import * as React from 'react'
import * as PropTypes from 'prop-types'
import styled from 'styled-components'
-import stringify from '../../services/stringify'
-import { Size, SizeMap } from '../../services/utilities'
+import stringify from '../../utilities/stringify'
+import { Size, SizeMap } from '../../utilities/utilities'
import Icon from '../Icon/Icon'
const MIN_HEIGHTS: SizeMap = {
@@ -216,6 +216,14 @@ const propTypes = {
* Event handler triggered when the component loses focus.
*/
onBlur: PropTypes.func,
+ /**
+ * Default value of the component.
+ */
+ defaultValue: PropTypes.any,
+ /**
+ * Value of the component.
+ */
+ value: PropTypes.any,
}
type Props = PropTypes.InferProps
@@ -237,7 +245,8 @@ const Select = React.forwardRef(
onChange,
onFocus,
onBlur,
- ...etcProps
+ defaultValue,
+ value,
},
ref,
) => {
@@ -261,7 +270,8 @@ const Select = React.forwardRef(
{stringify(label).length > 0 && ' '}
@@ -223,20 +236,20 @@ type Props = PropTypes.InferProps
* @param {*} [label] - Short textual description indicating the nature of the component's value.
* @param {string | number} [length] - CSS size for the component length.
* @param {boolean} [disabled] - Is the component active?
- * @returns {React.ReactElement} The component elements.
+ * @param [onChange] - Event handler triggered when the component changes value.
*/
-const Slider: React.FC = ({
+const Slider = React.forwardRef(({
orientation = 'horizontal',
label = '',
length = '16rem',
disabled = false,
onChange,
-}) => {
- const [isClient, setIsClient] = React.useState(false)
+ fallback = false,
+}, ref) => {
+ const isClient = useHydration()
React.useEffect(() => {
window.document.body.style.setProperty('--reach-slider', '1')
- setIsClient(true)
}, [])
const parallelDimension: Dimension = orientation === 'horizontal' ? 'width' : 'height'
@@ -255,7 +268,7 @@ const Slider: React.FC = ({
orient: orientation,
}
- if (isClient) {
+ if (!fallback && isClient) {
return (
= ({
cursor: disabled ? 'not-allowed' : undefined,
}}
onChange={onChange!}
+ ref={ref}
>
)
-}
+})
Slider.propTypes = propTypes
diff --git a/packages/react-common/src/components/TextInput/TextInput.test.tsx b/packages/react-common/src/components/TextInput/TextInput.test.tsx
index b0a20ff..5082179 100644
--- a/packages/react-common/src/components/TextInput/TextInput.test.tsx
+++ b/packages/react-common/src/components/TextInput/TextInput.test.tsx
@@ -6,7 +6,7 @@ import * as Enzyme from 'enzyme'
import * as Axe from 'jest-axe'
import * as React from 'react'
import TextInput from './TextInput'
-import stringify from '../../services/stringify'
+import stringify from '../../utilities/stringify'
it('should exist', () => {
expect(TextInput).toBeDefined()
diff --git a/packages/react-common/src/components/TextInput/TextInput.tsx b/packages/react-common/src/components/TextInput/TextInput.tsx
index a7f59e7..14ca99f 100644
--- a/packages/react-common/src/components/TextInput/TextInput.tsx
+++ b/packages/react-common/src/components/TextInput/TextInput.tsx
@@ -1,8 +1,8 @@
import * as React from 'react'
import * as PropTypes from 'prop-types'
import styled from 'styled-components'
-import stringify from '../../services/stringify'
-import { Size, SizeMap } from '../../services/utilities'
+import stringify from '../../utilities/stringify'
+import { Size, SizeMap } from '../../utilities/utilities'
// TODO implement web-client text inputs!
@@ -255,6 +255,14 @@ const propTypes = {
* Should the component be displayed with an alternate appearance?
*/
alternate: PropTypes.bool,
+ /**
+ * Default value of the component.
+ */
+ defaultValue: PropTypes.any,
+ /**
+ * Value of the component.
+ */
+ value: PropTypes.any,
}
type Props = PropTypes.InferProps
@@ -281,7 +289,8 @@ const TextInput = React.forwardRef (
@@ -306,7 +315,6 @@ const TextInput = React.forwardRef 0 && ' '}
{multiline && (
)}
{!multiline && (
)}
diff --git a/packages/react-common/src/utilities/hooks/useHydration.ts b/packages/react-common/src/utilities/hooks/useHydration.ts
new file mode 100644
index 0000000..5eadf9f
--- /dev/null
+++ b/packages/react-common/src/utilities/hooks/useHydration.ts
@@ -0,0 +1,13 @@
+import { useEffect, useState } from 'react'
+
+const useHydration = () => {
+ const [hydrated, setHydrated] = useState(false)
+
+ useEffect(() => {
+ setHydrated(true)
+ }, [])
+
+ return hydrated
+}
+
+export default useHydration
diff --git a/packages/react-common/src/services/isEmpty.test.ts b/packages/react-common/src/utilities/isEmpty.test.ts
similarity index 100%
rename from packages/react-common/src/services/isEmpty.test.ts
rename to packages/react-common/src/utilities/isEmpty.test.ts
diff --git a/packages/react-common/src/services/isEmpty.ts b/packages/react-common/src/utilities/isEmpty.ts
similarity index 100%
rename from packages/react-common/src/services/isEmpty.ts
rename to packages/react-common/src/utilities/isEmpty.ts
diff --git a/packages/react-common/src/services/splitValueAndUnit.test.ts b/packages/react-common/src/utilities/splitValueAndUnit.test.ts
similarity index 100%
rename from packages/react-common/src/services/splitValueAndUnit.test.ts
rename to packages/react-common/src/utilities/splitValueAndUnit.test.ts
diff --git a/packages/react-common/src/services/splitValueAndUnit.ts b/packages/react-common/src/utilities/splitValueAndUnit.ts
similarity index 100%
rename from packages/react-common/src/services/splitValueAndUnit.ts
rename to packages/react-common/src/utilities/splitValueAndUnit.ts
diff --git a/packages/react-common/src/services/stringify.test.ts b/packages/react-common/src/utilities/stringify.test.ts
similarity index 100%
rename from packages/react-common/src/services/stringify.test.ts
rename to packages/react-common/src/utilities/stringify.test.ts
diff --git a/packages/react-common/src/services/stringify.ts b/packages/react-common/src/utilities/stringify.ts
similarity index 100%
rename from packages/react-common/src/services/stringify.ts
rename to packages/react-common/src/utilities/stringify.ts
diff --git a/packages/react-common/src/services/utilities.ts b/packages/react-common/src/utilities/utilities.ts
similarity index 100%
rename from packages/react-common/src/services/utilities.ts
rename to packages/react-common/src/utilities/utilities.ts