├── .browserslistrc ├── .circleci └── config.yml ├── .editorconfig ├── .eslintrc.json ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── BUG.md │ ├── CHORE.md │ └── STORY.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .remarklintrc.json ├── .stylelintrc.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── VISION.md ├── __mocks__ ├── file-mock.js └── gatsby.js ├── _redirects ├── cypress.json ├── cypress ├── integration │ ├── a11y-spec.js │ └── e2e-spec.js ├── plugins │ └── index.js └── support │ └── index.js ├── gatsby-browser.js ├── gatsby-config.js ├── jest-preprocess.js ├── jest-setup.js ├── jest.config.js ├── loadershim.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── src ├── components │ ├── BackLink │ │ ├── index.css │ │ └── index.js │ ├── BlockQuote │ │ ├── index.css │ │ └── index.js │ ├── Breadcrumbs │ │ ├── index.css │ │ └── index.js │ ├── BulletedList │ │ ├── index.css │ │ └── index.js │ ├── Callout │ │ ├── index.css │ │ └── index.js │ ├── Callouts │ │ ├── index.css │ │ └── index.js │ ├── Caption │ │ ├── index.css │ │ └── index.js │ ├── CheckBox │ │ └── index.js │ ├── CheckBoxes │ │ └── index.js │ ├── Cite │ │ ├── index.css │ │ └── index.js │ ├── Code │ │ ├── index.css │ │ └── index.js │ ├── ColourFigure │ │ ├── index.css │ │ └── index.js │ ├── ColourGreyFigure │ │ ├── index.css │ │ └── index.js │ ├── Conditional │ │ ├── index.css │ │ └── index.js │ ├── Confirmation │ │ ├── index.css │ │ └── index.js │ ├── Content │ │ ├── index.css │ │ └── index.js │ ├── Contents │ │ ├── index.css │ │ └── index.js │ ├── ContentsMenu │ │ ├── index.css │ │ └── index.js │ ├── CurrencyInput │ │ ├── index.css │ │ └── index.js │ ├── DateInput │ │ ├── index.css │ │ └── index.js │ ├── Demo │ │ ├── index.css │ │ └── index.js │ ├── DemoItem │ │ ├── index.css │ │ └── index.js │ ├── Details │ │ ├── index.css │ │ └── index.js │ ├── DocSearch │ │ ├── index.css │ │ └── index.js │ ├── DownloadLink │ │ ├── index.css │ │ └── index.js │ ├── Error │ │ ├── index.css │ │ └── index.js │ ├── ErrorSummary │ │ ├── index.css │ │ └── index.js │ ├── Example │ │ ├── index.css │ │ └── index.js │ ├── Fact │ │ ├── index.css │ │ └── index.js │ ├── Feedback │ │ ├── index.css │ │ └── index.js │ ├── Field │ │ ├── index.css │ │ └── index.js │ ├── Fieldset │ │ ├── index.css │ │ └── index.js │ ├── Figure │ │ ├── index.css │ │ └── index.js │ ├── Figures │ │ ├── index.css │ │ └── index.js │ ├── Filter │ │ ├── cross.svg │ │ ├── index.css │ │ └── index.js │ ├── Footer │ │ ├── index.css │ │ └── index.js │ ├── Form │ │ ├── index.css │ │ └── index.js │ ├── Header │ │ ├── burger.svg │ │ ├── cross.svg │ │ ├── glass.svg │ │ ├── index.css │ │ ├── index.js │ │ └── logo.svg │ ├── Heading │ │ ├── index.css │ │ └── index.js │ ├── Hero │ │ ├── index.css │ │ └── index.js │ ├── Hint │ │ ├── index.css │ │ └── index.js │ ├── Image │ │ ├── index.css │ │ └── index.js │ ├── Label │ │ ├── index.css │ │ └── index.js │ ├── LandingMenu │ │ ├── index.css │ │ └── index.js │ ├── Layout │ │ ├── index.css │ │ └── index.js │ ├── Lede │ │ ├── index.css │ │ └── index.js │ ├── Link │ │ ├── index.css │ │ └── index.js │ ├── ListItem │ │ ├── index.css │ │ └── index.js │ ├── Main │ │ ├── index.css │ │ └── index.js │ ├── Menu │ │ ├── index.css │ │ └── index.js │ ├── NumberedList │ │ ├── index.css │ │ └── index.js │ ├── Page │ │ └── index.js │ ├── Pagination │ │ ├── index.css │ │ └── index.js │ ├── Paragraph │ │ ├── index.css │ │ └── index.js │ ├── Preformatted │ │ └── index.js │ ├── ProminentBlockQuote │ │ ├── index.css │ │ └── index.js │ ├── ProminentCallout │ │ ├── index.css │ │ └── index.js │ ├── ProminentLink │ │ ├── index.css │ │ └── index.js │ ├── ProminentTeaser │ │ ├── index.css │ │ └── index.js │ ├── PullQuote │ │ ├── index.css │ │ └── index.js │ ├── RadioButtons │ │ └── index.js │ ├── Search │ │ ├── glass.svg │ │ ├── index.css │ │ └── index.js │ ├── Section │ │ ├── index.css │ │ └── index.js │ ├── Sections │ │ ├── index.css │ │ └── index.js │ ├── SignpostLink │ │ ├── index.css │ │ └── index.js │ ├── Site │ │ ├── favicon.ico │ │ ├── index.css │ │ ├── index.js │ │ ├── reset.css │ │ └── viewport-scale.css │ ├── SkipLink │ │ ├── index.css │ │ └── index.js │ ├── SpacingFigure │ │ ├── index.css │ │ └── index.js │ ├── StartLink │ │ ├── index.css │ │ └── index.js │ ├── Subheading │ │ ├── index.css │ │ └── index.js │ ├── Submit │ │ ├── index.css │ │ └── index.js │ ├── Swatch │ │ ├── index.css │ │ └── index.js │ ├── Swatches │ │ ├── index.css │ │ └── index.js │ ├── Switch │ │ ├── index.css │ │ └── index.js │ ├── Switches │ │ ├── index.css │ │ └── index.js │ ├── Teaser │ │ ├── index.css │ │ └── index.js │ ├── Teasers │ │ ├── index.css │ │ └── index.js │ ├── TextArea │ │ ├── index.css │ │ └── index.js │ ├── TextInput │ │ ├── index.css │ │ └── index.js │ ├── Title │ │ ├── index.css │ │ ├── index.js │ │ └── index.test.js │ ├── Topic │ │ ├── index.css │ │ └── index.js │ ├── Trigger │ │ ├── index.css │ │ └── index.js │ ├── TypeFigures │ │ ├── index.css │ │ └── index.js │ ├── Video │ │ ├── index.css │ │ └── index.js │ ├── custom-properties.css │ └── index.js └── pages │ ├── 404.js │ ├── assets.js │ ├── assets │ ├── sketch-assets.js │ └── web-assets.js │ ├── components.js │ ├── components │ ├── content.js │ ├── forms.js │ ├── navigation.js │ └── structure.js │ ├── getting-started.js │ ├── getting-started │ └── contribute.js │ ├── index.js │ ├── patterns.js │ ├── patterns │ ├── filtering.js │ ├── gathering-information.js │ ├── interacting-with-young-people.js │ ├── preventing-spam.js │ └── start-page.js │ ├── principles.js │ ├── product-kit.js │ ├── standards.js │ └── standards │ ├── code-quality.js │ ├── colour.js │ ├── formatting.js │ ├── future-proof-code.js │ ├── iconography.js │ ├── images-and-videos.js │ ├── maintenance.js │ ├── performance.js │ ├── reading-age.js │ ├── spacing-and-layout.js │ ├── spelling.js │ ├── testing.js │ ├── typography.js │ ├── viewport-scale.js │ └── voice-and-tone.js ├── static ├── favicon-for-figure.svg ├── image-for-blockquote-example.jpg ├── image-for-caption-example.jpg ├── image-for-hero-example.jpg ├── image-for-image-example.jpg ├── image-for-interacting-example.jpg ├── image-for-prominent-teaser-example.jpg ├── image-for-teaser-example.jpg └── logo-for-figure.svg └── tsconfig.json /.browserslistrc: -------------------------------------------------------------------------------- 1 | defaults 2 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Javascript Node CircleCI 2.0 configuration file 2 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 3 | 4 | version: 2 5 | jobs: 6 | build: 7 | docker: 8 | - image: cypress/browsers:node8.15.1-chrome73 9 | environment: 10 | TERM: xterm 11 | 12 | working_directory: ~/app 13 | 14 | steps: 15 | - checkout 16 | 17 | - restore_cache: 18 | keys: 19 | - v2-dependencies-{{ checksum "package-lock.json" }} 20 | - v2-dependencies- 21 | 22 | - run: 23 | name: Check versions 24 | command: | 25 | node --version 26 | npm --version 27 | 28 | - run: npm ci 29 | 30 | - save_cache: 31 | paths: 32 | - node_modules 33 | key: v2-dependencies-{{ checksum "package-lock.json" }} 34 | 35 | - run: 36 | name: Run tests 37 | command: npm test 38 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@barnardos/eslint-config-barnardos"], 3 | "overrides": [ 4 | { 5 | "files": ["src/pages/**/*.js"], 6 | "rules": { 7 | "react/display-name": "off" 8 | } 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for wanting to contribute. We welcome contributions from everyone, both inside and outside Barnardo’s. 4 | 5 | If you’re unfamiliar with: 6 | 7 | - open source projects, refer to guidance on [how to contribute](https://opensource.guide/how-to-contribute) 8 | - the Barnardo’s development process, refer to the [developer manual](https://github.com/barnardos/developer-manual#contributing-code) 9 | 10 | ## Getting started 11 | 12 | First, install [Node.js](https://nodejs.org/en/). 13 | 14 | Then run these commands: 15 | 16 | - `npm install` - install all dependencies 17 | - `npm start` - start a development server 18 | 19 | You can watch tests using: 20 | 21 | - `npm run watch-unit-tests` 22 | - `npm run watch-e2e-tests` 23 | 24 | Before creating a PR you should run: 25 | 26 | - `npm run format` 27 | - `npm run test` 28 | 29 | Use `npm run` to see a list of all the other available commands. 30 | 31 | ## Known issues 32 | 33 | If you encounter an error, try deleting the `.cache` folder in the root of the project and run `npm start` again. 34 | 35 | ## Services 36 | 37 | The providers are: 38 | 39 | - [CircleCI](https://circleci.com) - continuous integration 40 | - [Netlify](https://www.netlify.com) - continuous deployment 41 | - [Google Analytics](https://analytics.google.com) - user analytics 42 | - [Project Wallace](https://www.projectwallace.com/~barnardos/design-system) - CSS analytics 43 | 44 | ### Netlify 45 | 46 | Deployment URLs: 47 | 48 | - [Site](https://barnardos-design-system.netlify.com) 49 | 50 | ## Releasing 51 | 52 | You should first publish to npm: 53 | 54 | 1. Run `npm --no-git-tag-version version major|minor|patch` to bump the version number in `package.json` and `package-lock.json`. 55 | 2. Update `CHANGELOG.md` and replace "Head" with the new version number. 56 | 3. Create a Pull Request with these changes. 57 | 4. Merge the Pull Request. 58 | 5. Run `npm publish` 59 | 60 | Then release to GitHub: 61 | 62 | 1. Create a [new release](https://github.com/barnardos/design-system/releases/new). 63 | 2. Enter the version number for the "Tag version" and "Release title". 64 | 3. Copy and paste the version items from `CHANGELOG.md`. 65 | 4. Publish release 66 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Bug" 3 | about: "Report a bug" 4 | --- 5 | 6 | ## Description 7 | 8 | ## Expected behaviour 9 | 10 | ## Actual behaviour 11 | 12 | ## Steps to reproduce 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/CHORE.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Chore" 3 | about: "Add a chore" 4 | --- 5 | 6 | ## Description 7 | 8 | ## Acceptance criteria 9 | 10 | - [ ] ... 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/STORY.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Story" 3 | about: "Write a user story" 4 | --- 5 | 6 | _As a [persona] 7 | I want [what] 8 | So that [why]_ 9 | 10 | ## Description 11 | 12 | ## Links and resources 13 | 14 | ## Acceptance criteria 15 | 16 | - [ ] Add component or pattern 17 | - [ ] Cross-browser test 18 | - [ ] Accessibility test 19 | - [ ] Add changelog entry 20 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Closes #000 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .DS_Store 3 | .cache 4 | cypress/fixtures 5 | cypress/screenshots 6 | cypress/videos 7 | public 8 | node_modules 9 | yarn.lock 10 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 10.15.0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .github/*.md 2 | package.json 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /.remarklintrc.json: -------------------------------------------------------------------------------- 1 | { "plugins": ["remark-preset-lint-itgalaxy"] } 2 | -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@barnardos/stylelint-config-barnardos" 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-present Barnardos Digital 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Design System 2 | 3 | ## Installation 4 | 5 | 1. Install latest LTS [Node.js](https://nodejs.org/en/). 6 | 2. Install the Barnardo’s Design System components using: 7 | 8 | ```shell 9 | npm install @barnardos/components 10 | ``` 11 | 12 | 3. Import the components you need. You can either import: 13 | 14 | - the React components (recommended) 15 | - just the CSS of the components 16 | 17 | ### Importing the React components 18 | 19 | Use named imports. 20 | 21 | For example, to import the `BackLink` and `Pagination` components: 22 | 23 | ```javascript 24 | // MyComponent/index.js 25 | import { BackLink, Pagination } from "@barnardos/components"; 26 | ``` 27 | 28 | ### Importing the CSS only 29 | 30 | If you aren’t using [React](https://reactjs.org), you can still use the CSS of each component. 31 | 32 | For example, to import the CSS of the `BackLink` and `Pagination` components: 33 | 34 | ```css 35 | /* src/index.css */ 36 | @import "node_modules/@barnardos/components/src/components/custom-properties.css"; 37 | @import "node_modules/@barnardos/components/src/components/BackLink/index.css"; 38 | @import "node_modules/@barnardos/components/src/components/Pagination/index.css"; 39 | ``` 40 | 41 | You’ll need to use [`postcss-present-env`](https://preset-env.cssdb.org) to transpile the CSS using the Design System’s [PostCSS](https://github.com/barnardos/design-system/blob/master/postcss.config.js) and [browserslist](https://github.com/barnardos/design-system/blob/master/.browserslistrc) configurations. 42 | 43 | --- 44 | 45 | Looking to contribute? View the [contributing guide](.github/CONTRIBUTING.md). 46 | -------------------------------------------------------------------------------- /VISION.md: -------------------------------------------------------------------------------- 1 | # Vision 2 | 3 | We should: 4 | 5 | - meet the needs of users 6 | - solve common problems 7 | - test with real people 8 | - deliver value quickly 9 | - maximise adoption 10 | - embrace change 11 | 12 | So that designers and developers can build products that allow users to successfully complete their journey. 13 | -------------------------------------------------------------------------------- /__mocks__/file-mock.js: -------------------------------------------------------------------------------- 1 | module.exports = "test-file-stub"; 2 | -------------------------------------------------------------------------------- /__mocks__/gatsby.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | const React = require("react"); 3 | const gatsby = jest.requireActual("gatsby"); 4 | 5 | module.exports = { 6 | ...gatsby, 7 | graphql: jest.fn(), 8 | Link: jest.fn().mockImplementation( 9 | // these props are invalid for an `a` tag 10 | ({ 11 | activeClassName, 12 | activeStyle, 13 | getProps, 14 | innerRef, 15 | ref, 16 | replace, 17 | to, 18 | ...rest 19 | }) => 20 | React.createElement("a", { 21 | ...rest, 22 | href: to 23 | }) 24 | ), 25 | StaticQuery: jest.fn(), 26 | useStaticQuery: jest.fn() 27 | }; 28 | -------------------------------------------------------------------------------- /_redirects: -------------------------------------------------------------------------------- 1 | # Redirect default Netlify subdomain to primary domain 2 | https://barnardos-design-system.netlify.com/* https://design-system.barnardos.org.uk/:splat 301! 3 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:8000" 3 | } 4 | -------------------------------------------------------------------------------- /cypress/integration/a11y-spec.js: -------------------------------------------------------------------------------- 1 | const urls = [ 2 | "components/content/", 3 | "components/navigation/", 4 | "components/forms/", 5 | "components/structure/" 6 | ]; 7 | 8 | describe("Components a11y standards", () => { 9 | urls.forEach(url => { 10 | it(`Should have no violations on "${url}"`, () => { 11 | cy.visit(url) 12 | .waitForRouteChange() 13 | .injectAxe() 14 | .configureAxe({ 15 | rules: [ 16 | { 17 | id: "html-has-lang", 18 | enabled: false 19 | }, 20 | { 21 | id: "heading-order", 22 | enabled: url === "components/content/" ? false : true 23 | } 24 | ] 25 | }) 26 | .checkA11y(); 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /cypress/integration/e2e-spec.js: -------------------------------------------------------------------------------- 1 | describe(`Drilling down to design standards colour page`, () => { 2 | it(`Successfully loads homepage`, () => { 3 | cy.visit(`/`).waitForRouteChange(); 4 | }); 5 | 6 | it(`Has link to standards page`, () => { 7 | cy.getByText("Standards").click(); 8 | cy.waitForRouteChange() 9 | .location(`pathname`) 10 | .should(`equal`, `/standards/`); 11 | }); 12 | 13 | it(`Has onwards link the colour page`, () => { 14 | cy.getByText("Colour").click(); 15 | cy.waitForRouteChange() 16 | .location(`pathname`) 17 | .should(`equal`, `/standards/colour/`); 18 | }); 19 | 20 | it(`Has the correct title`, () => { 21 | cy.queryByText("Colour").should("exist"); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | module.exports = (on, config) => {}; 3 | -------------------------------------------------------------------------------- /cypress/support/index.js: -------------------------------------------------------------------------------- 1 | import "cypress-axe"; 2 | import "gatsby-cypress/commands"; 3 | import "cypress-testing-library/add-commands"; 4 | -------------------------------------------------------------------------------- /gatsby-browser.js: -------------------------------------------------------------------------------- 1 | import "url-polyfill"; 2 | 3 | // :focus-within polyfil 4 | function focusWithin(e, t) { 5 | var n = Object(t).className, 6 | r = Object(t).attr || "focus-within", 7 | a = Object(t).force, 8 | c = []; 9 | try { 10 | if ((e.querySelector(":focus-within"), !a)) return i; 11 | } catch (e) { 12 | /* */ 13 | } 14 | function s() { 15 | for (var t; (t = c.pop()); ) 16 | r && t.removeAttribute(r), n && t.classList.remove(n); 17 | var a = e.activeElement; 18 | if (!/^(#document|HTML|BODY)$/.test(Object(a).nodeName)) 19 | for (; a && 1 === a.nodeType; ) 20 | r && a.setAttribute(r, ""), 21 | n && a.classList.add(n), 22 | c.push(a), 23 | (a = a.parentNode); 24 | } 25 | function i() { 26 | e.addEventListener("focus", s, !0), e.addEventListener("blur", s, !0); 27 | } 28 | return ( 29 | (function t() { 30 | /m/.test(e.readyState) 31 | ? (e.removeEventListener("readystatechange", t), i()) 32 | : e.addEventListener("readystatechange", t); 33 | })(), 34 | i 35 | ); 36 | } 37 | 38 | focusWithin(document); 39 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | siteUrl: `https://design-system.barnardos.org.uk` 4 | }, 5 | plugins: [ 6 | { 7 | resolve: `gatsby-plugin-google-analytics`, 8 | options: { 9 | trackingId: `${ 10 | process.env.CONTEXT !== "deploy-preview" 11 | ? process.env.GOOGLE_ANALYTICS_ID 12 | : "UA-000000-00" 13 | }`, 14 | head: false, 15 | anonymize: true, 16 | respectDNT: true 17 | } 18 | }, 19 | `gatsby-plugin-postcss`, 20 | `gatsby-plugin-react-helmet`, 21 | `gatsby-plugin-sitemap` 22 | ] 23 | }; 24 | -------------------------------------------------------------------------------- /jest-preprocess.js: -------------------------------------------------------------------------------- 1 | const babelOptions = { 2 | presets: ["babel-preset-gatsby"] 3 | }; 4 | 5 | module.exports = require("babel-jest").createTransformer(babelOptions); 6 | -------------------------------------------------------------------------------- /jest-setup.js: -------------------------------------------------------------------------------- 1 | import "jest-dom/extend-expect"; 2 | import "react-testing-library/cleanup-after-each"; 3 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/unambiguous */ 2 | module.exports = { 3 | transform: { 4 | "^.+\\.jsx?$": `/jest-preprocess.js` 5 | }, 6 | moduleNameMapper: { 7 | ".+\\.(css|styl|less|sass|scss)$": `identity-obj-proxy`, 8 | ".+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": `/__mocks__/file-mock.js` 9 | }, 10 | testPathIgnorePatterns: [`node_modules`, `.cache`], 11 | transformIgnorePatterns: [`node_modules/(?!(gatsby)/)`], 12 | globals: { 13 | __PATH_PREFIX__: `` 14 | }, 15 | testURL: `http://localhost`, 16 | setupFiles: [`/loadershim.js`], 17 | setupFilesAfterEnv: ["/jest-setup.js"] 18 | }; 19 | -------------------------------------------------------------------------------- /loadershim.js: -------------------------------------------------------------------------------- 1 | global.___loader = { 2 | enqueue: jest.fn() 3 | }; 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.1", 3 | "name": "@barnardos/components", 4 | "description": "Components of the Barnardo's Design System", 5 | "license": "MIT", 6 | "repository": "https://github.com/barnardos/design-system.git", 7 | "main": "src/components/index.js", 8 | "files": [ 9 | "src/components", 10 | "!*DS_Store" 11 | ], 12 | "scripts": { 13 | "lint:css": "stylelint '**/*.{css,js}' --max-warnings=0 --ignore-path .gitignore", 14 | "lint:md": "remark . --quiet --frail --rc-path .remarklintrc.json --ignore-path .gitignore", 15 | "lint:js": "eslint . --max-warnings 0 --ignore-path .gitignore ", 16 | "lint": "npm-run-all --parallel lint:*", 17 | "check-format": "prettier '**/*.{css,json,js,md}' --list-different --ignore-path .gitignore", 18 | "format": "prettier '**/*.{css,json,js,md}' --write --ignore-path .gitignore", 19 | "pretest": "npm-run-all --parallel lint check-format", 20 | "run-e2e-tests": "cypress run --browser chrome", 21 | "test:e2e": "CYPRESS_SUPPORT=y start-server-and-test http://localhost:8000 run-e2e-tests", 22 | "test:unit": "jest --ci --runInBand", 23 | "test": "npm-run-all --sequential test:*", 24 | "watch-e2e-tests": "cypress open", 25 | "watch-unit-tests": "jest --watch --onlyChanged", 26 | "start": "gatsby develop", 27 | "build": "gatsby build", 28 | "serve": "gatsby serve" 29 | }, 30 | "devDependencies": { 31 | "@barnardos/eslint-config-barnardos": "^0.3.0", 32 | "@barnardos/stylelint-config-barnardos": "^0.5.3", 33 | "axe-core": "^3.2.2", 34 | "babel-jest": "^24.7.1", 35 | "babel-preset-gatsby": "^0.1.11", 36 | "core-js": "^2.6.5", 37 | "cypress": "^3.2.0", 38 | "cypress-axe": "^0.4.0", 39 | "cypress-testing-library": "^2.4.0", 40 | "eslint": "^5.16.0", 41 | "gatsby": "^2.3.21", 42 | "gatsby-cypress": "^0.1.7", 43 | "gatsby-plugin-google-analytics": "^2.0.18", 44 | "gatsby-plugin-postcss": "^2.0.7", 45 | "gatsby-plugin-react-helmet": "^3.0.12", 46 | "gatsby-plugin-sitemap": "^2.0.12", 47 | "identity-obj-proxy": "^3.0.0", 48 | "jest": "^24.7.1", 49 | "jest-dom": "^3.1.3", 50 | "npm-run-all": "^4.1.5", 51 | "postcss-browser-reporter": "^0.6.0", 52 | "postcss-import": "^12.0.1", 53 | "postcss-preset-env": "^6.6.0", 54 | "postcss-reporter": "^6.0.1", 55 | "prettier": "1.16.4", 56 | "react": "^16.8.6", 57 | "react-dom": "^16.8.6", 58 | "react-helmet": "^5.2.0", 59 | "react-testing-library": "^6.1.2", 60 | "remark-cli": "^6.0.1", 61 | "remark-preset-lint-itgalaxy": "^14.0.0", 62 | "start-server-and-test": "^1.7.13", 63 | "stylelint": "^9.10.1" 64 | }, 65 | "dependencies": { 66 | "@sindresorhus/slugify": "^0.9.1", 67 | "url-polyfill": "^1.1.5" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = () => ({ 2 | plugins: [ 3 | require("postcss-import"), 4 | require("postcss-preset-env")({ 5 | autoprefixer: {}, 6 | features: { 7 | "focus-within": true, 8 | "nesting-rules": true, 9 | "color-mod-function": { 10 | unresolved: "warn" 11 | }, 12 | "custom-properties": { 13 | preserve: false, 14 | warnings: true 15 | } 16 | } 17 | }), 18 | require("postcss-browser-reporter"), 19 | require("postcss-reporter") 20 | ] 21 | }); 22 | -------------------------------------------------------------------------------- /src/components/BackLink/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define BackLink; */ 4 | 5 | .BackLink { 6 | color: color-mod(var(--brand-colour) shade(20%)); 7 | display: inline-block; 8 | font: 300 var(--type-0) var(--body-font); 9 | padding: 0.25rem 0; 10 | 11 | &::before { 12 | text-decoration: underline; /* ie11 fix */ 13 | } 14 | 15 | /* stylelint-disable-next-line no-duplicate-selectors */ 16 | &::before { 17 | content: "‹"; 18 | display: inline-block; 19 | font: 300 var(--type-6) var(--brand-font); 20 | line-height: 0; 21 | margin-right: 0.5rem; 22 | position: relative; 23 | text-decoration: none; 24 | top: 0.125rem; 25 | } 26 | 27 | &:hover { 28 | text-decoration: none; 29 | } 30 | 31 | &:visited { 32 | color: var(--visited-colour); 33 | } 34 | 35 | &:not(:first-child) { 36 | margin-top: 1.25rem; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/components/BackLink/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import Link from "../Link"; 5 | 6 | import "./index.css"; 7 | 8 | const BackLink = ({ href }) => ( 9 | 10 | Back 11 | 12 | ); 13 | 14 | BackLink.propTypes = { 15 | href: PropTypes.string.isRequired 16 | }; 17 | 18 | export default BackLink; 19 | -------------------------------------------------------------------------------- /src/components/BlockQuote/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define BlockQuote; */ 4 | 5 | .BlockQuote { 6 | color: var(--brand-colour); 7 | 8 | &:not(:first-child) { 9 | margin-top: 2.5rem; 10 | } 11 | } 12 | 13 | .BlockQuote-image { 14 | border-radius: 50%; 15 | margin: 0 1.5rem; 16 | max-width: 20rem; 17 | overflow: hidden; 18 | } 19 | 20 | .BlockQuote-text { 21 | box-shadow: inset 0.25rem 0 0 currentColor; 22 | padding-left: 1.5rem; 23 | padding-top: 4.5rem; 24 | position: relative; 25 | 26 | &::before { 27 | content: "“"; 28 | font: 600 var(--type-20) var(--brand-font); 29 | left: 1rem; 30 | line-height: 0; 31 | margin-top: 5rem; 32 | position: absolute; 33 | top: -0.5rem; 34 | } 35 | } 36 | 37 | .BlockQuote-children { 38 | color: var(--black); 39 | font: 600 var(--type-4) var(--brand-font); 40 | 41 | &::after { 42 | content: "”"; 43 | } 44 | } 45 | 46 | .BlockQuote-cite { 47 | display: block; 48 | margin-top: 1rem; 49 | } 50 | 51 | .BlockQuote-role { 52 | color: var(--black); 53 | font: 300 var(--type-2) var(--body-font); 54 | } 55 | 56 | .BlockQuote-name { 57 | font: 600 var(--type-2) var(--body-font); 58 | } 59 | 60 | .BlockQuote--orange { 61 | color: var(--orange); 62 | } 63 | 64 | .BlockQuote--pink { 65 | color: var(--pink); 66 | } 67 | 68 | .BlockQuote--purple { 69 | color: var(--purple); 70 | } 71 | 72 | .BlockQuote--teal { 73 | color: var(--teal); 74 | } 75 | 76 | .BlockQuote--withImage { 77 | @supports (display: grid) { 78 | display: grid; 79 | grid-template-columns: repeat(auto-fill, minmax(20rem, max-content)); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/components/BlockQuote/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import Image from "../Image"; 5 | 6 | import "./index.css"; 7 | 8 | const BlockQuote = ({ children, colour, name, role, src }) => ( 9 |
14 | {src && ( 15 |
16 |
17 | 18 |
19 |
20 | )} 21 |
22 |
{children}
23 | 24 |

