@apliteni/apliteni-ui 0.60.0 → 0.61.1

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.
@@ -8,7 +8,7 @@
8
8
 
9
9
  **Why:** Without a legend, readers need labels for unfamiliar glyphs.
10
10
 
11
- **Except:** The list grows by decision, not review debate. Today: `x` (close or dismiss), `copy` (copy to clipboard), `moreHorizontal` (overflow menu), `moreVertical` (overflow menu), `chevronDown` (expand or collapse), and `chevronUp` (expand or collapse).
11
+ **Except:** The list grows by decision, not review debate. Today: `x` (close or dismiss), `copy` (copy to clipboard), `moreHorizontal` (overflow menu), `moreVertical` (overflow menu), `chevronDown` (expand or collapse), `chevronUp` (expand or collapse), and the shell’s theme toggle, sidebar toggle and collapsed-rail links.
12
12
 
13
13
  **Do:** Show an overflow menu without words; keep the Settings label.
14
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apliteni/apliteni-ui",
3
- "version": "0.60.0",
3
+ "version": "0.61.1",
4
4
  "workspaces": [
5
5
  "react"
6
6
  ],
package/react/README.md CHANGED
@@ -433,7 +433,10 @@ Import both the kit CSS and React CSS. The Privileged story shows Undo adding a
433
433
 
434
434
  `TextField`, `TextArea`, `SelectField`, and `FileField` pair a label with a native
435
435
  control. Each creates its own IDs and links hints or errors automatically. Use
436
- native control props. `SelectField` accepts option children.
436
+ native control props. `SelectField` accepts option children. `TextField` takes
437
+ text, number, email, password and search, forwards its ref to the input, and
438
+ places a decorative kit glyph with `icon` — the same glyph names `Button` and
439
+ `Dropdown` take. Number fields can combine a glyph with a `unit`.
437
440
 
