@joewinke/jatui 0.36.3 → 0.37.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.
|
@@ -187,6 +187,14 @@
|
|
|
187
187
|
{/if}
|
|
188
188
|
|
|
189
189
|
<style>
|
|
190
|
+
/* ── Flat by default ──────────────────────────────────────────
|
|
191
|
+
DaisyUI v5 gives colored variants (primary, error, …) a drop shadow
|
|
192
|
+
through --btn-shadow. jatui buttons are flat. Only the variable is
|
|
193
|
+
cleared, so a consumer `shadow-*` utility still applies when wanted. */
|
|
194
|
+
.jatui-btn {
|
|
195
|
+
--btn-shadow: 0 0 0 0 transparent;
|
|
196
|
+
}
|
|
197
|
+
|
|
190
198
|
/* ── Press Squish ─────────────────────────────────────────────
|
|
191
199
|
Quick down on :active, spring back on release. Transform-only.
|
|
192
200
|
Local @media guard — motion.css is the backstop but not guaranteed. */
|
|
@@ -7,8 +7,35 @@
|
|
|
7
7
|
* opt-in floatingLabel prop (label translates/scales on focus-or-filled, pure CSS).
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Any other native attribute (aria-label, aria-labelledby, data-*, title,
|
|
14
|
+
* list, inputmode, step, min, max, event handlers…) passes straight through
|
|
15
|
+
* to the <input>. `label` is optional: a compact input with no visible label
|
|
16
|
+
* must pass `aria-label` (or `aria-labelledby`) to get an accessible name.
|
|
17
|
+
*/
|
|
18
|
+
interface Props
|
|
19
|
+
extends Omit<
|
|
20
|
+
HTMLInputAttributes,
|
|
21
|
+
| 'value'
|
|
22
|
+
| 'type'
|
|
23
|
+
| 'size'
|
|
24
|
+
| 'class'
|
|
25
|
+
| 'id'
|
|
26
|
+
| 'name'
|
|
27
|
+
| 'autocomplete'
|
|
28
|
+
| 'placeholder'
|
|
29
|
+
| 'required'
|
|
30
|
+
| 'disabled'
|
|
31
|
+
| 'readonly'
|
|
32
|
+
| 'maxlength'
|
|
33
|
+
| 'minlength'
|
|
34
|
+
| 'pattern'
|
|
35
|
+
| 'children'
|
|
36
|
+
> {
|
|
37
|
+
/** Visible label. Omit it only with `aria-label` / `aria-labelledby`. */
|
|
38
|
+
label?: string;
|
|
12
39
|
value?: string;
|
|
13
40
|
placeholder?: string;
|
|
14
41
|
type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url';
|
|
@@ -54,7 +81,8 @@
|
|
|
54
81
|
class: className = '',
|
|
55
82
|
id = `text-input-${Math.random().toString(36).substr(2, 9)}`,
|
|
56
83
|
name = '',
|
|
57
|
-
autocomplete = ''
|
|
84
|
+
autocomplete = '',
|
|
85
|
+
...rest
|
|
58
86
|
}: Props = $props();
|
|
59
87
|
|
|
60
88
|
const sizeClass = $derived({ sm: 'input-sm', md: '', lg: 'input-lg' }[size]);
|
|
@@ -97,7 +125,7 @@
|
|
|
97
125
|
</script>
|
|
98
126
|
|
|
99
127
|
<div class="form-control w-full" class:jatui-float-wrap={floatingLabel}>
|
|
100
|
-
{#if !floatingLabel}
|
|
128
|
+
{#if label && !floatingLabel}
|
|
101
129
|
<label for={id} class="label">
|
|
102
130
|
<span class="text-[0.8125rem] font-medium text-base-content/85">
|
|
103
131
|
{label}
|
|
@@ -110,6 +138,7 @@
|
|
|
110
138
|
|
|
111
139
|
<div class:jatui-float-field={floatingLabel}>
|
|
112
140
|
<input
|
|
141
|
+
{...rest}
|
|
113
142
|
bind:this={inputEl}
|
|
114
143
|
{id}
|
|
115
144
|
{name}
|
|
@@ -124,12 +153,16 @@
|
|
|
124
153
|
autocomplete={autocomplete as AutoFill}
|
|
125
154
|
bind:value
|
|
126
155
|
class={inputClass}
|
|
127
|
-
aria-describedby={error
|
|
156
|
+
aria-describedby={error
|
|
157
|
+
? `${id}-error`
|
|
158
|
+
: helpText
|
|
159
|
+
? `${id}-help`
|
|
160
|
+
: rest['aria-describedby']}
|
|
128
161
|
aria-invalid={error ? 'true' : 'false'}
|
|
129
162
|
onanimationend={() => inputEl?.classList.remove('jatui-input-shake')}
|
|
130
163
|
/>
|
|
131
164
|
|
|
132
|
-
{#if floatingLabel}
|
|
165
|
+
{#if label && floatingLabel}
|
|
133
166
|
<label for={id} class="jatui-float-label">
|
|
134
167
|
{label}
|
|
135
168
|
{#if required}
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
* TextInput Component
|
|
3
|
+
*
|
|
4
|
+
* Labeled text input with validation, error state, help text, and character count.
|
|
5
|
+
* Adds: motion-token error shake (embedded keyframe, no host-app dependency),
|
|
6
|
+
* opt-in floatingLabel prop (label translates/scales on focus-or-filled, pure CSS).
|
|
7
|
+
*/
|
|
8
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
9
|
+
/**
|
|
10
|
+
* Any other native attribute (aria-label, aria-labelledby, data-*, title,
|
|
11
|
+
* list, inputmode, step, min, max, event handlers…) passes straight through
|
|
12
|
+
* to the <input>. `label` is optional: a compact input with no visible label
|
|
13
|
+
* must pass `aria-label` (or `aria-labelledby`) to get an accessible name.
|
|
7
14
|
*/
|
|
8
|
-
interface Props {
|
|
9
|
-
label
|
|
15
|
+
interface Props extends Omit<HTMLInputAttributes, 'value' | 'type' | 'size' | 'class' | 'id' | 'name' | 'autocomplete' | 'placeholder' | 'required' | 'disabled' | 'readonly' | 'maxlength' | 'minlength' | 'pattern' | 'children'> {
|
|
16
|
+
/** Visible label. Omit it only with `aria-label` / `aria-labelledby`. */
|
|
17
|
+
label?: string;
|
|
10
18
|
value?: string;
|
|
11
19
|
placeholder?: string;
|
|
12
20
|
type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url';
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
2
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Any other native attribute (aria-label, aria-describedby, data-*, title,
|
|
6
|
+
* required, form…) passes straight through to the <input>. Without a visible
|
|
7
|
+
* `label`, pass `aria-label` so the checkbox has an accessible name.
|
|
8
|
+
*
|
|
9
|
+
* The click target is always at least 24×24px (WCAG 2.5.8), even at
|
|
10
|
+
* size xs/sm: the input sits in a <label> box with a 24px minimum, and a
|
|
11
|
+
* click anywhere in that box toggles it.
|
|
12
|
+
*/
|
|
13
|
+
interface Props
|
|
14
|
+
extends Omit<
|
|
15
|
+
HTMLInputAttributes,
|
|
16
|
+
'type' | 'checked' | 'size' | 'disabled' | 'name' | 'id' | 'onchange' | 'class' | 'children'
|
|
17
|
+
> {
|
|
3
18
|
checked?: boolean;
|
|
4
19
|
label?: string;
|
|
5
20
|
size?: 'xs' | 'sm' | 'md' | 'lg';
|
|
@@ -22,7 +37,8 @@
|
|
|
22
37
|
name,
|
|
23
38
|
id,
|
|
24
39
|
onchange,
|
|
25
|
-
class: className = ''
|
|
40
|
+
class: className = '',
|
|
41
|
+
...rest
|
|
26
42
|
}: Props = $props();
|
|
27
43
|
|
|
28
44
|
const sizeClass = $derived({ xs: 'checkbox-xs', sm: 'checkbox-sm', md: '', lg: 'checkbox-lg' }[size]);
|
|
@@ -57,8 +73,9 @@
|
|
|
57
73
|
</script>
|
|
58
74
|
|
|
59
75
|
{#if label}
|
|
60
|
-
<label class="
|
|
76
|
+
<label class="jatui-checkbox-target jatui-checkbox-row" for={inputId}>
|
|
61
77
|
<input
|
|
78
|
+
{...rest}
|
|
62
79
|
bind:this={inputEl}
|
|
63
80
|
type="checkbox"
|
|
64
81
|
{name}
|
|
@@ -71,15 +88,36 @@
|
|
|
71
88
|
<span class="label-text">{label}</span>
|
|
72
89
|
</label>
|
|
73
90
|
{:else}
|
|
74
|
-
<
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
91
|
+
<label class="jatui-checkbox-target jatui-checkbox-bare">
|
|
92
|
+
<input
|
|
93
|
+
{...rest}
|
|
94
|
+
bind:this={inputEl}
|
|
95
|
+
type="checkbox"
|
|
96
|
+
{name}
|
|
97
|
+
{id}
|
|
98
|
+
class={inputClass}
|
|
99
|
+
checked={checked}
|
|
100
|
+
{disabled}
|
|
101
|
+
onchange={handleChange}
|
|
102
|
+
/>
|
|
103
|
+
</label>
|
|
85
104
|
{/if}
|
|
105
|
+
|
|
106
|
+
<style>
|
|
107
|
+
/* 24px minimum target (WCAG 2.5.8). The visual checkbox keeps its size. */
|
|
108
|
+
.jatui-checkbox-target {
|
|
109
|
+
min-height: 1.5rem;
|
|
110
|
+
align-items: center;
|
|
111
|
+
cursor: pointer;
|
|
112
|
+
}
|
|
113
|
+
.jatui-checkbox-row {
|
|
114
|
+
display: flex;
|
|
115
|
+
gap: 0.5rem;
|
|
116
|
+
}
|
|
117
|
+
.jatui-checkbox-bare {
|
|
118
|
+
display: inline-flex;
|
|
119
|
+
justify-content: center;
|
|
120
|
+
min-width: 1.5rem;
|
|
121
|
+
vertical-align: middle;
|
|
122
|
+
}
|
|
123
|
+
</style>
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
2
|
+
/**
|
|
3
|
+
* Any other native attribute (aria-label, aria-describedby, data-*, title,
|
|
4
|
+
* required, form…) passes straight through to the <input>. Without a visible
|
|
5
|
+
* `label`, pass `aria-label` so the checkbox has an accessible name.
|
|
6
|
+
*
|
|
7
|
+
* The click target is always at least 24×24px (WCAG 2.5.8), even at
|
|
8
|
+
* size xs/sm: the input sits in a <label> box with a 24px minimum, and a
|
|
9
|
+
* click anywhere in that box toggles it.
|
|
10
|
+
*/
|
|
11
|
+
interface Props extends Omit<HTMLInputAttributes, 'type' | 'checked' | 'size' | 'disabled' | 'name' | 'id' | 'onchange' | 'class' | 'children'> {
|
|
2
12
|
checked?: boolean;
|
|
3
13
|
label?: string;
|
|
4
14
|
size?: 'xs' | 'sm' | 'md' | 'lg';
|