@jirawatpyk/aura-react 4.12.0 → 4.13.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.
package/dist/index.d.ts CHANGED
@@ -268,6 +268,96 @@ export interface TextFieldProps extends FieldProps, Omit<React$1.InputHTMLAttrib
268
268
  /** Trailing unit, e.g. "THB". */
269
269
  suffix?: React$1.ReactNode;
270
270
  }
271
+ /** A password input with a show/hide button. All TextField props; `ref` reaches the input (react-hook-form `register`). */
272
+ export interface PasswordFieldProps extends Omit<TextFieldProps, "type" | "suffix"> {
273
+ /** Set false to hide the show/hide button. Default true. */
274
+ toggle?: boolean;
275
+ }
276
+ /** One entry of a FormErrorSummary: the field's `id` (or `name`) and what to fix. */
277
+ export interface FormErrorItem {
278
+ field: string;
279
+ message: React$1.ReactNode;
280
+ }
281
+ /** The list of problems at the top of a form after a failed submit; each links to its field (GOV.UK pattern). */
282
+ export interface FormErrorSummaryProps {
283
+ /** A list, or react-hook-form's `formState.errors` as is (`{ name: { message } }`). Empty → renders nothing. */
284
+ errors: FormErrorItem[] | Record<string, {
285
+ message?: React$1.ReactNode;
286
+ } | undefined>;
287
+ /** Default "Fix N fields to continue" in the provider's language. */
288
+ title?: React$1.ReactNode;
289
+ /** Called with the field when a link is followed, e.g. react-hook-form's `setFocus`. Default: focus the element whose id (or name) is the field. */
290
+ onSelect?: (field: string) => void;
291
+ /** Change it on every submit (e.g. `formState.submitCount`) to move focus to the summary again. It also takes focus when errors first appear. */
292
+ focusKey?: unknown;
293
+ className?: string;
294
+ id?: string;
295
+ }
296
+ /** An applied filter, shown as a removable chip. */
297
+ export interface ActiveFilter {
298
+ id: string;
299
+ label: React$1.ReactNode;
300
+ onRemove: () => void;
301
+ }
302
+ /** The row above a table: search, filter controls, applied-filter chips, result count and actions. Wraps below md. */
303
+ export interface FilterBarProps {
304
+ /** Search text (controlled). Omit `onSearchChange` to hide the search field. */
305
+ search?: string;
306
+ /** Called after typing pauses (`searchDelay`), and at once on Enter or clear — ready to write to the URL. */
307
+ onSearchChange?: (value: string) => void;
308
+ /** ms to wait after the last keystroke. Default 300. */
309
+ searchDelay?: number;
310
+ searchLabel?: string;
311
+ searchPlaceholder?: string;
312
+ /** Filter controls beside the search: Select, SegmentedControl, a Popover of options… */
313
+ children?: React$1.ReactNode;
314
+ /** Applied filters as chips, each with its own remove button. */
315
+ filters?: ActiveFilter[];
316
+ /** Adds "Clear all" while any filter or search is set. */
317
+ onClearAll?: () => void;
318
+ /** A number ("312 results", announced politely) or your own node. */
319
+ resultCount?: number | React$1.ReactNode;
320
+ /** Trailing slot: export, a New button… */
321
+ actions?: React$1.ReactNode;
322
+ /** Accessible name of the region. Default "Filters". */
323
+ label?: string;
324
+ className?: string;
325
+ }
326
+ /** One command in the palette. */
327
+ export interface CommandItem {
328
+ id: string;
329
+ /** Text shown and searched. */
330
+ label: string;
331
+ /** Items with the same group are listed together under its heading, in first-seen order. */
332
+ group?: string;
333
+ icon?: IconInput;
334
+ description?: string;
335
+ /** Extra words that find it ("invoice" → Billing). */
336
+ keywords?: string[];
337
+ /** A shortcut shown at the right, e.g. "G I". Display only. */
338
+ shortcut?: string;
339
+ disabled?: boolean;
340
+ /** Runs when chosen (Enter or click); the palette then closes. */
341
+ onSelect?: () => void;
342
+ }
343
+ /** A command palette: a modal search over commands and pages, grouped, fully keyboard-driven. */
344
+ export interface CommandProps {
345
+ open: boolean;
346
+ onOpenChange: (open: boolean) => void;
347
+ items: CommandItem[];
348
+ /** Also called with the chosen item (after its own onSelect). */
349
+ onSelect?: (item: CommandItem) => void;
350
+ /** Accessible name. Default "Command menu". */
351
+ label?: string;
352
+ placeholder?: string;
353
+ /** Default "No matches". */
354
+ emptyText?: string;
355
+ /** ⌘K / Ctrl+K toggles the palette from anywhere on the page. Default true. */
356
+ hotkey?: boolean;
357
+ /** Replace the Thai-aware default filter. */
358
+ filter?: (item: CommandItem, query: string) => boolean;
359
+ className?: string;
360
+ }
271
361
  export interface TextareaProps extends FieldProps, Omit<React$1.TextareaHTMLAttributes<HTMLTextAreaElement>, "required"> {
272
362
  }
