@kerfjs/ui 5.0.0-beta.109 → 5.0.0-beta.110

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.
@@ -6716,7 +6716,7 @@
6716
6716
  "category": "Controls",
6717
6717
  "kind": "component",
6718
6718
  "source": "kerf",
6719
- "description": "A labeled single-line input or multi-line textarea with hint and error text, an optional leading icon, clear button, character count, and native numeric constraints, at the 44px control height or compact.",
6719
+ "description": "A labeled single-line input (including native date and number types) or multi-line textarea with hint and error text, an optional leading icon, clear button, character count, and native numeric constraints, at the 44px control height or compact.",
6720
6720
  "uses": [
6721
6721
  "lucide-icon"
6722
6722
  ],
@@ -6729,7 +6729,8 @@
6729
6729
  "A form or dialog collects a line of free text: label names it (or ariaLabel when nearby content already does), hint explains it, and error reports a validation problem.",
6730
6730
  "People write a longer note or message: multiline with rows, or rows plus maxRows to grow with the content; maxLength with showCount shows the remaining budget.",
6731
6731
  "A filter or search field needs a leading icon and a clear button: icon and clearable.",
6732
- "An exact number needs native range or decimal-step validation: type=number with min, max, and step (including step=any)."
6732
+ "An exact number needs native range or decimal-step validation: type=number with min, max, and step (including step=any).",
6733
+ "A form needs a calendar date with the browser's native date picker: type=date."
6733
6734
  ],
6734
6735
  "avoidWhen": [
6735
6736
  "Do not use when only existing values are allowed; use Select.",
@@ -6775,7 +6776,8 @@
6775
6776
  "disabled",
6776
6777
  "read-only",
6777
6778
  "required",
6778
- "email, password, search, url, tel, or number type",
6779
+ "native autofocus (input or textarea)",
6780
+ "email, password, search, url, tel, number, or date type",
6779
6781
  "number type with native min, max, and step constraints"
6780
6782
  ],
