@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
- interface Props {
11
- label: string;
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 ? `${id}-error` : helpText ? `${id}-help` : undefined}
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
- * 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).
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: string;
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
- interface Props {
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="flex cursor-pointer items-center gap-2" for={inputId}>
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
- <input
75
- bind:this={inputEl}
76
- type="checkbox"
77
- {name}
78
- {id}
79
- class={inputClass}
80
- checked={checked}
81
- {disabled}
82
- onchange={handleChange}
83
- aria-label={label}
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
- interface Props {
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';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joewinke/jatui",
3
- "version": "0.36.3",
3
+ "version": "0.37.0",
4
4
  "private": false,
5
5
  "description": "Shared Svelte 5 component library for JAT projects",
6
6
  "type": "module",