camox 0.43.0 → 0.44.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/bin/camox.mjs +9 -1
- package/dist/core/components/lexical/InlineStylesPlugin.js +22 -6
- package/dist/core/components/lexical/SelectionBroadcaster.js +4 -4
- package/dist/core/components/lexical/SidebarLexicalEditor.js +15 -15
- package/dist/core/createApp.d.ts +28 -2
- package/dist/core/createBlock.js +24 -10
- package/dist/core/editing/createEditableBlock.d.ts +135 -1
- package/dist/core/editing/createEditableBlock.js +209 -74
- package/dist/core/lib/contentType.d.ts +5 -0
- package/dist/core/lib/contentType.js +11 -0
- package/dist/core/lib/fieldTypes.js +1 -0
- package/dist/core/lib/iconTypes.d.ts +13 -0
- package/dist/core/lib/icons.d.ts +6 -0
- package/dist/core/lib/icons.js +130 -0
- package/dist/core/lib/lexicalState.js +6 -6
- package/dist/core/lib/modifierFormats.js +1 -1
- package/dist/core/lib/textStyles.d.ts +1 -1
- package/dist/core/lib/textStyles.js +3 -3
- package/dist/features/content/components/AssetCard.js +104 -68
- package/dist/features/preview/CamoxPreview.js +120 -95
- package/dist/features/preview/commentsEnabled.js +2 -2
- package/dist/features/preview/components/AssetLightbox.js +17 -6
- package/dist/features/preview/components/AttachedComments.js +224 -87
- package/dist/features/preview/components/CommentTargetQuote.js +22 -21
- package/dist/features/preview/components/DerivedLayoutDialog.js +36 -21
- package/dist/features/preview/components/FieldOverlayStyles.js +29 -9
- package/dist/features/preview/components/FieldToolbar.js +8 -8
- package/dist/features/preview/components/IconFieldEditor.js +231 -0
- package/dist/features/preview/components/ItemFieldsEditor.js +21 -14
- package/dist/features/preview/components/OverlayTracker.js +1 -1
- package/dist/features/preview/components/PagePicker.js +44 -44
- package/dist/features/preview/components/PreviewPanel.js +1 -1
- package/dist/features/preview/components/PreviewToolbar.js +224 -225
- package/dist/features/preview/components/SendFeedbackDialog.js +83 -0
- package/dist/features/preview/overlayHighlights.js +54 -0
- package/dist/features/preview/previewCommentsStore.js +54 -34
- package/dist/features/preview/previewSelection.js +28 -23
- package/dist/features/preview/usePageComments.js +39 -0
- package/dist/features/provider/CoreCamoxProvider.js +37 -5
- package/dist/features/provider/LocalhostPreviewProvider.js +81 -45
- package/dist/features/provider/components/CommandPalette.js +35 -84
- package/dist/features/runtime/pageApp.js +32 -28
- package/dist/features/runtime/pageServer.js +4 -1
- package/dist/features/runtime/runtime.d.ts +2 -0
- package/dist/features/runtime/runtime.js +25 -0
- package/dist/features/studio/components/EnvironmentMenu.js +75 -63
- package/dist/features/vite/auth.js +1 -50
- package/dist/features/vite/iconGeneration.js +16 -0
- package/dist/features/vite/vite.d.ts +4 -2
- package/dist/features/vite/vite.js +19 -2
- package/dist/lib/auth.js +39 -16
- package/dist/lib/preview-handoff.js +13 -0
- package/dist/lib/queries.js +12 -1
- package/dist/lib/use-project-room.js +5 -2
- package/dist/studio-overlays.css +19 -15
- package/dist/studio.css +1 -1
- package/package.json +5 -4
- package/skills/camox/SKILL.md +6 -0
- package/skills/camox/references/block-definitions.md +27 -0
- package/skills/camox/references/cli-common.md +14 -0
- package/skills/camox/references/cli-content.md +11 -0
- package/skills/camox/references/field-styling.md +4 -4
- package/skills/camoxify/SKILL.md +14 -0
|
@@ -2,6 +2,7 @@ import { generateAppFile, watchAppFile } from "./appGeneration.js";
|
|
|
2
2
|
import { readAuthTokenForUrl } from "./auth.js";
|
|
3
3
|
import { watchNewBlockFiles } from "./blockBoilerplate.js";
|
|
4
4
|
import { installDevAuthenticationMiddleware } from "./devAuthentication.js";
|
|
5
|
+
import { generateIconTypes } from "./iconGeneration.js";
|
|
5
6
|
import { syncDefinitions, syncDefinitionsToApi } from "./definitionsSync.js";
|
|
6
7
|
import { cleanupGeneratedRouteFiles } from "./routeGeneration.js";
|
|
7
8
|
import { installRuntimeNitroRoutes, loadRuntimeDevModule, resolveRuntimeDevId } from "./runtimeDev.js";
|
|
@@ -95,7 +96,8 @@ function camox(options) {
|
|
|
95
96
|
cpSync(serverAssets, join(options.output.publicDir, "assets"), { recursive: true });
|
|
96
97
|
});
|
|
97
98
|
} },
|
|
98
|
-
config(_config, env) {
|
|
99
|
+
async config(_config, env) {
|
|
100
|
+
const iconIds = await generateIconTypes(resolve(_config.root ?? process.cwd()), options.icons);
|
|
99
101
|
isBuild = env.command === "build";
|
|
100
102
|
isRelease = isBuild && process.env.CAMOX_INTERNAL_RELEASE === "1";
|
|
101
103
|
if (isRelease) environmentName = "production";
|
|
@@ -107,9 +109,10 @@ function camox(options) {
|
|
|
107
109
|
return {
|
|
108
110
|
build: { emitAssets: true },
|
|
109
111
|
define: {
|
|
112
|
+
__CAMOX_ICON_IDS__: JSON.stringify(iconIds),
|
|
110
113
|
__CAMOX_TELEMETRY_DISABLED__: JSON.stringify(!!options.disableTelemetry),
|
|
111
114
|
__ENABLE_TANSTACK_DEVTOOLS__: JSON.stringify(enableTanstackDevtools),
|
|
112
|
-
|
|
115
|
+
__CAMOX_ENABLE_EXPERIMENTAL_FEATURES__: JSON.stringify(options._internal?.enableExperimentalFeatures ?? false),
|
|
113
116
|
__CAMOX_ENVIRONMENT_NAME__: JSON.stringify(environmentName),
|
|
114
117
|
__CAMOX_API_URL__: JSON.stringify(apiUrl),
|
|
115
118
|
__CAMOX_AUTHENTICATION_URL__: JSON.stringify(authenticationUrl),
|
|
@@ -139,6 +142,8 @@ function camox(options) {
|
|
|
139
142
|
"camox > @base-ui/react/accordion",
|
|
140
143
|
"camox > @base-ui/react/alert-dialog",
|
|
141
144
|
"camox > @base-ui/react/avatar",
|
|
145
|
+
"camox > @base-ui/react/button",
|
|
146
|
+
"camox > @base-ui/react/combobox",
|
|
142
147
|
"camox > @base-ui/react/dialog",
|
|
143
148
|
"camox > @base-ui/react/input",
|
|
144
149
|
"camox > @base-ui/react/menu",
|
|
@@ -153,9 +158,12 @@ function camox(options) {
|
|
|
153
158
|
"camox > @base-ui/react/use-render",
|
|
154
159
|
"camox > @camox/api-contract",
|
|
155
160
|
"camox > @camox/api-contract/query-keys",
|
|
161
|
+
"camox > @camox/ui > class-variance-authority",
|
|
162
|
+
"camox > @camox/ui > clsx",
|
|
156
163
|
"camox > @camox/ui > cmdk",
|
|
157
164
|
"camox > @camox/ui > lucide-react",
|
|
158
165
|
"camox > @camox/ui > sonner",
|
|
166
|
+
"camox > @camox/ui > tailwind-merge",
|
|
159
167
|
"camox > @dnd-kit/core",
|
|
160
168
|
"camox > @dnd-kit/modifiers",
|
|
161
169
|
"camox > @dnd-kit/sortable",
|
|
@@ -179,7 +187,14 @@ function camox(options) {
|
|
|
179
187
|
"camox > @sinclair/typebox",
|
|
180
188
|
"camox > @takumi-rs/image-response",
|
|
181
189
|
"camox > @tanstack/react-form",
|
|
190
|
+
"camox > @tanstack/react-query",
|
|
191
|
+
"camox > @tanstack/react-router",
|
|
192
|
+
"camox > @tanstack/react-virtual",
|
|
193
|
+
"camox > @unhead/react/client",
|
|
194
|
+
"camox > @unhead/react/server",
|
|
182
195
|
"camox > @xstate/store-react",
|
|
196
|
+
"camox > better-auth/client/plugins",
|
|
197
|
+
"camox > better-auth/react",
|
|
183
198
|
"camox > better-auth > @better-auth/core/env",
|
|
184
199
|
"camox > better-auth > @better-auth/core/error",
|
|
185
200
|
"camox > better-auth > @better-auth/core/utils/error-codes",
|
|
@@ -190,6 +205,7 @@ function camox(options) {
|
|
|
190
205
|
"camox > fractional-indexing",
|
|
191
206
|
"camox > lexical",
|
|
192
207
|
"camox > lucide-react",
|
|
208
|
+
"camox > marked",
|
|
193
209
|
"camox > @tanstack/react-query-devtools/production",
|
|
194
210
|
"camox > partysocket/react"
|
|
195
211
|
] }
|
|
@@ -246,6 +262,7 @@ function camox(options) {
|
|
|
246
262
|
root: resolvedConfig.root,
|
|
247
263
|
cacheDir: resolve(resolvedConfig.root, "node_modules", ".vite-camox-temp"),
|
|
248
264
|
resolve: resolvedConfig.resolve,
|
|
265
|
+
define: resolvedConfig.define,
|
|
249
266
|
server: { middlewareMode: true },
|
|
250
267
|
logLevel: "silent"
|
|
251
268
|
});
|
package/dist/lib/auth.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { actionsStore } from "../features/provider/actionsStore.js";
|
|
2
|
+
import { validatePreviewTarget } from "./preview-handoff.js";
|
|
2
3
|
import { SERVER_AUTH_COOKIE_NAME, buildClearServerAuthCookieHeader, getServerAuthCookieHeader } from "./server-auth-cookie.js";
|
|
3
4
|
import { c } from "react/compiler-runtime";
|
|
4
5
|
import * as React from "react";
|
|
@@ -181,21 +182,32 @@ function createCamoxAuthClient(apiUrl) {
|
|
|
181
182
|
* Process a `?ott=` one-time token from the URL before the provider mounts.
|
|
182
183
|
* Verifies the token against the API backend and notifies the session store.
|
|
183
184
|
*
|
|
184
|
-
*
|
|
185
|
+
* Reports completion and explicit handoff failures instead of silently showing live content.
|
|
185
186
|
*/
|
|
186
|
-
function useProcessOtt(authClient) {
|
|
187
|
+
function useProcessOtt(authClient, target) {
|
|
188
|
+
const [error, setError] = React.useState(null);
|
|
189
|
+
const processing = React.useRef(false);
|
|
187
190
|
const [ready, setReady] = React.useState(() => {
|
|
188
191
|
if (typeof window === "undefined") return true;
|
|
189
192
|
return !new URL(window.location.href).searchParams.has("ott");
|
|
190
193
|
});
|
|
191
194
|
React.useEffect(() => {
|
|
192
|
-
if (ready) return;
|
|
193
195
|
const url = new URL(window.location.href);
|
|
196
|
+
const targetError = validatePreviewTarget(url.searchParams.get("camox-preview"), target);
|
|
197
|
+
if (targetError) {
|
|
198
|
+
url.searchParams.delete("ott");
|
|
199
|
+
window.history.replaceState({}, "", url);
|
|
200
|
+
setError(targetError);
|
|
201
|
+
setReady(true);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (ready || processing.current) return;
|
|
194
205
|
const ott = url.searchParams.get("ott");
|
|
195
206
|
if (!ott) {
|
|
196
207
|
setReady(true);
|
|
197
208
|
return;
|
|
198
209
|
}
|
|
210
|
+
processing.current = true;
|
|
199
211
|
url.searchParams.delete("ott");
|
|
200
212
|
window.history.replaceState({}, "", url);
|
|
201
213
|
(async () => {
|
|
@@ -205,18 +217,29 @@ function useProcessOtt(authClient) {
|
|
|
205
217
|
if (!verification.data) throw new Error("OTT verification returned no session");
|
|
206
218
|
window.location.reload();
|
|
207
219
|
return;
|
|
208
|
-
} catch {
|
|
220
|
+
} catch {
|
|
221
|
+
setError("Preview sign-in failed. The link may have expired or already been used. Run camox preview again for a fresh link.");
|
|
222
|
+
}
|
|
209
223
|
setReady(true);
|
|
210
224
|
})();
|
|
211
|
-
}, [
|
|
212
|
-
|
|
225
|
+
}, [
|
|
226
|
+
authClient,
|
|
227
|
+
ready,
|
|
228
|
+
target.projectSlug,
|
|
229
|
+
target.environmentName,
|
|
230
|
+
target.apiUrl
|
|
231
|
+
]);
|
|
232
|
+
return {
|
|
233
|
+
ready,
|
|
234
|
+
error
|
|
235
|
+
};
|
|
213
236
|
}
|
|
214
237
|
const AuthContext = React.createContext(null);
|
|
215
238
|
function useAuthContext() {
|
|
216
239
|
const $ = c(1);
|
|
217
|
-
if ($[0] !== "
|
|
240
|
+
if ($[0] !== "2870dba5d074cbe2d9a238f9ae39bb51493bf31c0dd30caa79404003309e1525") {
|
|
218
241
|
for (let $i = 0; $i < 1; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
219
|
-
$[0] = "
|
|
242
|
+
$[0] = "2870dba5d074cbe2d9a238f9ae39bb51493bf31c0dd30caa79404003309e1525";
|
|
220
243
|
}
|
|
221
244
|
const ctx = React.useContext(AuthContext);
|
|
222
245
|
if (!ctx) throw new Error("Missing CamoxProvider");
|
|
@@ -224,9 +247,9 @@ function useAuthContext() {
|
|
|
224
247
|
}
|
|
225
248
|
function useProjectSlug() {
|
|
226
249
|
const $ = c(1);
|
|
227
|
-
if ($[0] !== "
|
|
250
|
+
if ($[0] !== "2870dba5d074cbe2d9a238f9ae39bb51493bf31c0dd30caa79404003309e1525") {
|
|
228
251
|
for (let $i = 0; $i < 1; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
229
|
-
$[0] = "
|
|
252
|
+
$[0] = "2870dba5d074cbe2d9a238f9ae39bb51493bf31c0dd30caa79404003309e1525";
|
|
230
253
|
}
|
|
231
254
|
return useAuthContext().projectSlug;
|
|
232
255
|
}
|
|
@@ -242,18 +265,18 @@ function useAuthState() {
|
|
|
242
265
|
}
|
|
243
266
|
function useIsAuthenticated() {
|
|
244
267
|
const $ = c(1);
|
|
245
|
-
if ($[0] !== "
|
|
268
|
+
if ($[0] !== "2870dba5d074cbe2d9a238f9ae39bb51493bf31c0dd30caa79404003309e1525") {
|
|
246
269
|
for (let $i = 0; $i < 1; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
247
|
-
$[0] = "
|
|
270
|
+
$[0] = "2870dba5d074cbe2d9a238f9ae39bb51493bf31c0dd30caa79404003309e1525";
|
|
248
271
|
}
|
|
249
272
|
const { isAuthenticated } = useAuthState();
|
|
250
273
|
return isAuthenticated;
|
|
251
274
|
}
|
|
252
275
|
function useSignInRedirect(callbackHref) {
|
|
253
276
|
const $ = c(4);
|
|
254
|
-
if ($[0] !== "
|
|
277
|
+
if ($[0] !== "2870dba5d074cbe2d9a238f9ae39bb51493bf31c0dd30caa79404003309e1525") {
|
|
255
278
|
for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
256
|
-
$[0] = "
|
|
279
|
+
$[0] = "2870dba5d074cbe2d9a238f9ae39bb51493bf31c0dd30caa79404003309e1525";
|
|
257
280
|
}
|
|
258
281
|
const { authenticationUrl } = useAuthContext();
|
|
259
282
|
let t0;
|
|
@@ -275,9 +298,9 @@ function useSignInRedirect(callbackHref) {
|
|
|
275
298
|
*/
|
|
276
299
|
function useAuthActions() {
|
|
277
300
|
const $ = c(5);
|
|
278
|
-
if ($[0] !== "
|
|
301
|
+
if ($[0] !== "2870dba5d074cbe2d9a238f9ae39bb51493bf31c0dd30caa79404003309e1525") {
|
|
279
302
|
for (let $i = 0; $i < 5; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
280
|
-
$[0] = "
|
|
303
|
+
$[0] = "2870dba5d074cbe2d9a238f9ae39bb51493bf31c0dd30caa79404003309e1525";
|
|
281
304
|
}
|
|
282
305
|
const { authClient, authenticationUrl } = useAuthContext();
|
|
283
306
|
let t0;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/lib/preview-handoff.ts
|
|
2
|
+
/** Validate the destination before exchanging any credential with its backend. */
|
|
3
|
+
function validatePreviewTarget(raw, target) {
|
|
4
|
+
if (raw === null) return null;
|
|
5
|
+
try {
|
|
6
|
+
const expected = JSON.parse(raw);
|
|
7
|
+
if (expected.projectSlug === target.projectSlug && expected.environmentName === target.environmentName && typeof expected.apiUrl === "string" && expected.apiUrl.replace(/\/+$/, "") === target.apiUrl.replace(/\/+$/, "")) return null;
|
|
8
|
+
} catch {}
|
|
9
|
+
return "Preview destination does not match the CLI project, backend, or environment. Check --cwd and --url, then run camox preview again.";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
export { validatePreviewTarget };
|
package/dist/lib/queries.js
CHANGED
|
@@ -3,6 +3,17 @@ import { getApiUrl, getEnvironmentName, getOrpc } from "./api-client.js";
|
|
|
3
3
|
import { queryKeys } from "@camox/api-contract/query-keys";
|
|
4
4
|
|
|
5
5
|
//#region src/lib/queries.ts
|
|
6
|
+
const commentQueries = { list: (pageId) => ({
|
|
7
|
+
...getOrpc().comments.list.queryOptions({
|
|
8
|
+
input: { pageId },
|
|
9
|
+
staleTime: 3e4
|
|
10
|
+
}),
|
|
11
|
+
queryKey: [...queryKeys.comments.list(pageId), getEnvironmentName() ?? "production"]
|
|
12
|
+
}) };
|
|
13
|
+
const commentMutations = {
|
|
14
|
+
create: () => getOrpc().comments.create.mutationOptions(),
|
|
15
|
+
setResolved: () => getOrpc().comments.setResolved.mutationOptions()
|
|
16
|
+
};
|
|
6
17
|
const pageQueries = {
|
|
7
18
|
list: (projectId) => ({
|
|
8
19
|
...getOrpc().pages.list.queryOptions({
|
|
@@ -183,4 +194,4 @@ const fileMutations = {
|
|
|
183
194
|
};
|
|
184
195
|
|
|
185
196
|
//#endregion
|
|
186
|
-
export { blockMutations, blockQueries, environmentMutations, environmentQueries, fileMutations, fileQueries, layoutQueries, pageMutations, pageQueries, projectQueries, repeatableItemMutations };
|
|
197
|
+
export { blockMutations, blockQueries, commentMutations, commentQueries, environmentMutations, environmentQueries, fileMutations, fileQueries, layoutQueries, pageMutations, pageQueries, projectQueries, repeatableItemMutations };
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { getAuthCookieHeader } from "./auth.js";
|
|
2
|
+
import { areCommentsEnabled } from "../features/preview/commentsEnabled.js";
|
|
2
3
|
import { c } from "react/compiler-runtime";
|
|
3
4
|
import { useQueryClient } from "@tanstack/react-query";
|
|
4
5
|
import { useRef } from "react";
|
|
6
|
+
import { queryKeys } from "@camox/api-contract/query-keys";
|
|
5
7
|
import { usePartySocket } from "partysocket/react";
|
|
6
8
|
|
|
7
9
|
//#region src/lib/use-project-room.ts
|
|
8
10
|
const DEBOUNCE_MS = 300;
|
|
9
11
|
function useProjectRoom(apiUrl, projectId) {
|
|
10
12
|
const $ = c(10);
|
|
11
|
-
if ($[0] !== "
|
|
13
|
+
if ($[0] !== "67c19533e16ee15335bcc3b4e1e8e5b7b5ec3b876c8d1b4511e85727b85792f9") {
|
|
12
14
|
for (let $i = 0; $i < 10; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
13
|
-
$[0] = "
|
|
15
|
+
$[0] = "67c19533e16ee15335bcc3b4e1e8e5b7b5ec3b876c8d1b4511e85727b85792f9";
|
|
14
16
|
}
|
|
15
17
|
const queryClient = useQueryClient();
|
|
16
18
|
const timerRef = useRef(void 0);
|
|
@@ -44,6 +46,7 @@ function useProjectRoom(apiUrl, projectId) {
|
|
|
44
46
|
query: _temp,
|
|
45
47
|
enabled: t3,
|
|
46
48
|
onOpen() {
|
|
49
|
+
if (areCommentsEnabled()) queryClient.invalidateQueries({ queryKey: queryKeys.comments.all });
|
|
47
50
|
if (process.env.NODE_ENV !== "production") console.debug("[useProjectRoom] WebSocket connected");
|
|
48
51
|
},
|
|
49
52
|
onClose(event) {
|
package/dist/studio-overlays.css
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Visual editing overlay styles injected into the preview iframe.
|
|
3
3
|
*
|
|
4
4
|
* State is driven by data attributes on the elements:
|
|
5
|
-
* - data-camox-hovered: element
|
|
6
|
-
* - data-camox-focused:
|
|
5
|
+
* - data-camox-highlight-hovered: deepest hovered element (local or remote)
|
|
6
|
+
* - data-camox-highlight-focused: deepest focused/selected element
|
|
7
7
|
* - data-camox-overlay-mode="synced": use synced-block (purple) colors
|
|
8
8
|
*
|
|
9
9
|
* Elements are targeted via their existing data attributes:
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
|
|
36
36
|
/* ---- Hovered state ---- */
|
|
37
37
|
|
|
38
|
-
[data-camox-field-id][data-camox-field-type][data-camox-hovered]::after,
|
|
39
|
-
[data-camox-block-id][data-camox-hovered]:not([data-camox-detached])::after,
|
|
40
|
-
[data-camox-repeater-item-id][data-camox-hovered]::after {
|
|
38
|
+
[data-camox-field-id][data-camox-field-type][data-camox-highlight-hovered]::after,
|
|
39
|
+
[data-camox-block-id][data-camox-highlight-hovered]:not([data-camox-detached])::after,
|
|
40
|
+
[data-camox-repeater-item-id][data-camox-highlight-hovered]::after {
|
|
41
41
|
content: "";
|
|
42
42
|
position: absolute;
|
|
43
43
|
pointer-events: none;
|
|
@@ -48,8 +48,9 @@
|
|
|
48
48
|
|
|
49
49
|
/* ---- Focused state (overrides hovered via source order) ---- */
|
|
50
50
|
|
|
51
|
-
[data-camox-field-id][data-camox-field-type][data-camox-focused]::after,
|
|
52
|
-
[data-camox-block-id][data-camox-focused]:not([data-camox-detached])::after
|
|
51
|
+
[data-camox-field-id][data-camox-field-type][data-camox-highlight-focused]::after,
|
|
52
|
+
[data-camox-block-id][data-camox-highlight-focused]:not([data-camox-detached])::after,
|
|
53
|
+
[data-camox-repeater-item-id][data-camox-highlight-focused]::after {
|
|
53
54
|
content: "";
|
|
54
55
|
position: absolute;
|
|
55
56
|
pointer-events: none;
|
|
@@ -63,17 +64,20 @@
|
|
|
63
64
|
fragment when the inline wraps. Applied directly to the element via attribute
|
|
64
65
|
selectors with !important so user-supplied className/style box-shadows can't
|
|
65
66
|
clobber it. */
|
|
66
|
-
[data-camox-field-id]:not([data-camox-field-type])[data-camox-hovered],
|
|
67
|
-
[data-camox-field-id]:not([data-camox-field-type])[data-camox-focused] {
|
|
67
|
+
[data-camox-field-id]:not([data-camox-field-type])[data-camox-highlight-hovered],
|
|
68
|
+
[data-camox-field-id]:not([data-camox-field-type])[data-camox-highlight-focused] {
|
|
68
69
|
-webkit-box-decoration-break: clone;
|
|
69
70
|
box-decoration-break: clone;
|
|
70
71
|
}
|
|
71
72
|
|
|
72
|
-
|
|
73
|
+
/* SVG roots cannot render ::after; use the same direct outline as text fields. */
|
|
74
|
+
svg[data-camox-field-type="icon"][data-camox-highlight-hovered],
|
|
75
|
+
[data-camox-field-id]:not([data-camox-field-type])[data-camox-highlight-hovered] {
|
|
73
76
|
box-shadow: 0 0 0 var(--camox-overlay-width-hover) var(--camox-overlay-color-hover) !important;
|
|
74
77
|
}
|
|
75
78
|
|
|
76
|
-
[data-camox-field-
|
|
79
|
+
svg[data-camox-field-type="icon"][data-camox-highlight-focused],
|
|
80
|
+
[data-camox-field-id]:not([data-camox-field-type])[data-camox-highlight-focused] {
|
|
77
81
|
box-shadow: 0 0 0 var(--camox-overlay-width-selected) var(--camox-overlay-color-selected) !important;
|
|
78
82
|
}
|
|
79
83
|
|
|
@@ -85,20 +89,20 @@
|
|
|
85
89
|
|
|
86
90
|
/* ---- Embed: z-index above click-interceptor ---- */
|
|
87
91
|
|
|
88
|
-
[data-camox-field-type="embed"][data-camox-hovered]::after,
|
|
89
|
-
[data-camox-field-type="embed"][data-camox-focused]::after {
|
|
92
|
+
[data-camox-field-type="embed"][data-camox-highlight-hovered]::after,
|
|
93
|
+
[data-camox-field-type="embed"][data-camox-highlight-focused]::after {
|
|
90
94
|
z-index: 11;
|
|
91
95
|
}
|
|
92
96
|
|
|
93
97
|
/* ---- Detached: styled directly (not ::after) because the parent element
|
|
94
98
|
(e.g. fixed navbar) must not get position: relative ---- */
|
|
95
99
|
|
|
96
|
-
[data-camox-detached][data-camox-hovered] {
|
|
100
|
+
[data-camox-detached][data-camox-highlight-hovered] {
|
|
97
101
|
inset: var(--camox-overlay-inset-block-hover);
|
|
98
102
|
border: var(--camox-overlay-width-hover) solid var(--camox-overlay-color-hover);
|
|
99
103
|
}
|
|
100
104
|
|
|
101
|
-
[data-camox-detached][data-camox-focused] {
|
|
105
|
+
[data-camox-detached][data-camox-highlight-focused] {
|
|
102
106
|
inset: var(--camox-overlay-inset-block-selected);
|
|
103
107
|
border: var(--camox-overlay-width-selected) solid var(--camox-overlay-color-selected);
|
|
104
108
|
}
|