6781
6783
  "accessibility": [
@@ -4,7 +4,7 @@
4
4
 
5
5
  `@kerfjs/ui:text-field` · Kerf UI · component · Controls
6
6
 
7
- A labeled single-line input or multi-line textarea with hint and error text, an optional leading icon, clear button, character count, and native numeric constraints, at the 44px control height or compact.
7
+ A labeled single-line input (including native date and number types) or multi-line textarea with hint and error text, an optional leading icon, clear button, character count, and native numeric constraints, at the 44px control height or compact.
8
8
 
9
9
  ## When to use
10
10
 
@@ -14,6 +14,7 @@ Collect free text (names, addresses, notes, comments) with Kerf's field chrome,
14
14
  - People write a longer note or message: multiline with rows, or rows plus maxRows to grow with the content; maxLength with showCount shows the remaining budget.
15
15
  - A filter or search field needs a leading icon and a clear button: icon and clearable.
16
16
  - An exact number needs native range or decimal-step validation: type=number with min, max, and step (including step=any).
17
+ - A form needs a calendar date with the browser's native date picker: type=date.
17
18
 
18
19
  **Not when:**
19
20
 
@@ -53,7 +54,8 @@ Exact prop names and types: [`@kerfjs/ui/text-field`](../public-api-signatures-v
53
54
  - disabled
54
55
  - read-only
55
56
  - required
56
- - email, password, search, url, tel, or number type
57
+ - native autofocus (input or textarea)
58
+ - email, password, search, url, tel, number, or date type
57
59
  - number type with native min, max, and step constraints
58
60
 
59
61
  ## Composition
@@ -1,6 +1,6 @@
1
1
  # Public API signatures for the UI authoring corpus
2
2
 
3
- Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.109` and `kerfjs@5.0.0-beta.109`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
3
+ Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.110` and `kerfjs@5.0.0-beta.110`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
4
4
 
5
5
  ## `@kerfjs/ui/css-values`
6
6
 
@@ -6125,7 +6125,7 @@ import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
6125
6125
  /** `default` is the 44px control height; `compact` is 33px with smaller text. */
6126
6126
  type TextFieldSize = 'default' | 'compact';
6127
6127
  /** The kinds of single-line value a TextField takes. */
6128
- type TextFieldType = 'text' | 'email' | 'password' | 'search' | 'url' | 'tel' | 'number';
6128
+ type TextFieldType = 'text' | 'email' | 'password' | 'search' | 'url' | 'tel' | 'number' | 'date';
6129
6129
  /** Application `data-*` metadata; the TextField's own markers stay protected. */
6130
6130
  type TextFieldRootAttributes = Readonly<Record<`data-${string}`, string | undefined>>;
6131
6131
  /**
@@ -6169,7 +6169,7 @@ interface TextFieldOptions {
6169
6169
  * `wireTextFields(root)`, which updates it as people type.
6170
6170
  */
6171
6171
  showCount?: boolean;
6172
- /** Single-line value kind (default `text`). */
6172
+ /** Single-line value kind (default `text`); `date` uses the native picker. */
6173
6173
  type?: TextFieldType;
6174
6174
  /** Native lower bound for `type="number"` (number or numeric string). */
6175
6175
  min?: number | string;
@@ -6189,6 +6189,8 @@ interface TextFieldOptions {
6189
6189
  disabled?: boolean;
6190
6190
  readOnly?: boolean;
6191
6191
  required?: boolean;
6192
+ /** Request native focus on insertion or when the containing dialog opens. */
6193
+ autofocus?: boolean;
6192
6194
  autocomplete?: string;
6193
6195
  /** The input's id, for an external label or form. */
6194
6196
  id?: string;
@@ -6205,7 +6207,7 @@ interface TextFieldOptions {
6205
6207
  * The whole field is one `<label>`, so clicking anywhere on it focuses the
6206
6208
  * input; the input is named by `label` (or `ariaLabel`) directly.
6207
6209
  */
6208
- declare function TextField({ label, ariaLabel, value, name, placeholder, hint, error, size, icon, clearable, clearLabel, maxLength, showCount, type, min, max, step, multiline, rows, maxRows, disabled, readOnly, required, autocomplete, id, className, rootAttributes, slot, }: TextFieldProps): kerfjs.SafeHtml;
6210
+ declare function TextField({ label, ariaLabel, value, name, placeholder, hint, error, size, icon, clearable, clearLabel, maxLength, showCount, type, min, max, step, multiline, rows, maxRows, disabled, readOnly, required, autofocus, autocomplete, id, className, rootAttributes, slot, }: TextFieldProps): kerfjs.SafeHtml;
6209
6211
 
6210
6212
  export { TextField, type TextFieldName, type TextFieldOptions, type TextFieldProps, type TextFieldRootAttributes, type TextFieldSize, type TextFieldType };
6211
6213
  ```
package/ai/skill.md CHANGED
@@ -471,6 +471,10 @@ For a read-only field preview that replaces a Web Awesome input, use `FieldLabel
471
471
  For exact numeric entry, use `TextField` with `type="number"` and pass native
472
472
  `min`, `max`, and `step` as numbers or strings (`step="any"` permits arbitrary
473
473
  decimals). Those attributes reach the inner input only for numeric fields.
474
+ For a calendar date use `type="date"` with an ISO date value. Set
475
+ `autofocus` when the native input or textarea should receive initial focus on
476
+ insertion or when its containing dialog opens; move focus explicitly when an
477
+ application interaction needs different timing.
474
478
 
475
479
  Common mistakes:
476
480
 
@@ -1,6 +1,6 @@
1
1
  # Web Awesome JSX signatures for the UI authoring corpus
2
2
 
3
- Generated from the emitted `@kerfjs/ui@5.0.0-beta.109` declaration boundary. Import `@kerfjs/ui/webawesome` for type effects when authoring direct `wa-*` JSX. The module emits no runtime behavior and does not register custom elements.
3
+ Generated from the emitted `@kerfjs/ui@5.0.0-beta.110` declaration boundary. Import `@kerfjs/ui/webawesome` for type effects when authoring direct `wa-*` JSX. The module emits no runtime behavior and does not register custom elements.
4
4
 
5
5
  ```ts
6
6
  import { KerfCustomElement } from 'kerfjs/jsx-runtime';
@@ -33,6 +33,7 @@ function TextField({
33
33
  disabled = false,
34
34
  readOnly = false,
35
35
  required = false,
36
+ autofocus = false,
36
37
  autocomplete,
37
38
  id,
38
39
  className = "",
@@ -50,6 +51,7 @@ function TextField({
50
51
  disabled,
51
52
  readonly: readOnly,
52
53
  required,
54
+ autofocus,
53
55
  autocomplete,
54
56
  maxlength: maxLength,
55
57
  // The label element also wraps the clear button and the count, so the
@@ -118,4 +120,4 @@ function TextField({
118
120
 
119
121
  export { TextField };
120
122
 
121
- //# sourceMappingURL=chunk-YVZCKXR3.js.map
123
+ //# sourceMappingURL=chunk-36HVQ72F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/forms/text-field/text-field.tsx"],"names":[],"mappings":";;;;;AAaA,IAAM,oBAAA,uBAA2B,GAAA,CAAI;AAAA,EACnC,gBAAA;AAAA,EACA,WAAA;AAAA,EACA,cAAA;AAAA,EACA;AACF,CAAC,CAAA;AAoFM,SAAS,SAAA,CAAU;AAAA,EACxB,KAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,WAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA,GAAO,SAAA;AAAA,EACP,IAAA;AAAA,EACA,SAAA,GAAY,KAAA;AAAA,EACZ,UAAA,GAAa,OAAA;AAAA,EACb,SAAA;AAAA,EACA,SAAA,GAAY,KAAA;AAAA,EACZ,IAAA,GAAO,MAAA;AAAA,EACP,GAAA;AAAA,EACA,GAAA;AAAA,EACA,IAAA;AAAA,EACA,SAAA,GAAY,KAAA;AAAA,EACZ,IAAA,GAAO,CAAA;AAAA,EACP,OAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,QAAA,GAAW,KAAA;AAAA,EACX,QAAA,GAAW,KAAA;AAAA,EACX,SAAA,GAAY,KAAA;AAAA,EACZ,YAAA;AAAA,EACA,EAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,iBAAiB,EAAC;AAAA,EAClB;AACF,CAAA,EAAmB;AACjB,EAAA,MAAM,WAAA,GAAc,CAAC,IAAA,EAAM,KAAK,CAAA,CAAE,OAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA,IAAK,MAAA;AAC/D,EAAA,MAAM,MAAA,GAAS;AAAA,IACb,EAAA;AAAA,IACA,IAAA;AAAA;AAAA;AAAA;AAAA,IAIA,WAAA,EAAa,SAAA,IAAa,CAAC,SAAA,GAAa,eAAe,GAAA,GAAO,WAAA;AAAA,IAC9D,QAAA;AAAA,IACA,QAAA,EAAU,QAAA;AAAA,IACV,QAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,SAAA,EAAW,SAAA;AAAA;AAAA;AAAA,IAGX,cAAc,KAAA,IAAS,SAAA;AAAA,IACvB,kBAAA,EAAoB,WAAA;AAAA,IACpB,cAAA,EAAgB,QAAQ,MAAA,GAAS;AAAA,GACnC;AACA,EAAA,MAAM,QAAA,GACJ,IAAA,KAAS,MAAA,GAAY,IAAA,mBACnB,GAAA,CAAC,UAAK,KAAA,EAAM,sBAAA,EAAuB,aAAA,EAAY,MAAA,EAC5C,QAAA,EAAA,IAAA,EACH,CAAA;AAEJ,EAAA,MAAM,KAAA,GACJ,SAAA,IAAa,SAAA,KAAc,MAAA,GACvB,GAAG,MAAA,CAAA,CAAQ,KAAA,IAAS,EAAA,EAAI,MAAM,CAAC,CAAA,GAAA,EAAM,MAAA,CAAO,SAAS,CAAC,CAAA,CAAA,GACtD,MAAA;AACN,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,SAAA,GAAY,CAAA,uBAAA,EAA0B,MAAA,CAAO,IAAI,CAAC,CAAA,CAAA,GAAK,EAAA;AAAA,IACvD,SAAA,IAAa,OAAA,KAAY,MAAA,GACrB,CAAA,2BAAA,EAA8B,MAAA,CAAO,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,OAAO,CAAC,CAAC,CAAA,CAAA,GAC7D;AAAA,GACN,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AACX,EAAA,uBACE,IAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACE,GAAG,oBAAA,CAAqB,cAAA,EAAgB,oBAAoB,CAAA;AAAA,MAC7D,KAAA,EAAO,CAAA,eAAA,EAAkB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,MAC1C,gBAAA,EAAe,YAAA;AAAA,MACf,WAAA,EAAW,IAAA;AAAA,MACX,cAAA,EAAc,QAAQ,EAAA,GAAK,MAAA;AAAA,MAC3B,gBAAA,EACE,SAAA,GAAa,OAAA,KAAY,MAAA,GAAY,KAAK,MAAA,GAAU,MAAA;AAAA,MAEtD,OAAO,KAAA,IAAS,MAAA;AAAA,MAChB,IAAA;AAAA,MAEC,QAAA,EAAA;AAAA,QAAA,KAAA,KAAU,SAAY,IAAA,mBACrB,IAAA,CAAC,UAAK,KAAA,EAAM,uBAAA,EAAwB,eAAY,MAAA,EAC7C,QAAA,EAAA;AAAA,UAAA,KAAA;AAAA,UACA,QAAA,uBACE,MAAA,EAAA,EAAK,KAAA,EAAM,4BAA2B,aAAA,EAAY,MAAA,EAAO,eAE1D,CAAA,GACE;AAAA,SAAA,EACN,CAAA;AAAA,wBAEF,IAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAM,qBAAA,EACT,QAAA,EAAA;AAAA,UAAA,IAAA,KAAS,MAAA,IAAa,YAAY,IAAA,mBACjC,GAAA,CAAC,UAAK,KAAA,EAAM,sBAAA,EAAuB,aAAA,EAAY,MAAA,EAC5C,QAAA,EAAA,IAAA,EACH,CAAA;AAAA,UAED,SAAA,mBACC,GAAA,CAAC,UAAA,EAAA,EAAU,GAAG,MAAA,EAAQ,OAAM,uBAAA,EAAwB,IAAA,EACjD,QAAA,EAAA,KAAA,IAAS,EAAA,EACZ,CAAA,mBAEA,GAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACE,GAAG,MAAA;AAAA,cACJ,KAAA,EAAM,uBAAA;AAAA,cACN,IAAA;AAAA,cACA,KAAA;AAAA,cACA,GAAA,EAAK,IAAA,KAAS,QAAA,GAAW,GAAA,GAAM,MAAA;AAAA,cAC/B,GAAA,EAAK,IAAA,KAAS,QAAA,GAAW,GAAA,GAAM,MAAA;AAAA,cAC/B,IAAA,EAAM,IAAA,KAAS,QAAA,GAAW,IAAA,GAAO;AAAA;AAAA,WACnC;AAAA,UAED,SAAA,IAAa,CAAC,SAAA,mBACb,GAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,KAAA,EAAM,uBAAA;AAAA,cACN,YAAA,EAAY,UAAA;AAAA,cACZ,uBAAA,EAAsB,EAAA;AAAA,cACtB,UAAU,QAAA,IAAY,QAAA;AAAA,cAEtB,QAAA,kBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,IAAA,EAAM,OAAA,EAAS,MAAK,UAAA,EAAW;AAAA;AAAA,WAC7C,GACE;AAAA,SAAA,EACN,CAAA;AAAA,QACC,UAAU,MAAA,GACT,QAAA,mBAEA,IAAA,CAAC,MAAA,EAAA,EAAK,OAAM,wBAAA,EACT,QAAA,EAAA;AAAA,UAAA,QAAA;AAAA,8BACA,MAAA,EAAA,EAAK,KAAA,EAAM,uBAAA,EAAwB,uBAAA,EAAsB,IACvD,QAAA,EAAA,KAAA,EACH;AAAA,SAAA,EACF,CAAA;AAAA,QAED,KAAA,KAAU,SAAY,IAAA,mBACrB,GAAA,CAAC,UAAK,KAAA,EAAM,uBAAA,EAAwB,aAAA,EAAY,MAAA,EAC7C,QAAA,EAAA,KAAA,EACH;AAAA;AAAA;AAAA,GAEJ;AAEJ","file":"chunk-36HVQ72F.js","sourcesContent":["import { CircleX } from 'lucide';\n\nimport type { KerfUiContent } from '../../../shared/content/semantic-content.js';\nimport { filterDataAttributes } from '../../../shared/dom/extension-attributes.js';\nimport { LucideIcon } from '../../media/lucide-icon/lucide-icon.js';\n\n/** `default` is the 44px control height; `compact` is 33px with smaller text. */\nexport type TextFieldSize = 'default' | 'compact';\n\n/** The kinds of single-line value a TextField takes. */\nexport type TextFieldType =\n 'text' | 'email' | 'password' | 'search' | 'url' | 'tel' | 'number' | 'date';\n\nconst TEXT_FIELD_PROTECTED = new Set([\n 'data-component',\n 'data-size',\n 'data-invalid',\n 'data-multiline',\n]);\n\n/** Application `data-*` metadata; the TextField's own markers stay protected. */\nexport type TextFieldRootAttributes = Readonly<\n Record<`data-${string}`, string | undefined>\n>;\n\n/**\n * The field's accessible name: a visible `label`, or `ariaLabel` when the\n * surrounding content already names it.\n */\nexport type TextFieldName =\n { label: string; ariaLabel?: never } | { label?: never; ariaLabel: string };\n\nexport type TextFieldProps = TextFieldName & TextFieldOptions;\n\nexport interface TextFieldOptions {\n /** The controlled value. */\n value?: string;\n name?: string;\n placeholder?: string;\n /** Supporting text below the field, also its accessible description. */\n hint?: string;\n /**\n * A validation message: shown below the field in the danger color, added\n * to its description, and marking it `aria-invalid`.\n */\n error?: string;\n size?: TextFieldSize;\n /** A leading decorative icon, such as a `LucideIcon` (single-line only). */\n icon?: KerfUiContent;\n /**\n * A clear button while the field has a value (single-line only). Needs\n * `wireTextFields(root)`, which clears the field and announces `input`.\n */\n clearable?: boolean;\n /** The clear button's accessible name (default `Clear`). */\n clearLabel?: string;\n /** The most characters the field accepts (native `maxlength`). */\n maxLength?: number;\n /**\n * Show a live `count / maxLength` below the field. Needs `maxLength` and\n * `wireTextFields(root)`, which updates it as people type.\n */\n showCount?: boolean;\n /** Single-line value kind (default `text`); `date` uses the native picker. */\n type?: TextFieldType;\n /** Native lower bound for `type=\"number\"` (number or numeric string). */\n min?: number | string;\n /** Native upper bound for `type=\"number\"` (number or numeric string). */\n max?: number | string;\n /** Native number increment (number, numeric string, or `\"any\"`). */\n step?: number | string;\n /** A multi-line field: a `<textarea>`. */\n multiline?: boolean;\n /** A multi-line field's height in lines (default 3). */\n rows?: number;\n /**\n * Grow a multi-line field with its content from `rows` up to this many\n * lines, then scroll.\n */\n maxRows?: number;\n disabled?: boolean;\n readOnly?: boolean;\n required?: boolean;\n /** Request native focus on insertion or when the containing dialog opens. */\n autofocus?: boolean;\n autocomplete?: string;\n /** The input's id, for an external label or form. */\n id?: string;\n className?: string;\n /** Safe `data-*` metadata (a `data-key`). */\n rootAttributes?: TextFieldRootAttributes;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\n/**\n * A text input with its label above, an optional leading icon and clear\n * button, and supporting or error text below, at the 44px control height or\n * compact. `multiline` makes it a textarea that can grow with its content.\n * The whole field is one `<label>`, so clicking anywhere on it focuses the\n * input; the input is named by `label` (or `ariaLabel`) directly.\n */\nexport function TextField({\n label,\n ariaLabel,\n value,\n name,\n placeholder,\n hint,\n error,\n size = 'default',\n icon,\n clearable = false,\n clearLabel = 'Clear',\n maxLength,\n showCount = false,\n type = 'text',\n min,\n max,\n step,\n multiline = false,\n rows = 3,\n maxRows,\n disabled = false,\n readOnly = false,\n required = false,\n autofocus = false,\n autocomplete,\n id,\n className = '',\n rootAttributes = {},\n slot,\n}: TextFieldProps) {\n const description = [hint, error].filter(Boolean).join(' ') || undefined;\n const shared = {\n id,\n name,\n // A clearable field always has a placeholder, so CSS can hide its clear\n // button while the field is empty (`:placeholder-shown`); a blank one\n // shows nothing.\n placeholder: clearable && !multiline ? (placeholder ?? ' ') : placeholder,\n disabled,\n readonly: readOnly,\n required,\n autofocus,\n autocomplete,\n maxlength: maxLength,\n // The label element also wraps the clear button and the count, so the\n // input takes its name explicitly rather than from the label's text.\n 'aria-label': label ?? ariaLabel,\n 'aria-description': description,\n 'aria-invalid': error ? 'true' : undefined,\n } as const;\n const hintText =\n hint === undefined ? null : (\n <span class=\"kui-text-field__hint\" aria-hidden=\"true\">\n {hint}\n </span>\n );\n const count =\n showCount && maxLength !== undefined\n ? `${String((value ?? '').length)} / ${String(maxLength)}`\n : undefined;\n const style = [\n multiline ? `--_kui-text-field-rows:${String(rows)}` : '',\n multiline && maxRows !== undefined\n ? `--_kui-text-field-max-rows:${String(Math.max(rows, maxRows))}`\n : '',\n ]\n .filter(Boolean)\n .join(';');\n return (\n <label\n {...filterDataAttributes(rootAttributes, TEXT_FIELD_PROTECTED)}\n class={`kui-text-field ${className}`.trim()}\n data-component=\"text-field\"\n data-size={size}\n data-invalid={error ? '' : undefined}\n data-multiline={\n multiline ? (maxRows === undefined ? '' : 'grow') : undefined\n }\n style={style || undefined}\n slot={slot}\n >\n {label === undefined ? null : (\n <span class=\"kui-text-field__label\" aria-hidden=\"true\">\n {label}\n {required ? (\n <span class=\"kui-text-field__required\" aria-hidden=\"true\">\n *\n </span>\n ) : null}\n </span>\n )}\n <span class=\"kui-text-field__box\">\n {icon === undefined || multiline ? null : (\n <span class=\"kui-text-field__icon\" aria-hidden=\"true\">\n {icon}\n </span>\n )}\n {multiline ? (\n <textarea {...shared} class=\"kui-text-field__input\" rows={rows}>\n {value ?? ''}\n </textarea>\n ) : (\n <input\n {...shared}\n class=\"kui-text-field__input\"\n type={type}\n value={value}\n min={type === 'number' ? min : undefined}\n max={type === 'number' ? max : undefined}\n step={type === 'number' ? step : undefined}\n />\n )}\n {clearable && !multiline ? (\n <button\n type=\"button\"\n class=\"kui-text-field__clear\"\n aria-label={clearLabel}\n data-text-field-clear=\"\"\n disabled={disabled || readOnly}\n >\n <LucideIcon icon={CircleX} name=\"circle-x\" />\n </button>\n ) : null}\n </span>\n {count === undefined ? (\n hintText\n ) : (\n <span class=\"kui-text-field__footer\">\n {hintText}\n <span class=\"kui-text-field__count\" data-text-field-count=\"\">\n {count}\n </span>\n </span>\n )}\n {error === undefined ? null : (\n <span class=\"kui-text-field__error\" aria-hidden=\"true\">\n {error}\n </span>\n )}\n </label>\n );\n}\n"]}
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ export { wireScrollDividers } from './chunk-OZ6X76G5.js';
17
17
  export { wireCheckboxes } from './chunk-CNM6ZWP2.js';
18
18
  export { TabBarItem } from './chunk-ZCDRLN3B.js';
19
19
  export { TabBar } from './chunk-7AK5I7U7.js';
20
- export { TextField } from './chunk-YVZCKXR3.js';
20
+ export { TextField } from './chunk-36HVQ72F.js';
21
21
  export { Spacer } from './chunk-YMUIQRWK.js';
22
22
  export { SplitButton } from './chunk-TI2GV36S.js';
23
23
  export { StateBanner } from './chunk-2FW7D4IG.js';
@@ -44,7 +44,12 @@
44
44
  --_kui-button-fill: var(--kui-color-brand-fill-loud);
45
45
  --_kui-button-text: var(--kui-color-brand-on-loud);
46
46
  --_kui-button-quiet: var(--kui-color-brand-fill-quiet);
47
- --_kui-button-on-quiet: var(--kui-color-brand-on-quiet);
47
+ /* A quiet hover fill can be stronger than the page (including app-owned
48
+ palettes), so darken the brand label enough for text on that fill. */
49
+ --_kui-button-on-quiet: light-dark(
50
+ oklch(from var(--kui-color-brand-on-quiet) min(l, 0.38) c h),
51
+ var(--kui-color-brand-on-quiet)
52
+ );
48
53
  --_kui-button-outline: var(--kui-color-brand-border-loud);
49
54
  }
50
55
  .kui-button[data-tone="success"] {
@@ -108,7 +113,10 @@
108
113
  --_kui-button-fill: var(--kui-color-brand-fill-loud);
109
114
  --_kui-button-text: var(--kui-color-brand-on-loud);
110
115
  --_kui-button-quiet: var(--kui-color-brand-fill-quiet);
111
- --_kui-button-on-quiet: var(--kui-color-brand-on-quiet);
116
+ --_kui-button-on-quiet: light-dark(
117
+ oklch(from var(--kui-color-brand-on-quiet) min(l, 0.38) c h),
118
+ var(--kui-color-brand-on-quiet)
119
+ );
112
120
  --_kui-button-outline: var(--kui-color-brand-border-loud);
113
121
  }
114
122
  /* A pressed toggle draws on top of its tone and emphasis. Secondary and plain
@@ -44,7 +44,12 @@
44
44
  --_kui-button-fill: var(--kui-color-brand-fill-loud);
45
45
  --_kui-button-text: var(--kui-color-brand-on-loud);
46
46
  --_kui-button-quiet: var(--kui-color-brand-fill-quiet);
47
- --_kui-button-on-quiet: var(--kui-color-brand-on-quiet);
47
+ /* A quiet hover fill can be stronger than the page (including app-owned
48
+ palettes), so darken the brand label enough for text on that fill. */
49
+ --_kui-button-on-quiet: light-dark(
50
+ oklch(from var(--kui-color-brand-on-quiet) min(l, 0.38) c h),
51
+ var(--kui-color-brand-on-quiet)
52
+ );
48
53
  --_kui-button-outline: var(--kui-color-brand-border-loud);
49
54
  }
