pi-studio 0.9.51 → 0.9.53
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 +33 -0
- package/README.md +12 -8
- package/ROADMAP.md +87 -0
- package/client/studio-client.js +854 -124
- package/client/studio-preview-resource-helpers.js +61 -12
- package/client/studio.css +186 -9
- package/index.ts +547 -70
- package/package.json +2 -1
- package/shared/studio-resource-grants.js +157 -0
- package/shared/studio-side-question-context.js +17 -4
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
const STUDIO_PREVIEW_LOCAL_IMAGE_LIMIT = 100;
|
|
3
|
+
const STUDIO_PREVIEW_LOCAL_PDF_LIMIT = 40;
|
|
3
4
|
const STUDIO_PREVIEW_IMAGE_DATA_URL_PATTERN = /^data:image\/(?:png|jpeg|gif|webp);base64,/i;
|
|
5
|
+
const STUDIO_PREVIEW_PDF_DATA_URL_PATTERN = /^data:application\/pdf;base64,/i;
|
|
4
6
|
|
|
5
7
|
function isResolvableStudioPreviewImageSource(value) {
|
|
6
8
|
const source = String(value || "").trim();
|
|
7
9
|
if (!source || source.startsWith("#") || source.startsWith("//")) return false;
|
|
8
10
|
if (/^(?:data|blob|https?|about|javascript):/i.test(source)) return false;
|
|
11
|
+
if (/^file:/i.test(source)) {
|
|
12
|
+
try {
|
|
13
|
+
const fileUrl = new URL(source);
|
|
14
|
+
return fileUrl.protocol === "file:" && (!fileUrl.hostname || fileUrl.hostname === "localhost");
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
9
19
|
if (/^[a-z][a-z0-9+.-]*:/i.test(source) && !/^[a-z]:[\\/]/i.test(source)) return false;
|
|
10
20
|
return true;
|
|
11
21
|
}
|
|
@@ -17,30 +27,66 @@
|
|
|
17
27
|
&& String(a.resourceDir || "") === String(b.resourceDir || "");
|
|
18
28
|
}
|
|
19
29
|
|
|
20
|
-
|
|
30
|
+
function isResolvableStudioPreviewPdfSource(value) {
|
|
31
|
+
const source = String(value || "").trim();
|
|
32
|
+
return isResolvableStudioPreviewImageSource(source) && /\.pdf(?:[?#].*)?$/i.test(source);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function hydrateStudioPreviewLocalMediaElements(target, options) {
|
|
36
|
+
const selector = options && options.selector;
|
|
37
|
+
const sourceAllowed = options && options.sourceAllowed;
|
|
38
|
+
const dataUrlAllowed = options && options.dataUrlAllowed;
|
|
39
|
+
const resolveResource = options && options.resolveResource;
|
|
40
|
+
const onError = options && options.onError;
|
|
41
|
+
const limit = Math.max(1, Number(options && options.limit) || 1);
|
|
21
42
|
if (!target || typeof target.querySelectorAll !== "function" || typeof resolveResource !== "function") {
|
|
22
43
|
return { attempted: 0, resolved: 0 };
|
|
23
44
|
}
|
|
24
45
|
|
|
25
|
-
const
|
|
26
|
-
.filter((
|
|
27
|
-
.slice(0,
|
|
46
|
+
const elements = Array.from(target.querySelectorAll(selector))
|
|
47
|
+
.filter((element) => element && typeof element.getAttribute === "function" && sourceAllowed(element.getAttribute("src")))
|
|
48
|
+
.slice(0, limit);
|
|
28
49
|
|
|
29
50
|
let resolved = 0;
|
|
30
|
-
await Promise.all(
|
|
31
|
-
const originalSource = String(
|
|
51
|
+
await Promise.all(elements.map(async (element) => {
|
|
52
|
+
const originalSource = String(element.getAttribute("src") || "").trim();
|
|
32
53
|
try {
|
|
33
54
|
const dataUrl = await resolveResource(originalSource);
|
|
34
|
-
if (!
|
|
35
|
-
if (
|
|
36
|
-
|
|
55
|
+
if (!dataUrlAllowed.test(String(dataUrl || ""))) throw new Error("Studio returned an unsupported local media payload.");
|
|
56
|
+
if (element.isConnected === false || String(element.getAttribute("src") || "").trim() !== originalSource) return;
|
|
57
|
+
element.setAttribute("src", dataUrl);
|
|
37
58
|
resolved += 1;
|
|
38
|
-
} catch {
|
|
39
|
-
|
|
59
|
+
} catch (error) {
|
|
60
|
+
if (element.isConnected === false || String(element.getAttribute("src") || "").trim() !== originalSource) return;
|
|
61
|
+
if (typeof onError === "function") {
|
|
62
|
+
try { await onError(element, originalSource, error); } catch {}
|
|
63
|
+
}
|
|
40
64
|
}
|
|
41
65
|
}));
|
|
42
66
|
|
|
43
|
-
return { attempted:
|
|
67
|
+
return { attempted: elements.length, resolved };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function hydrateStudioPreviewLocalImages(target, resolveResource, options) {
|
|
71
|
+
return hydrateStudioPreviewLocalMediaElements(target, {
|
|
72
|
+
selector: "img[src]",
|
|
73
|
+
sourceAllowed: isResolvableStudioPreviewImageSource,
|
|
74
|
+
dataUrlAllowed: STUDIO_PREVIEW_IMAGE_DATA_URL_PATTERN,
|
|
75
|
+
resolveResource,
|
|
76
|
+
onError: options && options.onError,
|
|
77
|
+
limit: STUDIO_PREVIEW_LOCAL_IMAGE_LIMIT,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function hydrateStudioPreviewLocalPdfEmbeds(target, resolveResource, options) {
|
|
82
|
+
return hydrateStudioPreviewLocalMediaElements(target, {
|
|
83
|
+
selector: "embed[src]",
|
|
84
|
+
sourceAllowed: isResolvableStudioPreviewPdfSource,
|
|
85
|
+
dataUrlAllowed: STUDIO_PREVIEW_PDF_DATA_URL_PATTERN,
|
|
86
|
+
resolveResource,
|
|
87
|
+
onError: options && options.onError,
|
|
88
|
+
limit: STUDIO_PREVIEW_LOCAL_PDF_LIMIT,
|
|
89
|
+
});
|
|
44
90
|
}
|
|
45
91
|
|
|
46
92
|
function buildStudioPdfVersionSignature(headers) {
|
|
@@ -94,11 +140,14 @@
|
|
|
94
140
|
|
|
95
141
|
globalThis.PiStudioPreviewResourceHelpers = Object.freeze({
|
|
96
142
|
STUDIO_PREVIEW_LOCAL_IMAGE_LIMIT,
|
|
143
|
+
STUDIO_PREVIEW_LOCAL_PDF_LIMIT,
|
|
97
144
|
areStudioPreviewResourceContextsEqual,
|
|
98
145
|
buildStudioPdfVersionSignature,
|
|
99
146
|
createStudioPdfVersionObservationState,
|
|
100
147
|
hydrateStudioPreviewLocalImages,
|
|
148
|
+
hydrateStudioPreviewLocalPdfEmbeds,
|
|
101
149
|
isResolvableStudioPreviewImageSource,
|
|
150
|
+
isResolvableStudioPreviewPdfSource,
|
|
102
151
|
observeStudioPdfVersion,
|
|
103
152
|
});
|
|
104
153
|
})();
|
package/client/studio.css
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
justify-content: space-between;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
h1 {
|
|
32
|
+
body > header h1 {
|
|
33
33
|
margin: 0;
|
|
34
34
|
font-size: 18px;
|
|
35
35
|
font-weight: 600;
|
|
@@ -202,6 +202,10 @@
|
|
|
202
202
|
font-weight: 450;
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
.export-preview-menu button[hidden] {
|
|
206
|
+
display: none !important;
|
|
207
|
+
}
|
|
208
|
+
|
|
205
209
|
.export-preview-menu button:not(:disabled):hover,
|
|
206
210
|
.export-preview-menu button:not(:disabled):focus-visible {
|
|
207
211
|
background: var(--panel-2);
|
|
@@ -1182,6 +1186,7 @@
|
|
|
1182
1186
|
.rendered-markdown h4,
|
|
1183
1187
|
.rendered-markdown h5,
|
|
1184
1188
|
.rendered-markdown h6 {
|
|
1189
|
+
display: block;
|
|
1185
1190
|
margin-top: 1.2em;
|
|
1186
1191
|
margin-bottom: 0.5em;
|
|
1187
1192
|
line-height: 1.25;
|
|
@@ -1190,17 +1195,39 @@
|
|
|
1190
1195
|
}
|
|
1191
1196
|
|
|
1192
1197
|
.rendered-markdown h1 {
|
|
1193
|
-
font-size: 1.
|
|
1198
|
+
font-size: 1.7em;
|
|
1199
|
+
font-weight: 720;
|
|
1194
1200
|
border-bottom: 0;
|
|
1195
1201
|
padding-bottom: 0;
|
|
1196
1202
|
}
|
|
1197
1203
|
|
|
1198
1204
|
.rendered-markdown h2 {
|
|
1199
|
-
font-size: 1.
|
|
1205
|
+
font-size: 1.4em;
|
|
1206
|
+
font-weight: 700;
|
|
1200
1207
|
border-bottom: 0;
|
|
1201
1208
|
padding-bottom: 0;
|
|
1202
1209
|
}
|
|
1203
1210
|
|
|
1211
|
+
.rendered-markdown h3 {
|
|
1212
|
+
font-size: 1.2em;
|
|
1213
|
+
font-weight: 680;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
.rendered-markdown h4 {
|
|
1217
|
+
font-size: 1.08em;
|
|
1218
|
+
font-weight: 660;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
.rendered-markdown h5 {
|
|
1222
|
+
font-size: 1em;
|
|
1223
|
+
font-weight: 650;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
.rendered-markdown h6 {
|
|
1227
|
+
font-size: 0.92em;
|
|
1228
|
+
font-weight: 650;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1204
1231
|
.rendered-markdown #title-block-header {
|
|
1205
1232
|
text-align: center;
|
|
1206
1233
|
margin-bottom: 2em;
|
|
@@ -1767,6 +1794,7 @@
|
|
|
1767
1794
|
}
|
|
1768
1795
|
|
|
1769
1796
|
.rendered-markdown .studio-pdf-preview {
|
|
1797
|
+
position: relative;
|
|
1770
1798
|
display: block;
|
|
1771
1799
|
max-width: 100%;
|
|
1772
1800
|
border: 1px solid var(--md-table-border);
|
|
@@ -1776,6 +1804,10 @@
|
|
|
1776
1804
|
line-height: 0;
|
|
1777
1805
|
}
|
|
1778
1806
|
|
|
1807
|
+
.rendered-markdown .studio-pdf-preview-focus-target {
|
|
1808
|
+
cursor: zoom-in;
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1779
1811
|
.rendered-markdown .studio-pdf-preview[data-fig-align="center"] {
|
|
1780
1812
|
margin-left: auto;
|
|
1781
1813
|
margin-right: auto;
|
|
@@ -1881,6 +1913,19 @@
|
|
|
1881
1913
|
border-color: var(--control-border);
|
|
1882
1914
|
}
|
|
1883
1915
|
|
|
1916
|
+
.rendered-markdown button.studio-pdf-card-action[data-studio-action-feedback="success"],
|
|
1917
|
+
.studio-pdf-focus-btn[data-studio-action-feedback="success"] {
|
|
1918
|
+
background: var(--accent-soft);
|
|
1919
|
+
color: var(--accent);
|
|
1920
|
+
border-color: color-mix(in srgb, var(--accent) 45%, var(--control-border));
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
.rendered-markdown button.studio-pdf-card-action[data-studio-action-feedback="warning"],
|
|
1924
|
+
.studio-pdf-focus-btn[data-studio-action-feedback="warning"] {
|
|
1925
|
+
color: var(--warn);
|
|
1926
|
+
border-color: color-mix(in srgb, var(--warn) 45%, var(--control-border));
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1884
1929
|
.rendered-markdown button.studio-pdf-card-auto-refresh[aria-pressed="true"] {
|
|
1885
1930
|
background: transparent;
|
|
1886
1931
|
color: var(--accent);
|
|
@@ -1896,13 +1941,14 @@
|
|
|
1896
1941
|
}
|
|
1897
1942
|
|
|
1898
1943
|
.rendered-markdown button.studio-pdf-card-focus {
|
|
1899
|
-
width:
|
|
1944
|
+
width: auto;
|
|
1900
1945
|
min-width: 29px;
|
|
1901
1946
|
min-height: 29px;
|
|
1902
|
-
padding: 0;
|
|
1947
|
+
padding: 0 8px;
|
|
1903
1948
|
display: inline-flex;
|
|
1904
1949
|
align-items: center;
|
|
1905
1950
|
justify-content: center;
|
|
1951
|
+
gap: 5px;
|
|
1906
1952
|
}
|
|
1907
1953
|
|
|
1908
1954
|
.rendered-markdown button.studio-pdf-card-focus .studio-refresh-icon {
|
|
@@ -2075,6 +2121,10 @@
|
|
|
2075
2121
|
height: 14px;
|
|
2076
2122
|
}
|
|
2077
2123
|
|
|
2124
|
+
.studio-pdf-focus-fullscreen[hidden] {
|
|
2125
|
+
display: none !important;
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2078
2128
|
.studio-pdf-focus-fullscreen,
|
|
2079
2129
|
.studio-pdf-focus-close {
|
|
2080
2130
|
width: 29px;
|
|
@@ -2982,6 +3032,97 @@
|
|
|
2982
3032
|
overflow-anchor: none;
|
|
2983
3033
|
}
|
|
2984
3034
|
|
|
3035
|
+
.rendered-markdown .studio-blocked-media {
|
|
3036
|
+
display: flex;
|
|
3037
|
+
align-items: center;
|
|
3038
|
+
justify-content: space-between;
|
|
3039
|
+
gap: 12px;
|
|
3040
|
+
width: 100%;
|
|
3041
|
+
margin: 10px 0;
|
|
3042
|
+
padding: 10px 12px;
|
|
3043
|
+
border: 1px solid color-mix(in srgb, var(--warn) 42%, var(--panel-border));
|
|
3044
|
+
border-radius: 9px;
|
|
3045
|
+
background: color-mix(in srgb, var(--warn) 7%, var(--panel));
|
|
3046
|
+
color: var(--text);
|
|
3047
|
+
font-family: var(--font-ui);
|
|
3048
|
+
font-size: 12px;
|
|
3049
|
+
font-style: normal;
|
|
3050
|
+
line-height: 1.35;
|
|
3051
|
+
box-sizing: border-box;
|
|
3052
|
+
}
|
|
3053
|
+
|
|
3054
|
+
.rendered-markdown .studio-blocked-media-text {
|
|
3055
|
+
min-width: 0;
|
|
3056
|
+
display: flex;
|
|
3057
|
+
flex-direction: column;
|
|
3058
|
+
gap: 3px;
|
|
3059
|
+
}
|
|
3060
|
+
|
|
3061
|
+
.rendered-markdown .studio-blocked-media-text strong {
|
|
3062
|
+
color: var(--warn);
|
|
3063
|
+
font-weight: 650;
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
.rendered-markdown .studio-blocked-media-text code {
|
|
3067
|
+
display: block;
|
|
3068
|
+
max-width: min(72vw, 760px);
|
|
3069
|
+
overflow: hidden;
|
|
3070
|
+
color: var(--studio-info-text, var(--muted));
|
|
3071
|
+
font-family: var(--font-mono);
|
|
3072
|
+
font-size: 11px;
|
|
3073
|
+
text-overflow: ellipsis;
|
|
3074
|
+
white-space: nowrap;
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3077
|
+
.rendered-markdown button.studio-blocked-media-allow {
|
|
3078
|
+
flex: 0 0 auto;
|
|
3079
|
+
min-height: 30px;
|
|
3080
|
+
padding: 5px 10px;
|
|
3081
|
+
border: 1px solid color-mix(in srgb, var(--warn) 48%, var(--control-border));
|
|
3082
|
+
border-radius: 8px;
|
|
3083
|
+
background: var(--panel);
|
|
3084
|
+
color: var(--text);
|
|
3085
|
+
font: inherit;
|
|
3086
|
+
font-weight: 600;
|
|
3087
|
+
cursor: pointer;
|
|
3088
|
+
white-space: nowrap;
|
|
3089
|
+
}
|
|
3090
|
+
|
|
3091
|
+
.rendered-markdown button.studio-blocked-media-allow:not(:disabled):hover,
|
|
3092
|
+
.rendered-markdown button.studio-blocked-media-allow:focus-visible {
|
|
3093
|
+
border-color: var(--warn);
|
|
3094
|
+
background: var(--control-hover-bg, var(--panel-2));
|
|
3095
|
+
outline: none;
|
|
3096
|
+
}
|
|
3097
|
+
|
|
3098
|
+
.rendered-markdown button.studio-blocked-media-allow:disabled {
|
|
3099
|
+
cursor: default;
|
|
3100
|
+
opacity: 0.6;
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3103
|
+
.rendered-markdown .studio-html-artifact-blocked-media {
|
|
3104
|
+
display: grid;
|
|
3105
|
+
gap: 6px;
|
|
3106
|
+
padding: 0 10px;
|
|
3107
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
3108
|
+
background: var(--panel);
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3111
|
+
.rendered-markdown .studio-html-artifact-blocked-media .studio-blocked-media {
|
|
3112
|
+
margin: 8px 0;
|
|
3113
|
+
}
|
|
3114
|
+
|
|
3115
|
+
@media (max-width: 680px) {
|
|
3116
|
+
.rendered-markdown .studio-blocked-media {
|
|
3117
|
+
align-items: stretch;
|
|
3118
|
+
flex-direction: column;
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3121
|
+
.rendered-markdown button.studio-blocked-media-allow {
|
|
3122
|
+
align-self: flex-start;
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
|
|
2985
3126
|
.preview-error {
|
|
2986
3127
|
color: var(--warn);
|
|
2987
3128
|
margin-bottom: 0.75em;
|
|
@@ -3651,13 +3792,15 @@
|
|
|
3651
3792
|
|
|
3652
3793
|
.files-toolbar-actions button,
|
|
3653
3794
|
.files-actions button,
|
|
3654
|
-
.files-sort-select
|
|
3795
|
+
.files-sort-select,
|
|
3796
|
+
.files-location-select {
|
|
3655
3797
|
padding: 4px 7px;
|
|
3656
3798
|
font-size: 11px;
|
|
3657
3799
|
}
|
|
3658
3800
|
|
|
3659
|
-
.files-sort-select
|
|
3660
|
-
|
|
3801
|
+
.files-sort-select,
|
|
3802
|
+
.files-location-select {
|
|
3803
|
+
max-width: 240px;
|
|
3661
3804
|
border: 1px solid var(--control-border);
|
|
3662
3805
|
border-radius: 7px;
|
|
3663
3806
|
background: var(--panel);
|
|
@@ -3665,6 +3808,26 @@
|
|
|
3665
3808
|
font-family: var(--font-ui);
|
|
3666
3809
|
}
|
|
3667
3810
|
|
|
3811
|
+
.files-sort-select {
|
|
3812
|
+
max-width: 150px;
|
|
3813
|
+
}
|
|
3814
|
+
|
|
3815
|
+
.files-no-locations,
|
|
3816
|
+
.files-section-title {
|
|
3817
|
+
color: var(--studio-info-text, var(--muted));
|
|
3818
|
+
font-size: 11px;
|
|
3819
|
+
font-weight: 700;
|
|
3820
|
+
letter-spacing: 0.03em;
|
|
3821
|
+
text-transform: uppercase;
|
|
3822
|
+
}
|
|
3823
|
+
|
|
3824
|
+
.files-exact-section {
|
|
3825
|
+
display: grid;
|
|
3826
|
+
gap: 6px;
|
|
3827
|
+
padding-bottom: 10px;
|
|
3828
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
3829
|
+
}
|
|
3830
|
+
|
|
3668
3831
|
.files-subtitle,
|
|
3669
3832
|
.files-notice,
|
|
3670
3833
|
.files-empty {
|
|
@@ -5429,7 +5592,7 @@
|
|
|
5429
5592
|
gap: 9px;
|
|
5430
5593
|
}
|
|
5431
5594
|
|
|
5432
|
-
body.studio-ui-refresh h1 {
|
|
5595
|
+
body.studio-ui-refresh > header h1 {
|
|
5433
5596
|
font-size: 16px;
|
|
5434
5597
|
}
|
|
5435
5598
|
|
|
@@ -6267,6 +6430,13 @@
|
|
|
6267
6430
|
font-weight: 650;
|
|
6268
6431
|
}
|
|
6269
6432
|
|
|
6433
|
+
.studio-decision-confirm:not(.is-destructive):not(:disabled):hover,
|
|
6434
|
+
.studio-decision-confirm:not(.is-destructive):focus-visible {
|
|
6435
|
+
border-color: color-mix(in srgb, var(--accent) 84%, var(--text));
|
|
6436
|
+
background: color-mix(in srgb, var(--accent) 84%, var(--text));
|
|
6437
|
+
color: var(--accent-contrast);
|
|
6438
|
+
}
|
|
6439
|
+
|
|
6270
6440
|
.studio-decision-confirm.is-destructive {
|
|
6271
6441
|
border-color: var(--warn-border);
|
|
6272
6442
|
background: color-mix(in srgb, var(--warn) 15%, var(--panel));
|
|
@@ -6385,6 +6555,13 @@
|
|
|
6385
6555
|
margin: 6px 0 0 18px;
|
|
6386
6556
|
}
|
|
6387
6557
|
|
|
6558
|
+
.side-question-context-access-note {
|
|
6559
|
+
margin: 9px 0 0;
|
|
6560
|
+
color: var(--muted);
|
|
6561
|
+
font-size: 0.78rem;
|
|
6562
|
+
line-height: 1.42;
|
|
6563
|
+
}
|
|
6564
|
+
|
|
6388
6565
|
.side-question-context-grid select,
|
|
6389
6566
|
.side-question-path-label input,
|
|
6390
6567
|
.side-question-composer-label textarea {
|