@nxgt/material 3.54.0 → 3.56.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 (132) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +8 -3
  3. package/dist/{async-slice-DDSsekfm.js → async-slice-CORlM_wu.js} +2 -2
  4. package/dist/{button-Ct8DSLVv.js → button-CdpVEza0.js} +1 -1
  5. package/dist/charts.js +3 -3
  6. package/dist/{chip-BzoNsd-W.js → chip-C0yNYz9m.js} +2 -2
  7. package/dist/{code-editor-DsLQeiZc.js → code-editor-Bwzp2038.js} +6 -6
  8. package/dist/code-editor.js +5 -5
  9. package/dist/{code-language-items-4zXlIEZ0.js → code-language-items-nP-pF7yH.js} +2 -2
  10. package/dist/components/components.css +8 -0
  11. package/dist/components/ui/display/seat-ring/seat-ring-index.css +125 -0
  12. package/dist/components/ui/display/seat-ring/seat-ring-ring.css +87 -0
  13. package/dist/components/ui/display/seat-ring/seat-ring.css +139 -0
  14. package/dist/components/ui/display/secret-card/secret-card.css +65 -0
  15. package/dist/components/ui/display/vote-tally/vote-tally.css +94 -0
  16. package/dist/{components-DFG2mgsM.js → components-Dl2hVfzt.js} +16273 -15482
  17. package/dist/components.js +26 -26
  18. package/dist/{dialog-DwPmwmA3.js → dialog-BVgsN9Ch.js} +4 -4
  19. package/dist/dnd.js +1 -1
  20. package/dist/{dropdown-menu-CDN6Nqx6.js → dropdown-menu-C8PBmMIa.js} +1 -1
  21. package/dist/editor.js +9 -9
  22. package/dist/{empty-state-Bb9W9did.js → empty-state-C5wfbbW9.js} +2 -2
  23. package/dist/{escape-owner-DI_lg2ID.js → escape-owner-CYnfySUl.js} +1 -1
  24. package/dist/{field-blur-BcJH8H9B.js → field-blur-Nid7-bt_.js} +1 -1
  25. package/dist/{field-blur-context-Dg1nwWOV.js → field-blur-context-DxdIuHAY.js} +1 -1
  26. package/dist/hooks.js +28 -28
  27. package/dist/{hover-card-Qse4gnop.js → hover-card-C_9jiwp1.js} +2 -2
  28. package/dist/{i18n-provider-DlVPS58N.js → i18n-provider-CLVZK6tQ.js} +1 -1
  29. package/dist/i18n.js +5 -5
  30. package/dist/{icon-badge-DVPBQOKe.js → icon-badge-Dcjg_SKJ.js} +3 -3
  31. package/dist/{icon-button-C3wDxsh6.js → icon-button-Bo-VuZ2n.js} +1 -1
  32. package/dist/lib/components/ui/actions/link/link.d.ts +8 -0
  33. package/dist/lib/components/ui/collections/data-table/partials/data-table-page-control.d.ts +1 -1
  34. package/dist/lib/components/ui/collections/data-table/partials/data-table-row.d.ts +1 -1
  35. package/dist/lib/components/ui/collections/data-table/partials/layouts/data-table-card.d.ts +1 -1
  36. package/dist/lib/components/ui/collections/server-table/partials/server-table-past-end.d.ts +1 -1
  37. package/dist/lib/components/ui/display/index.d.ts +3 -0
  38. package/dist/lib/components/ui/display/list-tile/partials/list-tile-line.d.ts +1 -1
  39. package/dist/lib/components/ui/display/period-cards/period-cards.d.ts +1 -1
  40. package/dist/lib/components/ui/display/seat-ring/index.d.ts +2 -0
  41. package/dist/lib/components/ui/display/seat-ring/partials/empty-seat.d.ts +5 -0
  42. package/dist/lib/components/ui/display/seat-ring/partials/seat-body.d.ts +9 -0
  43. package/dist/lib/components/ui/display/seat-ring/partials/seat-item.d.ts +17 -0
  44. package/dist/lib/components/ui/display/seat-ring/seat-ring.d.ts +9 -0
  45. package/dist/lib/components/ui/display/seat-ring/seat-ring.utils.d.ts +9 -0
  46. package/dist/lib/components/ui/display/seat-ring/types.d.ts +67 -0
  47. package/dist/lib/components/ui/display/seat-ring/use-seat-ring.d.ts +12 -0
  48. package/dist/lib/components/ui/display/secret-card/index.d.ts +2 -0
  49. package/dist/lib/components/ui/display/secret-card/secret-card.d.ts +11 -0
  50. package/dist/lib/components/ui/display/secret-card/types.d.ts +49 -0
  51. package/dist/lib/components/ui/display/secret-card/use-secret-card.d.ts +20 -0
  52. package/dist/lib/components/ui/display/vote-tally/announcer.d.ts +11 -0
  53. package/dist/lib/components/ui/display/vote-tally/index.d.ts +2 -0
  54. package/dist/lib/components/ui/display/vote-tally/partials/tally-bar.d.ts +8 -0
  55. package/dist/lib/components/ui/display/vote-tally/partials/tally-row.d.ts +9 -0
  56. package/dist/lib/components/ui/display/vote-tally/partials/tally-voters.d.ts +9 -0
  57. package/dist/lib/components/ui/display/vote-tally/types.d.ts +73 -0
  58. package/dist/lib/components/ui/display/vote-tally/use-announcement.d.ts +7 -0
  59. package/dist/lib/components/ui/display/vote-tally/use-tally-summary.d.ts +3 -0
  60. package/dist/lib/components/ui/display/vote-tally/vote-tally.d.ts +10 -0
  61. package/dist/lib/components/ui/display/vote-tally/vote-tally.utils.d.ts +18 -0
  62. package/dist/lib/components/ui/fields/contacts/placeholders.d.ts +1 -1
  63. package/dist/lib/components/ui/layout/account-menu/account-menu.d.ts +1 -1
  64. package/dist/lib/components/ui/layout/app-shell/app-sidebar-icon-item.d.ts +1 -1
  65. package/dist/lib/components/ui/layout/app-shell/app-sidebar-label-item.d.ts +1 -1
  66. package/dist/lib/components/ui/layout/app-shell/app-sidebar.d.ts +1 -1
  67. package/dist/lib/components/ui/layout/pager/pager.d.ts +1 -1
  68. package/dist/lib/components/ui/layout/see-also/see-also.d.ts +1 -1
  69. package/dist/lib/components/ui/layout/toc/toc.d.ts +1 -1
  70. package/dist/lib/components/ui/primitives/index.d.ts +1 -0
  71. package/dist/lib/components/ui/primitives/link/index.d.ts +2 -0
  72. package/dist/lib/components/ui/primitives/link/link-component-provider.d.ts +26 -0
  73. package/dist/lib/components/ui/widgets/education/index.d.ts +1 -0
  74. package/dist/lib/components/ui/widgets/education/navigator/index.d.ts +2 -0
  75. package/dist/lib/components/ui/widgets/education/navigator/partials/navigator-item.d.ts +10 -0
  76. package/dist/lib/components/ui/widgets/education/navigator/question-navigator.d.ts +27 -0
  77. package/dist/lib/components/ui/widgets/education/questions/index.d.ts +1 -1
  78. package/dist/lib/components/ui/widgets/education/questions/partials/question-media.d.ts +5 -0
  79. package/dist/lib/components/ui/widgets/education/questions/partials/question-verdict.d.ts +12 -0
  80. package/dist/lib/components/ui/widgets/education/questions/question-options.d.ts +2 -2
  81. package/dist/lib/components/ui/widgets/education/questions/question-text.d.ts +1 -1
  82. package/dist/lib/components/ui/widgets/education/questions/question.d.ts +1 -1
  83. package/dist/lib/components/ui/widgets/education/questions/types.d.ts +33 -1
  84. package/dist/lib/hooks/index.d.ts +1 -0
  85. package/dist/lib/hooks/use-countdown.d.ts +18 -0
  86. package/dist/lib/i18n/resources/en/en.d.ts +34 -0
  87. package/dist/lib/i18n/resources/en/material.json.d.ts +34 -0
  88. package/dist/lib/i18n/resources/fr/fr.d.ts +34 -0
  89. package/dist/lib/i18n/resources/fr/material.json.d.ts +34 -0
  90. package/dist/lib/i18n/resources/resources.d.ts +68 -0
  91. package/dist/lib/i18n/translator.d.ts +1 -1
  92. package/dist/lib.js +1 -1
  93. package/dist/main.js +43 -43
  94. package/dist/map.js +8 -8
  95. package/dist/material.css +1 -1
  96. package/dist/pdf-reader.js +1 -1
  97. package/dist/print.js +2 -2
  98. package/dist/{public-BoVE0ffh.js → public-BtKAthSs.js} +9 -9
  99. package/dist/{rich-code-block-DAUM7Yh_.js → rich-code-block-BZYZ6ewr.js} +5 -5
  100. package/dist/{sortable-provider-BLXsGE_0.js → sortable-provider-hUCwt69K.js} +2 -2
  101. package/dist/{spinner-Rg4PnBPH.js → spinner-BmUXTzvJ.js} +1 -1
  102. package/dist/{stored-language-B1lJMPbR.js → stored-language-_OGPBCn0.js} +64 -0
  103. package/dist/theme-picker.js +2 -2
  104. package/dist/{theme-toggle-jVdxF_mc.js → theme-toggle-DdvEafno.js} +1 -1
  105. package/dist/{toolbar-items-BFY_hns5.js → toolbar-items-DKfY_6AG.js} +4 -4
  106. package/dist/{translate-material-q-JNxP1m.js → translate-material-DzBMPErh.js} +2 -2
  107. package/dist/{translator-BU1o3_l9.js → translator-BIVSiq4X.js} +1 -1
  108. package/dist/{use-chat-composer-DGbDuIUa.js → use-chat-composer-DCQW2EJ8.js} +16 -16
  109. package/dist/{use-heading-spy-CP63sAcS.js → use-heading-spy-Cr2C_Px8.js} +32 -5
  110. package/dist/{use-material-translation-nNF8fUXz.js → use-material-translation-C_bAxfvp.js} +2 -2
  111. package/docs/components/README.md +1 -1
  112. package/docs/components/buttons-and-actions.md +1 -0
  113. package/docs/components/data-display.md +212 -2
  114. package/docs/components/data-table-filter-and-lists.md +3 -3
  115. package/docs/components/feedback-and-status.md +5 -3
  116. package/docs/components/navigation-and-layout.md +4 -4
  117. package/docs/components/primitives.md +62 -0
  118. package/docs/components/rich-widgets.md +51 -0
  119. package/docs/components/selection-and-choice.md +1 -1
  120. package/docs/guides/app-shell.md +2 -2
  121. package/docs/guides/helpers.md +40 -0
  122. package/docs/previews/data-display-seatring.webp +0 -0
  123. package/docs/previews/data-display-secretcard.webp +0 -0
  124. package/docs/previews/data-display-votetally.webp +0 -0
  125. package/lib/components/components.css +8 -0
  126. package/lib/components/ui/display/seat-ring/seat-ring-index.css +125 -0
  127. package/lib/components/ui/display/seat-ring/seat-ring-ring.css +87 -0
  128. package/lib/components/ui/display/seat-ring/seat-ring.css +139 -0
  129. package/lib/components/ui/display/secret-card/secret-card.css +65 -0
  130. package/lib/components/ui/display/vote-tally/vote-tally.css +94 -0
  131. package/package.json +1 -1
  132. package/dist/lib/components/ui/feedback/countdown-timer/use-countdown.d.ts +0 -6