50
55
  .kui-button[data-tone="success"] {
@@ -108,7 +113,10 @@
108
113
  --_kui-button-fill: var(--kui-color-brand-fill-loud);
109
114
  --_kui-button-text: var(--kui-color-brand-on-loud);
110
115
  --_kui-button-quiet: var(--kui-color-brand-fill-quiet);
111
- --_kui-button-on-quiet: var(--kui-color-brand-on-quiet);
116
+ --_kui-button-on-quiet: light-dark(
117
+ oklch(from var(--kui-color-brand-on-quiet) min(l, 0.38) c h),
118
+ var(--kui-color-brand-on-quiet)
119
+ );
112
120
  --_kui-button-outline: var(--kui-color-brand-border-loud);
113
121
  }
114
122
  /* A pressed toggle draws on top of its tone and emphasis. Secondary and plain
@@ -4,7 +4,7 @@ import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
4
4
  /** `default` is the 44px control height; `compact` is 33px with smaller text. */
5
5
  type TextFieldSize = 'default' | 'compact';
6
6
  /** The kinds of single-line value a TextField takes. */
7
- type TextFieldType = 'text' | 'email' | 'password' | 'search' | 'url' | 'tel' | 'number';
7
+ type TextFieldType = 'text' | 'email' | 'password' | 'search' | 'url' | 'tel' | 'number' | 'date';
8
8
  /** Application `data-*` metadata; the TextField's own markers stay protected. */
