@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.
Files changed (84) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +401 -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 +83 -0
  6. package/dist/src/Dialog.js.map +1 -0
  7. package/dist/src/MyRecord.d.ts +12 -0
  8. package/dist/src/MyRecord.d.ts.map +1 -0
  9. package/dist/src/MyRecord.js +17 -0
  10. package/dist/src/MyRecord.js.map +1 -0
  11. package/dist/src/NoticeQueue.d.ts +26 -0
  12. package/dist/src/NoticeQueue.d.ts.map +1 -0
  13. package/dist/src/NoticeQueue.js +90 -0
  14. package/dist/src/NoticeQueue.js.map +1 -0
  15. package/dist/src/ReportDialog.d.ts +64 -0
  16. package/dist/src/ReportDialog.d.ts.map +1 -0
  17. package/dist/src/ReportDialog.js +146 -0
  18. package/dist/src/ReportDialog.js.map +1 -0
  19. package/dist/src/RestrictedChatLine.d.ts +12 -0
  20. package/dist/src/RestrictedChatLine.d.ts.map +1 -0
  21. package/dist/src/RestrictedChatLine.js +19 -0
  22. package/dist/src/RestrictedChatLine.js.map +1 -0
  23. package/dist/src/RulesPage.d.ts +10 -0
  24. package/dist/src/RulesPage.d.ts.map +1 -0
  25. package/dist/src/RulesPage.js +17 -0
  26. package/dist/src/RulesPage.js.map +1 -0
  27. package/dist/src/client.d.ts +51 -0
  28. package/dist/src/client.d.ts.map +1 -0
  29. package/dist/src/client.js +98 -0
  30. package/dist/src/client.js.map +1 -0
  31. package/dist/src/constants.d.ts +5 -0
  32. package/dist/src/constants.d.ts.map +1 -0
  33. package/dist/src/constants.js +5 -0
  34. package/dist/src/constants.js.map +1 -0
  35. package/dist/src/format.d.ts +14 -0
  36. package/dist/src/format.d.ts.map +1 -0
  37. package/dist/src/format.js +55 -0
  38. package/dist/src/format.js.map +1 -0
  39. package/dist/src/hooks.d.ts +15 -0
  40. package/dist/src/hooks.d.ts.map +1 -0
  41. package/dist/src/hooks.js +29 -0
  42. package/dist/src/hooks.js.map +1 -0
  43. package/dist/src/i18n.d.ts +153 -0
  44. package/dist/src/i18n.d.ts.map +1 -0
  45. package/dist/src/i18n.js +191 -0
  46. package/dist/src/i18n.js.map +1 -0
  47. package/dist/src/index.d.ts +21 -0
  48. package/dist/src/index.d.ts.map +1 -0
  49. package/dist/src/index.js +11 -0
  50. package/dist/src/index.js.map +1 -0
  51. package/dist/src/reporting.d.ts +20 -0
  52. package/dist/src/reporting.d.ts.map +1 -0
  53. package/dist/src/reporting.js +45 -0
  54. package/dist/src/reporting.js.map +1 -0
  55. package/dist/src/safeHref.d.ts +5 -0
  56. package/dist/src/safeHref.d.ts.map +1 -0
  57. package/dist/src/safeHref.js +41 -0
  58. package/dist/src/safeHref.js.map +1 -0
  59. package/dist/src/transport.d.ts +69 -0
  60. package/dist/src/transport.d.ts.map +1 -0
  61. package/dist/src/transport.js +74 -0
  62. package/dist/src/transport.js.map +1 -0
  63. package/dist/src/ui.d.ts +91 -0
  64. package/dist/src/ui.d.ts.map +1 -0
  65. package/dist/src/ui.js +116 -0
  66. package/dist/src/ui.js.map +1 -0
  67. package/package.json +73 -4
  68. package/src/Dialog.tsx +107 -0
  69. package/src/MyRecord.tsx +60 -0
  70. package/src/NoticeQueue.tsx +203 -0
  71. package/src/ReportDialog.tsx +319 -0
  72. package/src/RestrictedChatLine.tsx +42 -0
  73. package/src/RulesPage.tsx +49 -0
  74. package/src/client.ts +132 -0
  75. package/src/constants.ts +5 -0
  76. package/src/format.ts +53 -0
  77. package/src/hooks.ts +41 -0
  78. package/src/i18n.ts +211 -0
  79. package/src/index.ts +32 -0
  80. package/src/reporting.ts +51 -0
  81. package/src/safeHref.ts +36 -0
  82. package/src/styles.css +500 -0
  83. package/src/transport.ts +134 -0
  84. package/src/ui.tsx +199 -0
