@tuspe/components 1.6.26

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.
@@ -0,0 +1,51 @@
1
+ <script lang="ts">
2
+ import Button from './Button.svelte'
3
+ interface Props {
4
+ onclick?: () => any
5
+ ariaControls: string
6
+ ariaLabel: string
7
+ color?: 'black' | 'white'
8
+ extraClass?: string
9
+ hidden?: boolean
10
+ open: boolean
11
+ }
12
+ let {ariaControls, ariaLabel, color = 'white', extraClass, hidden = false, open = $bindable()}: Props = $props()
13
+ const handleOpen = () => {
14
+ open = !open
15
+ }
16
+ </script>
17
+
18
+ <div id="menu-button" class={extraClass} class:hidden>
19
+ <Button onclick={handleOpen} {ariaControls} ariaPopup="menu" ariaExpanded={open} {ariaLabel} {color} control fill>
20
+ <svg
21
+ fill={color}
22
+ clip-rule="evenodd"
23
+ fill-rule="evenodd"
24
+ stroke-linejoin="round"
25
+ stroke-miterlimit="2"
26
+ height="32"
27
+ width="32"
28
+ viewBox="0 0 24 24"
29
+ xmlns="http://www.w3.org/2000/svg"
30
+ >
31
+ <title>{open ? 'Close' : 'Open'} menu</title>
32
+ {#if !open}
33
+ <path
34
+ d="m22 16.75c0-.414-.336-.75-.75-.75h-18.5c-.414 0-.75.336-.75.75s.336.75.75.75h18.5c.414 0 .75-.336.75-.75zm0-5c0-.414-.336-.75-.75-.75h-18.5c-.414 0-.75.336-.75.75s.336.75.75.75h18.5c.414 0 .75-.336.75-.75zm0-5c0-.414-.336-.75-.75-.75h-18.5c-.414 0-.75.336-.75.75s.336.75.75.75h18.5c.414 0 .75-.336.75-.75z"
35
+ fill-rule="nonzero"
36
+ />
37
+ {:else}
38
+ <path
39
+ d="m12 10.93 5.719-5.72c.146-.146.339-.219.531-.219.404 0 .75.324.75.749 0 .193-.073.385-.219.532l-5.72 5.719 5.719 5.719c.147.147.22.339.22.531 0 .427-.349.75-.75.75-.192 0-.385-.073-.531-.219l-5.719-5.719-5.719 5.719c-.146.146-.339.219-.531.219-.401 0-.75-.323-.75-.75 0-.192.073-.384.22-.531l5.719-5.719-5.72-5.719c-.146-.147-.219-.339-.219-.532 0-.425.346-.749.75-.749.192 0 .385.073.531.219z"
40
+ />
41
+ {/if}
42
+ </svg>
43
+ </Button>
44
+ </div>
45
+
46
+ <style scoped>
47
+ #menu-button {
48
+ height: 48px;
49
+ width: 48px;
50
+ }
51
+ </style>
@@ -0,0 +1,12 @@
1
+ interface Props {
2
+ onclick?: () => any;
3
+ ariaControls: string;
4
+ ariaLabel: string;
5
+ color?: 'black' | 'white';
6
+ extraClass?: string;
7
+ hidden?: boolean;
8
+ open: boolean;
9
+ }
10
+ declare const ButtonMenu: import("svelte").Component<Props, {}, "open">;
11
+ type ButtonMenu = ReturnType<typeof ButtonMenu>;
12
+ export default ButtonMenu;
@@ -0,0 +1,55 @@
1
+ <script lang="ts">
2
+ import {loading} from './'
3
+ import type {Snippet} from 'svelte'
4
+
5
+ interface Props {
6
+ children: Snippet
7
+ onchange?: () => void
8
+ checked?: boolean
9
+ disabled?: boolean
10
+ id?: string
11
+ outerClass?: string
12
+ value?: string
13
+ }
14
+
15
+ let {children, onchange, checked = $bindable(false), disabled, id, outerClass, value}: Props = $props()
16
+ </script>
17
+
18
+ <label class={outerClass}>
19
+ <input bind:checked disabled={disabled || $loading} {id} {onchange} type="checkbox" {value} />
20
+ <span>{@render children?.()}</span>
21
+ </label>
22
+
23
+ <style scoped>
24
+ input {
25
+ accent-color: var(--color-primary);
26
+ border: 1px solid var(--color-border);
27
+ height: 20px;
28
+ margin-right: 10px;
29
+ outline: none;
30
+ vertical-align: middle;
31
+ width: 20px;
32
+ }
33
+
34
+ input:disabled {
35
+ cursor: not-allowed;
36
+ opacity: 0.6;
37
+ }
38
+
39
+ input,
40
+ label {
41
+ cursor: pointer;
42
+ }
43
+
44
+ label {
45
+ display: flex;
46
+ align-items: center;
47
+ cursor: pointer;
48
+ line-height: 1.25;
49
+ font-size: 1rem;
50
+ }
51
+
52
+ span {
53
+ margin-top: 1px;
54
+ }
55
+ </style>
@@ -0,0 +1,13 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ children: Snippet;
4
+ onchange?: () => void;
5
+ checked?: boolean;
6
+ disabled?: boolean;
7
+ id?: string;
8
+ outerClass?: string;
9
+ value?: string;
10
+ }
11
+ declare const Checkbox: import("svelte").Component<Props, {}, "checked">;
12
+ type Checkbox = ReturnType<typeof Checkbox>;
13
+ export default Checkbox;
@@ -0,0 +1,89 @@
1
+ <script lang="ts">
2
+ import type {ImageData} from './'
3
+
4
+ interface Props {
5
+ aspect?: '3:4' | '4:3' | 'square' | 'video'
6
+ ball?: boolean
7
+ border?: boolean
8
+ center?: boolean
9
+ extraClasses?: string
10
+ fullWidth?: boolean
11
+ image: ImageData
12
+ loading?: 'eager' | 'lazy'
13
+ objectFit?: 'contain' | 'cover'
14
+ }
15
+
16
+ let {aspect, ball = false, border, center = false, extraClasses, fullWidth, image, loading = 'lazy', objectFit}: Props = $props()
17
+
18
+ let classes = $state('')
19
+ if (aspect) {
20
+ classes += `aspect-${aspect}`
21
+ }
22
+ if (objectFit) {
23
+ classes += ' ' + objectFit
24
+ }
25
+ if (ball) {
26
+ classes += ' radius-full'
27
+ }
28
+ if (border) {
29
+ classes += ' border-full'
30
+ }
31
+ if (center) {
32
+ classes += ' mx-auto'
33
+ }
34
+ if (fullWidth) {
35
+ classes += ' full'
36
+ }
37
+ if (extraClasses) {
38
+ classes += ' ' + extraClasses
39
+ }
40
+ </script>
41
+
42
+ {#if image?.src}
43
+ <img alt={image.alt} class={classes} decoding="async" height={image.height} {loading} src={image.src} width={image.width} />
44
+ {/if}
45
+
46
+ <style scoped>
47
+ img {
48
+ display: inline-block;
49
+ }
50
+ img:not(.cover) {
51
+ height: auto;
52
+ max-width: 100%;
53
+ }
54
+ .aspect-4\:3 {
55
+ aspect-ratio: 4 / 3;
56
+ }
57
+ .aspect-3\:4 {
58
+ aspect-ratio: 3 / 4;
59
+ }
60
+ .aspect-square {
61
+ aspect-ratio: 1 / 1;
62
+ }
63
+ .aspect-video {
64
+ aspect-ratio: 16 / 9;
65
+ }
66
+ .border-full {
67
+ border: 1px solid var(--color-content);
68
+ }
69
+ .contain {
70
+ object-fit: contain;
71
+ max-height: 100%;
72
+ }
73
+ .cover {
74
+ object-fit: cover;
75
+ object-position: top;
76
+ }
77
+ .cover,
78
+ .full:not(.contain) {
79
+ width: 100%;
80
+ }
81
+ .mx-auto {
82
+ margin-left: auto;
83
+ margin-right: auto;
84
+ }
85
+ .radius-full {
86
+ border-radius: 50%;
87
+ overflow: hidden;
88
+ }
89
+ </style>
@@ -0,0 +1,15 @@
1
+ import type { ImageData } from './';
2
+ interface Props {
3
+ aspect?: '3:4' | '4:3' | 'square' | 'video';
4
+ ball?: boolean;
5
+ border?: boolean;
6
+ center?: boolean;
7
+ extraClasses?: string;
8
+ fullWidth?: boolean;
9
+ image: ImageData;
10
+ loading?: 'eager' | 'lazy';
11
+ objectFit?: 'contain' | 'cover';
12
+ }
13
+ declare const Image: import("svelte").Component<Props, {}, "">;
14
+ type Image = ReturnType<typeof Image>;
15
+ export default Image;
@@ -0,0 +1,170 @@
1
+ <script lang="ts">
2
+ import {loading} from './'
3
+
4
+ interface Props {
5
+ onchange?: () => void
6
+ onclick?: () => void
7
+ borderColor?: 'content' | 'default' | 'primary' | 'none'
8
+ bgColor?: 'transparent' | 'white' | 'none'
9
+ disabled?: boolean
10
+ id?: string
11
+ inputClass?: string
12
+ label: string
13
+ max?: number | string
14
+ min?: number | string
15
+ outerClass?: string
16
+ placeholder?: string
17
+ required?: boolean
18
+ step?: number
19
+ type?: 'email' | 'date' | 'number' | 'password' | 'search' | 'tel' | 'text' | 'textarea' | 'time' | 'url'
20
+ value: string | number
21
+ }
22
+
23
+ let {
24
+ bgColor = 'transparent',
25
+ borderColor = 'default',
26
+ disabled,
27
+ id,
28
+ inputClass,
29
+ label,
30
+ max,
31
+ min,
32
+ onchange,
33
+ outerClass,
34
+ placeholder,
35
+ required = false,
36
+ step,
37
+ type = 'text',
38
+ value = $bindable()
39
+ }: Props = $props()
40
+
41
+ let isDisabled = $state(disabled || $loading)
42
+
43
+ let classes = $state('')
44
+ if (inputClass) {
45
+ classes = inputClass
46
+ }
47
+ if (bgColor && bgColor !== 'none') {
48
+ classes += ` bg-${bgColor}`
49
+ }
50
+ if (borderColor && borderColor !== 'none') {
51
+ classes += ` border-color-${borderColor}`
52
+ }
53
+ </script>
54
+
55
+ <label class={outerClass}>
56
+ {label}{#if required}<sup>*</sup>{/if}
57
+
58
+ {#if type === 'textarea'}
59
+ <textarea bind:value class={classes} disabled={isDisabled} {id} maxlength={max ? Number(max) : undefined} {required} {placeholder} rows={4}
60
+ ></textarea>
61
+ {:else if ['date', 'number'].includes(type)}
62
+ <input bind:value class={classes} disabled={isDisabled} lang="fi-FI" {max} {min} {onchange} {required} {step} {type} {placeholder} />
63
+ {:else}
64
+ <input
65
+ bind:value
66
+ {id}
67
+ {placeholder}
68
+ {required}
69
+ {type}
70
+ class={classes}
71
+ disabled={isDisabled}
72
+ maxlength={max ? Number(max) : undefined}
73
+ minlength={min ? Number(min) : undefined}
74
+ onkeyup={onchange}
75
+ />
76
+ {#if type === 'search'}
77
+ <svg
78
+ clip-rule="evenodd"
79
+ fill-rule="evenodd"
80
+ stroke-linejoin="round"
81
+ stroke-miterlimit="2"
82
+ viewBox="0 0 24 24"
83
+ xmlns="http://www.w3.org/2000/svg"
84
+ height="20"
85
+ width="20"
86
+ >
87
+ <path
88
+ d="m15.97 17.031c-1.479 1.238-3.384 1.985-5.461 1.985-4.697 0-8.509-3.812-8.509-8.508s3.812-8.508 8.509-8.508c4.695 0 8.508 3.812 8.508 8.508 0 2.078-.747 3.984-1.985 5.461l4.749 4.75c.146.146.219.338.219.531 0 .587-.537.75-.75.75-.192 0-.384-.073-.531-.22zm-5.461-13.53c-3.868 0-7.007 3.14-7.007 7.007s3.139 7.007 7.007 7.007c3.866 0 7.007-3.14 7.007-7.007s-3.141-7.007-7.007-7.007z"
89
+ fill-rule="nonzero"
90
+ />
91
+ </svg>
92
+ {/if}
93
+ {/if}
94
+ </label>
95
+
96
+ <style scoped>
97
+ input {
98
+ height: 48px;
99
+ }
100
+
101
+ input,
102
+ textarea {
103
+ border-radius: 0.375rem;
104
+ border-style: solid;
105
+ border-width: 1px;
106
+ color: var(--color-content);
107
+ display: block;
108
+ font-size: 1rem;
109
+ margin-top: 0.25rem;
110
+ padding-left: 0.5rem;
111
+ padding-right: 0.5rem;
112
+ }
113
+
114
+ input,
115
+ label,
116
+ textarea {
117
+ width: 100%;
118
+ }
119
+
120
+ input:disabled,
121
+ textarea:disabled {
122
+ cursor: not-allowed;
123
+ opacity: 0.6;
124
+ }
125
+
126
+ label {
127
+ display: inline-block;
128
+ position: relative;
129
+ }
130
+
131
+ label.filter {
132
+ font-size: var(--text-sm);
133
+ }
134
+
135
+ label svg {
136
+ bottom: 15px;
137
+ position: absolute;
138
+ right: 8px;
139
+ }
140
+
141
+ sup {
142
+ color: darkred;
143
+ }
144
+
145
+ textarea {
146
+ height: 150px;
147
+ padding-bottom: 0.25rem;
148
+ padding-top: 0.25rem;
149
+ }
150
+
151
+ .bg-transparent {
152
+ background-color: transparent;
153
+ }
154
+
155
+ .bg-white {
156
+ background-color: white;
157
+ }
158
+
159
+ .border-color-default {
160
+ border-color: var(--color-border);
161
+ }
162
+
163
+ .border-color-primary {
164
+ border-color: var(--color-primary);
165
+ }
166
+
167
+ .border-color-content {
168
+ border-color: var(--color-content);
169
+ }
170
+ </style>
@@ -0,0 +1,21 @@
1
+ interface Props {
2
+ onchange?: () => void;
3
+ onclick?: () => void;
4
+ borderColor?: 'content' | 'default' | 'primary' | 'none';
5
+ bgColor?: 'transparent' | 'white' | 'none';
6
+ disabled?: boolean;
7
+ id?: string;
8
+ inputClass?: string;
9
+ label: string;
10
+ max?: number | string;
11
+ min?: number | string;
12
+ outerClass?: string;
13
+ placeholder?: string;
14
+ required?: boolean;
15
+ step?: number;
16
+ type?: 'email' | 'date' | 'number' | 'password' | 'search' | 'tel' | 'text' | 'textarea' | 'time' | 'url';
17
+ value: string | number;
18
+ }
19
+ declare const Input: import("svelte").Component<Props, {}, "value">;
20
+ type Input = ReturnType<typeof Input>;
21
+ export default Input;
@@ -0,0 +1,78 @@
1
+ <script lang="ts">
2
+ import type {Snippet} from 'svelte'
3
+ import ButtonClose from './ButtonClose.svelte'
4
+ interface Props {
5
+ children: Snippet
6
+ innerClass?: string
7
+ open?: boolean
8
+ outerClass?: string
9
+ title?: string
10
+ }
11
+ let {children, innerClass, open = $bindable(), outerClass, title}: Props = $props()
12
+ const handleClose = () => {
13
+ open = false
14
+ }
15
+ </script>
16
+
17
+ <div id="modal" class:hidden={!open}>
18
+ <div id="modal-content" class={outerClass}>
19
+ <header>
20
+ {#if title}
21
+ <h2>{title}</h2>
22
+ {/if}
23
+ <ButtonClose color="black" onclick={handleClose} />
24
+ </header>
25
+ <div id="modal-body" class={innerClass}>
26
+ {@render children?.()}
27
+ </div>
28
+ </div>
29
+ </div>
30
+
31
+ <style scoped>
32
+ #modal {
33
+ align-items: center;
34
+ background-color: rgba(0, 0, 0, 0.6);
35
+ height: 100vh;
36
+ justify-content: center;
37
+ left: 0;
38
+ position: fixed;
39
+ top: 0;
40
+ width: 100vw;
41
+ z-index: 200;
42
+ }
43
+ #modal:not(.hidden) {
44
+ display: flex;
45
+ }
46
+ #modal.hidden {
47
+ display: none;
48
+ visibility: hidden;
49
+ }
50
+ #modal-content {
51
+ background-color: #fff;
52
+ border-radius: 1rem;
53
+ border: 2px solid var(--color-primary);
54
+ box-shadow: var(--shadow-md);
55
+ margin-left: auto;
56
+ margin-right: auto;
57
+ max-height: 85vh;
58
+ max-width: 95vw;
59
+ overflow: hidden;
60
+ overscroll-behavior: contain;
61
+ position: relative;
62
+ }
63
+ #modal-body {
64
+ max-height: 45vh;
65
+ overflow-x: hidden;
66
+ overflow-y: auto;
67
+ padding: 1rem;
68
+ }
69
+ header {
70
+ border-bottom: 1px solid var(--color-border);
71
+ padding: 1rem;
72
+ }
73
+ h2 {
74
+ font-size: 1.6rem;
75
+ line-height: 1;
76
+ margin: 0;
77
+ }
78
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ children: Snippet;
4
+ innerClass?: string;
5
+ open?: boolean;
6
+ outerClass?: string;
7
+ title?: string;
8
+ }
9
+ declare const Modal: import("svelte").Component<Props, {}, "open">;
10
+ type Modal = ReturnType<typeof Modal>;
11
+ export default Modal;
@@ -0,0 +1,60 @@
1
+ <script lang="ts">
2
+ import {loading, type SelectItem} from './'
3
+
4
+ interface Props {
5
+ onchange?: () => void
6
+ disabled?: boolean
7
+ outerClass?: string
8
+ id?: string
9
+ label: string
10
+ placeholder?: string
11
+ required?: boolean
12
+ value: string | number
13
+ values: SelectItem[]
14
+ }
15
+
16
+ let {onchange, disabled, outerClass, id, label, placeholder, required = false, value = $bindable(), values}: Props = $props()
17
+ </script>
18
+
19
+ <label class={outerClass}>
20
+ {label}
21
+ {#if required}<sup>*</sup>{/if}
22
+ <select bind:value {onchange} disabled={disabled || $loading} {id} {placeholder} {required}>
23
+ {#each values as item}
24
+ <option value={item.value}>{item.name}</option>
25
+ {/each}
26
+ </select>
27
+ </label>
28
+
29
+ <style scoped>
30
+ select {
31
+ background-color: transparent;
32
+ border-radius: 0.375rem;
33
+ border: 1px solid var(--color-border);
34
+ color: var(--color-content);
35
+ font-size: 1rem;
36
+ height: 48px;
37
+ margin-top: 0.25rem;
38
+ padding: 0 0.5rem;
39
+ width: 100%;
40
+ }
41
+
42
+ select:disabled {
43
+ cursor: not-allowed;
44
+ opacity: 0.6;
45
+ }
46
+
47
+ label,
48
+ select {
49
+ display: block;
50
+ }
51
+
52
+ label.filter {
53
+ position: relative;
54
+ font-size: var(--text-sm);
55
+ }
56
+
57
+ sup {
58
+ color: darkred;
59
+ }
60
+ </style>
@@ -0,0 +1,15 @@
1
+ import { type SelectItem } from './';
2
+ interface Props {
3
+ onchange?: () => void;
4
+ disabled?: boolean;
5
+ outerClass?: string;
6
+ id?: string;
7
+ label: string;
8
+ placeholder?: string;
9
+ required?: boolean;
10
+ value: string | number;
11
+ values: SelectItem[];
12
+ }
13
+ declare const Select: import("svelte").Component<Props, {}, "value">;
14
+ type Select = ReturnType<typeof Select>;
15
+ export default Select;
@@ -0,0 +1,57 @@
1
+ import Breadcrumbs from './Breadcrumbs.svelte';
2
+ import Button from './Button.svelte';
3
+ import ButtonArrow from './ButtonArrow.svelte';
4
+ import ButtonClose from './ButtonClose.svelte';
5
+ import ButtonMenu from './ButtonMenu.svelte';
6
+ import Checkbox from './Checkbox.svelte';
7
+ import Image from './Image.svelte';
8
+ import Input from './Input.svelte';
9
+ import Modal from './Modal.svelte';
10
+ import Select from './Select.svelte';
11
+ export { Breadcrumbs, Button, ButtonArrow, ButtonClose, ButtonMenu, Checkbox, Image, Input, Modal, Select };
12
+ export interface Breadcrumb {
13
+ '@type'?: string;
14
+ item: string;
15
+ name: string;
16
+ position?: string;
17
+ }
18
+ export interface ImageData {
19
+ alt: string;
20
+ height: number;
21
+ src: string;
22
+ width: number;
23
+ }
24
+ export interface SelectItem {
25
+ name: string;
26
+ value: number | string;
27
+ }
28
+ export declare const loading: import("svelte/store").Writable<number>;
29
+ /**
30
+ * PRICES AND NUMBERS
31
+ */
32
+ export declare const formatPrice: (value: number | string, comma?: boolean, currency?: string) => string;
33
+ export declare const fixNumber: (value: number | string) => number;
34
+ export declare const calculateTax: (total: number, vatPercentage?: number) => number;
35
+ export declare const calculatePreTax: (total: number, vatPercentage?: number) => number;
36
+ /**
37
+ * STRING VALIDATIONS
38
+ */
39
+ export declare const slugify: (value: string) => string;
40
+ export declare const validateSlug: (value: string) => boolean;
41
+ export declare const validateEmail: (email: string) => boolean;
42
+ export declare const validateString: (value: string) => boolean;
43
+ /**
44
+ * ARRAY VALIDATIONS
45
+ */
46
+ export declare const validateArray: (value: any, items?: number) => boolean;
47
+ /**
48
+ * CACHE
49
+ */
50
+ export declare const cacheValues: import("svelte/store").Writable<{
51
+ [key: string]: any;
52
+ }>;
53
+ export declare const handleCache: (key: string, value?: any) => any;
54
+ /**
55
+ * PREVENT DEFAULT
56
+ */
57
+ export declare const preventDefault: (fn: Function) => (this: any, event: any) => void;