9
9
  type TextFieldRootAttributes = Readonly<Record<`data-${string}`, string | undefined>>;
10
10
  /**
@@ -48,7 +48,7 @@ interface TextFieldOptions {
48
48
  * `wireTextFields(root)`, which updates it as people type.
49
49
  */
50
50
  showCount?: boolean;
51
- /** Single-line value kind (default `text`). */
51
+ /** Single-line value kind (default `text`); `date` uses the native picker. */
52
52
  type?: TextFieldType;
53
53
  /** Native lower bound for `type="number"` (number or numeric string). */
54
54
  min?: number | string;
@@ -68,6 +68,8 @@ interface TextFieldOptions {
68
68
  disabled?: boolean;
69
69
  readOnly?: boolean;
70
70
  required?: boolean;
71
+ /** Request native focus on insertion or when the containing dialog opens. */
72
+ autofocus?: boolean;
71
73
  autocomplete?: string;
72
74
  /** The input's id, for an external label or form. */
73
75
  id?: string;
@@ -84,6 +86,6 @@ interface TextFieldOptions {
84
86
  * The whole field is one `<label>`, so clicking anywhere on it focuses the
85
87
  * input; the input is named by `label` (or `ariaLabel`) directly.
86
88
  */
87
- declare function TextField({ label, ariaLabel, value, name, placeholder, hint, error, size, icon, clearable, clearLabel, maxLength, showCount, type, min, max, step, multiline, rows, maxRows, disabled, readOnly, required, autocomplete, id, className, rootAttributes, slot, }: TextFieldProps): kerfjs.SafeHtml;
89
+ declare function TextField({ label, ariaLabel, value, name, placeholder, hint, error, size, icon, clearable, clearLabel, maxLength, showCount, type, min, max, step, multiline, rows, maxRows, disabled, readOnly, required, autofocus, autocomplete, id, className, rootAttributes, slot, }: TextFieldProps): kerfjs.SafeHtml;
88
90
 
89
91
  export { TextField, type TextFieldName, type TextFieldOptions, type TextFieldProps, type TextFieldRootAttributes, type TextFieldSize, type TextFieldType };
@@ -1,4 +1,4 @@
1
- export { TextField } from './chunk-YVZCKXR3.js';
1
+ export { TextField } from './chunk-36HVQ72F.js';
2
2
 
3
3
 
4
4
 
@@ -546,12 +546,22 @@ its label; the input itself reports `required`. The focus ring is drawn on the
546
546
  box around the input (`:focus-within`), 3px with a 1px offset like every Kerf
547
547
  control.
548
548
 
549
+ `autofocus` forwards to the native input or textarea. It requests initial focus
550
+ when a field is inserted or its containing native dialog opens. Applications
551
+ still direct focus themselves when it must move from an already focused control.
552
+
549
553
  For `type="number"`, `min`, `max`, and `step` pass through to the native input.
550
554
  Each accepts a number or string; `step="any"` allows arbitrary decimals.
551
555
  They are omitted for other input types and `multiline` textareas. Native
552
556
  constraint validation (`rangeUnderflow`, `rangeOverflow`, and `stepMismatch`)
553
557
  then applies without custom field wiring.
554
558
 
559
+ For `type="date"`, TextField renders a native date input. The browser owns its
560
+ picker, localized display, keyboard interaction, and `input`/`change` events;
561
+ the `value` remains an ISO date string (`YYYY-MM-DD`). The same `name`, label,
562
+ required, disabled, read-only, and focus behavior as other single-line fields
563
+ applies. Numeric `min`, `max`, and `step` props do not pass to date inputs.
564
+
555
565
  `clearable` adds a native `<button>` named by `clearLabel` (default "Clear")
556
566
  after the input. It is hidden while the field is empty, is a normal Tab stop,
557
567
  and with `wireTextFields(root)` empties the field, dispatches bubbling `input`
@@ -563,6 +573,12 @@ touch screens so focusing a field never zooms the page in iOS.
563
573
 
564
574
  ## Button and SplitButton focus
565
575
 
576
+ A brand `Button` with `secondary` or `plain` emphasis clamps its
577
+ `brand-on-quiet` label to a darker light-theme value. Its quiet hover fill can
578
+ be stronger than the page background, so the unclamped token may be too light
579
+ for the button label. The same label color applies to pressed and focused
580
+ states; the focus ring remains visible around the control.
581
+
566
582
  `Button` and each `SplitButton` half draw the 3px focus ring 1px outside the
567
583
  box, against the surrounding surface, because a loud fill can share the ring's
568
584
  hue (the brand fill matches the focus color in both schemes). An ancestor that
package/llms.txt CHANGED
@@ -743,11 +743,12 @@ headingLevel`, `SearchField clearIcon`, `ContentItem frame="framed"` for a
743
743
  an app div with `max-height`, `overflow`, and a border.
744
744
  - **Use `Button` for every standalone action, icon-only included.**
745
745
  `Button` (`@kerfjs/ui/button`) is a native button in a `tone` (`neutral`,
746
- `brand`, `danger`) and an `emphasis` (`primary`, `secondary`, `plain`), at
746
+ `brand`, `success`, `danger`) and an `emphasis` (`primary`, `secondary`, `plain`), at
747
747
  the 44px control height or `size="compact"`, with an optional `icon`,
748
748
  `loading`, `href`, form `type`, `shape` (`rounded` or `pill`), and `pressed`
749
749
  for a toggle. With an `icon` and `ariaLabel` but no label it is an icon-only
750
- square (a circle as a pill). Inside a `ToolbarControlGroup`
750
+ square (a circle as a pill). Brand secondary/plain labels darken the brand
751
+ token in light mode to stay legible on a quiet hover fill. Inside a `ToolbarControlGroup`
751
752
  keep a native `button`; the group owns its geometry.
752
753
  - **Paint a strip's surface with `List surface`.** `surface="base"` or
753
754
  `"raised"` fills a List and its insets with a solid surface (a banner strip
@@ -759,7 +760,10 @@ headingLevel`, `SearchField clearIcon`, `ContentItem frame="framed"` for a
759
760
  `showCount`, at the 44px height or `size="compact"`. Call
760
761
  `wireTextFields(root)` (`@kerfjs/ui/wire-text-fields`) once for clearing and
761
762
  counting. For `type="number"`, pass native `min`, `max`, and `step` as numbers
762
- or strings (`step="any"` accepts arbitrary decimals). Never render `wa-input`
763
+ or strings (`step="any"` accepts arbitrary decimals). For `type="date"`,
764
+ pass an ISO date string and use the browser's native picker. `autofocus`
765
+ forwards to the native input or textarea for insertion and dialog open.
766
+ Never render `wa-input`
763
767
  or `wa-textarea` for a form field.
764
768
  - **Use `Checkbox`, `CheckboxGroup`, `RadioGroup`, and `Switch` for native
765
769
  toggles.** `@kerfjs/ui/checkbox` (with `indeterminate` and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kerfjs/ui",
3
- "version": "5.0.0-beta.109",
3
+ "version": "5.0.0-beta.110",
4
4
  "description": "Accessible, composable UI primitives for kerf applications.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/forms/text-field/text-field.tsx"],"names":[],"mappings":"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","file":"chunk-YVZCKXR3.js","sourcesContent":["import { CircleX } from 'lucide';\n\nimport type { KerfUiContent } from '../../../shared/content/semantic-content.js';\nimport { filterDataAttributes } from '../../../shared/dom/extension-attributes.js';\nimport { LucideIcon } from '../../media/lucide-icon/lucide-icon.js';\n\n/** `default` is the 44px control height; `compact` is 33px with smaller text. */\nexport type TextFieldSize = 'default' | 'compact';\n\n/** The kinds of single-line value a TextField takes. */\nexport type TextFieldType =\n 'text' | 'email' | 'password' | 'search' | 'url' | 'tel' | 'number';\n\nconst TEXT_FIELD_PROTECTED = new Set([\n 'data-component',\n 'data-size',\n 'data-invalid',\n 'data-multiline',\n]);\n\n/** Application `data-*` metadata; the TextField's own markers stay protected. */\nexport type TextFieldRootAttributes = Readonly<\n Record<`data-${string}`, string | undefined>\n>;\n\n/**\n * The field's accessible name: a visible `label`, or `ariaLabel` when the\n * surrounding content already names it.\n */\nexport type TextFieldName =\n { label: string; ariaLabel?: never } | { label?: never; ariaLabel: string };\n\nexport type TextFieldProps = TextFieldName & TextFieldOptions;\n\nexport interface TextFieldOptions {\n /** The controlled value. */\n value?: string;\n name?: string;\n placeholder?: string;\n /** Supporting text below the field, also its accessible description. */\n hint?: string;\n /**\n * A validation message: shown below the field in the danger color, added\n * to its description, and marking it `aria-invalid`.\n */\n error?: string;\n size?: TextFieldSize;\n /** A leading decorative icon, such as a `LucideIcon` (single-line only). */\n icon?: KerfUiContent;\n /**\n * A clear button while the field has a value (single-line only). Needs\n * `wireTextFields(root)`, which clears the field and announces `input`.\n */\n clearable?: boolean;\n /** The clear button's accessible name (default `Clear`). */\n clearLabel?: string;\n /** The most characters the field accepts (native `maxlength`). */\n maxLength?: number;\n /**\n * Show a live `count / maxLength` below the field. Needs `maxLength` and\n * `wireTextFields(root)`, which updates it as people type.\n */\n showCount?: boolean;\n /** Single-line value kind (default `text`). */\n type?: TextFieldType;\n /** Native lower bound for `type=\"number\"` (number or numeric string). */\n min?: number | string;\n /** Native upper bound for `type=\"number\"` (number or numeric string). */\n max?: number | string;\n /** Native number increment (number, numeric string, or `\"any\"`). */\n step?: number | string;\n /** A multi-line field: a `<textarea>`. */\n multiline?: boolean;\n /** A multi-line field's height in lines (default 3). */\n rows?: number;\n /**\n * Grow a multi-line field with its content from `rows` up to this many\n * lines, then scroll.\n */\n maxRows?: number;\n disabled?: boolean;\n readOnly?: boolean;\n required?: boolean;\n autocomplete?: string;\n /** The input's id, for an external label or form. */\n id?: string;\n className?: string;\n /** Safe `data-*` metadata (a `data-key`). */\n rootAttributes?: TextFieldRootAttributes;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\n/**\n * A text input with its label above, an optional leading icon and clear\n * button, and supporting or error text below, at the 44px control height or\n * compact. `multiline` makes it a textarea that can grow with its content.\n * The whole field is one `<label>`, so clicking anywhere on it focuses the\n * input; the input is named by `label` (or `ariaLabel`) directly.\n */\nexport function TextField({\n label,\n ariaLabel,\n value,\n name,\n placeholder,\n hint,\n error,\n size = 'default',\n icon,\n clearable = false,\n clearLabel = 'Clear',\n maxLength,\n showCount = false,\n type = 'text',\n min,\n max,\n step,\n multiline = false,\n rows = 3,\n maxRows,\n disabled = false,\n readOnly = false,\n required = false,\n autocomplete,\n id,\n className = '',\n rootAttributes = {},\n slot,\n}: TextFieldProps) {\n const description = [hint, error].filter(Boolean).join(' ') || undefined;\n const shared = {\n id,\n name,\n // A clearable field always has a placeholder, so CSS can hide its clear\n // button while the field is empty (`:placeholder-shown`); a blank one\n // shows nothing.\n placeholder: clearable && !multiline ? (placeholder ?? ' ') : placeholder,\n disabled,\n readonly: readOnly,\n required,\n autocomplete,\n maxlength: maxLength,\n // The label element also wraps the clear button and the count, so the\n // input takes its name explicitly rather than from the label's text.\n 'aria-label': label ?? ariaLabel,\n 'aria-description': description,\n 'aria-invalid': error ? 'true' : undefined,\n } as const;\n const hintText =\n hint === undefined ? null : (\n <span class=\"kui-text-field__hint\" aria-hidden=\"true\">\n {hint}\n </span>\n );\n const count =\n showCount && maxLength !== undefined\n ? `${String((value ?? '').length)} / ${String(maxLength)}`\n : undefined;\n const style = [\n multiline ? `--_kui-text-field-rows:${String(rows)}` : '',\n multiline && maxRows !== undefined\n ? `--_kui-text-field-max-rows:${String(Math.max(rows, maxRows))}`\n : '',\n ]\n .filter(Boolean)\n .join(';');\n return (\n <label\n {...filterDataAttributes(rootAttributes, TEXT_FIELD_PROTECTED)}\n class={`kui-text-field ${className}`.trim()}\n data-component=\"text-field\"\n data-size={size}\n data-invalid={error ? '' : undefined}\n data-multiline={\n multiline ? (maxRows === undefined ? '' : 'grow') : undefined\n }\n style={style || undefined}\n slot={slot}\n >\n {label === undefined ? null : (\n <span class=\"kui-text-field__label\" aria-hidden=\"true\">\n {label}\n {required ? (\n <span class=\"kui-text-field__required\" aria-hidden=\"true\">\n *\n </span>\n ) : null}\n </span>\n )}\n <span class=\"kui-text-field__box\">\n {icon === undefined || multiline ? null : (\n <span class=\"kui-text-field__icon\" aria-hidden=\"true\">\n {icon}\n </span>\n )}\n {multiline ? (\n <textarea {...shared} class=\"kui-text-field__input\" rows={rows}>\n {value ?? ''}\n </textarea>\n ) : (\n <input\n {...shared}\n class=\"kui-text-field__input\"\n type={type}\n value={value}\n min={type === 'number' ? min : undefined}\n max={type === 'number' ? max : undefined}\n step={type === 'number' ? step : undefined}\n />\n )}\n {clearable && !multiline ? (\n <button\n type=\"button\"\n class=\"kui-text-field__clear\"\n aria-label={clearLabel}\n data-text-field-clear=\"\"\n disabled={disabled || readOnly}\n >\n <LucideIcon icon={CircleX} name=\"circle-x\" />\n </button>\n ) : null}\n </span>\n {count === undefined ? (\n hintText\n ) : (\n <span class=\"kui-text-field__footer\">\n {hintText}\n <span class=\"kui-text-field__count\" data-text-field-count=\"\">\n {count}\n </span>\n </span>\n )}\n {error === undefined ? null : (\n <span class=\"kui-text-field__error\" aria-hidden=\"true\">\n {error}\n </span>\n )}\n </label>\n );\n}\n"]}