@@ -0,0 +1,191 @@
1
+ // Every word the player components show is a key in this catalog; components never hold English.
2
+ //
3
+ // Key naming: `player.<area>.<thing>[.<detail>]`, lower camel case segments, for example `player.notice.title.warning`.
4
+ // Areas: error, state, notice, notices, record, rules, restricted, report.
5
+ // Plural forms add the CLDR category as the last segment: `player.report.remaining.one`, `.other`. A caller asks for the base
6
+ // key with a numeric `count` (`t('player.report.remaining', { count: 3 })`); `.zero` is used for 0 when it exists.
7
+ // `{name}` marks a value to fill in. To translate, spread this catalog over yours so a missing key falls back to English:
8
+ // `createT({ ...en, ...de }, 'de')`.
9
+ //
10
+ // The copy is written for a player in the middle of a game: second person, sentence case, plain words, and never shaming. It says
11
+ // what happened, until when, and what the player can do.
12
+ export const en = {
13
+ 'player.error.network': 'Could not reach the server. Check your connection and try again.',
14
+ 'player.error.unauthorized': 'You are signed out. Sign in again, then try again.',
15
+ 'player.error.forbidden': 'This account cannot do that.',
16
+ 'player.error.notFound': 'That could not be found.',
17
+ 'player.error.rateLimited': 'Too many requests. Try again in a moment.',
18
+ 'player.error.rateLimited.after.one': 'Too many requests. Try again in {count} second.',
19
+ 'player.error.rateLimited.after.other': 'Too many requests. Try again in {count} seconds.',
20
+ 'player.error.server': 'The server had a problem. Try again in a moment.',
21
+ 'player.error.generic': 'Something went wrong.',
22
+ 'player.state.retry': 'Try again',
23
+ 'player.notices.loadFailed': 'We could not check for notices.',
24
+ 'player.notice.title.warning': 'You have a warning',
25
+ 'player.notice.title.chat': 'Your chat is turned off',
26
+ 'player.notice.title.area': 'You cannot join public rooms',
27
+ 'player.notice.title.ban': 'You are banned',
28
+ 'player.notice.title.report_outcome': 'Thanks for your report',
29
+ 'player.notice.title.fallback': 'A message from the moderators',
30
+ 'player.notice.body.warning': 'A moderator gave you a warning for something you wrote. You can keep playing.',
31
+ 'player.notice.body.chat': 'A moderator turned off your chat. You can still play.',
32
+ 'player.notice.body.area': 'A moderator stopped you joining public rooms and matchmaking. You can still play in private rooms.',
33
+ 'player.notice.body.ban': 'A moderator banned you from playing.',
34
+ 'player.notice.body.report_outcome': 'A moderator looked at your report and took action. We do not share what was done.',
35
+ 'player.notice.body.fallback': 'There is a new message about your account.',
36
+ 'player.notice.position': 'Notice {n} of {total}',
37
+ 'player.notice.rule': 'Rule',
38
+ 'player.notice.given': 'Given',
39
+ 'player.notice.until': 'Until',
40
+ 'player.notice.ended': 'Ended',
41
+ 'player.notice.noEnd': 'No end date',
42
+ 'player.notice.onRecordUntil': 'On your record until',
43
+ 'player.notice.untilLeft': '{when} ({left})',
44
+ 'player.notice.ref': 'Reference',
45
+ 'player.notice.refHint': 'Quote this code if you contact us.',
46
+ 'player.notice.lines': 'Your messages that led to this',
47
+ 'player.notice.todo.warning': 'Press Acknowledge to confirm you saw this.',
48
+ 'player.notice.acknowledge': 'Acknowledge',
49
+ 'player.notice.gotIt': 'Got it',
50
+ 'player.notice.appeal': 'Think this is a mistake?',
51
+ 'player.notice.ackFailed': 'Your notice is still here.',
52
+ 'player.notice.closeForNow': 'Close for now',
53
+ 'player.record.title': 'Your record',
54
+ 'player.record.loading': 'Loading your record',
55
+ 'player.record.loadFailed': 'We could not load your record.',
56
+ 'player.record.intro': 'This is what is on your record now. A warning stays for {days} days.',
57
+ 'player.record.empty': 'Your record is clear. Nothing is on it right now.',
58
+ 'player.record.kind.warning': 'Warning',
59
+ 'player.record.kind.chat': 'Chat restriction',
60
+ 'player.record.kind.area': 'Public rooms restriction',
61
+ 'player.record.kind.ban': 'Ban',
62
+ 'player.record.kind.fallback': 'Notice',
63
+ 'player.rules.title': 'Community rules',
64
+ 'player.rules.loading': 'Loading the rules',
65
+ 'player.rules.loadFailed': 'We could not load the rules.',
66
+ 'player.rules.empty': 'No rules are published yet.',
67
+ 'player.restricted.moderator.until': 'A moderator turned off your chat until {when} ({left}).',
68
+ 'player.restricted.moderator.noEnd': 'A moderator turned off your chat. It does not end on its own.',
69
+ 'player.restricted.filter.until': 'Your chat is off until {when} ({left}). The automatic filter caught a message.',
70
+ 'player.restricted.filter.noEnd': 'Your chat is off. It does not end on its own. The automatic filter caught a message.',
71
+ 'player.restricted.ended': 'Your chat is back on. The restriction ended {when}.',
72
+ 'player.restricted.ref': 'Reference {code}',
73
+ /** @deprecated unused since 0.1.3; removed in a later minor */
74
+ 'player.report.title': 'Report a player',
75
+ /** @deprecated unused since 0.1.3; removed in a later minor */
76
+ 'player.report.titleNamed': 'Report {name}',
77
+ 'player.report.intro': 'Tell us why and a moderator will look at it.',
78
+ /** @deprecated unused since 0.1.3; removed in a later minor */
79
+ 'player.report.legend': 'What happened?',
80
+ 'player.report.titleOneTap': 'Report this message?',
81
+ 'player.report.titleOneTapNamed': 'Report {name}?',
82
+ 'player.report.titleOneTapPlayer': 'Report this player?',
83
+ 'player.report.titleSent': 'Report sent',
84
+ 'player.report.titleRefused': "Couldn't send the report",
85
+ 'player.report.oneTap.intro': 'We will pass it to the moderators. You do not need to say why.',
86
+ 'player.report.oneTap.send': 'Report',
87
+ 'player.report.quote': '“{line}”',
88
+ /** @deprecated unused since 0.1.3; removed in a later minor */
89
+ 'player.report.skip': 'Skip and report',
90
+ 'player.report.needReason': 'Choose a reason.',
91
+ /** @deprecated unused since 0.1.3; removed in a later minor */
92
+ 'player.report.needReasonOrSkip': 'Choose what happened, or skip.',
93
+ /** @deprecated unused since 0.1.3; removed in a later minor */
94
+ 'player.report.addReason': 'Add a reason',
95
+ /** @deprecated unused since 0.1.3; removed in a later minor */
96
+ 'player.report.addReasonHint': 'This helps, but the moderators decide what it really is. You can add this for a few minutes after you report.',
97
+ /** @deprecated unused since 0.1.3; removed in a later minor */
98
+ 'player.report.detail.legend': 'What was it about?',
99
+ /** @deprecated unused since 0.1.3; removed in a later minor */
100
+ 'player.report.detail.send': 'Add to my report',
101
+ /** @deprecated unused since 0.1.3; removed in a later minor */
102
+ 'player.report.detail.need': 'Choose a reason or write a note.',
103
+ /** @deprecated unused since 0.1.3; removed in a later minor */
104
+ 'player.report.detail.added': 'Added. Thanks.',
105
+ /** @deprecated unused since 0.1.3; removed in a later minor */
106
+ 'player.report.detail.failed': 'We could not add that.',
107
+ /** @deprecated unused since 0.1.3; removed in a later minor */
108
+ 'player.report.detail.refused.off': 'Adding to a report is not available right now.',
109
+ /** @deprecated unused since 0.1.3; removed in a later minor */
110
+ 'player.report.detail.refused.not_found': 'We cannot find that report any more.',
111
+ /** @deprecated unused since 0.1.3; removed in a later minor */
112
+ 'player.report.detail.refused.not_reporter': 'Only the player who sent a report can add to it.',
113
+ /** @deprecated unused since 0.1.3; removed in a later minor */
114
+ 'player.report.detail.refused.too_late': 'It is too late to add to this report. We still have the report.',
115
+ /** @deprecated unused since 0.1.3; removed in a later minor */
116
+ 'player.report.detail.refused.already_added': 'You already added to this report.',
117
+ /** @deprecated unused since 0.1.3; removed in a later minor */
118
+ 'player.report.detail.refused.reason_unknown': 'That reason is not available any more. Your report is still with us.',
119
+ 'player.report.note': 'Note (optional)',
120
+ 'player.report.addNote': 'Add a note',
121
+ 'player.report.why': 'Why? (optional)',
122
+ 'player.report.whyRequired': 'Why?',
123
+ 'player.report.choose': 'Choose a reason (optional)',
124
+ 'player.report.chooseRequired': 'Choose a reason',
125
+ 'player.report.noteHint': 'A moderator will read this. Up to {max} characters. Do not include passwords or personal details.',
126
+ /** @deprecated unused since 0.1.3; removed in a later minor */
127
+ 'player.report.send': 'Send report',
128
+ 'player.report.cancel': 'Cancel',
129
+ 'player.report.close': 'Close',
130
+ 'player.report.failed': 'Your report was not sent.',
131
+ 'player.report.thanks': 'Thanks. We got your report.',
132
+ 'player.report.remaining.zero': 'You have no more reports left today.',
133
+ 'player.report.remaining.one': 'You can send {count} more report today.',
134
+ 'player.report.remaining.other': 'You can send {count} more reports today.',
135
+ 'player.report.refused.duplicate': 'You already reported this player here. We have your report.',
136
+ 'player.report.refused.rate': 'You have sent as many reports as you can today. You can send more tomorrow.',
137
+ 'player.report.refused.self': 'You cannot report yourself.',
138
+ 'player.report.refused.not_player': 'We cannot find that player any more. They may have left.',
139
+ 'player.report.refused.off': 'Reports are not available right now. Try again later.',
140
+ 'player.report.refused.suspended': 'You cannot send reports from this account for now.',
141
+ 'player.report.refused.reason_required': 'This report needs a reason. Close this and report again to choose one.',
142
+ 'player.report.refused.reason_unknown': 'That reason is not available any more. Close this and report again.',
143
+ 'player.report.refused.unknown': 'We could not take that report.',
144
+ };
145
+ const isCount = (v) => typeof v === 'number' && Number.isFinite(v);
146
+ /**
147
+ * Builds the `t` function for a catalog and a locale.
148
+ * - `{name}` is replaced by `params.name`; a name with no value stays as written; a value is never expanded again.
149
+ * - Numbers are formatted for the locale (`1,234`).
150
+ * - With a numeric `count`, the plural form for the locale is used (`key.one`, `key.other`, ...), `key.zero` for 0 if it
151
+ * exists, and `key.other` when the locale's form is missing.
152
+ * - A key with no text comes back as the key itself, so a gap in a translation is visible instead of blank.
153
+ */
154
+ export function createT(catalog, locale = 'en') {
155
+ let numbers;
156
+ let plurals;
157
+ try {
158
+ numbers = new Intl.NumberFormat(locale);
159
+ plurals = new Intl.PluralRules(locale);
160
+ }
161
+ catch {
162
+ numbers = new Intl.NumberFormat('en');
163
+ plurals = new Intl.PluralRules('en');
164
+ }
165
+ const has = (key) => Object.hasOwn(catalog, key);
166
+ return (key, params) => {
167
+ let template;
168
+ const count = params?.count;
169
+ if (isCount(count)) {
170
+ const form = count === 0 && has(`${key}.zero`) ? 'zero' : plurals.select(count);
171
+ for (const candidate of [`${key}.${form}`, `${key}.other`]) {
172
+ if (has(candidate)) {
173
+ template = catalog[candidate];
174
+ break;
175
+ }
176
+ }
177
+ }
178
+ template ??= has(key) ? catalog[key] : undefined;
179
+ if (template === undefined)
180
+ return key;
181
+ if (params === undefined)
182
+ return template;
183
+ return template.replace(/\{([a-zA-Z]+)\}/g, (whole, name) => {
184
+ if (!Object.hasOwn(params, name))
185
+ return whole;
186
+ const value = params[name];
187
+ return typeof value === 'number' ? numbers.format(value) : String(value);
188
+ });
189
+ };
190
+ }
191
+ //# sourceMappingURL=i18n.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export declare const VERSION = "0.1.3";
2
+ export { NoticeQueue } from './NoticeQueue.js';
3
+ export type { NoticeQueueProps } from './NoticeQueue.js';
4
+ export { MyRecord } from './MyRecord.js';
5
+ export type { MyRecordProps } from './MyRecord.js';
6
+ export { RulesPage } from './RulesPage.js';
7
+ export type { RulesPageProps } from './RulesPage.js';
8
+ export { ReportDialog } from './ReportDialog.js';
9
+ export type { ReportFollowUp, ReportDialogProps, ReportDraft } from './ReportDialog.js';
10
+ export { RestrictedChatLine } from './RestrictedChatLine.js';
11
+ export type { RestrictedChatLineProps } from './RestrictedChatLine.js';
12
+ export { createPlayerClient, PlayerError, toPlayerError } from './client.js';
13
+ export type { PlayerClient, PlayerClientOptions, PlayerRule, PlayerRules } from './client.js';
14
+ export { fetchTransport, routerTransport } from './transport.js';
15
+ export type { FetchTransportOptions, RouterRequest, RouterResponse, RouterTransportOptions, Transport, TransportRequest, TransportResponse, } from './transport.js';
16
+ export { createT, en } from './i18n.js';
17
+ export type { PlayerCatalog, PlayerParams, PlayerT, PlayerText } from './i18n.js';
18
+ export type { PlayerUiProps } from './ui.js';
19
+ export { dayText, timeLeft, untilText } from './format.js';
20
+ export type { NoticeKind, PlayerNotice, PlayerReporting, ReportDetailResult, ReportFlow, ReportRefusal, ReportResult } from '@chatwarden/core';
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAEvE,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC7E,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC9F,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjE,YAAY,EACV,qBAAqB,EACrB,aAAa,EACb,cAAc,EACd,sBAAsB,EACtB,SAAS,EACT,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACxC,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAClF,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE3D,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,11 @@
1
+ export const VERSION = '0.1.3';
2
+ export { NoticeQueue } from './NoticeQueue.js';
3
+ export { MyRecord } from './MyRecord.js';
4
+ export { RulesPage } from './RulesPage.js';
5
+ export { ReportDialog } from './ReportDialog.js';
6
+ export { RestrictedChatLine } from './RestrictedChatLine.js';
7
+ export { createPlayerClient, PlayerError, toPlayerError } from './client.js';
8
+ export { fetchTransport, routerTransport } from './transport.js';
9
+ export { createT, en } from './i18n.js';
10
+ export { dayText, timeLeft, untilText } from './format.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAE/B,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAG7D,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE7E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAWjE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AAGxC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { PlayerReporting } from '@chatwarden/core';
2
+ /**
3
+ * The reporting payload of `GET /rules` as the dialog may rely on it. Anything that is not the documented shape is dropped: a
4
+ * reason needs a text id and label; the hint and group default to `''` and `asksNote` to false; an unknown flow is `one_tap` (the
5
+ * default); a field the server should not send (a rule mapping, an enabled flag) is never copied. `undefined` when there is no
6
+ * list of reasons at all (an older server, or something that is not the payload).
7
+ */
8
+ export declare function readReporting(raw: unknown): PlayerReporting | undefined;
9
+ export type ReasonItem = PlayerReporting['reasons'][number];
10
+ /** A heading (`''` for none) and the reasons under it. */
11
+ export interface ReasonGroup {
12
+ name: string;
13
+ items: ReasonItem[];
14
+ }
15
+ /**
16
+ * The reasons grouped for the screen: a group is where its first reason is in the list, "Something else" (`other`) is always
17
+ * last, and a group with no name has no heading.
18
+ */
19
+ export declare function groupReasons(reasons: readonly ReasonItem[]): ReasonGroup[];
20
+ //# sourceMappingURL=reporting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporting.d.ts","sourceRoot":"","sources":["../../src/reporting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAc,MAAM,kBAAkB,CAAC;AAOpE;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,GAAG,SAAS,CAQvE;AAED,MAAM,MAAM,UAAU,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5D,0DAA0D;AAC1D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,WAAW,EAAE,CAe1E"}
@@ -0,0 +1,45 @@
1
+ const FLOWS = ['one_tap', 'reason_first', 'reason_required'];
2
+ const isObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
3
+ const text = (v) => typeof v === 'string';
4
+ /**
5
+ * The reporting payload of `GET /rules` as the dialog may rely on it. Anything that is not the documented shape is dropped: a
6
+ * reason needs a text id and label; the hint and group default to `''` and `asksNote` to false; an unknown flow is `one_tap` (the
7
+ * default); a field the server should not send (a rule mapping, an enabled flag) is never copied. `undefined` when there is no
8
+ * list of reasons at all (an older server, or something that is not the payload).
9
+ */
10
+ export function readReporting(raw) {
11
+ if (!isObject(raw) || !Array.isArray(raw.reasons))
12
+ return undefined;
13
+ const reasons = raw.reasons
14
+ .filter(isObject)
15
+ .filter((r) => text(r.id) && r.id !== '' && text(r.label) && r.label !== '')
16
+ .map((r) => ({ id: r.id, label: r.label, hint: text(r.hint) ? r.hint : '', group: text(r.group) ? r.group : '', asksNote: r.asksNote === true }));
17
+ const flow = FLOWS.find((f) => f === raw.flow) ?? 'one_tap';
18
+ return { flow, reasons, thanks: text(raw.thanks) ? raw.thanks : '' };
19
+ }
20
+ /**
21
+ * The reasons grouped for the screen: a group is where its first reason is in the list, "Something else" (`other`) is always
22
+ * last, and a group with no name has no heading.
23
+ */
24
+ export function groupReasons(reasons) {
25
+ const groups = [];
26
+ for (const r of reasons) {
27
+ if (r.id === 'other')
28
+ continue;
29
+ const into = groups.find((g) => g.name === r.group);
30
+ if (into === undefined)
31
+ groups.push({ name: r.group, items: [r] });
32
+ else
33
+ into.items.push(r);
34
+ }
35
+ const other = reasons.find((r) => r.id === 'other');
36
+ if (other !== undefined) {
37
+ const last = groups.at(-1);
38
+ if (last !== undefined && last.name === '')
39
+ last.items.push(other);
40
+ else
41
+ groups.push({ name: '', items: [other] });
42
+ }
43
+ return groups;
44
+ }
45
+ //# sourceMappingURL=reporting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporting.js","sourceRoot":"","sources":["../../src/reporting.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /** Whether an address may become a link: `https:` (with a host), or a relative address on this site. */
2
+ export declare function isSafeHref(href: string): boolean;
3
+ /** The address for an appeal link (trimmed), or null when it is not safe to link to. `http:` is refused: https only. */
4
+ export declare function safeHref(url: string | undefined): string | null;
5
+ //# sourceMappingURL=safeHref.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safeHref.d.ts","sourceRoot":"","sources":["../../src/safeHref.ts"],"names":[],"mappings":"AAWA,wGAAwG;AACxG,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAiBhD;AAED,wHAAwH;AACxH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAG/D"}
@@ -0,0 +1,41 @@
1
+ // The rule for a link address, copied from `@chatwarden/hub-react` (its `isSafeHref`, which guards links in policy documents).
2
+ // The two packages never import each other, so this is a copy; test/safe-href.test.ts runs both on one table.
3
+ function hasControlOrSpace(text) {
4
+ for (const ch of text) {
5
+ const c = ch.codePointAt(0);
6
+ if (c <= 0x20 || (c >= 0x7f && c <= 0x9f))
7
+ return true;
8
+ }
9
+ return false;
10
+ }
11
+ /** Whether an address may become a link: `https:` (with a host), or a relative address on this site. */
12
+ export function isSafeHref(href) {
13
+ // A control character or space inside an address is how `java\tscript:` slips past a scheme check: refuse them all.
14
+ const s = href.trim();
15
+ if (s === '' || hasControlOrSpace(s) || /\s/u.test(s))
16
+ return false;
17
+ // A browser reads `\` as `/`, so `/\evil.example` is `//evil.example`, a different site: refuse a backslash anywhere, and a
18
+ // slash that is followed by another slash or by anything that could be read as one.
19
+ if (s.includes('\\') || /^\/[\s/]/u.test(s))
20
+ return false;
21
+ // An address that carries an entity is not one an adopter wrote: refuse.
22
+ if (/&#?\w+;/.test(s))
23
+ return false;
24
+ const scheme = /^([^/?#]*):/.exec(s);
25
+ if (scheme === null)
26
+ return true;
27
+ try {
28
+ const url = new URL(s);
29
+ return url.protocol === 'https:' && url.hostname !== '';
30
+ }
31
+ catch {
32
+ return false;
33
+ }
34
+ }
35
+ /** The address for an appeal link (trimmed), or null when it is not safe to link to. `http:` is refused: https only. */
36
+ export function safeHref(url) {
37
+ if (typeof url !== 'string')
38
+ return null;
39
+ return isSafeHref(url) ? url.trim() : null;
40
+ }
41
+ //# sourceMappingURL=safeHref.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safeHref.js","sourceRoot":"","sources":["../../src/safeHref.ts"],"names":[],"mappings":"AAAA,+HAA+H;AAC/H,8GAA8G;AAE9G,SAAS,iBAAiB,CAAC,IAAY;IACrC,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,CAAW,CAAC;QACtC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACzD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,oHAAoH;IACpH,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IACtB,IAAI,CAAC,KAAK,EAAE,IAAI,iBAAiB,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACpE,4HAA4H;IAC5H,oFAAoF;IACpF,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1D,yEAAyE;IACzE,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrC,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;QACvB,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,wHAAwH;AACxH,MAAM,UAAU,QAAQ,CAAC,GAAuB;IAC9C,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzC,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * One call to the player routes. `path` is the route path with no prefix (`/notices`); the transport adds whatever prefix its
3
+ * server uses. `query` values that are `undefined` are left out. `body` is sent as JSON.
4
+ *
5
+ * This is the same shape `@chatwarden/hub-react` uses for the staff routes. It is written out here so this package does not
6
+ * depend on that one; a test keeps the two assignable to each other.
7
+ */
8
+ export interface TransportRequest {
9
+ method: string;
10
+ path: string;
11
+ query?: Record<string, string | number | undefined>;
12
+ body?: unknown;
13
+ /** Lets the caller abandon the call (fetch only; the in-page router answers at once). */
14
+ signal?: AbortSignal;
15
+ /** Lets the call finish after the page is gone (fetch `keepalive`). Ignored by the in-page router. */
16
+ keepalive?: boolean;
17
+ }
18
+ /**
19
+ * What came back: any HTTP status is an answer, not an error. `headers` are lower-case. `body` is the parsed JSON, a string
20
+ * for a text document, or null when there was none.
21
+ */
22
+ export interface TransportResponse {
23
+ status: number;
24
+ headers: Record<string, string>;
25
+ body: unknown;
26
+ }
27
+ /**
28
+ * How the components reach the player routes. It resolves with the response whatever the status, and rejects only when no
29
+ * answer arrived (a dropped connection, a handler that threw); the client turns that into a `network` error.
30
+ */
31
+ export type Transport = (req: TransportRequest) => Promise<TransportResponse>;
32
+ /** What `routerTransport` sends to a `createRouter(...)` handler: the kit's `KitRequest`, written out structurally. */
33
+ export interface RouterRequest {
34
+ method: string;
35
+ path: string;
36
+ query: Record<string, string>;
37
+ headers: Record<string, string>;
38
+ body: undefined;
39
+ rawBody?: string;
40
+ }
41
+ /** What a `createRouter(...)` handler answers: the kit's `KitResponse`, written out structurally. */
42
+ export interface RouterResponse {
43
+ status: number;
44
+ headers?: Record<string, string>;
45
+ body: unknown;
46
+ }
47
+ export interface RouterTransportOptions {
48
+ /** Sent with every request, for an `identify` hook that reads a header. */
49
+ headers?: Record<string, string>;
50
+ }
51
+ /**
52
+ * A transport that calls `createRouter(playerRoutes(...))` directly, in the same process: no network. A demo and this
53
+ * package's tests use it, so the components run the real player routes. A response body goes through JSON on the way out, so
54
+ * the components see exactly what a fetch would deliver.
55
+ */
56
+ export declare function routerTransport(handle: (req: RouterRequest) => Promise<RouterResponse>, options?: RouterTransportOptions): Transport;
57
+ export interface FetchTransportOptions {
58
+ /** Where the player routes are mounted: `https://host/player` or `/player`. No trailing slash needed. */
59
+ baseUrl: string;
60
+ /** Sent with every request (a session token, for example). */
61
+ headers?: Record<string, string>;
62
+ /** `include` sends cookies to another origin. Default: the browser's (`same-origin`). */
63
+ credentials?: RequestCredentials;
64
+ /** For tests, or a polyfill. Default: the global `fetch`. */
65
+ fetch?: typeof fetch;
66
+ }
67
+ /** The default transport for a real game: `fetch` against the routes your server mounts. */
68
+ export declare function fetchTransport(options: FetchTransportOptions): Transport;
69
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/transport.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;IACpD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,yFAAyF;IACzF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sGAAsG;IACtG,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAE9E,uHAAuH;AACvH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qGAAqG;AACrG,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,EAAE,OAAO,CAAC;CACf;AAeD,MAAM,WAAW,sBAAsB;IACrC,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,cAAc,CAAC,EAAE,OAAO,GAAE,sBAA2B,GAAG,SAAS,CAexI;AAED,MAAM,WAAW,qBAAqB;IACpC,yGAAyG;IACzG,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,yFAAyF;IACzF,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,6DAA6D;IAC7D,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,4FAA4F;AAC5F,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,SAAS,CA8BxE"}
@@ -0,0 +1,74 @@
1
+ /** The query as strings, with `undefined` values dropped. */
2
+ function queryOf(query) {
3
+ const out = {};
4
+ for (const [key, value] of Object.entries(query ?? {}))
5
+ if (value !== undefined)
6
+ out[key] = String(value);
7
+ return out;
8
+ }
9
+ function lowerCased(headers) {
10
+ const out = {};
11
+ for (const [key, value] of Object.entries(headers ?? {}))
12
+ out[key.toLowerCase()] = value;
13
+ return out;
14
+ }
15
+ /**
16
+ * A transport that calls `createRouter(playerRoutes(...))` directly, in the same process: no network. A demo and this
17
+ * package's tests use it, so the components run the real player routes. A response body goes through JSON on the way out, so
18
+ * the components see exactly what a fetch would deliver.
19
+ */
20
+ export function routerTransport(handle, options = {}) {
21
+ return async (req) => {
22
+ const request = {
23
+ method: req.method,
24
+ path: req.path,
25
+ query: queryOf(req.query),
26
+ headers: { ...options.headers },
27
+ body: undefined,
28
+ };
29
+ // The routes read `rawBody`, never `body` (a pre-parsed body would skip the size cap and the key check).
30
+ if (req.body !== undefined)
31
+ request.rawBody = JSON.stringify(req.body);
32
+ const res = await handle(request);
33
+ const body = typeof res.body === 'string' ? res.body : res.body === undefined ? null : JSON.parse(JSON.stringify(res.body));
34
+ return { status: res.status, headers: lowerCased(res.headers), body };
35
+ };
36
+ }
37
+ /** The default transport for a real game: `fetch` against the routes your server mounts. */
38
+ export function fetchTransport(options) {
39
+ if (typeof options?.baseUrl !== 'string')
40
+ throw new TypeError('fetchTransport: baseUrl is required (for example "/player")');
41
+ // "/" and "" both mean the server root: routes are then "/notices", "/record", ...
42
+ const base = options.baseUrl.replace(/\/+$/, '');
43
+ return async (req) => {
44
+ const params = new URLSearchParams(queryOf(req.query)).toString();
45
+ const url = `${base}${req.path}${params === '' ? '' : `?${params}`}`;
46
+ const headers = { accept: 'application/json', ...options.headers };
47
+ const init = { method: req.method, headers };
48
+ if (req.body !== undefined) {
49
+ headers['content-type'] = 'application/json';
50
+ init.body = JSON.stringify(req.body);
51
+ }
52
+ if (options.credentials !== undefined)
53
+ init.credentials = options.credentials;
54
+ if (req.signal !== undefined)
55
+ init.signal = req.signal;
56
+ if (req.keepalive === true)
57
+ init.keepalive = true;
58
+ const res = await (options.fetch ?? globalThis.fetch)(url, init);
59
+ const headersOut = {};
60
+ res.headers.forEach((value, key) => (headersOut[key.toLowerCase()] = value));
61
+ const text = await res.text();
62
+ let body = text === '' ? null : text;
63
+ if (text !== '' && /\bjson\b/i.test(headersOut['content-type'] ?? '')) {
64
+ try {
65
+ body = JSON.parse(text);
66
+ }
67
+ catch {
68
+ body = text;
69
+ }
70
+ }
71
+ return { status: res.status, headers: headersOut, body };
72
+ };
73
+ }
74
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { NoticeKind, PlayerNotice } from '@chatwarden/core';
3
+ import type { PlayerError } from './client.js';
4
+ import type { PlayerT, PlayerText } from './i18n.js';
5
+ /** What every component takes besides its own props. */
6
+ export interface PlayerUiProps {
7
+ /** Words: `createT({ ...en, ...yourTranslation }, locale)`. Default: English. */
8
+ t?: PlayerT;
9
+ /** The locale for dates, times and plurals. Default: `en`. */
10
+ locale?: string;
11
+ /** The current time in epoch ms, for "how long is left". Default: `Date.now`. */
12
+ now?: () => number;
13
+ /** An IANA time zone for the times shown (`UTC`, `Europe/Berlin`). Default: the player's own. */
14
+ timeZone?: string;
15
+ /** Forces a theme; without it the player's `prefers-color-scheme` decides. */
16
+ theme?: 'light' | 'dark';
17
+ /** Added to the root element, so a game can theme it from its own stylesheet. */
18
+ className?: string;
19
+ }
20
+ export interface Ui {
21
+ t: PlayerT;
22
+ locale: string;
23
+ now: () => number;
24
+ timeZone: string | undefined;
25
+ }
26
+ export declare function useUi({ t, locale, now, timeZone }: PlayerUiProps): Ui;
27
+ /** What the two components that open a dialog take besides the common props. */
28
+ export interface DialogHostProps {
29
+ /**
30
+ * Draw the dialog inside this element instead of where the component is. The dialog is `position: fixed`, so an ancestor of the
31
+ * component with a `transform`, `filter`, `contain` or `will-change: transform` would make it relative to that ancestor and clip it;
32
+ * pass `document.body` (or a layer of your own) to avoid that. The theme and `className` still apply.
33
+ */
34
+ container?: HTMLElement | null;
35
+ /**
36
+ * Where focus goes when the dialog closes and the element that had focus before it opened is gone. Without it focus is left to the
37
+ * browser, which is the page body.
38
+ */
39
+ returnFocusTo?: () => HTMLElement | null;
40
+ }
41
+ /** Renders `children` where they are, or into `container` when one is given. */
42
+ export declare function Portal({ container, children }: {
43
+ container: HTMLElement | null | undefined;
44
+ children: ReactNode;
45
+ }): import("react").JSX.Element;
46
+ /** The root every component renders: the one class all the stylesheet's rules are scoped under. */
47
+ export declare function Root({ theme, className, children }: {
48
+ theme?: 'light' | 'dark';
49
+ className?: string;
50
+ children: ReactNode;
51
+ }): import("react").JSX.Element;
52
+ /**
53
+ * The referee card: a yellow card for a warning, half yellow and half red for a restriction, red for a ban, and a dashed outline
54
+ * for a note. The same card as the moderator hub's, so a sanction looks the same to staff and player. Decoration: the kind is
55
+ * always written beside it. A kind with no card (a thank-you for a report) draws nothing.
56
+ */
57
+ export declare function Card({ kind }: {
58
+ kind: string;
59
+ }): import("react").JSX.Element | null;
60
+ /** The plain sentence for a failed call. The server's own message is never shown. */
61
+ export declare function errorText(t: PlayerT, e: PlayerError): string;
62
+ /** A failed load: what could not be loaded, why, and a way to try again. */
63
+ export declare function ErrorBlock({ ui, what, error, onRetry }: {
64
+ ui: Ui;
65
+ what: string;
66
+ error: PlayerError;
67
+ onRetry: () => void;
68
+ }): import("react").JSX.Element;
69
+ /** "Think this is a mistake?", when the adopter gave an address that is safe to link to. */
70
+ export declare function AppealLink({ ui, href }: {
71
+ ui: Ui;
72
+ href: string | undefined;
73
+ }): import("react").JSX.Element | null;
74
+ export declare const titleKey: (kind: NoticeKind | string) => PlayerText;
75
+ export declare const bodyKey: (kind: NoticeKind | string) => PlayerText;
76
+ export declare const kindKey: (kind: NoticeKind | string) => PlayerText;
77
+ /** A sanction a player can contest (a thank-you for a report is not one). */
78
+ export declare const isSanction: (kind: string) => boolean;
79
+ /** The facts of a notice, as a term list: the rule, when it was given (the record only), until when, and the reference code. */
80
+ export declare function Facts({ ui, notice, record }: {
81
+ ui: Ui;
82
+ notice: PlayerNotice;
83
+ record?: boolean;
84
+ }): import("react").JSX.Element | null;
85
+ /** The player's own lines that led to a notice, as text with their day. Never HTML. */
86
+ export declare function Lines({ ui, notice, id }: {
87
+ ui: Ui;
88
+ notice: PlayerNotice;
89
+ id: string;
90
+ }): import("react").JSX.Element | null;
91
+ //# sourceMappingURL=ui.d.ts.map