@k2b/ui 0.11.0 → 0.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.
Files changed (139) hide show
  1. package/README.md +1 -1
  2. package/dist/browser/content/FileView.js +203 -136
  3. package/dist/browser/content/FileView.js.map +1 -1
  4. package/dist/browser/content/PdfPreview.js +5 -2
  5. package/dist/browser/content/PdfPreview.js.map +1 -1
  6. package/dist/browser/content/markdown-title.js +52 -0
  7. package/dist/browser/content/markdown-title.js.map +1 -0
  8. package/dist/browser/feedback/InstallGuide.js +267 -0
  9. package/dist/browser/feedback/InstallGuide.js.map +1 -0
  10. package/dist/browser/feedback/announce.js +50 -0
  11. package/dist/browser/feedback/announce.js.map +1 -0
  12. package/dist/browser/feedback/dialog-core.js +82 -1
  13. package/dist/browser/feedback/dialog-core.js.map +1 -1
  14. package/dist/browser/feedback/index.js +4 -0
  15. package/dist/browser/feedback/index.js.map +1 -1
  16. package/dist/browser/feedback/install.js +99 -0
  17. package/dist/browser/feedback/install.js.map +1 -0
  18. package/dist/browser/feedback/prompts.js +29 -20
  19. package/dist/browser/feedback/prompts.js.map +1 -1
  20. package/dist/browser/feedback/theme-color.js +15 -0
  21. package/dist/browser/feedback/theme-color.js.map +1 -0
  22. package/dist/browser/feedback/toast.js +329 -122
  23. package/dist/browser/feedback/toast.js.map +1 -1
  24. package/dist/browser/inputs/DatePicker.js +263 -222
  25. package/dist/browser/inputs/DatePicker.js.map +1 -1
  26. package/dist/browser/inputs/MultiSelectInput.js +139 -105
  27. package/dist/browser/inputs/MultiSelectInput.js.map +1 -1
  28. package/dist/browser/inputs/NumberInput.js +209 -122
  29. package/dist/browser/inputs/NumberInput.js.map +1 -1
  30. package/dist/browser/inputs/QrScanner.js +164 -0
  31. package/dist/browser/inputs/QrScanner.js.map +1 -0
  32. package/dist/browser/inputs/Select.js +184 -92
  33. package/dist/browser/inputs/Select.js.map +1 -1
  34. package/dist/browser/inputs/index.js +1 -0
  35. package/dist/browser/inputs/index.js.map +1 -1
  36. package/dist/browser/intl/messages.js +90 -2
  37. package/dist/browser/intl/messages.js.map +1 -1
  38. package/dist/browser/layout/DetailPanel.js +2 -1
  39. package/dist/browser/layout/DetailPanel.js.map +1 -1
  40. package/dist/browser/layout/Discussion.js +2 -1
  41. package/dist/browser/layout/Discussion.js.map +1 -1
  42. package/dist/browser/layout/MobileShell.js +242 -0
  43. package/dist/browser/layout/MobileShell.js.map +1 -0
  44. package/dist/browser/layout/Navigation.js +1 -0
  45. package/dist/browser/layout/Navigation.js.map +1 -1
  46. package/dist/browser/layout/PanelDialog.js +1 -0
  47. package/dist/browser/layout/PanelDialog.js.map +1 -1
  48. package/dist/browser/layout/Settings.js +2 -2
  49. package/dist/browser/layout/Settings.js.map +1 -1
  50. package/dist/browser/layout/TabBar.js +65 -0
  51. package/dist/browser/layout/TabBar.js.map +1 -0
  52. package/dist/browser/layout/index.js +2 -0
  53. package/dist/browser/layout/index.js.map +1 -1
  54. package/dist/browser/surfaces/NoticeCard.js +55 -60
  55. package/dist/browser/surfaces/NoticeCard.js.map +1 -1
  56. package/dist/browser/surfaces/index.js +1 -1
  57. package/dist/browser/surfaces/index.js.map +1 -1
  58. package/dist/ssr/content/FileView.js +141 -81
  59. package/dist/ssr/content/FileView.js.map +1 -1
  60. package/dist/ssr/content/PdfPreview.js +4 -2
  61. package/dist/ssr/content/PdfPreview.js.map +1 -1
  62. package/dist/ssr/content/markdown-title.js +52 -0
  63. package/dist/ssr/content/markdown-title.js.map +1 -0
  64. package/dist/ssr/feedback/InstallGuide.js +201 -0
  65. package/dist/ssr/feedback/InstallGuide.js.map +1 -0
  66. package/dist/ssr/feedback/announce.js +50 -0
  67. package/dist/ssr/feedback/announce.js.map +1 -0
  68. package/dist/ssr/feedback/dialog-core.js +82 -1
  69. package/dist/ssr/feedback/dialog-core.js.map +1 -1
  70. package/dist/ssr/feedback/index.js +4 -0
  71. package/dist/ssr/feedback/index.js.map +1 -1
  72. package/dist/ssr/feedback/install.js +99 -0
  73. package/dist/ssr/feedback/install.js.map +1 -0
  74. package/dist/ssr/feedback/prompts.js +12 -2
  75. package/dist/ssr/feedback/prompts.js.map +1 -1
  76. package/dist/ssr/feedback/theme-color.js +15 -0
  77. package/dist/ssr/feedback/theme-color.js.map +1 -0
  78. package/dist/ssr/feedback/toast.js +329 -122
  79. package/dist/ssr/feedback/toast.js.map +1 -1
  80. package/dist/ssr/inputs/DatePicker.js +78 -52
  81. package/dist/ssr/inputs/DatePicker.js.map +1 -1
  82. package/dist/ssr/inputs/MultiSelectInput.js +52 -32
  83. package/dist/ssr/inputs/MultiSelectInput.js.map +1 -1
  84. package/dist/ssr/inputs/NumberInput.js +93 -40
  85. package/dist/ssr/inputs/NumberInput.js.map +1 -1
  86. package/dist/ssr/inputs/QrScanner.js +128 -0
  87. package/dist/ssr/inputs/QrScanner.js.map +1 -0
  88. package/dist/ssr/inputs/Select.js +108 -29
  89. package/dist/ssr/inputs/Select.js.map +1 -1
  90. package/dist/ssr/inputs/index.js +1 -0
  91. package/dist/ssr/inputs/index.js.map +1 -1
  92. package/dist/ssr/intl/messages.js +90 -2
  93. package/dist/ssr/intl/messages.js.map +1 -1
  94. package/dist/ssr/layout/DetailPanel.js +2 -1
  95. package/dist/ssr/layout/DetailPanel.js.map +1 -1
  96. package/dist/ssr/layout/Discussion.js +2 -1
  97. package/dist/ssr/layout/Discussion.js.map +1 -1
  98. package/dist/ssr/layout/MobileShell.js +211 -0
  99. package/dist/ssr/layout/MobileShell.js.map +1 -0
  100. package/dist/ssr/layout/Navigation.js +1 -0
  101. package/dist/ssr/layout/Navigation.js.map +1 -1
  102. package/dist/ssr/layout/PanelDialog.js +1 -0
  103. package/dist/ssr/layout/PanelDialog.js.map +1 -1
  104. package/dist/ssr/layout/Settings.js +2 -2
  105. package/dist/ssr/layout/Settings.js.map +1 -1
  106. package/dist/ssr/layout/TabBar.js +24 -0
  107. package/dist/ssr/layout/TabBar.js.map +1 -0
  108. package/dist/ssr/layout/index.js +2 -0
  109. package/dist/ssr/layout/index.js.map +1 -1
  110. package/dist/ssr/surfaces/NoticeCard.js +21 -30
  111. package/dist/ssr/surfaces/NoticeCard.js.map +1 -1
  112. package/dist/ssr/surfaces/index.js +1 -1
  113. package/dist/ssr/surfaces/index.js.map +1 -1
  114. package/dist/styles.css +1 -1
  115. package/dist/tabler.css +1 -1
  116. package/dist/types/content/FileView.d.ts +11 -1
  117. package/dist/types/content/markdown-title.d.ts +9 -0
  118. package/dist/types/feedback/InstallGuide.d.ts +26 -0
  119. package/dist/types/feedback/announce.d.ts +19 -0
  120. package/dist/types/feedback/dialog-core.d.ts +5 -0
  121. package/dist/types/feedback/index.d.ts +8 -1
  122. package/dist/types/feedback/install.d.ts +32 -0
  123. package/dist/types/feedback/prompts.d.ts +2 -0
  124. package/dist/types/feedback/theme-color.d.ts +6 -0
  125. package/dist/types/feedback/toast.d.ts +7 -0
  126. package/dist/types/inputs/DatePicker.d.ts +11 -2
  127. package/dist/types/inputs/MultiSelectInput.d.ts +5 -1
  128. package/dist/types/inputs/NumberInput.d.ts +14 -0
  129. package/dist/types/inputs/QrScanner.d.ts +20 -0
  130. package/dist/types/inputs/Select.d.ts +10 -0
  131. package/dist/types/inputs/index.d.ts +3 -1
  132. package/dist/types/intl/messages.d.ts +44 -0
  133. package/dist/types/layout/MobileShell.d.ts +40 -0
  134. package/dist/types/layout/Settings.d.ts +2 -2
  135. package/dist/types/layout/TabBar.d.ts +23 -0
  136. package/dist/types/layout/index.d.ts +4 -0
  137. package/dist/types/surfaces/NoticeCard.d.ts +4 -4
  138. package/dist/types/surfaces/index.d.ts +1 -1
  139. package/package.json +3 -2
