| 1 |
(function(react, _elementor_editor_current_user, _elementor_editor_documents, _elementor_editor_panels, _elementor_editor_ui, _elementor_query, _elementor_store, _elementor_ui, _wordpress_i18n, _elementor_editor_styles, _elementor_utils, _elementor_http_client, _elementor_icons, _elementor_events, react_dom, _elementor_editor_styles_repository, _elementor_editor, _elementor_editor_editing_panel, _elementor_editor_embedded_documents_manager, _elementor_editor_mcp, _elementor_editor_canvas, _elementor_editor_v1_adapters, _elementor_schema) { |
| 2 |
|
| 3 |
//#region \0rolldown/runtime.js |
| 4 |
var __create = Object.create; |
| 5 |
var __defProp$1 = Object.defineProperty; |
| 6 |
var __name = (target, value) => __defProp$1(target, "name", { |
| 7 |
value, |
| 8 |
configurable: true |
| 9 |
}); |
| 10 |
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; |
| 11 |
var __getOwnPropNames = Object.getOwnPropertyNames; |
| 12 |
var __getProtoOf = Object.getPrototypeOf; |
| 13 |
var __hasOwnProp = Object.prototype.hasOwnProperty; |
| 14 |
var __exportAll = (all, no_symbols) => { |
| 15 |
let target = {}; |
| 16 |
for (var name in all) { |
| 17 |
__defProp$1(target, name, { |
| 18 |
get: all[name], |
| 19 |
enumerable: true |
| 20 |
}); |
| 21 |
} |
| 22 |
if (!no_symbols) { |
| 23 |
__defProp$1(target, Symbol.toStringTag, { value: "Module" }); |
| 24 |
} |
| 25 |
return target; |
| 26 |
}; |
| 27 |
var __copyProps = (to, from, except, desc) => { |
| 28 |
if (from && typeof from === "object" || typeof from === "function") { |
| 29 |
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { |
| 30 |
key = keys[i]; |
| 31 |
if (!__hasOwnProp.call(to, key) && key !== except) { |
| 32 |
__defProp$1(to, key, { |
| 33 |
get: ((k) => from[k]).bind(null, key), |
| 34 |
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable |
| 35 |
}); |
| 36 |
} |
| 37 |
} |
| 38 |
} |
| 39 |
return to; |
| 40 |
}; |
| 41 |
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp$1(target, "default", { |
| 42 |
value: mod, |
| 43 |
enumerable: true |
| 44 |
}) : target, mod)); |
| 45 |
|
| 46 |
//#endregion |
| 47 |
let react$1 = __toESM(react, 1); |
| 48 |
react = __toESM(react); |
| 49 |
|
| 50 |
//#region packages/packages/core/editor-global-classes/src/errors.ts |
| 51 |
var GlobalClassNotFoundError = (0, _elementor_utils.createError)({ |
| 52 |
code: "global_class_not_found", |
| 53 |
message: "Global class not found." |
| 54 |
}); |
| 55 |
var GlobalClassLabelAlreadyExistsError = (0, _elementor_utils.createError)({ |
| 56 |
code: "global_class_label_already_exists", |
| 57 |
message: "Class with this name already exists." |
| 58 |
}); |
| 59 |
var GlobalClassTrackingError = (0, _elementor_utils.createError)({ |
| 60 |
code: "global_class_tracking_error", |
| 61 |
message: "Error tracking global classes event." |
| 62 |
}); |
| 63 |
|
| 64 |
//#endregion |
| 65 |
//#region packages/packages/core/editor-global-classes/src/utils/snapshot-history.ts |
| 66 |
var __defProp = Object.defineProperty; |
| 67 |
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { |
| 68 |
enumerable: true, |
| 69 |
configurable: true, |
| 70 |
writable: true, |
| 71 |
value |
| 72 |
}) : obj[key] = value; |
| 73 |
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); |
| 74 |
function createLink({ value, next, prev }) { |
| 75 |
return { |
| 76 |
value, |
| 77 |
prev: prev || null, |
| 78 |
next: next || null |
| 79 |
}; |
| 80 |
} |
| 81 |
var _SnapshotHistory = class _SnapshotHistory { |
| 82 |
constructor(namespace) { |
| 83 |
__publicField(this, "namespace", namespace); |
| 84 |
__publicField(this, "first", null); |
| 85 |
__publicField(this, "current", null); |
| 86 |
} |
| 87 |
static get(namespace) { |
| 88 |
if (!_SnapshotHistory.registry[namespace]) _SnapshotHistory.registry[namespace] = new _SnapshotHistory(namespace); |
| 89 |
return _SnapshotHistory.registry[namespace]; |
| 90 |
} |
| 91 |
transform(item) { |
| 92 |
return JSON.parse(JSON.stringify(item)); |
| 93 |
} |
| 94 |
reset() { |
| 95 |
this.first = this.current = null; |
| 96 |
} |
| 97 |
prev() { |
| 98 |
if (!this.current || this.current === this.first) return null; |
| 99 |
this.current = this.current.prev; |
| 100 |
return this.current?.value || null; |
| 101 |
} |
| 102 |
isLast() { |
| 103 |
return !this.current || !this.current.next; |
| 104 |
} |
| 105 |
next(value) { |
| 106 |
if (value) { |
| 107 |
if (!this.current) { |
| 108 |
this.first = createLink({ value: this.transform(value) }); |
| 109 |
this.current = this.first; |
| 110 |
return this.current.value; |
| 111 |
} |
| 112 |
const nextLink = createLink({ |
| 113 |
value: this.transform(value), |
| 114 |
prev: this.current |
| 115 |
}); |
| 116 |
this.current.next = nextLink; |
| 117 |
this.current = nextLink; |
| 118 |
return this.current.value; |
| 119 |
} |
| 120 |
if (!this.current || !this.current.next) return null; |
| 121 |
this.current = this.current.next; |
| 122 |
return this.current.value; |
| 123 |
} |
| 124 |
}; |
| 125 |
__publicField(_SnapshotHistory, "registry", {}); |
| 126 |
var SnapshotHistory = _SnapshotHistory; |
| 127 |
|
| 128 |
//#endregion |
| 129 |
//#region packages/packages/core/editor-global-classes/src/store.ts |
| 130 |
var localHistory = SnapshotHistory.get("global-classes"); |
| 131 |
var initialState = { |
| 132 |
data: { |
| 133 |
items: {}, |
| 134 |
order: [] |
| 135 |
}, |
| 136 |
classLabels: {}, |
| 137 |
initialData: { |
| 138 |
frontend: { |
| 139 |
items: {}, |
| 140 |
order: [] |
| 141 |
}, |
| 142 |
preview: { |
| 143 |
items: {}, |
| 144 |
order: [] |
| 145 |
} |
| 146 |
}, |
| 147 |
isDirty: false |
| 148 |
}; |
| 149 |
var SLICE_NAME = "globalClasses"; |
| 150 |
var slice = (0, _elementor_store.__createSlice)({ |
| 151 |
name: SLICE_NAME, |
| 152 |
initialState, |
| 153 |
reducers: { |
| 154 |
load(state, { payload: { frontend, preview, classLabels } }) { |
| 155 |
state.initialData.frontend = frontend; |
| 156 |
state.initialData.preview = preview; |
| 157 |
state.data = preview; |
| 158 |
state.classLabels = classLabels; |
| 159 |
state.isDirty = false; |
| 160 |
}, |
| 161 |
add(state, { payload }) { |
| 162 |
localHistory.next(state.data); |
| 163 |
state.data.items[payload.id] = payload; |
| 164 |
state.data.order.unshift(payload.id); |
| 165 |
state.classLabels[payload.id] = payload.label; |
| 166 |
state.isDirty = true; |
| 167 |
}, |
| 168 |
delete(state, { payload }) { |
| 169 |
localHistory.next(state.data); |
| 170 |
state.data.items = Object.fromEntries(Object.entries(state.data.items).filter(([id]) => id !== payload)); |
| 171 |
state.data.order = state.data.order.filter((id) => id !== payload); |
| 172 |
delete state.classLabels[payload]; |
| 173 |
state.isDirty = true; |
| 174 |
}, |
| 175 |
setOrder(state, { payload }) { |
| 176 |
localHistory.next(state.data); |
| 177 |
state.data.order = payload; |
| 178 |
state.isDirty = true; |
| 179 |
}, |
| 180 |
update(state, { payload }) { |
| 181 |
const oldLabel = state.classLabels[payload.style.id]; |
| 182 |
localHistory.next(state.data); |
| 183 |
const mergedData = { |
| 184 |
...state.data.items[payload.style.id], |
| 185 |
...payload.style |
| 186 |
}; |
| 187 |
if (oldLabel && payload.style.label && payload.style.label !== oldLabel) state.classLabels[payload.style.id] = payload.style.label; |
| 188 |
state.data.items[payload.style.id] = mergedData; |
| 189 |
state.isDirty = true; |
| 190 |
}, |
| 191 |
updateMultiple(state, { payload }) { |
| 192 |
localHistory.next(state.data); |
| 193 |
Object.entries(payload).forEach(([id, { modified }]) => { |
| 194 |
state.data.items[id].label = modified; |
| 195 |
state.classLabels[id] = modified; |
| 196 |
}); |
| 197 |
state.isDirty = false; |
| 198 |
}, |
| 199 |
updateProps(state, { payload }) { |
| 200 |
const style = state.data.items[payload.id]; |
| 201 |
if (!style) throw new GlobalClassNotFoundError({ context: { styleId: payload.id } }); |
| 202 |
localHistory.next(state.data); |
| 203 |
const variant = (0, _elementor_editor_styles.getVariantByMeta)(style, payload.meta); |
| 204 |
let customCss = ("custom_css" in payload ? payload.custom_css : variant?.custom_css) ?? null; |
| 205 |
customCss = customCss?.raw ? customCss : null; |
| 206 |
if (variant) { |
| 207 |
const payloadProps = JSON.parse(JSON.stringify(payload.props)); |
| 208 |
if ((payload.mode ?? "merge") === "replace") variant.props = payloadProps; |
| 209 |
else { |
| 210 |
const variantProps = JSON.parse(JSON.stringify(variant.props)); |
| 211 |
variant.props = mergeProps(variantProps, payloadProps); |
| 212 |
} |
| 213 |
variant.custom_css = customCss; |
| 214 |
style.variants = getNonEmptyVariants(style); |
| 215 |
} else style.variants.push({ |
| 216 |
meta: payload.meta, |
| 217 |
props: payload.props, |
| 218 |
custom_css: customCss |
| 219 |
}); |
| 220 |
state.isDirty = true; |
| 221 |
}, |
| 222 |
reset(state, { payload: { context } }) { |
| 223 |
if (context === "frontend") { |
| 224 |
localHistory.reset(); |
| 225 |
state.initialData.frontend = state.data; |
| 226 |
state.isDirty = false; |
| 227 |
} |
| 228 |
state.initialData.preview = state.data; |
| 229 |
}, |
| 230 |
undo(state) { |
| 231 |
if (localHistory.isLast()) localHistory.next(state.data); |
| 232 |
const data = localHistory.prev(); |
| 233 |
if (data) { |
| 234 |
state.data = data; |
| 235 |
state.isDirty = true; |
| 236 |
} else state.data = state.initialData.preview; |
| 237 |
}, |
| 238 |
resetToInitialState(state, { payload: { context } }) { |
| 239 |
localHistory.reset(); |
| 240 |
state.data = state.initialData[context]; |
| 241 |
state.isDirty = false; |
| 242 |
}, |
| 243 |
redo(state) { |
| 244 |
const data = localHistory.next(); |
| 245 |
if (localHistory.isLast()) localHistory.prev(); |
| 246 |
if (data) { |
| 247 |
state.data = data; |
| 248 |
state.isDirty = true; |
| 249 |
} |
| 250 |
}, |
| 251 |
mergeExistingClasses(state, { payload: { preview, frontend } }) { |
| 252 |
Object.entries(preview).forEach(([id, previewClassData]) => { |
| 253 |
const frontendClassData = frontend[id]; |
| 254 |
if (previewClassData === null || previewClassData === void 0) return; |
| 255 |
if (!(id in state.data.items)) state.data.items[id] = previewClassData; |
| 256 |
if (frontendClassData && !(id in state.initialData.frontend.items)) state.initialData.frontend.items[id] = frontendClassData; |
| 257 |
if (!(id in state.initialData.preview.items)) state.initialData.preview.items[id] = previewClassData; |
| 258 |
if (!(id in state.classLabels)) state.classLabels[id] = previewClassData.label; |
| 259 |
}); |
| 260 |
}, |
| 261 |
setOrderWithoutHistory(state, { payload }) { |
| 262 |
state.data.order = payload; |
| 263 |
}, |
| 264 |
updateAfterTemplateImport(state, { payload }) { |
| 265 |
state.initialData.frontend.items = { |
| 266 |
...state.initialData.frontend.items, |
| 267 |
...payload.addedItems |
| 268 |
}; |
| 269 |
state.initialData.frontend.order = [...state.initialData.frontend.order, ...payload.addedIdsOrder]; |
| 270 |
state.initialData.preview.items = { |
| 271 |
...state.initialData.preview.items, |
| 272 |
...payload.addedItems |
| 273 |
}; |
| 274 |
state.initialData.preview.order = [...state.initialData.preview.order, ...payload.addedIdsOrder]; |
| 275 |
state.data.items = { |
| 276 |
...state.data.items, |
| 277 |
...payload.addedItems |
| 278 |
}; |
| 279 |
state.data.order = [...state.data.order, ...payload.addedIdsOrder]; |
| 280 |
state.classLabels = { |
| 281 |
...state.classLabels, |
| 282 |
...payload.addedClassLabels |
| 283 |
}; |
| 284 |
} |
| 285 |
} |
| 286 |
}); |
| 287 |
var mergeProps = (current, updates) => { |
| 288 |
const props = Array.isArray(current) ? {} : current; |
| 289 |
Object.entries(updates).forEach(([key, value]) => { |
| 290 |
if (value === null || value === void 0) delete props[key]; |
| 291 |
else props[key] = value; |
| 292 |
}); |
| 293 |
return props; |
| 294 |
}; |
| 295 |
var getNonEmptyVariants = (style) => { |
| 296 |
return style.variants.filter(({ props, custom_css: customCss }) => Object.keys(props).length || customCss?.raw); |
| 297 |
}; |
| 298 |
var placeholderDefinition = (id, label) => ({ |
| 299 |
id, |
| 300 |
type: "class", |
| 301 |
label, |
| 302 |
variants: [] |
| 303 |
}); |
| 304 |
var selectData = (state) => state[SLICE_NAME].data; |
| 305 |
var selectClassLabels = (state) => state[SLICE_NAME].classLabels; |
| 306 |
var selectFrontendInitialData = (state) => state[SLICE_NAME].initialData.frontend; |
| 307 |
var selectPreviewInitialData = (state) => state[SLICE_NAME].initialData.preview; |
| 308 |
var selectOrder = (0, _elementor_store.__createSelector)(selectData, ({ order }) => order); |
| 309 |
var selectGlobalClasses = (0, _elementor_store.__createSelector)(selectData, ({ items }) => items); |
| 310 |
var selectIsDirty = (state) => state[SLICE_NAME].isDirty; |
| 311 |
var selectOrderedClasses = (0, _elementor_store.__createSelector)(selectData, selectClassLabels, ({ items, order }, classLabels) => order.map((id) => { |
| 312 |
const loaded = items[id]; |
| 313 |
if (loaded) return loaded; |
| 314 |
const label = classLabels[id]; |
| 315 |
return label !== void 0 ? placeholderDefinition(id, label) : null; |
| 316 |
}).filter((s) => s !== null)); |
| 317 |
var selectClass = (state, id) => state[SLICE_NAME].data.items[id] ?? null; |
| 318 |
var selectEmptyCssClass = (0, _elementor_store.__createSelector)(selectData, ({ items }) => Object.values(items).filter((cssClass) => (cssClass.variants?.length ?? 0) === 0)); |
| 319 |
var selectIsClassFetched = (state, id) => !!state[SLICE_NAME].initialData.preview.items[id] || !!state[SLICE_NAME].initialData.frontend.items[id] || false; |
| 320 |
|
| 321 |
//#endregion |
| 322 |
//#region packages/packages/core/editor-global-classes/src/hooks/use-classes-order.ts |
| 323 |
var useClassesOrder = () => { |
| 324 |
return (0, _elementor_store.__useSelector)(selectOrder); |
| 325 |
}; |
| 326 |
|
| 327 |
//#endregion |
| 328 |
//#region packages/packages/core/editor-global-classes/src/hooks/use-dirty-state.ts |
| 329 |
var useDirtyState = () => { |
| 330 |
return (0, _elementor_store.__useSelector)(selectIsDirty); |
| 331 |
}; |
| 332 |
|
| 333 |
//#endregion |
| 334 |
//#region packages/packages/core/editor-global-classes/src/components/search-and-filter/context.tsx |
| 335 |
var SearchAndFilterContext = (0, react.createContext)(void 0); |
| 336 |
var INIT_CHECKED_FILTERS = { |
| 337 |
empty: false, |
| 338 |
onThisPage: false, |
| 339 |
unused: false |
| 340 |
}; |
| 341 |
var SearchAndFilterProvider = ({ children }) => { |
| 342 |
const [filters, setFilters] = (0, react.useState)(INIT_CHECKED_FILTERS); |
| 343 |
const getInitialSearchValue = () => { |
| 344 |
const storedValue = localStorage.getItem("elementor-global-classes-search"); |
| 345 |
if (storedValue) { |
| 346 |
localStorage.removeItem("elementor-global-classes-search"); |
| 347 |
return storedValue; |
| 348 |
} |
| 349 |
return ""; |
| 350 |
}; |
| 351 |
const { debouncedValue, inputValue, handleChange } = (0, _elementor_utils.useDebounceState)({ |
| 352 |
delay: 300, |
| 353 |
initialValue: getInitialSearchValue() |
| 354 |
}); |
| 355 |
const onClearSearch = () => { |
| 356 |
handleChange(""); |
| 357 |
}; |
| 358 |
const onClearFilter = () => { |
| 359 |
setFilters(INIT_CHECKED_FILTERS); |
| 360 |
}; |
| 361 |
return /* @__PURE__ */ react.createElement(SearchAndFilterContext.Provider, { value: { |
| 362 |
search: { |
| 363 |
debouncedValue, |
| 364 |
inputValue, |
| 365 |
handleChange, |
| 366 |
onClearSearch |
| 367 |
}, |
| 368 |
filters: { |
| 369 |
filters, |
| 370 |
setFilters, |
| 371 |
onClearFilter |
| 372 |
} |
| 373 |
} }, children); |
| 374 |
}; |
| 375 |
var useSearchAndFilters = () => { |
| 376 |
const context = (0, react.useContext)(SearchAndFilterContext); |
| 377 |
if (!context) throw new Error("useSearchContext must be used within a SearchContextProvider"); |
| 378 |
return context; |
| 379 |
}; |
| 380 |
|
| 381 |
//#endregion |
| 382 |
//#region packages/packages/core/editor-global-classes/src/api.ts |
| 383 |
var RESOURCE_URL = "/global-classes"; |
| 384 |
var BASE_URL = "elementor/v1"; |
| 385 |
var RESOURCE_USAGE_URL = `${RESOURCE_URL}/usage`; |
| 386 |
var RESOURCE_POST_URL = `${RESOURCE_URL}/post`; |
| 387 |
var RESOURCE_STYLES_URL = `${RESOURCE_URL}/styles`; |
| 388 |
function saveGlobalClasses$1(context, payload) { |
| 389 |
return (0, _elementor_http_client.httpService)().put(`${BASE_URL}${RESOURCE_URL}`, payload, { params: { context } }); |
| 390 |
} |
| 391 |
__name(saveGlobalClasses$1, "saveGlobalClasses"); |
| 392 |
var apiClient = { |
| 393 |
usage: () => (0, _elementor_http_client.httpService)().get(`${BASE_URL}${RESOURCE_USAGE_URL}`), |
| 394 |
all: (context = "preview") => (0, _elementor_http_client.httpService)().get(`${BASE_URL}${RESOURCE_URL}`, { params: { context } }), |
| 395 |
getStylesForPost: (postId, context = "preview") => (0, _elementor_http_client.httpService)().get(`${BASE_URL}${RESOURCE_POST_URL}`, { params: { |
| 396 |
context, |
| 397 |
post_id: postId |
| 398 |
} }), |
| 399 |
getStylesByIds: (ids, context = "preview") => (0, _elementor_http_client.httpService)().get(`${BASE_URL}${RESOURCE_STYLES_URL}`, { params: { |
| 400 |
context, |
| 401 |
ids: ids.join(",") |
| 402 |
} }), |
| 403 |
publish: (payload) => saveGlobalClasses$1("frontend", payload), |
| 404 |
saveDraft: (payload) => saveGlobalClasses$1("preview", payload) |
| 405 |
}; |
| 406 |
var API_ERROR_CODES = { DUPLICATED_LABEL: "DUPLICATED_LABEL" }; |
| 407 |
|
| 408 |
//#endregion |
| 409 |
//#region packages/packages/core/editor-global-classes/src/components/css-class-usage/utils.ts |
| 410 |
var transformData = (data) => Object.entries(data).reduce((acc, [key, value]) => { |
| 411 |
acc[key] = { |
| 412 |
content: value || [], |
| 413 |
total: value.reduce((total, val) => total + (val?.total || 0), 0) |
| 414 |
}; |
| 415 |
return acc; |
| 416 |
}, {}); |
| 417 |
|
| 418 |
//#endregion |
| 419 |
//#region packages/packages/core/editor-global-classes/service/css-class-usage-service.ts |
| 420 |
var fetchCssClassUsage = async () => { |
| 421 |
return transformData((await apiClient.usage())?.data?.data || {}); |
| 422 |
}; |
| 423 |
|
| 424 |
//#endregion |
| 425 |
//#region packages/packages/core/editor-global-classes/src/components/css-class-usage/types.ts |
| 426 |
var QUERY_KEY = "css-classes-usage"; |
| 427 |
|
| 428 |
//#endregion |
| 429 |
//#region packages/packages/core/editor-global-classes/src/hooks/use-css-class-usage.ts |
| 430 |
var useCssClassUsage = () => { |
| 431 |
return (0, _elementor_query.useQuery)({ |
| 432 |
queryKey: [QUERY_KEY], |
| 433 |
queryFn: fetchCssClassUsage, |
| 434 |
refetchOnMount: false, |
| 435 |
refetchOnWindowFocus: true |
| 436 |
}); |
| 437 |
}; |
| 438 |
|
| 439 |
//#endregion |
| 440 |
//#region packages/packages/core/editor-global-classes/src/hooks/use-empty-css-class.ts |
| 441 |
var useEmptyCssClass = () => { |
| 442 |
return (0, _elementor_store.__useSelector)(selectEmptyCssClass); |
| 443 |
}; |
| 444 |
var useAllCssClassesIDs = () => { |
| 445 |
const cssClasses = (0, _elementor_store.__useSelector)(selectGlobalClasses); |
| 446 |
return Object.keys(cssClasses); |
| 447 |
}; |
| 448 |
|
| 449 |
//#endregion |
| 450 |
//#region packages/packages/core/editor-global-classes/src/hooks/use-filtered-css-class-usage.tsx |
| 451 |
var findCssClassKeysByPageID = (data, pageId) => { |
| 452 |
const result = []; |
| 453 |
for (const key in data) data[key].content.forEach((content) => { |
| 454 |
if (+content.pageId === pageId) result.push(key); |
| 455 |
}); |
| 456 |
return result; |
| 457 |
}; |
| 458 |
var getUnusedClasses = (usedCssClass, potentialUnused) => { |
| 459 |
const set = new Set(usedCssClass); |
| 460 |
return potentialUnused.filter((cssClass) => !set.has(cssClass)); |
| 461 |
}; |
| 462 |
var EMPTY_FILTERED_CSS_CLASS_RESPONSE = { |
| 463 |
empty: [], |
| 464 |
onThisPage: [], |
| 465 |
unused: [] |
| 466 |
}; |
| 467 |
var useFilteredCssClassUsage = () => { |
| 468 |
const document = (0, _elementor_editor_documents.__useActiveDocument)(); |
| 469 |
const emptyCssClasses = useEmptyCssClass(); |
| 470 |
const { data, isLoading } = useCssClassUsage(); |
| 471 |
const listOfCssClasses = useAllCssClassesIDs(); |
| 472 |
const emptyCssClassesIDs = (0, react.useMemo)(() => emptyCssClasses.map(({ id }) => id), [emptyCssClasses]); |
| 473 |
const onThisPage = (0, react.useMemo)(() => { |
| 474 |
if (!data || !document) return []; |
| 475 |
return findCssClassKeysByPageID(data, document.id); |
| 476 |
}, [data, document]); |
| 477 |
const unused = (0, react.useMemo)(() => { |
| 478 |
if (!data) return []; |
| 479 |
return getUnusedClasses(Object.keys(data), listOfCssClasses); |
| 480 |
}, [data, listOfCssClasses]); |
| 481 |
if (isLoading || !data || !document) return EMPTY_FILTERED_CSS_CLASS_RESPONSE; |
| 482 |
return { |
| 483 |
onThisPage, |
| 484 |
unused, |
| 485 |
empty: emptyCssClassesIDs |
| 486 |
}; |
| 487 |
}; |
| 488 |
|
| 489 |
//#endregion |
| 490 |
//#region packages/packages/core/editor-global-classes/src/hooks/use-filters.ts |
| 491 |
var useFilters = () => { |
| 492 |
const { filters: { filters } } = useSearchAndFilters(); |
| 493 |
const allFilters = useFilteredCssClassUsage(); |
| 494 |
return (0, react.useMemo)(() => { |
| 495 |
const activeEntries = Object.entries(filters).filter(([, isActive]) => isActive); |
| 496 |
if (activeEntries.length === 0) return null; |
| 497 |
return activeEntries.reduce((acc, [key], index) => { |
| 498 |
const current = allFilters[key] || []; |
| 499 |
if (index === 0) return current; |
| 500 |
return acc.filter((val) => current.includes(val)); |
| 501 |
}, []); |
| 502 |
}, [filters, allFilters]); |
| 503 |
}; |
| 504 |
|
| 505 |
//#endregion |
| 506 |
//#region packages/packages/core/editor-global-classes/src/utils/create-labels-for-classes.ts |
| 507 |
function createLabelsForClasses(entries) { |
| 508 |
return Object.fromEntries(entries.map((e) => [e.id, e.label])); |
| 509 |
} |
| 510 |
|
| 511 |
//#endregion |
| 512 |
//#region packages/packages/core/editor-global-classes/src/load-document-classes.ts |
| 513 |
function styleDefinitionsMapWithoutNull(map) { |
| 514 |
return Object.fromEntries(Object.entries(map).filter((entry) => entry[1] !== null)); |
| 515 |
} |
| 516 |
function resetGlobalClassesState(globalOrder, classLabels) { |
| 517 |
(0, _elementor_store.__dispatch)(slice.actions.load({ |
| 518 |
preview: { |
| 519 |
items: {}, |
| 520 |
order: globalOrder |
| 521 |
}, |
| 522 |
frontend: { |
| 523 |
items: {}, |
| 524 |
order: globalOrder |
| 525 |
}, |
| 526 |
classLabels |
| 527 |
})); |
| 528 |
} |
| 529 |
async function loadCurrentDocumentClasses() { |
| 530 |
const [previewIndexRes, frontendIndexRes] = await Promise.all([apiClient.all("preview"), apiClient.all("frontend")]); |
| 531 |
const previewIndex = previewIndexRes.data.data; |
| 532 |
const frontendIndex = frontendIndexRes.data.data; |
| 533 |
const classLabels = createLabelsForClasses(previewIndex); |
| 534 |
const previewOrder = previewIndex.map((e) => e.id); |
| 535 |
const frontendOrder = frontendIndex.map((e) => e.id); |
| 536 |
resetGlobalClassesState(previewOrder, classLabels); |
| 537 |
const postId = (0, _elementor_editor_documents.getCurrentDocument)()?.id; |
| 538 |
if (!postId) return; |
| 539 |
const [previewPostRes, frontendPostRes] = await Promise.all([apiClient.getStylesForPost(postId, "preview"), apiClient.getStylesForPost(postId, "frontend")]); |
| 540 |
const previewItems = styleDefinitionsMapWithoutNull(previewPostRes.data.data); |
| 541 |
const frontendItems = styleDefinitionsMapWithoutNull(frontendPostRes.data.data); |
| 542 |
(0, _elementor_store.__dispatch)(slice.actions.load({ |
| 543 |
preview: { |
| 544 |
items: previewItems, |
| 545 |
order: previewOrder |
| 546 |
}, |
| 547 |
frontend: { |
| 548 |
items: frontendItems, |
| 549 |
order: frontendOrder |
| 550 |
}, |
| 551 |
classLabels |
| 552 |
})); |
| 553 |
} |
| 554 |
async function addDocumentClasses(documentId) { |
| 555 |
const [previewPostRes, frontendPostRes] = await Promise.all([apiClient.getStylesForPost(documentId, "preview"), apiClient.getStylesForPost(documentId, "frontend")]); |
| 556 |
const previewItems = styleDefinitionsMapWithoutNull(previewPostRes.data.data); |
| 557 |
const frontendItems = styleDefinitionsMapWithoutNull(frontendPostRes.data.data); |
| 558 |
(0, _elementor_store.__dispatch)(slice.actions.mergeExistingClasses({ |
| 559 |
preview: previewItems, |
| 560 |
frontend: frontendItems |
| 561 |
})); |
| 562 |
} |
| 563 |
|
| 564 |
//#endregion |
| 565 |
//#region packages/packages/core/editor-global-classes/src/load-existing-classes.ts |
| 566 |
var pendingLoad = null; |
| 567 |
var pendingIds = /* @__PURE__ */ new Set(); |
| 568 |
async function loadExistingClasses(classIds) { |
| 569 |
const existingClasses = selectGlobalClasses((0, _elementor_store.__getState)()); |
| 570 |
const missingIds = classIds.filter((id) => !(id in existingClasses)); |
| 571 |
if (missingIds.length === 0) return; |
| 572 |
missingIds.forEach((id) => pendingIds.add(id)); |
| 573 |
if (pendingLoad) { |
| 574 |
await pendingLoad; |
| 575 |
return loadExistingClasses(classIds); |
| 576 |
} |
| 577 |
pendingLoad = fetchAndMergeClasses(); |
| 578 |
try { |
| 579 |
await pendingLoad; |
| 580 |
} finally { |
| 581 |
pendingLoad = null; |
| 582 |
} |
| 583 |
} |
| 584 |
async function fetchAndMergeClasses() { |
| 585 |
const idsToFetch = Array.from(pendingIds); |
| 586 |
pendingIds.clear(); |
| 587 |
if (idsToFetch.length === 0) return; |
| 588 |
const [previewResponse, frontendResponse] = await Promise.all([apiClient.getStylesByIds(idsToFetch, "preview"), apiClient.getStylesByIds(idsToFetch, "frontend")]); |
| 589 |
const previewItems = styleDefinitionsMapWithoutNull(previewResponse.data.data); |
| 590 |
const frontendItems = styleDefinitionsMapWithoutNull(frontendResponse.data.data); |
| 591 |
(0, _elementor_store.__dispatch)(slice.actions.mergeExistingClasses({ |
| 592 |
preview: previewItems, |
| 593 |
frontend: frontendItems |
| 594 |
})); |
| 595 |
} |
| 596 |
|
| 597 |
//#endregion |
| 598 |
//#region packages/packages/core/editor-global-classes/src/components/class-manager/duplicate-label-dialog.tsx |
| 599 |
var DUP_PREFIX = "DUP_"; |
| 600 |
var DuplicateLabelDialog = ({ modifiedLabels, onApprove }) => { |
| 601 |
const handleButtonClick = () => { |
| 602 |
localStorage.setItem("elementor-global-classes-search", DUP_PREFIX); |
| 603 |
onApprove?.(); |
| 604 |
(0, _elementor_editor_ui.closeDialog)(); |
| 605 |
}; |
| 606 |
return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_ui.DialogHeader, { logo: false }, /* @__PURE__ */ react.createElement(_elementor_ui.Box, { |
| 607 |
display: "flex", |
| 608 |
alignItems: "center", |
| 609 |
gap: 1 |
| 610 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Icon, { color: "secondary" }, /* @__PURE__ */ react.createElement(_elementor_icons.InfoCircleFilledIcon, { fontSize: "medium" })), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { variant: "subtitle1" }, (0, _wordpress_i18n.__)("We've published your page and updated class names.", "elementor")))), /* @__PURE__ */ react.createElement(_elementor_ui.DialogContent, null, /* @__PURE__ */ react.createElement(_elementor_ui.Stack, { |
| 611 |
spacing: 2, |
| 612 |
direction: "column" |
| 613 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { variant: "body2" }, (0, _wordpress_i18n.__)("Some new classes used the same names as existing ones. To prevent conflicts, we added the prefix", "elementor"), /* @__PURE__ */ react.createElement("strong", null, " ", DUP_PREFIX)), /* @__PURE__ */ react.createElement(_elementor_ui.Box, null, /* @__PURE__ */ react.createElement(_elementor_ui.Box, { sx: { |
| 614 |
width: "100%", |
| 615 |
display: "flex", |
| 616 |
gap: 2, |
| 617 |
alignItems: "flex-start" |
| 618 |
} }, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 619 |
variant: "subtitle2", |
| 620 |
sx: { |
| 621 |
fontWeight: "bold", |
| 622 |
flex: 1, |
| 623 |
flexShrink: 1, |
| 624 |
flexGrow: 1, |
| 625 |
minWidth: 0 |
| 626 |
} |
| 627 |
}, (0, _wordpress_i18n.__)("Before", "elementor")), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 628 |
variant: "subtitle2", |
| 629 |
sx: { |
| 630 |
minWidth: "200px", |
| 631 |
fontWeight: "bold", |
| 632 |
flexShrink: 0, |
| 633 |
flexGrow: 0, |
| 634 |
width: "200px", |
| 635 |
maxWidth: "200px" |
| 636 |
} |
| 637 |
}, (0, _wordpress_i18n.__)("After", "elementor"))), /* @__PURE__ */ react.createElement(_elementor_ui.Divider, { sx: { |
| 638 |
mt: .5, |
| 639 |
mb: .5 |
| 640 |
} }), /* @__PURE__ */ react.createElement(_elementor_ui.Stack, { |
| 641 |
direction: "column", |
| 642 |
gap: .5, |
| 643 |
sx: { pb: 2 } |
| 644 |
}, Object.values(modifiedLabels).map(({ original, modified }, index) => /* @__PURE__ */ react.createElement(_elementor_ui.Box, { |
| 645 |
key: index, |
| 646 |
sx: { |
| 647 |
width: "100%", |
| 648 |
display: "flex", |
| 649 |
gap: 2, |
| 650 |
alignItems: "flex-start" |
| 651 |
} |
| 652 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Box, { sx: { |
| 653 |
flex: 1, |
| 654 |
flexShrink: 1, |
| 655 |
flexGrow: 1, |
| 656 |
minWidth: 0 |
| 657 |
} }, /* @__PURE__ */ react.createElement(_elementor_editor_ui.EllipsisWithTooltip, { title: original }, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 658 |
variant: "body2", |
| 659 |
sx: { color: "text.secondary" } |
| 660 |
}, original))), /* @__PURE__ */ react.createElement(_elementor_ui.Box, { sx: { |
| 661 |
minWidth: "200px", |
| 662 |
flexShrink: 0, |
| 663 |
flexGrow: 0, |
| 664 |
width: "200px", |
| 665 |
maxWidth: "200px" |
| 666 |
} }, /* @__PURE__ */ react.createElement(_elementor_editor_ui.EllipsisWithTooltip, { title: modified }, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 667 |
variant: "body2", |
| 668 |
sx: { color: "text.primary" } |
| 669 |
}, modified)))))), /* @__PURE__ */ react.createElement(_elementor_ui.Box, null, /* @__PURE__ */ react.createElement(_elementor_ui.Alert, { |
| 670 |
severity: "info", |
| 671 |
size: "small", |
| 672 |
color: "secondary" |
| 673 |
}, /* @__PURE__ */ react.createElement("strong", null, (0, _wordpress_i18n.__)("Your designs and classes are safe.", "elementor")), (0, _wordpress_i18n.__)("Only the prefixes were added. Find them in Class Manager by searching", "elementor"), /* @__PURE__ */ react.createElement("strong", null, DUP_PREFIX)))))), /* @__PURE__ */ react.createElement(_elementor_ui.DialogActions, null, /* @__PURE__ */ react.createElement(_elementor_ui.Button, { |
| 674 |
color: "secondary", |
| 675 |
variant: "text", |
| 676 |
onClick: handleButtonClick |
| 677 |
}, (0, _wordpress_i18n.__)("Go to Class Manager", "elementor")), /* @__PURE__ */ react.createElement(_elementor_ui.Button, { |
| 678 |
color: "secondary", |
| 679 |
variant: "contained", |
| 680 |
onClick: _elementor_editor_ui.closeDialog |
| 681 |
}, (0, _wordpress_i18n.__)("Done", "elementor")))); |
| 682 |
}; |
| 683 |
|
| 684 |
//#endregion |
| 685 |
//#region packages/packages/core/editor-global-classes/src/utils/tracking.ts |
| 686 |
var trackGlobalClasses = async (payload) => { |
| 687 |
const { runAction } = payload; |
| 688 |
const data = await getSanitizedData(payload); |
| 689 |
if (data) { |
| 690 |
track(data); |
| 691 |
if (data.event === "classCreated" && "classId" in data) fireClassApplied(data.classId); |
| 692 |
} |
| 693 |
runAction?.(); |
| 694 |
}; |
| 695 |
var fireClassApplied = async (classId) => { |
| 696 |
const appliedInfo = await getAppliedInfo(classId); |
| 697 |
track({ |
| 698 |
event: "classApplied", |
| 699 |
classId, |
| 700 |
...appliedInfo, |
| 701 |
totalInstancesAfterApply: 1 |
| 702 |
}); |
| 703 |
}; |
| 704 |
var getSanitizedData = async (payload) => { |
| 705 |
switch (payload.event) { |
| 706 |
case "classApplied": |
| 707 |
if ("classId" in payload && payload.classId) { |
| 708 |
const appliedInfo = await getAppliedInfo(payload.classId); |
| 709 |
return { |
| 710 |
...payload, |
| 711 |
...appliedInfo |
| 712 |
}; |
| 713 |
} |
| 714 |
break; |
| 715 |
case "classRemoved": |
| 716 |
if ("classId" in payload && payload.classId) { |
| 717 |
const deleteInfo = getRemovedInfo(payload.classId); |
| 718 |
return { |
| 719 |
...payload, |
| 720 |
...deleteInfo |
| 721 |
}; |
| 722 |
} |
| 723 |
break; |
| 724 |
case "classDeleted": |
| 725 |
if ("classId" in payload && payload.classId) { |
| 726 |
const deleteInfo = await trackDeleteClass(payload.classId); |
| 727 |
return { |
| 728 |
...payload, |
| 729 |
...deleteInfo |
| 730 |
}; |
| 731 |
} |
| 732 |
break; |
| 733 |
case "classCreated": |
| 734 |
if ("source" in payload && payload.source !== "created") { |
| 735 |
if ("classId" in payload && payload.classId) return { |
| 736 |
...payload, |
| 737 |
classTitle: getCssClass(payload.classId).label |
| 738 |
}; |
| 739 |
} |
| 740 |
return payload; |
| 741 |
case "classStateClicked": |
| 742 |
if ("classId" in payload && payload.classId) return { |
| 743 |
...payload, |
| 744 |
classTitle: getCssClass(payload.classId).label |
| 745 |
}; |
| 746 |
break; |
| 747 |
case "classSyncToV3PopupShown": return { |
| 748 |
...payload, |
| 749 |
interaction_type: "popup_shown", |
| 750 |
target_type: "popup", |
| 751 |
target_name: "sync_to_v3_popup", |
| 752 |
interaction_result: "popup_viewed", |
| 753 |
target_location: "widget_panel", |
| 754 |
location_l1: "class_manager" |
| 755 |
}; |
| 756 |
case "classSyncToV3": { |
| 757 |
const classLabel = getCssClass(payload.classId).label; |
| 758 |
const isSync = payload.action === "sync"; |
| 759 |
return { |
| 760 |
...payload, |
| 761 |
interaction_type: "click", |
| 762 |
target_type: classLabel, |
| 763 |
target_name: isSync ? "sync_to_v3" : "unsync_to_v3", |
| 764 |
interaction_result: isSync ? "class_is_synced_to_V3" : "class_is_unsynced_from_V3", |
| 765 |
target_location: "widget_panel", |
| 766 |
location_l1: "class_manager", |
| 767 |
interaction_description: isSync ? `user_synced_${classLabel}_to_v3` : `user_unsync_${classLabel}_from_v3` |
| 768 |
}; |
| 769 |
} |
| 770 |
case "classSyncToV3PopupClick": { |
| 771 |
const isSyncAction = payload.action === "sync"; |
| 772 |
return { |
| 773 |
...payload, |
| 774 |
interaction_type: "click", |
| 775 |
target_type: "button", |
| 776 |
target_name: isSyncAction ? "sync_to_v3" : "cancel", |
| 777 |
interaction_result: isSyncAction ? "class_is_synced" : "cancel", |
| 778 |
target_location: "sync_to_v3_popup" |
| 779 |
}; |
| 780 |
} |
| 781 |
default: return payload; |
| 782 |
} |
| 783 |
}; |
| 784 |
var track = (data) => { |
| 785 |
const { dispatchEvent, config } = (0, _elementor_events.getMixpanel)(); |
| 786 |
if (!config?.names?.global_classes?.[data.event]) { |
| 787 |
console.error("Global class tracking event not found", { event: data.event }); |
| 788 |
return; |
| 789 |
} |
| 790 |
const name = config.names.global_classes[data.event]; |
| 791 |
const { event, ...eventData } = data; |
| 792 |
try { |
| 793 |
dispatchEvent?.(name, { |
| 794 |
event, |
| 795 |
...eventData |
| 796 |
}); |
| 797 |
} catch (error) { |
| 798 |
throw new GlobalClassTrackingError({ cause: error }); |
| 799 |
} |
| 800 |
}; |
| 801 |
var extractCssClassData = (classId) => { |
| 802 |
return { classTitle: getCssClass(classId).label }; |
| 803 |
}; |
| 804 |
var getCssClass = (classId) => { |
| 805 |
const state = (0, _elementor_store.__getState)(); |
| 806 |
const cssClass = selectClass(state, classId); |
| 807 |
if (cssClass) return cssClass; |
| 808 |
const label = selectClassLabels(state)[classId]; |
| 809 |
if (label !== void 0) return placeholderDefinition(classId, label); |
| 810 |
throw new Error(`CSS class with ID ${classId} not found`); |
| 811 |
}; |
| 812 |
var trackDeleteClass = async (classId) => { |
| 813 |
const classTitle = getCssClass(classId).label; |
| 814 |
return { |
| 815 |
totalInstances: await getTotalInstancesByCssClassID(classId), |
| 816 |
classTitle |
| 817 |
}; |
| 818 |
}; |
| 819 |
var getTotalInstancesByCssClassID = async (classId) => { |
| 820 |
return (await fetchCssClassUsage())[classId]?.total ?? 1; |
| 821 |
}; |
| 822 |
var getAppliedInfo = async (classId) => { |
| 823 |
const { classTitle } = extractCssClassData(classId); |
| 824 |
return { |
| 825 |
classTitle, |
| 826 |
totalInstancesAfterApply: await getTotalInstancesByCssClassID(classId) + 1 |
| 827 |
}; |
| 828 |
}; |
| 829 |
var getRemovedInfo = (classId) => { |
| 830 |
const { classTitle } = extractCssClassData(classId); |
| 831 |
return { classTitle }; |
| 832 |
}; |
| 833 |
|
| 834 |
//#endregion |
| 835 |
//#region packages/packages/core/editor-global-classes/src/save-global-classes.tsx |
| 836 |
async function saveGlobalClasses({ context, onApprove }) { |
| 837 |
const state = selectData((0, _elementor_store.__getState)()); |
| 838 |
const apiAction = context === "preview" ? apiClient.saveDraft : apiClient.publish; |
| 839 |
const changes = calculateChanges(state, (context === "preview" ? selectPreviewInitialData : selectFrontendInitialData)((0, _elementor_store.__getState)())); |
| 840 |
const touchedIds = [...changes.added, ...changes.modified]; |
| 841 |
const response = await apiAction({ |
| 842 |
items: Object.fromEntries(touchedIds.map((id) => [id, state.items[id]]).filter(([, v]) => v)), |
| 843 |
order: state.order, |
| 844 |
changes |
| 845 |
}); |
| 846 |
(0, _elementor_store.__dispatch)(slice.actions.reset({ context })); |
| 847 |
window.dispatchEvent(new CustomEvent("classes:updated", { detail: { context } })); |
| 848 |
if (response?.data?.data?.code === API_ERROR_CODES.DUPLICATED_LABEL) { |
| 849 |
(0, _elementor_store.__dispatch)(slice.actions.updateMultiple(response.data.data.modifiedLabels)); |
| 850 |
trackGlobalClasses({ |
| 851 |
event: "classPublishConflict", |
| 852 |
numOfConflicts: Object.keys(response.data.data.modifiedLabels).length |
| 853 |
}); |
| 854 |
(0, _elementor_editor_ui.openDialog)({ component: /* @__PURE__ */ react.createElement(DuplicateLabelDialog, { |
| 855 |
modifiedLabels: response.data.data.modifiedLabels || [], |
| 856 |
onApprove |
| 857 |
}) }); |
| 858 |
} |
| 859 |
} |
| 860 |
function calculateChanges(state, initialData) { |
| 861 |
const stateIds = Object.keys(state.items); |
| 862 |
const initialDataIds = Object.keys(initialData.items); |
| 863 |
const { order: stateOrder } = state; |
| 864 |
const { order: initialDataOrder } = initialData; |
| 865 |
const stateOrderIdSet = new Set(stateOrder); |
| 866 |
const deleted = initialDataOrder.filter((id) => !stateOrderIdSet.has(id)); |
| 867 |
const order = stateOrder.join(";") !== initialDataOrder.join(";"); |
| 868 |
return { |
| 869 |
added: stateIds.filter((id) => !initialDataIds.includes(id)), |
| 870 |
deleted, |
| 871 |
modified: stateIds.filter((id) => { |
| 872 |
return id in initialData.items && (0, _elementor_utils.hash)(state.items[id]) !== (0, _elementor_utils.hash)(initialData.items[id]); |
| 873 |
}), |
| 874 |
order |
| 875 |
}; |
| 876 |
} |
| 877 |
|
| 878 |
//#endregion |
| 879 |
//#region packages/packages/core/editor-global-classes/src/components/search-and-filter/components/filter/clear-icon-button.tsx |
| 880 |
var ClearIconButton = ({ tooltipText, sx, trigger }) => { |
| 881 |
const { filters: { onClearFilter } } = useSearchAndFilters(); |
| 882 |
const handleClearFilters = () => { |
| 883 |
onClearFilter(trigger); |
| 884 |
trackGlobalClasses({ |
| 885 |
event: "classManagerFilterCleared", |
| 886 |
trigger |
| 887 |
}); |
| 888 |
}; |
| 889 |
return /* @__PURE__ */ react.createElement(_elementor_ui.Tooltip, { |
| 890 |
title: tooltipText, |
| 891 |
placement: "top", |
| 892 |
disableInteractive: true |
| 893 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Box, null, /* @__PURE__ */ react.createElement(CustomIconButton$1, { |
| 894 |
"aria-label": tooltipText, |
| 895 |
size: "tiny", |
| 896 |
onClick: handleClearFilters, |
| 897 |
sx |
| 898 |
}, /* @__PURE__ */ react.createElement(_elementor_icons.BrushBigIcon, { fontSize: "tiny" })))); |
| 899 |
}; |
| 900 |
var CustomIconButton$1 = (0, _elementor_ui.styled)(_elementor_ui.IconButton)(({ theme }) => ({ "&.Mui-disabled": { |
| 901 |
pointerEvents: "auto", |
| 902 |
"&:hover": { color: theme.palette.action.disabled } |
| 903 |
} })); |
| 904 |
|
| 905 |
//#endregion |
| 906 |
//#region packages/packages/core/editor-global-classes/src/components/search-and-filter/components/filter/filter-list.tsx |
| 907 |
var filterConfig = { |
| 908 |
unused: (0, _wordpress_i18n.__)("Unused", "elementor"), |
| 909 |
empty: (0, _wordpress_i18n.__)("Empty", "elementor"), |
| 910 |
onThisPage: (0, _wordpress_i18n.__)("On this page", "elementor") |
| 911 |
}; |
| 912 |
var FilterList = () => { |
| 913 |
const { filters: { filters, setFilters } } = useSearchAndFilters(); |
| 914 |
const filteredCssClass = useFilteredCssClassUsage(); |
| 915 |
const handleOnClick = (value) => { |
| 916 |
setFilters((prev) => ({ |
| 917 |
...prev, |
| 918 |
[value]: !prev[value] |
| 919 |
})); |
| 920 |
trackGlobalClasses({ |
| 921 |
event: "classManagerFilterUsed", |
| 922 |
action: filters[value] ? "remove" : "apply", |
| 923 |
type: value, |
| 924 |
trigger: "menu" |
| 925 |
}); |
| 926 |
}; |
| 927 |
return /* @__PURE__ */ react.createElement(_elementor_ui.MenuList, null, /* @__PURE__ */ react.createElement(_elementor_ui.MenuItem, { onClick: () => handleOnClick("unused") }, /* @__PURE__ */ react.createElement(LabeledCheckbox, { |
| 928 |
label: filterConfig.unused, |
| 929 |
checked: filters.unused, |
| 930 |
suffix: /* @__PURE__ */ react.createElement(_elementor_ui.Chip, { |
| 931 |
size: "tiny", |
| 932 |
sx: { ml: "auto" }, |
| 933 |
label: filteredCssClass.unused.length |
| 934 |
}) |
| 935 |
})), /* @__PURE__ */ react.createElement(_elementor_ui.MenuItem, { onClick: () => handleOnClick("empty") }, /* @__PURE__ */ react.createElement(LabeledCheckbox, { |
| 936 |
label: filterConfig.empty, |
| 937 |
checked: filters.empty, |
| 938 |
suffix: /* @__PURE__ */ react.createElement(_elementor_ui.Chip, { |
| 939 |
size: "tiny", |
| 940 |
sx: { ml: "auto" }, |
| 941 |
label: filteredCssClass.empty.length |
| 942 |
}) |
| 943 |
})), /* @__PURE__ */ react.createElement(_elementor_ui.MenuItem, { onClick: () => handleOnClick("onThisPage") }, /* @__PURE__ */ react.createElement(LabeledCheckbox, { |
| 944 |
label: filterConfig.onThisPage, |
| 945 |
checked: filters.onThisPage, |
| 946 |
suffix: /* @__PURE__ */ react.createElement(_elementor_ui.Chip, { |
| 947 |
size: "tiny", |
| 948 |
sx: { ml: "auto" }, |
| 949 |
label: filteredCssClass.onThisPage.length |
| 950 |
}) |
| 951 |
}))); |
| 952 |
}; |
| 953 |
var LabeledCheckbox = ({ label, suffix, checked }) => /* @__PURE__ */ react.createElement(_elementor_ui.Stack, { |
| 954 |
direction: "row", |
| 955 |
alignItems: "center", |
| 956 |
gap: .5, |
| 957 |
flex: 1 |
| 958 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Checkbox, { |
| 959 |
size: "small", |
| 960 |
checked, |
| 961 |
sx: { |
| 962 |
padding: 0, |
| 963 |
color: "text.tertiary", |
| 964 |
"&.Mui-checked": { color: "text.tertiary" } |
| 965 |
} |
| 966 |
}), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 967 |
variant: "caption", |
| 968 |
sx: { color: "text.secondary" } |
| 969 |
}, label), suffix); |
| 970 |
|
| 971 |
//#endregion |
| 972 |
//#region packages/packages/core/editor-global-classes/src/components/search-and-filter/components/filter/active-filters.tsx |
| 973 |
var ActiveFilters = () => { |
| 974 |
const { filters: { filters, setFilters } } = useSearchAndFilters(); |
| 975 |
const handleRemove = (key) => { |
| 976 |
setFilters((prev) => ({ |
| 977 |
...prev, |
| 978 |
[key]: false |
| 979 |
})); |
| 980 |
trackGlobalClasses({ |
| 981 |
event: "classManagerFilterUsed", |
| 982 |
action: "remove", |
| 983 |
type: key, |
| 984 |
trigger: "header" |
| 985 |
}); |
| 986 |
}; |
| 987 |
const activeKeys = Object.keys(filters).filter((key) => filters[key]); |
| 988 |
const showClearIcon = activeKeys.length > 0; |
| 989 |
return /* @__PURE__ */ react.createElement(_elementor_ui.Stack, { |
| 990 |
direction: "row", |
| 991 |
alignItems: "center", |
| 992 |
justifyContent: "space-between" |
| 993 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Stack, { |
| 994 |
direction: "row", |
| 995 |
gap: .5, |
| 996 |
alignItems: "center", |
| 997 |
flexWrap: "wrap" |
| 998 |
}, activeKeys.map((key) => /* @__PURE__ */ react.createElement(_elementor_ui.Chip, { |
| 999 |
key, |
| 1000 |
label: filterConfig[key], |
| 1001 |
onDelete: () => handleRemove(key), |
| 1002 |
sx: chipSx, |
| 1003 |
size: "tiny" |
| 1004 |
}))), showClearIcon && /* @__PURE__ */ react.createElement(ClearIconButton, { |
| 1005 |
trigger: "header", |
| 1006 |
tooltipText: (0, _wordpress_i18n.__)("Clear Filters", "elementor"), |
| 1007 |
sx: { margin: "0 0 auto auto" } |
| 1008 |
})); |
| 1009 |
}; |
| 1010 |
var chipSx = { |
| 1011 |
"& .MuiChip-deleteIcon": { |
| 1012 |
display: "none", |
| 1013 |
transition: "opacity 0.2s" |
| 1014 |
}, |
| 1015 |
"&:hover .MuiChip-deleteIcon": { display: "block" } |
| 1016 |
}; |
| 1017 |
|
| 1018 |
//#endregion |
| 1019 |
//#region packages/packages/core/editor-global-classes/src/components/search-and-filter/components/filter/css-class-filter.tsx |
| 1020 |
var CssClassFilter = () => { |
| 1021 |
const { filters: { filters } } = useSearchAndFilters(); |
| 1022 |
const popupState = (0, _elementor_ui.usePopupState)({ |
| 1023 |
variant: "popover", |
| 1024 |
disableAutoFocus: true |
| 1025 |
}); |
| 1026 |
(0, react.useEffect)(() => { |
| 1027 |
if (popupState.isOpen) trackGlobalClasses({ event: "classManagerFiltersOpened" }); |
| 1028 |
}, [popupState.isOpen]); |
| 1029 |
const showCleanIcon = Object.values(filters).some((value) => value); |
| 1030 |
return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_ui.Tooltip, { |
| 1031 |
title: (0, _wordpress_i18n.__)("Filters", "elementor"), |
| 1032 |
placement: "top" |
| 1033 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.ToggleButton, { |
| 1034 |
value: "filter", |
| 1035 |
size: "tiny", |
| 1036 |
selected: popupState.isOpen, |
| 1037 |
...(0, _elementor_ui.bindToggle)(popupState) |
| 1038 |
}, /* @__PURE__ */ react.createElement(_elementor_icons.FilterIcon, { fontSize: "tiny" }))), /* @__PURE__ */ react.createElement(_elementor_ui.Popover, { |
| 1039 |
sx: { maxWidth: "344px" }, |
| 1040 |
anchorOrigin: { |
| 1041 |
vertical: "top", |
| 1042 |
horizontal: "right" |
| 1043 |
}, |
| 1044 |
transformOrigin: { |
| 1045 |
vertical: "top", |
| 1046 |
horizontal: -21 |
| 1047 |
}, |
| 1048 |
...(0, _elementor_ui.bindPopover)(popupState) |
| 1049 |
}, /* @__PURE__ */ react.createElement(_elementor_editor_ui.PopoverHeader, { |
| 1050 |
actions: showCleanIcon ? [/* @__PURE__ */ react.createElement(ClearIconButton, { |
| 1051 |
trigger: "menu", |
| 1052 |
key: "clear-all-button", |
| 1053 |
tooltipText: (0, _wordpress_i18n.__)("Clear all", "elementor") |
| 1054 |
})] : [], |
| 1055 |
onClose: popupState.close, |
| 1056 |
title: (0, _wordpress_i18n.__)("Filters", "elementor"), |
| 1057 |
icon: /* @__PURE__ */ react.createElement(_elementor_icons.FilterIcon, { fontSize: "tiny" }) |
| 1058 |
}), /* @__PURE__ */ react.createElement(_elementor_ui.Divider, { sx: { borderWidth: "1px 0 0 0" } }), /* @__PURE__ */ react.createElement(_elementor_editor_ui.PopoverBody, { |
| 1059 |
width: 344, |
| 1060 |
height: 125 |
| 1061 |
}, /* @__PURE__ */ react.createElement(FilterList, null)))); |
| 1062 |
}; |
| 1063 |
|
| 1064 |
//#endregion |
| 1065 |
//#region packages/packages/core/editor-global-classes/src/components/search-and-filter/components/search/class-manager-search.tsx |
| 1066 |
var ClassManagerSearch = () => { |
| 1067 |
const { search: { inputValue, handleChange } } = useSearchAndFilters(); |
| 1068 |
return /* @__PURE__ */ react.createElement(_elementor_ui.Stack, { |
| 1069 |
direction: "row", |
| 1070 |
gap: .5, |
| 1071 |
sx: { width: "100%" } |
| 1072 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Box, { sx: { flexGrow: 1 } }, /* @__PURE__ */ react.createElement(_elementor_ui.TextField, { |
| 1073 |
role: "search", |
| 1074 |
fullWidth: true, |
| 1075 |
size: "tiny", |
| 1076 |
value: inputValue, |
| 1077 |
onFocus: () => { |
| 1078 |
trackGlobalClasses({ event: "classManagerSearched" }); |
| 1079 |
}, |
| 1080 |
placeholder: (0, _wordpress_i18n.__)("Search", "elementor"), |
| 1081 |
onChange: (e) => handleChange(e.target.value), |
| 1082 |
InputProps: { startAdornment: /* @__PURE__ */ react.createElement(_elementor_ui.InputAdornment, { position: "start" }, /* @__PURE__ */ react.createElement(_elementor_icons.SearchIcon, { fontSize: "tiny" })) } |
| 1083 |
}))); |
| 1084 |
}; |
| 1085 |
|
| 1086 |
//#endregion |
| 1087 |
//#region packages/packages/core/editor-global-classes/src/components/class-manager/class-manager-introduction.tsx |
| 1088 |
var MESSAGE_KEY = "global-class-manager"; |
| 1089 |
var ClassManagerIntroduction = () => { |
| 1090 |
const [isMessageSuppressed, suppressMessage] = (0, _elementor_editor_current_user.useSuppressedMessage)(MESSAGE_KEY); |
| 1091 |
const [shouldShowIntroduction, setShouldShowIntroduction] = (0, react.useState)(!isMessageSuppressed); |
| 1092 |
return /* @__PURE__ */ react.createElement(_elementor_editor_ui.IntroductionModal, { |
| 1093 |
open: shouldShowIntroduction, |
| 1094 |
title: (0, _wordpress_i18n.__)("Class Manager", "elementor"), |
| 1095 |
handleClose: (shouldShowAgain) => { |
| 1096 |
if (!shouldShowAgain) suppressMessage(); |
| 1097 |
setShouldShowIntroduction(false); |
| 1098 |
} |
| 1099 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Image, { |
| 1100 |
sx: { |
| 1101 |
width: "100%", |
| 1102 |
aspectRatio: "16 / 9" |
| 1103 |
}, |
| 1104 |
src: "https://assets.elementor.com/packages/v1/images/class-manager-intro.svg", |
| 1105 |
alt: "" |
| 1106 |
}), /* @__PURE__ */ react.createElement(IntroductionContent, null)); |
| 1107 |
}; |
| 1108 |
var IntroductionContent = () => { |
| 1109 |
return /* @__PURE__ */ react.createElement(_elementor_ui.Box, { p: 3 }, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { variant: "body2" }, (0, _wordpress_i18n.__)("The Class Manager lets you see all the classes you've created, plus adjust their priority, rename them, and delete unused classes to keep your CSS structured.", "elementor")), /* @__PURE__ */ react.createElement("br", null), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { variant: "body2" }, (0, _wordpress_i18n.__)("Remember, when editing an item within a specific class, any changes you make will apply across all elements in that class.", "elementor"))); |
| 1110 |
}; |
| 1111 |
|
| 1112 |
//#endregion |
| 1113 |
//#region packages/packages/core/editor-global-classes/src/components/class-manager/delete-class.ts |
| 1114 |
var isDeleted = false; |
| 1115 |
var deleteClass = (id) => { |
| 1116 |
trackGlobalClasses({ |
| 1117 |
event: "classDeleted", |
| 1118 |
classId: id, |
| 1119 |
runAction: () => { |
| 1120 |
(0, _elementor_store.__dispatch)(slice.actions.delete(id)); |
| 1121 |
isDeleted = true; |
| 1122 |
} |
| 1123 |
}); |
| 1124 |
}; |
| 1125 |
var onDelete = async () => { |
| 1126 |
isDeleted = false; |
| 1127 |
}; |
| 1128 |
var hasDeletedItems = () => isDeleted; |
| 1129 |
|
| 1130 |
//#endregion |
| 1131 |
//#region packages/packages/core/editor-global-classes/src/components/class-manager/flipped-color-swatch-icon.tsx |
| 1132 |
var FlippedColorSwatchIcon = ({ sx, ...props }) => /* @__PURE__ */ react.createElement(_elementor_icons.ColorSwatchIcon, { |
| 1133 |
sx: { |
| 1134 |
transform: "rotate(90deg)", |
| 1135 |
...sx |
| 1136 |
}, |
| 1137 |
...props |
| 1138 |
}); |
| 1139 |
|
| 1140 |
//#endregion |
| 1141 |
//#region packages/node_modules/@tanstack/virtual-core/dist/esm/utils.js |
| 1142 |
function memo(getDeps, fn, opts) { |
| 1143 |
let deps = opts.initialDeps ?? []; |
| 1144 |
let result; |
| 1145 |
let isInitial = true; |
| 1146 |
function memoizedFunction() { |
| 1147 |
var _a; |
| 1148 |
var _b; |
| 1149 |
var _c; |
| 1150 |
let depTime; |
| 1151 |
if (opts.key && ((_a = opts.debug) == null ? void 0 : _a.call(opts))) depTime = Date.now(); |
| 1152 |
const newDeps = getDeps(); |
| 1153 |
if (!(newDeps.length !== deps.length || newDeps.some((dep, index) => deps[index] !== dep))) return result; |
| 1154 |
deps = newDeps; |
| 1155 |
let resultTime; |
| 1156 |
if (opts.key && ((_b = opts.debug) == null ? void 0 : _b.call(opts))) resultTime = Date.now(); |
| 1157 |
result = fn(...newDeps); |
| 1158 |
if (opts.key && ((_c = opts.debug) == null ? void 0 : _c.call(opts))) { |
| 1159 |
const depEndTime = Math.round((Date.now() - depTime) * 100) / 100; |
| 1160 |
const resultEndTime = Math.round((Date.now() - resultTime) * 100) / 100; |
| 1161 |
const resultFpsPercentage = resultEndTime / 16; |
| 1162 |
const pad = (str, num) => { |
| 1163 |
str = String(str); |
| 1164 |
while (str.length < num) str = " " + str; |
| 1165 |
return str; |
| 1166 |
}; |
| 1167 |
console.info(`%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`, ` |
| 1168 |
font-size: .6rem; |
| 1169 |
font-weight: bold; |
| 1170 |
color: hsl(${Math.max(0, Math.min(120 - 120 * resultFpsPercentage, 120))}deg 100% 31%);`, opts == null ? void 0 : opts.key); |
| 1171 |
} |
| 1172 |
if ((opts == null ? void 0 : opts.onChange) && !(isInitial && opts.skipInitialOnChange)) opts.onChange(result); |
| 1173 |
isInitial = false; |
| 1174 |
return result; |
| 1175 |
} |
| 1176 |
memoizedFunction.updateDeps = (newDeps) => { |
| 1177 |
deps = newDeps; |
| 1178 |
}; |
| 1179 |
return memoizedFunction; |
| 1180 |
} |
| 1181 |
function notUndefined(value, msg) { |
| 1182 |
if (value === void 0) throw new Error(`Unexpected undefined${msg ? `: ${msg}` : ""}`); |
| 1183 |
else return value; |
| 1184 |
} |
| 1185 |
var approxEqual = (a, b) => Math.abs(a - b) < 1.01; |
| 1186 |
var debounce = (targetWindow, fn, ms) => { |
| 1187 |
let timeoutId; |
| 1188 |
return function(...args) { |
| 1189 |
targetWindow.clearTimeout(timeoutId); |
| 1190 |
timeoutId = targetWindow.setTimeout(() => fn.apply(this, args), ms); |
| 1191 |
}; |
| 1192 |
}; |
| 1193 |
|
| 1194 |
//#endregion |
| 1195 |
//#region packages/node_modules/@tanstack/virtual-core/dist/esm/index.js |
| 1196 |
var getRect = (element) => { |
| 1197 |
const { offsetWidth, offsetHeight } = element; |
| 1198 |
return { |
| 1199 |
width: offsetWidth, |
| 1200 |
height: offsetHeight |
| 1201 |
}; |
| 1202 |
}; |
| 1203 |
var defaultKeyExtractor = (index) => index; |
| 1204 |
var defaultRangeExtractor = (range) => { |
| 1205 |
const start = Math.max(range.startIndex - range.overscan, 0); |
| 1206 |
const end = Math.min(range.endIndex + range.overscan, range.count - 1); |
| 1207 |
const arr = []; |
| 1208 |
for (let i = start; i <= end; i++) arr.push(i); |
| 1209 |
return arr; |
| 1210 |
}; |
| 1211 |
var observeElementRect = (instance, cb) => { |
| 1212 |
const element = instance.scrollElement; |
| 1213 |
if (!element) return; |
| 1214 |
const targetWindow = instance.targetWindow; |
| 1215 |
if (!targetWindow) return; |
| 1216 |
const handler = (rect) => { |
| 1217 |
const { width, height } = rect; |
| 1218 |
cb({ |
| 1219 |
width: Math.round(width), |
| 1220 |
height: Math.round(height) |
| 1221 |
}); |
| 1222 |
}; |
| 1223 |
handler(getRect(element)); |
| 1224 |
if (!targetWindow.ResizeObserver) return () => {}; |
| 1225 |
const observer = new targetWindow.ResizeObserver((entries) => { |
| 1226 |
const run = () => { |
| 1227 |
const entry = entries[0]; |
| 1228 |
if (entry == null ? void 0 : entry.borderBoxSize) { |
| 1229 |
const box = entry.borderBoxSize[0]; |
| 1230 |
if (box) { |
| 1231 |
handler({ |
| 1232 |
width: box.inlineSize, |
| 1233 |
height: box.blockSize |
| 1234 |
}); |
| 1235 |
return; |
| 1236 |
} |
| 1237 |
} |
| 1238 |
handler(getRect(element)); |
| 1239 |
}; |
| 1240 |
instance.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run(); |
| 1241 |
}); |
| 1242 |
observer.observe(element, { box: "border-box" }); |
| 1243 |
return () => { |
| 1244 |
observer.unobserve(element); |
| 1245 |
}; |
| 1246 |
}; |
| 1247 |
var addEventListenerOptions = { passive: true }; |
| 1248 |
var supportsScrollend = typeof window == "undefined" ? true : "onscrollend" in window; |
| 1249 |
var observeElementOffset = (instance, cb) => { |
| 1250 |
const element = instance.scrollElement; |
| 1251 |
if (!element) return; |
| 1252 |
const targetWindow = instance.targetWindow; |
| 1253 |
if (!targetWindow) return; |
| 1254 |
let offset = 0; |
| 1255 |
const fallback = instance.options.useScrollendEvent && supportsScrollend ? () => void 0 : debounce(targetWindow, () => { |
| 1256 |
cb(offset, false); |
| 1257 |
}, instance.options.isScrollingResetDelay); |
| 1258 |
const createHandler = (isScrolling) => () => { |
| 1259 |
const { horizontal, isRtl } = instance.options; |
| 1260 |
offset = horizontal ? element["scrollLeft"] * (isRtl && -1 || 1) : element["scrollTop"]; |
| 1261 |
fallback(); |
| 1262 |
cb(offset, isScrolling); |
| 1263 |
}; |
| 1264 |
const handler = createHandler(true); |
| 1265 |
const endHandler = createHandler(false); |
| 1266 |
element.addEventListener("scroll", handler, addEventListenerOptions); |
| 1267 |
const registerScrollendEvent = instance.options.useScrollendEvent && supportsScrollend; |
| 1268 |
if (registerScrollendEvent) element.addEventListener("scrollend", endHandler, addEventListenerOptions); |
| 1269 |
return () => { |
| 1270 |
element.removeEventListener("scroll", handler); |
| 1271 |
if (registerScrollendEvent) element.removeEventListener("scrollend", endHandler); |
| 1272 |
}; |
| 1273 |
}; |
| 1274 |
var measureElement = (element, entry, instance) => { |
| 1275 |
if (entry == null ? void 0 : entry.borderBoxSize) { |
| 1276 |
const box = entry.borderBoxSize[0]; |
| 1277 |
if (box) return Math.round(box[instance.options.horizontal ? "inlineSize" : "blockSize"]); |
| 1278 |
} |
| 1279 |
return element[instance.options.horizontal ? "offsetWidth" : "offsetHeight"]; |
| 1280 |
}; |
| 1281 |
var elementScroll = (offset, { adjustments = 0, behavior }, instance) => { |
| 1282 |
var _a; |
| 1283 |
var _b; |
| 1284 |
const toOffset = offset + adjustments; |
| 1285 |
(_b = (_a = instance.scrollElement) == null ? void 0 : _a.scrollTo) == null || _b.call(_a, { |
| 1286 |
[instance.options.horizontal ? "left" : "top"]: toOffset, |
| 1287 |
behavior |
| 1288 |
}); |
| 1289 |
}; |
| 1290 |
var Virtualizer = class { |
| 1291 |
constructor(opts) { |
| 1292 |
this.unsubs = []; |
| 1293 |
this.scrollElement = null; |
| 1294 |
this.targetWindow = null; |
| 1295 |
this.isScrolling = false; |
| 1296 |
this.scrollState = null; |
| 1297 |
this.measurementsCache = []; |
| 1298 |
this.itemSizeCache = /* @__PURE__ */ new Map(); |
| 1299 |
this.laneAssignments = /* @__PURE__ */ new Map(); |
| 1300 |
this.pendingMeasuredCacheIndexes = []; |
| 1301 |
this.prevLanes = void 0; |
| 1302 |
this.lanesChangedFlag = false; |
| 1303 |
this.lanesSettling = false; |
| 1304 |
this.scrollRect = null; |
| 1305 |
this.scrollOffset = null; |
| 1306 |
this.scrollDirection = null; |
| 1307 |
this.scrollAdjustments = 0; |
| 1308 |
this.elementsCache = /* @__PURE__ */ new Map(); |
| 1309 |
this.now = () => { |
| 1310 |
var _a; |
| 1311 |
var _b; |
| 1312 |
var _c; |
| 1313 |
return ((_c = (_b = (_a = this.targetWindow) == null ? void 0 : _a.performance) == null ? void 0 : _b.now) == null ? void 0 : _c.call(_b)) ?? Date.now(); |
| 1314 |
}; |
| 1315 |
this.observer = /* @__PURE__ */ (() => { |
| 1316 |
let _ro = null; |
| 1317 |
const get = () => { |
| 1318 |
if (_ro) return _ro; |
| 1319 |
if (!this.targetWindow || !this.targetWindow.ResizeObserver) return null; |
| 1320 |
return _ro = new this.targetWindow.ResizeObserver((entries) => { |
| 1321 |
entries.forEach((entry) => { |
| 1322 |
const run = () => { |
| 1323 |
const node = entry.target; |
| 1324 |
const index = this.indexFromElement(node); |
| 1325 |
if (!node.isConnected) { |
| 1326 |
this.observer.unobserve(node); |
| 1327 |
return; |
| 1328 |
} |
| 1329 |
if (this.shouldMeasureDuringScroll(index)) this.resizeItem(index, this.options.measureElement(node, entry, this)); |
| 1330 |
}; |
| 1331 |
this.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run(); |
| 1332 |
}); |
| 1333 |
}); |
| 1334 |
}; |
| 1335 |
return { |
| 1336 |
disconnect: () => { |
| 1337 |
var _a; |
| 1338 |
(_a = get()) == null || _a.disconnect(); |
| 1339 |
_ro = null; |
| 1340 |
}, |
| 1341 |
observe: (target) => { |
| 1342 |
var _a; |
| 1343 |
return (_a = get()) == null ? void 0 : _a.observe(target, { box: "border-box" }); |
| 1344 |
}, |
| 1345 |
unobserve: (target) => { |
| 1346 |
var _a; |
| 1347 |
return (_a = get()) == null ? void 0 : _a.unobserve(target); |
| 1348 |
} |
| 1349 |
}; |
| 1350 |
})(); |
| 1351 |
this.range = null; |
| 1352 |
this.setOptions = (opts2) => { |
| 1353 |
Object.entries(opts2).forEach(([key, value]) => { |
| 1354 |
if (typeof value === "undefined") delete opts2[key]; |
| 1355 |
}); |
| 1356 |
this.options = { |
| 1357 |
debug: false, |
| 1358 |
initialOffset: 0, |
| 1359 |
overscan: 1, |
| 1360 |
paddingStart: 0, |
| 1361 |
paddingEnd: 0, |
| 1362 |
scrollPaddingStart: 0, |
| 1363 |
scrollPaddingEnd: 0, |
| 1364 |
horizontal: false, |
| 1365 |
getItemKey: defaultKeyExtractor, |
| 1366 |
rangeExtractor: defaultRangeExtractor, |
| 1367 |
onChange: () => {}, |
| 1368 |
measureElement, |
| 1369 |
initialRect: { |
| 1370 |
width: 0, |
| 1371 |
height: 0 |
| 1372 |
}, |
| 1373 |
scrollMargin: 0, |
| 1374 |
gap: 0, |
| 1375 |
indexAttribute: "data-index", |
| 1376 |
initialMeasurementsCache: [], |
| 1377 |
lanes: 1, |
| 1378 |
isScrollingResetDelay: 150, |
| 1379 |
enabled: true, |
| 1380 |
isRtl: false, |
| 1381 |
useScrollendEvent: false, |
| 1382 |
useAnimationFrameWithResizeObserver: false, |
| 1383 |
laneAssignmentMode: "estimate", |
| 1384 |
...opts2 |
| 1385 |
}; |
| 1386 |
}; |
| 1387 |
this.notify = (sync) => { |
| 1388 |
var _a; |
| 1389 |
var _b; |
| 1390 |
(_b = (_a = this.options).onChange) == null || _b.call(_a, this, sync); |
| 1391 |
}; |
| 1392 |
this.maybeNotify = memo(() => { |
| 1393 |
this.calculateRange(); |
| 1394 |
return [ |
| 1395 |
this.isScrolling, |
| 1396 |
this.range ? this.range.startIndex : null, |
| 1397 |
this.range ? this.range.endIndex : null |
| 1398 |
]; |
| 1399 |
}, (isScrolling) => { |
| 1400 |
this.notify(isScrolling); |
| 1401 |
}, { |
| 1402 |
key: "maybeNotify", |
| 1403 |
debug: () => this.options.debug, |
| 1404 |
initialDeps: [ |
| 1405 |
this.isScrolling, |
| 1406 |
this.range ? this.range.startIndex : null, |
| 1407 |
this.range ? this.range.endIndex : null |
| 1408 |
] |
| 1409 |
}); |
| 1410 |
this.cleanup = () => { |
| 1411 |
this.unsubs.filter(Boolean).forEach((d) => d()); |
| 1412 |
this.unsubs = []; |
| 1413 |
this.observer.disconnect(); |
| 1414 |
if (this.rafId != null && this.targetWindow) { |
| 1415 |
this.targetWindow.cancelAnimationFrame(this.rafId); |
| 1416 |
this.rafId = null; |
| 1417 |
} |
| 1418 |
this.scrollState = null; |
| 1419 |
this.scrollElement = null; |
| 1420 |
this.targetWindow = null; |
| 1421 |
}; |
| 1422 |
this._didMount = () => { |
| 1423 |
return () => { |
| 1424 |
this.cleanup(); |
| 1425 |
}; |
| 1426 |
}; |
| 1427 |
this._willUpdate = () => { |
| 1428 |
var _a; |
| 1429 |
const scrollElement = this.options.enabled ? this.options.getScrollElement() : null; |
| 1430 |
if (this.scrollElement !== scrollElement) { |
| 1431 |
this.cleanup(); |
| 1432 |
if (!scrollElement) { |
| 1433 |
this.maybeNotify(); |
| 1434 |
return; |
| 1435 |
} |
| 1436 |
this.scrollElement = scrollElement; |
| 1437 |
if (this.scrollElement && "ownerDocument" in this.scrollElement) this.targetWindow = this.scrollElement.ownerDocument.defaultView; |
| 1438 |
else this.targetWindow = ((_a = this.scrollElement) == null ? void 0 : _a.window) ?? null; |
| 1439 |
this.elementsCache.forEach((cached) => { |
| 1440 |
this.observer.observe(cached); |
| 1441 |
}); |
| 1442 |
this.unsubs.push(this.options.observeElementRect(this, (rect) => { |
| 1443 |
this.scrollRect = rect; |
| 1444 |
this.maybeNotify(); |
| 1445 |
})); |
| 1446 |
this.unsubs.push(this.options.observeElementOffset(this, (offset, isScrolling) => { |
| 1447 |
this.scrollAdjustments = 0; |
| 1448 |
this.scrollDirection = isScrolling ? this.getScrollOffset() < offset ? "forward" : "backward" : null; |
| 1449 |
this.scrollOffset = offset; |
| 1450 |
this.isScrolling = isScrolling; |
| 1451 |
if (this.scrollState) this.scheduleScrollReconcile(); |
| 1452 |
this.maybeNotify(); |
| 1453 |
})); |
| 1454 |
this._scrollToOffset(this.getScrollOffset(), { |
| 1455 |
adjustments: void 0, |
| 1456 |
behavior: void 0 |
| 1457 |
}); |
| 1458 |
} |
| 1459 |
}; |
| 1460 |
this.rafId = null; |
| 1461 |
this.getSize = () => { |
| 1462 |
if (!this.options.enabled) { |
| 1463 |
this.scrollRect = null; |
| 1464 |
return 0; |
| 1465 |
} |
| 1466 |
this.scrollRect = this.scrollRect ?? this.options.initialRect; |
| 1467 |
return this.scrollRect[this.options.horizontal ? "width" : "height"]; |
| 1468 |
}; |
| 1469 |
this.getScrollOffset = () => { |
| 1470 |
if (!this.options.enabled) { |
| 1471 |
this.scrollOffset = null; |
| 1472 |
return 0; |
| 1473 |
} |
| 1474 |
this.scrollOffset = this.scrollOffset ?? (typeof this.options.initialOffset === "function" ? this.options.initialOffset() : this.options.initialOffset); |
| 1475 |
return this.scrollOffset; |
| 1476 |
}; |
| 1477 |
this.getFurthestMeasurement = (measurements, index) => { |
| 1478 |
const furthestMeasurementsFound = /* @__PURE__ */ new Map(); |
| 1479 |
const furthestMeasurements = /* @__PURE__ */ new Map(); |
| 1480 |
for (let m = index - 1; m >= 0; m--) { |
| 1481 |
const measurement = measurements[m]; |
| 1482 |
if (furthestMeasurementsFound.has(measurement.lane)) continue; |
| 1483 |
const previousFurthestMeasurement = furthestMeasurements.get(measurement.lane); |
| 1484 |
if (previousFurthestMeasurement == null || measurement.end > previousFurthestMeasurement.end) furthestMeasurements.set(measurement.lane, measurement); |
| 1485 |
else if (measurement.end < previousFurthestMeasurement.end) furthestMeasurementsFound.set(measurement.lane, true); |
| 1486 |
if (furthestMeasurementsFound.size === this.options.lanes) break; |
| 1487 |
} |
| 1488 |
return furthestMeasurements.size === this.options.lanes ? Array.from(furthestMeasurements.values()).sort((a, b) => { |
| 1489 |
if (a.end === b.end) return a.index - b.index; |
| 1490 |
return a.end - b.end; |
| 1491 |
})[0] : void 0; |
| 1492 |
}; |
| 1493 |
this.getMeasurementOptions = memo(() => [ |
| 1494 |
this.options.count, |
| 1495 |
this.options.paddingStart, |
| 1496 |
this.options.scrollMargin, |
| 1497 |
this.options.getItemKey, |
| 1498 |
this.options.enabled, |
| 1499 |
this.options.lanes, |
| 1500 |
this.options.laneAssignmentMode |
| 1501 |
], (count, paddingStart, scrollMargin, getItemKey, enabled, lanes, laneAssignmentMode) => { |
| 1502 |
if (this.prevLanes !== void 0 && this.prevLanes !== lanes) this.lanesChangedFlag = true; |
| 1503 |
this.prevLanes = lanes; |
| 1504 |
this.pendingMeasuredCacheIndexes = []; |
| 1505 |
return { |
| 1506 |
count, |
| 1507 |
paddingStart, |
| 1508 |
scrollMargin, |
| 1509 |
getItemKey, |
| 1510 |
enabled, |
| 1511 |
lanes, |
| 1512 |
laneAssignmentMode |
| 1513 |
}; |
| 1514 |
}, { key: false }); |
| 1515 |
this.getMeasurements = memo(() => [this.getMeasurementOptions(), this.itemSizeCache], ({ count, paddingStart, scrollMargin, getItemKey, enabled, lanes, laneAssignmentMode }, itemSizeCache) => { |
| 1516 |
if (!enabled) { |
| 1517 |
this.measurementsCache = []; |
| 1518 |
this.itemSizeCache.clear(); |
| 1519 |
this.laneAssignments.clear(); |
| 1520 |
return []; |
| 1521 |
} |
| 1522 |
if (this.laneAssignments.size > count) { |
| 1523 |
for (const index of this.laneAssignments.keys()) if (index >= count) this.laneAssignments.delete(index); |
| 1524 |
} |
| 1525 |
if (this.lanesChangedFlag) { |
| 1526 |
this.lanesChangedFlag = false; |
| 1527 |
this.lanesSettling = true; |
| 1528 |
this.measurementsCache = []; |
| 1529 |
this.itemSizeCache.clear(); |
| 1530 |
this.laneAssignments.clear(); |
| 1531 |
this.pendingMeasuredCacheIndexes = []; |
| 1532 |
} |
| 1533 |
if (this.measurementsCache.length === 0 && !this.lanesSettling) { |
| 1534 |
this.measurementsCache = this.options.initialMeasurementsCache; |
| 1535 |
this.measurementsCache.forEach((item) => { |
| 1536 |
this.itemSizeCache.set(item.key, item.size); |
| 1537 |
}); |
| 1538 |
} |
| 1539 |
const min = this.lanesSettling ? 0 : this.pendingMeasuredCacheIndexes.length > 0 ? Math.min(...this.pendingMeasuredCacheIndexes) : 0; |
| 1540 |
this.pendingMeasuredCacheIndexes = []; |
| 1541 |
if (this.lanesSettling && this.measurementsCache.length === count) this.lanesSettling = false; |
| 1542 |
const measurements = this.measurementsCache.slice(0, min); |
| 1543 |
const laneLastIndex = new Array(lanes).fill(void 0); |
| 1544 |
for (let m = 0; m < min; m++) { |
| 1545 |
const item = measurements[m]; |
| 1546 |
if (item) laneLastIndex[item.lane] = m; |
| 1547 |
} |
| 1548 |
for (let i = min; i < count; i++) { |
| 1549 |
const key = getItemKey(i); |
| 1550 |
const cachedLane = this.laneAssignments.get(i); |
| 1551 |
let lane; |
| 1552 |
let start; |
| 1553 |
const shouldCacheLane = laneAssignmentMode === "estimate" || itemSizeCache.has(key); |
| 1554 |
if (cachedLane !== void 0 && this.options.lanes > 1) { |
| 1555 |
lane = cachedLane; |
| 1556 |
const prevIndex = laneLastIndex[lane]; |
| 1557 |
const prevInLane = prevIndex !== void 0 ? measurements[prevIndex] : void 0; |
| 1558 |
start = prevInLane ? prevInLane.end + this.options.gap : paddingStart + scrollMargin; |
| 1559 |
} else { |
| 1560 |
const furthestMeasurement = this.options.lanes === 1 ? measurements[i - 1] : this.getFurthestMeasurement(measurements, i); |
| 1561 |
start = furthestMeasurement ? furthestMeasurement.end + this.options.gap : paddingStart + scrollMargin; |
| 1562 |
lane = furthestMeasurement ? furthestMeasurement.lane : i % this.options.lanes; |
| 1563 |
if (this.options.lanes > 1 && shouldCacheLane) this.laneAssignments.set(i, lane); |
| 1564 |
} |
| 1565 |
const measuredSize = itemSizeCache.get(key); |
| 1566 |
const size = typeof measuredSize === "number" ? measuredSize : this.options.estimateSize(i); |
| 1567 |
const end = start + size; |
| 1568 |
measurements[i] = { |
| 1569 |
index: i, |
| 1570 |
start, |
| 1571 |
size, |
| 1572 |
end, |
| 1573 |
key, |
| 1574 |
lane |
| 1575 |
}; |
| 1576 |
laneLastIndex[lane] = i; |
| 1577 |
} |
| 1578 |
this.measurementsCache = measurements; |
| 1579 |
return measurements; |
| 1580 |
}, { |
| 1581 |
key: "getMeasurements", |
| 1582 |
debug: () => this.options.debug |
| 1583 |
}); |
| 1584 |
this.calculateRange = memo(() => [ |
| 1585 |
this.getMeasurements(), |
| 1586 |
this.getSize(), |
| 1587 |
this.getScrollOffset(), |
| 1588 |
this.options.lanes |
| 1589 |
], (measurements, outerSize, scrollOffset, lanes) => { |
| 1590 |
return this.range = measurements.length > 0 && outerSize > 0 ? calculateRange({ |
| 1591 |
measurements, |
| 1592 |
outerSize, |
| 1593 |
scrollOffset, |
| 1594 |
lanes |
| 1595 |
}) : null; |
| 1596 |
}, { |
| 1597 |
key: "calculateRange", |
| 1598 |
debug: () => this.options.debug |
| 1599 |
}); |
| 1600 |
this.getVirtualIndexes = memo(() => { |
| 1601 |
let startIndex = null; |
| 1602 |
let endIndex = null; |
| 1603 |
const range = this.calculateRange(); |
| 1604 |
if (range) { |
| 1605 |
startIndex = range.startIndex; |
| 1606 |
endIndex = range.endIndex; |
| 1607 |
} |
| 1608 |
this.maybeNotify.updateDeps([ |
| 1609 |
this.isScrolling, |
| 1610 |
startIndex, |
| 1611 |
endIndex |
| 1612 |
]); |
| 1613 |
return [ |
| 1614 |
this.options.rangeExtractor, |
| 1615 |
this.options.overscan, |
| 1616 |
this.options.count, |
| 1617 |
startIndex, |
| 1618 |
endIndex |
| 1619 |
]; |
| 1620 |
}, (rangeExtractor, overscan, count, startIndex, endIndex) => { |
| 1621 |
return startIndex === null || endIndex === null ? [] : rangeExtractor({ |
| 1622 |
startIndex, |
| 1623 |
endIndex, |
| 1624 |
overscan, |
| 1625 |
count |
| 1626 |
}); |
| 1627 |
}, { |
| 1628 |
key: "getVirtualIndexes", |
| 1629 |
debug: () => this.options.debug |
| 1630 |
}); |
| 1631 |
this.indexFromElement = (node) => { |
| 1632 |
const attributeName = this.options.indexAttribute; |
| 1633 |
const indexStr = node.getAttribute(attributeName); |
| 1634 |
if (!indexStr) { |
| 1635 |
console.warn(`Missing attribute name '${attributeName}={index}' on measured element.`); |
| 1636 |
return -1; |
| 1637 |
} |
| 1638 |
return parseInt(indexStr, 10); |
| 1639 |
}; |
| 1640 |
this.shouldMeasureDuringScroll = (index) => { |
| 1641 |
var _a; |
| 1642 |
if (!this.scrollState || this.scrollState.behavior !== "smooth") return true; |
| 1643 |
const scrollIndex = this.scrollState.index ?? ((_a = this.getVirtualItemForOffset(this.scrollState.lastTargetOffset)) == null ? void 0 : _a.index); |
| 1644 |
if (scrollIndex !== void 0 && this.range) { |
| 1645 |
const bufferSize = Math.max(this.options.overscan, Math.ceil((this.range.endIndex - this.range.startIndex) / 2)); |
| 1646 |
const minIndex = Math.max(0, scrollIndex - bufferSize); |
| 1647 |
const maxIndex = Math.min(this.options.count - 1, scrollIndex + bufferSize); |
| 1648 |
return index >= minIndex && index <= maxIndex; |
| 1649 |
} |
| 1650 |
return true; |
| 1651 |
}; |
| 1652 |
this.measureElement = (node) => { |
| 1653 |
if (!node) { |
| 1654 |
this.elementsCache.forEach((cached, key2) => { |
| 1655 |
if (!cached.isConnected) { |
| 1656 |
this.observer.unobserve(cached); |
| 1657 |
this.elementsCache.delete(key2); |
| 1658 |
} |
| 1659 |
}); |
| 1660 |
return; |
| 1661 |
} |
| 1662 |
const index = this.indexFromElement(node); |
| 1663 |
const key = this.options.getItemKey(index); |
| 1664 |
const prevNode = this.elementsCache.get(key); |
| 1665 |
if (prevNode !== node) { |
| 1666 |
if (prevNode) this.observer.unobserve(prevNode); |
| 1667 |
this.observer.observe(node); |
| 1668 |
this.elementsCache.set(key, node); |
| 1669 |
} |
| 1670 |
if ((!this.isScrolling || this.scrollState) && this.shouldMeasureDuringScroll(index)) this.resizeItem(index, this.options.measureElement(node, void 0, this)); |
| 1671 |
}; |
| 1672 |
this.resizeItem = (index, size) => { |
| 1673 |
var _a; |
| 1674 |
const item = this.measurementsCache[index]; |
| 1675 |
if (!item) return; |
| 1676 |
const delta = size - (this.itemSizeCache.get(item.key) ?? item.size); |
| 1677 |
if (delta !== 0) { |
| 1678 |
if (((_a = this.scrollState) == null ? void 0 : _a.behavior) !== "smooth" && (this.shouldAdjustScrollPositionOnItemSizeChange !== void 0 ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this) : item.start < this.getScrollOffset() + this.scrollAdjustments)) { |
| 1679 |
if (this.options.debug) console.info("correction", delta); |
| 1680 |
this._scrollToOffset(this.getScrollOffset(), { |
| 1681 |
adjustments: this.scrollAdjustments += delta, |
| 1682 |
behavior: void 0 |
| 1683 |
}); |
| 1684 |
} |
| 1685 |
this.pendingMeasuredCacheIndexes.push(item.index); |
| 1686 |
this.itemSizeCache = new Map(this.itemSizeCache.set(item.key, size)); |
| 1687 |
this.notify(false); |
| 1688 |
} |
| 1689 |
}; |
| 1690 |
this.getVirtualItems = memo(() => [this.getVirtualIndexes(), this.getMeasurements()], (indexes, measurements) => { |
| 1691 |
const virtualItems = []; |
| 1692 |
for (let k = 0, len = indexes.length; k < len; k++) { |
| 1693 |
const measurement = measurements[indexes[k]]; |
| 1694 |
virtualItems.push(measurement); |
| 1695 |
} |
| 1696 |
return virtualItems; |
| 1697 |
}, { |
| 1698 |
key: "getVirtualItems", |
| 1699 |
debug: () => this.options.debug |
| 1700 |
}); |
| 1701 |
this.getVirtualItemForOffset = (offset) => { |
| 1702 |
const measurements = this.getMeasurements(); |
| 1703 |
if (measurements.length === 0) return; |
| 1704 |
return notUndefined(measurements[findNearestBinarySearch(0, measurements.length - 1, (index) => notUndefined(measurements[index]).start, offset)]); |
| 1705 |
}; |
| 1706 |
this.getMaxScrollOffset = () => { |
| 1707 |
if (!this.scrollElement) return 0; |
| 1708 |
if ("scrollHeight" in this.scrollElement) return this.options.horizontal ? this.scrollElement.scrollWidth - this.scrollElement.clientWidth : this.scrollElement.scrollHeight - this.scrollElement.clientHeight; |
| 1709 |
else { |
| 1710 |
const doc = this.scrollElement.document.documentElement; |
| 1711 |
return this.options.horizontal ? doc.scrollWidth - this.scrollElement.innerWidth : doc.scrollHeight - this.scrollElement.innerHeight; |
| 1712 |
} |
| 1713 |
}; |
| 1714 |
this.getOffsetForAlignment = (toOffset, align, itemSize = 0) => { |
| 1715 |
if (!this.scrollElement) return 0; |
| 1716 |
const size = this.getSize(); |
| 1717 |
const scrollOffset = this.getScrollOffset(); |
| 1718 |
if (align === "auto") align = toOffset >= scrollOffset + size ? "end" : "start"; |
| 1719 |
if (align === "center") toOffset += (itemSize - size) / 2; |
| 1720 |
else if (align === "end") toOffset -= size; |
| 1721 |
const maxOffset = this.getMaxScrollOffset(); |
| 1722 |
return Math.max(Math.min(maxOffset, toOffset), 0); |
| 1723 |
}; |
| 1724 |
this.getOffsetForIndex = (index, align = "auto") => { |
| 1725 |
index = Math.max(0, Math.min(index, this.options.count - 1)); |
| 1726 |
const size = this.getSize(); |
| 1727 |
const scrollOffset = this.getScrollOffset(); |
| 1728 |
const item = this.measurementsCache[index]; |
| 1729 |
if (!item) return; |
| 1730 |
if (align === "auto") if (item.end >= scrollOffset + size - this.options.scrollPaddingEnd) align = "end"; |
| 1731 |
else if (item.start <= scrollOffset + this.options.scrollPaddingStart) align = "start"; |
| 1732 |
else return [scrollOffset, align]; |
| 1733 |
if (align === "end" && index === this.options.count - 1) return [this.getMaxScrollOffset(), align]; |
| 1734 |
const toOffset = align === "end" ? item.end + this.options.scrollPaddingEnd : item.start - this.options.scrollPaddingStart; |
| 1735 |
return [this.getOffsetForAlignment(toOffset, align, item.size), align]; |
| 1736 |
}; |
| 1737 |
this.scrollToOffset = (toOffset, { align = "start", behavior = "auto" } = {}) => { |
| 1738 |
const offset = this.getOffsetForAlignment(toOffset, align); |
| 1739 |
const now = this.now(); |
| 1740 |
this.scrollState = { |
| 1741 |
index: null, |
| 1742 |
align, |
| 1743 |
behavior, |
| 1744 |
startedAt: now, |
| 1745 |
lastTargetOffset: offset, |
| 1746 |
stableFrames: 0 |
| 1747 |
}; |
| 1748 |
this._scrollToOffset(offset, { |
| 1749 |
adjustments: void 0, |
| 1750 |
behavior |
| 1751 |
}); |
| 1752 |
this.scheduleScrollReconcile(); |
| 1753 |
}; |
| 1754 |
this.scrollToIndex = (index, { align: initialAlign = "auto", behavior = "auto" } = {}) => { |
| 1755 |
index = Math.max(0, Math.min(index, this.options.count - 1)); |
| 1756 |
const offsetInfo = this.getOffsetForIndex(index, initialAlign); |
| 1757 |
if (!offsetInfo) return; |
| 1758 |
const [offset, align] = offsetInfo; |
| 1759 |
const now = this.now(); |
| 1760 |
this.scrollState = { |
| 1761 |
index, |
| 1762 |
align, |
| 1763 |
behavior, |
| 1764 |
startedAt: now, |
| 1765 |
lastTargetOffset: offset, |
| 1766 |
stableFrames: 0 |
| 1767 |
}; |
| 1768 |
this._scrollToOffset(offset, { |
| 1769 |
adjustments: void 0, |
| 1770 |
behavior |
| 1771 |
}); |
| 1772 |
this.scheduleScrollReconcile(); |
| 1773 |
}; |
| 1774 |
this.scrollBy = (delta, { behavior = "auto" } = {}) => { |
| 1775 |
const offset = this.getScrollOffset() + delta; |
| 1776 |
const now = this.now(); |
| 1777 |
this.scrollState = { |
| 1778 |
index: null, |
| 1779 |
align: "start", |
| 1780 |
behavior, |
| 1781 |
startedAt: now, |
| 1782 |
lastTargetOffset: offset, |
| 1783 |
stableFrames: 0 |
| 1784 |
}; |
| 1785 |
this._scrollToOffset(offset, { |
| 1786 |
adjustments: void 0, |
| 1787 |
behavior |
| 1788 |
}); |
| 1789 |
this.scheduleScrollReconcile(); |
| 1790 |
}; |
| 1791 |
this.getTotalSize = () => { |
| 1792 |
var _a; |
| 1793 |
const measurements = this.getMeasurements(); |
| 1794 |
let end; |
| 1795 |
if (measurements.length === 0) end = this.options.paddingStart; |
| 1796 |
else if (this.options.lanes === 1) end = ((_a = measurements[measurements.length - 1]) == null ? void 0 : _a.end) ?? 0; |
| 1797 |
else { |
| 1798 |
const endByLane = Array(this.options.lanes).fill(null); |
| 1799 |
let endIndex = measurements.length - 1; |
| 1800 |
while (endIndex >= 0 && endByLane.some((val) => val === null)) { |
| 1801 |
const item = measurements[endIndex]; |
| 1802 |
if (endByLane[item.lane] === null) endByLane[item.lane] = item.end; |
| 1803 |
endIndex--; |
| 1804 |
} |
| 1805 |
end = Math.max(...endByLane.filter((val) => val !== null)); |
| 1806 |
} |
| 1807 |
return Math.max(end - this.options.scrollMargin + this.options.paddingEnd, 0); |
| 1808 |
}; |
| 1809 |
this._scrollToOffset = (offset, { adjustments, behavior }) => { |
| 1810 |
this.options.scrollToFn(offset, { |
| 1811 |
behavior, |
| 1812 |
adjustments |
| 1813 |
}, this); |
| 1814 |
}; |
| 1815 |
this.measure = () => { |
| 1816 |
this.itemSizeCache = /* @__PURE__ */ new Map(); |
| 1817 |
this.laneAssignments = /* @__PURE__ */ new Map(); |
| 1818 |
this.notify(false); |
| 1819 |
}; |
| 1820 |
this.setOptions(opts); |
| 1821 |
} |
| 1822 |
scheduleScrollReconcile() { |
| 1823 |
if (!this.targetWindow) { |
| 1824 |
this.scrollState = null; |
| 1825 |
return; |
| 1826 |
} |
| 1827 |
if (this.rafId != null) return; |
| 1828 |
this.rafId = this.targetWindow.requestAnimationFrame(() => { |
| 1829 |
this.rafId = null; |
| 1830 |
this.reconcileScroll(); |
| 1831 |
}); |
| 1832 |
} |
| 1833 |
reconcileScroll() { |
| 1834 |
if (!this.scrollState) return; |
| 1835 |
if (!this.scrollElement) return; |
| 1836 |
if (this.now() - this.scrollState.startedAt > 5e3) { |
| 1837 |
this.scrollState = null; |
| 1838 |
return; |
| 1839 |
} |
| 1840 |
const offsetInfo = this.scrollState.index != null ? this.getOffsetForIndex(this.scrollState.index, this.scrollState.align) : void 0; |
| 1841 |
const targetOffset = offsetInfo ? offsetInfo[0] : this.scrollState.lastTargetOffset; |
| 1842 |
const STABLE_FRAMES = 1; |
| 1843 |
const targetChanged = targetOffset !== this.scrollState.lastTargetOffset; |
| 1844 |
if (!targetChanged && approxEqual(targetOffset, this.getScrollOffset())) { |
| 1845 |
this.scrollState.stableFrames++; |
| 1846 |
if (this.scrollState.stableFrames >= STABLE_FRAMES) { |
| 1847 |
this.scrollState = null; |
| 1848 |
return; |
| 1849 |
} |
| 1850 |
} else { |
| 1851 |
this.scrollState.stableFrames = 0; |
| 1852 |
if (targetChanged) { |
| 1853 |
this.scrollState.lastTargetOffset = targetOffset; |
| 1854 |
this.scrollState.behavior = "auto"; |
| 1855 |
this._scrollToOffset(targetOffset, { |
| 1856 |
adjustments: void 0, |
| 1857 |
behavior: "auto" |
| 1858 |
}); |
| 1859 |
} |
| 1860 |
} |
| 1861 |
this.scheduleScrollReconcile(); |
| 1862 |
} |
| 1863 |
}; |
| 1864 |
var findNearestBinarySearch = (low, high, getCurrentValue, value) => { |
| 1865 |
while (low <= high) { |
| 1866 |
const middle = (low + high) / 2 | 0; |
| 1867 |
const currentValue = getCurrentValue(middle); |
| 1868 |
if (currentValue < value) low = middle + 1; |
| 1869 |
else if (currentValue > value) high = middle - 1; |
| 1870 |
else return middle; |
| 1871 |
} |
| 1872 |
if (low > 0) return low - 1; |
| 1873 |
else return 0; |
| 1874 |
}; |
| 1875 |
function calculateRange({ measurements, outerSize, scrollOffset, lanes }) { |
| 1876 |
const lastIndex = measurements.length - 1; |
| 1877 |
const getOffset = (index) => measurements[index].start; |
| 1878 |
if (measurements.length <= lanes) return { |
| 1879 |
startIndex: 0, |
| 1880 |
endIndex: lastIndex |
| 1881 |
}; |
| 1882 |
let startIndex = findNearestBinarySearch(0, lastIndex, getOffset, scrollOffset); |
| 1883 |
let endIndex = startIndex; |
| 1884 |
if (lanes === 1) while (endIndex < lastIndex && measurements[endIndex].end < scrollOffset + outerSize) endIndex++; |
| 1885 |
else if (lanes > 1) { |
| 1886 |
const endPerLane = Array(lanes).fill(0); |
| 1887 |
while (endIndex < lastIndex && endPerLane.some((pos) => pos < scrollOffset + outerSize)) { |
| 1888 |
const item = measurements[endIndex]; |
| 1889 |
endPerLane[item.lane] = item.end; |
| 1890 |
endIndex++; |
| 1891 |
} |
| 1892 |
const startPerLane = Array(lanes).fill(scrollOffset + outerSize); |
| 1893 |
while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) { |
| 1894 |
const item = measurements[startIndex]; |
| 1895 |
startPerLane[item.lane] = item.start; |
| 1896 |
startIndex--; |
| 1897 |
} |
| 1898 |
startIndex = Math.max(0, startIndex - startIndex % lanes); |
| 1899 |
endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - endIndex % lanes)); |
| 1900 |
} |
| 1901 |
return { |
| 1902 |
startIndex, |
| 1903 |
endIndex |
| 1904 |
}; |
| 1905 |
} |
| 1906 |
|
| 1907 |
//#endregion |
| 1908 |
//#region packages/node_modules/@tanstack/react-virtual/dist/esm/index.js |
| 1909 |
var useIsomorphicLayoutEffect = typeof document !== "undefined" ? react$1.useLayoutEffect : react$1.useEffect; |
| 1910 |
function useVirtualizerBase({ useFlushSync = true, ...options }) { |
| 1911 |
const rerender = react$1.useReducer(() => ({}), {})[1]; |
| 1912 |
const resolvedOptions = { |
| 1913 |
...options, |
| 1914 |
onChange: (instance2, sync) => { |
| 1915 |
var _a; |
| 1916 |
if (useFlushSync && sync) (0, react_dom.flushSync)(rerender); |
| 1917 |
else rerender(); |
| 1918 |
(_a = options.onChange) == null || _a.call(options, instance2, sync); |
| 1919 |
} |
| 1920 |
}; |
| 1921 |
const [instance] = react$1.useState(() => new Virtualizer(resolvedOptions)); |
| 1922 |
instance.setOptions(resolvedOptions); |
| 1923 |
useIsomorphicLayoutEffect(() => { |
| 1924 |
return instance._didMount(); |
| 1925 |
}, []); |
| 1926 |
useIsomorphicLayoutEffect(() => { |
| 1927 |
return instance._willUpdate(); |
| 1928 |
}); |
| 1929 |
return instance; |
| 1930 |
} |
| 1931 |
function useVirtualizer(options) { |
| 1932 |
return useVirtualizerBase({ |
| 1933 |
observeElementRect, |
| 1934 |
observeElementOffset, |
| 1935 |
scrollToFn: elementScroll, |
| 1936 |
...options |
| 1937 |
}); |
| 1938 |
} |
| 1939 |
|
| 1940 |
//#endregion |
| 1941 |
//#region packages/packages/core/editor-global-classes/src/hooks/use-ordered-classes.ts |
| 1942 |
var useOrderedClasses = () => { |
| 1943 |
return (0, _elementor_store.__useSelector)(selectOrderedClasses); |
| 1944 |
}; |
| 1945 |
|
| 1946 |
//#endregion |
| 1947 |
//#region packages/packages/core/editor-global-classes/src/hooks/use-css-class-usage-by-id.ts |
| 1948 |
var EMPTY_CLASS_USAGE = { |
| 1949 |
total: 0, |
| 1950 |
content: [] |
| 1951 |
}; |
| 1952 |
var useCssClassUsageByID = (id) => { |
| 1953 |
const { data, ...rest } = useCssClassUsage(); |
| 1954 |
const classData = data?.[id] ?? EMPTY_CLASS_USAGE; |
| 1955 |
return { |
| 1956 |
...rest, |
| 1957 |
data: classData |
| 1958 |
}; |
| 1959 |
}; |
| 1960 |
|
| 1961 |
//#endregion |
| 1962 |
//#region packages/packages/core/editor-global-classes/src/components/css-class-usage/components/css-class-usage-popover.tsx |
| 1963 |
var iconMapper = { |
| 1964 |
"wp-post": { |
| 1965 |
label: (0, _wordpress_i18n.__)("Post", "elementor"), |
| 1966 |
icon: /* @__PURE__ */ react.createElement(_elementor_icons.PostTypeIcon, { fontSize: "inherit" }) |
| 1967 |
}, |
| 1968 |
"wp-page": { |
| 1969 |
label: (0, _wordpress_i18n.__)("Page", "elementor"), |
| 1970 |
icon: /* @__PURE__ */ react.createElement(_elementor_icons.PagesIcon, { fontSize: "inherit" }) |
| 1971 |
}, |
| 1972 |
popup: { |
| 1973 |
label: (0, _wordpress_i18n.__)("Popup", "elementor"), |
| 1974 |
icon: /* @__PURE__ */ react.createElement(_elementor_icons.PopupTemplateIcon, { fontSize: "inherit" }) |
| 1975 |
}, |
| 1976 |
header: { |
| 1977 |
label: (0, _wordpress_i18n.__)("Header", "elementor"), |
| 1978 |
icon: /* @__PURE__ */ react.createElement(_elementor_icons.HeaderTemplateIcon, { fontSize: "inherit" }) |
| 1979 |
}, |
| 1980 |
footer: { |
| 1981 |
label: (0, _wordpress_i18n.__)("Footer", "elementor"), |
| 1982 |
icon: /* @__PURE__ */ react.createElement(_elementor_icons.FooterTemplateIcon, { fontSize: "inherit" }) |
| 1983 |
} |
| 1984 |
}; |
| 1985 |
var CssClassUsagePopover = ({ cssClassID, onClose }) => { |
| 1986 |
const { data: classUsage } = useCssClassUsageByID(cssClassID); |
| 1987 |
const onNavigate = (0, _elementor_editor_documents.__useOpenDocumentInNewTab)(); |
| 1988 |
const cssClassUsageRecords = classUsage?.content.map(({ title, elements, pageId, type }) => ({ |
| 1989 |
type: "item", |
| 1990 |
value: pageId, |
| 1991 |
label: title, |
| 1992 |
secondaryText: elements.length.toString(), |
| 1993 |
docType: type |
| 1994 |
})) ?? []; |
| 1995 |
const handleSelect = (value) => { |
| 1996 |
onNavigate(+value); |
| 1997 |
trackGlobalClasses({ |
| 1998 |
event: "classUsageLocate", |
| 1999 |
classId: cssClassID |
| 2000 |
}); |
| 2001 |
}; |
| 2002 |
return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_editor_ui.PopoverHeader, { |
| 2003 |
icon: /* @__PURE__ */ react.createElement(_elementor_icons.CurrentLocationIcon, { fontSize: "tiny" }), |
| 2004 |
title: /* @__PURE__ */ react.createElement(_elementor_ui.Stack, { |
| 2005 |
flexDirection: "row", |
| 2006 |
gap: 1, |
| 2007 |
alignItems: "center" |
| 2008 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Box, { "aria-label": "header-title" }, (0, _wordpress_i18n.__)("Locator", "elementor")), /* @__PURE__ */ react.createElement(_elementor_ui.Box, null, /* @__PURE__ */ react.createElement(_elementor_ui.Chip, { |
| 2009 |
sx: { lineHeight: 1 }, |
| 2010 |
size: "tiny", |
| 2011 |
label: classUsage.total |
| 2012 |
}))), |
| 2013 |
onClose |
| 2014 |
}), /* @__PURE__ */ react.createElement(_elementor_ui.Divider, null), /* @__PURE__ */ react.createElement(_elementor_editor_ui.PopoverBody, { width: 300 }, /* @__PURE__ */ react.createElement(_elementor_editor_ui.PopoverMenuList, { |
| 2015 |
onSelect: handleSelect, |
| 2016 |
items: cssClassUsageRecords, |
| 2017 |
onClose: () => {}, |
| 2018 |
menuListTemplate: StyledCssClassUsageItem, |
| 2019 |
menuItemContentTemplate: (cssClassUsageRecord) => /* @__PURE__ */ react.createElement(_elementor_ui.Stack, { |
| 2020 |
flexDirection: "row", |
| 2021 |
flex: 1, |
| 2022 |
alignItems: "center" |
| 2023 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Box, { |
| 2024 |
display: "flex", |
| 2025 |
sx: { pr: 1 } |
| 2026 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Tooltip, { |
| 2027 |
disableInteractive: true, |
| 2028 |
title: iconMapper?.[cssClassUsageRecord.docType]?.label ?? cssClassUsageRecord.docType, |
| 2029 |
placement: "top" |
| 2030 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Icon, { fontSize: "small" }, iconMapper?.[cssClassUsageRecord.docType]?.icon || /* @__PURE__ */ react.createElement(_elementor_icons.PagesIcon, { fontSize: "inherit" })))), /* @__PURE__ */ react.createElement(_elementor_ui.Box, { |
| 2031 |
sx: { |
| 2032 |
pr: .5, |
| 2033 |
maxWidth: "173px" |
| 2034 |
}, |
| 2035 |
display: "flex" |
| 2036 |
}, /* @__PURE__ */ react.createElement(_elementor_editor_ui.EllipsisWithTooltip, { |
| 2037 |
title: cssClassUsageRecord.label, |
| 2038 |
as: _elementor_ui.Typography, |
| 2039 |
variant: "caption", |
| 2040 |
maxWidth: "173px", |
| 2041 |
sx: { lineHeight: 1 } |
| 2042 |
})), /* @__PURE__ */ react.createElement(_elementor_icons.ExternalLinkIcon, { |
| 2043 |
className: "hover-only-icon", |
| 2044 |
fontSize: "tiny" |
| 2045 |
}), /* @__PURE__ */ react.createElement(_elementor_ui.Chip, { |
| 2046 |
sx: { ml: "auto" }, |
| 2047 |
size: "tiny", |
| 2048 |
label: cssClassUsageRecord.secondaryText |
| 2049 |
})) |
| 2050 |
}))); |
| 2051 |
}; |
| 2052 |
var StyledCssClassUsageItem = (0, _elementor_ui.styled)(_elementor_ui.MenuList)(({ theme }) => ({ |
| 2053 |
"& > li": { |
| 2054 |
display: "flex", |
| 2055 |
cursor: "pointer", |
| 2056 |
height: 32, |
| 2057 |
width: "100%" |
| 2058 |
}, |
| 2059 |
"& > [role=\"option\"]": { |
| 2060 |
...theme.typography.caption, |
| 2061 |
lineHeight: "inherit", |
| 2062 |
padding: theme.spacing(.5, 1, .5, 2), |
| 2063 |
textOverflow: "ellipsis", |
| 2064 |
position: "absolute", |
| 2065 |
top: 0, |
| 2066 |
left: 0, |
| 2067 |
opacity: 1, |
| 2068 |
".hover-only-icon": { |
| 2069 |
color: theme.palette.text.disabled, |
| 2070 |
opacity: 0 |
| 2071 |
}, |
| 2072 |
"&:hover": { |
| 2073 |
borderRadius: theme.spacing(.5), |
| 2074 |
backgroundColor: theme.palette.action.hover, |
| 2075 |
".hover-only-icon": { |
| 2076 |
color: theme.palette.text.disabled, |
| 2077 |
opacity: 1 |
| 2078 |
} |
| 2079 |
} |
| 2080 |
}, |
| 2081 |
width: "100%", |
| 2082 |
position: "relative" |
| 2083 |
})); |
| 2084 |
|
| 2085 |
//#endregion |
| 2086 |
//#region packages/packages/core/editor-global-classes/src/components/css-class-usage/components/css-class-usage-trigger.tsx |
| 2087 |
var CssClassUsageTrigger = ({ id, onClick }) => { |
| 2088 |
const { data: { total }, isLoading } = useCssClassUsageByID(id); |
| 2089 |
const cssClassUsagePopover = (0, _elementor_ui.usePopupState)({ |
| 2090 |
variant: "popover", |
| 2091 |
popupId: "css-class-usage-popover" |
| 2092 |
}); |
| 2093 |
if (isLoading) return null; |
| 2094 |
const WrapperComponent = total !== 0 ? TooltipWrapper : InfoAlertMessage; |
| 2095 |
const handleMouseEnter = () => { |
| 2096 |
trackGlobalClasses({ |
| 2097 |
event: "classUsageHovered", |
| 2098 |
classId: id, |
| 2099 |
usage: total |
| 2100 |
}); |
| 2101 |
}; |
| 2102 |
const handleClick = (e) => { |
| 2103 |
if (total !== 0) { |
| 2104 |
(0, _elementor_ui.bindTrigger)(cssClassUsagePopover).onClick(e); |
| 2105 |
onClick(id); |
| 2106 |
trackGlobalClasses({ |
| 2107 |
event: "classUsageClicked", |
| 2108 |
classId: id |
| 2109 |
}); |
| 2110 |
} |
| 2111 |
}; |
| 2112 |
return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_ui.Box, { |
| 2113 |
position: "relative", |
| 2114 |
onMouseEnter: handleMouseEnter |
| 2115 |
}, /* @__PURE__ */ react.createElement(WrapperComponent, { total }, /* @__PURE__ */ react.createElement(CustomIconButton, { |
| 2116 |
disabled: total === 0, |
| 2117 |
size: "tiny", |
| 2118 |
...(0, _elementor_ui.bindTrigger)(cssClassUsagePopover), |
| 2119 |
onClick: handleClick |
| 2120 |
}, /* @__PURE__ */ react.createElement(_elementor_icons.CurrentLocationIcon, { fontSize: "tiny" })))), /* @__PURE__ */ react.createElement(_elementor_ui.Box, null, /* @__PURE__ */ react.createElement(_elementor_ui.Popover, { |
| 2121 |
anchorOrigin: { |
| 2122 |
vertical: "center", |
| 2123 |
horizontal: "right" |
| 2124 |
}, |
| 2125 |
transformOrigin: { |
| 2126 |
vertical: 15, |
| 2127 |
horizontal: -50 |
| 2128 |
}, |
| 2129 |
...(0, _elementor_ui.bindPopover)(cssClassUsagePopover), |
| 2130 |
onClose: () => { |
| 2131 |
(0, _elementor_ui.bindPopover)(cssClassUsagePopover).onClose(); |
| 2132 |
onClick(""); |
| 2133 |
} |
| 2134 |
}, /* @__PURE__ */ react.createElement(CssClassUsagePopover, { |
| 2135 |
onClose: cssClassUsagePopover.close, |
| 2136 |
"aria-label": "css-class-usage-popover", |
| 2137 |
cssClassID: id |
| 2138 |
})))); |
| 2139 |
}; |
| 2140 |
var CustomIconButton = (0, _elementor_ui.styled)(_elementor_ui.IconButton)(({ theme }) => ({ |
| 2141 |
"&.Mui-disabled": { |
| 2142 |
pointerEvents: "auto", |
| 2143 |
"&:hover": { color: theme.palette.action.disabled } |
| 2144 |
}, |
| 2145 |
height: "22px", |
| 2146 |
width: "22px" |
| 2147 |
})); |
| 2148 |
var TooltipWrapper = ({ children, total }) => /* @__PURE__ */ react.createElement(_elementor_ui.Tooltip, { |
| 2149 |
disableInteractive: true, |
| 2150 |
placement: "top", |
| 2151 |
title: `${(0, _wordpress_i18n.__)("Show {{number}} {{locations}}", "elementor").replace("{{number}}", total.toString()).replace("{{locations}}", total === 1 ? (0, _wordpress_i18n.__)("location", "elementor") : (0, _wordpress_i18n.__)("locations", "elementor"))}` |
| 2152 |
}, /* @__PURE__ */ react.createElement("span", null, children)); |
| 2153 |
var InfoAlertMessage = ({ children }) => /* @__PURE__ */ react.createElement(_elementor_ui.Infotip, { |
| 2154 |
disableInteractive: true, |
| 2155 |
placement: "top", |
| 2156 |
color: "secondary", |
| 2157 |
content: /* @__PURE__ */ react.createElement(_elementor_editor_ui.InfoAlert, { sx: { mt: 1 } }, (0, _wordpress_i18n.__)("This class isn’t being used yet.", "elementor")) |
| 2158 |
}, /* @__PURE__ */ react.createElement("span", null, children)); |
| 2159 |
|
| 2160 |
//#endregion |
| 2161 |
//#region packages/packages/core/editor-global-classes/src/components/class-manager/delete-confirmation-dialog.tsx |
| 2162 |
var context = (0, react.createContext)(null); |
| 2163 |
var DeleteConfirmationProvider = ({ children }) => { |
| 2164 |
const [dialogProps, setDialogProps] = (0, react.useState)(null); |
| 2165 |
const openDialog = (props) => { |
| 2166 |
setDialogProps(props); |
| 2167 |
}; |
| 2168 |
const closeDialog = () => { |
| 2169 |
setDialogProps(null); |
| 2170 |
}; |
| 2171 |
return /* @__PURE__ */ react.createElement(context.Provider, { value: { |
| 2172 |
openDialog, |
| 2173 |
closeDialog, |
| 2174 |
dialogProps |
| 2175 |
} }, children, !!dialogProps && /* @__PURE__ */ react.createElement(DeleteClassDialog, { ...dialogProps })); |
| 2176 |
}; |
| 2177 |
var DeleteClassDialog = ({ label, id }) => { |
| 2178 |
const { closeDialog } = useDeleteConfirmation(); |
| 2179 |
const { data: { total, content } } = useCssClassUsageByID(id); |
| 2180 |
const handleConfirm = () => { |
| 2181 |
closeDialog(); |
| 2182 |
deleteClass(id); |
| 2183 |
}; |
| 2184 |
const text = total && content.length ? (0, _wordpress_i18n.__)("Will permanently remove it from your project and may affect the design across all elements using it. Used %1 times across %2 pages. This action cannot be undone.", "elementor").replace("%1", total.toString()).replace("%2", content.length.toString()) : (0, _wordpress_i18n.__)("Will permanently remove it from your project and may affect the design across all elements using it. This action cannot be undone.", "elementor"); |
| 2185 |
return /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog, { |
| 2186 |
open: true, |
| 2187 |
onClose: closeDialog |
| 2188 |
}, /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.Title, null, (0, _wordpress_i18n.__)("Delete this class?", "elementor")), /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.Content, null, /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.ContentText, null, (0, _wordpress_i18n.__)("Deleting", "elementor"), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 2189 |
variant: "subtitle2", |
| 2190 |
component: "span" |
| 2191 |
}, "\xA0", label, "\xA0"), text)), /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.Actions, { |
| 2192 |
onClose: closeDialog, |
| 2193 |
onConfirm: handleConfirm |
| 2194 |
})); |
| 2195 |
}; |
| 2196 |
var useDeleteConfirmation = () => { |
| 2197 |
const contextValue = (0, react.useContext)(context); |
| 2198 |
if (!contextValue) throw new Error("useDeleteConfirmation must be used within a DeleteConfirmationProvider"); |
| 2199 |
return contextValue; |
| 2200 |
}; |
| 2201 |
|
| 2202 |
//#endregion |
| 2203 |
//#region packages/packages/core/editor-global-classes/src/components/class-manager/sortable.tsx |
| 2204 |
var SortableProvider = (props) => /* @__PURE__ */ react.createElement(_elementor_ui.UnstableSortableProvider, { |
| 2205 |
restrictAxis: true, |
| 2206 |
variant: "static", |
| 2207 |
dragPlaceholderStyle: { visibility: "hidden" }, |
| 2208 |
...props |
| 2209 |
}); |
| 2210 |
var SortableTrigger = (props) => /* @__PURE__ */ react.createElement(StyledSortableTrigger, { |
| 2211 |
...props, |
| 2212 |
role: "button", |
| 2213 |
className: "class-item-sortable-trigger", |
| 2214 |
"aria-label": "sort" |
| 2215 |
}, /* @__PURE__ */ react.createElement(_elementor_icons.GripVerticalIcon, { fontSize: "tiny" })); |
| 2216 |
var SortableItem = ({ children, id, style, ...props }) => { |
| 2217 |
return /* @__PURE__ */ react.createElement(_elementor_ui.UnstableSortableItem, { |
| 2218 |
...props, |
| 2219 |
id, |
| 2220 |
render: ({ itemProps, isDragged, triggerProps, itemStyle, triggerStyle, dropIndicationStyle, showDropIndication, isDragOverlay, isDragPlaceholder }) => { |
| 2221 |
return /* @__PURE__ */ react.createElement(_elementor_ui.Box, { |
| 2222 |
...itemProps, |
| 2223 |
style: { |
| 2224 |
...itemStyle, |
| 2225 |
...!isDragOverlay ? style : null |
| 2226 |
}, |
| 2227 |
component: "li", |
| 2228 |
role: "listitem", |
| 2229 |
sx: { backgroundColor: isDragOverlay ? "background.paper" : void 0 } |
| 2230 |
}, children({ |
| 2231 |
itemProps, |
| 2232 |
isDragged, |
| 2233 |
triggerProps, |
| 2234 |
itemStyle, |
| 2235 |
triggerStyle, |
| 2236 |
isDragPlaceholder |
| 2237 |
}), showDropIndication && /* @__PURE__ */ react.createElement(SortableItemIndicator, { style: dropIndicationStyle })); |
| 2238 |
} |
| 2239 |
}); |
| 2240 |
}; |
| 2241 |
var StyledSortableTrigger = (0, _elementor_ui.styled)("div")(({ theme }) => ({ |
| 2242 |
position: "absolute", |
| 2243 |
left: 0, |
| 2244 |
top: "50%", |
| 2245 |
transform: `translate( -${theme.spacing(1.5)}, -50% )`, |
| 2246 |
color: theme.palette.action.active |
| 2247 |
})); |
| 2248 |
var SortableItemIndicator = (0, _elementor_ui.styled)(_elementor_ui.Box)` |
| 2249 |
width: 100%; |
| 2250 |
height: 1px; |
| 2251 |
background-color: ${({ theme }) => theme.palette.text.primary}; |
| 2252 |
`; |
| 2253 |
|
| 2254 |
//#endregion |
| 2255 |
//#region packages/packages/core/editor-global-classes/src/components/class-manager/class-item.tsx |
| 2256 |
var ClassItem = ({ id, label, renameClass, selected, disabled, sortableTriggerProps, showSortIndicator, syncToV3, onToggleSync }) => { |
| 2257 |
const itemRef = (0, react.useRef)(null); |
| 2258 |
const { ref: editableRef, openEditMode, isEditing, error, getProps: getEditableProps } = (0, _elementor_editor_ui.useEditable)({ |
| 2259 |
value: label, |
| 2260 |
onSubmit: renameClass, |
| 2261 |
validation: validateLabel |
| 2262 |
}); |
| 2263 |
const [selectedCssUsage, setSelectedCssUsage] = (0, react.useState)(""); |
| 2264 |
const { openDialog } = useDeleteConfirmation(); |
| 2265 |
const popupState = (0, _elementor_ui.usePopupState)({ |
| 2266 |
variant: "popover", |
| 2267 |
disableAutoFocus: true |
| 2268 |
}); |
| 2269 |
const isSelected = (selectedCssUsage === id || selected || popupState.isOpen) && !disabled; |
| 2270 |
return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_ui.Stack, { p: 0 }, /* @__PURE__ */ react.createElement(_elementor_editor_ui.WarningInfotip, { |
| 2271 |
open: Boolean(error), |
| 2272 |
text: error ?? "", |
| 2273 |
placement: "bottom", |
| 2274 |
width: itemRef.current?.getBoundingClientRect().width, |
| 2275 |
offset: [0, -15] |
| 2276 |
}, /* @__PURE__ */ react.createElement(StyledListItemButton, { |
| 2277 |
ref: itemRef, |
| 2278 |
dense: true, |
| 2279 |
disableGutters: true, |
| 2280 |
showSortIndicator, |
| 2281 |
showActions: isSelected || isEditing, |
| 2282 |
shape: "rounded", |
| 2283 |
onDoubleClick: openEditMode, |
| 2284 |
selected: isSelected, |
| 2285 |
disabled, |
| 2286 |
focusVisibleClassName: "visible-class-item" |
| 2287 |
}, /* @__PURE__ */ react.createElement(SortableTrigger, { ...sortableTriggerProps }), /* @__PURE__ */ react.createElement(Indicator, { |
| 2288 |
isActive: isEditing, |
| 2289 |
isError: !!error |
| 2290 |
}, isEditing ? /* @__PURE__ */ react.createElement(_elementor_editor_ui.EditableField, { |
| 2291 |
ref: editableRef, |
| 2292 |
as: _elementor_ui.Typography, |
| 2293 |
variant: "caption", |
| 2294 |
...getEditableProps() |
| 2295 |
}) : /* @__PURE__ */ react.createElement(_elementor_editor_ui.EllipsisWithTooltip, { |
| 2296 |
title: label, |
| 2297 |
as: _elementor_ui.Typography, |
| 2298 |
variant: "caption" |
| 2299 |
})), /* @__PURE__ */ react.createElement(_elementor_ui.Box, { className: "class-item-locator" }, /* @__PURE__ */ react.createElement(CssClassUsageTrigger, { |
| 2300 |
id, |
| 2301 |
onClick: setSelectedCssUsage |
| 2302 |
})), /* @__PURE__ */ react.createElement(_elementor_ui.Tooltip, { |
| 2303 |
placement: "top", |
| 2304 |
className: "class-item-more-actions", |
| 2305 |
title: (0, _wordpress_i18n.__)("More actions", "elementor") |
| 2306 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.IconButton, { |
| 2307 |
size: "tiny", |
| 2308 |
...(0, _elementor_ui.bindTrigger)(popupState), |
| 2309 |
"aria-label": "More actions" |
| 2310 |
}, /* @__PURE__ */ react.createElement(_elementor_icons.DotsVerticalIcon, { fontSize: "tiny" })))))), /* @__PURE__ */ react.createElement(_elementor_ui.Menu, { |
| 2311 |
...(0, _elementor_ui.bindMenu)(popupState), |
| 2312 |
anchorOrigin: { |
| 2313 |
vertical: "bottom", |
| 2314 |
horizontal: "right" |
| 2315 |
}, |
| 2316 |
transformOrigin: { |
| 2317 |
vertical: "top", |
| 2318 |
horizontal: "right" |
| 2319 |
} |
| 2320 |
}, /* @__PURE__ */ react.createElement(_elementor_editor_ui.MenuListItem, { |
| 2321 |
sx: { minWidth: "160px" }, |
| 2322 |
onClick: () => { |
| 2323 |
popupState.close(); |
| 2324 |
openEditMode(); |
| 2325 |
} |
| 2326 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 2327 |
variant: "caption", |
| 2328 |
sx: { color: "text.primary" } |
| 2329 |
}, (0, _wordpress_i18n.__)("Rename", "elementor"))), onToggleSync && /* @__PURE__ */ react.createElement(_elementor_editor_ui.MenuListItem, { onClick: () => { |
| 2330 |
popupState.close(); |
| 2331 |
onToggleSync(id, !syncToV3); |
| 2332 |
} }, /* @__PURE__ */ react.createElement(_elementor_ui.Stack, { |
| 2333 |
direction: "row", |
| 2334 |
alignItems: "center", |
| 2335 |
gap: 1 |
| 2336 |
}, syncToV3 ? /* @__PURE__ */ react.createElement(_elementor_icons.RefreshOffIcon, { fontSize: "tiny" }) : /* @__PURE__ */ react.createElement(_elementor_icons.RefreshIcon, { fontSize: "tiny" }), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 2337 |
variant: "caption", |
| 2338 |
sx: { color: "text.primary" } |
| 2339 |
}, syncToV3 ? (0, _wordpress_i18n.__)("Stop syncing to Global Fonts", "elementor") : (0, _wordpress_i18n.__)("Sync to Global Fonts", "elementor")))), /* @__PURE__ */ react.createElement(_elementor_editor_ui.MenuListItem, { onClick: () => { |
| 2340 |
popupState.close(); |
| 2341 |
openDialog({ |
| 2342 |
id, |
| 2343 |
label |
| 2344 |
}); |
| 2345 |
} }, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 2346 |
variant: "caption", |
| 2347 |
sx: { color: "error.light" } |
| 2348 |
}, (0, _wordpress_i18n.__)("Delete", "elementor"))))); |
| 2349 |
}; |
| 2350 |
var StyledListItemButton = (0, _elementor_ui.styled)(_elementor_ui.ListItemButton, { shouldForwardProp: (prop) => !["showActions", "showSortIndicator"].includes(prop) })(({ showActions, showSortIndicator }) => ` |
| 2351 |
min-height: 36px; |
| 2352 |
|
| 2353 |
&.visible-class-item { |
| 2354 |
box-shadow: none !important; |
| 2355 |
} |
| 2356 |
|
| 2357 |
.class-item-locator { |
| 2358 |
visibility: hidden; |
| 2359 |
} |
| 2360 |
|
| 2361 |
.class-item-sortable-trigger { |
| 2362 |
visibility: ${showSortIndicator && showActions ? "visible" : "hidden"}; |
| 2363 |
} |
| 2364 |
|
| 2365 |
&:hover:not(:disabled) { |
| 2366 |
.class-item-locator { |
| 2367 |
visibility: visible; |
| 2368 |
} |
| 2369 |
|
| 2370 |
.class-item-sortable-trigger { |
| 2371 |
visibility: ${showSortIndicator ? "visible" : "hidden"}; |
| 2372 |
} |
| 2373 |
} |
| 2374 |
`); |
| 2375 |
var Indicator = (0, _elementor_ui.styled)(_elementor_ui.Box, { shouldForwardProp: (prop) => !["isActive", "isError"].includes(prop) })(({ theme, isActive, isError }) => ({ |
| 2376 |
display: "flex", |
| 2377 |
width: "100%", |
| 2378 |
flexGrow: 1, |
| 2379 |
borderRadius: theme.spacing(.5), |
| 2380 |
border: getIndicatorBorder({ |
| 2381 |
isActive, |
| 2382 |
isError, |
| 2383 |
theme |
| 2384 |
}), |
| 2385 |
padding: `0 ${theme.spacing(1)}`, |
| 2386 |
marginLeft: isActive ? theme.spacing(1) : 0, |
| 2387 |
minWidth: 0 |
| 2388 |
})); |
| 2389 |
var getIndicatorBorder = ({ isActive, isError, theme }) => { |
| 2390 |
if (isError) return `2px solid ${theme.palette.error.main}`; |
| 2391 |
if (isActive) return `2px solid ${theme.palette.secondary.main}`; |
| 2392 |
return "none"; |
| 2393 |
}; |
| 2394 |
var validateLabel = (newLabel) => { |
| 2395 |
const result = (0, _elementor_editor_styles_repository.validateStyleLabel)(newLabel, "rename"); |
| 2396 |
if (result.isValid) return null; |
| 2397 |
return result.errorMessage; |
| 2398 |
}; |
| 2399 |
|
| 2400 |
//#endregion |
| 2401 |
//#region packages/packages/core/editor-global-classes/src/components/class-manager/not-found.tsx |
| 2402 |
var getNotFoundType = (searchValue, filters, filteredClasses) => { |
| 2403 |
const searchNotFound = filteredClasses.length <= 0 && searchValue.length > 1; |
| 2404 |
const filterNotFound = filters && filters.length === 0; |
| 2405 |
if (searchNotFound && filterNotFound) return "filterAndSearch"; |
| 2406 |
if (searchNotFound) return "search"; |
| 2407 |
if (filterNotFound) return "filter"; |
| 2408 |
}; |
| 2409 |
var notFound = { |
| 2410 |
filterAndSearch: { |
| 2411 |
mainText: (0, _wordpress_i18n.__)("Sorry, nothing matched.", "elementor"), |
| 2412 |
sceneryText: (0, _wordpress_i18n.__)("Try something else.", "elementor"), |
| 2413 |
icon: /* @__PURE__ */ react.createElement(_elementor_icons.PhotoIcon, { |
| 2414 |
color: "inherit", |
| 2415 |
fontSize: "large" |
| 2416 |
}) |
| 2417 |
}, |
| 2418 |
search: { |
| 2419 |
mainText: (0, _wordpress_i18n.__)("Sorry, nothing matched", "elementor"), |
| 2420 |
sceneryText: (0, _wordpress_i18n.__)("Clear your input and try something else.", "elementor"), |
| 2421 |
icon: /* @__PURE__ */ react.createElement(_elementor_icons.PhotoIcon, { |
| 2422 |
color: "inherit", |
| 2423 |
fontSize: "large" |
| 2424 |
}) |
| 2425 |
}, |
| 2426 |
filter: { |
| 2427 |
mainText: (0, _wordpress_i18n.__)("Sorry, nothing matched that search.", "elementor"), |
| 2428 |
sceneryText: (0, _wordpress_i18n.__)("Clear the filters and try something else.", "elementor"), |
| 2429 |
icon: /* @__PURE__ */ react.createElement(_elementor_icons.ColorSwatchIcon, { |
| 2430 |
color: "inherit", |
| 2431 |
fontSize: "large" |
| 2432 |
}) |
| 2433 |
} |
| 2434 |
}; |
| 2435 |
var NotFound = ({ notFoundType }) => { |
| 2436 |
const { search: { onClearSearch, inputValue }, filters: { onClearFilter } } = useSearchAndFilters(); |
| 2437 |
switch (notFoundType) { |
| 2438 |
case "filter": return /* @__PURE__ */ react.createElement(NotFoundLayout, { |
| 2439 |
...notFound.filter, |
| 2440 |
onClear: onClearFilter |
| 2441 |
}); |
| 2442 |
case "search": return /* @__PURE__ */ react.createElement(NotFoundLayout, { |
| 2443 |
...notFound.search, |
| 2444 |
searchValue: inputValue, |
| 2445 |
onClear: onClearSearch |
| 2446 |
}); |
| 2447 |
case "filterAndSearch": return /* @__PURE__ */ react.createElement(NotFoundLayout, { |
| 2448 |
...notFound.filterAndSearch, |
| 2449 |
onClear: () => { |
| 2450 |
onClearFilter(); |
| 2451 |
onClearSearch(); |
| 2452 |
} |
| 2453 |
}); |
| 2454 |
} |
| 2455 |
}; |
| 2456 |
var NotFoundLayout = ({ onClear, searchValue, mainText, sceneryText, icon }) => /* @__PURE__ */ react.createElement(_elementor_ui.Stack, { |
| 2457 |
color: "text.secondary", |
| 2458 |
pt: 5, |
| 2459 |
alignItems: "center", |
| 2460 |
gap: 1, |
| 2461 |
overflow: "hidden", |
| 2462 |
justifySelf: "center" |
| 2463 |
}, icon, /* @__PURE__ */ react.createElement(_elementor_ui.Box, { sx: { width: "100%" } }, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 2464 |
align: "center", |
| 2465 |
variant: "subtitle2", |
| 2466 |
color: "inherit" |
| 2467 |
}, mainText), searchValue && /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 2468 |
variant: "subtitle2", |
| 2469 |
color: "inherit", |
| 2470 |
sx: { |
| 2471 |
display: "flex", |
| 2472 |
width: "100%", |
| 2473 |
justifyContent: "center" |
| 2474 |
} |
| 2475 |
}, /* @__PURE__ */ react.createElement("span", null, "“"), /* @__PURE__ */ react.createElement("span", { style: { |
| 2476 |
maxWidth: "80%", |
| 2477 |
overflow: "hidden", |
| 2478 |
textOverflow: "ellipsis" |
| 2479 |
} }, searchValue), /* @__PURE__ */ react.createElement("span", null, "”."))), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 2480 |
align: "center", |
| 2481 |
variant: "caption", |
| 2482 |
color: "inherit" |
| 2483 |
}, sceneryText), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 2484 |
align: "center", |
| 2485 |
variant: "caption", |
| 2486 |
color: "inherit" |
| 2487 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Link, { |
| 2488 |
color: "secondary", |
| 2489 |
variant: "caption", |
| 2490 |
component: "button", |
| 2491 |
onClick: onClear |
| 2492 |
}, (0, _wordpress_i18n.__)("Clear & try again", "elementor")))); |
| 2493 |
|
| 2494 |
//#endregion |
| 2495 |
//#region packages/packages/core/editor-global-classes/src/components/class-manager/global-classes-list.tsx |
| 2496 |
var ROW_HEIGHT = 40; |
| 2497 |
var OVERSCAN = 6; |
| 2498 |
var GlobalClassesList = ({ disabled, scrollElement, onStopSyncRequest, onStartSyncRequest }) => { |
| 2499 |
const { search: { debouncedValue: searchValue } } = useSearchAndFilters(); |
| 2500 |
const cssClasses = useOrderedClasses(); |
| 2501 |
const dispatch = (0, _elementor_store.__useDispatch)(); |
| 2502 |
const filters = useFilters(); |
| 2503 |
const [draggedItemId, setDraggedItemId] = (0, react.useState)(null); |
| 2504 |
const [loading, setLoading] = (0, react.useState)({}); |
| 2505 |
const addLoadingClass = (classId) => setLoading((prev) => ({ |
| 2506 |
...prev, |
| 2507 |
[classId]: true |
| 2508 |
})); |
| 2509 |
const removeLoadingClass = (classId) => setLoading((prev) => { |
| 2510 |
const { [classId]: _, ...rest } = prev; |
| 2511 |
return rest; |
| 2512 |
}); |
| 2513 |
const draggedItemLabel = cssClasses.find((cssClass) => cssClass.id === draggedItemId)?.label ?? ""; |
| 2514 |
const [classesOrder, reorderClasses] = useReorder(draggedItemId, setDraggedItemId, draggedItemLabel ?? ""); |
| 2515 |
const filteredCssClasses = useFilteredCssClasses(); |
| 2516 |
const virtualizer = useVirtualizer({ |
| 2517 |
count: filteredCssClasses.length, |
| 2518 |
getScrollElement: () => scrollElement ?? null, |
| 2519 |
estimateSize: () => ROW_HEIGHT, |
| 2520 |
overscan: OVERSCAN, |
| 2521 |
getItemKey: (index) => filteredCssClasses[index].id, |
| 2522 |
rangeExtractor: (range) => { |
| 2523 |
const indices = new Set(defaultRangeExtractor(range)); |
| 2524 |
if (draggedItemId) { |
| 2525 |
const draggedItemIndex = filteredCssClasses.findIndex((cssClass) => cssClass.id === draggedItemId); |
| 2526 |
if (draggedItemIndex >= 0) indices.add(draggedItemIndex); |
| 2527 |
} |
| 2528 |
return [...indices].sort((a, b) => a - b); |
| 2529 |
} |
| 2530 |
}); |
| 2531 |
(0, react.useEffect)(() => { |
| 2532 |
const handler = (event) => { |
| 2533 |
if (event.key === "z" && (event.ctrlKey || event.metaKey)) { |
| 2534 |
event.stopImmediatePropagation(); |
| 2535 |
event.preventDefault(); |
| 2536 |
if (event.shiftKey) { |
| 2537 |
dispatch(slice.actions.redo()); |
| 2538 |
return; |
| 2539 |
} |
| 2540 |
dispatch(slice.actions.undo()); |
| 2541 |
} |
| 2542 |
}; |
| 2543 |
window.addEventListener("keydown", handler, { capture: true }); |
| 2544 |
return () => window.removeEventListener("keydown", handler); |
| 2545 |
}, [dispatch]); |
| 2546 |
if (!cssClasses?.length) return /* @__PURE__ */ react.createElement(EmptyState, null); |
| 2547 |
const notFoundType = getNotFoundType(searchValue, filters, filteredCssClasses); |
| 2548 |
if (notFoundType) return /* @__PURE__ */ react.createElement(NotFound, { notFoundType }); |
| 2549 |
const isFiltersApplied = filters?.length || searchValue; |
| 2550 |
const allowSorting = filteredCssClasses.length > 1 && !isFiltersApplied; |
| 2551 |
return /* @__PURE__ */ react.createElement(DeleteConfirmationProvider, null, /* @__PURE__ */ react.createElement(_elementor_ui.List, { sx: { |
| 2552 |
position: "relative", |
| 2553 |
display: "block", |
| 2554 |
height: virtualizer.getTotalSize(), |
| 2555 |
padding: 0 |
| 2556 |
} }, /* @__PURE__ */ react.createElement(SortableProvider, { |
| 2557 |
value: classesOrder, |
| 2558 |
onChange: reorderClasses, |
| 2559 |
onDragStart: (event) => setDraggedItemId(event.active.id), |
| 2560 |
onDragEnd: () => setDraggedItemId(null), |
| 2561 |
onDragCancel: () => setDraggedItemId(null), |
| 2562 |
disableDragOverlay: !allowSorting |
| 2563 |
}, virtualizer.getVirtualItems().map((virtualRow) => { |
| 2564 |
const cssClass = filteredCssClasses[virtualRow.index]; |
| 2565 |
return /* @__PURE__ */ react.createElement(SortableItem, { |
| 2566 |
key: virtualRow.key, |
| 2567 |
id: cssClass.id, |
| 2568 |
style: { |
| 2569 |
position: "absolute", |
| 2570 |
top: virtualRow.start, |
| 2571 |
left: 0, |
| 2572 |
width: "100%" |
| 2573 |
} |
| 2574 |
}, ({ isDragged, isDragPlaceholder, triggerProps, triggerStyle }) => /* @__PURE__ */ react.createElement(ClassItem, { |
| 2575 |
id: cssClass.id, |
| 2576 |
label: cssClass.label, |
| 2577 |
renameClass: async (newLabel) => { |
| 2578 |
addLoadingClass(cssClass.id); |
| 2579 |
try { |
| 2580 |
trackGlobalClasses({ |
| 2581 |
event: "classRenamed", |
| 2582 |
classId: cssClass.id, |
| 2583 |
oldValue: cssClass.label, |
| 2584 |
newValue: newLabel, |
| 2585 |
source: "class-manager" |
| 2586 |
}); |
| 2587 |
await loadExistingClasses([cssClass.id]); |
| 2588 |
dispatch(slice.actions.update({ style: { |
| 2589 |
id: cssClass.id, |
| 2590 |
label: newLabel |
| 2591 |
} })); |
| 2592 |
} finally { |
| 2593 |
removeLoadingClass(cssClass.id); |
| 2594 |
} |
| 2595 |
}, |
| 2596 |
selected: isDragged, |
| 2597 |
disabled: disabled || isDragPlaceholder || loading[cssClass.id], |
| 2598 |
sortableTriggerProps: { |
| 2599 |
...triggerProps, |
| 2600 |
style: triggerStyle |
| 2601 |
}, |
| 2602 |
showSortIndicator: allowSorting, |
| 2603 |
syncToV3: cssClass.sync_to_v3, |
| 2604 |
onToggleSync: (id, newValue) => { |
| 2605 |
if (!newValue && onStopSyncRequest) onStopSyncRequest(id); |
| 2606 |
else if (newValue && onStartSyncRequest) onStartSyncRequest(id); |
| 2607 |
else dispatch(slice.actions.update({ style: { |
| 2608 |
id, |
| 2609 |
sync_to_v3: newValue |
| 2610 |
} })); |
| 2611 |
} |
| 2612 |
})); |
| 2613 |
})))); |
| 2614 |
}; |
| 2615 |
var EmptyState = () => /* @__PURE__ */ react.createElement(_elementor_ui.Stack, { |
| 2616 |
alignItems: "center", |
| 2617 |
gap: 1.5, |
| 2618 |
pt: 10, |
| 2619 |
px: .5, |
| 2620 |
maxWidth: "260px", |
| 2621 |
margin: "auto" |
| 2622 |
}, /* @__PURE__ */ react.createElement(FlippedColorSwatchIcon, { fontSize: "large" }), /* @__PURE__ */ react.createElement(StyledHeader, { |
| 2623 |
variant: "subtitle2", |
| 2624 |
component: "h2", |
| 2625 |
color: "text.secondary" |
| 2626 |
}, (0, _wordpress_i18n.__)("There are no global classes yet.", "elementor")), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 2627 |
align: "center", |
| 2628 |
variant: "caption", |
| 2629 |
color: "text.secondary" |
| 2630 |
}, (0, _wordpress_i18n.__)("CSS classes created in the editor panel will appear here. Once they are available, you can arrange their hierarchy, rename them, or delete them as needed.", "elementor"))); |
| 2631 |
var StyledHeader = (0, _elementor_ui.styled)(_elementor_ui.Typography)(({ theme, variant }) => ({ "&.MuiTypography-root": { ...theme.typography[variant] } })); |
| 2632 |
var useReorder = (draggedItemId, setDraggedItemId, draggedItemLabel) => { |
| 2633 |
const dispatch = (0, _elementor_store.__useDispatch)(); |
| 2634 |
const order = useClassesOrder(); |
| 2635 |
const reorder = (newIds) => { |
| 2636 |
dispatch(slice.actions.setOrder(newIds)); |
| 2637 |
if (draggedItemId) { |
| 2638 |
trackGlobalClasses({ |
| 2639 |
event: "classManagerReorder", |
| 2640 |
classId: draggedItemId, |
| 2641 |
classTitle: draggedItemLabel |
| 2642 |
}); |
| 2643 |
setDraggedItemId(null); |
| 2644 |
} |
| 2645 |
}; |
| 2646 |
return [order, reorder]; |
| 2647 |
}; |
| 2648 |
var useFilteredCssClasses = () => { |
| 2649 |
const cssClasses = useOrderedClasses(); |
| 2650 |
const { search: { debouncedValue: searchValue } } = useSearchAndFilters(); |
| 2651 |
const filters = useFilters(); |
| 2652 |
const lowercaseLabels = (0, react.useMemo)(() => cssClasses.map((cssClass) => ({ |
| 2653 |
...cssClass, |
| 2654 |
lowerLabel: cssClass.label.toLowerCase() |
| 2655 |
})), [cssClasses]); |
| 2656 |
const filteredClasses = (0, react.useMemo)(() => { |
| 2657 |
const normalizedSearch = searchValue.replace(/[^a-zA-Z0-9_-]/g, "").toLowerCase(); |
| 2658 |
if (normalizedSearch.length > 1) return lowercaseLabels.filter((cssClass) => cssClass.lowerLabel.includes(normalizedSearch)); |
| 2659 |
return cssClasses; |
| 2660 |
}, [ |
| 2661 |
searchValue, |
| 2662 |
cssClasses, |
| 2663 |
lowercaseLabels |
| 2664 |
]); |
| 2665 |
return (0, react.useMemo)(() => { |
| 2666 |
if (filters && filters.length > 0) return filteredClasses.filter((cssClass) => filters.includes(cssClass.id)); |
| 2667 |
return filteredClasses; |
| 2668 |
}, [filteredClasses, filters]); |
| 2669 |
}; |
| 2670 |
|
| 2671 |
//#endregion |
| 2672 |
//#region packages/packages/core/editor-global-classes/src/components/class-manager/panel-interactions.ts |
| 2673 |
function blockPanelInteractions() { |
| 2674 |
window.$e?.components?.get?.("panel")?.blockUserInteractions?.(); |
| 2675 |
} |
| 2676 |
function unblockPanelInteractions() { |
| 2677 |
window.$e?.components?.get?.("panel")?.unblockUserInteractions?.(); |
| 2678 |
} |
| 2679 |
|
| 2680 |
//#endregion |
| 2681 |
//#region packages/packages/core/editor-global-classes/src/components/class-manager/start-sync-to-v3-modal.tsx |
| 2682 |
var IMAGE_URL = "https://assets.elementor.com/packages/v1/images/class-manager-sync-modal.png"; |
| 2683 |
var StartSyncToV3Modal = ({ externalOpen, classId, onExternalClose, onConfirm } = {}) => { |
| 2684 |
const [shouldShowAgain, setShouldShowAgain] = (0, react.useState)(true); |
| 2685 |
const hasTrackedExposure = (0, react.useRef)(false); |
| 2686 |
(0, react.useEffect)(() => { |
| 2687 |
if (externalOpen && classId && !hasTrackedExposure.current) { |
| 2688 |
hasTrackedExposure.current = true; |
| 2689 |
trackGlobalClasses({ |
| 2690 |
event: "classSyncToV3PopupShown", |
| 2691 |
classId |
| 2692 |
}); |
| 2693 |
} |
| 2694 |
if (!externalOpen) hasTrackedExposure.current = false; |
| 2695 |
}, [externalOpen, classId]); |
| 2696 |
const handleClose = () => { |
| 2697 |
if (classId) trackGlobalClasses({ |
| 2698 |
event: "classSyncToV3PopupClick", |
| 2699 |
classId, |
| 2700 |
action: "cancel" |
| 2701 |
}); |
| 2702 |
onExternalClose?.(); |
| 2703 |
}; |
| 2704 |
const handleConfirm = () => { |
| 2705 |
if (classId) trackGlobalClasses({ |
| 2706 |
event: "classSyncToV3PopupClick", |
| 2707 |
classId, |
| 2708 |
action: "sync" |
| 2709 |
}); |
| 2710 |
onConfirm?.(); |
| 2711 |
onExternalClose?.(); |
| 2712 |
}; |
| 2713 |
return /* @__PURE__ */ react.createElement(_elementor_ui.Dialog, { |
| 2714 |
open: !!externalOpen, |
| 2715 |
onClose: handleClose, |
| 2716 |
maxWidth: "sm", |
| 2717 |
fullWidth: true |
| 2718 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.DialogContent, { sx: { p: 0 } }, /* @__PURE__ */ react.createElement(_elementor_ui.Box, { |
| 2719 |
component: "img", |
| 2720 |
src: IMAGE_URL, |
| 2721 |
alt: "", |
| 2722 |
sx: { |
| 2723 |
width: "100%", |
| 2724 |
display: "block" |
| 2725 |
} |
| 2726 |
}), /* @__PURE__ */ react.createElement(_elementor_ui.Box, { sx: { |
| 2727 |
px: 3, |
| 2728 |
pt: 4, |
| 2729 |
pb: 1 |
| 2730 |
} }, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { variant: "h6" }, (0, _wordpress_i18n.__)("Sync class to Global Fonts", "elementor")), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 2731 |
variant: "body2", |
| 2732 |
color: "secondary", |
| 2733 |
sx: { |
| 2734 |
mb: 2, |
| 2735 |
pt: 1 |
| 2736 |
} |
| 2737 |
}, (0, _wordpress_i18n.__)("Only typography settings supported in Global Fonts will be applied, including: font family, responsive font sizes, weight, text transform, decoration, line height, letter spacing, and word spacing. Changes made in the class will automatically apply to Global Fonts.", "elementor")))), /* @__PURE__ */ react.createElement(_elementor_ui.DialogActions, { sx: { |
| 2738 |
justifyContent: "space-between", |
| 2739 |
px: 3, |
| 2740 |
pb: 2 |
| 2741 |
} }, /* @__PURE__ */ react.createElement(_elementor_ui.FormControlLabel, { |
| 2742 |
control: /* @__PURE__ */ react.createElement(_elementor_ui.Checkbox, { |
| 2743 |
checked: !shouldShowAgain, |
| 2744 |
onChange: (e) => setShouldShowAgain(!e.target.checked) |
| 2745 |
}), |
| 2746 |
label: /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { |
| 2747 |
variant: "body2", |
| 2748 |
color: "secondary" |
| 2749 |
}, (0, _wordpress_i18n.__)("Don't show again", "elementor")) |
| 2750 |
}), /* @__PURE__ */ react.createElement(_elementor_ui.Box, { sx: { |
| 2751 |
display: "flex", |
| 2752 |
gap: 1 |
| 2753 |
} }, /* @__PURE__ */ react.createElement(_elementor_ui.Button, { |
| 2754 |
onClick: handleClose, |
| 2755 |
color: "secondary", |
| 2756 |
size: "small" |
| 2757 |
}, (0, _wordpress_i18n.__)("Cancel", "elementor")), /* @__PURE__ */ react.createElement(_elementor_ui.Button, { |
| 2758 |
onClick: handleConfirm, |
| 2759 |
variant: "contained", |
| 2760 |
size: "small" |
| 2761 |
}, (0, _wordpress_i18n.__)("Sync to Global Fonts", "elementor"))))); |
| 2762 |
}; |
| 2763 |
|
| 2764 |
//#endregion |
| 2765 |
//#region packages/packages/core/editor-global-classes/src/components/class-manager/class-manager-panel.tsx |
| 2766 |
var STOP_SYNC_MESSAGE_KEY = "stop-sync-class"; |
| 2767 |
function ClassManagerPanelEmbedded({ onRequestClose, onExposeCloseAttempt, isActive }) { |
| 2768 |
return /* @__PURE__ */ react.createElement(ClassManagerPanelContent, { |
| 2769 |
onRequestClose, |
| 2770 |
onExposeCloseAttempt, |
| 2771 |
isActive |
| 2772 |
}); |
| 2773 |
} |
| 2774 |
function ClassManagerPanelContent({ onRequestClose, onExposeCloseAttempt, isActive = true }) { |
| 2775 |
const isDirty = useDirtyState(); |
| 2776 |
const { open: openSaveChangesDialog, close: closeSaveChangesDialog, isOpen: isSaveChangesDialogOpen } = (0, _elementor_editor_ui.useDialog)(); |
| 2777 |
const [stopSyncConfirmation, setStopSyncConfirmation] = (0, react.useState)(null); |
| 2778 |
const [startSyncConfirmation, setStartSyncConfirmation] = (0, react.useState)(null); |
| 2779 |
const [isStopSyncSuppressed] = (0, _elementor_editor_current_user.useSuppressedMessage)(STOP_SYNC_MESSAGE_KEY); |
| 2780 |
const [scrollElement, setScrollElement] = (0, react.useState)(null); |
| 2781 |
const { mutateAsync: publish, isPending: isPublishing } = usePublish(); |
| 2782 |
const resetAndClosePanel = () => { |
| 2783 |
(0, _elementor_store.__dispatch)(slice.actions.resetToInitialState({ context: "frontend" })); |
| 2784 |
closeSaveChangesDialog(); |
| 2785 |
}; |
| 2786 |
const handleClosePanel = (0, react.useCallback)(() => { |
| 2787 |
if (isDirty) { |
| 2788 |
openSaveChangesDialog(); |
| 2789 |
return; |
| 2790 |
} |
| 2791 |
onRequestClose(); |
| 2792 |
}, [ |
| 2793 |
isDirty, |
| 2794 |
openSaveChangesDialog, |
| 2795 |
onRequestClose |
| 2796 |
]); |
| 2797 |
(0, react.useEffect)(() => { |
| 2798 |
if (!onExposeCloseAttempt) return; |
| 2799 |
onExposeCloseAttempt(() => handleClosePanel()); |
| 2800 |
return () => onExposeCloseAttempt(null); |
| 2801 |
}, [onExposeCloseAttempt, handleClosePanel]); |
| 2802 |
(0, react.useEffect)(() => { |
| 2803 |
blockPanelInteractions(); |
| 2804 |
return () => { |
| 2805 |
unblockPanelInteractions(); |
| 2806 |
}; |
| 2807 |
}, []); |
| 2808 |
const handleStopSync = (0, react.useCallback)(async (classId) => { |
| 2809 |
await loadExistingClasses([classId]); |
| 2810 |
(0, _elementor_store.__dispatch)(slice.actions.update({ style: { |
| 2811 |
id: classId, |
| 2812 |
sync_to_v3: false |
| 2813 |
} })); |
| 2814 |
trackGlobalClasses({ |
| 2815 |
event: "classSyncToV3", |
| 2816 |
classId, |
| 2817 |
action: "unsync" |
| 2818 |
}); |
| 2819 |
setStopSyncConfirmation(null); |
| 2820 |
}, []); |
| 2821 |
const handleStartSync = (0, react.useCallback)(async (classId) => { |
| 2822 |
await loadExistingClasses([classId]); |
| 2823 |
(0, _elementor_store.__dispatch)(slice.actions.update({ style: { |
| 2824 |
id: classId, |
| 2825 |
sync_to_v3: true |
| 2826 |
} })); |
| 2827 |
trackGlobalClasses({ |
| 2828 |
event: "classSyncToV3", |
| 2829 |
classId, |
| 2830 |
action: "sync" |
| 2831 |
}); |
| 2832 |
setStartSyncConfirmation(null); |
| 2833 |
}, []); |
| 2834 |
const handleStopSyncRequest = (0, react.useCallback)((classId) => { |
| 2835 |
if (!isStopSyncSuppressed) setStopSyncConfirmation(classId); |
| 2836 |
else handleStopSync(classId); |
| 2837 |
}, [isStopSyncSuppressed, handleStopSync]); |
| 2838 |
usePreventUnload(); |
| 2839 |
return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_ui.ErrorBoundary, { fallback: /* @__PURE__ */ react.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ react.createElement(SearchAndFilterProvider, null, /* @__PURE__ */ react.createElement(_elementor_ui.Stack, { |
| 2840 |
direction: "column", |
| 2841 |
sx: { |
| 2842 |
height: "100%", |
| 2843 |
width: "100%", |
| 2844 |
flex: 1, |
| 2845 |
minHeight: 0, |
| 2846 |
overflow: "hidden" |
| 2847 |
} |
| 2848 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Box, { |
| 2849 |
px: 2, |
| 2850 |
pb: 1 |
| 2851 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Stack, { |
| 2852 |
direction: "row", |
| 2853 |
alignItems: "center", |
| 2854 |
justifyContent: "space-between", |
| 2855 |
gap: .5, |
| 2856 |
sx: { pb: .5 } |
| 2857 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Box, { sx: { |
| 2858 |
flexGrow: 1, |
| 2859 |
minWidth: 0 |
| 2860 |
} }, /* @__PURE__ */ react.createElement(ClassManagerSearch, null)), /* @__PURE__ */ react.createElement(CssClassFilter, null), /* @__PURE__ */ react.createElement(TotalCssClassCounter, null)), /* @__PURE__ */ react.createElement(ActiveFilters, null)), /* @__PURE__ */ react.createElement(_elementor_ui.Divider, null), /* @__PURE__ */ react.createElement(_elementor_ui.Box, { |
| 2861 |
ref: setScrollElement, |
| 2862 |
px: 2, |
| 2863 |
sx: { |
| 2864 |
flexGrow: 1, |
| 2865 |
overflowY: "auto", |
| 2866 |
minHeight: 0 |
| 2867 |
} |
| 2868 |
}, /* @__PURE__ */ react.createElement(GlobalClassesList, { |
| 2869 |
disabled: isPublishing, |
| 2870 |
scrollElement, |
| 2871 |
onStopSyncRequest: handleStopSyncRequest, |
| 2872 |
onStartSyncRequest: (classId) => setStartSyncConfirmation(classId) |
| 2873 |
})), /* @__PURE__ */ react.createElement(_elementor_editor_panels.PanelFooter, null, /* @__PURE__ */ react.createElement(_elementor_ui.Button, { |
| 2874 |
fullWidth: true, |
| 2875 |
size: "small", |
| 2876 |
color: "global", |
| 2877 |
variant: "contained", |
| 2878 |
onClick: publish, |
| 2879 |
disabled: !isDirty, |
| 2880 |
loading: isPublishing |
| 2881 |
}, (0, _wordpress_i18n.__)("Save changes", "elementor")))))), isActive && /* @__PURE__ */ react.createElement(ClassManagerIntroduction, null), startSyncConfirmation && /* @__PURE__ */ react.createElement(StartSyncToV3Modal, { |
| 2882 |
externalOpen: true, |
| 2883 |
classId: startSyncConfirmation, |
| 2884 |
onExternalClose: () => setStartSyncConfirmation(null), |
| 2885 |
onConfirm: () => handleStartSync(startSyncConfirmation) |
| 2886 |
}), stopSyncConfirmation && /* @__PURE__ */ react.createElement(StopSyncConfirmationDialog, { |
| 2887 |
open: true, |
| 2888 |
onClose: () => setStopSyncConfirmation(null), |
| 2889 |
onConfirm: () => handleStopSync(stopSyncConfirmation) |
| 2890 |
}), isSaveChangesDialogOpen && /* @__PURE__ */ react.createElement(_elementor_editor_ui.SaveChangesDialog, null, /* @__PURE__ */ react.createElement(_elementor_ui.DialogHeader, { |
| 2891 |
onClose: closeSaveChangesDialog, |
| 2892 |
logo: false |
| 2893 |
}, /* @__PURE__ */ react.createElement(_elementor_editor_ui.SaveChangesDialog.Title, null, (0, _wordpress_i18n.__)("You have unsaved changes", "elementor"))), /* @__PURE__ */ react.createElement(_elementor_editor_ui.SaveChangesDialog.Content, null, /* @__PURE__ */ react.createElement(_elementor_editor_ui.SaveChangesDialog.ContentText, null, (0, _wordpress_i18n.__)("You have unsaved changes in the Class Manager.", "elementor")), /* @__PURE__ */ react.createElement(_elementor_editor_ui.SaveChangesDialog.ContentText, null, (0, _wordpress_i18n.__)("To avoid losing your updates, save your changes before leaving.", "elementor"))), /* @__PURE__ */ react.createElement(_elementor_editor_ui.SaveChangesDialog.Actions, { actions: { |
| 2894 |
discard: { |
| 2895 |
label: (0, _wordpress_i18n.__)("Discard", "elementor"), |
| 2896 |
action: () => { |
| 2897 |
resetAndClosePanel(); |
| 2898 |
} |
| 2899 |
}, |
| 2900 |
confirm: { |
| 2901 |
label: (0, _wordpress_i18n.__)("Save & Continue", "elementor"), |
| 2902 |
action: async () => { |
| 2903 |
await publish(); |
| 2904 |
closeSaveChangesDialog(); |
| 2905 |
onRequestClose(); |
| 2906 |
} |
| 2907 |
} |
| 2908 |
} }))); |
| 2909 |
} |
| 2910 |
var ErrorBoundaryFallback = () => /* @__PURE__ */ react.createElement(_elementor_ui.Box, { |
| 2911 |
role: "alert", |
| 2912 |
sx: { |
| 2913 |
minHeight: "100%", |
| 2914 |
p: 2 |
| 2915 |
} |
| 2916 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.Alert, { |
| 2917 |
severity: "error", |
| 2918 |
sx: { |
| 2919 |
mb: 2, |
| 2920 |
maxWidth: 400, |
| 2921 |
textAlign: "center" |
| 2922 |
} |
| 2923 |
}, /* @__PURE__ */ react.createElement("strong", null, (0, _wordpress_i18n.__)("Something went wrong", "elementor")))); |
| 2924 |
var usePreventUnload = () => { |
| 2925 |
const isDirty = useDirtyState(); |
| 2926 |
(0, react.useEffect)(() => { |
| 2927 |
const handleBeforeUnload = (event) => { |
| 2928 |
if (isDirty) event.preventDefault(); |
| 2929 |
}; |
| 2930 |
window.addEventListener("beforeunload", handleBeforeUnload); |
| 2931 |
return () => { |
| 2932 |
window.removeEventListener("beforeunload", handleBeforeUnload); |
| 2933 |
}; |
| 2934 |
}, [isDirty]); |
| 2935 |
}; |
| 2936 |
var usePublish = () => { |
| 2937 |
return (0, _elementor_query.useMutation)({ |
| 2938 |
mutationFn: () => saveGlobalClasses({ context: "frontend" }), |
| 2939 |
onSuccess: async () => { |
| 2940 |
(0, _elementor_editor_documents.setDocumentModifiedStatus)(false); |
| 2941 |
if (hasDeletedItems()) await onDelete(); |
| 2942 |
} |
| 2943 |
}); |
| 2944 |
}; |
| 2945 |
var TotalCssClassCounter = () => { |
| 2946 |
const filters = useFilters(); |
| 2947 |
const cssClasses = useClassesOrder(); |
| 2948 |
return /* @__PURE__ */ react.createElement(_elementor_ui.Chip, { |
| 2949 |
size: "small", |
| 2950 |
label: filters ? `${filters.length} / ${cssClasses?.length}` : cssClasses?.length |
| 2951 |
}); |
| 2952 |
}; |
| 2953 |
var StopSyncConfirmationDialog = ({ open, onClose, onConfirm }) => { |
| 2954 |
const [, suppressStopSyncMessage] = (0, _elementor_editor_current_user.useSuppressedMessage)(STOP_SYNC_MESSAGE_KEY); |
| 2955 |
return /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog, { |
| 2956 |
open, |
| 2957 |
onClose |
| 2958 |
}, /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.Title, { |
| 2959 |
icon: FlippedColorSwatchIcon, |
| 2960 |
iconColor: "primary" |
| 2961 |
}, (0, _wordpress_i18n.__)("Un-sync typography class", "elementor")), /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.Content, null, /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.ContentText, null, (0, _wordpress_i18n.__)("You're about to stop syncing a typography class to Global Fonts.", "elementor")), /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.ContentText, { sx: { mt: 1 } }, (0, _wordpress_i18n.__)("Note that if it's being used anywhere, the affected elements will inherit the default typography.", "elementor"))), /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.Actions, { |
| 2962 |
onClose, |
| 2963 |
onConfirm, |
| 2964 |
cancelLabel: (0, _wordpress_i18n.__)("Cancel", "elementor"), |
| 2965 |
confirmLabel: (0, _wordpress_i18n.__)("Got it", "elementor"), |
| 2966 |
color: "primary", |
| 2967 |
onSuppressMessage: suppressStopSyncMessage, |
| 2968 |
suppressLabel: (0, _wordpress_i18n.__)("Don't show again", "elementor") |
| 2969 |
})); |
| 2970 |
}; |
| 2971 |
|
| 2972 |
//#endregion |
| 2973 |
//#region packages/packages/core/editor-global-classes/src/capabilities.ts |
| 2974 |
var UPDATE_CLASS_CAPABILITY_KEY = "elementor_global_classes_update_class"; |
| 2975 |
var getCapabilities = () => { |
| 2976 |
return { |
| 2977 |
update: UPDATE_CLASS_CAPABILITY_KEY, |
| 2978 |
create: UPDATE_CLASS_CAPABILITY_KEY, |
| 2979 |
delete: UPDATE_CLASS_CAPABILITY_KEY, |
| 2980 |
updateProps: UPDATE_CLASS_CAPABILITY_KEY |
| 2981 |
}; |
| 2982 |
}; |
| 2983 |
|
| 2984 |
//#endregion |
| 2985 |
//#region packages/packages/core/editor-global-classes/src/global-classes-styles-provider.ts |
| 2986 |
var MAX_CLASSES = 1e3; |
| 2987 |
var GLOBAL_CLASSES_PROVIDER_KEY = "global-classes"; |
| 2988 |
var PREGENERATED_LINK_PATTERN = /^global-([0-9]+-)?(preview|frontend)-[a-zA-Z_-]+-css$/; |
| 2989 |
var globalClassesStylesProvider = (0, _elementor_editor_styles_repository.createStylesProvider)({ |
| 2990 |
key: GLOBAL_CLASSES_PROVIDER_KEY, |
| 2991 |
priority: 30, |
| 2992 |
limit: MAX_CLASSES, |
| 2993 |
isPregeneratedLink: ({ id }) => PREGENERATED_LINK_PATTERN.test(id), |
| 2994 |
labels: { |
| 2995 |
singular: (0, _wordpress_i18n.__)("class", "elementor"), |
| 2996 |
plural: (0, _wordpress_i18n.__)("classes", "elementor") |
| 2997 |
}, |
| 2998 |
subscribe: (cb) => subscribeWithStates(cb), |
| 2999 |
capabilities: getCapabilities(), |
| 3000 |
actions: { |
| 3001 |
all: () => selectOrderedClasses((0, _elementor_store.__getState)()), |
| 3002 |
get: (id) => { |
| 3003 |
const state = (0, _elementor_store.__getState)(); |
| 3004 |
const isFetched = selectIsClassFetched(state, id); |
| 3005 |
const style = selectClass(state, id); |
| 3006 |
if (isFetched || style) return style; |
| 3007 |
loadExistingClasses([id]); |
| 3008 |
return placeholderDefinition(id, selectClassLabels(state)[id] ?? id); |
| 3009 |
}, |
| 3010 |
resolveCssName: (id) => { |
| 3011 |
const state = (0, _elementor_store.__getState)(); |
| 3012 |
const loaded = selectClass(state, id); |
| 3013 |
if (loaded) return loaded.label; |
| 3014 |
return selectClassLabels(state)[id] ?? id; |
| 3015 |
}, |
| 3016 |
create: (label, variants = [], id) => { |
| 3017 |
const existingClasses = Object.entries(selectClassLabels((0, _elementor_store.__getState)())); |
| 3018 |
if (existingClasses.map(([, classLabel]) => classLabel).includes(label)) throw new GlobalClassLabelAlreadyExistsError({ context: { label } }); |
| 3019 |
const existingIds = existingClasses.map(([existingId]) => existingId); |
| 3020 |
if (!id) id = (0, _elementor_editor_styles.generateId)("g-", existingIds); |
| 3021 |
(0, _elementor_store.__dispatch)(slice.actions.add({ |
| 3022 |
id, |
| 3023 |
type: "class", |
| 3024 |
label, |
| 3025 |
variants |
| 3026 |
})); |
| 3027 |
return id; |
| 3028 |
}, |
| 3029 |
update: (payload) => { |
| 3030 |
(0, _elementor_store.__dispatch)(slice.actions.update({ style: payload })); |
| 3031 |
}, |
| 3032 |
delete: (id) => { |
| 3033 |
(0, _elementor_store.__dispatch)(slice.actions.delete(id)); |
| 3034 |
}, |
| 3035 |
updateProps: (args) => { |
| 3036 |
(0, _elementor_store.__dispatch)(slice.actions.updateProps({ |
| 3037 |
id: args.id, |
| 3038 |
meta: args.meta, |
| 3039 |
props: args.props, |
| 3040 |
mode: args.mode |
| 3041 |
})); |
| 3042 |
}, |
| 3043 |
updateCustomCss: (args) => { |
| 3044 |
(0, _elementor_store.__dispatch)(slice.actions.updateProps({ |
| 3045 |
id: args.id, |
| 3046 |
meta: args.meta, |
| 3047 |
custom_css: args.custom_css, |
| 3048 |
props: {} |
| 3049 |
})); |
| 3050 |
}, |
| 3051 |
tracking: (data) => { |
| 3052 |
trackGlobalClasses(data).catch((error) => { |
| 3053 |
throw new GlobalClassTrackingError({ cause: error }); |
| 3054 |
}); |
| 3055 |
} |
| 3056 |
} |
| 3057 |
}); |
| 3058 |
var subscribeWithStates = (cb) => { |
| 3059 |
let previousState = selectData((0, _elementor_store.__getState)()); |
| 3060 |
return (0, _elementor_store.__subscribeWithSelector)((state) => selectData(state), (currentState) => { |
| 3061 |
cb(previousState.items, currentState.items); |
| 3062 |
previousState = currentState; |
| 3063 |
}); |
| 3064 |
}; |
| 3065 |
|
| 3066 |
//#endregion |
| 3067 |
//#region packages/packages/core/editor-global-classes/src/mcp-integration/classes-resource.ts |
| 3068 |
var GLOBAL_CLASSES_URI = "elementor://global-classes"; |
| 3069 |
var STORAGE_KEY = "elementor-global-classes"; |
| 3070 |
var updateLocalStorageCache = () => { |
| 3071 |
const classes = selectOrderedClasses((0, _elementor_store.__getState)()); |
| 3072 |
localStorage.setItem(STORAGE_KEY, JSON.stringify(classes)); |
| 3073 |
}; |
| 3074 |
var initClassesResource = (classesMcpEntry, canvasMcpEntry) => { |
| 3075 |
[canvasMcpEntry, classesMcpEntry].forEach((entry) => { |
| 3076 |
const { sendResourceUpdated, resource, waitForReady } = entry; |
| 3077 |
resource("global-classes", GLOBAL_CLASSES_URI, { description: "Global classes list." }, async () => { |
| 3078 |
return { contents: [{ |
| 3079 |
uri: GLOBAL_CLASSES_URI, |
| 3080 |
text: localStorage[STORAGE_KEY] ?? "[]" |
| 3081 |
}] }; |
| 3082 |
}); |
| 3083 |
waitForReady().then(() => { |
| 3084 |
updateLocalStorageCache(); |
| 3085 |
globalClassesStylesProvider.subscribe(() => { |
| 3086 |
updateLocalStorageCache(); |
| 3087 |
sendResourceUpdated({ uri: GLOBAL_CLASSES_URI }); |
| 3088 |
}); |
| 3089 |
}); |
| 3090 |
}); |
| 3091 |
}; |
| 3092 |
|
| 3093 |
//#endregion |
| 3094 |
//#region packages/packages/core/editor-global-classes/src/hooks/use-prefetch-css-class-usage.ts |
| 3095 |
function usePrefetchCssClassUsage() { |
| 3096 |
const queryClient = (0, _elementor_query.useQueryClient)(); |
| 3097 |
const prefetchClassesUsage = () => queryClient.prefetchQuery({ |
| 3098 |
queryKey: [QUERY_KEY], |
| 3099 |
queryFn: fetchCssClassUsage |
| 3100 |
}); |
| 3101 |
return { prefetchClassesUsage }; |
| 3102 |
} |
| 3103 |
var PrefetchCssClassUsage = () => { |
| 3104 |
const { prefetchClassesUsage } = usePrefetchCssClassUsage(); |
| 3105 |
prefetchClassesUsage(); |
| 3106 |
return null; |
| 3107 |
}; |
| 3108 |
|
| 3109 |
//#endregion |
| 3110 |
//#region packages/packages/core/editor-global-classes/src/components/class-manager/class-manager-button.tsx |
| 3111 |
var EVENT_TOGGLE_DESIGN_SYSTEM = "elementor/toggle-design-system"; |
| 3112 |
var ClassManagerButton = () => { |
| 3113 |
const { prefetchClassesUsage } = usePrefetchCssClassUsage(); |
| 3114 |
const { userCan } = (0, _elementor_editor_styles_repository.useUserStylesCapability)(); |
| 3115 |
if (!userCan(globalClassesStylesProvider.getKey()).update) return null; |
| 3116 |
const handleOpenPanel = () => { |
| 3117 |
window.dispatchEvent(new CustomEvent(EVENT_TOGGLE_DESIGN_SYSTEM, { detail: { tab: "classes" } })); |
| 3118 |
trackGlobalClasses({ |
| 3119 |
event: "classManagerOpened", |
| 3120 |
source: "style-panel" |
| 3121 |
}); |
| 3122 |
prefetchClassesUsage(); |
| 3123 |
}; |
| 3124 |
return /* @__PURE__ */ react.createElement(_elementor_ui.Tooltip, { |
| 3125 |
title: (0, _wordpress_i18n.__)("Class Manager", "elementor"), |
| 3126 |
placement: "top" |
| 3127 |
}, /* @__PURE__ */ react.createElement(_elementor_ui.IconButton, { |
| 3128 |
size: "tiny", |
| 3129 |
onClick: handleOpenPanel, |
| 3130 |
sx: { marginInlineEnd: -.75 } |
| 3131 |
}, /* @__PURE__ */ react.createElement(FlippedColorSwatchIcon, { fontSize: "tiny" }))); |
| 3132 |
}; |
| 3133 |
|
| 3134 |
//#endregion |
| 3135 |
//#region packages/packages/core/editor-global-classes/src/components/convert-local-class-to-global-class.tsx |
| 3136 |
var ConvertLocalClassToGlobalClass = (props) => { |
| 3137 |
const localStyleData = props.styleDef; |
| 3138 |
const handleConversion = () => { |
| 3139 |
const newClassName = createClassName(`converted-class-`); |
| 3140 |
if (!localStyleData) throw new Error("Style definition is required for converting local class to global class."); |
| 3141 |
const newId = globalClassesStylesProvider.actions.create?.(newClassName, localStyleData.variants); |
| 3142 |
if (newId) { |
| 3143 |
props.successCallback(newId); |
| 3144 |
trackGlobalClasses({ |
| 3145 |
classId: newId, |
| 3146 |
event: "classCreated", |
| 3147 |
source: "converted", |
| 3148 |
classTitle: newClassName |
| 3149 |
}); |
| 3150 |
} |
| 3151 |
}; |
| 3152 |
return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_editor_ui.MenuListItem, { |
| 3153 |
disabled: !props.canConvert, |
| 3154 |
onClick: handleConversion, |
| 3155 |
dense: true, |
| 3156 |
sx: { "&.Mui-focusVisible": { |
| 3157 |
border: "none", |
| 3158 |
boxShadow: "none !important", |
| 3159 |
backgroundColor: "transparent" |
| 3160 |
} } |
| 3161 |
}, (0, _wordpress_i18n.__)("Convert to global class", "elementor")), /* @__PURE__ */ react.createElement(_elementor_ui.Divider, null)); |
| 3162 |
}; |
| 3163 |
function createClassName(prefix) { |
| 3164 |
let i = 1; |
| 3165 |
let newClassName = `${prefix}${i}`; |
| 3166 |
while (!(0, _elementor_editor_styles_repository.validateStyleLabel)(newClassName, "create").isValid) newClassName = `${prefix}${++i}`; |
| 3167 |
return newClassName; |
| 3168 |
} |
| 3169 |
|
| 3170 |
//#endregion |
| 3171 |
//#region packages/packages/core/editor-global-classes/src/components/global-styles-import-listener.tsx |
| 3172 |
function GlobalStylesImportListener() { |
| 3173 |
const dispatch = (0, _elementor_store.__useDispatch)(); |
| 3174 |
(0, react.useEffect)(() => { |
| 3175 |
const handleGlobalStylesImported = async (event) => { |
| 3176 |
const globalClasses = event.detail?.global_classes; |
| 3177 |
if (!globalClasses?.added_items_order || !globalClasses?.added_items || globalClasses?.added_items_order?.length === 0) { |
| 3178 |
loadCurrentDocumentClasses(); |
| 3179 |
return; |
| 3180 |
} |
| 3181 |
dispatch(slice.actions.updateAfterTemplateImport({ |
| 3182 |
addedItems: globalClasses.added_items, |
| 3183 |
addedIdsOrder: globalClasses.added_items_order, |
| 3184 |
addedClassLabels: createLabelsForClasses(Object.values(globalClasses.added_items)) |
| 3185 |
})); |
| 3186 |
}; |
| 3187 |
window.addEventListener(_elementor_editor_canvas.GLOBAL_STYLES_IMPORTED_EVENT, handleGlobalStylesImported); |
| 3188 |
return () => { |
| 3189 |
window.removeEventListener(_elementor_editor_canvas.GLOBAL_STYLES_IMPORTED_EVENT, handleGlobalStylesImported); |
| 3190 |
}; |
| 3191 |
}, [dispatch]); |
| 3192 |
return null; |
| 3193 |
} |
| 3194 |
|
| 3195 |
//#endregion |
| 3196 |
//#region packages/packages/core/editor-global-classes/src/components/populate-store.tsx |
| 3197 |
function PopulateStore() { |
| 3198 |
(0, react.useEffect)(() => { |
| 3199 |
loadCurrentDocumentClasses(); |
| 3200 |
(0, _elementor_editor_v1_adapters.registerDataHook)("after", "editor/documents/attach-preview", async () => { |
| 3201 |
await loadCurrentDocumentClasses(); |
| 3202 |
}); |
| 3203 |
}, []); |
| 3204 |
return null; |
| 3205 |
} |
| 3206 |
|
| 3207 |
//#endregion |
| 3208 |
//#region packages/packages/core/editor-global-classes/src/mcp-integration/manage-classes-tool.ts |
| 3209 |
var MCP_PROXY_URL = "elementor/v1/mcp-proxy"; |
| 3210 |
var TOOL_NAME = "manage-classes"; |
| 3211 |
var initManageClassesTool = (reg) => { |
| 3212 |
const { addTool } = reg; |
| 3213 |
addTool({ |
| 3214 |
name: TOOL_NAME, |
| 3215 |
description: "Manage V4 global CSS classes on the active kit. Bulk create, update, or delete using raw CSS declarations (up to 50 operations). Duplicate labels are auto-renamed with a DUP_ prefix.", |
| 3216 |
schema: { |
| 3217 |
action: _elementor_schema.z.enum([ |
| 3218 |
"create", |
| 3219 |
"update", |
| 3220 |
"delete" |
| 3221 |
]), |
| 3222 |
id: _elementor_schema.z.string().optional().describe("Class id — required for update/delete. Get from the global-classes resource."), |
| 3223 |
label: _elementor_schema.z.string().optional().describe("Class label (lowercase, dash-separated) — required for create/update."), |
| 3224 |
css: _elementor_schema.z.string().optional().describe("Plain CSS string. Supports &:hover/&:focus/&:active nesting and @media(--breakpoint) blocks. font-family must be a single Google Font name (no fallback stacks). In patch mode: \"prop: null\" removes that prop; \"all: null\" wipes the variant."), |
| 3225 |
mode: _elementor_schema.z.enum(["patch", "replace"]).optional().describe("Merge strategy for update — patch (default): merge incoming props with existing; replace: discard all existing variants for the affected breakpoints.") |
| 3226 |
}, |
| 3227 |
outputSchema: { |
| 3228 |
status: _elementor_schema.z.enum(["ok"]).describe("Operation status"), |
| 3229 |
id: _elementor_schema.z.string().optional().describe("ID of the affected class — use for subsequent update/delete calls."), |
| 3230 |
label: _elementor_schema.z.string().optional().describe("Final label of the class after any auto-rename.") |
| 3231 |
}, |
| 3232 |
requiredResources: [{ |
| 3233 |
uri: GLOBAL_CLASSES_URI, |
| 3234 |
description: "Current global classes — check before creating to avoid duplicates" |
| 3235 |
}], |
| 3236 |
isDestructive: true, |
| 3237 |
handler: async (params) => { |
| 3238 |
const { data } = await (0, _elementor_http_client.httpService)().post(MCP_PROXY_URL, { |
| 3239 |
tool: TOOL_NAME, |
| 3240 |
input: { operations: [params] } |
| 3241 |
}); |
| 3242 |
const result = data.data.results?.[0]; |
| 3243 |
const { create, update, delete: del } = globalClassesStylesProvider.actions; |
| 3244 |
switch (params.action) { |
| 3245 |
case "create": |
| 3246 |
if (result && create) create(result.label, result.variants, result.id); |
| 3247 |
break; |
| 3248 |
case "update": |
| 3249 |
if (result && update) update(result); |
| 3250 |
break; |
| 3251 |
case "delete": |
| 3252 |
if (params.id && del) del(params.id); |
| 3253 |
break; |
| 3254 |
} |
| 3255 |
(0, _elementor_store.__dispatch)(slice.actions.reset({ context: "frontend" })); |
| 3256 |
window.dispatchEvent(new CustomEvent("classes:updated", { detail: { context: "frontend" } })); |
| 3257 |
return { |
| 3258 |
status: "ok", |
| 3259 |
id: result?.id, |
| 3260 |
label: result?.label |
| 3261 |
}; |
| 3262 |
} |
| 3263 |
}); |
| 3264 |
}; |
| 3265 |
|
| 3266 |
//#endregion |
| 3267 |
//#region packages/packages/core/editor-global-classes/src/mcp-integration/apply-global-class-guide-prompt.ts |
| 3268 |
var APPLY_GLOBAL_CLASS_GUIDE_URI = "elementor://global-classes/tools/apply-global-class-guide"; |
| 3269 |
var generateApplyGlobalClassGuidePrompt = () => { |
| 3270 |
const prompt = (0, _elementor_editor_mcp.toolPrompts)("apply-global-class"); |
| 3271 |
prompt.description("Apply a global class to an element, enabling consistent styling through your design system."); |
| 3272 |
prompt.instruction(`## When to use this tool: |
| 3273 |
**ALWAYS use this IMMEDIATELY AFTER creating or updating elements** to apply the global classes you created beforehand: |
| 3274 |
- After adding elements to the canvas, apply semantic classes to them |
| 3275 |
- When applying consistent typography styles (heading-primary, text-body, etc.) |
| 3276 |
- When applying theme colors or brand styles (bg-brand, button-cta, etc.) |
| 3277 |
- When ensuring spacing consistency (spacing-section-large, etc.) |
| 3278 |
|
| 3279 |
**DO NOT use this tool** for: |
| 3280 |
- Elements that don't share styles with other elements (use inline styles instead) |
| 3281 |
- Layout-specific properties (those should remain inline in stylesConfig)`); |
| 3282 |
prompt.instruction(`## Prerequisites: |
| 3283 |
- **REQUIRED**: Get the list of available global classes from 'elementor://global-classes' resource |
| 3284 |
- **REQUIRED**: Get element IDs from the page structure or selected element resources |
| 3285 |
- Ensure you have the most up-to-date list of classes applied to the element to avoid duplicates |
| 3286 |
- Make sure you have the correct class ID that you want to apply`); |
| 3287 |
prompt.instruction(`## Best Practices: |
| 3288 |
1. Apply multiple classes to a single element if needed (typography + color + spacing) |
| 3289 |
2. After applying, the tool will remind you to remove duplicate inline styles from elementConfig |
| 3290 |
3. Classes should describe purpose, not implementation (e.g., "heading-primary" not "big-red-text")`); |
| 3291 |
return prompt.prompt(); |
| 3292 |
}; |
| 3293 |
|
| 3294 |
//#endregion |
| 3295 |
//#region packages/packages/core/editor-global-classes/src/mcp-integration/mcp-apply-unapply-global-classes.ts |
| 3296 |
function initMcpApplyUnapplyGlobalClasses(server) { |
| 3297 |
const { addTool, resource } = server; |
| 3298 |
const applyGlobalClassGuideText = generateApplyGlobalClassGuidePrompt(); |
| 3299 |
resource("apply-global-class-guide", APPLY_GLOBAL_CLASS_GUIDE_URI, { |
| 3300 |
description: "Workflow, prerequisites, and best practices for apply-global-class", |
| 3301 |
mimeType: "text/plain", |
| 3302 |
title: "Apply global class tool guide" |
| 3303 |
}, async (uri) => ({ contents: [{ |
| 3304 |
mimeType: "text/plain", |
| 3305 |
text: applyGlobalClassGuideText, |
| 3306 |
uri: uri.href |
| 3307 |
}] })); |
| 3308 |
addTool({ |
| 3309 |
schema: { |
| 3310 |
classId: _elementor_schema.z.string().describe("The ID of the class to apply"), |
| 3311 |
elementId: _elementor_schema.z.string().describe("The ID of the element to which the class will be applied") |
| 3312 |
}, |
| 3313 |
outputSchema: { |
| 3314 |
result: _elementor_schema.z.string().describe("Result message indicating the success of the apply operation"), |
| 3315 |
llm_instructions: _elementor_schema.z.string().describe("Instructions what to do next, Important to follow these instructions!") |
| 3316 |
}, |
| 3317 |
name: "apply-global-class", |
| 3318 |
description: `Apply a global class to an element for shared design-system styling. Read the full guide at [${APPLY_GLOBAL_CLASS_GUIDE_URI}].`, |
| 3319 |
requiredResources: [{ |
| 3320 |
description: "Apply global class tool guide", |
| 3321 |
uri: APPLY_GLOBAL_CLASS_GUIDE_URI |
| 3322 |
}, { |
| 3323 |
description: "Global classes list", |
| 3324 |
uri: GLOBAL_CLASSES_URI |
| 3325 |
}], |
| 3326 |
handler: async (params) => { |
| 3327 |
const { classId, elementId } = params; |
| 3328 |
(0, _elementor_editor_editing_panel.doApplyClasses)(elementId, [...(0, _elementor_editor_editing_panel.doGetAppliedClasses)(elementId), classId]); |
| 3329 |
globalClassesStylesProvider.actions.tracking?.({ |
| 3330 |
event: "classApplied", |
| 3331 |
executedBy: "mcp_tool", |
| 3332 |
classId |
| 3333 |
}); |
| 3334 |
return { |
| 3335 |
llm_instructions: "Please check the element configuration, find inline styles duplicated by the applied global class, and remove them", |
| 3336 |
result: `Class ${classId} applied to element ${elementId} successfully.` |
| 3337 |
}; |
| 3338 |
} |
| 3339 |
}); |
| 3340 |
addTool({ |
| 3341 |
name: "unapply-global-class", |
| 3342 |
schema: { |
| 3343 |
classId: _elementor_schema.z.string().describe("The ID of the class to unapply"), |
| 3344 |
elementId: _elementor_schema.z.string().describe("The ID of the element from which the class will be unapplied") |
| 3345 |
}, |
| 3346 |
outputSchema: { result: _elementor_schema.z.string().describe("Result message indicating the success of the unapply operation") }, |
| 3347 |
description: `Unapply a global class from an element by class ID. Resolve class names to IDs via [${GLOBAL_CLASSES_URI}].`, |
| 3348 |
requiredResources: [{ |
| 3349 |
description: "Global classes list", |
| 3350 |
uri: GLOBAL_CLASSES_URI |
| 3351 |
}], |
| 3352 |
handler: async (params) => { |
| 3353 |
const { classId, elementId } = params; |
| 3354 |
if (!(0, _elementor_editor_editing_panel.doUnapplyClass)(elementId, classId)) throw new Error(`Class ${classId} is not applied to element ${elementId}, cannot unapply it.`); |
| 3355 |
return { result: `Class ${classId} unapplied from element ${elementId} successfully.` }; |
| 3356 |
} |
| 3357 |
}); |
| 3358 |
} |
| 3359 |
|
| 3360 |
//#endregion |
| 3361 |
//#region packages/packages/core/editor-global-classes/src/mcp-integration/mcp-get-global-class-usages.ts |
| 3362 |
function initMcpApplyGetGlobalClassUsages(reg) { |
| 3363 |
const { addTool } = reg; |
| 3364 |
const globalClassesUsageSchema = { usages: _elementor_schema.z.array(_elementor_schema.z.object({ |
| 3365 |
classId: _elementor_schema.z.string().describe("The ID of the class, not visible to the user. To retrieve the name of the class, use the \"list-global-classes\" tool"), |
| 3366 |
usages: _elementor_schema.z.array(_elementor_schema.z.object({ |
| 3367 |
pageId: _elementor_schema.z.string().describe("The ID of the page where the class is used"), |
| 3368 |
title: _elementor_schema.z.string().describe("The title of the page where the class is used"), |
| 3369 |
total: _elementor_schema.z.number().describe("The number of times the class is used on this page"), |
| 3370 |
elements: _elementor_schema.z.array(_elementor_schema.z.string()).describe("List of element IDs using this class on the page") |
| 3371 |
})) |
| 3372 |
})) }; |
| 3373 |
addTool({ |
| 3374 |
name: "get-global-class-usages", |
| 3375 |
description: `Retrieve usages of global classes across all Elementor pages. Heavy operation \u2014 scans every page in the site. |
| 3376 |
|
| 3377 |
## When to use: |
| 3378 |
- Before deleting or radically changing a class \u2014 to understand cross-page side effects and decide whether to consult the user. |
| 3379 |
- To identify unused global classes for cleanup. |
| 3380 |
|
| 3381 |
## When NOT to use: |
| 3382 |
- To list global classes themselves \u2014 use the global-classes resource instead (this tool returns usages, not the class list).`, |
| 3383 |
requiredResources: [{ |
| 3384 |
description: "Global classes list", |
| 3385 |
uri: GLOBAL_CLASSES_URI |
| 3386 |
}], |
| 3387 |
outputSchema: globalClassesUsageSchema, |
| 3388 |
handler: async () => { |
| 3389 |
const data = await fetchCssClassUsage(); |
| 3390 |
const result = { usages: [] }; |
| 3391 |
Object.entries(data).forEach(([classId, usageDetails]) => { |
| 3392 |
const newEntry = { |
| 3393 |
classId, |
| 3394 |
usages: [] |
| 3395 |
}; |
| 3396 |
if (typeof usageDetails !== "number") { |
| 3397 |
const { content } = usageDetails; |
| 3398 |
content.forEach((detail) => { |
| 3399 |
newEntry.usages.push({ |
| 3400 |
pageId: String(detail.pageId), |
| 3401 |
title: detail.title, |
| 3402 |
total: detail.total, |
| 3403 |
elements: detail.elements |
| 3404 |
}); |
| 3405 |
}); |
| 3406 |
result.usages.push(newEntry); |
| 3407 |
} |
| 3408 |
}); |
| 3409 |
return result; |
| 3410 |
} |
| 3411 |
}); |
| 3412 |
} |
| 3413 |
|
| 3414 |
//#endregion |
| 3415 |
//#region packages/packages/core/editor-global-classes/src/mcp-integration/index.ts |
| 3416 |
var initMcpIntegration = (reg, canvasMcpEntry) => { |
| 3417 |
initMcpApplyUnapplyGlobalClasses(reg); |
| 3418 |
initMcpApplyGetGlobalClassUsages(reg); |
| 3419 |
initManageClassesTool(reg); |
| 3420 |
initClassesResource(reg, canvasMcpEntry); |
| 3421 |
}; |
| 3422 |
|
| 3423 |
//#endregion |
| 3424 |
//#region packages/packages/core/editor-global-classes/src/sync-with-document-save.ts |
| 3425 |
var pendingSave = null; |
| 3426 |
function syncWithDocumentSave(panelActions) { |
| 3427 |
const unsubscribe = syncDirtyState(); |
| 3428 |
bindSaveAction(panelActions); |
| 3429 |
bindBeforeSaveTemplateAction(); |
| 3430 |
return unsubscribe; |
| 3431 |
} |
| 3432 |
function syncDirtyState() { |
| 3433 |
return (0, _elementor_store.__subscribeWithSelector)(selectIsDirty, () => { |
| 3434 |
if (!isDirty()) return; |
| 3435 |
(0, _elementor_editor_documents.setDocumentModifiedStatus)(true); |
| 3436 |
}); |
| 3437 |
} |
| 3438 |
function triggerSave(panelActions, context = "preview") { |
| 3439 |
if (!(0, _elementor_editor_current_user.getCurrentUser)()?.capabilities.includes("elementor_global_classes_update_class")) return null; |
| 3440 |
if (pendingSave) return pendingSave; |
| 3441 |
const promise = saveGlobalClasses({ |
| 3442 |
context, |
| 3443 |
onApprove: panelActions?.open |
| 3444 |
}); |
| 3445 |
pendingSave = promise; |
| 3446 |
promise.finally(() => { |
| 3447 |
pendingSave = null; |
| 3448 |
}); |
| 3449 |
return promise; |
| 3450 |
} |
| 3451 |
function bindSaveAction(panelActions) { |
| 3452 |
(0, _elementor_editor_v1_adapters.registerDataHook)("dependency", "document/save/save", (args) => { |
| 3453 |
triggerSave(panelActions, args.status === "publish" ? "frontend" : "preview"); |
| 3454 |
return true; |
| 3455 |
}); |
| 3456 |
} |
| 3457 |
function bindBeforeSaveTemplateAction() { |
| 3458 |
window.addEventListener("elementor/global-styles/before-save", (event) => { |
| 3459 |
if (!pendingSave && isDirty()) triggerSave(); |
| 3460 |
if (pendingSave) event.detail.promises.push(pendingSave); |
| 3461 |
}); |
| 3462 |
} |
| 3463 |
function isDirty() { |
| 3464 |
return selectIsDirty((0, _elementor_store.__getState)()); |
| 3465 |
} |
| 3466 |
|
| 3467 |
//#endregion |
| 3468 |
//#region packages/packages/core/editor-global-classes/src/sync-with-document.tsx |
| 3469 |
function SyncWithDocumentSave() { |
| 3470 |
(0, react.useEffect)(() => { |
| 3471 |
return (0, _elementor_editor_v1_adapters.__privateListenTo)((0, _elementor_editor_v1_adapters.v1ReadyEvent)(), () => { |
| 3472 |
const open = () => { |
| 3473 |
window.dispatchEvent(new CustomEvent("elementor/open-global-classes-manager")); |
| 3474 |
}; |
| 3475 |
syncWithDocumentSave({ open }); |
| 3476 |
}); |
| 3477 |
}, []); |
| 3478 |
return null; |
| 3479 |
} |
| 3480 |
|
| 3481 |
//#endregion |
| 3482 |
//#region packages/packages/core/editor-global-classes/src/init.ts |
| 3483 |
function init() { |
| 3484 |
(0, _elementor_store.__registerSlice)(slice); |
| 3485 |
_elementor_editor_embedded_documents_manager.embeddedDocumentsManager.onDocumentLoad((documentId) => { |
| 3486 |
addDocumentClasses(documentId); |
| 3487 |
}); |
| 3488 |
_elementor_editor_styles_repository.stylesRepository.register(globalClassesStylesProvider); |
| 3489 |
(0, _elementor_editor.injectIntoLogic)({ |
| 3490 |
id: "global-classes-populate-store", |
| 3491 |
component: PopulateStore |
| 3492 |
}); |
| 3493 |
(0, _elementor_editor.injectIntoLogic)({ |
| 3494 |
id: "global-classes-sync-with-document", |
| 3495 |
component: SyncWithDocumentSave |
| 3496 |
}); |
| 3497 |
(0, _elementor_editor.injectIntoLogic)({ |
| 3498 |
id: "global-classes-import-listener", |
| 3499 |
component: GlobalStylesImportListener |
| 3500 |
}); |
| 3501 |
(0, _elementor_editor.injectIntoLogic)({ |
| 3502 |
id: "global-classes-prefetch-css-class-usage", |
| 3503 |
component: PrefetchCssClassUsage |
| 3504 |
}); |
| 3505 |
(0, _elementor_editor_editing_panel.injectIntoCssClassConvert)({ |
| 3506 |
id: "global-classes-convert-from-local-class", |
| 3507 |
component: ConvertLocalClassToGlobalClass |
| 3508 |
}); |
| 3509 |
(0, _elementor_editor_editing_panel.injectIntoClassSelectorActions)({ |
| 3510 |
id: "global-classes-manager-button", |
| 3511 |
component: ClassManagerButton |
| 3512 |
}); |
| 3513 |
(0, _elementor_editor_editing_panel.registerStyleProviderToColors)(GLOBAL_CLASSES_PROVIDER_KEY, { |
| 3514 |
name: "global", |
| 3515 |
getThemeColor: (theme) => theme.palette.global.dark |
| 3516 |
}); |
| 3517 |
initMcpIntegration((0, _elementor_editor_mcp.getMCPByDomain)("classes", { |
| 3518 |
instructions: "MCP server for management of Elementor global classes", |
| 3519 |
docs: `Everything related to V4 ( Atomic ) global classes. |
| 3520 |
# Global classes |
| 3521 |
- Create/update/delete global classes |
| 3522 |
- Get list of global classes |
| 3523 |
- Get details of a global class |
| 3524 |
` |
| 3525 |
}), (0, _elementor_editor_mcp.getMCPByDomain)("canvas")); |
| 3526 |
} |
| 3527 |
|
| 3528 |
//#endregion |
| 3529 |
//#region packages/packages/core/editor-global-classes/src/index.ts |
| 3530 |
var src_exports = /* @__PURE__ */ __exportAll({ |
| 3531 |
ClassManagerPanelEmbedded: () => ClassManagerPanelEmbedded, |
| 3532 |
GLOBAL_CLASSES_URI: () => GLOBAL_CLASSES_URI, |
| 3533 |
addDocumentClasses: () => addDocumentClasses, |
| 3534 |
createLabelsForClasses: () => createLabelsForClasses, |
| 3535 |
init: () => init, |
| 3536 |
loadExistingClasses: () => loadExistingClasses, |
| 3537 |
trackGlobalClasses: () => trackGlobalClasses |
| 3538 |
}); |
| 3539 |
|
| 3540 |
//#endregion |
| 3541 |
//#region \0elementor-package-library-entry |
| 3542 |
(window.elementorV2 = window.elementorV2 || {}).editorGlobalClasses = src_exports; |
| 3543 |
|
| 3544 |
//#endregion |
| 3545 |
})(React, elementorV2.editorCurrentUser, elementorV2.editorDocuments, elementorV2.editorPanels, elementorV2.editorUi, elementorV2.query, elementorV2.store, elementorV2.ui, wp.i18n, elementorV2.editorStyles, elementorV2.utils, elementorV2.httpClient, elementorV2.icons, elementorV2.events, ReactDOM, elementorV2.editorStylesRepository, elementorV2.editor, elementorV2.editorEditingPanel, elementorV2.editorEmbeddedDocumentsManager, elementorV2.editorMcp, elementorV2.editorCanvas, elementorV2.editorV1Adapters, elementorV2.schema); |
| 3546 |
window.elementorV2.editorGlobalClasses?.init?.(); |
| 3547 |
//# sourceMappingURL=editor-global-classes.js.map |