@@ -0,0 +1,17 @@
1
+ import { KeyboardEvent } from 'react';
2
+ import { Seat, SeatRingProps } from '../types.js';
3
+ type Props = Pick<SeatRingProps, 'renderAvatar' | 'renderStatus' | 'renderBadge' | 'renderEmptySeat'> & {
4
+ seat: Seat;
5
+ index: number;
6
+ mode: 'single' | 'multiple' | null;
7
+ selected: boolean;
8
+ tabStop: boolean;
9
+ highlighted: boolean;
10
+ register: (node: HTMLElement | null) => void;
11
+ onPick: () => void;
12
+ onKeyDown: (event: KeyboardEvent<HTMLElement>) => void;
13
+ onFocus: () => void;
14
+ };
15
+ /** One seat: an `option` of a listbox when selectable, a `listitem` otherwise. */
16
+ export declare function SeatItem({ seat, index, mode, selected, tabStop, highlighted, register, onPick, onKeyDown, onFocus, ...slots }: Props): import("react").JSX.Element;
17
+ export {};
@@ -0,0 +1,9 @@
1
+ import { SeatRingProps } from './types.js';
2
+ /**
3
+ * Participants as seats: around a circle when there is room, a grid on a
4
+ * phone. A list of seats (`role="list"`), or with `selectionMode` a listbox
5
+ * (`aria-selected`, roving focus: arrows, Home and End move, Space or Enter
6
+ * picks). Layout switches by the component's own width (a container query),
7
+ * so it also follows a narrow column or a dialog.
8
+ */
9
+ export declare function SeatRing(props: SeatRingProps): import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import { Seat, SeatRingSize } from './types.js';
2
+ /**
3
+ * The most seats drawn on a circle: what fits, without two seats
4
+ * touching, in the narrowest box the circle is drawn in (32, 38 and 46rem
5
+ * by size); more is a grid.
6
+ */
7
+ export declare const RING_LIMIT: Record<SeatRingSize, number>;
8
+ /** Whether a seat can be chosen. */
9
+ export declare function pickable(seat: Seat): boolean;
@@ -0,0 +1,67 @@
1
+ import { ComponentProps, ReactNode } from 'react';
2
+ import { StatusTone } from '../status-indicator/status-indicator.js';
3
+ /** A seat's state in words (never colour alone): its label is always shown and read out. */
4
+ export type SeatStatus = {
5
+ /** "Ready", "Away", "Eliminated"…: shown under the name and part of the seat's name. */
6
+ label: string;
7
+ /** The dot's tone (neutral without one). */
8
+ tone?: StatusTone;
9
+ };
10
+ export type Seat = {
11
+ id: string;
12
+ /** The seat's name: shown, and the seat's accessible name with its status. */
13
+ label: string;
14
+ /** A photo (`src`) or the fallback; without either, the label's initials. */
15
+ avatar?: {
16
+ src?: string;
17
+ fallback?: ReactNode;
18
+ };
19
+ status?: SeatStatus;
20
+ /** A small mark at the seat's corner: a host crown, a role icon, a count. */
21
+ badge?: ReactNode;
22
+ /** Cannot be picked: `aria-disabled`, still reachable by keyboard. */
23
+ disabled?: boolean;
24
+ /** Nobody sits here: a dashed placeholder, never selectable. */
25
+ empty?: boolean;
26
+ };
27
+ export type SeatRingSize = 'sm' | 'md' | 'lg';
28
+ /** What the ring draws for a seat, besides the default look. */
29
+ export type SeatRingSlots = {
30
+ renderAvatar?: (seat: Seat) => ReactNode;
31
+ renderStatus?: (seat: Seat) => ReactNode;
32
+ renderBadge?: (seat: Seat) => ReactNode;
33
+ /** The content of an empty seat (default: a dashed circle and "Empty seat"). */
34
+ renderEmptySeat?: (seat: Seat) => ReactNode;
35
+ /** The middle of the ring (a timer, a title); above the seats in the grid. */
36
+ centerSlot?: ReactNode;
37
+ };
38
+ export type SeatRingSelection = {
39
+ selectionMode?: 'none';
40
+ value?: never;
41
+ defaultValue?: never;
42
+ onValueChange?: never;
43
+ } | {
44
+ selectionMode: 'single';
45
+ value?: string | null;
46
+ defaultValue?: string | null;
47
+ onValueChange?: (value: string | null) => void;
48
+ } | {
49
+ selectionMode: 'multiple';
50
+ value?: string[];
51
+ defaultValue?: string[];
52
+ onValueChange?: (value: string[]) => void;
53
+ };
54
+ export type SeatRingProps = Omit<ComponentProps<'div'>, 'children' | 'role' | 'value' | 'defaultValue' | 'onChange'> & SeatRingSlots & SeatRingSelection & {
55
+ seats: Seat[];
56
+ /**
57
+ * `ring` (default): seats around a circle when the box is at least
58
+ * 32 to 46rem wide (by `size`), a grid below it and above the ring's
59
+ * seat limit; `grid`: always the grid.
60
+ */
61
+ layout?: 'ring' | 'grid';
62
+ size?: SeatRingSize;
63
+ /** The seat to emphasise (whose turn it is): `aria-current` in a list. */
64
+ highlightedId?: string;
65
+ /** Names the list or the listbox; give it (or `aria-labelledby`). */
66
+ 'aria-label'?: string;
67
+ };
@@ -0,0 +1,12 @@
1
+ import { KeyboardEvent } from 'react';
2
+ import { Seat, SeatRingProps } from './types.js';
3
+ /** The selection, the roving tab stop and the keys of a selectable ring. */
4
+ export declare function useSeatRing(props: SeatRingProps): {
5
+ mode: "multiple" | "single" | null;
6
+ value: string[];
7
+ stop: string | undefined;
8
+ pick: (seat: Seat) => void;
9
+ onKeyDown: (event: KeyboardEvent<HTMLElement>, seat: Seat) => void;
10
+ register: (id: string) => (node: HTMLElement | null) => void;
11
+ setFocused: import('react').Dispatch<import('react').SetStateAction<string | undefined>>;
12
+ };
@@ -0,0 +1,2 @@
1
+ export * from './secret-card.js';
2
+ export type { SecretCardLabels, SecretCardProps, SecretCardState, } from './types.js';
@@ -0,0 +1,11 @@
1
+ import { SecretCardProps } from './types.js';
2
+ /**
3
+ * A card whose secret face is hidden until a deliberate tap or click: a
4
+ * private role, a one-time code, a recovery key. The secret (`back`) is not
5
+ * rendered while hidden, so it is not in the markup, not read by a screen
6
+ * reader and not copied. The reveal is a real button with one name and
7
+ * `aria-expanded` for the state; changes a click does not explain
8
+ * (`autoHideMs`, the parent) are announced politely. The flip runs only after
9
+ * a change and without `prefers-reduced-motion`.
10
+ */
11
+ export declare function SecretCard(props: SecretCardProps): import("react").JSX.Element;
@@ -0,0 +1,49 @@
1
+ import { ComponentProps, ReactNode } from 'react';
2
+ import { Tone } from '../../tones.js';
3
+ /** The words the card says: its button and what a screen reader hears after a change. */
4
+ export type SecretCardLabels = {
5
+ /** The button's name, the same hidden or shown: `aria-expanded` carries the state (default "Show secret"). */
6
+ reveal: string;
7
+ /** Announced politely when the secret is shown by something other than a click on the button (default "Secret revealed"). */
8
+ revealed: string;
9
+ /** Announced politely when it is hidden by something other than a click on the button, an auto-hide or the parent (default "Secret hidden"). */
10
+ hidden: string;
11
+ };
12
+ export type SecretCardState = 'hidden' | 'revealed';
13
+ /** Controlled (`revealed` and `onRevealedChange`) or not (`defaultRevealed`), never both. */
14
+ export type SecretCardReveal = {
15
+ revealed: boolean;
16
+ onRevealedChange: (revealed: boolean) => void;
17
+ defaultRevealed?: never;
18
+ } | {
19
+ revealed?: never;
20
+ defaultRevealed?: boolean;
21
+ onRevealedChange?: (revealed: boolean) => void;
22
+ };
23
+ export type SecretCardProps = Omit<ComponentProps<'div'>, 'children' | 'title' | 'defaultValue'> & SecretCardReveal & {
24
+ /** The card's name, always shown: "Your role", "Recovery key". */
25
+ title: ReactNode;
26
+ /** A hint shown only while the secret is hidden ("Tap to see it, then hide it"). */
27
+ description?: ReactNode;
28
+ /** A decorative icon or illustration before the title. */
29
+ icon?: ReactNode;
30
+ /** A named tone or one the app declared (`data-tone`). */
31
+ tone?: Tone;
32
+ /**
33
+ * The hidden face, under the title: anything that is no secret.
34
+ * Default: a neutral pattern.
35
+ */
36
+ front?: ReactNode;
37
+ /**
38
+ * The secret. It is not rendered, so it is not in the markup, read out
39
+ * or copied, until the card is revealed.
40
+ */
41
+ back: ReactNode;
42
+ /** Buttons beside the reveal button (a copy button, "Next player"). */
43
+ actions?: ReactNode;
44
+ /** Hides the secret again after this many milliseconds shown. */
45
+ autoHideMs?: number;
46
+ /** The card cannot be revealed. A revealed card can always be hidden. */
47
+ disabled?: boolean;
48
+ labels?: Partial<SecretCardLabels>;
49
+ };
@@ -0,0 +1,20 @@
1
+ import { SecretCardLabels, SecretCardProps } from './types.js';
2
+ /**
3
+ * The reveal state (controlled or not), the optional auto-hide, the focus
4
+ * kept on the button when the face under it is swapped, and a polite message
5
+ * for the changes a click on the button does not explain (auto-hide, the
6
+ * parent): a click is already said by `aria-expanded`.
7
+ */
8
+ export declare function useSecretCard(props: SecretCardProps): {
9
+ shown: boolean;
10
+ faceId: string;
11
+ message: string | null;
12
+ changed: boolean;
13
+ labels: SecretCardLabels;
14
+ button: import('react').RefObject<HTMLButtonElement | null>;
15
+ toggle: () => void;
16
+ faceProps: {
17
+ onFocus: () => void;
18
+ onBlur: () => void;
19
+ };
20
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The debounce behind the live status, apart from React so it can be tested
3
+ * with fake timers. `follow(text, delay)` is called each time the text or the
4
+ * delay changes: a text equal to the last one said (or the first one) cancels
5
+ * what is pending, any other waits `delay` ms from now, and `say` gets it only
6
+ * if nothing newer arrived meanwhile.
7
+ */
8
+ export declare function createAnnouncer(initial: string, say: (text: string) => void): {
9
+ follow(text: string, delay: number): void;
10
+ cancel: () => void;
11
+ };
@@ -0,0 +1,2 @@
1
+ export type { VoteOption, VoteRow, Voter, VoteTallyProps, VoteTallySlots, VoteTallySort, VoteTallyVoters, } from './types.js';
2
+ export * from './vote-tally.js';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The bar: decorative (the row's text carries the number). An SVG so the
3
+ * width is an attribute, never a `style` (strict CSP); its width transition
4
+ * is in the stylesheet, and only without reduced motion.
5
+ */
6
+ export declare function TallyBar({ percent }: {
7
+ percent: number;
8
+ }): import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import { VoteRow, VoteTallyProps } from '../types.js';
2
+ type Props = Pick<VoteTallyProps, 'renderOption' | 'renderVoters' | 'showLeader'> & {
3
+ row: VoteRow;
4
+ voters: NonNullable<VoteTallyProps['showVoters']>;
5
+ maxVoters: number;
6
+ };
7
+ /** One option: label and marks, "n votes, x%" as text, a decorative bar, voters. */
8
+ export declare function TallyRow({ row, voters, maxVoters, showLeader, renderOption, renderVoters, }: Props): import("react").JSX.Element;
9
+ export {};
@@ -0,0 +1,9 @@
1
+ import { VoteRow, VoteTallyVoters } from '../types.js';
2
+ type Props = {
3
+ row: VoteRow;
4
+ mode: VoteTallyVoters;
5
+ max: number;
6
+ };
7
+ /** Who voted for an option: an avatar group or a line of names, both named. */
8
+ export declare function TallyVoters({ row, mode, max }: Props): import("react").JSX.Element | null;
9
+ export {};
@@ -0,0 +1,73 @@
1
+ import { ComponentProps, ReactNode } from 'react';
2
+ /** Someone who voted: shown as an avatar (or a name) and read out by name. */
3
+ export type Voter = {
4
+ id: string;
5
+ /** The voter's name: the avatar's accessible name and the text in `names` mode. */
6
+ label: string;
7
+ /** A photo (`src`) or the fallback; without either, the label's initials. */
8
+ avatar?: {
9
+ src?: string;
10
+ fallback?: ReactNode;
11
+ };
12
+ };
13
+ export type VoteOption = {
14
+ id: string;
15
+ /** The option's name: a candidate, an answer, a player. */
16
+ label: string;
17
+ /** Votes it received (a whole number, 0 or more). */
18
+ count: number;
19
+ /** Who voted for it, when the vote is public. */
20
+ voters?: Voter[];
21
+ /** A photo or fallback shown beside the label. */
22
+ avatar?: {
23
+ src?: string;
24
+ fallback?: ReactNode;
25
+ };
26
+ };
27
+ /** How a row's rank and share are known to the slots. */
28
+ export type VoteRow = {
29
+ option: VoteOption;
30
+ /** 1-based place; options with the same count share it. */
31
+ rank: number;
32
+ /** Share of the total, 0 to 100, whole number. */
33
+ percent: number;
34
+ /** Has the top count, alone. */
35
+ leader: boolean;
36
+ /** Shares the top count with another option. */
37
+ tied: boolean;
38
+ /** The viewer's own vote. */
39
+ selected: boolean;
40
+ };
41
+ export type VoteTallySort = 'count' | 'none';
42
+ export type VoteTallyVoters = 'none' | 'avatars' | 'names';
43
+ export type VoteTallySlots = {
44
+ /** Replaces an option's label cell (avatar, name and marks). */
45
+ renderOption?: (row: VoteRow) => ReactNode;
46
+ /** Replaces the voters under a bar. */
47
+ renderVoters?: (row: VoteRow) => ReactNode;
48
+ header?: ReactNode;
49
+ footer?: ReactNode;
50
+ };
51
+ export type VoteTallyProps = {
52
+ options: VoteOption[];
53
+ /** The base of the shares; the sum of the counts when omitted. Abstentions are not in it. */
54
+ total?: number;
55
+ /** `count` ranks by votes, highest first (ties keep their order); `none` keeps the given order. */
56
+ sort?: VoteTallySort;
57
+ /** The viewer's own choice, marked "Your vote" in words. */
58
+ selectedId?: string;
59
+ /** Marks the leader, or the tied options, in words ("Leader", "Tie"), and says them in the live status. Off: no mark, the status gives the votes cast. On by default. */
60
+ showLeader?: boolean;
61
+ /** `avatars` shows who voted as an avatar group, `names` as text. */
62
+ showVoters?: VoteTallyVoters;
63
+ /** How many voters show before "+N". 5 by default. */
64
+ maxVoters?: number;
65
+ /** The bar's width eases when a count changes (only the width); never under reduced motion. On by default. */
66
+ animated?: boolean;
67
+ /** People who voted for nobody: counted and shown beneath the bars. */
68
+ abstainCount?: number;
69
+ /** Shown while there is no vote. */
70
+ emptyLabel?: ReactNode;
71
+ /** Milliseconds a change waits before it is announced. 1000 by default. */
72
+ announceDelay?: number;
73
+ } & VoteTallySlots & Omit<ComponentProps<'div'>, 'children'>;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The text a polite live region should say, once `text` has stopped changing
3
+ * for `delay` ms. The first text is never said (it is the page as loaded,
4
+ * not news), a return to what was last said is not said again, and a burst of
5
+ * live updates becomes one announcement. `null` while there is nothing to say.
6
+ */
7
+ export declare function useAnnouncement(text: string, delay: number): string | null;
@@ -0,0 +1,3 @@
1
+ import { Tally } from './vote-tally.utils.js';
2
+ /** One sentence on where the vote stands: the leader, the tie, the abstentions. */
3
+ export declare function useTallySummary(result: Tally, abstain: number, showLeader?: boolean): string;
@@ -0,0 +1,10 @@
1
+ import { VoteTallyProps } from './types.js';
2
+ /**
3
+ * A live ranked tally of a vote: one row per option with its count and share
4
+ * as text ("Ada, 3 votes, 42%"), a decorative bar, and who voted for it. A
5
+ * leader, a tie and the viewer's own vote are marked in words, never by
6
+ * colour alone. Counts may change at any time: bars ease only without
7
+ * reduced motion, and a polite live region says what changed, once the
8
+ * changes stop for `announceDelay`.
9
+ */
10
+ export declare function VoteTally(props: VoteTallyProps): import("react").JSX.Element;
@@ -0,0 +1,18 @@
1
+ import { VoteOption, VoteRow, VoteTallySort } from './types.js';
2
+ export type Tally = {
3
+ rows: VoteRow[];
4
+ /** The base of the shares. */
5
+ total: number;
6
+ /** Top count, 0 without a vote. */
7
+ top: number;
8
+ /** Several options share the top count. */
9
+ tie: boolean;
10
+ };
11
+ /**
12
+ * Ranks the options and works out each share. Options with the same count
13
+ * share a rank and are never ordered by an arbitrary leader: with the top
14
+ * count held by several, none is a `leader`, all are `tied`.
15
+ */
16
+ export declare function tally(options: VoteOption[], sort: VoteTallySort, total?: number, selectedId?: string, marks?: boolean): Tally;
17
+ /** Whole votes an option is shown with. */
18
+ export declare const votesOf: (option: VoteOption) => number;