@bonniernews/dn-design-system-web 9.0.0 → 9.1.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/CHANGELOG.md +19 -0
- package/components/modal/README.md +52 -0
- package/components/modal/modal.js +59 -0
- package/components/modal/modal.njk +66 -0
- package/components/modal/modal.scss +115 -0
- package/foundations/colors.scss +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,25 @@ All changes to @bonniernews/dn-design-system-web will be documented in this file
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
## [9.1.0](https://github.com/BonnierNews/dn-design-system/compare/@bonniernews/dn-design-system-web@9.0.0...@bonniernews/dn-design-system-web@9.1.0) (2024-01-04)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **web:** modal component ([#1150](https://github.com/BonnierNews/dn-design-system/issues/1150)) ([a0a70ec](https://github.com/BonnierNews/dn-design-system/commit/a0a70ec4d431b6b38738a70468e60ed9cc9e93ef))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* **app:** pressable remove hitslop ([#1146](https://github.com/BonnierNews/dn-design-system/issues/1146)) ([4f59509](https://github.com/BonnierNews/dn-design-system/commit/4f59509cc3c29bd1f66c7d064b0fb5e25451b07c))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Maintenance
|
|
21
|
+
|
|
22
|
+
* **foundations:** update tokens from Figma ([#1142](https://github.com/BonnierNews/dn-design-system/issues/1142)) ([66cc18e](https://github.com/BonnierNews/dn-design-system/commit/66cc18e2bd91337d5ffd8b38e76f9230ba5d3610))
|
|
23
|
+
* prerelease packages ([d6f9f31](https://github.com/BonnierNews/dn-design-system/commit/d6f9f31c313028d1e3b192a8b4b2dd59732ef192))
|
|
24
|
+
* prerelease packages ([49b5357](https://github.com/BonnierNews/dn-design-system/commit/49b53574003a03a233b63f467a69d9ea55d9b852))
|
|
25
|
+
|
|
7
26
|
## [9.0.0](https://github.com/BonnierNews/dn-design-system/compare/@bonniernews/dn-design-system-web@8.9.8...@bonniernews/dn-design-system-web@9.0.0) (2023-12-08)
|
|
8
27
|
|
|
9
28
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
- GitHub: [BonnierNews/dn-design-system/../web/src/components/modal](https://github.com/BonnierNews/dn-design-system/tree/main/web/src/components/modal)
|
|
2
|
+
- Storybook: [Modal](https://designsystem.dn.se/?path=/docs/basic-modal--docs)
|
|
3
|
+
- Storybook (Latest): [Modal](https://designsystem-latest.dn.se/?path=/docs/basic-modal--docs)
|
|
4
|
+
|
|
5
|
+
----
|
|
6
|
+
|
|
7
|
+
# Modal
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## Parameters
|
|
11
|
+
|
|
12
|
+
|parameter | type | required | options | default | description |
|
|
13
|
+
|:--- | :--- | :--- | :--- | :--- | :--- |
|
|
14
|
+
| title | String | yes | | | Title in modal |
|
|
15
|
+
| bodyText | String | yes | text | | Text in modal |
|
|
16
|
+
| primaryButton | Object | no | text | | Object with text, href (optional), classNames (optional) and attributes (optional) |
|
|
17
|
+
| secondaryButton | Object | no | text | | Object with text, href (optional), classNames (optional) and attributes (optional). Set isCloseButton to true if you wanna close modal with this button |
|
|
18
|
+
| classNames | String | no | | | Ex. "my-special-class" |
|
|
19
|
+
| attributes | Object | no | | | Ex. { data-prop: value } |
|
|
20
|
+
| forcePx | bool | no | true, false | false | Fixed pixel value is used for typography to prevent scaling based on html font-size
|
|
21
|
+
|
|
22
|
+
## Minimum requirement example
|
|
23
|
+
|
|
24
|
+
These are copy paste friendly examples to quickliy get started using a component.
|
|
25
|
+
|
|
26
|
+
### Nunjucks
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
{% from '@bonniernews/dn-design-system-web/components/modal/modal.njk' import Modal %}
|
|
30
|
+
|
|
31
|
+
{{ Modal({
|
|
32
|
+
title: "Rubrik",
|
|
33
|
+
bodyText: "Text i modalen",
|
|
34
|
+
primaryButton: "Text i knapp",
|
|
35
|
+
secondaryButton: "Text i knapp",
|
|
36
|
+
})}}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Scss
|
|
40
|
+
|
|
41
|
+
```scss
|
|
42
|
+
@use "@bonniernews/dn-design-system-web/components/modal/modal";
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Javascript
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
import { initModal, openModal } from '@bonniernews/dn-design-system-web/components/modal/modal.js'
|
|
49
|
+
const modalEl = document.querySelector(".ds-modal");
|
|
50
|
+
initModal(modalEl);
|
|
51
|
+
openModal(modalEl);
|
|
52
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export {
|
|
2
|
+
initModal,
|
|
3
|
+
openModal,
|
|
4
|
+
initModalStorybook
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function initModal(modalEl) {
|
|
8
|
+
const isDialogSupported = typeof HTMLDialogElement === "function";
|
|
9
|
+
let modalWrapper = modalEl.querySelector(".ds-modal__inner");
|
|
10
|
+
if (!isDialogSupported) {
|
|
11
|
+
modalWrapper = modalEl;
|
|
12
|
+
const modalElInner = document.querySelector(".ds-modal__inner");
|
|
13
|
+
const modalAttributes = Array.from(modalElInner.attributes);
|
|
14
|
+
const fallbackDiv = document.createElement("div");
|
|
15
|
+
modalEl.classList.add("ds-modal--hidden", "ds-modal--fallback");
|
|
16
|
+
modalAttributes.forEach((attr) => {
|
|
17
|
+
fallbackDiv.setAttribute(attr.name, attr.value);
|
|
18
|
+
});
|
|
19
|
+
fallbackDiv.setAttribute("role", "dialog");
|
|
20
|
+
fallbackDiv.setAttribute("aria-modal", "true");
|
|
21
|
+
fallbackDiv.innerHTML = modalElInner.innerHTML;
|
|
22
|
+
modalEl.replaceChild(fallbackDiv, modalElInner);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
modalEl.addEventListener("click", (e) => {
|
|
26
|
+
if (e.target === modalWrapper) closeModal(modalEl, isDialogSupported);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const closeButtons = Array.from(modalEl.getElementsByClassName("ds-modal__close"));
|
|
30
|
+
closeButtons.forEach((button) => {
|
|
31
|
+
button.addEventListener("click", () => {
|
|
32
|
+
closeModal(modalEl, isDialogSupported);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function openModal(modalEl) {
|
|
38
|
+
if (typeof HTMLDialogElement === "function") {
|
|
39
|
+
const modalElInner = modalEl.querySelector(".ds-modal__inner");
|
|
40
|
+
modalElInner.showModal();
|
|
41
|
+
} else {
|
|
42
|
+
modalEl.classList.remove("ds-modal--hidden");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function closeModal(modalEl, isDialogSupported) {
|
|
47
|
+
if (isDialogSupported) {
|
|
48
|
+
const modalElInner = modalEl.querySelector(".ds-modal__inner");
|
|
49
|
+
modalElInner.close();
|
|
50
|
+
} else {
|
|
51
|
+
modalEl.classList.add("ds-modal--hidden");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function initModalStorybook() {
|
|
56
|
+
const modalEl = document.querySelector(".ds-modal");
|
|
57
|
+
initModal(modalEl);
|
|
58
|
+
openModal(modalEl);
|
|
59
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{% from '@bonniernews/dn-design-system-web/components/icon-sprite/icon-sprite.njk' import IconUse %}
|
|
2
|
+
{% from '@bonniernews/dn-design-system-web/components/button/button.njk' import Button %}
|
|
3
|
+
{% from '@bonniernews/dn-design-system-web/components/icon-button/icon-button.njk' import IconButton %}
|
|
4
|
+
{% from '@bonniernews/dn-design-system-web/njk-helpers/attributes.njk' import getAttributes %}
|
|
5
|
+
|
|
6
|
+
{% macro Modal(params) %}
|
|
7
|
+
{% set componentClassName = "ds-modal" %}
|
|
8
|
+
|
|
9
|
+
{%- set classes = [
|
|
10
|
+
componentClassName,
|
|
11
|
+
"ds-force-px" if params.forcePx,
|
|
12
|
+
params.classNames if params.classNames
|
|
13
|
+
] | join(" ") %}
|
|
14
|
+
{% set attributes = getAttributes(params.attributes) %}
|
|
15
|
+
|
|
16
|
+
<div class="{{ classes }}">
|
|
17
|
+
<dialog class="{{ componentClassName + '__inner' }}" {{- attributes | safe }}>
|
|
18
|
+
<div class="{{ componentClassName + '__content' }}">
|
|
19
|
+
{{ IconButton({
|
|
20
|
+
variant: "transparent",
|
|
21
|
+
size: "small",
|
|
22
|
+
iconName: "close",
|
|
23
|
+
classNames: "ds-modal__close"
|
|
24
|
+
})}}
|
|
25
|
+
<h2>{{ params.title }}</h2>
|
|
26
|
+
<p>{{ params.bodyText }}</p>
|
|
27
|
+
|
|
28
|
+
{% if params.primaryButton or params.secondaryButton %}
|
|
29
|
+
<div class="ds-modal__buttons">
|
|
30
|
+
{% if params.secondaryButton %}
|
|
31
|
+
{%- set secondaryButtonClasses = [
|
|
32
|
+
"ds-modal__close" if params.secondaryButton.isCloseButton,
|
|
33
|
+
params.secondaryButton.classNames if params.secondaryButton.classNames
|
|
34
|
+
] | join(" ") %}
|
|
35
|
+
{{ Button({
|
|
36
|
+
text: params.secondaryButton.text,
|
|
37
|
+
variant: "secondaryOutlined",
|
|
38
|
+
href: params.secondaryButton.href,
|
|
39
|
+
classNames: secondaryButtonClasses,
|
|
40
|
+
attributes: params.secondaryButton.attributes,
|
|
41
|
+
forcePx: params.forcePx,
|
|
42
|
+
mobile: {
|
|
43
|
+
fullWidth: true
|
|
44
|
+
}
|
|
45
|
+
})}}
|
|
46
|
+
{% endif %}
|
|
47
|
+
|
|
48
|
+
{% if params.primaryButton %}
|
|
49
|
+
{{ Button({
|
|
50
|
+
text: params.primaryButton.text,
|
|
51
|
+
variant: "primary",
|
|
52
|
+
href: params.primaryButton.href,
|
|
53
|
+
classNames: params.primaryButton.classNames,
|
|
54
|
+
attributes: params.primaryButton.attributes,
|
|
55
|
+
forcePx: params.forcePx,
|
|
56
|
+
mobile: {
|
|
57
|
+
fullWidth: true
|
|
58
|
+
}
|
|
59
|
+
})}}
|
|
60
|
+
{% endif %}
|
|
61
|
+
</div>
|
|
62
|
+
{% endif %}
|
|
63
|
+
</div>
|
|
64
|
+
</dialog>
|
|
65
|
+
</div>
|
|
66
|
+
{% endmacro %}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
@use "../../foundations/helpers/forward.helpers.scss" as *;
|
|
2
|
+
@use "../../components/icon-sprite/icon-sprite.scss";
|
|
3
|
+
@use "../../components/button/button.scss";
|
|
4
|
+
@use "../../components/icon-button/icon-button.scss";
|
|
5
|
+
|
|
6
|
+
.ds-modal {
|
|
7
|
+
&--fallback.ds-modal--hidden {
|
|
8
|
+
display: none;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
&--fallback {
|
|
12
|
+
display: flex;
|
|
13
|
+
position: fixed;
|
|
14
|
+
top: 0;
|
|
15
|
+
bottom: 0;
|
|
16
|
+
right: 0;
|
|
17
|
+
left: 0;
|
|
18
|
+
z-index: 999;
|
|
19
|
+
background-color: $ds-color-surface-overlay;
|
|
20
|
+
|
|
21
|
+
@include ds-mq-only-breakpoint(mobile) {
|
|
22
|
+
align-items: flex-end;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@include ds-mq-smallest-breakpoint(tablet) {
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: center;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.ds-modal__inner {
|
|
31
|
+
position: relative;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.ds-modal__content {
|
|
35
|
+
@include ds-mq-only-breakpoint(mobile) {
|
|
36
|
+
border-radius: 16px 16px 0 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@include ds-mq-smallest-breakpoint(tablet) {
|
|
40
|
+
border-radius: ds-border-radius(x1);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.ds-modal__inner {
|
|
46
|
+
max-width: 700px;
|
|
47
|
+
border: none;
|
|
48
|
+
padding: 0;
|
|
49
|
+
|
|
50
|
+
@include ds-mq-only-breakpoint(mobile) {
|
|
51
|
+
margin-bottom: 0;
|
|
52
|
+
border-radius: 16px 16px 0 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@include ds-mq-smallest-breakpoint(tablet) {
|
|
56
|
+
border-radius: ds-border-radius(x1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
&::backdrop {
|
|
60
|
+
background-color: $ds-color-surface-overlay;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.ds-modal__content {
|
|
65
|
+
padding: ds-spacing($ds-s-400 $ds-s-300 $ds-s-300);
|
|
66
|
+
background-color: $ds-color-surface-background;
|
|
67
|
+
|
|
68
|
+
.ds-icon-btn.ds-modal__close {
|
|
69
|
+
position: absolute;
|
|
70
|
+
top: ds-spacing($ds-s-100);
|
|
71
|
+
right: ds-spacing($ds-s-100);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
> h2 {
|
|
75
|
+
@include ds-typography($ds-typography-functional-heading03bold);
|
|
76
|
+
margin: ds-spacing(0 0 $ds-s-200);
|
|
77
|
+
color: $ds-color-text-primary;
|
|
78
|
+
text-align: center;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
> p {
|
|
82
|
+
@include ds-typography($ds-typography-functional-body02regular);
|
|
83
|
+
margin: 0;
|
|
84
|
+
text-align: center;
|
|
85
|
+
color: $ds-color-text-primary;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
> .ds-modal__buttons {
|
|
89
|
+
margin: ds-spacing($ds-s-200 0 0);
|
|
90
|
+
|
|
91
|
+
@include ds-mq-only-breakpoint(mobile) {
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-wrap: wrap;
|
|
94
|
+
|
|
95
|
+
.ds-btn--primary:not(:only-child) {
|
|
96
|
+
order: 1;
|
|
97
|
+
margin-bottom: ds-spacing($ds-s-100);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.ds-btn--secondaryOutlined:not(:only-child) {
|
|
101
|
+
order: 2;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@include ds-mq-smallest-breakpoint(tablet) {
|
|
106
|
+
display: flex;
|
|
107
|
+
justify-content: center;
|
|
108
|
+
|
|
109
|
+
.ds-btn--secondaryOutlined:not(:only-child) {
|
|
110
|
+
margin-right: ds-spacing($ds-s-100);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
package/foundations/colors.scss
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
@use "./helpers/colors.scss" as *;
|
|
6
6
|
|
|
7
7
|
html,
|
|
8
|
+
::backdrop, //backdrop can't handle variables in html element. It needs to be defined here
|
|
8
9
|
.ds-light {
|
|
9
10
|
@each $name, $value in meta.module-variables("colorsDnLightTokens") {
|
|
10
11
|
--ds-color-#{string.slice($name, 8)}: #{$value};
|
package/package.json
CHANGED