@chatwarden/player-react 0.0.0-stage → 0.1.3
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.
- package/LICENSE +202 -0
- package/README.md +401 -2
- package/dist/src/Dialog.d.ts +13 -0
- package/dist/src/Dialog.d.ts.map +1 -0
- package/dist/src/Dialog.js +83 -0
- package/dist/src/Dialog.js.map +1 -0
- package/dist/src/MyRecord.d.ts +12 -0
- package/dist/src/MyRecord.d.ts.map +1 -0
- package/dist/src/MyRecord.js +17 -0
- package/dist/src/MyRecord.js.map +1 -0
- package/dist/src/NoticeQueue.d.ts +26 -0
- package/dist/src/NoticeQueue.d.ts.map +1 -0
- package/dist/src/NoticeQueue.js +90 -0
- package/dist/src/NoticeQueue.js.map +1 -0
- package/dist/src/ReportDialog.d.ts +64 -0
- package/dist/src/ReportDialog.d.ts.map +1 -0
- package/dist/src/ReportDialog.js +146 -0
- package/dist/src/ReportDialog.js.map +1 -0
- package/dist/src/RestrictedChatLine.d.ts +12 -0
- package/dist/src/RestrictedChatLine.d.ts.map +1 -0
- package/dist/src/RestrictedChatLine.js +19 -0
- package/dist/src/RestrictedChatLine.js.map +1 -0
- package/dist/src/RulesPage.d.ts +10 -0
- package/dist/src/RulesPage.d.ts.map +1 -0
- package/dist/src/RulesPage.js +17 -0
- package/dist/src/RulesPage.js.map +1 -0
- package/dist/src/client.d.ts +51 -0
- package/dist/src/client.d.ts.map +1 -0
- package/dist/src/client.js +98 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/constants.d.ts +5 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +5 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/format.d.ts +14 -0
- package/dist/src/format.d.ts.map +1 -0
- package/dist/src/format.js +55 -0
- package/dist/src/format.js.map +1 -0
- package/dist/src/hooks.d.ts +15 -0
- package/dist/src/hooks.d.ts.map +1 -0
- package/dist/src/hooks.js +29 -0
- package/dist/src/hooks.js.map +1 -0
- package/dist/src/i18n.d.ts +153 -0
- package/dist/src/i18n.d.ts.map +1 -0
- package/dist/src/i18n.js +191 -0
- package/dist/src/i18n.js.map +1 -0
- package/dist/src/index.d.ts +21 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +11 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/reporting.d.ts +20 -0
- package/dist/src/reporting.d.ts.map +1 -0
- package/dist/src/reporting.js +45 -0
- package/dist/src/reporting.js.map +1 -0
- package/dist/src/safeHref.d.ts +5 -0
- package/dist/src/safeHref.d.ts.map +1 -0
- package/dist/src/safeHref.js +41 -0
- package/dist/src/safeHref.js.map +1 -0
- package/dist/src/transport.d.ts +69 -0
- package/dist/src/transport.d.ts.map +1 -0
- package/dist/src/transport.js +74 -0
- package/dist/src/transport.js.map +1 -0
- package/dist/src/ui.d.ts +91 -0
- package/dist/src/ui.d.ts.map +1 -0
- package/dist/src/ui.js +116 -0
- package/dist/src/ui.js.map +1 -0
- package/package.json +73 -4
- package/src/Dialog.tsx +107 -0
- package/src/MyRecord.tsx +60 -0
- package/src/NoticeQueue.tsx +203 -0
- package/src/ReportDialog.tsx +319 -0
- package/src/RestrictedChatLine.tsx +42 -0
- package/src/RulesPage.tsx +49 -0
- package/src/client.ts +132 -0
- package/src/constants.ts +5 -0
- package/src/format.ts +53 -0
- package/src/hooks.ts +41 -0
- package/src/i18n.ts +211 -0
- package/src/index.ts +32 -0
- package/src/reporting.ts +51 -0
- package/src/safeHref.ts +36 -0
- package/src/styles.css +500 -0
- package/src/transport.ts +134 -0
- package/src/ui.tsx +199 -0
|
@@ -0,0 +1,83 @@
|
|
|
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
|
+
/** The controls Tab visits, in order. */
|
|
12
|
+
const tabStops = (box) => [...box.querySelectorAll(FOCUSABLE)];
|
|
13
|
+
export function Dialog({ labelledBy, initialFocus, onEscape, returnFocusTo, children, }) {
|
|
14
|
+
const box = useRef(null);
|
|
15
|
+
const fallback = useRef(returnFocusTo);
|
|
16
|
+
fallback.current = returnFocusTo;
|
|
17
|
+
// What had focus before the window opened, read while rendering for the first time: a child's own effect (which moves focus to
|
|
18
|
+
// its heading) runs before this component's effects, so reading it in an effect would find the heading.
|
|
19
|
+
const [before] = useState(() => (typeof document === 'undefined' ? null : document.activeElement));
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
(initialFocus.current ?? box.current)?.focus();
|
|
22
|
+
const onFocusIn = (e) => {
|
|
23
|
+
const target = e.target;
|
|
24
|
+
const inner = box.current;
|
|
25
|
+
if (inner !== null && target instanceof Node && !inner.contains(target))
|
|
26
|
+
(initialFocus.current ?? inner).focus();
|
|
27
|
+
};
|
|
28
|
+
document.addEventListener('focusin', onFocusIn);
|
|
29
|
+
return () => {
|
|
30
|
+
// Stop guarding first, so giving focus back is not pulled in again.
|
|
31
|
+
document.removeEventListener('focusin', onFocusIn);
|
|
32
|
+
// Give focus back, unless what had it is gone (the page moved on while the window was open): then to `returnFocusTo()`, if
|
|
33
|
+
// the host gave one, and otherwise to wherever the browser leaves it (the page body).
|
|
34
|
+
if (before instanceof HTMLElement && before.isConnected)
|
|
35
|
+
before.focus();
|
|
36
|
+
else {
|
|
37
|
+
try {
|
|
38
|
+
fallback.current?.()?.focus();
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// A host callback that throws must not stop the window closing.
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
// Once, when the window opens.
|
|
46
|
+
}, []);
|
|
47
|
+
const onKeyDown = (e) => {
|
|
48
|
+
if (e.key === 'Escape') {
|
|
49
|
+
if (onEscape === undefined)
|
|
50
|
+
return;
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
e.stopPropagation();
|
|
53
|
+
onEscape();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (e.key !== 'Tab' || box.current === null)
|
|
57
|
+
return;
|
|
58
|
+
const items = tabStops(box.current);
|
|
59
|
+
if (items.length === 0) {
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const first = items[0];
|
|
64
|
+
const last = items[items.length - 1];
|
|
65
|
+
const active = document.activeElement;
|
|
66
|
+
// From the heading (or the box), which is not in the list, Tab goes to the first control and Shift+Tab to the last.
|
|
67
|
+
const inList = items.includes(active);
|
|
68
|
+
if (e.shiftKey && (active === first || !inList)) {
|
|
69
|
+
e.preventDefault();
|
|
70
|
+
last.focus();
|
|
71
|
+
}
|
|
72
|
+
else if (!e.shiftKey && (active === last || !inList)) {
|
|
73
|
+
e.preventDefault();
|
|
74
|
+
first.focus();
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
return (_jsx("div", { className: "cw-scrim", onMouseDown: (e) => {
|
|
78
|
+
// 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.
|
|
79
|
+
if (e.target === e.currentTarget)
|
|
80
|
+
e.preventDefault();
|
|
81
|
+
}, children: _jsx("div", { ref: box, className: "cw-dialog", role: "dialog", "aria-modal": "true", "aria-labelledby": labelledBy, tabIndex: -1, onKeyDown: onKeyDown, children: children }) }));
|
|
82
|
+
}
|
|
83
|
+
//# 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,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,64 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { PlayerReporting, ReportDetailResult, ReportResult } from '@chatwarden/core';
|
|
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) and `note` in the one report. A
|
|
7
|
+
* reason is only a 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
|
+
/**
|
|
16
|
+
* A reason and a note added to a report after it was filed (`cw.reports.addDetail`). The dialog no longer has a follow-up step (the
|
|
17
|
+
* reason and the note go in the one report), so this is only the shape a follow-up of your own may take.
|
|
18
|
+
*/
|
|
19
|
+
export interface ReportFollowUp {
|
|
20
|
+
reason?: string;
|
|
21
|
+
note?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface ReportDialogProps extends PlayerUiProps, DialogHostProps {
|
|
24
|
+
/**
|
|
25
|
+
* Sends the report: your server calls `cw.reports.submit({ ...draft, roomId, reporterSeat, targetSeat })` and returns its
|
|
26
|
+
* `ReportResult`. A refusal is a result, not an error; reject only when no answer arrived.
|
|
27
|
+
*/
|
|
28
|
+
onSubmit: (draft: ReportDraft) => Promise<ReportResult>;
|
|
29
|
+
/**
|
|
30
|
+
* @deprecated The dialog is one step now: the reason and the note go in the single `onSubmit`, so this is accepted but never
|
|
31
|
+
* called. Remove it. (`cw.reports.addDetail` is still there for a follow-up of your own.)
|
|
32
|
+
*/
|
|
33
|
+
onAddDetail?: (reportId: string, detail: ReportFollowUp) => Promise<ReportDetailResult>;
|
|
34
|
+
/** Called on Escape, Cancel and Close. Unmount the dialog in answer. */
|
|
35
|
+
onClose: () => void;
|
|
36
|
+
/**
|
|
37
|
+
* How reporting works here: `(await createPlayerClient.rules()).reporting`, the `reporting` part of `GET /rules`. It gives the
|
|
38
|
+
* reasons (grouped, with hints), whether a reason is required, and the thank-you. Without it the dialog has no reasons to offer:
|
|
39
|
+
* one press files the report, with the dialog's own words, the same as when `GET /rules` cannot be loaded.
|
|
40
|
+
*/
|
|
41
|
+
reporting?: PlayerReporting;
|
|
42
|
+
/** Who is being reported, as the player knows them (a handle). Shown as text in the heading. */
|
|
43
|
+
targetName?: string;
|
|
44
|
+
/** The message being reported. Shown as quoted text (cut if very long) so the player sees what they are reporting. */
|
|
45
|
+
line?: string;
|
|
46
|
+
/**
|
|
47
|
+
* @experimental Your own controls, placed inside the form under the reason and the note and above Report and Cancel (for example
|
|
48
|
+
* an "Also mute this player" checkbox and a line about false reports). You own their state; the dialog only places them, adds no
|
|
49
|
+
* styling beyond the spacing, and keeps their focusable controls in its Tab order (reason, note, yours, Report, Cancel) and its
|
|
50
|
+
* focus trap. They are not shown once the report is sent. They sit inside the dialog's form, so give your buttons `type="button"`:
|
|
51
|
+
* a plain button, or Enter in a text field of yours, sends the report.
|
|
52
|
+
*/
|
|
53
|
+
extra?: ReactNode;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* A dialog for reporting a message or a player, in one step: "Report this message?", the quoted line, an optional "Why?" (one
|
|
57
|
+
* select, the reasons in groups) and a Report button. A note is behind "Add a note", or shown when the chosen reason asks for one.
|
|
58
|
+
* Report sends the reason and the note together (`onSubmit`); the dialog then says "Report sent" and the thank-you. The studio's
|
|
59
|
+
* `reporting` setting decides whether the reason is required (`reason_required`: the select is required, and Report without a
|
|
60
|
+
* reason asks for one and sends nothing), what the reasons are, and the thank-you. The reason is only a hint for the moderators.
|
|
61
|
+
* Every refusal the kit can give has its own plain message. Render it when the player chooses to report, and unmount it in `onClose`.
|
|
62
|
+
*/
|
|
63
|
+
export declare function ReportDialog(props: ReportDialogProps): import("react").JSX.Element;
|
|
64
|
+
//# sourceMappingURL=ReportDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReportDialog.d.ts","sourceRoot":"","sources":["../../src/ReportDialog.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAa,SAAS,EAAE,MAAM,OAAO,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAiB,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAOzG,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;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,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;IACd;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AA6BD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,+BA0NpD"}
|
|
@@ -0,0 +1,146 @@
|
|
|
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 { NOTE_MAX } from './constants.js';
|
|
4
|
+
import { PlayerError } from './client.js';
|
|
5
|
+
import { Dialog } from './Dialog.js';
|
|
6
|
+
import { groupReasons, readReporting } from './reporting.js';
|
|
7
|
+
import { errorText, Portal, Root, useUi } from './ui.js';
|
|
8
|
+
// One plain message for each refusal the kit has. Anything else (a refusal a newer kit adds) gets the last one.
|
|
9
|
+
const REFUSED_TEXT = {
|
|
10
|
+
duplicate: 'player.report.refused.duplicate',
|
|
11
|
+
rate: 'player.report.refused.rate',
|
|
12
|
+
self: 'player.report.refused.self',
|
|
13
|
+
not_player: 'player.report.refused.not_player',
|
|
14
|
+
off: 'player.report.refused.off',
|
|
15
|
+
suspended: 'player.report.refused.suspended',
|
|
16
|
+
reason_required: 'player.report.refused.reason_required',
|
|
17
|
+
reason_unknown: 'player.report.refused.reason_unknown',
|
|
18
|
+
};
|
|
19
|
+
/** How much of the reported message is quoted on the screen. */
|
|
20
|
+
const LINE_MAX = 280;
|
|
21
|
+
/** A failure to send as an error the components can word: anything that is not already a PlayerError is a dropped connection. */
|
|
22
|
+
const failureOf = (e) => e instanceof PlayerError ? e : new PlayerError({ status: 0, code: 'network', message: 'Could not reach the server.' });
|
|
23
|
+
/** 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. */
|
|
24
|
+
const resultOf = (answer, unknown) => (typeof answer === 'object' && answer !== null && !Array.isArray(answer) ? answer : unknown);
|
|
25
|
+
const quoted = (line) => {
|
|
26
|
+
const plain = (line ?? '').replace(/\s+/g, ' ').trim();
|
|
27
|
+
return plain.length > LINE_MAX ? `${plain.slice(0, LINE_MAX).trimEnd()}…` : plain;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* A dialog for reporting a message or a player, in one step: "Report this message?", the quoted line, an optional "Why?" (one
|
|
31
|
+
* select, the reasons in groups) and a Report button. A note is behind "Add a note", or shown when the chosen reason asks for one.
|
|
32
|
+
* Report sends the reason and the note together (`onSubmit`); the dialog then says "Report sent" and the thank-you. The studio's
|
|
33
|
+
* `reporting` setting decides whether the reason is required (`reason_required`: the select is required, and Report without a
|
|
34
|
+
* reason asks for one and sends nothing), what the reasons are, and the thank-you. The reason is only a hint for the moderators.
|
|
35
|
+
* Every refusal the kit can give has its own plain message. Render it when the player chooses to report, and unmount it in `onClose`.
|
|
36
|
+
*/
|
|
37
|
+
export function ReportDialog(props) {
|
|
38
|
+
const { onSubmit, onClose, targetName, line, theme, className, container, returnFocusTo, extra } = props;
|
|
39
|
+
const ui = useUi(props);
|
|
40
|
+
const { t } = ui;
|
|
41
|
+
const heading = useRef(null);
|
|
42
|
+
const select = useRef(null);
|
|
43
|
+
const noteField = useRef(null);
|
|
44
|
+
// One report on its way at a time: a second click, or a second Enter, does nothing.
|
|
45
|
+
const sending = useRef(false);
|
|
46
|
+
const titleId = useId();
|
|
47
|
+
const reasonId = useId();
|
|
48
|
+
const noteId = useId();
|
|
49
|
+
const noteHintId = useId();
|
|
50
|
+
const reasonHintId = useId();
|
|
51
|
+
const missingId = useId();
|
|
52
|
+
const [reason, setReason] = useState('');
|
|
53
|
+
const [note, setNote] = useState('');
|
|
54
|
+
// The note is shown once it was asked for (the "Add a note" button, or a reason that asks for one) and then stays.
|
|
55
|
+
const [noteOpen, setNoteOpen] = useState(false);
|
|
56
|
+
const [focusNote, setFocusNote] = useState(false);
|
|
57
|
+
const [missing, setMissing] = useState(false);
|
|
58
|
+
const [busy, setBusy] = useState(false);
|
|
59
|
+
const [failure, setFailure] = useState(null);
|
|
60
|
+
const [result, setResult] = useState(null);
|
|
61
|
+
// No `reporting` (or something that is not the payload): no reasons to offer, as when `GET /rules` cannot be loaded.
|
|
62
|
+
const read = readReporting(props.reporting) ?? { flow: 'one_tap', reasons: [], thanks: '' };
|
|
63
|
+
const thanks = read.thanks.trim();
|
|
64
|
+
const hasReasons = read.reasons.length > 0;
|
|
65
|
+
// A flow that asks for a reason has nothing to ask with when the list is empty.
|
|
66
|
+
const required = hasReasons && read.flow === 'reason_required';
|
|
67
|
+
const groups = groupReasons(read.reasons);
|
|
68
|
+
const named = groups.filter((g) => g.name !== '');
|
|
69
|
+
const bare = groups.filter((g) => g.name === '').flatMap((g) => g.items);
|
|
70
|
+
// The reason is read from the CURRENT list: if `reporting` changes while the dialog is open and the id the player chose is gone, the
|
|
71
|
+
// select shows the placeholder, and this is undefined, so nothing stale is sent (and a required reason is asked for again).
|
|
72
|
+
const chosen = read.reasons.find((r) => r.id === reason);
|
|
73
|
+
const reasonValue = chosen === undefined ? '' : chosen.id;
|
|
74
|
+
const hint = chosen !== undefined && chosen.hint !== '' ? chosen.hint : null;
|
|
75
|
+
const noteShown = hasReasons && noteOpen;
|
|
76
|
+
// The form is gone once there is an answer: focus goes back to the heading, so the answer is read and focus is not lost.
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (result !== null)
|
|
79
|
+
heading.current?.focus();
|
|
80
|
+
}, [result]);
|
|
81
|
+
// "Add a note" is replaced by the field: focus follows it.
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (focusNote) {
|
|
84
|
+
noteField.current?.focus();
|
|
85
|
+
setFocusNote(false);
|
|
86
|
+
}
|
|
87
|
+
}, [focusNote]);
|
|
88
|
+
const send = async (draft) => {
|
|
89
|
+
sending.current = true;
|
|
90
|
+
setBusy(true);
|
|
91
|
+
setFailure(null);
|
|
92
|
+
try {
|
|
93
|
+
setResult(resultOf(await onSubmit(draft), { ok: false, refused: 'unknown' }));
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
setFailure(failureOf(error));
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
sending.current = false;
|
|
100
|
+
setBusy(false);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
const trimmed = note.trim();
|
|
104
|
+
const submit = (e) => {
|
|
105
|
+
e.preventDefault();
|
|
106
|
+
if (sending.current)
|
|
107
|
+
return;
|
|
108
|
+
if (required && reasonValue === '') {
|
|
109
|
+
setMissing(true);
|
|
110
|
+
select.current?.focus();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const draft = {};
|
|
114
|
+
if (reasonValue !== '')
|
|
115
|
+
draft.reason = reasonValue;
|
|
116
|
+
if (noteShown && trimmed !== '')
|
|
117
|
+
draft.note = trimmed;
|
|
118
|
+
void send(draft);
|
|
119
|
+
};
|
|
120
|
+
const quote = quoted(line);
|
|
121
|
+
const title = quote !== '' ? t('player.report.titleOneTap') : targetName === undefined ? t('player.report.titleOneTapPlayer') : t('player.report.titleOneTapNamed', { name: targetName });
|
|
122
|
+
const taken = result?.ok === true;
|
|
123
|
+
const refusal = result !== null && !taken ? result : null;
|
|
124
|
+
// After an answer the heading says what happened (a question would be stale), and focus is on it.
|
|
125
|
+
const shownTitle = result === null ? title : taken ? t('player.report.titleSent') : t('player.report.titleRefused');
|
|
126
|
+
const remaining = taken && typeof result.remaining === 'number' && Number.isFinite(result.remaining) && result.remaining >= 0 ? result.remaining : null;
|
|
127
|
+
const refusedKey = (r) => {
|
|
128
|
+
const refused = r.refused;
|
|
129
|
+
return typeof refused === 'string' && Object.hasOwn(REFUSED_TEXT, refused) ? REFUSED_TEXT[refused] : 'player.report.refused.unknown';
|
|
130
|
+
};
|
|
131
|
+
const option = (r) => (_jsx("option", { value: r.id, children: r.label }, r.id));
|
|
132
|
+
const describedBy = [hint === null ? '' : reasonHintId, missing ? missingId : ''].filter((id) => id !== '').join(' ');
|
|
133
|
+
return (_jsx(Portal, { container: container, children: _jsx(Root, { theme: theme, className: className, children: _jsxs(Dialog, { labelledBy: titleId, initialFocus: heading, onEscape: () => !sending.current && onClose(), ...(returnFocusTo === undefined ? {} : { returnFocusTo }), children: [_jsx("h2", { id: titleId, ref: heading, className: "cw-title", tabIndex: -1, children: shownTitle }), _jsx("div", { role: "status", className: "cw-live", children: taken && (_jsxs("p", { className: "cw-result", children: [thanks === '' ? t('player.report.thanks') : thanks, remaining !== null && ` ${t('player.report.remaining', { count: remaining })}`] })) }), result === null ? (_jsxs("form", { onSubmit: submit, noValidate: true, children: [_jsx("p", { className: "cw-body", children: required ? t('player.report.intro') : t('player.report.oneTap.intro') }), quote !== '' && _jsx("blockquote", { className: "cw-quote", children: t('player.report.quote', { line: quote }) }), hasReasons && (_jsxs("div", { className: "cw-field", children: [_jsx("label", { className: "cw-label", htmlFor: reasonId, children: required ? t('player.report.whyRequired') : t('player.report.why') }), _jsxs("select", { id: reasonId, ref: select, className: "cw-select", value: reasonValue, required: required, "aria-invalid": missing || undefined, "aria-describedby": describedBy === '' ? undefined : describedBy, onChange: (e) => {
|
|
134
|
+
const id = e.target.value;
|
|
135
|
+
setReason(id);
|
|
136
|
+
setMissing(false);
|
|
137
|
+
if (read.reasons.find((r) => r.id === id)?.asksNote === true)
|
|
138
|
+
setNoteOpen(true);
|
|
139
|
+
}, children: [_jsx("option", { value: "", children: required ? t('player.report.chooseRequired') : t('player.report.choose') }), named.map((g) => (_jsx("optgroup", { label: g.name, children: g.items.map(option) }, g.name))), bare.map(option)] }), hint !== null && (_jsx("p", { id: reasonHintId, className: "cw-hint", children: hint })), missing && (_jsx("p", { id: missingId, className: "cw-field-error", role: "alert", children: t('player.report.needReason') }))] })), noteShown && (_jsxs("div", { className: "cw-field", children: [_jsx("label", { className: "cw-label", htmlFor: noteId, children: t('player.report.note') }), _jsx("textarea", { id: noteId, ref: noteField, className: "cw-textarea", rows: 3, maxLength: NOTE_MAX, value: note, "aria-describedby": noteHintId, onChange: (e) => setNote(e.target.value) }), _jsx("p", { id: noteHintId, className: "cw-hint", children: t('player.report.noteHint', { max: NOTE_MAX }) })] })), hasReasons && !noteShown && (
|
|
140
|
+
// No aria-expanded: this is a one-way door. It is removed when pressed (the note takes its place) and focus moves to the note.
|
|
141
|
+
_jsx("button", { type: "button", className: "cw-linkbtn", onClick: () => {
|
|
142
|
+
setNoteOpen(true);
|
|
143
|
+
setFocusNote(true);
|
|
144
|
+
}, children: t('player.report.addNote') })), extra !== undefined && extra !== null && extra !== false && _jsx("div", { className: "cw-extra", children: extra }), failure !== null && (_jsxs("p", { className: "cw-error", role: "alert", children: [t('player.report.failed'), " ", errorText(t, failure)] })), _jsxs("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.oneTap.send') }), _jsx("button", { type: "button", className: "cw-btn", "aria-disabled": busy || undefined, onClick: () => !sending.current && onClose(), children: t('player.report.cancel') })] })] })) : (_jsxs(_Fragment, { children: [!taken && (_jsx("p", { className: "cw-error", role: "alert", children: t(refusedKey(refusal)) })), _jsx("div", { className: "cw-actions", children: _jsx("button", { type: "button", className: "cw-btn cw-btn--primary", "aria-disabled": busy || undefined, onClick: () => !sending.current && onClose(), children: t('player.report.close') }) })] }))] }) }) }));
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=ReportDialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReportDialog.js","sourceRoot":"","sources":["../../src/ReportDialog.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PlayerUiProps } from './ui.js';
|
|
2
|
+
export interface RestrictedChatLineProps extends PlayerUiProps {
|
|
3
|
+
/** When the restriction ends (epoch ms), or `null` for no end. From `cw.chat.restricted(...)`. */
|
|
4
|
+
until: number | null;
|
|
5
|
+
/** `true` when a moderator turned the chat off, `false` when the automatic filter did (kind `auto`). */
|
|
6
|
+
byModerator: boolean;
|
|
7
|
+
/** The reference code to quote to a moderator, when you have one. */
|
|
8
|
+
refCode?: string;
|
|
9
|
+
}
|
|
10
|
+
/** One line for the place a chat box would be, saying why the player cannot type, until when, and who did it. */
|
|
11
|
+
export declare function RestrictedChatLine(props: RestrictedChatLineProps): import("react").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=RestrictedChatLine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RestrictedChatLine.d.ts","sourceRoot":"","sources":["../../src/RestrictedChatLine.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,MAAM,WAAW,uBAAwB,SAAQ,aAAa;IAC5D,kGAAkG;IAClG,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,wGAAwG;IACxG,WAAW,EAAE,OAAO,CAAC;IACrB,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,iHAAiH;AACjH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,+BA2BhE"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { timeLeft, untilText } from './format.js';
|
|
3
|
+
import { Card, Root, useUi } from './ui.js';
|
|
4
|
+
/** One line for the place a chat box would be, saying why the player cannot type, until when, and who did it. */
|
|
5
|
+
export function RestrictedChatLine(props) {
|
|
6
|
+
const { until, byModerator, refCode, theme, className } = props;
|
|
7
|
+
const ui = useUi(props);
|
|
8
|
+
const { t, locale, timeZone } = ui;
|
|
9
|
+
const ends = typeof until === 'number' && Number.isFinite(until);
|
|
10
|
+
const when = ends ? untilText(until, locale, timeZone) : '';
|
|
11
|
+
const left = ends ? timeLeft(until, ui.now(), locale) : null;
|
|
12
|
+
const text = !ends
|
|
13
|
+
? t(byModerator ? 'player.restricted.moderator.noEnd' : 'player.restricted.filter.noEnd')
|
|
14
|
+
: left === null
|
|
15
|
+
? t('player.restricted.ended', { when })
|
|
16
|
+
: t(byModerator ? 'player.restricted.moderator.until' : 'player.restricted.filter.until', { when, left });
|
|
17
|
+
return (_jsx(Root, { theme: theme, className: className, children: _jsxs("p", { className: "cw-restricted", role: "status", children: [_jsx(Card, { kind: "chat" }), _jsx("span", { className: "cw-text", children: text }), refCode !== undefined && (_jsxs(_Fragment, { children: [' ', _jsx("span", { className: "cw-ref", children: t('player.restricted.ref', { code: refCode }) })] }))] }) }));
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=RestrictedChatLine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RestrictedChatLine.js","sourceRoot":"","sources":["../../src/RestrictedChatLine.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAY5C,iHAAiH;AACjH,MAAM,UAAU,kBAAkB,CAAC,KAA8B;IAC/D,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAChE,MAAM,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IACxB,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACjE,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,MAAM,IAAI,GAAG,CAAC,IAAI;QAChB,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC,gCAAgC,CAAC;QACzF,CAAC,CAAC,IAAI,KAAK,IAAI;YACb,CAAC,CAAC,CAAC,CAAC,yBAAyB,EAAE,EAAE,IAAI,EAAE,CAAC;YACxC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC,gCAAgC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAE9G,OAAO,CACL,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,YACtC,aAAG,SAAS,EAAC,eAAe,EAAC,IAAI,EAAC,QAAQ,aACxC,KAAC,IAAI,IAAC,IAAI,EAAC,MAAM,GAAG,EACpB,eAAM,SAAS,EAAC,SAAS,YAAE,IAAI,GAAQ,EACtC,OAAO,KAAK,SAAS,IAAI,CACxB,8BACG,GAAG,EACJ,eAAM,SAAS,EAAC,QAAQ,YAAE,CAAC,CAAC,uBAAuB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,GAAQ,IAC9E,CACJ,IACC,GACC,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PlayerClient } from './client.js';
|
|
2
|
+
import type { PlayerUiProps } from './ui.js';
|
|
3
|
+
export interface RulesPageProps extends PlayerUiProps {
|
|
4
|
+
client: PlayerClient;
|
|
5
|
+
/** Change it to load the rules again. */
|
|
6
|
+
refreshKey?: number | string;
|
|
7
|
+
}
|
|
8
|
+
/** The community rules: the profile's summary and the numbered rules from `GET /rules`. Text only, never HTML. */
|
|
9
|
+
export declare function RulesPage(props: RulesPageProps): import("react").JSX.Element;
|
|
10
|
+
//# sourceMappingURL=RulesPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RulesPage.d.ts","sourceRoot":"","sources":["../../src/RulesPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,MAAM,EAAE,YAAY,CAAC;IACrB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9B;AAED,kHAAkH;AAClH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,+BAmC9C"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useId } from 'react';
|
|
3
|
+
import { usePlayerData } from './hooks.js';
|
|
4
|
+
import { ErrorBlock, Root, useUi } from './ui.js';
|
|
5
|
+
/** The community rules: the profile's summary and the numbered rules from `GET /rules`. Text only, never HTML. */
|
|
6
|
+
export function RulesPage(props) {
|
|
7
|
+
const { client, refreshKey, theme, className } = props;
|
|
8
|
+
const ui = useUi(props);
|
|
9
|
+
const { t } = ui;
|
|
10
|
+
const state = usePlayerData(() => client.rules(), refreshKey);
|
|
11
|
+
const titleId = useId();
|
|
12
|
+
const data = state.data;
|
|
13
|
+
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.rules.title') }), state.error !== null && _jsx(ErrorBlock, { ui: ui, what: t('player.rules.loadFailed'), error: state.error, onRetry: state.reload }), data === undefined && state.error === null && (_jsx("p", { className: "cw-state", role: "status", children: t('player.rules.loading') })), data !== undefined && data.summary !== '' && _jsx("p", { className: "cw-summary", children: data.summary }), data !== undefined && data.rules.length === 0 && _jsx("p", { className: "cw-state", children: t('player.rules.empty') }), data !== undefined && data.rules.length > 0 && (
|
|
14
|
+
// The kit's own numbers, so a retired rule leaves a gap instead of renumbering the ones after it.
|
|
15
|
+
_jsx("ol", { className: "cw-rules", "aria-labelledby": titleId, children: data.rules.map((rule) => (_jsxs("li", { value: rule.number, children: [_jsx("strong", { className: "cw-rule-title", children: rule.title }), " ", _jsx("span", { className: "cw-rule-text", children: rule.text })] }, rule.number))) }))] }) }));
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=RulesPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RulesPage.js","sourceRoot":"","sources":["../../src/RulesPage.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAE9B,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AASlD,kHAAkH;AAClH,MAAM,UAAU,SAAS,CAAC,KAAqB;IAC7C,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IACvD,MAAM,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IACxB,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC;IACjB,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,UAAU,CAAC,CAAC;IAC9D,MAAM,OAAO,GAAG,KAAK,EAAE,CAAC;IACxB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IAExB,OAAO,CACL,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,YACtC,mBAAS,SAAS,EAAC,YAAY,qBAAkB,OAAO,aACtD,aAAI,EAAE,EAAE,OAAO,EAAE,SAAS,EAAC,UAAU,YAClC,CAAC,CAAC,oBAAoB,CAAC,GACrB,EACJ,KAAK,CAAC,KAAK,KAAK,IAAI,IAAI,KAAC,UAAU,IAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,yBAAyB,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,GAAI,EAC7H,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI,IAAI,CAC7C,YAAG,SAAS,EAAC,UAAU,EAAC,IAAI,EAAC,QAAQ,YAClC,CAAC,CAAC,sBAAsB,CAAC,GACxB,CACL,EACA,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,EAAE,IAAI,YAAG,SAAS,EAAC,YAAY,YAAE,IAAI,CAAC,OAAO,GAAK,EACzF,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,YAAG,SAAS,EAAC,UAAU,YAAE,CAAC,CAAC,oBAAoB,CAAC,GAAK,EACtG,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI;gBAC9C,kGAAkG;gBAClG,aAAI,SAAS,EAAC,UAAU,qBAAkB,OAAO,YAC9C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACxB,cAAsB,KAAK,EAAE,IAAI,CAAC,MAAM,aACtC,iBAAQ,SAAS,EAAC,eAAe,YAAE,IAAI,CAAC,KAAK,GAAU,OAAC,eAAM,SAAS,EAAC,cAAc,YAAE,IAAI,CAAC,IAAI,GAAQ,KADlG,IAAI,CAAC,MAAM,CAEf,CACN,CAAC,GACC,CACN,IACO,GACL,CACR,CAAC;AACJ,CAAC"}
|