@k2b/ui 0.45.0 → 0.47.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 (121) 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/ViewTabs.js +225 -93
  6. package/dist/browser/actions/ViewTabs.js.map +1 -1
  7. package/dist/browser/chat/ChatDecision.js +10 -6
  8. package/dist/browser/chat/ChatDecision.js.map +1 -1
  9. package/dist/browser/content/FileGrid.js +125 -99
  10. package/dist/browser/content/FileGrid.js.map +1 -1
  11. package/dist/browser/content/VirtualFeed.js +26 -21
  12. package/dist/browser/content/VirtualFeed.js.map +1 -1
  13. package/dist/browser/inputs/Combobox.js +14 -6
  14. package/dist/browser/inputs/Combobox.js.map +1 -1
  15. package/dist/browser/inputs/choice.js +36 -9
  16. package/dist/browser/inputs/choice.js.map +1 -1
  17. package/dist/browser/layout/AnchoredPopover.js +2 -1
  18. package/dist/browser/layout/AnchoredPopover.js.map +1 -1
  19. package/dist/browser/layout/AppWorkspace.js +348 -444
  20. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  21. package/dist/browser/layout/AppWorkspaceSidebarItemStatus.js +113 -0
  22. package/dist/browser/layout/AppWorkspaceSidebarItemStatus.js.map +1 -0
  23. package/dist/browser/layout/DetailPanel.js +130 -108
  24. package/dist/browser/layout/DetailPanel.js.map +1 -1
  25. package/dist/browser/layout/DetailSections.js +1123 -0
  26. package/dist/browser/layout/DetailSections.js.map +1 -0
  27. package/dist/browser/layout/DetailsToggle.js +32 -0
  28. package/dist/browser/layout/DetailsToggle.js.map +1 -0
  29. package/dist/browser/layout/Discussion.js +3 -0
  30. package/dist/browser/layout/Discussion.js.map +1 -1
  31. package/dist/browser/layout/MobileShell.js +141 -102
  32. package/dist/browser/layout/MobileShell.js.map +1 -1
  33. package/dist/browser/layout/PageTitle.js +33 -10
  34. package/dist/browser/layout/PageTitle.js.map +1 -1
  35. package/dist/browser/layout/app-workspace-controller.js +12 -0
  36. package/dist/browser/layout/app-workspace-controller.js.map +1 -1
  37. package/dist/browser/layout/detail-sections-messages.js +127 -0
  38. package/dist/browser/layout/detail-sections-messages.js.map +1 -0
  39. package/dist/browser/layout/index.js +3 -0
  40. package/dist/browser/layout/index.js.map +1 -1
  41. package/dist/browser/surfaces/Avatar.js +3 -1
  42. package/dist/browser/surfaces/Avatar.js.map +1 -1
  43. package/dist/browser/surfaces/AvatarStack.js +95 -61
  44. package/dist/browser/surfaces/AvatarStack.js.map +1 -1
  45. package/dist/browser/surfaces/ChangeList.js +77 -0
  46. package/dist/browser/surfaces/ChangeList.js.map +1 -0
  47. package/dist/browser/surfaces/index.js +2 -1
  48. package/dist/browser/surfaces/index.js.map +1 -1
  49. package/dist/browser/text-editor/TextEditor.js +19 -8
  50. package/dist/browser/text-editor/TextEditor.js.map +1 -1
  51. package/dist/ssr/actions/Dropdown.js +6 -0
  52. package/dist/ssr/actions/Dropdown.js.map +1 -1
  53. package/dist/ssr/actions/FilterChip.js +1 -1
  54. package/dist/ssr/actions/FilterChip.js.map +1 -1
  55. package/dist/ssr/actions/ViewTabs.js +144 -37
  56. package/dist/ssr/actions/ViewTabs.js.map +1 -1
  57. package/dist/ssr/chat/ChatDecision.js +10 -6
  58. package/dist/ssr/chat/ChatDecision.js.map +1 -1
  59. package/dist/ssr/content/FileGrid.js +36 -22
  60. package/dist/ssr/content/FileGrid.js.map +1 -1
  61. package/dist/ssr/content/VirtualFeed.js +26 -21
  62. package/dist/ssr/content/VirtualFeed.js.map +1 -1
  63. package/dist/ssr/inputs/Combobox.js +6 -3
  64. package/dist/ssr/inputs/Combobox.js.map +1 -1
  65. package/dist/ssr/inputs/choice.js +36 -9
  66. package/dist/ssr/inputs/choice.js.map +1 -1
  67. package/dist/ssr/layout/AnchoredPopover.js +2 -1
  68. package/dist/ssr/layout/AnchoredPopover.js.map +1 -1
  69. package/dist/ssr/layout/AppWorkspace.js +66 -132
  70. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  71. package/dist/ssr/layout/AppWorkspaceSidebarItemStatus.js +76 -0
  72. package/dist/ssr/layout/AppWorkspaceSidebarItemStatus.js.map +1 -0
  73. package/dist/ssr/layout/DetailPanel.js +18 -1
  74. package/dist/ssr/layout/DetailPanel.js.map +1 -1
  75. package/dist/ssr/layout/DetailSections.js +838 -0
  76. package/dist/ssr/layout/DetailSections.js.map +1 -0
  77. package/dist/ssr/layout/DetailsToggle.js +29 -0
  78. package/dist/ssr/layout/DetailsToggle.js.map +1 -0
  79. package/dist/ssr/layout/Discussion.js +3 -0
  80. package/dist/ssr/layout/Discussion.js.map +1 -1
  81. package/dist/ssr/layout/MobileShell.js +60 -29
  82. package/dist/ssr/layout/MobileShell.js.map +1 -1
  83. package/dist/ssr/layout/PageTitle.js +29 -6
  84. package/dist/ssr/layout/PageTitle.js.map +1 -1
  85. package/dist/ssr/layout/app-workspace-controller.js +12 -0
  86. package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
  87. package/dist/ssr/layout/detail-sections-messages.js +127 -0
  88. package/dist/ssr/layout/detail-sections-messages.js.map +1 -0
  89. package/dist/ssr/layout/index.js +3 -0
  90. package/dist/ssr/layout/index.js.map +1 -1
  91. package/dist/ssr/surfaces/Avatar.js +3 -1
  92. package/dist/ssr/surfaces/Avatar.js.map +1 -1
  93. package/dist/ssr/surfaces/AvatarStack.js +61 -32
  94. package/dist/ssr/surfaces/AvatarStack.js.map +1 -1
  95. package/dist/ssr/surfaces/ChangeList.js +37 -0
  96. package/dist/ssr/surfaces/ChangeList.js.map +1 -0
  97. package/dist/ssr/surfaces/index.js +2 -1
  98. package/dist/ssr/surfaces/index.js.map +1 -1
  99. package/dist/ssr/text-editor/TextEditor.js +19 -8
  100. package/dist/ssr/text-editor/TextEditor.js.map +1 -1
  101. package/dist/styles.css +1 -1
  102. package/dist/types/actions/FilterChip.d.ts +4 -0
  103. package/dist/types/actions/ViewTabs.d.ts +11 -1
  104. package/dist/types/chat/ChatDecision.d.ts +5 -0
  105. package/dist/types/content/FileGrid.d.ts +6 -0
  106. package/dist/types/inputs/Combobox.d.ts +2 -0
  107. package/dist/types/inputs/choice.d.ts +9 -3
  108. package/dist/types/layout/AppWorkspace.d.ts +2 -28
  109. package/dist/types/layout/AppWorkspaceSidebarItemStatus.d.ts +30 -0
  110. package/dist/types/layout/DetailPanel.d.ts +9 -0
  111. package/dist/types/layout/DetailSections.d.ts +186 -0
  112. package/dist/types/layout/DetailsToggle.d.ts +13 -0
  113. package/dist/types/layout/MobileShell.d.ts +12 -0
  114. package/dist/types/layout/PageTitle.d.ts +7 -0
  115. package/dist/types/layout/detail-sections-messages.d.ts +61 -0
  116. package/dist/types/layout/index.d.ts +5 -1
  117. package/dist/types/surfaces/Avatar.d.ts +3 -0
  118. package/dist/types/surfaces/AvatarStack.d.ts +20 -1
  119. package/dist/types/surfaces/ChangeList.d.ts +20 -0
  120. package/dist/types/surfaces/index.d.ts +5 -3
  121. 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
  };
