@leabankab/component-library 8.6.1 → 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 (93) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/dist/component-library.es.js +1930 -1091
  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/buttons/action-button.d.ts +34 -4
  7. package/dist/components/buttons/button-base.d.ts +5 -2
  8. package/dist/components/buttons/icon-button.d.ts +16 -2
  9. package/dist/components/color-roles.d.ts +7 -1
  10. package/dist/components/data-display/arrow-circle.d.ts +21 -0
  11. package/dist/components/data-display/article-card.d.ts +88 -0
  12. package/dist/components/data-display/avatar.d.ts +33 -0
  13. package/dist/components/data-display/chip.d.ts +8 -3
  14. package/dist/components/data-display/featured-image.d.ts +42 -0
  15. package/dist/components/data-display/index.d.ts +12 -0
  16. package/dist/components/data-display/link-card.d.ts +52 -0
  17. package/dist/components/data-display/media-card.d.ts +102 -0
  18. package/dist/components/data-display/partner-row.d.ts +46 -0
  19. package/dist/components/data-display/rich-text.d.ts +27 -0
  20. package/dist/components/data-display/service-card.d.ts +80 -0
  21. package/dist/components/data-display/star-rating.d.ts +26 -0
  22. package/dist/components/data-display/table.d.ts +93 -0
  23. package/dist/components/data-display/testimonial-card.d.ts +43 -0
  24. package/dist/components/data-display/use-star-rating-labels.d.ts +5 -0
  25. package/dist/components/data-display/use-video-player-labels.d.ts +2 -0
  26. package/dist/components/data-display/video-player.d.ts +22 -0
  27. package/dist/components/data-display/website-card.d.ts +10 -0
  28. package/dist/components/feedback/index.d.ts +1 -0
  29. package/dist/components/feedback/skeleton.d.ts +22 -0
  30. package/dist/components/form/slider.d.ts +15 -2
  31. package/dist/components/navigation/breadcrumbs.d.ts +38 -0
  32. package/dist/components/navigation/index.d.ts +3 -0
  33. package/dist/components/navigation/pagination-dots.d.ts +34 -0
  34. package/dist/components/navigation/pagination.d.ts +37 -0
  35. package/dist/components/navigation/use-breadcrumbs-labels.d.ts +2 -0
  36. package/dist/components/navigation/use-pagination-labels.d.ts +7 -0
  37. package/dist/components/surfaces/accordion.d.ts +5 -1
  38. package/dist/components/surfaces/index.d.ts +1 -0
  39. package/dist/components/surfaces/panel.d.ts +30 -0
  40. package/dist/components/typography/link.d.ts +14 -1
  41. package/dist/cookie-consent-react.cjs +1 -1
  42. package/dist/cookie-consent-react.cjs.map +1 -1
  43. package/dist/cookie-consent-react.mjs +13 -13
  44. package/dist/cookie-consent-react.mjs.map +1 -1
  45. package/dist/cookie-consent.css +1 -1
  46. package/dist/date-picker.cjs +1 -1
  47. package/dist/date-picker.cjs.map +1 -1
  48. package/dist/date-picker.mjs +216 -203
  49. package/dist/date-picker.mjs.map +1 -1
  50. package/dist/index.css +1 -1
  51. package/dist/index.d.ts +1 -1
  52. package/dist/tailwind.css +16 -0
  53. package/dist/theme/index.d.ts +1 -1
  54. package/dist/theme/token-types.d.ts +13 -3
  55. package/dist/theme/tokens/breakpoints.d.ts +20 -0
  56. package/dist/theme/tokens/font-family.d.ts +6 -0
  57. package/dist/theme/tokens/index.d.ts +1 -0
  58. package/dist/theme/tokens/shadows.d.ts +6 -0
  59. package/dist/theme/tokens/text-styles.d.ts +8 -0
  60. package/dist/theme/tokens/widths.d.ts +10 -0
  61. package/dist/theme/types.d.ts +9 -1
  62. package/dist/website/brand-letters.d.ts +40 -0
  63. package/dist/website/calculator.d.ts +58 -0
  64. package/dist/website/carousel.d.ts +55 -0
  65. package/dist/website/cta-banner.d.ts +42 -0
  66. package/dist/website/expanding-cards-context.d.ts +8 -0
  67. package/dist/website/expanding-cards-item.d.ts +69 -0
  68. package/dist/website/expanding-cards.d.ts +48 -0
  69. package/dist/website/hero-service-grid.d.ts +52 -0
  70. package/dist/website/hero.d.ts +57 -0
  71. package/dist/website/index.d.ts +33 -0
  72. package/dist/website/navigation-grid.d.ts +39 -0
  73. package/dist/website/paragraphs.d.ts +11 -0
  74. package/dist/website/partner-list.d.ts +79 -0
  75. package/dist/website/payment-feature.d.ts +85 -0
  76. package/dist/website/promo-grid.d.ts +71 -0
  77. package/dist/website/section-header.d.ts +53 -0
  78. package/dist/website/section.d.ts +53 -0
  79. package/dist/website/service-card-grid.d.ts +33 -0
  80. package/dist/website/split-content.d.ts +69 -0
  81. package/dist/website/stats.d.ts +52 -0
  82. package/dist/website/testimonials.d.ts +100 -0
  83. package/dist/website/use-brand-letters-labels.d.ts +2 -0
  84. package/dist/website/use-carousel-labels.d.ts +6 -0
  85. package/dist/website/use-carousel.d.ts +50 -0
  86. package/dist/website/use-partner-list-labels.d.ts +6 -0
  87. package/dist/website/use-testimonials-labels.d.ts +6 -0
  88. package/dist/website.cjs +2 -0
  89. package/dist/website.cjs.map +1 -0
  90. package/dist/website.css +1 -0
  91. package/dist/website.mjs +1226 -0
  92. package/dist/website.mjs.map +1 -0
  93. package/package.json +7 -2
