Initial commit: MVP+ wish board with FastAPI + Tailwind
This commit is contained in:
commit
cd945a6128
2277 files changed
+843095
No files matched your search
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Alex Reardon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+290
@@ -0,0 +1,290 @@
|
||||
# `css-box-model` 📦
|
||||
|
||||
Get accurate and well named [CSS Box Model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model) information about a [`Element`](https://developer.mozilla.org/en-US/docs/Web/API/Element).
|
||||
|
||||
[](https://travis-ci.org/alexreardon/css-box-model)
|
||||
[](https://www.npmjs.com/package/css-box-model)
|
||||
[](https://david-dm.org/alexreardon/css-box-model)
|
||||
[](https://www.npmjs.com/package/css-box-model)
|
||||
[](https://www.npmjs.com/package/css-box-model)
|
||||
[](https://www.npmjs.com/package/css-box-model)
|
||||
|
||||
Any time you are using [`Element.getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect) you might want to consider using `css-box-model` instead to get more detailed box model information.
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
// @flow
|
||||
import { getBox } from 'css-box-model';
|
||||
|
||||
const el: HTMLElement = document.getElementById('foo');
|
||||
const box: BoxModel = getBox(el);
|
||||
|
||||
// profit
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
## yarn
|
||||
yarn add css-box-model
|
||||
|
||||
# npm
|
||||
npm install css-box-model --save
|
||||
```
|
||||
|
||||
## The [CSS Box Model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model)
|
||||
|
||||

|
||||
|
||||
| Box type | Composition |
|
||||
| ----------- | ----------------------------------- |
|
||||
| Margin box | margin + border + padding + content |
|
||||
| Border box | border + padding + content |
|
||||
| Padding box | padding + content |
|
||||
| Content box | content |
|
||||
|
||||
This our returned `BoxModel`:
|
||||
|
||||
```js
|
||||
export type BoxModel = {|
|
||||
// content + padding + border + margin
|
||||
marginBox: Rect,
|
||||
// content + padding + border
|
||||
borderBox: Rect,
|
||||
// content + padding
|
||||
paddingBox: Rect,
|
||||
// content
|
||||
contentBox: Rect,
|
||||
// for your own consumption
|
||||
border: Spacing,
|
||||
padding: Spacing,
|
||||
margin: Spacing,
|
||||
|};
|
||||
|
||||
// Supporting types
|
||||
|
||||
// This is an extension of DOMRect and ClientRect
|
||||
export type Rect = {|
|
||||
// ClientRect
|
||||
top: number,
|
||||
right: number,
|
||||
bottom: number,
|
||||
left: number,
|
||||
width: number,
|
||||
height: number,
|
||||
// DOMRect
|
||||
x: number,
|
||||
y: number,
|
||||
// Rect
|
||||
center: Position,
|
||||
|};
|
||||
|
||||
export type Position = {|
|
||||
x: number,
|
||||
y: number,
|
||||
|};
|
||||
|
||||
export type Spacing = {
|
||||
top: number,
|
||||
right: number,
|
||||
bottom: number,
|
||||
left: number,
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### `getBox`
|
||||
|
||||
> (el: HTMLElement) => BoxModel
|
||||
|
||||
Use `getBox` to return the box model for an element
|
||||
|
||||
### `withScroll`
|
||||
|
||||
> `(original: BoxModel, scroll?: Position = getWindowScroll()) => BoxModel`
|
||||
|
||||
This is useful if you want to know the box model for an element relative to a page
|
||||
|
||||
```js
|
||||
const el: HTMLElement = document.getElementById('app');
|
||||
const box: BoxModel = getBox(el);
|
||||
const withScroll: BoxModel = withScroll(box);
|
||||
```
|
||||
|
||||
You are welcome to pass in your own `scroll`. By default we we use the window scroll:
|
||||
|
||||
```js
|
||||
const getWindowScroll = (): Position => ({
|
||||
x: window.pageXOffset,
|
||||
y: window.pageYOffset,
|
||||
});
|
||||
```
|
||||
|
||||
### `calculateBox`
|
||||
|
||||
> `(borderBox: AnyRectType, styles: CSSStyleDeclaration) => BoxModel`
|
||||
|
||||
This will do the box model calculations without needing to read from the DOM. This is useful if you have already got a `ClientRect` / `DOMRect` and a `CSSStyleDeclaration` as then we can skip computing these values.
|
||||
|
||||
```js
|
||||
const el: HTMLElement = document.getElementById('app');
|
||||
const borderBox: ClientRect = el.getBoundingClientRect();
|
||||
const styles: CSSStyleDeclaration = window.getComputedStyles(el);
|
||||
|
||||
const box: BoxModel = calculateBox(borderBox, styles);
|
||||
```
|
||||
|
||||
**`AnyRectType`** allows for simple interoperability with any rect type
|
||||
|
||||
```js
|
||||
type AnyRectType = ClientRect | DOMRect | Rect | Spacing;
|
||||
```
|
||||
|
||||
### `createBox`
|
||||
|
||||
> `({ borderBox, margin, border, padding }: CreateBoxArgs) => BoxModel`
|
||||
|
||||
Allows you to create a `BoxModel` by passing in a `Rect` like shape (`AnyRectType`) and optionally your own `margin`, `border` and or `padding`.
|
||||
|
||||
```js
|
||||
type CreateBoxArgs = {|
|
||||
borderBox: AnyRectType,
|
||||
margin?: Spacing,
|
||||
border?: Spacing,
|
||||
padding?: Spacing,
|
||||
|};
|
||||
```
|
||||
|
||||
```js
|
||||
const borderBox: Spacing = {
|
||||
top: 10,
|
||||
right: 100,
|
||||
left: 20,
|
||||
bottom: 80,
|
||||
};
|
||||
const padding: Spacing = {
|
||||
top: 10,
|
||||
right: 20,
|
||||
left: 20,
|
||||
bottom: 10,
|
||||
};
|
||||
|
||||
const box: BoxModel = createBox({ borderBox, padding });
|
||||
```
|
||||
|
||||
## Utility API
|
||||
|
||||
> Functions to help you interact with the objects we provide
|
||||
|
||||
### `getRect`
|
||||
|
||||
> `(spacing: AnyRectType) => Rect`
|
||||
|
||||
Given any `Rect` like shape, return a `Rect`. Accepts any object that has `top`, `right`, `bottom` and `right` (eg `ClientRect`, `DOMRect`);
|
||||
|
||||
```js
|
||||
const spacing: Spacing = {
|
||||
top: 0,
|
||||
right: 100,
|
||||
bottom: 50,
|
||||
left: 50,
|
||||
};
|
||||
|
||||
const rect: Rect = getRect(spacing);
|
||||
|
||||
console.log(rect);
|
||||
|
||||
/*
|
||||
{
|
||||
top: 0,
|
||||
right: 100,
|
||||
bottom: 50,
|
||||
left: 50,
|
||||
width: 100,
|
||||
height: 50,
|
||||
x: 0,
|
||||
y: 0,
|
||||
center: { x: 50, y: 50 },
|
||||
}
|
||||
*/
|
||||
```
|
||||
|
||||
### `expand`
|
||||
|
||||
Used to expand a `Spacing`
|
||||
|
||||
```js
|
||||
(target: Spacing, expandBy: Spacing) => Spacing;
|
||||
```
|
||||
|
||||
```js
|
||||
const original: Spacing = {
|
||||
top: 10,
|
||||
left: 11,
|
||||
right: 21,
|
||||
bottom: 22,
|
||||
};
|
||||
|
||||
const expandBy: Spacing = {
|
||||
top: 1,
|
||||
left: 2,
|
||||
right: 3,
|
||||
bottom: 4,
|
||||
};
|
||||
|
||||
const expanded: Spacing = expand(original, expandBy);
|
||||
|
||||
console.log(expanded);
|
||||
|
||||
/*
|
||||
{
|
||||
// pulled back
|
||||
top: 8,
|
||||
left: 8
|
||||
// pushed forward
|
||||
bottom: 22,
|
||||
right: 22,
|
||||
}
|
||||
*/
|
||||
```
|
||||
|
||||
### `shrink`
|
||||
|
||||
Used to shrink a `Spacing`
|
||||
|
||||
```js
|
||||
(target: Spacing, shrinkBy: Spacing) => Spacing;
|
||||
```
|
||||
|
||||
```js
|
||||
const original: Spacing = {
|
||||
top: 10,
|
||||
left: 10,
|
||||
right: 20,
|
||||
bottom: 20,
|
||||
};
|
||||
|
||||
const shrinkBy: Spacing = {
|
||||
top: 2,
|
||||
left: 2,
|
||||
right: 2,
|
||||
bottom: 2,
|
||||
};
|
||||
|
||||
const smaller: Spacing = shrink(original, shrinkBy);
|
||||
|
||||
console.log(smaller);
|
||||
|
||||
/*
|
||||
{
|
||||
// pushed forward
|
||||
top: 12,
|
||||
left: 12
|
||||
// pulled back
|
||||
bottom: 18,
|
||||
right: 18,
|
||||
}
|
||||
*/
|
||||
```
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"name": "css-box-model",
|
||||
"version": "1.2.1",
|
||||
"description": "Get accurate and well named css box model information about an Element 📦",
|
||||
"author": "Alex Reardon <alexreardon@gmail.com>",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/alexreardon/css-box-model.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/alexreardon/css-box-model/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"css",
|
||||
"box model",
|
||||
"css box model",
|
||||
"getBoundingClientRect",
|
||||
"DOMRect",
|
||||
"ClientRect",
|
||||
"Rect",
|
||||
"Spacing",
|
||||
"DOM"
|
||||
],
|
||||
"files": [
|
||||
"/dist",
|
||||
"/src"
|
||||
],
|
||||
"main": "dist/css-box-model.cjs.js",
|
||||
"module": "dist/css-box-model.esm.js",
|
||||
"types": "src/index.d.ts",
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"test": "yarn jest",
|
||||
"lint": "yarn prettier --debug-check src/** test/**",
|
||||
"validate": "yarn lint && flow check",
|
||||
"build:clean": "rimraf dist",
|
||||
"build:flow": "echo \"// @flow\n\nexport * from '../src';\" > dist/css-box-model.cjs.js.flow",
|
||||
"build:dist": "yarn rollup --config rollup.config.js",
|
||||
"build": "yarn build:clean && yarn build:dist && yarn build:flow",
|
||||
"prepublishOnly": "yarn build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.5.5",
|
||||
"@babel/preset-env": "^7.5.5",
|
||||
"@babel/preset-flow": "^7.0.0",
|
||||
"babel-plugin-dev-expression": "^0.2.2",
|
||||
"flow-bin": "0.106.1",
|
||||
"jest": "^24.9.0",
|
||||
"prettier": "1.18.2",
|
||||
"rimraf": "^3.0.0",
|
||||
"rollup": "^1.20.2",
|
||||
"rollup-plugin-babel": "^4.3.3",
|
||||
"rollup-plugin-node-resolve": "^5.2.0",
|
||||
"rollup-plugin-replace": "^2.2.0",
|
||||
"rollup-plugin-terser": "^5.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"tiny-invariant": "^1.0.6"
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
declare module 'css-box-model' {
|
||||
export type Position = {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
|
||||
export type Rect = {
|
||||
top: number;
|
||||
right: number;
|
||||
bottom: number;
|
||||
left: number;
|
||||
width: number;
|
||||
height: number;
|
||||
x: number;
|
||||
y: number;
|
||||
center: Position;
|
||||
};
|
||||
|
||||
export type BoxModel = {
|
||||
marginBox: Rect;
|
||||
borderBox: Rect;
|
||||
paddingBox: Rect;
|
||||
contentBox: Rect;
|
||||
border: Spacing;
|
||||
padding: Spacing;
|
||||
margin: Spacing;
|
||||
};
|
||||
|
||||
export type AnyRectType = ClientRect | DOMRect | Rect | Spacing;
|
||||
|
||||
export type Spacing = {
|
||||
top: number;
|
||||
right: number;
|
||||
bottom: number;
|
||||
left: number;
|
||||
};
|
||||
|
||||
export const getRect: ({ top, right, bottom, left }: Spacing) => Rect;
|
||||
export const expand: (target: Spacing, expandBy: Spacing) => Spacing;
|
||||
export const shrink: (target: Spacing, shrinkBy: Spacing) => Spacing;
|
||||
|
||||
type CreateBoxArgs = {
|
||||
borderBox: AnyRectType;
|
||||
margin?: Spacing;
|
||||
border?: Spacing;
|
||||
padding?: Spacing;
|
||||
};
|
||||
|
||||
export const createBox: (boxArgs: CreateBoxArgs) => BoxModel;
|
||||
export const offset: (original: BoxModel, change: Position) => BoxModel;
|
||||
export const withScroll: (original: BoxModel, scroll?: Position) => BoxModel;
|
||||
|
||||
export const calculateBox: (
|
||||
borderBox: AnyRectType,
|
||||
styles: CSSStyleDeclaration,
|
||||
) => BoxModel;
|
||||
|
||||
export const getBox: (el: Element) => BoxModel;
|
||||
}
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
// @flow
|
||||
import invariant from 'tiny-invariant';
|
||||
|
||||
// # The CSS box model
|
||||
// > https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model
|
||||
//
|
||||
// ------------------------------------
|
||||
// | MARGIN | (marginBox)
|
||||
// | ------------------------------ |
|
||||
// | | BORDER | | (borderBox)
|
||||
// | | ------------------------ | |
|
||||
// | | | PADDING | | | (paddingBox) - not used by anything really
|
||||
// | | | ------------------ | | |
|
||||
// | | | | CONTENT | | | | (contentBox)
|
||||
// | | | | | | | |
|
||||
// | | | | | | | |
|
||||
// | | | | | | | |
|
||||
// | | | ------------------ | | |
|
||||
// | | | | | |
|
||||
// | | ------------------------ | |
|
||||
// | | | |
|
||||
// | ------------------------------ |
|
||||
// | |
|
||||
// | ----------------------------------|
|
||||
|
||||
export type Position = {|
|
||||
x: number,
|
||||
y: number,
|
||||
|};
|
||||
|
||||
export type Rect = {|
|
||||
top: number,
|
||||
right: number,
|
||||
bottom: number,
|
||||
left: number,
|
||||
width: number,
|
||||
height: number,
|
||||
x: number,
|
||||
y: number,
|
||||
center: Position,
|
||||
|};
|
||||
|
||||
export type BoxModel = {|
|
||||
// content + padding + border + margin
|
||||
marginBox: Rect,
|
||||
// content + padding + border
|
||||
borderBox: Rect,
|
||||
// content + padding
|
||||
paddingBox: Rect,
|
||||
// content
|
||||
contentBox: Rect,
|
||||
// for your own consumption
|
||||
border: Spacing,
|
||||
padding: Spacing,
|
||||
margin: Spacing,
|
||||
|};
|
||||
|
||||
export type AnyRectType = ClientRect | DOMRect | Rect | Spacing;
|
||||
|
||||
export type Spacing = {
|
||||
top: number,
|
||||
right: number,
|
||||
bottom: number,
|
||||
left: number,
|
||||
};
|
||||
|
||||
export const getRect = ({ top, right, bottom, left }: Spacing): Rect => {
|
||||
const width: number = right - left;
|
||||
const height: number = bottom - top;
|
||||
|
||||
const rect: Rect = {
|
||||
// ClientRect
|
||||
top,
|
||||
right,
|
||||
bottom,
|
||||
left,
|
||||
width,
|
||||
height,
|
||||
// DOMRect
|
||||
x: left,
|
||||
y: top,
|
||||
// Rect
|
||||
center: {
|
||||
x: (right + left) / 2,
|
||||
y: (bottom + top) / 2,
|
||||
},
|
||||
};
|
||||
|
||||
return rect;
|
||||
};
|
||||
|
||||
export const expand = (target: Spacing, expandBy: Spacing): Spacing => ({
|
||||
// pulling back to increase size
|
||||
top: target.top - expandBy.top,
|
||||
left: target.left - expandBy.left,
|
||||
// pushing forward to increase size
|
||||
bottom: target.bottom + expandBy.bottom,
|
||||
right: target.right + expandBy.right,
|
||||
});
|
||||
|
||||
export const shrink = (target: Spacing, shrinkBy: Spacing): Spacing => ({
|
||||
// pushing forward to decrease size
|
||||
top: target.top + shrinkBy.top,
|
||||
left: target.left + shrinkBy.left,
|
||||
// pulling backwards to decrease size
|
||||
bottom: target.bottom - shrinkBy.bottom,
|
||||
right: target.right - shrinkBy.right,
|
||||
});
|
||||
|
||||
const shift = (target: Spacing, shiftBy: Position): Spacing => ({
|
||||
top: target.top + shiftBy.y,
|
||||
left: target.left + shiftBy.x,
|
||||
bottom: target.bottom + shiftBy.y,
|
||||
right: target.right + shiftBy.x,
|
||||
});
|
||||
|
||||
const noSpacing: Spacing = {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
};
|
||||
|
||||
type CreateBoxArgs = {|
|
||||
borderBox: AnyRectType,
|
||||
margin?: Spacing,
|
||||
border?: Spacing,
|
||||
padding?: Spacing,
|
||||
|};
|
||||
|
||||
export const createBox = ({
|
||||
borderBox,
|
||||
margin = noSpacing,
|
||||
border = noSpacing,
|
||||
padding = noSpacing,
|
||||
}: CreateBoxArgs): BoxModel => {
|
||||
// marginBox = borderBox + margin
|
||||
const marginBox: Rect = getRect(expand(borderBox, margin));
|
||||
// borderBox = borderBox - padding
|
||||
const paddingBox: Rect = getRect(shrink(borderBox, border));
|
||||
// contentBox = paddingBox - padding
|
||||
const contentBox: Rect = getRect(shrink(paddingBox, padding));
|
||||
|
||||
return {
|
||||
marginBox,
|
||||
borderBox: getRect(borderBox),
|
||||
paddingBox,
|
||||
contentBox,
|
||||
margin,
|
||||
border,
|
||||
padding,
|
||||
};
|
||||
};
|
||||
|
||||
// Computed spacing styles will always be in pixels
|
||||
// https://codepen.io/alexreardon/pen/OZyqXe
|
||||
const parse = (raw: string): number => {
|
||||
const value: string = raw.slice(0, -2);
|
||||
const suffix: string = raw.slice(-2);
|
||||
|
||||
// ## Used values vs computed values
|
||||
// `getComputedStyle` will return the * used values * if the
|
||||
// element has `display: none` and the *computed values* otherwise
|
||||
// *used values* can include 'rem' etc.
|
||||
// Rather than throwing we are returning `0`.
|
||||
// Given that the element is _not visible_ it takes up no visible space and so `0` is correct
|
||||
// ## `jsdom`
|
||||
// The `raw` value can also not be populated in jsdom
|
||||
if (suffix !== 'px') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const result: number = Number(value);
|
||||
invariant(
|
||||
!isNaN(result),
|
||||
`Could not parse value [raw: ${raw}, without suffix: ${value}]`,
|
||||
);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const getWindowScroll = (): Position => ({
|
||||
x: window.pageXOffset,
|
||||
y: window.pageYOffset,
|
||||
});
|
||||
|
||||
export const offset = (original: BoxModel, change: Position): BoxModel => {
|
||||
const { borderBox, border, margin, padding } = original;
|
||||
const shifted: Spacing = shift(borderBox, change);
|
||||
|
||||
return createBox({
|
||||
borderBox: shifted,
|
||||
border,
|
||||
margin,
|
||||
padding,
|
||||
});
|
||||
};
|
||||
|
||||
export const withScroll = (
|
||||
original: BoxModel,
|
||||
scroll?: Position = getWindowScroll(),
|
||||
): BoxModel => offset(original, scroll);
|
||||
|
||||
// Exposing this function directly for performance. If you have already computed these things
|
||||
// then you can simply pass them in
|
||||
export const calculateBox = (
|
||||
borderBox: AnyRectType,
|
||||
styles: CSSStyleDeclaration,
|
||||
): BoxModel => {
|
||||
const margin: Spacing = {
|
||||
top: parse(styles.marginTop),
|
||||
right: parse(styles.marginRight),
|
||||
bottom: parse(styles.marginBottom),
|
||||
left: parse(styles.marginLeft),
|
||||
};
|
||||
const padding: Spacing = {
|
||||
top: parse(styles.paddingTop),
|
||||
right: parse(styles.paddingRight),
|
||||
bottom: parse(styles.paddingBottom),
|
||||
left: parse(styles.paddingLeft),
|
||||
};
|
||||
const border: Spacing = {
|
||||
top: parse(styles.borderTopWidth),
|
||||
right: parse(styles.borderRightWidth),
|
||||
bottom: parse(styles.borderBottomWidth),
|
||||
left: parse(styles.borderLeftWidth),
|
||||
};
|
||||
|
||||
return createBox({
|
||||
borderBox,
|
||||
margin,
|
||||
padding,
|
||||
border,
|
||||
});
|
||||
};
|
||||
|
||||
export const getBox = (el: Element): BoxModel => {
|
||||
// getBoundingClientRect always returns the borderBox
|
||||
const borderBox: ClientRect = el.getBoundingClientRect();
|
||||
const styles: CSSStyleDeclaration = window.getComputedStyle(el);
|
||||
|
||||
return calculateBox(borderBox, styles);
|
||||
};
|
||||
Reference in new issue
Block a user