@funidata/fudis-core 0.0.1

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/README.md ADDED
@@ -0,0 +1 @@
1
+ Do not edit - CI will overwrite this file with the root README.md on release.
package/_index.scss ADDED
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Export all Core SCSS files here
3
+ */
4
+ @forward './src/assets/fonts/fonts';
5
+ @forward './src/foundations/borders/tokens';
6
+ @forward './src/foundations/breakpoints/tokens';
7
+ @forward './src/foundations/colors/tokens';
8
+ @forward './src/foundations/focus/tokens';
9
+ @forward './src/foundations/grid/tokens';
10
+ @forward './src/foundations/spacing/tokens';
11
+ @forward './src/foundations/typography/tokens';
12
+ @forward './src/foundations/z-index/tokens';
13
+ @forward './src/foundations/borders/mixins';
14
+ @forward './src/foundations/breakpoints/mixins';
15
+ @forward './src/foundations/colors/mixins';
16
+ @forward './src/foundations/focus/mixins';
17
+ @forward './src/foundations/grid/mixins';
18
+ @forward './src/foundations/spacing/mixins';
19
+ @forward './src/foundations/typography/mixins';
20
+ @forward './src/foundations/utilities/mixins';
21
+ @forward './src/foundations/z-index/mixins';
22
+ @forward './src/foundations/spacing/classes';
23
+ @forward './src/foundations/utilities/classes';
24
+ @forward './src/components/button/button';
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@funidata/fudis-core",
3
+ "version": "0.0.1",
4
+ "description": "Core styles and foundations for Fudis Design System",
5
+ "files": [
6
+ "src",
7
+ "./_index.scss"
8
+ ],
9
+ "scripts": {
10
+ "start": "storybook dev -p 6007",
11
+ "build:storybook": "storybook build",
12
+ "build:dist": "scripts/copy-files.sh",
13
+ "test": "echo \"Error: no test specified\" && exit 1"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/funidata/fudis-core.git"
18
+ },
19
+ "keywords": [
20
+ "funidata",
21
+ "design-system",
22
+ "core-styles",
23
+ "foundations"
24
+ ],
25
+ "author": "Funidata Ltd",
26
+ "license": "CC-BY-NC-SA-4.0",
27
+ "bugs": {
28
+ "url": "https://github.com/funidata/fudis-core/issues"
29
+ },
30
+ "homepage": "https://github.com/funidata/fudis-core#readme",
31
+ "devDependencies": {
32
+ "@storybook/addon-a11y": "^8.6.12",
33
+ "@storybook/addon-essentials": "^8.6.12",
34
+ "@storybook/addon-storysource": "^8.6.12",
35
+ "@storybook/blocks": "^8.6.12",
36
+ "@storybook/html": "^8.6.12",
37
+ "@storybook/html-vite": "^8.6.12",
38
+ "@storybook/test": "^8.6.12",
39
+ "sass-embedded": "^1.86.3",
40
+ "storybook": "^8.6.12"
41
+ }
42
+ }
@@ -0,0 +1,33 @@
1
+ /* stylelint-disable property-disallowed-list */
2
+
3
+ // Light, 300
4
+ @font-face {
5
+ font-family: 'Fira Sans';
6
+ src: url('./woff/FiraSans-Light.woff2');
7
+ font-weight: 300;
8
+ font-style: normal;
9
+ }
10
+
11
+ // Regular, 400
12
+ @font-face {
13
+ font-family: 'Fira Sans';
14
+ src: url('./woff/FiraSans-Regular.woff2');
15
+ font-weight: 400;
16
+ font-style: normal;
17
+ }
18
+
19
+ // Medium, 500
20
+ @font-face {
21
+ font-family: 'Fira Sans';
22
+ src: url('./woff/FiraSans-Medium.woff2');
23
+ font-weight: 500;
24
+ font-style: normal;
25
+ }
26
+
27
+ // Semibold, 600
28
+ @font-face {
29
+ font-family: 'Fira Sans';
30
+ src: url('./woff/FiraSans-SemiBold.woff2');
31
+ font-weight: 600;
32
+ font-style: normal;
33
+ }
@@ -0,0 +1,58 @@
1
+ @use '../../foundations/colors/mixins.scss' as colors;
2
+ @use '../../foundations/focus/mixins.scss' as focus;
3
+ @use '../../foundations/borders/mixins.scss' as borders;
4
+ @use '../../foundations/typography/mixins.scss' as typography;
5
+ @use '../../foundations/spacing/tokens.scss' as spacing;
6
+ @use '../../foundations/utilities/mixins.scss' as utilities;
7
+
8
+ .fudis-button {
9
+ @include utilities.box-reset;
10
+ @include borders.border-radius('2px');
11
+ @include colors.bg-color('transparent');
12
+ @include typography.button-typography;
13
+ @include borders.border('2px', 'solid', 'primary');
14
+
15
+ display: inline-flex;
16
+ align-items: center;
17
+ justify-content: center;
18
+ cursor: pointer;
19
+ padding: 0 spacing.$spacing-xs;
20
+ min-width: spacing.$spacing-xxl;
21
+ vertical-align: middle;
22
+
23
+ &:focus {
24
+ @include focus.focus-generic;
25
+ }
26
+
27
+ &[aria-disabled='true'] {
28
+ @include colors.text-color('gray-dark');
29
+ @include colors.bg-color('gray-light');
30
+ @include borders.border('2px', 'solid', 'transparent');
31
+ @include borders.outline('1px', 'dashed', 'gray-middle');
32
+ }
33
+
34
+ &__primary {
35
+ @include colors.text-color('white');
36
+ @include colors.bg-color('primary');
37
+ }
38
+
39
+ &__secondary {
40
+ @include colors.text-color('primary');
41
+ @include colors.bg-color('white');
42
+ }
43
+
44
+ &__tertiary {
45
+ @include colors.text-color('primary');
46
+ @include borders.border('2px', 'solid', 'transparent');
47
+ }
48
+
49
+ &__size {
50
+ &__small {
51
+ min-height: spacing.$spacing-md;
52
+ }
53
+
54
+ &__medium {
55
+ min-height: spacing.$spacing-lg;
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,49 @@
1
+ export default {
2
+ title: "Components/Button",
3
+ decorators: [
4
+ (storyFn) =>
5
+ `<div style="display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-start;">${storyFn()}</div>`,
6
+ ],
7
+ };
8
+
9
+ export const Primary = () => `
10
+ <button class="fudis-button fudis-button__primary fudis-button__size__medium">
11
+ Primary
12
+ </button>
13
+ `;
14
+
15
+ export const Secondary = () => `
16
+ <button class="fudis-button fudis-button__secondary fudis-button__size__medium">
17
+ Secondary
18
+ </button>
19
+ `;
20
+
21
+ export const Tertiary = () => `
22
+ <button class="fudis-button fudis-button__tertiary fudis-button__size__medium">
23
+ Tertiary
24
+ </button>
25
+ `;
26
+
27
+ export const Primary_Small = () => `
28
+ <button class="fudis-button fudis-button__primary fudis-button__size__small">
29
+ Primary Small
30
+ </button>
31
+ `;
32
+
33
+ export const Secondary_Small = () => `
34
+ <button class="fudis-button fudis-button__secondary fudis-button__size__small">
35
+ Secondary Small
36
+ </button>
37
+ `;
38
+
39
+ export const Tertiary_Small = () => `
40
+ <button class="fudis-button fudis-button__tertiary fudis-button__size__small">
41
+ Tertiary Small
42
+ </button>
43
+ `;
44
+
45
+ export const Disabled = () => `
46
+ <button aria-disabled="true" class="fudis-button fudis-button__primary fudis-button__size__medium">
47
+ Disabled
48
+ </button>
49
+ `;
@@ -0,0 +1,57 @@
1
+ /* stylelint-disable @stylistic/block-opening-brace-space-before */
2
+ /* stylelint-disable declaration-property-value-disallowed-list */
3
+ /* stylelint-disable property-disallowed-list */
4
+ @use 'sass:map';
5
+ @use './../colors/tokens.scss' as colors;
6
+ @use './../spacing/tokens.scss' as spacing;
7
+ @use './tokens.scss' as borderTokens;
8
+
9
+ /**
10
+ Generates border, i. e.:
11
+ border: 2px solid $primary-dark;
12
+ */
13
+ @mixin border($width, $style, $color) {
14
+ @if map.has-key(spacing.$pixel-tokens, $width) and
15
+ map.has-key(borderTokens.$border-styles, $style) and
16
+ map.has-key(colors.$colors, $color)
17
+ {
18
+ border: map.get(spacing.$pixel-tokens, $width)
19
+ map.get(borderTokens.$border-styles, $style)
20
+ map.get(colors.$colors, $color);
21
+ } @else {
22
+ @error 'Unknown border parameter. Please check foundations/borders/mixins.scss for accepted arguments.';
23
+ }
24
+ }
25
+
26
+ /**
27
+ Generates outline i.e. outline: 2px solid $primary-dark;
28
+ */
29
+ @mixin outline($width, $style, $color) {
30
+ @if map.has-key(spacing.$pixel-tokens, $width) and
31
+ map.has-key(borderTokens.$border-styles, $style) and
32
+ map.has-key(colors.$colors, $color)
33
+ {
34
+ outline: map.get(spacing.$pixel-tokens, $width)
35
+ map.get(borderTokens.$border-styles, $style)
36
+ map.get(colors.$colors, $color);
37
+ outline-offset: -(map.get(spacing.$pixel-tokens, $width));
38
+ } @else {
39
+ @error 'Unknown border parameter. Please check foundations/borders/mixins.scss for accepted arguments.';
40
+ }
41
+ }
42
+
43
+ @mixin border-radius($width) {
44
+ @if map.has-key(spacing.$pixel-tokens, $width) {
45
+ border-radius: map.get(spacing.$pixel-tokens, $width);
46
+ } @else {
47
+ @error 'Unknown border-radius of #{$width}. It can only be "1px", "2px" or "3px"';
48
+ }
49
+ }
50
+
51
+ @mixin border-none() {
52
+ border: none;
53
+ }
54
+
55
+ @mixin outline-none() {
56
+ outline: none;
57
+ }
@@ -0,0 +1,5 @@
1
+ $border-styles: (
2
+ 'solid': solid,
3
+ 'dashed': dashed,
4
+ 'none': none,
5
+ );
@@ -0,0 +1,29 @@
1
+ /* stylelint-disable @stylistic/block-opening-brace-space-before */
2
+ @use 'sass:map';
3
+ @use './tokens';
4
+
5
+ @mixin breakpoint($breakpoint) {
6
+ @if map.has-key(tokens.$breakpoints, $breakpoint) {
7
+ $breakpoint-value: map.get(tokens.$breakpoints, $breakpoint);
8
+
9
+ @media screen and (min-width: #{$breakpoint-value}) {
10
+ @content;
11
+ }
12
+ } @else {
13
+ @error 'Unknown minimum breakpoint of #{$breakpoint}. Accepted arguments are: "xxl", "xl", "lg", "md", "sm", "xs".';
14
+ }
15
+ }
16
+
17
+ @mixin breakpoint-max($breakpoint) {
18
+ @if map.has-key(tokens.$max-breakpoints, $breakpoint) and $breakpoint != 'xs'
19
+ {
20
+ $breakpoint-value: map.get(tokens.$max-breakpoints, $breakpoint);
21
+ $calc-max-width: calc($breakpoint-value - 0.01em);
22
+
23
+ @media screen and (max-width: #{$calc-max-width}) {
24
+ @content;
25
+ }
26
+ } @else {
27
+ @error 'Unknown maximum breakpoint of #{$breakpoint}. Accepted arguments are: "xxl", "xl", "lg", "md", and "sm"';
28
+ }
29
+ }
@@ -0,0 +1,23 @@
1
+ // Meant to be used as "min-width" for breakpoints
2
+ $breakpoint-xxl: 100em; // 1600px-;
3
+ $breakpoint-xl: 75em; // 1200px-1599px;
4
+ $breakpoint-lg: 62em; // 992px-1199px;
5
+ $breakpoint-md: 48em; // 768px-991px;
6
+ $breakpoint-sm: 36em; // 576px-767px;
7
+ $breakpoint-xs: 0; // 0-575px;
8
+
9
+ $breakpoints: (
10
+ 'xxl': $breakpoint-xxl,
11
+ 'xl': $breakpoint-xl,
12
+ 'lg': $breakpoint-lg,
13
+ 'md': $breakpoint-md,
14
+ 'sm': $breakpoint-sm,
15
+ 'xs': $breakpoint-xs,
16
+ );
17
+ $max-breakpoints: (
18
+ 'xxl': $breakpoint-xxl,
19
+ 'xl': $breakpoint-xl,
20
+ 'lg': $breakpoint-lg,
21
+ 'md': $breakpoint-md,
22
+ 'sm': $breakpoint-sm,
23
+ );
@@ -0,0 +1,20 @@
1
+ @use 'sass:map';
2
+ @use './tokens' as colors;
3
+
4
+ @mixin text-color($color) {
5
+ @if map.has-key(colors.$colors, $color) {
6
+ /* stylelint-disable-next-line property-disallowed-list */
7
+ color: map.get(colors.$colors, $color);
8
+ } @else {
9
+ @error 'Unknown palette color of #{$color}. Check colors/tokens.scss file for accepted arguments.';
10
+ }
11
+ }
12
+
13
+ @mixin bg-color($color) {
14
+ @if map.has-key(colors.$colors, $color) {
15
+ /* stylelint-disable-next-line property-disallowed-list */
16
+ background-color: map.get(colors.$colors, $color);
17
+ } @else {
18
+ @error 'Unknown palette background color of #{$color}. Check colors/tokens.scss file for accepted arguments.';
19
+ }
20
+ }
@@ -0,0 +1,54 @@
1
+ @use 'sass:map';
2
+
3
+ /* stylelint-disable color-no-hex */
4
+
5
+ /*
6
+ --- Primary Colors ---
7
+ */
8
+ $color-primary-light: var(--fudis-color-primary-light);
9
+ $color-primary: var(--fudis-color-primary);
10
+ $color-primary-dark: var(--fudis-color-primary-dark);
11
+ $color-primary-extra-dark: var(--fudis-color-primary-extra-dark);
12
+
13
+ /*
14
+ --- Secondary & Accent Colors ---
15
+ */
16
+
17
+ // Grays
18
+
19
+ $color-black: #000000;
20
+ $color-white: #ffffff;
21
+ $color-gray-extra-light: #f1f1f1;
22
+ $color-gray-light: #d4d4d4;
23
+ $color-gray-middle: #727272;
24
+ $color-gray-dark: #484848;
25
+
26
+ // Accent colors
27
+
28
+ $color-red-light: #f8dcd9;
29
+ $color-red: #b83c2e;
30
+ $color-yellow-light: #fdefb4;
31
+ $color-yellow: #f1c40f;
32
+ $color-green-light: #c6ecd6;
33
+ $color-green: #1e874b;
34
+ $color-focus-primary: #1076db;
35
+ $colors: (
36
+ 'primary-light': $color-primary-light,
37
+ 'primary': $color-primary,
38
+ 'primary-dark': $color-primary-dark,
39
+ 'primary-extra-dark': $color-primary-extra-dark,
40
+ 'black': $color-black,
41
+ 'white': $color-white,
42
+ 'gray-extra-light': $color-gray-extra-light,
43
+ 'gray-light': $color-gray-light,
44
+ 'gray-middle': $color-gray-middle,
45
+ 'gray-dark': $color-gray-dark,
46
+ 'red-light': $color-red-light,
47
+ 'red': $color-red,
48
+ 'yellow-light': $color-yellow-light,
49
+ 'yellow': $color-yellow,
50
+ 'green-light': $color-green-light,
51
+ 'green': $color-green,
52
+ 'focus-primary': $color-focus-primary,
53
+ 'transparent': transparent,
54
+ );
@@ -0,0 +1,33 @@
1
+ /* stylelint-disable property-disallowed-list */
2
+ @use './../spacing/tokens.scss' as spacing;
3
+ @use './../borders/mixins.scss' as borders;
4
+ @use './../colors/tokens' as colors;
5
+ @use './tokens' as tokens;
6
+
7
+ @mixin focus-generic {
8
+ outline: tokens.$focus-generic-outline;
9
+ outline-offset: spacing.$pixel-1;
10
+ box-shadow: 0 0 0 spacing.$spacing-xxs colors.$color-white;
11
+ }
12
+
13
+ @mixin focus-form-field {
14
+ @include borders.border('1px', 'solid', 'focus-primary');
15
+
16
+ outline: tokens.$focus-form-field-outline;
17
+ outline-offset: -(spacing.$pixel-2);
18
+ box-shadow: 0 0 0 spacing.$pixel-1 colors.$color-white;
19
+ }
20
+
21
+ @mixin focus-checkbox {
22
+ @include borders.outline('2px', 'solid', 'primary');
23
+
24
+ outline-offset: -(spacing.$pixel-1);
25
+ width: spacing.$checkbox-size;
26
+ height: spacing.$checkbox-size;
27
+ }
28
+
29
+ @mixin focus-dropdown {
30
+ outline: tokens.$focus-generic-outline;
31
+ outline-offset: -(spacing.$pixel-2);
32
+ box-shadow: 0 0 0 spacing.$spacing-xxs colors.$color-white;
33
+ }
@@ -0,0 +1,6 @@
1
+ @use './../colors/tokens.scss' as colors;
2
+ @use './../spacing/tokens.scss' as spacing;
3
+
4
+ // Variables for Generic and Form field focus outlines
5
+ $focus-generic-outline: spacing.$pixel-2 dashed colors.$color-gray-dark;
6
+ $focus-form-field-outline: spacing.$pixel-2 solid colors.$color-focus-primary;
@@ -0,0 +1,30 @@
1
+ @use 'sass:map';
2
+ @use './tokens' as tokens;
3
+ @use './../spacing/tokens.scss' as spacing;
4
+
5
+ @mixin grid-max-width($width) {
6
+ @if map.has-key(tokens.$grid-widths, $width) {
7
+ $grid-width-value: map.get(tokens.$grid-widths, $width);
8
+
9
+ max-width: $grid-width-value;
10
+
11
+ @if $width == xl or $width == xxl {
12
+ gap: spacing.$spacing-lg spacing.$spacing-lg;
13
+ }
14
+
15
+ @if $width == md or $width == lg {
16
+ gap: spacing.$spacing-md spacing.$spacing-md;
17
+ }
18
+
19
+ @if $width == sm or $width == xs {
20
+ gap: spacing.$spacing-sm spacing.$spacing-sm;
21
+ }
22
+ } @else {
23
+ @error 'Unknown grid width of #{$width}. Accepted arguments are: "xxl", "xl", "lg", "md", "sm", "xs".';
24
+ }
25
+ }
26
+
27
+ @mixin grid-xs-margins() {
28
+ margin-right: spacing.$spacing-sm;
29
+ margin-left: spacing.$spacing-sm;
30
+ }
@@ -0,0 +1,18 @@
1
+ // TODO: is $grid-width-xs actually needed? Check from designers was there a reasoning for it
2
+
3
+ /* stylelint-disable unit-disallowed-list */
4
+ $grid-width-xs: calc(34rem / var(--fudis-rem-multiplier)); // 320px-544px
5
+ $grid-width-sm: calc(34rem / var(--fudis-rem-multiplier)); // 544px
6
+ $grid-width-md: calc(45rem / var(--fudis-rem-multiplier)); // 720px
7
+ $grid-width-lg: calc(60rem / var(--fudis-rem-multiplier)); // 960px
8
+ $grid-width-xl: calc(65rem / var(--fudis-rem-multiplier)); // 1040px
9
+ $grid-width-xxl: calc(96.25rem / var(--fudis-rem-multiplier)); // 1540px
10
+
11
+ $grid-widths: (
12
+ 'xxl': $grid-width-xxl,
13
+ 'xl': $grid-width-xl,
14
+ 'lg': $grid-width-lg,
15
+ 'md': $grid-width-md,
16
+ 'sm': $grid-width-sm,
17
+ 'xs': $grid-width-xs,
18
+ );
@@ -0,0 +1,28 @@
1
+ @use './tokens.scss' as spacing;
2
+ @use './mixins.scss' as mixins;
3
+ @use './../breakpoints/mixins.scss' as breakpoints;
4
+ @include mixins.spacing-classes('fudis');
5
+
6
+ @include breakpoints.breakpoint('xs') {
7
+ @include mixins.spacing-classes('fudis-xs');
8
+ }
9
+
10
+ @include breakpoints.breakpoint('sm') {
11
+ @include mixins.spacing-classes('fudis-sm');
12
+ }
13
+
14
+ @include breakpoints.breakpoint('md') {
15
+ @include mixins.spacing-classes('fudis-md');
16
+ }
17
+
18
+ @include breakpoints.breakpoint('lg') {
19
+ @include mixins.spacing-classes('fudis-lg');
20
+ }
21
+
22
+ @include breakpoints.breakpoint('xl') {
23
+ @include mixins.spacing-classes('fudis-xl');
24
+ }
25
+
26
+ @include breakpoints.breakpoint('xxl') {
27
+ @include mixins.spacing-classes('fudis-xxl');
28
+ }
@@ -0,0 +1,60 @@
1
+ /* stylelint-disable declaration-no-important */
2
+ @use './tokens.scss' as spacing;
3
+
4
+ $direction-attributes: (
5
+ 'm': 'margin',
6
+ 'mt': 'margin-top',
7
+ 'mb': 'margin-bottom',
8
+ 'ml': 'margin-left',
9
+ 'mr': 'margin-right',
10
+ 'p': 'padding',
11
+ 'pt': 'padding-top',
12
+ 'pb': 'padding-bottom',
13
+ 'pl': 'padding-left',
14
+ 'pr': 'padding-right',
15
+ );
16
+ $spacing-tokens: (
17
+ 'none': spacing.$spacing-none,
18
+ 'xxs': spacing.$spacing-xxs,
19
+ 'xs': spacing.$spacing-xs,
20
+ 'sm': spacing.$spacing-sm,
21
+ 'md': spacing.$spacing-md,
22
+ 'lg': spacing.$spacing-lg,
23
+ 'xl': spacing.$spacing-xl,
24
+ 'xxl': spacing.$spacing-xxl,
25
+ );
26
+
27
+ @mixin spacing-classes($prefix) {
28
+ @each $sKey, $sValue in $spacing-tokens {
29
+ @each $dirKey, $dirValue in $direction-attributes {
30
+ // Generates for desired screen size margin or padding with desired direction. E.g. .fudis-lg-ml-sm or .fudis-sm-pt-xl
31
+ .#{$prefix}-#{$dirKey}-#{$sKey} {
32
+ #{$dirValue}: #{$sValue} !important;
33
+ }
34
+ }
35
+
36
+ // Generates horizontal margins e.g. .fudis-lg-mx-sm
37
+ .#{$prefix}-mx-#{$sKey} {
38
+ margin-right: #{$sValue} !important;
39
+ margin-left: #{$sValue} !important;
40
+ }
41
+
42
+ // Generates vertical margins e.g. .fudis-lg-my-sm
43
+ .#{$prefix}-my-#{$sKey} {
44
+ margin-top: #{$sValue} !important;
45
+ margin-bottom: #{$sValue} !important;
46
+ }
47
+
48
+ // Generates horizontal padding e.g. .fudis-lg-px-sm
49
+ .#{$prefix}-px-#{$sKey} {
50
+ padding-right: #{$sValue} !important;
51
+ padding-left: #{$sValue} !important;
52
+ }
53
+
54
+ // Generates vertical padding e.g. .fudis-lg-py-sm
55
+ .#{$prefix}-py-#{$sKey} {
56
+ padding-top: #{$sValue} !important;
57
+ padding-bottom: #{$sValue} !important;
58
+ }
59
+ }
60
+ }
@@ -0,0 +1,31 @@
1
+ /* stylelint-disable unit-disallowed-list */
2
+
3
+ // Spacing values, based on default 16px base value
4
+ $spacing-none: 0; // 0px
5
+ $spacing-xxs: calc(0.25rem / var(--fudis-rem-multiplier)); // 4px
6
+ $spacing-xs: calc(0.5rem / var(--fudis-rem-multiplier)); // 8px
7
+ $spacing-sm: calc(1rem / var(--fudis-rem-multiplier)); // 16px
8
+ $spacing-md: calc(1.5rem / var(--fudis-rem-multiplier)); // 24px
9
+ $spacing-lg: calc(2rem / var(--fudis-rem-multiplier)); // 32px
10
+ $spacing-xl: calc(2.5rem / var(--fudis-rem-multiplier)); // 40px
11
+ $spacing-xxl: calc(4rem / var(--fudis-rem-multiplier)); // 64px
12
+
13
+ $pixel-1: 1px;
14
+ $pixel-2: 2px;
15
+ $pixel-3: 3px;
16
+
17
+ // Used with borders, border-radius and letter-spacing mixins. Any value >=4px should be used from spacing values above.
18
+ $pixel-tokens: (
19
+ '1px': $pixel-1,
20
+ '2px': $pixel-2,
21
+ '3px': $pixel-3,
22
+ );
23
+
24
+ // Form input width tokens
25
+ $input-width-xs: calc(5.75rem / var(--fudis-rem-multiplier));
26
+ $input-width-sm: calc(10rem / var(--fudis-rem-multiplier));
27
+ $input-width-md: calc(14rem / var(--fudis-rem-multiplier));
28
+ $input-width-lg: calc(23rem / var(--fudis-rem-multiplier));
29
+
30
+ // Fixed size for checkboxes' visual input box. Clickable input area should be 2rem high.
31
+ $checkbox-size: calc(1.25rem / var(--fudis-rem-multiplier));
@@ -0,0 +1,287 @@
1
+ /* stylelint-disable property-disallowed-list */
2
+ /* stylelint-disable unit-disallowed-list */
3
+ @use 'sass:map';
4
+ @use './../breakpoints/mixins.scss' as breakpoints;
5
+ @use './../spacing/tokens.scss' as spacing;
6
+ @use './../colors/mixins.scss' as colors;
7
+ @use './../focus/mixins.scss' as focus;
8
+ @use './tokens.scss' as tokens;
9
+
10
+ // Body Text
11
+
12
+ @mixin body-text-lg-light {
13
+ text-transform: initial;
14
+ line-height: tokens.$body-text-lg-line-height;
15
+ font-family: tokens.$font-family;
16
+ font-size: tokens.$body-text-lg-font-size;
17
+ font-weight: tokens.$font-weight-light;
18
+ }
19
+
20
+ @mixin body-text-lg-regular {
21
+ text-transform: initial;
22
+ line-height: tokens.$body-text-lg-line-height;
23
+ font-family: tokens.$font-family;
24
+ font-size: tokens.$body-text-lg-font-size;
25
+ font-weight: tokens.$font-weight-regular;
26
+ }
27
+
28
+ @mixin body-text-md-light {
29
+ text-transform: initial;
30
+ line-height: tokens.$body-text-md-line-height;
31
+ font-family: tokens.$font-family;
32
+ font-size: tokens.$body-text-md-font-size;
33
+ font-weight: tokens.$font-weight-light;
34
+ }
35
+
36
+ @mixin body-text-md-regular {
37
+ text-transform: initial;
38
+ line-height: tokens.$body-text-md-line-height;
39
+ font-family: tokens.$font-family;
40
+ font-size: tokens.$body-text-md-font-size;
41
+ font-weight: tokens.$font-weight-regular;
42
+ }
43
+
44
+ @mixin body-text-sm-regular {
45
+ text-transform: initial;
46
+ line-height: tokens.$body-text-sm-line-height;
47
+ font-family: tokens.$font-family;
48
+ font-size: tokens.$body-text-sm-font-size;
49
+ font-weight: tokens.$font-weight-regular;
50
+ }
51
+
52
+ // Headings
53
+
54
+ @mixin heading-xxl {
55
+ line-height: tokens.$heading-lg-line-height;
56
+ font-family: tokens.$font-family;
57
+ font-size: tokens.$heading-xxl-font-size;
58
+ font-weight: tokens.$font-weight-medium;
59
+
60
+ @include breakpoints.breakpoint-max('sm') {
61
+ font-size: tokens.$heading-xl-font-size;
62
+ }
63
+ }
64
+
65
+ @mixin heading-xl {
66
+ line-height: tokens.$heading-lg-line-height;
67
+ font-family: tokens.$font-family;
68
+ font-size: tokens.$heading-xl-font-size;
69
+ font-weight: tokens.$font-weight-medium;
70
+
71
+ @include breakpoints.breakpoint-max('sm') {
72
+ line-height: tokens.$heading-md-line-height;
73
+ font-size: tokens.$heading-lg-font-size;
74
+ }
75
+ }
76
+
77
+ @mixin heading-lg {
78
+ line-height: tokens.$heading-md-line-height;
79
+ font-family: tokens.$font-family;
80
+ font-size: tokens.$heading-lg-font-size;
81
+ font-weight: tokens.$font-weight-medium;
82
+
83
+ @include breakpoints.breakpoint-max('sm') {
84
+ font-size: tokens.$heading-md-font-size;
85
+ }
86
+ }
87
+
88
+ @mixin heading-md {
89
+ line-height: tokens.$heading-md-line-height;
90
+ font-family: tokens.$font-family;
91
+ font-size: tokens.$heading-md-font-size;
92
+ font-weight: tokens.$font-weight-medium;
93
+
94
+ @include breakpoints.breakpoint-max('sm') {
95
+ line-height: tokens.$heading-sm-line-height;
96
+ font-size: tokens.$heading-sm-font-size;
97
+ }
98
+ }
99
+
100
+ @mixin heading-sm {
101
+ line-height: tokens.$heading-sm-line-height;
102
+ font-family: tokens.$font-family;
103
+ font-size: tokens.$heading-sm-font-size;
104
+ font-weight: tokens.$font-weight-medium;
105
+
106
+ @include breakpoints.breakpoint-max('sm') {
107
+ font-size: tokens.$heading-xs-font-size;
108
+ font-weight: tokens.$font-weight-bold;
109
+ }
110
+ }
111
+
112
+ @mixin heading-xs {
113
+ line-height: tokens.$heading-sm-line-height;
114
+ font-family: tokens.$font-family;
115
+ font-size: tokens.$heading-xs-font-size;
116
+ font-weight: tokens.$font-weight-bold;
117
+
118
+ @include breakpoints.breakpoint-max('sm') {
119
+ font-size: tokens.$heading-xxs-font-size;
120
+ }
121
+ }
122
+
123
+ @mixin heading-xxs {
124
+ line-height: tokens.$heading-sm-line-height;
125
+ font-family: tokens.$font-family;
126
+ font-size: tokens.$heading-xxs-font-size;
127
+ font-weight: tokens.$font-weight-bold;
128
+ }
129
+
130
+ // Table caption
131
+
132
+ @mixin table-caption {
133
+ text-transform: uppercase;
134
+ line-height: tokens.$text-input-line-height;
135
+ font-family: tokens.$font-family;
136
+ font-size: tokens.$body-text-md-font-size;
137
+ font-weight: tokens.$font-weight-regular;
138
+ }
139
+
140
+ // Other UI styles
141
+
142
+ // Text-input, text-area, dropdown, legend components
143
+
144
+ @mixin text-field-label {
145
+ text-transform: uppercase;
146
+ line-height: tokens.$form-label-line-height;
147
+ font-family: tokens.$font-family;
148
+ font-size: tokens.$body-text-md-font-size;
149
+ font-weight: tokens.$font-weight-regular;
150
+ }
151
+
152
+ @mixin text-field-input {
153
+ line-height: tokens.$text-input-line-height;
154
+ font-family: tokens.$font-family;
155
+ font-size: tokens.$body-text-lg-font-size;
156
+ font-weight: tokens.$font-weight-light;
157
+ }
158
+
159
+ @mixin select-group-label {
160
+ line-height: tokens.$text-input-line-height;
161
+ font-family: tokens.$font-family;
162
+ font-size: tokens.$body-text-sm-font-size;
163
+ font-weight: tokens.$font-weight-light;
164
+ }
165
+
166
+ // Badge component
167
+
168
+ @mixin badge-typography {
169
+ text-transform: uppercase;
170
+ line-height: tokens.$badge-line-height;
171
+ font-family: tokens.$font-family;
172
+ font-size: tokens.$body-text-sm-font-size;
173
+ font-weight: tokens.$font-weight-regular;
174
+ }
175
+
176
+ // Description-list component
177
+
178
+ @mixin description-list-key-typography {
179
+ @include text-field-label;
180
+ }
181
+
182
+ @mixin description-list-value-typography {
183
+ line-height: tokens.$body-text-lg-line-height;
184
+ font-family: tokens.$font-family;
185
+ font-size: tokens.$body-text-lg-font-size;
186
+ font-weight: tokens.$font-weight-light;
187
+ }
188
+
189
+ @mixin description-list-compact-key-typography {
190
+ text-transform: none;
191
+ line-height: tokens.$body-text-lg-line-height;
192
+ font-family: tokens.$font-family;
193
+ font-size: tokens.$body-text-md-font-size;
194
+ font-weight: tokens.$font-weight-light;
195
+ }
196
+
197
+ @mixin description-list-compact-value-typography {
198
+ line-height: tokens.$body-text-lg-line-height;
199
+ font-family: tokens.$font-family;
200
+ font-size: tokens.$body-text-md-font-size;
201
+ font-weight: tokens.$font-weight-regular;
202
+ }
203
+
204
+ // Button component
205
+
206
+ @mixin button-typography {
207
+ @include letter-spacing('1px');
208
+
209
+ text-transform: uppercase;
210
+ line-height: tokens.$body-text-sm-line-height;
211
+ /* stylelint-disable-next-line @stylistic/declaration-colon-space-after */
212
+ font-family:
213
+ tokens.$font-family, 'Helvetica Neue', Helvetica, Arial, sans-serif;
214
+ font-size: tokens.$body-text-md-font-size;
215
+ font-weight: tokens.$font-weight-bold;
216
+ }
217
+
218
+ @mixin letter-spacing($width) {
219
+ @if map.has-key(spacing.$pixel-tokens, $width) {
220
+ letter-spacing: map.get(spacing.$pixel-tokens, $width);
221
+ } @else {
222
+ @error 'Unknown letter-spacing parameter. It can only be "1px", "2px" or "3px"';
223
+ }
224
+ }
225
+
226
+ // Expandable component
227
+
228
+ @mixin expandable-regular-typography {
229
+ line-height: tokens.$body-text-lg-line-height;
230
+ font-family: tokens.$font-family;
231
+ font-size: tokens.$body-text-lg-font-size;
232
+ font-weight: tokens.$font-weight-regular;
233
+ }
234
+
235
+ @mixin expandable-sub-title-typography {
236
+ font-family: tokens.$font-family;
237
+ font-size: tokens.$body-text-sm-font-size;
238
+ font-weight: tokens.$font-weight-light;
239
+ }
240
+
241
+ // Link component
242
+
243
+ @mixin text-link {
244
+ @include colors.text-color('primary-dark');
245
+
246
+ display: inline-block;
247
+ position: relative;
248
+ text-decoration: underline solid;
249
+ font-family: tokens.$font-family;
250
+ overflow-wrap: anywhere;
251
+
252
+ &:focus {
253
+ @include focus.focus-generic;
254
+ }
255
+ }
256
+
257
+ @mixin link-md {
258
+ @include text-link;
259
+
260
+ font-size: tokens.$body-text-md-font-size;
261
+ font-weight: tokens.$font-weight-regular;
262
+ }
263
+
264
+ @mixin link-lg {
265
+ @include text-link;
266
+
267
+ font-size: tokens.$body-text-lg-font-size;
268
+ font-weight: tokens.$font-weight-regular;
269
+ }
270
+
271
+ @mixin link-inherit {
272
+ @include text-link;
273
+
274
+ font-size: inherit;
275
+ font-weight: inherit;
276
+ }
277
+
278
+ // Empty state
279
+
280
+ @mixin text-emptystate {
281
+ @include colors.text-color('gray-middle');
282
+
283
+ font-family: tokens.$font-family;
284
+ font-size: tokens.$body-text-md-font-size;
285
+ font-weight: tokens.$font-weight-regular;
286
+ font-style: tokens.$font-style-italic;
287
+ }
@@ -0,0 +1,41 @@
1
+ /* stylelint-disable unit-disallowed-list */
2
+
3
+ $font-family: 'Fira Sans', sans-serif;
4
+
5
+ // Body text font size
6
+ $body-text-lg-font-size: calc(1rem / var(--fudis-rem-multiplier));
7
+ $body-text-md-font-size: calc(0.875rem / var(--fudis-rem-multiplier));
8
+ $body-text-sm-font-size: calc(0.75rem / var(--fudis-rem-multiplier));
9
+
10
+ // Heading font size
11
+ $heading-xxl-font-size: calc(2.25rem / var(--fudis-rem-multiplier));
12
+ $heading-xl-font-size: calc(1.75rem / var(--fudis-rem-multiplier));
13
+ $heading-lg-font-size: calc(1.5rem / var(--fudis-rem-multiplier));
14
+ $heading-md-font-size: calc(1.25rem / var(--fudis-rem-multiplier));
15
+ $heading-sm-font-size: calc(1.125rem / var(--fudis-rem-multiplier));
16
+ $heading-xs-font-size: calc(1rem / var(--fudis-rem-multiplier));
17
+ $heading-xxs-font-size: calc(0.875rem / var(--fudis-rem-multiplier));
18
+
19
+ // Body text line height
20
+ $body-text-lg-line-height: calc(1.25rem / var(--fudis-rem-multiplier));
21
+ $body-text-md-line-height: calc(1.125rem / var(--fudis-rem-multiplier));
22
+ $body-text-sm-line-height: calc(1rem / var(--fudis-rem-multiplier));
23
+
24
+ // Heading line heights
25
+ $heading-lg-line-height: calc(2.5rem / var(--fudis-rem-multiplier));
26
+ $heading-md-line-height: calc(1.75rem / var(--fudis-rem-multiplier));
27
+ $heading-sm-line-height: calc(1.125rem / var(--fudis-rem-multiplier));
28
+
29
+ // Other UI line heights
30
+ $text-input-line-height: calc(1.25rem / var(--fudis-rem-multiplier));
31
+ $form-label-line-height: calc(1.5rem / var(--fudis-rem-multiplier));
32
+ $badge-line-height: calc(0.875rem / var(--fudis-rem-multiplier));
33
+
34
+ // Font weight
35
+ $font-weight-light: 300;
36
+ $font-weight-regular: 400;
37
+ $font-weight-medium: 500;
38
+ $font-weight-bold: 600;
39
+
40
+ // Font styles
41
+ $font-style-italic: italic;
@@ -0,0 +1,53 @@
1
+ @use './mixins.scss' as mixins;
2
+ @use './../spacing/tokens.scss' as spacing;
3
+ @use './../borders/mixins.scss' as border;
4
+ @use './../colors/mixins.scss' as colors;
5
+
6
+ .fudis-visually-hidden {
7
+ @include mixins.visually-hidden;
8
+ }
9
+
10
+ .fudis-box-reset {
11
+ @include mixins.box-reset;
12
+ }
13
+
14
+ // Invalid and disabled state styles for input elemenets
15
+
16
+ .fudis-form-input {
17
+ @include border.border('1px', 'solid', 'gray-middle');
18
+ @include colors.bg-color('white');
19
+
20
+ /* stylelint-disable-next-line selector-class-pattern */
21
+ &.ng-touched,
22
+ &--touched {
23
+ &[aria-invalid='true'] {
24
+ @include border.border('1px', 'solid', 'red');
25
+ }
26
+ }
27
+
28
+ &[aria-disabled='true'] {
29
+ @include border.border('1px', 'dashed', 'gray-middle');
30
+ @include colors.bg-color('gray-extra-light');
31
+
32
+ cursor: default;
33
+ pointer-events: none;
34
+ }
35
+ }
36
+
37
+ .fudis-input-size {
38
+ &__xs {
39
+ max-width: spacing.$input-width-xs;
40
+ }
41
+
42
+ &__sm {
43
+ max-width: spacing.$input-width-sm;
44
+ }
45
+
46
+ &__md {
47
+ max-width: spacing.$input-width-md;
48
+ }
49
+
50
+ &__lg {
51
+ max-width: spacing.$input-width-lg;
52
+ }
53
+ }
@@ -0,0 +1,57 @@
1
+ /* stylelint-disable property-disallowed-list */
2
+ /* stylelint-disable unit-disallowed-list */
3
+ @use './../spacing/tokens.scss' as spacing;
4
+ @use './../colors/tokens.scss' as colors;
5
+ @use './../typography/mixins.scss' as typography;
6
+ @use './../borders/mixins.scss' as borders;
7
+ @use './../focus/mixins.scss' as focus;
8
+
9
+ @mixin visually-hidden() {
10
+ position: absolute;
11
+ left: 0;
12
+ opacity: 0;
13
+ margin: -1px;
14
+ outline: 0;
15
+ border: 0;
16
+ padding: 0;
17
+ width: 1px;
18
+ height: 1px;
19
+ overflow: hidden;
20
+ white-space: nowrap;
21
+ clip: rect(0 0 0 0);
22
+ }
23
+
24
+ @mixin box-reset() {
25
+ box-sizing: border-box;
26
+ margin: 0;
27
+ padding: 0;
28
+ }
29
+
30
+ @mixin text-input() {
31
+ @include typography.text-field-input;
32
+ @include borders.border-radius('2px');
33
+
34
+ box-sizing: border-box;
35
+ padding: spacing.$spacing-xxs spacing.$spacing-sm;
36
+ width: 100%;
37
+ height: spacing.$spacing-xl;
38
+
39
+ &:focus {
40
+ @include focus.focus-form-field;
41
+ }
42
+ }
43
+
44
+ @mixin text-area() {
45
+ @include typography.text-field-input;
46
+
47
+ box-sizing: border-box;
48
+ display: block;
49
+ padding: spacing.$spacing-xxs;
50
+ width: 100%;
51
+ height: calc(5rem / var(--fudis-rem-multiplier));
52
+ resize: vertical; // Enable resizing the textarea only vertically. Can be also 'none' if we want to disable resizing all together
53
+
54
+ &:focus {
55
+ @include focus.focus-form-field;
56
+ }
57
+ }
@@ -0,0 +1,11 @@
1
+ @use 'sass:map';
2
+ @use './tokens' as tokens;
3
+
4
+ @mixin z-index($layer-name) {
5
+ @if map.has-key(tokens.$layer-names, $layer-name) {
6
+ /* stylelint-disable-next-line property-disallowed-list */
7
+ z-index: map.get(tokens.$layer-names, $layer-name);
8
+ } @else {
9
+ @error 'Unknown z-index layer name of #{$layer-name}. Accepted names are: "dropdown-menu", "dialog" and "alert".';
10
+ }
11
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Add new z-index layer names when needed. Do not clutter, keep z-index options minimum.
3
+ */
4
+ $z-index-dropdown-menu: 100;
5
+ $z-index-dialog: 200;
6
+ $z-index-alert: 300;
7
+
8
+ /**
9
+ * If we don't want to maintain static z-index numbers, this could be refactored so that we have an array of layer names
10
+ * and z-indexes are calculated according to the array indexes * 100.
11
+ * This way the possible top/below priority doesn't need manual refactoring of the z-index values above.
12
+ */
13
+ $layer-names: (
14
+ 'dropdown-menu': $z-index-dropdown-menu,
15
+ 'dialog': $z-index-dialog,
16
+ 'alert': $z-index-alert,
17
+ );