@foir/sdk 0.27.1 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +90 -0
- package/dist/auth/auth.d.ts +14 -5
- package/dist/auth/code-flow.d.ts +97 -0
- package/dist/auth/hosted.d.ts +11 -3
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/operations.d.ts +5 -0
- package/dist/auth.js +177 -8
- package/dist/data/builtins.d.ts +1 -2
- package/dist/data/transport.d.ts +1 -0
- package/dist/data/ws-transport.d.ts +9 -0
- package/dist/data.js +44 -3
- package/dist/media/ProgressiveMedia.d.ts +27 -1
- package/dist/media.js +39 -10
- package/dist/next/session.d.ts +6 -2
- package/dist/next.js +4 -9
- package/dist/placement.js +2 -2
- package/dist/react/FoirFeedback.d.ts +58 -3
- package/dist/react/FoirProvider.d.ts +6 -2
- package/dist/react/index.d.ts +1 -1
- package/dist/react.js +299 -163
- package/dist/realtime/index.d.ts +6 -0
- package/dist/realtime.js +2 -1
- package/dist/server.js +54 -5
- package/package.json +2 -2
package/dist/data.js
CHANGED
|
@@ -1380,6 +1380,8 @@ function printSubscriptionDocument(input) {
|
|
|
1380
1380
|
}
|
|
1381
1381
|
|
|
1382
1382
|
// src/data/ws-transport.ts
|
|
1383
|
+
var CLOSE_CREDENTIAL_ENDED = 4402;
|
|
1384
|
+
var CLOSE_FORBIDDEN = 4403;
|
|
1383
1385
|
var GQL = {
|
|
1384
1386
|
connectionInit: "connection_init",
|
|
1385
1387
|
connectionAck: "connection_ack",
|
|
@@ -1414,6 +1416,9 @@ var FoirSocketTransport = class {
|
|
|
1414
1416
|
disposed = false;
|
|
1415
1417
|
keepAlive = null;
|
|
1416
1418
|
retryTimer = null;
|
|
1419
|
+
// A bearer renewed after the socket's lapsed (4402), presented from the next
|
|
1420
|
+
// connect on in place of the client's own.
|
|
1421
|
+
renewedBearer = null;
|
|
1417
1422
|
constructor(config) {
|
|
1418
1423
|
if (config.dispatch !== void 0) {
|
|
1419
1424
|
throw new FoirRequestError(
|
|
@@ -1486,12 +1491,14 @@ var FoirSocketTransport = class {
|
|
|
1486
1491
|
socket.onmessage = (event) => this.receive(event.data);
|
|
1487
1492
|
socket.onerror = () => {
|
|
1488
1493
|
};
|
|
1489
|
-
socket.onclose = () => this.handleClose();
|
|
1494
|
+
socket.onclose = (event) => this.handleClose(event);
|
|
1490
1495
|
}
|
|
1491
1496
|
async sendConnectionInit(socket) {
|
|
1492
1497
|
this.connecting = false;
|
|
1493
1498
|
try {
|
|
1494
|
-
const { headers } = await resolveFoirAuth(
|
|
1499
|
+
const { headers } = await resolveFoirAuth(
|
|
1500
|
+
this.renewedBearer ? { ...this.config, bearerToken: this.renewedBearer } : this.config
|
|
1501
|
+
);
|
|
1495
1502
|
const { "Content-Type": _contentType, ...params } = headers;
|
|
1496
1503
|
const extra = await this.config.connectionParams?.() ?? {};
|
|
1497
1504
|
this.send(socket, {
|
|
@@ -1505,19 +1512,53 @@ var FoirSocketTransport = class {
|
|
|
1505
1512
|
this.teardownSocket(true);
|
|
1506
1513
|
}
|
|
1507
1514
|
}
|
|
1508
|
-
handleClose() {
|
|
1515
|
+
handleClose(event) {
|
|
1516
|
+
const code = event?.code;
|
|
1509
1517
|
const wasAcknowledged = this.acknowledged;
|
|
1510
1518
|
this.teardownSocket(false);
|
|
1511
1519
|
if (this.disposed || this.registrations.size === 0) return;
|
|
1512
1520
|
for (const registration of this.registrations.values()) {
|
|
1513
1521
|
registration.sent = false;
|
|
1514
1522
|
}
|
|
1523
|
+
if (code === CLOSE_FORBIDDEN) {
|
|
1524
|
+
this.failAll(
|
|
1525
|
+
new FoirRequestError(
|
|
1526
|
+
"[foir] the subscription socket was refused where it asked to stand: the signed-in user is no member of the organization this client names"
|
|
1527
|
+
)
|
|
1528
|
+
);
|
|
1529
|
+
return;
|
|
1530
|
+
}
|
|
1531
|
+
if (code === CLOSE_CREDENTIAL_ENDED) {
|
|
1532
|
+
void this.reconnectWithARenewedBearer();
|
|
1533
|
+
return;
|
|
1534
|
+
}
|
|
1515
1535
|
this.scheduleReconnect(
|
|
1516
1536
|
new FoirRequestError(
|
|
1517
1537
|
wasAcknowledged ? "[foir] the subscription socket closed and could not be re-established" : "[foir] the subscription socket closed before the credential was accepted"
|
|
1518
1538
|
)
|
|
1519
1539
|
);
|
|
1520
1540
|
}
|
|
1541
|
+
/**
|
|
1542
|
+
* Reconnect after the socket's credential lapsed: with the bearer renewed
|
|
1543
|
+
* through the client's `refreshBearer` where it has one, failing every
|
|
1544
|
+
* subscription with `FoirSessionExpiredError` when the session is over. A
|
|
1545
|
+
* client without one reconnects at once, presenting what its bearer
|
|
1546
|
+
* provider gives now.
|
|
1547
|
+
*/
|
|
1548
|
+
async reconnectWithARenewedBearer() {
|
|
1549
|
+
const refresh = this.config.refreshBearer;
|
|
1550
|
+
if (refresh) {
|
|
1551
|
+
const token = await renewBearerOnce(refresh).catch(() => null);
|
|
1552
|
+
if (this.disposed) return;
|
|
1553
|
+
if (!token) {
|
|
1554
|
+
this.failAll(new FoirSessionExpiredError());
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
this.renewedBearer = token;
|
|
1558
|
+
}
|
|
1559
|
+
this.attempt = 0;
|
|
1560
|
+
this.ensureConnected();
|
|
1561
|
+
}
|
|
1521
1562
|
scheduleReconnect(error) {
|
|
1522
1563
|
if (this.disposed || this.registrations.size === 0) return;
|
|
1523
1564
|
if (this.attempt >= this.policy.maxAttempts) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Ref } from 'react';
|
|
1
2
|
import type { ProgressiveImageSource, ProgressiveVideoSource, VariantTierKey } from './media';
|
|
2
3
|
export interface ProgressiveMediaProps {
|
|
3
4
|
image?: ProgressiveImageSource;
|
|
@@ -25,6 +26,31 @@ export interface ProgressiveMediaProps {
|
|
|
25
26
|
muted?: boolean;
|
|
26
27
|
/** Video playback — loop on end. Default true. */
|
|
27
28
|
loop?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Video playback: show the browser's controls. Defaults to `!autoplay`. A
|
|
31
|
+
* video with controls shows from the start, its poster standing until it
|
|
32
|
+
* plays, so the controls can always be reached.
|
|
33
|
+
*/
|
|
34
|
+
controls?: boolean;
|
|
35
|
+
/** Video: how much the browser fetches before it plays (`<video preload>`). */
|
|
36
|
+
preload?: 'none' | 'metadata' | 'auto';
|
|
37
|
+
/**
|
|
38
|
+
* Where the media sits in its box when it is cropped to fit, as CSS
|
|
39
|
+
* `object-position` (`'30% 60%'`), for a focal point. Applies to the image,
|
|
40
|
+
* the video and its thumbnail. Default centre.
|
|
41
|
+
*/
|
|
42
|
+
objectPosition?: string;
|
|
43
|
+
/**
|
|
44
|
+
* The `<video>` element, once it mounts: for a caller's own play and pause
|
|
45
|
+
* controls, and the events that keep them in step.
|
|
46
|
+
*/
|
|
47
|
+
videoRef?: Ref<HTMLVideoElement>;
|
|
48
|
+
/**
|
|
49
|
+
* Called once when a video's source cannot be played. The video is then
|
|
50
|
+
* removed, and its thumbnail, labelled with `alt`, stands in for it over
|
|
51
|
+
* the colour and blurhash layers.
|
|
52
|
+
*/
|
|
53
|
+
onVideoError?: () => void;
|
|
28
54
|
/**
|
|
29
55
|
* When false, skip loading the full media layer (no `<video>`/full `<img>`
|
|
30
56
|
* mount, no HLS attach, no full-image preload). The lower layers — colour,
|
|
@@ -53,4 +79,4 @@ export interface ProgressiveMediaProps {
|
|
|
53
79
|
*/
|
|
54
80
|
variantTiers?: readonly VariantTierKey[];
|
|
55
81
|
}
|
|
56
|
-
export declare function ProgressiveMedia({ image, video, alt, className, fill, fit, placeholder, autoplay, muted, loop, active, sizes, priority, variantTiers, }: ProgressiveMediaProps): import("react/jsx-runtime").JSX.Element | null;
|
|
82
|
+
export declare function ProgressiveMedia({ image, video, alt, className, fill, fit, placeholder, autoplay, muted, loop, controls, preload, objectPosition, videoRef: externalVideoRef, onVideoError, active, sizes, priority, variantTiers, }: ProgressiveMediaProps): import("react/jsx-runtime").JSX.Element | null;
|
package/dist/media.js
CHANGED
|
@@ -213,6 +213,11 @@ function ProgressiveMedia({
|
|
|
213
213
|
autoplay = true,
|
|
214
214
|
muted = true,
|
|
215
215
|
loop = true,
|
|
216
|
+
controls,
|
|
217
|
+
preload,
|
|
218
|
+
objectPosition,
|
|
219
|
+
videoRef: externalVideoRef,
|
|
220
|
+
onVideoError,
|
|
216
221
|
active = true,
|
|
217
222
|
sizes = "100vw",
|
|
218
223
|
priority = false,
|
|
@@ -225,7 +230,13 @@ function ProgressiveMedia({
|
|
|
225
230
|
const source = video ?? image;
|
|
226
231
|
const isVideo = !!video;
|
|
227
232
|
const [wrapperRef, inViewport] = useInViewport("300px", priority);
|
|
228
|
-
const
|
|
233
|
+
const [failedUrl, setFailedUrl] = useState2(void 0);
|
|
234
|
+
const videoFailed = isVideo && failedUrl !== void 0 && failedUrl === video?.url;
|
|
235
|
+
const [videoSize, setVideoSize] = useState2(
|
|
236
|
+
null
|
|
237
|
+
);
|
|
238
|
+
const videoActive = isVideo && active && !videoFailed && (priority || inViewport);
|
|
239
|
+
const showControls = controls ?? !autoplay;
|
|
229
240
|
const imageActive = !isVideo && active;
|
|
230
241
|
const hlsUrl = video?.hlsUrl;
|
|
231
242
|
const useHls = isVideo && !!hlsUrl;
|
|
@@ -282,6 +293,8 @@ function ProgressiveMedia({
|
|
|
282
293
|
cleanupRef.current = null;
|
|
283
294
|
}
|
|
284
295
|
videoRef.current = el;
|
|
296
|
+
if (typeof externalVideoRef === "function") externalVideoRef(el);
|
|
297
|
+
else if (externalVideoRef) externalVideoRef.current = el;
|
|
285
298
|
if (!el) return;
|
|
286
299
|
if (el.readyState >= 3) {
|
|
287
300
|
onFullReady();
|
|
@@ -299,7 +312,7 @@ function ProgressiveMedia({
|
|
|
299
312
|
el.removeEventListener("playing", handler);
|
|
300
313
|
};
|
|
301
314
|
},
|
|
302
|
-
[onFullReady]
|
|
315
|
+
[onFullReady, externalVideoRef]
|
|
303
316
|
);
|
|
304
317
|
if (!source) {
|
|
305
318
|
if (!placeholder) return null;
|
|
@@ -314,8 +327,9 @@ function ProgressiveMedia({
|
|
|
314
327
|
);
|
|
315
328
|
}
|
|
316
329
|
const effective = !isVideo ? effectiveImageDimensions(image) : null;
|
|
317
|
-
const w = effective?.width ?? source.width;
|
|
318
|
-
const h = effective?.height ?? source.height;
|
|
330
|
+
const w = effective?.width ?? source.width ?? videoSize?.w;
|
|
331
|
+
const h = effective?.height ?? source.height ?? videoSize?.h;
|
|
332
|
+
const positioned = objectPosition ? { objectPosition } : void 0;
|
|
319
333
|
const aspect = w && h ? w / h : 16 / 10;
|
|
320
334
|
return /* @__PURE__ */ jsxs(
|
|
321
335
|
"div",
|
|
@@ -342,13 +356,14 @@ function ProgressiveMedia({
|
|
|
342
356
|
"img",
|
|
343
357
|
{
|
|
344
358
|
src: thumbnailUrl,
|
|
345
|
-
alt: "",
|
|
346
|
-
"aria-hidden": true,
|
|
359
|
+
alt: videoFailed ? alt ?? "" : "",
|
|
360
|
+
"aria-hidden": videoFailed ? void 0 : true,
|
|
347
361
|
width: w,
|
|
348
362
|
height: h,
|
|
349
363
|
loading: priority ? "eager" : "lazy",
|
|
350
364
|
fetchPriority: priority ? "high" : void 0,
|
|
351
|
-
className: `absolute inset-0 h-full w-full ${fitClass} transition-opacity duration-400 ease-in-out ${stage === "thumbnail" || stage === "full" ? "opacity-100" : "opacity-0"}
|
|
365
|
+
className: `absolute inset-0 h-full w-full ${fitClass} transition-opacity duration-400 ease-in-out ${stage === "thumbnail" || stage === "full" ? "opacity-100" : "opacity-0"}`,
|
|
366
|
+
style: positioned
|
|
352
367
|
}
|
|
353
368
|
),
|
|
354
369
|
videoActive ? /* @__PURE__ */ jsx2(
|
|
@@ -363,8 +378,21 @@ function ProgressiveMedia({
|
|
|
363
378
|
muted,
|
|
364
379
|
loop,
|
|
365
380
|
playsInline: true,
|
|
366
|
-
controls:
|
|
367
|
-
|
|
381
|
+
controls: showControls,
|
|
382
|
+
preload,
|
|
383
|
+
"aria-label": alt || void 0,
|
|
384
|
+
onLoadedMetadata: (e) => {
|
|
385
|
+
const v = e.currentTarget;
|
|
386
|
+
if (!source.width && v.videoWidth && v.videoHeight) {
|
|
387
|
+
setVideoSize({ w: v.videoWidth, h: v.videoHeight });
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
onError: () => {
|
|
391
|
+
setFailedUrl(video?.url);
|
|
392
|
+
onVideoError?.();
|
|
393
|
+
},
|
|
394
|
+
className: `absolute inset-0 h-full w-full ${fitClass} transition-opacity duration-500 ease-in-out ${stage === "full" || showControls ? "opacity-100" : "opacity-0"}`,
|
|
395
|
+
style: positioned
|
|
368
396
|
}
|
|
369
397
|
) : imageActive ? (
|
|
370
398
|
// <picture>: browser picks AVIF when it can decode it, else WebP. The
|
|
@@ -383,7 +411,8 @@ function ProgressiveMedia({
|
|
|
383
411
|
height: h,
|
|
384
412
|
loading: priority ? "eager" : "lazy",
|
|
385
413
|
fetchPriority: priority ? "high" : void 0,
|
|
386
|
-
className: `absolute inset-0 h-full w-full ${fitClass} transition-opacity duration-500 ease-in-out ${stage === "full" ? "opacity-100" : "opacity-0"}
|
|
414
|
+
className: `absolute inset-0 h-full w-full ${fitClass} transition-opacity duration-500 ease-in-out ${stage === "full" ? "opacity-100" : "opacity-0"}`,
|
|
415
|
+
style: positioned
|
|
387
416
|
}
|
|
388
417
|
)
|
|
389
418
|
] })
|
package/dist/next/session.d.ts
CHANGED
|
@@ -27,8 +27,12 @@ interface PasswordArgs {
|
|
|
27
27
|
}
|
|
28
28
|
/** Password sign-in in a route handler; persists the session to cookies. */
|
|
29
29
|
export declare function foirSignInWithPassword({ env, store, email, password, cookieOptions, }: PasswordArgs): Promise<FoirUser>;
|
|
30
|
-
/**
|
|
31
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Start a sign-up in a route handler: the address is mailed a code, and
|
|
32
|
+
* {@link foirSignInWithOtp} with it finishes the account and persists the
|
|
33
|
+
* session to cookies.
|
|
34
|
+
*/
|
|
35
|
+
export declare function foirRegisterWithPassword({ env, email, password, }: Pick<PasswordArgs, 'env' | 'email' | 'password'>): Promise<void>;
|
|
32
36
|
/** Complete an OTP sign-in in a route handler; persists the session to cookies. */
|
|
33
37
|
export declare function foirSignInWithOtp({ env, store, email, otp, cookieOptions, }: {
|
|
34
38
|
env: FoirEnv;
|
package/dist/next.js
CHANGED
|
@@ -1127,8 +1127,8 @@ async function getSessionUser(adapter) {
|
|
|
1127
1127
|
async function signInWithPassword(adapter, env, vars) {
|
|
1128
1128
|
return saveSession(adapter, await login(env, vars));
|
|
1129
1129
|
}
|
|
1130
|
-
async function signUpWithPassword(
|
|
1131
|
-
|
|
1130
|
+
async function signUpWithPassword(env, vars) {
|
|
1131
|
+
await register(env, vars);
|
|
1132
1132
|
}
|
|
1133
1133
|
async function signInWithOTP(adapter, env, vars) {
|
|
1134
1134
|
return saveSession(adapter, await loginWithOTP(env, vars));
|
|
@@ -1158,15 +1158,10 @@ function foirSignInWithPassword({
|
|
|
1158
1158
|
}
|
|
1159
1159
|
function foirRegisterWithPassword({
|
|
1160
1160
|
env,
|
|
1161
|
-
store,
|
|
1162
1161
|
email,
|
|
1163
|
-
password
|
|
1164
|
-
cookieOptions
|
|
1162
|
+
password
|
|
1165
1163
|
}) {
|
|
1166
|
-
return signUpWithPassword(
|
|
1167
|
-
email,
|
|
1168
|
-
password
|
|
1169
|
-
});
|
|
1164
|
+
return signUpWithPassword(env, { email, password });
|
|
1170
1165
|
}
|
|
1171
1166
|
function foirSignInWithOtp({
|
|
1172
1167
|
env,
|
package/dist/placement.js
CHANGED
|
@@ -70,6 +70,7 @@ var GRANT_TABLE = [
|
|
|
70
70
|
["apikeys:write", "none", [], []],
|
|
71
71
|
["organizations:read", "none", [], []],
|
|
72
72
|
["organizations:write", "none", [], []],
|
|
73
|
+
["orgsettings:write", "none", [], []],
|
|
73
74
|
["organizations:create", "none", [], []],
|
|
74
75
|
["organizations:delete", "none", [], []],
|
|
75
76
|
["organizations:reach", "none", [], []],
|
|
@@ -80,7 +81,7 @@ var GRANT_TABLE = [
|
|
|
80
81
|
["projects:read", "none", [], []],
|
|
81
82
|
["projects:write", "none", [], []],
|
|
82
83
|
["project:stand", "none", [], []],
|
|
83
|
-
["project:manage", "none", [], ["project:stand", "records:read.all", "records:create", "records:write.all", "records:delete.all", "records:publish.all", "records:attribute", "search:read", "embeddings:read", "embeddings:write", "schemas:read", "drafts:read", "files:read.all", "files:write.all", "files:delete.all", "users:read.all", "identities:read", "users:create", "identities:delete", "users:write.all", "users:setup", "users:delete.all", "notifications:read.all", "notifications:write.all", "notifications:consent", "pushcredentials:read", "pushcredentials:write", "notes:read.all", "notes:write.all", "notes:create", "approvals:read", "approvals:write", "rooms:read", "rooms:write", "presence:read", "operations:read", "operations:execute", "operations:write", "appconfig:read", "schedules:read", "schedules:write", "hooks:read", "hooks:write", "
|
|
84
|
+
["project:manage", "none", [], ["project:stand", "records:read.all", "records:create", "records:write.all", "records:delete.all", "records:publish.all", "records:attribute", "search:read", "embeddings:read", "embeddings:write", "schemas:read", "drafts:read", "files:read.all", "files:write.all", "files:delete.all", "users:read.all", "identities:read", "users:create", "identities:delete", "users:write.all", "users:setup", "users:delete.all", "notifications:read.all", "notifications:write.all", "notifications:consent", "pushcredentials:read", "pushcredentials:write", "notes:read.all", "notes:write.all", "notes:create", "approvals:read", "approvals:write", "rooms:read", "rooms:write", "presence:read", "operations:read", "operations:execute", "operations:write", "appconfig:read", "schedules:read", "schedules:write", "hooks:read", "hooks:write", "authclients:read", "authclients:write", "domains:read", "domains:write", "loginpages:read", "loginpages:write", "secrets:read", "secrets:list", "secrets:put", "secrets:delete", "appsecrets:read", "appsecrets:list", "appsecrets:put", "appsecrets:delete", "usersecrets:read", "usersecrets:list", "usersecrets:put", "usersecrets:delete", "opsecrets:read", "opsecrets:write", "settings:read", "settings:write", "designtokens:read", "designtokens:write", "models:read", "models:write", "configs:read", "configs:write", "signinproviders:read", "signinproviders:write", "apps:read", "apps:write", "events:read", "targeting:debug", "visitors:forward", "apikeys:read", "apikeys:write", "organizations:read", "organizations:create", "organizations:delete", "organizations:write", "orgsettings:write", "organizations:reach", "members:read", "members:write", "roles:read", "roles:write", "projects:read", "projects:write", "audit:read"]],
|
|
84
85
|
["projects:create", "none", [], []],
|
|
85
86
|
["projects:delete", "none", [], []],
|
|
86
87
|
["tenants:read", "none", [], []],
|
|
@@ -111,7 +112,6 @@ var GRANT_TABLE = [
|
|
|
111
112
|
["usersecrets:list", "none", [], []],
|
|
112
113
|
["usersecrets:put", "none", [], []],
|
|
113
114
|
["usersecrets:delete", "none", [], []],
|
|
114
|
-
["auth:login_with_foir", "none", [], []],
|
|
115
115
|
["signinproviders:read", "none", [], []],
|
|
116
116
|
["signinproviders:write", "none", [], []]
|
|
117
117
|
];
|
|
@@ -46,6 +46,25 @@ export interface FoirFeedbackProps {
|
|
|
46
46
|
* button that calls it; given none, it says so and stops.
|
|
47
47
|
*/
|
|
48
48
|
onSignIn?: () => void;
|
|
49
|
+
/**
|
|
50
|
+
* Whether a visitor can sign in on this site. Default true. `false` says
|
|
51
|
+
* they cannot, so where the project takes no notes from visitors who are not
|
|
52
|
+
* signed in, the widget says feedback is not open rather than asking them to
|
|
53
|
+
* sign in somewhere they cannot.
|
|
54
|
+
*/
|
|
55
|
+
signIn?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* How the panel opens. `inline` (the default) opens it under the button, in
|
|
58
|
+
* the page's flow. `dialog` opens it over the page in a modal `<dialog>`,
|
|
59
|
+
* with a backdrop, closed by Escape, the backdrop or its Close button.
|
|
60
|
+
*/
|
|
61
|
+
layout?: 'inline' | 'dialog';
|
|
62
|
+
/**
|
|
63
|
+
* The built-in styles' colours, radius and type. See
|
|
64
|
+
* `FoirFeedbackAppearance`: each is also a CSS custom property, so a
|
|
65
|
+
* stylesheet can set it instead. Ignored with `className`.
|
|
66
|
+
*/
|
|
67
|
+
appearance?: FoirFeedbackAppearance;
|
|
49
68
|
/** Called with a signed-in user's note once it is written. */
|
|
50
69
|
onSubmitted?: (note: FoirUserNote) => void;
|
|
51
70
|
/**
|
|
@@ -61,9 +80,45 @@ export interface FoirFeedbackProps {
|
|
|
61
80
|
onError?: (error: unknown) => void;
|
|
62
81
|
/**
|
|
63
82
|
* Style it yourself. Passing a class turns OFF the built-in inline styles
|
|
64
|
-
* entirely, so the `data-foir-feedback-*` attributes
|
|
65
|
-
* without fighting anything.
|
|
83
|
+
* entirely, `appearance` with them, so the `data-foir-feedback-*` attributes
|
|
84
|
+
* are yours to target without fighting anything.
|
|
66
85
|
*/
|
|
67
86
|
className?: string;
|
|
68
87
|
}
|
|
69
|
-
|
|
88
|
+
/**
|
|
89
|
+
* The built-in styles' tokens.
|
|
90
|
+
*
|
|
91
|
+
* Each is a CSS custom property on the wrapper, `--foir-feedback-<name>`, which
|
|
92
|
+
* the built-in styles read with today's look as the fallback. So a token can be
|
|
93
|
+
* set here, or from a stylesheet, where a design system's own variables can
|
|
94
|
+
* feed it:
|
|
95
|
+
*
|
|
96
|
+
* ```css
|
|
97
|
+
* [data-foir-feedback] { --foir-feedback-radius: var(--radius); }
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* A value is any CSS value the property takes.
|
|
101
|
+
*/
|
|
102
|
+
export interface FoirFeedbackAppearance {
|
|
103
|
+
/** `--foir-feedback-text`. Default: inherited, or the browser's dialog text in a dialog. */
|
|
104
|
+
colorText?: string;
|
|
105
|
+
/** `--foir-feedback-muted`, the line naming what it is about. Default: the text at three quarters. */
|
|
106
|
+
colorMuted?: string;
|
|
107
|
+
/** `--foir-feedback-background`, the panel and its fields. Default: none, or the browser's dialog background in a dialog. */
|
|
108
|
+
colorBackground?: string;
|
|
109
|
+
/** `--foir-feedback-border`. Default `currentColor`. */
|
|
110
|
+
colorBorder?: string;
|
|
111
|
+
/** `--foir-feedback-primary`, the send button's fill and border. Default: no fill. */
|
|
112
|
+
colorPrimary?: string;
|
|
113
|
+
/** `--foir-feedback-primary-text`, the send button's text. Default: inherited. */
|
|
114
|
+
colorPrimaryText?: string;
|
|
115
|
+
/** `--foir-feedback-danger`, a failure. Default `#c0392b`. */
|
|
116
|
+
colorDanger?: string;
|
|
117
|
+
/** `--foir-feedback-radius`, the panel's corners; its controls take three quarters. Default `8px`. */
|
|
118
|
+
radius?: string;
|
|
119
|
+
/** `--foir-feedback-font-family`. Default: inherited. */
|
|
120
|
+
fontFamily?: string;
|
|
121
|
+
/** `--foir-feedback-font-size`. Default: inherited. */
|
|
122
|
+
fontSize?: string;
|
|
123
|
+
}
|
|
124
|
+
export declare function FoirFeedback({ client, subjects, subject, label, triggerLabel, title, placeholder, defaultOpen, onSignIn, signIn, layout, appearance, onSubmitted, onVisitorSubmitted, onError, className, }: FoirFeedbackProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -28,10 +28,14 @@ export interface FoirContextValue {
|
|
|
28
28
|
email: string;
|
|
29
29
|
password: string;
|
|
30
30
|
}): Promise<FoirUser>;
|
|
31
|
+
/**
|
|
32
|
+
* Start a sign-up: the address is mailed a code, and `signInWithOtp` with it
|
|
33
|
+
* finishes the account and signs them in.
|
|
34
|
+
*/
|
|
31
35
|
register(vars: {
|
|
32
36
|
email: string;
|
|
33
37
|
password: string;
|
|
34
|
-
}): Promise<
|
|
38
|
+
}): Promise<void>;
|
|
35
39
|
requestOtp(email: string): Promise<boolean>;
|
|
36
40
|
signInWithOtp(vars: {
|
|
37
41
|
email: string;
|
|
@@ -138,7 +142,7 @@ export declare function useFoirAuth(): {
|
|
|
138
142
|
register: (vars: {
|
|
139
143
|
email: string;
|
|
140
144
|
password: string;
|
|
141
|
-
}) => Promise<
|
|
145
|
+
}) => Promise<void>;
|
|
142
146
|
requestOtp: (email: string) => Promise<boolean>;
|
|
143
147
|
signInWithOtp: (vars: {
|
|
144
148
|
email: string;
|
package/dist/react/index.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export type { OAuthButtonsProps } from './OAuthButtons';
|
|
|
20
20
|
export { UserButton } from './UserButton';
|
|
21
21
|
export type { UserButtonProps } from './UserButton';
|
|
22
22
|
export { FoirFeedback } from './FoirFeedback';
|
|
23
|
-
export type {
|
|
23
|
+
export type { FoirFeedbackAppearance, FoirFeedbackClient, FoirFeedbackProps, } from './FoirFeedback';
|
|
24
24
|
export { createLocalStorageAdapter } from './localStorageAdapter';
|
|
25
25
|
export type { FoirAccess, FoirUser, SessionAdapter, AuthProviderPublic } from '../auth';
|
|
26
26
|
export type { FoirEnv } from '../graphql/foir-request';
|