@k2b/ui 0.44.0 → 0.46.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.
Files changed (206) hide show
  1. package/dist/browser/actions/Dropdown.js +8 -1
  2. package/dist/browser/actions/Dropdown.js.map +1 -1
  3. package/dist/browser/actions/FilterChip.js +11 -5
  4. package/dist/browser/actions/FilterChip.js.map +1 -1
  5. package/dist/browser/actions/Tabs.js +3 -4
  6. package/dist/browser/actions/Tabs.js.map +1 -1
  7. package/dist/browser/actions/ViewTabs.js +225 -93
  8. package/dist/browser/actions/ViewTabs.js.map +1 -1
  9. package/dist/browser/actions/menu-sheet.js +2 -3
  10. package/dist/browser/actions/menu-sheet.js.map +1 -1
  11. package/dist/browser/actions/phone-sheet.js +4 -0
  12. package/dist/browser/actions/phone-sheet.js.map +1 -0
  13. package/dist/browser/content/DataTable.js +47 -51
  14. package/dist/browser/content/DataTable.js.map +1 -1
  15. package/dist/browser/content/FileGrid.js +125 -99
  16. package/dist/browser/content/FileGrid.js.map +1 -1
  17. package/dist/browser/feedback/dialog-core.js +5 -1
  18. package/dist/browser/feedback/dialog-core.js.map +1 -1
  19. package/dist/browser/feedback/dialog-tone.js +26 -0
  20. package/dist/browser/feedback/dialog-tone.js.map +1 -0
  21. package/dist/browser/feedback/index.js.map +1 -1
  22. package/dist/browser/feedback/prompt-confirm.js +223 -0
  23. package/dist/browser/feedback/prompt-confirm.js.map +1 -0
  24. package/dist/browser/feedback/prompts.js +195 -343
  25. package/dist/browser/feedback/prompts.js.map +1 -1
  26. package/dist/browser/inputs/ChoiceList.js +45 -17
  27. package/dist/browser/inputs/ChoiceList.js.map +1 -1
  28. package/dist/browser/inputs/DatePicker.js +1647 -334
  29. package/dist/browser/inputs/DatePicker.js.map +1 -1
  30. package/dist/browser/inputs/TextInput.js +5 -4
  31. package/dist/browser/inputs/TextInput.js.map +1 -1
  32. package/dist/browser/inputs/choice.js +36 -9
  33. package/dist/browser/inputs/choice.js.map +1 -1
  34. package/dist/browser/inputs/date-input-messages.js +128 -0
  35. package/dist/browser/inputs/date-input-messages.js.map +1 -0
  36. package/dist/browser/inputs/date-input-status.js +132 -0
  37. package/dist/browser/inputs/date-input-status.js.map +1 -0
  38. package/dist/browser/inputs/date-input.js +334 -0
  39. package/dist/browser/inputs/date-input.js.map +1 -0
  40. package/dist/browser/inputs/date-sheet.js +49 -0
  41. package/dist/browser/inputs/date-sheet.js.map +1 -0
  42. package/dist/browser/internal/reveal-in-scroller.js +28 -0
  43. package/dist/browser/internal/reveal-in-scroller.js.map +1 -0
  44. package/dist/browser/intl/messages.js +6 -0
  45. package/dist/browser/intl/messages.js.map +1 -1
  46. package/dist/browser/layout/AppWorkspace.js +556 -528
  47. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  48. package/dist/browser/layout/BottomSheet.js +3 -0
  49. package/dist/browser/layout/BottomSheet.js.map +1 -1
  50. package/dist/browser/layout/DetailPanel.js +130 -108
  51. package/dist/browser/layout/DetailPanel.js.map +1 -1
  52. package/dist/browser/layout/DetailSections.js +1019 -0
  53. package/dist/browser/layout/DetailSections.js.map +1 -0
  54. package/dist/browser/layout/DetailsToggle.js +32 -0
  55. package/dist/browser/layout/DetailsToggle.js.map +1 -0
  56. package/dist/browser/layout/Discussion.js +3 -0
  57. package/dist/browser/layout/Discussion.js.map +1 -1
  58. package/dist/browser/layout/MobileShell.js +116 -94
  59. package/dist/browser/layout/MobileShell.js.map +1 -1
  60. package/dist/browser/layout/PageTitle.js +33 -10
  61. package/dist/browser/layout/PageTitle.js.map +1 -1
  62. package/dist/browser/layout/PanelDialog.js +167 -132
  63. package/dist/browser/layout/PanelDialog.js.map +1 -1
  64. package/dist/browser/layout/Settings.js +175 -139
  65. package/dist/browser/layout/Settings.js.map +1 -1
  66. package/dist/browser/layout/SettingsModal.js +2 -4
  67. package/dist/browser/layout/SettingsModal.js.map +1 -1
  68. package/dist/browser/layout/app-workspace-controller.js +12 -0
  69. package/dist/browser/layout/app-workspace-controller.js.map +1 -1
  70. package/dist/browser/layout/detail-sections-messages.js +123 -0
  71. package/dist/browser/layout/detail-sections-messages.js.map +1 -0
  72. package/dist/browser/layout/index.js +2 -0
  73. package/dist/browser/layout/index.js.map +1 -1
  74. package/dist/browser/surfaces/Avatar.js +3 -1
  75. package/dist/browser/surfaces/Avatar.js.map +1 -1
  76. package/dist/browser/surfaces/AvatarStack.js +95 -61
  77. package/dist/browser/surfaces/AvatarStack.js.map +1 -1
  78. package/dist/browser/surfaces/ChangeList.js +77 -0
  79. package/dist/browser/surfaces/ChangeList.js.map +1 -0
  80. package/dist/browser/surfaces/StatusBadge.js +47 -14
  81. package/dist/browser/surfaces/StatusBadge.js.map +1 -1
  82. package/dist/browser/surfaces/index.js +2 -1
  83. package/dist/browser/surfaces/index.js.map +1 -1
  84. package/dist/browser/text-editor/TextEditor.js +26 -8
  85. package/dist/browser/text-editor/TextEditor.js.map +1 -1
  86. package/dist/ssr/actions/Dropdown.js +6 -0
  87. package/dist/ssr/actions/Dropdown.js.map +1 -1
  88. package/dist/ssr/actions/FilterChip.js +1 -1
  89. package/dist/ssr/actions/FilterChip.js.map +1 -1
  90. package/dist/ssr/actions/Tabs.js +3 -4
  91. package/dist/ssr/actions/Tabs.js.map +1 -1
  92. package/dist/ssr/actions/ViewTabs.js +144 -37
  93. package/dist/ssr/actions/ViewTabs.js.map +1 -1
  94. package/dist/ssr/actions/menu-sheet.js +2 -3
  95. package/dist/ssr/actions/menu-sheet.js.map +1 -1
  96. package/dist/ssr/actions/phone-sheet.js +4 -0
  97. package/dist/ssr/actions/phone-sheet.js.map +1 -0
  98. package/dist/ssr/content/DataTable.js +1 -2
  99. package/dist/ssr/content/DataTable.js.map +1 -1
  100. package/dist/ssr/content/FileGrid.js +36 -22
  101. package/dist/ssr/content/FileGrid.js.map +1 -1
  102. package/dist/ssr/feedback/dialog-core.js +5 -1
  103. package/dist/ssr/feedback/dialog-core.js.map +1 -1
  104. package/dist/ssr/feedback/dialog-tone.js +26 -0
  105. package/dist/ssr/feedback/dialog-tone.js.map +1 -0
  106. package/dist/ssr/feedback/index.js.map +1 -1
  107. package/dist/ssr/feedback/prompt-confirm.js +123 -0
  108. package/dist/ssr/feedback/prompt-confirm.js.map +1 -0
  109. package/dist/ssr/feedback/prompts.js +60 -132
  110. package/dist/ssr/feedback/prompts.js.map +1 -1
  111. package/dist/ssr/inputs/ChoiceList.js +29 -9
  112. package/dist/ssr/inputs/ChoiceList.js.map +1 -1
  113. package/dist/ssr/inputs/DatePicker.js +1183 -166
  114. package/dist/ssr/inputs/DatePicker.js.map +1 -1
  115. package/dist/ssr/inputs/TextInput.js +5 -4
  116. package/dist/ssr/inputs/TextInput.js.map +1 -1
  117. package/dist/ssr/inputs/choice.js +36 -9
  118. package/dist/ssr/inputs/choice.js.map +1 -1
  119. package/dist/ssr/inputs/date-input-messages.js +128 -0
  120. package/dist/ssr/inputs/date-input-messages.js.map +1 -0
  121. package/dist/ssr/inputs/date-input-status.js +132 -0
  122. package/dist/ssr/inputs/date-input-status.js.map +1 -0
  123. package/dist/ssr/inputs/date-input.js +334 -0
  124. package/dist/ssr/inputs/date-input.js.map +1 -0
  125. package/dist/ssr/inputs/date-sheet.js +44 -0
  126. package/dist/ssr/inputs/date-sheet.js.map +1 -0
  127. package/dist/ssr/internal/reveal-in-scroller.js +28 -0
  128. package/dist/ssr/internal/reveal-in-scroller.js.map +1 -0
  129. package/dist/ssr/intl/messages.js +6 -0
  130. package/dist/ssr/intl/messages.js.map +1 -1
  131. package/dist/ssr/layout/AppWorkspace.js +71 -50
  132. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  133. package/dist/ssr/layout/BottomSheet.js +3 -0
  134. package/dist/ssr/layout/BottomSheet.js.map +1 -1
  135. package/dist/ssr/layout/DetailPanel.js +17 -0
  136. package/dist/ssr/layout/DetailPanel.js.map +1 -1
  137. package/dist/ssr/layout/DetailSections.js +762 -0
  138. package/dist/ssr/layout/DetailSections.js.map +1 -0
  139. package/dist/ssr/layout/DetailsToggle.js +29 -0
  140. package/dist/ssr/layout/DetailsToggle.js.map +1 -0
  141. package/dist/ssr/layout/Discussion.js +3 -0
  142. package/dist/ssr/layout/Discussion.js.map +1 -1
  143. package/dist/ssr/layout/MobileShell.js +45 -28
  144. package/dist/ssr/layout/MobileShell.js.map +1 -1
  145. package/dist/ssr/layout/PageTitle.js +29 -6
  146. package/dist/ssr/layout/PageTitle.js.map +1 -1
  147. package/dist/ssr/layout/PanelDialog.js +48 -30
  148. package/dist/ssr/layout/PanelDialog.js.map +1 -1
  149. package/dist/ssr/layout/Settings.js +34 -18
  150. package/dist/ssr/layout/Settings.js.map +1 -1
  151. package/dist/ssr/layout/SettingsModal.js +2 -4
  152. package/dist/ssr/layout/SettingsModal.js.map +1 -1
  153. package/dist/ssr/layout/app-workspace-controller.js +12 -0
  154. package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
  155. package/dist/ssr/layout/detail-sections-messages.js +123 -0
  156. package/dist/ssr/layout/detail-sections-messages.js.map +1 -0
  157. package/dist/ssr/layout/index.js +2 -0
  158. package/dist/ssr/layout/index.js.map +1 -1
  159. package/dist/ssr/surfaces/Avatar.js +3 -1
  160. package/dist/ssr/surfaces/Avatar.js.map +1 -1
  161. package/dist/ssr/surfaces/AvatarStack.js +61 -32
  162. package/dist/ssr/surfaces/AvatarStack.js.map +1 -1
  163. package/dist/ssr/surfaces/ChangeList.js +37 -0
  164. package/dist/ssr/surfaces/ChangeList.js.map +1 -0
  165. package/dist/ssr/surfaces/StatusBadge.js +26 -8
  166. package/dist/ssr/surfaces/StatusBadge.js.map +1 -1
  167. package/dist/ssr/surfaces/index.js +2 -1
  168. package/dist/ssr/surfaces/index.js.map +1 -1
  169. package/dist/ssr/text-editor/TextEditor.js +26 -8
  170. package/dist/ssr/text-editor/TextEditor.js.map +1 -1
  171. package/dist/styles.css +1 -1
  172. package/dist/types/actions/FilterChip.d.ts +4 -0
  173. package/dist/types/actions/ViewTabs.d.ts +11 -1
  174. package/dist/types/actions/menu-sheet.d.ts +1 -3
  175. package/dist/types/actions/phone-sheet.d.ts +3 -0
  176. package/dist/types/content/FileGrid.d.ts +6 -0
  177. package/dist/types/feedback/dialog-tone.d.ts +10 -0
  178. package/dist/types/feedback/index.d.ts +1 -0
  179. package/dist/types/feedback/prompt-confirm.d.ts +19 -0
  180. package/dist/types/feedback/prompts.d.ts +4 -8
  181. package/dist/types/inputs/ChoiceList.d.ts +7 -3
  182. package/dist/types/inputs/DatePicker.d.ts +13 -3
  183. package/dist/types/inputs/TextInput.d.ts +1 -1
  184. package/dist/types/inputs/choice.d.ts +9 -3
  185. package/dist/types/inputs/date-input-messages.d.ts +64 -0
  186. package/dist/types/inputs/date-input-status.d.ts +35 -0
  187. package/dist/types/inputs/date-input.d.ts +90 -0
  188. package/dist/types/inputs/date-sheet.d.ts +14 -0
  189. package/dist/types/internal/reveal-in-scroller.d.ts +6 -0
  190. package/dist/types/intl/messages.d.ts +3 -0
  191. package/dist/types/layout/AppWorkspace.d.ts +14 -0
  192. package/dist/types/layout/BottomSheet.d.ts +3 -0
  193. package/dist/types/layout/DetailPanel.d.ts +9 -0
  194. package/dist/types/layout/DetailSections.d.ts +156 -0
  195. package/dist/types/layout/DetailsToggle.d.ts +13 -0
  196. package/dist/types/layout/PageTitle.d.ts +7 -0
  197. package/dist/types/layout/PanelDialog.d.ts +3 -0
  198. package/dist/types/layout/Settings.d.ts +17 -1
  199. package/dist/types/layout/detail-sections-messages.d.ts +59 -0
  200. package/dist/types/layout/index.d.ts +5 -2
  201. package/dist/types/surfaces/Avatar.d.ts +3 -0
  202. package/dist/types/surfaces/AvatarStack.d.ts +20 -1
  203. package/dist/types/surfaces/ChangeList.d.ts +20 -0
  204. package/dist/types/surfaces/StatusBadge.d.ts +5 -0
  205. package/dist/types/surfaces/index.d.ts +5 -3
  206. package/package.json +3 -3
