@chatwarden/player-react 0.0.0-stage → 0.1.2

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 (94) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +377 -2
  3. package/dist/src/Dialog.d.ts +13 -0
  4. package/dist/src/Dialog.d.ts.map +1 -0
  5. package/dist/src/Dialog.js +94 -0
  6. package/dist/src/Dialog.js.map +1 -0
  7. package/dist/src/FollowUp.d.ts +35 -0
  8. package/dist/src/FollowUp.d.ts.map +1 -0
  9. package/dist/src/FollowUp.js +69 -0
  10. package/dist/src/FollowUp.js.map +1 -0
  11. package/dist/src/MyRecord.d.ts +12 -0
  12. package/dist/src/MyRecord.d.ts.map +1 -0
  13. package/dist/src/MyRecord.js +17 -0
  14. package/dist/src/MyRecord.js.map +1 -0
  15. package/dist/src/NoticeQueue.d.ts +26 -0
  16. package/dist/src/NoticeQueue.d.ts.map +1 -0
  17. package/dist/src/NoticeQueue.js +90 -0
  18. package/dist/src/NoticeQueue.js.map +1 -0
  19. package/dist/src/Picker.d.ts +14 -0
  20. package/dist/src/Picker.d.ts.map +1 -0
  21. package/dist/src/Picker.js +14 -0
  22. package/dist/src/Picker.js.map +1 -0
  23. package/dist/src/ReportDialog.d.ts +50 -0
  24. package/dist/src/ReportDialog.d.ts.map +1 -0
  25. package/dist/src/ReportDialog.js +157 -0
  26. package/dist/src/ReportDialog.js.map +1 -0
  27. package/dist/src/RestrictedChatLine.d.ts +12 -0
  28. package/dist/src/RestrictedChatLine.d.ts.map +1 -0
  29. package/dist/src/RestrictedChatLine.js +19 -0
  30. package/dist/src/RestrictedChatLine.js.map +1 -0
  31. package/dist/src/RulesPage.d.ts +10 -0
  32. package/dist/src/RulesPage.d.ts.map +1 -0
  33. package/dist/src/RulesPage.js +17 -0
  34. package/dist/src/RulesPage.js.map +1 -0
  35. package/dist/src/client.d.ts +51 -0
  36. package/dist/src/client.d.ts.map +1 -0
  37. package/dist/src/client.js +98 -0
  38. package/dist/src/client.js.map +1 -0
  39. package/dist/src/constants.d.ts +5 -0
  40. package/dist/src/constants.d.ts.map +1 -0
  41. package/dist/src/constants.js +5 -0
  42. package/dist/src/constants.js.map +1 -0
  43. package/dist/src/format.d.ts +14 -0
  44. package/dist/src/format.d.ts.map +1 -0
  45. package/dist/src/format.js +55 -0
  46. package/dist/src/format.js.map +1 -0
  47. package/dist/src/hooks.d.ts +15 -0
  48. package/dist/src/hooks.d.ts.map +1 -0
  49. package/dist/src/hooks.js +29 -0
  50. package/dist/src/hooks.js.map +1 -0
  51. package/dist/src/i18n.d.ts +129 -0
  52. package/dist/src/i18n.d.ts.map +1 -0
  53. package/dist/src/i18n.js +167 -0
  54. package/dist/src/i18n.js.map +1 -0
  55. package/dist/src/index.d.ts +21 -0
  56. package/dist/src/index.d.ts.map +1 -0
  57. package/dist/src/index.js +11 -0
  58. package/dist/src/index.js.map +1 -0
  59. package/dist/src/reporting.d.ts +20 -0
  60. package/dist/src/reporting.d.ts.map +1 -0
  61. package/dist/src/reporting.js +45 -0
  62. package/dist/src/reporting.js.map +1 -0
  63. package/dist/src/safeHref.d.ts +5 -0
  64. package/dist/src/safeHref.d.ts.map +1 -0
  65. package/dist/src/safeHref.js +41 -0
  66. package/dist/src/safeHref.js.map +1 -0
  67. package/dist/src/transport.d.ts +69 -0
  68. package/dist/src/transport.d.ts.map +1 -0
  69. package/dist/src/transport.js +74 -0
  70. package/dist/src/transport.js.map +1 -0
  71. package/dist/src/ui.d.ts +91 -0
  72. package/dist/src/ui.d.ts.map +1 -0
  73. package/dist/src/ui.js +116 -0
  74. package/dist/src/ui.js.map +1 -0
  75. package/package.json +73 -4
  76. package/src/Dialog.tsx +117 -0
  77. package/src/FollowUp.tsx +139 -0
  78. package/src/MyRecord.tsx +60 -0
  79. package/src/NoticeQueue.tsx +203 -0
  80. package/src/Picker.tsx +60 -0
  81. package/src/ReportDialog.tsx +304 -0
  82. package/src/RestrictedChatLine.tsx +42 -0
  83. package/src/RulesPage.tsx +49 -0
  84. package/src/client.ts +132 -0
  85. package/src/constants.ts +5 -0
  86. package/src/format.ts +53 -0
  87. package/src/hooks.ts +41 -0
  88. package/src/i18n.ts +187 -0
  89. package/src/index.ts +32 -0
  90. package/src/reporting.ts +51 -0
  91. package/src/safeHref.ts +36 -0
  92. package/src/styles.css +516 -0
  93. package/src/transport.ts +134 -0
  94. package/src/ui.tsx +199 -0
