barbican-reset 3.32.0 → 3.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/BrConfirmDone.vue +19 -13
- package/components/BrConfirmEmail.vue +19 -18
- package/components/BrFormCheckbox.vue +38 -4
- package/components/BrFormLabel.vue +2 -1
- package/components/BrOverlay.vue +13 -6
- package/components/BrTableCell.vue +36 -0
- package/components/BrTableHeader.vue +1 -5
- package/components/BrTableRow.vue +19 -0
- package/index.js +4 -0
- package/package.json +1 -1
- package/scripts/animations/confirm.js +79 -0
- package/scripts/helpers/constrainTabbing.js +40 -0
- package/scripts/helpers/logObject.js +3 -10
- package/scripts/helpers.js +2 -1
- package/scss/_atomic.scss +5 -0
- package/scss/_br-form-fieldset.scss +2 -2
- package/scss/_br-table-cell.scss +58 -0
- package/scss/_br-table-header.scss +3 -49
- package/scss/_br-table-row.scss +24 -0
- package/scss/_variables.scss +2 -2
- package/scss/atomic/_font-sizes.scss +6 -0
- package/scss/atomic/_margins.scss +12 -0
- package/scss/atomic/_widths.scss +43 -0
- package/scss/index.scss +2 -0
- package/scss/mixins/_br-card.scss +3 -6
- package/scss/mixins/_br-wrap.scss +1 -2
- package/scss/mixins/_font-size.scss +9 -0
- package/scss/mixins/buttons/custom/_renew-membership.scss +2 -0
- package/scss/mixins/index.scss +1 -0
- package/scss/mixins/input/_checkbox.scss +13 -0
- package/animations/confirm.js +0 -61
- package/animations/index.js +0 -8
|
@@ -1,26 +1,32 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<br-card confirm
|
|
2
|
+
<br-card class="confirm-done">
|
|
3
3
|
<done-icon />
|
|
4
|
-
<br-card-title>Done</br-card-title>
|
|
5
|
-
<br-card-text v-if="$slots.default">
|
|
4
|
+
<br-card-title class="title">Done</br-card-title>
|
|
5
|
+
<br-card-text v-if="$slots.default" class="margin-top-1">
|
|
6
6
|
<slot />
|
|
7
7
|
</br-card-text>
|
|
8
8
|
</br-card>
|
|
9
9
|
</template>
|
|
10
10
|
|
|
11
|
-
<script>
|
|
11
|
+
<script setup>
|
|
12
|
+
import { onMounted } from 'vue'
|
|
13
|
+
import { animateDone } from '#scripts/animations/confirm'
|
|
14
|
+
|
|
12
15
|
import BrCard from '#components/BrCard.vue'
|
|
13
16
|
import BrCardTitle from '#components/BrCardTitle.vue'
|
|
14
17
|
import BrCardText from '#components/BrCardText.vue'
|
|
15
|
-
|
|
16
|
-
import Animations from '#animations/index'
|
|
17
18
|
import DoneIcon from '#icons/confirm/done.vue'
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
mixins: [Animations],
|
|
21
|
-
components: { BrCard, BrCardTitle, BrCardText, DoneIcon },
|
|
22
|
-
mounted() {
|
|
23
|
-
this.animateDone()
|
|
24
|
-
},
|
|
25
|
-
}
|
|
20
|
+
onMounted(() => animateDone())
|
|
26
21
|
</script>
|
|
22
|
+
|
|
23
|
+
<style scoped>
|
|
24
|
+
.confirm-done {
|
|
25
|
+
max-width: var(--width-title);
|
|
26
|
+
text-align: center;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.title {
|
|
30
|
+
text-align: center;
|
|
31
|
+
}
|
|
32
|
+
</style>
|
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<br-card confirm
|
|
2
|
+
<br-card class="confirm-email">
|
|
3
3
|
<email-icon />
|
|
4
|
-
<br-card-title v-if="$slots.title">
|
|
4
|
+
<br-card-title v-if="$slots.title" class="title">
|
|
5
5
|
<slot name="title" />
|
|
6
6
|
</br-card-title>
|
|
7
|
-
<br-card-text v-if="$slots.default">
|
|
7
|
+
<br-card-text v-if="$slots.default" class="margin-top-1">
|
|
8
8
|
<slot />
|
|
9
9
|
</br-card-text>
|
|
10
10
|
</br-card>
|
|
11
11
|
</template>
|
|
12
12
|
|
|
13
|
-
<script>
|
|
13
|
+
<script setup>
|
|
14
|
+
import { onMounted } from 'vue'
|
|
15
|
+
import { animateEmail } from '#scripts/animations/confirm'
|
|
16
|
+
|
|
14
17
|
import BrCard from '#components/BrCard.vue'
|
|
15
18
|
import BrCardTitle from '#components/BrCardTitle.vue'
|
|
16
19
|
import BrCardText from '#components/BrCardText.vue'
|
|
17
|
-
|
|
18
|
-
import Animations from '#animations/index'
|
|
19
20
|
import EmailIcon from '#icons/confirm/email.vue'
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
mixins: [Animations],
|
|
23
|
-
components: {
|
|
24
|
-
BrCard,
|
|
25
|
-
BrCardTitle,
|
|
26
|
-
BrCardText,
|
|
27
|
-
EmailIcon,
|
|
28
|
-
},
|
|
29
|
-
mounted() {
|
|
30
|
-
this.animateEmail()
|
|
31
|
-
},
|
|
32
|
-
}
|
|
22
|
+
onMounted(() => animateEmail())
|
|
33
23
|
</script>
|
|
24
|
+
|
|
25
|
+
<style scoped>
|
|
26
|
+
.confirm-email {
|
|
27
|
+
max-width: var(--width-title);
|
|
28
|
+
text-align: center;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.title {
|
|
32
|
+
text-align: center;
|
|
33
|
+
}
|
|
34
|
+
</style>
|
|
@@ -1,14 +1,22 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component BrFormCheckbox
|
|
3
|
+
@description A checkbox form field that wraps BrFormInput (type="checkbox") inside a BrFormLabel.
|
|
4
|
+
Supports success/error states, disabled state, block-level layout, and an optional label slot.
|
|
5
|
+
Non-prop attributes (e.g. name, value) are forwarded directly to the underlying input element.
|
|
6
|
+
Any classes passed to this component are merged onto the root wrapper div.
|
|
7
|
+
-->
|
|
1
8
|
<template>
|
|
2
|
-
<div :class="['br-form-checkbox', { block }]">
|
|
9
|
+
<div :class="['br-form-checkbox', { block }, $attrs.class]">
|
|
3
10
|
<br-form-label
|
|
4
11
|
:class="[{ success }, { error }]"
|
|
5
12
|
:disabled="disabled"
|
|
6
|
-
:id="generateID"
|
|
13
|
+
:id="generateID"
|
|
14
|
+
:table="table">
|
|
7
15
|
<br-form-input
|
|
8
16
|
:class="[{ success }, { error }]"
|
|
9
17
|
:disabled="disabled"
|
|
18
|
+
v-bind="inputAttrs"
|
|
10
19
|
:id="generateID"
|
|
11
|
-
v-bind="$attrs"
|
|
12
20
|
type="checkbox"
|
|
13
21
|
:error="error" />
|
|
14
22
|
<span v-if="$slots.default" class="label-text">
|
|
@@ -19,21 +27,47 @@
|
|
|
19
27
|
</template>
|
|
20
28
|
|
|
21
29
|
<script setup>
|
|
22
|
-
import { computed } from 'vue'
|
|
30
|
+
import { computed, useAttrs } from 'vue'
|
|
23
31
|
import formatKebabCase from '#helpers/formatKebabCase'
|
|
24
32
|
import BrFormLabel from '#components/BrFormLabel.vue'
|
|
25
33
|
import BrFormInput from '#components/BrFormInput.vue'
|
|
26
34
|
|
|
35
|
+
/** All fallthrough attributes from the parent. */
|
|
36
|
+
const attrs = useAttrs()
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Attrs forwarded to the inner input, with `class` removed so it doesn't
|
|
40
|
+
* double-apply (class is already merged onto the root div via $attrs.class).
|
|
41
|
+
*
|
|
42
|
+
* @type {import('vue').ComputedRef<Record<string, unknown>>}
|
|
43
|
+
*/
|
|
44
|
+
const inputAttrs = computed(() => {
|
|
45
|
+
const { class: _, ...rest } = attrs
|
|
46
|
+
return rest
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Disable automatic attribute inheritance so $attrs can be manually
|
|
51
|
+
* forwarded to the inner input element rather than the root div.
|
|
52
|
+
*/
|
|
27
53
|
defineOptions({
|
|
28
54
|
inheritAttrs: false,
|
|
29
55
|
})
|
|
30
56
|
|
|
57
|
+
/**
|
|
58
|
+
* @prop {string} [id] - Explicit id for the input/label pair. Falls back to a random id.
|
|
59
|
+
* @prop {boolean} [disabled] - Disables the checkbox input and label.
|
|
60
|
+
* @prop {boolean} [success] - Applies success styling to the label and input.
|
|
61
|
+
* @prop {boolean} [error] - Applies error styling to the label and input.
|
|
62
|
+
* @prop {boolean} [block] - Makes the checkbox wrapper display as a block-level element.
|
|
63
|
+
*/
|
|
31
64
|
const props = defineProps({
|
|
32
65
|
id: String,
|
|
33
66
|
disabled: Boolean,
|
|
34
67
|
success: Boolean,
|
|
35
68
|
error: Boolean,
|
|
36
69
|
block: Boolean,
|
|
70
|
+
table: Boolean,
|
|
37
71
|
})
|
|
38
72
|
|
|
39
73
|
// @description Returns a string for the "id" attribute
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<component
|
|
3
|
-
:class="['br-form-label', { disabled }]"
|
|
3
|
+
:class="['br-form-label', { disabled }, { table }]"
|
|
4
4
|
:is="!disabled ? 'label' : 'div'"
|
|
5
5
|
:for="!disabled ? id : null">
|
|
6
6
|
<slot />
|
|
@@ -14,6 +14,7 @@ const props = defineProps({
|
|
|
14
14
|
disabled: Boolean,
|
|
15
15
|
required: Boolean,
|
|
16
16
|
optional: Boolean,
|
|
17
|
+
table: Boolean,
|
|
17
18
|
id: String,
|
|
18
19
|
})
|
|
19
20
|
</script>
|
package/components/BrOverlay.vue
CHANGED
|
@@ -10,24 +10,31 @@
|
|
|
10
10
|
</template>
|
|
11
11
|
|
|
12
12
|
<script setup>
|
|
13
|
-
import { onMounted, onUnmounted } from 'vue'
|
|
14
|
-
import
|
|
15
|
-
import
|
|
13
|
+
import { onMounted, onUnmounted } from 'vue'
|
|
14
|
+
import { constrainTabbing } from '#scripts/helpers'
|
|
15
|
+
import BrButton from '#components/BrButton.vue'
|
|
16
|
+
import CloseIcon from '#icons/close.vue'
|
|
16
17
|
|
|
17
|
-
const emit = defineEmits([
|
|
18
|
+
const emit = defineEmits(['closeOverlay'])
|
|
19
|
+
|
|
20
|
+
function constrainOverlayPadding() {
|
|
21
|
+
let $overlay = document.querySelector('.br-overlay-wrap')
|
|
22
|
+
constrainTabbing($overlay)
|
|
23
|
+
}
|
|
18
24
|
|
|
19
25
|
function listenForKeys({ key }) {
|
|
20
26
|
if (key == 'Escape') {
|
|
21
|
-
emit('closeOverlay')
|
|
27
|
+
emit('closeOverlay')
|
|
22
28
|
}
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
onMounted(() => {
|
|
26
32
|
document.addEventListener('keydown', listenForKeys)
|
|
33
|
+
document.addEventListener('keydown', constrainOverlayPadding)
|
|
27
34
|
})
|
|
28
35
|
|
|
29
36
|
onUnmounted(() => {
|
|
30
37
|
document.removeEventListener('keydown', listenForKeys)
|
|
38
|
+
document.removeEventListener('keydown', constrainOverlayPadding)
|
|
31
39
|
})
|
|
32
40
|
</script>
|
|
33
|
-
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="generateClassnames">
|
|
3
|
+
<slot />
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup>
|
|
8
|
+
import { computed } from 'vue'
|
|
9
|
+
|
|
10
|
+
const generateClassnames = computed(() => {
|
|
11
|
+
let classnames = ['br-table-cell']
|
|
12
|
+
|
|
13
|
+
if (props.width) {
|
|
14
|
+
classnames.push('width-' + props.width)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (props.right) {
|
|
18
|
+
classnames.push('align-right')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (props.center) {
|
|
22
|
+
classnames.push('align-center')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return classnames
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const props = defineProps({
|
|
29
|
+
width: {
|
|
30
|
+
type: String,
|
|
31
|
+
default: 'stretch',
|
|
32
|
+
},
|
|
33
|
+
right: Boolean,
|
|
34
|
+
center: Boolean,
|
|
35
|
+
})
|
|
36
|
+
</script>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="generateClassnames">
|
|
3
|
+
<slot />
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup>
|
|
8
|
+
import { computed } from 'vue'
|
|
9
|
+
|
|
10
|
+
const generateClassnames = computed(() => {
|
|
11
|
+
let classnames = ['br-table-row']
|
|
12
|
+
return classnames
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const props = defineProps({
|
|
16
|
+
right: Boolean,
|
|
17
|
+
center: Boolean,
|
|
18
|
+
})
|
|
19
|
+
</script>
|
package/index.js
CHANGED
|
@@ -45,7 +45,9 @@ import BrOverlay from '#components/BrOverlay.vue'
|
|
|
45
45
|
import BrLoader from '#components/BrLoader.vue'
|
|
46
46
|
import BrSkiplink from '#components/BrSkiplink.vue'
|
|
47
47
|
import BrStatusBars from '#components/BrStatusBars.vue'
|
|
48
|
+
import BrTableCell from '#components/BrTableCell.vue'
|
|
48
49
|
import BrTableHeader from '#components/BrTableHeader.vue'
|
|
50
|
+
import BrTableRow from '#components/BrTableRow.vue'
|
|
49
51
|
import BrWrap from '#components/BrWrap.vue'
|
|
50
52
|
|
|
51
53
|
export {
|
|
@@ -89,6 +91,8 @@ export {
|
|
|
89
91
|
BrOverlay,
|
|
90
92
|
BrSkiplink,
|
|
91
93
|
BrStatusBars,
|
|
94
|
+
BrTableCell,
|
|
92
95
|
BrTableHeader,
|
|
96
|
+
BrTableRow,
|
|
93
97
|
BrWrap,
|
|
94
98
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "barbican-reset",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.33.0",
|
|
4
4
|
"description": "Shared design system for Barbican projects, providing SCSS utilities, animations, icons, Vue components, and JS helpers for consistent styling and behaviour.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"exports": {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import gsap from 'gsap'
|
|
2
|
+
|
|
3
|
+
let defaults = {
|
|
4
|
+
duration: 0.6,
|
|
5
|
+
ease: 'power1.in',
|
|
6
|
+
transformOrigin: 'center',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let fadeIn = {
|
|
10
|
+
duration: 0.3,
|
|
11
|
+
opacity: 0,
|
|
12
|
+
delay: 0.3,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let explode = {
|
|
16
|
+
ease: 'power1.out',
|
|
17
|
+
opacity: 0,
|
|
18
|
+
scale: 1.5,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function animateDone() {
|
|
22
|
+
let $card = document.querySelector('.br-card.confirm-done')
|
|
23
|
+
let $title = $card.querySelector('.br-card-title')
|
|
24
|
+
let $outline = $card.querySelector('.outline')
|
|
25
|
+
let $arrow = $card.querySelector('.arrow')
|
|
26
|
+
let $tick = $card.querySelector('.tick')
|
|
27
|
+
|
|
28
|
+
let tl = gsap.timeline({ defaults })
|
|
29
|
+
|
|
30
|
+
let $clone = $title.cloneNode(true)
|
|
31
|
+
|
|
32
|
+
$clone.classList.add('clone')
|
|
33
|
+
|
|
34
|
+
$title.after($clone)
|
|
35
|
+
|
|
36
|
+
let cloneHeight = $card.querySelector('.clone').offsetHeight
|
|
37
|
+
|
|
38
|
+
$clone.style.marginTop = `-${cloneHeight}px`
|
|
39
|
+
|
|
40
|
+
// prettier-ignore
|
|
41
|
+
tl.set($arrow, { opacity: 0 })
|
|
42
|
+
.from($title, fadeIn)
|
|
43
|
+
.set($clone, { opacity: 0.4 })
|
|
44
|
+
.from($outline, { drawSVG: '0%' }, 'start')
|
|
45
|
+
.from($tick, { drawSVG: '0%', duration: 0.3 }, 'start')
|
|
46
|
+
.to($clone, explode, 'start')
|
|
47
|
+
.set($arrow, { opacity: 1 })
|
|
48
|
+
.from($arrow, { x: -6, ease: 'power1.out' })
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function animateEmail() {
|
|
52
|
+
let $card = document.querySelector('.br-card.confirm-email')
|
|
53
|
+
let $title = $card.querySelector('.br-card-title')
|
|
54
|
+
let $outline = $card.querySelector('.outline')
|
|
55
|
+
let $arrow = $card.querySelector('.arrow')
|
|
56
|
+
let $fold = $card.querySelector('.fold')
|
|
57
|
+
|
|
58
|
+
let tl = gsap.timeline({ defaults })
|
|
59
|
+
|
|
60
|
+
let $clone = $title.cloneNode(true)
|
|
61
|
+
|
|
62
|
+
$clone.classList.add('clone')
|
|
63
|
+
|
|
64
|
+
$title.after($clone)
|
|
65
|
+
|
|
66
|
+
let cloneHeight = $card.querySelector('.clone').offsetHeight
|
|
67
|
+
|
|
68
|
+
$clone.style.marginTop = `-${cloneHeight}px`
|
|
69
|
+
|
|
70
|
+
// prettier-ignore
|
|
71
|
+
tl.set($arrow, { opacity: 0 })
|
|
72
|
+
.from($title, fadeIn)
|
|
73
|
+
.set($clone, { opacity: 0.4 })
|
|
74
|
+
.from($outline, { drawSVG: '0%' }, 'start')
|
|
75
|
+
.from($fold, { drawSVG: '0%', duration: 0.3 }, 'start')
|
|
76
|
+
.to($clone, explode, 'start')
|
|
77
|
+
.set($arrow, { opacity: 1 })
|
|
78
|
+
.from($arrow, { x: -6, ease: 'power1.out' })
|
|
79
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constrains keyboard tab focus to within a given DOM element, creating a focus trap.
|
|
3
|
+
* When the user tabs past the last focusable element, focus wraps to the first,
|
|
4
|
+
* and vice versa when shift-tabbing past the first.
|
|
5
|
+
*
|
|
6
|
+
* Useful for modal dialogs and overlays where focus should not escape to the
|
|
7
|
+
* rest of the page while the element is active.
|
|
8
|
+
*
|
|
9
|
+
* @param {HTMLElement} element - The container element to trap focus within.
|
|
10
|
+
* @returns {void}
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* constrainTabbing(document.getElementById('modal'))
|
|
14
|
+
*/
|
|
15
|
+
export default function (element) {
|
|
16
|
+
let focusableEls = element.querySelectorAll('a[href]:not([disabled], [rel=noopener]), button:not([disabled]), textarea:not([disabled]), input[type="text"]:not([disabled]), input[type="radio"]:not([disabled]), input[type="checkbox"]:not([disabled]), select:not([disabled])')
|
|
17
|
+
let firstFocusableEl = focusableEls[0]
|
|
18
|
+
let lastFocusableEl = focusableEls[focusableEls.length - 1]
|
|
19
|
+
let KEYCODE_TAB = 9
|
|
20
|
+
|
|
21
|
+
element.addEventListener('keydown', function (event) {
|
|
22
|
+
let { key, keyCode, shiftKey } = event
|
|
23
|
+
|
|
24
|
+
var isTabPressed = key === 'Tab' || keyCode === KEYCODE_TAB
|
|
25
|
+
|
|
26
|
+
if (!isTabPressed) return
|
|
27
|
+
|
|
28
|
+
if (shiftKey) {
|
|
29
|
+
if (document.activeElement === firstFocusableEl) {
|
|
30
|
+
lastFocusableEl.focus()
|
|
31
|
+
event.preventDefault()
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
if (document.activeElement === lastFocusableEl) {
|
|
35
|
+
firstFocusableEl.focus()
|
|
36
|
+
event.preventDefault()
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
}
|
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Logs
|
|
3
|
-
* Uses `util.inspect` to avoid truncation of complex or deeply nested structures.
|
|
2
|
+
* Logs a value to the console as pretty-printed JSON.
|
|
4
3
|
*
|
|
5
|
-
* @param {*} target - The value to
|
|
4
|
+
* @param {*} target - The value to log.
|
|
6
5
|
* @returns {void}
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* logObject({ complicated: 'object', with: { child: 'values' } })
|
|
10
6
|
*/
|
|
11
7
|
|
|
12
|
-
import util from 'util'
|
|
13
|
-
|
|
14
8
|
export default function (target) {
|
|
15
|
-
|
|
16
|
-
console.log(util.inspect(target, options))
|
|
9
|
+
return console.log(JSON.stringify(target, null, 2))
|
|
17
10
|
}
|
package/scripts/helpers.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import compareArrays from '#helpers/compareArrays'
|
|
2
|
+
import constrainTabbing from '#helpers/constrainTabbing'
|
|
2
3
|
import formatKebabCase from '#helpers/formatKebabCase'
|
|
3
4
|
import logObject from '#helpers/logObject'
|
|
4
5
|
|
|
5
|
-
export { compareArrays, formatKebabCase, logObject }
|
|
6
|
+
export { compareArrays, constrainTabbing, formatKebabCase, logObject }
|
package/scss/_atomic.scss
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
@use "atomic/min-widths";
|
|
10
10
|
@use "atomic/paddings";
|
|
11
11
|
@use "atomic/text-aligns";
|
|
12
|
+
@use "atomic/widths";
|
|
12
13
|
|
|
13
14
|
.border-radius-lg {
|
|
14
15
|
border-radius: var(--border-radius-lg);
|
|
@@ -48,4 +49,8 @@
|
|
|
48
49
|
|
|
49
50
|
.display-inline-block {
|
|
50
51
|
display: inline-block;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.word-wrap-break-word {
|
|
55
|
+
word-wrap: break-word;
|
|
51
56
|
}
|
|
@@ -23,14 +23,14 @@ fieldset,
|
|
|
23
23
|
|
|
24
24
|
@include small-up {
|
|
25
25
|
.fieldset.table {
|
|
26
|
-
grid-template-columns: auto calc(var(--width-column) * 2);
|
|
27
26
|
margin-top: var(--margin-sm);
|
|
28
27
|
border-radius: 0;
|
|
29
|
-
display:
|
|
28
|
+
display: flex;
|
|
30
29
|
padding: 0;
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
.fieldset .wrap-legend {
|
|
33
|
+
width: stretch;
|
|
34
34
|
margin-top: 0;
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
@use "mixins/breakpoints" as *;
|
|
2
|
+
@use "mixins/br-wrap" as *;
|
|
3
|
+
|
|
4
|
+
@include medium-up {
|
|
5
|
+
.br-table-cell:not(.activeReturn) {
|
|
6
|
+
padding: var(--padding-md);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.br-table-cell:not(.width-stretch) {
|
|
10
|
+
flex-shrink: 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.br-table-cell:not(:first-child) {
|
|
14
|
+
border-left-color: var(--color-black-25-lighten);
|
|
15
|
+
border-left-width: var(--border-width-sm);
|
|
16
|
+
border-left-style: solid;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.br-table-cell.align-right {
|
|
20
|
+
text-align: right;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.br-table-cell.align-center {
|
|
24
|
+
text-align: center;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.br-table-cell label {
|
|
28
|
+
display: none;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.br-table-cell.cluster {
|
|
32
|
+
@include br-wrap--cluster;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.br-table-cell.cluster>* {
|
|
36
|
+
vertical-align: middle;
|
|
37
|
+
display: inline-block;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@include medium-down {
|
|
42
|
+
.br-table-cell:not(.activeReturn) {
|
|
43
|
+
@include br-wrap--cluster;
|
|
44
|
+
|
|
45
|
+
& {
|
|
46
|
+
width: initial;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.br-table-cell:not(.activeReturn):not(:last-child) {
|
|
51
|
+
margin-bottom: var(--margin-sm);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.br-table-cell:not(.activeReturn)>* {
|
|
55
|
+
vertical-align: middle;
|
|
56
|
+
display: inline-block;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -3,58 +3,12 @@
|
|
|
3
3
|
.br-table-header {
|
|
4
4
|
border-color: var(--color-black-25-lighten);
|
|
5
5
|
border-width: var(--border-width-sm);
|
|
6
|
-
margin-bottom: var(--margin-
|
|
6
|
+
margin-bottom: var(--margin-md);
|
|
7
7
|
border-style: solid;
|
|
8
8
|
display: none;
|
|
9
9
|
|
|
10
|
-
@include
|
|
10
|
+
@include medium-up {
|
|
11
11
|
background-color: var(--color-black-5-lighten);
|
|
12
|
-
|
|
13
|
-
display: grid;
|
|
12
|
+
display: flex;
|
|
14
13
|
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.br-table-header-title {
|
|
18
|
-
padding: var(--padding-md);
|
|
19
|
-
font-weight: bold;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.br-table-header-title+.br-table-header-title {
|
|
23
|
-
border-left-color: var(--color-black-25-lighten);
|
|
24
|
-
border-left-width: var(--border-width-sm);
|
|
25
|
-
border-left-style: solid;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
.br-table-header-title.yes,
|
|
29
|
-
.br-table-header-title.no {
|
|
30
|
-
text-align: center;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.br-table-rows {
|
|
34
|
-
list-style: none;
|
|
35
|
-
padding: 0;
|
|
36
|
-
margin: 0;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.br-table-row {
|
|
40
|
-
border-color: var(--color-black-25-lighten);
|
|
41
|
-
border-width: var(--border-width-sm);
|
|
42
|
-
border-style: solid;
|
|
43
|
-
|
|
44
|
-
@include small-up {
|
|
45
|
-
grid-template-columns: auto repeat(2, 5rem);
|
|
46
|
-
display: grid;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.br-table-row div {
|
|
51
|
-
border-color: var(--color-black-25-lighten);
|
|
52
|
-
border-width: var(--border-width-sm);
|
|
53
|
-
padding: var(--padding-md);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.br-table-row div+div {
|
|
57
|
-
border-left-color: var(--color-black-25-lighten);
|
|
58
|
-
border-left-width: var(--border-width-sm);
|
|
59
|
-
border-left-style: solid;
|
|
60
14
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
@use "mixins/breakpoints" as *;
|
|
2
|
+
|
|
3
|
+
.br-table-row {
|
|
4
|
+
border-color: var(--color-black-25-lighten);
|
|
5
|
+
border-width: var(--border-width-sm);
|
|
6
|
+
border-style: solid;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.br-table-row:not(:last-child) {
|
|
10
|
+
margin-bottom: var(--margin-md);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@include medium-up {
|
|
14
|
+
.br-table-row {
|
|
15
|
+
display: flex;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@include medium-down {
|
|
20
|
+
.br-table-row {
|
|
21
|
+
border-radius: var(--border-radius-lg);
|
|
22
|
+
padding: var(--padding-md);
|
|
23
|
+
}
|
|
24
|
+
}
|
package/scss/_variables.scss
CHANGED
|
@@ -432,8 +432,8 @@
|
|
|
432
432
|
--width-icon: 10rem;
|
|
433
433
|
// Title column width (`320px`).
|
|
434
434
|
--width-title: 20rem;
|
|
435
|
-
// Extra-small layout max-width (`
|
|
436
|
-
--width-layout-xs:
|
|
435
|
+
// Extra-small layout max-width (`400px`).
|
|
436
|
+
--width-layout-xs: 25rem;
|
|
437
437
|
// Small layout max-width (`800px`).
|
|
438
438
|
--width-layout-sm: 50rem;
|
|
439
439
|
// Medium layout max-width (`960px`).
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@use "../mixins/font-size" as *;
|
|
2
|
+
|
|
1
3
|
$iterations: (
|
|
2
4
|
"lg": var(--font-size-lg),
|
|
3
5
|
"h1": var(--font-size-h1),
|
|
@@ -12,4 +14,8 @@ $iterations: (
|
|
|
12
14
|
.font-size-#{$name} {
|
|
13
15
|
font-size: #{$value};
|
|
14
16
|
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.font-size-subtitle {
|
|
20
|
+
@include font-size-subtitle;
|
|
15
21
|
}
|
|
@@ -20,4 +20,16 @@ $iterations: (
|
|
|
20
20
|
#{$margin}: #{$value}rem;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@each $name, $value in $iterations {
|
|
26
|
+
.margin-top-bottom-#{$name} {
|
|
27
|
+
margin-bottom: #{$value}rem;
|
|
28
|
+
margin-top: #{$value}rem;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.margin-left-right-#{$name} {
|
|
32
|
+
margin-right: #{$value}rem;
|
|
33
|
+
margin-left: #{$value}rem;
|
|
34
|
+
}
|
|
23
35
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
$iterations: (
|
|
2
|
+
"0": 0,
|
|
3
|
+
"0-5": 0.5,
|
|
4
|
+
"1": 1,
|
|
5
|
+
"1-5": 1.5,
|
|
6
|
+
"2": 2,
|
|
7
|
+
"2-5": 2.5,
|
|
8
|
+
"3": 3,
|
|
9
|
+
"3-5": 3.5,
|
|
10
|
+
"4": 4,
|
|
11
|
+
"4-5": 4.5,
|
|
12
|
+
"5": 5,
|
|
13
|
+
"5-5": 5.5,
|
|
14
|
+
"6": 6,
|
|
15
|
+
"6-5": 6.5,
|
|
16
|
+
"7": 7,
|
|
17
|
+
"7-5": 7.5,
|
|
18
|
+
"8": 8,
|
|
19
|
+
"8-5": 8.5,
|
|
20
|
+
"9": 9,
|
|
21
|
+
"9-5": 9.5,
|
|
22
|
+
"10": 10,
|
|
23
|
+
"10-5": 10.5,
|
|
24
|
+
"11": 11,
|
|
25
|
+
"11-5": 11.5,
|
|
26
|
+
"12": 12,
|
|
27
|
+
"12-5": 12.5,
|
|
28
|
+
"13": 13,
|
|
29
|
+
"13-5": 13.5,
|
|
30
|
+
"14": 14,
|
|
31
|
+
"14-5": 14.5,
|
|
32
|
+
"15": 15,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
@each $name, $value in $iterations {
|
|
36
|
+
.width-#{$name} {
|
|
37
|
+
width: #{$value}rem;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.width-stretch {
|
|
42
|
+
width: stretch;
|
|
43
|
+
}
|
package/scss/index.scss
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
@use "../mixins/breakpoints" as *;
|
|
2
|
+
@use "../mixins/font-size" as *;
|
|
2
3
|
@use "card/default" as *;
|
|
3
4
|
@use "card/inline" as *;
|
|
4
5
|
@use "card/membership" as *;
|
|
@@ -62,11 +63,7 @@
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
@mixin br-card-subtitle {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
@include medium-up {
|
|
68
|
-
font-size: var(--font-size-h4);
|
|
69
|
-
}
|
|
66
|
+
@include font-size-subtitle;
|
|
70
67
|
}
|
|
71
68
|
|
|
72
69
|
@mixin br-card--body {
|
|
@@ -114,6 +111,6 @@
|
|
|
114
111
|
|
|
115
112
|
@mixin br-card-text {
|
|
116
113
|
+.br-card-text {
|
|
117
|
-
margin-top: var(--margin-
|
|
114
|
+
margin-top: var(--margin-sm);
|
|
118
115
|
}
|
|
119
116
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
@use "../../../mixins/buttons/outline" as *;
|
|
2
|
+
@use "../../../mixins/buttons/slim" as *;
|
|
2
3
|
|
|
3
4
|
$iterations: (
|
|
4
5
|
"member": var(--color-brand-membership),
|
|
@@ -12,6 +13,7 @@ $iterations: (
|
|
|
12
13
|
|
|
13
14
|
@mixin btn-renew-membership {
|
|
14
15
|
@include outline-button($color: white, $background: transparent);
|
|
16
|
+
@include btn-slim;
|
|
15
17
|
|
|
16
18
|
&:focus,
|
|
17
19
|
&:hover {
|
package/scss/mixins/index.scss
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@use "../../mixins/breakpoints" as *;
|
|
2
|
+
|
|
1
3
|
@mixin br-form-checkbox--input-colors {
|
|
2
4
|
&:not(.error):not(.success) {
|
|
3
5
|
outline-color: var(--color-status-neutral);
|
|
@@ -79,6 +81,17 @@
|
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
83
|
|
|
84
|
+
&.table {
|
|
85
|
+
border-bottom-right-radius: 0;
|
|
86
|
+
border-bottom-left-radius: 0;
|
|
87
|
+
border-width: 0;
|
|
88
|
+
|
|
89
|
+
@include medium-up {
|
|
90
|
+
border-top-right-radius: 0;
|
|
91
|
+
border-top-left-radius: 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
82
95
|
&:not(.disabled) {
|
|
83
96
|
cursor: pointer;
|
|
84
97
|
|
package/animations/confirm.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import gsap from 'gsap'
|
|
2
|
-
|
|
3
|
-
/** @type {gsap.TweenVars} Fade-in vars: animates element from transparent with a short delay */
|
|
4
|
-
const fadeIn = {
|
|
5
|
-
duration: 0.3,
|
|
6
|
-
opacity: 0,
|
|
7
|
-
delay: 0.3,
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/** @type {gsap.TweenVars} Explode vars: scales element up and fades it out */
|
|
11
|
-
const explode = {
|
|
12
|
-
ease: 'power1.out',
|
|
13
|
-
opacity: 0,
|
|
14
|
-
scale: 1.5,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** @type {gsap.TimelineVars} Default timeline settings shared across all confirm animations */
|
|
18
|
-
const defaults = {
|
|
19
|
-
duration: 0.6,
|
|
20
|
-
ease: 'power1.in',
|
|
21
|
-
transformOrigin: 'center',
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Animates the email confirmation card.
|
|
26
|
-
* Fades in the title, draws the envelope outline and fold SVG paths,
|
|
27
|
-
* explodes a cloned title, then slides in the arrow.
|
|
28
|
-
*/
|
|
29
|
-
export const animateEmail = () => {
|
|
30
|
-
const query = (target) => document.querySelector(`.card[email] ${target}`)
|
|
31
|
-
const title = query('.card-title')
|
|
32
|
-
const outline = query('.outline')
|
|
33
|
-
const arrow = query('.arrow')
|
|
34
|
-
const fold = query('.fold')
|
|
35
|
-
const tl = gsap.timeline({ defaults })
|
|
36
|
-
|
|
37
|
-
const clone = title.cloneNode(true)
|
|
38
|
-
clone.classList.add('clone')
|
|
39
|
-
title.after(clone)
|
|
40
|
-
|
|
41
|
-
tl.set(arrow, { opacity: 0 }).from(title, fadeIn).set(clone, { opacity: 0.4 }).from(outline, { drawSVG: '0%' }, 'start').from(fold, { drawSVG: '0%', duration: 0.3 }, 'start').to(clone, explode, 'start').set(arrow, { opacity: 1 }).from(arrow, { x: -6, ease: 'power1.out' })
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Animates the done confirmation card.
|
|
46
|
-
* Fades in the title, draws the circle outline and tick SVG paths,
|
|
47
|
-
* and explodes a cloned title.
|
|
48
|
-
*/
|
|
49
|
-
export const animateDone = () => {
|
|
50
|
-
const query = (target) => document.querySelector(`.card[done] ${target}`)
|
|
51
|
-
const title = query('.card-title')
|
|
52
|
-
const outline = query('.outline')
|
|
53
|
-
const tick = query('.tick')
|
|
54
|
-
const tl = gsap.timeline({ defaults })
|
|
55
|
-
|
|
56
|
-
const clone = title.cloneNode(true)
|
|
57
|
-
clone.classList.add('clone')
|
|
58
|
-
title.after(clone)
|
|
59
|
-
|
|
60
|
-
tl.from(title, fadeIn).set(clone, { opacity: 0.4 }).from(outline, { drawSVG: '0%' }, 'start').from(tick, { drawSVG: '0%', duration: 0.3 }, 'start+=0.3').to(clone, explode, 'start')
|
|
61
|
-
}
|