@leabankab/component-library 8.7.0 → 8.9.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 +58 -0
- package/dist/component-library.es.js +906 -881
- package/dist/component-library.es.js.map +1 -1
- package/dist/component-library.umd.js +2 -2
- package/dist/component-library.umd.js.map +1 -1
- package/dist/components/form/select-field.d.ts +20 -1
- package/dist/components/form/select.d.ts +13 -3
- package/dist/components/form/slider.d.ts +15 -2
- package/dist/index.css +1 -1
- package/dist/website/alert-banner.d.ts +48 -0
- package/dist/website/arrow-reveal-link.d.ts +22 -0
- package/dist/website/brand-letters.d.ts +40 -0
- package/dist/website/calculator.d.ts +58 -0
- package/dist/website/carousel.d.ts +55 -0
- package/dist/website/cta-banner.d.ts +42 -0
- package/dist/website/expanding-cards-context.d.ts +8 -0
- package/dist/website/expanding-cards-item.d.ts +69 -0
- package/dist/website/expanding-cards.d.ts +48 -0
- package/dist/website/flags.d.ts +7 -0
- package/dist/website/hero-service-grid.d.ts +52 -0
- package/dist/website/hero.d.ts +57 -0
- package/dist/website/index.d.ts +37 -0
- package/dist/website/navigation-grid.d.ts +39 -0
- package/dist/website/paragraphs.d.ts +11 -0
- package/dist/website/partner-list.d.ts +79 -0
- package/dist/website/payment-feature.d.ts +85 -0
- package/dist/website/promo-grid.d.ts +71 -0
- package/dist/website/section-header.d.ts +53 -0
- package/dist/website/section.d.ts +53 -0
- package/dist/website/service-card-grid.d.ts +33 -0
- package/dist/website/side-nav.d.ts +57 -0
- package/dist/website/site-footer.d.ts +122 -0
- package/dist/website/site-header-link.d.ts +16 -0
- package/dist/website/site-header-menu.d.ts +21 -0
- package/dist/website/site-header.d.ts +141 -0
- package/dist/website/split-content.d.ts +69 -0
- package/dist/website/stats.d.ts +52 -0
- package/dist/website/testimonials.d.ts +100 -0
- package/dist/website/use-brand-letters-labels.d.ts +2 -0
- package/dist/website/use-carousel-labels.d.ts +6 -0
- package/dist/website/use-carousel.d.ts +50 -0
- package/dist/website/use-partner-list-labels.d.ts +6 -0
- package/dist/website/use-side-nav-labels.d.ts +5 -0
- package/dist/website/use-site-footer-labels.d.ts +7 -0
- package/dist/website/use-site-header-labels.d.ts +7 -0
- package/dist/website/use-testimonials-labels.d.ts +6 -0
- package/dist/website.cjs +2 -0
- package/dist/website.cjs.map +1 -0
- package/dist/website.css +1 -0
- package/dist/website.mjs +1933 -0
- package/dist/website.mjs.map +1 -0
- package/package.json +7 -2
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
2
|
+
import { ReactElement, ReactNode, Ref } from 'react';
|
|
3
|
+
/** `alt` is required with a logo. */
|
|
4
|
+
type PartnerListLogo = {
|
|
5
|
+
/** The partner's logo, shown on a white tile. */
|
|
6
|
+
src: string;
|
|
7
|
+
/**
|
|
8
|
+
* The partner's name, for screen readers; `""` when the text beside
|
|
9
|
+
* the logo already names the partner.
|
|
10
|
+
*/
|
|
11
|
+
alt: string;
|
|
12
|
+
/**
|
|
13
|
+
* The image element to render instead of the plain `<img>`, as on
|
|
14
|
+
* `PartnerRow`: `next/image`, or an `<img loading="lazy">`.
|
|
15
|
+
*/
|
|
16
|
+
imageRender?: ReactElement;
|
|
17
|
+
} | {
|
|
18
|
+
src?: undefined;
|
|
19
|
+
alt?: undefined;
|
|
20
|
+
imageRender?: undefined;
|
|
21
|
+
};
|
|
22
|
+
/** One partner in the list. */
|
|
23
|
+
export type PartnerListItem = PartnerListLogo & {
|
|
24
|
+
/** The partner's name. The list is sorted by it. */
|
|
25
|
+
name: string;
|
|
26
|
+
/**
|
|
27
|
+
* The text about the partner, beside the logo: usually `RichText` with the
|
|
28
|
+
* CMS content, whose heading is the name.
|
|
29
|
+
*/
|
|
30
|
+
content: ReactNode;
|
|
31
|
+
};
|
|
32
|
+
export type PartnerListProps = Omit<useRender.ComponentProps<"div">, "ref" | "children" | "defaultValue" | "onChange"> & {
|
|
33
|
+
/** The rendered element: the `<div>`, or the element passed to `render`. */
|
|
34
|
+
ref?: Ref<HTMLElement>;
|
|
35
|
+
/** The partners, in any order. */
|
|
36
|
+
items: readonly PartnerListItem[];
|
|
37
|
+
/**
|
|
38
|
+
* How many partners a page shows.
|
|
39
|
+
* @default 9
|
|
40
|
+
*/
|
|
41
|
+
pageSize?: number;
|
|
42
|
+
/** The page shown, counted from 1. Pass it to control the list. */
|
|
43
|
+
value?: number;
|
|
44
|
+
/**
|
|
45
|
+
* The page shown first when the list is not controlled.
|
|
46
|
+
* @default 1
|
|
47
|
+
*/
|
|
48
|
+
defaultValue?: number;
|
|
49
|
+
/** Called with the page number when the visitor turns the page. */
|
|
50
|
+
onValueChange?: (page: number) => void;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* The website's list of partners, as on leabank.no/om-oss/samarbeidspartnere:
|
|
54
|
+
* a `PartnerRow` per partner, sorted by name, nine to a page, with previous
|
|
55
|
+
* and next buttons and a dot per page under them.
|
|
56
|
+
*
|
|
57
|
+
* ```tsx
|
|
58
|
+
* <Section surface="subtle" width="wide">
|
|
59
|
+
* <PartnerList
|
|
60
|
+
* items={partners.map((partner) => ({
|
|
61
|
+
* name: partner.name,
|
|
62
|
+
* content: <RichText>…</RichText>,
|
|
63
|
+
* src: partner.logo,
|
|
64
|
+
* alt: "",
|
|
65
|
+
* }))}
|
|
66
|
+
* />
|
|
67
|
+
* </Section>
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* The partners are sorted in the `LeaProvider` language (Å after Z in
|
|
71
|
+
* Norwegian and Swedish, Ä and Ö in Swedish and Finnish order), so the
|
|
72
|
+
* order follows the market. The controls show from two pages: elevated
|
|
73
|
+
* buttons named "Forrige side" and "Neste side", which stay focusable at the
|
|
74
|
+
* first and last page, and `PaginationDots`; the new page is announced as
|
|
75
|
+
* "Side 2 av 3". The list takes the width it is given: on the website a
|
|
76
|
+
* `Section` with `width="wide"`.
|
|
77
|
+
*/
|
|
78
|
+
export declare function PartnerList({ items, pageSize, value: valueProp, defaultValue, onValueChange, render, ref, className, ...rest }: PartnerListProps): ReactElement<unknown, string | import('react').JSXElementConstructor<any>> | null;
|
|
79
|
+
export {};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { PanelProps } from '../index';
|
|
3
|
+
export type PaymentFeatureImagePosition = "start" | "end";
|
|
4
|
+
/** A logo in the row at the top. */
|
|
5
|
+
export type PaymentFeatureLogo = {
|
|
6
|
+
/** The logo file. */
|
|
7
|
+
src: string;
|
|
8
|
+
/** The name of the brand, for screen readers. */
|
|
9
|
+
alt: string;
|
|
10
|
+
/**
|
|
11
|
+
* The image element to render instead of the plain `<img>`, such as
|
|
12
|
+
* `next/image` with the logo's own `width` and `height`.
|
|
13
|
+
*/
|
|
14
|
+
imageRender?: ReactElement;
|
|
15
|
+
};
|
|
16
|
+
/** `alt` is required with a photo, `""` when it is decoration. */
|
|
17
|
+
type PaymentFeatureImage = {
|
|
18
|
+
/** The photo beside the text. Without one, the text takes the card. */
|
|
19
|
+
src: string;
|
|
20
|
+
/**
|
|
21
|
+
* What the photo shows, for screen readers; `""` when it is decoration
|
|
22
|
+
* and the text says it all.
|
|
23
|
+
*/
|
|
24
|
+
alt: string;
|
|
25
|
+
/**
|
|
26
|
+
* The image element to render instead of the plain `<img>`, such as
|
|
27
|
+
* `next/image`. Its own props win over `src` and `alt`.
|
|
28
|
+
*/
|
|
29
|
+
imageRender?: ReactElement;
|
|
30
|
+
} | {
|
|
31
|
+
src?: undefined;
|
|
32
|
+
alt?: undefined;
|
|
33
|
+
imageRender?: undefined;
|
|
34
|
+
};
|
|
35
|
+
export type PaymentFeatureProps = Omit<PanelProps, "title" | "children" | "size"> & PaymentFeatureImage & {
|
|
36
|
+
/** The logos of the payment brands, in a row over the text. */
|
|
37
|
+
logos?: readonly PaymentFeatureLogo[];
|
|
38
|
+
/** The title. */
|
|
39
|
+
title: ReactNode;
|
|
40
|
+
/** The element for the title, an `<h2>` by default: `titleRender={<h3 />}`. */
|
|
41
|
+
titleRender?: ReactElement;
|
|
42
|
+
/**
|
|
43
|
+
* The text under the title. A string becomes one paragraph; pass `<p>`
|
|
44
|
+
* elements for several.
|
|
45
|
+
*/
|
|
46
|
+
text?: ReactNode;
|
|
47
|
+
/**
|
|
48
|
+
* The calls to action, in a row that wraps: an `ActionButton`, a `Link`
|
|
49
|
+
* with `arrow`, or both.
|
|
50
|
+
*/
|
|
51
|
+
actions?: ReactNode;
|
|
52
|
+
/** The price example under the actions, in the small print. */
|
|
53
|
+
priceExample?: ReactNode;
|
|
54
|
+
/**
|
|
55
|
+
* Where the photo sits: `"start"` before the text (on the left, or on
|
|
56
|
+
* top below 1024px), `"end"` after it.
|
|
57
|
+
* @default "end"
|
|
58
|
+
*/
|
|
59
|
+
imagePosition?: PaymentFeatureImagePosition;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* A payment feature on a white `Panel`: a row of brand logos, a title, a
|
|
63
|
+
* text and the calls to action in one column, and a photo in the other.
|
|
64
|
+
*
|
|
65
|
+
* ```tsx
|
|
66
|
+
* <Section surface="subtle">
|
|
67
|
+
* <PaymentFeature
|
|
68
|
+
* logos={[{ src: "/logoer/vipps.svg", alt: "Vipps" }, { src: "/logoer/visa.svg", alt: "Visa" }]}
|
|
69
|
+
* title="Betal med Lea Bank i nettbutikken"
|
|
70
|
+
* text="Del opp betalingen eller betal senere når du handler hos våre partnere."
|
|
71
|
+
* actions={<ActionButton render={<NextLink href="/betaling" />}>Les mer</ActionButton>}
|
|
72
|
+
* src="/bilder/betaling.jpg"
|
|
73
|
+
* alt=""
|
|
74
|
+
* />
|
|
75
|
+
* </Section>
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* From 1024px the text column is at most 560px and the photo, at most 435px
|
|
79
|
+
* wide, sits at the end of the other column; below 1024px they stack 32px
|
|
80
|
+
* apart. The logos are up to 48px tall (32px below 768px) with a line between
|
|
81
|
+
* them, and wrap on a narrow screen. Put it on a coloured section: the panel
|
|
82
|
+
* is white.
|
|
83
|
+
*/
|
|
84
|
+
export declare function PaymentFeature({ logos, title, titleRender, text, actions, priceExample, src, alt, imageRender, imagePosition, className, ...rest }: PaymentFeatureProps): import("react").JSX.Element;
|
|
85
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
2
|
+
import { ReactElement, ReactNode, Ref } from 'react';
|
|
3
|
+
export type PromoGridImagePosition = "start" | "end";
|
|
4
|
+
/** One of the smaller photos over the text. */
|
|
5
|
+
export type PromoGridImage = {
|
|
6
|
+
/** The photo. */
|
|
7
|
+
src: string;
|
|
8
|
+
/** What the photo shows, for screen readers; `""` when it is decoration. */
|
|
9
|
+
alt: string;
|
|
10
|
+
/**
|
|
11
|
+
* The image element to render instead of the plain `<img>`, such as
|
|
12
|
+
* `next/image` with `fill`. Its own props win over `src` and `alt`.
|
|
13
|
+
*/
|
|
14
|
+
imageRender?: ReactElement;
|
|
15
|
+
};
|
|
16
|
+
export type PromoGridProps = Omit<useRender.ComponentProps<"div">, "ref" | "title" | "children"> & {
|
|
17
|
+
/** The rendered element: the `<div>`, or the element passed to `render`. */
|
|
18
|
+
ref?: Ref<HTMLElement>;
|
|
19
|
+
/** The large photo. */
|
|
20
|
+
src: string;
|
|
21
|
+
/** What the large photo shows, for screen readers; `""` when it is decoration. */
|
|
22
|
+
alt: string;
|
|
23
|
+
/**
|
|
24
|
+
* The image element to render for the large photo instead of the plain
|
|
25
|
+
* `<img>`, as on `FeaturedImage`.
|
|
26
|
+
*/
|
|
27
|
+
imageRender?: ReactElement;
|
|
28
|
+
/** A call to action on the large photo: an `ActionButton`. */
|
|
29
|
+
action?: ReactNode;
|
|
30
|
+
/** One or two smaller photos over the text, side by side. */
|
|
31
|
+
images?: readonly [PromoGridImage] | readonly [PromoGridImage, PromoGridImage];
|
|
32
|
+
/** The title on the beige block, in capitals. */
|
|
33
|
+
title: ReactNode;
|
|
34
|
+
/** The element for the title, an `<h2>` by default: `titleRender={<h3 />}`. */
|
|
35
|
+
titleRender?: ReactElement;
|
|
36
|
+
/**
|
|
37
|
+
* The text under the title. A string becomes one paragraph; pass `<p>`
|
|
38
|
+
* elements for several.
|
|
39
|
+
*/
|
|
40
|
+
subtitle?: ReactNode;
|
|
41
|
+
/**
|
|
42
|
+
* Where the large photo sits from 1024px: `"start"` (on the left) or
|
|
43
|
+
* `"end"`. Below 1024px it is always on top.
|
|
44
|
+
* @default "start"
|
|
45
|
+
*/
|
|
46
|
+
imagePosition?: PromoGridImagePosition;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* A promotion of photos and a title: a large `FeaturedImage` on one side, and
|
|
50
|
+
* on the other one or two photos over a beige block with the title in
|
|
51
|
+
* capitals, as on leabank.no's about page.
|
|
52
|
+
*
|
|
53
|
+
* ```tsx
|
|
54
|
+
* <Section>
|
|
55
|
+
* <PromoGrid
|
|
56
|
+
* src="/bilder/kontor.jpg"
|
|
57
|
+
* alt=""
|
|
58
|
+
* action={<ActionButton render={<NextLink href="/lan" />}>Se våre lån</ActionButton>}
|
|
59
|
+
* images={[{ src: "/bilder/team.jpg", alt: "" }]}
|
|
60
|
+
* title="Lån til det du trenger"
|
|
61
|
+
* subtitle="Vi hjelper deg med lån uten sikkerhet til det du har lyst på."
|
|
62
|
+
* />
|
|
63
|
+
* </Section>
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* From 1024px two equal columns 600px tall, 16px apart, the smaller photos
|
|
67
|
+
* taking the room the block leaves. Below 1024px everything stacks, the
|
|
68
|
+
* photos at 1 : 0.5, the two smaller ones side by side down to 768px. The
|
|
69
|
+
* block is beige with dark text on any section.
|
|
70
|
+
*/
|
|
71
|
+
export declare function PromoGrid({ src, alt, imageRender, action, images, title, titleRender, subtitle, imagePosition, render, ref, className, ...rest }: PromoGridProps): ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
2
|
+
import { ReactElement, ReactNode, Ref } from 'react';
|
|
3
|
+
export type SectionHeaderTitleSize = "sm" | "lg";
|
|
4
|
+
export type SectionHeaderProps = Omit<useRender.ComponentProps<"div">, "ref" | "title" | "children"> & {
|
|
5
|
+
/** The rendered element: the `<div>`, or the element passed to `render`. */
|
|
6
|
+
ref?: Ref<HTMLElement>;
|
|
7
|
+
/** The short line above the title. */
|
|
8
|
+
eyebrow?: ReactNode;
|
|
9
|
+
/** The title of the section. */
|
|
10
|
+
title: ReactNode;
|
|
11
|
+
/**
|
|
12
|
+
* The element for the title, an `<h2>` by default. Pass another level where
|
|
13
|
+
* the page outline needs one: `titleRender={<h1 />}`.
|
|
14
|
+
*/
|
|
15
|
+
titleRender?: ReactElement;
|
|
16
|
+
/**
|
|
17
|
+
* `"lg"`: 41px (26px below 768px). `"sm"`: 26px at every width.
|
|
18
|
+
* @default "lg"
|
|
19
|
+
*/
|
|
20
|
+
titleSize?: SectionHeaderTitleSize;
|
|
21
|
+
/**
|
|
22
|
+
* The text under the title, at most 720px wide. A string becomes one
|
|
23
|
+
* paragraph; pass `<p>` elements for several.
|
|
24
|
+
*/
|
|
25
|
+
subtitle?: ReactNode;
|
|
26
|
+
/**
|
|
27
|
+
* The calls to action, in a centred row that wraps: an `ActionButton`,
|
|
28
|
+
* a `Link` with `arrow`, or both. The row is only there when this is.
|
|
29
|
+
*/
|
|
30
|
+
actions?: ReactNode;
|
|
31
|
+
/** The price example under the actions, in the small print. */
|
|
32
|
+
priceExample?: ReactNode;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The centred heading of a website section: a short line, the title, a text
|
|
36
|
+
* of at most 720px and a row of calls to action, as at the top of the
|
|
37
|
+
* sections on leabank.no.
|
|
38
|
+
*
|
|
39
|
+
* ```tsx
|
|
40
|
+
* <Section>
|
|
41
|
+
* <SectionHeader
|
|
42
|
+
* eyebrow="Om Lea Bank"
|
|
43
|
+
* title="Vi gjør det enkelt å ta smarte økonomiske valg"
|
|
44
|
+
* subtitle="Lea Bank er en digital bank …"
|
|
45
|
+
* actions={<ActionButton render={<NextLink href="/om-oss" />}>Les mer om oss</ActionButton>}
|
|
46
|
+
* />
|
|
47
|
+
* </Section>
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* It takes the text colour of its section. The parts are 16px apart and the
|
|
51
|
+
* actions 32px under them; the actions are 32px apart.
|
|
52
|
+
*/
|
|
53
|
+
export declare function SectionHeader({ eyebrow, title, titleRender, titleSize, subtitle, actions, priceExample, render, ref, className, ...rest }: SectionHeaderProps): ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
2
|
+
import { Ref } from 'react';
|
|
3
|
+
import { SurfaceRoles } from '../components/color-roles';
|
|
4
|
+
export type SectionSurface = SurfaceRoles<"base" | "subtle" | "muted" | "contrast" | "contrast-accent">;
|
|
5
|
+
export type SectionSpacing = "none" | "sm" | "lg";
|
|
6
|
+
export type SectionWidth = "full" | "wide" | "narrow";
|
|
7
|
+
export type SectionProps = Omit<useRender.ComponentProps<"section">, "ref"> & {
|
|
8
|
+
/** The rendered element: the `<section>`, or the element passed to `render`. */
|
|
9
|
+
ref?: Ref<HTMLElement>;
|
|
10
|
+
/**
|
|
11
|
+
* The colour of the band, after its `bg` token: `"base"` (white),
|
|
12
|
+
* `"subtle"` (grey), `"muted"` (beige), `"contrast"` (near-black) or
|
|
13
|
+
* `"contrast-accent"` (deep purple). On the last two the text is white;
|
|
14
|
+
* give a `Link` inside `color="contrast"` there.
|
|
15
|
+
* @default "base"
|
|
16
|
+
*/
|
|
17
|
+
surface?: SectionSurface;
|
|
18
|
+
/**
|
|
19
|
+
* The room above the content: `"lg"` 112px (64px below 768px), `"sm"` 64px
|
|
20
|
+
* (32px), `"none"`.
|
|
21
|
+
* @default "lg"
|
|
22
|
+
*/
|
|
23
|
+
spacingTop?: SectionSpacing;
|
|
24
|
+
/**
|
|
25
|
+
* The room below the content, in the same steps as `spacingTop`.
|
|
26
|
+
* @default "lg"
|
|
27
|
+
*/
|
|
28
|
+
spacingBottom?: SectionSpacing;
|
|
29
|
+
/**
|
|
30
|
+
* How much of the content column the content takes, centred: `"full"`,
|
|
31
|
+
* `"wide"` (75 %) or `"narrow"` (60 %). Below 1024px it is always the full
|
|
32
|
+
* column.
|
|
33
|
+
* @default "full"
|
|
34
|
+
*/
|
|
35
|
+
width?: SectionWidth;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* A band of a website page: the colour from edge to edge, the content in a
|
|
39
|
+
* column of at most 1312px in the middle, 64px from the sides (16px below
|
|
40
|
+
* 768px). Every block on leabank.no sits in one.
|
|
41
|
+
*
|
|
42
|
+
* ```tsx
|
|
43
|
+
* <Section surface="subtle" spacingTop="none">
|
|
44
|
+
* <SectionHeader title="Vi gjør det enkelt å ta smarte økonomiske valg" />
|
|
45
|
+
* </Section>
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* The section sets the text colour for what is inside it, white on the dark
|
|
49
|
+
* surfaces, so text, a vertical `MediaCard` and the sections that have no
|
|
50
|
+
* colour of their own follow it. Renders a `section`; pass `render` for
|
|
51
|
+
* another element.
|
|
52
|
+
*/
|
|
53
|
+
export declare function Section({ surface, spacingTop, spacingBottom, width, render, ref, className, children, ...rest }: SectionProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
2
|
+
import { ReactNode, Ref } from 'react';
|
|
3
|
+
export type ServiceCardGridProps = Omit<useRender.ComponentProps<"div">, "ref" | "children"> & {
|
|
4
|
+
/** The rendered element: the `<div>`, or the element passed to `render`. */
|
|
5
|
+
ref?: Ref<HTMLElement>;
|
|
6
|
+
/**
|
|
7
|
+
* The cards: one to four `ServiceCard`s, in the order of the website's
|
|
8
|
+
* grid. The first two are `layout="stacked"` (the default); give the third
|
|
9
|
+
* and fourth `layout="row"`. Each one is put in an item of a list.
|
|
10
|
+
*/
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* The website's grid of service cards, as on leabank.no/lan: a large card
|
|
15
|
+
* and a narrow one side by side, then a wide row under them.
|
|
16
|
+
*
|
|
17
|
+
* ```tsx
|
|
18
|
+
* <Section surface="muted">
|
|
19
|
+
* <ServiceCardGrid>
|
|
20
|
+
* <ServiceCard render={<NextLink href="/lan/forbrukslan" />} title="Forbrukslån" … />
|
|
21
|
+
* <ServiceCard render={<NextLink href="/lan/refinansiering" />} title="Refinansiering" … />
|
|
22
|
+
* <ServiceCard render={<NextLink href="/sparing" />} layout="row" title="Sparing" … />
|
|
23
|
+
* <ServiceCard render={<NextLink href="/betalingsforsikring" />} layout="row" title="Betalingsforsikring" … />
|
|
24
|
+
* </ServiceCardGrid>
|
|
25
|
+
* </Section>
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* From 1024px three columns: the first card two columns wide and the second
|
|
29
|
+
* one, both 576px tall; a third card takes the row under them (320px) on its
|
|
30
|
+
* own, or the first column of it with a fourth in the other two. Below
|
|
31
|
+
* 1024px one column, each card at most 440px tall. The cards are a list.
|
|
32
|
+
*/
|
|
33
|
+
export declare function ServiceCardGrid({ render, ref, className, children, ...rest }: ServiceCardGridProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
import { SiteHeaderLink } from './site-header';
|
|
3
|
+
/**
|
|
4
|
+
* A link in the side navigation: `{ label, href }`, or `{ label, render }`
|
|
5
|
+
* with a router link carrying its own `href`. A link without either does not
|
|
6
|
+
* compile.
|
|
7
|
+
*/
|
|
8
|
+
export type SideNavItem = SiteHeaderLink & {
|
|
9
|
+
/**
|
|
10
|
+
* This page: the link is marked `aria-current="page"` and has the arrow
|
|
11
|
+
* before it.
|
|
12
|
+
*/
|
|
13
|
+
current?: boolean;
|
|
14
|
+
};
|
|
15
|
+
export type SideNavProps = Omit<ComponentProps<"div">, "children"> & {
|
|
16
|
+
/** The pages beside this one (the website's child pages), in order. */
|
|
17
|
+
items: SideNavItem[];
|
|
18
|
+
/**
|
|
19
|
+
* The name of the navigation, read out with it: the part of the site it
|
|
20
|
+
* covers ("Investor Relations"). Left out, "Sidemeny".
|
|
21
|
+
*/
|
|
22
|
+
label?: string;
|
|
23
|
+
/** The `Breadcrumbs` at the top of the content panel. */
|
|
24
|
+
breadcrumbs?: ReactNode;
|
|
25
|
+
/** The page's content, in the white panel. */
|
|
26
|
+
children: ReactNode;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* The website's two-column page (`TwoColumnLayout`, the Investor Relations
|
|
30
|
+
* pages of leabank.no): a beige sidebar of links to the pages of one part of
|
|
31
|
+
* the site, beside a white panel with the breadcrumbs and the content. Put it
|
|
32
|
+
* in a `Section` (grey, `spacingTop` and `spacingBottom` `sm`, as on the
|
|
33
|
+
* website).
|
|
34
|
+
*
|
|
35
|
+
* ```tsx
|
|
36
|
+
* <Section surface="subtle" spacingTop="sm" spacingBottom="sm">
|
|
37
|
+
* <SideNav
|
|
38
|
+
* label="Investor Relations"
|
|
39
|
+
* items={[
|
|
40
|
+
* { label: "About Lea Bank", render: <NextLink href="/om-oss/investor-relations/about-lea-bank" />, current: true },
|
|
41
|
+
* { label: "Dividend policy", render: <NextLink href="/om-oss/investor-relations/dividend-policy" /> },
|
|
42
|
+
* ]}
|
|
43
|
+
* breadcrumbs={<Breadcrumbs items={crumbs} />}
|
|
44
|
+
* >
|
|
45
|
+
* <RichText>…</RichText>
|
|
46
|
+
* </SideNav>
|
|
47
|
+
* </Section>
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* From 1024px the sidebar is 280px wide (360 from 1312px), 16 from the
|
|
51
|
+
* panel, and stays in view while the page scrolls (32 from the top); below
|
|
52
|
+
* 1024px it is a block over the panel, 32 apart. The sidebar is a `nav`
|
|
53
|
+
* named by `label`; the link to this page is marked `aria-current="page"`
|
|
54
|
+
* and has a purple arrow before it, the others underline on hover. The panel
|
|
55
|
+
* is a `Panel size="sm"`: what is in it stacks 16 apart.
|
|
56
|
+
*/
|
|
57
|
+
export declare function SideNav({ items, label, breadcrumbs, children, className, ...rest }: SideNavProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { ComponentProps, ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { SiteHeaderLink } from './site-header';
|
|
3
|
+
/**
|
|
4
|
+
* A link in the footer: `{ label, href }`, or `{ label, render }` with a
|
|
5
|
+
* router link carrying its own `href`. A link without either does not
|
|
6
|
+
* compile. A link that opens in a new tab is a `render` with `target`.
|
|
7
|
+
*/
|
|
8
|
+
export type SiteFooterLink = SiteHeaderLink;
|
|
9
|
+
/** A column of links under a title ("Tjenester", "Support", "Juridisk"). */
|
|
10
|
+
export type SiteFooterColumn = {
|
|
11
|
+
/** The title over the links, a heading (`titleRender`). */
|
|
12
|
+
title: ReactNode;
|
|
13
|
+
links: SiteFooterLink[];
|
|
14
|
+
};
|
|
15
|
+
/** A link to one of the bank's pages on a social network. */
|
|
16
|
+
export type SiteFooterSocialLink = SiteFooterLink & {
|
|
17
|
+
/**
|
|
18
|
+
* The network's logo, 24px: an `<img>` or `next/image` with `alt=""`, as
|
|
19
|
+
* the label names the link.
|
|
20
|
+
*/
|
|
21
|
+
icon: ReactNode;
|
|
22
|
+
};
|
|
23
|
+
/** The four markets, by the codes of the languages they speak. */
|
|
24
|
+
export type SiteFooterMarketCode = "no" | "se" | "fi" | "es";
|
|
25
|
+
/** The list of markets: the select that takes the visitor to another one. */
|
|
26
|
+
export type SiteFooterMarket = {
|
|
27
|
+
/** The market of this site, shown with its flag. */
|
|
28
|
+
value: SiteFooterMarketCode;
|
|
29
|
+
/**
|
|
30
|
+
* Called with the market the visitor picks. The website goes to that
|
|
31
|
+
* market's site (`https://leabank.se/`).
|
|
32
|
+
*/
|
|
33
|
+
onValueChange: (value: SiteFooterMarketCode) => void;
|
|
34
|
+
/**
|
|
35
|
+
* The markets to choose from, sorted by name in the page's language.
|
|
36
|
+
* @default ["no", "se", "fi", "es"]
|
|
37
|
+
*/
|
|
38
|
+
options?: readonly SiteFooterMarketCode[];
|
|
39
|
+
/** The title over the select, which names it. Left out, "Marked". */
|
|
40
|
+
title?: ReactNode;
|
|
41
|
+
};
|
|
42
|
+
/** The links to the bank on social networks, under a title. */
|
|
43
|
+
export type SiteFooterSocial = {
|
|
44
|
+
/** The title over the links. Left out, "Sosiale medier". */
|
|
45
|
+
title?: ReactNode;
|
|
46
|
+
links: SiteFooterSocialLink[];
|
|
47
|
+
};
|
|
48
|
+
export type SiteFooterProps = Omit<ComponentProps<"footer">, "children"> & {
|
|
49
|
+
/**
|
|
50
|
+
* The white logo, an `<img>` or `next/image`, 140px wide. It is the
|
|
51
|
+
* content of the link to the start page, named "Lea Bank, forside" as in
|
|
52
|
+
* `SiteHeader`, so the image can take `alt=""`.
|
|
53
|
+
*/
|
|
54
|
+
logo: ReactNode;
|
|
55
|
+
/**
|
|
56
|
+
* The link to the start page, a router link carrying its own `href`:
|
|
57
|
+
* `<NextLink href="/" />`.
|
|
58
|
+
* @default <a href="/" />
|
|
59
|
+
*/
|
|
60
|
+
homeRender?: ReactElement;
|
|
61
|
+
/** The columns of links, in order. */
|
|
62
|
+
columns?: SiteFooterColumn[];
|
|
63
|
+
/** The market select, at the top of the last column. */
|
|
64
|
+
market?: SiteFooterMarket;
|
|
65
|
+
/** The social links, at the foot of the last column. */
|
|
66
|
+
social?: SiteFooterSocial;
|
|
67
|
+
/**
|
|
68
|
+
* Called by the button that opens the cookie settings, which shows only
|
|
69
|
+
* with it: `openCookieSettings` from
|
|
70
|
+
* `@leabankab/component-library/cookie-consent`, or the website's own.
|
|
71
|
+
*/
|
|
72
|
+
onOpenCookieSettings?: () => void;
|
|
73
|
+
/**
|
|
74
|
+
* The line at the very end. A string becomes a `<p>`; anything else (the
|
|
75
|
+
* CMS's paragraphs) goes in a `<div>`.
|
|
76
|
+
*/
|
|
77
|
+
copyright?: ReactNode;
|
|
78
|
+
/**
|
|
79
|
+
* The element of every title in the footer.
|
|
80
|
+
* @default <h2 />
|
|
81
|
+
*/
|
|
82
|
+
titleRender?: ReactElement;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* The website's footer, as at the end of every page of leabank.no: the
|
|
86
|
+
* white logo, the columns of links, the market select and the social links
|
|
87
|
+
* on a near-black band, then a line, the cookie settings and the copyright.
|
|
88
|
+
*
|
|
89
|
+
* ```tsx
|
|
90
|
+
* <SiteFooter
|
|
91
|
+
* logo={<img src="/lea-bank-white.svg" alt="" />}
|
|
92
|
+
* homeRender={<NextLink href="/" />}
|
|
93
|
+
* columns={[
|
|
94
|
+
* {
|
|
95
|
+
* title: "Tjenester",
|
|
96
|
+
* links: [{ label: "Lån", render: <NextLink href="/lan" /> }],
|
|
97
|
+
* },
|
|
98
|
+
* ]}
|
|
99
|
+
* market={{ value: "no", onValueChange: (market) => location.assign(sites[market]) }}
|
|
100
|
+
* social={{
|
|
101
|
+
* links: [
|
|
102
|
+
* {
|
|
103
|
+
* label: "Facebook",
|
|
104
|
+
* icon: <img src="/facebook.svg" alt="" />,
|
|
105
|
+
* render: <a href="https://www.facebook.com/leabank" target="_blank" rel="noopener noreferrer" />,
|
|
106
|
+
* },
|
|
107
|
+
* ],
|
|
108
|
+
* }}
|
|
109
|
+
* onOpenCookieSettings={openCookieSettings}
|
|
110
|
+
* copyright="Copyright © 2005–2026 Lea Bank AB NUF (publ)."
|
|
111
|
+
* />
|
|
112
|
+
* ```
|
|
113
|
+
*
|
|
114
|
+
* The columns share the width, as many 140px columns as fit beside the logo
|
|
115
|
+
* from 1024px (five at 1440px), under it below; two columns below 768px and
|
|
116
|
+
* one below 640px. The market select is Paloma's `Select` at `size="sm"`,
|
|
117
|
+
* each market with its flag, named by the title over it; picking a market
|
|
118
|
+
* calls `onValueChange` and goes nowhere by itself. `market.onValueChange`
|
|
119
|
+
* and `onOpenCookieSettings` are functions, so a server component renders
|
|
120
|
+
* the footer through a client component of its own.
|
|
121
|
+
*/
|
|
122
|
+
export declare function SiteFooter({ logo, homeRender, columns, market, social, onOpenCookieSettings, copyright, titleRender, className, ...rest }: SiteFooterProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ComponentProps, ReactElement } from 'react';
|
|
2
|
+
import { SiteHeaderGroup, SiteHeaderItem } from './site-header';
|
|
3
|
+
/**
|
|
4
|
+
* Internal to `SiteHeader`: a link to `href`, or the router link in
|
|
5
|
+
* `render`, which carries its own.
|
|
6
|
+
*/
|
|
7
|
+
export declare function SiteLink({ href, render, ...rest }: Omit<ComponentProps<"a">, "href"> & {
|
|
8
|
+
href?: string;
|
|
9
|
+
render?: ReactElement;
|
|
10
|
+
}): ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
|
|
11
|
+
/** Whether an item opens a menu: it has a group to show. */
|
|
12
|
+
export declare const hasMenu: (item: SiteHeaderItem) => item is Extract<SiteHeaderItem, {
|
|
13
|
+
groups: SiteHeaderGroup[];
|
|
14
|
+
}>;
|
|
15
|
+
/** Whether an item has a page of its own to link to. */
|
|
16
|
+
export declare const hasPage: (item: SiteHeaderItem) => boolean;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { SiteHeaderItem } from './site-header';
|
|
3
|
+
type SiteHeaderMenuProps = {
|
|
4
|
+
items: SiteHeaderItem[];
|
|
5
|
+
/** The link around the logo, shown in the menu's own bar too. */
|
|
6
|
+
home: ReactNode;
|
|
7
|
+
/** The account link, shown in the menu's own bar too. */
|
|
8
|
+
account: ReactNode;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Internal to `SiteHeader`: the menu below 1312px. The button in the bar
|
|
12
|
+
* opens a dialog that drops in from the top (Base UI's `Drawer`): focus
|
|
13
|
+
* moves into it and stays there, the page behind it does not scroll, and
|
|
14
|
+
* Escape, the close button, a swipe up or a press outside closes it. The
|
|
15
|
+
* dialog starts with a bar of its own, the bar of the header with a close
|
|
16
|
+
* button where the menu button was, so the visitor sees the same bar and
|
|
17
|
+
* always has a visible way out. Its links are not in the page while it is
|
|
18
|
+
* closed, and following one closes it.
|
|
19
|
+
*/
|
|
20
|
+
export declare function SiteHeaderMenu({ items, home, account }: SiteHeaderMenuProps): import("react").JSX.Element;
|
|
21
|
+
export {};
|