@@ -4,6 +4,7 @@
4
4
  * without it every renderer is read-only. IDE-style chrome: editors reuse
5
5
  * the markdown editor's surface (toolbar with an in-toolbar save, Ctrl/Cmd+S),
6
6
  * previews are quiet paper panels with icon-only actions overlaid top-right.
7
+ * A plain preview drops the panel and sits on its host's surface instead.
7
8
  * Custom renderers are passed per instance, which keeps SSR requests and
8
9
  * independently mounted applications isolated.
9
10
  */
@@ -17,8 +18,17 @@ export type FileViewContent = {
17
18
  mediaType: string;
18
19
  };
19
20
  export type FileViewProps = {
20
- /** Plain previews inherit the surrounding surface without a frame or inset padding. */
21
+ /**
22
+ * Plain previews inherit the surrounding surface without a frame or inset padding. They keep their natural height,
23
+ * so the host scrolls them and owns the actions around them; a host that stretches one gets its scrolling back.
24
+ */
21
25
  variant?: "default" | "plain";
26
+ /**
27
+ * Lifts a leading Markdown level-one heading into the host, for example a dialog title. Reports its plain text and
28
+ * leaves that heading out of the preview, or reports null when the shown file has none, the heading holds a link or
29
+ * image or is the whole document, or the file fails to load.
30
+ */
31
+ onDocumentTitle?: (title: string | null) => void;
22
32
  /** Read-only excerpt limit; omitted renders the complete preview. */
23
33
  previewLines?: number;
24
34
  onExpandPreview?: () => void;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The document title of Markdown that starts with a level-one heading: its plain text, and the Markdown after it.
3
+ * Null when the first block is anything else, the heading has no text or holds a link or image, or nothing follows
4
+ * it; the heading then stays in the document.
5
+ */
6
+ export declare function leadingMarkdownTitle(markdown: string): {
7
+ title: string;
8
+ body: string;
9
+ } | null;
@@ -0,0 +1,26 @@
1
+ import { type JSX } from "solid-js";
2
+ import type { InstallPrompt } from "./install";
3
+ export type InstallGuideProps = {
4
+ /** The name people see on their Home Screen, used in the guidance text. */
5
+ appName: string;
6
+ install: InstallPrompt;
7
+ /**
8
+ * The address a browser inside another app copies, to open it in Safari or Chrome. Shown as text when copying
9
+ * fails, so it can be copied by hand.
10
+ */
11
+ url: string;
12
+ /**
13
+ * An application note under the installation steps or the embedded browser's link, for example what else the
14
+ * installed app enables.
15
+ */
16
+ note?: string;
17
+ class?: string;
18
+ };
19
+ /**
20
+ * Explains how to install the current page as an app on this platform: the browser's own dialog where it offers
21
+ * one, otherwise the steps for Safari on iPhone, iPad, and Mac, other browsers on iPhone and iPad, Android, and other
22
+ * browsers. A browser inside another app cannot install, so it gets a warning and the link to copy into Safari or
23
+ * Chrome instead. The host owns the surrounding surface, its heading, and dismissal.
24
+ */
25
+ export declare function InstallGuide(props: InstallGuideProps): JSX.Element;
26
+ export default InstallGuide;
@@ -0,0 +1,19 @@
1
+ export type AnnouncePoliteness = "polite" | "assertive";
2
+ export type AnnounceOptions = {
3
+ /** `polite` waits until the screen reader is idle; `assertive` interrupts it. Defaults to `polite`. */
4
+ politeness?: AnnouncePoliteness;
5
+ };
6
+ /**
7
+ * One pair of persistent, empty live regions per document, polite and assertive, shared by `announce` and every
8
+ * toast. A region that already exists when its text arrives is announced reliably, unlike one inserted with its text
9
+ * already inside. They sit directly in the body, outside every portal and the toast rail, which moves into a fresh
10
+ * top-layer element for every toast, so no scope that closes takes them along.
11
+ */
12
+ export declare const ensureLiveRegions: (doc: Document) => HTMLElement;
13
+ /**
14
+ * Tells screen readers about an outcome without showing anything: a change the screen shows but the focused control
15
+ * does not say, because a shortcut acted, the control was busy, or it was replaced. Each message is its own line, so
16
+ * a burst of messages or the same message twice is still read. Calls without `document`, including during SSR, do
17
+ * nothing.
18
+ */
19
+ export declare const announce: (message: string, options?: AnnounceOptions) => void;
@@ -8,6 +8,11 @@ export type OpenDialogOptions = {
8
8
  initialFocus?: "first-input" | "none" | ((dialog: HTMLDialogElement) => HTMLElement | null);
9
9
  cancelBehavior?: "resolve-undefined" | "ignore";
10
10
  ariaLabel?: string;
11
+ /**
12
+ * Add a same-URL history entry while the dialog is open, so the browser's or the phone's Back closes the dialog
13
+ * instead of leaving the page. Closing the dialog removes the entry again; the returned promise settles after that.
14
+ */
15
+ history?: boolean;
11
16
  };
12
17
  export type DialogRender<T> = (close: DialogClose<T>, context: {
13
18
  dialog: HTMLDialogElement;
@@ -1,12 +1,19 @@
1
+ export type { AnnounceOptions, AnnouncePoliteness } from "./announce";
2
+ export { announce } from "./announce";
1
3
  export type { DialogClose, DialogCore, DialogRender, OpenDialogOptions } from "./dialog-core";
2
4
  export { dialogCore } from "./dialog-core";
3
5
  export type { HoverPreviewController, HoverPreviewOptions, HoverPreviewPlacement, HoverPreviewProps } from "./HoverPreview";
4
6
  export { createHoverPreview, HoverPreview } from "./HoverPreview";
5
7
  export type { InlineGuidanceProps } from "./InlineGuidance";
6
8
  export { default as InlineGuidance } from "./InlineGuidance";
9
+ export type { InstallGuideProps } from "./InstallGuide";
10
+ export { default as InstallGuide } from "./InstallGuide";
11
+ export type { InstallationPlatform, InstallPrompt } from "./install";
12
+ export { createInstallPrompt, installationPlatform } from "./install";
7
13
  export type { ConfirmOptions, DialogOptions, FieldSchema, PromptFieldBase, PromptSearchInput, PromptSearchItem, PromptSearchOptions, } from "./prompts";
8
14
  export { createFormState, DialogHeader, prompts } from "./prompts";
9
15
  export type { TooltipAnchorProps, TooltipPlacement, TooltipProps, TooltipTriggerProps } from "./Tooltip";
10
16
  export { Tooltip } from "./Tooltip";
11
- export type { ToastAction, ToastFn, ToastHandle, ToastOptions, ToastVariant } from "./toast";
17
+ export { syncThemeColor } from "./theme-color";
18
+ export type { ToastAction, ToastFn, ToastHandle, ToastOptions, ToastSlot, ToastVariant } from "./toast";
12
19
  export { isPointInsideToast, toast } from "./toast";
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Which installation steps a browser needs. `apple-in-app` and `in-app` are browsers embedded in another app, on
3
+ * iPhone or iPad and elsewhere, which cannot install at all. `apple-browser` is Chrome, Firefox, Edge, or another
4
+ * browser on iPhone or iPad, which installs through its Share menu but less reliably than Safari. `android-browser`
5
+ * is an Android browser other than Chrome.
6
+ */
7
+ export type InstallationPlatform = "in-app" | "apple-in-app" | "apple-browser" | "apple-mobile" | "apple-desktop" | "android-browser" | "android" | "generic";
8
+ /**
9
+ * Classifies the browser from its user agent; `platform` and `touchPoints` only tell an iPad that reports a Mac apart.
10
+ * A pure function, so the server and the browser compute the same value from the same user agent. Not a device
11
+ * check: an installed app on iPhone may itself look like an embedded browser.
12
+ */
13
+ export declare function installationPlatform(userAgent: string, platform: string, touchPoints: number): InstallationPlatform;
14
+ export type InstallPrompt = {
15
+ platform: InstallationPlatform;
16
+ /** Running from the Home Screen or as an installed app, or installed during this visit. */
17
+ installed: () => boolean;
18
+ /** The browser offered its own installation dialog, which `install()` opens. */
19
+ canPrompt: () => boolean;
20
+ busy: () => boolean;
21
+ /** The person accepted the browser's dialog; the browser finishes the installation. */
22
+ requested: () => boolean;
23
+ /** The browser's dialog could not be opened. */
24
+ failed: () => boolean;
25
+ /** Opens the browser's dialog once. Call it directly from a click. */
26
+ install: () => Promise<void>;
27
+ };
28
+ /**
29
+ * Tracks whether the page runs installed and captures the browser's installation prompt. Browser-only; call it once,
30
+ * when the page loads, under an owner that lives as long as the page: Chrome offers its prompt only once, early.
31
+ */
32
+ export declare function createInstallPrompt(): InstallPrompt;
@@ -13,6 +13,8 @@ export interface DialogOptions {
13
13
  surface?: "default" | "bare";
14
14
  header?: false;
15
15
  cancelBehavior?: OpenDialogOptions["cancelBehavior"];
16
+ /** Back closes the prompt like Cancel, as in a phone app; see `OpenDialogOptions.history`. */
17
+ history?: boolean;
16
18
  }
17
19
  export interface ConfirmOptions extends DialogOptions {
18
20
  confirmationPhrase?: string;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Gives the browser chrome the page's current background after a theme change: the `html` background, which iOS
3
+ * shows behind the status bar and in overscroll, and every `theme-color` meta element. A `media` attribute is
4
+ * dropped, because the page's chosen theme wins over the system scheme. Browser-only.
5
+ */
6
+ export declare function syncThemeColor(root?: Element): void;
@@ -8,8 +8,10 @@ export type ToastAction = {
8
8
  });
9
9
  export type ToastOptions = {
10
10
  variant?: ToastVariant;
11
+ /** Milliseconds until the toast closes; `0` keeps it until it is closed. Omit it for the default by variant, length, and action. */
11
12
  duration?: number;
12
13
  iconClass?: string;
14
+ /** A short line of context above the message. There is no default title. */
13
15
  title?: string;
14
16
  action?: ToastAction | null;
15
17
  /** Fraction from 0 to 1, or an indeterminate activity indicator. null removes it. */
@@ -20,10 +22,15 @@ export type ToastHandle = {
20
22
  dismiss: () => void;
21
23
  update: (description: string, options?: ToastOptions) => void;
22
24
  };
25
+ export type ToastSlot = {
26
+ dismiss: () => void;
27
+ };
23
28
  export interface ToastFn {
24
29
  (description: string, options?: ToastOptions): ToastHandle;
25
30
  success: (description: string, options?: Omit<ToastOptions, "variant">) => ToastHandle;
26
31
  error: (description: string, options?: Omit<ToastOptions, "variant">) => ToastHandle;
32
+ /** Places an application-owned element in the toast rail, in toast chrome; the caller owns its content and lifetime. */
33
+ custom: (content: HTMLElement) => ToastSlot;
27
34
  dismissAll: () => void;
28
35
  }
29
36
  export declare const K2B_TOAST_CONTAINER_ID = "k2b-ui-toast-container";
@@ -2,6 +2,7 @@ import { type DateContext } from "@k2b/stdlib";
2
2
  import { type JSX } from "solid-js";
3
3
  import { type DateRangeValue } from "./date-picker";
4
4
  import type { MaybeAccessor, ValueFieldProps } from "./field-contract";
5
+ import type { ChoiceAppearance } from "./Select";
5
6
  export type { DateRangeValue } from "./date-picker";
6
7
  export type DatePreset<T> = {
7
8
  label: string;
@@ -17,9 +18,17 @@ export type DatePickerBaseProps<T> = Omit<ValueFieldProps<T>, "value"> & {
17
18
  presets?: readonly DatePreset<T>[];
18
19
  dateConfig?: DateContext;
19
20
  clearable?: boolean;
21
+ /** `plain` shows the value as text for property rows; a clearable picker offers clearing in its panel. */
22
+ appearance?: ChoiceAppearance;
23
+ };
24
+ export type DatePickerProps = DatePickerBaseProps<string | null> & {
25
+ /** Trigger content for a set value, for example the date with a relative hint. */
26
+ renderValue?: (value: string) => JSX.Element;
27
+ };
28
+ export type DateTimePickerProps = DatePickerBaseProps<string | null> & {
29
+ /** Trigger content for a set value, for example the date and time with a relative hint. */
30
+ renderValue?: (value: string) => JSX.Element;
20
31
  };
21
- export type DatePickerProps = DatePickerBaseProps<string | null>;
22
- export type DateTimePickerProps = DatePickerBaseProps<string | null>;
23
32
  export type DateRangePickerProps = DatePickerBaseProps<DateRangeValue> & {
24
33
  withTime?: boolean;
25
34
  datePresets?: readonly DatePreset<string | null>[];
@@ -1,7 +1,7 @@
1
1
  import { type JSX } from "solid-js";
2
2
  import { type ChoiceOption } from "./choice";
3
3
  import type { ValueFieldProps } from "./field-contract";
4
- import type { SelectGroup } from "./Select";
4
+ import type { ChoiceAppearance, SelectGroup } from "./Select";
5
5
  export type MultiSelectOption = string | {
6
6
  id: string;
7
7
  label?: string;
@@ -36,6 +36,10 @@ export type MultiSelectInputProps = ValueFieldProps<string[]> & {
36
36
  emptyLabel?: string;
37
37
  retryLabel?: string;
38
38
  clearLabel?: string;
39
+ /** `plain` shows the selection as wrapping pills without a box; options are removed in the list. */
40
+ appearance?: ChoiceAppearance;
41
+ /** Icon class shown before the placeholder while nothing is selected. */
42
+ placeholderIcon?: string;
39
43
  };
40
44
  export declare function MultiSelectInput(props: MultiSelectInputProps): JSX.Element;
41
45
  export default MultiSelectInput;
@@ -1,5 +1,6 @@
1
1
  import { type JSX } from "solid-js";
2
2
  import type { ValueFieldProps } from "./field-contract";
3
+ import type { ChoiceAppearance } from "./Select";
3
4
  export type NumberInputProps = Omit<JSX.InputHTMLAttributes<HTMLInputElement>, "max" | "min" | "onChange" | "onInput" | "prefix" | "step" | "type" | "value" | keyof ValueFieldProps<number | null>> & ValueFieldProps<number | null> & {
4
5
  max?: number;
5
6
  min?: number;
@@ -21,6 +22,19 @@ export type NumberInputProps = Omit<JSX.InputHTMLAttributes<HTMLInputElement>, "
21
22
  activeIcon?: string;
22
23
  prefix?: JSX.Element;
23
24
  suffix?: JSX.Element;
25
+ /**
26
+ * `plain` edits the value in place for property rows: no box and no steppers
27
+ * or clear button. The field sizes to its text, Enter commits, Escape
28
+ * restores the current value, and clearing the text clears the value. Focus
29
+ * stays in the field.
30
+ */
31
+ appearance?: ChoiceAppearance;
32
+ /**
33
+ * Text for a set value while a plain field is not being edited, such as
34
+ * `90` as "1 h 30 min". It also names the value for assistive technology.
35
+ * The suffix then shows only while editing.
36
+ */
37
+ formatValue?: (value: number) => string;
24
38
  };
25
39
  export declare function NumberInput(props: NumberInputProps): JSX.Element;
26
40
  export default NumberInput;
@@ -0,0 +1,20 @@
1
+ import { type JSX } from "solid-js";
2
+ export type QrScannerError = "denied" | "unavailable";
3
+ export type QrScannerProps = {
4
+ /** Decoded text is untrusted. Return `true` to accept it and stop the camera, `false` to reject it and keep scanning. */
5
+ onResult: (text: string) => boolean;
6
+ /** The page was hidden or left; unmount the scanner. */
7
+ onStop: () => void;
8
+ /** The camera could not start: access was denied, or there is no usable camera. Offer another way in. */
9
+ onError: (reason: QrScannerError) => void;
10
+ /** What to point the camera at. Defaults to a generic QR code hint. */
11
+ instructions?: string;
12
+ class?: string;
13
+ };
14
+ /**
15
+ * Scans a QR code with the rear camera. Each mount owns exactly one camera session, which stops when the scanner
16
+ * unmounts, the page is hidden, or a result is accepted. The scanning engine loads only when the scanner mounts.
17
+ * Decoded content is never logged.
18
+ */
19
+ export declare function QrScanner(props: QrScannerProps): JSX.Element;
20
+ export default QrScanner;
@@ -8,6 +8,13 @@ export type SelectGroup = {
8
8
  };
9
9
  export type SelectView = "list" | "grid";
10
10
  export type SelectGridSize = "sm" | "md" | "lg";
11
+ /**
12
+ * `field` draws the boxed form control. `plain` shows the value as text for
13
+ * property rows: no box, no chevron, and a quiet surface on hover or while
14
+ * open. Its surface and hit area cover the nearest positioned ancestor, such as
15
+ * a `DescriptionList` row, so the whole row opens the picker.
16
+ */
17
+ export type ChoiceAppearance = "field" | "plain";
11
18
  export type SelectSourceOption = string | {
12
19
  id: string;
13
20
  label?: string;
@@ -45,6 +52,9 @@ export type SelectProps = ValueFieldProps<string | null> & {
45
52
  searchPlaceholder?: string;
46
53
  clearable?: boolean;
47
54
  name?: string;
55
+ appearance?: ChoiceAppearance;
56
+ /** Icon class shown before the placeholder while nothing is selected. */
57
+ placeholderIcon?: string;
48
58
  };
49
59
  export declare function Select(props: SelectProps): JSX.Element;
50
60
  export default Select;
@@ -27,7 +27,9 @@ export type { MarkdownEditorProps } from "./markdown/MarkdownEditor";
27
27
  export { MarkdownEditor } from "./markdown/MarkdownEditor";
28
28
  export type { NumberInputProps } from "./NumberInput";
29
29
  export { NumberInput } from "./NumberInput";
30
- export type { SelectGridSize, SelectGroup, SelectOption, SelectProps, SelectSourceOption, SelectView } from "./Select";
30
+ export type { QrScannerError, QrScannerProps } from "./QrScanner";
31
+ export { QrScanner } from "./QrScanner";
32
+ export type { ChoiceAppearance, SelectGridSize, SelectGroup, SelectOption, SelectProps, SelectSourceOption, SelectView } from "./Select";
31
33
  export { Select } from "./Select";
32
34
  export type { SelectChipOption, SelectChipProps } from "./SelectChip";
33
35
  export { SelectChip } from "./SelectChip";
@@ -18,6 +18,7 @@ declare const uiMessages: import("@k2b/stdlib").Catalog<{
18
18
  add: string;
19
19
  addTag: string;
20
20
  addImage: string;
21
+ apply: string;
21
22
  attachments: string;
22
23
  assistant: string;
23
24
  avatarLabel: ({ name }: {
@@ -250,6 +251,7 @@ declare const uiMessages: import("@k2b/stdlib").Catalog<{
250
251
  filterActions: string;
251
252
  info: string;
252
253
  dismissNotification: string;
254
+ notifications: string;
253
255
  interactiveLineChart: string;
254
256
  interactiveChart: string;
255
257
  chartFields: ({ key }: {
@@ -425,6 +427,48 @@ declare const uiMessages: import("@k2b/stdlib").Catalog<{
425
427
  audioUnsupported: string;
426
428
  videoUnsupported: string;
427
429
  yes: string;
430
+ installApp: string;
431
+ installNative: ({ appName }: {
432
+ appName: string;
433
+ }) => string;
434
+ installRequested: string;
435
+ installFailed: string;
436
+ installOpenShare: string;
437
+ installOpenShareDetail: string;
438
+ installHomeScreen: string;
439
+ installHomeScreenDetail: string;
440
+ installConfirmAdd: string;
441
+ installConfirmAddDetail: string;
442
+ installOpenShareBrowserDetail: string;
443
+ installSafariFallback: string;
444
+ installSafariMenu: string;
445
+ installSafariMenuDetail: string;
446
+ installAddDock: string;
447
+ installAddDockDetail: string;
448
+ installBrowserMenu: string;
449
+ installBrowserMenuDetail: string;
450
+ installAndroidDetail: string;
451
+ installBrowserDetail: string;
452
+ installUnavailable: string;
453
+ installAppleInAppTitle: string;
454
+ installAppleInAppDetail: ({ appName }: {
455
+ appName: string;
456
+ }) => string;
457
+ installInAppTitle: string;
458
+ installInAppDetail: ({ appName }: {
459
+ appName: string;
460
+ }) => string;
461
+ installAppleBrowserTitle: string;
462
+ installAppleBrowserDetail: string;
463
+ installAndroidBrowserTitle: string;
464
+ installAndroidBrowserDetail: string;
465
+ installCopyLink: string;
466
+ installLinkCopied: string;
467
+ installCopyFailed: string;
468
+ qrCameraPreview: string;
469
+ qrCameraStarting: string;
470
+ qrCameraInstructions: string;
471
+ qrCameraPrivacy: string;
428
472
  }>;
429
473
  export type UiMessages = ReturnType<(typeof uiMessages)["resolve"]>["t"];
430
474
  /** Generic component chrome owned by @k2b/ui, resolved from the inherited render locale. */
@@ -0,0 +1,40 @@
1
+ import { type JSX } from "solid-js";
2
+ export type MobileShellProps = {
3
+ /** Usually `MobileShell.Header`; it sits above the scroll area and pads the top safe area. */
4
+ header: JSX.Element;
5
+ /** Usually a `TabBar`; it sits below the scroll area and pads the bottom safe area itself. */
6
+ footer?: JSX.Element;
7
+ /** The page content, inside the shell's only scroll area. */
8
+ children: JSX.Element;
9
+ class?: string;
10
+ };
11
+ export type MobileShellHeaderProps = {
12
+ title: string;
13
+ /** A Back control before the title: a link with `href`, otherwise a button. */
14
+ back?: {
15
+ href?: string;
16
+ onClick?: () => void;
17
+ label: string;
18
+ };
19
+ /** Controls after the title, such as a menu. */
20
+ actions?: JSX.Element;
21
+ };
22
+ /**
23
+ * Keeps a mounted shell working: the footer height on the body, which the portalled toast rail reads, the room a
24
+ * persistent toast takes from the scroll area, the scroll area's edge fade, and immediate feedback for link taps.
25
+ * The fade is the only cue at the footer's edge, which has no rule. `MobileShell` calls it itself;
26
+ * a page that renders the shell on the server without hydrating it calls it once in the browser. Returns the
27
+ * cleanup.
28
+ */
29
+ export declare function observeMobileShell(root: HTMLElement): () => void;
30
+ declare function MobileShellRoot(props: MobileShellProps): JSX.Element;
31
+ declare function MobileShellHeader(props: MobileShellHeaderProps): JSX.Element;
32
+ /**
33
+ * The full-screen frame of a phone app: a header, one scroll area, and an optional footer such as a `TabBar`. While
34
+ * it is mounted, the document itself never scrolls, pinch zoom and rubber-banding are off, and the toast rail sits
35
+ * above the footer. Mount one per page, as the page's layout.
36
+ */
37
+ export declare const MobileShell: typeof MobileShellRoot & {
38
+ Header: typeof MobileShellHeader;
39
+ };
40
+ export default MobileShell;
@@ -22,8 +22,8 @@ export type SettingsSectionProps = {
22
22
  class?: string;
23
23
  };
24
24
  /**
25
- * A full-page settings group. Dialogs keep using PanelDialog.Section; this
26
- * component owns the quieter, observability-style paper used on admin pages.
25
+ * A full-page settings group: a heading, optional actions and its fields on the
26
+ * page surface without a card. Dialogs keep using PanelDialog.Section.
27
27
  */
28
28
  export declare function SettingsSection(props: SettingsSectionProps): JSX.Element;
29
29
  export type SettingsGroupProps = {
@@ -0,0 +1,23 @@
1
+ import { type JSX } from "solid-js";
2
+ export type TabBarItem = {
3
+ id: string;
4
+ label: string;
5
+ /** Icon class, for example `ti ti-home`. */
6
+ icon: string;
7
+ href: string;
8
+ /** The page this item leads to is open. */
9
+ current?: boolean;
10
+ };
11
+ export type TabBarProps = {
12
+ /** Accessible name of the navigation landmark. */
13
+ label: string;
14
+ /** Up to five destinations; further items are not rendered. Put the rest behind a "More" destination. */
15
+ items: readonly TabBarItem[];
16
+ class?: string;
17
+ };
18
+ /**
19
+ * Bottom navigation between a phone app's top-level pages: native links with equal widths, an icon above each label,
20
+ * and `aria-current="page"` on the open page. Place it in `MobileShell`'s footer; it pads the bottom safe area.
21
+ */
22
+ export declare function TabBar(props: TabBarProps): JSX.Element;
23
+ export default TabBar;
@@ -15,6 +15,8 @@ export type { DiscussionComposerProps, DiscussionItemProps, DiscussionListProps,
15
15
  export { default as Discussion } from "./Discussion";
16
16
  export type { FloatingWindowClose, FloatingWindowProps, OpenFloatingWindowOptions, } from "./FloatingWindow";
17
17
  export { default as FloatingWindow, type FloatingWindowRect, fitFloatingWindowRect, openFloatingWindow, } from "./FloatingWindow";
18
+ export type { MobileShellHeaderProps, MobileShellProps } from "./MobileShell";
19
+ export { default as MobileShell, observeMobileShell } from "./MobileShell";
18
20
  export { default as Navigation, type NavigationProps } from "./Navigation";
19
21
  export { createNavigation, findNavigationItem, type NavigationController, type NavigationItem, type NavigationOptions, } from "./navigation-model";
20
22
  export type { PanelDialogBodyProps, PanelDialogFooterProps, PanelDialogHeaderProps, PanelDialogProps, PanelDialogSectionProps, PanelDialogSurface, PanelDialogTabOption, PanelDialogTabsProps, } from "./PanelDialog";
@@ -35,3 +37,5 @@ export type { SettingsCollectionActionProps, SettingsCollectionItemActionsProps,
35
37
  export { default as SettingsCollection } from "./SettingsCollection";
36
38
  export type { SettingsModalFooterProps, SettingsModalGroupProps, SettingsModalProps, SettingsModalTabProps, SettingsModalTabTone, } from "./SettingsModal";
37
39
  export { default as SettingsModal } from "./SettingsModal";
40
+ export type { TabBarItem, TabBarProps } from "./TabBar";
41
+ export { default as TabBar } from "./TabBar";
@@ -4,28 +4,28 @@ export type NoticeTone = Extract<IntentTone, "neutral" | "info" | "success" | "w
4
4
  type NoticeCardContentProps = {
5
5
  title: JSX.Element;
6
6
  detail?: JSX.Element;
7
+ meta?: JSX.Element;
7
8
  children?: JSX.Element;
8
9
  } | {
9
10
  title?: never;
10
11
  detail?: never;
12
+ meta?: never;
11
13
  children: JSX.Element;
12
14
  };
13
15
  export type NoticeCardProps = Omit<JSX.HTMLAttributes<HTMLElement>, "children" | "class" | "title"> & NoticeCardContentProps & {
14
16
  tone?: NoticeTone;
15
- icon?: string | false;
16
17
  class?: string;
17
18
  bodyClass?: string;
18
19
  };
19
20
  export declare const NOTICE_CARD_CLASSES: {
20
21
  readonly root: "k2b-notice-card";
21
- readonly inner: "k2b-notice-card__inner";
22
- readonly icon: "k2b-notice-card__icon";
23
22
  readonly content: "k2b-notice-card__content";
23
+ readonly head: "k2b-notice-card__head";
24
24
  readonly title: "k2b-notice-card__title";
25
+ readonly meta: "k2b-notice-card__meta";
25
26
  readonly description: "k2b-notice-card__description";
26
27
  readonly body: "k2b-notice-card__body";
27
28
  };
28
- export declare const NOTICE_CARD_ICONS: Readonly<Record<NoticeTone, string>>;
29
29
  declare function NoticeCardComponent(props: NoticeCardProps): JSX.Element;
30
30
  export type NoticeGridProps<T> = {
31
31
  items: readonly T[];
@@ -7,7 +7,7 @@ export { LinkCard } from "./LinkCard";
7
7
  export type { NotFoundStateAction, NotFoundStateProps } from "./NotFoundState";
8
8
  export { NotFoundState } from "./NotFoundState";
9
9
  export type { NoticeCardProps, NoticeGridProps, NoticeTone } from "./NoticeCard";
10
- export { NOTICE_CARD_CLASSES, NOTICE_CARD_ICONS, NoticeCard } from "./NoticeCard";
10
+ export { NOTICE_CARD_CLASSES, NoticeCard } from "./NoticeCard";
11
11
  export type { PaperProps, PaperTag } from "./Paper";
12
12
  export { Paper } from "./Paper";
13
13
  export type { PlaceholderAlign, PlaceholderProps, PlaceholderState, PlaceholderSurface, PlaceholderVariant, } from "./Placeholder";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k2b/ui",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "Production-ready components for SolidJS applications.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -46,7 +46,8 @@
46
46
  "@fontsource/ibm-plex-sans": "5.3.0",
47
47
  "@k2b/stdlib": "0.27.0",
48
48
  "@tabler/icons-webfont": "3.48.0",
49
- "marked": "18.0.14"
49
+ "marked": "18.0.14",
50
+ "qr-scanner": "1.4.2"
50
51
  },
51
52
  "peerDependencies": {
52
53
  "@k2b/ssr": "^0.12.0 || ^0.13.0 || ^0.14.0",