Skip to content

Commit

Permalink
Merge pull request #114 from oaknational/chore/PUPIL-439/documentatio…
Browse files Browse the repository at this point in the history
…n-improvements

PUPIL-439: Documentation improvements
  • Loading branch information
carlmw authored Feb 23, 2024
2 parents 5e693ae + 471c833 commit 97d8282
Show file tree
Hide file tree
Showing 85 changed files with 789 additions and 333 deletions.
36 changes: 29 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,45 @@
<img alt="Oak National Academy" src="https://github.com/oaknational/oak-components/assets/122096/3b34c863-ff79-403a-a38e-0c997003909c" width="300" style="margin-bottom: 2rem" />

# Oak Components

## Overview

This is a React Typescript components library which supports React and Next applications produced by [Oak National Academy](https://www.thenational.academy/). A storybook for the components can be found [here](https://lively-meringue-8ebd43.netlify.app/) please consult OnePassword for access.
This is a React Typescript components library which supports React and Next applications produced by [Oak National Academy](https://www.thenational.academy/). A Storybook for the components can be found [here](https://lively-meringue-8ebd43.netlify.app/) please consult 1Password for access.

## Installation

## Usage
This library is suitable for use in an app using React 18 and Next.js 13+

TODO: Instructions for how to add Oak Components to a React App
You can install it using `npm i @oaknational/oak-components` or any other package manager that supports the NPM registry.

## Install for development
## Development

1. Copy the example env config `cp .env.example .env`
2. Ask a colleague for the values to populate `.env`
3. run `nvm use`
4. run `npm install`
5. To view the storybook run `npm run storybook`

## Testing components inside a host app like OWA

Sometimes it isn't enough to develop entirely inside Storybook and it might be necessary to try local changes inside a target app. You can do this with [yalc](https://github.com/wclr/yalc)

1. Install yalc `npm i yalc -g`
2. Run `npm run publish:local` to add the package to yalc's local registry.
3. Inside the target app run `yalc add @oaknational/oak-components` — this will install the package from the local registry like it would from NPM
- 🚨 if you're an Oak engineer developing in OWA there is a convenience script and you should use `npm run use-local-components` instead
as it will perform some additional work to remove any existing installation of the package.
4. Now when you start your target app you should have access to the locally packaged version of the library
5. To uninstall the local package you can run `yalc remove @oaknational/oak-components` inside the target app
- 🚨 if you're an Oak engineer developing in OWA there is a convenience script and you should use `npm run remove-local-components` instead
as it will automaticallyt re-install the library from NPM.

## Structure

We're trying to follow the tenets of "Atomic design". [Brad Frost's book](https://atomicdesign.bradfrost.com/) is
a great resource if you're just starting out building your first component for this library. It's also a great reference
if you're in doubt as to where a component belongs (it can be a little fuzzy at times!).

Components are organised into a three tier hierarchical structure applying the following rules:

### Atoms
Expand All @@ -28,7 +50,7 @@ Components are organised into a three tier hierarchical structure applying the f
- Unstyled
- Avoid embedded logic and state
- No sub-components
(eg. Box)
(eg. `Box`)

### Molecules

Expand All @@ -38,7 +60,7 @@ Components are organised into a three tier hierarchical structure applying the f
- Styled
- Avoid embedded logic and state
- No sub-components
(eg. IconButton)
(eg. `IconButton`)

### Organisms

Expand All @@ -48,6 +70,6 @@ Components are organised into a three tier hierarchical structure applying the f
- Styled
- May contain embedded logic or state
- May be split into sub-components
(eg. SchoolInputForm)
(eg. `SchoolInputForm`)

NB. these rules are a work in progress. Modifications may be required as the library builds.
4 changes: 4 additions & 0 deletions src/Introduction.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { Markdown } from "@storybook/blocks";
import readme from "../README.md?raw";

<Markdown>{readme}</Markdown>
13 changes: 0 additions & 13 deletions src/components/atoms/InternalButton/InternalButton.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,6 @@ import { colorArgTypes } from "@/storybook-helpers/colorStyleHelpers";
import { spacingArgTypes } from "@/storybook-helpers/spacingStyleHelpers";
import { borderArgTypes } from "@/storybook-helpers/borderStyleHelpers";

/**
*
* An unstyled button to be used as a basis for all UI button components.
* The following callbacks are available for tracking focus events:
*
* ### onClick
* `onClick?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;`
* ### onHovered
* `onHovered?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>, duration: number) => void;`<br>
* called after a mouseEnter and mouseLeave event has happened
*/

const meta: Meta<typeof InternalButton> = {
component: InternalButton,
tags: ["autodocs"],
Expand Down
17 changes: 15 additions & 2 deletions src/components/atoms/InternalButton/InternalButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
DropShadowStyleProps,
} from "@/styles/utils/dropShadowStyle";
import { borderStyle, BorderStyleProps } from "@/styles/utils/borderStyle";
import { PolymorphicPropsWithoutRef } from "@/components/utils/polymorphic";
import { PolymorphicPropsWithoutRef } from "@/components/polymorphic";

type StyledButtonProps = TypographyStyleProps &
SpacingStyleProps &
Expand Down Expand Up @@ -87,7 +87,20 @@ const UnstyledInternalButton = <C extends ElementType = "button">(
);
};

// NB. We must export a styled component for it to be inheritable
/**
*
* An unstyled button to be used as a basis for all UI button components.
* The following callbacks are available for tracking focus events:
*
* ### onClick
* `onClick?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;`
* ### onHovered
* `onHovered?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>, duration: number) => void;`<br>
* called after a mouseEnter and mouseLeave event has happened
*
* NB. We must export a styled component for it to be inheritable
*/
export const InternalButton = styled(UnstyledInternalButton)`
${internalButtonCss}
`;
6 changes: 0 additions & 6 deletions src/components/atoms/InternalCard/InternalCard.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@ import { Meta, StoryObj } from "@storybook/react";

import { InternalCard, InternalCardProps } from "./InternalCard";

/**
*
* InternalCard extends OakFlex. It has all the props of OakFlex, but applies default styles for consistency.
*
*/

const meta: Meta<typeof InternalCard> = {
component: InternalCard,
tags: ["autodocs"],
Expand Down
6 changes: 6 additions & 0 deletions src/components/atoms/InternalCard/InternalCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ import styled from "styled-components";
import { OakFlex, OakFlexProps } from "@/components/atoms/OakFlex";

export type InternalCardProps = OakFlexProps;

/**
*
* InternalCard extends OakFlex. It has all the props of OakFlex, but applies default styles for consistency.
*
*/
const InternalCard = styled(OakFlex)``;

InternalCard.defaultProps = {
Expand Down
35 changes: 0 additions & 35 deletions src/components/atoms/InternalCheckBox/InternalCheckBox.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,41 +14,6 @@ import { spacingArgTypes } from "@/storybook-helpers/spacingStyleHelpers";
import { borderArgTypes } from "@/storybook-helpers/borderStyleHelpers";
import { sizeArgTypes } from "@/storybook-helpers/sizeStyleHelpers";

/**
*
* These components can be used with InternalCheckBoxWrapper which allows for customisable icons
*
* Several flavours of checkbox are created here:
* - Default
* - Hover decorations
* - Focus decorations
* - Hover + Focus decorations
*
* NB. Hover decorations must be wrapped in a box with position relative to allow for the hover effect to work
*
* As they are styled components they can be further customised in implementation. Alternatively additional
* components can be created here.
*
*
* ## Events
* The following callbacks are available for tracking focus events:
*
* ### onChange
* onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
*
* ### onFocus
* onFocus?: (event: React.FocusEvent<HTMLInputElement>) => void;
*
* ### onBlur
* onBlur?: (event: React.FocusEvent<HTMLInputElement>) => void;
*
* ### onHovered
* `onHovered?: (id, value, duration: number) => void;`<br>
* called after a mouseEnter and mouseLeave event has happened
*
*
*/

const meta: Meta<typeof InternalCheckBox> = {
component: InternalCheckBox,
tags: ["autodocs"],
Expand Down
34 changes: 34 additions & 0 deletions src/components/atoms/InternalCheckBox/InternalCheckBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,40 @@ type HoverBaseCheckBoxProps = {
$hoverBorderRadius: OakBorderRadiusToken;
};

/**
*
* These components can be used with InternalCheckBoxWrapper which allows for customisable icons
*
* Several flavours of checkbox are created here:
* - Default
* - Hover decorations
* - Focus decorations
* - Hover + Focus decorations
*
* NB. Hover decorations must be wrapped in a box with position relative to allow for the hover effect to work
*
* As they are styled components they can be further customised in implementation. Alternatively additional
* components can be created here.
*
*
* ## Events
* The following callbacks are available for tracking focus events:
*
* ### onChange
* onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
*
* ### onFocus
* onFocus?: (event: React.FocusEvent<HTMLInputElement>) => void;
*
* ### onBlur
* onBlur?: (event: React.FocusEvent<HTMLInputElement>) => void;
*
* ### onHovered
* `onHovered?: (id, value, duration: number) => void;`<br>
* called after a mouseEnter and mouseLeave event has happened
*
*
*/
export const InternalCheckBox = styled(BaseCheckBox)<StyledBaseCheckBoxProps>`
/* removing default appearance */
-webkit-appearance: none;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@ import { InternalCheckBoxLabel } from "./InternalCheckBoxLabel";

import { flexArgTypes } from "@/storybook-helpers/flexStyleHelpers";

/**
*
* Specialised Label Component can be used and extended to create various different versions of CheckboxLabels
*
*/

const meta: Meta<typeof InternalCheckBoxLabel> = {
component: InternalCheckBoxLabel,
tags: ["autodocs"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ export type InternalCheckBoxLabelProps = {
"data-testid"?: string;
} & OakLabelProps;

/**
*
* Specialised Label Component can be used and extended to create various different versions of CheckboxLabels
*
*/
export const InternalCheckBoxLabel = styled(
OakLabel,
)<InternalCheckBoxLabelProps>`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,6 @@ import { InternalCheckBoxWrapper } from "./InternalCheckBoxWrapper";
import { spacingArgTypes } from "@/storybook-helpers/spacingStyleHelpers";
import { InternalCheckBoxHoverFocus } from "@/components/atoms/InternalCheckBox/InternalCheckBox";

/**
*
* This component is a wrapper for the InternalCheckBox component. It allows for customisable icons.
*
* NB. size must have the same value as the InternalCheckBox width and height
*
*
*/

const meta: Meta<typeof InternalCheckBoxWrapper> = {
component: InternalCheckBoxWrapper,
tags: ["autodocs"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ export type InternalCheckBoxWrapperProps = {
checkedIcon?: React.JSX.Element;
};

/**
*
* This component is a wrapper for the InternalCheckBox component. It allows for customisable icons.
*
* NB. size must have the same value as the InternalCheckBox width and height
*
*
*/
export const InternalCheckBoxWrapper = (
props: InternalCheckBoxWrapperProps,
) => {
Expand Down
10 changes: 0 additions & 10 deletions src/components/atoms/OakAnchorTarget/OakAnchorTarget.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,6 @@ import {
OakAnchorTargetProps,
} from "@/components/atoms/OakAnchorTarget";

/**
*
* AnchorTarget is a component to enable in-page linking to a particular section
*
*
* Drop AnchorTarget inside a relative or absolulely positioned element without content, passing
* it a unique 'id'. Then link it elsewhere using `<a href='#${id}' />`.
*
*/

const meta: Meta<typeof OakAnchorTarget> = {
component: OakAnchorTarget,
tags: ["autodocs"],
Expand Down
5 changes: 2 additions & 3 deletions src/components/atoms/OakAnchorTarget/OakAnchorTarget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { PaddingStyleProps } from "@/styles/utils/spacingStyle";
import { parseSpacing } from "@/styles/helpers/parseSpacing";
import { responsiveStyle } from "@/styles/utils/responsiveStyle";

export type OakAnchorTargetProps = PaddingStyleProps;

/**
* * AnchorTarget is a component to enable in-page linking to a particular section
*
Expand All @@ -15,9 +17,6 @@ import { responsiveStyle } from "@/styles/utils/responsiveStyle";
* it a unique 'id'. Then link it elsewhere using `<a href='#${id}' />`.
*
* */

export type OakAnchorTargetProps = PaddingStyleProps;

export const OakAnchorTarget = styled.span<OakAnchorTargetProps>`
position: absolute;
top: 0;
Expand Down
13 changes: 0 additions & 13 deletions src/components/atoms/OakAspectRatio/OakAspectRatio.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,6 @@ import { OakAspectRatio, OakAspectRatioProps } from "./OakAspectRatio";

import { OakImage } from "@/components/atoms/OakImage";

/**
*
* AspectRatio provides a container of fixed aspect ratio
*
* ## Usage
* Use this component when you want to ensure a box has a certain aspect ratio.
* Wrap with component with <code>position: relative</code> and a width or min-width
* The 'ratio' prop is responsive, so you can pass an array e.g. <code>["3:2", "16:9"]</code>
* which will result in different aspect ratios on different screen widths.
* For an example usage, see the <code>CardImage</code> component.
*
*/

const meta: Meta<typeof OakAspectRatio> = {
component: OakAspectRatio,
tags: ["autodocs"],
Expand Down
1 change: 1 addition & 0 deletions src/components/atoms/OakAspectRatio/OakAspectRatio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const OakAspectRatioInner = styled.div`
export type OakAspectRatioProps = {
children?: React.ReactNode;
} & OakAspectRatioOuterProps;

/**
*
* AspectRatio provides a container of fixed aspect ratio
Expand Down
17 changes: 0 additions & 17 deletions src/components/atoms/OakBox/OakBox.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,6 @@ import { opacityArgTypes } from "@/storybook-helpers/opacityStyleHelpers";
import { zIndexArgTypes } from "@/storybook-helpers/zIndexStyleHelpers";
import { transitionArgTypes } from "@/storybook-helpers/transitionStyleHelpers";

/**
* OakBox exposes all the styles that are available styles on a div tag. These include:
* - color
* - size
* - display
* - spacing
* - position
* - border
* - opacity
* - z-index
* - typography
* - transition
* - transform
* - drop-shadow
*
*/

const meta: Meta<typeof OakBox> = {
component: OakBox,
tags: ["autodocs"],
Expand Down
Loading

0 comments on commit 97d8282

Please sign in to comment.