@@ -0,0 +1,94 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from 'react';
3
+ // A modal window: it takes focus when it opens, keeps focus inside, and hands focus back to what had it. It is a plain ARIA dialog
4
+ // (not <dialog>), so it works the same in every embedded browser a game may use. A click outside never closes it: a notice has to
5
+ // be acknowledged, and a half-written report is not lost by a stray click.
6
+ //
7
+ // Focus is kept in three ways, because Tab alone is not enough: the keydown handler wraps Tab at the ends, a click on the backdrop
8
+ // does not move focus (mousedown is cancelled), and a document-wide `focusin` guard pulls focus back if anything outside the window
9
+ // gets it (a script, a click on a game control that is still reachable).
10
+ const FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
11
+ /**
12
+ * The controls Tab visits, in order. A radio group is one stop (the checked radio, or the first when none is checked), because the
13
+ * browser moves between its radios with the arrow keys: counting every radio would make "the first control" the wrong one to wrap at.
14
+ */
15
+ function tabStops(box) {
16
+ const all = [...box.querySelectorAll(FOCUSABLE)];
17
+ return all.filter((el) => {
18
+ if (!(el instanceof HTMLInputElement) || el.type !== 'radio' || el.name === '')
19
+ return true;
20
+ const group = all.filter((o) => o instanceof HTMLInputElement && o.type === 'radio' && o.name === el.name);
21
+ return el === (group.find((r) => r.checked) ?? group[0]);
22
+ });
23
+ }
24
+ export function Dialog({ labelledBy, initialFocus, onEscape, returnFocusTo, children, }) {
25
+ const box = useRef(null);
26
+ const fallback = useRef(returnFocusTo);
27
+ fallback.current = returnFocusTo;
28
+ // What had focus before the window opened, read while rendering for the first time: a child's own effect (which moves focus to
29
+ // its heading) runs before this component's effects, so reading it in an effect would find the heading.
30
+ const [before] = useState(() => (typeof document === 'undefined' ? null : document.activeElement));
31
+ useEffect(() => {
32
+ (initialFocus.current ?? box.current)?.focus();
33
+ const onFocusIn = (e) => {
34
+ const target = e.target;
35
+ const inner = box.current;
36
+ if (inner !== null && target instanceof Node && !inner.contains(target))
37
+ (initialFocus.current ?? inner).focus();
38
+ };
39
+ document.addEventListener('focusin', onFocusIn);
40
+ return () => {
41
+ // Stop guarding first, so giving focus back is not pulled in again.
42
+ document.removeEventListener('focusin', onFocusIn);
43
+ // Give focus back, unless what had it is gone (the page moved on while the window was open): then to `returnFocusTo()`, if
44
+ // the host gave one, and otherwise to wherever the browser leaves it (the page body).
45
+ if (before instanceof HTMLElement && before.isConnected)
46
+ before.focus();
47
+ else {
48
+ try {
49
+ fallback.current?.()?.focus();
50
+ }
51
+ catch {
52
+ // A host callback that throws must not stop the window closing.
53
+ }
54
+ }
55
+ };
56
+ // Once, when the window opens.
57
+ }, []);
58
+ const onKeyDown = (e) => {
59
+ if (e.key === 'Escape') {
60
+ if (onEscape === undefined)
61
+ return;
62
+ e.preventDefault();
63
+ e.stopPropagation();
64
+ onEscape();
65
+ return;
66
+ }
67
+ if (e.key !== 'Tab' || box.current === null)
68
+ return;
69
+ const items = tabStops(box.current);
70
+ if (items.length === 0) {
71
+ e.preventDefault();
72
+ return;
73
+ }
74
+ const first = items[0];
75
+ const last = items[items.length - 1];
76
+ const active = document.activeElement;
77
+ // From the heading (or the box), which is not in the list, Tab goes to the first control and Shift+Tab to the last.
78
+ const inList = items.includes(active);
79
+ if (e.shiftKey && (active === first || !inList)) {
80
+ e.preventDefault();
81
+ last.focus();
82
+ }
83
+ else if (!e.shiftKey && (active === last || !inList)) {
84
+ e.preventDefault();
85
+ first.focus();
86
+ }
87
+ };
88
+ return (_jsx("div", { className: "cw-scrim", onMouseDown: (e) => {
89
+ // A press on the backdrop would drop focus to the page body, and the next Tab would leave the window: keep it where it is.
90
+ if (e.target === e.currentTarget)
91
+ e.preventDefault();
92
+ }, children: _jsx("div", { ref: box, className: "cw-dialog", role: "dialog", "aria-modal": "true", "aria-labelledby": labelledBy, tabIndex: -1, onKeyDown: onKeyDown, children: children }) }));
93
+ }
94
+ //# sourceMappingURL=Dialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dialog.js","sourceRoot":"","sources":["../../src/Dialog.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { MutableRefObject } from 'react';
2
+ import type { ReportDetailResult } from '@chatwarden/core';
3
+ import type { PlayerText } from './i18n.js';
4
+ import type { ReasonGroup } from './reporting.js';
5
+ import type { PlayerT } from './i18n.js';
6
+ /** What the player adds after a one-tap report. Your server calls `cw.reports.addDetail(reportId, reporterSeat, detail)`. */
7
+ export interface ReportFollowUp {
8
+ reason?: string;
9
+ note?: string;
10
+ }
11
+ /** How the follow-up ended, for the dialog to say: added, or the refusal word (an unknown one reads as a failure). */
12
+ export type FollowUpOutcome = {
13
+ ok: true;
14
+ } | {
15
+ ok: false;
16
+ refused: string;
17
+ };
18
+ /**
19
+ * The optional step after a one-tap report: an "Add a reason" button that opens the reasons (in groups) and a note, and sends them to
20
+ * `onAddDetail` for the report just filed. Nothing is sent when nothing is chosen. One thing on its way at a time, shared with the
21
+ * dialog through `sending` (so Escape and Close wait for it); `onBusy` tells the dialog to dim its Close button.
22
+ */
23
+ export declare function FollowUp(props: {
24
+ t: PlayerT;
25
+ groups: readonly ReasonGroup[];
26
+ reportId: string;
27
+ onAddDetail: (reportId: string, detail: ReportFollowUp) => Promise<ReportDetailResult>;
28
+ sending: MutableRefObject<boolean>;
29
+ busy: boolean;
30
+ onBusy: (busy: boolean) => void;
31
+ onDone: (outcome: FollowUpOutcome) => void;
32
+ }): import("react").JSX.Element;
33
+ /** The plain message for a follow-up refusal; one a newer kit adds gets the general one. */
34
+ export declare const DETAIL_REFUSED_TEXT: Readonly<Record<string, PlayerText>>;
35
+ //# sourceMappingURL=FollowUp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FollowUp.d.ts","sourceRoot":"","sources":["../../src/FollowUp.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAa,gBAAgB,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAG3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,6HAA6H;AAC7H,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,sHAAsH;AACtH,MAAM,MAAM,eAAe,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAM5E;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE;IAC9B,CAAC,EAAE,OAAO,CAAC;IACX,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACvF,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAChC,MAAM,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;CAC5C,+BA0FA;AAED,4FAA4F;AAC5F,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAOpE,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useId, useState } from 'react';
3
+ import { NOTE_MAX } from './constants.js';
4
+ import { PlayerError } from './client.js';
5
+ import { Picker } from './Picker.js';
6
+ import { errorText } from './ui.js';
7
+ /** A failure to send as an error the components can word: anything that is not already a PlayerError is a dropped connection. */
8
+ const failureOf = (e) => e instanceof PlayerError ? e : new PlayerError({ status: 0, code: 'network', message: 'Could not reach the server.' });
9
+ /**
10
+ * The optional step after a one-tap report: an "Add a reason" button that opens the reasons (in groups) and a note, and sends them to
11
+ * `onAddDetail` for the report just filed. Nothing is sent when nothing is chosen. One thing on its way at a time, shared with the
12
+ * dialog through `sending` (so Escape and Close wait for it); `onBusy` tells the dialog to dim its Close button.
13
+ */
14
+ export function FollowUp(props) {
15
+ const { t, groups, reportId, onAddDetail, sending, busy, onBusy, onDone } = props;
16
+ const name = useId();
17
+ const noteId = useId();
18
+ const missingId = useId();
19
+ const panelId = useId();
20
+ const [open, setOpen] = useState(false);
21
+ const [reason, setReason] = useState(null);
22
+ const [note, setNote] = useState('');
23
+ const [missing, setMissing] = useState(false);
24
+ const [failure, setFailure] = useState(null);
25
+ const trimmed = note.trim();
26
+ const submit = async (e) => {
27
+ e.preventDefault();
28
+ if (sending.current)
29
+ return;
30
+ if (reason === null && trimmed === '') {
31
+ setMissing(true);
32
+ return;
33
+ }
34
+ sending.current = true;
35
+ onBusy(true);
36
+ setFailure(null);
37
+ try {
38
+ const detail = { ...(reason === null ? {} : { reason }), ...(trimmed === '' ? {} : { note: trimmed }) };
39
+ const raw = await onAddDetail(reportId, detail);
40
+ // Anything that is not a result object (undefined, null, a string) is not a success and not a crash: it reads as an unknown refusal.
41
+ const answer = typeof raw === 'object' && raw !== null && !Array.isArray(raw) ? raw : { ok: false, refused: 'unknown' };
42
+ onDone(answer.ok === true ? { ok: true } : { ok: false, refused: String(answer.refused) });
43
+ }
44
+ catch (error) {
45
+ setFailure(failureOf(error));
46
+ }
47
+ finally {
48
+ sending.current = false;
49
+ onBusy(false);
50
+ }
51
+ };
52
+ return (_jsxs("form", { onSubmit: (e) => void submit(e), noValidate: true, children: [_jsx("button", { type: "button", className: "cw-btn cw-disclosure", "aria-expanded": open, "aria-controls": open ? panelId : undefined, onClick: () => setOpen(!open), children: t('player.report.addReason') }), open && (_jsxs("div", { id: panelId, className: "cw-panel", children: [_jsx("p", { className: "cw-hint", children: t('player.report.addReasonHint') }), _jsx(Picker, { groups: groups, name: name, value: reason, legend: t('player.report.detail.legend'), invalid: missing, describedBy: missingId, onChange: (id) => {
53
+ setReason(id);
54
+ setMissing(false);
55
+ } }), missing && (_jsx("p", { id: missingId, className: "cw-field-error", role: "alert", children: t('player.report.detail.need') })), _jsx("label", { className: "cw-label", htmlFor: noteId, children: t('player.report.note') }), _jsx("textarea", { id: noteId, className: "cw-textarea", rows: 3, maxLength: NOTE_MAX, value: note, onChange: (e) => {
56
+ setNote(e.target.value);
57
+ setMissing(false);
58
+ } }), failure !== null && (_jsxs("p", { className: "cw-error", role: "alert", children: [t('player.report.detail.failed'), " ", errorText(t, failure)] })), _jsx("div", { className: "cw-actions", children: _jsx("button", { type: "submit", className: "cw-btn cw-btn--primary", "aria-disabled": busy || undefined, "aria-busy": busy || undefined, children: t('player.report.detail.send') }) })] }))] }));
59
+ }
60
+ /** The plain message for a follow-up refusal; one a newer kit adds gets the general one. */
61
+ export const DETAIL_REFUSED_TEXT = {
62
+ off: 'player.report.detail.refused.off',
63
+ not_found: 'player.report.detail.refused.not_found',
64
+ not_reporter: 'player.report.detail.refused.not_reporter',
65
+ too_late: 'player.report.detail.refused.too_late',
66
+ already_added: 'player.report.detail.refused.already_added',
67
+ reason_unknown: 'player.report.detail.refused.reason_unknown',
68
+ };
69
+ //# sourceMappingURL=FollowUp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FollowUp.js","sourceRoot":"","sources":["../../src/FollowUp.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { PlayerClient } from './client.js';
2
+ import type { PlayerUiProps } from './ui.js';
3
+ export interface MyRecordProps extends PlayerUiProps {
4
+ client: PlayerClient;
5
+ /** Where "Think this is a mistake?" goes: an `http(s)` address or a path starting with `/`. Left out when absent or unsafe. */
6
+ appealUrl?: string;
7
+ /** Change it to load the record again. */
8
+ refreshKey?: number | string;
9
+ }
10
+ /** "My record": what is on the player's record now, newest first, from `GET /record`; or a calm line when it is clear. */
11
+ export declare function MyRecord(props: MyRecordProps): import("react").JSX.Element;
12
+ //# sourceMappingURL=MyRecord.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MyRecord.d.ts","sourceRoot":"","sources":["../../src/MyRecord.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD,MAAM,EAAE,YAAY,CAAC;IACrB,+HAA+H;IAC/H,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9B;AAED,0HAA0H;AAC1H,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,+BA2C5C"}
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useId } from 'react';
3
+ import { usePlayerData } from './hooks.js';
4
+ import { WARNING_DAYS } from './constants.js';
5
+ import { AppealLink, Card, ErrorBlock, Facts, kindKey, Lines, Root, useUi } from './ui.js';
6
+ /** "My record": what is on the player's record now, newest first, from `GET /record`; or a calm line when it is clear. */
7
+ export function MyRecord(props) {
8
+ const { client, appealUrl, refreshKey, theme, className } = props;
9
+ const ui = useUi(props);
10
+ const { t } = ui;
11
+ const state = usePlayerData(() => client.record(), refreshKey);
12
+ const titleId = useId();
13
+ const linesId = useId();
14
+ const items = state.data === undefined ? [] : [...state.data].sort((a, b) => b.createdAt - a.createdAt);
15
+ return (_jsx(Root, { theme: theme, className: className, children: _jsxs("section", { className: "cw-section", "aria-labelledby": titleId, children: [_jsx("h2", { id: titleId, className: "cw-title", children: t('player.record.title') }), state.error !== null && _jsx(ErrorBlock, { ui: ui, what: t('player.record.loadFailed'), error: state.error, onRetry: state.reload }), state.data === undefined && state.error === null && (_jsx("p", { className: "cw-state", role: "status", children: t('player.record.loading') })), state.data !== undefined && items.length === 0 && _jsx("p", { className: "cw-state", children: t('player.record.empty') }), items.length > 0 && (_jsxs(_Fragment, { children: [_jsx("p", { className: "cw-body", children: t('player.record.intro', { days: WARNING_DAYS }) }), _jsx(AppealLink, { ui: ui, href: appealUrl }), _jsx("ul", { className: "cw-items", "aria-labelledby": titleId, children: items.map((notice, i) => (_jsxs("li", { className: "cw-item", children: [_jsxs("div", { className: "cw-head", children: [_jsx(Card, { kind: notice.kind }), _jsx("h3", { className: "cw-kind", children: t(kindKey(notice.kind)) })] }), _jsx(Facts, { ui: ui, notice: notice, record: true }), _jsx(Lines, { ui: ui, notice: notice, id: `${linesId}-${i}` })] }, notice.id))) })] }))] }) }));
16
+ }
17
+ //# sourceMappingURL=MyRecord.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MyRecord.js","sourceRoot":"","sources":["../../src/MyRecord.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { PlayerNotice } from '@chatwarden/core';
2
+ import type { PlayerClient } from './client.js';
3
+ import type { DialogHostProps, PlayerUiProps } from './ui.js';
4
+ export interface NoticeQueueProps extends PlayerUiProps, DialogHostProps {
5
+ client: PlayerClient;
6
+ /**
7
+ * Whether a notice may appear now. Pass `false` during a match: notices are held (kept, not dropped, not acknowledged) and
8
+ * appear, oldest first, when it turns `true` again; the list is asked for once more at that moment, so a notice that arrived during
9
+ * the match is not missed. Default: `true`.
10
+ */
11
+ canShow?: boolean;
12
+ /** Where "Think this is a mistake?" goes: an `https` address or a relative one (`/appeal`). Left out when absent or unsafe. */
13
+ appealUrl?: string;
14
+ /** Change it to ask the server again (for example when your own push channel says a notice is pending). */
15
+ refreshKey?: number | string;
16
+ /** Called once for each notice the player acknowledged. */
17
+ onAcknowledged?: (notice: PlayerNotice) => void;
18
+ /** Called with how many notices are waiting (shown or held) each time that number changes, after the first load. */
19
+ onPendingChange?: (count: number) => void;
20
+ }
21
+ /**
22
+ * Shows the player's pending notices, oldest first, one at a time in a modal dialog. Every notice is acknowledged (a warning with
23
+ * "Acknowledge", the others with "Got it"); the dialog closes after the last one and focus returns to where it was.
24
+ */
25
+ export declare function NoticeQueue(props: NoticeQueueProps): import("react").JSX.Element | null;
26
+ //# sourceMappingURL=NoticeQueue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NoticeQueue.d.ts","sourceRoot":"","sources":["../../src/NoticeQueue.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,aAAa,CAAC;AAI7D,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAM,MAAM,SAAS,CAAC;AAElE,MAAM,WAAW,gBAAiB,SAAQ,aAAa,EAAE,eAAe;IACtE,MAAM,EAAE,YAAY,CAAC;IACrB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+HAA+H;IAC/H,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2GAA2G;IAC3G,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,2DAA2D;IAC3D,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;IAChD,oHAAoH;IACpH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,sCA0ElD"}
@@ -0,0 +1,90 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useId, useRef, useState } from 'react';
3
+ import { toPlayerError } from './client.js';
4
+ import { Dialog } from './Dialog.js';
5
+ import { usePlayerData } from './hooks.js';
6
+ import { AppealLink, bodyKey, Card, errorText, Facts, isSanction, Lines, Portal, Root, titleKey, useUi } from './ui.js';
7
+ /**
8
+ * Shows the player's pending notices, oldest first, one at a time in a modal dialog. Every notice is acknowledged (a warning with
9
+ * "Acknowledge", the others with "Got it"); the dialog closes after the last one and focus returns to where it was.
10
+ */
11
+ export function NoticeQueue(props) {
12
+ const { client, canShow = true, appealUrl, refreshKey, onAcknowledged, onPendingChange, theme, className, container, returnFocusTo } = props;
13
+ const ui = useUi(props);
14
+ const state = usePlayerData(() => client.notices(), refreshKey);
15
+ // The ids acknowledged since this list arrived. A newer list replaces both, so the server stays the truth.
16
+ const [done, setDone] = useState({ list: undefined, ids: [] });
17
+ const gone = done.list === state.data ? done.ids : [];
18
+ const queue = (state.data ?? []).filter((n) => !gone.includes(n.id)).sort((a, b) => a.createdAt - b.createdAt);
19
+ const count = queue.length;
20
+ const loaded = state.data !== undefined;
21
+ // "Close for now" after a failed acknowledge hides the queue until a newer list arrives (a refresh, or the next release of a hold).
22
+ const [later, setLater] = useState(undefined);
23
+ const titleId = useId();
24
+ const heading = useRef(null);
25
+ const reload = state.reload;
26
+ // Releasing a hold asks the server once more: a warning that landed during the match must be seen before the next one.
27
+ const wasShown = useRef(canShow);
28
+ useEffect(() => {
29
+ if (canShow && !wasShown.current)
30
+ reload();
31
+ wasShown.current = canShow;
32
+ }, [canShow, reload]);
33
+ const told = useRef(onPendingChange);
34
+ told.current = onPendingChange;
35
+ useEffect(() => {
36
+ if (loaded)
37
+ told.current?.(count);
38
+ }, [loaded, count]);
39
+ if (!canShow)
40
+ return null;
41
+ if (state.data === undefined) {
42
+ if (state.error === null)
43
+ return null;
44
+ return (_jsx(Root, { theme: theme, className: className, children: _jsxs("div", { className: "cw-error", role: "alert", children: [_jsxs("p", { children: [_jsx("strong", { children: ui.t('player.notices.loadFailed') }), " ", errorText(ui.t, state.error)] }), _jsx("button", { type: "button", className: "cw-btn", onClick: state.reload, children: ui.t('player.state.retry') })] }) }));
45
+ }
46
+ const current = queue[0];
47
+ if (current === undefined || later === state.data)
48
+ return null;
49
+ const acknowledged = (notice) => {
50
+ setDone({ list: state.data, ids: [...gone, notice.id] });
51
+ onAcknowledged?.(notice);
52
+ };
53
+ return (_jsx(Portal, { container: container, children: _jsx(Root, { theme: theme, className: className, children: _jsx(Dialog, { labelledBy: titleId, initialFocus: heading, ...(returnFocusTo === undefined ? {} : { returnFocusTo }), children: _jsx(NoticeCard, { ui: ui, client: client, notice: current, total: count, appealUrl: appealUrl, titleId: titleId, heading: heading, onDone: acknowledged, onLater: () => setLater(state.data) }, current.id) }) }) }));
54
+ }
55
+ function NoticeCard({ ui, client, notice, total, appealUrl, titleId, heading, onDone, onLater, }) {
56
+ const { t } = ui;
57
+ const linesId = useId();
58
+ const sending = useRef(false);
59
+ const [busy, setBusy] = useState(false);
60
+ const [failure, setFailure] = useState(null);
61
+ // Each notice, not only the first, takes focus at its heading: it is what a screen reader should read next.
62
+ useEffect(() => heading.current?.focus(), []);
63
+ const acknowledge = async () => {
64
+ // One request at a time: a second click, or a second Enter, while one is on its way does nothing.
65
+ if (sending.current)
66
+ return;
67
+ sending.current = true;
68
+ setBusy(true);
69
+ setFailure(null);
70
+ try {
71
+ await client.ack(notice.id);
72
+ // `false` (a 200 that is not ours) and a 404 both mean the notice is no longer pending: it is done.
73
+ onDone(notice);
74
+ }
75
+ catch (e) {
76
+ const error = toPlayerError(e);
77
+ if (error.status === 404)
78
+ onDone(notice);
79
+ else
80
+ setFailure(error);
81
+ }
82
+ finally {
83
+ sending.current = false;
84
+ setBusy(false);
85
+ }
86
+ };
87
+ const mustAck = notice.kind === 'warning' || notice.mustAcknowledge;
88
+ return (_jsxs(_Fragment, { children: [_jsx("p", { className: "cw-position", "aria-live": "polite", children: total > 1 ? t('player.notice.position', { n: 1, total }) : null }), _jsxs("div", { className: "cw-head", children: [_jsx(Card, { kind: notice.kind }), _jsx("h2", { id: titleId, ref: heading, className: "cw-title", tabIndex: -1, children: t(titleKey(notice.kind)) })] }), _jsx("p", { className: "cw-body", children: t(bodyKey(notice.kind)) }), _jsx(Facts, { ui: ui, notice: notice }), notice.refCode !== null && _jsx("p", { className: "cw-hint", children: t('player.notice.refHint') }), _jsx(Lines, { ui: ui, notice: notice, id: linesId }), isSanction(notice.kind) && _jsx(AppealLink, { ui: ui, href: appealUrl }), mustAck && _jsx("p", { className: "cw-hint", children: t('player.notice.todo.warning') }), failure !== null && (_jsxs("div", { className: "cw-error", role: "alert", children: [_jsxs("p", { children: [t('player.notice.ackFailed'), " ", errorText(t, failure)] }), _jsx("button", { type: "button", className: "cw-btn", onClick: onLater, children: t('player.notice.closeForNow') })] })), _jsx("div", { className: "cw-actions", children: _jsx("button", { type: "button", className: "cw-btn cw-btn--primary", "aria-disabled": busy || undefined, "aria-busy": busy || undefined, onClick: () => void acknowledge(), children: t(mustAck ? 'player.notice.acknowledge' : 'player.notice.gotIt') }) })] }));
89
+ }
90
+ //# sourceMappingURL=NoticeQueue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NoticeQueue.js","sourceRoot":"","sources":["../../src/NoticeQueue.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { RefObject } from 'react';
2
+ import type { ReasonGroup } from './reporting.js';
3
+ /** The radios, by group. One radio group (one name) across the groups, so the arrow keys walk all of them and Tab stops once. */
4
+ export declare function Picker(props: {
5
+ groups: readonly ReasonGroup[];
6
+ name: string;
7
+ value: string | null;
8
+ onChange: (id: string) => void;
9
+ legend: string;
10
+ invalid?: boolean;
11
+ describedBy?: string | undefined;
12
+ fieldset?: RefObject<HTMLFieldSetElement | null>;
13
+ }): import("react").JSX.Element;
14
+ //# sourceMappingURL=Picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Picker.d.ts","sourceRoot":"","sources":["../../src/Picker.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,gBAAgB,CAAC;AAE9D,iIAAiI;AACjI,wBAAgB,MAAM,CAAC,KAAK,EAAE;IAC5B,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,EAAE,SAAS,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;CAClD,+BA6CA"}
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useId } from 'react';
3
+ /** The radios, by group. One radio group (one name) across the groups, so the arrow keys walk all of them and Tab stops once. */
4
+ export function Picker(props) {
5
+ const { groups, name, value, onChange, legend, invalid, describedBy, fieldset } = props;
6
+ const base = useId();
7
+ const choice = (r) => {
8
+ const label = `${base}-${r.id}-l`;
9
+ const hint = `${base}-${r.id}-h`;
10
+ return (_jsxs("label", { className: "cw-choice", children: [_jsx("input", { type: "radio", name: name, value: r.id, checked: value === r.id, "aria-labelledby": label, "aria-describedby": r.hint === '' ? undefined : hint, onChange: () => onChange(r.id) }), _jsxs("span", { className: "cw-choice-text", children: [_jsx("span", { id: label, children: r.label }), r.hint !== '' && (_jsx("span", { id: hint, className: "cw-choice-hint", children: r.hint }))] })] }, r.id));
11
+ };
12
+ return (_jsxs("fieldset", { ref: fieldset, className: "cw-fieldset", role: "radiogroup", "aria-invalid": invalid || undefined, "aria-describedby": invalid ? describedBy : undefined, children: [_jsx("legend", { className: "cw-legend", children: legend }), groups.map((g, i) => g.name === '' ? (_jsx("div", { className: "cw-group", children: g.items.map(choice) }, `g${i}`)) : (_jsxs("fieldset", { className: "cw-fieldset cw-group", children: [_jsx("legend", { className: "cw-group-legend", children: g.name }), g.items.map(choice)] }, `g${i}`)))] }));
13
+ }
14
+ //# sourceMappingURL=Picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Picker.js","sourceRoot":"","sources":["../../src/Picker.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAI9B,iIAAiI;AACjI,MAAM,UAAU,MAAM,CAAC,KAStB;IACC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IACxF,MAAM,IAAI,GAAG,KAAK,EAAE,CAAC;IACrB,MAAM,MAAM,GAAG,CAAC,CAAa,EAAE,EAAE;QAC/B,MAAM,KAAK,GAAG,GAAG,IAAI,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC;QAClC,MAAM,IAAI,GAAG,GAAG,IAAI,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC;QACjC,OAAO,CACL,iBAAkB,SAAS,EAAC,WAAW,aACrC,gBACE,IAAI,EAAC,OAAO,EACZ,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,CAAC,CAAC,EAAE,EACX,OAAO,EAAE,KAAK,KAAK,CAAC,CAAC,EAAE,qBACN,KAAK,sBACJ,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,EAClD,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,GAC9B,EACF,gBAAM,SAAS,EAAC,gBAAgB,aAC9B,eAAM,EAAE,EAAE,KAAK,YAAG,CAAC,CAAC,KAAK,GAAQ,EAChC,CAAC,CAAC,IAAI,KAAK,EAAE,IAAI,CAChB,eAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAC,gBAAgB,YACvC,CAAC,CAAC,IAAI,GACF,CACR,IACI,KAjBG,CAAC,CAAC,EAAE,CAkBR,CACT,CAAC;IACJ,CAAC,CAAC;IACF,OAAO,CACL,oBAAU,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAC,aAAa,EAAC,IAAI,EAAC,YAAY,kBAAe,OAAO,IAAI,SAAS,sBAAoB,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,aACxJ,iBAAQ,SAAS,EAAC,WAAW,YAAE,MAAM,GAAU,EAC9C,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACnB,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,CACd,cAAmB,SAAS,EAAC,UAAU,YACpC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IADZ,IAAI,CAAC,EAAE,CAEX,CACP,CAAC,CAAC,CAAC,CACF,oBAAwB,SAAS,EAAC,sBAAsB,aACtD,iBAAQ,SAAS,EAAC,iBAAiB,YAAE,CAAC,CAAC,IAAI,GAAU,EACpD,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,KAFP,IAAI,CAAC,EAAE,CAGX,CACZ,CACF,IACQ,CACZ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,50 @@
1
+ import type { PlayerReporting, ReportDetailResult, ReportResult } from '@chatwarden/core';
2
+ import type { ReportFollowUp } from './FollowUp.js';
3
+ import type { DialogHostProps, PlayerUiProps } from './ui.js';
4
+ /**
5
+ * What the player filled in. Your server adds the room and the seats and calls `cw.reports.submit({ ...draft, roomId, reporterSeat,
6
+ * targetSeat })`. The dialog sends `reason` (an id from the studio's `reporting` list, or nothing, as in one tap). A reason is only a
7
+ * hint: the moderators decide what a report really is.
8
+ */
9
+ export interface ReportDraft {
10
+ /** The reason the player chose: an id from `reporting.reasons`. Left out when none was chosen. */
11
+ reason?: string;
12
+ /** The note, trimmed; left out when blank. */
13
+ note?: string;
14
+ }
15
+ export type { ReportFollowUp } from './FollowUp.js';
16
+ export interface ReportDialogProps extends PlayerUiProps, DialogHostProps {
17
+ /**
18
+ * Sends the report: your server calls `cw.reports.submit({ ...draft, roomId, reporterSeat, targetSeat })` and returns its
19
+ * `ReportResult`. A refusal is a result, not an error; reject only when no answer arrived.
20
+ */
21
+ onSubmit: (draft: ReportDraft) => Promise<ReportResult>;
22
+ /**
23
+ * The optional follow-up after a one-tap report: your server calls `cw.reports.addDetail(reportId, reporterSeat, detail)` (the seat
24
+ * from its own session, never from the page) and returns its `ReportDetailResult`. Without it the "Add a reason" step is not shown.
25
+ */
26
+ onAddDetail?: (reportId: string, detail: ReportFollowUp) => Promise<ReportDetailResult>;
27
+ /** Called on Escape, Cancel and Close. Unmount the dialog in answer. */
28
+ onClose: () => void;
29
+ /**
30
+ * How reporting works here: `(await createPlayerClient.rules()).reporting`, the `reporting` part of `GET /rules`. It sets the flow
31
+ * (one tap, pick a reason first, reason required), the reasons (grouped, with hints) and the thank-you. Without it the dialog is
32
+ * one tap with the dialog's own words, the same as when `GET /rules` cannot be loaded.
33
+ */
34
+ reporting?: PlayerReporting;
35
+ /** Who is being reported, as the player knows them (a handle). Shown as text in the heading. */
36
+ targetName?: string;
37
+ /** The message being reported. Shown as quoted text (cut if very long) so the player sees what they are reporting. */
38
+ line?: string;
39
+ }
40
+ /**
41
+ * A dialog for reporting a message or a player. How it works is the studio's setting (`reporting`, from `GET /rules`):
42
+ * - `one_tap` (the default): one step, "Report this message?" and a Report button. The report is filed at once and the thank-you
43
+ * shown; an optional "Add a reason" step then attaches a reason and a note to the same report (`onAddDetail`).
44
+ * - `reason_first`: the reasons in groups, then an optional note; a reason can be skipped.
45
+ * - `reason_required`: the same without the skip.
46
+ * The reason is only a hint for the moderators. Every refusal the kit can give has its own plain message. Render it when the player
47
+ * chooses to report, and unmount it in `onClose`.
48
+ */
49
+ export declare function ReportDialog(props: ReportDialogProps): import("react").JSX.Element;
50
+ //# sourceMappingURL=ReportDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReportDialog.d.ts","sourceRoot":"","sources":["../../src/ReportDialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAA6B,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAKrH,OAAO,KAAK,EAAmB,cAAc,EAAE,MAAM,eAAe,CAAC;AAMrE,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE9D;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,kGAAkG;IAClG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,MAAM,WAAW,iBAAkB,SAAQ,aAAa,EAAE,eAAe;IACvE;;;OAGG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IACxD;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACxF,wEAAwE;IACxE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sHAAsH;IACtH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAoCD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,+BA8MpD"}