1import { R as get_inputs_outputs, T as get_component, U as determine_interactivity } from './i18n-CMo5lpzy.js'; 2export { E as Embed, I as changeLocale, V as get_initial_locale, W as is_translation_metadata, H as language_choices, X as load_translations, D as mount_css, A as prefix_css, Y as process_langs, y as setupi18n } from './i18n-CMo5lpzy.js'; 3import { u as state, w as get, x as set, M as tick } from './index-BvBk1Iap.js'; 4import { d as dequal } from './index-DnoGeqVF.js'; 5import { b as allowed_shared_props } from './utils.svelte-CYLB_jIA.js'; 6export { I as i18n_marker } from './utils.svelte-CYLB_jIA.js'; 7import './clone-DaB-S2nH.js'; 8 9/* init.svelte.ts generated by Svelte v5.48.0 */ 10 11const type_map = { walkthrough: "tabs", walkthroughstep: "tabitem" }; 12 13function get_api_url(config) { 14 const rootUrl = new URL(config.root); 15 const rootPath = rootUrl.pathname.endsWith("/") ? rootUrl.pathname : rootUrl.pathname + "/"; 16 const apiPrefix = config.api_prefix.startsWith("/") ? config.api_prefix : "/" + config.api_prefix; 17 18 return new URL(rootPath.slice(0, -1) + apiPrefix, rootUrl.origin).toString(); 19} 20 21class AppTree { 22 /** the raw component structure received from the backend */ 23 #component_payload; 24 25 /** the raw layout node structure received from the backend */ 26 #layout_payload; 27 28 /** the raw dependency structure received from the backend */ 29 #dependency_payload; 30 31 /** Need this to set i18n in re-render */ 32 reactive_formatter = (str) => str; 33 34 /** the config for the app */ 35 #config; 36 37 client; 38 39 #root = /** the root node of the processed layout tree */ 40 state(); 41 42 get root() { 43 return get(this.#root); 44 } 45 46 set root(value) { 47 set(this.#root, value, true); 48 } 49 50 root_untracked; 51 #input_ids = new Set(); 52 #output_ids = new Set(); 53 #pending_components = []; 54 #get_callbacks = new Map(); 55 #set_callbacks = new Map(); 56 #pending_updates = new Map(); 57 #event_dispatcher; 58 component_ids; 59 initial_tabs = {}; 60 components_to_register = new Set(); 61 ready; 62 ready_resolve; 63 resolved = false; 64 #hidden_on_startup = new Set(); 65 66 constructor( 67 components, 68 layout, 69 dependencies, 70 config, 71 app, 72 reactive_formatter, 73 event_dispatcher 74 ) { 75 this.ready = new Promise((resolve) => { 76 this.ready_resolve = resolve; 77 }); 78 79 this.reactive_formatter = reactive_formatter; 80 81 const api_url = get_api_url(config); 82 83 this.#config = { ...config, api_url }; 84 this.#component_payload = components; 85 this.#layout_payload = layout; 86 this.#dependency_payload = dependencies; 87 this.#event_dispatcher = event_dispatcher; 88 this.root = this.create_node({ id: layout.id, children: [] }, /* @__PURE__ */ new Map(), true); 89 90 for (const comp of components) { 91 if (comp.props.visible != false) this.components_to_register.add(comp.id); 92 } 93 94 this.client = app; 95 this.prepare(); 96 97 const component_map = components.reduce( 98 (map, comp) => { 99 map.set(comp.id, comp); 100 101 return map; 102 }, /* @__PURE__ */ 103 new Map() 104 ); 105 106 this.root.children = this.#layout_payload.children.map((node) => this.traverse(node, (node2) => { 107 const new_node = this.create_node(node2, component_map, false, this.reactive_formatter); 108 109 return new_node; 110 })); 111 112 this.component_ids = components.map((c) => c.id); 113 this.initial_tabs = {}; 114 gather_initial_tabs(this.root, this.initial_tabs); 115 this.postprocess(this.root); 116 this.root_untracked = this.root; 117 } 118 119 reload(components, layout, dependencies, config) { 120 this.#layout_payload = layout; 121 this.#component_payload = components; 122 123 const api_url = get_api_url(config); 124 125 this.#config = { ...config, api_url }; 126 this.#dependency_payload = dependencies; 127 this.root = this.create_node({ id: layout.id, children: [] }, /* @__PURE__ */ new Map(), true); 128 129 for (const comp of components) { 130 if (comp.props.visible != false) this.components_to_register.add(comp.id); 131 } 132 133 this.prepare(); 134 135 const component_map = components.reduce( 136 (map, comp) => { 137 map.set(comp.id, comp); 138 139 return map; 140 }, /* @__PURE__ */ 141 new Map() 142 ); 143 144 this.root.children = this.#layout_payload.children.map((node) => this.traverse(node, (node2) => { 145 const new_node = this.create_node(node2, component_map, false, this.reactive_formatter); 146 147 return new_node; 148 })); 149 150 this.component_ids = components.map((c) => c.id); 151 this.initial_tabs = {}; 152 gather_initial_tabs(this.root, this.initial_tabs); 153 this.postprocess(this.root); 154 } 155 156 /** 157 * Registers a component with its ID and data callbacks 158 * @param id the ID of the component 159 * @param _set_data the set data callback 160 * @param _get_data the get data callback 161 */ 162 register_component(id, _set_data, _get_data) { 163 this.#set_callbacks.set(id, _set_data); 164 this.#get_callbacks.set(id, _get_data); 165 this.components_to_register.delete(id); 166 167 const pending = this.#pending_updates.get(id); 168 169 if (pending) { 170 this.#pending_updates.delete(id); 171 172 tick().then(() => { 173 const _set = this.#set_callbacks.get(id); 174 175 if (_set) _set(pending); 176 }); 177 } 178 179 if (this.components_to_register.size === 0 && !this.resolved) { 180 this.resolved = true; 181 this.ready_resolve(); 182 } 183 } 184
185 /** 186 * Preprocess the payloads to get the correct state read to build the tree 187 */ 188 prepare() { 189 const [inputs, outputs] = get_inputs_outputs(this.#dependency_payload); 190 191 this.#input_ids = inputs; 192 this.#output_ids = outputs; 193 } 194 195 /** Processes the layout payload into a tree of components */ 196 process() {} 197 198 postprocess(tree) { 199 this.root = this.traverse(tree, [ 200 (node) => handle_visibility(node, this.#config.api_url), 201 (node) => untrack_children_of_invisible_parents(node, this.components_to_register), 202 (node) => apply_initial_tabs(node, this.initial_tabs), 203 (node) => this.find_attached_events(node, this.#dependency_payload), 204 (node) => untrack_children_of_closed_accordions_or_inactive_tabs(node, this.components_to_register, this.#hidden_on_startup) 205 ]); 206 } 207 208 find_attached_events(node, dependencies) { 209 const attached_events = dependencies.filter((dep) => dep.targets.find(([id]) => id === node.id)).map((dep) => { 210 const target = dep.targets.find(([id]) => id === node.id); 211 212 return target ? target[1] : null; 213 }).filter(Boolean); 214 215 node.props.shared_props.attached_events = attached_events; 216 217 return node; 218 } 219 220 /** 221 * Traverses the layout tree and applies a callback to each node 222 * @param node the current layout node 223 * @param visit the callback to apply to each node 224 * @returns the return value of the callback, with a `children` property added for any child nodes 225 */ 226 traverse(node, visit) { 227 function single_visit(node2, visit2, traverse_fn) { 228 const result = visit2(node2); 229 230 if ("children" in node2 && node2.children.length > 0) { 231 result.children = node2.children?.map((child) => traverse_fn(child, visit2)) || []; 232 } 233 234 return result; 235 } 236 237 if (Array.isArray(visit)) { 238 let result = node; 239 240 for (const v of visit) { 241 result = single_visit(result, v, this.traverse.bind(this)); 242 } 243 244 return result; 245 } else { 246 return single_visit(node, visit, this.traverse.bind(this)); 247 } 248 } 249 250 /** 251 * Creates a processed component node from a layout node 252 * @param opts the layout node options 253 * @param root whether this is the root node 254 * @returns the processed component node 255 */ 256 create_node(opts, component_map, root = false, reactive_formatter) { 257 let component; 258 259 if (!root) { 260 component = component_map.get(opts.id); 261 } else { 262 component = { 263 type: "column", 264 id: opts.id, 265 // @ts-ignore 266 props: { 267 visible: true, 268 root: "", 269 theme_mode: "light", 270 scale: this.#config.fill_height ? 1 : null 271 }, 272 component_class_id: "column", 273 key: null 274 }; 275 } 276 277 if (!component) { 278 throw new Error(`Component with ID ${opts.id} not found`); 279 } 280 281 if (reactive_formatter) { 282 component.props.i18n = reactive_formatter; 283 } 284 285 const processed_props = gather_props(opts.id, component.props, [this.#input_ids, this.#output_ids], this.client, this.#config.api_url, { 286 ...this.#config, 287 register_component: this.register_component.bind(this), 288 dispatcher: this.#event_dispatcher.bind(this) 289 }); 290 291 const type = type_map[component.type] || component.type; 292 293 const loading_component = processed_props.shared_props.visible !== false 294 ? get_component(component.type, component.component_class_id, this.#config.api_url || "") 295 : null; 296 297 const node = { 298 id: opts.id, 299 type, 300 props: processed_props, 301 children: [], 302 show_progress_on: null, 303 component_class_id: component.component_class_id || component.type, 304 component: processed_props.shared_props.visible !== false ? loading_component?.component || null : null, 305 runtime: loading_component?.runtime || false, 306 key: component.key, 307 rendered_in: component.rendered_in, 308 documentation: component.documentation, 309 original_visibility: processed_props.shared_props.visible 310 }; 311 312 return node; 313 } 314 315 rerender(components, layout) { 316 const component_map = components.reduce( 317 (map, comp) => { 318 map.set(comp.id, comp); 319 320 return map; 321 }, /* @__PURE__ */ 322 new Map() 323 ); 324 325 const _subtree = this.traverse(layout, (node) => { 326 const new_node = this.create_node(node, component_map, false, this.reactive_formatter); 327 328 return new_node; 329 }); 330 331 gather_initial_tabs(_subtree, this.initial_tabs); 332 333 const subtree = this.traverse(_subtree, (node) =>
333 apply_initial_tabs(node, this.initial_tabs)); 334 const n = find_node_by_id(this.root, subtree.id); 335 336 if (!n) { 337 throw new Error("Rerender failed: root node not found in current tree"); 338 } 339 340 n.children = subtree.children; 341 } 342 343 /* 344 * Updates the state of a component by its ID 345 * @param id the ID of the component to update 346 * @param new_state the new state to set 347 * */ 348 async update_state(id, new_state, check_visibility = true) { 349 const node = find_node_by_id(this.root, id); 350 let already_updated_visibility = false; 351 352 if (check_visibility && !node?.component) { 353 await tick(); 354 355 this.root = this.traverse(this.root, [ 356 //@ts-ignore 357 (n) => set_visibility_for_updated_node(n, id, new_state.visible), 358 359 //@ts-ignore 360 (n) => handle_visibility(n, this.#config.api_url) 361 ]); 362 363 await tick(); 364 already_updated_visibility = true; 365 } 366 367 const _set_data = this.#set_callbacks.get(id); 368 369 if (!_set_data) { 370 const old_value = node?.props.props.value; 371 const new_props = create_props_shared_props(new_state); 372 373 for (const key in new_props.shared_props) { 374 node.props.shared_props[key] = new_props.shared_props[key]; 375 } 376 377 for (const key in new_props.props) { 378 node.props.props[key] = new_props.props[key]; 379 } 380 381 const existing = this.#pending_updates.get(id) || {}; 382 383 this.#pending_updates.set(id, { ...existing, ...new_state }); 384 385 if ("value" in new_state && !dequal(old_value, new_state.value)) { 386 this.#event_dispatcher(id, "change", null); 387 } 388 389 if (node?.type === "tabitem") { 390 this.#update_parent_tabs_initial_tab(id, node); 391 } 392 } else if (_set_data) { 393 _set_data(new_state); 394 } 395 396 if (!check_visibility || already_updated_visibility) return; 397 398 await tick(); 399 await this.update_visibility(node, new_state); 400 } 401 402 async update_visibility(node, new_state) { 403 node.children.forEach((child) => { 404 const _set_data = this.#set_callbacks.get(child.id); 405 406 if (_set_data) { 407 _set_data(new_state); 408 } 409 410 this.update_visibility(child, new_state); 411 }); 412 } 413 414 /** 415 * Updates the parent Tabs component's initial_tabs when a non-mounted 416 * tabitem's props change. This ensures the tab button (rendered by 417 * the Tabs component) reflects the updated state even though the 418 * TabItem component itself is not mounted. 419 */ 420 #update_parent_tabs_initial_tab(id, node) { 421 const parent = find_parent(this.root, id); 422 423 if (!parent || parent.type !== "tabs") return; 424 425 const initial_tabs = parent.props.props.initial_tabs; 426 427 if (!initial_tabs) return; 428 429 const tab_index = initial_tabs.findIndex((t) => t.component_id === node.id); 430 431 if (tab_index === -1) return; 432 433 const i18n = node.props.props.i18n; 434 const raw_label = node.props.shared_props.label; 435 436 const visible = "original_visibility" in node 437 ? node.original_visibility 438 : node.props.shared_props.visible; 439 440 initial_tabs[tab_index] = { 441 label: i18n ? i18n(raw_label) : raw_label, 442 id: node.props.props.id, 443 elem_id: node.props.shared_props.elem_id, 444 visible, 445 interactive: node.props.shared_props.interactive, 446 scale: node.props.shared_props.scale || null, 447 component_id: node.id 448 }; 449 450 parent.props.props.initial_tabs = [...initial_tabs]; 451 452 const parent_set_data = this.#set_callbacks.get(parent.id); 453 454 if (parent_set_data) { 455 parent_set_data({ initial_tabs: parent.props.props.initial_tabs }); 456 } 457 } 458 459 /** 460 * Gets the current state of a component by its ID 461 * @param id the ID of the component to get the state of 462 * @returns the current state of the component, or null if not found 463 */ 464 async get_state(id) { 465 const _get_data = this.#get_callbacks.get(id); 466 const component = find_node_by_id(this.root, id); 467 468 if (!_get_data && !component) return null; 469 if (_get_data) return await _get_data(); 470 if (component) return Promise.resolve({ value: component.props.props.value }); 471 472 return null; 473 } 474 475 async render_previously_invisible_children(id) { 476 const node = find_node_by_id(this.root, id); 477 478 if (!node) return; 479 480 if (!this.#hidden_on_startup.has(node.id) && !has_hidden_descendants(node, this.#hidden_on_startup)) { 481 return; 482 } 483 484 make_visible_if_not_rendered(node, this.#hidden_on_startup, true); 485 load_components(node, this.#config.api_url); 486 } 487} 488 489function make_visible_if_not_rendered(node, hidden_on_startup, is_target_node = false) { 490 node.props.shared_props.visible = hidden_on_startup.has(node.id) ? true : node.props.shared_props.visible; 491 492 if (node.type === "tabs") { 493 const selectedId = node.props.props.selected ?? node.props.props.initial_tabs?.[0]?.id; 494
495 node.children.forEach((child) => { 496 if (child.type === "tabitem" && (child.props.props.id === selectedId || child.id === selectedId)) { 497 make_visible_if_not_rendered(child, hidden_on_startup, false); 498 } 499 }); 500 } else if (node.type === "accordion" && node.props.props.open === false && !is_target_node) ; else { 501 node.children.forEach((child) => { 502 make_visible_if_not_rendered(child, hidden_on_startup, false); 503 }); 504 } 505} 506 507function has_hidden_descendants(node, hidden_on_startup) { 508 for (const child of node.children) { 509 if (hidden_on_startup.has(child.id)) return true; 510 if (has_hidden_descendants(child, hidden_on_startup)) return true; 511 } 512 513 return false; 514} 515 516function load_components(node, api_url) { 517 if (node.props.shared_props.visible && !node.component) { 518 node.component = get_component(node.type, node.component_class_id, api_url); 519 } 520 521 node.children.forEach((child) => load_components(child, api_url)); 522} 523 524function process_server_fn(id, server_fns, app) { 525 if (!server_fns) { 526 return {}; 527 } 528 529 return server_fns.reduce( 530 (acc, fn) => { 531 acc[fn] = async (...args) => { 532 if (args.length === 1) { 533 args = args[0]; 534 } 535 536 const result = await app.component_server(id, fn, args); 537 538 return result; 539 }; 540 541 return acc; 542 }, 543 {} 544 ); 545} 546 547function create_props_shared_props(props) { 548 const _shared_props = {}; 549 const _props = {}; 550 551 for (const key in props) { 552 if (key === "id" || key === "autoscroll") { 553 _props[key] = props[key]; 554 } else if (allowed_shared_props.includes(key)) { 555 const _key = key; 556 557 _shared_props[_key] = props[key]; 558 } else { 559 _props[key] = props[key]; 560 } 561 } 562 563 return { shared_props: _shared_props, props: _props }; 564} 565 566function gather_props(id, props, dependencies, client, api_url, additional = {}) { 567 const { shared_props: _shared_props, props: _props } = create_props_shared_props(props); 568 569 _shared_props.server = process_server_fn(id, props.server_fns, client); 570 571 for (const key in additional) { 572 if (allowed_shared_props.includes(key)) { 573 const _key = key; 574 575 _shared_props[_key] = additional[key]; 576 } else { 577 _props[key] = additional[key]; 578 } 579 } 580 581 _shared_props.client = client; 582 _shared_props.id = id; 583 _shared_props.interactive = determine_interactivity(id, _shared_props.interactive, _props.value, dependencies); 584 _shared_props.load_component = (name, variant, component_class_id) => get_component(name, component_class_id || "", api_url, variant); 585 _shared_props.visible = _shared_props.visible === void 0 ? true : _shared_props.visible; 586 _shared_props.loading_status = {}; 587 588 return { shared_props: _shared_props, props: _props }; 589} 590 591function handle_visibility(node, api_url) { 592 if (node.props.shared_props.visible && !node.component) { 593 const loading_component = get_component(node.type, node.component_class_id, api_url); 594 595 const result = { 596 ...node, 597 component: loading_component.component, 598 children: [] 599 }; 600 601 if (node.children) { 602 result.children = node.children.map((child) => handle_visibility(child, api_url)); 603 } 604 605 return result; 606 } else { 607 return node; 608 } 609} 610 611function set_visibility_for_updated_node(node, id, visible) { 612 if (node.id == id) { 613 node.props.shared_props.visible = visible; 614 } 615 616 return node; 617} 618 619function _untrack(node, components_to_register) { 620 components_to_register.delete(node.id); 621 622 if (node.children) { 623 node.children.forEach((child) => _untrack(child, components_to_register)); 624 } 625 626 return; 627} 628 629function untrack_children_of_invisible_parents(node, components_to_register) { 630 if (node.props.shared_props.visible !== true) { 631 _untrack(node, components_to_register); 632 } 633 634 return node; 635} 636 637function mark_component_invisible_if_visible(node, hidden_on_startup) { 638 if (node.props.shared_props.visible === true) { 639 hidden_on_startup.add(node.id); 640 node.props.shared_props.visible = false; 641 } 642 643 node.children.forEach((child) => { 644 mark_component_invisible_if_visible(child, hidden_on_startup); 645 }); 646 647 return node; 648} 649 650function untrack_children_of_closed_accordions_or_inactive_tabs(node, components_to_register, hidden_on_startup) { 651 if (node.type === "accordion" && node.props.props.open === false) { 652 _untrack(node, components_to_register); 653 654 if (node.children) {
655 node.children.forEach((child) => { 656 mark_component_invisible_if_visible(child, hidden_on_startup); 657 }); 658 } 659 } 660 661 if (node.type === "tabs") { 662 node.children.forEach((child) => { 663 if (child.type === "tabitem" && child.props.props.id !== (//@ts-ignore 664 node.props.props.selected || node.props.props.initial_tabs[0].id)) { 665 _untrack(child, components_to_register); 666 mark_component_invisible_if_visible(child, hidden_on_startup); 667 } 668 }); 669 } 670 671 return node; 672} 673 674function apply_initial_tabs(node, initial_tabs) { 675 if (node.type === "tabs" && node.id in initial_tabs) { 676 const tabs = initial_tabs[node.id].sort((a, b) => a.order - b.order); 677 678 node.props.props.initial_tabs = tabs; 679 } else if (node.type === "tabitem") { 680 node.props.props.component_id = node.id; 681 } 682 683 return node; 684} 685 686function _gather_initial_tabs(node, initial_tabs, parent_tab_id, order) { 687 if (parent_tab_id !== null && node.type === "tabitem") { 688 if (!(parent_tab_id in initial_tabs)) { 689 initial_tabs[parent_tab_id] = []; 690 } 691 692 if (!("id" in node.props.props)) { 693 node.props.props.id = node.id; 694 } 695 696 const i18n = node.props.props.i18n; 697 const raw_label = node.props.shared_props.label; 698 699 initial_tabs[parent_tab_id].push({ 700 label: i18n ? i18n(raw_label) : raw_label, 701 id: node.props.props.id, 702 elem_id: node.props.shared_props.elem_id, 703 visible: node.props.shared_props.visible, 704 interactive: node.props.shared_props.interactive, 705 scale: node.props.shared_props.scale || null, 706 component_id: node.id 707 }); 708 709 node.props.props.order = order; 710 } 711 712 if (node.children) { 713 node.children.forEach((child, i) => { 714 _gather_initial_tabs(child, initial_tabs, node.type === "tabs" ? node.id : null, node.type === "tabs" ? i : null); 715 }); 716 } 717 718 return; 719} 720 721function gather_initial_tabs(node, initial_tabs) { 722 function single_visit(node2) { 723 if ("children" in node2 && node2.children.length > 0) { 724 node2.children?.forEach((child) => _gather_initial_tabs(child, initial_tabs, node2.type === "tabs" ? node2.id : null, null)); 725 } 726 } 727 728 return single_visit(node); 729} 730 731function find_node_by_id(tree, id) { 732 if (tree.id === id) { 733 return tree; 734 } 735 736 if (tree.children) { 737 for (const child of tree.children) { 738 const result = find_node_by_id(child, id); 739 740 if (result) { 741 return result; 742 } 743 } 744 } 745 746 return null; 747} 748 749function find_parent(tree, id) { 750 if (tree.children) { 751 for (const child of tree.children) { 752 if (child.id === id) { 753 return tree; 754 } 755 756 const result = find_parent(child, id); 757 758 if (result) { 759 return result; 760 } 761 } 762 } 763 764 return null; 765} 766 767export { AppTree }; 768//# sourceMappingURL=index-BJk8VOjP.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.