@@ -58,6 +58,10 @@ export type FilterToggleProps = {
58
58
  /** Link to the URL with the filter switched. The link keeps working without JavaScript. */
59
59
  href?: string;
60
60
  onClick?: (event: MouseEvent) => void;
61
+ /** The button opens a dialog with more filters, such as a filter builder; it stays pressed while they apply. */
62
+ opensDialog?: boolean;
63
+ /** The button is loading what it opens; it stays enabled so it keeps focus for the dialog to return it. */
64
+ busy?: boolean;
61
65
  title?: string;
62
66
  disabled?: boolean;
63
67
  class?: string;
@@ -5,6 +5,10 @@ export type ViewTab = {
5
5
  href: string;
6
6
  icon?: string;
7
7
  count?: number | string;
8
+ /** A short quiet label after the count, such as "New" for a view people have not opened yet. */
9
+ badge?: string;
10
+ /** Stays in the strip after More at every width, for a view of another kind than the ones that overflow. */
11
+ pinned?: boolean;
8
12
  };
9
13
  export type ViewTabsProps = {
10
14
  /** Accessible name of the navigation landmark, e.g. "Views". */
@@ -12,14 +16,20 @@ export type ViewTabsProps = {
12
16
  items: readonly ViewTab[];
13
17
  /** Id of the open view; the server reads it from `?view=`. Unknown ids select nothing. */
14
18
  current: string | undefined;
15
- /** Tabs shown before More (default 5). */
19
+ /** At most this many views before More (default 5). */
16
20
  max?: number;
21
+ /**
22
+ * The strip shows only the views that fit its room and counts the rest in More, instead of scrolling them. The open
23
+ * view and pinned views stay. Pair it with a larger `max` so a wide head shows more views.
24
+ */
25
+ fit?: boolean;
17
26
  class?: string;
18
27
  };
19
28
  /** Two deterministic strip levels; only opening the menu reads CSS visibility. */
20
29
  export declare function viewTabsLayout(items: readonly ViewTab[], current: string | undefined, max?: number): {
21
30
  wide: number[];
22
31
  compact: number[];
32
+ pinned: number[];
23
33
  wideHidden: number;
24
34
  compactHidden: number;
25
35
  };
@@ -1,8 +1,6 @@
1
1
  import { type JSX } from "solid-js";
2
2
  import type { DropdownItem, DropdownSearch } from "./Dropdown";
3
- /** Phones, where a menu opens as a bottom sheet instead of beside its trigger. */
4
- export declare const PHONE_SHEET_QUERY = "(max-width: 47.999rem)";
5
- export declare const prefersMenuSheet: () => boolean;
3
+ export { PHONE_SHEET_QUERY, prefersMenuSheet } from "./phone-sheet";
6
4
  export type MenuSheetOptions = {
7
5
  /** Renders the rows: the dropdown's own `DropdownItems`, passed in so this module does not import it back. */
8
6
  Items: (props: {
@@ -0,0 +1,3 @@
1
+ /** Phones, where a menu or a date calendar opens as a bottom sheet instead of beside its trigger. */
2
+ export declare const PHONE_SHEET_QUERY = "(max-width: 47.999rem)";
3
+ export declare const prefersMenuSheet: () => boolean;
@@ -34,6 +34,11 @@ type FileGridBaseProps<T> = {
34
34
  export type FileGridSelectableProps<T> = FileGridBaseProps<T> & {
35
35
  selection: CollectionSelection;
36
36
  onRowClick?: (row: T) => void;
37
+ /**
38
+ * Shows a check box before each item that `checks` returns `true` for, or a circle when only one item may be
39
+ * selected. The check only mirrors the selection; items without one keep its slot, so names stay in line.
40
+ */
41
+ checks?: (row: T) => boolean;
37
42
  limit?: never;
38
43
  expanded?: never;
39
44
  onExpandedChange?: never;
@@ -45,6 +50,7 @@ export type FileGridSelectableProps<T> = FileGridBaseProps<T> & {
45
50
  export type FileGridOpenProps<T> = FileGridBaseProps<T> & {
46
51
  selection?: never;
47
52
  onRowClick?: never;
53
+ checks?: never;
48
54
  /** Shows the first `limit` items, then "Show all N", which opens the full list in place. Without it, the list is always full. */
49
55
  limit?: number;
50
56
  /** Controls whether the full list is open. Without it, the list keeps its own state. */
@@ -0,0 +1,10 @@
1
+ import type { UiMessages } from "../intl/messages";
2
+ /** A dialog's outcome or risk: a 2 px edge in its colour inside the frame and its icon in the header. */
3
+ export type DialogTone = "success" | "warning" | "danger";
4
+ /** The header icon of a toned dialog; it replaces the dialog's own icon. */
5
+ export declare const dialogToneIcon: (tone: DialogTone) => string;
6
+ /**
7
+ * The tone's word for screen readers, so the tone is not carried by colour alone. Headers render it hidden with
8
+ * `data-dialog-tone-label`; the dialog core makes it the dialog's description, and the heading keeps the title alone.
9
+ */
10
+ export declare const dialogToneLabel: (messages: UiMessages, tone: DialogTone) => string;
@@ -2,6 +2,7 @@ export type { AnnounceOptions, AnnouncePoliteness } from "./announce";
2
2
  export { announce } from "./announce";
3
3
  export type { DialogClose, DialogCore, DialogRender, OpenDialogOptions } from "./dialog-core";
4
4
  export { dialogCore } from "./dialog-core";
5
+ export type { DialogTone } from "./dialog-tone";
5
6
  export type { HoverPreviewController, HoverPreviewOptions, HoverPreviewPlacement, HoverPreviewProps } from "./HoverPreview";
6
7
  export { createHoverPreview, HoverPreview } from "./HoverPreview";
7
8
  export type { InlineGuidanceProps } from "./InlineGuidance";
@@ -0,0 +1,19 @@
1
+ import { type JSX } from "solid-js";
2
+ import { type DialogTone } from "./dialog-tone";
3
+ import type { ConfirmOptions, DialogOptions } from "./prompts";
4
+ export type PromptContent = string | HTMLElement | JSX.Element;
5
+ /** A prompt's `variant` is its tone too: a success or danger prompt carries the dialog tone of that name. */
6
+ export declare const promptTone: (variant: DialogOptions["variant"]) => DialogTone | undefined;
7
+ export declare const DialogHeader: (props: {
8
+ close: () => void;
9
+ title?: string;
10
+ icon?: string;
11
+ tone?: DialogTone;
12
+ }) => JSX.Element;
13
+ export declare const panelClass: (options?: Pick<DialogOptions, "size" | "surface" | "variant">) => string;
14
+ export declare const contentClass: (surface?: DialogOptions["surface"]) => string;
15
+ export declare const confirmPrompt: (content: PromptContent, options?: ConfirmOptions) => Promise<boolean | undefined>;
16
+ /** `prompts` starts as this object; `PanelDialog` asks through it, so it reaches a replaced `prompts.confirm` too. */
17
+ export declare const sharedPrompts: {
18
+ confirm: typeof confirmPrompt;
19
+ };
@@ -1,5 +1,7 @@
1
1
  import { type JSX } from "solid-js";
2
2
  import { type DialogRender, type OpenDialogOptions } from "./dialog-core";
3
+ import { type PromptContent } from "./prompt-confirm";
4
+ export { DialogHeader } from "./prompt-confirm";
3
5
  export interface DialogOptions {
4
6
  signal?: AbortSignal;
5
7
  title?: string;
@@ -19,7 +21,6 @@ export interface DialogOptions {
19
21
  export interface ConfirmOptions extends DialogOptions {
20
22
  confirmationPhrase?: string;
21
23
  }
22
- type PromptContent = string | HTMLElement | JSX.Element;
23
24
  export type PromptSearchItem<T = unknown> = {
24
25
  /**
25
26
  * Stable identity of the result, such as its record ID. With it, a newer answer that contains the same result keeps
@@ -153,11 +154,6 @@ export declare const createFormState: <T extends Record<string, FieldSchema>>(sc
153
154
  validateAll: () => boolean;
154
155
  reset: () => void;
155
156
  };
156
- export declare const DialogHeader: (props: {
157
- close: () => void;
158
- title?: string;
159
- icon?: string;
160
- }) => JSX.Element;
161
157
  type CloudSearchResolver<T> = (input: PromptSearchInput) => Promise<PromptSearchItem<T>[]> | PromptSearchItem<T>[];
162
158
  declare const openSearchPrompt: <T extends unknown = unknown>(resolver: CloudSearchResolver<T>, options?: PromptSearchOptions) => Promise<PromptSearchItem<T> | undefined>;
163
159
  declare const promptText: (content: string, defaultValue?: string, options?: DialogOptions) => Promise<string | null>;
@@ -166,9 +162,10 @@ declare const promptNumber: (content: string, defaultValue?: number, options?: D
166
162
  max?: number;
167
163
  }) => Promise<number | null>;
168
164
  export declare const prompts: {
165
+ confirm: typeof import("./prompt-confirm").confirmPrompt;
166
+ } & {
169
167
  alert: (content: PromptContent, options?: DialogOptions) => Promise<void | undefined>;
170
168
  success: (content: PromptContent, options?: Omit<DialogOptions, "variant">) => Promise<void | undefined>;
171
- confirm: (content: PromptContent, options?: ConfirmOptions) => Promise<boolean | undefined>;
172
169
  prompt: typeof promptText;
173
170
  promptNumber: typeof promptNumber;
174
171
  form: <T extends Record<string, FieldSchema>>(config: PromptFormOptions<T>) => Promise<InferFormValues<T> | null>;
@@ -182,4 +179,3 @@ export declare const prompts: {
182
179
  search: typeof openSearchPrompt;
183
180
  error: (content: string | HTMLElement, options?: DialogOptions) => Promise<unknown>;
184
181
  };
185
- export {};
@@ -7,6 +7,10 @@ export type ChoiceListOption<T extends string = string> = {
7
7
  description?: string;
8
8
  /** A quiet tag after the label, such as "Default" for the choice that applies without one. */
9
9
  marker?: string;
10
+ /** A Tabler icon class before the text, such as `ti ti-truck`, when a picture helps tell the choices apart. */
11
+ icon?: string;
12
+ /** This choice is not possible now. Say why in `description`; a disabled chosen option still shows as chosen. */
13
+ disabled?: boolean;
10
14
  };
11
15
  export type ChoiceListProps<T extends string = string> = Omit<ValueFieldProps<T | null>, "onValueChange" | "onValueCommit"> & {
12
16
  options: readonly ChoiceListOption<T>[];
@@ -20,9 +24,9 @@ export type ChoiceListProps<T extends string = string> = Omit<ValueFieldProps<T
20
24
  onValueCommit?: (value: T) => void;
21
25
  };
22
26
  /**
23
- * A labeled single choice shown as a short list of rows, each with a radio, a label and one sentence on what it
24
- * means, for a few choices whose consequences need words. Choosing changes only paint, so no row moves; `details`
25
- * opens under the chosen row. Use `ChoiceChips` for quick picks without explanation, `RichSelect` for longer lists
27
+ * A labeled single choice shown as cards, each with a radio, a label and one sentence on what it
28
+ * means, for a few choices whose consequences need words. Choosing changes only paint, so no card moves; `details`
29
+ * opens under the chosen card's row. Use `ChoiceChips` for quick picks without explanation, `RichSelect` for longer lists
26
30
  * in a dropdown, and `ChoiceTiles` when a preview decides.
27
31
  */
28
32
  export declare function ChoiceList<T extends string = string>(props: ChoiceListProps<T>): JSX.Element;
@@ -18,11 +18,20 @@ export type DatePickerBaseProps<T> = Omit<ValueFieldProps<T>, "value"> & {
18
18
  presets?: readonly DatePreset<T>[];
19
19
  dateConfig?: DateContext;
20
20
  clearable?: boolean;
21
- /** `plain` shows the value as text for property rows; a clearable picker offers clearing in its panel. */
21
+ /**
22
+ * `field` (default) is a text field: people type a date or open the calendar. `plain` shows the value as text for
23
+ * property rows and only opens the calendar; a clearable plain picker offers clearing in its panel.
24
+ */
22
25
  appearance?: ChoiceAppearance;
26
+ /** Earliest selectable day as a date key such as `2026-11-02`; earlier days are locked and typed ones refused. */
27
+ min?: string;
28
+ /** Latest selectable day as a date key. */
29
+ max?: string;
30
+ /** Shows and announces the value without changing it; the field stays focusable. */
31
+ readOnly?: boolean;
23
32
  };
24
33
  export type DatePickerProps = DatePickerBaseProps<string | null> & {
25
- /** Trigger content for a set value, for example the date with a relative hint. */
34
+ /** Content for a set value: the trigger of a `plain` picker, or the resting status line of a typed field. */
26
35
  renderValue?: (value: string) => JSX.Element;
27
36
  };
28
37
  export type DateTimePickerProps = DatePickerBaseProps<string | null> & {
@@ -41,7 +50,8 @@ export type DateRangePickerProps = DatePickerBaseProps<DateRangeValue> & {
41
50
  datePresets?: readonly DatePreset<string | null>[];
42
51
  durationPresets?: readonly DurationPreset[];
43
52
  };
44
- export declare const placeDatePopover: (trigger: HTMLElement, popover: HTMLElement, wide: boolean) => void;
53
+ /** `below` is a line under the trigger that the panel must not cover, such as a typed field's status line. */
54
+ export declare const placeDatePopover: (trigger: HTMLElement, popover: HTMLElement, wide: boolean, below?: HTMLElement) => void;
45
55
  export declare function DatePicker(props: DatePickerProps): JSX.Element;
46
56
  export declare function DateTimePicker(props: DateTimePickerProps): JSX.Element;
47
57
  export declare function DateRangePicker(props: DateRangePickerProps): JSX.Element;
@@ -6,7 +6,7 @@ export type TextInputProps = Omit<JSX.InputHTMLAttributes<HTMLInputElement>, "on
6
6
  maxLength?: number;
7
7
  type?: "text" | "search" | "email" | "url" | "tel";
8
8
  variant?: "default" | "ai" | "compact";
9
- /** Set false for a plain field without a leading icon. */
9
+ /** A leading icon such as a search magnifier. Plain text fields have none. */
10
10
  icon?: string | false;
11
11
  activeIcon?: string;
12
12
  /** ID of a consumer-owned visible error; caller owns its announcement. Native controls only. */
@@ -45,14 +45,20 @@ export declare function createChoiceLoader<T extends string>(loader: () => Choic
45
45
  };
46
46
  export type ChoicePopoverPlacement = {
47
47
  /**
48
- * `trigger` (default) gives the popover the trigger's width; `own` keeps the
49
- * width its stylesheet sets, such as a RichSelect with a preview.
48
+ * `trigger` (default) makes the popover at least as wide as the trigger and
49
+ * as wide as its longest name, so names stay on one line; `own` keeps
50
+ * the width its stylesheet sets, such as a RichSelect with a preview.
50
51
  */
51
52
  width?: "trigger" | "own";
52
53
  /** The side tried first. The popover flips when the other side has more room. */
53
54
  side?: "below" | "above";
54
55
  };
55
- export declare const placeChoicePopover: (trigger: HTMLElement, popover: HTMLElement, placement?: ChoicePopoverPlacement) => void;
56
+ /**
57
+ * Places the popover under (or above) its trigger. `floor` is the narrowest
58
+ * width it may take, such as the width it already had while open, so filtering
59
+ * the options never makes it narrower.
60
+ */
61
+ export declare const placeChoicePopover: (trigger: HTMLElement, popover: HTMLElement, placement?: ChoicePopoverPlacement, floor?: number) => void;
56
62
  export declare function createChoicePopover(disabled: () => boolean, placement?: () => ChoicePopoverPlacement): {
57
63
  open: () => boolean;
58
64
  setTrigger: Setter<HTMLElement | undefined>;
@@ -0,0 +1,64 @@
1
+ /** Status line and errors of the typed date field; dates, weekdays and distances come from Intl. */
2
+ declare const dateInputMessages: import("@k2b/stdlib").Catalog<{
3
+ dayLetters: string;
4
+ monthLetters: string;
5
+ yearLetters: string;
6
+ openCalendar: string;
7
+ closeCalendar: string;
8
+ notADate: ({ example }: {
9
+ example: string;
10
+ }) => string;
11
+ notYet: string;
12
+ ambiguous: string;
13
+ incompleteYear: ({ year }: {
14
+ year: string;
15
+ }) => string;
16
+ unknownUnit: string;
17
+ noSuchMonth: ({ month }: {
18
+ month: number;
19
+ }) => string;
20
+ shortMonth: ({ month, days }: {
21
+ month: string;
22
+ days: number;
23
+ }) => string;
24
+ earliest: ({ date }: {
25
+ date: string;
26
+ }) => string;
27
+ latest: ({ date }: {
28
+ date: string;
29
+ }) => string;
30
+ outsideRange: string;
31
+ required: string;
32
+ endBeforeStart: string;
33
+ missingEnd: string;
34
+ missingStart: string;
35
+ nextWeekday: ({ weekday }: {
36
+ weekday: string;
37
+ }) => string;
38
+ nextWeek: string;
39
+ notSelectable: ({ date }: {
40
+ date: string;
41
+ }) => string;
42
+ limitFrom: ({ date }: {
43
+ date: string;
44
+ }) => string;
45
+ limitUntil: ({ date }: {
46
+ date: string;
47
+ }) => string;
48
+ start: string;
49
+ end: string;
50
+ startOf: ({ label }: {
51
+ label: string;
52
+ }) => string;
53
+ endOf: ({ label }: {
54
+ label: string;
55
+ }) => string;
56
+ startMissing: string;
57
+ endMissing: string;
58
+ noDate: string;
59
+ }>;
60
+ export type DateInputMessages = ReturnType<(typeof dateInputMessages)["resolve"]>["t"];
61
+ /** Resolved from the date locale, so the words join the dates they describe in one language. */
62
+ export declare const resolveDateInputMessages: (locale?: string) => DateInputMessages;
63
+ export declare const checkDateInputMessages: () => import("@k2b/stdlib").CatalogIssue[];
64
+ export {};
@@ -0,0 +1,35 @@
1
+ import { type DateInputError, type DateInputNote } from "./date-input";
2
+ import type { DateInputMessages } from "./date-input-messages";
3
+ /**
4
+ * The line under a typed date field. It always says which day is meant: grey at rest (weekday and distance), blue
5
+ * while typing (the absolute date that a commit would save), red after a commit that failed.
6
+ */
7
+ export type DateStatusTone = "rest" | "draft" | "error";
8
+ export type DateStatus = {
9
+ tone: DateStatusTone;
10
+ text: string;
11
+ };
12
+ /** "Mi., 4. Nov. 2026" / "Wed, Nov 4, 2026": the absolute date of a draft. */
13
+ export declare const formatDateLong: (key: string, locale?: string) => string;
14
+ /** "Mittwoch, in 9 Tagen": the saved date at rest. */
15
+ export declare const restStatusText: (key: string, today: string, locale?: string) => string;
16
+ /** What a word or offset meant: "morgen", "nächster Mittwoch", "gestern + 34 Tage". */
17
+ export declare const noteText: (note: DateInputNote, locale: string | undefined, t: DateInputMessages) => string;
18
+ /** The draft line: "→ Mi., 4. Nov. 2026 · nächster Mittwoch". */
19
+ export declare const draftStatusText: (key: string, note: DateInputNote | undefined, locale: string | undefined, t: DateInputMessages) => string;
20
+ /** The reason a text is not a date, short enough for one line. */
21
+ export declare const errorText: (error: DateInputError, locale: string | undefined, t: DateInputMessages, today: string) => string;
22
+ /** A date outside `min`/`max` (date keys) is refused with the nearest allowed day. */
23
+ export declare const limitErrorText: (key: string, limits: {
24
+ min?: string;
25
+ max?: string;
26
+ }, locale: string | undefined, t: DateInputMessages) => string | undefined;
27
+ /** While typing nothing is red yet: an unfinished entry says so calmly, a definite mistake already names the reason. */
28
+ export declare const typingStatusText: (error: DateInputError, locale: string | undefined, t: DateInputMessages, today: string) => string;
29
+ /** "Mittwoch, 4. November 2026, nächster Mittwoch": what the live region reads after typing pauses. */
30
+ export declare const spokenDateText: (key: string, note: DateInputNote | undefined, locale: string | undefined, t: DateInputMessages) => string;
31
+ /** "Mi., 11. Nov. 2026 – Sa., 14. Nov. 2026 · 4 Tage", or one end with what is missing. */
32
+ export declare const rangeStatusText: (range: {
33
+ start: string | null;
34
+ end: string | null;
35
+ }, locale: string | undefined, t: DateInputMessages) => string;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Typed date input: a small, predictable grammar instead of a natural-language parser. Every input resolves to one
3
+ * calendar day (a date key such as `2026-11-11`), so the field can show the absolute date before it is committed.
4
+ *
5
+ * - Dates in the locale's order of day, month and year: `11.11.2026`, `11.11.26`, `11.11.`, `11.11`, `11/11/2026`.
6
+ * - Digits only: 1–2 digits are a day of the current month; 4, 6 or 8 digits are day, month and year without separators.
7
+ * - ISO dates (`2026-11-11`) and month names (`11. November 2026`, `Nov 11, 2026`).
8
+ * - Day words and weekdays in German and English: `heute`, `morgen`, `mi`, `wed`, `Mittwoch`. A weekday is its next
9
+ * occurrence after today; today's weekday is the same day next week.
10
+ * - One offset at the end: `[anchor] ± N [unit]`, such as `+14`, `-3`, `heute +2w`, `gestern + 34`, `mi +7`, `11.11. -3`.
11
+ * The anchor is any of the forms above; without one it is today, never the saved value.
12
+ */
13
+ export type DatePart = "day" | "month" | "year";
14
+ export type DateUnit = "day" | "week" | "month" | "year";
15
+ /** What a word or offset meant, so the field can say it next to the resolved date. */
16
+ export type DateInputAnchor = {
17
+ kind: "today";
18
+ } | {
19
+ kind: "date";
20
+ date: string;
21
+ } | {
22
+ kind: "day";
23
+ offset: number;
24
+ } | {
25
+ kind: "weekday";
26
+ weekday: number;
27
+ };
28
+ export type DateInputNote = {
29
+ kind: "day";
30
+ offset: number;
31
+ } | {
32
+ kind: "weekday";
33
+ weekday: number;
34
+ nextWeek: boolean;
35
+ } | {
36
+ kind: "offset";
37
+ anchor: DateInputAnchor;
38
+ amount: number;
39
+ unit: DateUnit;
40
+ };
41
+ export type DateInputError = {
42
+ code: "not-a-date";
43
+ } | {
44
+ code: "incomplete";
45
+ } | {
46
+ code: "ambiguous";
47
+ } | {
48
+ code: "year";
49
+ } | {
50
+ code: "unit";
51
+ } | {
52
+ code: "month";
53
+ month: number;
54
+ } | {
55
+ code: "day";
56
+ year: number;
57
+ month: number;
58
+ days: number;
59
+ };
60
+ export type DateInputResult = {
61
+ kind: "empty";
62
+ } | {
63
+ kind: "date";
64
+ date: string;
65
+ note?: DateInputNote;
66
+ } | {
67
+ kind: "error";
68
+ error: DateInputError;
69
+ };
70
+ export declare const addDaysToKey: (key: string, days: number) => string;
71
+ /** Months and years keep the day where it exists and otherwise end on the last day of the month (31.01. + 1m = 28.02.). */
72
+ export declare const addMonthsToKey: (key: string, months: number) => string;
73
+ /** Monday 0 … Sunday 6. */
74
+ export declare const weekdayOfKey: (key: string) => number;
75
+ /** Whole days from `from` to `to`. */
76
+ export declare const daysBetweenKeys: (from: string, to: string) => number;
77
+ /** The locale's order of day, month and year in a numeric date, read from Intl; day-month-year without data. */
78
+ export declare const dateOrder: (locale?: string) => DatePart[];
79
+ /** The numeric form the field shows after a commit, such as `11.11.2026` or `11/11/2026`. */
80
+ export declare const formatDateInput: (key: string, locale?: string) => string;
81
+ /** The placeholder pattern in the locale's order, with letters from the caller (`TT.MM.JJJJ`, `MM/DD/YYYY`). */
82
+ export declare const dateInputPattern: (locale: string | undefined, letters: Record<DatePart, string>) => string;
83
+ /**
84
+ * Parses what a person typed into a date field. `today` is the current date key in the field's time zone; the result
85
+ * never depends on the clock.
86
+ */
87
+ export declare const parseDateInput: (raw: string, options: {
88
+ today: string;
89
+ locale?: string;
90
+ }) => DateInputResult;
@@ -0,0 +1,14 @@
1
+ import type { JSX } from "solid-js";
2
+ /**
3
+ * The phone calendar of a typed date field as a bottom sheet. Date pickers load this module only when the sheet opens:
4
+ * the sheet reaches `PanelDialog`, whose prompts render date pickers, so a static import would be a cycle.
5
+ */
6
+ export declare const openDateSheet: <T>(options: {
7
+ title: JSX.Element;
8
+ subtitle: string;
9
+ ariaLabel?: string;
10
+ /** The calendar's id, which the field's `aria-controls` names while the sheet is open. */
11
+ id: string;
12
+ locale: string;
13
+ content: (close: (result: T) => void) => JSX.Element;
14
+ }) => Promise<T | undefined>;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Scrolls `scroller` alone so `item` sits fully inside it, with the "nearest" rule of `scrollIntoView`: an item already
3
+ * in view stays put, and one larger than the view keeps its start in view. Unlike `scrollIntoView`, no ancestor moves,
4
+ * so a strip that keeps its selection visible never scrolls the page or panel around it.
5
+ */
6
+ export declare function revealInScroller(scroller: HTMLElement | undefined, item: HTMLElement | undefined): void;
@@ -76,6 +76,9 @@ declare const uiMessages: import("@k2b/stdlib").Catalog<{
76
76
  info: string;
77
77
  ok: string;
78
78
  success: string;
79
+ dialogToneSuccess: string;
80
+ dialogToneWarning: string;
81
+ dialogToneDanger: string;
79
82
  unknown: string;
80
83
  name: string;
81
84
  color: string;
@@ -106,8 +106,22 @@ export type AppWorkspaceMainPaneProps = {
106
106
  description?: JSX.Element;
107
107
  /** Levels mode: a small mark before the level title, such as the colour dot of the object's container. */
108
108
  lead?: JSX.Element;
109
+ /**
110
+ * Levels mode: the level's own parent inside the same column, such as a sub-view of a detail that replaces the
111
+ * detail in place. Its back step shows at every width and replaces the shared step to the level before.
112
+ */
113
+ back?: {
114
+ href: string;
115
+ label: string;
116
+ };
109
117
  /** Controls at the end of the level head. */
110
118
  actions?: JSX.Element;
119
+ /**
120
+ * Levels mode: `"page"` marks the level that holds the page itself, such as a settings form or the list of an
121
+ * area, rather than a column that leads there or a detail beside it. Its title takes the page step of the type
122
+ * scale, above every group title in it, and its content starts at the title's edge without an inset of its own.
123
+ */
124
+ heading?: "page";
111
125
  surface?: "default" | "navigation";
112
126
  open?: boolean;
113
127
  resizable?: boolean;
@@ -1,4 +1,5 @@
1
1
  import { type JSX } from "solid-js";
2
+ import type { DialogTone } from "../feedback/dialog-tone";
2
3
  /** Initial focus goes to the first input of the top sheet, otherwise to the
3
4
  * dialog element itself. Native `showModal()` focuses the first focusable
4
5
  * descendant, which is the drag handle; iOS shows a ring for that programmatic
@@ -24,6 +25,8 @@ export type BottomSheetProps = {
24
25
  dismissDisabled?: boolean;
25
26
  dismissLabel?: string;
26
27
  handle?: boolean;
28
+ /** See `PanelDialog`'s `tone`. */
29
+ tone?: DialogTone;
27
30
  };
28
31
  declare function BottomSheetRoot(props: BottomSheetProps): JSX.Element;
29
32
  /** Bottom-edge presentation; dialogCore continues to own all modal state. */
@@ -100,6 +100,14 @@ export type DetailPanelActionButtonProps = DetailPanelActionBaseProps & DetailPa
100
100
  href?: never;
101
101
  };
102
102
  export type DetailPanelActionProps = DetailPanelActionLinkProps | DetailPanelActionButtonProps;
103
+ /** A row that only shows something, such as a person and their role: the columns of an action, without a command. */
104
+ export type DetailPanelRowProps = {
105
+ title: JSX.Element;
106
+ description?: JSX.Element;
107
+ leading?: JSX.Element;
108
+ trailing?: JSX.Element;
109
+ class?: string;
110
+ };
103
111
  export type DetailPanelSectionProps = DetailPanelSectionBaseProps & ({
104
112
  children?: JSX.Element;
105
113
  actions?: JSX.Element;
@@ -127,6 +135,7 @@ type DetailPanelComponent = ((props: DetailPanelProps) => JSX.Element) & {
127
135
  Group: (props: DetailPanelGroupProps) => JSX.Element;
128
136
  Section: (props: DetailPanelSectionProps) => JSX.Element;
129
137
  Action: (props: DetailPanelActionProps) => JSX.Element;
138
+ Row: (props: DetailPanelRowProps) => JSX.Element;
130
139
  };
131
140
  /** A count chip, or "None yet" for zero; shared by sections and discussions. */
132
141
  export declare const DetailPanelCount: (props: {