273
363
  export type SelectOption = string | {
@@ -332,9 +422,11 @@ export interface ToastOptions {
332
422
  };
333
423
  /** ms before it closes itself. Default 5000; Infinity keeps it until dismissed. */
334
424
  duration?: number;
335
- /** Reuse an id to replace a toast in place. */
425
+ /** Reuse an id to replace a toast in place (same position, timer restarts) — never a second toast. */
336
426
  id?: string;
337
427
  }
428
+ /** Options for the shorthands (`toast.success(title, opts)` …): everything but the title and tone. */
429
+ export type ToastShorthandOptions = Omit<ToastOptions, "title" | "tone">;
338
430
  export interface TooltipProps {
339
431
  content: React$1.ReactNode;
340
432
  /** One focusable element. */
@@ -979,6 +1071,11 @@ export declare const Alert: React$1.ForwardRefExoticComponent<AlertProps & React
979
1071
  /** Show a toast; returns its id. Needs `<Toaster />` mounted once. */
980
1072
  export declare function toast(opts: ToastOptions | string): string;
981
1073
  export declare namespace toast {
1074
+ var success: (title: string, opts?: ToastShorthandOptions) => string;
1075
+ var error: (title: string, opts?: ToastShorthandOptions) => string;
1076
+ var warning: (title: string, opts?: ToastShorthandOptions) => string;
1077
+ var info: (title: string, opts?: ToastShorthandOptions) => string;
1078
+ var loading: (title: string, opts?: ToastShorthandOptions) => string;
982
1079
  var dismiss: (id: string) => void;
983
1080
  }
984
1081
  export interface ToasterProps {
@@ -986,6 +1083,10 @@ export interface ToasterProps {
986
1083
  position?: "bottom" | "top";
987
1084
  }
988
1085
  export declare function Toaster(props: ToasterProps): React$1.ReactElement | null;
1086
+ export declare const PasswordField: React$1.ForwardRefExoticComponent<PasswordFieldProps & React$1.RefAttributes<HTMLInputElement>>;
1087
+ export declare const FormErrorSummary: React$1.ForwardRefExoticComponent<FormErrorSummaryProps & React$1.RefAttributes<HTMLDivElement>>;
1088
+ export declare const FilterBar: React$1.ForwardRefExoticComponent<FilterBarProps & React$1.RefAttributes<HTMLDivElement>>;
1089
+ export declare function Command(props: CommandProps): React$1.ReactElement | null;
989
1090
  export declare const Tooltip: React$1.ForwardRefExoticComponent<TooltipProps & React$1.RefAttributes<HTMLSpanElement>>;
990
1091
  export declare const Dialog: React$1.ForwardRefExoticComponent<DialogProps & React$1.RefAttributes<HTMLDivElement>>;
991
1092
  /** Side panel over the page: record detail, filters, mobile navigation. Modal (focus trap, scroll lock, focus restore). */
@@ -1032,6 +1133,15 @@ export interface AuraStrings {
1032
1133
  close: string;
1033
1134
  dismiss: string;
1034
1135
  dismissToast: string;
1136
+ showPassword: string;
1137
+ filters: string;
1138
+ search: string;
1139
+ clearFilters: string;
1140
+ results: (n: number) => string;
1141
+ commandMenu: string;
1142
+ commandPlaceholder: string;
1143
+ commandHint: string;
1144
+ errorSummary: (n: number) => string;
1035
1145
  notifications: string;
1036
1146
  mainNav: string;
1037
1147
  breadcrumb: string;
package/dist/styles.css CHANGED
@@ -1141,3 +1141,103 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1141
1141
  .aura-radio-group__list { gap: 0; }
1142
1142
  .aura-radio-group__list.is-horizontal { gap: 0 var(--aura-space-6); }
1143
1143
  }
1144
+
1145
+ /* PasswordField: the show/hide IconButton sits in the suffix slot, 6px from the edge */
1146
+ .aura-password .aura-input__suffix { padding-right: 6px; display: flex; align-items: center; }
1147
+
1148
+ /* FormErrorSummary: a danger alert whose items link to their fields */
1149
+ .aura-error-summary:focus-visible, .aura-error-summary:focus { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: var(--aura-focus-ring-offset); }
1150
+ .aura-error-summary h2.aura-alert__title { font-family: inherit; }
1151
+ .aura-error-summary__list { margin: var(--aura-space-2) 0 0; padding-left: var(--aura-space-5); display: grid; gap: var(--aura-space-1); font-size: 14px; line-height: 20px; }
1152
+ .aura-error-summary__list a { color: var(--aura-alert-danger-fg); text-decoration: underline; text-underline-offset: 2px; font-weight: 500; }
1153
+ .aura-error-summary__list a:hover { text-decoration-thickness: 2px; }
1154
+ .aura-error-summary__list a:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 2px; border-radius: var(--aura-radius-xs); }
1155
+
1156
+ /* aura-prose: sanitised rich text (editor output, e-mail previews). Styles exactly p, h1–h4, ul/ol/li, blockquote,
1157
+ * hr, a, strong, em, u with AURA type and spacing, in both themes. */
1158
+ .aura-prose { font-family: var(--font-sans); font-size: 14px; line-height: 1.7; color: var(--aura-fg-primary); overflow-wrap: anywhere; }
1159
+ .aura-prose > :first-child { margin-top: 0; }
1160
+ .aura-prose > :last-child { margin-bottom: 0; }
1161
+ .aura-prose p { margin: 0 0 var(--aura-space-4); }
1162
+ .aura-prose h1, .aura-prose h2, .aura-prose h3, .aura-prose h4 { color: var(--aura-fg-primary); margin: var(--aura-space-8) 0 var(--aura-space-3); }
1163
+ .aura-prose h1 { font-family: var(--font-display); font-weight: 600; font-size: 30px; line-height: 1.2; letter-spacing: -0.01em; }
1164
+ .aura-prose h2 { font-weight: 600; font-size: 22px; line-height: 1.3; }
1165
+ .aura-prose h3 { font-weight: 600; font-size: 17px; line-height: 1.45; }
1166
+ .aura-prose h4 { font-weight: 600; font-size: 15px; line-height: 1.5; }
1167
+ .aura-prose ul, .aura-prose ol { margin: 0 0 var(--aura-space-4); padding-left: var(--aura-space-6); }
1168
+ .aura-prose li { margin: var(--aura-space-1) 0; }
1169
+ .aura-prose li > ul, .aura-prose li > ol { margin: var(--aura-space-1) 0 0; }
1170
+ .aura-prose ul { list-style: disc; }
1171
+ .aura-prose ol { list-style: decimal; }
1172
+ .aura-prose li::marker { color: var(--aura-fg-secondary); }
1173
+ .aura-prose blockquote { margin: 0 0 var(--aura-space-4); padding: var(--aura-space-1) 0 var(--aura-space-1) var(--aura-space-4); border-left: 3px solid var(--aura-border-control); color: var(--aura-fg-secondary); }
1174
+ .aura-prose hr { margin: var(--aura-space-8) 0; border: 0; border-top: 1px solid var(--aura-border-default); }
1175
+ .aura-prose a { color: var(--aura-fg-accent); text-decoration: underline; text-underline-offset: 2px; }
1176
+ .aura-prose a:hover { text-decoration-thickness: 2px; }
1177
+ .aura-prose a:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 2px; border-radius: var(--aura-radius-xs); }
1178
+ .aura-prose strong { font-weight: 600; }
1179
+ .aura-prose em { font-style: italic; }
1180
+ .aura-prose u { text-decoration: underline; text-underline-offset: 2px; }
1181
+
1182
+ /* FilterBar: search + controls + count + actions on one row, applied-filter chips below; wraps on small screens */
1183
+ .aura-filterbar { display: flex; flex-direction: column; gap: var(--aura-space-3); font-family: var(--font-sans); }
1184
+ .aura-filterbar__row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--aura-space-3); }
1185
+ .aura-filterbar__search { flex: 1 1 240px; max-width: 360px; width: auto; }
1186
+ .aura-filterbar__search .aura-input__control::-webkit-search-cancel-button { display: none; }
1187
+ .aura-filterbar__clear-search { margin-right: 6px; }
1188
+ .aura-filterbar__controls { display: flex; flex-wrap: wrap; align-items: center; gap: var(--aura-space-3); }
1189
+ .aura-filterbar__spacer { flex: 1 1 0; }
1190
+ .aura-filterbar__count { font-size: 13px; color: var(--aura-fg-secondary); font-variant-numeric: tabular-nums; white-space: nowrap; }
1191
+ .aura-filterbar__actions { display: flex; align-items: center; gap: var(--aura-space-2); }
1192
+ .aura-filterbar__chips { display: flex; flex-wrap: wrap; align-items: center; gap: var(--aura-space-2); }
1193
+ .aura-filterbar__clear {
1194
+ border: 0; background: transparent; padding: 4px var(--aura-space-2); border-radius: var(--aura-radius-sm);
1195
+ font: inherit; font-size: 13px; font-weight: 500; color: var(--aura-fg-accent); cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
1196
+ }
1197
+ .aura-filterbar__clear:hover { background: var(--aura-bg-surface-hover); }
1198
+ .aura-filterbar__clear:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: var(--aura-focus-ring-offset); }
1199
+ @media (max-width: 767.98px) {
1200
+ .aura-filterbar__search { flex-basis: 100%; max-width: none; }
1201
+ .aura-filterbar__spacer { display: none; }
1202
+ }
1203
+
1204
+ /* Command palette: a search field over a grouped list, above everything else (it can open from a Dialog) */
1205
+ .aura-dialog-layer.aura-command-layer { z-index: var(--aura-z-menu); align-items: flex-start; padding: 12vh var(--aura-space-4) var(--aura-space-4); }
1206
+ .aura-command {
1207
+ position: relative; box-sizing: border-box; width: 100%; max-width: 640px; max-height: 70vh; display: flex; flex-direction: column; overflow: hidden;
1208
+ background: var(--aura-bg-surface); color: var(--aura-fg-primary); font-family: var(--font-sans);
1209
+ border: 1px solid var(--aura-border-default); border-radius: var(--aura-radius-xl); box-shadow: var(--aura-shadow-overlay);
1210
+ animation: aura-dialog-in var(--aura-duration-base) var(--aura-ease);
1211
+ }
1212
+ .aura-command:focus { outline: none; }
1213
+ .aura-command__search { display: flex; align-items: center; gap: var(--aura-space-3); padding: 0 var(--aura-space-4); border-bottom: 1px solid var(--aura-border-default); }
1214
+ .aura-command__search-icon { color: var(--aura-fg-secondary); }
1215
+ .aura-command__input {
1216
+ flex: 1; min-width: 0; height: 52px; border: 0; background: transparent; color: inherit; outline: none;
1217
+ font: inherit; font-size: max(16px, var(--aura-input-font-size));
1218
+ }
1219
+ .aura-command__input::placeholder { color: var(--aura-fg-tertiary); opacity: 1; }
1220
+ .aura-command__list { flex: 1 1 auto; overflow-y: auto; overscroll-behavior: contain; padding: var(--aura-space-2); }
1221
+ .aura-command__group + .aura-command__group { margin-top: var(--aura-space-2); }
1222
+ .aura-command__heading { padding: var(--aura-space-2) var(--aura-space-2) var(--aura-space-1); font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--aura-fg-secondary); }
1223
+ .aura-command__item { display: flex; align-items: center; gap: var(--aura-space-3); min-height: 40px; padding: 6px var(--aura-space-2); border-radius: var(--aura-radius-sm); cursor: pointer; font-size: 14px; }
1224
+ .aura-command__item > .aura-icon { color: var(--aura-fg-secondary); }
1225
+ .aura-command__item.is-active { background: var(--aura-bg-surface-hover); outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: calc(-1 * var(--aura-focus-ring-width)); }
1226
+ .aura-command__item.is-disabled { opacity: var(--aura-disabled-opacity); cursor: default; }
1227
+ .aura-command__text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
1228
+ .aura-command__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1229
+ .aura-command__desc { font-size: 12px; line-height: 1.5; color: var(--aura-fg-secondary); }
1230
+ .aura-command__kbd {
1231
+ flex: none; padding: 2px 6px; border: 1px solid var(--aura-border-default); border-radius: var(--aura-radius-xs);
1232
+ font-family: var(--font-mono); font-size: 11px; line-height: 16px; color: var(--aura-fg-secondary); background: var(--aura-bg-canvas);
1233
+ }
1234
+ .aura-command__empty { margin: 0; padding: var(--aura-space-6) var(--aura-space-2); text-align: center; font-size: 14px; color: var(--aura-fg-secondary); }
1235
+ .aura-command__foot { display: flex; justify-content: space-between; gap: var(--aura-space-3); padding: var(--aura-space-2) var(--aura-space-4); border-top: 1px solid var(--aura-border-default); font-size: 12px; color: var(--aura-fg-secondary); }
1236
+ @media (max-width: 639.98px) {
1237
+ .aura-dialog-layer.aura-command-layer { align-items: flex-start; padding: var(--aura-space-4); }
1238
+ .aura-command { max-height: 80vh; }
1239
+ .aura-command__foot { display: none; }
1240
+ .aura-command__item { min-height: 44px; }
1241
+ }
1242
+ @media (prefers-reduced-motion: reduce) { .aura-command { animation: none; } }
1243
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "4.12.0",
3
+ "version": "4.13.0",
4
4
  "description": "AURA Design System — React components (Enterprise Standard, Human Creative). Thai-first: Buddhist-era dates, Thai collation.",
5
5
  "license": "MIT",
6
6
  "type": "module",