@@ -19,6 +19,11 @@ export type ChatDecisionProps = {
19
19
  remember?: ChatDecisionAnswer;
20
20
  /** Turns `confirm` and `remember` off; this reason replaces `reason` in the same place. */
21
21
  unavailable?: ChatDecisionReason;
22
+ /**
23
+ * Turns every answer off until the reason clears, such as no connection, so no answer is lost on the way; this
24
+ * reason replaces `reason` and `unavailable` in the same place.
25
+ */
26
+ waiting?: ChatDecisionReason;
22
27
  /** The result line shown in every state but `open`, usually `Chat.Outcome`. */
23
28
  outcome?: JSX.Element;
24
29
  /** Receives a rejected promise from an answer's `onSelect`. */
@@ -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. */
@@ -5,6 +5,8 @@ export type ComboboxOption = {
5
5
  label: string;
6
6
  description?: string;
7
7
  icon?: string;
8
+ /** Shown but cannot be picked, such as someone who is already on the list; say why in `description`. */
9
+ disabled?: boolean;
8
10
  };
9
11
  export type ComboboxProps = FieldProps & {
10
12
  readOnly?: boolean;
@@ -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>;
@@ -1,3 +1,5 @@
1
+ import { type AppWorkspaceSidebarItemStatusProps } from "./AppWorkspaceSidebarItemStatus";
2
+ export type { AppWorkspaceSidebarItemStatusProps } from "./AppWorkspaceSidebarItemStatus";
1
3
  import { type LinkNavigateEvent, type NavigationScrollMode } from "@k2b/ssr/nav";
2
4
  import { type JSX } from "solid-js";
3
5
  import { type AppWorkspaceLayoutState } from "./app-workspace-state";
@@ -361,34 +363,6 @@ export type AppWorkspaceSidebarItemActionsProps = {
361
363
  children: JSX.Element;
362
364
  visibility?: AppWorkspaceSidebarAccessoryVisibility;
363
365
  };
364
- /**
365
- * Unread state for the trailing `meta` slot. Every mark keeps a fixed width,
366
- * so the row keeps its height and the label its start in every state.
367
- */
368
- export type AppWorkspaceSidebarItemStatusProps = {
369
- /**
370
- * A positive number shows a count (above 99 as "99+") and sets the label in
371
- * a stronger weight; `true` shows a quiet dot for new activity that should
372
- * not draw attention, such as in a muted conversation.
373
- */
374
- unread?: number | boolean;
375
- /** Marks unread items that mention the person with "@". */
376
- mention?: boolean;
377
- /**
378
- * Shows a muted bell, and the item reads as set aside: its label in the muted ink without unread weight, and a
379
- * mention count without its fill.
380
- */
381
- muted?: boolean;
382
- /**
383
- * Items that wait for the person, such as requests to approve, in the unread slot instead of `unread`. `label` is
384
- * the phrase a screen reader hears, for example "3 waiting". `0` stays as a muted count, for a count that dropped
385
- * to zero while the row is still shown; leave the prop out when nothing waits.
386
- */
387
- waiting?: {
388
- count: number;
389
- label: string;
390
- };
391
- };
392
366
  export type AppWorkspaceNavTreeProps = {
393
367
  children: JSX.Element;
394
368
  ariaLabel: string;
@@ -0,0 +1,30 @@
1
+ import { type JSX } from "solid-js";
2
+ /**
3
+ * Unread state for the trailing `meta` slot. Every mark keeps a fixed width,
4
+ * so the row keeps its height and the label its start in every state.
5
+ */
6
+ export type AppWorkspaceSidebarItemStatusProps = {
7
+ /**
8
+ * A positive number shows a count (above 99 as "99+") and sets the label in
9
+ * a stronger weight; `true` shows a quiet dot for new activity that should
10
+ * not draw attention, such as in a muted conversation.
11
+ */
12
+ unread?: number | boolean;
13
+ /** Marks unread items that mention the person with "@". */
14
+ mention?: boolean;
15
+ /**
16
+ * Shows a muted bell, and the item reads as set aside: its label in the muted ink without unread weight, and a
17
+ * mention count without its fill.
18
+ */
19
+ muted?: boolean;
20
+ /**
21
+ * Items that wait for the person, such as requests to approve, in the unread slot instead of `unread`. `label` is
22
+ * the phrase a screen reader hears, for example "3 waiting". `0` stays as a muted count, for a count that dropped
23
+ * to zero while the row is still shown; leave the prop out when nothing waits.
24
+ */
25
+ waiting?: {
26
+ count: number;
27
+ label: string;
28
+ };
29
+ };
30
+ export declare const AppWorkspaceSidebarItemStatus: (props: AppWorkspaceSidebarItemStatusProps) => JSX.Element;
@@ -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: {
@@ -0,0 +1,186 @@
1
+ import { type JSX } from "solid-js";
2
+ import type { DropdownItem } from "../actions/Dropdown";
3
+ import { type AvatarShape } from "../surfaces/Avatar";
4
+ export type DetailPresencePerson = {
5
+ /** Stable key, such as the account id. */
6
+ id: string;
7
+ name: string;
8
+ /** A shorter name for the chip and the line below it, such as the first name. Defaults to `name`. */
9
+ shortName?: string;
10
+ src?: string | null;
11
+ icon?: string;
12
+ /** `square` for agents and service accounts. */
13
+ shape?: AvatarShape;
14
+ /** The person's color, the same as their cursor and comments. Defaults to `personColor(name)`. */
15
+ color?: string;
16
+ /** Writing shows a pen and the person's place; reading shows an eye. */
17
+ activity?: "writing" | "reading";
18
+ /** Where the person is, such as the heading of the section they write in. */
19
+ place?: string;
20
+ /** Short text at the end of the person's row in the full list, such as "2 tabs". */
21
+ trailing?: JSX.Element;
22
+ /** Goes to the person's place. */
23
+ onSelect?: () => void;
24
+ /** The person viewing: the fixed "You" chip at the end, never one of the others. */
25
+ self?: boolean;
26
+ };
27
+ /** `offline` keeps the last known people, pale and without live dots; `unavailable` offers `onRetry`. */
28
+ export type DetailPresenceState = "live" | "loading" | "offline" | "unavailable";
29
+ export type DetailPresenceProps = {
30
+ people: readonly DetailPresencePerson[];
31
+ state?: DetailPresenceState;
32
+ /**
33
+ * The quiet line below the people when it does not say who writes where: alone ("Whoever opens the note appears
34
+ * here"), offline ("Offline · as of 19:24"), or unavailable ("Your changes are still being saved").
35
+ */
36
+ note?: JSX.Element;
37
+ onRetry?: () => void;
38
+ /** One control at the end of the title row, such as "Copy link". */
39
+ actions?: JSX.Element;
40
+ /** Defaults to "Here now". */
41
+ title?: string;
42
+ /** One quiet line below the full list. */
43
+ listHint?: JSX.Element;
44
+ class?: string;
45
+ };
46
+ /**
47
+ * "Here now": who has the object open, what they do, and where. Always two lines tall in every state, so people
48
+ * coming, going, or moving never shift the panel. Chips that do not fit wrap into a hidden line and count as "+n";
49
+ * "+n" and "You" open the full list, which `AvatarStack` shows beside it or as a sheet on phones.
50
+ */
51
+ export declare function DetailPresence(props: DetailPresenceProps): JSX.Element;
52
+ /** A fixed slot at the end of a row for the people working there, such as an outline heading. Always the same width. */
53
+ export declare function DetailPresenceSlot(props: {
54
+ people: readonly DetailPresencePerson[];
55
+ max?: number;
56
+ }): JSX.Element;
57
+ export type DetailAccessEntry = {
58
+ id: string;
59
+ name: string;
60
+ /** Sets the avatar: a person's picture or initials, a group, a service, all signed-in people, or public. */
61
+ kind?: "person" | "group" | "service" | "everyone" | "public";
62
+ src?: string | null;
63
+ /** One quiet word after the name, such as "Service". */
64
+ detail?: JSX.Element;
65
+ /** The role in words, such as "Can edit". */
66
+ role: JSX.Element;
67
+ /** The person viewing; listed as "You". */
68
+ self?: boolean;
69
+ };
70
+ export type DetailAccessProps = {
71
+ entries: readonly DetailAccessEntry[];
72
+ state?: "ready" | "loading" | "error";
73
+ onRetry?: () => void;
74
+ /** Rows before "Show n more". Defaults to 5. */
75
+ limit?: number;
76
+ /** A way to change access, only for people who may; others read the list. */
77
+ manage?: {
78
+ label: string;
79
+ href?: string;
80
+ onClick?: () => void;
81
+ };
82
+ /** A quiet line below the list, such as "Applies to the whole notebook". */
83
+ note?: JSX.Element;
84
+ /** Defaults to "Access". */
85
+ title?: string;
86
+ defaultOpen?: boolean;
87
+ open?: boolean;
88
+ onOpenChange?: (open: boolean) => void;
89
+ class?: string;
90
+ };
91
+ /**
92
+ * Who has access and with which role, read-only. Closed it names the first entries; open it lists `limit` rows and
93
+ * "Show n more". A list that may load later passes `state="loading"` and keeps its place.
94
+ */
95
+ export declare function DetailAccess(props: DetailAccessProps): JSX.Element;
96
+ export type DetailLinkItem = {
97
+ id: string;
98
+ title: string;
99
+ href?: string;
100
+ onClick?: (event: MouseEvent) => void;
101
+ /** Defaults to a document. */
102
+ icon?: string;
103
+ /** Replaces the icon, such as a site's favicon. */
104
+ leading?: JSX.Element;
105
+ /** One quiet line below the title, such as where the item lives. */
106
+ description?: JSX.Element;
107
+ /** Quiet text at the end, such as the other notebook's name. */
108
+ trailing?: JSX.Element;
109
+ /** For a link to another site, such as `_blank` with `rel="noreferrer"`. */
110
+ target?: string;
111
+ rel?: string;
112
+ /** An item that cannot be opened right now, such as one the person may no longer read. */
113
+ disabled?: boolean;
114
+ } & ({
115
+ menuItems?: never;
116
+ menuLabel?: never;
117
+ } | {
118
+ /** Further commands on the item, such as "Unlink", only for people who may run them. */
119
+ menuItems: readonly DropdownItem[];
120
+ menuLabel: string;
121
+ });
122
+ export type DetailLinksProps = {
123
+ /** What links here. */
124
+ incoming: readonly DetailLinkItem[];
125
+ /** What this object links to. */
126
+ outgoing: readonly DetailLinkItem[];
127
+ /** Rows per direction before "Show n more". Defaults to 5. */
128
+ limit?: number;
129
+ /** Defaults to "Links". */
130
+ title?: string;
131
+ defaultOpen?: boolean;
132
+ /**
133
+ * `loading` while links still load after the first paint: a placeholder row keeps their place. `error` keeps the
134
+ * loaded rows and says that the rest failed, with `onRetry`.
135
+ */
136
+ state?: "ready" | "loading" | "error";
137
+ onRetry?: () => void;
138
+ /** Rows after the links, such as "Add link" or "Load more", only for people who may use them. */
139
+ footer?: JSX.Element;
140
+ class?: string;
141
+ };
142
+ /**
143
+ * "Linked from" and "Links to" in one section. Without links it is one row: the title and "None yet", followed by the
144
+ * `footer` when there is one.
145
+ */
146
+ export declare function DetailLinks(props: DetailLinksProps): JSX.Element;
147
+ export type DetailProperty = {
148
+ id: string;
149
+ label: JSX.Element;
150
+ value: JSX.Element;
151
+ /** An avatar or icon before the value. */
152
+ leading?: JSX.Element;
153
+ /** Makes the value a link, such as "23 versions" to the version history. */
154
+ href?: string;
155
+ };
156
+ export type DetailPropertiesProps = {
157
+ items: readonly DetailProperty[];
158
+ /** Defaults to "Properties". */
159
+ title?: string;
160
+ icon?: string;
161
+ /** One line for the closed section, such as "412 words · created 12 March by Jana Berger". */
162
+ summary?: JSX.Element;
163
+ /** Open by default only when the properties are the object's main content. */
164
+ defaultOpen?: boolean;
165
+ /** Rows after the facts, such as a command that copies the object's ID. */
166
+ children?: JSX.Element;
167
+ class?: string;
168
+ };
169
+ /** Facts about the object as label and value rows, such as created, edited, size, and the way to its history. */
170
+ export declare function DetailProperties(props: DetailPropertiesProps): JSX.Element;
171
+ export type DetailTag = {
172
+ id: string;
173
+ label: string;
174
+ /** Where the tag leads, such as everything with that tag. */
175
+ href?: string;
176
+ };
177
+ export type DetailTagsProps = {
178
+ tags: readonly DetailTag[];
179
+ /** Defaults to "Tags". */
180
+ title?: string;
181
+ /** Shown without tags, such as how to add one. */
182
+ emptyHint?: JSX.Element;
183
+ class?: string;
184
+ };
185
+ /** The object's tags as chips; a chip with `href` leads to everything with that tag. */
186
+ export declare function DetailTags(props: DetailTagsProps): JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { type JSX } from "solid-js";
2
+ import { type IconButtonProps } from "../actions/Button";
3
+ /** The one icon for "Details" in every app: a circle, so it never reads as the side panel's rectangle with an arrow. */
4
+ export declare const DETAILS_ICON = "ti ti-info-circle";
5
+ export type DetailsToggleProps = Omit<IconButtonProps, "children" | "variant"> & {
6
+ /** Extra classes for the glyph, such as a text size in a dense toolbar. */
7
+ iconClass?: string;
8
+ };
9
+ /**
10
+ * An icon-only Details button for an app's own toolbar or reader head. It shows the selection fill while its panel
11
+ * is open (`aria-expanded="true"`), without a border or shadow, like `AppWorkspace.Detail`'s own button.
12
+ */
13
+ export declare function DetailsToggle(props: DetailsToggleProps): JSX.Element;
@@ -18,6 +18,12 @@ export type MobileShellProps = {
18
18
  * tab's page loads.
19
19
  */
20
20
  scroll?: boolean;
21
+ /**
22
+ * The content is a screen of its own, such as an open chat on a phone: the footer steps aside, so the content
23
+ * reaches the bottom edge and pads its safe area itself. Content that opens or leaves such a screen in place calls
24
+ * `MobileShell.setScreen`.
25
+ */
26
+ screen?: boolean;
21
27
  class?: string;
22
28
  };
23
29
  export type MobileShellHeaderProps = {
@@ -37,6 +43,11 @@ export type MobileShellHeaderProps = {
37
43
  /** Controls after the title, such as a menu. */
38
44
  actions?: JSX.Element;
39
45
  };
46
+ /**
47
+ * Marks the shell around `from` as showing a screen of its own, or not, after the first paint; the server renders
48
+ * the first state with the `screen` prop. Does nothing outside a shell.
49
+ */
50
+ declare const setMobileShellScreen: (from: Element, screen: boolean) => void;
40
51
  /**
41
52
  * Keeps a mounted shell working: the footer height on the body, which the portalled toast rail reads, the room a
42
53
  * persistent toast takes from the scroll area, the scroll area's edge fade, and immediate feedback for link taps.
@@ -86,5 +97,6 @@ declare function MobileShellSidebar(props: MobileShellSidebarProps): JSX.Element
86
97
  export declare const MobileShell: typeof MobileShellRoot & {
87
98
  Header: typeof MobileShellHeader;
88
99
  Sidebar: typeof MobileShellSidebar;
100
+ setScreen: typeof setMobileShellScreen;
89
101
  };
90
102
  export default MobileShell;
@@ -38,9 +38,16 @@ export declare const setPageTrail: (trail: PageTrailState) => void;
38
38
  * the context carries it; the provider also publishes it into the document,
39
39
  * where browser-rendered parts such as islands read it. Below a provider that
40
40
  * renders in the browser, its `trail` prop is the source: update the prop.
41
+ *
42
+ * `onOwnTitle` runs on the server for each `PageTitle` below that is not a
43
+ * fallback. The host then sets `data-k2b-own-title` on an element around the
44
+ * page, inside the `k2b-ui` root, so the chrome's fallback titles step back.
45
+ * With `data-k2b-title-host` on that element, titles that mount or leave in
46
+ * the browser keep the attribute current.
41
47
  */
42
48
  export declare function PageTrailProvider(props: {
43
49
  trail: PageTrailState | undefined;
50
+ onOwnTitle?: () => void;
44
51
  children: JSX.Element;
45
52
  }): JSX.Element;
46
53
  /** The host's page trail: from the provider while rendering below it, otherwise from the document. */
@@ -0,0 +1,61 @@
1
+ /** Titles and sentences of the shared detail sections: presence, access, links, properties, and tags. */
2
+ declare const detailSectionMessages: import("@k2b/stdlib").Catalog<{
3
+ hereNow: string;
4
+ onlyYou: string;
5
+ you: string;
6
+ writesIn: string;
7
+ writing: string;
8
+ reading: string;
9
+ readingAlong: ({ names, count }: {
10
+ names: string;
11
+ count: number;
12
+ }) => string;
13
+ and: string;
14
+ jumpTo: ({ name, place }: {
15
+ name: string;
16
+ place: string;
17
+ }) => string;
18
+ personWriting: ({ name, place }: {
19
+ name: string;
20
+ place: string;
21
+ }) => string;
22
+ personReading: ({ name }: {
23
+ name: string;
24
+ }) => string;
25
+ everyoneHere: ({ count }: {
26
+ count: number;
27
+ }) => string;
28
+ presenceLoading: string;
29
+ presenceUnavailable: string;
30
+ retry: string;
31
+ access: string;
32
+ accessLoading: string;
33
+ accessFailed: string;
34
+ accessSummary: ({ names, more }: {
35
+ names: string;
36
+ more: number;
37
+ }) => string;
38
+ links: string;
39
+ linkedBy: ({ count }: {
40
+ count: number;
41
+ }) => string;
42
+ linksTo: ({ count }: {
43
+ count: number;
44
+ }) => string;
45
+ linkedBySummary: ({ names, more }: {
46
+ names: string;
47
+ more: number;
48
+ }) => string;
49
+ linksToSummary: ({ names, more }: {
50
+ names: string;
51
+ more: number;
52
+ }) => string;
53
+ linksLoading: string;
54
+ linksFailed: string;
55
+ properties: string;
56
+ tags: string;
57
+ }>;
58
+ export type DetailSectionMessages = ReturnType<(typeof detailSectionMessages)["resolve"]>["t"];
59
+ export declare const useDetailSectionMessages: () => (() => DetailSectionMessages);
60
+ export declare const checkDetailSectionMessages: () => import("@k2b/stdlib").CatalogIssue[];
61
+ export {};
@@ -3,6 +3,7 @@ export type { AppOverviewCardsProps, AppOverviewEmptyStateProps, AppOverviewPane
3
3
  export { default as AppOverview } from "./AppOverview";
4
4
  export type { AppWorkspaceBottomDrawerHeight, AppWorkspaceBottomDrawerProps, AppWorkspaceContentProps, AppWorkspaceDetailProps, AppWorkspaceDetailWidth, AppWorkspaceHeadProps, AppWorkspaceMainPaneProps, AppWorkspaceMainProps, AppWorkspaceNavTreeItemProps, AppWorkspaceNavTreeMove, AppWorkspaceNavTreeProps, AppWorkspaceProps, AppWorkspaceSidebarAccessoryVisibility, AppWorkspaceSidebarBodyProps, AppWorkspaceSidebarIconActionProps, AppWorkspaceSidebarIconActionTone, AppWorkspaceSidebarIconGridProps, AppWorkspaceSidebarItemActionProps, AppWorkspaceSidebarItemActionsProps, AppWorkspaceSidebarItemIconProps, AppWorkspaceSidebarItemLabelProps, AppWorkspaceSidebarItemMetaProps, AppWorkspaceSidebarItemProps, AppWorkspaceSidebarItemStatusProps, AppWorkspaceSidebarItemTone, AppWorkspaceSidebarProps, AppWorkspaceSidebarSectionProps, AppWorkspaceSidebarVisibility, AppWorkspaceWidthShare, } from "./AppWorkspace";
5
5
  export { appWorkspaceDetailElementId, default as AppWorkspace } from "./AppWorkspace";
6
+ export { AppWorkspaceSidebarItemStatus } from "./AppWorkspaceSidebarItemStatus";
6
7
  export { watchAppHostWidth } from "./app-host-width";
7
8
  export type { AppWorkspaceControllerOptions } from "./app-workspace-controller";
8
9
  export { installAppWorkspaceController, parkWorkspaceDetailDrawers } from "./app-workspace-controller";
@@ -11,8 +12,11 @@ export { APP_WORKSPACE_DETAIL_DEFAULT, APP_WORKSPACE_DETAIL_MAX, APP_WORKSPACE_D
11
12
  export { type BottomSheetProps, bottomSheetAdaptiveOptions, bottomSheetOptions, default as BottomSheet } from "./BottomSheet";
12
13
  export type { DataPanelProps } from "./DataPanel";
13
14
  export { DataPanel } from "./DataPanel";
14
- export type { DetailPanelActionButtonProps, DetailPanelActionLinkProps, DetailPanelActionProps, DetailPanelActionSecondary, DetailPanelBodyProps, DetailPanelGroupProps, DetailPanelHeaderProps, DetailPanelProps, DetailPanelSectionProps, DetailPanelSummaryProps, DetailPanelTone, } from "./DetailPanel";
15
+ export type { DetailPanelActionButtonProps, DetailPanelActionLinkProps, DetailPanelActionProps, DetailPanelActionSecondary, DetailPanelBodyProps, DetailPanelGroupProps, DetailPanelHeaderProps, DetailPanelProps, DetailPanelRowProps, DetailPanelSectionProps, DetailPanelSummaryProps, DetailPanelTone, } from "./DetailPanel";
15
16
  export { default as DetailPanel } from "./DetailPanel";
17
+ export type { DetailAccessEntry, DetailAccessProps, DetailLinkItem, DetailLinksProps, DetailPresencePerson, DetailPresenceProps, DetailPresenceState, DetailPropertiesProps, DetailProperty, DetailTag, DetailTagsProps, } from "./DetailSections";
18
+ export { DetailAccess, DetailLinks, DetailPresence, DetailPresenceSlot, DetailProperties, DetailTags } from "./DetailSections";
19
+ export { DETAILS_ICON, DetailsToggle, type DetailsToggleProps } from "./DetailsToggle";
16
20
  export type { DiscussionComposerProps, DiscussionItemProps, DiscussionListProps, DiscussionProps } from "./Discussion";
17
21
  export { default as Discussion } from "./Discussion";
18
22
  export type { FloatingWindowClose, FloatingWindowProps, OpenFloatingWindowOptions, } from "./FloatingWindow";
@@ -9,6 +9,8 @@ export type AvatarRing = "success" | {
9
9
  };
10
10
  /** `square` marks an agent or service account; people stay round. */
11
11
  export type AvatarShape = "circle" | "square";
12
+ /** `person` tints initials and icons by name; `neutral` keeps them gray, such as for someone outside the team. */
13
+ export type AvatarTone = "person" | "neutral";
12
14
  export type AvatarProps = {
13
15
  name: string;
14
16
  src?: string | null;
@@ -19,6 +21,7 @@ export type AvatarProps = {
19
21
  /** Draws a ring with a small transparent gap inside the avatar's own box, so the avatar keeps its size and no container clips the ring. */
20
22
  ring?: AvatarRing;
21
23
  shape?: AvatarShape;
24
+ tone?: AvatarTone;
22
25
  loading?: "eager" | "lazy";
23
26
  class?: string;
24
27
  style?: JSX.CSSProperties | string;
@@ -1,5 +1,5 @@
1
1
  import { type JSX } from "solid-js";
2
- import { type AvatarShape } from "./Avatar";
2
+ import { type AvatarShape, type AvatarTone } from "./Avatar";
3
3
  export type AvatarStackPerson = {
4
4
  /** Stable key, such as the account id. */
5
5
  id: string;
@@ -32,8 +32,27 @@ export type AvatarStackProps = {
32
32
  hint?: JSX.Element;
33
33
  /** Faces before "+n". Defaults to 3. */
34
34
  max?: number;
35
+ /** What the button shows instead of the faces, such as a "+n" chip and the viewer's own chip. */
36
+ trigger?: JSX.Element;
35
37
  class?: string;
36
38
  };
39
+ export type AvatarFacesPerson = Pick<AvatarStackPerson, "name" | "src" | "icon" | "shape"> & {
40
+ tone?: AvatarTone;
41
+ };
42
+ export type AvatarFacesProps = {
43
+ people: readonly AvatarFacesPerson[];
44
+ /** Faces before "+n". Defaults to 3. */
45
+ max?: number;
46
+ /** Everyone the faces stand for when `people` lists only some of them; "+n" counts the rest. */
47
+ total?: number;
48
+ /** `sm` (default) matches the stack button; `md` suits a row or table cell whose text the faces stand beside. */
49
+ size?: "sm" | "md";
50
+ };
51
+ /**
52
+ * The stack's faces and "+n" without its button or list, for a row or link that is already interactive. The faces
53
+ * are decorative: name the people in the surrounding label or a tooltip.
54
+ */
55
+ export declare function AvatarFaces(props: AvatarFacesProps): JSX.Element;
37
56
  /**
38
57
  * A few overlapping faces, then "+n", as one button. It opens the full list of people beside it, or as a bottom sheet
39
58
  * on phones. People with `self` are listed last and never shown in the stack.
@@ -0,0 +1,20 @@
1
+ import { type JSX } from "solid-js";
2
+ /** `add` gains something, `change` alters it, `remove` takes it away, `neutral` names a setting. */
3
+ export type ChangeTone = "add" | "change" | "remove" | "neutral" | "warning";
4
+ export type ChangeListItem = {
5
+ tone: ChangeTone;
6
+ /** A Tabler icon class; defaults to plus, arrows or minus by tone. */
7
+ icon?: string;
8
+ content: JSX.Element;
9
+ /** One quiet line under the content, such as what the change means for others. */
10
+ detail?: JSX.Element;
11
+ };
12
+ export type ChangeListProps = {
13
+ items: readonly ChangeListItem[];
14
+ /** Names the list for assistive technology, such as "What changes". */
15
+ label: string;
16
+ class?: string;
17
+ };
18
+ /** Pending changes before they are saved, one line each, so a person can check them in one look. */
19
+ export declare function ChangeList(props: ChangeListProps): JSX.Element;
20
+ export default ChangeList;
@@ -1,7 +1,9 @@
1
- export type { AvatarProps, AvatarRing, AvatarShape, AvatarSize } from "./Avatar";
1
+ export type { AvatarProps, AvatarRing, AvatarShape, AvatarSize, AvatarTone } from "./Avatar";
2
2
  export { Avatar } from "./Avatar";
3
- export type { AvatarStackPerson, AvatarStackProps } from "./AvatarStack";
4
- export { AvatarStack } from "./AvatarStack";
3
+ export type { AvatarFacesPerson, AvatarFacesProps, AvatarStackPerson, AvatarStackProps } from "./AvatarStack";
4
+ export { AvatarFaces, AvatarStack } from "./AvatarStack";
5
+ export type { ChangeListItem, ChangeListProps, ChangeTone } from "./ChangeList";
6
+ export { ChangeList } from "./ChangeList";
5
7
  export type { DescriptionListItem, DescriptionListProps } from "./DescriptionList";
6
8
  export { DescriptionList } from "./DescriptionList";
7
9
  export type { DotStripProps, DotStripTone } from "./DotStrip";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k2b/ui",
3
- "version": "0.45.0",
3
+ "version": "0.47.0",
4
4
  "description": "Production-ready components for SolidJS applications.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -91,13 +91,13 @@
91
91
  "qr-scanner": "1.4.2"
92
92
  },
93
93
  "peerDependencies": {
94
- "@k2b/ssr": "^0.12.0 || ^0.13.0 || ^0.14.0 || ^0.15.0 || ^0.16.0 || ^0.17.0 || ^0.18.0 || ^0.19.0 || ^0.20.0",
94
+ "@k2b/ssr": "^0.12.0 || ^0.13.0 || ^0.14.0 || ^0.15.0 || ^0.16.0 || ^0.17.0 || ^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0",
95
95
  "solid-js": "^1.9.10"
96
96
  },
97
97
  "devDependencies": {
98
98
  "@babel/core": "8.0.6",
99
99
  "@babel/preset-typescript": "8.0.1",
100
- "@k2b/ssr": "0.20.2",
100
+ "@k2b/ssr": "0.21.0",
101
101
  "@types/babel__core": "7.20.5",
102
102
  "@types/bun": "1.4.2",
103
103
  "axe-core": "4.11.0",