mertani-web-toolkit 0.1.27 → 0.1.29
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/dist/components/inputs/Radio/Radio.d.ts +4 -0
- package/dist/components/inputs/Radio/Radio.js +1 -0
- package/dist/components/inputs/Radio/Radio.svelte +159 -0
- package/dist/components/inputs/Radio/Radio.svelte.d.ts +17 -0
- package/dist/components/inputs/Segmented/Segmented.d.ts +4 -0
- package/dist/components/inputs/Segmented/Segmented.js +1 -0
- package/dist/components/inputs/Segmented/Segmented.svelte +153 -0
- package/dist/components/inputs/Segmented/Segmented.svelte.d.ts +17 -0
- package/dist/components/inputs/SelectInput/SelectInput.svelte +6 -6
- package/dist/components/inputs/SelectInput/SelectInput.svelte.d.ts +1 -1
- package/dist/components/inputs/Steppers/Steppers.svelte +141 -0
- package/dist/components/inputs/Steppers/Steppers.svelte.d.ts +18 -0
- package/dist/components/inputs/TextInput/TextInput.svelte +5 -5
- package/dist/components/inputs/TextInput/TextInput.svelte.d.ts +1 -1
- package/dist/components/inputs/TextareaInput/TextareaInput.svelte +26 -7
- package/dist/components/inputs/TextareaInput/TextareaInput.svelte.d.ts +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
import type { IFieldOption } from './Radio.js';
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
id,
|
|
7
|
+
value = '',
|
|
8
|
+
options = [],
|
|
9
|
+
onChange,
|
|
10
|
+
required = false,
|
|
11
|
+
errorMessage,
|
|
12
|
+
disabled = false,
|
|
13
|
+
label = '',
|
|
14
|
+
subLabel = '',
|
|
15
|
+
class: className = '',
|
|
16
|
+
style: customStyle = ''
|
|
17
|
+
}: {
|
|
18
|
+
id: string;
|
|
19
|
+
value?: string;
|
|
20
|
+
options?: Array<IFieldOption>;
|
|
21
|
+
onChange?: (val: string) => void;
|
|
22
|
+
required?: boolean;
|
|
23
|
+
errorMessage?: string;
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
label?: string;
|
|
26
|
+
subLabel?: string;
|
|
27
|
+
class?: string;
|
|
28
|
+
style?: string;
|
|
29
|
+
} = $props();
|
|
30
|
+
|
|
31
|
+
const baseClasses = $derived(() => {
|
|
32
|
+
let classes = 'radio-container';
|
|
33
|
+
if (className) {
|
|
34
|
+
classes += ` ${className}`;
|
|
35
|
+
}
|
|
36
|
+
return classes;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const mergedClasses = $derived(twMerge(baseClasses(), className));
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<div class={mergedClasses} style={customStyle}>
|
|
43
|
+
{#if label}
|
|
44
|
+
<label for={id} class="radio-label">
|
|
45
|
+
{label}
|
|
46
|
+
{#if required}
|
|
47
|
+
<span class="required-indicator">*</span>
|
|
48
|
+
{/if}
|
|
49
|
+
{#if subLabel}
|
|
50
|
+
<span class="label-subLabel">{subLabel}</span>
|
|
51
|
+
{/if}
|
|
52
|
+
</label>
|
|
53
|
+
{/if}
|
|
54
|
+
|
|
55
|
+
<div
|
|
56
|
+
class="flex flex-wrap items-center gap-6"
|
|
57
|
+
class:opacity-50={disabled}
|
|
58
|
+
class:pointer-events-none={disabled}
|
|
59
|
+
>
|
|
60
|
+
{#each options as option (option.id)}
|
|
61
|
+
<label
|
|
62
|
+
class="relative inline-flex items-center gap-2 text-sm text-[#212529] transition-colors"
|
|
63
|
+
class:active={value === option.id}
|
|
64
|
+
>
|
|
65
|
+
<input
|
|
66
|
+
type="radio"
|
|
67
|
+
class="absolute inset-0 h-full w-full cursor-pointer opacity-0"
|
|
68
|
+
name={id}
|
|
69
|
+
style={customStyle}
|
|
70
|
+
value={option.id}
|
|
71
|
+
checked={value === option.id}
|
|
72
|
+
{disabled}
|
|
73
|
+
on:change={() => onChange?.(option.id)}
|
|
74
|
+
/>
|
|
75
|
+
<span
|
|
76
|
+
class="flex h-4 w-4 items-center justify-center rounded-full border bg-white {value ===
|
|
77
|
+
option.id
|
|
78
|
+
? 'border-4 border-[#ffa000]'
|
|
79
|
+
: 'border-[#ced4da]'}"
|
|
80
|
+
></span>
|
|
81
|
+
<span>{option.nama}</span>
|
|
82
|
+
</label>
|
|
83
|
+
{/each}
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
{#if errorMessage && required}
|
|
87
|
+
<p class="mt-1 text-xs text-red-500">{errorMessage}</p>
|
|
88
|
+
{/if}
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<style>
|
|
92
|
+
.radio-container {
|
|
93
|
+
display: flex;
|
|
94
|
+
flex-direction: column;
|
|
95
|
+
width: 100%;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.radio-label {
|
|
99
|
+
font-size: 14px;
|
|
100
|
+
font-weight: 500;
|
|
101
|
+
color: #212529;
|
|
102
|
+
margin-bottom: 8px;
|
|
103
|
+
display: block;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.label-subLabel {
|
|
107
|
+
font-weight: 400;
|
|
108
|
+
color: #98a2b3;
|
|
109
|
+
margin-left: 4px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.required-indicator {
|
|
113
|
+
color: #ef4444;
|
|
114
|
+
margin-left: 4px;
|
|
115
|
+
font-weight: 500;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.segmented-group {
|
|
119
|
+
background: #fff;
|
|
120
|
+
}
|
|
121
|
+
.segmented-option {
|
|
122
|
+
border-right: 1px solid #ced4da;
|
|
123
|
+
&:last-child {
|
|
124
|
+
border-right: none;
|
|
125
|
+
}
|
|
126
|
+
&.active {
|
|
127
|
+
background: #ffa000;
|
|
128
|
+
color: #fff;
|
|
129
|
+
}
|
|
130
|
+
&:not(.active):hover {
|
|
131
|
+
background: #f2f4f7;
|
|
132
|
+
}
|
|
133
|
+
.text {
|
|
134
|
+
width: 100%;
|
|
135
|
+
text-align: center;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.title {
|
|
140
|
+
font-size: 1.125rem;
|
|
141
|
+
font-weight: bold;
|
|
142
|
+
margin-bottom: 1rem;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.title.horizontal {
|
|
146
|
+
display: flex;
|
|
147
|
+
align-items: center;
|
|
148
|
+
justify-content: center;
|
|
149
|
+
margin: 0;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.title.horizontal.left {
|
|
153
|
+
justify-content: flex-start;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.title.horizontal.right {
|
|
157
|
+
justify-content: flex-end;
|
|
158
|
+
}
|
|
159
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IFieldOption } from './Radio.js';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
id: string;
|
|
4
|
+
value?: string;
|
|
5
|
+
options?: Array<IFieldOption>;
|
|
6
|
+
onChange?: (val: string) => void;
|
|
7
|
+
required?: boolean;
|
|
8
|
+
errorMessage?: string;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
label?: string;
|
|
11
|
+
subLabel?: string;
|
|
12
|
+
class?: string;
|
|
13
|
+
style?: string;
|
|
14
|
+
};
|
|
15
|
+
declare const Radio: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
16
|
+
type Radio = ReturnType<typeof Radio>;
|
|
17
|
+
export default Radio;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
import type { IFieldOption } from './Segmented.js';
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
id,
|
|
7
|
+
value = '',
|
|
8
|
+
options = [],
|
|
9
|
+
onChange,
|
|
10
|
+
required = false,
|
|
11
|
+
errorMessage,
|
|
12
|
+
disabled = false,
|
|
13
|
+
label = '',
|
|
14
|
+
subLabel = '',
|
|
15
|
+
class: className = '',
|
|
16
|
+
style: customStyle = ''
|
|
17
|
+
}: {
|
|
18
|
+
id: string;
|
|
19
|
+
value?: string;
|
|
20
|
+
options?: Array<IFieldOption>;
|
|
21
|
+
onChange?: (val: string) => void;
|
|
22
|
+
required?: boolean;
|
|
23
|
+
errorMessage?: string;
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
label?: string;
|
|
26
|
+
subLabel?: string;
|
|
27
|
+
class?: string;
|
|
28
|
+
style?: string;
|
|
29
|
+
} = $props();
|
|
30
|
+
|
|
31
|
+
const baseClasses = $derived(() => {
|
|
32
|
+
let classes = 'radio-container';
|
|
33
|
+
if (className) {
|
|
34
|
+
classes += ` ${className}`;
|
|
35
|
+
}
|
|
36
|
+
return classes;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const mergedClasses = $derived(twMerge(baseClasses(), className));
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<div class={mergedClasses} style={customStyle}>
|
|
43
|
+
{#if label}
|
|
44
|
+
<label for={id} class="radio-label">
|
|
45
|
+
{label}
|
|
46
|
+
{#if required}
|
|
47
|
+
<span class="required-indicator">*</span>
|
|
48
|
+
{/if}
|
|
49
|
+
{#if subLabel}
|
|
50
|
+
<span class="label-subLabel">{subLabel}</span>
|
|
51
|
+
{/if}
|
|
52
|
+
</label>
|
|
53
|
+
{/if}
|
|
54
|
+
|
|
55
|
+
<div
|
|
56
|
+
class="segmented-group flex overflow-hidden rounded-lg border border-[#ced4da]"
|
|
57
|
+
class:opacity-50={disabled}
|
|
58
|
+
class:pointer-events-none={disabled}
|
|
59
|
+
>
|
|
60
|
+
{#each options as option (option.id)}
|
|
61
|
+
<label
|
|
62
|
+
class="segmented-option relative inline-flex flex-1 cursor-pointer items-center justify-center px-4 py-2 text-sm font-medium text-[#475467] transition-colors"
|
|
63
|
+
class:active={value === option.id}
|
|
64
|
+
>
|
|
65
|
+
<input
|
|
66
|
+
type="radio"
|
|
67
|
+
class="absolute inset-0 h-full w-full cursor-pointer opacity-0"
|
|
68
|
+
name={id}
|
|
69
|
+
style={customStyle}
|
|
70
|
+
value={option.id}
|
|
71
|
+
checked={value === option.id}
|
|
72
|
+
{disabled}
|
|
73
|
+
on:change={() => onChange?.(option.id)}
|
|
74
|
+
/>
|
|
75
|
+
<span class="text">{option.nama}</span>
|
|
76
|
+
</label>
|
|
77
|
+
{/each}
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
{#if errorMessage && required}
|
|
81
|
+
<p class="mt-1 text-xs text-red-500">{errorMessage}</p>
|
|
82
|
+
{/if}
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<style>
|
|
86
|
+
.radio-container {
|
|
87
|
+
display: flex;
|
|
88
|
+
flex-direction: column;
|
|
89
|
+
width: 100%;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.radio-label {
|
|
93
|
+
font-size: 14px;
|
|
94
|
+
font-weight: 500;
|
|
95
|
+
color: #212529;
|
|
96
|
+
margin-bottom: 8px;
|
|
97
|
+
display: block;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.label-subLabel {
|
|
101
|
+
font-weight: 400;
|
|
102
|
+
color: #98a2b3;
|
|
103
|
+
margin-left: 4px;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.required-indicator {
|
|
107
|
+
color: #ef4444;
|
|
108
|
+
margin-left: 4px;
|
|
109
|
+
font-weight: 500;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.segmented-group {
|
|
113
|
+
background: #fff;
|
|
114
|
+
}
|
|
115
|
+
.segmented-option {
|
|
116
|
+
border-right: 1px solid #ced4da;
|
|
117
|
+
&:last-child {
|
|
118
|
+
border-right: none;
|
|
119
|
+
}
|
|
120
|
+
&.active {
|
|
121
|
+
background: #ffa000;
|
|
122
|
+
color: #fff;
|
|
123
|
+
}
|
|
124
|
+
&:not(.active):hover {
|
|
125
|
+
background: #f2f4f7;
|
|
126
|
+
}
|
|
127
|
+
.text {
|
|
128
|
+
width: 100%;
|
|
129
|
+
text-align: center;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.title {
|
|
134
|
+
font-size: 1.125rem;
|
|
135
|
+
font-weight: bold;
|
|
136
|
+
margin-bottom: 1rem;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.title.horizontal {
|
|
140
|
+
display: flex;
|
|
141
|
+
align-items: center;
|
|
142
|
+
justify-content: center;
|
|
143
|
+
margin: 0;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.title.horizontal.left {
|
|
147
|
+
justify-content: flex-start;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.title.horizontal.right {
|
|
151
|
+
justify-content: flex-end;
|
|
152
|
+
}
|
|
153
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IFieldOption } from './Segmented.js';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
id: string;
|
|
4
|
+
value?: string;
|
|
5
|
+
options?: Array<IFieldOption>;
|
|
6
|
+
onChange?: (val: string) => void;
|
|
7
|
+
required?: boolean;
|
|
8
|
+
errorMessage?: string;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
label?: string;
|
|
11
|
+
subLabel?: string;
|
|
12
|
+
class?: string;
|
|
13
|
+
style?: string;
|
|
14
|
+
};
|
|
15
|
+
declare const Segmented: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
16
|
+
type Segmented = ReturnType<typeof Segmented>;
|
|
17
|
+
export default Segmented;
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
errorMessage,
|
|
13
13
|
disabled = false,
|
|
14
14
|
label = '',
|
|
15
|
-
|
|
15
|
+
subLabel = '',
|
|
16
16
|
placeholder = 'Pilih',
|
|
17
17
|
searchPlaceholder = 'Cari',
|
|
18
18
|
emptyMessage = 'Tidak ada hasil',
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
errorMessage?: string;
|
|
29
29
|
disabled?: boolean;
|
|
30
30
|
label?: string;
|
|
31
|
-
|
|
31
|
+
subLabel?: string;
|
|
32
32
|
placeholder?: string;
|
|
33
33
|
searchPlaceholder?: string;
|
|
34
34
|
emptyMessage?: string;
|
|
@@ -197,8 +197,8 @@
|
|
|
197
197
|
{#if required}
|
|
198
198
|
<span class="required-indicator">*</span>
|
|
199
199
|
{/if}
|
|
200
|
-
{#if
|
|
201
|
-
<span class="label-
|
|
200
|
+
{#if subLabel}
|
|
201
|
+
<span class="label-subLabel">{subLabel}</span>
|
|
202
202
|
{/if}
|
|
203
203
|
</label>
|
|
204
204
|
{/if}
|
|
@@ -299,7 +299,7 @@
|
|
|
299
299
|
display: block;
|
|
300
300
|
}
|
|
301
301
|
|
|
302
|
-
.label-
|
|
302
|
+
.label-subLabel {
|
|
303
303
|
font-weight: 400;
|
|
304
304
|
color: #98a2b3;
|
|
305
305
|
margin-left: 4px;
|
|
@@ -391,7 +391,7 @@
|
|
|
391
391
|
}
|
|
392
392
|
|
|
393
393
|
.select-option.selected {
|
|
394
|
-
color: #
|
|
394
|
+
color: #ffa000;
|
|
395
395
|
}
|
|
396
396
|
|
|
397
397
|
.select-empty {
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
id,
|
|
6
|
+
value = '0',
|
|
7
|
+
min = 0,
|
|
8
|
+
max = Number.POSITIVE_INFINITY,
|
|
9
|
+
step = 1,
|
|
10
|
+
onChange,
|
|
11
|
+
label = '',
|
|
12
|
+
subLabel = '',
|
|
13
|
+
required = false,
|
|
14
|
+
errorMessage,
|
|
15
|
+
disabled = false,
|
|
16
|
+
class: className = '',
|
|
17
|
+
style: customStyle = ''
|
|
18
|
+
}: {
|
|
19
|
+
id: string;
|
|
20
|
+
value?: string | number;
|
|
21
|
+
min?: number;
|
|
22
|
+
max?: number;
|
|
23
|
+
step?: number;
|
|
24
|
+
onChange?: (val: string) => void;
|
|
25
|
+
label?: string;
|
|
26
|
+
subLabel?: string;
|
|
27
|
+
required?: boolean;
|
|
28
|
+
errorMessage?: string;
|
|
29
|
+
disabled?: boolean;
|
|
30
|
+
class?: string;
|
|
31
|
+
style?: string;
|
|
32
|
+
} = $props();
|
|
33
|
+
|
|
34
|
+
function toNum(v: any) {
|
|
35
|
+
const n = Number(v);
|
|
36
|
+
return isNaN(n) ? 0 : n;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function dec() {
|
|
40
|
+
const cur = toNum(value);
|
|
41
|
+
const next = Math.max(min, cur - (step ?? 1));
|
|
42
|
+
if (next !== cur) onChange?.(String(next));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function inc() {
|
|
46
|
+
const cur = toNum(value);
|
|
47
|
+
const next = Math.min(max, cur + (step ?? 1));
|
|
48
|
+
if (next !== cur) onChange?.(String(next));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const baseClasses = $derived(() => {
|
|
52
|
+
let classes = 'stepper-container';
|
|
53
|
+
if (className) {
|
|
54
|
+
classes += ` ${className}`;
|
|
55
|
+
}
|
|
56
|
+
return classes;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const mergedClasses = $derived(twMerge(baseClasses(), className));
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<div class={mergedClasses} style={customStyle}>
|
|
63
|
+
{#if label}
|
|
64
|
+
<label for={id} class="stepper-label">
|
|
65
|
+
{label}
|
|
66
|
+
{#if required}
|
|
67
|
+
<span class="required-indicator">*</span>
|
|
68
|
+
{/if}
|
|
69
|
+
{#if subLabel}
|
|
70
|
+
<span class="label-subLabel">{subLabel}</span>
|
|
71
|
+
{/if}
|
|
72
|
+
</label>
|
|
73
|
+
{/if}
|
|
74
|
+
<div class="flex items-center">
|
|
75
|
+
<button
|
|
76
|
+
type="button"
|
|
77
|
+
class="grid h-9 w-9 place-items-center rounded-l-md border border-[#CED4DA] bg-[#E9ECEF] text-sm font-medium transition hover:bg-[#E9ECEF]"
|
|
78
|
+
on:click={dec}
|
|
79
|
+
style:color={toNum(value) <= (min ?? Number.NEGATIVE_INFINITY) || disabled
|
|
80
|
+
? '#CED4DA'
|
|
81
|
+
: '#6C757D'}
|
|
82
|
+
{disabled}
|
|
83
|
+
>
|
|
84
|
+
-
|
|
85
|
+
</button>
|
|
86
|
+
<input
|
|
87
|
+
{id}
|
|
88
|
+
type="number"
|
|
89
|
+
class="h-9 w-16 border-t border-r-0 border-b border-l-0 border-[#CED4DA] bg-white pl-3 text-center text-sm font-medium text-[#2C2C30]"
|
|
90
|
+
value={value as any}
|
|
91
|
+
placeholder={''}
|
|
92
|
+
{disabled}
|
|
93
|
+
readonly
|
|
94
|
+
/>
|
|
95
|
+
<button
|
|
96
|
+
type="button"
|
|
97
|
+
class="grid h-9 w-9 place-items-center rounded-r-md border border-[#CED4DA] bg-[#E9ECEF] text-sm font-medium text-[#6C757D] transition hover:bg-[#E9ECEF]"
|
|
98
|
+
on:click={inc}
|
|
99
|
+
style:color={toNum(value) >= (max ?? Number.POSITIVE_INFINITY) || disabled
|
|
100
|
+
? '#CED4DA'
|
|
101
|
+
: '#6C757D'}
|
|
102
|
+
{disabled}
|
|
103
|
+
>
|
|
104
|
+
+
|
|
105
|
+
</button>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
{#if errorMessage && required}
|
|
109
|
+
<p class="error-message">{errorMessage}</p>
|
|
110
|
+
{/if}
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<style>
|
|
114
|
+
.stepper-container {
|
|
115
|
+
display: flex;
|
|
116
|
+
flex-direction: column;
|
|
117
|
+
width: 100%;
|
|
118
|
+
}
|
|
119
|
+
.stepper-label {
|
|
120
|
+
font-size: 14px;
|
|
121
|
+
font-weight: 500;
|
|
122
|
+
color: #212529;
|
|
123
|
+
margin-bottom: 8px;
|
|
124
|
+
display: block;
|
|
125
|
+
}
|
|
126
|
+
.label-subLabel {
|
|
127
|
+
font-weight: 400;
|
|
128
|
+
color: #98a2b3;
|
|
129
|
+
margin-left: 4px;
|
|
130
|
+
}
|
|
131
|
+
.required-indicator {
|
|
132
|
+
color: #ef4444;
|
|
133
|
+
margin-left: 4px;
|
|
134
|
+
font-weight: 500;
|
|
135
|
+
}
|
|
136
|
+
.error-message {
|
|
137
|
+
font-size: 12px;
|
|
138
|
+
color: #ef4444;
|
|
139
|
+
margin-top: 4px;
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
id: string;
|
|
3
|
+
value?: string | number;
|
|
4
|
+
min?: number;
|
|
5
|
+
max?: number;
|
|
6
|
+
step?: number;
|
|
7
|
+
onChange?: (val: string) => void;
|
|
8
|
+
label?: string;
|
|
9
|
+
subLabel?: string;
|
|
10
|
+
required?: boolean;
|
|
11
|
+
errorMessage?: string;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
class?: string;
|
|
14
|
+
style?: string;
|
|
15
|
+
};
|
|
16
|
+
declare const Steppers: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
17
|
+
type Steppers = ReturnType<typeof Steppers>;
|
|
18
|
+
export default Steppers;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
value = '',
|
|
11
11
|
placeholder = '',
|
|
12
12
|
label = '',
|
|
13
|
-
|
|
13
|
+
subLabel = '',
|
|
14
14
|
prefix = '',
|
|
15
15
|
suffix = '',
|
|
16
16
|
rightIcon,
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
value?: string | number;
|
|
30
30
|
placeholder?: string;
|
|
31
31
|
label?: string;
|
|
32
|
-
|
|
32
|
+
subLabel?: string;
|
|
33
33
|
prefix?: string;
|
|
34
34
|
suffix?: string;
|
|
35
35
|
rightIcon?: TIconName;
|
|
@@ -114,8 +114,8 @@
|
|
|
114
114
|
{#if label}
|
|
115
115
|
<label for={id} class="input-label">
|
|
116
116
|
{label}
|
|
117
|
-
{#if
|
|
118
|
-
<span class="label-
|
|
117
|
+
{#if subLabel}
|
|
118
|
+
<span class="label-subLabel">{subLabel}</span>
|
|
119
119
|
{/if}
|
|
120
120
|
</label>
|
|
121
121
|
{/if}
|
|
@@ -173,7 +173,7 @@
|
|
|
173
173
|
display: block;
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
.label-
|
|
176
|
+
.label-subLabel {
|
|
177
177
|
font-weight: 400;
|
|
178
178
|
color: #98a2b3;
|
|
179
179
|
margin-left: 4px;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<!-- TODO Perbaiki border ring color -->
|
|
1
2
|
<script lang="ts">
|
|
2
3
|
import { twMerge } from 'tailwind-merge';
|
|
3
4
|
|
|
@@ -6,7 +7,7 @@
|
|
|
6
7
|
value = '',
|
|
7
8
|
placeholder = '',
|
|
8
9
|
label = '',
|
|
9
|
-
|
|
10
|
+
subLabel = '',
|
|
10
11
|
rows = 4,
|
|
11
12
|
disabled = false,
|
|
12
13
|
readOnly = false,
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
value?: string;
|
|
21
22
|
placeholder?: string;
|
|
22
23
|
label?: string;
|
|
23
|
-
|
|
24
|
+
subLabel?: string;
|
|
24
25
|
rows?: number;
|
|
25
26
|
disabled?: boolean;
|
|
26
27
|
readOnly?: boolean;
|
|
@@ -39,7 +40,7 @@
|
|
|
39
40
|
// Base classes untuk textarea
|
|
40
41
|
const baseClasses = $derived(() => {
|
|
41
42
|
let classes =
|
|
42
|
-
'w-full py-2.5 text-sm transition
|
|
43
|
+
'w-full py-2.5 text-sm transition rounded-md text-sm text-[#212529]';
|
|
43
44
|
return classes;
|
|
44
45
|
});
|
|
45
46
|
|
|
@@ -51,15 +52,15 @@
|
|
|
51
52
|
{#if label}
|
|
52
53
|
<label for={id} class="input-label">
|
|
53
54
|
{label}
|
|
54
|
-
{#if
|
|
55
|
-
<span class="label-
|
|
55
|
+
{#if subLabel}
|
|
56
|
+
<span class="label-subLabel">{subLabel}</span>
|
|
56
57
|
{/if}
|
|
57
58
|
</label>
|
|
58
59
|
{/if}
|
|
59
60
|
<div class="input-wrapper">
|
|
60
61
|
<textarea
|
|
61
62
|
{id}
|
|
62
|
-
class="px-4 {mergedClasses}"
|
|
63
|
+
class="textarea-input px-4 {mergedClasses}"
|
|
63
64
|
style={customStyle}
|
|
64
65
|
{rows}
|
|
65
66
|
{placeholder}
|
|
@@ -89,7 +90,7 @@
|
|
|
89
90
|
display: block;
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
.label-
|
|
93
|
+
.label-subLabel {
|
|
93
94
|
font-weight: 400;
|
|
94
95
|
color: #98a2b3;
|
|
95
96
|
margin-left: 4px;
|
|
@@ -107,4 +108,22 @@
|
|
|
107
108
|
border-color 0.2s,
|
|
108
109
|
box-shadow 0.2s;
|
|
109
110
|
}
|
|
111
|
+
|
|
112
|
+
.input-wrapper:focus-within {
|
|
113
|
+
border-color: #ffa000;
|
|
114
|
+
box-shadow: 0 0 0 2px rgba(255, 160, 0, 0.25);
|
|
115
|
+
outline: none;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.textarea-input {
|
|
119
|
+
border: none;
|
|
120
|
+
background: transparent;
|
|
121
|
+
outline: none;
|
|
122
|
+
width: 100%;
|
|
123
|
+
resize: vertical;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.textarea-input:focus {
|
|
127
|
+
outline: none;
|
|
128
|
+
}
|
|
110
129
|
</style>
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,10 @@ export { default as Button } from './components/Button/Button.svelte';
|
|
|
2
2
|
export { default as Icon } from './components/Icon/Icon.svelte';
|
|
3
3
|
export { default as TextInput } from './components/inputs/TextInput/TextInput.svelte';
|
|
4
4
|
export { default as TextareaInput } from './components/inputs/TextareaInput/TextareaInput.svelte';
|
|
5
|
+
export { default as SelectInput } from './components/inputs/SelectInput/SelectInput.svelte';
|
|
6
|
+
export { default as Radio } from './components/inputs/Radio/Radio.svelte';
|
|
7
|
+
export { default as Segmented } from './components/inputs/Segmented/Segmented.svelte';
|
|
8
|
+
export { default as Steppers } from './components/inputs/Steppers/Steppers.svelte';
|
|
5
9
|
export { default as IMSLayout1 } from './layouts/IMS/IMSLayout1/IMSLayout1.svelte';
|
|
6
10
|
export { default as Table } from './components/Table/Table.svelte';
|
|
7
11
|
export { default as HeaderContent } from './components/HeaderContent/HeaderContent.svelte';
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,10 @@ export { default as Button } from './components/Button/Button.svelte';
|
|
|
3
3
|
export { default as Icon } from './components/Icon/Icon.svelte';
|
|
4
4
|
export { default as TextInput } from './components/inputs/TextInput/TextInput.svelte';
|
|
5
5
|
export { default as TextareaInput } from './components/inputs/TextareaInput/TextareaInput.svelte';
|
|
6
|
+
export { default as SelectInput } from './components/inputs/SelectInput/SelectInput.svelte';
|
|
7
|
+
export { default as Radio } from './components/inputs/Radio/Radio.svelte';
|
|
8
|
+
export { default as Segmented } from './components/inputs/Segmented/Segmented.svelte';
|
|
9
|
+
export { default as Steppers } from './components/inputs/Steppers/Steppers.svelte';
|
|
6
10
|
export { default as IMSLayout1 } from './layouts/IMS/IMSLayout1/IMSLayout1.svelte';
|
|
7
11
|
export { default as Table } from './components/Table/Table.svelte';
|
|
8
12
|
export { default as HeaderContent } from './components/HeaderContent/HeaderContent.svelte';
|