@leabankab/component-library 8.7.0 → 8.8.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/component-library.es.js +27 -26
  3. package/dist/component-library.es.js.map +1 -1
  4. package/dist/component-library.umd.js +2 -2
  5. package/dist/component-library.umd.js.map +1 -1
  6. package/dist/components/form/slider.d.ts +15 -2
  7. package/dist/index.css +1 -1
  8. package/dist/website/brand-letters.d.ts +40 -0
  9. package/dist/website/calculator.d.ts +58 -0
  10. package/dist/website/carousel.d.ts +55 -0
  11. package/dist/website/cta-banner.d.ts +42 -0
  12. package/dist/website/expanding-cards-context.d.ts +8 -0
  13. package/dist/website/expanding-cards-item.d.ts +69 -0
  14. package/dist/website/expanding-cards.d.ts +48 -0
  15. package/dist/website/hero-service-grid.d.ts +52 -0
  16. package/dist/website/hero.d.ts +57 -0
  17. package/dist/website/index.d.ts +33 -0
  18. package/dist/website/navigation-grid.d.ts +39 -0
  19. package/dist/website/paragraphs.d.ts +11 -0
  20. package/dist/website/partner-list.d.ts +79 -0
  21. package/dist/website/payment-feature.d.ts +85 -0
  22. package/dist/website/promo-grid.d.ts +71 -0
  23. package/dist/website/section-header.d.ts +53 -0
  24. package/dist/website/section.d.ts +53 -0
  25. package/dist/website/service-card-grid.d.ts +33 -0
  26. package/dist/website/split-content.d.ts +69 -0
  27. package/dist/website/stats.d.ts +52 -0
  28. package/dist/website/testimonials.d.ts +100 -0
  29. package/dist/website/use-brand-letters-labels.d.ts +2 -0
  30. package/dist/website/use-carousel-labels.d.ts +6 -0
  31. package/dist/website/use-carousel.d.ts +50 -0
  32. package/dist/website/use-partner-list-labels.d.ts +6 -0
  33. package/dist/website/use-testimonials-labels.d.ts +6 -0
  34. package/dist/website.cjs +2 -0
  35. package/dist/website.cjs.map +1 -0
  36. package/dist/website.css +1 -0
  37. package/dist/website.mjs +1226 -0
  38. package/dist/website.mjs.map +1 -0
  39. package/package.json +7 -2