@@ -1,6 +1,6 @@
1
1
  export type ColorToken = "base" | "subtle" | "muted" | "contrast" | "accent";
2
- export type BgColorToken = ColorToken | "overlay";
3
- export type TextColorToken = ColorToken;
2
+ export type BgColorToken = ColorToken | "overlay" | "hover" | "contrast-hover" | "contrast-accent";
3
+ export type TextColorToken = ColorToken | "contrast-hover";
4
4
  export type BorderColorToken = ColorToken;
5
5
  export type BrandColorToken = "base" | "hover" | "subtle" | "contrast";
6
6
  export type StatusColorToken = "base" | "subtle";
@@ -15,8 +15,18 @@ export type ColorPath = `bg.${BgColorToken}` | `text.${TextColorToken}` | `borde
15
15
  * - `neutral`: the greys, for something that should carry no meaning.
16
16
  * - `success`, `info`, `warning`, `error`: the statuses.
17
17
  * - `contrast`: for use on a dark surface.
18
+ * - `muted`: the warm beige of `bg.muted`, for a tag on the website.
18
19
  */
19
- export type ColorRole = "primary" | "secondary" | "tertiary" | "neutral" | "success" | "info" | "warning" | "error" | "contrast";
20
+ export type ColorRole = "primary" | "secondary" | "tertiary" | "neutral" | "success" | "info" | "warning" | "error" | "contrast" | "muted";
21
+ /**
22
+ * The values a website component's `surface` prop can take: the background of
23
+ * a section or card, named after its `bg` token. `base` is white, `subtle` the
24
+ * grey, `muted` the beige, `contrast` the near-black and `contrast-accent` the
25
+ * deep purple. On the last two, text is `text.contrast`. Like `ColorRole`, it
26
+ * names a role and never a hue, and a component accepts the ones it has a
27
+ * design for.
28
+ */
29
+ export type SurfaceRole = "base" | "subtle" | "muted" | "contrast" | "contrast-accent";
20
30
  /** Allowed values for MUI `Typography` `color` prop (semantic text tokens). */
21
31
  export type TypographyColorToken = `text.${TextColorToken}`;
22
32
  /** Common spacing scale factors (8px base via `theme.spacing` / `theme.space`). */
@@ -14,3 +14,23 @@ export declare const breakpoints: {
14
14
  readonly xl: 1536;
15
15
  };
16
16
  export type Breakpoint = keyof typeof breakpoints;
17
+ /**
18
+ * The website's own widths, for the website components only, so a layout on
19
+ * leabank.no switches where it does today. Named as in the website's theme.
20
+ * There each is a `max-width` (`mobile` is up to 640px); here, as everywhere in
21
+ * the library, a CSS Module writes them mobile-first: `@media (min-width:
22
+ * 640px)` starts above `mobile`, and `max-width: 639.95px` ends below it. That
23
+ * moves each switch by one pixel, at exactly the width itself.
24
+ *
25
+ * They are not part of `Breakpoint`, so `Container` sizes and the responsive
26
+ * props of `Stack` and `Grid` keep their five steps.
27
+ */
28
+ export declare const websiteBreakpoints: {
29
+ readonly mobile: 640;
30
+ readonly tablet: 768;
31
+ readonly desktop: 1024;
32
+ /** The website's `mobileHeader`: below it the header is the mobile one. */
33
+ readonly header: 1312;
34
+ readonly wide: 1440;
35
+ };
36
+ export type WebsiteBreakpoint = keyof typeof websiteBreakpoints;
@@ -7,3 +7,9 @@
7
7
  * loads.
8
8
  */
9
9
  export declare const fontFamily = "\"ClashGrotesk\", \"ClashGrotesk Fallback\", sans-serif";
10
+ /**
11
+ * The stack for code in CMS text (`RichText`'s `code` and `pre`), emitted as
12
+ * `--lea-font-family-mono`: the website's Courier New, then the platform's own
13
+ * monospace. Nothing else sets text in it, and no face is shipped for it.
14
+ */
15
+ export declare const fontFamilyMono = "\"Courier New\", Courier, monospace";
@@ -12,3 +12,4 @@ export * from './spacing';
12
12
  export * from './text-styles';
13
13
  export * from './transitions';
14
14
  export * from './type-scale';
15
+ export * from './widths';
@@ -5,5 +5,11 @@ export declare const shadows: {
5
5
  readonly lg: "0px 10px 15px -3px rgba(0, 0, 0, 0.10), 0px 4px 6px -4px rgba(0, 0, 0, 0.10)";
6
6
  readonly xl: "0px 20px 25px -5px rgba(0, 0, 0, 0.10), 0px 8px 10px -6px rgba(0, 0, 0, 0.10)";
7
7
  readonly "2xl": "0px 25px 50px -12px rgba(0, 0, 0, 0.25)";
8
+ /**
9
+ * The website's shadow: an even 6px halo with no offset, the exact value of
10
+ * leabank.no. For the website components that float over a section (the
11
+ * elevated `IconButton`, the partner logo tile, the header dropdown).
12
+ */
13
+ readonly soft: "0 0 6px 0 rgba(86, 86, 118, 0.10)";
8
14
  readonly inner: "0px 2px 4px 0px rgba(0, 0, 0, 0.05) inset";
9
15
  };
@@ -18,6 +18,10 @@ type TextStyleDefinition = {
18
18
  * `label` move one step at a time; `heading` and `display` move two, because
19
19
  * neighbouring steps are too close to tell two headings apart.
20
20
  *
21
+ * `title` is a heading in the regular weight, for the website: the title of a
22
+ * link card (`title-md`) and an uppercase promo title (`title-xl`). It takes
23
+ * the sizes and line heights of `heading-md` and `heading-xl`.
24
+ *
21
25
  * The Figma text styles `heading/lg` and so on mirror this file.
22
26
  */
23
27
  export declare const textStyles: {
@@ -32,6 +36,10 @@ export declare const textStyles: {
32
36
  lg: TextStyleDefinition;
33
37
  xl: TextStyleDefinition;
34
38
  };
39
+ title: {
40
+ md: TextStyleDefinition;
41
+ xl: TextStyleDefinition;
42
+ };
35
43
  body: {
36
44
  xs: TextStyleDefinition;
37
45
  sm: TextStyleDefinition;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Content widths in pixels, emitted as `--lea-width-{name}`. Not breakpoints:
3
+ * a width caps how wide content grows, a breakpoint is where a layout changes.
4
+ *
5
+ * - `section`: the content column of a website section, 1312px (1440 less 64
6
+ * at each side). The Figma variable `width/section` holds the same number.
7
+ */
8
+ export declare const widths: {
9
+ readonly section: 1312;
10
+ };
@@ -16,6 +16,12 @@ export type Palette = {
16
16
  accent: string;
17
17
  /** The see-through layer behind a dialog or drawer. */
18
18
  overlay: string;
19
+ /** Hover on a website card or panel with a light surface. */
20
+ hover: string;
21
+ /** Hover on a website card or panel with a dark surface. */
22
+ "contrast-hover": string;
23
+ /** The deep purple of a website section or card. Takes `text.contrast`. */
24
+ "contrast-accent": string;
19
25
  };
20
26
  text: {
21
27
  base: string;
@@ -23,6 +29,8 @@ export type Palette = {
23
29
  muted: string;
24
30
  accent: string;
25
31
  contrast: string;
32
+ /** Hover on a link on a dark surface, on the website. */
33
+ "contrast-hover": string;
26
34
  };
27
35
  border: {
28
36
  base: string;
@@ -66,4 +74,4 @@ export type EasingToken = keyof typeof import('./tokens/transitions').easings;
66
74
  export type DurationToken = keyof typeof import('./tokens/transitions').durations;
67
75
  export type LineHeightToken = keyof typeof import('./tokens/line-heights').lineHeights;
68
76
  export type { TextStyleToken } from './tokens/text-styles';
69
- export type { BgColorToken, BorderColorToken, BrandColorToken, ColorPath, ColorRole, ColorToken, SpacingFactor, StatusColorToken, TextColorToken, TypographyColorToken, } from './token-types';
77
+ export type { BgColorToken, BorderColorToken, BrandColorToken, ColorPath, ColorRole, ColorToken, SpacingFactor, StatusColorToken, SurfaceRole, TextColorToken, TypographyColorToken, } from './token-types';
@@ -0,0 +1,40 @@
1
+ import { useRender } from '@base-ui/react/use-render';
2
+ import { Ref } from 'react';
3
+ /** The video in one letter. */
4
+ export type BrandLettersVideo = {
5
+ /** The video file. It plays without sound, so it should need none. */
6
+ src: string;
7
+ /** A still to show before the video starts, and while it is paused. */
8
+ poster?: string;
9
+ };
10
+ export type BrandLettersProps = Omit<useRender.ComponentProps<"div">, "ref" | "children"> & {
11
+ /** The rendered element: the `<div>`, or the element passed to `render`. */
12
+ ref?: Ref<HTMLElement>;
13
+ /** The three videos, in the L, the E and the A. */
14
+ videos: readonly [BrandLettersVideo, BrandLettersVideo, BrandLettersVideo];
15
+ };
16
+ /**
17
+ * The letters L, E and A of the logo side by side, each filled with a silent
18
+ * video in a loop, as the brand block of leabank.no.
19
+ *
20
+ * ```tsx
21
+ * <Section>
22
+ * <BrandLetters
23
+ * videos={[
24
+ * { src: "/video/l.mp4", poster: "/video/l.jpg" },
25
+ * { src: "/video/e.mp4", poster: "/video/e.jpg" },
26
+ * { src: "/video/a.mp4", poster: "/video/a.jpg" },
27
+ * ]}
28
+ * />
29
+ * </Section>
30
+ * ```
31
+ *
32
+ * The letters share the width they are given, each 437 : 510. The videos
33
+ * start on their own once the page has loaded, unless the visitor has asked
34
+ * for reduced motion: then they wait for the button. One button under the
35
+ * letters pauses and plays all three, named "Sett videoene på pause" or
36
+ * "Spill av videoene" in the `LeaProvider` language, since moving content
37
+ * that plays on its own needs a way to stop it. The videos are decoration
38
+ * and hidden from screen readers.
39
+ */
40
+ export declare function BrandLetters({ videos, render, ref, className, ...rest }: BrandLettersProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
@@ -0,0 +1,58 @@
1
+ import { useRender } from '@base-ui/react/use-render';
2
+ import { ReactNode, Ref } from 'react';
3
+ /** A figure the calculator works out, shown in the summary column. */
4
+ export type CalculatorResult = {
5
+ /** What the figure is: "Beregnet sparesaldo". */
6
+ label: ReactNode;
7
+ /** The figure, written out: "399 418 kr". */
8
+ value: ReactNode;
9
+ };
10
+ export type CalculatorProps = Omit<useRender.ComponentProps<"div">, "ref" | "children" | "results"> & {
11
+ /** The rendered element: the `<div>`, or the element passed to `render`. */
12
+ ref?: Ref<HTMLElement>;
13
+ /** The heading above the calculator: a `SectionHeader`. */
14
+ header?: ReactNode;
15
+ /**
16
+ * The inputs, in the panel: `Slider`s with `color="contrast"`, each with
17
+ * its `label`, `min`, `max`, `step`, `format` and `locale`.
18
+ */
19
+ children: ReactNode;
20
+ /**
21
+ * The figures worked out from the inputs, at the top of the summary
22
+ * column. The page does the sums: one result for savings, three for
23
+ * refinancing on leabank.no. A change is announced to screen readers.
24
+ */
25
+ results: readonly CalculatorResult[];
26
+ /** The call to action under the results: an `ActionButton`. */
27
+ action?: ReactNode;
28
+ /** The price example under the action, in the small print. */
29
+ priceExample?: ReactNode;
30
+ };
31
+ /**
32
+ * The website's savings and refinancing calculator: a heading, a panel of
33
+ * sliders and a column with the results and a call to action, as on
34
+ * leabank.no/sparing and leabank.no/lan. It lays the parts out; the inputs
35
+ * are `Slider`s and the sums stay with the page.
36
+ *
37
+ * ```tsx
38
+ * <Section surface="contrast-accent">
39
+ * <Calculator
40
+ * header={<SectionHeader eyebrow="Sparekalkulator" title="Se hvor mye sparingen din kan vokse" />}
41
+ * results={[{ label: "Beregnet sparesaldo", value: format(balance) }]}
42
+ * action={<ActionButton render={<NextLink href="/sparing/apne-konto" />}>Opprett konto</ActionButton>}
43
+ * >
44
+ * <Slider color="contrast" label="Startbeløp" min={0} max={1000000} step={1000} value={start} onValueChange={setStart} locale="nb-NO" format={{ style: "currency", currency: "NOK", maximumFractionDigits: 0 }} />
45
+ * …
46
+ * </Calculator>
47
+ * </Section>
48
+ * ```
49
+ *
50
+ * The header is 80px above the rest (32px below 768px). From 1024px the
51
+ * panel and a 280px column sit side by side, 64px apart: the results at the
52
+ * top of the column, right-aligned, the action and the price example at its
53
+ * foot; below 1024px one under the other, left-aligned, 32px apart. The
54
+ * panel is black at 30 % over the section, with `5xl` corners and 32px
55
+ * inside, the sliders 16px apart. It has no colour of its own and is made
56
+ * for the dark surfaces, `contrast` and `contrast-accent`.
57
+ */
58
+ export declare function Calculator({ header, results, action, priceExample, render, ref, className, children, ...rest }: CalculatorProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
@@ -0,0 +1,55 @@
1
+ import { useRender } from '@base-ui/react/use-render';
2
+ import { ReactNode, Ref } from 'react';
3
+ /**
4
+ * A carousel is a region, so it needs a name: the title of what it shows.
5
+ * Provide exactly one of `aria-label` or `aria-labelledby`.
6
+ */
7
+ type CarouselName = {
8
+ "aria-label": string;
9
+ "aria-labelledby"?: never;
10
+ } | {
11
+ "aria-labelledby": string;
12
+ "aria-label"?: never;
13
+ };
14
+ export type CarouselProps = Omit<useRender.ComponentProps<"div">, "ref" | "children" | "aria-label" | "aria-labelledby"> & CarouselName & {
15
+ /** The rendered element: the `<div>`, or the element passed to `render`. */
16
+ ref?: Ref<HTMLElement>;
17
+ /**
18
+ * The slides, such as `TestimonialCard`s. Each one is put in an item of
19
+ * a list and stretched to the height of the tallest.
20
+ */
21
+ children: ReactNode;
22
+ /**
23
+ * The name of each dot, when "Gå til side 3" does not say enough, as on
24
+ * `PaginationDots`.
25
+ */
26
+ getItemLabel?: (page: number) => string;
27
+ };
28
+ /**
29
+ * A row of slides that scrolls sideways, as the website's carousel of
30
+ * reviews: 2.2 slides in view from 1024px and 1.15 below, 16px apart, with
31
+ * previous and next buttons and a dot per place under them.
32
+ *
33
+ * ```tsx
34
+ * <Carousel aria-labelledby={titleId}>
35
+ * <TestimonialCard rating={5} quote="…" name="Kari Nordmann" meta="Kunde, Oslo" />
36
+ * <TestimonialCard rating={5} quote="…" name="Ola Hansen" meta="Kunde, Bergen" />
37
+ * <TestimonialCard rating={4} quote="…" name="Ingrid Berg" meta="Kunde, Trondheim" />
38
+ * </Carousel>
39
+ * ```
40
+ *
41
+ * The track scrolls on its own, with scroll snap: swipe it, scroll it with a
42
+ * trackpad, or focus it and use the arrow keys. It stops at the start of
43
+ * each slide; the last slides, which can't reach the start, share the end.
44
+ * The buttons and dots move it a place at a time, and once it has moved, the
45
+ * place it comes to rest at is announced ("Side 2 av 3"). The edges fade into the section's colour where
46
+ * there is more to scroll. Under reduced motion the buttons jump instead of
47
+ * scrolling smoothly.
48
+ *
49
+ * It is a region named by `aria-label` or `aria-labelledby`, described as a
50
+ * carousel in the `LeaProvider` language. The controls show only when the
51
+ * slides don't fit. The buttons and dots are made for the light surfaces
52
+ * (`base`, `subtle`, `muted`).
53
+ */
54
+ export declare function Carousel({ getItemLabel, render, ref, className, children, ...rest }: CarouselProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
55
+ export {};
@@ -0,0 +1,42 @@
1
+ import { useRender } from '@base-ui/react/use-render';
2
+ import { ReactElement, ReactNode, Ref } from 'react';
3
+ export type CtaBannerProps = Omit<useRender.ComponentProps<"div">, "ref" | "title" | "children"> & {
4
+ /** The rendered element: the `<div>`, or the element passed to `render`. */
5
+ ref?: Ref<HTMLElement>;
6
+ /** The big title. */
7
+ title: ReactNode;
8
+ /**
9
+ * The element for the title, an `<h2>` by default: `titleRender={<h1 />}`
10
+ * where the banner opens the page.
11
+ */
12
+ titleRender?: ReactElement;
13
+ /**
14
+ * The text beside the title. A string becomes one paragraph; pass `<p>`
15
+ * elements for several.
16
+ */
17
+ text?: ReactNode;
18
+ /** The call to action under the text: an `ActionButton`. */
19
+ action?: ReactNode;
20
+ /** The price example under the action, in the small print. */
21
+ priceExample?: ReactNode;
22
+ };
23
+ /**
24
+ * A closing call to action: a big title on the left, and a text, a button
25
+ * and the price example on the right, as at the foot of leabank.no's home
26
+ * page.
27
+ *
28
+ * ```tsx
29
+ * <Section surface="muted">
30
+ * <CtaBanner
31
+ * title="Klar for å komme i gang med Lea Bank?"
32
+ * text="Vi er her for deg og står klare til å hjelpe deg."
33
+ * action={<ActionButton render={<NextLink href="/lan" />}>Søk om forbrukslån</ActionButton>}
34
+ * />
35
+ * </Section>
36
+ * ```
37
+ *
38
+ * Two equal columns 64px apart from 1024px, one column below with the title
39
+ * at 41px. With only a title, the title takes the whole width. It takes the
40
+ * text colour of its section.
41
+ */
42
+ export declare function CtaBanner({ title, titleRender, text, action, priceExample, render, ref, className, ...rest }: CtaBannerProps): ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Whether an `ExpandingCardsItem` is open: the one card `ExpandingCards`
3
+ * keeps open in its row from 1312px, or every card below that and outside
4
+ * the row. Internal.
5
+ */
6
+ export declare const ExpandingCardsContext: import('react').Context<{
7
+ open: boolean;
8
+ }>;
@@ -0,0 +1,69 @@
1
+ import { useRender } from '@base-ui/react/use-render';
2
+ import { ReactElement, ReactNode, Ref } from 'react';
3
+ import { SurfaceRoles } from '../components/color-roles';
4
+ export type ExpandingCardsItemSurface = SurfaceRoles<"base" | "subtle" | "muted" | "contrast" | "contrast-accent">;
5
+ /** `alt` is required with a photo, `""` when it is decoration. */
6
+ type ExpandingCardsItemImage = {
7
+ /** The photo: the whole card while it is closed, half of it open. */
8
+ src: string;
9
+ /** What the photo shows, for screen readers; `""` for decoration. */
10
+ alt: string;
11
+ /**
12
+ * The image element to render instead of the plain `<img>`, such as
13
+ * `next/image` with `fill`. Its own props win over `src` and `alt`.
14
+ */
15
+ imageRender?: ReactElement;
16
+ } | {
17
+ src?: undefined;
18
+ alt?: undefined;
19
+ imageRender?: undefined;
20
+ };
21
+ export type ExpandingCardsItemProps = Omit<useRender.ComponentProps<"div">, "ref" | "title" | "children"> & ExpandingCardsItemImage & {
22
+ /** The rendered element: the `<div>`, or the element passed to `render`. */
23
+ ref?: Ref<HTMLElement>;
24
+ /** The title, in capitals. */
25
+ title: ReactNode;
26
+ /**
27
+ * The element for the title, an `<h2>` by default. Pass another level
28
+ * where the page outline needs one: `titleRender={<h3 />}`.
29
+ */
30
+ titleRender?: ReactElement;
31
+ /** The text under the title. A string becomes one paragraph. */
32
+ text?: ReactNode;
33
+ /**
34
+ * The call to action: an `ActionButton`. While the card is closed it
35
+ * shows only its arrow, with the label kept for screen readers.
36
+ */
37
+ action?: ReactNode;
38
+ /**
39
+ * The colour of the card, after its `bg` token, as on `Section`. On
40
+ * `"contrast"` and `"contrast-accent"` the text is white.
41
+ * @default "base"
42
+ */
43
+ surface?: ExpandingCardsItemSurface;
44
+ };
45
+ /**
46
+ * A card of `ExpandingCards`: a photo, a title in capitals, a text and a
47
+ * call to action, on one of the five section colours.
48
+ *
49
+ * ```tsx
50
+ * <ExpandingCardsItem
51
+ * surface="contrast"
52
+ * title="Forbrukslån"
53
+ * text="Lån til det du trenger, uten sikkerhet. Søk på få minutter."
54
+ * src="/bilder/forbrukslan.jpg"
55
+ * alt=""
56
+ * action={<ActionButton render={<NextLink href="/lan/forbrukslan" />}>Søk nå</ActionButton>}
57
+ * />
58
+ * ```
59
+ *
60
+ * Open, the text takes the start half (32px inside, at the bottom) and the
61
+ * photo the end half, 16px from the card's edges. Closed (in the row of
62
+ * `ExpandingCards` from 1312px), the photo fills the card and only the
63
+ * `ActionButton`'s arrow shows; the title and text are still there for
64
+ * screen readers, and focusing the button opens the card. Below 640px the
65
+ * photo is on top at 2 : 1. Outside `ExpandingCards` the card is always
66
+ * open. At least 280px tall; it grows with its text.
67
+ */
68
+ export declare function ExpandingCardsItem({ title, titleRender, text, action, src, alt, imageRender, surface, render, ref, className, ...rest }: ExpandingCardsItemProps): ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
69
+ export {};
@@ -0,0 +1,48 @@
1
+ import { useRender } from '@base-ui/react/use-render';
2
+ import { ReactNode, Ref } from 'react';
3
+ export type ExpandingCardsDefaultOpen = "first" | "last";
4
+ export type ExpandingCardsProps = Omit<useRender.ComponentProps<"div">, "ref" | "children"> & {
5
+ /** The rendered element: the `<div>`, or the element passed to `render`. */
6
+ ref?: Ref<HTMLElement>;
7
+ /**
8
+ * The cards: `ExpandingCardsItem`s, usually three. Each one is put in an
9
+ * item of a list.
10
+ */
11
+ children: ReactNode;
12
+ /**
13
+ * The card that is open before the visitor points at one: the website's
14
+ * "Main card".
15
+ * @default "first"
16
+ */
17
+ defaultOpen?: ExpandingCardsDefaultOpen;
18
+ };
19
+ /**
20
+ * A row of photo cards in which one is open, as on the home page of
21
+ * leabank.no: the open card is twice as wide as the others, with its title,
22
+ * text and call to action beside its photo; the others show the photo and
23
+ * the arrow.
24
+ *
25
+ * ```tsx
26
+ * <Section>
27
+ * <ExpandingCards>
28
+ * <ExpandingCardsItem
29
+ * surface="contrast"
30
+ * title="Forbrukslån"
31
+ * text="Lån til det du trenger, uten sikkerhet."
32
+ * src="/bilder/forbrukslan.jpg"
33
+ * alt=""
34
+ * action={<ActionButton render={<NextLink href="/lan/forbrukslan" />}>Søk nå</ActionButton>}
35
+ * />
36
+ * …
37
+ * </ExpandingCards>
38
+ * </Section>
39
+ * ```
40
+ *
41
+ * From 1312px the cards share a row, 16px apart, and the card the pointer
42
+ * or the keyboard focus moves into opens; the last one opened stays open.
43
+ * The row keeps its height while a card opens, so the page under it does
44
+ * not move. Below 1312px every card is open, one under the other, and below
45
+ * 640px the photo sits on top of the text. The cards are a list. Under
46
+ * reduced motion they open without moving.
47
+ */
48
+ export declare function ExpandingCards({ defaultOpen, render, ref, className, children, ...rest }: ExpandingCardsProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
@@ -0,0 +1,52 @@
1
+ import { useRender } from '@base-ui/react/use-render';
2
+ import { ReactElement, ReactNode, Ref } from 'react';
3
+ export type HeroServiceGridImagePosition = "start" | "end";
4
+ export type HeroServiceGridProps = Omit<useRender.ComponentProps<"div">, "ref" | "children"> & {
5
+ /** The rendered element: the `<div>`, or the element passed to `render`. */
6
+ ref?: Ref<HTMLElement>;
7
+ /** The large photo. */
8
+ src: string;
9
+ /** What the photo shows, for screen readers; `""` when it is decoration. */
10
+ alt: string;
11
+ /**
12
+ * The image element to render instead of the plain `<img>`, as on
13
+ * `FeaturedImage`: `next/image` with `fill`, or an `<img loading="lazy">`.
14
+ */
15
+ imageRender?: ReactElement;
16
+ /** A call to action on the photo: an `ActionButton`. */
17
+ action?: ReactNode;
18
+ /**
19
+ * Where the photo sits from 1024px: `"start"` (on the left) or `"end"`.
20
+ * Below 1024px it is always on top.
21
+ * @default "start"
22
+ */
23
+ imagePosition?: HeroServiceGridImagePosition;
24
+ /**
25
+ * The cards beside the photo: up to four `LinkCard`s, two by two. Each one
26
+ * is put in an item of a list.
27
+ */
28
+ children?: ReactNode;
29
+ };
30
+ /**
31
+ * A large photo beside a block of link cards, as on leabank.no's home page:
32
+ * a `FeaturedImage` with a call to action, and up to four `LinkCard`s.
33
+ *
34
+ * ```tsx
35
+ * <Section>
36
+ * <HeroServiceGrid
37
+ * src="/bilder/familie.jpg"
38
+ * alt=""
39
+ * action={<ActionButton render={<NextLink href="/lan" />}>Se våre lån</ActionButton>}
40
+ * >
41
+ * <LinkCard render={<NextLink href="/lan" />} title="Lån etter dine behov." surface="contrast" />
42
+ * <LinkCard render={<NextLink href="/sparing" />} title="Se hvor mye du kan spare." surface="muted" />
43
+ * </HeroServiceGrid>
44
+ * </Section>
45
+ * ```
46
+ *
47
+ * From 1024px two equal columns 16px apart, at least 600px tall: the photo
48
+ * fills one, the cards share the other two by two. Below 1024px the photo is
49
+ * on top at 1 : 0.7, the cards two by two under it, and one under the other
50
+ * below 768px. The cards are a list.
51
+ */
52
+ export declare function HeroServiceGrid({ src, alt, imageRender, action, imagePosition, render, ref, className, children, ...rest }: HeroServiceGridProps): ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
@@ -0,0 +1,57 @@
1
+ import { useRender } from '@base-ui/react/use-render';
2
+ import { ReactElement, ReactNode, Ref } from 'react';
3
+ export type HeroProps = Omit<useRender.ComponentProps<"section">, "ref" | "title" | "children"> & {
4
+ /** The rendered element: the `<section>`, or the element passed to `render`. */
5
+ ref?: Ref<HTMLElement>;
6
+ /** The photo behind the band, cropped to fill it. */
7
+ src: string;
8
+ /**
9
+ * What the photo shows, for screen readers; `""` when it is decoration,
10
+ * as a photo behind a title usually is.
11
+ */
12
+ alt: string;
13
+ /**
14
+ * The image element to render instead of the plain `<img>`, such as
15
+ * `next/image` with `fill` and `priority` (the hero photo is usually the
16
+ * largest thing on the page). Its own props win over `src` and `alt`.
17
+ */
18
+ imageRender?: ReactElement;
19
+ /** The title of the page. */
20
+ title: ReactNode;
21
+ /**
22
+ * The element for the title, an `<h1>` by default, as a hero opens the
23
+ * page: `titleRender={<h2 />}` where it does not.
24
+ */
25
+ titleRender?: ReactElement;
26
+ /**
27
+ * The text under the title. A string becomes one paragraph; pass `<p>`
28
+ * elements for several.
29
+ */
30
+ text?: ReactNode;
31
+ /** The call to action under the text: an `ActionButton`. */
32
+ action?: ReactNode;
33
+ /** The price example under the action, in the small print. */
34
+ priceExample?: ReactNode;
35
+ };
36
+ /**
37
+ * The top of a product page: a photo from edge to edge, and on it a white
38
+ * `Panel` with the page title, a text, a call to action and the price
39
+ * example, as on leabank.no's loan pages.
40
+ *
41
+ * ```tsx
42
+ * <Hero
43
+ * src="/bilder/kjokken.jpg"
44
+ * alt=""
45
+ * imageRender={<NextImage src={kitchen} alt="" fill priority />}
46
+ * title="Forbrukslån med rente fra 7,90 %"
47
+ * text="Søk om lån uten sikkerhet på få minutter og få svar med én gang."
48
+ * action={<ActionButton render={<NextLink href="/sok" />}>Søk om lån</ActionButton>}
49
+ * />
50
+ * ```
51
+ *
52
+ * It is a band of its own, not inside a `Section`: at least 700px tall
53
+ * (600px below 768px, 500px below 640px), with the panel at most 600px wide
54
+ * at the start of the 1312px column. In the reading order the panel comes
55
+ * first and the photo after it.
56
+ */
57
+ export declare function Hero({ src, alt, imageRender, title, titleRender, text, action, priceExample, render, ref, className, ...rest }: HeroProps): ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The `@leabankab/component-library/website` entry: the sections that
3
+ * leabank.no is built from. They are website-only, so they are not part of
4
+ * the main entry, and an app ships them, and their stylesheet, only where it
5
+ * imports them. The build writes their CSS Modules to dist/website.css,
6
+ * which the entry imports itself.
7
+ *
8
+ * The primitives and cards the sections hold (`Panel`, `FeaturedImage`,
9
+ * `MediaCard` and the rest) stay in the main entry. Import what this folder
10
+ * shares with the main entry from "../index" (see vite.website.config.ts and
11
+ * tests/entries.test.tsx).
12
+ *
13
+ * Names are flat (`SectionHeader`, not `Section.Header`): the website renders
14
+ * these from server components, which can't dot into a client bundle.
15
+ */
16
+ export * from './brand-letters';
17
+ export * from './calculator';
18
+ export * from './carousel';
19
+ export * from './cta-banner';
20
+ export * from './expanding-cards';
21
+ export * from './expanding-cards-item';
22
+ export * from './hero';
23
+ export * from './hero-service-grid';
24
+ export * from './navigation-grid';
25
+ export * from './partner-list';
26
+ export * from './payment-feature';
27
+ export * from './promo-grid';
28
+ export * from './section';
29
+ export * from './section-header';
30
+ export * from './service-card-grid';
31
+ export * from './split-content';
32
+ export * from './stats';
33
+ export * from './testimonials';