{name}

25 | {role &&

{role}

} 26 |
27 |
28 |
29 | ); 30 | 31 | BlockQuote.propTypes = { 32 | children: PropTypes.node.isRequired, 33 | colour: PropTypes.oneOf(["orange", "pink", "purple", "teal"]), 34 | name: PropTypes.string.isRequired, 35 | role: PropTypes.string, 36 | src: PropTypes.string 37 | }; 38 | 39 | export default BlockQuote; 40 | -------------------------------------------------------------------------------- /src/components/Breadcrumbs/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Breadcrumbs; */ 4 | 5 | .Breadcrumbs { 6 | &:not(:first-child) { 7 | margin-top: 1.25rem; 8 | } 9 | } 10 | 11 | .Breadcrumbs-items { 12 | display: flex; 13 | flex-wrap: wrap; 14 | } 15 | 16 | .Breadcrumbs-item { 17 | list-style: none; 18 | margin-right: 0.5rem; 19 | position: relative; 20 | 21 | &:not(:first-child) { 22 | padding-left: 1rem; 23 | 24 | &::before { 25 | color: color-mod(var(--black) tint(80%)); 26 | content: "›"; 27 | font: 300 var(--type-6) var(--brand-font); 28 | line-height: 0; 29 | margin: 0.5rem 0 0 -1rem; 30 | position: absolute; 31 | top: 0.5rem; 32 | } 33 | } 34 | } 35 | 36 | .Breadcrumbs-link { 37 | color: color-mod(var(--brand-colour) shade(20%)); 38 | display: inline-block; 39 | font: 300 var(--type-0) var(--body-font); 40 | padding: 0.25rem 0; 41 | 42 | &:hover { 43 | text-decoration: none; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/components/Breadcrumbs/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import Link from "../Link"; 5 | 6 | import "./index.css"; 7 | 8 | const Breadcrumbs = ({ items }) => ( 9 | 20 | ); 21 | 22 | Breadcrumbs.propTypes = { 23 | items: PropTypes.arrayOf( 24 | PropTypes.shape({ 25 | href: PropTypes.string.isRequired, 26 | text: PropTypes.string.isRequired 27 | }) 28 | ).isRequired 29 | }; 30 | 31 | export default Breadcrumbs; 32 | -------------------------------------------------------------------------------- /src/components/BulletedList/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define BulletedList; */ 4 | 5 | .BulletedList { 6 | font: 300 var(--type-0) var(--body-font); 7 | max-width: 36rem; 8 | padding-left: 1rem; 9 | 10 | &:not(:first-child) { 11 | margin-top: 0.75rem; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/components/BulletedList/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const BulletedList = ({ children }) => ( 7 |
    {children}
8 | ); 9 | 10 | BulletedList.propTypes = { 11 | children: PropTypes.node.isRequired 12 | }; 13 | 14 | export default BulletedList; 15 | -------------------------------------------------------------------------------- /src/components/Callout/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Callout; */ 4 | 5 | .Callout { 6 | background-color: var(--white); 7 | box-shadow: inset 0 0 0 1px color-mod(var(--black) tint(80%)); 8 | color: var(--black); 9 | padding: 1rem; 10 | 11 | &:not(:first-child) { 12 | margin-top: 2.5rem; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/components/Callout/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Callout = ({ children }) =>
{children}
; 7 | 8 | Callout.propTypes = { 9 | children: PropTypes.node.isRequired 10 | }; 11 | 12 | export default Callout; 13 | -------------------------------------------------------------------------------- /src/components/Callouts/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Callouts; weak; */ 4 | 5 | /* Uses flex fallback for IE11 */ 6 | 7 | .Callouts { 8 | display: flex; 9 | flex-wrap: wrap; 10 | margin: -1rem; 11 | 12 | &:not(:first-child) { 13 | margin-top: 2.5rem; 14 | } 15 | 16 | & > * { 17 | flex: 0 0 20rem; 18 | margin: 1rem; 19 | } 20 | 21 | @supports (display: grid) { 22 | display: grid; 23 | grid-gap: 2rem; 24 | grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr)); 25 | margin: 0; 26 | 27 | & > * { 28 | margin: 0; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/components/Callouts/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Callouts = ({ children }) =>
{children}
; 7 | 8 | Callouts.propTypes = { 9 | children: PropTypes.node.isRequired 10 | }; 11 | 12 | export default Callouts; 13 | -------------------------------------------------------------------------------- /src/components/Caption/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Caption; */ 4 | 5 | .Caption { 6 | display: block; 7 | 8 | &:not(:first-child) { 9 | margin-top: 2.5rem; 10 | } 11 | } 12 | 13 | .Caption-label { 14 | background-color: color-mod(var(--black) tint(95%)); 15 | color: var(--black); 16 | font: 300 var(--type-0) var(--body-font); 17 | padding: 0.5rem 0.75rem; 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Caption/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Caption = ({ label, children }) => ( 7 |
8 |
{children}
9 |
{label}
10 |
11 | ); 12 | 13 | Caption.propTypes = { 14 | children: PropTypes.node.isRequired, 15 | label: PropTypes.string.isRequired 16 | }; 17 | 18 | export default Caption; 19 | -------------------------------------------------------------------------------- /src/components/CheckBox/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import Switch from "../Switch"; 4 | 5 | const CheckBox = props => ; 6 | 7 | export default CheckBox; 8 | -------------------------------------------------------------------------------- /src/components/CheckBoxes/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import Switches from "../Switches"; 4 | 5 | const CheckBoxes = props => ; 6 | 7 | export default CheckBoxes; 8 | -------------------------------------------------------------------------------- /src/components/Cite/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Cite; */ 4 | 5 | .Cite { 6 | color: color-mod(var(--black) tint(30%)); 7 | font: 300 var(--type--1) var(--body-font); 8 | max-width: 36rem; 9 | 10 | &:not(:first-child) { 11 | margin-top: 1.25rem; 12 | } 13 | } 14 | 15 | .Cite-inner { 16 | font-style: normal; 17 | } 18 | -------------------------------------------------------------------------------- /src/components/Cite/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Cite = ({ children }) => ( 7 |

8 | {children} 9 |

10 | ); 11 | 12 | Cite.propTypes = { 13 | children: PropTypes.node.isRequired 14 | }; 15 | 16 | export default Cite; 17 | -------------------------------------------------------------------------------- /src/components/Code/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Code; */ 4 | 5 | .Code { 6 | font: 400 var(--type-1) monospace; 7 | line-height: inherit; 8 | } 9 | -------------------------------------------------------------------------------- /src/components/Code/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Code = ({ children }) => {children}; 7 | 8 | Code.propTypes = { 9 | children: PropTypes.node.isRequired 10 | }; 11 | 12 | export default Code; 13 | -------------------------------------------------------------------------------- /src/components/ColourFigure/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define ColourFigure; */ 4 | 5 | .ColourFigure { 6 | display: flex; 7 | max-width: 30rem; 8 | 9 | @media (min-width: 30rem) { 10 | max-width: none; 11 | } 12 | } 13 | 14 | .ColourFigure-item { 15 | background: var(--brand-colour); 16 | display: block; 17 | flex: 1 1 3rem; 18 | height: 3rem; 19 | list-style: none; 20 | 21 | @media (min-width: 30rem) { 22 | flex-basis: 4.5rem; 23 | height: 4.5rem; 24 | } 25 | } 26 | 27 | .ColourFigure-item--10tint { 28 | background-color: color-mod(var(--brand-colour) tint(10%)); 29 | } 30 | 31 | .ColourFigure-item--20tint { 32 | background-color: color-mod(var(--brand-colour) tint(20%)); 33 | } 34 | 35 | .ColourFigure-item--30tint { 36 | background-color: color-mod(var(--brand-colour) tint(30%)); 37 | } 38 | 39 | .ColourFigure-item--40tint { 40 | background-color: color-mod(var(--brand-colour) tint(40%)); 41 | } 42 | 43 | .ColourFigure-item--50tint { 44 | background-color: color-mod(var(--brand-colour) tint(50%)); 45 | } 46 | 47 | .ColourFigure-item--60tint { 48 | background-color: color-mod(var(--brand-colour) tint(60%)); 49 | } 50 | 51 | .ColourFigure-item--70tint { 52 | background-color: color-mod(var(--brand-colour) tint(70%)); 53 | } 54 | 55 | .ColourFigure-item--80tint { 56 | background-color: color-mod(var(--brand-colour) tint(80%)); 57 | } 58 | 59 | .ColourFigure-item--90tint { 60 | background-color: color-mod(var(--brand-colour) tint(90%)); 61 | } 62 | 63 | .ColourFigure-item--10shade { 64 | background-color: color-mod(var(--brand-colour) shade(10%)); 65 | } 66 | 67 | .ColourFigure-item--20shade { 68 | background-color: color-mod(var(--brand-colour) shade(20%)); 69 | } 70 | 71 | .ColourFigure-item--30shade { 72 | background-color: color-mod(var(--brand-colour) shade(30%)); 73 | } 74 | 75 | .ColourFigure-item--40shade { 76 | background-color: color-mod(var(--brand-colour) shade(40%)); 77 | } 78 | 79 | .ColourFigure-item--50shade { 80 | background-color: color-mod(var(--brand-colour) shade(50%)); 81 | } 82 | 83 | .ColourFigure-item--60shade { 84 | background-color: color-mod(var(--brand-colour) shade(60%)); 85 | } 86 | 87 | .ColourFigure-item--70shade { 88 | background-color: color-mod(var(--brand-colour) shade(70%)); 89 | } 90 | 91 | .ColourFigure-item--80shade { 92 | background-color: color-mod(var(--brand-colour) shade(80%)); 93 | } 94 | 95 | .ColourFigure-item--90shade { 96 | background-color: color-mod(var(--brand-colour) shade(90%)); 97 | } 98 | -------------------------------------------------------------------------------- /src/components/ColourFigure/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const ColourFigure = ({ type }) => ( 7 |
    8 |
  • 9 | {Array.apply(null, { length: 9 }).map((x, index) => ( 10 |
  • 15 | ))} 16 |
17 | ); 18 | 19 | ColourFigure.propTypes = { 20 | type: PropTypes.oneOf(["tint", "shade"]).isRequired 21 | }; 22 | 23 | export default ColourFigure; 24 | -------------------------------------------------------------------------------- /src/components/ColourGreyFigure/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define ColourGreyFigure; */ 4 | 5 | .ColourGreyFigure { 6 | background: color-mod(var(--black) tint(95%)); 7 | height: 3rem; 8 | width: 100%; 9 | } 10 | -------------------------------------------------------------------------------- /src/components/ColourGreyFigure/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import "./index.css"; 4 | 5 | const ColourGreyFigure = () =>
; 6 | 7 | export default ColourGreyFigure; 8 | -------------------------------------------------------------------------------- /src/components/Conditional/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Conditional; */ 4 | 5 | .Conditional-target { 6 | box-shadow: inset 0.25rem 0 0 color-mod(var(--black) tint(90%)); 7 | display: none; 8 | margin-top: 1rem; 9 | padding-left: 1rem; 10 | } 11 | 12 | .Conditional-target--active { 13 | display: block; 14 | } 15 | -------------------------------------------------------------------------------- /src/components/Conditional/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React, { useState } from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Conditional = ({ target, trigger }) => { 7 | const [isActive, setActive] = useState(false); 8 | return ( 9 |
10 |
setActive(!isActive)}> 11 | {trigger} 12 |
13 |
18 | {target} 19 |
20 |
21 | ); 22 | }; 23 | 24 | Conditional.propTypes = { 25 | trigger: PropTypes.node.isRequired, 26 | target: PropTypes.node.isRequired 27 | }; 28 | 29 | export default Conditional; 30 | -------------------------------------------------------------------------------- /src/components/Confirmation/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Confirmation; */ 4 | 5 | .Confirmation { 6 | background-color: var(--brand-colour); 7 | color: var(--white); 8 | max-width: 36rem; 9 | padding: 2rem 1rem; 10 | text-align: center; 11 | 12 | &:not(:first-child) { 13 | margin-top: 2.5rem; 14 | } 15 | } 16 | 17 | .Confirmation-inner { 18 | margin: 0 auto; 19 | max-width: 36rem; 20 | } 21 | 22 | .Confirmation-reference { 23 | display: block; 24 | } 25 | -------------------------------------------------------------------------------- /src/components/Confirmation/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import Lede from "../Lede"; 5 | import Title from "../Title"; 6 | 7 | import "./index.css"; 8 | 9 | const Confirmation = ({ title, lede, reference }) => ( 10 |
11 |
12 | {title} 13 | 14 | {lede} 15 | {reference} 16 | 17 |
18 |
19 | ); 20 | 21 | Confirmation.propTypes = { 22 | title: PropTypes.string.isRequired, 23 | lede: PropTypes.string.isRequired, 24 | reference: PropTypes.string.isRequired 25 | }; 26 | 27 | export default Confirmation; 28 | -------------------------------------------------------------------------------- /src/components/Content/index.css: -------------------------------------------------------------------------------- 1 | /** @define Content; */ 2 | 3 | .Content { 4 | margin-top: 2rem; 5 | 6 | @supports (display: grid) { 7 | @media (min-width: 48rem) { 8 | margin-top: 0; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/components/Content/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Content = ({ children }) =>
{children}
; 7 | 8 | Content.propTypes = { 9 | children: PropTypes.node.isRequired 10 | }; 11 | 12 | export default Content; 13 | -------------------------------------------------------------------------------- /src/components/Contents/index.css: -------------------------------------------------------------------------------- 1 | /** @define Contents; weak; */ 2 | 3 | .Contents { 4 | margin-top: 2rem; 5 | 6 | @media (min-width: 48rem) { 7 | display: grid; 8 | grid-gap: 2.5rem; 9 | grid-template-columns: 16rem 1fr; 10 | 11 | & > * { 12 | grid-column: 2; 13 | 14 | &:nth-child(1) { 15 | grid-column: 1; 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/components/Contents/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Contents = ({ children }) =>
{children}
; 7 | 8 | Contents.propTypes = { 9 | children: PropTypes.node.isRequired 10 | }; 11 | 12 | export default Contents; 13 | -------------------------------------------------------------------------------- /src/components/ContentsMenu/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define ContentsMenu; */ 4 | 5 | .ContentsMenu { 6 | &:not(:first-child) { 7 | margin-top: 2.5rem; 8 | } 9 | } 10 | 11 | .ContentsMenu-inner { 12 | background: color-mod(var(--black) tint(95%)); 13 | box-shadow: 0 -0.25rem 0 0 var(--brand-colour); 14 | padding: 1rem; 15 | 16 | @media (min-width: 48rem) { 17 | max-height: calc(100vh - 2rem); 18 | overflow-y: scroll; 19 | position: sticky; 20 | top: 1rem; 21 | } 22 | } 23 | 24 | .ContentsMenu-heading { 25 | font: 600 var(--type-0) var(--body-font); 26 | } 27 | 28 | .ContentsMenu-items--level1 { 29 | margin-top: 0.5rem; 30 | } 31 | 32 | .ContentsMenu-item { 33 | list-style: none; 34 | } 35 | 36 | .ContentsMenu-link { 37 | color: var(--black); 38 | display: block; 39 | font: 300 var(--type-0) var(--body-font); 40 | margin: 0 -0.25rem; 41 | padding: 0.25rem; 42 | text-decoration: underline; 43 | 44 | &:hover { 45 | text-decoration: none; 46 | } 47 | } 48 | 49 | .ContentsMenu-items--level2 { 50 | margin: 0.25rem 0 1rem; 51 | 52 | & .ContentsMenu-link { 53 | box-shadow: inset 0.25rem 0 0 color-mod(var(--black) tint(90%)); 54 | font: 300 var(--type-0) var(--body-font); 55 | padding-left: 1rem; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/components/ContentsMenu/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import Link from "../Link"; 5 | 6 | import "./index.css"; 7 | 8 | const ContentsMenuItem = ({ items, level, text, href }) => ( 9 |
  • 10 | 11 | {text} 12 | 13 | {items && } 14 |
  • 15 | ); 16 | 17 | const ContentsMenuItems = ({ items, level }) => ( 18 |
      19 | {items.map((item, index) => ( 20 | 21 | ))} 22 |
    23 | ); 24 | 25 | const ContentsMenu = ({ items }) => ( 26 | 32 | ); 33 | 34 | ContentsMenuItem.propTypes = { 35 | level: PropTypes.number.isRequired, 36 | text: PropTypes.string.isRequired, 37 | href: PropTypes.string.isRequired, 38 | items: PropTypes.array 39 | }; 40 | 41 | ContentsMenuItems.propTypes = { 42 | level: PropTypes.number.isRequired, 43 | items: PropTypes.array 44 | }; 45 | 46 | ContentsMenu.propTypes = { 47 | items: PropTypes.array.isRequired 48 | }; 49 | 50 | export default ContentsMenu; 51 | -------------------------------------------------------------------------------- /src/components/CurrencyInput/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define CurrencyInput; */ 4 | 5 | .CurrencyInput-prefixAndInput { 6 | margin-top: 1rem; 7 | position: relative; 8 | } 9 | 10 | .CurrencyInput-prefix { 11 | align-items: center; 12 | background: color-mod(var(--black) tint(90%)); 13 | box-shadow: inset 0 0 0 1px var(--black); 14 | display: flex; 15 | font: 600 var(--type-2) var(--body-font); 16 | height: 2.75rem; 17 | justify-content: center; 18 | left: 0; 19 | pointer-events: none; 20 | position: absolute; 21 | top: 0; 22 | width: 2.5rem; 23 | } 24 | 25 | .CurrencyInput-input { 26 | -moz-appearance: textfield; /* stylelint-disable-line property-no-vendor-prefix */ 27 | appearance: none; 28 | border: none; 29 | border-radius: 0; 30 | box-shadow: inset 0 0 0 1px var(--black), 31 | inset 0 0.25rem color-mod(var(--black) alpha(20%)); 32 | font: 300 var(--type-2) var(--body-font); 33 | max-width: 100%; 34 | padding: 0.5rem 0.75rem 0.5rem 3rem; 35 | width: 8rem; 36 | 37 | &::-webkit-inner-spin-button, 38 | &::-webkit-outer-spin-button { 39 | appearance: none; 40 | margin: 0; 41 | } 42 | } 43 | 44 | .CurrencyInput-input--errored { 45 | box-shadow: inset 0 0 0 1px var(--error-colour), 46 | inset 0 0.25rem color-mod(var(--error-colour) alpha(20%)); 47 | } 48 | -------------------------------------------------------------------------------- /src/components/CurrencyInput/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import Error from "../Error"; 5 | import Field from "../Field"; 6 | import Hint from "../Hint"; 7 | import Label from "../Label"; 8 | 9 | import "./index.css"; 10 | 11 | const CurrencyInput = ({ currency, error, hint, id, label, max, min }) => ( 12 | 13 | 14 | {hint && {hint}} 15 | {error && {error}} 16 |
    17 |

    {currency}

    18 | 29 |
    30 |
    31 | ); 32 | 33 | CurrencyInput.propTypes = { 34 | currency: PropTypes.string.isRequired, 35 | error: PropTypes.string, 36 | hint: PropTypes.string, 37 | id: PropTypes.string.isRequired, 38 | label: PropTypes.string.isRequired, 39 | max: PropTypes.number, 40 | min: PropTypes.number 41 | }; 42 | 43 | export default CurrencyInput; 44 | -------------------------------------------------------------------------------- /src/components/DateInput/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define DateInput; */ 4 | 5 | .DateInput-labelsAndInputs { 6 | display: flex; 7 | margin-top: 0.5rem; 8 | } 9 | 10 | .DateInput-labelsAndInput { 11 | flex: 0 0 3rem; 12 | 13 | &:not(:first-child) { 14 | margin-left: 1rem; 15 | } 16 | 17 | &:nth-child(3) { 18 | flex-basis: 5rem; 19 | } 20 | } 21 | 22 | .DateInput-input { 23 | -moz-appearance: textfield; /* stylelint-disable-line property-no-vendor-prefix */ 24 | appearance: none; 25 | border: none; 26 | border-radius: 0; 27 | box-shadow: inset 0 0 0 1px var(--black), 28 | inset 0 0.25rem color-mod(var(--black) alpha(20%)); 29 | font: 300 var(--type-2) var(--body-font); 30 | margin-top: 0.5rem; 31 | padding: 0.5rem 0.75rem; 32 | width: 100%; 33 | 34 | &::-webkit-inner-spin-button, 35 | &::-webkit-outer-spin-button { 36 | appearance: none; 37 | margin: 0; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/components/DateInput/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import Error from "../Error"; 5 | import Fieldset from "../Fieldset"; 6 | import Hint from "../Hint"; 7 | import Label from "../Label"; 8 | 9 | import "./index.css"; 10 | 11 | const DateInput = ({ hint, id, legend, error }) => ( 12 |
    13 | {hint && {hint}} 14 | {error && {error}} 15 |
    16 |
    17 | 20 | 26 |
    27 |
    28 | 31 | 37 |
    38 |
    39 | 42 | 48 |
    49 |
    50 |
    51 | ); 52 | 53 | DateInput.propTypes = { 54 | hint: PropTypes.string, 55 | id: PropTypes.string.isRequired, 56 | legend: PropTypes.string.isRequired, 57 | error: PropTypes.string 58 | }; 59 | 60 | export default DateInput; 61 | -------------------------------------------------------------------------------- /src/components/Demo/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Demo; weak; */ 4 | 5 | .Demo--thirds { 6 | margin: -2rem 0 0 -2rem; 7 | 8 | & > * { 9 | margin: 2rem 0 0 2rem; 10 | } 11 | 12 | @media (min-width: 44rem) { 13 | display: flex; 14 | 15 | & > *:nth-child(1) { 16 | flex: 2 2 auto; 17 | } 18 | 19 | & > *:nth-child(2) { 20 | flex: 1 1 auto; 21 | } 22 | } 23 | } 24 | 25 | .Demo--constrained { 26 | & > * { 27 | box-shadow: 0 0.25rem 0 color-mod(var(--teal) tint(20%)); 28 | margin: 0 auto; 29 | max-width: 28rem; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/components/Demo/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Demo = ({ children, type }) => ( 7 |
    {children}
    8 | ); 9 | 10 | Demo.propTypes = { 11 | children: PropTypes.node.isRequired, 12 | type: PropTypes.oneOf(["thirds", "constrained"]) 13 | }; 14 | 15 | export default Demo; 16 | -------------------------------------------------------------------------------- /src/components/DemoItem/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define DemoItem; */ 4 | 5 | .DemoItem { 6 | background: color-mod(var(--teal) tint(80%)); 7 | height: 3rem; 8 | } 9 | -------------------------------------------------------------------------------- /src/components/DemoItem/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import "./index.css"; 4 | 5 | const DemoItem = () =>
    ; 6 | 7 | export default DemoItem; 8 | -------------------------------------------------------------------------------- /src/components/Details/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Details; */ 4 | 5 | .Details { 6 | max-width: 36rem; 7 | 8 | &:not(:first-child) { 9 | margin-top: 1.5rem; 10 | } 11 | } 12 | 13 | .Details-summary { 14 | cursor: pointer; 15 | font: 300 var(--type-0) var(--body-font); 16 | } 17 | 18 | .Details-children { 19 | margin-top: 1.5rem; 20 | } 21 | -------------------------------------------------------------------------------- /src/components/Details/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Details = ({ children, summary }) => ( 7 |
    8 | {summary} 9 |
    {children}
    10 |
    11 | ); 12 | 13 | Details.propTypes = { 14 | children: PropTypes.node.isRequired, 15 | summary: PropTypes.string.isRequired 16 | }; 17 | 18 | export default Details; 19 | -------------------------------------------------------------------------------- /src/components/DocSearch/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** 4 | * Adapted 3rd party code from Algolia 5 | **/ 6 | 7 | /* stylelint-disable declaration-no-important, property-whitelist, selector-max-class */ 8 | 9 | .DocSearch { 10 | & .algolia-autocomplete { 11 | width: 100%; 12 | } 13 | 14 | & .ds-input { 15 | width: 100%; 16 | } 17 | 18 | & .ds-dropdown-menu { 19 | background-color: var(--white); 20 | border-radius: 0.25rem; 21 | box-shadow: inset 0 0 0 1px color-mod(var(--black) tint(80%)), 22 | 0 0 0.25rem 0.125rem color-mod(var(--black) alpha(10%)); 23 | margin-top: 1rem; 24 | max-width: 38rem; 25 | padding: 1rem 1.25rem 1.25rem; 26 | width: calc(100vw - 2rem); 27 | 28 | &::before { 29 | background: var(--white); 30 | border-radius: 2px; 31 | border-right: 1px solid color-mod(var(--black) tint(70%)); 32 | border-top: 1px solid color-mod(var(--black) tint(70%)); 33 | content: ""; 34 | display: block; 35 | height: 14px; 36 | left: 25px; 37 | position: absolute; 38 | top: -7px; 39 | transform: rotate(-45deg); 40 | width: 14px; 41 | z-index: 1000; 42 | } 43 | } 44 | 45 | & .algolia-autocomplete-right .ds-dropdown-menu { 46 | left: inherit !important; 47 | right: 0 !important; 48 | 49 | &::before { 50 | left: auto; 51 | right: 3rem; 52 | } 53 | } 54 | 55 | & .algolia-docsearch-suggestion--content { 56 | margin-left: 0.25rem; 57 | } 58 | 59 | & .algolia-docsearch-suggestion { 60 | text-decoration: none; 61 | 62 | &:hover { 63 | & .algolia-docsearch-suggestion--content { 64 | color: var(--black); 65 | text-decoration: underline; 66 | } 67 | } 68 | } 69 | 70 | & .algolia-docsearch-suggestion--category-header { 71 | display: none; 72 | } 73 | 74 | & .algolia-docsearch-suggestion--wrapper { 75 | display: flex; 76 | padding-top: 0.5rem; 77 | } 78 | 79 | & .algolia-docsearch-suggestion--subcategory-column { 80 | color: color-mod(var(--black) tint(40%)); 81 | font: 600 var(--type-0) var(--body-font); 82 | white-space: nowrap; 83 | 84 | &::after { 85 | content: "|"; 86 | } 87 | } 88 | 89 | & .algolia-docsearch-suggestion--subcategory-inline { 90 | display: none; 91 | } 92 | 93 | & .algolia-docsearch-suggestion--title { 94 | color: var(--black); 95 | font: 300 var(--type-0) var(--body-font); 96 | } 97 | 98 | & .algolia-docsearch-suggestion--text { 99 | color: var(--black); 100 | font: 300 var(--type--1) var(--body-font); 101 | } 102 | 103 | & .algolia-docsearch-suggestion--highlight { 104 | background: color-mod(var(--brand-colour) alpha(10%)); 105 | } 106 | 107 | & .algolia-docsearch-suggestion--no-results { 108 | text-align: center; 109 | text-decoration: none !important; 110 | width: 100%; 111 | } 112 | 113 | & .algolia-docsearch-footer { 114 | font: 300 var(--type--2) var(--body-font); 115 | margin-top: 0.75rem; 116 | text-align: right; 117 | } 118 | 119 | & .algolia-docsearch-footer--logo { 120 | color: var(--brand-colour); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/components/DocSearch/index.js: -------------------------------------------------------------------------------- 1 | import { navigate } from "gatsby"; 2 | import PropTypes from "prop-types"; 3 | import React, { forwardRef, useEffect } from "react"; 4 | 5 | import Search from "../Search"; 6 | 7 | import "./index.css"; 8 | 9 | const DocSearch = forwardRef((props, ref) => { 10 | useEffect(() => { 11 | const d = document.createElement("script"); 12 | d.id = "docsearch-script"; 13 | d.async = true; 14 | d.src = 15 | "https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js"; 16 | 17 | d.onload = () => { 18 | window.docsearch({ 19 | apiKey: "ea683d85005bef58d24fc7b13a06ae4e", 20 | indexName: "barnardos_design-system", 21 | inputSelector: "#algolia-docsearch", 22 | handleSelected: function(input, event, { url }) { 23 | const { hash, pathname } = new URL(url); 24 | navigate(`${pathname}${hash}`); 25 | } 26 | }); 27 | }; 28 | document.getElementsByTagName("body")[0].appendChild(d); 29 | }); 30 | return ( 31 |
    32 | 33 |
    34 | ); 35 | }); 36 | 37 | DocSearch.propTypes = { 38 | id: PropTypes.string 39 | }; 40 | 41 | DocSearch.displayName = "DocSearch"; 42 | 43 | export default DocSearch; 44 | -------------------------------------------------------------------------------- /src/components/DownloadLink/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define DownloadLink; */ 4 | 5 | .DownloadLink-link { 6 | color: var(--brand-colour); 7 | display: inline-block; 8 | font: 600 var(--type-2) var(--brand-font); 9 | 10 | &:hover { 11 | text-decoration: none; 12 | } 13 | 14 | &:visited { 15 | color: var(--visited-colour); 16 | } 17 | 18 | &:not(:first-child) { 19 | margin-top: 1.5rem; 20 | } 21 | } 22 | 23 | .DownloadLink-meta { 24 | color: var(--black); 25 | display: inline-block; 26 | font: 300 var(--type-2) var(--brand-font); 27 | margin-left: 0.5rem; 28 | } 29 | -------------------------------------------------------------------------------- /src/components/DownloadLink/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import Link from "../Link"; 5 | 6 | import "./index.css"; 7 | 8 | const DownloadLink = ({ children, format, href, size }) => ( 9 | 10 | {children} 11 | {`– ${format}, ${size}`} 12 | 13 | ); 14 | 15 | DownloadLink.propTypes = { 16 | children: PropTypes.node.isRequired, 17 | format: PropTypes.string.isRequired, 18 | href: PropTypes.string.isRequired, 19 | size: PropTypes.string.isRequired 20 | }; 21 | 22 | export default DownloadLink; 23 | -------------------------------------------------------------------------------- /src/components/Error/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Error; */ 4 | 5 | .Error { 6 | margin-top: 0.25rem; 7 | } 8 | 9 | .Error-inner { 10 | color: var(--error-colour); 11 | font: 600 var(--type-0) var(--body-font); 12 | } 13 | -------------------------------------------------------------------------------- /src/components/Error/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Error = ({ children }) => ( 7 |

    8 | {children} 9 |

    10 | ); 11 | 12 | Error.propTypes = { 13 | children: PropTypes.node.isRequired 14 | }; 15 | 16 | export default Error; 17 | -------------------------------------------------------------------------------- /src/components/ErrorSummary/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define ErrorSummary; */ 4 | 5 | .ErrorSummary { 6 | box-shadow: inset 0 0 0 0.25rem var(--error-colour); 7 | max-width: 36rem; 8 | padding: 1.25rem; 9 | 10 | &:not(:first-child) { 11 | margin-top: 2.5rem; 12 | } 13 | } 14 | 15 | .ErrorSummary-heading { 16 | font: 600 var(--type-3) var(--body-font); 17 | } 18 | 19 | .ErrorSummary-items { 20 | list-style: none; 21 | margin-top: 0.5rem; 22 | } 23 | 24 | .ErrorSummary-item { 25 | &:not(:first-child) { 26 | margin-top: 0.5rem; 27 | } 28 | } 29 | 30 | .ErrorSummary-link { 31 | color: var(--error-colour); 32 | font: 600 var(--type-0) var(--body-font); 33 | 34 | &:hover { 35 | text-decoration: none; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/components/ErrorSummary/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | import "./index.css"; 4 | 5 | const ErrorSummary = ({ items }) => { 6 | return ( 7 |
    8 |

    There is a problem

    9 | 18 |
    19 | ); 20 | }; 21 | 22 | ErrorSummary.propTypes = { 23 | items: PropTypes.arrayOf( 24 | PropTypes.shape({ 25 | id: PropTypes.string.isRequired, 26 | error: PropTypes.string.isRequired 27 | }) 28 | ).isRequired 29 | }; 30 | 31 | export default ErrorSummary; 32 | -------------------------------------------------------------------------------- /src/components/Example/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Example; */ 4 | 5 | .Example { 6 | box-shadow: 0 0 0 1px color-mod(var(--black) tint(60%)); 7 | overflow: hidden; 8 | padding: 2.5rem 1rem 1rem; 9 | position: relative; 10 | 11 | &::before { 12 | background: color-mod(var(--black) tint(60%)); 13 | color: var(--white); 14 | content: "Example"; 15 | display: block; 16 | font: 300 var(--type--1) var(--body-font); 17 | left: 0; 18 | line-height: 1.25; 19 | padding: 0.25rem 0.5rem; 20 | position: absolute; 21 | top: 0; 22 | } 23 | 24 | &:not(:first-child) { 25 | margin-top: 1.5rem; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/components/Example/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Example = ({ children }) =>
    {children}
    ; 7 | 8 | Example.propTypes = { 9 | children: PropTypes.node.isRequired 10 | }; 11 | 12 | export default Example; 13 | -------------------------------------------------------------------------------- /src/components/Fact/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Fact; */ 4 | 5 | .Fact { 6 | box-shadow: inset 0.25rem 0 0 currentColor; 7 | color: var(--brand-colour); 8 | max-width: 36rem; 9 | padding-left: 1.5rem; 10 | 11 | &:not(:first-child) { 12 | margin-top: 2.5rem; 13 | } 14 | } 15 | 16 | .Fact-children { 17 | font: 600 var(--type-12) var(--brand-font); 18 | } 19 | 20 | .Fact-label { 21 | font: 600 var(--type-2) var(--body-font); 22 | } 23 | 24 | .Fact--orange { 25 | color: var(--orange); 26 | } 27 | 28 | .Fact--pink { 29 | color: var(--pink); 30 | } 31 | 32 | .Fact--purple { 33 | color: var(--purple); 34 | } 35 | 36 | .Fact--teal { 37 | color: var(--teal); 38 | } 39 | -------------------------------------------------------------------------------- /src/components/Fact/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Fact = ({ children, colour, label }) => ( 7 |
    8 |
    {children}
    9 |

    {label}

    10 |
    11 | ); 12 | 13 | Fact.propTypes = { 14 | children: PropTypes.node.isRequired, 15 | colour: PropTypes.oneOf(["orange", "pink", "purple", "teal"]), 16 | label: PropTypes.string 17 | }; 18 | 19 | export default Fact; 20 | -------------------------------------------------------------------------------- /src/components/Feedback/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Feedback; weak */ 4 | 5 | .Feedback { 6 | background-color: var(--white); 7 | border-radius: 0; 8 | box-shadow: inset 0 0 0 0.25rem var(--brand-colour); 9 | display: block; 10 | padding: 1.5rem 1.5rem 1.75rem; 11 | 12 | &:not(:first-child) { 13 | margin-top: 2.5rem; 14 | } 15 | } 16 | 17 | .Feedback-heading { 18 | color: var(--brand-colour); 19 | font: 600 var(--type-5) var(--brand-font); 20 | } 21 | 22 | .Feedback-children { 23 | color: var(--black); 24 | font: 300 var(--type-0) var(--body-font); 25 | margin-top: 0.75rem; 26 | } 27 | -------------------------------------------------------------------------------- /src/components/Feedback/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Feedback = ({ children, heading }) => ( 7 | 11 | ); 12 | 13 | Feedback.propTypes = { 14 | children: PropTypes.node.isRequired, 15 | heading: PropTypes.string.isRequired 16 | }; 17 | 18 | export default Feedback; 19 | -------------------------------------------------------------------------------- /src/components/Field/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Field; */ 4 | 5 | .Field { 6 | max-width: 36rem; 7 | 8 | &:not(:first-child) { 9 | margin-top: 2.5rem; 10 | } 11 | } 12 | 13 | .Field--errored { 14 | box-shadow: inset 0.25rem 0 0 var(--error-colour); 15 | padding-left: 1rem; 16 | } 17 | -------------------------------------------------------------------------------- /src/components/Field/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Field = ({ children, errored }) => ( 7 |
    {children}
    8 | ); 9 | 10 | Field.propTypes = { 11 | children: PropTypes.node.isRequired, 12 | errored: PropTypes.bool 13 | }; 14 | 15 | export default Field; 16 | -------------------------------------------------------------------------------- /src/components/Fieldset/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Fieldset; */ 4 | 5 | .Fieldset { 6 | border: none; 7 | max-width: 36rem; 8 | 9 | &:not(:first-child) { 10 | margin-top: 2.5rem; 11 | } 12 | } 13 | 14 | .Fieldset-legend { 15 | display: block; 16 | float: left; 17 | font: 600 var(--type-3) var(--body-font); 18 | } 19 | 20 | .Fieldset-children { 21 | clear: left; 22 | padding-top: 0.25rem; 23 | } 24 | 25 | .Fieldset--errored { 26 | box-shadow: inset 0.25rem 0 0 var(--error-colour); 27 | padding-left: 1rem; 28 | } 29 | -------------------------------------------------------------------------------- /src/components/Fieldset/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Fieldset = ({ children, errored, id, legend }) => ( 7 |
    11 | {legend} 12 |
    {children}
    13 |
    14 | ); 15 | 16 | Fieldset.propTypes = { 17 | children: PropTypes.node.isRequired, 18 | errored: PropTypes.bool, 19 | id: PropTypes.string.isRequired, 20 | legend: PropTypes.string.isRequired 21 | }; 22 | 23 | export default Fieldset; 24 | -------------------------------------------------------------------------------- /src/components/Figure/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Figure; */ 4 | 5 | .Figure { 6 | display: block; 7 | 8 | &:not(:first-child) { 9 | margin-top: 1.5rem; 10 | } 11 | } 12 | 13 | .Figure-caption { 14 | background: color-mod(var(--black) tint(90%)); 15 | display: block; 16 | font: 300 var(--type--1) var(--body-font); 17 | font-variant-numeric: tabular-nums; 18 | margin-top: 1rem; 19 | padding: 0 0.5rem; 20 | } 21 | 22 | .Figure-secondaryCaption { 23 | display: block; 24 | } 25 | 26 | .Figure-tertiaryCaption { 27 | display: block; 28 | } 29 | -------------------------------------------------------------------------------- /src/components/Figure/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Figure = ({ caption, secondaryCaption, tertiaryCaption, children }) => ( 7 |
    8 |
    {children}
    9 |
    10 | {caption} 11 | {secondaryCaption && ( 12 | {secondaryCaption} 13 | )} 14 | {tertiaryCaption && ( 15 | {tertiaryCaption} 16 | )} 17 |
    18 |
    19 | ); 20 | 21 | Figure.propTypes = { 22 | children: PropTypes.node.isRequired, 23 | caption: PropTypes.string.isRequired, 24 | secondaryCaption: PropTypes.string, 25 | tertiaryCaption: PropTypes.string 26 | }; 27 | 28 | export default Figure; 29 | -------------------------------------------------------------------------------- /src/components/Figures/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Figures; */ 4 | 5 | .Figures { 6 | box-shadow: inset 0 0 0 1px color-mod(var(--black) tint(60%)); 7 | padding: 1rem; 8 | 9 | &:not(:first-child) { 10 | margin-top: 1.5rem; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/components/Figures/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Figures = ({ children }) =>
    {children}
    ; 7 | 8 | Figures.propTypes = { 9 | children: PropTypes.node.isRequired 10 | }; 11 | 12 | export default Figures; 13 | -------------------------------------------------------------------------------- /src/components/Filter/cross.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/components/Filter/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Filter; */ 4 | 5 | .Filter { 6 | &:not(:first-child) { 7 | margin-top: 1rem; 8 | } 9 | } 10 | 11 | .Filter-target { 12 | display: none; 13 | } 14 | 15 | .Filter-target--active { 16 | display: block; 17 | } 18 | 19 | .Filter-children { 20 | margin-top: 1rem; 21 | } 22 | -------------------------------------------------------------------------------- /src/components/Filter/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React, { useState } from "react"; 3 | 4 | import Trigger from "../Trigger"; 5 | 6 | import cross from "./cross.svg"; 7 | 8 | import "./index.css"; 9 | 10 | const Filter = ({ children }) => { 11 | const [isActive, setActive] = useState(false); 12 | return ( 13 |
    14 | setActive(!isActive)}> 15 | {isActive ? Close : `Filter`} 16 | 17 |
    20 |
    {children}
    21 |
    22 |
    23 | ); 24 | }; 25 | 26 | Filter.propTypes = { 27 | children: PropTypes.node.isRequired 28 | }; 29 | 30 | export default Filter; 31 | -------------------------------------------------------------------------------- /src/components/Footer/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Footer; */ 4 | 5 | .Footer { 6 | background-color: color-mod(var(--black) tint(95%)); 7 | box-shadow: 0 50vh 0 50vh color-mod(var(--black) tint(95%)), 8 | inset 0 0.25rem 0 0 color-mod(var(--black) tint(90%)); 9 | margin: 4rem -1rem 0; 10 | padding: 2rem 1rem; 11 | position: relative; 12 | 13 | @media (min-width: 48rem) { 14 | margin-left: -2rem; 15 | margin-right: -2rem; 16 | padding: 3rem 2rem; 17 | } 18 | } 19 | 20 | .Footer-items { 21 | display: flex; 22 | flex-direction: column; 23 | list-style: none; 24 | 25 | @media (min-width: 48rem) { 26 | flex-direction: row; 27 | } 28 | } 29 | 30 | .Footer-item { 31 | font: 300 var(--type--1) var(--body-font); 32 | 33 | @media (min-width: 48rem) { 34 | &:not(:first-child) { 35 | margin-left: 1rem; 36 | } 37 | } 38 | } 39 | 40 | .Footer-link { 41 | color: var(--black); 42 | display: inline-block; 43 | font: 300 var(--type--1) var(--body-font); 44 | padding: 0.25rem 0; 45 | 46 | &:hover { 47 | text-decoration: none; 48 | } 49 | } 50 | 51 | .Footer-children { 52 | color: var(--black); 53 | font: 300 var(--type--1) var(--body-font); 54 | 55 | &:not(:first-child) { 56 | margin-top: 1rem; 57 | } 58 | } 59 | 60 | .Footer-copyright { 61 | color: var(--black); 62 | font: 300 var(--type--1) var(--body-font); 63 | 64 | &:not(:first-child) { 65 | margin-top: 1rem; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/components/Footer/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import Link from "../Link"; 5 | 6 | import "./index.css"; 7 | 8 | const Footer = ({ children, items }) => ( 9 |
    10 | {items && ( 11 |
      12 | {items.map(({ text, href }, index) => ( 13 |
    • 14 | 15 | {text} 16 | 17 |
    • 18 | ))} 19 |
    20 | )} 21 | {children &&
    {children}
    } 22 |

    © Barnardo’s

    23 |
    24 | ); 25 | 26 | Footer.propTypes = { 27 | children: PropTypes.node, 28 | items: PropTypes.arrayOf( 29 | PropTypes.shape({ 30 | href: PropTypes.string.isRequired, 31 | text: PropTypes.string.isRequired 32 | }) 33 | ) 34 | }; 35 | 36 | export default Footer; 37 | -------------------------------------------------------------------------------- /src/components/Form/index.css: -------------------------------------------------------------------------------- 1 | /** @define Form; */ 2 | 3 | .Form { 4 | &:not(:first-child) { 5 | margin-top: 2.5rem; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/components/Form/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Form = ({ action, children }) => ( 7 |
    8 | {children} 9 |
    10 | ); 11 | 12 | Form.propTypes = { 13 | action: PropTypes.string.isRequired, 14 | children: PropTypes.node.isRequired 15 | }; 16 | 17 | export default Form; 18 | -------------------------------------------------------------------------------- /src/components/Header/burger.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/components/Header/cross.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/components/Header/glass.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/components/Header/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Header; */ 4 | 5 | .Header { 6 | box-shadow: inset 0 -1px 0 0 color-mod(var(--black) tint(90%)); 7 | margin: 0 -1rem; 8 | padding: 0 1rem 0.5rem; 9 | 10 | @media (min-width: 48rem) { 11 | display: flex; 12 | justify-content: space-between; 13 | margin: 0 -2rem; 14 | padding: 0 2rem 1rem; 15 | } 16 | } 17 | 18 | .Header-actions { 19 | display: flex; 20 | justify-content: space-between; 21 | } 22 | 23 | .Header-logo { 24 | display: block; 25 | width: 5rem; 26 | 27 | @media (min-width: 48rem) { 28 | width: 7.5rem; 29 | } 30 | } 31 | 32 | .Header-logoInner { 33 | display: block; 34 | height: auto; 35 | width: 100%; 36 | } 37 | 38 | .Header-trigger { 39 | align-items: center; 40 | appearance: none; 41 | background: transparent; 42 | border: none; 43 | border-radius: 0; 44 | color: var(--black); 45 | display: flex; 46 | font: 600 var(--type-0) var(--brand-font); 47 | justify-content: center; 48 | margin-left: 0.5rem; 49 | padding: 0 0.5rem; 50 | white-space: normal; 51 | 52 | &:hover { 53 | background-color: color-mod(var(--white) shade(10%)); 54 | } 55 | 56 | &:active { 57 | box-shadow: inset 0 0 0 1px var(--black); 58 | position: relative; 59 | top: 0.125rem; 60 | } 61 | 62 | @media (min-width: 48rem) { 63 | display: none; 64 | } 65 | } 66 | 67 | .Header-triggerText { 68 | margin-left: 0.25rem; 69 | } 70 | 71 | .Header-target { 72 | left: -100vw; 73 | position: absolute; 74 | 75 | &:focus-within { 76 | position: static; 77 | } 78 | 79 | @media (min-width: 48rem) { 80 | align-self: center; 81 | flex: 0 1 30rem; 82 | margin-left: 4rem; 83 | position: static; 84 | } 85 | } 86 | 87 | .Header-target--active { 88 | position: static; 89 | } 90 | 91 | .Header-search { 92 | padding: 1.5rem 0 1rem; 93 | 94 | @media (min-width: 48rem) { 95 | padding: 0; 96 | } 97 | } 98 | 99 | .Header-menu { 100 | margin: 0 -1rem; 101 | 102 | @media (min-width: 48rem) { 103 | margin: 0.5rem 0 -1rem 0; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/components/Header/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React, { useState } from "react"; 3 | 4 | import burger from "./burger.svg"; 5 | import cross from "./cross.svg"; 6 | import glass from "./glass.svg"; 7 | import logo from "./logo.svg"; 8 | 9 | import "./index.css"; 10 | 11 | const Header = ({ href = "/", menu, search, title = "Go to the homepage" }) => { 12 | const [isActive, setActive] = useState(false); 13 | const ref = React.createRef(); 14 | 15 | function handleClick() { 16 | setActive(!isActive); 17 | if (!isActive) ref.current.focus(); 18 | } 19 | 20 | return ( 21 |
    22 |
    23 | 24 | Believe in children Barnardo’s 29 | 30 | {(menu || search) && ( 31 | 43 | )} 44 |
    45 |
    48 | {search && ( 49 |
    50 | {React.cloneElement(search, { ref: ref })} 51 |
    52 | )} 53 | {menu &&
    {menu}
    } 54 |
    55 |
    56 | ); 57 | }; 58 | 59 | Header.propTypes = { 60 | href: PropTypes.string, 61 | menu: PropTypes.node, 62 | search: PropTypes.node, 63 | title: PropTypes.string 64 | }; 65 | 66 | export default Header; 67 | -------------------------------------------------------------------------------- /src/components/Heading/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Heading; */ 4 | 5 | .Heading { 6 | font: 600 var(--type-6) var(--brand-font); 7 | max-width: 36rem; 8 | 9 | &:not(:first-child) { 10 | margin-top: 2.5rem; 11 | } 12 | 13 | @media (min-width: 40rem) { 14 | font: 600 var(--type-7) var(--brand-font); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/components/Heading/index.js: -------------------------------------------------------------------------------- 1 | import slugify from "@sindresorhus/slugify"; 2 | import PropTypes from "prop-types"; 3 | import React from "react"; 4 | 5 | import "./index.css"; 6 | 7 | const Heading = ({ children }) => ( 8 |

    9 | {children} 10 |

    11 | ); 12 | 13 | Heading.propTypes = { 14 | children: PropTypes.node.isRequired 15 | }; 16 | 17 | export default Heading; 18 | -------------------------------------------------------------------------------- /src/components/Hero/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Hero; */ 4 | 5 | .Hero { 6 | background-color: var(--brand-colour); 7 | color: var(--white); 8 | margin: -2rem -1rem 0; 9 | 10 | @media (min-width: 48rem) { 11 | margin-left: -2rem; 12 | margin-right: -2rem; 13 | } 14 | } 15 | 16 | .Hero-inner { 17 | padding: 2rem 1rem; 18 | 19 | @media (min-width: 48rem) { 20 | padding: 3rem 2rem; 21 | } 22 | } 23 | 24 | .Hero-children { 25 | &:not(:first-child) { 26 | margin-top: 1.5rem; 27 | } 28 | } 29 | 30 | .Hero--withImage { 31 | background-position: top right; 32 | background-size: cover; 33 | height: 50vmin; 34 | margin-bottom: 4rem; 35 | max-height: 30rem; 36 | min-height: 20rem; 37 | position: relative; 38 | 39 | & .Hero-inner { 40 | background-color: var(--brand-colour); 41 | bottom: -4rem; 42 | left: 1rem; 43 | max-width: 30rem; 44 | padding: 1.5rem; 45 | position: absolute; 46 | right: 1rem; 47 | 48 | @media (min-width: 48rem) { 49 | left: 2rem; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/components/Hero/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import Lede from "../Lede"; 5 | import Title from "../Title"; 6 | 7 | import "./index.css"; 8 | 9 | const Hero = ({ children, lede, src, title }) => ( 10 |
    20 |
    21 | {title && {title}} 22 | {lede && {lede}} 23 | {children &&
    {children}
    } 24 |
    25 |
    26 | ); 27 | 28 | Hero.propTypes = { 29 | children: PropTypes.node, 30 | lede: PropTypes.string, 31 | src: PropTypes.string, 32 | title: PropTypes.string.isRequired 33 | }; 34 | 35 | export default Hero; 36 | -------------------------------------------------------------------------------- /src/components/Hint/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Hint; */ 4 | 5 | .Hint { 6 | color: color-mod(var(--black) tint(30%)); 7 | font: 300 var(--type-0) var(--body-font); 8 | margin-top: 0.25rem; 9 | max-width: 36rem; 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Hint/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Hint = ({ children }) =>

    {children}

    ; 7 | 8 | Hint.propTypes = { 9 | children: PropTypes.node.isRequired 10 | }; 11 | 12 | export default Hint; 13 | -------------------------------------------------------------------------------- /src/components/Image/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Image; */ 4 | 5 | .Image { 6 | display: block; 7 | max-width: 100%; 8 | position: relative; 9 | 10 | &::before { 11 | content: ""; 12 | display: block; 13 | padding-bottom: calc(2 / 3 * 100%); 14 | width: 100%; 15 | } 16 | 17 | &:not(:first-child) { 18 | margin-top: 2.5rem; 19 | } 20 | } 21 | 22 | .Image--1by1 { 23 | &::before { 24 | padding-bottom: 100%; 25 | } 26 | } 27 | 28 | .Image--16by9 { 29 | &::before { 30 | padding-bottom: 56.25%; 31 | } 32 | } 33 | 34 | .Image-media { 35 | border: none; 36 | bottom: 0; 37 | height: 100%; 38 | left: 0; 39 | max-width: 100%; 40 | position: absolute; 41 | top: 0; 42 | width: 100%; 43 | } 44 | -------------------------------------------------------------------------------- /src/components/Image/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Image = ({ alt, ratio, src }) => ( 7 |
    8 | {alt} 9 |
    10 | ); 11 | 12 | Image.propTypes = { 13 | alt: PropTypes.string.isRequired, 14 | ratio: PropTypes.oneOf[("1by1", "16by9")], 15 | src: PropTypes.string.isRequired 16 | }; 17 | 18 | export default Image; 19 | -------------------------------------------------------------------------------- /src/components/Label/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Label; */ 4 | 5 | .Label { 6 | display: block; 7 | font: 600 var(--type-3) var(--body-font); 8 | max-width: 36rem; 9 | } 10 | 11 | .Label--inlined { 12 | font: 300 var(--type-2) var(--body-font); 13 | } 14 | -------------------------------------------------------------------------------- /src/components/Label/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Label = ({ children, htmlFor, inlined }) => ( 7 | 13 | ); 14 | 15 | Label.propTypes = { 16 | children: PropTypes.node.isRequired, 17 | htmlFor: PropTypes.string.isRequired, 18 | inlined: PropTypes.bool 19 | }; 20 | 21 | export default Label; 22 | -------------------------------------------------------------------------------- /src/components/LandingMenu/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define LandingMenu; */ 4 | 5 | .LandingMenu-items--level1 { 6 | margin-top: 1rem; 7 | } 8 | 9 | .LandingMenu-item { 10 | list-style: none; 11 | } 12 | 13 | .LandingMenu-link { 14 | color: var(--black); 15 | display: block; 16 | font: 300 var(--type-0) var(--body-font); 17 | margin: 0 -0.25rem; 18 | max-width: 20rem; 19 | padding: 0.25rem; 20 | text-decoration: underline; 21 | 22 | &:hover { 23 | text-decoration: none; 24 | } 25 | } 26 | 27 | .LandingMenu-items--level2 { 28 | margin: 0.25rem 0 1rem; 29 | 30 | & .LandingMenu-link { 31 | box-shadow: inset 0.25rem 0 0 color-mod(var(--black) tint(90%)); 32 | font: 300 var(--type-0) var(--body-font); 33 | padding-left: 1rem; 34 | } 35 | } 36 | 37 | .LandingMenu-items--level3 { 38 | & .LandingMenu-link { 39 | box-shadow: inset 0.25rem 0 0 color-mod(var(--black) tint(90%)); 40 | font: 300 var(--type-0) system-ui; 41 | padding-left: 1rem; 42 | 43 | &::before { 44 | content: "- "; 45 | display: inline-block; 46 | margin-right: 0.5rem; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/components/LandingMenu/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import Heading from "../Heading"; 5 | import Link from "../Link"; 6 | import Paragraph from "../Paragraph"; 7 | import SignpostLink from "../SignpostLink"; 8 | 9 | import "./index.css"; 10 | 11 | const LandingMenuLink = ({ text, href }) => ( 12 | 13 | {text} 14 | 15 | ); 16 | 17 | const LandingMenuItem = ({ items, level, text, href }) => ( 18 |
  • 19 | 20 | {text} 21 | 22 | {items && } 23 |
  • 24 | ); 25 | 26 | const LandingMenuItems = ({ items, level }) => ( 27 |
      28 | {items.map((item, index) => ( 29 | 30 | ))} 31 |
    32 | ); 33 | 34 | const LandingMenu = ({ heading, items, link }) => ( 35 | 40 | ); 41 | 42 | LandingMenuItem.propTypes = { 43 | level: PropTypes.number.isRequired, 44 | text: PropTypes.string.isRequired, 45 | href: PropTypes.string.isRequired, 46 | items: PropTypes.array 47 | }; 48 | 49 | LandingMenuItems.propTypes = { 50 | level: PropTypes.number.isRequired, 51 | items: PropTypes.array 52 | }; 53 | 54 | LandingMenuLink.propTypes = { 55 | text: PropTypes.string.isRequired, 56 | href: PropTypes.string.isRequired 57 | }; 58 | 59 | LandingMenu.propTypes = { 60 | heading: PropTypes.string, 61 | items: PropTypes.array.isRequired, 62 | link: PropTypes.shape({ 63 | text: PropTypes.string.isRequired, 64 | href: PropTypes.string.isRequired 65 | }) 66 | }; 67 | 68 | export default LandingMenu; 69 | -------------------------------------------------------------------------------- /src/components/Layout/index.css: -------------------------------------------------------------------------------- 1 | /** @define Layout */ 2 | 3 | .Layout { 4 | padding: 0.5rem 1rem; 5 | 6 | @media (min-width: 48rem) { 7 | padding: 1rem 2rem; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/components/Layout/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Layout = ({ children }) =>
    {children}
    ; 7 | 8 | Layout.propTypes = { 9 | children: PropTypes.node 10 | }; 11 | 12 | export default Layout; 13 | -------------------------------------------------------------------------------- /src/components/Lede/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Lede; */ 4 | 5 | .Lede { 6 | font: 300 var(--type-4) var(--brand-font); 7 | max-width: 36rem; 8 | 9 | &:not(:first-child) { 10 | margin-top: 1.25rem; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/components/Lede/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Lede = ({ children }) =>

    {children}

    ; 7 | 8 | Lede.propTypes = { 9 | children: PropTypes.node.isRequired 10 | }; 11 | 12 | export default Lede; 13 | -------------------------------------------------------------------------------- /src/components/Link/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | .Link { 4 | color: color-mod(var(--brand-colour) shade(30%)); 5 | 6 | &:hover { 7 | text-decoration: none; 8 | } 9 | 10 | &:visited { 11 | color: var(--visited-colour); 12 | } 13 | } 14 | 15 | .Link--inverted { 16 | color: white; 17 | 18 | &:visited { 19 | color: white; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/components/Link/index.js: -------------------------------------------------------------------------------- 1 | import { Link as GatsbyLink } from "gatsby"; 2 | import PropTypes from "prop-types"; 3 | import React from "react"; 4 | 5 | import "./index.css"; 6 | 7 | const Link = ({ children, inverted, href, activeClassName, ...other }) => { 8 | const className = `Link ${inverted ? "Link--inverted" : ""}`; 9 | // Assume internal links start with exactly one slash 10 | if (/^\/(?!\/)/.test(href)) { 11 | return ( 12 | 18 | {children} 19 | 20 | ); 21 | } 22 | return ( 23 | 24 | {children} 25 | 26 | ); 27 | }; 28 | 29 | Link.propTypes = { 30 | activeClassName: PropTypes.string, 31 | href: PropTypes.string.isRequired, 32 | inverted: PropTypes.bool, 33 | children: PropTypes.node.isRequired 34 | }; 35 | 36 | export default Link; 37 | -------------------------------------------------------------------------------- /src/components/ListItem/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define ListItem; */ 4 | 5 | .ListItem { 6 | font: 300 var(--type-0) var(--body-font); 7 | margin-left: 0.25rem; 8 | 9 | &:not(:first-child) { 10 | margin-top: 0.25rem; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/components/ListItem/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const ListItem = ({ children }) =>
  • {children}
  • ; 7 | 8 | ListItem.propTypes = { 9 | children: PropTypes.node.isRequired 10 | }; 11 | 12 | export default ListItem; 13 | -------------------------------------------------------------------------------- /src/components/Main/index.css: -------------------------------------------------------------------------------- 1 | /** @define Main; */ 2 | 3 | .Main { 4 | display: block; 5 | margin-top: 2rem; 6 | } 7 | -------------------------------------------------------------------------------- /src/components/Main/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const Main = ({ children }) => ( 7 |
    8 | {children} 9 |
    10 | ); 11 | 12 | Main.propTypes = { 13 | children: PropTypes.node.isRequired 14 | }; 15 | 16 | export default Main; 17 | -------------------------------------------------------------------------------- /src/components/Menu/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define Menu; */ 4 | 5 | .Menu-items { 6 | list-style: none; 7 | 8 | @media (min-width: 48rem) { 9 | display: flex; 10 | justify-content: space-between; 11 | margin-top: 0; 12 | } 13 | } 14 | 15 | .Menu-secondaryItems { 16 | list-style: none; 17 | 18 | @media (min-width: 48rem) { 19 | background: color-mod(var(--black) tint(95%)); 20 | box-shadow: 0 0 0 -1px color-mod(var(--black) tint(60%)); 21 | left: -100vh; 22 | min-width: 12rem; 23 | position: absolute; 24 | 25 | &:focus-within { 26 | left: auto; 27 | } 28 | } 29 | } 30 | 31 | .Menu-secondaryItem { 32 | @media (min-width: 48rem) { 33 | box-shadow: none; 34 | text-align: left; 35 | } 36 | } 37 | 38 | .Menu-link { 39 | color: var(--black); 40 | display: block; 41 | font: 600 var(--type-2) proxima-nova; 42 | padding: 0.75rem 1rem; 43 | text-decoration: none; 44 | white-space: nowrap; 45 | 46 | &:hover, 47 | &:active { 48 | background: color-mod(var(--black) tint(95%)); 49 | color: var(--brand-colour); 50 | } 51 | 52 | @media (min-width: 48rem) { 53 | box-shadow: none; 54 | 55 | &:hover { 56 | box-shadow: inset 0 0.25rem 0 0 var(--brand-colour), 57 | inset 0 -1px 0 0 var(--white); 58 | } 59 | } 60 | } 61 | 62 | .Menu-secondaryLink { 63 | color: var(--black); 64 | display: block; 65 | font: 300 var(--type-1) var(--body-font); 66 | margin: 0.25rem 0; 67 | padding: 0.5rem 1rem; 68 | text-decoration: none; 69 | 70 | &:hover { 71 | text-decoration: underline; 72 | } 73 | } 74 | 75 | .Menu-item { 76 | &:hover, 77 | &:focus-within { 78 | background: color-mod(var(--black) tint(95%)); 79 | 80 | & .Menu-link { 81 | box-shadow: inset 0 0.25rem 0 0 var(--brand-colour), 82 | inset 0 -1px 0 0 var(--white); 83 | color: var(--brand-colour); 84 | } 85 | } 86 | 87 | @media (min-width: 48rem) { 88 | flex: 1; 89 | text-align: center; 90 | 91 | &:hover { 92 | & .Menu-secondaryItems { 93 | left: auto; 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/components/Menu/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import Link from "../Link"; 5 | 6 | import "./index.css"; 7 | 8 | const Menu = ({ items }) => ( 9 | 39 | ); 40 | 41 | Menu.propTypes = { 42 | items: PropTypes.arrayOf( 43 | PropTypes.shape({ 44 | active: PropTypes.bool, 45 | href: PropTypes.string.isRequired, 46 | text: PropTypes.string.isRequired, 47 | items: PropTypes.arrayOf( 48 | PropTypes.shape({ 49 | active: PropTypes.bool, 50 | href: PropTypes.string.isRequired, 51 | text: PropTypes.string.isRequired 52 | }) 53 | ) 54 | }) 55 | ).isRequired 56 | }; 57 | 58 | export default Menu; 59 | -------------------------------------------------------------------------------- /src/components/NumberedList/index.css: -------------------------------------------------------------------------------- 1 | @import "../custom-properties.css"; 2 | 3 | /** @define NumberedList; */ 4 | 5 | .NumberedList { 6 | font: 300 var(--type-0) var(--body-font); 7 | max-width: 36rem; 8 | padding-left: 1rem; 9 | 10 | &:not(:first-child) { 11 | margin-top: 0.75rem; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/components/NumberedList/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | 4 | import "./index.css"; 5 | 6 | const NumberedList = ({ children }) => ( 7 |
      {children}
    8 | ); 9 | 10 | NumberedList.propTypes = { 11 | children: PropTypes.node.isRequired 12 | }; 13 | 14 | export default NumberedList; 15 | -------------------------------------------------------------------------------- /src/components/Page/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | import Helmet from "react-helmet"; 4 | 5 | import DocSearch from "../DocSearch"; 6 | import Footer from "../Footer"; 7 | import Header from "../Header"; 8 | import Layout from "../Layout"; 9 | import Site from "../Site"; 10 | import SkipLink from "../SkipLink"; 11 | 12 | const Page = ({ children, title }) => ( 13 | 17 | 18 | {title} 19 | 20 | 21 | 22 |
    } 24 | title="Go to the Barnardo’s Design System homepage" 25 | /> 26 | {children} 27 |