@drawnagency/primitives 0.1.117 → 0.1.118
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/dist/{chunk-L7WTERU5.js → chunk-4NSOKEA7.js} +21 -3
- package/dist/{chunk-MSBHMY3C.js → chunk-ERLIL4RU.js} +3 -3
- package/dist/{chunk-LNQUUC2S.js → chunk-HRX3XJBU.js} +1 -1
- package/dist/{chunk-HUOW3ZV2.js → chunk-ZOTRHHUB.js} +1 -1
- package/dist/components/primitives/EditablePlainText.d.ts.map +1 -1
- package/dist/components/primitives/index.js +2 -2
- package/dist/components/sections/brand-guide.js +2 -2
- package/dist/components/sections/register-schemas.js +4 -4
- package/dist/components/sections/register.js +4 -4
- package/dist/components/shell/AudienceDetailsPanel.d.ts +3 -1
- package/dist/components/shell/AudienceDetailsPanel.d.ts.map +1 -1
- package/dist/components/shell/EditorShell.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/primitives/EditablePlainText.tsx +27 -3
- package/src/components/shell/AudienceDetailsPanel.tsx +6 -4
- package/src/components/shell/EditorShell.tsx +13 -1
|
@@ -66,6 +66,22 @@ function useEditablePlainText({
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
// src/components/primitives/EditablePlainText.tsx
|
|
69
|
+
function caretOffset(el) {
|
|
70
|
+
const sel = window.getSelection();
|
|
71
|
+
if (!sel || sel.rangeCount === 0) return null;
|
|
72
|
+
const range = sel.getRangeAt(0);
|
|
73
|
+
if (!el.contains(range.endContainer)) return null;
|
|
74
|
+
const before = document.createRange();
|
|
75
|
+
before.selectNodeContents(el);
|
|
76
|
+
before.setEnd(range.endContainer, range.endOffset);
|
|
77
|
+
return before.toString().length;
|
|
78
|
+
}
|
|
79
|
+
function placeCaret(el, offset) {
|
|
80
|
+
const sel = window.getSelection();
|
|
81
|
+
if (!sel) return;
|
|
82
|
+
if (el.firstChild) sel.collapse(el.firstChild, offset);
|
|
83
|
+
else sel.collapse(el, 0);
|
|
84
|
+
}
|
|
69
85
|
function EditablePlainText({
|
|
70
86
|
tag,
|
|
71
87
|
value,
|
|
@@ -86,9 +102,11 @@ function EditablePlainText({
|
|
|
86
102
|
shouldPreventEnter
|
|
87
103
|
} = useEditablePlainText({ value, onChange, multiline });
|
|
88
104
|
useEffect2(() => {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
105
|
+
const el = ref.current;
|
|
106
|
+
if (!el || el.textContent === localValue) return;
|
|
107
|
+
const caret = document.activeElement === el ? caretOffset(el) : null;
|
|
108
|
+
el.textContent = localValue;
|
|
109
|
+
if (caret !== null) placeCaret(el, Math.min(caret, localValue.length));
|
|
92
110
|
}, [localValue]);
|
|
93
111
|
const onInput = useCallback2(() => {
|
|
94
112
|
if (ref.current) {
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
pluralize,
|
|
5
5
|
stripHtmlToPlainText,
|
|
6
6
|
truncate
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-HRX3XJBU.js";
|
|
8
8
|
import {
|
|
9
9
|
DeleteButton,
|
|
10
10
|
DragHandle,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
EditableRichText,
|
|
26
26
|
defineHeadingSection,
|
|
27
27
|
useSanitizedHtml
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-ZOTRHHUB.js";
|
|
29
29
|
import {
|
|
30
30
|
EditablePlainText,
|
|
31
31
|
ImageDropZone,
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
containerGridClass,
|
|
36
36
|
masonryColumnsClass,
|
|
37
37
|
spacerHiddenClass
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-4NSOKEA7.js";
|
|
39
39
|
import {
|
|
40
40
|
DropEdgeIndicator,
|
|
41
41
|
useMediaLibrary,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditablePlainText.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/EditablePlainText.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,cAAc,EACpB,MAAM,OAAO,CAAC;AAGf,UAAU,sBACR,SAAQ,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC;IACrD,GAAG,EAAE,WAAW,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;
|
|
1
|
+
{"version":3,"file":"EditablePlainText.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/EditablePlainText.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,cAAc,EACpB,MAAM,OAAO,CAAC;AAGf,UAAU,sBACR,SAAQ,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC;IACrD,GAAG,EAAE,WAAW,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAqBD,wBAAgB,iBAAiB,CAAC,EAChC,GAAG,EACH,KAAK,EACL,QAAQ,EACR,UAAU,EACV,SAAiB,EACjB,WAAW,EACX,SAAS,EACT,GAAG,SAAS,EACb,EAAE,sBAAsB,0FAoFxB"}
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
EditableRichText,
|
|
3
3
|
LinkPopover,
|
|
4
4
|
defineHeadingSection
|
|
5
|
-
} from "../../chunk-
|
|
5
|
+
} from "../../chunk-ZOTRHHUB.js";
|
|
6
6
|
import {
|
|
7
7
|
EditableGrid,
|
|
8
8
|
EditableList,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
ImageDropZone,
|
|
11
11
|
MediaBlock,
|
|
12
12
|
ResolvedMedia
|
|
13
|
-
} from "../../chunk-
|
|
13
|
+
} from "../../chunk-4NSOKEA7.js";
|
|
14
14
|
import {
|
|
15
15
|
LinkField,
|
|
16
16
|
PagesContext,
|
|
@@ -2,9 +2,9 @@ import {
|
|
|
2
2
|
ColorItemSchema,
|
|
3
3
|
ColorSpaceSchema,
|
|
4
4
|
brandGuideSectionDefs
|
|
5
|
-
} from "../../chunk-
|
|
5
|
+
} from "../../chunk-HRX3XJBU.js";
|
|
6
6
|
import "../../chunk-JR24U7FJ.js";
|
|
7
|
-
import "../../chunk-
|
|
7
|
+
import "../../chunk-4NSOKEA7.js";
|
|
8
8
|
import "../../chunk-RIITGTV3.js";
|
|
9
9
|
import "../../chunk-DIMDRBFK.js";
|
|
10
10
|
import "../../chunk-IIDKW7AV.js";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
allSectionDefs
|
|
3
|
-
} from "../../chunk-
|
|
4
|
-
import "../../chunk-
|
|
3
|
+
} from "../../chunk-ERLIL4RU.js";
|
|
4
|
+
import "../../chunk-HRX3XJBU.js";
|
|
5
5
|
import "../../chunk-CEFFP3CH.js";
|
|
6
6
|
import "../../chunk-JR24U7FJ.js";
|
|
7
|
-
import "../../chunk-
|
|
8
|
-
import "../../chunk-
|
|
7
|
+
import "../../chunk-ZOTRHHUB.js";
|
|
8
|
+
import "../../chunk-4NSOKEA7.js";
|
|
9
9
|
import "../../chunk-RIITGTV3.js";
|
|
10
10
|
import "../../chunk-JCDZAFX2.js";
|
|
11
11
|
import "../../chunk-DIMDRBFK.js";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
allSectionDefs
|
|
3
|
-
} from "../../chunk-
|
|
4
|
-
import "../../chunk-
|
|
3
|
+
} from "../../chunk-ERLIL4RU.js";
|
|
4
|
+
import "../../chunk-HRX3XJBU.js";
|
|
5
5
|
import "../../chunk-CEFFP3CH.js";
|
|
6
6
|
import "../../chunk-JR24U7FJ.js";
|
|
7
|
-
import "../../chunk-
|
|
8
|
-
import "../../chunk-
|
|
7
|
+
import "../../chunk-ZOTRHHUB.js";
|
|
8
|
+
import "../../chunk-4NSOKEA7.js";
|
|
9
9
|
import "../../chunk-RIITGTV3.js";
|
|
10
10
|
import "../../chunk-JCDZAFX2.js";
|
|
11
11
|
import "../../chunk-DIMDRBFK.js";
|
|
@@ -23,12 +23,14 @@ interface Props {
|
|
|
23
23
|
* an audience-filtered site.
|
|
24
24
|
*/
|
|
25
25
|
canImpersonate?: boolean;
|
|
26
|
+
/** Open the view in a new tab — set by the editor, so it keeps the editor tab. */
|
|
27
|
+
viewAsInNewTab?: boolean;
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* The Audience Details page body: who can see what, and what password to share.
|
|
29
31
|
* Reachable by editors and the site's default audience (the client), so the
|
|
30
32
|
* client can hand a new partner access without going through us.
|
|
31
33
|
*/
|
|
32
|
-
export declare function AudienceDetailsPanel({ audiences, revealSupported, canImpersonate }: Props): import("react/jsx-runtime").JSX.Element;
|
|
34
|
+
export declare function AudienceDetailsPanel({ audiences, revealSupported, canImpersonate, viewAsInNewTab }: Props): import("react/jsx-runtime").JSX.Element;
|
|
33
35
|
export default AudienceDetailsPanel;
|
|
34
36
|
//# sourceMappingURL=AudienceDetailsPanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudienceDetailsPanel.d.ts","sourceRoot":"","sources":["../../../src/components/shell/AudienceDetailsPanel.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAgB,MAAM,6BAA6B,CAAC;AAElF,sEAAsE;AACtE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,8EAA8E;IAC9E,WAAW,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAC/D,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED,UAAU,KAAK;IACb,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,8EAA8E;IAC9E,eAAe,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAoOD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,cAAsB,EAAE,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"AudienceDetailsPanel.d.ts","sourceRoot":"","sources":["../../../src/components/shell/AudienceDetailsPanel.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAgB,MAAM,6BAA6B,CAAC;AAElF,sEAAsE;AACtE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,8EAA8E;IAC9E,WAAW,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAC/D,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED,UAAU,KAAK;IACb,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,8EAA8E;IAC9E,eAAe,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kFAAkF;IAClF,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAoOD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,cAAsB,EAAE,cAAsB,EAAE,EAAE,KAAK,2CAgBzH;AAED,eAAe,oBAAoB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditorShell.d.ts","sourceRoot":"","sources":["../../../src/components/shell/EditorShell.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAejD,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAuDtF,OAAO,KAAK,EAAE,eAAe,EAA2D,MAAM,oBAAoB,CAAC;AA6DnH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AA8BxD,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;IAIhB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,YAAY,EAAE;QACZ,KAAK,EAAE,OAAO,CAAC;QACf,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,OAAO,CAAC;QACxB,kBAAkB,EAAE,OAAO,CAAC;QAC5B,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC;IACF,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC;IAIhE,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAKjC,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;CAC1C;AAQD,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,OAAO,EACP,YAAY,EACZ,MAAM,EACN,SAAS,EAAE,gBAAgB,EAC3B,YAAY,EACZ,WAAW,EACX,sBAA8B,EAC9B,eAAe,GAChB,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"EditorShell.d.ts","sourceRoot":"","sources":["../../../src/components/shell/EditorShell.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAejD,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAuDtF,OAAO,KAAK,EAAE,eAAe,EAA2D,MAAM,oBAAoB,CAAC;AA6DnH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AA8BxD,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;IAIhB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,YAAY,EAAE;QACZ,KAAK,EAAE,OAAO,CAAC;QACf,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,OAAO,CAAC;QACxB,kBAAkB,EAAE,OAAO,CAAC;QAC5B,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC;IACF,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC;IAIhE,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAKjC,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;CAC1C;AAQD,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,OAAO,EACP,YAAY,EACZ,MAAM,EACN,SAAS,EAAE,gBAAgB,EAC3B,YAAY,EACZ,WAAW,EACX,sBAA8B,EAC9B,eAAe,GAChB,EAAE,KAAK,2CAkwEP;AA8ED;6EAC6E;AAC7E,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,WAAW,CAAC,YAAY,CAAC,EACvC,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,eAAe,EAAE,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAK/B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drawnagency/primitives",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.118",
|
|
4
4
|
"description": "Browser-safe foundation of the Brand Portal framework: Zod schemas, section components, editor shell, hooks, pure libs, collab contract, document engine.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -18,6 +18,25 @@ interface EditablePlainTextProps
|
|
|
18
18
|
placeholder?: string;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
function caretOffset(el: HTMLElement): number | null {
|
|
22
|
+
const sel = window.getSelection();
|
|
23
|
+
if (!sel || sel.rangeCount === 0) return null;
|
|
24
|
+
const range = sel.getRangeAt(0);
|
|
25
|
+
if (!el.contains(range.endContainer)) return null;
|
|
26
|
+
const before = document.createRange();
|
|
27
|
+
before.selectNodeContents(el);
|
|
28
|
+
before.setEnd(range.endContainer, range.endOffset);
|
|
29
|
+
return before.toString().length;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function placeCaret(el: HTMLElement, offset: number) {
|
|
33
|
+
const sel = window.getSelection();
|
|
34
|
+
if (!sel) return;
|
|
35
|
+
// textContent leaves a single text node, or none for an empty string.
|
|
36
|
+
if (el.firstChild) sel.collapse(el.firstChild, offset);
|
|
37
|
+
else sel.collapse(el, 0);
|
|
38
|
+
}
|
|
39
|
+
|
|
21
40
|
export function EditablePlainText({
|
|
22
41
|
tag,
|
|
23
42
|
value,
|
|
@@ -48,9 +67,14 @@ export function EditablePlainText({
|
|
|
48
67
|
|
|
49
68
|
// Set textContent via ref (safe — plain text only, no HTML injection)
|
|
50
69
|
useEffect(() => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
70
|
+
const el = ref.current;
|
|
71
|
+
if (!el || el.textContent === localValue) return;
|
|
72
|
+
// A value that differs from the DOM while the field is focused (a peer
|
|
73
|
+
// save, a rebase or a 409 recovery landing mid-typing) replaces the text
|
|
74
|
+
// node, which collapses the caret to offset 0. Put it back, clamped.
|
|
75
|
+
const caret = document.activeElement === el ? caretOffset(el) : null;
|
|
76
|
+
el.textContent = localValue;
|
|
77
|
+
if (caret !== null) placeCaret(el, Math.min(caret, localValue.length));
|
|
54
78
|
}, [localValue]);
|
|
55
79
|
|
|
56
80
|
const onInput = useCallback(() => {
|
|
@@ -27,6 +27,8 @@ interface Props {
|
|
|
27
27
|
* an audience-filtered site.
|
|
28
28
|
*/
|
|
29
29
|
canImpersonate?: boolean;
|
|
30
|
+
/** Open the view in a new tab — set by the editor, so it keeps the editor tab. */
|
|
31
|
+
viewAsInNewTab?: boolean;
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
const PLACEHOLDER_COLOR = "#94a3b8";
|
|
@@ -174,7 +176,7 @@ function PageRow({ page }: { page: OverviewPage }) {
|
|
|
174
176
|
);
|
|
175
177
|
}
|
|
176
178
|
|
|
177
|
-
function AudienceBlock({ audience, revealSupported, canImpersonate }: { audience: AudienceDetail; revealSupported: boolean; canImpersonate: boolean }) {
|
|
179
|
+
function AudienceBlock({ audience, revealSupported, canImpersonate, viewAsInNewTab }: { audience: AudienceDetail; revealSupported: boolean; canImpersonate: boolean; viewAsInNewTab: boolean }) {
|
|
178
180
|
const [open, setOpen] = useState(false);
|
|
179
181
|
const { overview } = audience;
|
|
180
182
|
|
|
@@ -208,7 +210,7 @@ function AudienceBlock({ audience, revealSupported, canImpersonate }: { audience
|
|
|
208
210
|
</button>
|
|
209
211
|
{canImpersonate && (
|
|
210
212
|
// A plain form POST: the route sets the cookie and 303s to the viewer site.
|
|
211
|
-
<form method="post" action="/api/auth/impersonate" className="shrink-0">
|
|
213
|
+
<form method="post" action="/api/auth/impersonate" target={viewAsInNewTab ? "_blank" : undefined} className="shrink-0">
|
|
212
214
|
<input type="hidden" name="audience" value={audience.name} />
|
|
213
215
|
<Button type="submit" variant="secondary" size="sm" aria-label={`View the site as ${audience.displayName}`}>
|
|
214
216
|
<span className="inline-flex items-center gap-1.5">
|
|
@@ -260,7 +262,7 @@ function AudienceBlock({ audience, revealSupported, canImpersonate }: { audience
|
|
|
260
262
|
* Reachable by editors and the site's default audience (the client), so the
|
|
261
263
|
* client can hand a new partner access without going through us.
|
|
262
264
|
*/
|
|
263
|
-
export function AudienceDetailsPanel({ audiences, revealSupported, canImpersonate = false }: Props) {
|
|
265
|
+
export function AudienceDetailsPanel({ audiences, revealSupported, canImpersonate = false, viewAsInNewTab = false }: Props) {
|
|
264
266
|
if (audiences.length === 0) {
|
|
265
267
|
return (
|
|
266
268
|
<p className="text-sm text-base-contrast-light">
|
|
@@ -272,7 +274,7 @@ export function AudienceDetailsPanel({ audiences, revealSupported, canImpersonat
|
|
|
272
274
|
return (
|
|
273
275
|
<div className="flex flex-col gap-3">
|
|
274
276
|
{audiences.map((a) => (
|
|
275
|
-
<AudienceBlock key={a.name} audience={a} revealSupported={revealSupported} canImpersonate={canImpersonate} />
|
|
277
|
+
<AudienceBlock key={a.name} audience={a} revealSupported={revealSupported} canImpersonate={canImpersonate} viewAsInNewTab={viewAsInNewTab} />
|
|
276
278
|
))}
|
|
277
279
|
</div>
|
|
278
280
|
);
|
|
@@ -328,6 +328,9 @@ export default function EditorShell({
|
|
|
328
328
|
// null = the auth provider has no named sign-ins (`.env` mode → route 501s),
|
|
329
329
|
// which is also what turns the reveal buttons off.
|
|
330
330
|
const [viewerCredentials, setViewerCredentials] = useState<ViewerCredential[] | null>(null);
|
|
331
|
+
// Gates "View as" in Audience Details: without password protection no visitor
|
|
332
|
+
// sees an audience-filtered site, and the impersonate route refuses.
|
|
333
|
+
const [passwordEnabled, setPasswordEnabled] = useState(false);
|
|
331
334
|
const [movingSectionId, setMovingSectionId] = useState<string | null>(null);
|
|
332
335
|
// Set by recoverConflict when a rebase surfaces overlapping edits; drives the
|
|
333
336
|
// keep-mine/take-theirs dialog. `resolve` is the promise resolver recovery
|
|
@@ -1221,6 +1224,15 @@ export default function EditorShell({
|
|
|
1221
1224
|
if (!cancelled) setViewerCredentials(null);
|
|
1222
1225
|
}
|
|
1223
1226
|
})();
|
|
1227
|
+
(async () => {
|
|
1228
|
+
try {
|
|
1229
|
+
const res = await fetch("/api/auth/audiences");
|
|
1230
|
+
const enabled = res.ok && (await res.json()).passwordEnabled === true;
|
|
1231
|
+
if (!cancelled) setPasswordEnabled(enabled);
|
|
1232
|
+
} catch {
|
|
1233
|
+
if (!cancelled) setPasswordEnabled(false);
|
|
1234
|
+
}
|
|
1235
|
+
})();
|
|
1224
1236
|
return () => { cancelled = true; };
|
|
1225
1237
|
}, [showAudienceDetails]);
|
|
1226
1238
|
|
|
@@ -2308,7 +2320,7 @@ export default function EditorShell({
|
|
|
2308
2320
|
current working copy — add or remove sign-ins under Site settings → Audiences.
|
|
2309
2321
|
</p>
|
|
2310
2322
|
<div className="mt-6">
|
|
2311
|
-
<AudienceDetailsPanel audiences={audienceDetails} revealSupported={viewerCredentials !== null} />
|
|
2323
|
+
<AudienceDetailsPanel audiences={audienceDetails} revealSupported={viewerCredentials !== null} canImpersonate={passwordEnabled} viewAsInNewTab />
|
|
2312
2324
|
</div>
|
|
2313
2325
|
</div>
|
|
2314
2326
|
) : (
|