@custardui/custardui 2.1.2-beta.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/custardui.js +82 -76
- package/dist/custardui.js.map +1 -1
- package/dist/custardui.min.js +2 -2
- package/dist/custardui.min.js.map +1 -1
- package/dist/types/src/lib/app/ui-manager.d.ts.map +1 -1
- package/dist/types/src/lib/features/anchor/descriptor.d.ts.map +1 -1
- package/dist/types/src/lib/features/anchor/resolver.d.ts +1 -1
- package/dist/types/src/lib/features/anchor/resolver.d.ts.map +1 -1
- package/dist/types/src/lib/features/focus/services/focus-service.svelte.d.ts +1 -2
- package/dist/types/src/lib/features/focus/services/focus-service.svelte.d.ts.map +1 -1
- package/dist/types/src/lib/features/highlight/services/highlight-service.svelte.d.ts +1 -2
- package/dist/types/src/lib/features/highlight/services/highlight-service.svelte.d.ts.map +1 -1
- package/dist/types/src/lib/utils/init-utils.d.ts +2 -3
- package/dist/types/src/lib/utils/init-utils.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/types/tests/functional/fingerprint-compatibility.test.d.ts +0 -2
- package/dist/types/tests/functional/fingerprint-compatibility.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/adaptation/adaptation-manager.test.d.ts +0 -2
- package/dist/types/tests/lib/features/adaptation/adaptation-manager.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/adaptation/stores/adaptation-store.test.d.ts +0 -2
- package/dist/types/tests/lib/features/adaptation/stores/adaptation-store.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/anchor/anchor.test.d.ts +0 -2
- package/dist/types/tests/lib/features/anchor/anchor.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/focus/focus-logic.test.d.ts +0 -2
- package/dist/types/tests/lib/features/focus/focus-logic.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/focus/focus-store.test.d.ts +0 -2
- package/dist/types/tests/lib/features/focus/focus-store.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/highlight/highlight-logic.test.d.ts +0 -2
- package/dist/types/tests/lib/features/highlight/highlight-logic.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/labels/label-manager.test.d.ts +0 -2
- package/dist/types/tests/lib/features/labels/label-manager.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/labels/label-registry-store.test.d.ts +0 -2
- package/dist/types/tests/lib/features/labels/label-registry-store.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/labels/label-utils.test.d.ts +0 -2
- package/dist/types/tests/lib/features/labels/label-utils.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/notifications/stores/toast-store.test.d.ts +0 -2
- package/dist/types/tests/lib/features/notifications/stores/toast-store.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/placeholder/placeholder-binder.test.d.ts +0 -2
- package/dist/types/tests/lib/features/placeholder/placeholder-binder.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/placeholder/placeholder-manager.test.d.ts +0 -2
- package/dist/types/tests/lib/features/placeholder/placeholder-manager.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/settings/intro-manager.test.d.ts +0 -2
- package/dist/types/tests/lib/features/settings/intro-manager.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/settings/stores/icon-settings-store.test.d.ts +0 -2
- package/dist/types/tests/lib/features/settings/stores/icon-settings-store.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/share/share-logic.test.d.ts +0 -2
- package/dist/types/tests/lib/features/share/share-logic.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/share/share-store.test.d.ts +0 -2
- package/dist/types/tests/lib/features/share/share-store.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/url/url-action-handler.test.d.ts +0 -2
- package/dist/types/tests/lib/features/url/url-action-handler.test.d.ts.map +0 -1
- package/dist/types/tests/lib/features/url/url-state-manager.test.d.ts +0 -2
- package/dist/types/tests/lib/features/url/url-state-manager.test.d.ts.map +0 -1
- package/dist/types/tests/lib/services/url-action-router.test.d.ts +0 -2
- package/dist/types/tests/lib/services/url-action-router.test.d.ts.map +0 -1
- package/dist/types/tests/lib/stores/active-state-store.test.d.ts +0 -2
- package/dist/types/tests/lib/stores/active-state-store.test.d.ts.map +0 -1
- package/dist/types/tests/lib/stores/color-scheme-store.test.d.ts +0 -2
- package/dist/types/tests/lib/stores/color-scheme-store.test.d.ts.map +0 -1
- package/dist/types/tests/lib/stores/derived-store.test.d.ts +0 -2
- package/dist/types/tests/lib/stores/derived-store.test.d.ts.map +0 -1
- package/dist/types/tests/lib/stores/element-store.test.d.ts +0 -2
- package/dist/types/tests/lib/stores/element-store.test.d.ts.map +0 -1
- package/dist/types/tests/lib/stores/ui-store.test.d.ts +0 -2
- package/dist/types/tests/lib/stores/ui-store.test.d.ts.map +0 -1
- package/dist/types/tests/lib/utils/persistence.test.d.ts +0 -2
- package/dist/types/tests/lib/utils/persistence.test.d.ts.map +0 -1
- package/dist/types/tests/lib/utils/scroll-utils.test.d.ts +0 -2
- package/dist/types/tests/lib/utils/scroll-utils.test.d.ts.map +0 -1
- package/dist/types/tests/lib/utils/url-utils.test.d.ts +0 -2
- package/dist/types/tests/lib/utils/url-utils.test.d.ts.map +0 -1
- package/dist/types/tests/setup.d.ts +0 -2
- package/dist/types/tests/setup.d.ts.map +0 -1
package/dist/custardui.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @custardui/custardui v2.
|
|
2
|
+
* @custardui/custardui v2.2.0
|
|
3
3
|
* (c) 2026 Chan Ger Teck
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -28,58 +28,61 @@
|
|
|
28
28
|
return cleanbaseUrl + cleanPath;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
const SCRIPT_ATTRIBUTE_DEFAULTS = {
|
|
32
|
+
baseURL: '/',
|
|
33
|
+
configPath: '/custardui.config.json',
|
|
34
|
+
};
|
|
35
|
+
const FALLBACK_CONFIG = {
|
|
36
|
+
config: {},
|
|
37
|
+
settings: { enabled: false },
|
|
38
|
+
};
|
|
31
39
|
/**
|
|
32
40
|
* Finds the script tag that loaded the library and extracts configuration attributes.
|
|
33
41
|
* Looks for `data-base-url` and `data-config-path`.
|
|
34
42
|
*/
|
|
35
43
|
function getScriptAttributes() {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
const scriptTag = findScriptTag();
|
|
45
|
+
if (!scriptTag)
|
|
46
|
+
return SCRIPT_ATTRIBUTE_DEFAULTS;
|
|
47
|
+
return {
|
|
48
|
+
baseURL: scriptTag.getAttribute('data-base-url') || SCRIPT_ATTRIBUTE_DEFAULTS.baseURL,
|
|
49
|
+
configPath: scriptTag.getAttribute('data-config-path') || SCRIPT_ATTRIBUTE_DEFAULTS.configPath,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function findScriptTag() {
|
|
53
|
+
const current = document.currentScript;
|
|
54
|
+
if (current?.hasAttribute('data-base-url'))
|
|
55
|
+
return current;
|
|
56
|
+
const byAttr = document.querySelector('script[data-base-url]');
|
|
57
|
+
if (byAttr)
|
|
58
|
+
return byAttr;
|
|
59
|
+
// Fallback: find script by src pattern
|
|
60
|
+
for (const script of document.scripts) {
|
|
61
|
+
if (/(?:custard(?:ui)?|@custardui\/custard(?:ui)?)(?:\.min)?\.(?:esm\.)?js($|\?)/i.test(script.src)) {
|
|
62
|
+
return script;
|
|
52
63
|
}
|
|
53
64
|
}
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
baseURL: scriptTag.getAttribute('data-base-url') || defaults.baseURL,
|
|
57
|
-
configPath: scriptTag.getAttribute('data-config-path') || defaults.configPath,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
return defaults;
|
|
65
|
+
return null;
|
|
61
66
|
}
|
|
62
67
|
/**
|
|
63
68
|
* Fetches and parses the configuration file.
|
|
69
|
+
* Returns the fallback config silently if the file is not found (404),
|
|
70
|
+
* since operating without a config file is a valid use case.
|
|
64
71
|
*/
|
|
65
72
|
async function fetchConfig(configPath, baseURL) {
|
|
66
|
-
const fallbackMinimalConfig = {
|
|
67
|
-
config: {},
|
|
68
|
-
settings: { enabled: true },
|
|
69
|
-
};
|
|
70
73
|
try {
|
|
71
74
|
const fullConfigPath = prependBaseUrl(configPath, baseURL);
|
|
72
75
|
const response = await fetch(fullConfigPath);
|
|
73
|
-
if (!response.ok)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return
|
|
76
|
+
if (!response.ok)
|
|
77
|
+
return FALLBACK_CONFIG;
|
|
78
|
+
const text = await response.text();
|
|
79
|
+
if (!text.trim())
|
|
80
|
+
return FALLBACK_CONFIG;
|
|
81
|
+
return JSON.parse(text);
|
|
79
82
|
}
|
|
80
83
|
catch (error) {
|
|
81
84
|
console.error('[CustardUI] Error loading config file:', error);
|
|
82
|
-
return
|
|
85
|
+
return FALLBACK_CONFIG;
|
|
83
86
|
}
|
|
84
87
|
}
|
|
85
88
|
|
|
@@ -12210,33 +12213,45 @@
|
|
|
12210
12213
|
return getStableTextContent(el).trim().replace(/\s+/g, ' ');
|
|
12211
12214
|
}
|
|
12212
12215
|
|
|
12216
|
+
/**
|
|
12217
|
+
* Walks the ancestor chain of `el` to find the first element with a non-empty
|
|
12218
|
+
* `id` attribute. Returns both the id string and the ancestor element so the
|
|
12219
|
+
* caller can use the element itself as a query scope.
|
|
12220
|
+
* Returns `ancestorEl: null` when no id-bearing ancestor exists.
|
|
12221
|
+
*/
|
|
12222
|
+
function findNearestIdAncestor(el) {
|
|
12223
|
+
let node = el.parentElement;
|
|
12224
|
+
while (node) {
|
|
12225
|
+
if (node.id)
|
|
12226
|
+
return { parentId: node.id, ancestorEl: node };
|
|
12227
|
+
node = node.parentElement;
|
|
12228
|
+
}
|
|
12229
|
+
return { parentId: undefined, ancestorEl: null };
|
|
12230
|
+
}
|
|
12213
12231
|
/**
|
|
12214
12232
|
* Creates an AnchorDescriptor for a given DOM element.
|
|
12215
12233
|
*/
|
|
12216
12234
|
function createDescriptor(el) {
|
|
12217
12235
|
const tag = el.tagName;
|
|
12218
12236
|
const normalizedText = getStableNormalizedText(el);
|
|
12219
|
-
|
|
12220
|
-
|
|
12221
|
-
let parent = el.parentElement;
|
|
12222
|
-
while (parent) {
|
|
12223
|
-
if (parent.id) {
|
|
12224
|
-
parentId = parent.id;
|
|
12225
|
-
break;
|
|
12226
|
-
}
|
|
12227
|
-
parent = parent.parentElement;
|
|
12228
|
-
}
|
|
12229
|
-
// Calculate index relative to the container
|
|
12230
|
-
const container = parent || document.body;
|
|
12237
|
+
const { parentId, ancestorEl: idAncestor } = findNearestIdAncestor(el);
|
|
12238
|
+
const container = idAncestor ?? document.body;
|
|
12231
12239
|
const siblings = Array.from(container.querySelectorAll(tag));
|
|
12232
|
-
const
|
|
12240
|
+
const rawIndex = siblings.indexOf(el);
|
|
12241
|
+
if (rawIndex === -1) {
|
|
12242
|
+
console.error('[CustardUI] createDescriptor: element not found in container, ' +
|
|
12243
|
+
'element may be detached from the DOM. Please open an issue.', el);
|
|
12244
|
+
}
|
|
12245
|
+
const index = rawIndex !== -1 ? rawIndex : 0;
|
|
12233
12246
|
const descriptor = {
|
|
12234
12247
|
tag,
|
|
12235
|
-
index
|
|
12248
|
+
index,
|
|
12236
12249
|
textSnippet: normalizedText.substring(0, 32),
|
|
12237
12250
|
textHash: hashCode(normalizedText),
|
|
12238
|
-
elementId: el.id,
|
|
12239
12251
|
};
|
|
12252
|
+
if (el.id) {
|
|
12253
|
+
descriptor.elementId = el.id;
|
|
12254
|
+
}
|
|
12240
12255
|
if (parentId) {
|
|
12241
12256
|
descriptor.parentId = parentId;
|
|
12242
12257
|
}
|
|
@@ -12438,7 +12453,7 @@
|
|
|
12438
12453
|
* Returns an array of elements. For specific descriptors, usually contains 0 or 1 element.
|
|
12439
12454
|
* For ID-only descriptors (tag='ANY'), may return multiple if duplicates exist.
|
|
12440
12455
|
*/
|
|
12441
|
-
function resolve(
|
|
12456
|
+
function resolve(descriptor) {
|
|
12442
12457
|
// 0. Direct ID Shortcut
|
|
12443
12458
|
if (descriptor.elementId) {
|
|
12444
12459
|
// Always support duplicate IDs for consistency, even if technically invalid HTML.
|
|
@@ -12450,19 +12465,15 @@
|
|
|
12450
12465
|
return [];
|
|
12451
12466
|
}
|
|
12452
12467
|
// 1. Determine Scope
|
|
12453
|
-
|
|
12454
|
-
//
|
|
12468
|
+
// Default to document.body so index pool matches descriptor.ts,
|
|
12469
|
+
// which also falls back to document.body when no id-bearing ancestor is found.
|
|
12470
|
+
let scope = document.body;
|
|
12471
|
+
// Optimization: If parentId exists, try to narrow scope immediately.
|
|
12455
12472
|
if (descriptor.parentId) {
|
|
12456
|
-
const foundParent =
|
|
12473
|
+
const foundParent = document.getElementById(descriptor.parentId);
|
|
12457
12474
|
if (foundParent instanceof HTMLElement) {
|
|
12458
12475
|
scope = foundParent;
|
|
12459
12476
|
}
|
|
12460
|
-
else {
|
|
12461
|
-
const globalParent = document.getElementById(descriptor.parentId);
|
|
12462
|
-
if (globalParent) {
|
|
12463
|
-
scope = globalParent;
|
|
12464
|
-
}
|
|
12465
|
-
}
|
|
12466
12477
|
}
|
|
12467
12478
|
// 2. Candidate Search & Scoring
|
|
12468
12479
|
const candidates = scope.querySelectorAll(descriptor.tag);
|
|
@@ -14567,7 +14578,8 @@
|
|
|
14567
14578
|
* Initializes the UI manager (settings and share UI) using the provided config.
|
|
14568
14579
|
*/
|
|
14569
14580
|
function initUIManager(runtime, config) {
|
|
14570
|
-
const
|
|
14581
|
+
const { enabled, ...widgetSettings } = config.settings ?? {};
|
|
14582
|
+
const settingsEnabled = enabled === true;
|
|
14571
14583
|
const callbacks = {
|
|
14572
14584
|
resetToDefault: () => runtime.resetToDefault(),
|
|
14573
14585
|
iconSettings: runtime.iconSettingsStore,
|
|
@@ -14576,7 +14588,7 @@
|
|
|
14576
14588
|
const uiManager = new CustardUIManager({
|
|
14577
14589
|
callbacks,
|
|
14578
14590
|
settingsEnabled,
|
|
14579
|
-
...
|
|
14591
|
+
...widgetSettings,
|
|
14580
14592
|
});
|
|
14581
14593
|
uiManager.render();
|
|
14582
14594
|
return uiManager;
|
|
@@ -15728,7 +15740,6 @@
|
|
|
15728
15740
|
}
|
|
15729
15741
|
|
|
15730
15742
|
class HighlightService {
|
|
15731
|
-
rootEl;
|
|
15732
15743
|
overlayApp;
|
|
15733
15744
|
state = new HighlightState();
|
|
15734
15745
|
resizeObserver;
|
|
@@ -15737,9 +15748,7 @@
|
|
|
15737
15748
|
activeAnnotations = new Map();
|
|
15738
15749
|
onWindowResize = () => this.updatePositions();
|
|
15739
15750
|
|
|
15740
|
-
constructor(
|
|
15741
|
-
this.rootEl = rootEl;
|
|
15742
|
-
|
|
15751
|
+
constructor() {
|
|
15743
15752
|
this.resizeObserver = new ResizeObserver(() => {
|
|
15744
15753
|
this.updatePositions();
|
|
15745
15754
|
});
|
|
@@ -15753,7 +15762,7 @@
|
|
|
15753
15762
|
const targets = [];
|
|
15754
15763
|
|
|
15755
15764
|
descriptors.forEach((desc) => {
|
|
15756
|
-
const matchingEls = resolve(
|
|
15765
|
+
const matchingEls = resolve(desc);
|
|
15757
15766
|
|
|
15758
15767
|
if (matchingEls && matchingEls.length > 0) targets.push(...matchingEls);
|
|
15759
15768
|
});
|
|
@@ -15771,7 +15780,7 @@
|
|
|
15771
15780
|
const annotations = new Map();
|
|
15772
15781
|
|
|
15773
15782
|
descriptors.forEach((desc) => {
|
|
15774
|
-
const matchingEls = resolve(
|
|
15783
|
+
const matchingEls = resolve(desc);
|
|
15775
15784
|
|
|
15776
15785
|
if (matchingEls && matchingEls.length > 0) {
|
|
15777
15786
|
targets.push(...matchingEls);
|
|
@@ -15937,7 +15946,6 @@
|
|
|
15937
15946
|
const SHOW_ELEMENT_CLASS = 'cv-show-element';
|
|
15938
15947
|
|
|
15939
15948
|
class FocusService {
|
|
15940
|
-
rootEl;
|
|
15941
15949
|
hiddenElements = new SvelteSet();
|
|
15942
15950
|
dividers = new SvelteSet(); // Store Svelte App instances
|
|
15943
15951
|
excludedTags;
|
|
@@ -15948,15 +15956,13 @@
|
|
|
15948
15956
|
|
|
15949
15957
|
highlightService;
|
|
15950
15958
|
|
|
15951
|
-
constructor(
|
|
15952
|
-
this.rootEl = rootEl;
|
|
15953
|
-
|
|
15959
|
+
constructor(options) {
|
|
15954
15960
|
const userTags = options.shareExclusions?.tags || [];
|
|
15955
15961
|
const userIds = options.shareExclusions?.ids || [];
|
|
15956
15962
|
|
|
15957
15963
|
this.excludedTags = new SvelteSet([...DEFAULT_EXCLUDED_TAGS, ...userTags].map((t) => t.toUpperCase()));
|
|
15958
15964
|
this.excludedIds = new SvelteSet([...DEFAULT_EXCLUDED_IDS, ...userIds]);
|
|
15959
|
-
this.highlightService = new HighlightService(
|
|
15965
|
+
this.highlightService = new HighlightService();
|
|
15960
15966
|
|
|
15961
15967
|
// Subscribe to store for exit signal
|
|
15962
15968
|
this.unsubscribe = effect_root(() => {
|
|
@@ -16048,7 +16054,7 @@
|
|
|
16048
16054
|
const targets = [];
|
|
16049
16055
|
|
|
16050
16056
|
descriptors.forEach((desc) => {
|
|
16051
|
-
const matchingEls = resolve(
|
|
16057
|
+
const matchingEls = resolve(desc);
|
|
16052
16058
|
|
|
16053
16059
|
if (matchingEls && matchingEls.length > 0) {
|
|
16054
16060
|
targets.push(...matchingEls);
|
|
@@ -16087,7 +16093,7 @@
|
|
|
16087
16093
|
const targets = [];
|
|
16088
16094
|
|
|
16089
16095
|
descriptors.forEach((desc) => {
|
|
16090
|
-
const matchingEls = resolve(
|
|
16096
|
+
const matchingEls = resolve(desc);
|
|
16091
16097
|
|
|
16092
16098
|
if (matchingEls && matchingEls.length > 0) {
|
|
16093
16099
|
targets.push(...matchingEls);
|
|
@@ -16779,7 +16785,7 @@
|
|
|
16779
16785
|
this.resolveInitialState(opt.adaptationConfig ?? null);
|
|
16780
16786
|
|
|
16781
16787
|
// Resolve Exclusions
|
|
16782
|
-
this.focusService = new FocusService(
|
|
16788
|
+
this.focusService = new FocusService({
|
|
16783
16789
|
shareExclusions: opt.configFile.config?.shareExclusions || {}
|
|
16784
16790
|
});
|
|
16785
16791
|
}
|