@dnanpm/styleguide 3.12.1 → 3.12.3
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/build/cjs/assets/fonts/fonts.css.js +3 -0
- package/build/cjs/components/Breadcrumb/Breadcrumb.d.ts +42 -0
- package/build/cjs/components/Breadcrumb/Breadcrumb.js +90 -0
- package/build/cjs/components/ButtonCard/ButtonCard.js +3 -5
- package/build/cjs/components/Carousel/Carousel.d.ts +11 -14
- package/build/cjs/components/Carousel/Carousel.js +52 -40
- package/build/cjs/components/Hero/Hero.d.ts +0 -6
- package/build/cjs/components/Hero/Hero.js +3 -3
- package/build/cjs/components/index.d.ts +1 -0
- package/build/cjs/index.js +2 -0
- package/build/cjs/themes/globalStyles.js +1 -0
- package/build/cjs/themes/theme.d.ts +9 -2
- package/build/cjs/themes/themeComponents/breakpoints.d.ts +9 -4
- package/build/cjs/utils/styledUtils.d.ts +22 -1
- package/build/cjs/utils/styledUtils.js +26 -6
- package/build/es/assets/fonts/fonts.css.js +1 -0
- package/build/es/components/Breadcrumb/Breadcrumb.d.ts +42 -0
- package/build/es/components/Breadcrumb/Breadcrumb.js +82 -0
- package/build/es/components/ButtonCard/ButtonCard.js +3 -5
- package/build/es/components/Carousel/Carousel.d.ts +11 -14
- package/build/es/components/Carousel/Carousel.js +52 -40
- package/build/es/components/Hero/Hero.d.ts +0 -6
- package/build/es/components/Hero/Hero.js +3 -3
- package/build/es/components/index.d.ts +1 -0
- package/build/es/index.js +1 -0
- package/build/es/themes/globalStyles.js +1 -0
- package/build/es/themes/theme.d.ts +9 -2
- package/build/es/themes/themeComponents/breakpoints.d.ts +9 -4
- package/build/es/utils/styledUtils.d.ts +22 -1
- package/build/es/utils/styledUtils.js +26 -6
- package/package.json +12 -8
- package/build/cjs/build/assets/fonts/fonts.css +0 -129
- package/build/es/build/assets/fonts/fonts.css +0 -129
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
if(typeof document!=="undefined")document.head.appendChild(document.createElement("style")).textContent="@font-face{font-family:'DNA Text';font-style: normal;font-weight: 400;font-display: swap;src: url('https://www.dna.fi/fonts/DNAText-Regular.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAText-Regular.woff') format('woff');}@font-face{font-family:'DNA Text';font-style: normal;font-weight: 500;font-display: swap;src: url('https://www.dna.fi/fonts/DNAText-Medium.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAText-Medium.woff') format('woff');}@font-face{font-family:'DNA Text';font-style: normal;font-weight: 700;font-display: swap;src: url('https://www.dna.fi/fonts/DNAText-Bold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAText-Bold.woff') format('woff');}@font-face{font-family:'DNA Heading';font-style: normal;font-weight: 600;font-display: swap;src: url('https://www.dna.fi/fonts/DNAHeading-DemiBold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAHeading-DemiBold.woff') format('woff');}@font-face{font-family:'DNA Heading';font-style: normal;font-weight: 700;font-display: swap;src: url('https://www.dna.fi/fonts/DNAHeading-Bold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAHeading-Bold.woff') format('woff');}@font-face{font-family:'DNA Heading';font-style: normal;font-weight: 900;font-display: swap;src: url('https://www.dna.fi/fonts/DNAHeading-Black.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAHeading-Black.woff') format('woff');}@font-face{font-family:'DNA Numerals';font-style: normal;font-weight: 700;font-display: swap;src: url('https://www.dna.fi/fonts/DNANumerals-Bold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNANumerals-Bold.woff') format('woff');}@font-face{font-family:'DNA Text Regular';font-style: normal;font-weight: 400;font-display: swap;src: url('https://www.dna.fi/fonts/DNAText-Regular.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAText-Regular.woff') format('woff');}@font-face{font-family:'DNA Text Medium';font-style: normal;font-weight: 500;font-display: swap;src: url('https://www.dna.fi/fonts/DNAText-Medium.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAText-Medium.woff') format('woff');}@font-face{font-family:'DNA Text Bold';font-style: normal;font-weight: 700;font-display: swap;src: url('https://www.dna.fi/fonts/DNAText-Bold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAText-Bold.woff') format('woff');}@font-face{font-family:'DNA Heading Demi Bold';font-style: normal;font-weight: 600;font-display: swap;src: url('https://www.dna.fi/fonts/DNAHeading-DemiBold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAHeading-DemiBold.woff') format('woff');}@font-face{font-family:'DNA Heading Bold';font-style: normal;font-weight: 700;font-display: swap;src: url('https://www.dna.fi/fonts/DNAHeading-Bold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAHeading-Bold.woff') format('woff');}@font-face{font-family:'DNA Heading Black';font-style: normal;font-weight: 900;font-display: swap;src: url('https://www.dna.fi/fonts/DNAHeading-Black.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAHeading-Black.woff') format('woff');}@font-face{font-family:'DNA Numerals Bold';font-style: normal;font-weight: 700;font-display: swap;src: url('https://www.dna.fi/fonts/DNANumerals-Bold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNANumerals-Bold.woff') format('woff');}";
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ComponentType } from 'react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export interface BreadcrumbItem {
|
|
4
|
+
/**
|
|
5
|
+
* Display text for the breadcrumb item
|
|
6
|
+
*/
|
|
7
|
+
label: string;
|
|
8
|
+
/**
|
|
9
|
+
* URL/path for the breadcrumb item. If not provided, item will be rendered as text only
|
|
10
|
+
*/
|
|
11
|
+
href?: string;
|
|
12
|
+
}
|
|
13
|
+
interface Props {
|
|
14
|
+
/**
|
|
15
|
+
* Array of breadcrumb items to display
|
|
16
|
+
*/
|
|
17
|
+
items?: BreadcrumbItem[];
|
|
18
|
+
/**
|
|
19
|
+
* Custom link component to use instead of default anchor element
|
|
20
|
+
* Useful for router integration (e.g., Next.js Link, React Router Link)
|
|
21
|
+
*/
|
|
22
|
+
linkComponent?: ComponentType<any>;
|
|
23
|
+
/**
|
|
24
|
+
* Props to pass to the link component
|
|
25
|
+
*/
|
|
26
|
+
linkProps?: Record<string, unknown>;
|
|
27
|
+
/**
|
|
28
|
+
* Screen reader label describing the breadcrumb navigation
|
|
29
|
+
*/
|
|
30
|
+
ariaLabel?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Allows to pass testid string for testing purposes
|
|
33
|
+
*/
|
|
34
|
+
'data-testid'?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Allows to pass a custom className
|
|
37
|
+
*/
|
|
38
|
+
className?: string;
|
|
39
|
+
}
|
|
40
|
+
declare const Breadcrumb: ({ "data-testid": dataTestId, ariaLabel, className, items, linkComponent: LinkComponent, linkProps, }: Props) => React.JSX.Element | null;
|
|
41
|
+
/** @component */
|
|
42
|
+
export default Breadcrumb;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var React = require('react');
|
|
6
|
+
var icons = require('@dnanpm/icons');
|
|
7
|
+
var styledComponents = require('styled-components');
|
|
8
|
+
var theme = require('../../themes/theme.js');
|
|
9
|
+
var styledUtils = require('../../utils/styledUtils.js');
|
|
10
|
+
|
|
11
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
12
|
+
|
|
13
|
+
var React__default = /*#__PURE__*/_interopDefaultCompat(React);
|
|
14
|
+
|
|
15
|
+
const BreadcrumbNav = styledComponents.styled.nav `
|
|
16
|
+
font-size: ${theme.default.fontSize.s};
|
|
17
|
+
font-weight: ${theme.default.fontWeight.medium};
|
|
18
|
+
`;
|
|
19
|
+
const BreadcrumbList = styledComponents.styled.ol `
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
flex-wrap: nowrap;
|
|
23
|
+
list-style: none;
|
|
24
|
+
margin: ${styledUtils.getMultipliedSize(theme.default.base.baseHeight, 2)} 0;
|
|
25
|
+
padding: 0;
|
|
26
|
+
gap: ${styledUtils.getMultipliedSize(theme.default.base.baseHeight, 0.5)};
|
|
27
|
+
overflow: visible;
|
|
28
|
+
container: breadcrumb / inline-size;
|
|
29
|
+
|
|
30
|
+
/* Responsive behavior: show only last 2 items when container < 600px */
|
|
31
|
+
@container (max-width: 599px) {
|
|
32
|
+
li:not(:nth-last-child(-n + 2)) {
|
|
33
|
+
display: none;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
37
|
+
const BreadcrumbListItem = styledComponents.styled.li `
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
gap: ${styledUtils.getMultipliedSize(theme.default.base.baseHeight, 0.5)};
|
|
41
|
+
|
|
42
|
+
&:last-child {
|
|
43
|
+
min-width: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
a {
|
|
47
|
+
&:focus-visible {
|
|
48
|
+
outline: none;
|
|
49
|
+
border-radius: ${theme.default.radius.s};
|
|
50
|
+
box-shadow:
|
|
51
|
+
0px 0px 0px 2px ${theme.default.color.focus.light},
|
|
52
|
+
0px 0px 0px 4px ${theme.default.color.focus.dark};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
span {
|
|
57
|
+
flex: 1 1 0%;
|
|
58
|
+
white-space: nowrap;
|
|
59
|
+
overflow: hidden;
|
|
60
|
+
text-overflow: ellipsis;
|
|
61
|
+
}
|
|
62
|
+
`;
|
|
63
|
+
const Breadcrumb = ({ 'data-testid': dataTestId, ariaLabel, className, items, linkComponent: LinkComponent, linkProps = {}, }) => {
|
|
64
|
+
if (!items || items.length === 0) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const renderItem = (item, index) => {
|
|
68
|
+
const isLastItem = index === items.length - 1;
|
|
69
|
+
if (isLastItem || !item.href) {
|
|
70
|
+
return React__default.default.createElement("span", { "aria-current": isLastItem ? 'page' : undefined }, item.label);
|
|
71
|
+
}
|
|
72
|
+
if (LinkComponent) {
|
|
73
|
+
return (React__default.default.createElement(LinkComponent, Object.assign({ href: item.href, itemProp: "item", itemScope: true, itemType: "https://schema.org/WebPage" }, linkProps),
|
|
74
|
+
React__default.default.createElement("span", { itemProp: "name" }, item.label)));
|
|
75
|
+
}
|
|
76
|
+
return (React__default.default.createElement("a", { href: item.href, itemProp: "item", itemScope: true, itemType: "https://schema.org/WebPage" },
|
|
77
|
+
React__default.default.createElement("span", { itemProp: "name" }, item.label)));
|
|
78
|
+
};
|
|
79
|
+
return (React__default.default.createElement(BreadcrumbNav, { "aria-label": ariaLabel, className: className, "data-testid": dataTestId },
|
|
80
|
+
React__default.default.createElement(BreadcrumbList, { itemScope: true, itemType: "https://schema.org/BreadcrumbList" }, items.map((item, index) => {
|
|
81
|
+
var _a;
|
|
82
|
+
const isLastItem = index === items.length - 1;
|
|
83
|
+
return (React__default.default.createElement(BreadcrumbListItem, { itemProp: "itemListElement", itemScope: true, itemType: "https://schema.org/ListItem", key: `breadcrumb-${item.label}-${(_a = item.href) !== null && _a !== void 0 ? _a : 'nolink'}` },
|
|
84
|
+
renderItem(item, index),
|
|
85
|
+
React__default.default.createElement("meta", { itemProp: "position", content: (index + 1).toString() }),
|
|
86
|
+
!isLastItem && (React__default.default.createElement(icons.ChevronRight, { color: theme.default.color.background.pink.default, size: "0.9rem" }))));
|
|
87
|
+
}))));
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
exports.default = Breadcrumb;
|
|
@@ -17,7 +17,7 @@ var React__default = /*#__PURE__*/_interopDefaultCompat(React);
|
|
|
17
17
|
const ButtonCardWrapper = styledComponents.styled.button `
|
|
18
18
|
display: block;
|
|
19
19
|
padding: 0;
|
|
20
|
-
border: 0
|
|
20
|
+
border: 0;
|
|
21
21
|
width: 100%;
|
|
22
22
|
background-color: transparent;
|
|
23
23
|
cursor: pointer;
|
|
@@ -25,6 +25,7 @@ const ButtonCardWrapper = styledComponents.styled.button `
|
|
|
25
25
|
font-size: ${theme.default.fontSize.default};
|
|
26
26
|
line-height: ${theme.default.lineHeight.default};
|
|
27
27
|
color: ${theme.default.color.text.black};
|
|
28
|
+
text-decoration: none;
|
|
28
29
|
|
|
29
30
|
&:focus-visible {
|
|
30
31
|
border: 1px solid ${theme.default.color.focus.light};
|
|
@@ -33,13 +34,12 @@ const ButtonCardWrapper = styledComponents.styled.button `
|
|
|
33
34
|
outline: none;
|
|
34
35
|
|
|
35
36
|
& > div {
|
|
36
|
-
border: 0
|
|
37
|
+
border: 0;
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
&:hover {
|
|
41
42
|
color: ${theme.default.color.text.black};
|
|
42
|
-
text-decoration: none;
|
|
43
43
|
}
|
|
44
44
|
`;
|
|
45
45
|
const StyledBox = styledComponents.styled(Box.default) `
|
|
@@ -74,7 +74,6 @@ const Title = styledComponents.styled.div `
|
|
|
74
74
|
font-size: ${theme.default.fontSize.default};
|
|
75
75
|
line-height: ${theme.default.lineHeight.default};
|
|
76
76
|
font-weight: ${theme.default.fontWeight.bold};
|
|
77
|
-
|
|
78
77
|
text-overflow: ellipsis;
|
|
79
78
|
overflow: hidden;
|
|
80
79
|
white-space: nowrap;
|
|
@@ -97,7 +96,6 @@ const Subtitle = styledComponents.styled.div `
|
|
|
97
96
|
font-size: ${theme.default.fontSize.s};
|
|
98
97
|
line-height: ${theme.default.lineHeight.s};
|
|
99
98
|
font-weight: ${theme.default.fontWeight.medium};
|
|
100
|
-
|
|
101
99
|
text-overflow: ellipsis;
|
|
102
100
|
overflow: hidden;
|
|
103
101
|
white-space: nowrap;
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import type { MouseEvent, ReactNode } from 'react';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
interface Responsive {
|
|
4
|
-
minItems: number;
|
|
5
|
-
maxItems: number;
|
|
6
|
-
minWidth: number;
|
|
7
|
-
maxWidth: number;
|
|
8
|
-
}
|
|
9
3
|
interface Props {
|
|
10
4
|
/**
|
|
11
5
|
* Unique ID for the component
|
|
@@ -50,10 +44,12 @@ interface Props {
|
|
|
50
44
|
*/
|
|
51
45
|
className?: string;
|
|
52
46
|
/**
|
|
53
|
-
* Allows
|
|
54
|
-
*
|
|
47
|
+
* Allows for responsive behavior in the carousel.
|
|
48
|
+
* Shows as many items as possible; each item requires a defined width.
|
|
49
|
+
* This overrides the `visibleItems` prop.
|
|
50
|
+
* @default false
|
|
55
51
|
*/
|
|
56
|
-
responsive?:
|
|
52
|
+
responsive?: boolean;
|
|
57
53
|
/**
|
|
58
54
|
* Allows to pass a screen reader label for the pagination item next to the current slide number
|
|
59
55
|
*/
|
|
@@ -73,12 +69,13 @@ interface Props {
|
|
|
73
69
|
*/
|
|
74
70
|
swipeStep?: number;
|
|
75
71
|
}
|
|
76
|
-
declare const SlideItem: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>,
|
|
77
|
-
$visibleItems?: Props["visibleItems"];
|
|
78
|
-
}> & {
|
|
79
|
-
$itemWidthCorrection: number;
|
|
72
|
+
declare const SlideItem: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
80
73
|
$isSwiping: boolean;
|
|
81
|
-
|
|
74
|
+
$responsive: boolean;
|
|
75
|
+
$gap: number;
|
|
76
|
+
} & Partial<Required<{
|
|
77
|
+
$visibleItems: Props["visibleItems"];
|
|
78
|
+
}>>>> & string;
|
|
82
79
|
/** @visibleName Carousel */
|
|
83
80
|
declare const Carousel: ({ "data-testid": dataTestId, ...props }: Props) => React.JSX.Element;
|
|
84
81
|
/** @component */
|
|
@@ -41,7 +41,6 @@ const SlidesWrapper = styledComponents.styled.div `
|
|
|
41
41
|
display: flex;
|
|
42
42
|
width: 100%;
|
|
43
43
|
height: 100%;
|
|
44
|
-
gap: ${({ $gap }) => $gap}rem;
|
|
45
44
|
transition-property: transform;
|
|
46
45
|
transform: translate3d(0px, 0, 0);
|
|
47
46
|
transition-duration: 0ms;
|
|
@@ -52,9 +51,14 @@ const SlideItem = styledComponents.styled.div `
|
|
|
52
51
|
display: block;
|
|
53
52
|
position: relative;
|
|
54
53
|
flex-shrink: 0;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
)
|
|
54
|
+
padding-right: ${({ $gap }) => $gap}rem;
|
|
55
|
+
|
|
56
|
+
${({ $responsive, $visibleItems }) => !$responsive && $visibleItems
|
|
57
|
+
? `flex-basis: calc(100% / ${$visibleItems});`
|
|
58
|
+
: `
|
|
59
|
+
flex-basis: auto;
|
|
60
|
+
width: max-content;
|
|
61
|
+
`}
|
|
58
62
|
|
|
59
63
|
a {
|
|
60
64
|
pointer-events: ${({ $isSwiping }) => ($isSwiping ? 'none' : 'auto')};
|
|
@@ -146,53 +150,51 @@ const Counter = styledComponents.styled.span `
|
|
|
146
150
|
`;
|
|
147
151
|
/** @visibleName Carousel */
|
|
148
152
|
const Carousel = (_a) => {
|
|
149
|
-
var _b;
|
|
153
|
+
var _b, _c;
|
|
150
154
|
var { 'data-testid': dataTestId } = _a, props = tslib.__rest(_a, ['data-testid']);
|
|
151
155
|
const slidesWrapperRef = React.useRef(null);
|
|
152
156
|
const scrollbarRef = React.useRef(null);
|
|
153
157
|
const knobRef = React.useRef(null);
|
|
154
|
-
const
|
|
158
|
+
const firstItemRef = React.useRef(null);
|
|
159
|
+
const { isMobile, width: windowWidth } = useWindowSize.default(theme.default.breakpoints.md);
|
|
155
160
|
const [currentIndex, setCurrentIndex] = React.useState(0);
|
|
156
161
|
const [isSwiping, setIsSwiping] = React.useState(false);
|
|
157
|
-
const [
|
|
162
|
+
const [autoVisibleItems, setAutoVisibleItems] = React.useState(null);
|
|
158
163
|
React.useEffect(() => {
|
|
159
|
-
|
|
160
|
-
const
|
|
161
|
-
const
|
|
162
|
-
if (
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
if (props.responsive) {
|
|
165
|
+
const container = slidesWrapperRef.current;
|
|
166
|
+
const firstItem = firstItemRef.current;
|
|
167
|
+
if (container && firstItem) {
|
|
168
|
+
Array.from(container.children).forEach(itemElement => {
|
|
169
|
+
const item = itemElement;
|
|
170
|
+
item.style.flexBasis = '';
|
|
171
|
+
item.style.width = '';
|
|
172
|
+
});
|
|
173
|
+
const containerWidth = container.offsetWidth;
|
|
174
|
+
const itemWidth = firstItem.offsetWidth;
|
|
175
|
+
if (itemWidth > 0) {
|
|
176
|
+
const realVisibleItems = containerWidth / itemWidth;
|
|
177
|
+
setAutoVisibleItems(Math.max(1, realVisibleItems));
|
|
178
|
+
}
|
|
168
179
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const timeoutId = setTimeout(() => {
|
|
175
|
-
setCalculatedItems(calculateVisibleItems());
|
|
176
|
-
}, 100);
|
|
177
|
-
return () => clearTimeout(timeoutId);
|
|
178
|
-
}, [width, isMobile, props.responsive, props.visibleItems, props.children]);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
setAutoVisibleItems(null);
|
|
183
|
+
}
|
|
184
|
+
}, [props.responsive, windowWidth, props.children]);
|
|
179
185
|
const getStep = (step, visibleItems) => {
|
|
180
186
|
if (step > visibleItems) {
|
|
181
187
|
return Math.floor(visibleItems);
|
|
182
188
|
}
|
|
183
189
|
return Math.floor(step);
|
|
184
190
|
};
|
|
185
|
-
const visibleItems = props.visibleItems
|
|
191
|
+
const visibleItems = (_b = autoVisibleItems !== null && autoVisibleItems !== void 0 ? autoVisibleItems : props.visibleItems) !== null && _b !== void 0 ? _b : (isMobile ? 1.2 : 1);
|
|
186
192
|
const slidesWrapperGapSizePx = 20;
|
|
187
193
|
const slidesCount = React.Children.count(props.children);
|
|
188
194
|
const slideScreensCount = Math.max(1, slidesCount - Math.floor(visibleItems) + 1);
|
|
189
|
-
const step = getStep((
|
|
195
|
+
const step = getStep((_c = props.swipeStep) !== null && _c !== void 0 ? _c : 1, visibleItems);
|
|
190
196
|
const currentStepIndex = Math.ceil(currentIndex / step);
|
|
191
197
|
const totalSwipeSteps = Math.ceil(slideScreensCount / step + ((slideScreensCount - 1) % step !== 0 ? 1 : 0));
|
|
192
|
-
const itemWidthCorrectionRatio = (slidesWrapperGapSizePx * visibleItems) % Math.floor(visibleItems) === 0
|
|
193
|
-
? (visibleItems - 1) / visibleItems
|
|
194
|
-
: Math.floor(visibleItems) / visibleItems;
|
|
195
|
-
const itemWidthCorrection = itemWidthCorrectionRatio * slidesWrapperGapSizePx;
|
|
196
198
|
const data = React.useMemo(() => ({
|
|
197
199
|
startX: 0,
|
|
198
200
|
startTime: 0,
|
|
@@ -328,12 +330,10 @@ const Carousel = (_a) => {
|
|
|
328
330
|
React.useEffect(() => {
|
|
329
331
|
if (slidesWrapperRef.current && scrollbarRef.current) {
|
|
330
332
|
const isRest = React.Children.count(props.children) - (currentIndex + visibleItems) < 0;
|
|
331
|
-
data.itemWidth =
|
|
332
|
-
slidesWrapperRef.current.offsetWidth / visibleItems - itemWidthCorrection;
|
|
333
|
+
data.itemWidth = slidesWrapperRef.current.offsetWidth / visibleItems;
|
|
333
334
|
data.scrollWidth = slidesWrapperRef.current.scrollWidth;
|
|
334
335
|
data.lastItemX =
|
|
335
|
-
|
|
336
|
-
(React.Children.count(props.children) - visibleItems) -
|
|
336
|
+
data.itemWidth * (React.Children.count(props.children) - visibleItems) -
|
|
337
337
|
(isRest ? slidesWrapperGapSizePx * (Math.ceil(visibleItems) - visibleItems) : 0);
|
|
338
338
|
data.scrollbarToSlidesRatio =
|
|
339
339
|
data.lastItemX /
|
|
@@ -342,14 +342,26 @@ const Carousel = (_a) => {
|
|
|
342
342
|
let slidesTransform = 0;
|
|
343
343
|
if (React.Children.count(props.children) >= visibleItems) {
|
|
344
344
|
slidesTransform =
|
|
345
|
-
data.itemWidth * currentIndex
|
|
346
|
-
slidesWrapperGapSizePx * currentIndex -
|
|
345
|
+
data.itemWidth * currentIndex -
|
|
347
346
|
(isRest ? data.itemWidth * (visibleItems % 1) + slidesWrapperGapSizePx : 0);
|
|
348
347
|
}
|
|
349
348
|
setElementTransform(slidesWrapperRef, -slidesTransform);
|
|
350
349
|
setElementTransform(knobRef, slidesTransform / data.scrollbarToSlidesRatio);
|
|
351
350
|
}
|
|
352
|
-
}, [currentIndex, data,
|
|
351
|
+
}, [currentIndex, data, props.children, slideScreensCount, visibleItems]);
|
|
352
|
+
React.useEffect(() => {
|
|
353
|
+
var _a;
|
|
354
|
+
if (props.responsive && autoVisibleItems) {
|
|
355
|
+
const items = (_a = slidesWrapperRef.current) === null || _a === void 0 ? void 0 : _a.children;
|
|
356
|
+
if (items) {
|
|
357
|
+
Array.from(items).forEach(itemElement => {
|
|
358
|
+
const item = itemElement;
|
|
359
|
+
item.style.flexBasis = `calc(100% / ${autoVisibleItems})`;
|
|
360
|
+
item.style.width = '';
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}, [autoVisibleItems, props.responsive]);
|
|
353
365
|
return (React__default.default.createElement(CarouselWrapper, { id: props.id, className: props.className, "data-testid": dataTestId },
|
|
354
366
|
React__default.default.createElement(Header, { "data-testid": dataTestId && `${dataTestId}-header` },
|
|
355
367
|
props.title && React__default.default.createElement(Title, null, props.title),
|
|
@@ -361,7 +373,7 @@ const Carousel = (_a) => {
|
|
|
361
373
|
React__default.default.createElement(ButtonArrow.default, { direction: "left", "aria-label": props.previousAriaLabel, onClick: handleNavigationButtonPreviousClick, disabled: currentIndex <= 0, type: "button" }),
|
|
362
374
|
React__default.default.createElement(ButtonArrow.default, { direction: "right", "aria-label": props.nextAriaLabel, onClick: handleNavigationButtonNextClick, disabled: currentIndex + visibleItems >= React.Children.count(props.children), type: "button" }))),
|
|
363
375
|
React__default.default.createElement(Content, { "data-testid": dataTestId && `${dataTestId}-content` },
|
|
364
|
-
React__default.default.createElement(SlidesWrapper, { ref: slidesWrapperRef, onPointerDown: handleSlidesPointerDown
|
|
376
|
+
React__default.default.createElement(SlidesWrapper, { ref: slidesWrapperRef, onPointerDown: handleSlidesPointerDown }, React.Children.map(props.children, (child, index) => (React__default.default.createElement(SlideItem, { ref: index === 0 ? firstItemRef : undefined, "$visibleItems": visibleItems, "$isSwiping": isSwiping, onPointerDown: handlePointerDown, "$responsive": Boolean(props.responsive), "$gap": slidesWrapperGapSizePx / 16 }, child))))),
|
|
365
377
|
React__default.default.createElement(Footer, { "data-testid": dataTestId && `${dataTestId}-footer` },
|
|
366
378
|
React__default.default.createElement(Pagination, null, [...Array(totalSwipeSteps).keys()].map((value, index) => (React__default.default.createElement(PaginationItem, { key: value, "aria-label": props.paginationAriaLabel &&
|
|
367
379
|
`${props.paginationAriaLabel} ${index + 1}`, "aria-current": Math.ceil(currentIndex / step) === index, "$isActive": Math.ceil(currentIndex / step) === index, onClick: handlePaginationItemClick, type: "button" })))),
|
|
@@ -34,12 +34,6 @@ interface HeroProps {
|
|
|
34
34
|
* Background color when no image is provided
|
|
35
35
|
*/
|
|
36
36
|
backgroundColor?: string;
|
|
37
|
-
/**
|
|
38
|
-
* Enable gradient overlay on background
|
|
39
|
-
*
|
|
40
|
-
* @default false
|
|
41
|
-
*/
|
|
42
|
-
hasGradient?: boolean;
|
|
43
37
|
/**
|
|
44
38
|
* Logo image component for logo-style heroes
|
|
45
39
|
*/
|
|
@@ -35,9 +35,9 @@ const HeroImage = styledComponents.styled.div `
|
|
|
35
35
|
height: ${HERO_CONSTANTS.mobileHeight}px;
|
|
36
36
|
background-color: ${({ $backgroundColor }) => $backgroundColor || 'transparent'};
|
|
37
37
|
|
|
38
|
-
${({ $
|
|
38
|
+
${({ $backgroundColor }) => $backgroundColor &&
|
|
39
39
|
`
|
|
40
|
-
linear-gradient(180deg, ${theme.default.color.background.plum.default}${theme.default.color.transparency.T0} 0%, ${theme.default.color.background.plum.default}${theme.default.color.transparency.T30}
|
|
40
|
+
background-image: linear-gradient(180deg, ${theme.default.color.background.plum.default}${theme.default.color.transparency.T0} 0%, ${theme.default.color.background.plum.default}${theme.default.color.transparency.T30} 100%);
|
|
41
41
|
background-size: 100% 33.33%;
|
|
42
42
|
background-repeat: no-repeat;
|
|
43
43
|
background-position: bottom;
|
|
@@ -184,7 +184,7 @@ const Hero = (_a) => {
|
|
|
184
184
|
var { variant = 'default', headingLevel = 'h1', Image = 'img', LogoImage = 'img', 'data-testid': dataTestId } = _a, props = tslib.__rest(_a, ["variant", "headingLevel", "Image", "LogoImage", 'data-testid']);
|
|
185
185
|
const HeadingTag = headingLevel;
|
|
186
186
|
return (React__default.default.createElement(HeroContainer, { "$variant": variant, className: props.className, "data-testid": dataTestId },
|
|
187
|
-
React__default.default.createElement(HeroImage, { "$
|
|
187
|
+
React__default.default.createElement(HeroImage, { "$backgroundColor": props.backgroundColor },
|
|
188
188
|
props.logoImageProps && (React__default.default.createElement(LogoImageWrap, null,
|
|
189
189
|
React__default.default.createElement(LogoImageContainer, null, renderImage(LogoImage, props.logoImageProps)))),
|
|
190
190
|
!props.logoImageProps && props.imageProps && renderImage(Image, props.imageProps)),
|
|
@@ -2,6 +2,7 @@ export { default as Accordion } from './Accordion/Accordion';
|
|
|
2
2
|
export { default as AccordionItem } from './AccordionItem/AccordionItem';
|
|
3
3
|
export { default as AmountSelector } from './AmountSelector/AmountSelector';
|
|
4
4
|
export { default as Box } from './Box/Box';
|
|
5
|
+
export { default as Breadcrumb } from './Breadcrumb/Breadcrumb';
|
|
5
6
|
export { default as Button } from './Button/Button';
|
|
6
7
|
export { default as ButtonArrow } from './ButtonArrow/ButtonArrow';
|
|
7
8
|
export { default as ButtonCard } from './ButtonCard/ButtonCard';
|
package/build/cjs/index.js
CHANGED
|
@@ -4,6 +4,7 @@ var Accordion = require('./components/Accordion/Accordion.js');
|
|
|
4
4
|
var AccordionItem = require('./components/AccordionItem/AccordionItem.js');
|
|
5
5
|
var AmountSelector = require('./components/AmountSelector/AmountSelector.js');
|
|
6
6
|
var Box = require('./components/Box/Box.js');
|
|
7
|
+
var Breadcrumb = require('./components/Breadcrumb/Breadcrumb.js');
|
|
7
8
|
var Button = require('./components/Button/Button.js');
|
|
8
9
|
var ButtonArrow = require('./components/ButtonArrow/ButtonArrow.js');
|
|
9
10
|
var ButtonCard = require('./components/ButtonCard/ButtonCard.js');
|
|
@@ -176,6 +177,7 @@ exports.Accordion = Accordion.default;
|
|
|
176
177
|
exports.AccordionItem = AccordionItem.default;
|
|
177
178
|
exports.AmountSelector = AmountSelector.default;
|
|
178
179
|
exports.Box = Box.default;
|
|
180
|
+
exports.Breadcrumb = Breadcrumb.default;
|
|
179
181
|
exports.Button = Button.default;
|
|
180
182
|
exports.ButtonArrow = ButtonArrow.default;
|
|
181
183
|
exports.ButtonCard = ButtonCard.default;
|
|
@@ -9,7 +9,14 @@ declare const theme: {
|
|
|
9
9
|
unit: string;
|
|
10
10
|
};
|
|
11
11
|
};
|
|
12
|
-
breakpoints:
|
|
12
|
+
breakpoints: {
|
|
13
|
+
readonly xxl: 1440;
|
|
14
|
+
readonly xl: 1200;
|
|
15
|
+
readonly lg: 992;
|
|
16
|
+
readonly md: 768;
|
|
17
|
+
readonly sm: 576;
|
|
18
|
+
readonly xs: 480;
|
|
19
|
+
};
|
|
13
20
|
color: {
|
|
14
21
|
default: {
|
|
15
22
|
pink: string;
|
|
@@ -155,7 +162,7 @@ declare const theme: {
|
|
|
155
162
|
h1: string;
|
|
156
163
|
h2: string;
|
|
157
164
|
};
|
|
158
|
-
media: Record<
|
|
165
|
+
media: Record<"xxl" | "xl" | "lg" | "md" | "sm" | "xs", (l: TemplateStringsArray, ...p: (string | number)[]) => ReturnType<typeof import("styled-components").css>>;
|
|
159
166
|
radius: {
|
|
160
167
|
default: string;
|
|
161
168
|
s: string;
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
declare const breakpoints: {
|
|
2
|
+
readonly xxl: 1440;
|
|
3
|
+
readonly xl: 1200;
|
|
4
|
+
readonly lg: 992;
|
|
5
|
+
readonly md: 768;
|
|
6
|
+
readonly sm: 576;
|
|
7
|
+
readonly xs: 480;
|
|
8
|
+
};
|
|
9
|
+
export type ViewBreakpoints = typeof breakpoints;
|
|
5
10
|
export default breakpoints;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { css } from '../themes/styled';
|
|
1
2
|
export declare const getMultipliedSize: (base: {
|
|
2
3
|
value: number;
|
|
3
4
|
unit: string;
|
|
@@ -6,4 +7,24 @@ export declare const getDividedSize: (base: {
|
|
|
6
7
|
value: number;
|
|
7
8
|
unit: string;
|
|
8
9
|
}, divide: number) => string;
|
|
9
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Media query helpers for responsive design.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const StyledDiv = styled.div`
|
|
16
|
+
* font-size: 1rem;
|
|
17
|
+
* ${media.md`font-size: 1.2rem;`}
|
|
18
|
+
* ${media.lg`font-size: 1.5rem;`}
|
|
19
|
+
* `;
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Available breakpoints:
|
|
23
|
+
* - `xs`: 480px
|
|
24
|
+
* - `sm`: 576px
|
|
25
|
+
* - `md`: 768px
|
|
26
|
+
* - `lg`: 992px
|
|
27
|
+
* - `xl`: 1200px
|
|
28
|
+
* - `xxl`: 1440px
|
|
29
|
+
*/
|
|
30
|
+
export declare const media: Record<"xxl" | "xl" | "lg" | "md" | "sm" | "xs", (l: TemplateStringsArray, ...p: (string | number)[]) => ReturnType<typeof css>>;
|
|
@@ -5,12 +5,32 @@ var breakpoints = require('../themes/themeComponents/breakpoints.js');
|
|
|
5
5
|
|
|
6
6
|
const getMultipliedSize = (base, multiply) => `${multiply * base.value}${base.unit}`;
|
|
7
7
|
const getDividedSize = (base, divide) => `${base.value / divide}${base.unit}`;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Media query helpers for responsive design.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const StyledDiv = styled.div`
|
|
14
|
+
* font-size: 1rem;
|
|
15
|
+
* ${media.md`font-size: 1.2rem;`}
|
|
16
|
+
* ${media.lg`font-size: 1.5rem;`}
|
|
17
|
+
* `;
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Available breakpoints:
|
|
21
|
+
* - `xs`: 480px
|
|
22
|
+
* - `sm`: 576px
|
|
23
|
+
* - `md`: 768px
|
|
24
|
+
* - `lg`: 992px
|
|
25
|
+
* - `xl`: 1200px
|
|
26
|
+
* - `xxl`: 1440px
|
|
27
|
+
*/
|
|
28
|
+
const media = Object.keys(breakpoints.default).reduce((acc, key) => {
|
|
29
|
+
acc[key] = (literals, ...placeholders) => styledComponents.css `
|
|
30
|
+
@media (min-width: ${breakpoints.default[key]}px) {
|
|
31
|
+
${styledComponents.css(literals, ...placeholders)}
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
14
34
|
return acc;
|
|
15
35
|
}, {});
|
|
16
36
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
if(typeof document!=="undefined")document.head.appendChild(document.createElement("style")).textContent="@font-face{font-family:'DNA Text';font-style: normal;font-weight: 400;font-display: swap;src: url('https://www.dna.fi/fonts/DNAText-Regular.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAText-Regular.woff') format('woff');}@font-face{font-family:'DNA Text';font-style: normal;font-weight: 500;font-display: swap;src: url('https://www.dna.fi/fonts/DNAText-Medium.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAText-Medium.woff') format('woff');}@font-face{font-family:'DNA Text';font-style: normal;font-weight: 700;font-display: swap;src: url('https://www.dna.fi/fonts/DNAText-Bold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAText-Bold.woff') format('woff');}@font-face{font-family:'DNA Heading';font-style: normal;font-weight: 600;font-display: swap;src: url('https://www.dna.fi/fonts/DNAHeading-DemiBold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAHeading-DemiBold.woff') format('woff');}@font-face{font-family:'DNA Heading';font-style: normal;font-weight: 700;font-display: swap;src: url('https://www.dna.fi/fonts/DNAHeading-Bold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAHeading-Bold.woff') format('woff');}@font-face{font-family:'DNA Heading';font-style: normal;font-weight: 900;font-display: swap;src: url('https://www.dna.fi/fonts/DNAHeading-Black.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAHeading-Black.woff') format('woff');}@font-face{font-family:'DNA Numerals';font-style: normal;font-weight: 700;font-display: swap;src: url('https://www.dna.fi/fonts/DNANumerals-Bold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNANumerals-Bold.woff') format('woff');}@font-face{font-family:'DNA Text Regular';font-style: normal;font-weight: 400;font-display: swap;src: url('https://www.dna.fi/fonts/DNAText-Regular.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAText-Regular.woff') format('woff');}@font-face{font-family:'DNA Text Medium';font-style: normal;font-weight: 500;font-display: swap;src: url('https://www.dna.fi/fonts/DNAText-Medium.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAText-Medium.woff') format('woff');}@font-face{font-family:'DNA Text Bold';font-style: normal;font-weight: 700;font-display: swap;src: url('https://www.dna.fi/fonts/DNAText-Bold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAText-Bold.woff') format('woff');}@font-face{font-family:'DNA Heading Demi Bold';font-style: normal;font-weight: 600;font-display: swap;src: url('https://www.dna.fi/fonts/DNAHeading-DemiBold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAHeading-DemiBold.woff') format('woff');}@font-face{font-family:'DNA Heading Bold';font-style: normal;font-weight: 700;font-display: swap;src: url('https://www.dna.fi/fonts/DNAHeading-Bold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAHeading-Bold.woff') format('woff');}@font-face{font-family:'DNA Heading Black';font-style: normal;font-weight: 900;font-display: swap;src: url('https://www.dna.fi/fonts/DNAHeading-Black.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNAHeading-Black.woff') format('woff');}@font-face{font-family:'DNA Numerals Bold';font-style: normal;font-weight: 700;font-display: swap;src: url('https://www.dna.fi/fonts/DNANumerals-Bold.woff2') format('woff2'),url('https://www.dna.fi/fonts/DNANumerals-Bold.woff') format('woff');}";
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ComponentType } from 'react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export interface BreadcrumbItem {
|
|
4
|
+
/**
|
|
5
|
+
* Display text for the breadcrumb item
|
|
6
|
+
*/
|
|
7
|
+
label: string;
|
|
8
|
+
/**
|
|
9
|
+
* URL/path for the breadcrumb item. If not provided, item will be rendered as text only
|
|
10
|
+
*/
|
|
11
|
+
href?: string;
|
|
12
|
+
}
|
|
13
|
+
interface Props {
|
|
14
|
+
/**
|
|
15
|
+
* Array of breadcrumb items to display
|
|
16
|
+
*/
|
|
17
|
+
items?: BreadcrumbItem[];
|
|
18
|
+
/**
|
|
19
|
+
* Custom link component to use instead of default anchor element
|
|
20
|
+
* Useful for router integration (e.g., Next.js Link, React Router Link)
|
|
21
|
+
*/
|
|
22
|
+
linkComponent?: ComponentType<any>;
|
|
23
|
+
/**
|
|
24
|
+
* Props to pass to the link component
|
|
25
|
+
*/
|
|
26
|
+
linkProps?: Record<string, unknown>;
|
|
27
|
+
/**
|
|
28
|
+
* Screen reader label describing the breadcrumb navigation
|
|
29
|
+
*/
|
|
30
|
+
ariaLabel?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Allows to pass testid string for testing purposes
|
|
33
|
+
*/
|
|
34
|
+
'data-testid'?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Allows to pass a custom className
|
|
37
|
+
*/
|
|
38
|
+
className?: string;
|
|
39
|
+
}
|
|
40
|
+
declare const Breadcrumb: ({ "data-testid": dataTestId, ariaLabel, className, items, linkComponent: LinkComponent, linkProps, }: Props) => React.JSX.Element | null;
|
|
41
|
+
/** @component */
|
|
42
|
+
export default Breadcrumb;
|