@@ -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,69 @@
1
+ import { useRender } from '@base-ui/react/use-render';
2
+ import { ReactElement, ReactNode, Ref } from 'react';
3
+ export type SplitContentImagePosition = "start" | "end";
4
+ /** `alt` is required with a photo, `""` when it is decoration. */
5
+ type SplitContentImage = {
6
+ /** The photo. Without one, the text takes the whole width. */
7
+ src: string;
8
+ /**
9
+ * What the photo shows, for screen readers; `""` when it is decoration
10
+ * and the text says it all.
11
+ */
12
+ alt: string;
13
+ /**
14
+ * The image element to render instead of the plain `<img>`, such as
15
+ * `next/image`, or an `<img loading="lazy">`. Its own props win over
16
+ * `src` and `alt`.
17
+ */
18
+ imageRender?: ReactElement;
19
+ } | {
20
+ src?: undefined;
21
+ alt?: undefined;
22
+ imageRender?: undefined;
23
+ };
24
+ export type SplitContentProps = Omit<useRender.ComponentProps<"div">, "ref" | "title" | "children"> & SplitContentImage & {
25
+ /** The rendered element: the `<div>`, or the element passed to `render`. */
26
+ ref?: Ref<HTMLElement>;
27
+ /** The title. */
28
+ title: ReactNode;
29
+ /** The element for the title, an `<h2>` by default: `titleRender={<h3 />}`. */
30
+ titleRender?: ReactElement;
31
+ /**
32
+ * The text under the title. A string becomes one paragraph; pass `<p>`
33
+ * elements for several.
34
+ */
35
+ text?: ReactNode;
36
+ /**
37
+ * Where the photo sits: `"start"` before the text (on the left, or on
38
+ * top below 1024px), `"end"` after it.
39
+ * @default "end"
40
+ */
41
+ imagePosition?: SplitContentImagePosition;
42
+ /** The call to action under both columns: an `ActionButton`. */
43
+ action?: ReactNode;
44
+ /** The price example under the action, in the small print. */
45
+ priceExample?: ReactNode;
46
+ };
47
+ /**
48
+ * Text beside a photo, on the section's own colour: a title and a text in one
49
+ * column, a photo without corners in the other, and the call to action
50
+ * centred under both.
51
+ *
52
+ * ```tsx
53
+ * <Section surface="subtle">
54
+ * <SplitContent
55
+ * title="Refinansier dyre smålån"
56
+ * text="Samle kredittkortgjeld og smålån i ett lån med én månedlig betaling."
57
+ * src="/bilder/par.jpg"
58
+ * alt=""
59
+ * action={<ActionButton render={<NextLink href="/refinansiering" />}>Søk om refinansiering</ActionButton>}
60
+ * />
61
+ * </Section>
62
+ * ```
63
+ *
64
+ * Two equal columns 64px apart from 1024px, the photo at most 560px wide at
65
+ * the end of its column; one column below, the photo at most 440px and
66
+ * the action at the start. It takes the text colour of its section.
67
+ */
68
+ export declare function SplitContent({ title, titleRender, text, src, alt, imageRender, imagePosition, action, priceExample, render, ref, className, ...rest }: SplitContentProps): ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
69
+ export {};
@@ -0,0 +1,52 @@
1
+ import { useRender } from '@base-ui/react/use-render';
2
+ import { ReactElement, ReactNode, Ref } from 'react';
3
+ /** One number, with what it stands for. */
4
+ export type StatsItem = {
5
+ /** The big number: a figure, or the step of a process. */
6
+ number: ReactNode;
7
+ /** What the number is. */
8
+ title?: ReactNode;
9
+ /** A line about it, under the title. */
10
+ text?: ReactNode;
11
+ };
12
+ export type StatsProps = Omit<useRender.ComponentProps<"div">, "ref" | "children"> & {
13
+ /** The rendered element: the `<div>`, or the element passed to `render`. */
14
+ ref?: Ref<HTMLElement>;
15
+ /** The heading above the numbers: a `SectionHeader`. */
16
+ header?: ReactNode;
17
+ /** The numbers, in a row from 1024px. Two to four fit the website's row. */
18
+ items: readonly StatsItem[];
19
+ /**
20
+ * The element for the title of each number, an `<h3>` by default, as the
21
+ * titles sit under the section's `<h2>`: `titleRender={<p />}` where they
22
+ * should not be headings.
23
+ */
24
+ titleRender?: ReactElement;
25
+ /** The call to action under the numbers: an `ActionButton`. */
26
+ action?: ReactNode;
27
+ /** The price example under the action, in the small print. */
28
+ priceExample?: ReactNode;
29
+ };
30
+ /**
31
+ * A row of big numbers with a line on each side, each with a title and a
32
+ * line of text, as the four steps of "Slik fungerer det" on leabank.no's
33
+ * loan pages. The numbers are a list.
34
+ *
35
+ * ```tsx
36
+ * <Section>
37
+ * <Stats
38
+ * header={<SectionHeader eyebrow="Søk uforpliktende" title="Slik fungerer det" />}
39
+ * items={[
40
+ * { number: "1", title: "Fyll inn søknaden", text: "Tar ca. 3 minutter." },
41
+ * { number: "2", title: "Send inn søknad", text: "…" },
42
+ * ]}
43
+ * />
44
+ * </Section>
45
+ * ```
46
+ *
47
+ * From 1024px the numbers are 224px, at least 200px wide each, with rounded
48
+ * bars filling the space between and around them; below 1024px they are
49
+ * 160px in a row without bars, and below 768px 128px in a column. The bars
50
+ * and the text follow the section's text colour.
51
+ */
52
+ export declare function Stats({ header, items, titleRender, action, priceExample, render, ref, className, ...rest }: StatsProps): ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
@@ -0,0 +1,100 @@
1
+ import { useRender } from '@base-ui/react/use-render';
2
+ import { ReactElement, ReactNode, Ref } from 'react';
3
+ export type TestimonialsVideoPosition = "start" | "end";
4
+ /** The video's other props only make sense with a video. */
5
+ type TestimonialsVideo = {
6
+ /**
7
+ * A video of the featured customer, shown as a square still with a
8
+ * play button that opens it in a dialog, with sound and controls.
9
+ */
10
+ videoSrc: string;
11
+ /**
12
+ * The still to show. Left out, the video's first frame is shown, which
13
+ * loads the start of the video with the page.
14
+ */
15
+ videoPoster?: string;
16
+ /**
17
+ * Captions for the video, a WebVTT file in the `LeaProvider` language.
18
+ * A video in which people speak needs them.
19
+ */
20
+ videoCaptions?: string;
21
+ /**
22
+ * Where the video sits from 768px: `"start"` (on the left of the quote)
23
+ * or `"end"`. Below 768px it is always above the quote.
24
+ * @default "start"
25
+ */
26
+ videoPosition?: TestimonialsVideoPosition;
27
+ } | {
28
+ videoSrc?: undefined;
29
+ videoPoster?: undefined;
30
+ videoCaptions?: undefined;
31
+ videoPosition?: undefined;
32
+ };
33
+ /** A subtitle goes under a title. */
34
+ type TestimonialsHeader = {
35
+ /** The title of the section. It also names the carousel. */
36
+ title: ReactNode;
37
+ /**
38
+ * The element for the title, an `<h2>` by default, as on
39
+ * `SectionHeader`.
40
+ */
41
+ titleRender?: ReactElement;
42
+ /** The text under the title. */
43
+ subtitle?: ReactNode;
44
+ } | {
45
+ title?: undefined;
46
+ titleRender?: undefined;
47
+ subtitle?: undefined;
48
+ };
49
+ export type TestimonialsProps = Omit<useRender.ComponentProps<"div">, "ref" | "title" | "children"> & TestimonialsHeader & TestimonialsVideo & {
50
+ /** The rendered element: the `<div>`, or the element passed to `render`. */
51
+ ref?: Ref<HTMLElement>;
52
+ /**
53
+ * What the featured customer said, without quotation marks: the section
54
+ * adds them. Shown large beside the video. A string becomes one
55
+ * paragraph; pass `<p>` elements for several.
56
+ */
57
+ quote?: ReactNode;
58
+ /** Who said the featured quote. */
59
+ name?: ReactNode;
60
+ /** A line under the name, such as the position and the company. */
61
+ meta?: ReactNode;
62
+ /** Stars above the featured quote, from 0 to 5. Left out, no stars. */
63
+ rating?: number;
64
+ /** The reviews in the carousel: `TestimonialCard`s. */
65
+ children?: ReactNode;
66
+ };
67
+ /**
68
+ * The website's block of customer reviews: a centred title, a featured
69
+ * customer with a video, and a carousel of `TestimonialCard`s, as on the home
70
+ * page of leabank.no.
71
+ *
72
+ * ```tsx
73
+ * <Section surface="subtle">
74
+ * <Testimonials
75
+ * title="Kundeanmeldelser"
76
+ * subtitle="Se hva andre synes om oss"
77
+ * rating={5}
78
+ * quote="Lea Bank gjorde det enkelt å samle lånene mine."
79
+ * name="Marte Olsen"
80
+ * meta="Kunde, Oslo"
81
+ * videoSrc="/video/marte.mp4"
82
+ * videoPoster="/video/marte.jpg"
83
+ * >
84
+ * <TestimonialCard rating={5} quote="…" name="Kari Nordmann" meta="Kunde, bytt.no" />
85
+ * <TestimonialCard rating={5} quote="…" name="Ola Hansen" meta="Kunde, bytt.no" />
86
+ * </Testimonials>
87
+ * </Section>
88
+ * ```
89
+ *
90
+ * The parts are 64px apart. From 768px the video (a square with 64px
91
+ * corners, dimmed under its play button) and the featured quote share the
92
+ * width, 64px apart; below 768px the video is on top. The play button,
93
+ * named "Spill av video", opens the video in a dialog with its controls and
94
+ * captions, and the focus comes back to it when the dialog closes. The
95
+ * reviews are a `Carousel`, named by the title (or "Kundeomtaler" without
96
+ * one). It takes the text colour of its section; the carousel's controls
97
+ * are made for the light surfaces.
98
+ */
99
+ export declare function Testimonials({ title, titleRender, subtitle, quote, name, meta, rating, videoSrc, videoPoster, videoCaptions, videoPosition, render, ref, className, children, ...rest }: TestimonialsProps): ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
100
+ export {};
@@ -0,0 +1,2 @@
1
+ /** The names of `BrandLetters`' button, for paused and playing videos. */
2
+ export declare const useBrandLettersLabels: () => Record<"play" | "pause", string>;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The words of `Carousel`. `carousel` describes the region to screen readers
3
+ * (`aria-roledescription`); `{page}` and `{count}` in `status` are replaced
4
+ * with the page shown and the number of pages.
5
+ */
6
+ export declare const useCarouselLabels: () => Record<"status" | "next" | "previous" | "carousel", string>;
@@ -0,0 +1,50 @@
1
+ import { RefObject } from 'react';
2
+ export type CarouselState = {
3
+ /** How many places the track can stop at: one per slide that can start it. */
4
+ pageCount: number;
5
+ /** The place the track is nearest to now, from 0. */
6
+ page: number;
7
+ /** The place the track came to rest at, from 0: what is announced. */
8
+ settledPage: number;
9
+ /** Whether the track is at its start, so nothing lies before the view. */
10
+ atStart: boolean;
11
+ /** Whether the track is at its end, so nothing lies after the view. */
12
+ atEnd: boolean;
13
+ /** Whether the slides are wider than the track, so it scrolls. */
14
+ overflowing: boolean;
15
+ /**
16
+ * Whether the track has moved since it was shown, so that the place it
17
+ * shows first is not announced on load.
18
+ */
19
+ moved: boolean;
20
+ };
21
+ /**
22
+ * The state of a scroll-snap track, for `Carousel`: the places it can stop at
23
+ * (a slide's start, or the end of the track for the last slides, which never
24
+ * reach the start), the one it is at, and `goTo` to scroll to another. The
25
+ * browser does the scrolling and the swiping; this only measures. Internal.
26
+ *
27
+ * Before it has measured (on the server, and in the first render), it
28
+ * assumes the website's 2.2 slides from 1024px: one place per slide but the
29
+ * last.
30
+ */
31
+ export declare function useCarousel(trackRef: RefObject<HTMLElement | null>, slideCount: number): {
32
+ goTo: (page: number) => void;
33
+ /** How many places the track can stop at: one per slide that can start it. */
34
+ pageCount: number;
35
+ /** The place the track is nearest to now, from 0. */
36
+ page: number;
37
+ /** The place the track came to rest at, from 0: what is announced. */
38
+ settledPage: number;
39
+ /** Whether the track is at its start, so nothing lies before the view. */
40
+ atStart: boolean;
41
+ /** Whether the track is at its end, so nothing lies after the view. */
42
+ atEnd: boolean;
43
+ /** Whether the slides are wider than the track, so it scrolls. */
44
+ overflowing: boolean;
45
+ /**
46
+ * Whether the track has moved since it was shown, so that the place it
47
+ * shows first is not announced on load.
48
+ */
49
+ moved: boolean;
50
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The words of `PartnerList`'s controls. `{page}` and `{count}` are replaced
3
+ * with the page number and the number of pages. `collation` is the language
4
+ * the partners are sorted in, as a BCP 47 tag for `Intl.Collator`.
5
+ */
6
+ export declare const usePartnerListLabels: () => Record<"status" | "next" | "previous" | "collation", string>;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The words of `Testimonials`: the carousel's name when the section has no
3
+ * title, the video button and dialog, and the language of the captions
4
+ * (`captionsLanguage`, a BCP 47 tag for the `<track>`, and its name).
5
+ */
6
+ export declare const useTestimonialsLabels: () => Record<"video" | "close" | "play" | "reviews" | "captionsLanguage" | "captionsLabel", string>;
@@ -0,0 +1,2 @@
1
+ "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});require('./website.css');let e=require("@base-ui/react/use-render"),t=require("lucide-react"),n=require("react"),r=require("./component-library.umd.js"),i=require("react/jsx-runtime");var a=(e,t)=>n=>[e,typeof t==`function`?t(n):t].filter(Boolean).join(` `),o={BrandLetters:`_BrandLetters_1ygg1_9`,Letters:`_Letters_1ygg1_17`,Letter:`_Letter_1ygg1_17`,Video:`_Video_1ygg1_48`},s=(0,r.createTranslation)({play:{no:`Spill av videoene`,se:`Spela upp videorna`,fi:`Toista videot`,es:`Reproducir los vídeos`},pause:{no:`Sett videoene på pause`,se:`Pausa videorna`,fi:`Keskeytä videot`,es:`Pausar los vídeos`}}),c=`(prefers-reduced-motion: reduce)`,l=[`L`,`E`,`A`];function u({videos:u,render:d,ref:f,className:p,...m}){let h=s(),g=(0,n.useRef)([]),[_,v]=(0,n.useState)(!1),y=e=>{for(let t of g.current)t&&e(t)},b=e=>{e.muted=!0,e.play().catch(()=>{})};(0,n.useEffect)(()=>{let e=window.matchMedia(c);e.matches||y(b);let t=e=>{e.matches&&y(e=>e.pause())};return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)},[]);let x=()=>v(g.current.some(e=>e!=null&&!e.paused)),S=()=>{y(_?e=>e.pause():b)};return(0,e.useRender)({render:d,ref:f,defaultTagName:`div`,props:{...m,className:a(o.BrandLetters,p)({}),children:(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(`div`,{className:o.Letters,children:l.map((e,t)=>(0,i.jsx)(`div`,{className:o.Letter,"data-letter":e,children:(0,i.jsx)(`video`,{ref:e=>{g.current[t]=e},className:o.Video,src:u[t].src,poster:u[t].poster,muted:!0,loop:!0,playsInline:!0,"aria-hidden":!0,onPlay:x,onPause:x})},e))}),(0,i.jsx)(r.IconButton,{variant:`elevated`,color:`secondary`,"aria-label":_?h.pause:h.play,onClick:S,children:_?(0,i.jsx)(t.Pause,{"aria-hidden":!0}):(0,i.jsx)(t.Play,{"aria-hidden":!0})})]})}})}var d={Calculator:`_Calculator_1mamd_12`,Body:`_Body_1mamd_26`,Panel:`_Panel_1mamd_41`,Summary:`_Summary_1mamd_55`,Results:`_Results_1mamd_64`,Result:`_Result_1mamd_64`,Label:`_Label_1mamd_77`,Value:`_Value_1mamd_78`,Actions:`_Actions_1mamd_95`,Price:`_Price_1mamd_103`};function f({header:t,results:n,action:r,priceExample:o,render:s,ref:c,className:l,children:u,...f}){return(0,e.useRender)({render:s,ref:c,defaultTagName:`div`,props:{...f,className:a(d.Calculator,l)({}),children:(0,i.jsxs)(i.Fragment,{children:[t,(0,i.jsxs)(`div`,{className:d.Body,children:[(0,i.jsx)(`div`,{className:d.Panel,children:u}),(0,i.jsxs)(`div`,{className:d.Summary,children:[n.length>0&&(0,i.jsx)(`dl`,{className:d.Results,"aria-live":`polite`,children:n.map((e,t)=>(0,i.jsxs)(`div`,{className:d.Result,children:[(0,i.jsx)(`dt`,{className:d.Label,children:e.label}),(0,i.jsx)(`dd`,{className:d.Value,children:e.value})]},t))}),(r!=null||o!=null)&&(0,i.jsxs)(`div`,{className:d.Actions,children:[r,o!=null&&(0,i.jsx)(`p`,{className:d.Price,children:o})]})]})]})]})}})}var p={Carousel:`_Carousel_17a24_14`,Viewport:`_Viewport_17a24_31`,Track:`_Track_17a24_66`,Slide:`_Slide_17a24_94`,Controls:`_Controls_17a24_100`,VisuallyHidden:`_VisuallyHidden_17a24_109`},m=`(prefers-reduced-motion: reduce)`,h=150;function g(e,t){let r=(0,n.useRef)([0]),i=(0,n.useRef)(void 0),[a,o]=(0,n.useState)(()=>({pageCount:Math.max(1,t-1),page:0,settledPage:0,atStart:!0,atEnd:t<=2,overflowing:t>2,moved:!1})),s=(0,n.useCallback)((t,n=!1)=>{let i=e.current;if(!i)return;let a=i.scrollLeft,s=Math.max(0,i.scrollWidth-i.clientWidth),c=r.current,l=0;for(let e=1;e<c.length;e+=1)Math.abs(c[e]-a)<Math.abs(c[l]-a)&&(l=e);o(e=>{let r={pageCount:c.length,page:l,settledPage:t?l:e.settledPage,atStart:a<=1,atEnd:a>=s-1,overflowing:s>1,moved:e.moved||n};return Object.keys(r).every(t=>r[t]===e[t])?e:r})},[e]),c=(0,n.useCallback)(()=>{let t=e.current;if(!t)return;let n=Math.max(0,t.scrollWidth-t.clientWidth),i=Array.from(t.children),a=i[0]?.offsetLeft??0,o=[];for(let e of i){let t=Math.min(Math.max(0,e.offsetLeft-a),n);(o.length===0||t-o[o.length-1]>1)&&o.push(t)}r.current=o.length>0?o:[0],s(!0)},[s,e]);(0,n.useEffect)(()=>{let t=e.current;if(!t)return;c();let n=()=>{s(!1,!0),clearTimeout(i.current),i.current=setTimeout(()=>s(!0),h)},r=new ResizeObserver(c);return t.addEventListener(`scroll`,n,{passive:!0}),r.observe(t),()=>{t.removeEventListener(`scroll`,n),r.disconnect(),clearTimeout(i.current)}},[c,s,t,e]);let l=(0,n.useCallback)(t=>{let n=e.current;if(!n)return;let i=r.current,a=Math.min(i.length-1,Math.max(0,t)),o=!window.matchMedia(m).matches;n.scrollTo({left:i[a],behavior:o?`smooth`:`auto`})},[e]);return{...a,goTo:l}}var _=(0,r.createTranslation)({carousel:{no:`karusell`,se:`karusell`,fi:`karuselli`,es:`carrusel`},previous:{no:`Forrige`,se:`Föregående`,fi:`Edellinen`,es:`Anterior`},next:{no:`Neste`,se:`Nästa`,fi:`Seuraava`,es:`Siguiente`},status:{no:`Side {page} av {count}`,se:`Sida {page} av {count}`,fi:`Sivu {page}/{count}`,es:`Página {page} de {count}`}});function v({getItemLabel:o,render:s,ref:c,className:l,children:u,...d}){let f=_(),m=(0,n.useRef)(null),h=n.Children.toArray(u),{pageCount:v,page:y,settledPage:b,atStart:x,atEnd:S,overflowing:C,moved:w,goTo:T}=g(m,h.length);return(0,e.useRender)({render:s,ref:c,defaultTagName:`div`,props:{role:`region`,"aria-roledescription":f.carousel,...d,className:a(p.Carousel,l)({}),children:(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(`div`,{className:p.Viewport,"data-at-start":x||void 0,"data-at-end":S||void 0,children:(0,i.jsx)(`ul`,{ref:m,className:p.Track,tabIndex:C?0:void 0,children:h.map((e,t)=>(0,i.jsx)(`li`,{className:p.Slide,children:e},t))})}),v>1&&(0,i.jsxs)(`div`,{className:p.Controls,children:[(0,i.jsx)(r.IconButton,{variant:`elevated`,color:`secondary`,"aria-label":f.previous,disabled:y===0,focusableWhenDisabled:!0,onClick:()=>T(y-1),children:(0,i.jsx)(t.ChevronLeft,{"aria-hidden":!0})}),(0,i.jsx)(r.PaginationDots,{count:v,value:y+1,onValueChange:e=>T(e-1),getItemLabel:o}),(0,i.jsx)(r.IconButton,{variant:`elevated`,color:`secondary`,"aria-label":f.next,disabled:y===v-1,focusableWhenDisabled:!0,onClick:()=>T(y+1),children:(0,i.jsx)(t.ChevronRight,{"aria-hidden":!0})}),(0,i.jsx)(`span`,{role:`status`,className:p.VisuallyHidden,children:w&&f.status.replace(`{page}`,String(b+1)).replace(`{count}`,String(v))})]})]})}})}var y={CtaBanner:`_CtaBanner_vkp5c_7`,Title:`_Title_vkp5c_15`,Content:`_Content_vkp5c_24`,Text:`_Text_vkp5c_32`,Action:`_Action_vkp5c_48`,Price:`_Price_vkp5c_53`};function b({className:e,id:t,children:n}){return typeof n==`string`||typeof n==`number`?(0,i.jsx)(`p`,{className:e,id:t,children:n}):(0,i.jsx)(`div`,{className:e,id:t,children:n})}function x({title:t,titleRender:n,text:r,action:o,priceExample:s,render:c,ref:l,className:u,...d}){let f=(0,e.useRender)({render:n,defaultTagName:`h2`,props:{className:y.Title,children:t}}),p=r!=null||o!=null||s!=null;return(0,e.useRender)({render:c,ref:l,defaultTagName:`div`,props:{...d,"data-has-content":p||void 0,className:a(y.CtaBanner,u)({}),children:(0,i.jsxs)(i.Fragment,{children:[f,p&&(0,i.jsxs)(`div`,{className:y.Content,children:[r!=null&&(0,i.jsx)(b,{className:y.Text,children:r}),o!=null&&(0,i.jsx)(`div`,{className:y.Action,children:o}),s!=null&&(0,i.jsx)(`p`,{className:y.Price,children:s})]})]})}})}var S=(0,n.createContext)({open:!0}),C={ExpandingCards:`_ExpandingCards_14pq8_19`,List:`_List_14pq8_23`,Item:`_Item_14pq8_32`},w=`(min-width: 1312px)`,T={open:!0},E={open:!1},D=e=>{let t=window.matchMedia(w);return t.addEventListener(`change`,e),()=>t.removeEventListener(`change`,e)},ee=()=>(0,n.useSyncExternalStore)(D,()=>window.matchMedia(w).matches,()=>!0);function te({defaultOpen:t=`first`,render:r,ref:o,className:s,children:c,...l}){let u=n.Children.toArray(c),d=ee(),[f,p]=(0,n.useState)(()=>t===`last`?Math.max(0,u.length-1):0);return(0,e.useRender)({render:r,ref:o,defaultTagName:`div`,props:{...l,className:a(C.ExpandingCards,s)({}),children:(0,i.jsx)(`ul`,{className:C.List,style:{"--expanding-cards-count":u.length},children:u.map((e,t)=>(0,i.jsx)(`li`,{className:C.Item,"data-open":t===f||void 0,onPointerEnter:()=>p(t),onFocus:()=>p(t),children:(0,i.jsx)(S.Provider,{value:!d||t===f?T:E,children:e})},t))})}})}var O={ExpandingCardsItem:`_ExpandingCardsItem_1v7ai_17`,Content:`_Content_1v7ai_53`,Title:`_Title_1v7ai_70`,Text:`_Text_1v7ai_81`,Action:`_Action_1v7ai_99`,Photo:`_Photo_1v7ai_110`,Image:`_Image_1v7ai_117`};function k({title:t,titleRender:o,text:s,action:c,src:l,alt:u,imageRender:d,surface:f=`base`,render:p,ref:m,className:h,...g}){let{open:_}=(0,n.useContext)(S),v=(0,e.useRender)({render:o,defaultTagName:`h2`,props:{className:O.Title,children:t}}),y=(0,e.useRender)({enabled:l!=null,render:d,defaultTagName:`img`,props:{src:l,alt:u,className:O.Image}}),x=(0,n.isValidElement)(c)&&c.type===r.ActionButton?(0,n.cloneElement)(c,{iconOnly:!_}):c;return(0,e.useRender)({render:p,ref:m,defaultTagName:`div`,props:{...g,"data-surface":f,"data-open":_||void 0,"data-image":l!=null||void 0,className:a(O.ExpandingCardsItem,h)({}),children:(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(`div`,{className:O.Content,children:[v,s!=null&&(0,i.jsx)(b,{className:O.Text,children:s}),c!=null&&(0,i.jsx)(`div`,{className:O.Action,children:x})]}),y!=null&&(0,i.jsx)(`div`,{className:O.Photo,children:y})]})}})}var A={Hero:`_Hero_1ik22_8`,Background:`_Background_1ik22_24`,Image:`_Image_1ik22_30`,Container:`_Container_1ik22_37`,Box:`_Box_1ik22_45`,Title:`_Title_1ik22_50`,Text:`_Text_1ik22_59`,Action:`_Action_1ik22_75`,Price:`_Price_1ik22_80`};function j({src:t,alt:n,imageRender:o,title:s,titleRender:c,text:l,action:u,priceExample:d,render:f,ref:p,className:m,...h}){let g=(0,e.useRender)({render:c,defaultTagName:`h1`,props:{className:A.Title,children:s}}),_=(0,e.useRender)({render:o,defaultTagName:`img`,props:{src:t,alt:n,className:A.Image}});return(0,e.useRender)({render:f,ref:p,defaultTagName:`section`,props:{...h,className:a(A.Hero,m)({}),children:(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(`div`,{className:A.Container,children:(0,i.jsxs)(r.Panel,{className:A.Box,children:[g,l!=null&&(0,i.jsx)(b,{className:A.Text,children:l}),u!=null&&(0,i.jsx)(`div`,{className:A.Action,children:u}),d!=null&&(0,i.jsx)(`p`,{className:A.Price,children:d})]})}),(0,i.jsx)(`div`,{className:A.Background,children:_})]})}})}var M={HeroServiceGrid:`_HeroServiceGrid_yr3eo_8`,Cards:`_Cards_yr3eo_15`,Item:`_Item_yr3eo_26`,Featured:`_Featured_yr3eo_51`};function N({src:t,alt:o,imageRender:s,action:c,imagePosition:l=`start`,render:u,ref:d,className:f,children:p,...m}){let h=n.Children.toArray(p);return(0,e.useRender)({render:u,ref:d,defaultTagName:`div`,props:{...m,"data-image-position":l,className:a(M.HeroServiceGrid,f)({}),children:(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(r.FeaturedImage,{className:M.Featured,src:t,alt:o,imageRender:s,action:c}),h.length>0&&(0,i.jsx)(`ul`,{className:M.Cards,children:h.map((e,t)=>(0,i.jsx)(`li`,{className:M.Item,children:e},t))})]})}})}var P={NavigationGrid:`_NavigationGrid_ocatr_9`,Title:`_Title_ocatr_16`,List:`_List_ocatr_25`,Item:`_Item_ocatr_35`};function F({title:t,titleRender:r,render:o,ref:s,className:c,children:l,...u}){let d=n.Children.toArray(l),f=d.length>=3&&d.length%2==1,p=(0,e.useRender)({enabled:t!=null,render:r,defaultTagName:`h2`,props:{className:P.Title,children:t}});return(0,e.useRender)({render:o,ref:s,defaultTagName:`div`,props:{...u,className:a(P.NavigationGrid,c)({}),children:(0,i.jsxs)(i.Fragment,{children:[p,(0,i.jsx)(`ul`,{className:P.List,"data-odd":f||void 0,children:d.map((e,t)=>(0,i.jsx)(`li`,{className:P.Item,children:e},t))})]})}})}var I={PartnerList:`_PartnerList_9o9wx_7`,List:`_List_9o9wx_11`,Controls:`_Controls_9o9wx_19`,VisuallyHidden:`_VisuallyHidden_9o9wx_29`},L=(0,r.createTranslation)({previous:{no:`Forrige side`,se:`Föregående sida`,fi:`Edellinen sivu`,es:`Página anterior`},next:{no:`Neste side`,se:`Nästa sida`,fi:`Seuraava sivu`,es:`Página siguiente`},status:{no:`Side {page} av {count}`,se:`Sida {page} av {count}`,fi:`Sivu {page}/{count}`,es:`Página {page} de {count}`},collation:{no:`nb`,se:`sv`,fi:`fi`,es:`es`}});function R({items:o,pageSize:s=9,value:c,defaultValue:l=1,onValueChange:u,render:d,ref:f,className:p,...m}){let h=L(),[g,_]=(0,n.useState)(l),v=(0,n.useMemo)(()=>{let e=new Intl.Collator(h.collation,{sensitivity:`base`});return[...o].sort((t,n)=>e.compare(t.name,n.name))},[o,h.collation]),y=Math.max(1,Math.floor(s)),b=Math.max(1,Math.ceil(v.length/y)),x=Math.min(b,Math.max(1,c??g)),S=(x-1)*y,C=e=>{let t=Math.min(b,Math.max(1,e));c===void 0&&_(t),t!==x&&u?.(t)};return(0,e.useRender)({enabled:v.length>0,render:d,ref:f,defaultTagName:`div`,props:{...m,className:a(I.PartnerList,p)({}),children:(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(`ul`,{className:I.List,children:v.slice(S,S+y).map(({name:e,content:t,...n},a)=>(0,i.jsx)(r.PartnerRow,{...n,render:(0,i.jsx)(`li`,{}),children:t},`${S+a}-${e}`))}),b>1&&(0,i.jsxs)(`div`,{className:I.Controls,children:[(0,i.jsx)(r.IconButton,{variant:`elevated`,color:`secondary`,"aria-label":h.previous,disabled:x===1,focusableWhenDisabled:!0,onClick:()=>C(x-1),children:(0,i.jsx)(t.ChevronLeft,{"aria-hidden":!0})}),(0,i.jsx)(r.PaginationDots,{count:b,value:x,onValueChange:C}),(0,i.jsx)(r.IconButton,{variant:`elevated`,color:`secondary`,"aria-label":h.next,disabled:x===b,focusableWhenDisabled:!0,onClick:()=>C(x+1),children:(0,i.jsx)(t.ChevronRight,{"aria-hidden":!0})}),(0,i.jsx)(`span`,{role:`status`,className:I.VisuallyHidden,children:h.status.replace(`{page}`,String(x)).replace(`{count}`,String(b))})]})]})}})}var z={Grid:`_Grid_1vukg_10`,Content:`_Content_1vukg_17`,Logos:`_Logos_1vukg_28`,LogoItem:`_LogoItem_1vukg_38`,Logo:`_Logo_1vukg_28`,Text:`_Text_1vukg_60`,Title:`_Title_1vukg_66`,Description:`_Description_1vukg_75`,Actions:`_Actions_1vukg_91`,Price:`_Price_1vukg_98`,Media:`_Media_1vukg_106`,PaymentFeature:`_PaymentFeature_1vukg_111`,Image:`_Image_1vukg_115`};function B({logos:t,title:n,titleRender:a,text:o,actions:s,priceExample:c,src:l,alt:u,imageRender:d,imagePosition:f=`end`,className:p,...m}){let h=(0,e.useRender)({render:a,defaultTagName:`h2`,props:{className:z.Title,children:n}}),g=(0,e.useRender)({enabled:l!=null,render:d,defaultTagName:`img`,props:{src:l,alt:u,className:z.Image}});return(0,i.jsx)(r.Panel,{...m,className:[z.PaymentFeature,p].filter(Boolean).join(` `),"data-image-position":f,"data-has-image":g!=null||void 0,children:(0,i.jsxs)(`div`,{className:z.Grid,children:[(0,i.jsxs)(`div`,{className:z.Content,children:[t!=null&&t.length>0&&(0,i.jsx)(`ul`,{className:z.Logos,children:t.map((e,t)=>(0,i.jsx)(V,{...e},t))}),(0,i.jsxs)(`div`,{className:z.Text,children:[h,o!=null&&(0,i.jsx)(b,{className:z.Description,children:o})]}),s!=null&&(0,i.jsx)(`div`,{className:z.Actions,children:s}),c!=null&&(0,i.jsx)(`p`,{className:z.Price,children:c})]}),g!=null&&(0,i.jsx)(`div`,{className:z.Media,children:g})]})})}function V({src:t,alt:n,imageRender:r}){let a=(0,e.useRender)({render:r,defaultTagName:`img`,props:{src:t,alt:n,className:z.Logo}});return(0,i.jsx)(`li`,{className:z.LogoItem,children:a})}var H={PromoGrid:`_PromoGrid_1l2yi_10`,Featured:`_Featured_1l2yi_19`,Content:`_Content_1l2yi_23`,Photos:`_Photos_1l2yi_31`,Photo:`_Photo_1l2yi_31`,Block:`_Block_1l2yi_51`,Title:`_Title_1l2yi_63`,Subtitle:`_Subtitle_1l2yi_73`};function U({src:t,alt:n,imageRender:o,action:s,images:c,title:l,titleRender:u,subtitle:d,imagePosition:f=`start`,render:p,ref:m,className:h,...g}){let _=(0,e.useRender)({render:u,defaultTagName:`h2`,props:{className:H.Title,children:l}});return(0,e.useRender)({render:p,ref:m,defaultTagName:`div`,props:{...g,"data-image-position":f,className:a(H.PromoGrid,h)({}),children:(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(r.FeaturedImage,{className:H.Featured,src:t,alt:n,imageRender:o,action:s}),(0,i.jsxs)(`div`,{className:H.Content,children:[c!=null&&c.length>0&&(0,i.jsx)(`div`,{className:H.Photos,"data-count":c.length,children:c.map((e,t)=>(0,i.jsx)(W,{...e},t))}),(0,i.jsxs)(`div`,{className:H.Block,children:[_,d!=null&&(0,i.jsx)(b,{className:H.Subtitle,children:d})]})]})]})}})}function W({src:t,alt:n,imageRender:r}){return(0,e.useRender)({render:r,defaultTagName:`img`,props:{src:t,alt:n,className:H.Photo}})}var G={Section:`_Section_f8rp9_11`,Content:`_Content_f8rp9_60`};function K({surface:t=`base`,spacingTop:n=`lg`,spacingBottom:r=`lg`,width:o=`full`,render:s,ref:c,className:l,children:u,...d}){return(0,e.useRender)({render:s,ref:c,defaultTagName:`section`,props:{...d,"data-surface":t,"data-spacing-top":n,"data-spacing-bottom":r,className:a(G.Section,l)({}),children:(0,i.jsx)(`div`,{className:G.Content,"data-width":o,children:u})}})}var q={SectionHeader:`_SectionHeader_11mff_8`,Text:`_Text_11mff_17`,Eyebrow:`_Eyebrow_11mff_25`,Title:`_Title_11mff_33`,Subtitle:`_Subtitle_11mff_49`,Actions:`_Actions_11mff_67`,Price:`_Price_11mff_75`};function J({eyebrow:t,title:n,titleRender:r,titleSize:o=`lg`,subtitle:s,actions:c,priceExample:l,render:u,ref:d,className:f,...p}){let m=(0,e.useRender)({render:r,defaultTagName:`h2`,props:{className:q.Title,children:n}});return(0,e.useRender)({render:u,ref:d,defaultTagName:`div`,props:{...p,"data-title-size":o,className:a(q.SectionHeader,f)({}),children:(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(`div`,{className:q.Text,children:[t!=null&&(0,i.jsx)(`p`,{className:q.Eyebrow,children:t}),m,s!=null&&(0,i.jsx)(b,{className:q.Subtitle,children:s})]}),c!=null&&(0,i.jsx)(`div`,{className:q.Actions,children:c}),l!=null&&(0,i.jsx)(`p`,{className:q.Price,children:l})]})}})}var Y={ServiceCardGrid:`_ServiceCardGrid_nutvc_9`,List:`_List_nutvc_13`,Item:`_Item_nutvc_23`};function X({render:t,ref:r,className:o,children:s,...c}){let l=n.Children.toArray(s);return(0,e.useRender)({render:t,ref:r,defaultTagName:`div`,props:{...c,className:a(Y.ServiceCardGrid,o)({}),children:(0,i.jsx)(`ul`,{className:Y.List,"data-count":l.length,children:l.map((e,t)=>(0,i.jsx)(`li`,{className:Y.Item,children:e},t))})}})}var Z={SplitContent:`_SplitContent_16c8f_11`,Grid:`_Grid_16c8f_19`,Text:`_Text_16c8f_26`,Title:`_Title_16c8f_33`,Description:`_Description_16c8f_42`,Media:`_Media_16c8f_58`,Image:`_Image_16c8f_67`,Actions:`_Actions_16c8f_75`,Price:`_Price_16c8f_82`};function ne({title:t,titleRender:n,text:r,src:o,alt:s,imageRender:c,imagePosition:l=`end`,action:u,priceExample:d,render:f,ref:p,className:m,...h}){let g=(0,e.useRender)({render:n,defaultTagName:`h2`,props:{className:Z.Title,children:t}}),_=(0,e.useRender)({enabled:o!=null,render:c,defaultTagName:`img`,props:{src:o,alt:s,className:Z.Image}});return(0,e.useRender)({render:f,ref:p,defaultTagName:`div`,props:{...h,"data-image-position":l,"data-has-image":_!=null||void 0,className:a(Z.SplitContent,m)({}),children:(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(`div`,{className:Z.Grid,children:[(0,i.jsxs)(`div`,{className:Z.Text,children:[g,r!=null&&(0,i.jsx)(b,{className:Z.Description,children:r})]}),_!=null&&(0,i.jsx)(`div`,{className:Z.Media,children:_})]}),(u!=null||d!=null)&&(0,i.jsxs)(`div`,{className:Z.Actions,children:[u,d!=null&&(0,i.jsx)(`p`,{className:Z.Price,children:d})]})]})}})}var Q={Stats:`_Stats_1o0ef_16`,List:`_List_1o0ef_25`,Bar:`_Bar_1o0ef_33`,Stat:`_Stat_1o0ef_16`,Number:`_Number_1o0ef_59`,Labels:`_Labels_1o0ef_69`,Title:`_Title_1o0ef_77`,Text:`_Text_1o0ef_85`,Actions:`_Actions_1o0ef_95`,Price:`_Price_1o0ef_103`};function re({header:t,items:r,titleRender:o,action:s,priceExample:c,render:l,ref:u,className:d,...f}){return(0,e.useRender)({render:l,ref:u,defaultTagName:`div`,props:{...f,className:a(Q.Stats,d)({}),children:(0,i.jsxs)(i.Fragment,{children:[t,(0,i.jsxs)(`ul`,{className:Q.List,children:[r.map((e,t)=>(0,i.jsxs)(n.Fragment,{children:[(0,i.jsx)(`li`,{"aria-hidden":!0,className:Q.Bar}),(0,i.jsx)(ie,{...e,titleRender:o})]},t)),(0,i.jsx)(`li`,{"aria-hidden":!0,className:Q.Bar})]}),(s!=null||c!=null)&&(0,i.jsxs)(`div`,{className:Q.Actions,children:[s,c!=null&&(0,i.jsx)(`p`,{className:Q.Price,children:c})]})]})}})}function ie({number:t,title:n,text:r,titleRender:a}){let o=(0,e.useRender)({enabled:n!=null,render:a,defaultTagName:`h3`,props:{className:Q.Title,children:n}});return(0,i.jsxs)(`li`,{className:Q.Stat,children:[(0,i.jsx)(`p`,{className:Q.Number,children:t}),(o!=null||r!=null)&&(0,i.jsxs)(`div`,{className:Q.Labels,children:[o,r!=null&&(0,i.jsx)(`p`,{className:Q.Text,children:r})]})]})}var $={Testimonials:`_Testimonials_13hpt_11`,Featured:`_Featured_13hpt_18`,Video:`_Video_13hpt_31`,Quote:`_Quote_13hpt_36`,Blockquote:`_Blockquote_13hpt_44`,Person:`_Person_13hpt_72`,Name:`_Name_13hpt_81`,Meta:`_Meta_13hpt_88`,Still:`_Still_13hpt_124`,Play:`_Play_13hpt_133`,DialogViewport:`_DialogViewport_13hpt_143`,DialogPopup:`_DialogPopup_13hpt_143`,DialogVideo:`_DialogVideo_13hpt_149`,Close:`_Close_13hpt_157`},ae=(0,r.createTranslation)({reviews:{no:`Kundeomtaler`,se:`Kundomdömen`,fi:`Asiakasarviot`,es:`Opiniones de clientes`},play:{no:`Spill av video`,se:`Spela upp video`,fi:`Toista video`,es:`Reproducir vídeo`},video:{no:`Video fra kunde`,se:`Video från kund`,fi:`Asiakkaan video`,es:`Vídeo de un cliente`},close:{no:`Lukk video`,se:`Stäng video`,fi:`Sulje video`,es:`Cerrar vídeo`},captionsLanguage:{no:`nb`,se:`sv`,fi:`fi`,es:`es`},captionsLabel:{no:`Norsk`,se:`Svenska`,fi:`Suomi`,es:`Español`}});function oe({title:o,titleRender:s,subtitle:c,quote:l,name:u,meta:d,rating:f,videoSrc:p,videoPoster:m,videoCaptions:h,videoPosition:g=`start`,render:_,ref:y,className:b,children:x,...S}){let C=ae(),w=(0,n.useId)(),T=l!=null||u!=null,E=n.Children.toArray(x).length>0;return(0,e.useRender)({render:_,ref:y,defaultTagName:`div`,props:{...S,className:a($.Testimonials,b)({}),children:(0,i.jsxs)(i.Fragment,{children:[o!=null&&(0,i.jsx)(J,{title:o,titleRender:(0,n.cloneElement)(s??(0,i.jsx)(`h2`,{}),{id:w}),subtitle:c}),(T||p!=null)&&(0,i.jsxs)(`div`,{className:$.Featured,"data-video":p!=null||void 0,"data-video-position":g,children:[T&&(0,i.jsxs)(`figure`,{className:$.Quote,children:[f!=null&&(0,i.jsx)(r.StarRating,{rating:f}),l!=null&&(0,i.jsx)(`blockquote`,{className:$.Blockquote,children:typeof l==`string`||typeof l==`number`?(0,i.jsx)(`p`,{children:l}):l}),(u!=null||d!=null)&&(0,i.jsxs)(`figcaption`,{className:$.Person,children:[u!=null&&(0,i.jsx)(`span`,{className:$.Name,children:u}),d!=null&&(0,i.jsx)(`span`,{className:$.Meta,children:d})]})]}),p!=null&&(0,i.jsxs)(`div`,{className:$.Video,children:[m==null?(0,i.jsx)(`video`,{className:$.Still,src:`${p}#t=0.1`,preload:`metadata`,muted:!0,playsInline:!0,"aria-hidden":!0,tabIndex:-1}):(0,i.jsx)(`img`,{className:$.Still,src:m,alt:``}),(0,i.jsxs)(r.Dialog.Root,{children:[(0,i.jsx)(r.Dialog.Trigger,{render:(0,i.jsx)(r.IconButton,{variant:`elevated`,color:`secondary`,"aria-label":C.play,className:$.Play,children:(0,i.jsx)(t.Play,{"aria-hidden":!0})})}),(0,i.jsxs)(r.Dialog.Portal,{children:[(0,i.jsx)(r.Dialog.Backdrop,{}),(0,i.jsx)(r.Dialog.Viewport,{className:$.DialogViewport,children:(0,i.jsxs)(r.Dialog.Popup,{size:`lg`,"aria-label":C.video,className:$.DialogPopup,children:[(0,i.jsx)(r.Dialog.Close,{render:(0,i.jsx)(r.IconButton,{variant:`elevated`,color:`secondary`,"aria-label":C.close,className:$.Close,children:(0,i.jsx)(t.X,{"aria-hidden":!0})})}),(0,i.jsx)(`video`,{className:$.DialogVideo,src:p,controls:!0,autoPlay:!0,playsInline:!0,children:h!=null&&(0,i.jsx)(`track`,{kind:`captions`,src:h,srcLang:C.captionsLanguage,label:C.captionsLabel,default:!0})})]})})]})]})]})]}),E&&(0,i.jsx)(v,{...o==null?{"aria-label":C.reviews}:{"aria-labelledby":w},children:x})]})}})}exports.BrandLetters=u,exports.Calculator=f,exports.Carousel=v,exports.CtaBanner=x,exports.ExpandingCards=te,exports.ExpandingCardsItem=k,exports.Hero=j,exports.HeroServiceGrid=N,exports.NavigationGrid=F,exports.PartnerList=R,exports.PaymentFeature=B,exports.PromoGrid=U,exports.Section=K,exports.SectionHeader=J,exports.ServiceCardGrid=X,exports.SplitContent=ne,exports.Stats=re,exports.Testimonials=oe;
2
+ //# sourceMappingURL=website.cjs.map