Skip to content

Commit

Permalink
Merge branch 'next'
Browse files Browse the repository at this point in the history
  • Loading branch information
khamer committed Sep 12, 2022
2 parents 44eed9a + 24f5686 commit 6b02555
Show file tree
Hide file tree
Showing 215 changed files with 13,919 additions and 24,388 deletions.
7 changes: 3 additions & 4 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ To work on Boilerplate locally,

1. Clone this repository.
2. Run `npm install` to install its dependencies.
3. Run `npm run watch` to run the front-end build and watch for file changes.
4. Additionally (in a separate terminal) run `npm run fractal start` to use Fractal's dev server and view the components within your browser.
3. Run `npm run dev` to run the front-end build and watch for file changes, and to use Fractal's dev server and view the components within your browser. (Unlike prior versions, this is now a single command.)

While running like this, any changes made to source files will be picked up immediately. If you add new scss files, you will need to restart `npm run watch` but will not need to restart Fractal.
While running like this, any changes made to source files will be picked up immediately, as will the addition and deletion of new files.


## Creating Pull Requests
Expand All @@ -33,7 +32,7 @@ Submit a pull request and describe what your code is meant to do and why it shou

## Follow Code Conventions

Boilerplate follows [its own conventions](https://imarc-boilerplate.netlify.app/pattern-library/docs/abem.html) as closely as it can; make sure any code you submit does too. If there's areas you're not sure, fallback to Vue style guidelines and ABEM or BEM conventions, or [Imarc's Handbook.](https://handbook.imarc.com/)
See [CONVENTIONS.](CONVENTIONS.md)


## Versioning
Expand Down
56 changes: 56 additions & 0 deletions .github/CONVENTIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Conventions

Beyond Boilerplate's own [documented file structure conventions](https://imarc-boilerplate.netlify.app/pattern-library/docs/structure.html), here are some internal conventions that make sense to follow when contributing to Boilerplate itself. These are just meant to make sure that Boilerplate itself has consistent patterns and terminology.

## Files

In general, avoid huge files in favor of breaking up files into smaller pieces. If a single component gets too complicated, consider breaking it up or creating separate files for its modifiers.


## Code

### Lint Your Code

Make sure to lint your code before pull requests. You can do this by running `npm run lint` or through your editor if your editor has eslint integration.

### CSS/Sass

#### Avoid `@import`, use `@use`/`@forwards`

Unless necessary, avoid the Sass `@import` statement. Using the CSS native `@import` (for things like web fonts) is fine.

#### Only use common as *

Only use /resources/styles/common without a namespace. As in, only
```
@use "/resource/styles/common" as *;
```
All other use statements should put them in their own namespaces.

#### Prefer Sass Variables

Prefer Sass variables over custom properties. In general, only use custom properties if

1. If the value will change based on media queries.
2. You're going to change the value and use the value more than once.
3. You're going to change the value and the value is only part of a property. For example, a stop within a gradient.

Prefer to keep canonical values in Sass. Sass is more powerful than CSS still. You can use Sass variables in CSS expressions, but you can't use custom properties in Sass expressions.

##### Custom Property Naming

Use [BPM](https://www.imarc.com/blog/block-property-modifier-a-bem-like-css-custom-properties-methodology) for general naming. There are some project specific conventions as well:

* In general, `--color` and `--<componentName>-color` will be used to set a component's dominant color instead of text color.
* A suffix of `-contrast` (for example, `--color-contrast`) indicates that it's a near black or near white color meant to provide sufficient contrast for text when used on top of the related color.
* A suffix of `-faded` is used for repeating an existing color with a lower opacity.


#### Prefer Triple slashes for docblock comments


### Vue

#### Use The Composition API

All components should be built to use the Vue composition API. We should aim to clearly separate composable components for functionality that are used by simple, UI focused components.
48 changes: 34 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
This is a front-end development framework that includes a curated set of conventions and libraries, including

* [Sass](https://sass-lang.com) and [Vue](https://vuejs.org/) **components**, built using
* [Atomic Design](https://atomicdesign.bradfrost.com/) and [ABEM](https://css-tricks.com/abem-useful-adaptation-bem/) **conventions**, integrated with
* [Laravel Mix](https://laravel-mix.com/)-based **build scripts**,
* [Atomic Design](https://atomicdesign.bradfrost.com/) and [ABEM](https://css-tricks.com/abem-useful-adaptation-bem/) **conventions**, powered by
* [Vite](https://vitejs.dev/) for fast builds and hot reloading, and
* **starter documentation** and a **pattern library** powered by [Fractal](https://fractal.build/) and [Twig](https://github.com/twigjs/twig.js).

### **[View Boilerplate](https://imarc-boilerplate.netlify.app/)**
This is an *work in progress* branch that replaces Webpack/Mix with Vite. Please give us feedback!


Framework, not a Library
------------------------

Unlike traditional libraries, the code included within Boilerplate is *scaffolded* into your project so you can adapt it to do your needs. It adds a `fractal.config.js`, `webpack.mix.js`, as well as everything in the `resources/` folder to your project. [Learn more about Boilerplate's structure.](https://imarc-boilerplate.netlify.app/pattern-library/docs/structure.html)
Unlike traditional libraries, the code included within Boilerplate is *scaffolded* into your project so you can adapt it to do your needs. It adds a `fractal.config.js`, `vite.config.js`, as well as everything in the `resources/` folder to your project. [Learn more about Boilerplate's structure.](https://imarc-boilerplate.netlify.app/pattern-library/docs/structure.html)

Goals
-----
Expand All @@ -40,29 +40,49 @@ npm init -y
Once you have a `package.json` file, you can install Boilerplate:

```
npm install imarc-boilerplate
npm install imarc-boilerplate@next
npx imarc-boilerplate
```

The `npx` command automatically copies `fractal.config.js`, `webpack.mix.js`, and the `resources/` folder out of `node_modules/` into your project for your use. It also updates the npm `scripts` section within your `package.json`.
The `npx` command automatically copies `fractal.config.js`, `vite.config.js`, and the `resources/` folder out of `node_modules/` into your project for your use. It also updates the npm `scripts` section within your `package.json`.



### Using the Build (Laravel Mix)
### Using the Build (Vite)

After Boilerplate is installed, you can build your front-end files by running the following:

* `npm run dev` will run the the development build (make sourcemaps, don't minify, etc.)
* `npm run watch` also runs the development build, but it watches for changes to the source files and automatically re-runs the build when they change.
* `npm run lint` uses eslint to lint your code.
* `npm run dev` runs Vite's development server and fractal.
* `npm run prod` will run the production build which is optimized for deployment in production.
* `npm run preview` runs a Vite development server but serves the files build by `npm run prod` so you can test the production build locally.

### Using the Pattern Library (Fractal)

Boilerplate includes [Fractal](https://fractal.build/), a pattern library. Within Fractal you can see all the components available within your project. You can [see an example here.](https://imarc-boilerplate.netlify.app/)

* `npm run fractal start` runs Fractal's development server. It has hot reloading and will automatically detect when you add or remove components.
* `npm run fractal build` has Fractal build a static version of the pattern library, by default into /web/pattern-library/.
Fractal's development server is automatically started whenever you're running Vite's development server, and is served by default when you run `npm run dev`. Both Vite's hot reloading of compiled code as well as Fractal's automatic detection of new components work together.

You can still run `npm run fractal build` to build a static version of the pattern library, however it requires that you have already run `npm run prod` to compile your CSS/JS first.

You can customize this behavior further by editing either the `vite.config.js` or `fractal.config.js` files per the [Vite](https://vitejs.dev/) or [Fractal documentation](https://fractal.build/) respectively.

**It's no longer needed to run `npm run watch` and `npm run fractal start` in different terminals at the same time.** Enjoy!

### Using with Craft or Laravel

To use with Craft, try the [Vite plugin](https://plugins.craftcms.com/vite) by nystudio107.

To use with Laravel, try out [Laravel Vite](https://laravel-vite.dev/).


You can customize this behavior further by editing either the `webpack.mix.js` or `fractal.config.js` files per the [Laravel Mix](https://laravel-mix.com/) or [Fractal documentation](https://fractal.build/) respectively.
### What's New From Boilerplate 5

**While working on components within the pattern library,** you will likely want to run `npm run watch` in one terminal while running `npm run fractal start` in another. The first will watch for source file changes and the second will watch for changes to the twig and compiled files.
* Vite
* Explicit imports (no globbing)
* Directory structure changes
* Less mixins
* Modular Sass: `@use`, `@forwards`, `_index.scss`
* Grid
* CSS custom properties
* Vue 3
* Cypress (Vitest)
18 changes: 6 additions & 12 deletions boilerplate.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,19 @@ const dest = path.resolve('./')
const packageJsonPath = path.resolve('./package.json')

const scripts = {
lint: 'eslint resources',
fractal: 'fractal',
dev: "mix",
prod: "mix --production",
watch: "mix watch",
"watch-poll": "mix watch -- -- watch-options-poll=1000",
hot: "mix watch --hot",
build: "npm run prod && npm run fractal build"
dev: 'vite',
preview: 'vite preview',
prod: 'vite build',
}

// Add the files
console.log(`Copying files to ${dest}...`)

const files = [
'resources',
'webpack.mix.js',
'vite.config.js',
'fractal.config.js',
]

Expand All @@ -46,8 +44,4 @@ json.writeFileSync(packageJsonPath, packageJson)

// All done.
console.log('Done.')
console.log('Remember to run ' +
chalk.underline('npm run dev') + ' first, then either ' +
chalk.underline('npm run fractal start') + ' or ' +
chalk.underline('npm run fractal build') +
' to create your pattern library.\n')
console.log('Run ' + chalk.underline('npm run dev') + ' to get started.\n')
5 changes: 5 additions & 0 deletions cypress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"baseUrl": "http://localhost:5173",
"testFiles": "**/*.spec.js",
"componentFolder": "resources/"
}
23 changes: 23 additions & 0 deletions cypress/integration/BpClickable.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
describe('BpClickable', () => {
beforeEach(() => cy.visit('/components/preview/clickable'))

it('is clickable', () => {
cy.get('.card').first().click()
cy.location('hash').should('eq', '#example')
})

it('works with multiple instances', () => {
cy.get('.card').eq(1).click()
cy.location('hash').should('eq', '#example2')
})

it('allows nested links to work', () => {
cy.get('.card .card__content a').first().click()
cy.location('hash').should('eq', '#nope')
})

it('clicking the CTA still works', () => {
cy.get('.card .card__action').first().click()
cy.location('hash').should('eq', '#example')
})
})
102 changes: 102 additions & 0 deletions cypress/integration/BpDirectional.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
describe('BpDirectional at 1000px wide', () => {
beforeEach(() => cy.visit('/components/preview/directional'))
it('can be focused', () => {
cy.get('li a').first().focus()
cy.get('li a').first().should('be.focused')
})

it('moves focus right', () => {
cy.get('li a').first().focus()
cy.get('li a').first().should('be.focused')
cy.get('body').type('{rightArrow}')
cy.get('li a').eq(1).should('be.focused')
cy.get('body').type('{rightArrow}')
cy.get('li a').eq(2).should('be.focused')
})

it('moves focus left', () => {
cy.get('li a').eq(2).focus()
cy.get('body').type('{leftArrow}')
cy.get('li a').eq(1).should('be.focused')
cy.get('body').type('{leftArrow}')
cy.get('li a').eq(0).should('be.focused')
})

it('moves focus down', () => {
cy.get('li a').first().focus()
cy.get('body').type('{downArrow}')
cy.get('li a').eq(3).should('be.focused')
cy.get('body').type('{downArrow}')
cy.get('li a').eq(6).should('be.focused')
})

it('moves focus up', () => {
cy.get('li a').eq(7).focus()
cy.get('body').type('{upArrow}')
cy.get('li a').eq(4).should('be.focused')
cy.get('body').type('{upArrow}')
cy.get('li a').eq(1).should('be.focused')
})

it('moves focus via home', () => {
cy.get('li a').eq(7).focus()
cy.get('body').type('{home}')
cy.get('li a').eq(0).should('be.focused')
})

it('moves focus via end', () => {
cy.get('li a').eq(7).focus()
cy.get('body').type('{end}')
cy.get('li a').last().should('be.focused')
})

it('contrains bounds', () => {
cy.get('li a').first().focus()
cy.get('body').type('{upArrow}')
cy.get('li a').first().should('be.focused')
cy.get('body').type('{leftArrow}')
cy.get('li a').first().should('be.focused')

cy.get('li a').last().focus()
cy.get('body').type('{downArrow}')
cy.get('li a').last().should('be.focused')
cy.get('body').type('{rightArrow}')
cy.get('li a').last().should('be.focused')
})
})

describe('BpDirectional at 700px wide', () => {
beforeEach(() => {
cy.viewport(700, 660)
cy.visit('/components/preview/directional')
})

it('moves focus right', () => {
cy.get('li a').first().focus()
cy.get('li a').first().should('be.focused')
cy.get('body').type('{rightArrow}')
cy.get('li a').eq(1).should('be.focused')
})

it('moves focus left', () => {
cy.get('li a').eq(1).focus()
cy.get('body').type('{leftArrow}')
cy.get('li a').eq(0).should('be.focused')
})

it('moves focus down', () => {
cy.get('li a').first().focus()
cy.get('body').type('{downArrow}')
cy.get('li a').eq(2).should('be.focused')
cy.get('body').type('{downArrow}')
cy.get('li a').eq(4).should('be.focused')
})

it('moves focus up', () => {
cy.get('li a').eq(5).focus()
cy.get('body').type('{upArrow}')
cy.get('li a').eq(3).should('be.focused')
cy.get('body').type('{upArrow}')
cy.get('li a').eq(1).should('be.focused')
})
})
19 changes: 19 additions & 0 deletions cypress/integration/BpDismissable.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
describe('BpDismissable', () => {
it('visible on load', () => {
cy.visit('/components/preview/dismissable')
cy.get('.banner').should('be.visible')
})

it('can be dismissed', () => {
cy.visit('/components/preview/dismissable')
cy.get('button.banner__dismiss').first().click()
cy.get('.banner').should('not.exist')
})
it('stays dismissed', () => {
cy.visit('/components/preview/dismissable')
cy.get('button.banner__dismiss').first().click()
cy.get('.banner').should('not.exist')
cy.reload()
cy.get('.banner').should('not.exist')
})
})
26 changes: 26 additions & 0 deletions cypress/integration/BpDropdown.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
describe('BpDropdown', () => {
it('opens on click', () => {
cy.visit('/components/preview/dropdown')

cy.get('button[aria-controls="js-about"]').first().click()
cy.get('#js-about').should('be.visible')
})

it('closes on escape', () => {
cy.visit('/components/preview/dropdown')

cy.get('button[aria-controls="js-about"]').first().click()

cy.get('body').type('{esc}')
cy.get('#js-about').should('be.hidden')
})

it('closes on click', () => {
cy.visit('/components/preview/dropdown')

cy.get('button[aria-controls="js-about"]').first().click()

cy.get('button[aria-controls="js-about"]').first().click()
cy.get('#js-about').should('be.hidden')
})
})
Loading

0 comments on commit 6b02555

Please sign in to comment.