438
441
  ```tsx
439
442
  <TextField label="Weight" type="number" unit="kg" required />
@@ -447,6 +450,19 @@ native control props. `SelectField` accepts option children.
447
450
  `onFileChange`. Use `accept` and `hint` to describe allowed file types and size.
448
451
  Your application must validate files before upload.
449
452
 
453
+ Use `Field` when an existing labelled control needs the kit frame. Spread its
454
+ render-prop attributes onto one labelable control, and apply the existing control
455
+ class and invalid styling as appropriate:
456
+
457
+ ```tsx
458
+ <Field label="Due date" hint="Use the delivery date." required>
459
+ {control => <input {...control} className="ui-input" type="date" />}
460
+ </Field>
461
+ ```
462
+
463
+ The frame supplies a stable ID, required state, and linked hint/error messages.
464
+ An optional `id` lets the caller choose the control ID; it must be unique.
465
+
450
466
  ## Toast
451
467
 
452
468
  Wrap your app in `Toast`, then call `useToast()` inside it to add a notice.
@@ -416,6 +416,10 @@
416
416
  .ui-textarea.is-invalid {
417
417
  border-color: var(--pink);
418
418
  }
419
+ .ui-input[type=search]::-webkit-search-cancel-button {
420
+ appearance: none;
421
+ display: none;
422
+ }
419
423
  .ui-input-group {
420
424
  position: relative;
421
425
  display: flex;
@@ -546,11 +546,33 @@ type FieldMessage = {
546
546
  error?: string;
547
547
  };
548
548
  type Wiring = 'id' | 'aria-describedby' | 'aria-invalid';
549
+ type FieldControlProps = {
550
+ id: string;
551
+ 'aria-describedby'?: string;
552
+ 'aria-invalid'?: true;
553
+ required?: boolean;
554
+ };
555
+ type FieldProps = FieldMessage & {
556
+ id?: string;
557
+ required?: boolean;
558
+ children: (control: FieldControlProps) => ReactNode;
559
+ };
560
+ /** Spread the supplied attributes onto one labelable control. */
561
+ declare function Field({ id: suppliedId, label, hint, error, required, children }: FieldProps): react.JSX.Element;
549
562
  type TextFieldProps = FieldMessage & Omit<InputHTMLAttributes<HTMLInputElement>, Wiring | 'type'> & {
550
- type?: 'text' | 'number' | 'email';
563
+ type?: 'text' | 'number' | 'email' | 'password' | 'search';
551
564
  unit?: string;
565
+ /** Kit glyph name, as Button, Dropdown and vanilla input() take it. Decorative;
566
+ the label supplies the control's name. */
567
+ icon?: string;
552
568
  };
553
- declare function TextField({ label, hint, error, required, type, unit, className, ...props }: TextFieldProps): react.JSX.Element;
569
+ declare const TextField: react.ForwardRefExoticComponent<FieldMessage & Omit<InputHTMLAttributes<HTMLInputElement>, "type" | Wiring> & {
570
+ type?: "text" | "number" | "email" | "password" | "search";
571
+ unit?: string;
572
+ /** Kit glyph name, as Button, Dropdown and vanilla input() take it. Decorative;
573
+ the label supplies the control's name. */
574
+ icon?: string;
575
+ } & react.RefAttributes<HTMLInputElement>>;
554
576
  type TextAreaProps = FieldMessage & Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, Wiring>;
555
577
  declare function TextArea({ label, hint, error, required, className, ...props }: TextAreaProps): react.JSX.Element;
556
578
  type SelectFieldProps = FieldMessage & Omit<SelectHTMLAttributes<HTMLSelectElement>, Wiring>;
@@ -640,4 +662,4 @@ declare function Tooltip({ text, children }: TooltipProps): react.JSX.Element;
640
662
  declare const PAGE_SIZES: readonly number[];
641
663
  declare const DEFAULT_PAGE_SIZE: number;
642
664
 
643
- export { AppShell, type AppShellProps, type AppShellSection, BackLink, type BackLinkOwnProps, type BackLinkProps, Badge, BusyRegion, type BusyRegionProps, Button, type ButtonProps, Callout, type CalloutProps, type CalloutVariant, Card, type Column, type CommandGroup, type CommandItem, CommandPalette, type CommandPaletteProps, Confirm, type ConfirmProps, DEFAULT_PAGE_SIZE, DataTable, type DataTableProps, DeltaValue, type DeltaValueProps, Denied, type DeniedProps, Drawer, type DrawerProps, DrawerSection, type DrawerSectionProps, Dropdown, type DropdownBadge, type DropdownEntry, type DropdownItem, type DropdownProps, type DropdownRowProps, type DropdownSearch, type DropdownSection, type DropdownSeparator, EmptyState, type EmptyStateProps, type EmptyStateVariant, FileField, type FileFieldProps, type Filter, FilterBar, type FilterBarProps, Icon, KeyValueList, type KeyValueListProps, type KeyValueRow, Modal, type ModalProps, NumericValue, type NumericValueProps, PAGE_SIZES, Pagination, type PaginationProps, Pill, type PillProps, RowIdentity, type RowIdentityProps, type SegmentOption, Segmented, type SegmentedProps, SelectField, type SelectFieldProps, Skeleton, type SkeletonProps, SkeletonTable, type SkeletonTableProps, Snippet, type SnippetProps, StatBand, type StatBandProps, type StatDelta, type StatFigure, type StatTone, type StatVariant, StatusDot, type StatusDotProps, THEME_INIT_SCRIPT, type TabItem, type TableSort, Tabs, type TabsProps, TextArea, type TextAreaProps, TextField, type TextFieldProps, ThemeToggle, type ThemeToggleProps, Timeline, type TimelineEvent, type TimelineEventKind, type TimelineProps, Toast, type ToastNotice, type ToastProps, Tooltip, type TooltipProps, sortTableRows, useToast };
665
+ export { AppShell, type AppShellProps, type AppShellSection, BackLink, type BackLinkOwnProps, type BackLinkProps, Badge, BusyRegion, type BusyRegionProps, Button, type ButtonProps, Callout, type CalloutProps, type CalloutVariant, Card, type Column, type CommandGroup, type CommandItem, CommandPalette, type CommandPaletteProps, Confirm, type ConfirmProps, DEFAULT_PAGE_SIZE, DataTable, type DataTableProps, DeltaValue, type DeltaValueProps, Denied, type DeniedProps, Drawer, type DrawerProps, DrawerSection, type DrawerSectionProps, Dropdown, type DropdownBadge, type DropdownEntry, type DropdownItem, type DropdownProps, type DropdownRowProps, type DropdownSearch, type DropdownSection, type DropdownSeparator, EmptyState, type EmptyStateProps, type EmptyStateVariant, Field, type FieldControlProps, type FieldProps, FileField, type FileFieldProps, type Filter, FilterBar, type FilterBarProps, Icon, KeyValueList, type KeyValueListProps, type KeyValueRow, Modal, type ModalProps, NumericValue, type NumericValueProps, PAGE_SIZES, Pagination, type PaginationProps, Pill, type PillProps, RowIdentity, type RowIdentityProps, type SegmentOption, Segmented, type SegmentedProps, SelectField, type SelectFieldProps, Skeleton, type SkeletonProps, SkeletonTable, type SkeletonTableProps, Snippet, type SnippetProps, StatBand, type StatBandProps, type StatDelta, type StatFigure, type StatTone, type StatVariant, StatusDot, type StatusDotProps, THEME_INIT_SCRIPT, type TabItem, type TableSort, Tabs, type TabsProps, TextArea, type TextAreaProps, TextField, type TextFieldProps, ThemeToggle, type ThemeToggleProps, Timeline, type TimelineEvent, type TimelineEventKind, type TimelineProps, Toast, type ToastNotice, type ToastProps, Tooltip, type TooltipProps, sortTableRows, useToast };
@@ -2167,7 +2167,7 @@ function Timeline({ events, className, ...rest }) {
2167
2167
  }
2168
2168
 
2169
2169
  // src/Field.tsx
2170
- import { useEffect as useEffect10, useId as useId10, useRef as useRef15, useState as useState9 } from "react";
2170
+ import { forwardRef as forwardRef4, useEffect as useEffect10, useId as useId10, useRef as useRef15, useState as useState9 } from "react";
2171
2171
  import { esc, icon as icon4 } from "@apliteni/apliteni-ui";
2172
2172
  import { jsx as jsx26, jsxs as jsxs21 } from "react/jsx-runtime";
2173
2173
  function messages(id, hint, error) {
@@ -2195,13 +2195,19 @@ function Frame({ id, label, hint, error, required, children }) {
2195
2195
  function wiring(id, hint, error) {
2196
2196
  return { id, "aria-describedby": messages(id, hint, error), "aria-invalid": error ? true : void 0 };
2197
2197
  }
2198
- function TextField({ label, hint, error, required, type = "text", unit, className = "", ...props }) {
2198
+ function Field({ id: suppliedId, label, hint, error, required, children }) {
2199
+ const generatedId = useId10();
2200
+ const id = suppliedId ?? generatedId;
2201
+ return /* @__PURE__ */ jsx26(Frame, { ...{ id, label, hint, error, required }, children: children({ ...wiring(id, hint, error), required }) });
2202
+ }
2203
+ var TextField = forwardRef4(function TextField2({ label, hint, error, required, type = "text", unit, icon: glyph, className = "", ...props }, ref) {
2199
2204
  const id = useId10();
2200
2205
  const hasUnit = type === "number" && !!unit;
2201
2206
  const describedBy = [messages(id, hint, error), hasUnit ? `${id}-unit` : ""].filter(Boolean).join(" ") || void 0;
2202
2207
  const control = /* @__PURE__ */ jsx26(
2203
2208
  "input",
2204
2209
  {
2210
+ ref,
2205
2211
  ...props,
2206
2212
  ...wiring(id, hint, error),
2207
2213
  required,
@@ -2211,11 +2217,16 @@ function TextField({ label, hint, error, required, type = "text", unit, classNam
2211
2217
  className: `ui-input${error ? " is-invalid" : ""} ${className}`
2212
2218
  }
2213
2219
  );
2214
- return /* @__PURE__ */ jsx26(Frame, { ...{ id, label, hint, error, required }, children: hasUnit ? /* @__PURE__ */ jsxs21("div", { className: "ui-field-number", children: [
2220
+ const unitSpan = hasUnit ? /* @__PURE__ */ jsx26("span", { id: `${id}-unit`, className: "ui-field-number__unit", children: unit }) : null;
2221
+ return /* @__PURE__ */ jsx26(Frame, { ...{ id, label, hint, error, required }, children: glyph ? /* @__PURE__ */ jsxs21("div", { className: `ui-input-group${hasUnit ? " ui-field-number" : ""}`, children: [
2222
+ /* @__PURE__ */ jsx26("span", { className: "ui-input-group__icon", dangerouslySetInnerHTML: { __html: icon4(glyph) } }),
2223
+ control,
2224
+ unitSpan
2225
+ ] }) : hasUnit ? /* @__PURE__ */ jsxs21("div", { className: "ui-field-number", children: [
2215
2226
  control,
2216
- /* @__PURE__ */ jsx26("span", { id: `${id}-unit`, className: "ui-field-number__unit", children: unit })
2227
+ unitSpan
2217
2228
  ] }) : control });
2218
- }
2229
+ });
2219
2230
  function TextArea({ label, hint, error, required, className = "", ...props }) {
2220
2231
  const id = useId10();
2221
2232
  return /* @__PURE__ */ jsx26(Frame, { ...{ id, label, hint, error, required }, children: /* @__PURE__ */ jsx26(
@@ -2714,6 +2725,7 @@ export {
2714
2725
  DrawerSection,
2715
2726
  Dropdown,
2716
2727
  EmptyState,
2728
+ Field,
2717
2729
  FileField,
2718
2730
  FilterBar,
2719
2731
  Icon,
@@ -69,6 +69,20 @@
69
69
  .ui-textarea.is-invalid { border-color: var(--pink); }
70
70
  /* Invalid fields keep the shared focus indicator; their border carries the error. */
71
71
 
72
+ /* A search field with a value gets the browser's own clear button, and the
73
+ browser paints it — near-black on the light field, white on the dark one,
74
+ beside the kit's --muted magnifier. Two glyphs, and only one answers to a
75
+ token. .ui-select refuses UA chrome for the same reason, hand-drawing its
76
+ chevron per theme; and the vanilla search specimen is a text input with a
77
+ `search` glyph and no clear button, so a field without one is what the
78
+ design already says. Measured in Chromium; Firefox draws nothing here and
79
+ Edge is untested.
80
+ why: docs/specification.md#colour-and-contrast */
81
+ .ui-input[type="search"]::-webkit-search-cancel-button {
82
+ appearance: none;
83
+ display: none;
84
+ }
85
+
72
86
  /* Input with a leading icon / adornment */
73
87
  .ui-input-group { position: relative; display: flex; align-items: center; }
74
88
  .ui-input-group .ui-input { padding-left: 42px; }